From e5a188c2fc337152e5db957cdfb4fc504fba1148 Mon Sep 17 00:00:00 2001 From: "erik.corry@gmail.com" Date: Wed, 12 May 2010 09:00:29 +0000 Subject: [PATCH] ARM: Fix jumptargets to actually merge virtual frames. Make use of the new functionality to make ++ and -- non-spilled operations. Review URL: http://codereview.chromium.org/2041010 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4644 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/codegen-arm.cc | 74 +++++++++++++++++++----------------- src/arm/virtual-frame-arm.cc | 45 +++++++++++++++++++++- src/arm/virtual-frame-arm.h | 15 +++++++- 3 files changed, 95 insertions(+), 39 deletions(-) diff --git a/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc index cf6dce0e9a..9f28b0311a 100644 --- a/src/arm/codegen-arm.cc +++ b/src/arm/codegen-arm.cc @@ -4958,7 +4958,6 @@ void CodeGenerator::VisitCountOperation(CountOperation* node) { #ifdef DEBUG int original_height = frame_->height(); #endif - VirtualFrame::SpilledScope spilled_scope(frame_); Comment cmnt(masm_, "[ CountOperation"); bool is_postfix = node->is_postfix(); @@ -4967,10 +4966,8 @@ void CodeGenerator::VisitCountOperation(CountOperation* node) { Variable* var = node->expression()->AsVariableProxy()->AsVariable(); bool is_const = (var != NULL && var->mode() == Variable::CONST); - // Postfix: Make room for the result. if (is_postfix) { - __ mov(r0, Operand(0)); - frame_->EmitPush(r0); + frame_->EmitPush(Operand(Smi::FromInt(0))); } // A constant reference is not saved to, so a constant reference is not a @@ -4980,35 +4977,33 @@ void CodeGenerator::VisitCountOperation(CountOperation* node) { // Spoof the virtual frame to have the expected height (one higher // than on entry). if (!is_postfix) { - __ mov(r0, Operand(Smi::FromInt(0))); - frame_->EmitPush(r0); + frame_->EmitPush(Operand(Smi::FromInt(0))); } ASSERT_EQ(original_height + 1, frame_->height()); return; } + // This pushes 0, 1 or 2 words on the object to be used later when updating + // the target. It also pushes the current value of the target. target.GetValue(); - frame_->EmitPop(r0); JumpTarget slow; JumpTarget exit; - // Load the value (1) into register r1. - __ mov(r1, Operand(Smi::FromInt(1))); - // Check for smi operand. - __ tst(r0, Operand(kSmiTagMask)); + Register value = frame_->PopToRegister(); + __ tst(value, Operand(kSmiTagMask)); slow.Branch(ne); // Postfix: Store the old value as the result. if (is_postfix) { - __ str(r0, frame_->ElementAt(target.size())); + frame_->SetElementAt(value, target.size()); } // Perform optimistic increment/decrement. if (is_increment) { - __ add(r0, r0, Operand(r1), SetCC); + __ add(value, value, Operand(Smi::FromInt(1)), SetCC); } else { - __ sub(r0, r0, Operand(r1), SetCC); + __ sub(value, value, Operand(Smi::FromInt(1)), SetCC); } // If the increment/decrement didn't overflow, we're done. @@ -5016,41 +5011,50 @@ void CodeGenerator::VisitCountOperation(CountOperation* node) { // Revert optimistic increment/decrement. if (is_increment) { - __ sub(r0, r0, Operand(r1)); + __ sub(value, value, Operand(Smi::FromInt(1))); } else { - __ add(r0, r0, Operand(r1)); + __ add(value, value, Operand(Smi::FromInt(1))); } - // Slow case: Convert to number. + // Slow case: Convert to number. At this point the + // value to be incremented is in the value register.. slow.Bind(); + + // Convert the operand to a number. + frame_->EmitPush(value); + { - // Convert the operand to a number. - frame_->EmitPush(r0); + VirtualFrame::SpilledScope spilled(frame_); frame_->InvokeBuiltin(Builtins::TO_NUMBER, CALL_JS, 1); - } - if (is_postfix) { - // Postfix: store to result (on the stack). - __ str(r0, frame_->ElementAt(target.size())); - } - - // Compute the new value. - __ mov(r1, Operand(Smi::FromInt(1))); - frame_->EmitPush(r0); - frame_->EmitPush(r1); - if (is_increment) { - frame_->CallRuntime(Runtime::kNumberAdd, 2); - } else { - frame_->CallRuntime(Runtime::kNumberSub, 2); + + if (is_postfix) { + // Postfix: store to result (on the stack). + __ str(r0, frame_->ElementAt(target.size())); + } + + // Compute the new value. + frame_->EmitPush(r0); + frame_->EmitPush(Operand(Smi::FromInt(1))); + if (is_increment) { + frame_->CallRuntime(Runtime::kNumberAdd, 2); + } else { + frame_->CallRuntime(Runtime::kNumberSub, 2); + } } + __ Move(value, r0); // Store the new value in the target if not const. + // At this point the answer is in the value register. exit.Bind(); - frame_->EmitPush(r0); + frame_->EmitPush(value); + // Set the target with the result, leaving the result on + // top of the stack. Removes the target from the stack if + // it has a non-zero size. if (!is_const) target.SetValue(NOT_CONST_INIT); } // Postfix: Discard the new value and use the old. - if (is_postfix) frame_->EmitPop(r0); + if (is_postfix) frame_->Pop(); ASSERT_EQ(original_height + 1, frame_->height()); } diff --git a/src/arm/virtual-frame-arm.cc b/src/arm/virtual-frame-arm.cc index 475f933bb4..f9c5982954 100644 --- a/src/arm/virtual-frame-arm.cc +++ b/src/arm/virtual-frame-arm.cc @@ -72,8 +72,15 @@ void VirtualFrame::PopToR0() { void VirtualFrame::MergeTo(VirtualFrame* expected) { if (Equals(expected)) return; + MergeTOSTo(expected->top_of_stack_state_); + ASSERT(register_allocation_map_ == expected->register_allocation_map_); +} + + +void VirtualFrame::MergeTOSTo( + VirtualFrame::TopOfStack expected_top_of_stack_state) { #define CASE_NUMBER(a, b) ((a) * TOS_STATES + (b)) - switch (CASE_NUMBER(top_of_stack_state_, expected->top_of_stack_state_)) { + switch (CASE_NUMBER(top_of_stack_state_, expected_top_of_stack_state)) { case CASE_NUMBER(NO_TOS_REGISTERS, NO_TOS_REGISTERS): break; case CASE_NUMBER(NO_TOS_REGISTERS, R0_TOS): @@ -154,7 +161,7 @@ void VirtualFrame::MergeTo(VirtualFrame* expected) { UNREACHABLE(); #undef CASE_NUMBER } - ASSERT(register_allocation_map_ == expected->register_allocation_map_); + top_of_stack_state_ = expected_top_of_stack_state; } @@ -627,6 +634,40 @@ void VirtualFrame::EmitPush(Register reg) { } +void VirtualFrame::SetElementAt(Register reg, int this_far_down) { + int virtual_elements = kVirtualElements[top_of_stack_state_]; + if (this_far_down == 0) { + Pop(); + Register dest = GetTOSRegister(); + if (dest.is(reg)) { + // We already popped one item off the top of the stack. If the only + // free register is the one we were asked to push then we have been + // asked to push a register that was already in use, which cannot + // happen. It therefore folows that there are two free TOS registers: + ASSERT(top_of_stack_state_ == NO_TOS_REGISTERS); + dest = dest.is(r0) ? r1 : r0; + } + __ mov(dest, reg); + EmitPush(dest); + } else if (this_far_down == 1) { + int virtual_elements = kVirtualElements[top_of_stack_state_]; + if (virtual_elements < 2) { + __ str(reg, ElementAt(this_far_down)); + } else { + ASSERT(virtual_elements == 2); + ASSERT(!reg.is(r0)); + ASSERT(!reg.is(r1)); + Register dest = kBottomRegister[top_of_stack_state_]; + __ mov(dest, reg); + } + } else { + ASSERT(this_far_down >= 2); + ASSERT(virtual_elements <= 2); + __ str(reg, ElementAt(this_far_down)); + } +} + + Register VirtualFrame::GetTOSRegister() { if (SpilledScope::is_spilled()) return r0; diff --git a/src/arm/virtual-frame-arm.h b/src/arm/virtual-frame-arm.h index 52b94f7240..655194d70c 100644 --- a/src/arm/virtual-frame-arm.h +++ b/src/arm/virtual-frame-arm.h @@ -229,8 +229,9 @@ class VirtualFrame : public ZoneObject { // An element of the expression stack as an assembly operand. MemOperand ElementAt(int index) { - AssertIsSpilled(); - return MemOperand(sp, index * kPointerSize); + int adjusted_index = index - kVirtualElements[top_of_stack_state_]; + ASSERT(adjusted_index >= 0); + return MemOperand(sp, adjusted_index * kPointerSize); } // A frame-allocated local as an assembly operand. @@ -355,6 +356,12 @@ class VirtualFrame : public ZoneObject { void EmitPush(MemOperand operand); void EmitPushRoot(Heap::RootListIndex index); + // Overwrite the nth thing on the stack. If the nth position is in a + // register then this turns into a mov, otherwise an str. Afterwards + // you can still use the register even if it is a register that can be + // used for TOS (r0 or r1). + void SetElementAt(Register reg, int this_far_down); + // Get a register which is free and which must be immediately used to // push on the top of the stack. Register GetTOSRegister(); @@ -459,6 +466,10 @@ class VirtualFrame : public ZoneObject { // onto the physical stack and made free. void EnsureOneFreeTOSRegister(); + // Emit instructions to get the top of stack state from where we are to where + // we want to be. + void MergeTOSTo(TopOfStack expected_state); + inline bool Equals(VirtualFrame* other); friend class JumpTarget;