From d0e76971a6ecea4aad36ed8b6617bad9082578c9 Mon Sep 17 00:00:00 2001 From: "kmillikin@chromium.org" Date: Thu, 12 Mar 2009 14:55:17 +0000 Subject: [PATCH] Change the way we handle backward jumps in the code generator. Keep the frame states of all the forward-entering frames that had merge code generated. At a backward branch, check if there is no merge code or if we can reuse an existing merge block. Review URL: http://codereview.chromium.org/40169 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@1502 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/jump-target-arm.cc | 263 ++++++++++++++++++++++++++-------------- src/jump-target-ia32.cc | 261 +++++++++++++++++++++++++-------------- src/jump-target.cc | 58 +++------ 3 files changed, 359 insertions(+), 223 deletions(-) diff --git a/src/jump-target-arm.cc b/src/jump-target-arm.cc index b7aad93fb6..f889d25e05 100644 --- a/src/jump-target-arm.cc +++ b/src/jump-target-arm.cc @@ -70,40 +70,58 @@ void JumpTarget::Branch(Condition cc, Hint ignored) { ASSERT(cgen_->has_valid_frame()); if (is_bound()) { - // Backward branch. We have an expected frame to merge to on the - // backward edge. We negate the condition and emit the merge code - // here. - // - // TODO(210): we should try to avoid negating the condition in the - // case where there is no merge code to emit. Otherwise, we emit - // a branch around an unconditional jump. ASSERT(direction_ == BIDIRECTIONAL); + // Backward branch. We have an expected frame to merge to on the + // backward edge. + + // Swap the current frame for a copy (we do the swapping to get + // the off-frame registers off the fall through) to use for the + // branch. + VirtualFrame* fall_through_frame = cgen_->frame(); + VirtualFrame* branch_frame = new VirtualFrame(fall_through_frame); + RegisterFile non_frame_registers = RegisterAllocator::Reserved(); + cgen_->SetFrame(branch_frame, &non_frame_registers); + + // Check if we can avoid merge code. + cgen_->frame()->PrepareMergeTo(entry_frame_); + if (cgen_->frame()->Equals(entry_frame_)) { + // Branch right in to the block. + cgen_->DeleteFrame(); + __ b(cc, &entry_label_); + cgen_->SetFrame(fall_through_frame, &non_frame_registers); + return; + } + + // Check if we can reuse existing merge code. + for (int i = 0; i < reaching_frames_.length(); i++) { + if (reaching_frames_[i] != NULL && + cgen_->frame()->Equals(reaching_frames_[i])) { + // Branch to the merge code. + cgen_->DeleteFrame(); + __ b(cc, &merge_labels_[i]); + cgen_->SetFrame(fall_through_frame, &non_frame_registers); + return; + } + } + + // To emit the merge code here, we negate the condition and branch + // around the merge code on the fall through path. Label original_fall_through; __ b(NegateCondition(cc), &original_fall_through); - // Swap the current frame for a copy of it, saving non-frame - // register reference counts and invalidating all non-frame register - // references except the reserved ones on the backward edge. - VirtualFrame* original_frame = cgen_->frame(); - VirtualFrame* working_frame = new VirtualFrame(original_frame); - RegisterFile non_frame_registers = RegisterAllocator::Reserved(); - cgen_->SetFrame(working_frame, &non_frame_registers); - - working_frame->MergeTo(entry_frame_); + cgen_->frame()->MergeTo(entry_frame_); cgen_->DeleteFrame(); - __ jmp(&entry_label_); - - // Restore the frame and its associated non-frame registers. - cgen_->SetFrame(original_frame, &non_frame_registers); + __ b(&entry_label_); + cgen_->SetFrame(fall_through_frame, &non_frame_registers); __ bind(&original_fall_through); + } else { // Forward branch. A copy of the current frame is added to the end // of the list of frames reaching the target block and a branch to // the merge code is emitted. AddReachingFrame(new VirtualFrame(cgen_->frame())); __ b(cc, &merge_labels_.last()); + is_linked_ = true; } - - is_linked_ = !is_bound_; } @@ -138,79 +156,130 @@ void JumpTarget::Bind(int mergable_elements) { // block. ASSERT(!cgen_->has_valid_frame() || cgen_->HasValidEntryRegisters()); + if (direction_ == FORWARD_ONLY) { + // A simple case: no forward jumps and no possible backward jumps. + if (!is_linked()) { + // 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); + if (difference > 0) { + frame->stack_pointer_ -= difference; + __ add(sp, sp, Operand(difference * kPointerSize)); + } + + is_bound_ = true; + return; + } + + // 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(sp, sp, Operand(difference * kPointerSize)); + } + + is_linked_ = false; + is_bound_ = true; + return; + } + } + + // If there is a current frame, record it as the fall-through. It + // is owned by the reaching frames for now. + bool had_fall_through = false; + if (cgen_->has_valid_frame()) { + had_fall_through = true; + AddReachingFrame(cgen_->frame()); + RegisterFile empty; + cgen_->SetFrame(NULL, &empty); + } + // Compute the frame to use for entry to the block. ComputeEntryFrame(mergable_elements); + // Some moves required to merge to an expected frame require purely + // frame state changes, and do not require any code generation. + // Perform those first to increase the possibility of finding equal + // frames below. + for (int i = 0; i < reaching_frames_.length(); i++) { + if (reaching_frames_[i] != NULL) { + reaching_frames_[i]->PrepareMergeTo(entry_frame_); + } + } + if (is_linked()) { // There were forward jumps. Handle merging the reaching frames // and possible fall through to the entry frame. - // Some moves required to merge to an expected frame require - // purely frame state changes, and do not require any code - // generation. Perform those first to increase the possibility of - // finding equal frames below. - if (cgen_->has_valid_frame()) { - cgen_->frame()->PrepareMergeTo(entry_frame_); - } - for (int i = 0; i < reaching_frames_.length(); i++) { - reaching_frames_[i]->PrepareMergeTo(entry_frame_); - } - - // If there is a fall through to the jump target and it needs - // merge code, process it first. - if (cgen_->has_valid_frame() && !cgen_->frame()->Equals(entry_frame_)) { - // Loop over all the reaching frames, looking for any that can - // share merge code with this one. - for (int i = 0; i < reaching_frames_.length(); i++) { - if (cgen_->frame()->Equals(reaching_frames_[i])) { - // Set the reaching frames element to null to avoid - // processing it later, and then bind its entry label. - delete reaching_frames_[i]; - reaching_frames_[i] = NULL; - __ bind(&merge_labels_[i]); - } - } - - // Emit the merge code. - cgen_->frame()->MergeTo(entry_frame_); - } - // Loop over the (non-null) reaching frames and process any that - // need merge code. - for (int i = 0; i < reaching_frames_.length(); i++) { + // need merge code. Iterate backwards through the list to handle + // the fall-through frame first. Set frames that will be + // processed after 'i' to NULL if we want to avoid processing + // them. + for (int i = reaching_frames_.length() - 1; i >= 0; i--) { VirtualFrame* frame = reaching_frames_[i]; - if (frame != NULL && !frame->Equals(entry_frame_)) { - // Set the reaching frames element to null to avoid processing - // it later. Do not delete it as it is needed for merging. - reaching_frames_[i] = NULL; - // If the code generator has a current frame (a fall-through - // or a previously merged frame), insert a jump around the - // merge code we are about to generate. - if (cgen_->has_valid_frame()) { - cgen_->DeleteFrame(); - __ jmp(&entry_label_); - } - - // Set the frame to merge as the code generator's current - // frame and bind its merge label. - RegisterFile reserved_registers = RegisterAllocator::Reserved(); - cgen_->SetFrame(frame, &reserved_registers); - __ bind(&merge_labels_[i]); - - // Loop over the remaining (non-null) reaching frames, looking - // for any that can share merge code with this one. - for (int j = i + 1; j < reaching_frames_.length(); j++) { - VirtualFrame* other = reaching_frames_[j]; - if (other != NULL && frame->Equals(other)) { - delete other; - reaching_frames_[j] = NULL; - __ bind(&merge_labels_[j]); + if (frame != NULL) { + // Does the frame (probably) need merge code? + if (!frame->Equals(entry_frame_)) { + // We could have a valid frame as the fall through to the + // binding site or as the fall through from a previous merge + // code block. Jump around the code we are about to + // generate. + if (cgen_->has_valid_frame()) { + cgen_->DeleteFrame(); + __ b(&entry_label_); } - } + // Pick up the frame for this block. Assume ownership if + // there cannot be backward jumps. + RegisterFile reserved = RegisterAllocator::Reserved(); + if (direction_ == BIDIRECTIONAL) { + cgen_->SetFrame(new VirtualFrame(frame), &reserved); + } else { + cgen_->SetFrame(frame, &reserved); + reaching_frames_[i] = NULL; + } + __ bind(&merge_labels_[i]); - // Emit the merge code. - cgen_->frame()->MergeTo(entry_frame_); + // Loop over the remaining (non-null) reaching frames, + // looking for any that can share merge code with this one. + for (int j = 0; j < i; j++) { + VirtualFrame* other = reaching_frames_[j]; + if (other != NULL && other->Equals(cgen_->frame())) { + // Set the reaching frame element to null to avoid + // processing it later, and then bind its entry label. + delete other; + reaching_frames_[j] = NULL; + __ bind(&merge_labels_[j]); + } + } + + // Emit the merge code. + cgen_->frame()->MergeTo(entry_frame_); + } else if (i == reaching_frames_.length() - 1 && had_fall_through) { + // If this is the fall through, and it didn't need merge + // code, we need to pick up the frame so we can jump around + // subsequent merge blocks if necessary. + RegisterFile reserved = RegisterAllocator::Reserved(); + cgen_->SetFrame(frame, &reserved); + reaching_frames_[i] = NULL; + } } } @@ -227,23 +296,31 @@ void JumpTarget::Bind(int mergable_elements) { __ bind(&entry_label_); // There may be unprocessed reaching frames that did not need - // merge code. Bind their merge labels to be the same as the - // entry label. + // merge code. They will have unbound merge labels. Bind their + // merge labels to be the same as the entry label and deallocate + // them. for (int i = 0; i < reaching_frames_.length(); i++) { - if (reaching_frames_[i] != NULL) { + if (!merge_labels_[i].is_bound()) { delete reaching_frames_[i]; + reaching_frames_[i] = NULL; __ bind(&merge_labels_[i]); } } - // All the reaching frames except the one that is the current - // frame (if it is one of the reaching frames) have been deleted. - reaching_frames_.Clear(); - merge_labels_.Clear(); - + // There are non-NULL reaching frames with bound labels for each + // merge block, but only on backward targets. } else { - // There were no forward jumps. The current frame is merged to - // the entry frame. + // There were no forward jumps. There must be a current frame and + // this must be a bidirectional target. + ASSERT(reaching_frames_.length() == 1); + ASSERT(reaching_frames_[0] != NULL); + ASSERT(direction_ == BIDIRECTIONAL); + + // Use a copy of the reaching frame so the original can be saved + // for possible reuse as a backward merge block. + RegisterFile reserved = RegisterAllocator::Reserved(); + cgen_->SetFrame(new VirtualFrame(reaching_frames_[0]), &reserved); + __ bind(&merge_labels_[0]); cgen_->frame()->MergeTo(entry_frame_); __ bind(&entry_label_); } diff --git a/src/jump-target-ia32.cc b/src/jump-target-ia32.cc index 12eb26f330..7c3ece1855 100644 --- a/src/jump-target-ia32.cc +++ b/src/jump-target-ia32.cc @@ -70,40 +70,58 @@ void JumpTarget::Branch(Condition cc, Hint hint) { ASSERT(cgen_->has_valid_frame()); if (is_bound()) { - // Backward branch. We have an expected frame to merge to on the - // backward edge. We negate the condition and emit the merge code - // here. - // - // TODO(210): we should try to avoid negating the condition in the - // case where there is no merge code to emit. Otherwise, we emit - // a branch around an unconditional jump. ASSERT(direction_ == BIDIRECTIONAL); + // Backward branch. We have an expected frame to merge to on the + // backward edge. + + // Swap the current frame for a copy (we do the swapping to get + // the off-frame registers off the fall through) to use for the + // branch. + VirtualFrame* fall_through_frame = cgen_->frame(); + VirtualFrame* branch_frame = new VirtualFrame(fall_through_frame); + RegisterFile non_frame_registers = RegisterAllocator::Reserved(); + cgen_->SetFrame(branch_frame, &non_frame_registers); + + // Check if we can avoid merge code. + cgen_->frame()->PrepareMergeTo(entry_frame_); + if (cgen_->frame()->Equals(entry_frame_)) { + // Branch right in to the block. + cgen_->DeleteFrame(); + __ j(cc, &entry_label_, hint); + cgen_->SetFrame(fall_through_frame, &non_frame_registers); + return; + } + + // Check if we can reuse existing merge code. + for (int i = 0; i < reaching_frames_.length(); i++) { + if (reaching_frames_[i] != NULL && + cgen_->frame()->Equals(reaching_frames_[i])) { + // Branch to the merge code. + cgen_->DeleteFrame(); + __ j(cc, &merge_labels_[i], hint); + cgen_->SetFrame(fall_through_frame, &non_frame_registers); + return; + } + } + + // To emit the merge code here, we negate the condition and branch + // around the merge code on the fall through path. Label original_fall_through; __ j(NegateCondition(cc), &original_fall_through, NegateHint(hint)); - // Swap the current frame for a copy of it, saving non-frame - // register reference counts and invalidating all non-frame register - // references except the reserved ones on the backward edge. - VirtualFrame* original_frame = cgen_->frame(); - VirtualFrame* working_frame = new VirtualFrame(original_frame); - RegisterFile non_frame_registers = RegisterAllocator::Reserved(); - cgen_->SetFrame(working_frame, &non_frame_registers); - - working_frame->MergeTo(entry_frame_); + cgen_->frame()->MergeTo(entry_frame_); cgen_->DeleteFrame(); __ jmp(&entry_label_); - - // Restore the frame and its associated non-frame registers. - cgen_->SetFrame(original_frame, &non_frame_registers); + cgen_->SetFrame(fall_through_frame, &non_frame_registers); __ bind(&original_fall_through); + } else { // Forward branch. A copy of the current frame is added to the end // of the list of frames reaching the target block and a branch to // the merge code is emitted. AddReachingFrame(new VirtualFrame(cgen_->frame())); __ j(cc, &merge_labels_.last(), hint); + is_linked_ = true; } - - is_linked_ = !is_bound_; } @@ -138,79 +156,130 @@ void JumpTarget::Bind(int mergable_elements) { // block. ASSERT(!cgen_->has_valid_frame() || cgen_->HasValidEntryRegisters()); + if (direction_ == FORWARD_ONLY) { + // A simple case: no forward jumps and no possible backward jumps. + if (!is_linked()) { + // 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); + if (difference > 0) { + frame->stack_pointer_ -= difference; + __ add(Operand(esp), Immediate(difference * kPointerSize)); + } + + is_bound_ = true; + return; + } + + // 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; + } + } + + // If there is a current frame, record it as the fall-through. It + // is owned by the reaching frames for now. + bool had_fall_through = false; + if (cgen_->has_valid_frame()) { + had_fall_through = true; + AddReachingFrame(cgen_->frame()); + RegisterFile empty; + cgen_->SetFrame(NULL, &empty); + } + // Compute the frame to use for entry to the block. ComputeEntryFrame(mergable_elements); - if (is_linked()) { - // There were forward jumps. Handle merging the reaching frames - // and possible fall through to the entry frame. - - // Some moves required to merge to an expected frame require - // purely frame state changes, and do not require any code - // generation. Perform those first to increase the possibility of - // finding equal frames below. - if (cgen_->has_valid_frame()) { - cgen_->frame()->PrepareMergeTo(entry_frame_); - } - for (int i = 0; i < reaching_frames_.length(); i++) { + // Some moves required to merge to an expected frame require purely + // frame state changes, and do not require any code generation. + // Perform those first to increase the possibility of finding equal + // frames below. + for (int i = 0; i < reaching_frames_.length(); i++) { + if (reaching_frames_[i] != NULL) { reaching_frames_[i]->PrepareMergeTo(entry_frame_); } + } - // If there is a fall through to the jump target and it needs - // merge code, process it first. - if (cgen_->has_valid_frame() && !cgen_->frame()->Equals(entry_frame_)) { - // Loop over all the reaching frames, looking for any that can - // share merge code with this one. - for (int i = 0; i < reaching_frames_.length(); i++) { - if (cgen_->frame()->Equals(reaching_frames_[i])) { - // Set the reaching frames element to null to avoid - // processing it later, and then bind its entry label. - delete reaching_frames_[i]; - reaching_frames_[i] = NULL; - __ bind(&merge_labels_[i]); - } - } - - // Emit the merge code. - cgen_->frame()->MergeTo(entry_frame_); - } + if (is_linked()) { + // There were forward jumps. Handle merging the reaching frames + // to the entry frame. // Loop over the (non-null) reaching frames and process any that - // need merge code. - for (int i = 0; i < reaching_frames_.length(); i++) { + // need merge code. Iterate backwards through the list to handle + // the fall-through frame first. Set frames that will be + // processed after 'i' to NULL if we want to avoid processing + // them. + for (int i = reaching_frames_.length() - 1; i >= 0; i--) { VirtualFrame* frame = reaching_frames_[i]; - if (frame != NULL && !frame->Equals(entry_frame_)) { - // Set the reaching frames element to null to avoid processing - // it later. Do not delete it as it is needed for merging. - reaching_frames_[i] = NULL; - // If the code generator has a current frame (a fall-through - // or a previously merged frame), insert a jump around the - // merge code we are about to generate. - if (cgen_->has_valid_frame()) { - cgen_->DeleteFrame(); - __ jmp(&entry_label_); - } - - // Set the frame to merge as the code generator's current - // frame and bind its merge label. - RegisterFile reserved_registers = RegisterAllocator::Reserved(); - cgen_->SetFrame(frame, &reserved_registers); - __ bind(&merge_labels_[i]); - - // Loop over the remaining (non-null) reaching frames, looking - // for any that can share merge code with this one. - for (int j = i + 1; j < reaching_frames_.length(); j++) { - VirtualFrame* other = reaching_frames_[j]; - if (other != NULL && frame->Equals(other)) { - delete other; - reaching_frames_[j] = NULL; - __ bind(&merge_labels_[j]); + if (frame != NULL) { + // Does the frame (probably) need merge code? + if (!frame->Equals(entry_frame_)) { + // We could have a valid frame as the fall through to the + // binding site or as the fall through from a previous merge + // code block. Jump around the code we are about to + // generate. + if (cgen_->has_valid_frame()) { + cgen_->DeleteFrame(); + __ jmp(&entry_label_); } - } + // Pick up the frame for this block. Assume ownership if + // there cannot be backward jumps. + RegisterFile reserved = RegisterAllocator::Reserved(); + if (direction_ == BIDIRECTIONAL) { + cgen_->SetFrame(new VirtualFrame(frame), &reserved); + } else { + cgen_->SetFrame(frame, &reserved); + reaching_frames_[i] = NULL; + } + __ bind(&merge_labels_[i]); - // Emit the merge code. - cgen_->frame()->MergeTo(entry_frame_); + // Loop over the remaining (non-null) reaching frames, + // looking for any that can share merge code with this one. + for (int j = 0; j < i; j++) { + VirtualFrame* other = reaching_frames_[j]; + if (other != NULL && other->Equals(cgen_->frame())) { + // Set the reaching frame element to null to avoid + // processing it later, and then bind its entry label. + delete other; + reaching_frames_[j] = NULL; + __ bind(&merge_labels_[j]); + } + } + + // Emit the merge code. + cgen_->frame()->MergeTo(entry_frame_); + } else if (i == reaching_frames_.length() - 1 && had_fall_through) { + // If this is the fall through frame, and it didn't need + // merge code, we need to pick up the frame so we can jump + // around subsequent merge blocks if necessary. + RegisterFile reserved = RegisterAllocator::Reserved(); + cgen_->SetFrame(frame, &reserved); + reaching_frames_[i] = NULL; + } } } @@ -227,23 +296,31 @@ void JumpTarget::Bind(int mergable_elements) { __ bind(&entry_label_); // There may be unprocessed reaching frames that did not need - // merge code. Bind their merge labels to be the same as the - // entry label. + // merge code. They will have unbound merge labels. Bind their + // merge labels to be the same as the entry label and deallocate + // them. for (int i = 0; i < reaching_frames_.length(); i++) { - if (reaching_frames_[i] != NULL) { + if (!merge_labels_[i].is_bound()) { delete reaching_frames_[i]; + reaching_frames_[i] = NULL; __ bind(&merge_labels_[i]); } } - // All the reaching frames except the one that is the current - // frame (if it is one of the reaching frames) have been deleted. - reaching_frames_.Clear(); - merge_labels_.Clear(); - + // There are non-NULL reaching frames with bound labels for each + // merge block, but only on backward targets. } else { - // There were no forward jumps. The current frame is merged to - // the entry frame. + // There were no forward jumps. There must be a current frame and + // this must be a bidirectional target. + ASSERT(reaching_frames_.length() == 1); + ASSERT(reaching_frames_[0] != NULL); + ASSERT(direction_ == BIDIRECTIONAL); + + // Use a copy of the reaching frame so the original can be saved + // for possible reuse as a backward merge block. + RegisterFile reserved = RegisterAllocator::Reserved(); + cgen_->SetFrame(new VirtualFrame(reaching_frames_[0]), &reserved); + __ bind(&merge_labels_[0]); cgen_->frame()->MergeTo(entry_frame_); __ bind(&entry_label_); } diff --git a/src/jump-target.cc b/src/jump-target.cc index 8994cc097b..48b05b579f 100644 --- a/src/jump-target.cc +++ b/src/jump-target.cc @@ -74,13 +74,10 @@ void JumpTarget::Unuse() { // to them. In the event of a compile-time stack overflow or an // unitialized jump target, we don't care. ASSERT(!is_linked() || cgen_ == NULL || cgen_->HasStackOverflow()); -#ifdef DEBUG for (int i = 0; i < reaching_frames_.length(); i++) { - ASSERT(reaching_frames_[i] == NULL); + delete reaching_frames_[i]; } -#endif delete entry_frame_; - Reset(); } @@ -146,19 +143,12 @@ FrameElement* JumpTarget::Combine(FrameElement* left, FrameElement* right) { void JumpTarget::ComputeEntryFrame(int mergable_elements) { - // Given: a collection of frames reaching by forward CFG edges - // (including the code generator's current frame) and the - // directionality of the block. Compute: an entry frame for the + // Given: a collection of frames reaching by forward CFG edges and + // the directionality of the block. Compute: an entry frame for the // block. - // Choose an initial frame, either the code generator's current - // frame if there is one, or the first reaching frame if not. - VirtualFrame* initial_frame = cgen_->frame(); - int start_index = 0; // Begin iteration with the 1st reaching frame. - if (initial_frame == NULL) { - initial_frame = reaching_frames_[0]; - start_index = 1; // Begin iteration with the 2nd reaching frame. - } + // Choose an initial frame. + VirtualFrame* initial_frame = reaching_frames_[0]; // A list of pointers to frame elements in the entry frame. NULL // indicates that the element has not yet been determined. @@ -188,9 +178,9 @@ void JumpTarget::ComputeEntryFrame(int mergable_elements) { } // Compute elements based on the other reaching frames. - if (start_index < reaching_frames_.length()) { + if (reaching_frames_.length() > 1) { for (int i = 0; i < length; i++) { - for (int j = start_index; j < reaching_frames_.length(); j++) { + for (int j = 1; j < reaching_frames_.length(); j++) { FrameElement* element = elements[i]; // Element computation is monotonic: new information will not @@ -229,12 +219,11 @@ void JumpTarget::ComputeEntryFrame(int mergable_elements) { // If the value is synced on all frames, put it in memory. This // costs nothing at the merge code but will incur a // memory-to-register move when the value is needed later. - bool is_synced = initial_frame->elements_[i].is_synced(); - int j = start_index; - while (is_synced && j < reaching_frames_.length()) { + bool is_synced = true; + for (int j = 0; is_synced && j < reaching_frames_.length(); j++) { is_synced = reaching_frames_[j]->elements_[i].is_synced(); - j++; } + // There is nothing to be done if the elements are all synced. // It is already recorded as a memory element. if (is_synced) continue; @@ -245,17 +234,8 @@ void JumpTarget::ComputeEntryFrame(int mergable_elements) { int max_count = kMinInt; int best_reg_code = no_reg.code_; - // Consider the initial frame. - FrameElement element = initial_frame->elements_[i]; - if (element.is_register() && - !frame_registers.is_used(element.reg())) { - candidate_registers.Use(element.reg()); - max_count = 1; - best_reg_code = element.reg().code(); - } - // Consider the other frames. - for (int j = start_index; j < reaching_frames_.length(); j++) { - element = reaching_frames_[j]->elements_[i]; + for (int j = 0; j < reaching_frames_.length(); j++) { + FrameElement element = reaching_frames_[j]->elements_[i]; if (element.is_register() && !frame_registers.is_used(element.reg())) { candidate_registers.Use(element.reg()); @@ -592,16 +572,18 @@ void BreakTarget::Bind(int mergable_elements) { #ifdef DEBUG ASSERT(mergable_elements == kAllElements); ASSERT(cgen_ != NULL); + // 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]->height() == expected_height_); + ASSERT(reaching_frames_[i] == NULL || + reaching_frames_[i]->height() == expected_height_); } #endif - - // This is a break target so drop leftover statement state from the - // frame before merging. + // This is a break target so we drop leftover statement state from + // the frame before merging, even on the fall through. This is + // because 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()->ForgetElements(cgen_->frame()->height() - expected_height_); } JumpTarget::Bind(mergable_elements); }