| Index: src/arm/codegen-arm.cc
|
| ===================================================================
|
| --- src/arm/codegen-arm.cc (revision 4738)
|
| +++ src/arm/codegen-arm.cc (working copy)
|
| @@ -66,50 +66,16 @@
|
| static bool IsEasyToMultiplyBy(int x);
|
|
|
|
|
| -#define __ ACCESS_MASM(masm)
|
| -
|
| -// -------------------------------------------------------------------------
|
| -// Platform-specific FrameRegisterState functions.
|
| -
|
| -void FrameRegisterState::Save(MacroAssembler* masm) const {
|
| - for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
|
| - int action = registers_[i];
|
| - if (action == kPush) {
|
| - __ push(RegisterAllocator::ToRegister(i));
|
| - } else if (action != kIgnore && (action & kSyncedFlag) == 0) {
|
| - __ str(RegisterAllocator::ToRegister(i), MemOperand(fp, action));
|
| - }
|
| - }
|
| -}
|
| -
|
| -
|
| -void FrameRegisterState::Restore(MacroAssembler* masm) const {
|
| - // Restore registers in reverse order due to the stack.
|
| - for (int i = RegisterAllocator::kNumRegisters - 1; i >= 0; i--) {
|
| - int action = registers_[i];
|
| - if (action == kPush) {
|
| - __ pop(RegisterAllocator::ToRegister(i));
|
| - } else if (action != kIgnore) {
|
| - action &= ~kSyncedFlag;
|
| - __ ldr(RegisterAllocator::ToRegister(i), MemOperand(fp, action));
|
| - }
|
| - }
|
| -}
|
| -
|
| -
|
| -#undef __
|
| #define __ ACCESS_MASM(masm_)
|
|
|
| // -------------------------------------------------------------------------
|
| // Platform-specific DeferredCode functions.
|
|
|
| void DeferredCode::SaveRegisters() {
|
| - frame_state_.Save(masm_);
|
| }
|
|
|
|
|
| void DeferredCode::RestoreRegisters() {
|
| - frame_state_.Restore(masm_);
|
| }
|
|
|
|
|
| @@ -117,16 +83,16 @@
|
| // Platform-specific RuntimeCallHelper functions.
|
|
|
| void VirtualFrameRuntimeCallHelper::BeforeCall(MacroAssembler* masm) const {
|
| - frame_state_->Save(masm);
|
| + frame_state_.frame()->AssertIsSpilled();
|
| }
|
|
|
|
|
| void VirtualFrameRuntimeCallHelper::AfterCall(MacroAssembler* masm) const {
|
| - frame_state_->Restore(masm);
|
| }
|
|
|
|
|
| void ICRuntimeCallHelper::BeforeCall(MacroAssembler* masm) const {
|
| + frame_state_.frame()->AssertIsSpilled();
|
| masm->EnterInternalFrame();
|
| }
|
|
|
| @@ -3457,7 +3423,6 @@
|
| frame_->Dup();
|
| }
|
| EmitNamedLoad(name, var != NULL);
|
| - frame_->EmitPush(r0);
|
|
|
| // Perform the binary operation.
|
| Literal* literal = node->value()->AsLiteral();
|
| @@ -5614,11 +5579,19 @@
|
| };
|
|
|
|
|
| +// Convention for this is that on entry the receiver is in a register that
|
| +// is not used by the stack. On exit the answer is found in that same
|
| +// register and the stack has the same height.
|
| void DeferredReferenceGetNamedValue::Generate() {
|
| - ASSERT(receiver_.is(r0) || receiver_.is(r1));
|
| +#ifdef DEBUG
|
| + int expected_height = frame_state()->frame()->height();
|
| +#endif
|
| + VirtualFrame copied_frame(*frame_state()->frame());
|
| + copied_frame.SpillAll();
|
|
|
| Register scratch1 = VirtualFrame::scratch0();
|
| Register scratch2 = VirtualFrame::scratch1();
|
| + ASSERT(!receiver_.is(scratch1) && !receiver_.is(scratch2));
|
| __ DecrementCounter(&Counters::named_load_inline, 1, scratch1, scratch2);
|
| __ IncrementCounter(&Counters::named_load_inline_miss, 1, scratch1, scratch2);
|
|
|
| @@ -5634,11 +5607,23 @@
|
| // in-object has been inlined.
|
| __ nop(PROPERTY_ACCESS_INLINED);
|
|
|
| + // At this point the answer is in r0. We move it to the expected register
|
| + // if necessary.
|
| + __ Move(receiver_, r0);
|
| +
|
| + // Now go back to the frame that we entered with. This will not overwrite
|
| + // the receiver register since that register was not in use when we came
|
| + // in. The instructions emitted by this merge are skipped over by the
|
| + // inline load patching mechanism when looking for the branch instruction
|
| + // that tells it where the code to patch is.
|
| + copied_frame.MergeTo(frame_state()->frame());
|
| +
|
| // Block the constant pool for one more instruction after leaving this
|
| // constant pool block scope to include the branch instruction ending the
|
| // deferred code.
|
| __ BlockConstPoolFor(1);
|
| }
|
| + ASSERT_EQ(expected_height, frame_state()->frame()->height());
|
| }
|
|
|
|
|
| @@ -5739,6 +5724,7 @@
|
| }
|
|
|
|
|
| +// Consumes the top of stack (the receiver) and pushes the result instead.
|
| 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");
|
| @@ -5747,6 +5733,7 @@
|
| is_contextual
|
| ? RelocInfo::CODE_TARGET_CONTEXT
|
| : RelocInfo::CODE_TARGET);
|
| + frame_->EmitPush(r0); // Push answer.
|
| } else {
|
| // Inline the in-object property case.
|
| Comment cmnt(masm(), "[ Inlined named property load");
|
| @@ -5763,7 +5750,6 @@
|
|
|
| // Load the receiver from the stack.
|
| Register receiver = frame_->PopToRegister();
|
| - VirtualFrame::SpilledScope spilled(frame_);
|
|
|
| DeferredReferenceGetNamedValue* deferred =
|
| new DeferredReferenceGetNamedValue(receiver, name);
|
| @@ -5779,16 +5765,19 @@
|
| __ tst(receiver, Operand(kSmiTagMask));
|
| deferred->Branch(eq);
|
|
|
| + Register scratch = VirtualFrame::scratch0();
|
| + Register scratch2 = VirtualFrame::scratch1();
|
| +
|
| // Check the map. The null map used below is patched by the inline cache
|
| - // code.
|
| - __ ldr(r2, FieldMemOperand(receiver, HeapObject::kMapOffset));
|
| - __ mov(r3, Operand(Factory::null_value()));
|
| - __ cmp(r2, r3);
|
| + // code. Therefore we can't use a LoadRoot call.
|
| + __ ldr(scratch, FieldMemOperand(receiver, HeapObject::kMapOffset));
|
| + __ mov(scratch2, Operand(Factory::null_value()));
|
| + __ cmp(scratch, scratch2);
|
| deferred->Branch(ne);
|
|
|
| // Initially use an invalid index. The index will be patched by the
|
| // inline cache code.
|
| - __ ldr(r0, MemOperand(receiver, 0));
|
| + __ ldr(receiver, MemOperand(receiver, 0));
|
|
|
| // Make sure that the expected number of instructions are generated.
|
| ASSERT_EQ(kInlinedNamedLoadInstructions,
|
| @@ -5796,6 +5785,9 @@
|
| }
|
|
|
| deferred->BindExit();
|
| + // At this point the receiver register has the result, either from the
|
| + // deferred code or from the inlined code.
|
| + frame_->EmitPush(receiver);
|
| }
|
| }
|
|
|
| @@ -6011,6 +6003,27 @@
|
| }
|
|
|
|
|
| +void Reference::DupIfPersist() {
|
| + if (persist_after_get_) {
|
| + switch (type_) {
|
| + case KEYED:
|
| + cgen_->frame()->Dup2();
|
| + break;
|
| + case NAMED:
|
| + cgen_->frame()->Dup();
|
| + // Fall through.
|
| + case UNLOADED:
|
| + case ILLEGAL:
|
| + case SLOT:
|
| + // Do nothing.
|
| + ;
|
| + }
|
| + } else {
|
| + set_unloaded();
|
| + }
|
| +}
|
| +
|
| +
|
| void Reference::GetValue() {
|
| ASSERT(cgen_->HasValidEntryRegisters());
|
| ASSERT(!is_illegal());
|
| @@ -6026,10 +6039,8 @@
|
| Comment cmnt(masm, "[ Load from Slot");
|
| Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot();
|
| ASSERT(slot != NULL);
|
| + DupIfPersist();
|
| cgen_->LoadFromSlotCheckForArguments(slot, NOT_INSIDE_TYPEOF);
|
| - if (!persist_after_get_) {
|
| - cgen_->UnloadReference(this);
|
| - }
|
| break;
|
| }
|
|
|
| @@ -6037,23 +6048,17 @@
|
| Variable* var = expression_->AsVariableProxy()->AsVariable();
|
| bool is_global = var != NULL;
|
| ASSERT(!is_global || var->is_global());
|
| - if (persist_after_get_) {
|
| - cgen_->frame()->Dup();
|
| - }
|
| - cgen_->EmitNamedLoad(GetName(), is_global);
|
| - cgen_->frame()->EmitPush(r0);
|
| - if (!persist_after_get_) set_unloaded();
|
| + Handle<String> name = GetName();
|
| + DupIfPersist();
|
| + cgen_->EmitNamedLoad(name, is_global);
|
| break;
|
| }
|
|
|
| case KEYED: {
|
| ASSERT(property != NULL);
|
| - if (persist_after_get_) {
|
| - cgen_->frame()->Dup2();
|
| - }
|
| + DupIfPersist();
|
| cgen_->EmitKeyedLoad();
|
| cgen_->frame()->EmitPush(r0);
|
| - if (!persist_after_get_) set_unloaded();
|
| break;
|
| }
|
|
|
|
|