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

View File

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

View File

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