Chromium Code Reviews| Index: src/x64/code-stubs-x64.cc |
| =================================================================== |
| --- src/x64/code-stubs-x64.cc (revision 7084) |
| +++ src/x64/code-stubs-x64.cc (working copy) |
| @@ -3653,20 +3653,31 @@ |
| void InstanceofStub::Generate(MacroAssembler* masm) { |
| // Implements "value instanceof function" operator. |
| - // Expected input state: |
| + // Expected input state with no inline cache: |
| // rsp[0] : return address |
| // rsp[1] : function pointer |
| // rsp[2] : value |
| + // Expected input state with an inline one-element cache: |
| + // rsp[0] : return address |
| + // rsp[1] : offset from return address to location of inline cache |
| + // rsp[2] : function pointer |
| + // rsp[3] : value |
| // Returns a bitwise zero to indicate that the value |
| // is and instance of the function and anything else to |
| // indicate that the value is not an instance. |
| + static const int kOffsetToMapCheckValue = 5; |
| + static const int kOffsetToResultValue = 21; |
|
Søren Thygesen Gjesse
2011/03/09 15:21:53
Please comment on what instructions these words re
|
| + static const unsigned int kWordBeforeMapCheckValue = 0xBA49FF78; |
| + static const unsigned int kWordBeforeResultValue = 0x458B4909; |
| // None of the flags are supported on X64. |
|
Søren Thygesen Gjesse
2011/03/09 15:21:53
This comment seems no longer valid. None -> Some?
|
| - ASSERT(flags_ == kNoFlags); |
| + ASSERT(flags_ == kNoFlags || HasCallSiteInlineCheck()); |
| + int extra_stack_space = HasCallSiteInlineCheck() ? kPointerSize : 0; |
| // Get the object - go slow case if it's a smi. |
| Label slow; |
| - __ movq(rax, Operand(rsp, 2 * kPointerSize)); |
| + |
| + __ movq(rax, Operand(rsp, 2 * kPointerSize + extra_stack_space)); |
| __ JumpIfSmi(rax, &slow); |
| // Check that the left hand is a JS object. Leave its map in rax. |
| @@ -3676,19 +3687,23 @@ |
| __ j(above, &slow); |
| // Get the prototype of the function. |
| - __ movq(rdx, Operand(rsp, 1 * kPointerSize)); |
| + __ movq(rdx, Operand(rsp, 1 * kPointerSize + extra_stack_space)); |
| // rdx is function, rax is map. |
| - // Look up the function and the map in the instanceof cache. |
| - NearLabel miss; |
| - __ CompareRoot(rdx, Heap::kInstanceofCacheFunctionRootIndex); |
| - __ j(not_equal, &miss); |
| - __ CompareRoot(rax, Heap::kInstanceofCacheMapRootIndex); |
| - __ j(not_equal, &miss); |
| - __ LoadRoot(rax, Heap::kInstanceofCacheAnswerRootIndex); |
| - __ ret(2 * kPointerSize); |
| + // If there is a call site cache don't look in the global cache, but do the |
| + // real lookup and update the call site cache. |
| + if (!HasCallSiteInlineCheck()) { |
| + // Look up the function and the map in the instanceof cache. |
| + NearLabel miss; |
| + __ CompareRoot(rdx, Heap::kInstanceofCacheFunctionRootIndex); |
| + __ j(not_equal, &miss); |
| + __ CompareRoot(rax, Heap::kInstanceofCacheMapRootIndex); |
| + __ j(not_equal, &miss); |
| + __ LoadRoot(rax, Heap::kInstanceofCacheAnswerRootIndex); |
| + __ ret(2 * kPointerSize); |
| + __ bind(&miss); |
| + } |
| - __ bind(&miss); |
| __ TryGetFunctionPrototype(rdx, rbx, &slow); |
| // Check that the function prototype is a JS object. |
| @@ -3702,8 +3717,19 @@ |
| // rax is object map. |
| // rdx is function. |
| // rbx is function prototype. |
| - __ StoreRoot(rdx, Heap::kInstanceofCacheFunctionRootIndex); |
| - __ StoreRoot(rax, Heap::kInstanceofCacheMapRootIndex); |
| + if (!HasCallSiteInlineCheck()) { |
| + __ StoreRoot(rdx, Heap::kInstanceofCacheFunctionRootIndex); |
| + __ StoreRoot(rax, Heap::kInstanceofCacheMapRootIndex); |
| + } else { |
| + __ movq(kScratchRegister, Operand(rsp, 0 * kPointerSize)); |
| + __ subq(kScratchRegister, Operand(rsp, 1 * kPointerSize)); |
| + __ movq(Operand(kScratchRegister, kOffsetToMapCheckValue), rax); |
| + if (FLAG_debug_code) { |
| + __ movl(rdi, Immediate(kWordBeforeMapCheckValue)); |
| + __ cmpl(Operand(kScratchRegister, kOffsetToMapCheckValue - 4), rdi); |
| + __ Assert(equal, "InstanceofStub unexpected call site cache."); |
| + } |
| + } |
| __ movq(rcx, FieldOperand(rax, Map::kPrototypeOffset)); |
| @@ -3722,19 +3748,56 @@ |
| __ jmp(&loop); |
| __ bind(&is_instance); |
| - __ xorl(rax, rax); |
| - // Store bitwise zero in the cache. This is a Smi in GC terms. |
| - STATIC_ASSERT(kSmiTag == 0); |
| - __ StoreRoot(rax, Heap::kInstanceofCacheAnswerRootIndex); |
| - __ ret(2 * kPointerSize); |
| + if (!HasCallSiteInlineCheck()) { |
| + __ xorl(rax, rax); |
| + // Store bitwise zero in the cache. This is a Smi in GC terms. |
| + STATIC_ASSERT(kSmiTag == 0); |
| + __ StoreRoot(rax, Heap::kInstanceofCacheAnswerRootIndex); |
| + } else { |
| + // Store offset of true in the root array at the inline check site. |
| + ASSERT((Heap::kTrueValueRootIndex << kPointerSizeLog2) - kRootRegisterBias |
| + == 0xB0 - 0x100); |
| + __ movl(rax, Immediate(0xB0)); // TrueValue is at -10 * kPointerSize. |
| + __ movq(kScratchRegister, Operand(rsp, 0 * kPointerSize)); |
| + __ subq(kScratchRegister, Operand(rsp, 1 * kPointerSize)); |
| + __ movb(Operand(kScratchRegister, kOffsetToResultValue), rax); |
| + if (FLAG_debug_code) { |
| + __ movl(rax, Immediate(kWordBeforeResultValue)); |
| + __ cmpl(Operand(kScratchRegister, kOffsetToResultValue - 4), rax); |
| + __ Assert(equal, "InstanceofStub unexpected call site cache."); |
| + } |
| + __ xorl(rax, rax); |
| + } |
| + __ ret(2 * kPointerSize + extra_stack_space); |
| __ bind(&is_not_instance); |
| - // We have to store a non-zero value in the cache. |
| - __ StoreRoot(kScratchRegister, Heap::kInstanceofCacheAnswerRootIndex); |
| - __ ret(2 * kPointerSize); |
| + if (!HasCallSiteInlineCheck()) { |
| + // We have to store a non-zero value in the cache. |
| + __ StoreRoot(kScratchRegister, Heap::kInstanceofCacheAnswerRootIndex); |
| + } else { |
| + // Store offset of false in the root array at the inline check site. |
| + ASSERT((Heap::kFalseValueRootIndex << kPointerSizeLog2) - kRootRegisterBias |
| + == 0xB8 - 0x100); |
| + __ movl(rax, Immediate(0xB8)); // TrueValue is at -9 * kPointerSize. |
|
Søren Thygesen Gjesse
2011/03/09 15:21:53
TrueValue -> FalseValue
|
| + __ movq(kScratchRegister, Operand(rsp, 0 * kPointerSize)); |
| + __ subq(kScratchRegister, Operand(rsp, 1 * kPointerSize)); |
| + __ movb(Operand(kScratchRegister, kOffsetToResultValue), rax); |
| + if (FLAG_debug_code) { |
| + __ movl(rax, Immediate(kWordBeforeResultValue)); |
| + __ cmpl(Operand(kScratchRegister, kOffsetToResultValue - 4), rax); |
| + __ Assert(equal, "InstanceofStub unexpected call site cache (mov)"); |
| + } |
| + } |
| + __ ret(2 * kPointerSize + extra_stack_space); |
| // Slow-case: Go through the JavaScript implementation. |
| __ bind(&slow); |
| + if (HasCallSiteInlineCheck()) { |
| + // Remove extra value from the stack. |
| + __ pop(rcx); |
| + __ pop(rax); |
| + __ push(rcx); |
| + } |
| __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
| } |