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
This commit is contained in:
erik.corry@gmail.com 2010-05-12 09:00:29 +00:00
parent 48d38e3063
commit e5a188c2fc
3 changed files with 95 additions and 39 deletions

View File

@ -4958,7 +4958,6 @@ void CodeGenerator::VisitCountOperation(CountOperation* node) {
#ifdef DEBUG #ifdef DEBUG
int original_height = frame_->height(); int original_height = frame_->height();
#endif #endif
VirtualFrame::SpilledScope spilled_scope(frame_);
Comment cmnt(masm_, "[ CountOperation"); Comment cmnt(masm_, "[ CountOperation");
bool is_postfix = node->is_postfix(); bool is_postfix = node->is_postfix();
@ -4967,10 +4966,8 @@ void CodeGenerator::VisitCountOperation(CountOperation* node) {
Variable* var = node->expression()->AsVariableProxy()->AsVariable(); Variable* var = node->expression()->AsVariableProxy()->AsVariable();
bool is_const = (var != NULL && var->mode() == Variable::CONST); bool is_const = (var != NULL && var->mode() == Variable::CONST);
// Postfix: Make room for the result.
if (is_postfix) { if (is_postfix) {
__ mov(r0, Operand(0)); frame_->EmitPush(Operand(Smi::FromInt(0)));
frame_->EmitPush(r0);
} }
// A constant reference is not saved to, so a constant reference is not a // 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 // Spoof the virtual frame to have the expected height (one higher
// than on entry). // than on entry).
if (!is_postfix) { if (!is_postfix) {
__ mov(r0, Operand(Smi::FromInt(0))); frame_->EmitPush(Operand(Smi::FromInt(0)));
frame_->EmitPush(r0);
} }
ASSERT_EQ(original_height + 1, frame_->height()); ASSERT_EQ(original_height + 1, frame_->height());
return; 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(); target.GetValue();
frame_->EmitPop(r0);
JumpTarget slow; JumpTarget slow;
JumpTarget exit; JumpTarget exit;
// Load the value (1) into register r1.
__ mov(r1, Operand(Smi::FromInt(1)));
// Check for smi operand. // Check for smi operand.
__ tst(r0, Operand(kSmiTagMask)); Register value = frame_->PopToRegister();
__ tst(value, Operand(kSmiTagMask));
slow.Branch(ne); slow.Branch(ne);
// Postfix: Store the old value as the result. // Postfix: Store the old value as the result.
if (is_postfix) { if (is_postfix) {
__ str(r0, frame_->ElementAt(target.size())); frame_->SetElementAt(value, target.size());
} }
// Perform optimistic increment/decrement. // Perform optimistic increment/decrement.
if (is_increment) { if (is_increment) {
__ add(r0, r0, Operand(r1), SetCC); __ add(value, value, Operand(Smi::FromInt(1)), SetCC);
} else { } 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. // If the increment/decrement didn't overflow, we're done.
@ -5016,41 +5011,50 @@ void CodeGenerator::VisitCountOperation(CountOperation* node) {
// Revert optimistic increment/decrement. // Revert optimistic increment/decrement.
if (is_increment) { if (is_increment) {
__ sub(r0, r0, Operand(r1)); __ sub(value, value, Operand(Smi::FromInt(1)));
} else { } 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(); slow.Bind();
// Convert the operand to a number.
frame_->EmitPush(value);
{ {
// Convert the operand to a number. VirtualFrame::SpilledScope spilled(frame_);
frame_->EmitPush(r0);
frame_->InvokeBuiltin(Builtins::TO_NUMBER, CALL_JS, 1); frame_->InvokeBuiltin(Builtins::TO_NUMBER, CALL_JS, 1);
}
if (is_postfix) { if (is_postfix) {
// Postfix: store to result (on the stack). // Postfix: store to result (on the stack).
__ str(r0, frame_->ElementAt(target.size())); __ str(r0, frame_->ElementAt(target.size()));
} }
// Compute the new value. // Compute the new value.
__ mov(r1, Operand(Smi::FromInt(1))); frame_->EmitPush(r0);
frame_->EmitPush(r0); frame_->EmitPush(Operand(Smi::FromInt(1)));
frame_->EmitPush(r1); if (is_increment) {
if (is_increment) { frame_->CallRuntime(Runtime::kNumberAdd, 2);
frame_->CallRuntime(Runtime::kNumberAdd, 2); } else {
} else { frame_->CallRuntime(Runtime::kNumberSub, 2);
frame_->CallRuntime(Runtime::kNumberSub, 2); }
} }
__ Move(value, r0);
// Store the new value in the target if not const. // Store the new value in the target if not const.
// At this point the answer is in the value register.
exit.Bind(); 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); if (!is_const) target.SetValue(NOT_CONST_INIT);
} }
// Postfix: Discard the new value and use the old. // 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()); ASSERT_EQ(original_height + 1, frame_->height());
} }

View File

@ -72,8 +72,15 @@ void VirtualFrame::PopToR0() {
void VirtualFrame::MergeTo(VirtualFrame* expected) { void VirtualFrame::MergeTo(VirtualFrame* expected) {
if (Equals(expected)) return; 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)) #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): case CASE_NUMBER(NO_TOS_REGISTERS, NO_TOS_REGISTERS):
break; break;
case CASE_NUMBER(NO_TOS_REGISTERS, R0_TOS): case CASE_NUMBER(NO_TOS_REGISTERS, R0_TOS):
@ -154,7 +161,7 @@ void VirtualFrame::MergeTo(VirtualFrame* expected) {
UNREACHABLE(); UNREACHABLE();
#undef CASE_NUMBER #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() { Register VirtualFrame::GetTOSRegister() {
if (SpilledScope::is_spilled()) return r0; if (SpilledScope::is_spilled()) return r0;

View File

@ -229,8 +229,9 @@ class VirtualFrame : public ZoneObject {
// An element of the expression stack as an assembly operand. // An element of the expression stack as an assembly operand.
MemOperand ElementAt(int index) { MemOperand ElementAt(int index) {
AssertIsSpilled(); int adjusted_index = index - kVirtualElements[top_of_stack_state_];
return MemOperand(sp, index * kPointerSize); ASSERT(adjusted_index >= 0);
return MemOperand(sp, adjusted_index * kPointerSize);
} }
// A frame-allocated local as an assembly operand. // A frame-allocated local as an assembly operand.
@ -355,6 +356,12 @@ class VirtualFrame : public ZoneObject {
void EmitPush(MemOperand operand); void EmitPush(MemOperand operand);
void EmitPushRoot(Heap::RootListIndex index); 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 // Get a register which is free and which must be immediately used to
// push on the top of the stack. // push on the top of the stack.
Register GetTOSRegister(); Register GetTOSRegister();
@ -459,6 +466,10 @@ class VirtualFrame : public ZoneObject {
// onto the physical stack and made free. // onto the physical stack and made free.
void EnsureOneFreeTOSRegister(); 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); inline bool Equals(VirtualFrame* other);
friend class JumpTarget; friend class JumpTarget;