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:
parent
48d38e3063
commit
e5a188c2fc
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user