| 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 Interceptors { | 5 class Interceptors { |
| 6 Compiler compiler; | 6 Compiler compiler; |
| 7 Interceptors(Compiler this.compiler); | 7 Interceptors(Compiler this.compiler); |
| 8 | 8 |
| 9 SourceString mapOperatorToMethodName(Operator op) { | 9 SourceString mapOperatorToMethodName(Operator op) { |
| 10 String name = op.source.stringValue; | 10 String name = op.source.stringValue; |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 161 return builder.buildFactory(classElement, work.element); | 161 return builder.buildFactory(classElement, work.element); |
| 162 } | 162 } |
| 163 } | 163 } |
| 164 | 164 |
| 165 /** | 165 /** |
| 166 * Keeps track of locals (including parameters and phis) when building. The | 166 * Keeps track of locals (including parameters and phis) when building. The |
| 167 * 'this' reference is treated as parameter and hence handled by this class, | 167 * 'this' reference is treated as parameter and hence handled by this class, |
| 168 * too. | 168 * too. |
| 169 */ | 169 */ |
| 170 class LocalsHandler { | 170 class LocalsHandler { |
| 171 // The values of locals that can be directly accessed (without redirections | 171 /** |
| 172 // to boxes or closure-fields). | 172 * The values of locals that can be directly accessed (without redirections |
| 173 * to boxes or closure-fields). |
| 174 */ |
| 173 Map<Element, HInstruction> directLocals; | 175 Map<Element, HInstruction> directLocals; |
| 174 Map<Element, Element> redirectionMapping; | 176 Map<Element, Element> redirectionMapping; |
| 175 SsaBuilder builder; | 177 SsaBuilder builder; |
| 176 ClosureData closureData; | 178 ClosureData closureData; |
| 177 | 179 |
| 178 LocalsHandler(this.builder) | 180 LocalsHandler(this.builder) |
| 179 : directLocals = new Map<Element, HInstruction>(), | 181 : directLocals = new Map<Element, HInstruction>(), |
| 180 redirectionMapping = new Map<Element, Element>(); | 182 redirectionMapping = new Map<Element, Element>(); |
| 181 | 183 |
| 182 /** | 184 /** |
| (...skipping 1215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1398 visit(node.receiver); | 1400 visit(node.receiver); |
| 1399 HNot not = new HNot(popBoolified()); | 1401 HNot not = new HNot(popBoolified()); |
| 1400 push(not); | 1402 push(not); |
| 1401 } | 1403 } |
| 1402 | 1404 |
| 1403 void visitUnary(Send node, Operator op) { | 1405 void visitUnary(Send node, Operator op) { |
| 1404 assert(node.argumentsNode is Prefix); | 1406 assert(node.argumentsNode is Prefix); |
| 1405 visit(node.receiver); | 1407 visit(node.receiver); |
| 1406 assert(op.token.kind !== PLUS_TOKEN); | 1408 assert(op.token.kind !== PLUS_TOKEN); |
| 1407 HInstruction operand = pop(); | 1409 HInstruction operand = pop(); |
| 1410 |
| 1408 HInstruction target = | 1411 HInstruction target = |
| 1409 new HStatic(interceptors.getPrefixOperatorInterceptor(op)); | 1412 new HStatic(interceptors.getPrefixOperatorInterceptor(op)); |
| 1410 add(target); | 1413 add(target); |
| 1411 HInvokeUnary result; | 1414 HInvokeUnary result; |
| 1412 switch (op.source.stringValue) { | 1415 switch (op.source.stringValue) { |
| 1413 case "-": result = new HNegate(target, operand); break; | 1416 case "-": result = new HNegate(target, operand); break; |
| 1414 case "~": result = new HBitNot(target, operand); break; | 1417 case "~": result = new HBitNot(target, operand); break; |
| 1415 default: unreachable(); | 1418 default: unreachable(); |
| 1416 } | 1419 } |
| 1417 // See if we can constant-fold right away. This avoids rewrites later on. | 1420 // See if we can constant-fold right away. This avoids rewrites later on. |
| (...skipping 655 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2073 } | 2076 } |
| 2074 | 2077 |
| 2075 void visitLiteralBool(LiteralBool node) { | 2078 void visitLiteralBool(LiteralBool node) { |
| 2076 stack.add(graph.addConstantBool(node.value)); | 2079 stack.add(graph.addConstantBool(node.value)); |
| 2077 } | 2080 } |
| 2078 | 2081 |
| 2079 void visitLiteralString(LiteralString node) { | 2082 void visitLiteralString(LiteralString node) { |
| 2080 stack.add(graph.addConstantString(node.dartString)); | 2083 stack.add(graph.addConstantString(node.dartString)); |
| 2081 } | 2084 } |
| 2082 | 2085 |
| 2083 void visitLiteralStringJuxtaposition(LiteralStringJuxtaposition node) { | 2086 void visitStringJuxtaposition(StringJuxtaposition node) { |
| 2084 visitLiteralString(node); | 2087 if (!node.isInterpolation) { |
| 2088 // This is a simple string with no interpolations. |
| 2089 stack.add(graph.addConstantString(node.dartString)); |
| 2090 return; |
| 2091 } |
| 2092 int offset = node.getBeginToken().charOffset; |
| 2093 StringBuilderVisitor stringBuilder = |
| 2094 new StringBuilderVisitor(this, offset); |
| 2095 stringBuilder.visit(node); |
| 2096 stack.add(stringBuilder.result()); |
| 2085 } | 2097 } |
| 2086 | 2098 |
| 2087 void visitLiteralNull(LiteralNull node) { | 2099 void visitLiteralNull(LiteralNull node) { |
| 2088 stack.add(graph.addConstantNull()); | 2100 stack.add(graph.addConstantNull()); |
| 2089 } | 2101 } |
| 2090 | 2102 |
| 2091 visitNodeList(NodeList node) { | 2103 visitNodeList(NodeList node) { |
| 2092 for (Link<Node> link = node.nodes; !link.isEmpty(); link = link.tail) { | 2104 for (Link<Node> link = node.nodes; !link.isEmpty(); link = link.tail) { |
| 2093 if (isAborted()) { | 2105 if (isAborted()) { |
| 2094 compiler.reportWarning(link.head, 'dead code'); | 2106 compiler.reportWarning(link.head, 'dead code'); |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2197 open(joinBlock); | 2209 open(joinBlock); |
| 2198 | 2210 |
| 2199 localsHandler.mergeWith(thenLocals, joinBlock); | 2211 localsHandler.mergeWith(thenLocals, joinBlock); |
| 2200 HPhi phi = new HPhi.manyInputs(null, [thenInstruction, elseInstruction]); | 2212 HPhi phi = new HPhi.manyInputs(null, [thenInstruction, elseInstruction]); |
| 2201 joinBlock.addPhi(phi); | 2213 joinBlock.addPhi(phi); |
| 2202 stack.add(phi); | 2214 stack.add(phi); |
| 2203 } | 2215 } |
| 2204 | 2216 |
| 2205 visitStringInterpolation(StringInterpolation node) { | 2217 visitStringInterpolation(StringInterpolation node) { |
| 2206 int offset = node.getBeginToken().charOffset; | 2218 int offset = node.getBeginToken().charOffset; |
| 2207 Operator op = new Operator(new StringToken(PLUS_INFO, "+", offset)); | 2219 StringBuilderVisitor stringBuilder = |
| 2208 HInstruction target = new HStatic(interceptors.getOperatorInterceptor(op)); | 2220 new StringBuilderVisitor(this, offset); |
| 2209 add(target); | 2221 stringBuilder.visit(node); |
| 2210 visit(node.string); | 2222 stack.add(stringBuilder.result()); |
| 2211 // Handle the parts here, to avoid recreating [target]. | |
| 2212 for (StringInterpolationPart part in node.parts) { | |
| 2213 HInstruction prefix = pop(); | |
| 2214 visit(part.expression); | |
| 2215 push(new HAdd(target, prefix, pop())); | |
| 2216 prefix = pop(); | |
| 2217 visit(part.string); | |
| 2218 push(new HAdd(target, prefix, pop())); | |
| 2219 } | |
| 2220 } | 2223 } |
| 2221 | 2224 |
| 2222 visitStringInterpolationPart(StringInterpolationPart node) { | 2225 visitStringInterpolationPart(StringInterpolationPart node) { |
| 2223 // The parts are iterated in visitStringInterpolation. | 2226 // The parts are iterated in visitStringInterpolation. |
| 2224 unreachable(); | 2227 unreachable(); |
| 2225 } | 2228 } |
| 2226 | 2229 |
| 2227 visitEmptyStatement(EmptyStatement node) { | 2230 visitEmptyStatement(EmptyStatement node) { |
| 2228 // Do nothing, empty statement. | 2231 // Do nothing, empty statement. |
| 2229 } | 2232 } |
| (...skipping 471 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2701 buildBody() { | 2704 buildBody() { |
| 2702 // TODO(lrn): Make sure to take continue into account. | 2705 // TODO(lrn): Make sure to take continue into account. |
| 2703 visit(body); | 2706 visit(body); |
| 2704 if (isAborted()) { | 2707 if (isAborted()) { |
| 2705 compiler.reportWarning(body, "aborting loop body"); | 2708 compiler.reportWarning(body, "aborting loop body"); |
| 2706 } | 2709 } |
| 2707 } | 2710 } |
| 2708 handleIf(buildBody, null); | 2711 handleIf(buildBody, null); |
| 2709 } | 2712 } |
| 2710 } | 2713 } |
| 2714 |
| 2715 /** |
| 2716 * Visitor that handles generation of string literals (LiteralString, |
| 2717 * StringInterpolation), and otherwise delegates to the given visitor for |
| 2718 * non-literal subexpressions. |
| 2719 * TODO(lrn): Consider whether to handle compile time constant int/boolean |
| 2720 * expressions as well. |
| 2721 */ |
| 2722 class StringBuilderVisitor extends AbstractVisitor { |
| 2723 final SsaBuilder builder; |
| 2724 |
| 2725 /** |
| 2726 * Offset used for the synthetic operator token used by concat. |
| 2727 * Can probably be removed when we stop using String.operator+. |
| 2728 */ |
| 2729 final int offset; |
| 2730 |
| 2731 /** |
| 2732 * Used to collect concatenated string literals into a single literal |
| 2733 * instead of introducing unnecessary concatenations. |
| 2734 */ |
| 2735 DartString accumulator = const LiteralDartString(""); |
| 2736 |
| 2737 /** |
| 2738 * The string value generated so far (not including that which is still |
| 2739 * in [accumulator]). |
| 2740 */ |
| 2741 HInstruction prefix = null; |
| 2742 |
| 2743 StringBuilderVisitor(this.builder, this.offset); |
| 2744 |
| 2745 void visit(Node node) { |
| 2746 node.accept(this); |
| 2747 } |
| 2748 |
| 2749 visitNode(Node node) { |
| 2750 compiler.internalError('unexpected node', node: node); |
| 2751 } |
| 2752 |
| 2753 void visitExpression(Node node) { |
| 2754 flushAccumulator(); |
| 2755 node.accept(builder); |
| 2756 prefix = concat(prefix, builder.pop()); |
| 2757 } |
| 2758 |
| 2759 void visitStringInterpolation(StringInterpolation node) { |
| 2760 node.visitChildren(this); |
| 2761 } |
| 2762 |
| 2763 void visitStringInterpolationPart(StringInterpolationPart node) { |
| 2764 visit(node.expression); |
| 2765 visit(node.string); |
| 2766 } |
| 2767 |
| 2768 void visitLiteralString(LiteralString node) { |
| 2769 accumulator = new DartString.concat(accumulator, node.dartString); |
| 2770 } |
| 2771 |
| 2772 void visitStringJuxtaposition(StringJuxtaposition node) { |
| 2773 node.visitChildren(this); |
| 2774 } |
| 2775 |
| 2776 void visitNodeList(NodeList node) { |
| 2777 node.visitChildren(this); |
| 2778 } |
| 2779 |
| 2780 /** |
| 2781 * Combine the strings in [accumulator] into the prefix instruction. |
| 2782 * After this, the [accumulator] is empty and [prefix] is non-null. |
| 2783 */ |
| 2784 void flushAccumulator() { |
| 2785 if (accumulator.isEmpty()) { |
| 2786 if (prefix === null) { |
| 2787 prefix = builder.graph.addConstantString(accumulator); |
| 2788 } |
| 2789 return; |
| 2790 } |
| 2791 HInstruction string = builder.graph.addConstantString(accumulator); |
| 2792 accumulator = new DartString.empty(); |
| 2793 if (prefix !== null) { |
| 2794 prefix = concat(prefix, string); |
| 2795 } else { |
| 2796 prefix = string; |
| 2797 } |
| 2798 } |
| 2799 |
| 2800 HInstruction concat(HInstruction left, HInstruction right) { |
| 2801 Operator op = new Operator(new StringToken(PLUS_INFO, "+", offset)); |
| 2802 HStatic target = |
| 2803 new HStatic(builder.interceptors.getOperatorInterceptor(op)); |
| 2804 builder.add(target); |
| 2805 HInstruction concat = new HAdd(target, left, right); |
| 2806 builder.add(concat); |
| 2807 return concat; |
| 2808 } |
| 2809 |
| 2810 HInstruction result() { |
| 2811 flushAccumulator(); |
| 2812 return prefix; |
| 2813 } |
| 2814 } |
| OLD | NEW |