diff --git a/src/ia32/jump-target-ia32.cc b/src/ia32/jump-target-ia32.cc index 8c88473e0c..c8801d950e 100644 --- a/src/ia32/jump-target-ia32.cc +++ b/src/ia32/jump-target-ia32.cc @@ -195,12 +195,12 @@ void JumpTarget::DoBind(int mergable_elements) { return; } - if (direction_ == FORWARD_ONLY) { - // A simple case: no forward jumps and no possible backward jumps. - if (!is_linked()) { + if (!is_linked()) { + ASSERT(cgen_->has_valid_frame()); + if (direction_ == FORWARD_ONLY) { + // Fast case: no forward jumps and no possible backward jumps. // The stack pointer can be floating above the top of the // virtual frame before the bind. Afterward, it should not. - ASSERT(cgen_->has_valid_frame()); VirtualFrame* frame = cgen_->frame(); int difference = frame->stack_pointer_ - (frame->elements_.length() - 1); @@ -209,34 +209,43 @@ void JumpTarget::DoBind(int mergable_elements) { __ add(Operand(esp), Immediate(difference * kPointerSize)); } - is_bound_ = true; - return; + } else { + ASSERT(direction_ == BIDIRECTIONAL); + // Fast case: no forward jumps, possible backward ones. Remove + // constants and copies above the watermark on the fall-through + // frame and use it as the entry frame. + cgen_->frame()->MakeMergable(mergable_elements); + entry_frame_ = new VirtualFrame(cgen_->frame()); + __ bind(&entry_label_); + } + is_bound_ = true; + return; + } + + if (direction_ == FORWARD_ONLY && + !cgen_->has_valid_frame() && + reaching_frames_.length() == 1) { + // Fast case: no fall-through, a single forward jump, and no + // possible backward jumps. Pick up the only reaching frame, take + // ownership of it, and use it for the block about to be emitted. + VirtualFrame* frame = reaching_frames_[0]; + RegisterFile reserved = RegisterAllocator::Reserved(); + cgen_->SetFrame(frame, &reserved); + reaching_frames_[0] = NULL; + __ bind(&merge_labels_[0]); + + // The stack pointer can be floating above the top of the + // virtual frame before the bind. Afterward, it should not. + int difference = + frame->stack_pointer_ - (frame->elements_.length() - 1); + if (difference > 0) { + frame->stack_pointer_ -= difference; + __ add(Operand(esp), Immediate(difference * kPointerSize)); } - // Another simple case: no fall through, a single forward jump, - // and no possible backward jumps. - if (!cgen_->has_valid_frame() && reaching_frames_.length() == 1) { - // Pick up the only reaching frame, take ownership of it, and - // use it for the block about to be emitted. - VirtualFrame* frame = reaching_frames_[0]; - RegisterFile reserved = RegisterAllocator::Reserved(); - cgen_->SetFrame(frame, &reserved); - reaching_frames_[0] = NULL; - __ bind(&merge_labels_[0]); - - // The stack pointer can be floating above the top of the - // virtual frame before the bind. Afterward, it should not. - int difference = - frame->stack_pointer_ - (frame->elements_.length() - 1); - if (difference > 0) { - frame->stack_pointer_ -= difference; - __ add(Operand(esp), Immediate(difference * kPointerSize)); - } - - is_linked_ = false; - is_bound_ = true; - return; - } + is_linked_ = false; + is_bound_ = true; + return; } // If there is a current frame, record it as the fall-through. It @@ -250,9 +259,7 @@ void JumpTarget::DoBind(int mergable_elements) { } // Compute the frame to use for entry to the block. - if (entry_frame_ == NULL) { - ComputeEntryFrame(mergable_elements); - } + ComputeEntryFrame(mergable_elements); // Some moves required to merge to an expected frame require purely // frame state changes, and do not require any code generation. diff --git a/src/ia32/virtual-frame-ia32.cc b/src/ia32/virtual-frame-ia32.cc index 8fdb5c6ad0..d8d8b9cc47 100644 --- a/src/ia32/virtual-frame-ia32.cc +++ b/src/ia32/virtual-frame-ia32.cc @@ -180,6 +180,80 @@ void VirtualFrame::SyncRange(int begin, int end) { } +void VirtualFrame::MakeMergable(int mergable_elements) { + if (mergable_elements == JumpTarget::kAllElements) { + mergable_elements = elements_.length(); + } + ASSERT(mergable_elements <= elements_.length()); + + int start_index = elements_.length() - mergable_elements; + + // The is_copied flags on entry frame elements are expected to be + // exact. Set them for the elements below the water mark. + for (int i = 0; i < start_index; i++) { + elements_[i].clear_copied(); + if (elements_[i].is_copy()) { + elements_[elements_[i].index()].set_copied(); + } + } + + for (int i = start_index; i < elements_.length(); i++) { + FrameElement element = elements_[i]; + + if (element.is_constant() || element.is_copy()) { + if (element.is_synced()) { + // Just spill. + elements_[i] = FrameElement::MemoryElement(); + } else { + // Allocate to a register. + FrameElement backing_element; // Invalid if not a copy. + if (element.is_copy()) { + backing_element = elements_[element.index()]; + } + Result fresh = cgen_->allocator()->Allocate(); + ASSERT(fresh.is_valid()); + elements_[i] = + FrameElement::RegisterElement(fresh.reg(), + FrameElement::NOT_SYNCED); + Use(fresh.reg(), i); + + // Emit a move. + if (element.is_constant()) { + if (cgen_->IsUnsafeSmi(element.handle())) { + cgen_->LoadUnsafeSmi(fresh.reg(), element.handle()); + } else { + __ Set(fresh.reg(), Immediate(element.handle())); + } + } else { + ASSERT(element.is_copy()); + // Copies are only backed by register or memory locations. + if (backing_element.is_register()) { + // The backing store may have been spilled by allocating, + // but that's OK. If it was, the value is right where we + // want it. + if (!fresh.reg().is(backing_element.reg())) { + __ mov(fresh.reg(), backing_element.reg()); + } + } else { + ASSERT(backing_element.is_memory()); + __ mov(fresh.reg(), Operand(ebp, fp_relative(element.index()))); + } + } + } + // No need to set the copied flag---there are no copies of + // copies or constants so the original was not copied. + elements_[i].set_static_type(element.static_type()); + } else { + // Clear the copy flag of non-constant, non-copy elements above + // the high water mark. They cannot be copied because copes are + // always higher than their backing store and copies are not + // allowed above the water mark. + elements_[i].clear_copied(); + } + } +} + + void VirtualFrame::MergeTo(VirtualFrame* expected) { Comment cmnt(masm_, "[ Merge frame"); // We should always be merging the code generator's current frame to an diff --git a/src/ia32/virtual-frame-ia32.h b/src/ia32/virtual-frame-ia32.h index 37fd2e9aaf..30869f3e5a 100644 --- a/src/ia32/virtual-frame-ia32.h +++ b/src/ia32/virtual-frame-ia32.h @@ -116,6 +116,13 @@ class VirtualFrame : public ZoneObject { // (ie, they all have frame-external references). Register SpillAnyRegister(); + // Make this frame so that an arbitrary frame of the same height can + // be merged to it. Copies and constants are removed from the + // topmost mergable_elements elements of the frame. A + // mergable_elements of JumpTarget::kAllElements indicates constants + // and copies are should be removed from the entire frame. + void MakeMergable(int mergable_elements); + // Prepare this virtual frame for merging to an expected frame by // performing some state changes that do not require generating // code. It is guaranteed that no code will be generated.