| 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 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2607 void startLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { | 2595 void startLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { |
| 2608 } | 2596 } |
| 2609 | 2597 |
| 2610 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { | 2598 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { |
| 2611 } | 2599 } |
| 2612 } | 2600 } |
| 2613 | 2601 |
| 2614 class SsaUnoptimizedCodeGenerator extends SsaCodeGenerator { | 2602 class SsaUnoptimizedCodeGenerator extends SsaCodeGenerator { |
| 2615 | 2603 |
| 2616 final StringBuffer setup; | 2604 final StringBuffer setup; |
| 2605 final StringBuffer newParameters; |
| 2617 final List<String> labels; | 2606 final List<String> labels; |
| 2618 int labelId = 0; | 2607 int labelId = 0; |
| 2619 int maxBailoutParameters = 0; | 2608 int maxBailoutParameters = 0; |
| 2620 | 2609 |
| 2610 SsaBailoutPropagator propagator; |
| 2611 HInstruction savedFirstInstruction; |
| 2612 |
| 2621 SsaUnoptimizedCodeGenerator(backend, work, parameters, parameterNames) | 2613 SsaUnoptimizedCodeGenerator(backend, work, parameters, parameterNames) |
| 2622 : super(backend, work, parameters, parameterNames), | 2614 : super(backend, work, parameters, parameterNames), |
| 2623 setup = new StringBuffer(), | 2615 setup = new StringBuffer(), |
| 2616 newParameters = new StringBuffer(), |
| 2624 labels = <String>[]; | 2617 labels = <String>[]; |
| 2625 | 2618 |
| 2626 String pushLabel() { | 2619 String pushLabel() { |
| 2627 String label = 'L${labelId++}'; | 2620 String label = 'L${labelId++}'; |
| 2628 labels.addLast(label); | 2621 labels.addLast(label); |
| 2629 return label; | 2622 return label; |
| 2630 } | 2623 } |
| 2631 | 2624 |
| 2632 String popLabel() { | 2625 String popLabel() { |
| 2633 return labels.removeLast(); | 2626 return labels.removeLast(); |
| 2634 } | 2627 } |
| 2635 | 2628 |
| 2636 String currentLabel() { | 2629 String currentLabel() { |
| 2637 return labels.last(); | 2630 return labels.last(); |
| 2638 } | 2631 } |
| 2639 | 2632 |
| 2640 void beginGraph(HGraph graph) { | 2633 HBasicBlock beginGraph(HGraph graph) { |
| 2641 if (!graph.entry.hasGuards()) return; | 2634 propagator = new SsaBailoutPropagator(compiler, generateAtUseSite); |
| 2642 addIndented('switch (state) {\n'); | 2635 propagator.visitGraph(graph); |
| 2643 indent++; | |
| 2644 addIndented('case 0:\n'); | |
| 2645 indent++; | |
| 2646 | 2636 |
| 2647 // The setup phase of a bailout function sets up the environment for | 2637 if (propagator.hasComplexTypeGuards) { |
| 2648 // each bailout target. Each bailout target will populate this | 2638 startBailoutSwitch(); |
| 2649 // setup phase. It is put at the beginning of the function. | 2639 |
| 2650 setup.add(' switch (state) {\n'); | 2640 // The setup phase of a bailout function sets up the environment for |
| 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 return graph.entry; |
| 2645 } else { |
| 2646 // We change the first instruction of the first guard to be the |
| 2647 // guard. We will change it back in the call to [endGraph]. |
| 2648 HBasicBlock block = propagator.firstTypeGuard.block; |
| 2649 savedFirstInstruction = block.first; |
| 2650 block.first = propagator.firstTypeGuard; |
| 2651 return block; |
| 2652 } |
| 2651 } | 2653 } |
| 2652 | 2654 |
| 2653 void endGraph(HGraph graph) { | |
| 2654 if (!graph.entry.hasGuards()) return; | |
| 2655 indent--; // Close original case. | |
| 2656 indent--; | |
| 2657 addIndented('}\n'); // Close 'switch'. | |
| 2658 setup.add(' }\n'); | |
| 2659 } | |
| 2660 | |
| 2661 bool visitAndOrInfo(HAndOrBlockInformation info) => false; | |
| 2662 bool visitIfInfo(HIfBlockInformation info) => false; | |
| 2663 bool visitLoopInfo(HLoopBlockInformation info) => false; | |
| 2664 bool visitTryInfo(HTryBlockInformation info) => false; | |
| 2665 bool visitSequenceInfo(HStatementSequenceInformation info) => false; | |
| 2666 | |
| 2667 // If argument is a [HCheck] and it does not have a name, we try to | 2655 // If argument is a [HCheck] and it does not have a name, we try to |
| 2668 // find the name of its checked input. Note that there must be a | 2656 // find the name of its checked input. Note that there must be a |
| 2669 // name, otherwise the instruction would not be in the live | 2657 // name, otherwise the instruction would not be in the live |
| 2670 // environment. | 2658 // environment. |
| 2671 HInstruction unwrap(argument) { | 2659 HInstruction unwrap(HInstruction argument) { |
| 2672 while (argument is HCheck && !variableNames.hasName(argument)) { | 2660 while (argument is HCheck && !variableNames.hasName(argument)) { |
| 2673 argument = argument.checkedInput; | 2661 argument = argument.checkedInput; |
| 2674 } | 2662 } |
| 2675 assert(variableNames.hasName(argument)); | 2663 assert(variableNames.hasName(argument)); |
| 2676 return argument; | 2664 return argument; |
| 2677 } | 2665 } |
| 2678 | 2666 |
| 2667 void endGraph(HGraph graph) { |
| 2668 // TODO(ngeoffray): We could avoid generating the state at the |
| 2669 // call site for non-complex bailout methods. |
| 2670 newParameters.add('state'); |
| 2671 |
| 2672 if (!propagator.hasComplexTypeGuards) { |
| 2673 propagator.firstTypeGuard.block.first = savedFirstInstruction; |
| 2674 for (HInstruction input in propagator.firstTypeGuard.inputs) { |
| 2675 input = unwrap(input); |
| 2676 newParameters.add(', ${variableNames.getName(input)}'); |
| 2677 } |
| 2678 } else { |
| 2679 for (int i = 0; i < maxBailoutParameters; i++) { |
| 2680 newParameters.add(', env$i'); |
| 2681 } |
| 2682 indent--; // Close original case. |
| 2683 indent--; |
| 2684 addIndented('}\n'); // Close 'switch'. |
| 2685 setup.add(' }\n'); |
| 2686 } |
| 2687 } |
| 2688 |
| 2689 bool visitAndOrInfo(HAndOrBlockInformation info) => false; |
| 2690 |
| 2691 bool visitIfInfo(HIfBlockInformation info) { |
| 2692 if (info.thenGraph.start.hasGuards()) return false; |
| 2693 if (info.elseGraph.start.hasGuards()) return false; |
| 2694 return super.visitIfInfo(info); |
| 2695 } |
| 2696 |
| 2697 bool visitLoopInfo(HLoopBlockInformation info) { |
| 2698 if (info.start.hasGuards()) return false; |
| 2699 if (info.loopHeader.hasGuards()) return false; |
| 2700 return super.visitLoopInfo(info); |
| 2701 } |
| 2702 |
| 2703 bool visitTryInfo(HTryBlockInformation info) => false; |
| 2704 bool visitSequenceInfo(HStatementSequenceInformation info) => false; |
| 2705 |
| 2679 void visitTypeGuard(HTypeGuard node) { | 2706 void visitTypeGuard(HTypeGuard node) { |
| 2707 if (!propagator.hasComplexTypeGuards) return; |
| 2708 |
| 2680 indent--; | 2709 indent--; |
| 2681 addIndented('case ${node.state}:\n'); | 2710 addIndented('case ${node.state}:\n'); |
| 2682 indent++; | 2711 indent++; |
| 2683 addIndented('state = 0;\n'); | 2712 addIndented('state = 0;\n'); |
| 2684 | 2713 |
| 2685 setup.add(' case ${node.state}:\n'); | 2714 setup.add(' case ${node.state}:\n'); |
| 2686 int i = 0; | 2715 int i = 0; |
| 2687 for (HInstruction input in node.inputs) { | 2716 for (HInstruction input in node.inputs) { |
| 2688 HInstruction instruction = unwrap(input); | 2717 input = unwrap(input); |
| 2689 setup.add(' ${variableNames.getName(instruction)} = env$i;\n'); | 2718 String name = variableNames.getName(input); |
| 2719 setup.add(' '); |
| 2720 if (!isVariableDeclared(name)) { |
| 2721 declaredVariables.add(name); |
| 2722 setup.add('var '); |
| 2723 } |
| 2724 setup.add('$name = env$i;\n'); |
| 2690 i++; | 2725 i++; |
| 2691 } | 2726 } |
| 2692 if (i > maxBailoutParameters) maxBailoutParameters = i; | 2727 if (i > maxBailoutParameters) maxBailoutParameters = i; |
| 2693 setup.add(' break;\n'); | 2728 setup.add(' break;\n'); |
| 2694 } | 2729 } |
| 2695 | 2730 |
| 2696 void startBailoutCase(List<HTypeGuard> bailouts1, | 2731 void startBailoutCase(List<HTypeGuard> bailouts1, |
| 2697 List<HTypeGuard> bailouts2) { | 2732 List<HTypeGuard> bailouts2) { |
| 2698 indent--; | 2733 indent--; |
| 2699 handleBailoutCase(bailouts1); | 2734 handleBailoutCase(bailouts1); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 2714 indent++; | 2749 indent++; |
| 2715 } | 2750 } |
| 2716 | 2751 |
| 2717 void endBailoutSwitch() { | 2752 void endBailoutSwitch() { |
| 2718 indent--; // Close 'case'. | 2753 indent--; // Close 'case'. |
| 2719 indent--; | 2754 indent--; |
| 2720 addIndented('}\n'); // Close 'switch'. | 2755 addIndented('}\n'); // Close 'switch'. |
| 2721 } | 2756 } |
| 2722 | 2757 |
| 2723 void beginLoop(HBasicBlock block) { | 2758 void beginLoop(HBasicBlock block) { |
| 2724 // TODO(ngeoffray): Don't put labels on loops that don't bailout. | |
| 2725 String newLabel = pushLabel(); | 2759 String newLabel = pushLabel(); |
| 2726 if (block.hasGuards()) { | 2760 if (block.hasGuards()) { |
| 2727 startBailoutCase(block.guards, const <HTypeGuard>[]); | 2761 startBailoutCase(block.guards, const <HTypeGuard>[]); |
| 2728 } | 2762 } |
| 2729 | 2763 |
| 2730 addIndentation(); | 2764 addIndentation(); |
| 2731 HLoopInformation loopInformation = block.loopInformation; | 2765 HLoopInformation loopInformation = block.loopInformation; |
| 2732 for (LabelElement label in loopInformation.labels) { | 2766 for (LabelElement label in loopInformation.labels) { |
| 2733 writeLabel(label); | 2767 writeLabel(label); |
| 2734 buffer.add(":"); | 2768 buffer.add(":"); |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2823 startBailoutSwitch(); | 2857 startBailoutSwitch(); |
| 2824 } | 2858 } |
| 2825 } | 2859 } |
| 2826 | 2860 |
| 2827 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { | 2861 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { |
| 2828 if (labeledBlockInfo.body.start.hasGuards()) { | 2862 if (labeledBlockInfo.body.start.hasGuards()) { |
| 2829 endBailoutSwitch(); | 2863 endBailoutSwitch(); |
| 2830 } | 2864 } |
| 2831 } | 2865 } |
| 2832 } | 2866 } |
| OLD | NEW |