Index: src/ia32/codegen-ia32.cc |
=================================================================== |
--- src/ia32/codegen-ia32.cc (revision 1804) |
+++ src/ia32/codegen-ia32.cc (working copy) |
@@ -30,6 +30,7 @@ |
#include "bootstrapper.h" |
#include "codegen-inl.h" |
#include "debug.h" |
+#include "ic-inl.h" |
#include "parser.h" |
#include "register-allocator-inl.h" |
#include "runtime.h" |
@@ -3410,7 +3411,10 @@ |
? RelocInfo::CODE_TARGET |
: RelocInfo::CODE_TARGET_CONTEXT; |
Result answer = frame_->CallLoadIC(mode); |
- |
+ // A test eax instruction following the call signals that the inobject |
+ // property case was inlined. Ensure that there is not a test eax |
+ // instruction here. |
+ __ nop(); |
// Discard the global object. The result is in answer. |
frame_->Drop(); |
return answer; |
@@ -5233,6 +5237,47 @@ |
#endif |
+class DeferredReferenceGetNamedValue: public DeferredCode { |
+ public: |
+ DeferredReferenceGetNamedValue(CodeGenerator* cgen, Handle<String> name) |
+ : DeferredCode(cgen), name_(name) { |
+ set_comment("[ DeferredReferenceGetNamedValue"); |
+ } |
+ |
+ virtual void Generate(); |
+ |
+ Label* patch_site() { return &patch_site_; } |
+ |
+ private: |
+ Label patch_site_; |
+ Handle<String> name_; |
+}; |
+ |
+ |
+void DeferredReferenceGetNamedValue::Generate() { |
+ CodeGenerator* cgen = generator(); |
+ Result receiver(cgen); |
+ enter()->Bind(&receiver); |
+ |
+ cgen->frame()->Push(&receiver); |
+ cgen->frame()->Push(name_); |
+ Result answer = cgen->frame()->CallLoadIC(RelocInfo::CODE_TARGET); |
+ // The call must be followed by a test eax instruction to indicate |
+ // that the inobject property case was inlined. |
+ ASSERT(answer.is_register() && answer.reg().is(eax)); |
+ // Store the delta to the map check instruction here in the test |
+ // instruction. |
+ int delta_to_patch_site = __ SizeOfCodeGeneratedSince(patch_site()); |
+ // Here we use masm_-> instead of the double underscore macro because |
+ // this is the instruction that gets patched and coverage code gets in |
+ // the way. |
+ masm_->test(answer.reg(), Immediate(-delta_to_patch_site)); |
+ __ IncrementCounter(&Counters::named_load_inline_miss, 1); |
+ receiver = cgen->frame()->Pop(); |
+ exit_.Jump(&receiver, &answer); |
+} |
+ |
+ |
class DeferredReferenceGetKeyedValue: public DeferredCode { |
public: |
DeferredReferenceGetKeyedValue(CodeGenerator* generator, bool is_global) |
@@ -5334,16 +5379,63 @@ |
// 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"); |
- cgen_->frame()->Push(GetName()); |
+ Variable* var = expression_->AsVariableProxy()->AsVariable(); |
+ bool is_global = var != NULL; |
+ ASSERT(!is_global || var->is_global()); |
- Variable* var = expression_->AsVariableProxy()->AsVariable(); |
- ASSERT(var == NULL || var->is_global()); |
- RelocInfo::Mode mode = (var == NULL) |
- ? RelocInfo::CODE_TARGET |
- : RelocInfo::CODE_TARGET_CONTEXT; |
- Result answer = cgen_->frame()->CallLoadIC(mode); |
- cgen_->frame()->Push(&answer); |
+ if (is_global || cgen_->scope()->is_global_scope()) { |
+ // Do not inline the inobject property case for loads from the |
+ // global object or loads in toplevel code. |
+ Comment cmnt(masm, "[ Load from named Property"); |
+ cgen_->frame()->Push(GetName()); |
+ |
+ RelocInfo::Mode mode = is_global |
+ ? RelocInfo::CODE_TARGET_CONTEXT |
+ : RelocInfo::CODE_TARGET; |
+ Result answer = cgen_->frame()->CallLoadIC(mode); |
+ // A test eax instruction following the call signals that the |
+ // inobject property case was inlined. Ensure that there is not |
+ // a test eax instruction here. |
+ __ nop(); |
+ cgen_->frame()->Push(&answer); |
+ } else { |
+ // Inline the inobject property case. |
+ Comment cmnt(masm, "[ Inlined named property load"); |
+ DeferredReferenceGetNamedValue* deferred = |
+ new DeferredReferenceGetNamedValue(cgen_, GetName()); |
+ Result receiver = cgen_->frame()->Pop(); |
+ receiver.ToRegister(); |
+ // Check that the receiver is a heap object. |
+ __ test(receiver.reg(), Immediate(kSmiTagMask)); |
+ deferred->enter()->Branch(zero, &receiver, not_taken); |
+ |
+ // Preallocate the value register to ensure that there is no |
+ // spill emitted between the patch site label and the offset in |
+ // the load instruction. |
+ Result value = cgen_->allocator()->Allocate(); |
+ ASSERT(value.is_valid()); |
+ __ bind(deferred->patch_site()); |
+ // This is the map chack instruction that will be patched. |
+ // Initially use an invalid map to force a failure. |
+ __ cmp(FieldOperand(receiver.reg(), HeapObject::kMapOffset), |
+ Immediate(Factory::null_value())); |
+ deferred->enter()->Branch(not_equal, &receiver, not_taken); |
+ |
+ // The delta from the patch label to the load offset must be |
+ // statically known. |
+ ASSERT(masm->SizeOfCodeGeneratedSince(deferred->patch_site()) == |
+ LoadIC::kOffsetToLoadInstruction); |
+ // The initial (invalid) offset has to be large enough to force |
+ // a 32-bit instruction encoding to allow patching with an |
+ // arbitrary offset. Use kMaxInt (minus kHeapObjectTag). |
+ int offset = kMaxInt; |
+ __ mov(value.reg(), FieldOperand(receiver.reg(), offset)); |
+ |
+ __ IncrementCounter(&Counters::named_load_inline, 1); |
+ deferred->BindExit(&receiver, &value); |
+ cgen_->frame()->Push(&receiver); |
+ cgen_->frame()->Push(&value); |
+ } |
break; |
} |