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

Side by Side Diff: lib/compiler/implementation/ssa/bailout.dart

Issue 10539106: Simplify generated code for trivial bailout methods. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 6 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 | lib/compiler/implementation/ssa/codegen.dart » ('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 (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 class BailoutInfo { 5 class BailoutInfo {
6 int instructionId; 6 int instructionId;
7 int bailoutId; 7 int bailoutId;
8 BailoutInfo(this.instructionId, this.bailoutId); 8 BailoutInfo(this.instructionId, this.bailoutId);
9 } 9 }
10 10
11 /** 11 /**
12 * Keeps track of the execution environment for instructions. An 12 * Keeps track of the execution environment for instructions. An
13 * execution environment contains the SSA instructions that are live. 13 * execution environment contains the SSA instructions that are live.
14 */ 14 */
15 class Environment { 15 class Environment {
16 final Set<HInstruction> lives; 16 final Set<HInstruction> lives;
17 final Set<HBasicBlock> loopMarkers; 17 final Set<HBasicBlock> loopMarkers;
18 Environment() : lives = new Set<HInstruction>(), 18 Environment() : lives = new Set<HInstruction>(),
19 loopMarkers = new Set<HBasicBlock>(); 19 loopMarkers = new Set<HBasicBlock>();
20 Environment.from(Environment other) 20 Environment.from(Environment other)
21 : lives = new Set<HInstruction>.from(other.lives), 21 : lives = new Set<HInstruction>.from(other.lives),
22 loopMarkers = new Set<HBasicBlock>.from(other.loopMarkers); 22 loopMarkers = new Set<HBasicBlock>.from(other.loopMarkers);
23 23
24 void remove(HInstruction instruction) { 24 void remove(HInstruction instruction) {
25 lives.remove(instruction); 25 lives.remove(instruction);
26 } 26 }
27 27
28 void add(HInstruction instruction) { 28 void add(HInstruction instruction) {
29 if (!instruction.isCodeMotionInvariant()) { 29 // If the instruction is a type guard, we add its checked input
30 // instead. This allows sharing the same environment between
31 // different type guards.
32 //
33 // Also, we don't need to add code motion invariant instructions
34 // in the live set (because we generate them at use-site), except
35 // for parameters that are not 'this', which is always passed as
36 // the receiver.
37 if (instruction is HTypeGuard) {
38 add(instruction.checkedInput);
39 } else if (!instruction.isCodeMotionInvariant()
40 || (instruction is HParameterValue && instruction is !HThis)) {
30 lives.add(instruction); 41 lives.add(instruction);
31 } else { 42 } else {
32 for (int i = 0, len = instruction.inputs.length; i < len; i++) { 43 for (int i = 0, len = instruction.inputs.length; i < len; i++) {
33 add(instruction.inputs[i]); 44 add(instruction.inputs[i]);
34 } 45 }
35 } 46 }
36 } 47 }
37 48
38 void addLoopMarker(HBasicBlock block) { 49 void addLoopMarker(HBasicBlock block) {
39 loopMarkers.add(block); 50 loopMarkers.add(block);
40 } 51 }
41 52
42 void removeLoopMarker(HBasicBlock block) { 53 void removeLoopMarker(HBasicBlock block) {
43 loopMarkers.remove(block); 54 loopMarkers.remove(block);
44 } 55 }
45 56
46 void addAll(Environment other) { 57 void addAll(Environment other) {
47 lives.addAll(other.lives); 58 lives.addAll(other.lives);
48 loopMarkers.addAll(other.loopMarkers); 59 loopMarkers.addAll(other.loopMarkers);
49 } 60 }
50 61
51 /**
52 * Stores all live variables in the guard. The guarded instruction will be the
53 * last input in the guard's input list.
54 */
55 void storeInGuard(HTypeGuard guard) {
56 HInstruction guarded = guard.guarded;
57 List<HInstruction> inputs = guard.inputs;
58 assert(inputs.length == 1);
59 inputs.clear();
60 // Remove the guarded from the environment, so that we are sure it is last
61 // when we add it again.
62 remove(guarded);
63 inputs.addAll(lives);
64 inputs.addLast(guarded);
65 add(guarded);
66 for (int i = 0; i < inputs.length - 1; i++) {
67 HInstruction input = inputs[i];
68 input.usedBy.add(guard);
69 }
70 }
71
72 bool isEmpty() => lives.isEmpty() && loopMarkers.isEmpty(); 62 bool isEmpty() => lives.isEmpty() && loopMarkers.isEmpty();
73 } 63 }
74 64
75 65
76 /** 66 /**
77 * Visits the graph in dominator order and inserts TypeGuards in places where 67 * Visits the graph in dominator order and inserts TypeGuards in places where
78 * we consider the guard to be of value. 68 * we consider the guard to be of value.
79 * 69 *
80 * Might modify the [:propagatedType:] fields of the instructions in an 70 * Might modify the [:propagatedType:] fields of the instructions in an
81 * inconsistent way. No further analysis should rely on them. 71 * inconsistent way. No further analysis should rely on them.
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
177 if (speculativeType == computedType) return false; 167 if (speculativeType == computedType) return false;
178 // If a bailout check is more expensive than doing the actual operation 168 // If a bailout check is more expensive than doing the actual operation
179 // don't do it either. 169 // don't do it either.
180 return typeGuardWouldBeValuable(instruction, speculativeType); 170 return typeGuardWouldBeValuable(instruction, speculativeType);
181 } 171 }
182 172
183 void visitInstruction(HInstruction instruction) { 173 void visitInstruction(HInstruction instruction) {
184 HType speculativeType = instruction.propagatedType; 174 HType speculativeType = instruction.propagatedType;
185 if (shouldInsertTypeGuard(instruction)) { 175 if (shouldInsertTypeGuard(instruction)) {
186 List<HInstruction> inputs = <HInstruction>[instruction]; 176 List<HInstruction> inputs = <HInstruction>[instruction];
187 HTypeGuard guard = new HTypeGuard(speculativeType, stateId++, inputs); 177 HInstruction insertionPoint;
178 if (instruction is HPhi) {
179 insertionPoint = instruction.block.first;
180 } else if (instruction is HParameterValue) {
181 // We insert the type guard at the end of the entry block
182 // because if a parameter is live, it must be kept in the live
183 // environment. Not doing so would mean we could visit a
184 // parameter and remove it from the environment before
185 // visiting a type guard.
186 insertionPoint = instruction.block.last;
187 } else {
188 insertionPoint = instruction.next;
189 }
190 // If the previous instruction is also a type guard, then both
191 // guards have the same environment, and can therefore share the
192 // same state id.
193 int state;
194 if (insertionPoint.previous is HTypeGuard) {
195 HTypeGuard other = insertionPoint.previous;
196 state = other.state;
197 } else {
198 state = stateId++;
199 }
200 HTypeGuard guard = new HTypeGuard(speculativeType, state, inputs);
188 guard.propagatedType = speculativeType; 201 guard.propagatedType = speculativeType;
189 work.guards.add(guard); 202 work.guards.add(guard);
190 instruction.block.rewrite(instruction, guard); 203 instruction.block.rewrite(instruction, guard);
191 HInstruction insertionPoint = (instruction is HPhi)
192 ? instruction.block.first
193 : instruction.next;
194 insertionPoint.block.addBefore(insertionPoint, guard); 204 insertionPoint.block.addBefore(insertionPoint, guard);
195 } 205 }
196 } 206 }
197 } 207 }
198 208
199 /** 209 /**
200 * Computes the environment for each SSA instruction: visits the graph 210 * Computes the environment for each SSA instruction: visits the graph
201 * in post-dominator order. Removes an instruction from the environment 211 * in post-dominator order. Removes an instruction from the environment
202 * and adds its inputs to the environment at the instruction's 212 * and adds its inputs to the environment at the instruction's
203 * definition. 213 * definition.
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
303 } 313 }
304 314
305 void visitInstruction(HInstruction instruction) { 315 void visitInstruction(HInstruction instruction) {
306 environment.remove(instruction); 316 environment.remove(instruction);
307 for (int i = 0, len = instruction.inputs.length; i < len; i++) { 317 for (int i = 0, len = instruction.inputs.length; i < len; i++) {
308 environment.add(instruction.inputs[i]); 318 environment.add(instruction.inputs[i]);
309 } 319 }
310 } 320 }
311 321
312 void insertCapturedEnvironments() { 322 void insertCapturedEnvironments() {
323 Map<int, HTypeGuard> seenGuardStates = new Map<int, HTypeGuard>();
313 capturedEnvironments.forEach((HTypeGuard guard, Environment env) { 324 capturedEnvironments.forEach((HTypeGuard guard, Environment env) {
314 env.storeInGuard(guard); 325 storeInGuard(guard, env.lives, seenGuardStates);
315 }); 326 });
316 } 327 }
328
329 /**
330 * Stores all live variables in the guard.
331 */
332 void storeInGuard(HTypeGuard guard,
333 Set<HInstruction> lives,
334 Map<int, HTypeGuard> seenGuardStates) {
335 HInstruction guarded = guard.guarded;
336 List<HInstruction> inputs = guard.inputs;
337 assert(inputs.length == 1);
338 inputs.clear();
339 HTypeGuard other = seenGuardStates[guard.state];
340 if (other !== null) {
341 // The guards are sharing the same state. Also share the same
342 // environment, in the same order.
343 inputs.addAll(other.inputs);
344 assert(inputs.length == lives.length);
345 } else {
346 seenGuardStates[guard.state] = guard;
347 inputs.addAll(lives);
348 }
349
350 for (int i = 0; i < inputs.length; i++) {
351 HInstruction input = inputs[i];
352 if (input == guarded) {
353 guard.checkedInputIndex = i;
354 // No need to update [input.usedBy], the guard is already
355 // there.
356 } else {
357 input.usedBy.add(guard);
358 }
359 }
360 }
317 } 361 }
318 362
319 /** 363 /**
320 * Propagates bailout information to blocks that need it. This visitor 364 * Propagates bailout information to blocks that need it. This visitor
321 * is run before codegen, to know which blocks have to deal with 365 * is run before codegen, to know which blocks have to deal with
322 * bailouts. 366 * bailouts.
323 */ 367 */
324 class SsaBailoutPropagator extends HBaseVisitor { 368 class SsaBailoutPropagator extends HBaseVisitor {
325 final Compiler compiler; 369 final Compiler compiler;
326 final List<HBasicBlock> blocks; 370 final List<HBasicBlock> blocks;
327 final List<HLabeledBlockInformation> labeledBlockInformations; 371 final List<HLabeledBlockInformation> labeledBlockInformations;
372 final Set<HInstruction> generateAtUseSite;
328 SubGraph subGraph; 373 SubGraph subGraph;
329 374
330 SsaBailoutPropagator(Compiler this.compiler) 375 /**
376 * If set to true, the graph has either multiple bailouts in
377 * different places, or a bailout inside an if or a loop. For such a
378 * graph, the code generator will emit a generic switch.
379 */
380 bool hasComplexTypeGuards = false;
381
382 /**
383 * The first type guard in the graph.
384 */
385 HTypeGuard firstTypeGuard;
386
387 /**
388 * If set, it is the first block in the graph where we generate
389 * code. Blocks before this one are dead code in the bailout
390 * version.
391 */
392
393 SsaBailoutPropagator(this.compiler,
kasperl 2012/06/13 07:37:05 Arguments fit on one line.
ngeoffray 2012/06/13 07:41:38 Done.
394 this.generateAtUseSite)
331 : blocks = <HBasicBlock>[], 395 : blocks = <HBasicBlock>[],
332 labeledBlockInformations = <HLabeledBlockInformation>[]; 396 labeledBlockInformations = <HLabeledBlockInformation>[];
333 397
334 void visitGraph(HGraph graph) { 398 void visitGraph(HGraph graph) {
335 subGraph = new SubGraph(graph.entry, graph.exit); 399 subGraph = new SubGraph(graph.entry, graph.exit);
336 blocks.addLast(graph.entry);
337 visitBasicBlock(graph.entry); 400 visitBasicBlock(graph.entry);
338 blocks.removeLast();
339 if (!blocks.isEmpty()) { 401 if (!blocks.isEmpty()) {
340 compiler.internalError('Bailout propagation', 402 compiler.internalError('Bailout propagation',
341 node: compiler.currentElement.parseNode(compiler)); 403 node: compiler.currentElement.parseNode(compiler));
342 } 404 }
343 } 405 }
344 406
345 void visitBasicBlock(HBasicBlock block) { 407 void visitBasicBlock(HBasicBlock block) {
346 // Abort traversal if we are leaving the currently active sub-graph. 408 // Abort traversal if we are leaving the currently active sub-graph.
347 if (!subGraph.contains(block)) return; 409 if (!subGraph.contains(block)) return;
348 410
349 if (block.isLoopHeader()) { 411 if (block.isLoopHeader()) {
350 blocks.addLast(block); 412 blocks.addLast(block);
351 } else if (block.isLabeledBlock() && blocks.last() !== block) { 413 } else if (block.isLabeledBlock()
414 && (blocks.isEmpty() || blocks.last() !== block)) {
352 HLabeledBlockInformation info = block.blockFlow.body; 415 HLabeledBlockInformation info = block.blockFlow.body;
353 visitStatements(info.body); 416 visitStatements(info.body);
354 return; 417 return;
355 } 418 }
356 419
357 HInstruction instruction = block.first; 420 HInstruction instruction = block.first;
358 while (instruction != null) { 421 while (instruction != null) {
359 instruction.accept(this); 422 instruction.accept(this);
360 instruction = instruction.next; 423 instruction = instruction.next;
361 } 424 }
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
439 visitBasicBlock(branchBlock.successors[1]); 502 visitBasicBlock(branchBlock.successors[1]);
440 // With labeled breaks we can have more dominated blocks. 503 // With labeled breaks we can have more dominated blocks.
441 if (dominated.length >= 3) { 504 if (dominated.length >= 3) {
442 for (int i = 2; i < dominated.length; i++) { 505 for (int i = 2; i < dominated.length; i++) {
443 visitBasicBlock(dominated[i]); 506 visitBasicBlock(dominated[i]);
444 } 507 }
445 } 508 }
446 } 509 }
447 510
448 visitTypeGuard(HTypeGuard guard) { 511 visitTypeGuard(HTypeGuard guard) {
449 blocks.forEach((HBasicBlock block) { 512 if (blocks.isEmpty()) {
450 block.guards.add(guard); 513 if (firstTypeGuard === null || firstTypeGuard.state === guard.state) {
451 }); 514 firstTypeGuard = guard;
515 } else {
516 hasComplexTypeGuards = true;
517 }
518 } else {
519 hasComplexTypeGuards = true;
520 blocks.forEach((HBasicBlock block) {
521 block.guards.add(guard);
522 });
523 }
452 } 524 }
453 } 525 }
OLDNEW
« no previous file with comments | « no previous file | lib/compiler/implementation/ssa/codegen.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698