Chromium Code Reviews| Index: src/ia32/code-stubs-ia32.cc |
| =================================================================== |
| --- src/ia32/code-stubs-ia32.cc (revision 6109) |
| +++ src/ia32/code-stubs-ia32.cc (working copy) |
| @@ -4973,6 +4973,18 @@ |
| } |
| +// Generate stub code for instanceof. |
| +// This code can patch an call site inlined cache of the instance of check, |
|
Mads Ager (chromium)
2011/01/04 17:25:58
an call site -> a call site
Søren Thygesen Gjesse
2011/01/05 09:28:00
Done.
|
| +// which looks like this. |
| +// cmp edi, <the hole, patched to a map> |
| +// jne <some label> |
| +// mov eax, <the hole, patched to either true or false> |
| +// If that patching is requested the stack will have the delte from the return |
| +// address to the cmp instruction just just below the return address. |
|
Mads Ager (chromium)
2011/01/04 17:25:58
just just -> just
Søren Thygesen Gjesse
2011/01/05 09:28:00
Done.
|
| +// esp[0] : return address |
| +// esp[4] : delta from return address to cmp instruction |
|
Mads Ager (chromium)
2011/01/04 17:25:58
You should add to this comment that call site patc
Søren Thygesen Gjesse
2011/01/05 09:28:00
Done.
|
| +// This also means that for the call site patching the args have to be in |
| +// registers and not on the stack. |
| void InstanceofStub::Generate(MacroAssembler* masm) { |
| // Fixed register usage throughout the stub. |
| Register object = eax; // Object (lhs). |
| @@ -4981,9 +4993,14 @@ |
| Register prototype = edi; // Prototype of the function. |
| Register scratch = ecx; |
| + ExternalReference roots_address = ExternalReference::roots_address(); |
| + |
| + ASSERT_EQ(object.code(), InstanceofStub::left().code()); |
| + ASSERT_EQ(function.code(), InstanceofStub::right().code()); |
| + |
| // Get the object and function - they are always both needed. |
| Label slow, not_js_object; |
| - if (!args_in_registers()) { |
| + if (!HasArgsInRegisters()) { |
| __ mov(object, Operand(esp, 2 * kPointerSize)); |
| __ mov(function, Operand(esp, 1 * kPointerSize)); |
| } |
| @@ -4993,22 +5010,26 @@ |
| __ j(zero, ¬_js_object, not_taken); |
| __ IsObjectJSObjectType(object, map, scratch, ¬_js_object); |
| - // Look up the function and the map in the instanceof cache. |
| - NearLabel miss; |
| - ExternalReference roots_address = ExternalReference::roots_address(); |
| - __ mov(scratch, Immediate(Heap::kInstanceofCacheFunctionRootIndex)); |
| - __ cmp(function, |
| - Operand::StaticArray(scratch, times_pointer_size, roots_address)); |
| - __ j(not_equal, &miss); |
| - __ mov(scratch, Immediate(Heap::kInstanceofCacheMapRootIndex)); |
| - __ cmp(map, Operand::StaticArray(scratch, times_pointer_size, roots_address)); |
| - __ j(not_equal, &miss); |
| - __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); |
| - __ mov(eax, Operand::StaticArray(scratch, times_pointer_size, roots_address)); |
| - __ IncrementCounter(&Counters::instance_of_cache, 1); |
| - __ ret((args_in_registers() ? 0 : 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; |
| + __ mov(scratch, Immediate(Heap::kInstanceofCacheFunctionRootIndex)); |
| + __ cmp(function, |
| + Operand::StaticArray(scratch, times_pointer_size, roots_address)); |
| + __ j(not_equal, &miss); |
| + __ mov(scratch, Immediate(Heap::kInstanceofCacheMapRootIndex)); |
| + __ cmp(map, Operand::StaticArray( |
| + scratch, times_pointer_size, roots_address)); |
| + __ j(not_equal, &miss); |
| + __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); |
| + __ mov(eax, Operand::StaticArray( |
| + scratch, times_pointer_size, roots_address)); |
| + __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); |
| + __ bind(&miss); |
| + } |
| - __ bind(&miss); |
| // Get the prototype of the function. |
| __ TryGetFunctionPrototype(function, prototype, scratch, &slow); |
| @@ -5017,13 +5038,24 @@ |
| __ j(zero, &slow, not_taken); |
| __ IsObjectJSObjectType(prototype, scratch, scratch, &slow); |
| - // Update the golbal instanceof cache with the current map and function. The |
| + // Update the global instanceof cache with the current map and function. The |
|
Mads Ager (chromium)
2011/01/04 17:25:58
global -> global or inlined?
Søren Thygesen Gjesse
2011/01/05 09:28:00
Done.
|
| // cached answer will be set when it is known. |
| + if (!HasCallSiteInlineCheck()) { |
| __ mov(scratch, Immediate(Heap::kInstanceofCacheMapRootIndex)); |
| __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_address), map); |
| __ mov(scratch, Immediate(Heap::kInstanceofCacheFunctionRootIndex)); |
| __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_address), |
| function); |
| + } else { |
| + // The constatns in for the code patching are based on no push instructions |
|
Mads Ager (chromium)
2011/01/04 17:25:58
constatns in for -> constants for
Søren Thygesen Gjesse
2011/01/05 09:28:00
Done.
|
| + // at the call site. |
| + ASSERT(HasArgsInRegisters()); |
| + // Get return address and delta to inlined map check. |
| + __ mov(scratch, Operand(esp, 0 * kPointerSize)); |
| + __ sub(scratch, Operand(esp, 1 * kPointerSize)); |
| + __ add(Operand(scratch), Immediate(2)); |
|
Mads Ager (chromium)
2011/01/04 17:25:58
Named constant? Also, can't this be part of the op
Søren Thygesen Gjesse
2011/01/05 09:28:00
Done.
|
| + __ mov(Operand(scratch, 0), map); |
| + } |
| // Loop through the prototype chain of the object looking for the function |
| // prototype. |
| @@ -5039,18 +5071,42 @@ |
| __ jmp(&loop); |
| __ bind(&is_instance); |
| - __ IncrementCounter(&Counters::instance_of_stub_true, 1); |
| - __ Set(eax, Immediate(0)); |
| - __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); |
| - __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_address), eax); |
| - __ ret((args_in_registers() ? 0 : 2) * kPointerSize); |
| + if (!HasCallSiteInlineCheck()) { |
| + __ Set(eax, Immediate(0)); |
| + __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); |
| + __ mov(Operand::StaticArray(scratch, |
| + times_pointer_size, roots_address), eax); |
| + } else { |
| + // Get return address and delte to inlined map check. |
| + __ mov(eax, Factory::true_value()); |
| + __ mov(scratch, Operand(esp, 0 * kPointerSize)); |
| + __ sub(scratch, Operand(esp, 1 * kPointerSize)); |
| + __ add(Operand(scratch), Immediate(13)); |
|
Mads Ager (chromium)
2011/01/04 17:25:58
Named constant? Combine with move?
Søren Thygesen Gjesse
2011/01/05 09:28:00
Done.
|
| + __ mov(Operand(scratch, 0), eax); |
| + if (!ReturnTrueFalseObject()) { |
| + __ Set(eax, Immediate(0)); |
| + } |
| + } |
| + __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); |
| __ bind(&is_not_instance); |
| - __ IncrementCounter(&Counters::instance_of_stub_false, 1); |
| - __ Set(eax, Immediate(Smi::FromInt(1))); |
| - __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); |
| - __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_address), eax); |
| - __ ret((args_in_registers() ? 0 : 2) * kPointerSize); |
| + if (!HasCallSiteInlineCheck()) { |
| + __ Set(eax, Immediate(Smi::FromInt(1))); |
| + __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); |
| + __ mov(Operand::StaticArray( |
| + scratch, times_pointer_size, roots_address), eax); |
| + } else { |
| + // Get return address and delte to inlined map check. |
| + __ mov(eax, Factory::false_value()); |
| + __ mov(scratch, Operand(esp, 0 * kPointerSize)); |
| + __ sub(scratch, Operand(esp, 1 * kPointerSize)); |
| + __ add(Operand(scratch), Immediate(13)); |
|
Mads Ager (chromium)
2011/01/04 17:25:58
Same here.
Søren Thygesen Gjesse
2011/01/05 09:28:00
Done.
|
| + __ mov(Operand(scratch, 0), eax); |
| + if (!ReturnTrueFalseObject()) { |
| + __ Set(eax, Immediate(Smi::FromInt(1))); |
| + } |
| + } |
| + __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); |
| Label object_not_null, object_not_null_or_smi; |
| __ bind(¬_js_object); |
| @@ -5064,39 +5120,70 @@ |
| // Null is not instance of anything. |
| __ cmp(object, Factory::null_value()); |
| __ j(not_equal, &object_not_null); |
| - __ IncrementCounter(&Counters::instance_of_stub_false_null, 1); |
| __ Set(eax, Immediate(Smi::FromInt(1))); |
| - __ ret((args_in_registers() ? 0 : 2) * kPointerSize); |
| + __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); |
| __ bind(&object_not_null); |
| // Smi values is not instance of anything. |
| __ test(object, Immediate(kSmiTagMask)); |
| __ j(not_zero, &object_not_null_or_smi, not_taken); |
| __ Set(eax, Immediate(Smi::FromInt(1))); |
| - __ ret((args_in_registers() ? 0 : 2) * kPointerSize); |
| + __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); |
| __ bind(&object_not_null_or_smi); |
| // String values is not instance of anything. |
| Condition is_string = masm->IsObjectStringType(object, scratch, scratch); |
| __ j(NegateCondition(is_string), &slow); |
| - __ IncrementCounter(&Counters::instance_of_stub_false_string, 1); |
| __ Set(eax, Immediate(Smi::FromInt(1))); |
| - __ ret((args_in_registers() ? 0 : 2) * kPointerSize); |
| + __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); |
| // Slow-case: Go through the JavaScript implementation. |
| __ bind(&slow); |
| - if (args_in_registers()) { |
| + if (HasArgsInRegisters()) { |
| // Push arguments below return address. |
| __ pop(scratch); |
| __ push(object); |
| __ push(function); |
| __ push(scratch); |
| } |
| - __ IncrementCounter(&Counters::instance_of_slow, 1); |
| __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
| } |
| +Register InstanceofStub::left() { return eax; } |
| + |
|
Mads Ager (chromium)
2011/01/04 17:25:58
two blank lines between functions
Søren Thygesen Gjesse
2011/01/05 09:28:00
Done.
|
| +Register InstanceofStub::right() { return edx; } |
| + |
|
Mads Ager (chromium)
2011/01/04 17:25:58
Two blanks.
Søren Thygesen Gjesse
2011/01/05 09:28:00
Done.
|
| +const char* InstanceofStub::GetName() { |
| + if (name_ != NULL) return name_; |
| + const int kMaxNameLength = 100; |
| + name_ = Bootstrapper::AllocateAutoDeletedArray(kMaxNameLength); |
| + if (name_ == NULL) return "OOM"; |
| + |
| + const char* args = ""; |
| + if (HasArgsInRegisters()) { |
| + args = "_REGS"; |
| + } |
| + |
| + const char* inline_check = ""; |
| + if (HasCallSiteInlineCheck()) { |
| + inline_check = "_INLINE"; |
| + } |
| + |
| + const char* return_true_false_object = ""; |
| + if (ReturnTrueFalseObject()) { |
| + return_true_false_object = "_TRUEFALSE"; |
| + } |
| + |
| + OS::SNPrintF(Vector<char>(name_, kMaxNameLength), |
| + "InstanceofStub%s%s", |
|
Mads Ager (chromium)
2011/01/04 17:25:58
Isn't there a %s missing here?
Søren Thygesen Gjesse
2011/01/05 09:28:00
Done.
|
| + args, |
| + inline_check, |
| + return_true_false_object); |
| + return name_; |
| +} |
| + |
| + |
| int CompareStub::MinorKey() { |
| // Encode the three parameters in a unique 16 bit value. To avoid duplicate |
| // stubs the never NaN NaN condition is only taken into account if the |