Index: src/arm/codegen-arm.cc |
=================================================================== |
--- src/arm/codegen-arm.cc (revision 4459) |
+++ src/arm/codegen-arm.cc (working copy) |
@@ -358,12 +358,9 @@ |
Label check_exit_codesize; |
masm_->bind(&check_exit_codesize); |
#endif |
- |
- { // NOLINT |
- // Make sure that the constant pool is not emitted inside of the return |
- // sequence. |
- Assembler::BlockConstPoolScope block_const_pool(masm_); |
- |
+ // Make sure that the constant pool is not emitted inside of the return |
+ // sequence. |
+ { Assembler::BlockConstPoolScope block_const_pool(masm_); |
// Tear down the frame which will restore the caller's frame pointer and |
// the link register. |
frame_->Exit(); |
@@ -393,6 +390,7 @@ |
// Code generation state must be reset. |
ASSERT(!has_cc()); |
ASSERT(state_ == NULL); |
+ ASSERT(loop_nesting() == 0); |
ASSERT(!function_return_is_shadowed_); |
function_return_.Unuse(); |
DeleteFrame(); |
@@ -2940,20 +2938,13 @@ |
__ bind(&fast); |
} |
- // All extension objects were empty and it is safe to use a global |
- // load IC call. |
- Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
// Load the global object. |
LoadGlobal(); |
- // Setup the name register. |
+ // Setup the name register and call load IC. |
__ mov(r2, Operand(slot->var()->name())); |
- // Call IC stub. |
- if (typeof_state == INSIDE_TYPEOF) { |
- frame_->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); |
- } else { |
- frame_->CallCodeObject(ic, RelocInfo::CODE_TARGET_CONTEXT, 0); |
- } |
- |
+ frame_->CallLoadIC(typeof_state == INSIDE_TYPEOF |
+ ? RelocInfo::CODE_TARGET |
+ : RelocInfo::CODE_TARGET_CONTEXT); |
// Drop the global object. The result is in r0. |
frame_->Drop(); |
} |
@@ -4935,6 +4926,85 @@ |
} |
+class DeferredReferenceGetNamedValue: public DeferredCode { |
+ public: |
+ explicit DeferredReferenceGetNamedValue(Handle<String> name) : name_(name) { |
+ set_comment("[ DeferredReferenceGetNamedValue"); |
+ } |
+ |
+ virtual void Generate(); |
+ |
+ private: |
+ Handle<String> name_; |
+}; |
+ |
+ |
+void DeferredReferenceGetNamedValue::Generate() { |
+ __ IncrementCounter(&Counters::named_load_inline_miss, 1, r1, r2); |
+ // Setup the name register and call load IC. |
+ __ mov(r2, Operand(name_)); |
+ Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
+ __ Call(ic, RelocInfo::CODE_TARGET); |
+ // The call must be followed by a b instruction to indicate that the inobject |
+ // property case was inlined. Jumping back from the deferred code ensures |
+ // that. |
+} |
+ |
+ |
+void CodeGenerator::EmitNamedLoad(Handle<String> name, bool is_contextual) { |
+ if (is_contextual || scope()->is_global_scope() || loop_nesting() == 0) { |
+ Comment cmnt(masm(), "[ Load from named Property"); |
+ // Setup the name register and call load IC. |
+ __ mov(r2, Operand(name)); |
+ frame_->CallLoadIC(is_contextual |
+ ? RelocInfo::CODE_TARGET_CONTEXT |
+ : RelocInfo::CODE_TARGET); |
+ } else { |
+ // Inline the inobject property case. |
+ Comment cmnt(masm(), "[ Inlined named property load"); |
+ |
+ DeferredReferenceGetNamedValue* deferred = |
+ new DeferredReferenceGetNamedValue(name); |
+ |
+ // The following instructions are the inlined load of an in-object property. |
+ // Parts of this code is patched, so the exact instructions generated needs |
+ // to be fixed. Therefore the instruction pool is blocked when generating |
+ // this code |
+#ifdef DEBUG |
+ int kInlinedNamedLoadInstructions = 8; |
+ Label check_inlined_codesize; |
+ masm_->bind(&check_inlined_codesize); |
+#endif |
+ { Assembler::BlockConstPoolScope block_const_pool(masm_); |
+ // Load the receiver from the stack. |
+ __ ldr(r1, MemOperand(sp, 0)); |
+ |
+ // Check that the receiver is a heap object. |
+ __ tst(r1, Operand(kSmiTagMask)); |
+ deferred->Branch(eq); |
+ |
+ // Check the map. The null map used below is patched by the inline cache |
+ // code. |
+ __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); |
+ __ mov(r3, Operand(Factory::null_value())); |
+ __ cmp(r2, r3); |
+ deferred->Branch(ne); |
+ |
+ // Use initially use an invalid index. The index will be patched by the |
+ // inline cache code. |
+ __ ldr(r0, MemOperand(r1, 0)); |
+ } |
+ |
+ // Make sure that the expected number of instructions are generated. |
+ ASSERT_EQ(kInlinedNamedLoadInstructions, |
+ masm_->InstructionsGeneratedSince(&check_inlined_codesize)); |
+ |
+ __ IncrementCounter(&Counters::named_load_inline, 1, r1, r2); |
+ deferred->BindExit(); |
+ } |
+} |
+ |
+ |
void CodeGenerator::EmitKeyedLoad(bool is_global) { |
Comment cmnt(masm_, "[ Load from keyed Property"); |
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
@@ -4991,19 +5061,11 @@ |
} |
case NAMED: { |
- VirtualFrame* frame = cgen_->frame(); |
- 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(r2, Operand(name)); |
- ASSERT(var == NULL || var->is_global()); |
- RelocInfo::Mode rmode = (var == NULL) |
- ? RelocInfo::CODE_TARGET |
- : RelocInfo::CODE_TARGET_CONTEXT; |
- frame->CallCodeObject(ic, rmode, 0); |
- frame->EmitPush(r0); |
+ bool is_global = var != NULL; |
+ ASSERT(!is_global || var->is_global()); |
+ cgen_->EmitNamedLoad(GetName(), is_global); |
+ cgen_->frame()->EmitPush(r0); |
break; |
} |