| OLD | NEW |
| 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 final JavaScriptBackend backend; | 6 final JavaScriptBackend backend; |
| 7 SsaCodeGeneratorTask(JavaScriptBackend backend) | 7 SsaCodeGeneratorTask(JavaScriptBackend backend) |
| 8 : this.backend = backend, | 8 : this.backend = backend, |
| 9 super(backend.compiler); | 9 super(backend.compiler); |
| 10 String get name() => 'SSA code generator'; | 10 String get name() => 'SSA code generator'; |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 65 } else { | 65 } else { |
| 66 code = codegen.buffer.toString(); | 66 code = codegen.buffer.toString(); |
| 67 } | 67 } |
| 68 return buildJavaScriptFunction(element, parameters, code); | 68 return buildJavaScriptFunction(element, parameters, code); |
| 69 }); | 69 }); |
| 70 } | 70 } |
| 71 | 71 |
| 72 String generateBailoutMethod(WorkItem work, HGraph graph) { | 72 String generateBailoutMethod(WorkItem work, HGraph graph) { |
| 73 return measure(() { | 73 return measure(() { |
| 74 compiler.tracer.traceGraph("codegen-bailout", graph); | 74 compiler.tracer.traceGraph("codegen-bailout", graph); |
| 75 new SsaBailoutPropagator(compiler).visitGraph(graph); |
| 75 | 76 |
| 76 Map<Element, String> parameterNames = getParameterNames(work); | 77 Map<Element, String> parameterNames = getParameterNames(work); |
| 77 String parameters = Strings.join(parameterNames.getValues(), ', '); | 78 String parameters = Strings.join(parameterNames.getValues(), ', '); |
| 78 SsaUnoptimizedCodeGenerator codegen = new SsaUnoptimizedCodeGenerator( | 79 SsaUnoptimizedCodeGenerator codegen = new SsaUnoptimizedCodeGenerator( |
| 79 backend, work, parameters, parameterNames); | 80 backend, work, parameters, parameterNames); |
| 80 codegen.visitGraph(graph); | 81 codegen.visitGraph(graph); |
| 81 | 82 |
| 83 StringBuffer newParameters = new StringBuffer(); |
| 84 if (!parameterNames.isEmpty()) newParameters.add('$parameters, '); |
| 85 newParameters.add('state'); |
| 86 |
| 87 for (int i = 0; i < codegen.maxBailoutParameters; i++) { |
| 88 newParameters.add(', env$i'); |
| 89 } |
| 90 |
| 91 Element element = work.element; |
| 82 String body = '${codegen.setup}${codegen.buffer}'; | 92 String body = '${codegen.setup}${codegen.buffer}'; |
| 83 return buildJavaScriptFunction( | 93 return buildJavaScriptFunction(element, newParameters.toString(), body); |
| 84 work.element, codegen.newParameters.toString(), body); | |
| 85 }); | 94 }); |
| 86 } | 95 } |
| 87 | 96 |
| 88 Map<Element, String> getParameterNames(WorkItem work) { | 97 Map<Element, String> getParameterNames(WorkItem work) { |
| 89 Map<Element, String> parameterNames = new LinkedHashMap<Element, String>(); | 98 Map<Element, String> parameterNames = new LinkedHashMap<Element, String>(); |
| 90 FunctionElement function = work.element; | 99 FunctionElement function = work.element; |
| 91 | 100 |
| 92 // The dom/html libraries have inline JS code that reference | 101 // The dom/html libraries have inline JS code that reference |
| 93 // parameter names directly. Long-term such code will be rejected. | 102 // parameter names directly. Long-term such code will be rejected. |
| 94 // Now, just don't mangle the parameter name. | 103 // Now, just don't mangle the parameter name. |
| (...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 257 parameterNames); | 266 parameterNames); |
| 258 allocator.visitGraph(graph); | 267 allocator.visitGraph(graph); |
| 259 variableNames = allocator.names; | 268 variableNames = allocator.names; |
| 260 } | 269 } |
| 261 | 270 |
| 262 visitGraph(HGraph graph) { | 271 visitGraph(HGraph graph) { |
| 263 preGenerateMethod(graph); | 272 preGenerateMethod(graph); |
| 264 currentGraph = graph; | 273 currentGraph = graph; |
| 265 indent++; // We are already inside a function. | 274 indent++; // We are already inside a function. |
| 266 subGraph = new SubGraph(graph.entry, graph.exit); | 275 subGraph = new SubGraph(graph.entry, graph.exit); |
| 267 HBasicBlock start = beginGraph(graph); | 276 beginGraph(graph); |
| 268 visitBasicBlock(start); | 277 visitBasicBlock(graph.entry); |
| 269 if (!delayedVariableDeclarations.isEmpty()) { | 278 if (!delayedVariableDeclarations.isEmpty()) { |
| 270 addIndented("var "); | 279 addIndented("var "); |
| 271 buffer.add(Strings.join( | 280 buffer.add(Strings.join( |
| 272 new List<String>.from(delayedVariableDeclarations), ', ')); | 281 new List<String>.from(delayedVariableDeclarations), ', ')); |
| 273 buffer.add(";\n"); | 282 buffer.add(";\n"); |
| 274 } | 283 } |
| 275 endGraph(graph); | 284 endGraph(graph); |
| 276 } | 285 } |
| 277 | 286 |
| 278 void visitSubGraph(SubGraph newSubGraph) { | 287 void visitSubGraph(SubGraph newSubGraph) { |
| (...skipping 2168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2447 } | 2456 } |
| 2448 } | 2457 } |
| 2449 } | 2458 } |
| 2450 | 2459 |
| 2451 class SsaOptimizedCodeGenerator extends SsaCodeGenerator { | 2460 class SsaOptimizedCodeGenerator extends SsaCodeGenerator { |
| 2452 SsaOptimizedCodeGenerator(backend, work, parameters, parameterNames) | 2461 SsaOptimizedCodeGenerator(backend, work, parameters, parameterNames) |
| 2453 : super(backend, work, parameters, parameterNames); | 2462 : super(backend, work, parameters, parameterNames); |
| 2454 | 2463 |
| 2455 int maxBailoutParameters; | 2464 int maxBailoutParameters; |
| 2456 | 2465 |
| 2457 HBasicBlock beginGraph(HGraph graph) => graph.entry; | 2466 void beginGraph(HGraph graph) {} |
| 2458 void endGraph(HGraph graph) {} | 2467 void endGraph(HGraph graph) {} |
| 2459 | 2468 |
| 2460 void bailout(HTypeGuard guard, String reason) { | 2469 void bailout(HTypeGuard guard, String reason) { |
| 2461 if (maxBailoutParameters === null) { | 2470 if (maxBailoutParameters === null) { |
| 2462 maxBailoutParameters = 0; | 2471 maxBailoutParameters = 0; |
| 2463 work.guards.forEach((HTypeGuard guard) { | 2472 work.guards.forEach((HTypeGuard guard) { |
| 2464 int inputLength = guard.inputs.length; | 2473 int inputLength = guard.inputs.length; |
| 2465 if (inputLength > maxBailoutParameters) { | 2474 if (inputLength > maxBailoutParameters) { |
| 2466 maxBailoutParameters = inputLength; | 2475 maxBailoutParameters = inputLength; |
| 2467 } | 2476 } |
| 2468 }); | 2477 }); |
| 2469 } | 2478 } |
| 2470 HInstruction input = guard.guarded; | 2479 HInstruction input = guard.guarded; |
| 2471 Namer namer = compiler.namer; | 2480 Namer namer = compiler.namer; |
| 2472 Element element = work.element; | 2481 Element element = work.element; |
| 2473 buffer.add('return '); | 2482 buffer.add('return '); |
| 2474 if (element.isInstanceMember()) { | 2483 if (element.isInstanceMember()) { |
| 2475 // TODO(ngeoffray): This does not work in case we come from a | 2484 // TODO(ngeoffray): This does not work in case we come from a |
| 2476 // super call. We must make bailout names unique. | 2485 // super call. We must make bailout names unique. |
| 2477 buffer.add('this.${namer.getBailoutName(element)}'); | 2486 buffer.add('this.${namer.getBailoutName(element)}'); |
| 2478 } else { | 2487 } else { |
| 2479 buffer.add(namer.isolateBailoutAccess(element)); | 2488 buffer.add(namer.isolateBailoutAccess(element)); |
| 2480 } | 2489 } |
| 2481 buffer.add('(${guard.state}'); | 2490 int parametersCount = parameterNames.length; |
| 2491 buffer.add('($parameters'); |
| 2492 if (parametersCount != 0) buffer.add(', '); |
| 2493 buffer.add('${guard.state}'); |
| 2482 // TODO(ngeoffray): try to put a variable at a deterministic | 2494 // TODO(ngeoffray): try to put a variable at a deterministic |
| 2483 // location, so that multiple bailout calls put the variable at | 2495 // location, so that multiple bailout calls put the variable at |
| 2484 // the same parameter index. | 2496 // the same parameter index. |
| 2485 int i = 0; | 2497 int i = 0; |
| 2486 for (; i < guard.inputs.length; i++) { | 2498 for (; i < guard.inputs.length; i++) { |
| 2487 buffer.add(', '); | 2499 buffer.add(', '); |
| 2488 use(guard.inputs[i], JSPrecedence.ASSIGNMENT_PRECEDENCE); | 2500 use(guard.inputs[i], JSPrecedence.ASSIGNMENT_PRECEDENCE); |
| 2489 } | 2501 } |
| 2490 // Make sure we call the bailout method with the number of | 2502 // Make sure we call the bailout method with the number of |
| 2491 // arguments it expects. This avoids having the underlying | 2503 // arguments it expects. This avoids having the underlying |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2588 void startLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { | 2600 void startLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { |
| 2589 } | 2601 } |
| 2590 | 2602 |
| 2591 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { | 2603 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { |
| 2592 } | 2604 } |
| 2593 } | 2605 } |
| 2594 | 2606 |
| 2595 class SsaUnoptimizedCodeGenerator extends SsaCodeGenerator { | 2607 class SsaUnoptimizedCodeGenerator extends SsaCodeGenerator { |
| 2596 | 2608 |
| 2597 final StringBuffer setup; | 2609 final StringBuffer setup; |
| 2598 final StringBuffer newParameters; | |
| 2599 final List<String> labels; | 2610 final List<String> labels; |
| 2600 int labelId = 0; | 2611 int labelId = 0; |
| 2601 int maxBailoutParameters = 0; | 2612 int maxBailoutParameters = 0; |
| 2602 | 2613 |
| 2603 SsaBailoutPropagator propagator; | |
| 2604 HInstruction savedFirstInstruction; | |
| 2605 | |
| 2606 SsaUnoptimizedCodeGenerator(backend, work, parameters, parameterNames) | 2614 SsaUnoptimizedCodeGenerator(backend, work, parameters, parameterNames) |
| 2607 : super(backend, work, parameters, parameterNames), | 2615 : super(backend, work, parameters, parameterNames), |
| 2608 setup = new StringBuffer(), | 2616 setup = new StringBuffer(), |
| 2609 newParameters = new StringBuffer(), | |
| 2610 labels = <String>[]; | 2617 labels = <String>[]; |
| 2611 | 2618 |
| 2612 String pushLabel() { | 2619 String pushLabel() { |
| 2613 String label = 'L${labelId++}'; | 2620 String label = 'L${labelId++}'; |
| 2614 labels.addLast(label); | 2621 labels.addLast(label); |
| 2615 return label; | 2622 return label; |
| 2616 } | 2623 } |
| 2617 | 2624 |
| 2618 String popLabel() { | 2625 String popLabel() { |
| 2619 return labels.removeLast(); | 2626 return labels.removeLast(); |
| 2620 } | 2627 } |
| 2621 | 2628 |
| 2622 String currentLabel() { | 2629 String currentLabel() { |
| 2623 return labels.last(); | 2630 return labels.last(); |
| 2624 } | 2631 } |
| 2625 | 2632 |
| 2626 HBasicBlock beginGraph(HGraph graph) { | 2633 void beginGraph(HGraph graph) { |
| 2627 propagator = new SsaBailoutPropagator(compiler, generateAtUseSite); | 2634 if (!graph.entry.hasGuards()) return; |
| 2628 propagator.visitGraph(graph); | 2635 addIndented('switch (state) {\n'); |
| 2636 indent++; |
| 2637 addIndented('case 0:\n'); |
| 2638 indent++; |
| 2629 | 2639 |
| 2630 if (propagator.hasComplexTypeGuards) { | 2640 // The setup phase of a bailout function sets up the environment for |
| 2631 startBailoutSwitch(); | 2641 // each bailout target. Each bailout target will populate this |
| 2642 // setup phase. It is put at the beginning of the function. |
| 2643 setup.add(' switch (state) {\n'); |
| 2644 } |
| 2632 | 2645 |
| 2633 // The setup phase of a bailout function sets up the environment for | 2646 void endGraph(HGraph graph) { |
| 2634 // each bailout target. Each bailout target will populate this | 2647 if (!graph.entry.hasGuards()) return; |
| 2635 // setup phase. It is put at the beginning of the function. | 2648 indent--; // Close original case. |
| 2636 setup.add(' switch (state) {\n'); | 2649 indent--; |
| 2637 return graph.entry; | 2650 addIndented('}\n'); // Close 'switch'. |
| 2638 } else { | 2651 setup.add(' }\n'); |
| 2639 // We change the first instruction of the first guard to be the | |
| 2640 // guard. We will change it back in the call to [endGraph]. | |
| 2641 HBasicBlock block = propagator.firstTypeGuard.block; | |
| 2642 savedFirstInstruction = block.first; | |
| 2643 block.first = propagator.firstTypeGuard; | |
| 2644 return block; | |
| 2645 } | |
| 2646 } | 2652 } |
| 2647 | 2653 |
| 2654 bool visitAndOrInfo(HAndOrBlockInformation info) => false; |
| 2655 bool visitIfInfo(HIfBlockInformation info) => false; |
| 2656 bool visitLoopInfo(HLoopBlockInformation info) => false; |
| 2657 bool visitTryInfo(HTryBlockInformation info) => false; |
| 2658 bool visitSequenceInfo(HStatementSequenceInformation info) => false; |
| 2659 |
| 2648 // If argument is a [HCheck] and it does not have a name, we try to | 2660 // If argument is a [HCheck] and it does not have a name, we try to |
| 2649 // find the name of its checked input. Note that there must be a | 2661 // find the name of its checked input. Note that there must be a |
| 2650 // name, otherwise the instruction would not be in the live | 2662 // name, otherwise the instruction would not be in the live |
| 2651 // environment. | 2663 // environment. |
| 2652 HInstruction unwrap(HInstruction argument) { | 2664 HInstruction unwrap(argument) { |
| 2653 while (argument is HCheck && !variableNames.hasName(argument)) { | 2665 while (argument is HCheck && !variableNames.hasName(argument)) { |
| 2654 argument = argument.checkedInput; | 2666 argument = argument.checkedInput; |
| 2655 } | 2667 } |
| 2656 assert(variableNames.hasName(argument)); | 2668 assert(variableNames.hasName(argument)); |
| 2657 return argument; | 2669 return argument; |
| 2658 } | 2670 } |
| 2659 | 2671 |
| 2660 void endGraph(HGraph graph) { | |
| 2661 // TODO(ngeoffray): We could avoid generating the state at the | |
| 2662 // call site for non-complex bailout methods. | |
| 2663 newParameters.add('state'); | |
| 2664 | |
| 2665 if (!propagator.hasComplexTypeGuards) { | |
| 2666 propagator.firstTypeGuard.block.first = savedFirstInstruction; | |
| 2667 for (HInstruction input in propagator.firstTypeGuard.inputs) { | |
| 2668 input = unwrap(input); | |
| 2669 newParameters.add(', ${variableNames.getName(input)}'); | |
| 2670 } | |
| 2671 } else { | |
| 2672 for (int i = 0; i < maxBailoutParameters; i++) { | |
| 2673 newParameters.add(', env$i'); | |
| 2674 } | |
| 2675 indent--; // Close original case. | |
| 2676 indent--; | |
| 2677 addIndented('}\n'); // Close 'switch'. | |
| 2678 setup.add(' }\n'); | |
| 2679 } | |
| 2680 } | |
| 2681 | |
| 2682 bool visitAndOrInfo(HAndOrBlockInformation info) => false; | |
| 2683 | |
| 2684 bool visitIfInfo(HIfBlockInformation info) { | |
| 2685 if (info.thenGraph.start.hasGuards()) return false; | |
| 2686 if (info.elseGraph.start.hasGuards()) return false; | |
| 2687 return super.visitIfInfo(info); | |
| 2688 } | |
| 2689 | |
| 2690 bool visitLoopInfo(HLoopBlockInformation info) { | |
| 2691 if (info.start.hasGuards()) return false; | |
| 2692 if (info.loopHeader.hasGuards()) return false; | |
| 2693 return super.visitLoopInfo(info); | |
| 2694 } | |
| 2695 | |
| 2696 bool visitTryInfo(HTryBlockInformation info) => false; | |
| 2697 bool visitSequenceInfo(HStatementSequenceInformation info) => false; | |
| 2698 | |
| 2699 void visitTypeGuard(HTypeGuard node) { | 2672 void visitTypeGuard(HTypeGuard node) { |
| 2700 if (!propagator.hasComplexTypeGuards) return; | |
| 2701 | |
| 2702 indent--; | 2673 indent--; |
| 2703 addIndented('case ${node.state}:\n'); | 2674 addIndented('case ${node.state}:\n'); |
| 2704 indent++; | 2675 indent++; |
| 2705 addIndented('state = 0;\n'); | 2676 addIndented('state = 0;\n'); |
| 2706 | 2677 |
| 2707 setup.add(' case ${node.state}:\n'); | 2678 setup.add(' case ${node.state}:\n'); |
| 2708 int i = 0; | 2679 int i = 0; |
| 2709 for (HInstruction input in node.inputs) { | 2680 for (HInstruction input in node.inputs) { |
| 2710 input = unwrap(input); | 2681 HInstruction instruction = unwrap(input); |
| 2711 String name = variableNames.getName(input); | 2682 setup.add(' ${variableNames.getName(instruction)} = env$i;\n'); |
| 2712 setup.add(' $name = env$i;\n'); | |
| 2713 i++; | 2683 i++; |
| 2714 } | 2684 } |
| 2715 if (i > maxBailoutParameters) maxBailoutParameters = i; | 2685 if (i > maxBailoutParameters) maxBailoutParameters = i; |
| 2716 setup.add(' break;\n'); | 2686 setup.add(' break;\n'); |
| 2717 } | 2687 } |
| 2718 | 2688 |
| 2719 void startBailoutCase(List<HTypeGuard> bailouts1, | 2689 void startBailoutCase(List<HTypeGuard> bailouts1, |
| 2720 List<HTypeGuard> bailouts2) { | 2690 List<HTypeGuard> bailouts2) { |
| 2721 indent--; | 2691 indent--; |
| 2722 handleBailoutCase(bailouts1); | 2692 handleBailoutCase(bailouts1); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 2737 indent++; | 2707 indent++; |
| 2738 } | 2708 } |
| 2739 | 2709 |
| 2740 void endBailoutSwitch() { | 2710 void endBailoutSwitch() { |
| 2741 indent--; // Close 'case'. | 2711 indent--; // Close 'case'. |
| 2742 indent--; | 2712 indent--; |
| 2743 addIndented('}\n'); // Close 'switch'. | 2713 addIndented('}\n'); // Close 'switch'. |
| 2744 } | 2714 } |
| 2745 | 2715 |
| 2746 void beginLoop(HBasicBlock block) { | 2716 void beginLoop(HBasicBlock block) { |
| 2717 // TODO(ngeoffray): Don't put labels on loops that don't bailout. |
| 2747 String newLabel = pushLabel(); | 2718 String newLabel = pushLabel(); |
| 2748 if (block.hasGuards()) { | 2719 if (block.hasGuards()) { |
| 2749 startBailoutCase(block.guards, const <HTypeGuard>[]); | 2720 startBailoutCase(block.guards, const <HTypeGuard>[]); |
| 2750 } | 2721 } |
| 2751 | 2722 |
| 2752 addIndentation(); | 2723 addIndentation(); |
| 2753 HLoopInformation loopInformation = block.loopInformation; | 2724 HLoopInformation loopInformation = block.loopInformation; |
| 2754 for (LabelElement label in loopInformation.labels) { | 2725 for (LabelElement label in loopInformation.labels) { |
| 2755 writeLabel(label); | 2726 writeLabel(label); |
| 2756 buffer.add(":"); | 2727 buffer.add(":"); |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2845 startBailoutSwitch(); | 2816 startBailoutSwitch(); |
| 2846 } | 2817 } |
| 2847 } | 2818 } |
| 2848 | 2819 |
| 2849 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { | 2820 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { |
| 2850 if (labeledBlockInfo.body.start.hasGuards()) { | 2821 if (labeledBlockInfo.body.start.hasGuards()) { |
| 2851 endBailoutSwitch(); | 2822 endBailoutSwitch(); |
| 2852 } | 2823 } |
| 2853 } | 2824 } |
| 2854 } | 2825 } |
| OLD | NEW |