| 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 final JavaScriptBackend backend; | 6 final JavaScriptBackend backend; |
| 7 SsaCodeGeneratorTask(JavaScriptBackend backend) | 7 SsaCodeGeneratorTask(JavaScriptBackend backend) |
| 8 : this.backend = backend, | 8 : this.backend = backend, |
| 9 super(backend.compiler); | 9 super(backend.compiler); |
| 10 String get name() => 'SSA code generator'; | 10 String get name() => 'SSA code generator'; |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 147 * - [TYPE_DECLARATION] means that the graph can be generated as an | 147 * - [TYPE_DECLARATION] means that the graph can be generated as an |
| 148 * expression, and that it only generates expressions of the form | 148 * expression, and that it only generates expressions of the form |
| 149 * variable = expression | 149 * variable = expression |
| 150 * which are also valid as parts of a "var" declaration. | 150 * which are also valid as parts of a "var" declaration. |
| 151 */ | 151 */ |
| 152 static final int TYPE_STATEMENT = 0; | 152 static final int TYPE_STATEMENT = 0; |
| 153 static final int TYPE_EXPRESSION = 1; | 153 static final int TYPE_EXPRESSION = 1; |
| 154 static final int TYPE_DECLARATION = 2; | 154 static final int TYPE_DECLARATION = 2; |
| 155 | 155 |
| 156 final JavaScriptBackend backend; | 156 final JavaScriptBackend backend; |
| 157 final WorkItem work; | 157 final JavaScriptWorkItem work; |
| 158 final CodeBuffer buffer; | 158 final CodeBuffer buffer; |
| 159 final String parameters; | 159 final String parameters; |
| 160 | 160 |
| 161 final Set<HInstruction> generateAtUseSite; | 161 final Set<HInstruction> generateAtUseSite; |
| 162 final Set<HInstruction> controlFlowOperators; | 162 final Set<HInstruction> controlFlowOperators; |
| 163 final Map<Element, ElementAction> breakAction; | 163 final Map<Element, ElementAction> breakAction; |
| 164 final Map<Element, ElementAction> continueAction; | 164 final Map<Element, ElementAction> continueAction; |
| 165 final Map<Element, String> parameterNames; | 165 final Map<Element, String> parameterNames; |
| 166 | 166 |
| 167 /** | 167 /** |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 292 void withPrecedence(int precedence, void action()) { | 292 void withPrecedence(int precedence, void action()) { |
| 293 int oldPrecedence = expectedPrecedence; | 293 int oldPrecedence = expectedPrecedence; |
| 294 beginExpression(precedence); | 294 beginExpression(precedence); |
| 295 expectedPrecedence = precedence; | 295 expectedPrecedence = precedence; |
| 296 action(); | 296 action(); |
| 297 expectedPrecedence = oldPrecedence; | 297 expectedPrecedence = oldPrecedence; |
| 298 endExpression(precedence); | 298 endExpression(precedence); |
| 299 } | 299 } |
| 300 | 300 |
| 301 void preGenerateMethod(HGraph graph) { | 301 void preGenerateMethod(HGraph graph) { |
| 302 new SsaInstructionMerger(generateAtUseSite).visitGraph(graph); | 302 new SsaInstructionMerger(work, generateAtUseSite).visitGraph(graph); |
| 303 new SsaConditionMerger(generateAtUseSite, | 303 new SsaConditionMerger( |
| 304 controlFlowOperators).visitGraph(graph); | 304 work, generateAtUseSite, controlFlowOperators).visitGraph(graph); |
| 305 SsaLiveIntervalBuilder intervalBuilder = | 305 SsaLiveIntervalBuilder intervalBuilder = |
| 306 new SsaLiveIntervalBuilder(compiler, generateAtUseSite); | 306 new SsaLiveIntervalBuilder(compiler, generateAtUseSite); |
| 307 intervalBuilder.visitGraph(graph); | 307 intervalBuilder.visitGraph(graph); |
| 308 SsaVariableAllocator allocator = new SsaVariableAllocator( | 308 SsaVariableAllocator allocator = new SsaVariableAllocator( |
| 309 compiler, | 309 compiler, |
| 310 intervalBuilder.liveInstructions, | 310 intervalBuilder.liveInstructions, |
| 311 intervalBuilder.liveIntervals, | 311 intervalBuilder.liveIntervals, |
| 312 generateAtUseSite, | 312 generateAtUseSite, |
| 313 parameterNames); | 313 parameterNames); |
| 314 allocator.visitGraph(graph); | 314 allocator.visitGraph(graph); |
| (...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 556 | 556 |
| 557 // Check that the operation is one of +, *, - or /. Record whether | 557 // Check that the operation is one of +, *, - or /. Record whether |
| 558 // or not the operation is commutative. | 558 // or not the operation is commutative. |
| 559 var isCommutative = false; | 559 var isCommutative = false; |
| 560 if (instruction is HAdd || instruction is HMultiply) { | 560 if (instruction is HAdd || instruction is HMultiply) { |
| 561 isCommutative = true; | 561 isCommutative = true; |
| 562 } else if (instruction is !HSubtract && instruction is !HDivide) { | 562 } else if (instruction is !HSubtract && instruction is !HDivide) { |
| 563 return false; | 563 return false; |
| 564 } | 564 } |
| 565 | 565 |
| 566 HTypeMap types = work.types; |
| 567 |
| 566 // Is it a builtin operation involving +, -, /, or *? | 568 // Is it a builtin operation involving +, -, /, or *? |
| 567 HBinaryArithmetic binaryInstruction = instruction; | 569 HBinaryArithmetic binaryInstruction = instruction; |
| 568 assert(binaryInstruction.inputs.length == 3); | 570 assert(binaryInstruction.inputs.length == 3); |
| 569 if (binaryInstruction.builtin) { | 571 if (binaryInstruction.isBuiltin(types)) { |
| 570 var left = binaryInstruction.left; | 572 var left = binaryInstruction.left; |
| 571 var right = binaryInstruction.right; | 573 var right = binaryInstruction.right; |
| 572 if (isCommutative && variableNames.getName(right) == name) { | 574 if (isCommutative && variableNames.getName(right) == name) { |
| 573 var tmp = right; | 575 var tmp = right; |
| 574 right = left; | 576 right = left; |
| 575 left = tmp; | 577 left = tmp; |
| 576 } | 578 } |
| 577 | 579 |
| 578 // Check that left has the same name as the definition and emit | 580 // Check that left has the same name as the definition and emit |
| 579 // the short update definition if it is. | 581 // the short update definition if it is. |
| (...skipping 598 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1178 instruction = instruction.next; | 1180 instruction = instruction.next; |
| 1179 } | 1181 } |
| 1180 assignPhisOfSuccessors(node); | 1182 assignPhisOfSuccessors(node); |
| 1181 if (instruction is HLoopBranch && isGeneratingExpression()) { | 1183 if (instruction is HLoopBranch && isGeneratingExpression()) { |
| 1182 addExpressionSeparator(); | 1184 addExpressionSeparator(); |
| 1183 } | 1185 } |
| 1184 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE); | 1186 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE); |
| 1185 } | 1187 } |
| 1186 | 1188 |
| 1187 visitInvokeBinary(HInvokeBinary node, String op) { | 1189 visitInvokeBinary(HInvokeBinary node, String op) { |
| 1188 if (node.builtin) { | 1190 if (node.isBuiltin(work.types)) { |
| 1189 JSBinaryOperatorPrecedence operatorPrecedences = JSPrecedence.binary[op]; | 1191 JSBinaryOperatorPrecedence operatorPrecedences = JSPrecedence.binary[op]; |
| 1190 beginExpression(operatorPrecedences.precedence); | 1192 beginExpression(operatorPrecedences.precedence); |
| 1191 use(node.left, operatorPrecedences.left); | 1193 use(node.left, operatorPrecedences.left); |
| 1192 buffer.add(' $op '); | 1194 buffer.add(' $op '); |
| 1193 use(node.right, operatorPrecedences.right); | 1195 use(node.right, operatorPrecedences.right); |
| 1194 endExpression(operatorPrecedences.precedence); | 1196 endExpression(operatorPrecedences.precedence); |
| 1195 } else { | 1197 } else { |
| 1196 visitInvokeStatic(node); | 1198 visitInvokeStatic(node); |
| 1197 } | 1199 } |
| 1198 } | 1200 } |
| 1199 | 1201 |
| 1200 // We want the outcome of bit-operations to be positive. We use the unsigned | 1202 // We want the outcome of bit-operations to be positive. We use the unsigned |
| 1201 // shift operator to achieve this. | 1203 // shift operator to achieve this. |
| 1202 visitBitInvokeBinary(HBinaryBitOp node, String op) { | 1204 visitBitInvokeBinary(HBinaryBitOp node, String op) { |
| 1203 if (node.builtin && requiresUintConversion(node)) { | 1205 HTypeMap types = work.types; |
| 1206 if (node.isBuiltin(types) && requiresUintConversion(node)) { |
| 1204 beginExpression(unsignedShiftPrecedences.precedence); | 1207 beginExpression(unsignedShiftPrecedences.precedence); |
| 1205 int oldPrecedence = this.expectedPrecedence; | 1208 int oldPrecedence = this.expectedPrecedence; |
| 1206 this.expectedPrecedence = JSPrecedence.SHIFT_PRECEDENCE; | 1209 this.expectedPrecedence = JSPrecedence.SHIFT_PRECEDENCE; |
| 1207 visitInvokeBinary(node, op); | 1210 visitInvokeBinary(node, op); |
| 1208 buffer.add(' >>> 0'); | 1211 buffer.add(' >>> 0'); |
| 1209 this.expectedPrecedence = oldPrecedence; | 1212 this.expectedPrecedence = oldPrecedence; |
| 1210 endExpression(unsignedShiftPrecedences.precedence); | 1213 endExpression(unsignedShiftPrecedences.precedence); |
| 1211 } else { | 1214 } else { |
| 1212 visitInvokeBinary(node, op); | 1215 visitInvokeBinary(node, op); |
| 1213 } | 1216 } |
| 1214 } | 1217 } |
| 1215 | 1218 |
| 1216 visitInvokeUnary(HInvokeUnary node, String op) { | 1219 visitInvokeUnary(HInvokeUnary node, String op) { |
| 1217 if (node.builtin) { | 1220 if (node.isBuiltin(work.types)) { |
| 1218 beginExpression(JSPrecedence.PREFIX_PRECEDENCE); | 1221 beginExpression(JSPrecedence.PREFIX_PRECEDENCE); |
| 1219 buffer.add('$op'); | 1222 buffer.add('$op'); |
| 1220 use(node.operand, JSPrecedence.PREFIX_PRECEDENCE); | 1223 use(node.operand, JSPrecedence.PREFIX_PRECEDENCE); |
| 1221 endExpression(JSPrecedence.PREFIX_PRECEDENCE); | 1224 endExpression(JSPrecedence.PREFIX_PRECEDENCE); |
| 1222 } else { | 1225 } else { |
| 1223 visitInvokeStatic(node); | 1226 visitInvokeStatic(node); |
| 1224 } | 1227 } |
| 1225 } | 1228 } |
| 1226 | 1229 |
| 1227 // We want the outcome of bit-operations to be positive. We use the unsigned | 1230 // We want the outcome of bit-operations to be positive. We use the unsigned |
| 1228 // shift operator to achieve this. | 1231 // shift operator to achieve this. |
| 1229 visitBitInvokeUnary(HInvokeUnary node, String op) { | 1232 visitBitInvokeUnary(HInvokeUnary node, String op) { |
| 1230 if (node.builtin && requiresUintConversion(node)) { | 1233 HTypeMap types = work.types; |
| 1234 if (node.isBuiltin(types) && requiresUintConversion(node)) { |
| 1231 beginExpression(unsignedShiftPrecedences.precedence); | 1235 beginExpression(unsignedShiftPrecedences.precedence); |
| 1232 int oldPrecedence = this.expectedPrecedence; | 1236 int oldPrecedence = this.expectedPrecedence; |
| 1233 this.expectedPrecedence = JSPrecedence.SHIFT_PRECEDENCE; | 1237 this.expectedPrecedence = JSPrecedence.SHIFT_PRECEDENCE; |
| 1234 visitInvokeUnary(node, op); | 1238 visitInvokeUnary(node, op); |
| 1235 buffer.add(' >>> 0'); | 1239 buffer.add(' >>> 0'); |
| 1236 this.expectedPrecedence = oldPrecedence; | 1240 this.expectedPrecedence = oldPrecedence; |
| 1237 endExpression(unsignedShiftPrecedences.precedence); | 1241 endExpression(unsignedShiftPrecedences.precedence); |
| 1238 } else { | 1242 } else { |
| 1239 visitInvokeUnary(node, op); | 1243 visitInvokeUnary(node, op); |
| 1240 } | 1244 } |
| 1241 } | 1245 } |
| 1242 | 1246 |
| 1243 void emitIdentityComparison(HInstruction left, HInstruction right) { | 1247 void emitIdentityComparison(HInstruction left, HInstruction right) { |
| 1244 String op = singleIdentityComparison(left, right); | 1248 String op = singleIdentityComparison(left, right, work.types); |
| 1245 if (op != null) { | 1249 if (op != null) { |
| 1246 beginExpression(JSPrecedence.EQUALITY_PRECEDENCE); | 1250 beginExpression(JSPrecedence.EQUALITY_PRECEDENCE); |
| 1247 use(left, JSPrecedence.EQUALITY_PRECEDENCE); | 1251 use(left, JSPrecedence.EQUALITY_PRECEDENCE); |
| 1248 buffer.add(' $op '); | 1252 buffer.add(' $op '); |
| 1249 use(right, JSPrecedence.RELATIONAL_PRECEDENCE); | 1253 use(right, JSPrecedence.RELATIONAL_PRECEDENCE); |
| 1250 endExpression(JSPrecedence.EQUALITY_PRECEDENCE); | 1254 endExpression(JSPrecedence.EQUALITY_PRECEDENCE); |
| 1251 } else { | 1255 } else { |
| 1252 assert(NullConstant.JsNull == 'null'); | 1256 assert(NullConstant.JsNull == 'null'); |
| 1253 withPrecedence(JSPrecedence.CONDITIONAL_PRECEDENCE, () { | 1257 withPrecedence(JSPrecedence.CONDITIONAL_PRECEDENCE, () { |
| 1254 beginExpression(JSPrecedence.EQUALITY_PRECEDENCE); | 1258 beginExpression(JSPrecedence.EQUALITY_PRECEDENCE); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1267 use(left, JSPrecedence.EQUALITY_PRECEDENCE); | 1271 use(left, JSPrecedence.EQUALITY_PRECEDENCE); |
| 1268 buffer.add(' === '); | 1272 buffer.add(' === '); |
| 1269 use(right, JSPrecedence.EQUALITY_PRECEDENCE); | 1273 use(right, JSPrecedence.EQUALITY_PRECEDENCE); |
| 1270 endExpression(JSPrecedence.EQUALITY_PRECEDENCE); | 1274 endExpression(JSPrecedence.EQUALITY_PRECEDENCE); |
| 1271 }); | 1275 }); |
| 1272 }); | 1276 }); |
| 1273 } | 1277 } |
| 1274 } | 1278 } |
| 1275 | 1279 |
| 1276 visitEquals(HEquals node) { | 1280 visitEquals(HEquals node) { |
| 1277 if (node.builtin) { | 1281 if (node.isBuiltin(work.types)) { |
| 1278 emitIdentityComparison(node.left, node.right); | 1282 emitIdentityComparison(node.left, node.right); |
| 1279 } else { | 1283 } else { |
| 1280 visitInvokeStatic(node); | 1284 visitInvokeStatic(node); |
| 1281 } | 1285 } |
| 1282 } | 1286 } |
| 1283 | 1287 |
| 1284 visitIdentity(HIdentity node) { | 1288 visitIdentity(HIdentity node) { |
| 1285 assert(node.builtin); | 1289 assert(node.isBuiltin(work.types)); |
| 1286 emitIdentityComparison(node.left, node.right); | 1290 emitIdentityComparison(node.left, node.right); |
| 1287 } | 1291 } |
| 1288 | 1292 |
| 1289 visitAdd(HAdd node) => visitInvokeBinary(node, '+'); | 1293 visitAdd(HAdd node) => visitInvokeBinary(node, '+'); |
| 1290 visitDivide(HDivide node) => visitInvokeBinary(node, '/'); | 1294 visitDivide(HDivide node) => visitInvokeBinary(node, '/'); |
| 1291 visitMultiply(HMultiply node) => visitInvokeBinary(node, '*'); | 1295 visitMultiply(HMultiply node) => visitInvokeBinary(node, '*'); |
| 1292 visitSubtract(HSubtract node) => visitInvokeBinary(node, '-'); | 1296 visitSubtract(HSubtract node) => visitInvokeBinary(node, '-'); |
| 1293 // Truncating divide does not have a JS equivalent. | 1297 // Truncating divide does not have a JS equivalent. |
| 1294 visitTruncatingDivide(HTruncatingDivide node) => visitInvokeStatic(node); | 1298 visitTruncatingDivide(HTruncatingDivide node) => visitInvokeStatic(node); |
| 1295 // Modulo cannot be mapped to the native operator (different semantics). | 1299 // Modulo cannot be mapped to the native operator (different semantics). |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1425 // all blocks. | 1429 // all blocks. |
| 1426 if (start !== end) return MULTIPLE_STATEMENTS; | 1430 if (start !== end) return MULTIPLE_STATEMENTS; |
| 1427 | 1431 |
| 1428 int kind = EMPTY; | 1432 int kind = EMPTY; |
| 1429 bool updateKind(int newKind) { | 1433 bool updateKind(int newKind) { |
| 1430 if (kind != EMPTY) return false; | 1434 if (kind != EMPTY) return false; |
| 1431 kind = newKind; | 1435 kind = newKind; |
| 1432 return true; | 1436 return true; |
| 1433 } | 1437 } |
| 1434 | 1438 |
| 1439 HTypeMap types = work.types; |
| 1440 |
| 1435 for (HInstruction instruction = start.first; | 1441 for (HInstruction instruction = start.first; |
| 1436 instruction != start.last; | 1442 instruction != start.last; |
| 1437 instruction = instruction.next) { | 1443 instruction = instruction.next) { |
| 1438 if (instruction.isStatement) { | 1444 if (instruction.isStatement(types)) { |
| 1439 if (!updateKind(ONE_STATEMENT)) return MULTIPLE_STATEMENTS; | 1445 if (!updateKind(ONE_STATEMENT)) return MULTIPLE_STATEMENTS; |
| 1440 } else if (!isGenerateAtUseSite(instruction)) { | 1446 } else if (!isGenerateAtUseSite(instruction)) { |
| 1441 if (!updateKind(ONE_EXPRESSION)) return MULTIPLE_STATEMENTS; | 1447 if (!updateKind(ONE_EXPRESSION)) return MULTIPLE_STATEMENTS; |
| 1442 } | 1448 } |
| 1443 } | 1449 } |
| 1444 | 1450 |
| 1445 HInstruction last = start.last; | 1451 HInstruction last = start.last; |
| 1446 if (last is !HGoto) { | 1452 if (last is !HGoto) { |
| 1447 if (!updateKind(last.isStatement ? ONE_STATEMENT : ONE_EXPRESSION)) { | 1453 if (!updateKind(last.isStatement(types) |
| 1454 ? ONE_STATEMENT |
| 1455 : ONE_EXPRESSION)) { |
| 1448 return MULTIPLE_STATEMENTS; | 1456 return MULTIPLE_STATEMENTS; |
| 1449 } | 1457 } |
| 1450 } | 1458 } |
| 1451 | 1459 |
| 1452 CopyHandler handler = variableNames.getCopyHandler(start); | 1460 CopyHandler handler = variableNames.getCopyHandler(start); |
| 1453 if (handler !== null && !handler.isEmpty()) { | 1461 if (handler !== null && !handler.isEmpty()) { |
| 1454 if (handler.assignments.length > 1) return MULTIPLE_STATEMENTS; | 1462 if (handler.assignments.length > 1) return MULTIPLE_STATEMENTS; |
| 1455 if (handler.assignments.length == 1) { | 1463 if (handler.assignments.length == 1) { |
| 1456 if (!updateKind(ONE_STATEMENT)) return MULTIPLE_STATEMENTS; | 1464 if (!updateKind(ONE_STATEMENT)) return MULTIPLE_STATEMENTS; |
| 1457 } | 1465 } |
| (...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1741 } else { | 1749 } else { |
| 1742 Selector selector = getOptimizedSelectorFor(node, node.selector); | 1750 Selector selector = getOptimizedSelectorFor(node, node.selector); |
| 1743 world.registerDynamicInvocation(node.name, selector); | 1751 world.registerDynamicInvocation(node.name, selector); |
| 1744 if (inLoop) backend.builder.selectorsCalledInLoop[node.name] = selector; | 1752 if (inLoop) backend.builder.selectorsCalledInLoop[node.name] = selector; |
| 1745 } | 1753 } |
| 1746 } | 1754 } |
| 1747 endExpression(JSPrecedence.CALL_PRECEDENCE); | 1755 endExpression(JSPrecedence.CALL_PRECEDENCE); |
| 1748 } | 1756 } |
| 1749 | 1757 |
| 1750 Selector getOptimizedSelectorFor(HInvoke node, Selector defaultSelector) { | 1758 Selector getOptimizedSelectorFor(HInvoke node, Selector defaultSelector) { |
| 1751 Type receiverType = node.inputs[0].propagatedType.computeType(compiler); | 1759 HType receiverHType = work.types[node.inputs[0]]; |
| 1760 Type receiverType = receiverHType.computeType(compiler); |
| 1752 if (receiverType !== null) { | 1761 if (receiverType !== null) { |
| 1753 return new TypedSelector(receiverType, defaultSelector); | 1762 return new TypedSelector(receiverType, defaultSelector); |
| 1754 } else { | 1763 } else { |
| 1755 return defaultSelector; | 1764 return defaultSelector; |
| 1756 } | 1765 } |
| 1757 } | 1766 } |
| 1758 | 1767 |
| 1759 visitInvokeDynamicSetter(HInvokeDynamicSetter node) { | 1768 visitInvokeDynamicSetter(HInvokeDynamicSetter node) { |
| 1760 beginExpression(JSPrecedence.CALL_PRECEDENCE); | 1769 beginExpression(JSPrecedence.CALL_PRECEDENCE); |
| 1761 use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE); | 1770 use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE); |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1830 world.registerStaticUse(superMethod); | 1839 world.registerStaticUse(superMethod); |
| 1831 } | 1840 } |
| 1832 | 1841 |
| 1833 visitFieldGet(HFieldGet node) { | 1842 visitFieldGet(HFieldGet node) { |
| 1834 String name = compiler.namer.getName(node.element); | 1843 String name = compiler.namer.getName(node.element); |
| 1835 beginExpression(JSPrecedence.MEMBER_PRECEDENCE); | 1844 beginExpression(JSPrecedence.MEMBER_PRECEDENCE); |
| 1836 use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE); | 1845 use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE); |
| 1837 buffer.add('.'); | 1846 buffer.add('.'); |
| 1838 buffer.add(name); | 1847 buffer.add(name); |
| 1839 beginExpression(JSPrecedence.MEMBER_PRECEDENCE); | 1848 beginExpression(JSPrecedence.MEMBER_PRECEDENCE); |
| 1840 Type type = node.receiver.propagatedType.computeType(compiler); | 1849 HType receiverHType = work.types[node.receiver]; |
| 1850 Type type = receiverHType.computeType(compiler); |
| 1841 if (type != null) { | 1851 if (type != null) { |
| 1842 world.registerFieldGetter(node.element.name, type); | 1852 world.registerFieldGetter(node.element.name, type); |
| 1843 } | 1853 } |
| 1844 } | 1854 } |
| 1845 | 1855 |
| 1846 // Determine if an instruction is a simple number computation | 1856 // Determine if an instruction is a simple number computation |
| 1847 // involving only things with guaranteed number types and a given | 1857 // involving only things with guaranteed number types and a given |
| 1848 // field. | 1858 // field. |
| 1849 bool isSimpleFieldNumberComputation(HInstruction value, HFieldSet node) { | 1859 bool isSimpleFieldNumberComputation(HInstruction value, HFieldSet node) { |
| 1850 if (value.guaranteedType.union(HType.NUMBER) == HType.NUMBER) return true; | 1860 if (value.guaranteedType.union(HType.NUMBER) == HType.NUMBER) return true; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1862 node.value.hasGuaranteedType() && | 1872 node.value.hasGuaranteedType() && |
| 1863 node.block.dominates(currentGraph.exit)) { | 1873 node.block.dominates(currentGraph.exit)) { |
| 1864 backend.updateFieldConstructorSetters(node.element, | 1874 backend.updateFieldConstructorSetters(node.element, |
| 1865 node.value.guaranteedType); | 1875 node.value.guaranteedType); |
| 1866 } | 1876 } |
| 1867 String name = compiler.namer.getName(node.element); | 1877 String name = compiler.namer.getName(node.element); |
| 1868 beginExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE); | 1878 beginExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE); |
| 1869 use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE); | 1879 use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE); |
| 1870 buffer.add('.'); | 1880 buffer.add('.'); |
| 1871 buffer.add(name); | 1881 buffer.add(name); |
| 1872 Type type = node.receiver.propagatedType.computeType(compiler); | 1882 HTypeMap types = work.types; |
| 1883 Type type = types[node.receiver].computeType(compiler); |
| 1873 if (type != null) { | 1884 if (type != null) { |
| 1874 if (!work.element.isGenerativeConstructorBody()) { | 1885 if (!work.element.isGenerativeConstructorBody()) { |
| 1875 world.registerFieldSetter(node.element.name, type); | 1886 world.registerFieldSetter(node.element.name, type); |
| 1876 } | 1887 } |
| 1877 // Determine the types seen so far for the field. If only number | 1888 // Determine the types seen so far for the field. If only number |
| 1878 // types have been seen and the value of the field set is a | 1889 // types have been seen and the value of the field set is a |
| 1879 // simple number computation only depending on that field, we | 1890 // simple number computation only depending on that field, we |
| 1880 // can safely keep the number type for the field. | 1891 // can safely keep the number type for the field. |
| 1881 HType fieldSettersType = backend.fieldSettersTypeSoFar(node.element); | 1892 HType fieldSettersType = backend.fieldSettersTypeSoFar(node.element); |
| 1882 HType initializersType = backend.typeFromInitializersSoFar(node.element); | 1893 HType initializersType = backend.typeFromInitializersSoFar(node.element); |
| 1883 HType fieldType = fieldSettersType.union(initializersType); | 1894 HType fieldType = fieldSettersType.union(initializersType); |
| 1884 if (HType.NUMBER.union(fieldType) == HType.NUMBER && | 1895 if (HType.NUMBER.union(fieldType) == HType.NUMBER && |
| 1885 isSimpleFieldNumberComputation(node.value, node)) { | 1896 isSimpleFieldNumberComputation(node.value, node)) { |
| 1886 backend.updateFieldSetters(node.element, HType.NUMBER); | 1897 backend.updateFieldSetters(node.element, HType.NUMBER); |
| 1887 } else { | 1898 } else { |
| 1888 backend.updateFieldSetters(node.element, | 1899 backend.updateFieldSetters(node.element, types[node.value]); |
| 1889 node.value.propagatedType); | |
| 1890 } | 1900 } |
| 1891 } | 1901 } |
| 1892 buffer.add(' = '); | 1902 buffer.add(' = '); |
| 1893 use(node.value, JSPrecedence.ASSIGNMENT_PRECEDENCE); | 1903 use(node.value, JSPrecedence.ASSIGNMENT_PRECEDENCE); |
| 1894 endExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE); | 1904 endExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE); |
| 1895 } | 1905 } |
| 1896 | 1906 |
| 1897 visitLocalGet(HLocalGet node) { | 1907 visitLocalGet(HLocalGet node) { |
| 1898 use(node.receiver, JSPrecedence.EXPRESSION_PRECEDENCE); | 1908 use(node.receiver, JSPrecedence.EXPRESSION_PRECEDENCE); |
| 1899 } | 1909 } |
| (...skipping 15 matching lines...) Expand all Loading... |
| 1915 beginExpression(JSPrecedence.EXPRESSION_PRECEDENCE); | 1925 beginExpression(JSPrecedence.EXPRESSION_PRECEDENCE); |
| 1916 buffer.add(parts[0]); | 1926 buffer.add(parts[0]); |
| 1917 for (int i = 0; i < inputs.length; i++) { | 1927 for (int i = 0; i < inputs.length; i++) { |
| 1918 use(inputs[i], JSPrecedence.EXPRESSION_PRECEDENCE); | 1928 use(inputs[i], JSPrecedence.EXPRESSION_PRECEDENCE); |
| 1919 buffer.add(parts[i + 1]); | 1929 buffer.add(parts[i + 1]); |
| 1920 } | 1930 } |
| 1921 endExpression(JSPrecedence.EXPRESSION_PRECEDENCE); | 1931 endExpression(JSPrecedence.EXPRESSION_PRECEDENCE); |
| 1922 } | 1932 } |
| 1923 | 1933 |
| 1924 visitForeignNew(HForeignNew node) { | 1934 visitForeignNew(HForeignNew node) { |
| 1935 HTypeMap types = work.types; |
| 1925 int j = 0; | 1936 int j = 0; |
| 1926 node.element.forEachInstanceField( | 1937 node.element.forEachInstanceField( |
| 1927 includeBackendMembers: true, | 1938 includeBackendMembers: true, |
| 1928 includeSuperMembers: true, | 1939 includeSuperMembers: true, |
| 1929 f: (ClassElement enclosingClass, Element member) { | 1940 f: (ClassElement enclosingClass, Element member) { |
| 1930 backend.updateFieldInitializers(member, | 1941 backend.updateFieldInitializers(member, types[node.inputs[j]]); |
| 1931 node.inputs[j].propagatedType); | |
| 1932 j++; | 1942 j++; |
| 1933 }); | 1943 }); |
| 1934 String jsClassReference = compiler.namer.isolateAccess(node.element); | 1944 String jsClassReference = compiler.namer.isolateAccess(node.element); |
| 1935 beginExpression(JSPrecedence.MEMBER_PRECEDENCE); | 1945 beginExpression(JSPrecedence.MEMBER_PRECEDENCE); |
| 1936 buffer.add('new $jsClassReference('); | 1946 buffer.add('new $jsClassReference('); |
| 1937 // We can't use 'visitArguments', since our arguments start at input[0]. | 1947 // We can't use 'visitArguments', since our arguments start at input[0]. |
| 1938 List<HInstruction> inputs = node.inputs; | 1948 List<HInstruction> inputs = node.inputs; |
| 1939 for (int i = 0; i < inputs.length; i++) { | 1949 for (int i = 0; i < inputs.length; i++) { |
| 1940 if (i != 0) buffer.add(', '); | 1950 if (i != 0) buffer.add(', '); |
| 1941 use(inputs[i], JSPrecedence.ASSIGNMENT_PRECEDENCE); | 1951 use(inputs[i], JSPrecedence.ASSIGNMENT_PRECEDENCE); |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2011 } | 2021 } |
| 2012 } | 2022 } |
| 2013 | 2023 |
| 2014 visitNot(HNot node) { | 2024 visitNot(HNot node) { |
| 2015 assert(node.inputs.length == 1); | 2025 assert(node.inputs.length == 1); |
| 2016 generateNot(node.inputs[0]); | 2026 generateNot(node.inputs[0]); |
| 2017 } | 2027 } |
| 2018 | 2028 |
| 2019 | 2029 |
| 2020 void generateNot(HInstruction input) { | 2030 void generateNot(HInstruction input) { |
| 2031 HTypeMap types = work.types; |
| 2032 |
| 2021 bool isBuiltinRelational(HInstruction instruction) { | 2033 bool isBuiltinRelational(HInstruction instruction) { |
| 2022 if (instruction is !HRelational) return false; | 2034 if (instruction is !HRelational) return false; |
| 2023 HRelational relational = instruction; | 2035 HRelational relational = instruction; |
| 2024 return relational.builtin; | 2036 return relational.isBuiltin(types); |
| 2025 } | 2037 } |
| 2026 | 2038 |
| 2027 if (input is HBoolify && isGenerateAtUseSite(input)) { | 2039 if (input is HBoolify && isGenerateAtUseSite(input)) { |
| 2028 beginExpression(JSPrecedence.EQUALITY_PRECEDENCE); | 2040 beginExpression(JSPrecedence.EQUALITY_PRECEDENCE); |
| 2029 use(input.inputs[0], JSPrecedence.EQUALITY_PRECEDENCE); | 2041 use(input.inputs[0], JSPrecedence.EQUALITY_PRECEDENCE); |
| 2030 buffer.add(' !== true'); | 2042 buffer.add(' !== true'); |
| 2031 endExpression(JSPrecedence.EQUALITY_PRECEDENCE); | 2043 endExpression(JSPrecedence.EQUALITY_PRECEDENCE); |
| 2032 } else if (isBuiltinRelational(input) && | 2044 } else if (isBuiltinRelational(input) && |
| 2033 isGenerateAtUseSite(input) && | 2045 isGenerateAtUseSite(input) && |
| 2034 input.inputs[0].propagatedType.isUseful() && | 2046 types[input.inputs[0]].isUseful() && |
| 2035 !input.inputs[0].isDouble() && | 2047 !input.inputs[0].isDouble(types) && |
| 2036 input.inputs[1].propagatedType.isUseful() && | 2048 types[input.inputs[1]].isUseful() && |
| 2037 !input.inputs[1].isDouble()) { | 2049 !input.inputs[1].isDouble(types)) { |
| 2038 // This optimization doesn't work for NaN, so we only do it if the | 2050 // This optimization doesn't work for NaN, so we only do it if the |
| 2039 // type is known to be non-Double. | 2051 // type is known to be non-Double. |
| 2040 Map<String, String> inverseOperator = const <String>{ | 2052 Map<String, String> inverseOperator = const <String>{ |
| 2041 "==" : "!=", | 2053 "==" : "!=", |
| 2042 "!=" : "==", | 2054 "!=" : "==", |
| 2043 "===": "!==", | 2055 "===": "!==", |
| 2044 "!==": "===", | 2056 "!==": "===", |
| 2045 "<" : ">=", | 2057 "<" : ">=", |
| 2046 "<=" : ">", | 2058 "<=" : ">", |
| 2047 ">" : "<=", | 2059 ">" : "<=", |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2225 } | 2237 } |
| 2226 | 2238 |
| 2227 bool isEmptyString(HInstruction node) { | 2239 bool isEmptyString(HInstruction node) { |
| 2228 if (!node.isConstantString()) return false; | 2240 if (!node.isConstantString()) return false; |
| 2229 HConstant constant = node; | 2241 HConstant constant = node; |
| 2230 StringConstant string = constant.constant; | 2242 StringConstant string = constant.constant; |
| 2231 return string.value.length == 0; | 2243 return string.value.length == 0; |
| 2232 } | 2244 } |
| 2233 | 2245 |
| 2234 void useStringified(HInstruction node, int precedence) { | 2246 void useStringified(HInstruction node, int precedence) { |
| 2235 if (node.isString()) { | 2247 if (node.isString(work.types)) { |
| 2236 use(node, precedence); | 2248 use(node, precedence); |
| 2237 } else { | 2249 } else { |
| 2238 Element convertToString = compiler.findHelper(const SourceString("S")); | 2250 Element convertToString = compiler.findHelper(const SourceString("S")); |
| 2239 world.registerStaticUse(convertToString); | 2251 world.registerStaticUse(convertToString); |
| 2240 buffer.add(compiler.namer.isolateAccess(convertToString)); | 2252 buffer.add(compiler.namer.isolateAccess(convertToString)); |
| 2241 buffer.add('('); | 2253 buffer.add('('); |
| 2242 use(node, JSPrecedence.EXPRESSION_PRECEDENCE); | 2254 use(node, JSPrecedence.EXPRESSION_PRECEDENCE); |
| 2243 buffer.add(')'); | 2255 buffer.add(')'); |
| 2244 } | 2256 } |
| 2245 } | 2257 } |
| 2246 | 2258 |
| 2247 void visitLiteralList(HLiteralList node) { | 2259 void visitLiteralList(HLiteralList node) { |
| 2248 generateArrayLiteral(node); | 2260 generateArrayLiteral(node); |
| 2249 } | 2261 } |
| 2250 | 2262 |
| 2251 void generateArrayLiteral(HLiteralList node) { | 2263 void generateArrayLiteral(HLiteralList node) { |
| 2252 buffer.add('['); | 2264 buffer.add('['); |
| 2253 int len = node.inputs.length; | 2265 int len = node.inputs.length; |
| 2254 for (int i = 0; i < len; i++) { | 2266 for (int i = 0; i < len; i++) { |
| 2255 if (i != 0) buffer.add(', '); | 2267 if (i != 0) buffer.add(', '); |
| 2256 use(node.inputs[i], JSPrecedence.ASSIGNMENT_PRECEDENCE); | 2268 use(node.inputs[i], JSPrecedence.ASSIGNMENT_PRECEDENCE); |
| 2257 } | 2269 } |
| 2258 buffer.add(']'); | 2270 buffer.add(']'); |
| 2259 } | 2271 } |
| 2260 | 2272 |
| 2261 void visitIndex(HIndex node) { | 2273 void visitIndex(HIndex node) { |
| 2262 if (node.builtin) { | 2274 if (node.isBuiltin(work.types)) { |
| 2263 beginExpression(JSPrecedence.MEMBER_PRECEDENCE); | 2275 beginExpression(JSPrecedence.MEMBER_PRECEDENCE); |
| 2264 use(node.inputs[1], JSPrecedence.MEMBER_PRECEDENCE); | 2276 use(node.inputs[1], JSPrecedence.MEMBER_PRECEDENCE); |
| 2265 buffer.add('['); | 2277 buffer.add('['); |
| 2266 use(node.inputs[2], JSPrecedence.EXPRESSION_PRECEDENCE); | 2278 use(node.inputs[2], JSPrecedence.EXPRESSION_PRECEDENCE); |
| 2267 buffer.add(']'); | 2279 buffer.add(']'); |
| 2268 endExpression(JSPrecedence.MEMBER_PRECEDENCE); | 2280 endExpression(JSPrecedence.MEMBER_PRECEDENCE); |
| 2269 } else { | 2281 } else { |
| 2270 visitInvokeStatic(node); | 2282 visitInvokeStatic(node); |
| 2271 } | 2283 } |
| 2272 } | 2284 } |
| 2273 | 2285 |
| 2274 void visitIndexAssign(HIndexAssign node) { | 2286 void visitIndexAssign(HIndexAssign node) { |
| 2275 if (node.builtin) { | 2287 if (node.isBuiltin(work.types)) { |
| 2276 beginExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE); | 2288 beginExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE); |
| 2277 use(node.inputs[1], JSPrecedence.MEMBER_PRECEDENCE); | 2289 use(node.inputs[1], JSPrecedence.MEMBER_PRECEDENCE); |
| 2278 buffer.add('['); | 2290 buffer.add('['); |
| 2279 use(node.inputs[2], JSPrecedence.EXPRESSION_PRECEDENCE); | 2291 use(node.inputs[2], JSPrecedence.EXPRESSION_PRECEDENCE); |
| 2280 buffer.add('] = '); | 2292 buffer.add('] = '); |
| 2281 use(node.inputs[3], JSPrecedence.ASSIGNMENT_PRECEDENCE); | 2293 use(node.inputs[3], JSPrecedence.ASSIGNMENT_PRECEDENCE); |
| 2282 endExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE); | 2294 endExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE); |
| 2283 } else { | 2295 } else { |
| 2284 visitInvokeStatic(node); | 2296 visitInvokeStatic(node); |
| 2285 } | 2297 } |
| 2286 } | 2298 } |
| 2287 | 2299 |
| 2288 String builtinJsName(HInvokeInterceptor interceptor) { | 2300 String builtinJsName(HInvokeInterceptor interceptor) { |
| 2289 // Don't count the target method or the receiver in the arity. | 2301 // Don't count the target method or the receiver in the arity. |
| 2290 int arity = interceptor.inputs.length - 2; | 2302 int arity = interceptor.inputs.length - 2; |
| 2291 HInstruction receiver = interceptor.inputs[1]; | 2303 HInstruction receiver = interceptor.inputs[1]; |
| 2292 bool getter = interceptor.getter; | 2304 bool getter = interceptor.getter; |
| 2293 SourceString name = interceptor.name; | 2305 SourceString name = interceptor.name; |
| 2294 | 2306 |
| 2295 if (interceptor.isLengthGetterOnStringOrArray()) { | 2307 HTypeMap types = work.types; |
| 2308 |
| 2309 if (interceptor.isLengthGetterOnStringOrArray(types)) { |
| 2296 return 'length'; | 2310 return 'length'; |
| 2297 } else if (receiver.isExtendableArray() && !getter) { | 2311 } else if (receiver.isExtendableArray(types) && !getter) { |
| 2298 if (name == const SourceString('add') && arity == 1) { | 2312 if (name == const SourceString('add') && arity == 1) { |
| 2299 return 'push'; | 2313 return 'push'; |
| 2300 } | 2314 } |
| 2301 if (name == const SourceString('removeLast') && arity == 0) { | 2315 if (name == const SourceString('removeLast') && arity == 0) { |
| 2302 return 'pop'; | 2316 return 'pop'; |
| 2303 } | 2317 } |
| 2304 } else if (receiver.isString() && !getter) { | 2318 } else if (receiver.isString(types) && !getter) { |
| 2305 if (name == const SourceString('concat') && | 2319 if (name == const SourceString('concat') && |
| 2306 arity == 1 && | 2320 arity == 1 && |
| 2307 interceptor.inputs[2].isString()) { | 2321 interceptor.inputs[2].isString(types)) { |
| 2308 return '+'; | 2322 return '+'; |
| 2309 } | 2323 } |
| 2310 } | 2324 } |
| 2311 | 2325 |
| 2312 return null; | 2326 return null; |
| 2313 } | 2327 } |
| 2314 | 2328 |
| 2315 void visitInvokeInterceptor(HInvokeInterceptor node) { | 2329 void visitInvokeInterceptor(HInvokeInterceptor node) { |
| 2316 String builtin = builtinJsName(node); | 2330 String builtin = builtinJsName(node); |
| 2317 if (builtin !== null) { | 2331 if (builtin !== null) { |
| (...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2552 beginExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE); | 2566 beginExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE); |
| 2553 checkNum(input, '==='); | 2567 checkNum(input, '==='); |
| 2554 buffer.add(' && '); | 2568 buffer.add(' && '); |
| 2555 checkInt(input, '==='); | 2569 checkInt(input, '==='); |
| 2556 endExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE); | 2570 endExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE); |
| 2557 } else if (Elements.isStringSupertype(element, compiler)) { | 2571 } else if (Elements.isStringSupertype(element, compiler)) { |
| 2558 handleStringSupertypeCheck(input, element); | 2572 handleStringSupertypeCheck(input, element); |
| 2559 } else if (element === compiler.listClass | 2573 } else if (element === compiler.listClass |
| 2560 || Elements.isListSupertype(element, compiler)) { | 2574 || Elements.isListSupertype(element, compiler)) { |
| 2561 handleListOrSupertypeCheck(input, element); | 2575 handleListOrSupertypeCheck(input, element); |
| 2562 } else if (input.propagatedType.canBePrimitive() | 2576 } else if (work.types[input].canBePrimitive() |
| 2563 || input.propagatedType.canBeNull()) { | 2577 || work.types[input].canBeNull()) { |
| 2564 beginExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE); | 2578 beginExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE); |
| 2565 checkObject(input, '==='); | 2579 checkObject(input, '==='); |
| 2566 buffer.add(' && '); | 2580 buffer.add(' && '); |
| 2567 checkType(input, element); | 2581 checkType(input, element); |
| 2568 endExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE); | 2582 endExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE); |
| 2569 } else { | 2583 } else { |
| 2570 checkType(input, element); | 2584 checkType(input, element); |
| 2571 } | 2585 } |
| 2572 if (compiler.codegenWorld.rti.hasTypeArguments(type)) { | 2586 if (compiler.codegenWorld.rti.hasTypeArguments(type)) { |
| 2573 InterfaceType interfaceType = type; | 2587 InterfaceType interfaceType = type; |
| (...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2749 // Make sure we call the bailout method with the number of | 2763 // Make sure we call the bailout method with the number of |
| 2750 // arguments it expects. This avoids having the underlying | 2764 // arguments it expects. This avoids having the underlying |
| 2751 // JS engine fill them in for us. | 2765 // JS engine fill them in for us. |
| 2752 for (; i < maxBailoutParameters; i++) { | 2766 for (; i < maxBailoutParameters; i++) { |
| 2753 buffer.add(', 0'); | 2767 buffer.add(', 0'); |
| 2754 } | 2768 } |
| 2755 buffer.add(')'); | 2769 buffer.add(')'); |
| 2756 } | 2770 } |
| 2757 | 2771 |
| 2758 void visitTypeGuard(HTypeGuard node) { | 2772 void visitTypeGuard(HTypeGuard node) { |
| 2773 HTypeMap types = work.types; |
| 2759 addIndentation(); | 2774 addIndentation(); |
| 2760 HInstruction input = node.guarded; | 2775 HInstruction input = node.guarded; |
| 2761 Element indexingBehavior = compiler.jsIndexingBehaviorInterface; | 2776 Element indexingBehavior = compiler.jsIndexingBehaviorInterface; |
| 2762 if (node.isInteger()) { | 2777 if (node.isInteger(types)) { |
| 2763 // if (input is !int) bailout | 2778 // if (input is !int) bailout |
| 2764 buffer.add('if ('); | 2779 buffer.add('if ('); |
| 2765 checkInt(input, '!=='); | 2780 checkInt(input, '!=='); |
| 2766 buffer.add(') '); | 2781 buffer.add(') '); |
| 2767 bailout(node, 'Not an integer'); | 2782 bailout(node, 'Not an integer'); |
| 2768 } else if (node.isNumber()) { | 2783 } else if (node.isNumber(types)) { |
| 2769 // if (input is !num) bailout | 2784 // if (input is !num) bailout |
| 2770 buffer.add('if ('); | 2785 buffer.add('if ('); |
| 2771 checkNum(input, '!=='); | 2786 checkNum(input, '!=='); |
| 2772 buffer.add(') '); | 2787 buffer.add(') '); |
| 2773 bailout(node, 'Not a number'); | 2788 bailout(node, 'Not a number'); |
| 2774 } else if (node.isBoolean()) { | 2789 } else if (node.isBoolean(types)) { |
| 2775 // if (input is !bool) bailout | 2790 // if (input is !bool) bailout |
| 2776 buffer.add('if ('); | 2791 buffer.add('if ('); |
| 2777 checkBool(input, '!=='); | 2792 checkBool(input, '!=='); |
| 2778 buffer.add(') '); | 2793 buffer.add(') '); |
| 2779 bailout(node, 'Not a boolean'); | 2794 bailout(node, 'Not a boolean'); |
| 2780 } else if (node.isString()) { | 2795 } else if (node.isString(types)) { |
| 2781 // if (input is !string) bailout | 2796 // if (input is !string) bailout |
| 2782 buffer.add('if ('); | 2797 buffer.add('if ('); |
| 2783 checkString(input, '!=='); | 2798 checkString(input, '!=='); |
| 2784 buffer.add(') '); | 2799 buffer.add(') '); |
| 2785 bailout(node, 'Not a string'); | 2800 bailout(node, 'Not a string'); |
| 2786 } else if (node.isExtendableArray()) { | 2801 } else if (node.isExtendableArray(types)) { |
| 2787 // if (input is !Object || input is !Array || input.isFixed) bailout | 2802 // if (input is !Object || input is !Array || input.isFixed) bailout |
| 2788 buffer.add('if ('); | 2803 buffer.add('if ('); |
| 2789 checkObject(input, '!=='); | 2804 checkObject(input, '!=='); |
| 2790 buffer.add('||'); | 2805 buffer.add('||'); |
| 2791 checkArray(input, '!=='); | 2806 checkArray(input, '!=='); |
| 2792 buffer.add('||'); | 2807 buffer.add('||'); |
| 2793 checkFixedArray(input); | 2808 checkFixedArray(input); |
| 2794 buffer.add(') '); | 2809 buffer.add(') '); |
| 2795 bailout(node, 'Not an extendable array'); | 2810 bailout(node, 'Not an extendable array'); |
| 2796 } else if (node.isMutableArray()) { | 2811 } else if (node.isMutableArray(types)) { |
| 2797 // if (input is !Object | 2812 // if (input is !Object |
| 2798 // || ((input is !Array || input.isImmutable) | 2813 // || ((input is !Array || input.isImmutable) |
| 2799 // && input is !JsIndexingBehavior)) bailout | 2814 // && input is !JsIndexingBehavior)) bailout |
| 2800 buffer.add('if ('); | 2815 buffer.add('if ('); |
| 2801 checkObject(input, '!=='); | 2816 checkObject(input, '!=='); |
| 2802 buffer.add(' || (('); | 2817 buffer.add(' || (('); |
| 2803 checkArray(input, '!=='); | 2818 checkArray(input, '!=='); |
| 2804 buffer.add(' || '); | 2819 buffer.add(' || '); |
| 2805 checkImmutableArray(input); | 2820 checkImmutableArray(input); |
| 2806 buffer.add(') && '); | 2821 buffer.add(') && '); |
| 2807 checkType(input, indexingBehavior, negative: true); | 2822 checkType(input, indexingBehavior, negative: true); |
| 2808 buffer.add(')) '); | 2823 buffer.add(')) '); |
| 2809 bailout(node, 'Not a mutable array'); | 2824 bailout(node, 'Not a mutable array'); |
| 2810 } else if (node.isReadableArray()) { | 2825 } else if (node.isReadableArray(types)) { |
| 2811 // if (input is !Object | 2826 // if (input is !Object |
| 2812 // || (input is !Array && input is !JsIndexingBehavior)) bailout | 2827 // || (input is !Array && input is !JsIndexingBehavior)) bailout |
| 2813 buffer.add('if ('); | 2828 buffer.add('if ('); |
| 2814 checkObject(input, '!=='); | 2829 checkObject(input, '!=='); |
| 2815 buffer.add(' || ('); | 2830 buffer.add(' || ('); |
| 2816 checkArray(input, '!=='); | 2831 checkArray(input, '!=='); |
| 2817 buffer.add(' && '); | 2832 buffer.add(' && '); |
| 2818 checkType(input, indexingBehavior, negative: true); | 2833 checkType(input, indexingBehavior, negative: true); |
| 2819 buffer.add(')) '); | 2834 buffer.add(')) '); |
| 2820 bailout(node, 'Not an array'); | 2835 bailout(node, 'Not an array'); |
| 2821 } else if (node.isIndexablePrimitive()) { | 2836 } else if (node.isIndexablePrimitive(types)) { |
| 2822 // if (input is !String | 2837 // if (input is !String |
| 2823 // && (input is !Object | 2838 // && (input is !Object |
| 2824 // || (input is !Array && input is !JsIndexingBehavior))) bailout | 2839 // || (input is !Array && input is !JsIndexingBehavior))) bailout |
| 2825 buffer.add('if ('); | 2840 buffer.add('if ('); |
| 2826 checkString(input, '!=='); | 2841 checkString(input, '!=='); |
| 2827 buffer.add(' && ('); | 2842 buffer.add(' && ('); |
| 2828 checkObject(input, '!=='); | 2843 checkObject(input, '!=='); |
| 2829 buffer.add(' || ('); | 2844 buffer.add(' || ('); |
| 2830 checkArray(input, '!=='); | 2845 checkArray(input, '!=='); |
| 2831 buffer.add(' && '); | 2846 buffer.add(' && '); |
| (...skipping 336 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3168 } | 3183 } |
| 3169 } | 3184 } |
| 3170 | 3185 |
| 3171 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { | 3186 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { |
| 3172 if (labeledBlockInfo.body.start.hasBailoutTargets()) { | 3187 if (labeledBlockInfo.body.start.hasBailoutTargets()) { |
| 3173 endBailoutSwitch(); | 3188 endBailoutSwitch(); |
| 3174 } | 3189 } |
| 3175 } | 3190 } |
| 3176 } | 3191 } |
| 3177 | 3192 |
| 3178 String singleIdentityComparison(HInstruction left, HInstruction right) { | 3193 String singleIdentityComparison(HInstruction left, |
| 3194 HInstruction right, |
| 3195 HTypeMap propagatedTypes) { |
| 3179 // Returns the single identity comparison (== or ===) or null if a more | 3196 // Returns the single identity comparison (== or ===) or null if a more |
| 3180 // complex expression is required. | 3197 // complex expression is required. |
| 3181 HType leftType = left.propagatedType; | 3198 HType leftType = propagatedTypes[left]; |
| 3182 HType rightType = right.propagatedType; | 3199 HType rightType = propagatedTypes[right]; |
| 3183 if (leftType.canBeNull() && rightType.canBeNull()) { | 3200 if (leftType.canBeNull() && rightType.canBeNull()) { |
| 3184 if (left.isConstantNull() || right.isConstantNull() || | 3201 if (left.isConstantNull() || right.isConstantNull() || |
| 3185 (leftType.isPrimitive() && leftType == rightType)) { | 3202 (leftType.isPrimitive() && leftType == rightType)) { |
| 3186 return '=='; | 3203 return '=='; |
| 3187 } | 3204 } |
| 3188 return null; | 3205 return null; |
| 3189 } else { | 3206 } else { |
| 3190 return '==='; | 3207 return '==='; |
| 3191 } | 3208 } |
| 3192 } | 3209 } |
| OLD | NEW |