Index: src/codegen-ia32.cc |
=================================================================== |
--- src/codegen-ia32.cc (revision 1003) |
+++ src/codegen-ia32.cc (working copy) |
@@ -3778,6 +3778,40 @@ |
} |
+class DeferredReferenceGetKeyedValue: public DeferredCode { |
+ public: |
+ DeferredReferenceGetKeyedValue(CodeGenerator* generator, bool is_global) |
+ : DeferredCode(generator), is_global_(is_global) { |
+ set_comment("[ DeferredReferenceGetKeyedValue"); |
+ } |
+ |
+ virtual void Generate() { |
+ Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
+ // Calculate the delta from the IC call instruction to the map |
+ // check cmp instruction in the inlined version. This delta is |
+ // stored in a test(eax, delta) instruction after the call so that |
+ // we can find it in the IC initialization code and patch the cmp |
+ // instruction. This means that we cannot allow test instructions |
+ // after calls to KeyedLoadIC stubs in other places. |
+ int delta_to_patch_site = __ SizeOfCodeGeneratedSince(patch_site()); |
+ if (is_global_) { |
+ __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
+ } else { |
+ __ call(ic, RelocInfo::CODE_TARGET); |
+ } |
+ __ test(eax, Immediate(-delta_to_patch_site)); |
+ __ IncrementCounter(&Counters::keyed_load_inline_miss, 1); |
+ } |
+ |
+ Label* patch_site() { return &patch_site_; } |
+ |
+ private: |
+ Label patch_site_; |
+ bool is_global_; |
+}; |
+ |
+ |
+ |
#undef __ |
#define __ masm-> |
@@ -3813,42 +3847,94 @@ |
} |
case NAMED: { |
- // TODO(1241834): Make sure that this it is safe to ignore the |
- // distinction between expressions in a typeof and not in a typeof. If |
- // there is a chance that reference errors can be thrown below, we |
- // must distinguish between the two kinds of loads (typeof expression |
- // loads must not throw a reference error). |
+ // TODO(1241834): Make sure that it is safe to ignore the |
+ // distinction between expressions in a typeof and not in a |
+ // typeof. If there is a chance that reference errors can be |
+ // thrown below, we must distinguish between the two kinds of |
+ // loads (typeof expression loads must not throw a reference |
+ // error). |
Comment cmnt(masm, "[ Load from named Property"); |
Handle<String> name(GetName()); |
+ Variable* var = expression_->AsVariableProxy()->AsVariable(); |
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
// Setup the name register. |
__ mov(ecx, name); |
- |
- Variable* var = expression_->AsVariableProxy()->AsVariable(); |
if (var != NULL) { |
ASSERT(var->is_global()); |
__ call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
} else { |
__ call(ic, RelocInfo::CODE_TARGET); |
} |
- frame->Push(eax); // IC call leaves result in eax, push it out |
+ // Push the result. |
+ frame->Push(eax); |
break; |
} |
case KEYED: { |
- // TODO(1241834): Make sure that this it is safe to ignore the |
- // distinction between expressions in a typeof and not in a typeof. |
- Comment cmnt(masm, "[ Load from keyed Property"); |
- Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
- |
+ // TODO(1241834): Make sure that it is safe to ignore the |
+ // distinction between expressions in a typeof and not in a |
+ // typeof. |
Variable* var = expression_->AsVariableProxy()->AsVariable(); |
- if (var != NULL) { |
- ASSERT(var->is_global()); |
- __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
+ // Inline array load code if inside of a loop. We do not know |
+ // the receiver map yet, so we initially generate the code with |
+ // a check against an invalid map. In the inline cache code, we |
+ // patch the map check if appropriate. |
+ if (cgen_->loop_nesting() > 0) { |
+ Comment cmnt(masm, "[ Inlined array index load"); |
+ DeferredReferenceGetKeyedValue* deferred = |
+ new DeferredReferenceGetKeyedValue(cgen_, var != NULL); |
+ // Load receiver and check that it is not a smi (only needed |
+ // if not contextual) and that it has the expected map. |
iposva
2008/12/22 18:59:16
I think it would improve the readability if was cl
|
+ __ mov(edx, Operand(esp, kPointerSize)); |
+ if (var == NULL) { |
+ __ test(edx, Immediate(kSmiTagMask)); |
+ __ j(zero, deferred->enter(), not_taken); |
+ } |
+ // Initially, use an invalid map. The map is patched in the IC |
+ // initialization code. |
+ __ bind(deferred->patch_site()); |
+ __ cmp(FieldOperand(edx, HeapObject::kMapOffset), |
+ Immediate(Factory::null_value())); |
+ __ j(not_equal, deferred->enter(), not_taken); |
+ // Load key and check that it is a smi. |
+ __ mov(eax, Operand(esp, 0)); |
+ __ test(eax, Immediate(kSmiTagMask)); |
+ __ j(not_zero, deferred->enter(), not_taken); |
+ // Shift to get actual index value. |
+ __ sar(eax, kSmiTagSize); |
Kasper Lund
2008/12/22 09:52:13
Maybe we should consider keeping the FixedArray le
Mads Ager (chromium)
2008/12/22 12:59:11
That would be an interesting experiment. I'll try
|
+ // Get the elements array from the receiver and check that it |
+ // is not a dictionary. |
+ __ mov(edx, FieldOperand(edx, JSObject::kElementsOffset)); |
+ __ cmp(FieldOperand(edx, HeapObject::kMapOffset), |
+ Immediate(Factory::hash_table_map())); |
+ __ j(equal, deferred->enter(), not_taken); |
+ // Check that key is within bounds. |
+ __ cmp(eax, FieldOperand(edx, Array::kLengthOffset)); |
+ __ j(above_equal, deferred->enter(), not_taken); |
+ // Load and check that the result is not the hole. |
+ __ mov(eax, |
+ Operand(edx, eax, times_4, Array::kHeaderSize - kHeapObjectTag)); |
+ __ cmp(Operand(eax), Immediate(Factory::the_hole_value())); |
+ __ j(equal, deferred->enter(), not_taken); |
+ __ IncrementCounter(&Counters::keyed_load_inline, 1); |
+ __ bind(deferred->exit()); |
} else { |
- __ call(ic, RelocInfo::CODE_TARGET); |
+ Comment cmnt(masm, "[ Load from keyed Property"); |
+ Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
+ if (var != NULL) { |
+ ASSERT(var->is_global()); |
+ __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
+ } else { |
+ __ call(ic, RelocInfo::CODE_TARGET); |
+ } |
+ // Make sure that we do not have a test instruction after the |
+ // call. A test instruction after the call is used to |
+ // indicate that we have generated an inline version of the |
+ // keyed load. |
+ __ nop(); |
Kasper Lund
2008/12/22 09:52:13
I guess here the nop is really needed because the
Mads Ager (chromium)
2008/12/22 12:59:11
Yes, exactly. I'll update the comment to make it
iposva
2008/12/22 18:59:16
Alternatively you could bind a label after the pus
|
} |
- frame->Push(eax); // IC call leaves result in eax, push it out |
+ // Push the result. |
+ frame->Push(eax); |
break; |
} |