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

Side by Side Diff: frog/leg/ssa/codegen.dart

Issue 9863037: Generate prettier loops. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Address review comments. Created 8 years, 8 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 | « frog/leg/ssa/builder.dart ('k') | frog/leg/ssa/nodes.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 SsaCodeGeneratorTask extends CompilerTask { 5 class SsaCodeGeneratorTask extends CompilerTask {
6 SsaCodeGeneratorTask(Compiler compiler) : super(compiler); 6 SsaCodeGeneratorTask(Compiler compiler) : super(compiler);
7 String get name() => 'SSA code generator'; 7 String get name() => 'SSA code generator';
8 8
9 9
10 String generateMethod(WorkItem work, HGraph graph) { 10 String generateMethod(WorkItem work, HGraph graph) {
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
54 ? element.name.slowToString() 54 ? element.name.slowToString()
55 : JsNames.getValid('${element.name.slowToString()}'); 55 : JsNames.getValid('${element.name.slowToString()}');
56 }); 56 });
57 return parameterNames; 57 return parameterNames;
58 } 58 }
59 } 59 }
60 60
61 typedef void ElementAction(Element element); 61 typedef void ElementAction(Element element);
62 62
63 class SsaCodeGenerator implements HVisitor { 63 class SsaCodeGenerator implements HVisitor {
64 /**
65 * Current state for generating simple (non-local-control) code.
66 * It is generated as either statements (indented and ';'-terminated),
67 * expressions (comma separated) or declarations (also comma separated,
68 * but expected to be preceeded by a 'var' so it declares its variables);
69 */
70 static final int STATE_STATEMENT = 0;
71 static final int STATE_FIRST_EXPRESSION = 1;
72 static final int STATE_FIRST_DECLARATION = 2;
73 static final int STATE_EXPRESSION = 3;
74 static final int STATE_DECLARATION = 4;
75
64 final Compiler compiler; 76 final Compiler compiler;
65 final WorkItem work; 77 final WorkItem work;
66 final StringBuffer buffer; 78 final StringBuffer buffer;
67 final String parameters; 79 final String parameters;
68 80
69 final Map<Element, String> parameterNames; 81 final Map<Element, String> parameterNames;
70 final Map<int, String> names; 82 final Map<int, String> names;
71 final Map<String, int> prefixes; 83 final Map<String, int> prefixes;
72 final Set<HInstruction> generateAtUseSite; 84 final Set<HInstruction> generateAtUseSite;
73 final Map<HPhi, String> logicalOperations; 85 final Map<HPhi, String> logicalOperations;
74 final Map<Element, ElementAction> breakAction; 86 final Map<Element, ElementAction> breakAction;
75 final Map<Element, ElementAction> continueAction; 87 final Map<Element, ElementAction> continueAction;
76 88
77 Element equalsNullElement; 89 Element equalsNullElement;
78 int indent = 0; 90 int indent = 0;
79 int expectedPrecedence = JSPrecedence.STATEMENT_PRECEDENCE; 91 int expectedPrecedence = JSPrecedence.STATEMENT_PRECEDENCE;
80 HGraph currentGraph; 92 HGraph currentGraph;
93 /**
94 * Whether the code-generation should try to generate an expression
95 * instead of a sequence of statements.
96 */
97 int generationState = STATE_STATEMENT;
98 /**
99 * While generating expressions, we can't insert variable declarations.
100 * Instead we declare them at the end of the function
101 */
102 Link<String> delayedVarDecl = const EmptyLink<String>();
81 HBasicBlock currentBlock; 103 HBasicBlock currentBlock;
82 104
83 // Records a block-information that is being handled specially. 105 // Records a block-information that is being handled specially.
84 // Used to break bad recursion. 106 // Used to break bad recursion.
85 HLabeledBlockInformation currentBlockInformation; 107 HBlockInformation currentBlockInformation;
86 // The subgraph is used to delimit traversal for some constructions, e.g., 108 // The subgraph is used to delimit traversal for some constructions, e.g.,
87 // if branches. 109 // if branches.
88 SubGraph subGraph; 110 SubGraph subGraph;
89 111
90 LibraryElement get currentLibrary() => work.element.getLibrary(); 112 LibraryElement get currentLibrary() => work.element.getLibrary();
91 113
92 bool isGenerateAtUseSite(HInstruction instruction) { 114 bool isGenerateAtUseSite(HInstruction instruction) {
93 return generateAtUseSite.contains(instruction); 115 return generateAtUseSite.contains(instruction);
94 } 116 }
95 117
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
147 logicalOperations).visitGraph(graph); 169 logicalOperations).visitGraph(graph);
148 } 170 }
149 171
150 visitGraph(HGraph graph) { 172 visitGraph(HGraph graph) {
151 preGenerateMethod(graph); 173 preGenerateMethod(graph);
152 currentGraph = graph; 174 currentGraph = graph;
153 indent++; // We are already inside a function. 175 indent++; // We are already inside a function.
154 subGraph = new SubGraph(graph.entry, graph.exit); 176 subGraph = new SubGraph(graph.entry, graph.exit);
155 beginGraph(graph); 177 beginGraph(graph);
156 visitBasicBlock(graph.entry); 178 visitBasicBlock(graph.entry);
179 if (!delayedVarDecl.isEmpty()) {
180 addIndentation();
181 buffer.add("var ");
182 while (true) {
183 buffer.add(delayedVarDecl.head);
184 delayedVarDecl = delayedVarDecl.tail;
185 if (delayedVarDecl.isEmpty()) break;
186 buffer.add(", ");
187 }
188 buffer.add(";\n");
189 }
157 endGraph(graph); 190 endGraph(graph);
158 } 191 }
159 192
160 void visitSubGraph(SubGraph newSubGraph) { 193 void visitSubGraph(SubGraph newSubGraph) {
161 SubGraph oldSubGraph = subGraph; 194 SubGraph oldSubGraph = subGraph;
162 subGraph = newSubGraph; 195 subGraph = newSubGraph;
163 visitBasicBlock(subGraph.start); 196 visitBasicBlock(subGraph.start);
164 subGraph = oldSubGraph; 197 subGraph = oldSubGraph;
165 } 198 }
166 199
200 bool isExpression(SubGraph limits) {
201 HBasicBlock basicBlock = limits.start;
202 do {
203 HInstruction current = basicBlock.first;
204 while (current != basicBlock.last) {
205 // E.g, type guards.
206 if (current.isControlFlow()) {
207 return false;
208 }
209 current = current.next;
210 }
211 if (current is HGoto) {
212 basicBlock = basicBlock.successors[0];
213 } else if (current is HConditionalBranch) {
214 if (generateAtUseSite.contains(current)) {
215 // Short-circuit logical operator trickery.
216 // Check the second half, which will continue into the join.
217 // (The first half is [inputs[0]], the second half is [successors[0]],
218 // and [successors[1]] is the join-block).
219 basicBlock = basicBlock.successors[0];
220 } else {
221 // We allow an expression to end on an HIf (a condition expression).
222 return basicBlock === limits.end;
223 }
224 } else {
225 // Expression-incompatible control flow.
226 return false;
227 }
228 } while (limits.contains(basicBlock));
229 return true;
230 }
231
232 bool isCondition(SubGraph limits) {
233 return isExpression(limits) && (limits.end.last is HConditionalBranch);
234 }
235
236 void visitExpressionGraph(SubGraph subGraph) {
237 int oldState = generationState;
238 generationState = STATE_FIRST_EXPRESSION;
239 visitSubGraph(subGraph);
240 generationState = oldState;
241 }
242
243 void visitConditionGraph(SubGraph subGraph) {
244 visitExpressionGraph(subGraph);
245 }
246
167 String temporary(HInstruction instruction) { 247 String temporary(HInstruction instruction) {
168 int id = instruction.id; 248 int id = instruction.id;
169 String name = names[id]; 249 String name = names[id];
170 if (name !== null) return name; 250 if (name !== null) return name;
171 251
172 if (instruction is HPhi) { 252 if (instruction is HPhi) {
173 HPhi phi = instruction; 253 HPhi phi = instruction;
174 Element element = phi.element; 254 Element element = phi.element;
175 if (element != null && element.kind == ElementKind.PARAMETER) { 255 if (element != null && element.kind == ElementKind.PARAMETER) {
176 name = parameterNames[element]; 256 name = parameterNames[element];
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
213 void visitArguments(List<HInstruction> inputs) { 293 void visitArguments(List<HInstruction> inputs) {
214 assert(inputs.length >= HInvoke.ARGUMENTS_OFFSET); 294 assert(inputs.length >= HInvoke.ARGUMENTS_OFFSET);
215 buffer.add('('); 295 buffer.add('(');
216 for (int i = HInvoke.ARGUMENTS_OFFSET; i < inputs.length; i++) { 296 for (int i = HInvoke.ARGUMENTS_OFFSET; i < inputs.length; i++) {
217 if (i != HInvoke.ARGUMENTS_OFFSET) buffer.add(', '); 297 if (i != HInvoke.ARGUMENTS_OFFSET) buffer.add(', ');
218 use(inputs[i], JSPrecedence.ASSIGNMENT_PRECEDENCE); 298 use(inputs[i], JSPrecedence.ASSIGNMENT_PRECEDENCE);
219 } 299 }
220 buffer.add(')'); 300 buffer.add(')');
221 } 301 }
222 302
303
304
305 /**
306 * Whether we are currently generating expressions instead of statements.
307 * This includes declarations, which are generated as expressions.
308 */
309 bool isGeneratingExpression() {
310 return generationState != STATE_STATEMENT;
311 }
312
313 /**
314 * Whether we are generating a declaration.
315 */
316 bool isGeneratingDeclaration() {
317 return (generationState == STATE_DECLARATION ||
318 generationState == STATE_FIRST_DECLARATION);
319 }
320
321 /**
322 * Called before writing an expression.
323 * Ensures that expressions are comma spearated.
324 */
325 void addExpressionSeparator() {
326 if (generationState == STATE_FIRST_DECLARATION) {
327 generationState = STATE_DECLARATION;
328 } else if (generationState == STATE_FIRST_EXPRESSION) {
329 generationState = STATE_EXPRESSION;
330 } else {
331 buffer.add(", ");
332 }
333 }
334
335 void declareVariable(String variableName) {
336 if (isGeneratingExpression()) {
337 buffer.add(variableName);
338 if (!isGeneratingDeclaration()) {
339 delayedVarDecl = delayedVarDecl.prepend(variableName);
340 }
341 } else {
342 buffer.add("var ");
343 buffer.add(variableName);
344 }
345 }
346
223 void define(HInstruction instruction) { 347 void define(HInstruction instruction) {
224 buffer.add('var ${temporary(instruction)} = '); 348 String name = temporary(instruction);
349 declareVariable(name);
350 buffer.add(" = ");
225 visit(instruction, JSPrecedence.ASSIGNMENT_PRECEDENCE); 351 visit(instruction, JSPrecedence.ASSIGNMENT_PRECEDENCE);
226 } 352 }
227 353
228 void use(HInstruction argument, int expectedPrecedence) { 354 void use(HInstruction argument, int expectedPrecedence) {
229 if (isGenerateAtUseSite(argument)) { 355 if (isGenerateAtUseSite(argument)) {
230 visit(argument, expectedPrecedence); 356 visit(argument, expectedPrecedence);
231 } else if (argument is HIntegerCheck) { 357 } else if (argument is HIntegerCheck) {
232 HIntegerCheck instruction = argument; 358 HIntegerCheck instruction = argument;
233 use(instruction.value, expectedPrecedence); 359 use(instruction.value, expectedPrecedence);
234 } else if (argument is HBoundsCheck) { 360 } else if (argument is HBoundsCheck) {
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
336 void emitLogicalOperation(HPhi node, String operation) { 462 void emitLogicalOperation(HPhi node, String operation) {
337 JSBinaryOperatorPrecedence operatorPrecedence = 463 JSBinaryOperatorPrecedence operatorPrecedence =
338 JSPrecedence.binary[operation]; 464 JSPrecedence.binary[operation];
339 beginExpression(operatorPrecedence.precedence); 465 beginExpression(operatorPrecedence.precedence);
340 use(node.inputs[0], operatorPrecedence.left); 466 use(node.inputs[0], operatorPrecedence.left);
341 buffer.add(" $operation "); 467 buffer.add(" $operation ");
342 use(node.inputs[1], operatorPrecedence.right); 468 use(node.inputs[1], operatorPrecedence.right);
343 endExpression(operatorPrecedence.precedence); 469 endExpression(operatorPrecedence.precedence);
344 } 470 }
345 471
346 visitBasicBlock(HBasicBlock node) { 472 // Wraps a loop body in a block to make continues have a target to break
473 // to (if necessary).
474 void wrapLoopBodyForContinue(HLoopInformation info) {
475 TargetElement target = info.target;
476 if (target !== null && target.isContinueTarget) {
477 addIndentation();
478 for (LabelElement label in info.labels) {
479 if (label.isContinueTarget) {
480 writeContinueLabel(label);
481 buffer.add(":");
482 continueAction[label] = continueAsBreak;
483 }
484 }
485 addImplicitContinueLabel();
486 buffer.add(":{\n");
487 continueAction[info.target] = implicitContinueAsBreak;
488 indent++;
489 visitSubGraph(info.body);
490 indent--;
491 addIndentation();
492 buffer.add("}\n");
493 continueAction.remove(info.target);
494 for (LabelElement label in info.labels) {
495 if (label.isContinueTarget) {
496 continueAction.remove(label);
497 }
498 }
499 } else {
500 // Loop body contains no continues, so we don't need a break target.
501 visitSubGraph(info.body);
502 }
503 }
504
505 bool handleLoop(HBasicBlock node) {
506 bool success = false;
507 assert(node.isLoopHeader());
508 HLoopInformation info = node.loopInformation;
509 SubExpression condition = info.condition;
510 if (isCondition(condition)) {
511 switch (info.type) {
512 case HLoopInformation.WHILE_LOOP:
513 case HLoopInformation.FOR_IN_LOOP: {
514 addIndentation();
515 for (LabelElement label in info.labels) {
516 writeLabel(label);
517 buffer.add(":");
518 }
519 bool inlineUpdates =
520 info.updates !== null && isExpression(info.updates);
521 if (inlineUpdates) {
522 buffer.add("for (; ");
523 visitConditionGraph(condition);
524 buffer.add("; ");
525 visitExpressionGraph(info.updates);
526 buffer.add(") {\n");
527 indent++;
528 // The body might be labeled. Ignore this when recursing on the
529 // subgraph.
530 // TODO(lrn): Remove this extra labeling when handling all loops
531 // using subgraphs.
532 HBlockInformation oldInfo = currentBlockInformation;
533 currentBlockInformation = info.body.start.labeledBlockInformation;
534 visitSubGraph(info.body);
535 currentBlockInformation = oldInfo;
536
537 indent--;
538 } else {
539 buffer.add("while (");
540 visitConditionGraph(condition);
541 buffer.add(") {\n");
542 indent++;
543 wrapLoopBodyForContinue(info);
544 if (info.updates !== null) visitSubGraph(info.updates);
545 indent--;
546 }
547 addIndentation();
548 buffer.add("}\n");
549 success = true;
550 break;
551 }
552 case HLoopInformation.FOR_LOOP: {
553 // TODO(lrn): Find a way to put initialization into the for.
554 // It's currently handled before we reach the [HLoopInformation].
555 addIndentation();
556 for (LabelElement label in info.labels) {
557 if (label.isTarget) {
558 writeLabel(label);
559 buffer.add(":");
560 }
561 }
562 buffer.add("for(;");
563 visitConditionGraph(info.condition);
564 buffer.add(";");
565 if (isExpression(info.updates)) {
566 visitExpressionGraph(info.updates);
567 buffer.add(") {\n");
568 indent++;
569
570 HBlockInformation oldInfo = currentBlockInformation;
571 currentBlockInformation = info.body.start.labeledBlockInformation;
572 visitSubGraph(info.body);
573 currentBlockInformation = oldInfo;
574
575 indent--;
576 addIndentation();
577 buffer.add("}\n");
578 } else {
579 buffer.add(") {\n");
580 indent++;
581 wrapLoopBodyForContinue(info);
582 visitSubGraph(info.updates);
583 indent--;
584 buffer.add("}\n");
585 }
586 success = true;
587 break;
588 }
589 case HLoopInformation.DO_WHILE_LOOP:
590 // Currently unhandled.
591 default:
592 }
593 }
594 return success;
595 }
596
597 void visitBasicBlock(HBasicBlock node) {
347 // Abort traversal if we are leaving the currently active sub-graph. 598 // Abort traversal if we are leaving the currently active sub-graph.
348 if (!subGraph.contains(node)) return; 599 if (!subGraph.contains(node)) return;
349 600
350 // If this node has special behavior attached, handle it. 601 // If this node has special behavior attached, handle it.
351 // If we reach here again while handling the attached information, 602 // If we reach here again while handling the attached information,
352 // e.g., because we call visitSubGraph on a subgraph starting here, 603 // e.g., because we call visitSubGraph on a subgraph starting here,
353 // don't handle it again. 604 // don't handle it again.
354 if (node.hasLabeledBlockInformation() && 605 if (node.hasLabeledBlockInformation() &&
355 node.labeledBlockInformation !== currentBlockInformation) { 606 node.labeledBlockInformation !== currentBlockInformation) {
356 HLabeledBlockInformation oldBlockInformation = currentBlockInformation; 607 HBlockInformation oldBlockInformation = currentBlockInformation;
357 currentBlockInformation = node.labeledBlockInformation; 608 currentBlockInformation = node.labeledBlockInformation;
358 handleLabeledBlock(currentBlockInformation); 609 handleLabeledBlock(currentBlockInformation);
359 currentBlockInformation = oldBlockInformation; 610 currentBlockInformation = oldBlockInformation;
360 return; 611 return;
361 } 612 }
362 613
363 currentBlock = node; 614 if (node.isLoopHeader() &&
364 615 node.loopInformation !== currentBlockInformation) {
365 if (node.isLoopHeader()) { 616 HBlockInformation oldBlockInformation = currentBlockInformation;
366 // While loop will be closed by the conditional loop-branch. 617 currentBlockInformation = node.loopInformation;
367 // TODO(floitsch): HACK HACK HACK. 618 bool prettyLoop = handleLoop(node);
619 currentBlockInformation = oldBlockInformation;
620 if (prettyLoop) {
621 visitBasicBlock(node.loopInformation.joinBlock);
622 return;
623 }
368 beginLoop(node); 624 beginLoop(node);
369 } 625 }
370 626
627 iterateBasicBlock(node);
628 }
629
630 void iterateBasicBlock(HBasicBlock node) {
631 currentBlock = node;
371 HInstruction instruction = node.first; 632 HInstruction instruction = node.first;
372 while (instruction != null) { 633 while (instruction != null) {
373 if (instruction === node.last) { 634 if (instruction === node.last) {
374 for (HBasicBlock successor in node.successors) { 635 for (HBasicBlock successor in node.successors) {
375 int index = successor.predecessors.indexOf(node); 636 int index = successor.predecessors.indexOf(node);
376 successor.forEachPhi((HPhi phi) { 637 successor.forEachPhi((HPhi phi) {
377 bool isLogicalOperation = logicalOperations.containsKey(phi); 638 bool isLogicalOperation = logicalOperations.containsKey(phi);
378 // In case the phi is being generated by another 639 // In case the phi is being generated by another
379 // instruction. 640 // instruction.
380 if (isLogicalOperation && isGenerateAtUseSite(phi)) return; 641 if (isLogicalOperation && isGenerateAtUseSite(phi)) return;
381 addIndentation(); 642 if (isGeneratingExpression()) {
382 if (!temporaryExists(phi)) buffer.add('var '); 643 addExpressionSeparator();
383 buffer.add('${temporary(phi)} = '); 644 } else {
645 addIndentation();
646 }
647 if (!temporaryExists(phi)) {
648 declareVariable(temporary(phi));
649 } else {
650 buffer.add(temporary(phi));
651 }
652 buffer.add(" = ");
384 if (isLogicalOperation) { 653 if (isLogicalOperation) {
385 emitLogicalOperation(phi, logicalOperations[phi]); 654 emitLogicalOperation(phi, logicalOperations[phi]);
386 } else { 655 } else {
387 use(phi.inputs[index], JSPrecedence.ASSIGNMENT_PRECEDENCE); 656 use(phi.inputs[index], JSPrecedence.ASSIGNMENT_PRECEDENCE);
388 } 657 }
389 buffer.add(';\n'); 658 if (!isGeneratingExpression()) {
659 buffer.add(';\n');
660 }
390 }); 661 });
391 } 662 }
392 } 663 }
393 664
394 if (instruction is HGoto || instruction is HExit || instruction is HTry) { 665 if (instruction is HGoto || instruction is HExit || instruction is HTry) {
395 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE); 666 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE);
396 return; 667 return;
397 } else if (!isGenerateAtUseSite(instruction)) { 668 } else if (!isGenerateAtUseSite(instruction)) {
398 if (instruction is !HIf && instruction is !HTypeGuard) { 669 if (instruction is !HIf && instruction is !HTypeGuard &&
670 !isGeneratingExpression()) {
399 addIndentation(); 671 addIndentation();
400 } 672 }
673 if (isGeneratingExpression()) {
674 addExpressionSeparator();
675 }
401 if (instruction.usedBy.isEmpty() 676 if (instruction.usedBy.isEmpty()
402 || instruction is HTypeGuard 677 || instruction is HTypeGuard
403 || instruction is HCheck) { 678 || instruction is HCheck) {
404 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE); 679 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE);
405 } else { 680 } else {
406 define(instruction); 681 define(instruction);
407 } 682 }
408 // Control flow instructions know how to handle ';'. 683 // Control flow instructions know how to handle ';'.
409 if (instruction is !HControlFlow && instruction is !HTypeGuard) { 684 if (instruction is !HControlFlow && instruction is !HTypeGuard &&
685 !isGeneratingExpression()) {
410 buffer.add(';\n'); 686 buffer.add(';\n');
411 } 687 }
412 } else if (instruction is HIf) { 688 } else if (instruction is HIf) {
413 HIf hif = instruction; 689 HIf hif = instruction;
414 // The "if" is implementing part of a logical expression. 690 // The "if" is implementing part of a logical expression.
415 // Skip directly forward to to its latest successor, since everything 691 // Skip directly forward to to its latest successor, since everything
416 // in-between must also be generateAtUseSite. 692 // in-between must also be generateAtUseSite.
417 assert(hif.trueBranch.id < hif.falseBranch.id); 693 assert(hif.trueBranch.id < hif.falseBranch.id);
418 visitBasicBlock(hif.falseBranch); 694 visitBasicBlock(hif.falseBranch);
419 return; 695 return;
(...skipping 340 matching lines...) Expand 10 before | Expand all | Expand 10 after
760 use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE); 1036 use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE);
761 buffer.add('.'); 1037 buffer.add('.');
762 buffer.add(name); 1038 buffer.add(name);
763 beginExpression(JSPrecedence.MEMBER_PRECEDENCE); 1039 beginExpression(JSPrecedence.MEMBER_PRECEDENCE);
764 } else { 1040 } else {
765 buffer.add(name); 1041 buffer.add(name);
766 } 1042 }
767 } 1043 }
768 1044
769 visitFieldSet(HFieldSet node) { 1045 visitFieldSet(HFieldSet node) {
1046 // This method may introduce variable declarations in the JS code.
1047 // If we are generating an expression, those variable declarations
1048 // must be delayed until later.
1049 bool delayDeclaration = false;
1050 String name = JsNames.getValid(node.element.name.slowToString());
770 if (node.receiver !== null) { 1051 if (node.receiver !== null) {
771 beginExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE); 1052 beginExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE);
772 use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE); 1053 use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE);
773 buffer.add('.'); 1054 buffer.add('.');
1055 buffer.add(name);
774 } else { 1056 } else {
775 // TODO(ngeoffray): Remove the 'var' once we don't globally box 1057 // TODO(ngeoffray): Remove the 'var' once we don't globally box
776 // variables used in a try/catch. 1058 // variables used in a try/catch.
777 buffer.add('var '); 1059 declareVariable(name);
778 } 1060 }
779 String name = JsNames.getValid(node.element.name.slowToString()); 1061 if (delayDeclaration) delayedVarDecl = delayedVarDecl.prepend(name);
780 buffer.add(name);
781 buffer.add(' = '); 1062 buffer.add(' = ');
782 use(node.value, JSPrecedence.ASSIGNMENT_PRECEDENCE); 1063 use(node.value, JSPrecedence.ASSIGNMENT_PRECEDENCE);
783 if (node.receiver !== null) { 1064 if (node.receiver !== null) {
784 endExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE); 1065 endExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE);
785 } 1066 }
786 } 1067 }
787 1068
788 visitForeign(HForeign node) { 1069 visitForeign(HForeign node) {
789 String code = node.code.slowToString(); 1070 String code = node.code.slowToString();
790 List<HInstruction> inputs = node.inputs; 1071 List<HInstruction> inputs = node.inputs;
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
834 node.constant.writeJsCode(buffer, handler); 1115 node.constant.writeJsCode(buffer, handler);
835 } 1116 }
836 } else { 1117 } else {
837 buffer.add(compiler.namer.CURRENT_ISOLATE); 1118 buffer.add(compiler.namer.CURRENT_ISOLATE);
838 buffer.add("."); 1119 buffer.add(".");
839 buffer.add(name); 1120 buffer.add(name);
840 } 1121 }
841 } 1122 }
842 1123
843 visitLoopBranch(HLoopBranch node) { 1124 visitLoopBranch(HLoopBranch node) {
1125 if (subGraph !== null && node.block == subGraph.end) {
1126 // We are generating code for a loop condition.
1127 // If doing this as part of a SubGraph traversal, the
1128 // calling code will handle the control flow logic.
1129
1130 // Currently we only traverse condition subgraphs as expressions.
1131 assert(isGeneratingExpression());
1132 use(node.inputs[0], JSPrecedence.EXPRESSION_PRECEDENCE);
1133 return;
1134 }
844 HBasicBlock branchBlock = currentBlock; 1135 HBasicBlock branchBlock = currentBlock;
845 handleLoopCondition(node); 1136 handleLoopCondition(node);
846 List<HBasicBlock> dominated = currentBlock.dominatedBlocks; 1137 List<HBasicBlock> dominated = currentBlock.dominatedBlocks;
847 // For a do while loop, the body has already been visited. 1138 // For a do while loop, the body has already been visited.
848 if (!node.isDoWhile()) { 1139 if (!node.isDoWhile()) {
849 visitBasicBlock(dominated[0]); 1140 visitBasicBlock(dominated[0]);
850 } 1141 }
851 endLoop(node.block); 1142 endLoop(node.block);
852 visitBasicBlock(branchBlock.successors[1]); 1143 visitBasicBlock(branchBlock.successors[1]);
853 // With labeled breaks we can have more dominated blocks. 1144 // With labeled breaks we can have more dominated blocks.
(...skipping 550 matching lines...) Expand 10 before | Expand all | Expand 10 after
1404 HBoundsCheck instruction = argument; 1695 HBoundsCheck instruction = argument;
1405 return unwrap(instruction.index); 1696 return unwrap(instruction.index);
1406 } else if (argument is HTypeGuard) { 1697 } else if (argument is HTypeGuard) {
1407 HTypeGuard instruction = argument; 1698 HTypeGuard instruction = argument;
1408 return unwrap(instruction.guarded); 1699 return unwrap(instruction.guarded);
1409 } else { 1700 } else {
1410 return argument; 1701 return argument;
1411 } 1702 }
1412 } 1703 }
1413 1704
1705 bool handleLoop(HBasicBlock node) => false;
1706
1414 void visitTypeGuard(HTypeGuard node) { 1707 void visitTypeGuard(HTypeGuard node) {
1415 indent--; 1708 indent--;
1416 addIndentation(); 1709 addIndentation();
1417 buffer.add('case ${node.state}:\n'); 1710 buffer.add('case ${node.state}:\n');
1418 indent++; 1711 indent++;
1419 addIndentation(); 1712 addIndentation();
1420 buffer.add('state = 0;\n'); 1713 buffer.add('state = 0;\n');
1421 1714
1422 setup.add(' case ${node.state}:\n'); 1715 setup.add(' case ${node.state}:\n');
1423 int i = 0; 1716 int i = 0;
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
1556 startBailoutSwitch(); 1849 startBailoutSwitch();
1557 } 1850 }
1558 } 1851 }
1559 1852
1560 void endElse(HIf node) { 1853 void endElse(HIf node) {
1561 if (node.elseBlock.hasGuards()) { 1854 if (node.elseBlock.hasGuards()) {
1562 endBailoutSwitch(); 1855 endBailoutSwitch();
1563 } 1856 }
1564 } 1857 }
1565 } 1858 }
OLDNEW
« no previous file with comments | « frog/leg/ssa/builder.dart ('k') | frog/leg/ssa/nodes.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698