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

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

Issue 18089: Experimental: for forward CFG edges, generate the code to merge to an... (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/toiger/
Patch Set: Created 11 years, 11 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
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 20 matching lines...) Expand all
31 #include "jump-target.h" 31 #include "jump-target.h"
32 32
33 namespace v8 { namespace internal { 33 namespace v8 { namespace internal {
34 34
35 // ------------------------------------------------------------------------- 35 // -------------------------------------------------------------------------
36 // JumpTarget implementation. 36 // JumpTarget implementation.
37 37
38 #define __ masm_-> 38 #define __ masm_->
39 39
40 JumpTarget::JumpTarget(CodeGenerator* cgen) 40 JumpTarget::JumpTarget(CodeGenerator* cgen)
41 : expected_frame_(NULL), 41 : cgen_(cgen),
42 cgen_(cgen), 42 reaching_frames_(0),
43 masm_(cgen->masm()) { 43 merge_labels_(0),
44 expected_frame_(NULL) {
45 ASSERT(cgen_ != NULL);
46 masm_ = cgen_->masm();
44 } 47 }
45 48
46 49
47 JumpTarget::JumpTarget() 50 JumpTarget::JumpTarget()
48 : expected_frame_(NULL), 51 : cgen_(NULL),
49 cgen_(NULL), 52 masm_(NULL),
50 masm_(NULL) { 53 reaching_frames_(0),
54 merge_labels_(0),
55 expected_frame_(NULL) {
51 } 56 }
52 57
53 58
54 void JumpTarget::set_code_generator(CodeGenerator* cgen) { 59 void JumpTarget::set_code_generator(CodeGenerator* cgen) {
55 ASSERT(cgen != NULL); 60 ASSERT(cgen != NULL);
56 ASSERT(cgen_ == NULL); 61 ASSERT(cgen_ == NULL);
57 cgen_ = cgen; 62 cgen_ = cgen;
58 masm_ = cgen->masm(); 63 masm_ = cgen->masm();
59 } 64 }
60 65
61 66
62 void JumpTarget::Jump() { 67 void JumpTarget::Jump() {
63 // Precondition: there is a current frame. There may or may not be an
64 // expected frame at the label.
65 ASSERT(cgen_ != NULL); 68 ASSERT(cgen_ != NULL);
69 ASSERT(cgen_->has_valid_frame());
66 ASSERT(!cgen_->has_cc()); 70 ASSERT(!cgen_->has_cc());
67 71 // Live non-frame registers are not allowed at unconditional jumps
68 VirtualFrame* current_frame = cgen_->frame(); 72 // because we have no way of invalidating the corresponding results
69 ASSERT(current_frame != NULL); 73 // which are still live in the C++ code.
70 ASSERT(cgen_->HasValidEntryRegisters()); 74 ASSERT(cgen_->HasValidEntryRegisters());
71 75
72 if (expected_frame_ == NULL) { 76 if (is_bound()) {
73 current_frame->MakeMergable(); 77 // Backward jump. There is an expected frame to merge to.
74 expected_frame_ = current_frame; 78 cgen_->frame()->MergeTo(expected_frame_);
75 ASSERT(cgen_->HasValidEntryRegisters()); 79 cgen_->DeleteFrame();
76 RegisterFile ignored; 80 __ jmp(&entry_label_);
77 cgen_->SetFrame(NULL, &ignored);
78 } else { 81 } else {
79 current_frame->MergeTo(expected_frame_); 82 // Forward jump. The current frame is added to the end of the list
80 ASSERT(cgen_->HasValidEntryRegisters()); 83 // of frames reaching the target block and a jump to the merge code
81 cgen_->DeleteFrame(); 84 // is emitted.
85 AddReachingFrame(cgen_->frame());
86 RegisterFile empty;
87 cgen_->SetFrame(NULL, &empty);
88 __ jmp(&merge_labels_.last());
82 } 89 }
83
84 __ jmp(&label_);
85 // Postcondition: there is no current frame but there is an expected frame
86 // at the label.
87 } 90 }
88 91
89 92
90 void JumpTarget::Jump(Result* arg) { 93 void JumpTarget::Jump(Result* arg) {
91 ASSERT(cgen_ != NULL); 94 ASSERT(cgen_ != NULL);
92 ASSERT(cgen_->has_valid_frame()); 95 ASSERT(cgen_->has_valid_frame());
93 96
94 cgen_->frame()->Push(arg); 97 cgen_->frame()->Push(arg);
95 Jump(); 98 Jump();
96 } 99 }
97 100
98 101
99 void JumpTarget::Branch(Condition cc, Hint hint) { 102 void JumpTarget::Branch(Condition cc, Hint hint) {
100 // Precondition: there is a current frame. There may or may not be an
101 // expected frame at the label.
102 ASSERT(cgen_ != NULL); 103 ASSERT(cgen_ != NULL);
103 ASSERT(masm_ != NULL); 104 ASSERT(cgen_->has_valid_frame());
105 ASSERT(!cgen_->has_cc());
104 ASSERT(!cgen_->has_cc()); 106 ASSERT(!cgen_->has_cc());
William Hesse 2009/01/15 12:21:54 This looks like a duplicate line.
Kevin Millikin (Chromium) 2009/01/15 13:08:18 Oops. Fixed.
105 107
106 VirtualFrame* current_frame = cgen_->frame(); 108 if (is_bound()) {
107 ASSERT(current_frame != NULL); 109 // Backward branch. We have an expected frame to merge to on the
108 110 // backward edge. We negate the condition and emit the merge code
109 if (expected_frame_ == NULL) { 111 // here.
110 expected_frame_ = new VirtualFrame(current_frame);
111 // For a branch, the frame at the fall-through basic block (not labeled)
112 // does not need to be mergable, but only the other (labeled) one. That
113 // is achieved by reversing the condition and emitting the make mergable
114 // code as the actual fall-through block.
115 // 112 //
116 // TODO(): This is necessary only when MakeMergable will generate code. 113 // TODO(): we should try to avoid negating the condition in the case
114 // where there is no merge code to emit. Otherwise, we emit a
115 // branch around an unconditional jump.
117 Label original_fall_through; 116 Label original_fall_through;
118 __ j(NegateCondition(cc), &original_fall_through, NegateHint(hint)); 117 __ j(NegateCondition(cc), &original_fall_through, NegateHint(hint));
119 expected_frame_->MakeMergable(); 118 // Swap the current frame for a copy of it, saving non-frame
120 __ jmp(&label_); 119 // register reference counts and invalidating all non-frame register
121 __ bind(&original_fall_through); 120 // references except the reserved ones on the backward edge.
122 } else { 121 VirtualFrame* original_frame = cgen_->frame();
123 // We negate the condition and emit the code to merge to the expected 122 VirtualFrame* working_frame = new VirtualFrame(original_frame);
124 // frame immediately. 123 RegisterFile non_frame_registers = RegisterAllocator::Reserved();
125 //
126 // TODO(): This should be replaced with a solution that emits the
127 // merge code for forward CFG edges at the appropriate entry to the
128 // target block.
129 Label original_fall_through;
130 __ j(NegateCondition(cc), &original_fall_through, NegateHint(hint));
131 VirtualFrame* working_frame = new VirtualFrame(current_frame);
132
133 // Switch to the working frame for the merge code with only the reserved
134 // registers referenced outside the frame. Explicitly setting
135 // references here is ugly, but temporary.
136 RegisterFile non_frame_registers;
137 non_frame_registers.Use(esi);
138 non_frame_registers.Use(ebp);
139 non_frame_registers.Use(esp);
140 cgen_->SetFrame(working_frame, &non_frame_registers); 124 cgen_->SetFrame(working_frame, &non_frame_registers);
141 125
142 working_frame->MergeTo(expected_frame_); 126 working_frame->MergeTo(expected_frame_);
143 ASSERT(cgen_->HasValidEntryRegisters()); 127 cgen_->DeleteFrame();
144 __ jmp(&label_); 128 __ jmp(&entry_label_);
145 129
146 // Restore the current frame and its associated non-frame registers. 130 // Restore the frame and its associated non-frame registers.
147 cgen_->SetFrame(current_frame, &non_frame_registers); 131 cgen_->SetFrame(original_frame, &non_frame_registers);
148 delete working_frame;
149 __ bind(&original_fall_through); 132 __ bind(&original_fall_through);
133 } else {
134 // Forward branch. A copy of the current frame is added to the end
135 // of the list of frames reaching the target block and a branch to
136 // the merge code is emitted.
137 AddReachingFrame(new VirtualFrame(cgen_->frame()));
138 __ j(cc, &merge_labels_.last(), hint);
150 } 139 }
151 // Postcondition: there is both a current frame and an expected frame at
152 // the label and they match.
153 } 140 }
154 141
155 142
143 #ifdef DEBUG
144 #define DECLARE_ARGCHECK_VARS(name) \
145 Result::Type name##_type = name->type(); \
146 Register name##_reg = name->is_register() ? name->reg() : no_reg
147
148 #define ASSERT_ARGCHECK(name) \
149 ASSERT(name->type() == name##_type); \
150 ASSERT(!name->is_register() || name->reg().is(name##_reg))
151
152 #else
153 #define DECLARE_ARGCHECK_VARS(name) do {} while (false)
154
155 #define ASSERT_ARGCHECK(name) do {} while (false)
156 #endif
157
158
159
156 void JumpTarget::Branch(Condition cc, Result* arg, Hint hint) { 160 void JumpTarget::Branch(Condition cc, Result* arg, Hint hint) {
157 ASSERT(cgen_ != NULL); 161 ASSERT(cgen_ != NULL);
158 ASSERT(cgen_->has_valid_frame()); 162 ASSERT(cgen_->has_valid_frame());
159 163
160 #ifdef DEBUG 164 // We want to check that non-frame registers at the call site stay in
161 // We want register results at the call site to stay in the same registers 165 // the same registers on the fall-through branch.
162 // on the fall-through branch. 166 DECLARE_ARGCHECK_VARS(arg);
163 Result::Type arg_type = arg->type();
164 Register arg_reg = arg->is_register() ? arg->reg() : no_reg;
165 #endif
166 167
167 cgen_->frame()->Push(arg); 168 cgen_->frame()->Push(arg);
168 Branch(cc, hint); 169 Branch(cc, hint);
169 *arg = cgen_->frame()->Pop(); 170 *arg = cgen_->frame()->Pop();
170 171
171 ASSERT(arg->type() == arg_type); 172 ASSERT_ARGCHECK(arg);
172 ASSERT(!arg->is_register() || arg->reg().is(arg_reg));
173 } 173 }
174 174
175 175
176 void JumpTarget::Branch(Condition cc, Result* arg0, Result* arg1, Hint hint) { 176 void JumpTarget::Branch(Condition cc, Result* arg0, Result* arg1, Hint hint) {
177 ASSERT(cgen_ != NULL); 177 ASSERT(cgen_ != NULL);
178 ASSERT(cgen_->frame() != NULL); 178 ASSERT(cgen_->frame() != NULL);
179 179
180 #ifdef DEBUG 180 // We want to check that non-frame registers at the call site stay in
181 // We want register results at the call site to stay in the same registers 181 // the same registers on the fall-through branch.
182 // on the fall-through branch. 182 DECLARE_ARGCHECK_VARS(arg0);
183 Result::Type arg0_type = arg0->type(); 183 DECLARE_ARGCHECK_VARS(arg1);
184 Register arg0_reg = arg0->is_register() ? arg0->reg() : no_reg;
185 Result::Type arg1_type = arg1->type();
186 Register arg1_reg = arg1->is_register() ? arg1->reg() : no_reg;
187 #endif
188 184
189 cgen_->frame()->Push(arg0); 185 cgen_->frame()->Push(arg0);
190 cgen_->frame()->Push(arg1); 186 cgen_->frame()->Push(arg1);
191 Branch(cc, hint); 187 Branch(cc, hint);
192 *arg1 = cgen_->frame()->Pop(); 188 *arg1 = cgen_->frame()->Pop();
193 *arg0 = cgen_->frame()->Pop(); 189 *arg0 = cgen_->frame()->Pop();
194 190
195 ASSERT(arg0->type() == arg0_type); 191 ASSERT_ARGCHECK(arg0);
196 ASSERT(!arg0->is_register() || arg0->reg().is(arg0_reg)); 192 ASSERT_ARGCHECK(arg1);
197 ASSERT(arg1->type() == arg1_type);
198 ASSERT(!arg1->is_register() || arg1->reg().is(arg1_reg));
199 } 193 }
200 194
195 #undef DECLARE_ARGCHECK_VARS
196 #undef ASSERT_ARGCHECK
197
201 198
202 void JumpTarget::Call() { 199 void JumpTarget::Call() {
203 // Precondition: there is a current frame, and there is no expected frame 200 // Call is used to push the address of the catch block on the stack as
204 // at the label. 201 // a return address when compiling try/catch and try/finally. We
202 // fully spill the frame before making the call. The expected frame
203 // at the label (which should be the only one) is the spilled current
204 // frame plus an in-memory return address. The "fall-through" frame
205 // at the return site is the spilled current frame.
205 ASSERT(cgen_ != NULL); 206 ASSERT(cgen_ != NULL);
206 ASSERT(masm_ != NULL); 207 ASSERT(cgen_->has_valid_frame());
207 ASSERT(!cgen_->has_cc()); 208 ASSERT(!cgen_->has_cc());
209 // There are no non-frame references across the call.
210 ASSERT(cgen_->HasValidEntryRegisters());
211 ASSERT(!is_linked());
208 212
209 VirtualFrame* current_frame = cgen_->frame(); 213 cgen_->frame()->SpillAll();
210 ASSERT(current_frame != NULL); 214 VirtualFrame* target_frame = new VirtualFrame(cgen_->frame());
211 ASSERT(expected_frame_ == NULL); 215 target_frame->Adjust(1);
212 ASSERT(cgen_->HasValidEntryRegisters()); 216 AddReachingFrame(target_frame);
213 217 __ call(&merge_labels_.last());
214 expected_frame_ = new VirtualFrame(current_frame);
215 expected_frame_->MakeMergable();
216 // Adjust the expected frame's height to account for the return address
217 // pushed by the call instruction.
218 expected_frame_->Adjust(1);
219 ASSERT(cgen_->HasValidEntryRegisters());
220
221 __ call(&label_);
222 // Postcondition: there is both a current frame and an expected frame at
223 // the label. The current frame is one shorter than the one at the label
224 // (which contains the return address in memory).
225 } 218 }
226 219
227 220
228 void JumpTarget::Bind() { 221 void JumpTarget::Bind() {
229 // Precondition: there is either a current frame or an expected frame at
230 // the label (and possibly both). The label is unbound.
231 ASSERT(cgen_ != NULL); 222 ASSERT(cgen_ != NULL);
232 ASSERT(masm_ != NULL); 223 ASSERT(is_linked() || cgen_->has_valid_frame());
224 ASSERT(!cgen_->has_cc());
225 ASSERT(!is_bound());
233 ASSERT(!cgen_->has_cc()); 226 ASSERT(!cgen_->has_cc());
234 227
235 VirtualFrame* current_frame = cgen_->frame(); 228 if (is_linked()) {
236 ASSERT(current_frame != NULL || expected_frame_ != NULL); 229 // There were forward jumps. A mergable frame is created and all
237 ASSERT(!label_.is_bound()); 230 // the frames reaching the block via forward jumps are merged to it.
231 ASSERT(reaching_frames_.length() == merge_labels_.length());
238 232
239 if (expected_frame_ == NULL) { 233 // Choose a frame as the basis of the expected frame, and make it
234 // mergable. If there is a current frame use it, otherwise use the
235 // first in the list (there will be at least one).
236 int start_index = 0;
237 if (cgen_->has_valid_frame()) {
238 // Live non-frame registers are not allowed at the start of a labeled
239 // basic block.
240 ASSERT(cgen_->HasValidEntryRegisters());
241 } else {
242 RegisterFile reserved_registers = RegisterAllocator::Reserved();
243 cgen_->SetFrame(reaching_frames_[start_index], &reserved_registers);
244 __ bind(&merge_labels_[start_index++]);
245 }
246 cgen_->frame()->MakeMergable();
247 expected_frame_ = new VirtualFrame(cgen_->frame());
248
249 for (int i = start_index; i < reaching_frames_.length(); i++) {
250 cgen_->DeleteFrame();
251 __ jmp(&entry_label_);
252
253 RegisterFile reserved_registers = RegisterAllocator::Reserved();
254 cgen_->SetFrame(reaching_frames_[i], &reserved_registers);
255 __ bind(&merge_labels_[i]);
256
257 cgen_->frame()->MergeTo(expected_frame_);
258 }
259 __ bind(&entry_label_);
260
261 // All but the last reaching virtual frame have been deleted, and
262 // the last one is the current frame.
263 reaching_frames_.Clear();
264 merge_labels_.Clear();
265 } else {
266 // There were no forward jumps. There must be a current frame,
267 // which is made mergable and used as the expected frame.
240 ASSERT(cgen_->HasValidEntryRegisters()); 268 ASSERT(cgen_->HasValidEntryRegisters());
241 // When a label is bound the current frame becomes the expected frame at 269 cgen_->frame()->MakeMergable();
242 // the label. This requires the current frame to be mergable. 270 expected_frame_ = new VirtualFrame(cgen_->frame());
243 current_frame->MakeMergable(); 271 __ bind(&entry_label_);
244 ASSERT(cgen_->HasValidEntryRegisters());
245 expected_frame_ = new VirtualFrame(current_frame);
246 } else if (current_frame == NULL) {
247 // Pick up the frame from the label. No merge code is necessary.
248 // Manually setting the reserved register reference counts is clumsy but
249 // temporary.
250 RegisterFile non_frame_registers;
251 non_frame_registers.Use(esi);
252 non_frame_registers.Use(ebp);
253 non_frame_registers.Use(esp);
254 cgen_->SetFrame(new VirtualFrame(expected_frame_), &non_frame_registers);
255 ASSERT(cgen_->HasValidEntryRegisters());
256 } else {
257 ASSERT(cgen_->HasValidEntryRegisters());
258 current_frame->MergeTo(expected_frame_);
259 ASSERT(cgen_->HasValidEntryRegisters());
260 } 272 }
261
262 __ bind(&label_);
263 // Postcondition: there is both a current frame and an expected frame at
264 // the label and they match. The label is bound.
265 } 273 }
266 274
267 275
268 void JumpTarget::Bind(Result* arg) { 276 void JumpTarget::Bind(Result* arg) {
269 ASSERT(cgen_ != NULL); 277 ASSERT(cgen_ != NULL);
270 278
271 if (cgen_->has_valid_frame()) { 279 if (cgen_->has_valid_frame()) {
272 cgen_->frame()->Push(arg); 280 cgen_->frame()->Push(arg);
273 } 281 }
274 Bind(); 282 Bind();
275 *arg = cgen_->frame()->Pop(); 283 *arg = cgen_->frame()->Pop();
276 } 284 }
277 285
278 286
279 void JumpTarget::Bind(Result* arg0, Result* arg1) { 287 void JumpTarget::Bind(Result* arg0, Result* arg1) {
280 ASSERT(cgen_ != NULL); 288 ASSERT(cgen_ != NULL);
281 289
282 if (cgen_->frame() != NULL) { 290 if (cgen_->has_valid_frame()) {
283 cgen_->frame()->Push(arg0); 291 cgen_->frame()->Push(arg0);
284 cgen_->frame()->Push(arg1); 292 cgen_->frame()->Push(arg1);
285 } 293 }
286 Bind(); 294 Bind();
287 *arg1 = cgen_->frame()->Pop(); 295 *arg1 = cgen_->frame()->Pop();
288 *arg0 = cgen_->frame()->Pop(); 296 *arg0 = cgen_->frame()->Pop();
289 } 297 }
290 298
291 299
300 void JumpTarget::CopyTo(JumpTarget* destination) {
301 ASSERT(destination != NULL);
302 destination->cgen_ = cgen_;
303 destination->masm_ = masm_;
304
305 destination->reaching_frames_.Clear();
306 destination->merge_labels_.Clear();
307 ASSERT(reaching_frames_.length() == merge_labels_.length());
308 for (int i = 0; i < reaching_frames_.length(); i++) {
309 destination->reaching_frames_.Add(reaching_frames_[i]);
310 destination->merge_labels_.Add(merge_labels_[i]);
311 }
312 destination->expected_frame_ = expected_frame_;
313 destination->entry_label_ = entry_label_;
314 }
315
316
292 // ------------------------------------------------------------------------- 317 // -------------------------------------------------------------------------
293 // ShadowTarget implementation. 318 // ShadowTarget implementation.
294 319
295 ShadowTarget::ShadowTarget(JumpTarget* original) { 320 ShadowTarget::ShadowTarget(JumpTarget* shadowed) {
296 ASSERT(original != NULL); 321 ASSERT(shadowed != NULL);
297 original_target_ = original; 322 other_target_ = shadowed;
298 original_pos_ = original->label()->pos_;
299 original_expected_frame_ = original->expected_frame();
300 323
301 // We do not call Unuse() on the orginal jump target, because we do not
302 // want to delete the expected frame.
303 original->label()->pos_ = 0;
304 original->set_expected_frame(NULL);
305 #ifdef DEBUG 324 #ifdef DEBUG
306 is_shadowing_ = true; 325 is_shadowing_ = true;
307 #endif 326 #endif
327 // While shadowing this shadow target saves the state of the original.
328 shadowed->CopyTo(this);
329
330 // Setting the code generator to null prevents the shadow target from
331 // being used until shadowing stops.
332 cgen_ = NULL;
333 masm_ = NULL;
334
335 // The original's state is reset. We do not Unuse it because that
336 // would delete the expected frame and assert that the target is not
337 // linked.
338 shadowed->Reset();
308 } 339 }
309 340
310 341
311 void ShadowTarget::StopShadowing() { 342 void ShadowTarget::StopShadowing() {
312 ASSERT(is_shadowing_); 343 ASSERT(is_shadowing_);
313 ASSERT(is_unused());
314 344
315 set_code_generator(original_target_->code_generator()); 345 // The states of this target, which was shadowed, and the original
316 label_.pos_ = original_target_->label()->pos_; 346 // target, which was shadowing, are swapped.
317 expected_frame_ = original_target_->expected_frame(); 347 JumpTarget temp;
318 348
319 original_target_->label()->pos_ = original_pos_; 349 other_target_->CopyTo(&temp);
320 original_target_->set_expected_frame(original_expected_frame_); 350 CopyTo(other_target_);
351 temp.CopyTo(this);
352 temp.Reset(); // So the destructor does not deallocate virtual frames.
321 353
354 // The shadowing target does not have a valid code generator yet.
355 other_target_->set_code_generator(cgen_);
322 #ifdef DEBUG 356 #ifdef DEBUG
323 is_shadowing_ = false; 357 is_shadowing_ = false;
324 #endif 358 #endif
325 } 359 }
326 360
327 #undef __ 361 #undef __
328 362
329 363
330 } } // namespace v8::internal 364 } } // namespace v8::internal
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698