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