Chromium Code Reviews| 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 2152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2440 } | 2431 } |
| 2441 } | 2432 } |
| 2442 } | 2433 } |
| 2443 | 2434 |
| 2444 class SsaOptimizedCodeGenerator extends SsaCodeGenerator { | 2435 class SsaOptimizedCodeGenerator extends SsaCodeGenerator { |
| 2445 SsaOptimizedCodeGenerator(backend, work, parameters, parameterNames) | 2436 SsaOptimizedCodeGenerator(backend, work, parameters, parameterNames) |
| 2446 : super(backend, work, parameters, parameterNames); | 2437 : super(backend, work, parameters, parameterNames); |
| 2447 | 2438 |
| 2448 int maxBailoutParameters; | 2439 int maxBailoutParameters; |
| 2449 | 2440 |
| 2450 void beginGraph(HGraph graph) {} | 2441 HBasicBlock beginGraph(HGraph graph) => graph.entry; |
| 2451 void endGraph(HGraph graph) {} | 2442 void endGraph(HGraph graph) {} |
| 2452 | 2443 |
| 2453 void bailout(HTypeGuard guard, String reason) { | 2444 void bailout(HTypeGuard guard, String reason) { |
| 2454 if (maxBailoutParameters === null) { | 2445 if (maxBailoutParameters === null) { |
| 2455 maxBailoutParameters = 0; | 2446 maxBailoutParameters = 0; |
| 2456 work.guards.forEach((HTypeGuard guard) { | 2447 work.guards.forEach((HTypeGuard guard) { |
| 2457 int inputLength = guard.inputs.length; | 2448 int inputLength = guard.inputs.length; |
| 2458 if (inputLength > maxBailoutParameters) { | 2449 if (inputLength > maxBailoutParameters) { |
| 2459 maxBailoutParameters = inputLength; | 2450 maxBailoutParameters = inputLength; |
| 2460 } | 2451 } |
| 2461 }); | 2452 }); |
| 2462 } | 2453 } |
| 2463 HInstruction input = guard.guarded; | 2454 HInstruction input = guard.guarded; |
| 2464 Namer namer = compiler.namer; | 2455 Namer namer = compiler.namer; |
| 2465 Element element = work.element; | 2456 Element element = work.element; |
| 2466 buffer.add('return '); | 2457 buffer.add('return '); |
| 2467 if (element.isInstanceMember()) { | 2458 if (element.isInstanceMember()) { |
| 2468 // TODO(ngeoffray): This does not work in case we come from a | 2459 // TODO(ngeoffray): This does not work in case we come from a |
| 2469 // super call. We must make bailout names unique. | 2460 // super call. We must make bailout names unique. |
| 2470 buffer.add('this.${namer.getBailoutName(element)}'); | 2461 buffer.add('this.${namer.getBailoutName(element)}'); |
| 2471 } else { | 2462 } else { |
| 2472 buffer.add(namer.isolateBailoutAccess(element)); | 2463 buffer.add(namer.isolateBailoutAccess(element)); |
| 2473 } | 2464 } |
| 2474 int parametersCount = parameterNames.length; | 2465 buffer.add('(${guard.state}'); |
| 2475 buffer.add('($parameters'); | |
| 2476 if (parametersCount != 0) buffer.add(', '); | |
| 2477 buffer.add('${guard.state}'); | |
| 2478 // TODO(ngeoffray): try to put a variable at a deterministic | 2466 // TODO(ngeoffray): try to put a variable at a deterministic |
| 2479 // location, so that multiple bailout calls put the variable at | 2467 // location, so that multiple bailout calls put the variable at |
| 2480 // the same parameter index. | 2468 // the same parameter index. |
| 2481 int i = 0; | 2469 int i = 0; |
| 2482 for (; i < guard.inputs.length; i++) { | 2470 for (; i < guard.sortedVariableNames.length; i++) { |
| 2483 buffer.add(', '); | 2471 buffer.add(', ${guard.sortedVariableNames[i]}'); |
| 2484 use(guard.inputs[i], JSPrecedence.ASSIGNMENT_PRECEDENCE); | |
| 2485 } | 2472 } |
| 2486 // Make sure we call the bailout method with the number of | 2473 // Make sure we call the bailout method with the number of |
| 2487 // arguments it expects. This avoids having the underlying | 2474 // arguments it expects. This avoids having the underlying |
| 2488 // JS engine fill them in for us. | 2475 // JS engine fill them in for us. |
| 2489 for (; i < maxBailoutParameters; i++) { | 2476 for (; i < maxBailoutParameters; i++) { |
| 2490 buffer.add(', 0'); | 2477 buffer.add(', 0'); |
| 2491 } | 2478 } |
| 2492 buffer.add(')'); | 2479 buffer.add(')'); |
| 2493 } | 2480 } |
| 2494 | 2481 |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2584 void startLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { | 2571 void startLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { |
| 2585 } | 2572 } |
| 2586 | 2573 |
| 2587 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { | 2574 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { |
| 2588 } | 2575 } |
| 2589 } | 2576 } |
| 2590 | 2577 |
| 2591 class SsaUnoptimizedCodeGenerator extends SsaCodeGenerator { | 2578 class SsaUnoptimizedCodeGenerator extends SsaCodeGenerator { |
| 2592 | 2579 |
| 2593 final StringBuffer setup; | 2580 final StringBuffer setup; |
| 2581 final StringBuffer newParameters; | |
| 2594 final List<String> labels; | 2582 final List<String> labels; |
| 2595 int labelId = 0; | 2583 int labelId = 0; |
| 2596 int maxBailoutParameters = 0; | 2584 int maxBailoutParameters = 0; |
| 2597 | 2585 |
| 2586 SsaBailoutPropagator propagator; | |
| 2587 HInstruction savedFirstInstruction; | |
| 2588 | |
| 2598 SsaUnoptimizedCodeGenerator(backend, work, parameters, parameterNames) | 2589 SsaUnoptimizedCodeGenerator(backend, work, parameters, parameterNames) |
| 2599 : super(backend, work, parameters, parameterNames), | 2590 : super(backend, work, parameters, parameterNames), |
| 2600 setup = new StringBuffer(), | 2591 setup = new StringBuffer(), |
| 2601 labels = <String>[]; | 2592 newParameters = new StringBuffer(), |
| 2593 labels = <String>[] { | |
|
kasperl
2012/06/12 12:18:40
Keep ;
ngeoffray
2012/06/12 12:28:18
Done.
| |
| 2594 } | |
| 2602 | 2595 |
| 2603 String pushLabel() { | 2596 String pushLabel() { |
| 2604 String label = 'L${labelId++}'; | 2597 String label = 'L${labelId++}'; |
| 2605 labels.addLast(label); | 2598 labels.addLast(label); |
| 2606 return label; | 2599 return label; |
| 2607 } | 2600 } |
| 2608 | 2601 |
| 2609 String popLabel() { | 2602 String popLabel() { |
| 2610 return labels.removeLast(); | 2603 return labels.removeLast(); |
| 2611 } | 2604 } |
| 2612 | 2605 |
| 2613 String currentLabel() { | 2606 String currentLabel() { |
| 2614 return labels.last(); | 2607 return labels.last(); |
| 2615 } | 2608 } |
| 2616 | 2609 |
| 2617 void beginGraph(HGraph graph) { | 2610 HBasicBlock beginGraph(HGraph graph) { |
| 2618 if (!graph.entry.hasGuards()) return; | 2611 propagator = new SsaBailoutPropagator( |
| 2619 addIndented('switch (state) {\n'); | 2612 compiler, generateAtUseSite, variableNames); |
| 2620 indent++; | 2613 propagator.visitGraph(graph); |
| 2621 addIndented('case 0:\n'); | |
| 2622 indent++; | |
| 2623 | 2614 |
| 2624 // The setup phase of a bailout function sets up the environment for | 2615 if (propagator.hasComplexTypeGuards) { |
| 2625 // each bailout target. Each bailout target will populate this | 2616 startBailoutSwitch(); |
| 2626 // setup phase. It is put at the beginning of the function. | 2617 |
| 2627 setup.add(' switch (state) {\n'); | 2618 // The setup phase of a bailout function sets up the environment for |
| 2619 // each bailout target. Each bailout target will populate this | |
| 2620 // setup phase. It is put at the beginning of the function. | |
| 2621 setup.add(' switch (state) {\n'); | |
| 2622 } | |
| 2623 | |
| 2624 if (propagator.startGeneratingAt !== null) { | |
| 2625 return propagator.startGeneratingAt; | |
| 2626 } | |
| 2627 | |
| 2628 // We change the first instruction of the first guard to be the | |
| 2629 // guard. We will change it back in the call to [endGraph]. | |
| 2630 HBasicBlock block = propagator.firstTypeGuard.block; | |
| 2631 savedFirstInstruction = block.first; | |
| 2632 block.first = propagator.firstTypeGuard; | |
| 2633 return block; | |
| 2628 } | 2634 } |
| 2629 | 2635 |
| 2630 void endGraph(HGraph graph) { | 2636 void endGraph(HGraph graph) { |
| 2631 if (!graph.entry.hasGuards()) return; | 2637 // Restore the first instruction of the first guard. |
| 2632 indent--; // Close original case. | 2638 if (propagator.startGeneratingAt === null) { |
| 2633 indent--; | 2639 propagator.firstTypeGuard.block.first = savedFirstInstruction; |
| 2634 addIndented('}\n'); // Close 'switch'. | 2640 } |
| 2635 setup.add(' }\n'); | 2641 |
| 2642 // TODO(ngeoffray): We could avoid generating the state at the | |
| 2643 // call site for non-complex bailout methods. | |
| 2644 newParameters.add('state'); | |
| 2645 | |
| 2646 if (!propagator.hasComplexTypeGuards) { | |
| 2647 for (String name in propagator.firstTypeGuard.sortedVariableNames) { | |
| 2648 newParameters.add(', $name'); | |
| 2649 } | |
| 2650 } else { | |
| 2651 for (int i = 0; i < maxBailoutParameters; i++) { | |
| 2652 newParameters.add(', env$i'); | |
| 2653 } | |
| 2654 indent--; // Close original case. | |
| 2655 indent--; | |
| 2656 addIndented('}\n'); // Close 'switch'. | |
| 2657 setup.add(' }\n'); | |
| 2658 } | |
| 2636 } | 2659 } |
| 2637 | 2660 |
| 2638 bool visitAndOrInfo(HAndOrBlockInformation info) => false; | 2661 bool visitAndOrInfo(HAndOrBlockInformation info) => false; |
| 2639 bool visitIfInfo(HIfBlockInformation info) => false; | 2662 |
| 2640 bool visitLoopInfo(HLoopBlockInformation info) => false; | 2663 bool visitIfInfo(HIfBlockInformation info) { |
| 2664 if (info.thenGraph.start.hasGuards()) return false; | |
| 2665 if (info.elseGraph.start.hasGuards()) return false; | |
| 2666 return super.visitIfInfo(info); | |
| 2667 } | |
| 2668 | |
| 2669 bool visitLoopInfo(HLoopBlockInformation info) { | |
| 2670 if (info.start.hasGuards()) return false; | |
| 2671 if (info.loopHeader.hasGuards()) return false; | |
| 2672 return super.visitLoopInfo(info); | |
| 2673 } | |
| 2674 | |
| 2641 bool visitTryInfo(HTryBlockInformation info) => false; | 2675 bool visitTryInfo(HTryBlockInformation info) => false; |
| 2642 bool visitSequenceInfo(HStatementSequenceInformation info) => false; | 2676 bool visitSequenceInfo(HStatementSequenceInformation info) => false; |
| 2643 | 2677 |
| 2644 // If argument is a [HCheck] and it does not have a name, we try to | 2678 void visitTypeGuard(HTypeGuard node) { |
| 2645 // find the name of its checked input. Note that there must be a | 2679 if (!propagator.hasComplexTypeGuards) return; |
| 2646 // name, otherwise the instruction would not be in the live | |
| 2647 // environment. | |
| 2648 HInstruction unwrap(argument) {» | |
| 2649 while (argument is HCheck && !variableNames.hasName(argument)) { | |
| 2650 argument = argument.checkedInput; | |
| 2651 } | |
| 2652 assert(variableNames.hasName(argument)); | |
| 2653 return argument;» | |
| 2654 } | |
| 2655 | 2680 |
| 2656 void visitTypeGuard(HTypeGuard node) { | |
| 2657 indent--; | 2681 indent--; |
| 2658 addIndented('case ${node.state}:\n'); | 2682 addIndented('case ${node.state}:\n'); |
| 2659 indent++; | 2683 indent++; |
| 2660 addIndented('state = 0;\n'); | 2684 addIndented('state = 0;\n'); |
| 2661 | 2685 |
| 2662 setup.add(' case ${node.state}:\n'); | 2686 setup.add(' case ${node.state}:\n'); |
| 2663 int i = 0; | 2687 int i = 0; |
| 2664 for (HInstruction input in node.inputs) { | 2688 for (String name in node.sortedVariableNames) { |
| 2665 HInstruction instruction = unwrap(input); | 2689 setup.add(' $name = env$i;\n'); |
| 2666 setup.add(' ${variableNames.getName(instruction)} = env$i;\n'); | |
| 2667 i++; | 2690 i++; |
| 2668 } | 2691 } |
| 2669 if (i > maxBailoutParameters) maxBailoutParameters = i; | 2692 if (i > maxBailoutParameters) maxBailoutParameters = i; |
| 2670 setup.add(' break;\n'); | 2693 setup.add(' break;\n'); |
| 2671 } | 2694 } |
| 2672 | 2695 |
| 2673 void startBailoutCase(List<HTypeGuard> bailouts1, | 2696 void startBailoutCase(List<HTypeGuard> bailouts1, |
| 2674 List<HTypeGuard> bailouts2) { | 2697 List<HTypeGuard> bailouts2) { |
| 2675 indent--; | 2698 indent--; |
| 2676 handleBailoutCase(bailouts1); | 2699 handleBailoutCase(bailouts1); |
| 2677 handleBailoutCase(bailouts2); | 2700 handleBailoutCase(bailouts2); |
| 2678 indent++; | 2701 indent++; |
| 2679 } | 2702 } |
| 2680 | 2703 |
| 2681 void handleBailoutCase(List<HTypeGuard> guards) { | 2704 void handleBailoutCase(List<HTypeGuard> guards) { |
| 2682 for (int i = 0, len = guards.length; i < len; i++) { | 2705 for (int i = 0, len = guards.length; i < len; i++) { |
| 2683 addIndented('case ${guards[i].state}:\n'); | 2706 addIndented('case ${guards[i].state}:\n'); |
| 2684 } | 2707 } |
| 2685 } | 2708 } |
| 2686 | 2709 |
| 2687 void startBailoutSwitch() { | 2710 void startBailoutSwitch() { |
| 2688 addIndented('switch (state) {\n'); | 2711 addIndented('switch (state) {\n'); |
| 2689 indent++; | 2712 indent += 2; |
| 2690 addIndented('case 0:\n'); | |
| 2691 indent++; | |
| 2692 } | 2713 } |
| 2693 | 2714 |
| 2694 void endBailoutSwitch() { | 2715 void endBailoutSwitch() { |
| 2695 indent--; // Close 'case'. | 2716 indent--; // Close 'case'. |
| 2696 indent--; | 2717 indent--; |
| 2697 addIndented('}\n'); // Close 'switch'. | 2718 addIndented('}\n'); // Close 'switch'. |
| 2698 } | 2719 } |
| 2699 | 2720 |
| 2700 void beginLoop(HBasicBlock block) { | 2721 void beginLoop(HBasicBlock block) { |
| 2701 // TODO(ngeoffray): Don't put labels on loops that don't bailout. | |
| 2702 String newLabel = pushLabel(); | 2722 String newLabel = pushLabel(); |
| 2703 if (block.hasGuards()) { | 2723 if (block.hasGuards()) { |
| 2704 startBailoutCase(block.guards, const <HTypeGuard>[]); | 2724 startBailoutCase(block.guards, const <HTypeGuard>[]); |
| 2705 } | 2725 } |
| 2706 | 2726 |
| 2707 addIndentation(); | 2727 addIndentation(); |
| 2708 HLoopInformation loopInformation = block.loopInformation; | 2728 HLoopInformation loopInformation = block.loopInformation; |
| 2709 for (LabelElement label in loopInformation.labels) { | 2729 for (LabelElement label in loopInformation.labels) { |
| 2710 writeLabel(label); | 2730 writeLabel(label); |
| 2711 buffer.add(":"); | 2731 buffer.add(":"); |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2800 startBailoutSwitch(); | 2820 startBailoutSwitch(); |
| 2801 } | 2821 } |
| 2802 } | 2822 } |
| 2803 | 2823 |
| 2804 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { | 2824 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { |
| 2805 if (labeledBlockInfo.body.start.hasGuards()) { | 2825 if (labeledBlockInfo.body.start.hasGuards()) { |
| 2806 endBailoutSwitch(); | 2826 endBailoutSwitch(); |
| 2807 } | 2827 } |
| 2808 } | 2828 } |
| 2809 } | 2829 } |
| OLD | NEW |