| 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 SsaCodeGeneratorTask(Compiler compiler) : super(compiler); | 6 final JavaScriptBackend backend; |
| 7 SsaCodeGeneratorTask(JavaScriptBackend backend) |
| 8 : this.backend = backend, |
| 9 super(backend.compiler); |
| 7 String get name() => 'SSA code generator'; | 10 String get name() => 'SSA code generator'; |
| 11 NativeEmitter get nativeEmitter() => backend.emitter.nativeEmitter; |
| 8 | 12 |
| 9 | 13 |
| 10 String buildJavaScriptFunction(FunctionElement element, | 14 String buildJavaScriptFunction(FunctionElement element, |
| 11 String parameters, | 15 String parameters, |
| 12 String body) { | 16 String body) { |
| 13 String extraSpace = ""; | 17 String extraSpace = ""; |
| 14 // Members are emitted inside a JavaScript object literal. To line up the | 18 // Members are emitted inside a JavaScript object literal. To line up the |
| 15 // indentation we want the closing curly brace to be indented by one space. | 19 // indentation we want the closing curly brace to be indented by one space. |
| 16 // Example: | 20 // Example: |
| 17 // defineClass("A", "B", ... , { | 21 // defineClass("A", "B", ... , { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 30 } | 34 } |
| 31 return 'function($parameters) {\n$body$extraSpace}'; | 35 return 'function($parameters) {\n$body$extraSpace}'; |
| 32 } | 36 } |
| 33 | 37 |
| 34 String generateMethod(WorkItem work, HGraph graph) { | 38 String generateMethod(WorkItem work, HGraph graph) { |
| 35 return measure(() { | 39 return measure(() { |
| 36 compiler.tracer.traceGraph("codegen", graph); | 40 compiler.tracer.traceGraph("codegen", graph); |
| 37 Map<Element, String> parameterNames = getParameterNames(work); | 41 Map<Element, String> parameterNames = getParameterNames(work); |
| 38 String parameters = Strings.join(parameterNames.getValues(), ', '); | 42 String parameters = Strings.join(parameterNames.getValues(), ', '); |
| 39 SsaOptimizedCodeGenerator codegen = new SsaOptimizedCodeGenerator( | 43 SsaOptimizedCodeGenerator codegen = new SsaOptimizedCodeGenerator( |
| 40 compiler, work, parameters, parameterNames); | 44 backend, work, parameters, parameterNames); |
| 41 codegen.visitGraph(graph); | 45 codegen.visitGraph(graph); |
| 42 | 46 |
| 43 FunctionElement element = work.element; | 47 FunctionElement element = work.element; |
| 44 String code; | 48 String code; |
| 45 if (element.isInstanceMember() | 49 if (element.isInstanceMember() |
| 46 && element.enclosingElement.isClass() | 50 && element.enclosingElement.isClass() |
| 47 && element.enclosingElement.isNative() | 51 && element.enclosingElement.isNative() |
| 48 && native.isOverriddenMethod(element, | 52 && native.isOverriddenMethod( |
| 49 element.enclosingElement, | 53 element, element.enclosingElement, nativeEmitter)) { |
| 50 compiler.emitter.nativeEmitter)) { | |
| 51 // Record that this method is overridden. In case of optional | 54 // Record that this method is overridden. In case of optional |
| 52 // arguments, the emitter will generate stubs to handle them, | 55 // arguments, the emitter will generate stubs to handle them, |
| 53 // and needs to know if the method is overridden. | 56 // and needs to know if the method is overridden. |
| 54 compiler.emitter.nativeEmitter.overriddenMethods.add(element); | 57 nativeEmitter.overriddenMethods.add(element); |
| 55 StringBuffer buffer = new StringBuffer(); | 58 StringBuffer buffer = new StringBuffer(); |
| 56 native.generateMethodWithPrototypeCheckForElement( | 59 native.generateMethodWithPrototypeCheckForElement( |
| 57 compiler, buffer, element, '${codegen.buffer}', parameters); | 60 compiler, buffer, element, '${codegen.buffer}', parameters); |
| 58 code = buffer.toString(); | 61 code = buffer.toString(); |
| 59 } else { | 62 } else { |
| 60 code = codegen.buffer.toString(); | 63 code = codegen.buffer.toString(); |
| 61 } | 64 } |
| 62 return buildJavaScriptFunction(element, parameters, code); | 65 return buildJavaScriptFunction(element, parameters, code); |
| 63 }); | 66 }); |
| 64 } | 67 } |
| 65 | 68 |
| 66 String generateBailoutMethod(WorkItem work, HGraph graph) { | 69 String generateBailoutMethod(WorkItem work, HGraph graph) { |
| 67 return measure(() { | 70 return measure(() { |
| 68 compiler.tracer.traceGraph("codegen-bailout", graph); | 71 compiler.tracer.traceGraph("codegen-bailout", graph); |
| 69 new SsaBailoutPropagator(compiler).visitGraph(graph); | 72 new SsaBailoutPropagator(compiler).visitGraph(graph); |
| 70 | 73 |
| 71 Map<Element, String> parameterNames = getParameterNames(work); | 74 Map<Element, String> parameterNames = getParameterNames(work); |
| 72 String parameters = Strings.join(parameterNames.getValues(), ', '); | 75 String parameters = Strings.join(parameterNames.getValues(), ', '); |
| 73 SsaUnoptimizedCodeGenerator codegen = new SsaUnoptimizedCodeGenerator( | 76 SsaUnoptimizedCodeGenerator codegen = new SsaUnoptimizedCodeGenerator( |
| 74 compiler, work, parameters, parameterNames); | 77 backend, work, parameters, parameterNames); |
| 75 codegen.visitGraph(graph); | 78 codegen.visitGraph(graph); |
| 76 | 79 |
| 77 StringBuffer newParameters = new StringBuffer(); | 80 StringBuffer newParameters = new StringBuffer(); |
| 78 if (!parameterNames.isEmpty()) newParameters.add('$parameters, '); | 81 if (!parameterNames.isEmpty()) newParameters.add('$parameters, '); |
| 79 newParameters.add('state'); | 82 newParameters.add('state'); |
| 80 | 83 |
| 81 for (int i = 0; i < codegen.maxBailoutParameters; i++) { | 84 for (int i = 0; i < codegen.maxBailoutParameters; i++) { |
| 82 newParameters.add(', env$i'); | 85 newParameters.add(', env$i'); |
| 83 } | 86 } |
| 84 | 87 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 130 * expression, and that it only generates expressions of the form | 133 * expression, and that it only generates expressions of the form |
| 131 * variable = expression | 134 * variable = expression |
| 132 * which are also valid as parts of a "var" declaration. | 135 * which are also valid as parts of a "var" declaration. |
| 133 */ | 136 */ |
| 134 static final int TYPE_STATEMENT = 0; | 137 static final int TYPE_STATEMENT = 0; |
| 135 static final int TYPE_EXPRESSION = 1; | 138 static final int TYPE_EXPRESSION = 1; |
| 136 static final int TYPE_DECLARATION = 2; | 139 static final int TYPE_DECLARATION = 2; |
| 137 | 140 |
| 138 static final String TEMPORARY_PREFIX = 't'; | 141 static final String TEMPORARY_PREFIX = 't'; |
| 139 | 142 |
| 140 final Compiler compiler; | 143 final JavaScriptBackend backend; |
| 141 final WorkItem work; | 144 final WorkItem work; |
| 142 final StringBuffer buffer; | 145 final StringBuffer buffer; |
| 143 final String parameters; | 146 final String parameters; |
| 144 | 147 |
| 145 final Map<Element, String> parameterNames; | 148 final Map<Element, String> parameterNames; |
| 146 final Map<int, String> names; | 149 final Map<int, String> names; |
| 147 final Set<String> usedNames; | 150 final Set<String> usedNames; |
| 148 final Set<HInstruction> declaredInstructions; | 151 final Set<HInstruction> declaredInstructions; |
| 149 final Map<String, int> prefixes; | 152 final Map<String, int> prefixes; |
| 150 final Set<HInstruction> generateAtUseSite; | 153 final Set<HInstruction> generateAtUseSite; |
| (...skipping 21 matching lines...) Expand all Loading... |
| 172 HBasicBlock currentBlock; | 175 HBasicBlock currentBlock; |
| 173 | 176 |
| 174 // Records a block-information that is being handled specially. | 177 // Records a block-information that is being handled specially. |
| 175 // Used to break bad recursion. | 178 // Used to break bad recursion. |
| 176 HBlockInformation currentBlockInformation; | 179 HBlockInformation currentBlockInformation; |
| 177 // The subgraph is used to delimit traversal for some constructions, e.g., | 180 // The subgraph is used to delimit traversal for some constructions, e.g., |
| 178 // if branches. | 181 // if branches. |
| 179 SubGraph subGraph; | 182 SubGraph subGraph; |
| 180 | 183 |
| 181 LibraryElement get currentLibrary() => work.element.getLibrary(); | 184 LibraryElement get currentLibrary() => work.element.getLibrary(); |
| 185 Compiler get compiler() => backend.compiler; |
| 182 | 186 |
| 183 bool isGenerateAtUseSite(HInstruction instruction) { | 187 bool isGenerateAtUseSite(HInstruction instruction) { |
| 184 return generateAtUseSite.contains(instruction); | 188 return generateAtUseSite.contains(instruction); |
| 185 } | 189 } |
| 186 | 190 |
| 187 SsaCodeGenerator(this.compiler, | 191 SsaCodeGenerator(this.backend, |
| 188 this.work, | 192 this.work, |
| 189 this.parameters, | 193 this.parameters, |
| 190 this.parameterNames) | 194 this.parameterNames) |
| 191 : names = new Map<int, String>(), | 195 : names = new Map<int, String>(), |
| 192 prefixes = new Map<String, int>(), | 196 prefixes = new Map<String, int>(), |
| 193 usedNames = new Set<String>(), | 197 usedNames = new Set<String>(), |
| 194 declaredInstructions = new Set<HInstruction>(), | 198 declaredInstructions = new Set<HInstruction>(), |
| 195 buffer = new StringBuffer(), | 199 buffer = new StringBuffer(), |
| 196 generateAtUseSite = new Set<HInstruction>(), | 200 generateAtUseSite = new Set<HInstruction>(), |
| 197 logicalOperations = new Map<HPhi, String>(), | 201 logicalOperations = new Map<HPhi, String>(), |
| 198 breakAction = new Map<Element, ElementAction>(), | 202 breakAction = new Map<Element, ElementAction>(), |
| 199 continueAction = new Map<Element, ElementAction>(), | 203 continueAction = new Map<Element, ElementAction>(), |
| 200 phiEquivalence = new Equivalence<HPhi>(), | 204 phiEquivalence = new Equivalence<HPhi>(), |
| 201 unsignedShiftPrecedences = JSPrecedence.binary['>>>'] { | 205 unsignedShiftPrecedences = JSPrecedence.binary['>>>'] { |
| 202 | 206 |
| 203 for (final name in parameterNames.getValues()) { | 207 for (final name in parameterNames.getValues()) { |
| 204 prefixes[name] = 0; | 208 prefixes[name] = 0; |
| 205 } | 209 } |
| 206 | 210 |
| 207 // Create a namespace for temporaries. | 211 // Create a namespace for temporaries. |
| 208 prefixes[TEMPORARY_PREFIX] = 0; | 212 prefixes[TEMPORARY_PREFIX] = 0; |
| 209 | 213 |
| 210 Interceptors interceptors = compiler.builder.interceptors; | 214 Interceptors interceptors = backend.builder.interceptors; |
| 211 equalsNullElement = interceptors.getEqualsNullInterceptor(); | 215 equalsNullElement = interceptors.getEqualsNullInterceptor(); |
| 212 boolifiedEqualsNullElement = | 216 boolifiedEqualsNullElement = |
| 213 interceptors.getBoolifiedVersionOf(equalsNullElement); | 217 interceptors.getBoolifiedVersionOf(equalsNullElement); |
| 214 } | 218 } |
| 215 | 219 |
| 216 abstract visitTypeGuard(HTypeGuard node); | 220 abstract visitTypeGuard(HTypeGuard node); |
| 217 | 221 |
| 218 abstract beginGraph(HGraph graph); | 222 abstract beginGraph(HGraph graph); |
| 219 abstract endGraph(HGraph graph); | 223 abstract endGraph(HGraph graph); |
| 220 | 224 |
| (...skipping 1815 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2036 beginExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE); | 2040 beginExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE); |
| 2037 checkObject(input, '==='); | 2041 checkObject(input, '==='); |
| 2038 buffer.add(" && "); | 2042 buffer.add(" && "); |
| 2039 checkType(input, element); | 2043 checkType(input, element); |
| 2040 endExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE); | 2044 endExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE); |
| 2041 endExpression(JSPrecedence.LOGICAL_OR_PRECEDENCE); | 2045 endExpression(JSPrecedence.LOGICAL_OR_PRECEDENCE); |
| 2042 } | 2046 } |
| 2043 | 2047 |
| 2044 void checkType(HInstruction input, Element element) { | 2048 void checkType(HInstruction input, Element element) { |
| 2045 bool requiresNativeIsCheck = | 2049 bool requiresNativeIsCheck = |
| 2046 compiler.emitter.nativeEmitter.requiresNativeIsCheck(element); | 2050 compiler.backend.emitter.nativeEmitter.requiresNativeIsCheck(element); |
| 2047 if (!requiresNativeIsCheck) buffer.add('!!'); | 2051 if (!requiresNativeIsCheck) buffer.add('!!'); |
| 2048 use(input, JSPrecedence.MEMBER_PRECEDENCE); | 2052 use(input, JSPrecedence.MEMBER_PRECEDENCE); |
| 2049 buffer.add('.'); | 2053 buffer.add('.'); |
| 2050 buffer.add(compiler.namer.operatorIs(element)); | 2054 buffer.add(compiler.namer.operatorIs(element)); |
| 2051 if (requiresNativeIsCheck) buffer.add('()'); | 2055 if (requiresNativeIsCheck) buffer.add('()'); |
| 2052 } | 2056 } |
| 2053 | 2057 |
| 2054 void handleStringSupertypeCheck(HInstruction input, Element element) { | 2058 void handleStringSupertypeCheck(HInstruction input, Element element) { |
| 2055 // Make sure List and String don't share supertypes, otherwise we | 2059 // Make sure List and String don't share supertypes, otherwise we |
| 2056 // would need to check for List too. | 2060 // would need to check for List too. |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2155 endExpression(JSPrecedence.LOGICAL_OR_PRECEDENCE); | 2159 endExpression(JSPrecedence.LOGICAL_OR_PRECEDENCE); |
| 2156 } | 2160 } |
| 2157 } | 2161 } |
| 2158 | 2162 |
| 2159 void visitTypeConversion(HTypeConversion node) { | 2163 void visitTypeConversion(HTypeConversion node) { |
| 2160 if (node.checked) { | 2164 if (node.checked) { |
| 2161 Element element = node.type.computeType(compiler).element; | 2165 Element element = node.type.computeType(compiler).element; |
| 2162 compiler.registerIsCheck(element); | 2166 compiler.registerIsCheck(element); |
| 2163 SourceString helper; | 2167 SourceString helper; |
| 2164 String additionalArgument; | 2168 String additionalArgument; |
| 2165 bool nativeCheck = | 2169 bool nativeCheck = nativeEmitter.requiresNativeIsCheck(element); |
| 2166 compiler.emitter.nativeEmitter.requiresNativeIsCheck(element); | |
| 2167 beginExpression(JSPrecedence.CALL_PRECEDENCE); | 2170 beginExpression(JSPrecedence.CALL_PRECEDENCE); |
| 2168 | 2171 |
| 2169 if (element == compiler.stringClass) { | 2172 if (element == compiler.stringClass) { |
| 2170 helper = const SourceString('stringTypeCheck'); | 2173 helper = const SourceString('stringTypeCheck'); |
| 2171 } else if (element == compiler.doubleClass) { | 2174 } else if (element == compiler.doubleClass) { |
| 2172 helper = const SourceString('doubleTypeCheck'); | 2175 helper = const SourceString('doubleTypeCheck'); |
| 2173 } else if (element == compiler.numClass) { | 2176 } else if (element == compiler.numClass) { |
| 2174 helper = const SourceString('numTypeCheck'); | 2177 helper = const SourceString('numTypeCheck'); |
| 2175 } else if (element == compiler.boolClass) { | 2178 } else if (element == compiler.boolClass) { |
| 2176 helper = const SourceString('boolTypeCheck'); | 2179 helper = const SourceString('boolTypeCheck'); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2208 if (additionalArgument !== null) buffer.add(", '$additionalArgument'"); | 2211 if (additionalArgument !== null) buffer.add(", '$additionalArgument'"); |
| 2209 buffer.add(')'); | 2212 buffer.add(')'); |
| 2210 endExpression(JSPrecedence.CALL_PRECEDENCE); | 2213 endExpression(JSPrecedence.CALL_PRECEDENCE); |
| 2211 } else { | 2214 } else { |
| 2212 use(node.checkedInput, expectedPrecedence); | 2215 use(node.checkedInput, expectedPrecedence); |
| 2213 } | 2216 } |
| 2214 } | 2217 } |
| 2215 } | 2218 } |
| 2216 | 2219 |
| 2217 class SsaOptimizedCodeGenerator extends SsaCodeGenerator { | 2220 class SsaOptimizedCodeGenerator extends SsaCodeGenerator { |
| 2218 SsaOptimizedCodeGenerator(compiler, work, parameters, parameterNames) | 2221 SsaOptimizedCodeGenerator(backend, work, parameters, parameterNames) |
| 2219 : super(compiler, work, parameters, parameterNames); | 2222 : super(backend, work, parameters, parameterNames); |
| 2220 | 2223 |
| 2221 void beginGraph(HGraph graph) {} | 2224 void beginGraph(HGraph graph) {} |
| 2222 void endGraph(HGraph graph) {} | 2225 void endGraph(HGraph graph) {} |
| 2223 | 2226 |
| 2224 void bailout(HTypeGuard guard, String reason) { | 2227 void bailout(HTypeGuard guard, String reason) { |
| 2225 HInstruction input = guard.guarded; | 2228 HInstruction input = guard.guarded; |
| 2226 Namer namer = compiler.namer; | 2229 Namer namer = compiler.namer; |
| 2227 Element element = work.element; | 2230 Element element = work.element; |
| 2228 buffer.add('return '); | 2231 buffer.add('return '); |
| 2229 if (element.isInstanceMember()) { | 2232 if (element.isInstanceMember()) { |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2377 } | 2380 } |
| 2378 } | 2381 } |
| 2379 | 2382 |
| 2380 class SsaUnoptimizedCodeGenerator extends SsaCodeGenerator { | 2383 class SsaUnoptimizedCodeGenerator extends SsaCodeGenerator { |
| 2381 | 2384 |
| 2382 final StringBuffer setup; | 2385 final StringBuffer setup; |
| 2383 final List<String> labels; | 2386 final List<String> labels; |
| 2384 int labelId = 0; | 2387 int labelId = 0; |
| 2385 int maxBailoutParameters = 0; | 2388 int maxBailoutParameters = 0; |
| 2386 | 2389 |
| 2387 SsaUnoptimizedCodeGenerator(compiler, work, parameters, parameterNames) | 2390 SsaUnoptimizedCodeGenerator(backend, work, parameters, parameterNames) |
| 2388 : super(compiler, work, parameters, parameterNames), | 2391 : super(backend, work, parameters, parameterNames), |
| 2389 setup = new StringBuffer(), | 2392 setup = new StringBuffer(), |
| 2390 labels = <String>[]; | 2393 labels = <String>[]; |
| 2391 | 2394 |
| 2392 String pushLabel() { | 2395 String pushLabel() { |
| 2393 String label = 'L${labelId++}'; | 2396 String label = 'L${labelId++}'; |
| 2394 labels.addLast(label); | 2397 labels.addLast(label); |
| 2395 return label; | 2398 return label; |
| 2396 } | 2399 } |
| 2397 | 2400 |
| 2398 String popLabel() { | 2401 String popLabel() { |
| (...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2610 startBailoutSwitch(); | 2613 startBailoutSwitch(); |
| 2611 } | 2614 } |
| 2612 } | 2615 } |
| 2613 | 2616 |
| 2614 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { | 2617 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { |
| 2615 if (labeledBlockInfo.body.start.hasGuards()) { | 2618 if (labeledBlockInfo.body.start.hasGuards()) { |
| 2616 endBailoutSwitch(); | 2619 endBailoutSwitch(); |
| 2617 } | 2620 } |
| 2618 } | 2621 } |
| 2619 } | 2622 } |
| OLD | NEW |