Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(43)

Side by Side Diff: src/arm/jump-target-arm.cc

Issue 165230: Eliminate most of the jump target jumping, branching, and binding... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: Created 11 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | src/arm/virtual-frame-arm.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2008 the V8 project authors. All rights reserved. 1 // Copyright 2008 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 29 matching lines...) Expand all
40 #define __ ACCESS_MASM(cgen()->masm()) 40 #define __ ACCESS_MASM(cgen()->masm())
41 41
42 void JumpTarget::DoJump() { 42 void JumpTarget::DoJump() {
43 ASSERT(cgen()->has_valid_frame()); 43 ASSERT(cgen()->has_valid_frame());
44 // Live non-frame registers are not allowed at unconditional jumps 44 // Live non-frame registers are not allowed at unconditional jumps
45 // because we have no way of invalidating the corresponding results 45 // because we have no way of invalidating the corresponding results
46 // which are still live in the C++ code. 46 // which are still live in the C++ code.
47 ASSERT(cgen()->HasValidEntryRegisters()); 47 ASSERT(cgen()->HasValidEntryRegisters());
48 48
49 if (is_bound()) { 49 if (is_bound()) {
50 // Backward jump. There is an expected frame to merge to. 50 // Backward jump. There already a frame expectation at the target.
51 ASSERT(direction_ == BIDIRECTIONAL); 51 ASSERT(direction_ == BIDIRECTIONAL);
52 cgen()->frame()->PrepareMergeTo(entry_frame_);
53 cgen()->frame()->MergeTo(entry_frame_); 52 cgen()->frame()->MergeTo(entry_frame_);
54 cgen()->DeleteFrame(); 53 cgen()->DeleteFrame();
55 __ jmp(&entry_label_);
56 } else { 54 } else {
57 // Preconfigured entry frame is not used on ARM. 55 // Use the current frame as the expected one at the target if necessary.
58 ASSERT(entry_frame_ == NULL); 56 if (entry_frame_ == NULL) {
59 // Forward jump. The current frame is added to the end of the list 57 entry_frame_ = cgen()->frame();
60 // of frames reaching the target block and a jump to the merge code 58 RegisterFile empty;
61 // is emitted. 59 cgen()->SetFrame(NULL, &empty);
62 AddReachingFrame(cgen()->frame()); 60 } else {
63 RegisterFile empty; 61 cgen()->frame()->MergeTo(entry_frame_);
64 cgen()->SetFrame(NULL, &empty); 62 cgen()->DeleteFrame();
65 __ jmp(&merge_labels_.last()); 63 }
64
65 // 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
66 // uses the presence of a frame pointer in the reaching_frames_ list.
67 if (!is_linked()) {
68 reaching_frames_.Add(NULL);
69 ASSERT(is_linked());
70 }
66 } 71 }
72 __ jmp(&entry_label_);
67 } 73 }
68 74
69 75
70 void JumpTarget::DoBranch(Condition cc, Hint ignored) { 76 void JumpTarget::DoBranch(Condition cc, Hint ignored) {
71 ASSERT(cgen()->has_valid_frame()); 77 ASSERT(cgen()->has_valid_frame());
72 78
73 if (is_bound()) { 79 if (is_bound()) {
74 ASSERT(direction_ == BIDIRECTIONAL); 80 ASSERT(direction_ == BIDIRECTIONAL);
75 // Backward branch. We have an expected frame to merge to on the 81 // Backward branch. We have an expected frame to merge to on the
76 // backward edge. 82 // backward edge.
77 83 cgen()->frame()->MergeTo(entry_frame_);
78 // Swap the current frame for a copy (we do the swapping to get 84 } else {
79 // the off-frame registers off the fall through) to use for the 85 // Clone the current frame to use as the expected one at the target if
80 // branch. 86 // necessary.
81 VirtualFrame* fall_through_frame = cgen()->frame(); 87 if (entry_frame_ == NULL) {
82 VirtualFrame* branch_frame = new VirtualFrame(fall_through_frame); 88 entry_frame_ = new VirtualFrame(cgen()->frame());
83 RegisterFile non_frame_registers;
84 cgen()->SetFrame(branch_frame, &non_frame_registers);
85
86 // Check if we can avoid merge code.
87 cgen()->frame()->PrepareMergeTo(entry_frame_);
88 if (cgen()->frame()->Equals(entry_frame_)) {
89 // Branch right in to the block.
90 cgen()->DeleteFrame();
91 __ b(cc, &entry_label_);
92 cgen()->SetFrame(fall_through_frame, &non_frame_registers);
93 return;
94 } 89 }
95 90 // The predicate is_linked() should now be true. The implementation
96 // Check if we can reuse existing merge code. 91 // uses the presence of a frame pointer in the reaching_frames_ list.
97 for (int i = 0; i < reaching_frames_.length(); i++) { 92 if (!is_linked()) {
98 if (reaching_frames_[i] != NULL && 93 reaching_frames_.Add(NULL);
99 cgen()->frame()->Equals(reaching_frames_[i])) { 94 ASSERT(is_linked());
100 // Branch to the merge code.
101 cgen()->DeleteFrame();
102 __ b(cc, &merge_labels_[i]);
103 cgen()->SetFrame(fall_through_frame, &non_frame_registers);
104 return;
105 }
106 } 95 }
107
108 // To emit the merge code here, we negate the condition and branch
109 // around the merge code on the fall through path.
110 Label original_fall_through;
111 __ b(NegateCondition(cc), &original_fall_through);
112 cgen()->frame()->MergeTo(entry_frame_);
113 cgen()->DeleteFrame();
114 __ b(&entry_label_);
115 cgen()->SetFrame(fall_through_frame, &non_frame_registers);
116 __ bind(&original_fall_through);
117
118 } else {
119 // Preconfigured entry frame is not used on ARM.
120 ASSERT(entry_frame_ == NULL);
121 // Forward branch. A copy of the current frame is added to the end
122 // of the list of frames reaching the target block and a branch to
123 // the merge code is emitted.
124 AddReachingFrame(new VirtualFrame(cgen()->frame()));
125 __ b(cc, &merge_labels_.last());
126 } 96 }
97 __ b(cc, &entry_label_);
127 } 98 }
128 99
129 100
130 void JumpTarget::Call() { 101 void JumpTarget::Call() {
131 // Call is used to push the address of the catch block on the stack as 102 // Call is used to push the address of the catch block on the stack as
132 // a return address when compiling try/catch and try/finally. We 103 // a return address when compiling try/catch and try/finally. We
133 // fully spill the frame before making the call. The expected frame 104 // fully spill the frame before making the call. The expected frame
134 // at the label (which should be the only one) is the spilled current 105 // at the label (which should be the only one) is the spilled current
135 // frame plus an in-memory return address. The "fall-through" frame 106 // frame plus an in-memory return address. The "fall-through" frame
136 // at the return site is the spilled current frame. 107 // at the return site is the spilled current frame.
137 ASSERT(cgen()->has_valid_frame()); 108 ASSERT(cgen()->has_valid_frame());
138 // There are no non-frame references across the call. 109 // There are no non-frame references across the call.
139 ASSERT(cgen()->HasValidEntryRegisters()); 110 ASSERT(cgen()->HasValidEntryRegisters());
140 ASSERT(!is_linked()); 111 ASSERT(!is_linked());
141 112
142 cgen()->frame()->SpillAll(); 113 // Calls are always 'forward' so we use a copy of the current frame (plus
114 // one for a return address) as the expected frame.
115 ASSERT(entry_frame_ == NULL);
143 VirtualFrame* target_frame = new VirtualFrame(cgen()->frame()); 116 VirtualFrame* target_frame = new VirtualFrame(cgen()->frame());
144 target_frame->Adjust(1); 117 target_frame->Adjust(1);
145 // We do not expect a call with a preconfigured entry frame. 118 entry_frame_ = target_frame;
146 ASSERT(entry_frame_ == NULL); 119
147 AddReachingFrame(target_frame); 120 // is_linked() should now be true. The JumpTarget class uses the presence
148 __ bl(&merge_labels_.last()); 121 // of a frame pointer in the reaching_frames_ list.
122 reaching_frames_.Add(NULL);
123 ASSERT(is_linked());
124
125 __ bl(&entry_label_);
149 } 126 }
150 127
151 128
152 void JumpTarget::DoBind() { 129 void JumpTarget::DoBind() {
153 ASSERT(!is_bound()); 130 ASSERT(!is_bound());
154 131
155 // Live non-frame registers are not allowed at the start of a basic 132 // Live non-frame registers are not allowed at the start of a basic
156 // block. 133 // block.
157 ASSERT(!cgen()->has_valid_frame() || cgen()->HasValidEntryRegisters()); 134 ASSERT(!cgen()->has_valid_frame() || cgen()->HasValidEntryRegisters());
158 135
159 if (direction_ == FORWARD_ONLY) { 136 if (cgen()->has_valid_frame()) {
160 // A simple case: no forward jumps and no possible backward jumps. 137 // If there is a current frame we can use it on the fall through.
161 if (!is_linked()) { 138 if (entry_frame_ == NULL) {
162 // The stack pointer can be floating above the top of the 139 entry_frame_ = new VirtualFrame(cgen()->frame());
163 // virtual frame before the bind. Afterward, it should not. 140 } else {
164 ASSERT(cgen()->has_valid_frame()); 141 ASSERT(cgen()->frame()->Equals(entry_frame_));
165 VirtualFrame* frame = cgen()->frame();
166 int difference = frame->stack_pointer_ - (frame->element_count() - 1);
167 if (difference > 0) {
168 frame->stack_pointer_ -= difference;
169 __ add(sp, sp, Operand(difference * kPointerSize));
170 }
171 __ bind(&entry_label_);
172 return;
173 } 142 }
174 143 } else {
175 // Another simple case: no fall through, a single forward jump, 144 // If there is no current frame we must have an entry frame which we can
176 // and no possible backward jumps. 145 // copy.
177 if (!cgen()->has_valid_frame() && reaching_frames_.length() == 1) { 146 ASSERT(entry_frame_ != NULL);
178 // Pick up the only reaching frame, take ownership of it, and 147 RegisterFile empty;
179 // use it for the block about to be emitted. 148 cgen()->SetFrame(new VirtualFrame(entry_frame_), &empty);
180 VirtualFrame* frame = reaching_frames_[0];
181 RegisterFile empty;
182 cgen()->SetFrame(frame, &empty);
183 reaching_frames_[0] = NULL;
184 __ bind(&merge_labels_[0]);
185
186 // The stack pointer can be floating above the top of the
187 // virtual frame before the bind. Afterward, it should not.
188 int difference = frame->stack_pointer_ - (frame->element_count() - 1);
189 if (difference > 0) {
190 frame->stack_pointer_ -= difference;
191 __ add(sp, sp, Operand(difference * kPointerSize));
192 }
193 __ bind(&entry_label_);
194 return;
195 }
196 } 149 }
197 150
198 // If there is a current frame, record it as the fall-through. It 151 // is_linked() should now be false. We may have inserted a bogus reaching
199 // is owned by the reaching frames for now. 152 // frame to make it true, remove it now.
200 bool had_fall_through = false;
201 if (cgen()->has_valid_frame()) {
202 had_fall_through = true;
203 AddReachingFrame(cgen()->frame()); // Return value ignored.
204 RegisterFile empty;
205 cgen()->SetFrame(NULL, &empty);
206 }
207
208 // Compute the frame to use for entry to the block.
209 if (entry_frame_ == NULL) {
210 ComputeEntryFrame();
211 }
212
213 // Some moves required to merge to an expected frame require purely
214 // frame state changes, and do not require any code generation.
215 // Perform those first to increase the possibility of finding equal
216 // frames below.
217 for (int i = 0; i < reaching_frames_.length(); i++) {
218 if (reaching_frames_[i] != NULL) {
219 reaching_frames_[i]->PrepareMergeTo(entry_frame_);
220 }
221 }
222
223 if (is_linked()) { 153 if (is_linked()) {
224 // There were forward jumps. Handle merging the reaching frames 154 reaching_frames_.Clear();
225 // and possible fall through to the entry frame.
226
227 // Loop over the (non-null) reaching frames and process any that
228 // need merge code. Iterate backwards through the list to handle
229 // the fall-through frame first. Set frames that will be
230 // processed after 'i' to NULL if we want to avoid processing
231 // them.
232 for (int i = reaching_frames_.length() - 1; i >= 0; i--) {
233 VirtualFrame* frame = reaching_frames_[i];
234
235 if (frame != NULL) {
236 // Does the frame (probably) need merge code?
237 if (!frame->Equals(entry_frame_)) {
238 // We could have a valid frame as the fall through to the
239 // binding site or as the fall through from a previous merge
240 // code block. Jump around the code we are about to
241 // generate.
242 if (cgen()->has_valid_frame()) {
243 cgen()->DeleteFrame();
244 __ b(&entry_label_);
245 }
246 // Pick up the frame for this block. Assume ownership if
247 // there cannot be backward jumps.
248 RegisterFile empty;
249 if (direction_ == BIDIRECTIONAL) {
250 cgen()->SetFrame(new VirtualFrame(frame), &empty);
251 } else {
252 cgen()->SetFrame(frame, &empty);
253 reaching_frames_[i] = NULL;
254 }
255 __ bind(&merge_labels_[i]);
256
257 // Loop over the remaining (non-null) reaching frames,
258 // looking for any that can share merge code with this one.
259 for (int j = 0; j < i; j++) {
260 VirtualFrame* other = reaching_frames_[j];
261 if (other != NULL && other->Equals(cgen()->frame())) {
262 // Set the reaching frame element to null to avoid
263 // processing it later, and then bind its entry label.
264 reaching_frames_[j] = NULL;
265 __ bind(&merge_labels_[j]);
266 }
267 }
268
269 // Emit the merge code.
270 cgen()->frame()->MergeTo(entry_frame_);
271 } else if (i == reaching_frames_.length() - 1 && had_fall_through) {
272 // If this is the fall through, and it didn't need merge
273 // code, we need to pick up the frame so we can jump around
274 // subsequent merge blocks if necessary.
275 RegisterFile empty;
276 cgen()->SetFrame(frame, &empty);
277 reaching_frames_[i] = NULL;
278 }
279 }
280 }
281
282 // The code generator may not have a current frame if there was no
283 // fall through and none of the reaching frames needed merging.
284 // In that case, clone the entry frame as the current frame.
285 if (!cgen()->has_valid_frame()) {
286 RegisterFile empty;
287 cgen()->SetFrame(new VirtualFrame(entry_frame_), &empty);
288 }
289
290 // There may be unprocessed reaching frames that did not need
291 // merge code. They will have unbound merge labels. Bind their
292 // merge labels to be the same as the entry label and deallocate
293 // them.
294 for (int i = 0; i < reaching_frames_.length(); i++) {
295 if (!merge_labels_[i].is_bound()) {
296 reaching_frames_[i] = NULL;
297 __ bind(&merge_labels_[i]);
298 }
299 }
300
301 // There are non-NULL reaching frames with bound labels for each
302 // merge block, but only on backward targets.
303 } else {
304 // There were no forward jumps. There must be a current frame and
305 // this must be a bidirectional target.
306 ASSERT(reaching_frames_.length() == 1);
307 ASSERT(reaching_frames_[0] != NULL);
308 ASSERT(direction_ == BIDIRECTIONAL);
309
310 // Use a copy of the reaching frame so the original can be saved
311 // for possible reuse as a backward merge block.
312 RegisterFile empty;
313 cgen()->SetFrame(new VirtualFrame(reaching_frames_[0]), &empty);
314 __ bind(&merge_labels_[0]);
315 cgen()->frame()->MergeTo(entry_frame_);
316 } 155 }
317 156
318 __ bind(&entry_label_); 157 __ bind(&entry_label_);
319 } 158 }
320 159
160
161 void BreakTarget::Jump() {
162 // On ARM we do not currently emit merge code for jumps, so we need to do
163 // it explicitly here. The only merging necessary is to drop extra
164 // statement state from the stack.
165 ASSERT(cgen()->has_valid_frame());
166 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
167 cgen()->frame()->Drop(count);
168 DoJump();
169 }
170
171
172 void BreakTarget::Jump(Result* arg) {
173 // On ARM we do not currently emit merge code for jumps, so we need to do
174 // it explicitly here. The only merging necessary is to drop extra
175 // statement state from the stack.
176 ASSERT(cgen()->has_valid_frame());
177 int count = cgen()->frame()->height() - expected_height_;
178 cgen()->frame()->Drop(count);
179 cgen()->frame()->Push(arg);
180 DoJump();
181 }
182
183
184 void BreakTarget::Bind() {
185 #ifdef DEBUG
186 // All the forward-reaching frames should have been adjusted at the
187 // jumps to this target.
188 for (int i = 0; i < reaching_frames_.length(); i++) {
189 ASSERT(reaching_frames_[i] == NULL ||
190 reaching_frames_[i]->height() == expected_height_);
191 }
192 #endif
193 // Drop leftover statement state from the frame before merging, even
194 // on the fall through. This is so we can bind the return target
195 // with state on the frame.
196 if (cgen()->has_valid_frame()) {
197 int count = cgen()->frame()->height() - expected_height_;
198 // On ARM we do not currently emit merge code at binding sites, so we need
199 // to do it explicitly here. The only merging necessary is to drop extra
200 // statement state from the stack.
201 cgen()->frame()->Drop(count);
202 }
203
204 DoBind();
205 }
206
207
208 void BreakTarget::Bind(Result* arg) {
209 #ifdef DEBUG
210 // All the forward-reaching frames should have been adjusted at the
211 // jumps to this target.
212 for (int i = 0; i < reaching_frames_.length(); i++) {
213 ASSERT(reaching_frames_[i] == NULL ||
214 reaching_frames_[i]->height() == expected_height_ + 1);
215 }
216 #endif
217 // Drop leftover statement state from the frame before merging, even
218 // on the fall through. This is so we can bind the return target
219 // with state on the frame.
220 if (cgen()->has_valid_frame()) {
221 int count = cgen()->frame()->height() - expected_height_;
222 // On ARM we do not currently emit merge code at binding sites, so we need
223 // to do it explicitly here. The only merging necessary is to drop extra
224 // statement state from the stack.
225 cgen()->frame()->ForgetElements(count);
226 cgen()->frame()->Push(arg);
227 }
228 DoBind();
229 *arg = cgen()->frame()->Pop();
230 }
231
232
321 #undef __ 233 #undef __
322 234
323 235
324 } } // namespace v8::internal 236 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « no previous file | src/arm/virtual-frame-arm.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698