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 237 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
248 | 248 |
249 js.Node attachLocationRange(js.Node jsNode, | 249 js.Node attachLocationRange(js.Node jsNode, |
250 SourceFileLocation sourcePosition, | 250 SourceFileLocation sourcePosition, |
251 SourceFileLocation endSourcePosition) { | 251 SourceFileLocation endSourcePosition) { |
252 jsNode.sourcePosition = sourcePosition; | 252 jsNode.sourcePosition = sourcePosition; |
253 jsNode.endSourcePosition = endSourcePosition; | 253 jsNode.endSourcePosition = endSourcePosition; |
254 return jsNode; | 254 return jsNode; |
255 } | 255 } |
256 | 256 |
257 void preGenerateMethod(HGraph graph) { | 257 void preGenerateMethod(HGraph graph) { |
| 258 new SsaInstructionSelection(compiler).visitGraph(graph); |
258 new SsaTypeKnownRemover().visitGraph(graph); | 259 new SsaTypeKnownRemover().visitGraph(graph); |
259 new SsaInstructionMerger(generateAtUseSite, compiler).visitGraph(graph); | 260 new SsaInstructionMerger(generateAtUseSite, compiler).visitGraph(graph); |
260 new SsaConditionMerger( | 261 new SsaConditionMerger( |
261 generateAtUseSite, controlFlowOperators).visitGraph(graph); | 262 generateAtUseSite, controlFlowOperators).visitGraph(graph); |
262 SsaLiveIntervalBuilder intervalBuilder = new SsaLiveIntervalBuilder( | 263 SsaLiveIntervalBuilder intervalBuilder = new SsaLiveIntervalBuilder( |
263 compiler, generateAtUseSite, controlFlowOperators); | 264 compiler, generateAtUseSite, controlFlowOperators); |
264 intervalBuilder.visitGraph(graph); | 265 intervalBuilder.visitGraph(graph); |
265 SsaVariableAllocator allocator = new SsaVariableAllocator( | 266 SsaVariableAllocator allocator = new SsaVariableAllocator( |
266 compiler, | 267 compiler, |
267 intervalBuilder.liveInstructions, | 268 intervalBuilder.liveInstructions, |
(...skipping 924 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1192 | 1193 |
1193 // We want the outcome of bit-operations to be positive. We use the unsigned | 1194 // We want the outcome of bit-operations to be positive. We use the unsigned |
1194 // shift operator to achieve this. | 1195 // shift operator to achieve this. |
1195 visitBitInvokeUnary(HInvokeUnary node, String op) { | 1196 visitBitInvokeUnary(HInvokeUnary node, String op) { |
1196 visitInvokeUnary(node, op); | 1197 visitInvokeUnary(node, op); |
1197 if (requiresUintConversion(node)) { | 1198 if (requiresUintConversion(node)) { |
1198 push(new js.Binary(">>>", pop(), new js.LiteralNumber("0")), node); | 1199 push(new js.Binary(">>>", pop(), new js.LiteralNumber("0")), node); |
1199 } | 1200 } |
1200 } | 1201 } |
1201 | 1202 |
1202 void emitIdentityComparison(HInstruction left, | 1203 void emitIdentityComparison(HIdentity instruction, bool inverse) { |
1203 HInstruction right, | 1204 String op = instruction.singleComparisonOp; |
1204 bool inverse) { | 1205 HInstruction left = instruction.left; |
1205 String op = singleIdentityComparison(left, right, compiler); | 1206 HInstruction right = instruction.right; |
1206 if (op != null) { | 1207 if (op != null) { |
1207 use(left); | 1208 use(left); |
1208 js.Expression jsLeft = pop(); | 1209 js.Expression jsLeft = pop(); |
1209 use(right); | 1210 use(right); |
1210 push(new js.Binary(mapRelationalOperator(op, inverse), jsLeft, pop())); | 1211 push(new js.Binary(mapRelationalOperator(op, inverse), jsLeft, pop())); |
1211 } else { | 1212 } else { |
1212 assert(NullConstant.JsNull == 'null'); | 1213 assert(NullConstant.JsNull == 'null'); |
1213 use(left); | 1214 use(left); |
1214 js.Binary leftEqualsNull = | 1215 js.Binary leftEqualsNull = |
1215 new js.Binary("==", pop(), new js.LiteralNull()); | 1216 new js.Binary("==", pop(), new js.LiteralNull()); |
1216 use(right); | 1217 use(right); |
1217 js.Binary rightEqualsNull = | 1218 js.Binary rightEqualsNull = |
1218 new js.Binary(mapRelationalOperator("==", inverse), | 1219 new js.Binary(mapRelationalOperator("==", inverse), |
1219 pop(), new js.LiteralNull()); | 1220 pop(), new js.LiteralNull()); |
1220 use(right); | 1221 use(right); |
1221 use(left); | 1222 use(left); |
1222 js.Binary tripleEq = new js.Binary(mapRelationalOperator("===", inverse), | 1223 js.Binary tripleEq = new js.Binary(mapRelationalOperator("===", inverse), |
1223 pop(), pop()); | 1224 pop(), pop()); |
1224 | 1225 |
1225 push(new js.Conditional(leftEqualsNull, rightEqualsNull, tripleEq)); | 1226 push(new js.Conditional(leftEqualsNull, rightEqualsNull, tripleEq)); |
1226 } | 1227 } |
1227 } | 1228 } |
1228 | 1229 |
1229 visitIdentity(HIdentity node) { | 1230 visitIdentity(HIdentity node) { |
1230 emitIdentityComparison(node.left, node.right, false); | 1231 emitIdentityComparison(node, false); |
1231 } | 1232 } |
1232 | 1233 |
1233 visitAdd(HAdd node) => visitInvokeBinary(node, '+'); | 1234 visitAdd(HAdd node) => visitInvokeBinary(node, '+'); |
1234 visitDivide(HDivide node) => visitInvokeBinary(node, '/'); | 1235 visitDivide(HDivide node) => visitInvokeBinary(node, '/'); |
1235 visitMultiply(HMultiply node) => visitInvokeBinary(node, '*'); | 1236 visitMultiply(HMultiply node) => visitInvokeBinary(node, '*'); |
1236 visitSubtract(HSubtract node) => visitInvokeBinary(node, '-'); | 1237 visitSubtract(HSubtract node) => visitInvokeBinary(node, '-'); |
1237 visitBitAnd(HBitAnd node) => visitBitInvokeBinary(node, '&'); | 1238 visitBitAnd(HBitAnd node) => visitBitInvokeBinary(node, '&'); |
1238 visitBitNot(HBitNot node) => visitBitInvokeUnary(node, '~'); | 1239 visitBitNot(HBitNot node) => visitBitInvokeUnary(node, '~'); |
1239 visitBitOr(HBitOr node) => visitBitInvokeBinary(node, '|'); | 1240 visitBitOr(HBitOr node) => visitBitInvokeBinary(node, '|'); |
1240 visitBitXor(HBitXor node) => visitBitInvokeBinary(node, '^'); | 1241 visitBitXor(HBitXor node) => visitBitInvokeBinary(node, '^'); |
(...skipping 564 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1805 // This optimization doesn't work for NaN, so we only do it if the | 1806 // This optimization doesn't work for NaN, so we only do it if the |
1806 // type is known to be an integer. | 1807 // type is known to be an integer. |
1807 return left.isInteger(compiler) && right.isInteger(compiler); | 1808 return left.isInteger(compiler) && right.isInteger(compiler); |
1808 } | 1809 } |
1809 | 1810 |
1810 bool handledBySpecialCase = false; | 1811 bool handledBySpecialCase = false; |
1811 if (isGenerateAtUseSite(input)) { | 1812 if (isGenerateAtUseSite(input)) { |
1812 handledBySpecialCase = true; | 1813 handledBySpecialCase = true; |
1813 if (input is HIs) { | 1814 if (input is HIs) { |
1814 emitIs(input, '!=='); | 1815 emitIs(input, '!=='); |
| 1816 } else if (input is HIsViaInterceptor) { |
| 1817 emitIsViaInterceptor(input, true); |
1815 } else if (input is HNot) { | 1818 } else if (input is HNot) { |
1816 use(input.inputs[0]); | 1819 use(input.inputs[0]); |
1817 } else if (input is HIdentity) { | 1820 } else if (input is HIdentity) { |
1818 HIdentity identity = input; | 1821 emitIdentityComparison(input, true); |
1819 emitIdentityComparison(identity.left, identity.right, true); | |
1820 } else if (input is HBoolify) { | 1822 } else if (input is HBoolify) { |
1821 use(input.inputs[0]); | 1823 use(input.inputs[0]); |
1822 push(new js.Binary("!==", pop(), newLiteralBool(true)), input); | 1824 push(new js.Binary("!==", pop(), newLiteralBool(true)), input); |
1823 } else if (canGenerateOptimizedComparison(input)) { | 1825 } else if (canGenerateOptimizedComparison(input)) { |
1824 HRelational relational = input; | 1826 HRelational relational = input; |
1825 BinaryOperation operation = | 1827 BinaryOperation operation = |
1826 relational.operation(backend.constantSystem); | 1828 relational.operation(backend.constantSystem); |
1827 String op = mapRelationalOperator(operation.name, true); | 1829 String op = mapRelationalOperator(operation.name, true); |
1828 visitRelational(input, op); | 1830 visitRelational(input, op); |
1829 } else { | 1831 } else { |
(...skipping 403 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2233 return; | 2235 return; |
2234 } else if (element == backend.jsFixedArrayClass) { | 2236 } else if (element == backend.jsFixedArrayClass) { |
2235 if (negative) { | 2237 if (negative) { |
2236 checkExtendableArray(input); | 2238 checkExtendableArray(input); |
2237 } else { | 2239 } else { |
2238 checkFixedArray(input); | 2240 checkFixedArray(input); |
2239 } | 2241 } |
2240 return; | 2242 return; |
2241 } | 2243 } |
2242 if (interceptor != null) { | 2244 if (interceptor != null) { |
2243 use(interceptor); | 2245 checkTypeViaProperty(interceptor, type, negative); |
2244 } else { | 2246 } else { |
2245 use(input); | 2247 checkTypeViaProperty(input, type, negative); |
2246 } | 2248 } |
| 2249 } |
2247 | 2250 |
| 2251 void checkTypeViaProperty(HInstruction input, DartType type, bool negative) { |
2248 world.registerIsCheck(type, work.resolutionTree); | 2252 world.registerIsCheck(type, work.resolutionTree); |
2249 | 2253 |
| 2254 use(input); |
| 2255 |
2250 js.PropertyAccess field = | 2256 js.PropertyAccess field = |
2251 new js.PropertyAccess.field(pop(), backend.namer.operatorIsType(type)); | 2257 new js.PropertyAccess.field(pop(), backend.namer.operatorIsType(type)); |
2252 // We always negate at least once so that the result is boolified. | 2258 // We always negate at least once so that the result is boolified. |
2253 push(new js.Prefix('!', field)); | 2259 push(new js.Prefix('!', field)); |
2254 // If the result is not negated, put another '!' in front. | 2260 // If the result is not negated, put another '!' in front. |
2255 if (!negative) push(new js.Prefix('!', pop())); | 2261 if (!negative) push(new js.Prefix('!', pop())); |
2256 } | 2262 } |
2257 | 2263 |
2258 void handleNumberOrStringSupertypeCheck(HInstruction input, | 2264 void handleNumberOrStringSupertypeCheck(HInstruction input, |
2259 HInstruction interceptor, | 2265 HInstruction interceptor, |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2312 String combiner = negative ? '&&' : '||'; | 2318 String combiner = negative ? '&&' : '||'; |
2313 push(new js.Binary(negative ? '||' : '&&', | 2319 push(new js.Binary(negative ? '||' : '&&', |
2314 objectTest, | 2320 objectTest, |
2315 new js.Binary(combiner, arrayTest, pop()))); | 2321 new js.Binary(combiner, arrayTest, pop()))); |
2316 } | 2322 } |
2317 | 2323 |
2318 void visitIs(HIs node) { | 2324 void visitIs(HIs node) { |
2319 emitIs(node, "==="); | 2325 emitIs(node, "==="); |
2320 } | 2326 } |
2321 | 2327 |
| 2328 void visitIsViaInterceptor(HIsViaInterceptor node) { |
| 2329 emitIsViaInterceptor(node, false); |
| 2330 } |
| 2331 |
2322 void emitIs(HIs node, String relation) { | 2332 void emitIs(HIs node, String relation) { |
2323 DartType type = node.typeExpression; | 2333 DartType type = node.typeExpression; |
2324 world.registerIsCheck(type, work.resolutionTree); | 2334 world.registerIsCheck(type, work.resolutionTree); |
2325 HInstruction input = node.expression; | 2335 HInstruction input = node.expression; |
2326 | 2336 |
2327 // If this is changed to single == there are several places below that must | 2337 // If this is changed to single == there are several places below that must |
2328 // be changed to match. | 2338 // be changed to match. |
2329 assert(relation == '===' || relation == '!=='); | 2339 assert(relation == '===' || relation == '!=='); |
2330 bool negative = relation == '!=='; | 2340 bool negative = relation == '!=='; |
2331 | 2341 |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2391 js.Expression objectTest = pop(); | 2401 js.Expression objectTest = pop(); |
2392 checkType(input, interceptor, type, negative: negative); | 2402 checkType(input, interceptor, type, negative: negative); |
2393 push(new js.Binary(negative ? '||' : '&&', objectTest, pop()), node); | 2403 push(new js.Binary(negative ? '||' : '&&', objectTest, pop()), node); |
2394 } else { | 2404 } else { |
2395 checkType(input, interceptor, type, negative: negative); | 2405 checkType(input, interceptor, type, negative: negative); |
2396 attachLocationToLast(node); | 2406 attachLocationToLast(node); |
2397 } | 2407 } |
2398 } | 2408 } |
2399 } | 2409 } |
2400 | 2410 |
| 2411 void emitIsViaInterceptor(HIsViaInterceptor node, bool negative) { |
| 2412 checkTypeViaProperty(node.interceptor, node.typeExpression, negative); |
| 2413 attachLocationToLast(node); |
| 2414 } |
| 2415 |
2401 js.Expression generateTest(HInstruction input, TypeMask checkedType) { | 2416 js.Expression generateTest(HInstruction input, TypeMask checkedType) { |
2402 TypeMask receiver = input.instructionType; | 2417 TypeMask receiver = input.instructionType; |
2403 // Figure out if it is beneficial to turn this into a null check. | 2418 // Figure out if it is beneficial to turn this into a null check. |
2404 // V8 generally prefers 'typeof' checks, but for integers and | 2419 // V8 generally prefers 'typeof' checks, but for integers and |
2405 // indexable primitives we cannot compile this test into a single | 2420 // indexable primitives we cannot compile this test into a single |
2406 // typeof check so the null check is cheaper. | 2421 // typeof check so the null check is cheaper. |
2407 bool turnIntoNumCheck = input.isIntegerOrNull(compiler) | 2422 bool turnIntoNumCheck = input.isIntegerOrNull(compiler) |
2408 && checkedType.containsOnlyInt(compiler); | 2423 && checkedType.containsOnlyInt(compiler); |
2409 bool turnIntoNullCheck = !turnIntoNumCheck | 2424 bool turnIntoNullCheck = !turnIntoNumCheck |
2410 && (checkedType.nullable() == receiver) | 2425 && (checkedType.nullable() == receiver) |
(...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2644 js.PropertyAccess accessHelper(String name) { | 2659 js.PropertyAccess accessHelper(String name) { |
2645 Element helper = compiler.findHelper(name); | 2660 Element helper = compiler.findHelper(name); |
2646 if (helper == null) { | 2661 if (helper == null) { |
2647 // For mocked-up tests. | 2662 // For mocked-up tests. |
2648 return js.js('(void 0).$name'); | 2663 return js.js('(void 0).$name'); |
2649 } | 2664 } |
2650 world.registerStaticUse(helper); | 2665 world.registerStaticUse(helper); |
2651 return backend.namer.elementAccess(helper); | 2666 return backend.namer.elementAccess(helper); |
2652 } | 2667 } |
2653 } | 2668 } |
2654 | |
2655 String singleIdentityComparison(HInstruction left, | |
2656 HInstruction right, | |
2657 Compiler compiler) { | |
2658 // Returns the single identity comparison (== or ===) or null if a more | |
2659 // complex expression is required. | |
2660 if (left.canBeNull() && right.canBeNull()) { | |
2661 if (left.isConstantNull() || right.isConstantNull() || | |
2662 (left.isPrimitive(compiler) && | |
2663 left.instructionType == right.instructionType)) { | |
2664 return '=='; | |
2665 } | |
2666 return null; | |
2667 } else { | |
2668 return '==='; | |
2669 } | |
2670 } | |
OLD | NEW |