| 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 1822 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2043 beginExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE); | 2047 beginExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE); |
| 2044 checkObject(input, '==='); | 2048 checkObject(input, '==='); |
| 2045 buffer.add(" && "); | 2049 buffer.add(" && "); |
| 2046 checkType(input, element); | 2050 checkType(input, element); |
| 2047 endExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE); | 2051 endExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE); |
| 2048 endExpression(JSPrecedence.LOGICAL_OR_PRECEDENCE); | 2052 endExpression(JSPrecedence.LOGICAL_OR_PRECEDENCE); |
| 2049 } | 2053 } |
| 2050 | 2054 |
| 2051 void checkType(HInstruction input, Element element) { | 2055 void checkType(HInstruction input, Element element) { |
| 2052 bool requiresNativeIsCheck = | 2056 bool requiresNativeIsCheck = |
| 2053 compiler.emitter.nativeEmitter.requiresNativeIsCheck(element); | 2057 backend.emitter.nativeEmitter.requiresNativeIsCheck(element); |
| 2054 if (!requiresNativeIsCheck) buffer.add('!!'); | 2058 if (!requiresNativeIsCheck) buffer.add('!!'); |
| 2055 use(input, JSPrecedence.MEMBER_PRECEDENCE); | 2059 use(input, JSPrecedence.MEMBER_PRECEDENCE); |
| 2056 buffer.add('.'); | 2060 buffer.add('.'); |
| 2057 buffer.add(compiler.namer.operatorIs(element)); | 2061 buffer.add(compiler.namer.operatorIs(element)); |
| 2058 if (requiresNativeIsCheck) buffer.add('()'); | 2062 if (requiresNativeIsCheck) buffer.add('()'); |
| 2059 } | 2063 } |
| 2060 | 2064 |
| 2061 void handleStringSupertypeCheck(HInstruction input, Element element) { | 2065 void handleStringSupertypeCheck(HInstruction input, Element element) { |
| 2062 // Make sure List and String don't share supertypes, otherwise we | 2066 // Make sure List and String don't share supertypes, otherwise we |
| 2063 // would need to check for List too. | 2067 // would need to check for List too. |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2162 endExpression(JSPrecedence.LOGICAL_OR_PRECEDENCE); | 2166 endExpression(JSPrecedence.LOGICAL_OR_PRECEDENCE); |
| 2163 } | 2167 } |
| 2164 } | 2168 } |
| 2165 | 2169 |
| 2166 void visitTypeConversion(HTypeConversion node) { | 2170 void visitTypeConversion(HTypeConversion node) { |
| 2167 if (node.checked) { | 2171 if (node.checked) { |
| 2168 Element element = node.type.computeType(compiler).element; | 2172 Element element = node.type.computeType(compiler).element; |
| 2169 compiler.registerIsCheck(element); | 2173 compiler.registerIsCheck(element); |
| 2170 SourceString helper; | 2174 SourceString helper; |
| 2171 String additionalArgument; | 2175 String additionalArgument; |
| 2172 bool nativeCheck = | 2176 bool nativeCheck = nativeEmitter.requiresNativeIsCheck(element); |
| 2173 compiler.emitter.nativeEmitter.requiresNativeIsCheck(element); | |
| 2174 beginExpression(JSPrecedence.CALL_PRECEDENCE); | 2177 beginExpression(JSPrecedence.CALL_PRECEDENCE); |
| 2175 | 2178 |
| 2176 if (element == compiler.stringClass) { | 2179 if (element == compiler.stringClass) { |
| 2177 helper = const SourceString('stringTypeCheck'); | 2180 helper = const SourceString('stringTypeCheck'); |
| 2178 } else if (element == compiler.doubleClass) { | 2181 } else if (element == compiler.doubleClass) { |
| 2179 helper = const SourceString('doubleTypeCheck'); | 2182 helper = const SourceString('doubleTypeCheck'); |
| 2180 } else if (element == compiler.numClass) { | 2183 } else if (element == compiler.numClass) { |
| 2181 helper = const SourceString('numTypeCheck'); | 2184 helper = const SourceString('numTypeCheck'); |
| 2182 } else if (element == compiler.boolClass) { | 2185 } else if (element == compiler.boolClass) { |
| 2183 helper = const SourceString('boolTypeCheck'); | 2186 helper = const SourceString('boolTypeCheck'); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2215 if (additionalArgument !== null) buffer.add(", '$additionalArgument'"); | 2218 if (additionalArgument !== null) buffer.add(", '$additionalArgument'"); |
| 2216 buffer.add(')'); | 2219 buffer.add(')'); |
| 2217 endExpression(JSPrecedence.CALL_PRECEDENCE); | 2220 endExpression(JSPrecedence.CALL_PRECEDENCE); |
| 2218 } else { | 2221 } else { |
| 2219 use(node.checkedInput, expectedPrecedence); | 2222 use(node.checkedInput, expectedPrecedence); |
| 2220 } | 2223 } |
| 2221 } | 2224 } |
| 2222 } | 2225 } |
| 2223 | 2226 |
| 2224 class SsaOptimizedCodeGenerator extends SsaCodeGenerator { | 2227 class SsaOptimizedCodeGenerator extends SsaCodeGenerator { |
| 2225 SsaOptimizedCodeGenerator(compiler, work, parameters, parameterNames) | 2228 SsaOptimizedCodeGenerator(backend, work, parameters, parameterNames) |
| 2226 : super(compiler, work, parameters, parameterNames); | 2229 : super(backend, work, parameters, parameterNames); |
| 2227 | 2230 |
| 2228 void beginGraph(HGraph graph) {} | 2231 void beginGraph(HGraph graph) {} |
| 2229 void endGraph(HGraph graph) {} | 2232 void endGraph(HGraph graph) {} |
| 2230 | 2233 |
| 2231 void bailout(HTypeGuard guard, String reason) { | 2234 void bailout(HTypeGuard guard, String reason) { |
| 2232 HInstruction input = guard.guarded; | 2235 HInstruction input = guard.guarded; |
| 2233 Namer namer = compiler.namer; | 2236 Namer namer = compiler.namer; |
| 2234 Element element = work.element; | 2237 Element element = work.element; |
| 2235 buffer.add('return '); | 2238 buffer.add('return '); |
| 2236 if (element.isInstanceMember()) { | 2239 if (element.isInstanceMember()) { |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2384 } | 2387 } |
| 2385 } | 2388 } |
| 2386 | 2389 |
| 2387 class SsaUnoptimizedCodeGenerator extends SsaCodeGenerator { | 2390 class SsaUnoptimizedCodeGenerator extends SsaCodeGenerator { |
| 2388 | 2391 |
| 2389 final StringBuffer setup; | 2392 final StringBuffer setup; |
| 2390 final List<String> labels; | 2393 final List<String> labels; |
| 2391 int labelId = 0; | 2394 int labelId = 0; |
| 2392 int maxBailoutParameters = 0; | 2395 int maxBailoutParameters = 0; |
| 2393 | 2396 |
| 2394 SsaUnoptimizedCodeGenerator(compiler, work, parameters, parameterNames) | 2397 SsaUnoptimizedCodeGenerator(backend, work, parameters, parameterNames) |
| 2395 : super(compiler, work, parameters, parameterNames), | 2398 : super(backend, work, parameters, parameterNames), |
| 2396 setup = new StringBuffer(), | 2399 setup = new StringBuffer(), |
| 2397 labels = <String>[]; | 2400 labels = <String>[]; |
| 2398 | 2401 |
| 2399 String pushLabel() { | 2402 String pushLabel() { |
| 2400 String label = 'L${labelId++}'; | 2403 String label = 'L${labelId++}'; |
| 2401 labels.addLast(label); | 2404 labels.addLast(label); |
| 2402 return label; | 2405 return label; |
| 2403 } | 2406 } |
| 2404 | 2407 |
| 2405 String popLabel() { | 2408 String popLabel() { |
| (...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2617 startBailoutSwitch(); | 2620 startBailoutSwitch(); |
| 2618 } | 2621 } |
| 2619 } | 2622 } |
| 2620 | 2623 |
| 2621 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { | 2624 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { |
| 2622 if (labeledBlockInfo.body.start.hasGuards()) { | 2625 if (labeledBlockInfo.body.start.hasGuards()) { |
| 2623 endBailoutSwitch(); | 2626 endBailoutSwitch(); |
| 2624 } | 2627 } |
| 2625 } | 2628 } |
| 2626 } | 2629 } |
| OLD | NEW |