Eliminate most of the jump target jumping, branching, and binding

overhead on the ARM platform.

Because virtual frames are always in memory, there is no work to be
done for control flow except in the case of breaking or continuing
when there is extra statement state on the stack.

Review URL: http://codereview.chromium.org/165230

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2655 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 1005fa3f
This diff is collapsed.
......@@ -76,72 +76,23 @@ void VirtualFrame::SyncRange(int begin, int end) {
void VirtualFrame::MergeTo(VirtualFrame* expected) {
Comment cmnt(masm(), "[ Merge frame");
// We should always be merging the code generator's current frame to an
// expected frame.
ASSERT(cgen()->frame() == this);
// Adjust the stack pointer upward (toward the top of the virtual
// frame) if necessary.
if (stack_pointer_ < expected->stack_pointer_) {
int difference = expected->stack_pointer_ - stack_pointer_;
stack_pointer_ = expected->stack_pointer_;
__ sub(sp, sp, Operand(difference * kPointerSize));
}
MergeMoveRegistersToMemory(expected);
MergeMoveRegistersToRegisters(expected);
MergeMoveMemoryToRegisters(expected);
// Fix any sync bit problems from the bottom-up, stopping when we
// hit the stack pointer or the top of the frame if the stack
// pointer is floating above the frame.
int limit = Min(static_cast<int>(stack_pointer_), element_count() - 1);
for (int i = 0; i <= limit; i++) {
FrameElement source = elements_[i];
FrameElement target = expected->elements_[i];
if (source.is_synced() && !target.is_synced()) {
elements_[i].clear_sync();
} else if (!source.is_synced() && target.is_synced()) {
SyncElementAt(i);
}
}
// Adjust the stack point downard if necessary.
if (stack_pointer_ > expected->stack_pointer_) {
int difference = stack_pointer_ - expected->stack_pointer_;
stack_pointer_ = expected->stack_pointer_;
__ add(sp, sp, Operand(difference * kPointerSize));
}
// At this point, the frames should be identical.
// ARM frames are currently always in memory.
ASSERT(Equals(expected));
}
void VirtualFrame::MergeMoveRegistersToMemory(VirtualFrame* expected) {
ASSERT(stack_pointer_ >= expected->stack_pointer_);
// Move registers, constants, and copies to memory. Perform moves
// from the top downward in the frame in order to leave the backing
// stores of copies in registers.
// On ARM, all elements are in memory.
#ifdef DEBUG
int start = Min(static_cast<int>(stack_pointer_), element_count() - 1);
for (int i = start; i >= 0; i--) {
ASSERT(elements_[i].is_memory());
ASSERT(expected->elements_[i].is_memory());
}
#endif
UNREACHABLE();
}
void VirtualFrame::MergeMoveRegistersToRegisters(VirtualFrame* expected) {
UNREACHABLE();
}
void VirtualFrame::MergeMoveMemoryToRegisters(VirtualFrame* expected) {
UNREACHABLE();
}
......@@ -390,6 +341,7 @@ Result VirtualFrame::CallCodeObject(Handle<Code> code,
void VirtualFrame::Drop(int count) {
ASSERT(count >= 0);
ASSERT(height() >= count);
int num_virtual_elements = (element_count() - 1) - stack_pointer_;
......
......@@ -112,12 +112,14 @@ class VirtualFrame : public ZoneObject {
ASSERT(count >= 0);
ASSERT(stack_pointer_ == element_count() - 1);
stack_pointer_ -= count;
ForgetElements(count);
// On ARM, all elements are in memory, so there is no extra bookkeeping
// (registers, copies, etc.) beyond dropping the elements.
elements_.Rewind(stack_pointer_ + 1);
}
// Forget count elements from the top of the frame without adjusting
// the stack pointer downward. This is used, for example, before
// merging frames at break, continue, and return targets.
// Forget count elements from the top of the frame and adjust the stack
// pointer downward. This is used, for example, before merging frames at
// break, continue, and return targets.
void ForgetElements(int count);
// Spill all values from the frame to memory.
......
......@@ -362,6 +362,70 @@ void JumpTarget::DoBind() {
__ bind(&entry_label_);
}
void BreakTarget::Jump() {
// Drop leftover statement state from the frame before merging, without
// emitting code.
ASSERT(cgen()->has_valid_frame());
int count = cgen()->frame()->height() - expected_height_;
cgen()->frame()->ForgetElements(count);
DoJump();
}
void BreakTarget::Jump(Result* arg) {
// Drop leftover statement state from the frame before merging, without
// emitting code.
ASSERT(cgen()->has_valid_frame());
int count = cgen()->frame()->height() - expected_height_;
cgen()->frame()->ForgetElements(count);
cgen()->frame()->Push(arg);
DoJump();
}
void BreakTarget::Bind() {
#ifdef DEBUG
// All the forward-reaching frames should have been adjusted at the
// jumps to this target.
for (int i = 0; i < reaching_frames_.length(); i++) {
ASSERT(reaching_frames_[i] == NULL ||
reaching_frames_[i]->height() == expected_height_);
}
#endif
// Drop leftover statement state from the frame before merging, even on
// the fall through. This is so we can bind the return target with state
// on the frame.
if (cgen()->has_valid_frame()) {
int count = cgen()->frame()->height() - expected_height_;
cgen()->frame()->ForgetElements(count);
}
DoBind();
}
void BreakTarget::Bind(Result* arg) {
#ifdef DEBUG
// All the forward-reaching frames should have been adjusted at the
// jumps to this target.
for (int i = 0; i < reaching_frames_.length(); i++) {
ASSERT(reaching_frames_[i] == NULL ||
reaching_frames_[i]->height() == expected_height_ + 1);
}
#endif
// Drop leftover statement state from the frame before merging, even on
// the fall through. This is so we can bind the return target with state
// on the frame.
if (cgen()->has_valid_frame()) {
int count = cgen()->frame()->height() - expected_height_;
cgen()->frame()->ForgetElements(count);
cgen()->frame()->Push(arg);
}
DoBind();
*arg = cgen()->frame()->Pop();
}
#undef __
......
......@@ -323,25 +323,6 @@ void BreakTarget::CopyTo(BreakTarget* destination) {
}
void BreakTarget::Jump() {
ASSERT(cgen()->has_valid_frame());
// Drop leftover statement state from the frame before merging.
cgen()->frame()->ForgetElements(cgen()->frame()->height() - expected_height_);
DoJump();
}
void BreakTarget::Jump(Result* arg) {
ASSERT(cgen()->has_valid_frame());
// Drop leftover statement state from the frame before merging.
cgen()->frame()->ForgetElements(cgen()->frame()->height() - expected_height_);
cgen()->frame()->Push(arg);
DoJump();
}
void BreakTarget::Branch(Condition cc, Hint hint) {
ASSERT(cgen()->has_valid_frame());
......@@ -362,48 +343,6 @@ void BreakTarget::Branch(Condition cc, Hint hint) {
}
void BreakTarget::Bind() {
#ifdef DEBUG
// All the forward-reaching frames should have been adjusted at the
// jumps to this target.
for (int i = 0; i < reaching_frames_.length(); i++) {
ASSERT(reaching_frames_[i] == NULL ||
reaching_frames_[i]->height() == expected_height_);
}
#endif
// Drop leftover statement state from the frame before merging, even
// on the fall through. This is so we can bind the return target
// with state on the frame.
if (cgen()->has_valid_frame()) {
int count = cgen()->frame()->height() - expected_height_;
cgen()->frame()->ForgetElements(count);
}
DoBind();
}
void BreakTarget::Bind(Result* arg) {
#ifdef DEBUG
// All the forward-reaching frames should have been adjusted at the
// jumps to this target.
for (int i = 0; i < reaching_frames_.length(); i++) {
ASSERT(reaching_frames_[i] == NULL ||
reaching_frames_[i]->height() == expected_height_ + 1);
}
#endif
// Drop leftover statement state from the frame before merging, even
// on the fall through. This is so we can bind the return target
// with state on the frame.
if (cgen()->has_valid_frame()) {
int count = cgen()->frame()->height() - expected_height_;
cgen()->frame()->ForgetElements(count);
cgen()->frame()->Push(arg);
}
DoBind();
*arg = cgen()->frame()->Pop();
}
// -------------------------------------------------------------------------
// ShadowTarget implementation.
......
......@@ -362,6 +362,70 @@ void JumpTarget::DoBind() {
__ bind(&entry_label_);
}
void BreakTarget::Jump() {
// Drop leftover statement state from the frame before merging, without
// emitting code.
ASSERT(cgen()->has_valid_frame());
int count = cgen()->frame()->height() - expected_height_;
cgen()->frame()->ForgetElements(count);
DoJump();
}
void BreakTarget::Jump(Result* arg) {
// Drop leftover statement state from the frame before merging, without
// emitting code.
ASSERT(cgen()->has_valid_frame());
int count = cgen()->frame()->height() - expected_height_;
cgen()->frame()->ForgetElements(count);
cgen()->frame()->Push(arg);
DoJump();
}
void BreakTarget::Bind() {
#ifdef DEBUG
// All the forward-reaching frames should have been adjusted at the
// jumps to this target.
for (int i = 0; i < reaching_frames_.length(); i++) {
ASSERT(reaching_frames_[i] == NULL ||
reaching_frames_[i]->height() == expected_height_);
}
#endif
// Drop leftover statement state from the frame before merging, even on
// the fall through. This is so we can bind the return target with state
// on the frame.
if (cgen()->has_valid_frame()) {
int count = cgen()->frame()->height() - expected_height_;
cgen()->frame()->ForgetElements(count);
}
DoBind();
}
void BreakTarget::Bind(Result* arg) {
#ifdef DEBUG
// All the forward-reaching frames should have been adjusted at the
// jumps to this target.
for (int i = 0; i < reaching_frames_.length(); i++) {
ASSERT(reaching_frames_[i] == NULL ||
reaching_frames_[i]->height() == expected_height_ + 1);
}
#endif
// Drop leftover statement state from the frame before merging, even on
// the fall through. This is so we can bind the return target with state
// on the frame.
if (cgen()->has_valid_frame()) {
int count = cgen()->frame()->height() - expected_height_;
cgen()->frame()->ForgetElements(count);
cgen()->frame()->Push(arg);
}
DoBind();
*arg = cgen()->frame()->Pop();
}
#undef __
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment