| 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 part of ssa; | 5 part of ssa; |
| 6 | 6 |
| 7 class SsaCodeGeneratorTask extends CompilerTask { | 7 class SsaCodeGeneratorTask extends CompilerTask { |
| 8 | 8 |
| 9 final JavaScriptBackend backend; | 9 final JavaScriptBackend backend; |
| 10 | 10 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 47 if (work.element.isField()) { | 47 if (work.element.isField()) { |
| 48 return generateLazyInitializer(work, graph); | 48 return generateLazyInitializer(work, graph); |
| 49 } else { | 49 } else { |
| 50 return generateMethod(work, graph); | 50 return generateMethod(work, graph); |
| 51 } | 51 } |
| 52 } | 52 } |
| 53 | 53 |
| 54 CodeBuffer generateLazyInitializer(work, graph) { | 54 CodeBuffer generateLazyInitializer(work, graph) { |
| 55 return measure(() { | 55 return measure(() { |
| 56 compiler.tracer.traceGraph("codegen", graph); | 56 compiler.tracer.traceGraph("codegen", graph); |
| 57 List<js.Parameter> parameters = <js.Parameter>[]; | 57 SsaOptimizedCodeGenerator codegen = |
| 58 SsaOptimizedCodeGenerator codegen = new SsaOptimizedCodeGenerator( | 58 new SsaOptimizedCodeGenerator(backend, work); |
| 59 backend, work, parameters, new Map<Element, String>()); | |
| 60 codegen.visitGraph(graph); | 59 codegen.visitGraph(graph); |
| 61 js.Block body = codegen.body; | 60 js.Block body = codegen.body; |
| 62 js.Fun fun = new js.Fun(parameters, body); | 61 js.Fun fun = new js.Fun(codegen.parameters, body); |
| 63 return prettyPrint(fun); | 62 return prettyPrint(fun); |
| 64 }); | 63 }); |
| 65 } | 64 } |
| 66 | 65 |
| 67 CodeBuffer generateMethod(WorkItem work, HGraph graph) { | 66 CodeBuffer generateMethod(WorkItem work, HGraph graph) { |
| 68 return measure(() { | 67 return measure(() { |
| 69 JavaScriptItemCompilationContext context = work.compilationContext; | 68 JavaScriptItemCompilationContext context = work.compilationContext; |
| 70 HTypeMap types = context.types; | 69 HTypeMap types = context.types; |
| 71 graph.exit.predecessors.forEach((block) { | 70 graph.exit.predecessors.forEach((block) { |
| 72 assert(block.last is HGoto || block.last is HReturn); | 71 assert(block.last is HGoto || block.last is HReturn); |
| 73 if (block.last is HReturn) { | 72 if (block.last is HReturn) { |
| 74 backend.registerReturnType(work.element, types[block.last.inputs[0]]); | 73 backend.registerReturnType(work.element, types[block.last.inputs[0]]); |
| 75 } else { | 74 } else { |
| 76 backend.registerReturnType(work.element, HType.NULL); | 75 backend.registerReturnType(work.element, HType.NULL); |
| 77 } | 76 } |
| 78 }); | 77 }); |
| 79 compiler.tracer.traceGraph("codegen", graph); | 78 compiler.tracer.traceGraph("codegen", graph); |
| 80 Map<Element, String> parameterNames = getParameterNames(work); | 79 SsaOptimizedCodeGenerator codegen = |
| 81 // Use [work.element] to ensure that the parameter element come from | 80 new SsaOptimizedCodeGenerator(backend, work); |
| 82 // the declaration. | |
| 83 FunctionElement function = work.element; | |
| 84 function.computeSignature(compiler).forEachParameter((element) { | |
| 85 compiler.enqueuer.codegen.addToWorkList(element, work.resolutionTree); | |
| 86 }); | |
| 87 List<js.Parameter> parameters = <js.Parameter>[]; | |
| 88 parameterNames.forEach((element, name) { | |
| 89 parameters.add(new js.Parameter(name)); | |
| 90 }); | |
| 91 addBackendParameters(work.element, parameters, parameterNames); | |
| 92 String parametersString = Strings.join(parameterNames.values, ", "); | |
| 93 SsaOptimizedCodeGenerator codegen = new SsaOptimizedCodeGenerator( | |
| 94 backend, work, parameters, parameterNames); | |
| 95 codegen.visitGraph(graph); | 81 codegen.visitGraph(graph); |
| 96 | 82 |
| 97 FunctionElement element = work.element; | 83 FunctionElement element = work.element; |
| 98 js.Block body; | 84 js.Block body; |
| 99 ClassElement enclosingClass = element.getEnclosingClass(); | 85 ClassElement enclosingClass = element.getEnclosingClass(); |
| 100 bool allowVariableMinification; | 86 bool allowVariableMinification; |
| 101 if (element.isInstanceMember() | 87 if (element.isInstanceMember() |
| 102 && enclosingClass.isNative() | 88 && enclosingClass.isNative() |
| 103 && native.isOverriddenMethod( | 89 && native.isOverriddenMethod( |
| 104 element, enclosingClass, nativeEmitter)) { | 90 element, enclosingClass, nativeEmitter)) { |
| 105 // Record that this method is overridden. In case of optional | 91 // Record that this method is overridden. In case of optional |
| 106 // arguments, the emitter will generate stubs to handle them, | 92 // arguments, the emitter will generate stubs to handle them, |
| 107 // and needs to know if the method is overridden. | 93 // and needs to know if the method is overridden. |
| 108 nativeEmitter.overriddenMethods.add(element); | 94 nativeEmitter.overriddenMethods.add(element); |
| 109 StringBuffer buffer = new StringBuffer(); | 95 StringBuffer buffer = new StringBuffer(); |
| 110 String codeString = prettyPrint(codegen.body).toString(); | 96 String codeString = prettyPrint(codegen.body).toString(); |
| 97 String parametersString = |
| 98 Strings.join(codegen.parameterNames.values, ", "); |
| 111 native.generateMethodWithPrototypeCheckForElement( | 99 native.generateMethodWithPrototypeCheckForElement( |
| 112 compiler, buffer, element, codeString, parametersString); | 100 compiler, buffer, element, codeString, parametersString); |
| 113 js.Node nativeCode = new js.LiteralStatement(buffer.toString()); | 101 js.Node nativeCode = new js.LiteralStatement(buffer.toString()); |
| 114 body = new js.Block(<js.Statement>[nativeCode]); | 102 body = new js.Block(<js.Statement>[nativeCode]); |
| 115 allowVariableMinification = false; | 103 allowVariableMinification = false; |
| 116 } else { | 104 } else { |
| 117 body = codegen.body; | 105 body = codegen.body; |
| 118 allowVariableMinification = !codegen.visitedForeignCode; | 106 allowVariableMinification = !codegen.visitedForeignCode; |
| 119 } | 107 } |
| 120 js.Fun fun = buildJavaScriptFunction(element, parameters, body); | 108 js.Fun fun = buildJavaScriptFunction(element, codegen.parameters, body); |
| 121 return prettyPrint(fun, | 109 return prettyPrint(fun, |
| 122 allowVariableMinification: allowVariableMinification); | 110 allowVariableMinification: allowVariableMinification); |
| 123 }); | 111 }); |
| 124 } | 112 } |
| 125 | 113 |
| 126 void addBackendParameter(Element element, | |
| 127 List<js.Parameter> parameters, | |
| 128 Map<Element, String> parameterNames) { | |
| 129 String name = element.name.slowToString(); | |
| 130 String prefix = ''; | |
| 131 // Avoid collisions with real parameters of the method. | |
| 132 do { | |
| 133 name = JsNames.getValid('$prefix$name'); | |
| 134 prefix = '\$$prefix'; | |
| 135 } while (parameterNames.containsValue(name)); | |
| 136 parameterNames[element] = name; | |
| 137 parameters.add(new js.Parameter(name)); | |
| 138 } | |
| 139 | |
| 140 void addBackendParameters(Element element, | |
| 141 List<js.Parameter> parameters, | |
| 142 Map<Element, String> parameterNames) { | |
| 143 // TODO(ngeoffray): We should infer this information from the | |
| 144 // graph, instead of recomputing what the builder did. | |
| 145 if (element.isConstructor()) { | |
| 146 // Put the type parameters. | |
| 147 ClassElement cls = element.enclosingElement; | |
| 148 if (!compiler.world.needsRti(cls)) return; | |
| 149 cls.typeVariables.forEach((TypeVariableType typeVariable) { | |
| 150 addBackendParameter(typeVariable.element, parameters, parameterNames); | |
| 151 }); | |
| 152 } else if (element.isGenerativeConstructorBody()) { | |
| 153 // Put the parameter checks parameters. | |
| 154 Node node = element.implementation.parseNode(compiler); | |
| 155 ClosureClassMap closureData = | |
| 156 compiler.closureToClassMapper.getMappingForNestedFunction(node); | |
| 157 FunctionElement functionElement = element; | |
| 158 FunctionSignature params = functionElement.computeSignature(compiler); | |
| 159 TreeElements elements = | |
| 160 compiler.enqueuer.resolution.getCachedElements(element); | |
| 161 params.orderedForEachParameter((Element element) { | |
| 162 if (elements.isParameterChecked(element)) { | |
| 163 Element checkResultElement = | |
| 164 closureData.parametersWithSentinel[element]; | |
| 165 addBackendParameter(checkResultElement, parameters, parameterNames); | |
| 166 } | |
| 167 }); | |
| 168 // Put the box parameter. | |
| 169 ClosureScope scopeData = closureData.capturingScopes[node]; | |
| 170 if (scopeData != null) { | |
| 171 addBackendParameter(scopeData.boxElement, parameters, parameterNames); | |
| 172 } | |
| 173 } | |
| 174 } | |
| 175 | |
| 176 CodeBuffer generateBailoutMethod(WorkItem work, HGraph graph) { | 114 CodeBuffer generateBailoutMethod(WorkItem work, HGraph graph) { |
| 177 return measure(() { | 115 return measure(() { |
| 178 compiler.tracer.traceGraph("codegen-bailout", graph); | 116 compiler.tracer.traceGraph("codegen-bailout", graph); |
| 179 | 117 |
| 180 Map<Element, String> parameterNames = getParameterNames(work); | 118 SsaUnoptimizedCodeGenerator codegen = |
| 181 List<js.Parameter> parameters = <js.Parameter>[]; | 119 new SsaUnoptimizedCodeGenerator(backend, work); |
| 182 parameterNames.forEach((element, name) { | |
| 183 parameters.add(new js.Parameter(name)); | |
| 184 }); | |
| 185 addBackendParameters(work.element, parameters, parameterNames); | |
| 186 | |
| 187 SsaUnoptimizedCodeGenerator codegen = new SsaUnoptimizedCodeGenerator( | |
| 188 backend, work, parameters, parameterNames); | |
| 189 codegen.visitGraph(graph); | 120 codegen.visitGraph(graph); |
| 190 | 121 |
| 191 js.Block body = new js.Block(<js.Statement>[]); | 122 js.Block body = new js.Block(<js.Statement>[]); |
| 192 if (codegen.setup != null) body.statements.add(codegen.setup); | 123 if (codegen.setup != null) body.statements.add(codegen.setup); |
| 193 body.statements.add(codegen.body); | 124 body.statements.add(codegen.body); |
| 194 js.Fun fun = | 125 js.Fun fun = |
| 195 buildJavaScriptFunction(work.element, codegen.newParameters, body); | 126 buildJavaScriptFunction(work.element, codegen.newParameters, body); |
| 196 return prettyPrint(fun); | 127 return prettyPrint(fun); |
| 197 }); | 128 }); |
| 198 } | 129 } |
| 199 | |
| 200 Map<Element, String> getParameterNames(WorkItem work) { | |
| 201 // Make sure the map preserves insertion order, so that fetching | |
| 202 // the values will keep the order of parameters. | |
| 203 Map<Element, String> parameterNames = new LinkedHashMap<Element, String>(); | |
| 204 FunctionElement function = work.element.implementation; | |
| 205 | |
| 206 // The dom/html libraries have inline JS code that reference | |
| 207 // parameter names directly. Long-term such code will be rejected. | |
| 208 // Now, just don't mangle the parameter name. | |
| 209 FunctionSignature signature = function.computeSignature(compiler); | |
| 210 signature.orderedForEachParameter((Element element) { | |
| 211 parameterNames[element] = function.isNative() | |
| 212 ? element.name.slowToString() | |
| 213 : JsNames.getValid('${element.name.slowToString()}'); | |
| 214 }); | |
| 215 return parameterNames; | |
| 216 } | |
| 217 } | 130 } |
| 218 | 131 |
| 219 // Stop-gap until the core classes have such a class. | 132 // Stop-gap until the core classes have such a class. |
| 220 class OrderedSet<T> { | 133 class OrderedSet<T> { |
| 221 final LinkedHashMap<T, bool> map = new LinkedHashMap<T, bool>(); | 134 final LinkedHashMap<T, bool> map = new LinkedHashMap<T, bool>(); |
| 222 | 135 |
| 223 void add(T x) { | 136 void add(T x) { |
| 224 if (!map.containsKey(x)) { | 137 if (!map.containsKey(x)) { |
| 225 map[x] = true; | 138 map[x] = true; |
| 226 } | 139 } |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 268 | 181 |
| 269 final JavaScriptBackend backend; | 182 final JavaScriptBackend backend; |
| 270 final WorkItem work; | 183 final WorkItem work; |
| 271 final HTypeMap types; | 184 final HTypeMap types; |
| 272 | 185 |
| 273 final Set<HInstruction> generateAtUseSite; | 186 final Set<HInstruction> generateAtUseSite; |
| 274 final Set<HInstruction> controlFlowOperators; | 187 final Set<HInstruction> controlFlowOperators; |
| 275 final Map<Element, ElementAction> breakAction; | 188 final Map<Element, ElementAction> breakAction; |
| 276 final Map<Element, ElementAction> continueAction; | 189 final Map<Element, ElementAction> continueAction; |
| 277 final Map<Element, String> parameterNames; | 190 final Map<Element, String> parameterNames; |
| 191 final List<js.Parameter> parameters; |
| 278 | 192 |
| 279 js.Block currentContainer; | 193 js.Block currentContainer; |
| 280 js.Block get body => currentContainer; | 194 js.Block get body => currentContainer; |
| 281 List<js.Expression> expressionStack; | 195 List<js.Expression> expressionStack; |
| 282 List<js.Block> oldContainerStack; | 196 List<js.Block> oldContainerStack; |
| 283 | 197 |
| 284 /** | 198 /** |
| 285 * Contains the names of the instructions, as well as the parallel | 199 * Contains the names of the instructions, as well as the parallel |
| 286 * copies to perform on block transitioning. | 200 * copies to perform on block transitioning. |
| 287 */ | 201 */ |
| (...skipping 19 matching lines...) Expand all Loading... |
| 307 HGraph currentGraph; | 221 HGraph currentGraph; |
| 308 HBasicBlock currentBlock; | 222 HBasicBlock currentBlock; |
| 309 | 223 |
| 310 // Records a block-information that is being handled specially. | 224 // Records a block-information that is being handled specially. |
| 311 // Used to break bad recursion. | 225 // Used to break bad recursion. |
| 312 HBlockInformation currentBlockInformation; | 226 HBlockInformation currentBlockInformation; |
| 313 // The subgraph is used to delimit traversal for some constructions, e.g., | 227 // The subgraph is used to delimit traversal for some constructions, e.g., |
| 314 // if branches. | 228 // if branches. |
| 315 SubGraph subGraph; | 229 SubGraph subGraph; |
| 316 | 230 |
| 317 SsaCodeGenerator(this.backend, | 231 SsaCodeGenerator(this.backend, WorkItem work) |
| 318 WorkItem work, | |
| 319 this.parameterNames) | |
| 320 : this.work = work, | 232 : this.work = work, |
| 321 this.types = | 233 this.types = |
| 322 (work.compilationContext as JavaScriptItemCompilationContext).types, | 234 (work.compilationContext as JavaScriptItemCompilationContext).types, |
| 235 parameterNames = new LinkedHashMap<Element, String>(), |
| 323 declaredLocals = new Set<String>(), | 236 declaredLocals = new Set<String>(), |
| 324 collectedVariableDeclarations = new OrderedSet<String>(), | 237 collectedVariableDeclarations = new OrderedSet<String>(), |
| 325 currentContainer = new js.Block.empty(), | 238 currentContainer = new js.Block.empty(), |
| 239 parameters = <js.Parameter>[], |
| 326 expressionStack = <js.Expression>[], | 240 expressionStack = <js.Expression>[], |
| 327 oldContainerStack = <js.Block>[], | 241 oldContainerStack = <js.Block>[], |
| 328 generateAtUseSite = new Set<HInstruction>(), | 242 generateAtUseSite = new Set<HInstruction>(), |
| 329 controlFlowOperators = new Set<HInstruction>(), | 243 controlFlowOperators = new Set<HInstruction>(), |
| 330 breakAction = new Map<Element, ElementAction>(), | 244 breakAction = new Map<Element, ElementAction>(), |
| 331 continueAction = new Map<Element, ElementAction>(); | 245 continueAction = new Map<Element, ElementAction>(); |
| 332 | 246 |
| 333 LibraryElement get currentLibrary => work.element.getLibrary(); | 247 LibraryElement get currentLibrary => work.element.getLibrary(); |
| 334 Compiler get compiler => backend.compiler; | 248 Compiler get compiler => backend.compiler; |
| 335 NativeEmitter get nativeEmitter => backend.emitter.nativeEmitter; | 249 NativeEmitter get nativeEmitter => backend.emitter.nativeEmitter; |
| (...skipping 574 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 910 currentBlockInformation = info.body.start.blockFlow.body; | 824 currentBlockInformation = info.body.start.blockFlow.body; |
| 911 generateStatements(info.body); | 825 generateStatements(info.body); |
| 912 currentBlockInformation = oldInfo; | 826 currentBlockInformation = oldInfo; |
| 913 } else { | 827 } else { |
| 914 generateStatements(info.body); | 828 generateStatements(info.body); |
| 915 } | 829 } |
| 916 } | 830 } |
| 917 | 831 |
| 918 bool visitLoopInfo(HLoopBlockInformation info) { | 832 bool visitLoopInfo(HLoopBlockInformation info) { |
| 919 HExpressionInformation condition = info.condition; | 833 HExpressionInformation condition = info.condition; |
| 920 bool isConditionExpression = isJSCondition(condition); | 834 bool isConditionExpression = condition == null || isJSCondition(condition); |
| 921 | 835 |
| 922 js.Loop loop; | 836 js.Loop loop; |
| 923 | 837 |
| 924 switch (info.kind) { | 838 switch (info.kind) { |
| 925 // Treate all three "test-first" loops the same way. | 839 // Treate all three "test-first" loops the same way. |
| 926 case HLoopBlockInformation.FOR_LOOP: | 840 case HLoopBlockInformation.FOR_LOOP: |
| 927 case HLoopBlockInformation.WHILE_LOOP: | 841 case HLoopBlockInformation.WHILE_LOOP: |
| 928 case HLoopBlockInformation.FOR_IN_LOOP: | 842 case HLoopBlockInformation.FOR_IN_LOOP: |
| 929 HBlockInformation initialization = info.initializer; | 843 HBlockInformation initialization = info.initializer; |
| 930 int initializationType = TYPE_STATEMENT; | 844 int initializationType = TYPE_STATEMENT; |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1022 generateStatements(info.updates); | 936 generateStatements(info.updates); |
| 1023 } else { | 937 } else { |
| 1024 visitBodyIgnoreLabels(info); | 938 visitBodyIgnoreLabels(info); |
| 1025 } | 939 } |
| 1026 currentContainer = oldContainer; | 940 currentContainer = oldContainer; |
| 1027 body = unwrapStatement(body); | 941 body = unwrapStatement(body); |
| 1028 loop = new js.While(jsCondition, body); | 942 loop = new js.While(jsCondition, body); |
| 1029 } | 943 } |
| 1030 break; | 944 break; |
| 1031 case HLoopBlockInformation.DO_WHILE_LOOP: | 945 case HLoopBlockInformation.DO_WHILE_LOOP: |
| 1032 // Generate do-while loop in all cases. | 946 // If there are phi copies after the condition, we cannot emit |
| 947 // a pretty do/while loop, se we fallback to the generic |
| 948 // emission of a loop. |
| 949 CopyHandler handler = variableNames.getCopyHandler(info.end); |
| 950 if (handler != null && !handler.isEmpty) return false; |
| 1033 if (info.initializer != null) { | 951 if (info.initializer != null) { |
| 1034 generateStatements(info.initializer); | 952 generateStatements(info.initializer); |
| 1035 } | 953 } |
| 1036 js.Block oldContainer = currentContainer; | 954 js.Block oldContainer = currentContainer; |
| 1037 js.Statement body = new js.Block.empty(); | 955 js.Statement body = new js.Block.empty(); |
| 1038 currentContainer = body; | 956 currentContainer = body; |
| 1039 if (!isConditionExpression || info.updates != null) { | 957 if (!isConditionExpression || info.updates != null) { |
| 1040 wrapLoopBodyForContinue(info); | 958 wrapLoopBodyForContinue(info); |
| 1041 } else { | 959 } else { |
| 1042 visitBodyIgnoreLabels(info); | 960 visitBodyIgnoreLabels(info); |
| 1043 } | 961 } |
| 1044 if (info.updates != null) { | 962 if (info.updates != null) { |
| 1045 generateStatements(info.updates); | 963 generateStatements(info.updates); |
| 1046 } | 964 } |
| 1047 if (isConditionExpression) { | 965 if (condition == null) { |
| 966 push(newLiteralBool(false)); |
| 967 } else if (isConditionExpression) { |
| 1048 push(generateExpression(condition)); | 968 push(generateExpression(condition)); |
| 1049 } else { | 969 } else { |
| 1050 generateStatements(condition); | 970 generateStatements(condition); |
| 1051 use(condition.conditionExpression); | 971 use(condition.conditionExpression); |
| 1052 } | 972 } |
| 1053 js.Expression jsCondition = pop(); | 973 js.Expression jsCondition = pop(); |
| 1054 currentContainer = oldContainer; | 974 currentContainer = oldContainer; |
| 1055 body = unwrapStatement(body); | 975 body = unwrapStatement(body); |
| 1056 loop = new js.Do(body, jsCondition); | 976 loop = new js.Do(body, jsCondition); |
| 1057 break; | 977 break; |
| (...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1317 void iterateBasicBlock(HBasicBlock node) { | 1237 void iterateBasicBlock(HBasicBlock node) { |
| 1318 HInstruction instruction = node.first; | 1238 HInstruction instruction = node.first; |
| 1319 while (!identical(instruction, node.last)) { | 1239 while (!identical(instruction, node.last)) { |
| 1320 if (instruction is HTypeGuard || instruction is HBailoutTarget) { | 1240 if (instruction is HTypeGuard || instruction is HBailoutTarget) { |
| 1321 visit(instruction); | 1241 visit(instruction); |
| 1322 } else if (!isGenerateAtUseSite(instruction)) { | 1242 } else if (!isGenerateAtUseSite(instruction)) { |
| 1323 define(instruction); | 1243 define(instruction); |
| 1324 } | 1244 } |
| 1325 instruction = instruction.next; | 1245 instruction = instruction.next; |
| 1326 } | 1246 } |
| 1327 assignPhisOfSuccessors(node); | 1247 if (instruction is HLoopBranch) { |
| 1248 HLoopBranch branch = instruction; |
| 1249 // If the loop is a do/while loop, the phi updates must happen |
| 1250 // after the evaluation of the condition. |
| 1251 if (!branch.isDoWhile()) { |
| 1252 assignPhisOfSuccessors(node); |
| 1253 } |
| 1254 } else { |
| 1255 assignPhisOfSuccessors(node); |
| 1256 } |
| 1328 visit(instruction); | 1257 visit(instruction); |
| 1329 } | 1258 } |
| 1330 | 1259 |
| 1331 visitInvokeBinary(HInvokeBinary node, String op) { | 1260 visitInvokeBinary(HInvokeBinary node, String op) { |
| 1332 if (node.isBuiltin(types)) { | 1261 if (node.isBuiltin(types)) { |
| 1333 use(node.left); | 1262 use(node.left); |
| 1334 js.Expression jsLeft = pop(); | 1263 js.Expression jsLeft = pop(); |
| 1335 use(node.right); | 1264 use(node.right); |
| 1336 push(new js.Binary(op, jsLeft, pop()), node); | 1265 push(new js.Binary(op, jsLeft, pop()), node); |
| 1337 } else { | 1266 } else { |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1493 node); | 1422 node); |
| 1494 } | 1423 } |
| 1495 } else { | 1424 } else { |
| 1496 TargetElement target = node.target; | 1425 TargetElement target = node.target; |
| 1497 if (!tryCallAction(continueAction, target)) { | 1426 if (!tryCallAction(continueAction, target)) { |
| 1498 pushStatement(new js.Continue(null), node); | 1427 pushStatement(new js.Continue(null), node); |
| 1499 } | 1428 } |
| 1500 } | 1429 } |
| 1501 } | 1430 } |
| 1502 | 1431 |
| 1432 visitExitTry(HExitTry node) { |
| 1433 // An [HExitTry] is used to represent the control flow graph of a |
| 1434 // try/catch block, ie the try body is always a predecessor |
| 1435 // of the catch and finally. Here, we continue visiting the try |
| 1436 // body by visiting the block that contains the user-level control |
| 1437 // flow instruction. |
| 1438 visitBasicBlock(node.bodyTrySuccessor); |
| 1439 } |
| 1440 |
| 1503 visitTry(HTry node) { | 1441 visitTry(HTry node) { |
| 1504 // We should never get here. Try/catch/finally is always handled using block | 1442 // We should never get here. Try/catch/finally is always handled using block |
| 1505 // information in [visitTryInfo], or not at all, in the case of the bailout | 1443 // information in [visitTryInfo], or not at all, in the case of the bailout |
| 1506 // generator. | 1444 // generator. |
| 1507 compiler.internalError('visitTry should not be called', instruction: node); | 1445 compiler.internalError('visitTry should not be called', instruction: node); |
| 1508 } | 1446 } |
| 1509 | 1447 |
| 1510 bool tryControlFlowOperation(HIf node) { | 1448 bool tryControlFlowOperation(HIf node) { |
| 1511 if (!controlFlowOperators.contains(node)) return false; | 1449 if (!controlFlowOperators.contains(node)) return false; |
| 1512 HPhi phi = node.joinBlock.phis.first; | 1450 HPhi phi = node.joinBlock.phis.first; |
| (...skipping 387 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1900 // Otherwise, we don't generate the expression, and leave that | 1838 // Otherwise, we don't generate the expression, and leave that |
| 1901 // to the code that called [visitSubGraph]. | 1839 // to the code that called [visitSubGraph]. |
| 1902 if (isGeneratingExpression) { | 1840 if (isGeneratingExpression) { |
| 1903 use(node.inputs[0]); | 1841 use(node.inputs[0]); |
| 1904 } | 1842 } |
| 1905 return; | 1843 return; |
| 1906 } | 1844 } |
| 1907 HBasicBlock branchBlock = currentBlock; | 1845 HBasicBlock branchBlock = currentBlock; |
| 1908 handleLoopCondition(node); | 1846 handleLoopCondition(node); |
| 1909 List<HBasicBlock> dominated = currentBlock.dominatedBlocks; | 1847 List<HBasicBlock> dominated = currentBlock.dominatedBlocks; |
| 1910 // For a do while loop, the body has already been visited. | 1848 if (node.isDoWhile()) { |
| 1911 if (!node.isDoWhile()) { | 1849 // Now that the condition has been evaluated, we can update the |
| 1850 // phis of a do/while loop. |
| 1851 assignPhisOfSuccessors(node.block); |
| 1852 } else { |
| 1853 // For a do while loop, the body has already been visited. |
| 1912 visitBasicBlock(dominated[0]); | 1854 visitBasicBlock(dominated[0]); |
| 1913 } | 1855 } |
| 1914 endLoop(node.block); | 1856 endLoop(node.block); |
| 1915 | 1857 |
| 1916 // If the branch does not dominate the code after the loop, the | 1858 // If the branch does not dominate the code after the loop, the |
| 1917 // dominator will visit it. | 1859 // dominator will visit it. |
| 1918 if (!identical(branchBlock.successors[1].dominator, branchBlock)) return; | 1860 if (!identical(branchBlock.successors[1].dominator, branchBlock)) return; |
| 1919 | 1861 |
| 1920 visitBasicBlock(branchBlock.successors[1]); | 1862 visitBasicBlock(branchBlock.successors[1]); |
| 1921 // With labeled breaks we can have more dominated blocks. | 1863 // With labeled breaks we can have more dominated blocks. |
| (...skipping 685 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2607 } | 2549 } |
| 2608 String helperName = backend.namer.isolateAccess(helperElement); | 2550 String helperName = backend.namer.isolateAccess(helperElement); |
| 2609 push(new js.Call(new js.VariableUse(helperName), arguments)); | 2551 push(new js.Call(new js.VariableUse(helperName), arguments)); |
| 2610 } else { | 2552 } else { |
| 2611 use(node.checkedInput); | 2553 use(node.checkedInput); |
| 2612 } | 2554 } |
| 2613 } | 2555 } |
| 2614 } | 2556 } |
| 2615 | 2557 |
| 2616 class SsaOptimizedCodeGenerator extends SsaCodeGenerator { | 2558 class SsaOptimizedCodeGenerator extends SsaCodeGenerator { |
| 2617 SsaOptimizedCodeGenerator(backend, work, parameters, parameterNames) | 2559 SsaOptimizedCodeGenerator(backend, work) : super(backend, work); |
| 2618 : super(backend, work, parameterNames) { | 2560 |
| 2561 int maxBailoutParameters; |
| 2562 |
| 2563 HBasicBlock beginGraph(HGraph graph) { |
| 2619 // Declare the parameter names only for the optimized version. The | 2564 // Declare the parameter names only for the optimized version. The |
| 2620 // unoptimized version has different parameters. | 2565 // unoptimized version has different parameters. |
| 2621 parameterNames.forEach((Element element, String name) { | 2566 parameterNames.forEach((Element element, String name) { |
| 2567 parameters.add(new js.Parameter(name)); |
| 2622 declaredLocals.add(name); | 2568 declaredLocals.add(name); |
| 2623 }); | 2569 }); |
| 2570 return graph.entry; |
| 2624 } | 2571 } |
| 2625 | 2572 |
| 2626 int maxBailoutParameters; | |
| 2627 | |
| 2628 HBasicBlock beginGraph(HGraph graph) => graph.entry; | |
| 2629 void endGraph(HGraph graph) {} | 2573 void endGraph(HGraph graph) {} |
| 2630 | 2574 |
| 2631 js.Statement bailout(HTypeGuard guard, String reason) { | 2575 js.Statement bailout(HTypeGuard guard, String reason) { |
| 2632 if (maxBailoutParameters == null) { | 2576 if (maxBailoutParameters == null) { |
| 2633 maxBailoutParameters = 0; | 2577 maxBailoutParameters = 0; |
| 2634 work.guards.forEach((HTypeGuard workGuard) { | 2578 work.guards.forEach((HTypeGuard workGuard) { |
| 2635 HBailoutTarget target = workGuard.bailoutTarget; | 2579 HBailoutTarget target = workGuard.bailoutTarget; |
| 2636 int inputLength = target.inputs.length; | 2580 int inputLength = target.inputs.length; |
| 2637 if (inputLength > maxBailoutParameters) { | 2581 if (inputLength > maxBailoutParameters) { |
| 2638 maxBailoutParameters = inputLength; | 2582 maxBailoutParameters = inputLength; |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2763 oldContainerStack.add(currentContainer); | 2707 oldContainerStack.add(currentContainer); |
| 2764 currentContainer = new js.Block.empty(); | 2708 currentContainer = new js.Block.empty(); |
| 2765 } | 2709 } |
| 2766 | 2710 |
| 2767 void endLoop(HBasicBlock block) { | 2711 void endLoop(HBasicBlock block) { |
| 2768 js.Statement body = currentContainer; | 2712 js.Statement body = currentContainer; |
| 2769 currentContainer = oldContainerStack.removeLast(); | 2713 currentContainer = oldContainerStack.removeLast(); |
| 2770 body = unwrapStatement(body); | 2714 body = unwrapStatement(body); |
| 2771 js.While loop = new js.While(newLiteralBool(true), body); | 2715 js.While loop = new js.While(newLiteralBool(true), body); |
| 2772 | 2716 |
| 2773 HLoopInformation info = block.loopInformation; | 2717 HBasicBlock header = block.isLoopHeader() ? block : block.parentLoopHeader; |
| 2718 HLoopInformation info = header.loopInformation; |
| 2774 attachLocationRange(loop, | 2719 attachLocationRange(loop, |
| 2775 info.loopBlockInformation.sourcePosition, | 2720 info.loopBlockInformation.sourcePosition, |
| 2776 info.loopBlockInformation.endSourcePosition); | 2721 info.loopBlockInformation.endSourcePosition); |
| 2777 pushStatement(wrapIntoLabels(loop, info.labels)); | 2722 pushStatement(wrapIntoLabels(loop, info.labels)); |
| 2778 } | 2723 } |
| 2779 | 2724 |
| 2780 void handleLoopCondition(HLoopBranch node) { | 2725 void handleLoopCondition(HLoopBranch node) { |
| 2781 use(node.inputs[0]); | 2726 use(node.inputs[0]); |
| 2782 pushStatement(new js.If.noElse(pop(), new js.Break(null)), node); | 2727 js.Expression test = new js.Prefix('!', pop()); |
| 2728 js.Statement then = new js.Break(null); |
| 2729 pushStatement(new js.If.noElse(test, then), node); |
| 2783 } | 2730 } |
| 2784 | 2731 |
| 2785 | 2732 |
| 2786 void preLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { | 2733 void preLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { |
| 2787 } | 2734 } |
| 2788 | 2735 |
| 2789 void startLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { | 2736 void startLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { |
| 2790 } | 2737 } |
| 2791 | 2738 |
| 2792 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { | 2739 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 2804 /** | 2751 /** |
| 2805 * Keeps track if a bailout switch already used its [:default::] clause. New | 2752 * Keeps track if a bailout switch already used its [:default::] clause. New |
| 2806 * bailout-switches just push [:false:] on the stack and replace it when | 2753 * bailout-switches just push [:false:] on the stack and replace it when |
| 2807 * they used the [:default::] clause. | 2754 * they used the [:default::] clause. |
| 2808 */ | 2755 */ |
| 2809 final List<bool> defaultClauseUsedInBailoutStack; | 2756 final List<bool> defaultClauseUsedInBailoutStack; |
| 2810 | 2757 |
| 2811 SsaBailoutPropagator propagator; | 2758 SsaBailoutPropagator propagator; |
| 2812 HInstruction savedFirstInstruction; | 2759 HInstruction savedFirstInstruction; |
| 2813 | 2760 |
| 2814 SsaUnoptimizedCodeGenerator(backend, work, parameters, parameterNames) | 2761 SsaUnoptimizedCodeGenerator(backend, work) |
| 2815 : super(backend, work, parameterNames), | 2762 : super(backend, work), |
| 2816 oldBailoutSwitches = <js.Switch>[], | 2763 oldBailoutSwitches = <js.Switch>[], |
| 2817 newParameters = <js.Parameter>[], | 2764 newParameters = <js.Parameter>[], |
| 2818 labels = <String>[], | 2765 labels = <String>[], |
| 2819 defaultClauseUsedInBailoutStack = <bool>[]; | 2766 defaultClauseUsedInBailoutStack = <bool>[]; |
| 2820 | 2767 |
| 2821 String pushLabel() { | 2768 String pushLabel() { |
| 2822 String label = 'L${labelId++}'; | 2769 String label = 'L${labelId++}'; |
| 2823 labels.addLast(label); | 2770 labels.addLast(label); |
| 2824 return label; | 2771 return label; |
| 2825 } | 2772 } |
| (...skipping 307 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3133 if (leftType.canBeNull() && rightType.canBeNull()) { | 3080 if (leftType.canBeNull() && rightType.canBeNull()) { |
| 3134 if (left.isConstantNull() || right.isConstantNull() || | 3081 if (left.isConstantNull() || right.isConstantNull() || |
| 3135 (leftType.isPrimitive() && leftType == rightType)) { | 3082 (leftType.isPrimitive() && leftType == rightType)) { |
| 3136 return '=='; | 3083 return '=='; |
| 3137 } | 3084 } |
| 3138 return null; | 3085 return null; |
| 3139 } else { | 3086 } else { |
| 3140 return '==='; | 3087 return '==='; |
| 3141 } | 3088 } |
| 3142 } | 3089 } |
| OLD | NEW |