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
|
#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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user