Chromium Code Reviews| Index: src/arm/jump-target-arm.cc |
| =================================================================== |
| --- src/arm/jump-target-arm.cc (revision 2654) |
| +++ src/arm/jump-target-arm.cc (working copy) |
| @@ -47,23 +47,29 @@ |
| ASSERT(cgen()->HasValidEntryRegisters()); |
| if (is_bound()) { |
| - // Backward jump. There is an expected frame to merge to. |
| + // Backward jump. There already a frame expectation at the target. |
| ASSERT(direction_ == BIDIRECTIONAL); |
| - cgen()->frame()->PrepareMergeTo(entry_frame_); |
| cgen()->frame()->MergeTo(entry_frame_); |
| cgen()->DeleteFrame(); |
| - __ jmp(&entry_label_); |
| } else { |
| - // Preconfigured entry frame is not used on ARM. |
| - ASSERT(entry_frame_ == NULL); |
| - // Forward jump. The current frame is added to the end of the list |
| - // of frames reaching the target block and a jump to the merge code |
| - // is emitted. |
| - AddReachingFrame(cgen()->frame()); |
| - RegisterFile empty; |
| - cgen()->SetFrame(NULL, &empty); |
| - __ jmp(&merge_labels_.last()); |
| + // Use the current frame as the expected one at the target if necessary. |
| + if (entry_frame_ == NULL) { |
| + entry_frame_ = cgen()->frame(); |
| + RegisterFile empty; |
| + cgen()->SetFrame(NULL, &empty); |
| + } else { |
| + cgen()->frame()->MergeTo(entry_frame_); |
| + cgen()->DeleteFrame(); |
| + } |
| + |
| + // The predicate is_linked() should now be true. The implementation |
|
Erik Corry
2009/08/10 10:56:45
This comment doesn't explain itself very well.
Kevin Millikin (Chromium)
2009/08/10 11:11:31
Reworded:
"The predicate is_linked() should be ma
|
| + // uses the presence of a frame pointer in the reaching_frames_ list. |
| + if (!is_linked()) { |
| + reaching_frames_.Add(NULL); |
| + ASSERT(is_linked()); |
| + } |
| } |
| + __ jmp(&entry_label_); |
| } |
| @@ -74,56 +80,21 @@ |
| 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; |
| - 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); |
| cgen()->frame()->MergeTo(entry_frame_); |
| - cgen()->DeleteFrame(); |
| - __ b(&entry_label_); |
| - cgen()->SetFrame(fall_through_frame, &non_frame_registers); |
| - __ bind(&original_fall_through); |
| - |
| } else { |
| - // Preconfigured entry frame is not used on ARM. |
| - ASSERT(entry_frame_ == NULL); |
| - // 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()); |
| + // Clone the current frame to use as the expected one at the target if |
| + // necessary. |
| + if (entry_frame_ == NULL) { |
| + entry_frame_ = new VirtualFrame(cgen()->frame()); |
| + } |
| + // The predicate is_linked() should now be true. The implementation |
| + // uses the presence of a frame pointer in the reaching_frames_ list. |
| + if (!is_linked()) { |
| + reaching_frames_.Add(NULL); |
| + ASSERT(is_linked()); |
| + } |
| } |
| + __ b(cc, &entry_label_); |
| } |
| @@ -139,13 +110,19 @@ |
| ASSERT(cgen()->HasValidEntryRegisters()); |
| ASSERT(!is_linked()); |
| - cgen()->frame()->SpillAll(); |
| + // Calls are always 'forward' so we use a copy of the current frame (plus |
| + // one for a return address) as the expected frame. |
| + ASSERT(entry_frame_ == NULL); |
| VirtualFrame* target_frame = new VirtualFrame(cgen()->frame()); |
| target_frame->Adjust(1); |
| - // We do not expect a call with a preconfigured entry frame. |
| - ASSERT(entry_frame_ == NULL); |
| - AddReachingFrame(target_frame); |
| - __ bl(&merge_labels_.last()); |
| + entry_frame_ = target_frame; |
| + |
| + // is_linked() should now be true. The JumpTarget class uses the presence |
| + // of a frame pointer in the reaching_frames_ list. |
| + reaching_frames_.Add(NULL); |
| + ASSERT(is_linked()); |
| + |
| + __ bl(&entry_label_); |
| } |
| @@ -156,168 +133,103 @@ |
| // 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->element_count() - 1); |
| - if (difference > 0) { |
| - frame->stack_pointer_ -= difference; |
| - __ add(sp, sp, Operand(difference * kPointerSize)); |
| - } |
| - __ bind(&entry_label_); |
| - 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 empty; |
| - cgen()->SetFrame(frame, &empty); |
| - 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->element_count() - 1); |
| - if (difference > 0) { |
| - frame->stack_pointer_ -= difference; |
| - __ add(sp, sp, Operand(difference * kPointerSize)); |
| - } |
| - __ bind(&entry_label_); |
| - 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()); // Return value ignored. |
| + // If there is a current frame we can use it on the fall through. |
| + if (entry_frame_ == NULL) { |
| + entry_frame_ = new VirtualFrame(cgen()->frame()); |
| + } else { |
| + ASSERT(cgen()->frame()->Equals(entry_frame_)); |
| + } |
| + } else { |
| + // If there is no current frame we must have an entry frame which we can |
| + // copy. |
| + ASSERT(entry_frame_ != NULL); |
| RegisterFile empty; |
| - cgen()->SetFrame(NULL, &empty); |
| + cgen()->SetFrame(new VirtualFrame(entry_frame_), &empty); |
| } |
| - // Compute the frame to use for entry to the block. |
| - if (entry_frame_ == NULL) { |
| - ComputeEntryFrame(); |
| + // is_linked() should now be false. We may have inserted a bogus reaching |
| + // frame to make it true, remove it now. |
| + if (is_linked()) { |
| + reaching_frames_.Clear(); |
| } |
| - // 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_); |
| - } |
| - } |
| + __ bind(&entry_label_); |
| +} |
| - if (is_linked()) { |
| - // There were forward jumps. Handle merging the reaching frames |
| - // and possible fall through to the entry frame. |
| - // Loop over the (non-null) reaching frames and process any that |
| - // 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]; |
| +void BreakTarget::Jump() { |
| + // On ARM we do not currently emit merge code for jumps, so we need to do |
| + // it explicitly here. The only merging necessary is to drop extra |
| + // statement state from the stack. |
| + ASSERT(cgen()->has_valid_frame()); |
| + int count = cgen()->frame()->height() - expected_height_; |
|
Erik Corry
2009/08/10 10:56:45
Should we assert that count is positive?
Kevin Millikin (Chromium)
2009/08/10 11:11:31
Yea verily. Even better it should go in VirtualFr
|
| + cgen()->frame()->Drop(count); |
| + DoJump(); |
| +} |
| - 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 empty; |
| - if (direction_ == BIDIRECTIONAL) { |
| - cgen()->SetFrame(new VirtualFrame(frame), &empty); |
| - } else { |
| - cgen()->SetFrame(frame, &empty); |
| - reaching_frames_[i] = NULL; |
| - } |
| - __ 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 = 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. |
| - reaching_frames_[j] = NULL; |
| - __ bind(&merge_labels_[j]); |
| - } |
| - } |
| +void BreakTarget::Jump(Result* arg) { |
| + // On ARM we do not currently emit merge code for jumps, so we need to do |
| + // it explicitly here. The only merging necessary is to drop extra |
| + // statement state from the stack. |
| + ASSERT(cgen()->has_valid_frame()); |
| + int count = cgen()->frame()->height() - expected_height_; |
| + cgen()->frame()->Drop(count); |
| + cgen()->frame()->Push(arg); |
| + DoJump(); |
| +} |
| - // 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 empty; |
| - cgen()->SetFrame(frame, &empty); |
| - reaching_frames_[i] = NULL; |
| - } |
| - } |
| - } |
| - // The code generator may not have a current frame if there was no |
| - // fall through and none of the reaching frames needed merging. |
| - // In that case, clone the entry frame as the current frame. |
| - if (!cgen()->has_valid_frame()) { |
| - RegisterFile empty; |
| - cgen()->SetFrame(new VirtualFrame(entry_frame_), &empty); |
| - } |
| +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_; |
| + // On ARM we do not currently emit merge code at binding sites, so we need |
| + // to do it explicitly here. The only merging necessary is to drop extra |
| + // statement state from the stack. |
| + cgen()->frame()->Drop(count); |
| + } |
| - // There may be unprocessed reaching frames that did not need |
| - // 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 (!merge_labels_[i].is_bound()) { |
| - reaching_frames_[i] = NULL; |
| - __ bind(&merge_labels_[i]); |
| - } |
| - } |
| + DoBind(); |
| +} |
| - // There are non-NULL reaching frames with bound labels for each |
| - // merge block, but only on backward targets. |
| - } else { |
| - // 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 empty; |
| - cgen()->SetFrame(new VirtualFrame(reaching_frames_[0]), &empty); |
| - __ bind(&merge_labels_[0]); |
| - cgen()->frame()->MergeTo(entry_frame_); |
| +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); |
| } |
| - |
| - __ bind(&entry_label_); |
| +#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_; |
| + // On ARM we do not currently emit merge code at binding sites, so we need |
| + // to do it explicitly here. The only merging necessary is to drop extra |
| + // statement state from the stack. |
| + cgen()->frame()->ForgetElements(count); |
| + cgen()->frame()->Push(arg); |
| + } |
| + DoBind(); |
| + *arg = cgen()->frame()->Pop(); |
| } |
| + |
| #undef __ |