| 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;
|
| }
|
|
|
|
|