| 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 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 266 buffer.add('('); | 266 buffer.add('('); |
| 267 } | 267 } |
| 268 } | 268 } |
| 269 | 269 |
| 270 void endExpression(int precedence) { | 270 void endExpression(int precedence) { |
| 271 if (precedence < expectedPrecedence) { | 271 if (precedence < expectedPrecedence) { |
| 272 buffer.add(')'); | 272 buffer.add(')'); |
| 273 } | 273 } |
| 274 } | 274 } |
| 275 | 275 |
| 276 /** |
| 277 * Adds parenthes around the code generated by [body] if necessary. |
| 278 * The precedence level of the body is assumed to be [precedence]. |
| 279 */ |
| 280 void parenthesize(int precedence, void body()) { |
| 281 int oldPrecedence = expectedPrecedence; |
| 282 beginExpression(precedence); |
| 283 // Raise the expected precedence-level to what the body expects. |
| 284 expectedPrecedence = precedence; |
| 285 body(); |
| 286 expectedPrecedence = oldPrecedence; |
| 287 endExpression(precedence); |
| 288 } |
| 289 |
| 276 void withPrecedence(int precedence, void action()) { | 290 void withPrecedence(int precedence, void action()) { |
| 277 int oldPrecedence = expectedPrecedence; | 291 int oldPrecedence = expectedPrecedence; |
| 278 beginExpression(precedence); | |
| 279 expectedPrecedence = precedence; | 292 expectedPrecedence = precedence; |
| 280 action(); | 293 action(); |
| 281 expectedPrecedence = oldPrecedence; | 294 expectedPrecedence = oldPrecedence; |
| 282 endExpression(precedence); | 295 } |
| 296 |
| 297 /** |
| 298 * Generates code for a JavaScript binary operator. |
| 299 * The code is parenthesized if necessary, and the expected |
| 300 * precedence level of the left- and right-hand sides is set, |
| 301 * based on the operator. |
| 302 */ |
| 303 void binary(String operator, void lhs(), void rhs()) { |
| 304 JSBinaryOperatorPrecedence op = JSPrecedence.binary[operator]; |
| 305 beginExpression(op.precedence); |
| 306 withPrecedence(op.left, lhs); |
| 307 buffer.add(' '); |
| 308 buffer.add(operator); |
| 309 buffer.add(' '); |
| 310 withPrecedence(op.right, rhs); |
| 311 endExpression(op.precedence); |
| 312 } |
| 313 |
| 314 /** |
| 315 * Generate code for a JavaScript postfix operator (only -- and ++ |
| 316 * exist). |
| 317 */ |
| 318 void PostfixExpression(String operator, void body()) { |
| 319 // Corresponds to a JavaScript production of the form (ES5 11.3): |
| 320 // PostfixExpression ::= LeftHandSideExpression <operator> |
| 321 beginExpression(JSPrecedence.POSTFIX_PRECEDENCE); |
| 322 withPrecedence(JSPrecedence.CALL_PRECEDENCE, body); |
| 323 buffer.add(operator); |
| 324 endExpression(JSPrecedence.PSOTFIX_PRECEDENCE); |
| 325 } |
| 326 |
| 327 /** |
| 328 * Generate code for a JavaScript prefix operator. |
| 329 * There are no validation on the operator text. If it is a "word" |
| 330 * operator (e.g., "typeof" or "void") the caller should put in a |
| 331 * trailing space if necessary to delimit it from the following |
| 332 * expression. |
| 333 */ |
| 334 void prefix(String operator, void body()) { |
| 335 // Corresponds to a JavaScript production of the form (ES5 11.4): |
| 336 // UnaryExpression ::= <operator> UnaryExpression |
| 337 beginExpression(JSPrecedence.PREFIX_PRECEDENCE); |
| 338 buffer.add(operator); |
| 339 withPrecedence(JSPrecedence.PREFIX_PRECEDENCE, body); |
| 340 endExpression(JSPrecedence.PREFIX_PRECEDENCE); |
| 341 } |
| 342 |
| 343 void conditional(void condition(), [void ifTrue(), void ifFalse()]) { |
| 344 beginExpression(JSPrecedence.CONDITIONAL_PRECEDENCE); |
| 345 withPrecedence(JSPrecedence.LOGICAL_OR_PRECEDENCE, condition); |
| 346 buffer.add(" ? "); |
| 347 withPrecedence(JSPrecedence.ASSIGNMENT_PRECEDENCE, ifTrue); |
| 348 buffer.add(" : "); |
| 349 withPrecedence(JSPrecedence.ASSIGNMENT_PRECEDENCE, ifFalse); |
| 350 endExpression(JSPrecedence.CONDITIONAL_PRECEDENCE); |
| 351 } |
| 352 |
| 353 void literal(String text) { |
| 354 buffer.add(text); |
| 283 } | 355 } |
| 284 | 356 |
| 285 void preGenerateMethod(HGraph graph) { | 357 void preGenerateMethod(HGraph graph) { |
| 286 new SsaInstructionMerger(generateAtUseSite).visitGraph(graph); | 358 new SsaInstructionMerger(generateAtUseSite).visitGraph(graph); |
| 287 new SsaConditionMerger(generateAtUseSite, | 359 new SsaConditionMerger(generateAtUseSite, |
| 288 controlFlowOperators).visitGraph(graph); | 360 controlFlowOperators).visitGraph(graph); |
| 289 SsaLiveIntervalBuilder intervalBuilder = | 361 SsaLiveIntervalBuilder intervalBuilder = |
| 290 new SsaLiveIntervalBuilder(compiler, generateAtUseSite); | 362 new SsaLiveIntervalBuilder(compiler, generateAtUseSite); |
| 291 intervalBuilder.visitGraph(graph); | 363 intervalBuilder.visitGraph(graph); |
| 292 SsaVariableAllocator allocator = new SsaVariableAllocator( | 364 SsaVariableAllocator allocator = new SsaVariableAllocator( |
| (...skipping 270 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 563 // the short update definition if it is. | 635 // the short update definition if it is. |
| 564 if (variableNames.getName(left) == name) { | 636 if (variableNames.getName(left) == name) { |
| 565 // Check if the right operand is constant one. | 637 // Check if the right operand is constant one. |
| 566 bool rightIsOne = false; | 638 bool rightIsOne = false; |
| 567 if (right.isConstantNumber()) { | 639 if (right.isConstantNumber()) { |
| 568 HConstant rightConstant = right; | 640 HConstant rightConstant = right; |
| 569 NumConstant numConstant = rightConstant.constant; | 641 NumConstant numConstant = rightConstant.constant; |
| 570 rightIsOne = (numConstant.value == 1); | 642 rightIsOne = (numConstant.value == 1); |
| 571 } | 643 } |
| 572 if (binaryInstruction is HAdd && rightIsOne) { | 644 if (binaryInstruction is HAdd && rightIsOne) { |
| 573 beginExpression(JSPrecedence.PREFIX_PRECEDENCE); | 645 prefix('++', () => declareVariable(name)); |
| 574 buffer.add('++'); | |
| 575 declareVariable(name); | |
| 576 endExpression(JSPrecedence.PREFIX_PRECEDENCE); | |
| 577 } else if (binaryInstruction is HSubtract && rightIsOne) { | 646 } else if (binaryInstruction is HSubtract && rightIsOne) { |
| 578 beginExpression(JSPrecedence.PREFIX_PRECEDENCE); | 647 prefix("--", () => declareVariable(name)); |
| 579 buffer.add('--'); | |
| 580 declareVariable(name); | |
| 581 endExpression(JSPrecedence.PREFIX_PRECEDENCE); | |
| 582 } else { | 648 } else { |
| 583 var operation = binaryInstruction.operation.name; | 649 var operation = binaryInstruction.operation.name; |
| 584 beginExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE); | 650 binary('$operation=', |
| 585 declareVariable(name); | 651 () => declareVariable(name), |
| 586 buffer.add(' ${operation}= '); | 652 () => use(right, expectedPrecedence)); |
| 587 use(right, JSPrecedence.ASSIGNMENT_PRECEDENCE); | |
| 588 endExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE); | |
| 589 } | 653 } |
| 590 return true; | 654 return true; |
| 591 } | 655 } |
| 592 } | 656 } |
| 593 return false; | 657 return false; |
| 594 } | 658 } |
| 595 | 659 |
| 596 // For simple type checks like i = intTypeCheck(i), we don't have to | 660 // For simple type checks like i = intTypeCheck(i), we don't have to |
| 597 // emit an assignment, because the intTypeCheck just returns its | 661 // emit an assignment, because the intTypeCheck just returns its |
| 598 // argument. | 662 // argument. |
| 599 bool handleTypeConversion(instruction, name) { | 663 bool handleTypeConversion(instruction, name) { |
| 600 if (instruction is !HTypeConversion) return false; | 664 if (instruction is !HTypeConversion) return false; |
| 601 String inputName = variableNames.getName(instruction.checkedInput); | 665 String inputName = variableNames.getName(instruction.checkedInput); |
| 602 if (name != inputName) return false; | 666 if (name != inputName) return false; |
| 603 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE); | 667 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE); |
| 604 return true; | 668 return true; |
| 605 } | 669 } |
| 606 | 670 |
| 607 void define(HInstruction instruction) { | 671 void define(HInstruction instruction) { |
| 608 if (isGeneratingExpression()) { | 672 if (isGeneratingExpression()) { |
| 609 addExpressionSeparator(); | 673 addExpressionSeparator(); |
| 610 } else { | 674 } else { |
| 611 assert(expectedPrecedence == JSPrecedence.STATEMENT_PRECEDENCE); | 675 assert(expectedPrecedence == JSPrecedence.STATEMENT_PRECEDENCE); |
| 612 addIndentation(); | 676 addIndentation(); |
| 613 } | 677 } |
| 614 if (!instruction.isControlFlow() && variableNames.hasName(instruction)) { | 678 if (!instruction.isControlFlow() && variableNames.hasName(instruction)) { |
| 615 var name = variableNames.getName(instruction); | 679 var name = variableNames.getName(instruction); |
| 616 if (!handleSimpleUpdateDefinition(instruction, name) | 680 if (!handleSimpleUpdateDefinition(instruction, name) |
| 617 && !handleTypeConversion(instruction, name)) { | 681 && !handleTypeConversion(instruction, name)) { |
| 618 withPrecedence(JSPrecedence.ASSIGNMENT_PRECEDENCE, () { | 682 binary("=", |
| 619 declareInstruction(instruction); | 683 () => declareInstruction(instruction), |
| 620 buffer.add(" = "); | 684 () => visit(instruction, expectedPrecedence)); |
| 621 visit(instruction, JSPrecedence.ASSIGNMENT_PRECEDENCE); | |
| 622 }); | |
| 623 } | 685 } |
| 624 } else { | 686 } else { |
| 625 visit(instruction, expectedPrecedence); | 687 visit(instruction, expectedPrecedence); |
| 626 } | 688 } |
| 627 if (!isGeneratingExpression()) buffer.add(';\n'); | 689 if (!isGeneratingExpression()) buffer.add(';\n'); |
| 628 } | 690 } |
| 629 | 691 |
| 630 void use(HInstruction argument, int expectedPrecedenceForArgument) { | 692 void use(HInstruction argument, int expectedPrecedenceForArgument) { |
| 631 if (isGenerateAtUseSite(argument)) { | 693 if (isGenerateAtUseSite(argument)) { |
| 632 visit(argument, expectedPrecedenceForArgument); | 694 visit(argument, expectedPrecedenceForArgument); |
| (...skipping 525 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1158 } | 1220 } |
| 1159 assignPhisOfSuccessors(node); | 1221 assignPhisOfSuccessors(node); |
| 1160 if (instruction is HLoopBranch && isGeneratingExpression()) { | 1222 if (instruction is HLoopBranch && isGeneratingExpression()) { |
| 1161 addExpressionSeparator(); | 1223 addExpressionSeparator(); |
| 1162 } | 1224 } |
| 1163 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE); | 1225 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE); |
| 1164 } | 1226 } |
| 1165 | 1227 |
| 1166 visitInvokeBinary(HInvokeBinary node, String op) { | 1228 visitInvokeBinary(HInvokeBinary node, String op) { |
| 1167 if (node.builtin) { | 1229 if (node.builtin) { |
| 1168 JSBinaryOperatorPrecedence operatorPrecedences = JSPrecedence.binary[op]; | 1230 binary(op, |
| 1169 beginExpression(operatorPrecedences.precedence); | 1231 () => use(node.left, expectedPrecedence), |
| 1170 use(node.left, operatorPrecedences.left); | 1232 () => use(node.right, expectedPrecedence)); |
| 1171 buffer.add(' $op '); | |
| 1172 use(node.right, operatorPrecedences.right); | |
| 1173 endExpression(operatorPrecedences.precedence); | |
| 1174 } else { | 1233 } else { |
| 1175 visitInvokeStatic(node); | 1234 visitInvokeStatic(node); |
| 1176 } | 1235 } |
| 1177 } | 1236 } |
| 1178 | 1237 |
| 1179 // We want the outcome of bit-operations to be positive. We use the unsigned | 1238 // We want the outcome of bit-operations to be positive. We use the unsigned |
| 1180 // shift operator to achieve this. | 1239 // shift operator to achieve this. |
| 1181 visitBitInvokeBinary(HBinaryBitOp node, String op) { | 1240 visitBitInvokeBinary(HBinaryBitOp node, String op) { |
| 1182 if (node.builtin && requiresUintConversion(node)) { | 1241 if (node.builtin && requiresUintConversion(node)) { |
| 1183 beginExpression(unsignedShiftPrecedences.precedence); | 1242 binary(">>>", |
| 1184 int oldPrecedence = this.expectedPrecedence; | 1243 () => visitInvokeBinary(node, op), |
| 1185 this.expectedPrecedence = JSPrecedence.SHIFT_PRECEDENCE; | 1244 () => literal("0")); |
| 1186 visitInvokeBinary(node, op); | |
| 1187 buffer.add(' >>> 0'); | |
| 1188 this.expectedPrecedence = oldPrecedence; | |
| 1189 endExpression(unsignedShiftPrecedences.precedence); | |
| 1190 } else { | 1245 } else { |
| 1191 visitInvokeBinary(node, op); | 1246 visitInvokeBinary(node, op); |
| 1192 } | 1247 } |
| 1193 } | 1248 } |
| 1194 | 1249 |
| 1195 visitInvokeUnary(HInvokeUnary node, String op) { | 1250 visitInvokeUnary(HInvokeUnary node, String op) { |
| 1196 if (node.builtin) { | 1251 if (node.builtin) { |
| 1197 beginExpression(JSPrecedence.PREFIX_PRECEDENCE); | 1252 prefix(op, () => use(node.operand, expectedPrecedence)); |
| 1198 buffer.add('$op'); | |
| 1199 use(node.operand, JSPrecedence.PREFIX_PRECEDENCE); | |
| 1200 endExpression(JSPrecedence.PREFIX_PRECEDENCE); | |
| 1201 } else { | 1253 } else { |
| 1202 visitInvokeStatic(node); | 1254 visitInvokeStatic(node); |
| 1203 } | 1255 } |
| 1204 } | 1256 } |
| 1205 | 1257 |
| 1206 // We want the outcome of bit-operations to be positive. We use the unsigned | 1258 // We want the outcome of bit-operations to be positive. We use the unsigned |
| 1207 // shift operator to achieve this. | 1259 // shift operator to achieve this. |
| 1208 visitBitInvokeUnary(HInvokeUnary node, String op) { | 1260 visitBitInvokeUnary(HInvokeUnary node, String op) { |
| 1209 if (node.builtin && requiresUintConversion(node)) { | 1261 if (node.builtin && requiresUintConversion(node)){ |
| 1210 beginExpression(unsignedShiftPrecedences.precedence); | 1262 binary(">>>", |
| 1211 int oldPrecedence = this.expectedPrecedence; | 1263 () => visitInvokeUnary(node, op), |
| 1212 this.expectedPrecedence = JSPrecedence.SHIFT_PRECEDENCE; | 1264 () => literal("0")); |
| 1213 visitInvokeUnary(node, op); | |
| 1214 buffer.add(' >>> 0'); | |
| 1215 this.expectedPrecedence = oldPrecedence; | |
| 1216 endExpression(unsignedShiftPrecedences.precedence); | |
| 1217 } else { | 1265 } else { |
| 1218 visitInvokeUnary(node, op); | 1266 visitInvokeUnary(node, op); |
| 1219 } | 1267 } |
| 1220 } | 1268 } |
| 1221 | 1269 |
| 1222 void emitIdentityComparison(HInstruction left, HInstruction right) { | 1270 void emitIdentityComparison(HInstruction left, HInstruction right) { |
| 1223 HType leftType = left.propagatedType; | 1271 HType leftType = left.propagatedType; |
| 1224 HType rightType = right.propagatedType; | 1272 HType rightType = right.propagatedType; |
| 1225 if (leftType.canBeNull() && rightType.canBeNull()) { | 1273 if (leftType.canBeNull() && rightType.canBeNull()) { |
| 1226 if (left.isConstantNull() || right.isConstantNull() || | 1274 if (left.isConstantNull() || right.isConstantNull() || |
| 1227 (leftType.isPrimitive() && leftType == rightType)) { | 1275 (leftType.isPrimitive() && leftType == rightType)) { |
| 1228 beginExpression(JSPrecedence.EQUALITY_PRECEDENCE); | 1276 binary("==", |
| 1229 use(left, JSPrecedence.EQUALITY_PRECEDENCE); | 1277 () => use(left, expectedPrecedence), |
| 1230 buffer.add(' == '); | 1278 () => use(right, expectedPrecedence)); |
| 1231 use(right, JSPrecedence.RELATIONAL_PRECEDENCE); | |
| 1232 endExpression(JSPrecedence.EQUALITY_PRECEDENCE); | |
| 1233 } else { | 1279 } else { |
| 1234 assert(NullConstant.JsNull == 'null'); | 1280 assert(NullConstant.JsNull == 'null'); |
| 1235 withPrecedence(JSPrecedence.CONDITIONAL_PRECEDENCE, () { | 1281 void condition() { |
| 1236 beginExpression(JSPrecedence.EQUALITY_PRECEDENCE); | 1282 binary("==", |
| 1237 use(left, JSPrecedence.EQUALITY_PRECEDENCE); | 1283 () => use(left, expectedPrecedence), |
| 1238 buffer.add(' == null'); | 1284 () => literal("null")); |
| 1239 endExpression(JSPrecedence.EQUALITY_PRECEDENCE); | 1285 } |
| 1240 buffer.add(' ? '); | 1286 void ifTrue() { |
| 1241 this.expectedPrecedence = JSPrecedence.ASSIGNMENT_PRECEDENCE; | 1287 binary("==", |
| 1242 withPrecedence(JSPrecedence.LOGICAL_AND_PRECEDENCE, () { | 1288 () => use(right, expectedPrecedence), |
| 1243 beginExpression(JSPrecedence.EQUALITY_PRECEDENCE); | 1289 () => literal("null")); |
| 1244 use(right, JSPrecedence.EQUALITY_PRECEDENCE); | 1290 } |
| 1245 buffer.add(' == null'); | 1291 void ifFalse() { |
| 1246 endExpression(JSPrecedence.EQUALITY_PRECEDENCE); | 1292 binary("===", |
| 1247 buffer.add(" : "); | 1293 () => use(left, expectedPrecedence), |
| 1248 beginExpression(JSPrecedence.EQUALITY_PRECEDENCE); | 1294 () => use(right, expectedPrecedence)); |
| 1249 use(left, JSPrecedence.EQUALITY_PRECEDENCE); | 1295 } |
| 1250 buffer.add(' === '); | 1296 conditional(condition, ifTrue, ifFalse); |
| 1251 use(right, JSPrecedence.EQUALITY_PRECEDENCE); | |
| 1252 endExpression(JSPrecedence.EQUALITY_PRECEDENCE); | |
| 1253 }); | |
| 1254 }); | |
| 1255 } | 1297 } |
| 1256 } else { | 1298 } else { |
| 1257 beginExpression(JSPrecedence.EQUALITY_PRECEDENCE); | 1299 binary("===", |
| 1258 use(left, JSPrecedence.EQUALITY_PRECEDENCE); | 1300 () => use(left, expectedPrecedence), |
| 1259 buffer.add(' === '); | 1301 () => use(right, expectedPrecedence)); |
| 1260 use(right, JSPrecedence.RELATIONAL_PRECEDENCE); | |
| 1261 endExpression(JSPrecedence.EQUALITY_PRECEDENCE); | |
| 1262 } | 1302 } |
| 1263 } | 1303 } |
| 1264 | 1304 |
| 1265 visitEquals(HEquals node) { | 1305 visitEquals(HEquals node) { |
| 1266 if (node.builtin) { | 1306 if (node.builtin) { |
| 1267 emitIdentityComparison(node.left, node.right); | 1307 emitIdentityComparison(node.left, node.right); |
| 1268 } else if (node.element === equalsNullElement || | 1308 } else if (node.element === equalsNullElement || |
| 1269 node.element === boolifiedEqualsNullElement) { | 1309 node.element === boolifiedEqualsNullElement) { |
| 1270 beginExpression(JSPrecedence.CALL_PRECEDENCE); | 1310 beginExpression(JSPrecedence.CALL_PRECEDENCE); |
| 1271 use(node.target, JSPrecedence.CALL_PRECEDENCE); | 1311 use(node.target, JSPrecedence.CALL_PRECEDENCE); |
| (...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1531 indent--; | 1571 indent--; |
| 1532 addIndented('}'); | 1572 addIndented('}'); |
| 1533 } | 1573 } |
| 1534 | 1574 |
| 1535 void emitIf() { | 1575 void emitIf() { |
| 1536 addIndented('if ('); | 1576 addIndented('if ('); |
| 1537 use(node.inputs[0], JSPrecedence.EXPRESSION_PRECEDENCE); | 1577 use(node.inputs[0], JSPrecedence.EXPRESSION_PRECEDENCE); |
| 1538 buffer.add(') '); | 1578 buffer.add(') '); |
| 1539 } | 1579 } |
| 1540 | 1580 |
| 1541 JSBinaryOperatorPrecedence operatorPrecedence = JSPrecedence.binary['&&']; | |
| 1542 void generateAnd(HStatementInformation toVisit, Function condition) { | 1581 void generateAnd(HStatementInformation toVisit, Function condition) { |
| 1543 addIndentation(); | 1582 addIndentation(); |
| 1544 beginExpression(operatorPrecedence.precedence); | 1583 binary("&&", condition, () => visitExpression(toVisit)); |
| 1545 var oldPrecedence = expectedPrecedence; | |
| 1546 expectedPrecedence = operatorPrecedence.left; | |
| 1547 condition(); | |
| 1548 buffer.add(" && "); | |
| 1549 expectedPrecedence = operatorPrecedence.right; | |
| 1550 visitExpression(toVisit); | |
| 1551 expectedPrecedence = oldPrecedence; | |
| 1552 endExpression(operatorPrecedence.precedence); | |
| 1553 buffer.add(";\n"); | 1584 buffer.add(";\n"); |
| 1554 } | 1585 } |
| 1555 | 1586 |
| 1556 List<HBasicBlock> thenSuccessors = thenGraph.end.successors; | 1587 List<HBasicBlock> thenSuccessors = thenGraph.end.successors; |
| 1557 bool thenGraphHasSuccessor = thenSuccessors.length != 0 | 1588 bool thenGraphHasSuccessor = thenSuccessors.length != 0 |
| 1558 && thenSuccessors[0] !== currentGraph.exit; | 1589 && thenSuccessors[0] !== currentGraph.exit; |
| 1559 | 1590 |
| 1560 switch (thenKind) { | 1591 switch (thenKind) { |
| 1561 case EMPTY: | 1592 case EMPTY: |
| 1562 switch (elseKind) { | 1593 switch (elseKind) { |
| (...skipping 25 matching lines...) Expand all Loading... |
| 1588 break; | 1619 break; |
| 1589 } | 1620 } |
| 1590 | 1621 |
| 1591 break; | 1622 break; |
| 1592 | 1623 |
| 1593 case ONE_EXPRESSION: | 1624 case ONE_EXPRESSION: |
| 1594 case ONE_STATEMENT: | 1625 case ONE_STATEMENT: |
| 1595 switch (elseKind) { | 1626 switch (elseKind) { |
| 1596 case EMPTY: | 1627 case EMPTY: |
| 1597 if (thenKind == ONE_EXPRESSION) { | 1628 if (thenKind == ONE_EXPRESSION) { |
| 1598 int precedence = operatorPrecedence.left; | 1629 generateAnd(thenGraph, |
| 1599 generateAnd(thenGraph, () { use(node.inputs[0], precedence); }); | 1630 () => use(node.inputs[0], expectedPrecedence)); |
| 1600 } else { | 1631 } else { |
| 1601 emitIf(); | 1632 emitIf(); |
| 1602 visitWithoutIndent(thenGraph); | 1633 visitWithoutIndent(thenGraph); |
| 1603 } | 1634 } |
| 1604 break; | 1635 break; |
| 1605 | 1636 |
| 1606 case ONE_EXPRESSION: | 1637 case ONE_EXPRESSION: |
| 1607 case ONE_STATEMENT: | 1638 case ONE_STATEMENT: |
| 1608 // TODO(ngeoffray): Generate a conditional. | 1639 // TODO(ngeoffray): Generate a conditional. |
| 1609 emitIf(); | 1640 emitIf(); |
| (...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1845 | 1876 |
| 1846 visitFieldSet(HFieldSet node) { | 1877 visitFieldSet(HFieldSet node) { |
| 1847 if (work.element.isGenerativeConstructorBody() && | 1878 if (work.element.isGenerativeConstructorBody() && |
| 1848 node.element.enclosingElement.isClass() && | 1879 node.element.enclosingElement.isClass() && |
| 1849 node.value.hasGuaranteedType() && | 1880 node.value.hasGuaranteedType() && |
| 1850 node.block.dominates(currentGraph.exit)) { | 1881 node.block.dominates(currentGraph.exit)) { |
| 1851 backend.updateFieldConstructorSetters(node.element, | 1882 backend.updateFieldConstructorSetters(node.element, |
| 1852 node.value.guaranteedType); | 1883 node.value.guaranteedType); |
| 1853 } | 1884 } |
| 1854 String name = compiler.namer.getName(node.element); | 1885 String name = compiler.namer.getName(node.element); |
| 1855 beginExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE); | 1886 binary("=", () { |
| 1856 use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE); | 1887 use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE); |
| 1857 buffer.add('.'); | 1888 buffer.add('.'); |
| 1858 buffer.add(name); | 1889 buffer.add(name); |
| 1859 Type type = node.receiver.propagatedType.computeType(compiler); | 1890 Type type = node.receiver.propagatedType.computeType(compiler); |
| 1860 if (type != null) { | 1891 if (type != null) { |
| 1861 world.registerFieldSetter(node.element.name, type); | 1892 world.registerFieldSetter(node.element.name, type); |
| 1862 backend.updateFieldIntegerSetters(node.element, | 1893 backend.updateFieldIntegerSetters(node.element, |
| 1863 node.value.isInteger()); | 1894 node.value.isInteger()); |
| 1864 } | 1895 } |
| 1865 buffer.add(' = '); | 1896 }, () { |
| 1866 use(node.value, JSPrecedence.ASSIGNMENT_PRECEDENCE); | 1897 use(node.value, expectedPrecedence); |
| 1867 endExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE); | 1898 }); |
| 1868 } | 1899 } |
| 1869 | 1900 |
| 1870 visitLocalGet(HLocalGet node) { | 1901 visitLocalGet(HLocalGet node) { |
| 1871 use(node.receiver, JSPrecedence.EXPRESSION_PRECEDENCE); | 1902 use(node.receiver, JSPrecedence.EXPRESSION_PRECEDENCE); |
| 1872 } | 1903 } |
| 1873 | 1904 |
| 1874 visitLocalSet(HLocalSet node) { | 1905 visitLocalSet(HLocalSet node) { |
| 1875 declareInstruction(node.receiver); | 1906 binary("=", |
| 1876 buffer.add(' = '); | 1907 () => declareInstruction(node.receiver), |
| 1877 use(node.value, JSPrecedence.ASSIGNMENT_PRECEDENCE); | 1908 () => use(node.value, expectedPrecedence)); |
| 1878 } | 1909 } |
| 1879 | 1910 |
| 1880 visitForeign(HForeign node) { | 1911 visitForeign(HForeign node) { |
| 1881 String code = node.code.slowToString(); | 1912 String code = node.code.slowToString(); |
| 1882 List<HInstruction> inputs = node.inputs; | 1913 List<HInstruction> inputs = node.inputs; |
| 1883 List<String> parts = code.split('#'); | 1914 List<String> parts = code.split('#'); |
| 1884 if (parts.length != inputs.length + 1) { | 1915 if (parts.length != inputs.length + 1) { |
| 1885 compiler.internalError( | 1916 compiler.internalError( |
| 1886 'Wrong number of arguments for JS', instruction: node); | 1917 'Wrong number of arguments for JS', instruction: node); |
| 1887 } | 1918 } |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1991 | 2022 |
| 1992 | 2023 |
| 1993 void generateNot(HInstruction input) { | 2024 void generateNot(HInstruction input) { |
| 1994 bool isBuiltinRelational(HInstruction instruction) { | 2025 bool isBuiltinRelational(HInstruction instruction) { |
| 1995 if (instruction is !HRelational) return false; | 2026 if (instruction is !HRelational) return false; |
| 1996 HRelational relational = instruction; | 2027 HRelational relational = instruction; |
| 1997 return relational.builtin; | 2028 return relational.builtin; |
| 1998 } | 2029 } |
| 1999 | 2030 |
| 2000 if (input is HBoolify && isGenerateAtUseSite(input)) { | 2031 if (input is HBoolify && isGenerateAtUseSite(input)) { |
| 2001 beginExpression(JSPrecedence.EQUALITY_PRECEDENCE); | 2032 binary("!==", |
| 2002 use(input.inputs[0], JSPrecedence.EQUALITY_PRECEDENCE); | 2033 () => use(input.inputs[0], JSPrecedence.EQUALITY_PRECEDENCE), |
| 2003 buffer.add(' !== true'); | 2034 () => literal("true")); |
| 2004 endExpression(JSPrecedence.EQUALITY_PRECEDENCE); | |
| 2005 } else if (isBuiltinRelational(input) && | 2035 } else if (isBuiltinRelational(input) && |
| 2006 isGenerateAtUseSite(input) && | 2036 isGenerateAtUseSite(input) && |
| 2007 input.inputs[0].propagatedType.isUseful() && | 2037 input.inputs[0].propagatedType.isUseful() && |
| 2008 !input.inputs[0].isDouble() && | 2038 !input.inputs[0].isDouble() && |
| 2009 input.inputs[1].propagatedType.isUseful() && | 2039 input.inputs[1].propagatedType.isUseful() && |
| 2010 !input.inputs[1].isDouble()) { | 2040 !input.inputs[1].isDouble()) { |
| 2011 // This optimization doesn't work for NaN, so we only do it if the | 2041 // This optimization doesn't work for NaN, so we only do it if the |
| 2012 // type is known to be non-Double. | 2042 // type is known to be non-Double. |
| 2013 Map<String, String> inverseOperator = const <String>{ | 2043 Map<String, String> inverseOperator = const <String>{ |
| 2014 "==" : "!=", | 2044 "==" : "!=", |
| 2015 "!=" : "==", | 2045 "!=" : "==", |
| 2016 "===": "!==", | 2046 "===": "!==", |
| 2017 "!==": "===", | 2047 "!==": "===", |
| 2018 "<" : ">=", | 2048 "<" : ">=", |
| 2019 "<=" : ">", | 2049 "<=" : ">", |
| 2020 ">" : "<=", | 2050 ">" : "<=", |
| 2021 ">=" : "<" | 2051 ">=" : "<" |
| 2022 }; | 2052 }; |
| 2023 HRelational relational = input; | 2053 HRelational relational = input; |
| 2024 visitInvokeBinary(input, | 2054 visitInvokeBinary(input, |
| 2025 inverseOperator[relational.operation.name.stringValue]); | 2055 inverseOperator[relational.operation.name.stringValue]); |
| 2026 } else { | 2056 } else { |
| 2027 beginExpression(JSPrecedence.PREFIX_PRECEDENCE); | 2057 prefix("!", () => use(input, JSPrecedence.PREFIX_PRECEDENCE)); |
| 2028 buffer.add('!'); | |
| 2029 use(input, JSPrecedence.PREFIX_PRECEDENCE); | |
| 2030 endExpression(JSPrecedence.PREFIX_PRECEDENCE); | |
| 2031 } | 2058 } |
| 2032 } | 2059 } |
| 2033 | 2060 |
| 2034 visitParameterValue(HParameterValue node) => visitLocalValue(node); | 2061 visitParameterValue(HParameterValue node) => visitLocalValue(node); |
| 2035 | 2062 |
| 2036 visitLocalValue(HLocalValue node) { | 2063 visitLocalValue(HLocalValue node) { |
| 2037 assert(isGenerateAtUseSite(node)); | 2064 assert(isGenerateAtUseSite(node)); |
| 2038 buffer.add(variableNames.getName(node)); | 2065 buffer.add(variableNames.getName(node)); |
| 2039 } | 2066 } |
| 2040 | 2067 |
| 2041 visitPhi(HPhi node) { | 2068 visitPhi(HPhi node) { |
| 2042 // This method is only called for phis that are generated at use | 2069 // This method is only called for phis that are generated at use |
| 2043 // site. A phi can be generated at use site only if it is the | 2070 // site. A phi can be generated at use site only if it is the |
| 2044 // result of a control flow operation. | 2071 // result of a control flow operation. |
| 2045 HBasicBlock ifBlock = node.block.dominator; | 2072 HBasicBlock ifBlock = node.block.dominator; |
| 2046 assert(controlFlowOperators.contains(ifBlock.last)); | 2073 assert(controlFlowOperators.contains(ifBlock.last)); |
| 2047 HInstruction input = ifBlock.last.inputs[0]; | 2074 HInstruction input = ifBlock.last.inputs[0]; |
| 2048 if (input.isConstantFalse()) { | 2075 if (input.isConstantFalse()) { |
| 2049 use(node.inputs[1], expectedPrecedence); | 2076 use(node.inputs[1], expectedPrecedence); |
| 2050 } else if (input.isConstantTrue()) { | 2077 } else if (input.isConstantTrue()) { |
| 2051 use(node.inputs[0], expectedPrecedence); | 2078 use(node.inputs[0], expectedPrecedence); |
| 2052 } else if (node.inputs[1].isConstantBoolean()) { | 2079 } else if (node.inputs[1].isConstantBoolean()) { |
| 2053 String operation = node.inputs[1].isConstantFalse() ? '&&' : '||'; | 2080 String operation = node.inputs[1].isConstantFalse() ? '&&' : '||'; |
| 2054 JSBinaryOperatorPrecedence operatorPrecedence = | 2081 binary(operation, () { |
| 2055 JSPrecedence.binary[operation]; | 2082 if (operation == '||') { |
| 2056 beginExpression(operatorPrecedence.precedence); | 2083 if (input is HNot) { |
| 2057 if (operation == '||') { | 2084 use(input.inputs[0], expectedPrecedence); |
| 2058 if (input is HNot) { | 2085 } else { |
| 2059 use(input.inputs[0], operatorPrecedence.left); | 2086 generateNot(input); |
| 2087 } |
| 2060 } else { | 2088 } else { |
| 2061 generateNot(input); | 2089 use(input, expectedPrecedence); |
| 2062 } | 2090 } |
| 2063 } else { | 2091 }, () { |
| 2064 use(input, operatorPrecedence.left); | 2092 use(node.inputs[0], expectedPrecedence); |
| 2065 } | 2093 }); |
| 2066 buffer.add(" $operation "); | |
| 2067 use(node.inputs[0], operatorPrecedence.right); | |
| 2068 endExpression(operatorPrecedence.precedence); | |
| 2069 } else { | 2094 } else { |
| 2070 beginExpression(JSPrecedence.CONDITIONAL_PRECEDENCE); | 2095 conditional( |
| 2071 use(input, JSPrecedence.LOGICAL_OR_PRECEDENCE); | 2096 () => use(input, expectedPrecedence), |
| 2072 buffer.add(' ? '); | 2097 ifTrue: () => use(node.inputs[0], expectedPrecedence), |
| 2073 use(node.inputs[0], JSPrecedence.ASSIGNMENT_PRECEDENCE); | 2098 ifFalse: () => use(node.inputs[1], expectedPrecedence)); |
| 2074 buffer.add(' : '); | |
| 2075 use(node.inputs[1], JSPrecedence.ASSIGNMENT_PRECEDENCE); | |
| 2076 endExpression(JSPrecedence.CONDITIONAL_PRECEDENCE); | |
| 2077 } | 2099 } |
| 2078 } | 2100 } |
| 2079 | 2101 |
| 2080 visitReturn(HReturn node) { | 2102 visitReturn(HReturn node) { |
| 2081 addIndentation(); | 2103 addIndentation(); |
| 2082 assert(node.inputs.length == 1); | 2104 assert(node.inputs.length == 1); |
| 2083 HInstruction input = node.inputs[0]; | 2105 HInstruction input = node.inputs[0]; |
| 2084 if (input.isConstantNull()) { | 2106 if (input.isConstantNull()) { |
| 2085 buffer.add('return;\n'); | 2107 buffer.add('return;\n'); |
| 2086 } else { | 2108 } else { |
| (...skipping 19 matching lines...) Expand all Loading... |
| 2106 } | 2128 } |
| 2107 | 2129 |
| 2108 visitBoundsCheck(HBoundsCheck node) { | 2130 visitBoundsCheck(HBoundsCheck node) { |
| 2109 // TODO(ngeoffray): Separate the two checks of the bounds check, so, | 2131 // TODO(ngeoffray): Separate the two checks of the bounds check, so, |
| 2110 // e.g., the zero checks can be shared if possible. | 2132 // e.g., the zero checks can be shared if possible. |
| 2111 | 2133 |
| 2112 // If the checks always succeede, we would have removed the bounds check | 2134 // If the checks always succeede, we would have removed the bounds check |
| 2113 // completely. | 2135 // completely. |
| 2114 assert(node.staticChecks != HBoundsCheck.ALWAYS_TRUE); | 2136 assert(node.staticChecks != HBoundsCheck.ALWAYS_TRUE); |
| 2115 if (node.staticChecks != HBoundsCheck.ALWAYS_FALSE) { | 2137 if (node.staticChecks != HBoundsCheck.ALWAYS_FALSE) { |
| 2138 void checkUpperBound() { |
| 2139 binary(">=", |
| 2140 () => use(node.index, expectedPrecedence), |
| 2141 () => use(node.length, expectedPrecedence)); |
| 2142 } |
| 2116 buffer.add('if ('); | 2143 buffer.add('if ('); |
| 2117 if (node.staticChecks != HBoundsCheck.ALWAYS_ABOVE_ZERO) { | 2144 if (node.staticChecks != HBoundsCheck.ALWAYS_ABOVE_ZERO) { |
| 2118 assert(node.staticChecks == HBoundsCheck.FULL_CHECK); | 2145 assert(node.staticChecks == HBoundsCheck.FULL_CHECK); |
| 2119 use(node.index, JSPrecedence.RELATIONAL_PRECEDENCE); | 2146 binary("||", |
| 2120 buffer.add(' < 0 || '); | 2147 () => binary("<", |
| 2148 () => use(node.index, expectedPrecedence), |
| 2149 () => literal("0")), |
| 2150 checkUpperBound); |
| 2151 } else { |
| 2152 checkUpperBound(); |
| 2121 } | 2153 } |
| 2122 use(node.index, JSPrecedence.RELATIONAL_PRECEDENCE); | |
| 2123 buffer.add(' >= '); | |
| 2124 use(node.length, JSPrecedence.SHIFT_PRECEDENCE); | |
| 2125 buffer.add(") "); | 2154 buffer.add(") "); |
| 2126 } | 2155 } |
| 2127 generateThrowWithHelper('ioore', node.index); | 2156 generateThrowWithHelper('ioore', node.index); |
| 2128 } | 2157 } |
| 2129 | 2158 |
| 2130 visitIntegerCheck(HIntegerCheck node) { | 2159 visitIntegerCheck(HIntegerCheck node) { |
| 2131 if (!node.alwaysFalse) { | 2160 if (!node.alwaysFalse) { |
| 2132 buffer.add('if ('); | 2161 buffer.add('if ('); |
| 2133 checkInt(node.value, '!=='); | 2162 checkInt(node.value, '!=='); |
| 2134 buffer.add(') '); | 2163 buffer.add(') '); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2176 use(node.inputs[0], JSPrecedence.ASSIGNMENT_PRECEDENCE); | 2205 use(node.inputs[0], JSPrecedence.ASSIGNMENT_PRECEDENCE); |
| 2177 endExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE); | 2206 endExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE); |
| 2178 } | 2207 } |
| 2179 | 2208 |
| 2180 void visitStringConcat(HStringConcat node) { | 2209 void visitStringConcat(HStringConcat node) { |
| 2181 if (isEmptyString(node.left)) { | 2210 if (isEmptyString(node.left)) { |
| 2182 useStringified(node.right, expectedPrecedence); | 2211 useStringified(node.right, expectedPrecedence); |
| 2183 } else if (isEmptyString(node.right)) { | 2212 } else if (isEmptyString(node.right)) { |
| 2184 useStringified(node.left, expectedPrecedence); | 2213 useStringified(node.left, expectedPrecedence); |
| 2185 } else { | 2214 } else { |
| 2186 JSBinaryOperatorPrecedence operatorPrecedences = JSPrecedence.binary['+']; | |
| 2187 beginExpression(operatorPrecedences.precedence); | |
| 2188 useStringified(node.left, operatorPrecedences.left); | |
| 2189 buffer.add(' + '); | |
| 2190 // If the right hand side is a string concatenation itself it is | 2215 // If the right hand side is a string concatenation itself it is |
| 2191 // safe to make it left associative. | 2216 // safe to make it left associative by omitting parentheses. |
| 2192 int rightPrecedence = (node.right is HStringConcat) | 2217 bool useAdditivePrecedence = node.right is HStringConcat; |
| 2193 ? JSPrecedence.ADDITIVE_PRECEDENCE | 2218 binary("+", |
| 2194 : operatorPrecedences.right; | 2219 () => useStringified(node.left, expectedPrecedence), |
| 2195 useStringified(node.right, rightPrecedence); | 2220 () => useStringified(node.right, |
| 2196 endExpression(operatorPrecedences.precedence); | 2221 useAdditivePrecedence |
| 2222 ? JSPrecedence.ADDITIVE_PRECEDENCE |
| 2223 : expectedPrecedence)); |
| 2197 } | 2224 } |
| 2198 } | 2225 } |
| 2199 | 2226 |
| 2200 bool isEmptyString(HInstruction node) { | 2227 bool isEmptyString(HInstruction node) { |
| 2201 if (!node.isConstantString()) return false; | 2228 if (!node.isConstantString()) return false; |
| 2202 HConstant constant = node; | 2229 HConstant constant = node; |
| 2203 StringConstant string = constant.constant; | 2230 StringConstant string = constant.constant; |
| 2204 return string.value.length == 0; | 2231 return string.value.length == 0; |
| 2205 } | 2232 } |
| 2206 | 2233 |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2282 } | 2309 } |
| 2283 } | 2310 } |
| 2284 | 2311 |
| 2285 return null; | 2312 return null; |
| 2286 } | 2313 } |
| 2287 | 2314 |
| 2288 void visitInvokeInterceptor(HInvokeInterceptor node) { | 2315 void visitInvokeInterceptor(HInvokeInterceptor node) { |
| 2289 String builtin = builtinJsName(node); | 2316 String builtin = builtinJsName(node); |
| 2290 if (builtin !== null) { | 2317 if (builtin !== null) { |
| 2291 if (builtin == '+') { | 2318 if (builtin == '+') { |
| 2292 beginExpression(JSPrecedence.ADDITIVE_PRECEDENCE); | 2319 binary('+', |
| 2293 use(node.inputs[1], JSPrecedence.ADDITIVE_PRECEDENCE); | 2320 () => use(node.inputs[1], expectedPrecedence), |
| 2294 buffer.add(' + '); | 2321 () => use(node.inputs[2], expectedPrecedence)); |
| 2295 use(node.inputs[2], JSPrecedence.MULTIPLICATIVE_PRECEDENCE); | |
| 2296 endExpression(JSPrecedence.ADDITIVE_PRECEDENCE); | |
| 2297 } else { | 2322 } else { |
| 2298 beginExpression(JSPrecedence.CALL_PRECEDENCE); | 2323 beginExpression(JSPrecedence.CALL_PRECEDENCE); |
| 2299 use(node.inputs[1], JSPrecedence.MEMBER_PRECEDENCE); | 2324 use(node.inputs[1], JSPrecedence.MEMBER_PRECEDENCE); |
| 2300 buffer.add('.'); | 2325 buffer.add('.'); |
| 2301 buffer.add(builtin); | 2326 buffer.add(builtin); |
| 2302 if (node.getter) return; | 2327 if (node.getter) return; |
| 2303 buffer.add('('); | 2328 buffer.add('('); |
| 2304 for (int i = 2; i < node.inputs.length; i++) { | 2329 for (int i = 2; i < node.inputs.length; i++) { |
| 2305 if (i != 2) buffer.add(', '); | 2330 if (i != 2) buffer.add(', '); |
| 2306 use(node.inputs[i], JSPrecedence.ASSIGNMENT_PRECEDENCE); | 2331 use(node.inputs[i], JSPrecedence.ASSIGNMENT_PRECEDENCE); |
| 2307 } | 2332 } |
| 2308 buffer.add(")"); | 2333 buffer.add(")"); |
| 2309 endExpression(JSPrecedence.CALL_PRECEDENCE); | 2334 endExpression(JSPrecedence.CALL_PRECEDENCE); |
| 2310 } | 2335 } |
| 2311 } else { | 2336 } else { |
| 2312 return visitInvokeStatic(node); | 2337 return visitInvokeStatic(node); |
| 2313 } | 2338 } |
| 2314 } | 2339 } |
| 2315 | 2340 |
| 2316 void checkInt(HInstruction input, String cmp) { | 2341 void checkInt(HInstruction input, String cmp) { |
| 2317 beginExpression(JSPrecedence.EQUALITY_PRECEDENCE); | 2342 binary(cmp, |
| 2318 use(input, JSPrecedence.EQUALITY_PRECEDENCE); | 2343 () => use(input, expectedPrecedence), |
| 2319 buffer.add(' $cmp ('); | 2344 () => binary("|", |
| 2320 use(input, JSPrecedence.BITWISE_OR_PRECEDENCE); | 2345 () => use(input, expectedPrecedence), |
| 2321 buffer.add(' | 0)'); | 2346 () => literal("0"))); |
| 2322 endExpression(JSPrecedence.EQUALITY_PRECEDENCE); | 2347 } |
| 2348 |
| 2349 void checkJSType(HInstruction input, String cmp, String type) { |
| 2350 binary(cmp, |
| 2351 () => prefix("typeof ", () => use(input, expectedPrecedence)), |
| 2352 () => literal("'$type'")); |
| 2323 } | 2353 } |
| 2324 | 2354 |
| 2325 void checkNum(HInstruction input, String cmp) { | 2355 void checkNum(HInstruction input, String cmp) { |
| 2326 beginExpression(JSPrecedence.EQUALITY_PRECEDENCE); | 2356 checkJSType(input, cmp, "number"); |
| 2327 buffer.add('typeof '); | |
| 2328 use(input, JSPrecedence.PREFIX_PRECEDENCE); | |
| 2329 buffer.add(" $cmp 'number'"); | |
| 2330 endExpression(JSPrecedence.EQUALITY_PRECEDENCE); | |
| 2331 } | 2357 } |
| 2332 | 2358 |
| 2333 void checkDouble(HInstruction input, String cmp) { | 2359 void checkDouble(HInstruction input, String cmp) { |
| 2334 checkNum(input, cmp); | 2360 checkNum(input, cmp); |
| 2335 } | 2361 } |
| 2336 | 2362 |
| 2337 void checkString(HInstruction input, String cmp) { | 2363 void checkString(HInstruction input, String cmp) { |
| 2338 beginExpression(JSPrecedence.EQUALITY_PRECEDENCE); | 2364 checkJSType(input, cmp, "string"); |
| 2339 buffer.add('typeof '); | |
| 2340 use(input, JSPrecedence.PREFIX_PRECEDENCE); | |
| 2341 buffer.add(" $cmp 'string'"); | |
| 2342 endExpression(JSPrecedence.EQUALITY_PRECEDENCE); | |
| 2343 } | 2365 } |
| 2344 | 2366 |
| 2345 void checkBool(HInstruction input, String cmp) { | 2367 void checkBool(HInstruction input, String cmp) { |
| 2346 beginExpression(JSPrecedence.EQUALITY_PRECEDENCE); | 2368 checkJSType(input, cmp, "boolean"); |
| 2347 buffer.add('typeof '); | |
| 2348 use(input, JSPrecedence.PREFIX_PRECEDENCE); | |
| 2349 buffer.add(" $cmp 'boolean'"); | |
| 2350 endExpression(JSPrecedence.EQUALITY_PRECEDENCE); | |
| 2351 } | 2369 } |
| 2352 | 2370 |
| 2353 void checkObject(HInstruction input, String cmp) { | 2371 void checkObject(HInstruction input, String cmp) { |
| 2354 assert(NullConstant.JsNull == 'null'); | 2372 assert(NullConstant.JsNull == 'null'); |
| 2355 if (cmp == "===") { | 2373 if (cmp == "===") { |
| 2356 withPrecedence(JSPrecedence.LOGICAL_AND_PRECEDENCE, () { | 2374 binary("&&", |
| 2357 beginExpression(JSPrecedence.EQUALITY_PRECEDENCE); | 2375 () => checkJSType(input, "===", "object"), |
| 2358 buffer.add('typeof '); | 2376 () => binary("!==", |
| 2359 use(input, JSPrecedence.PREFIX_PRECEDENCE); | 2377 () => use(input, expectedPrecedence), |
| 2360 buffer.add(" === 'object'"); | 2378 () => literal("null"))); |
| 2361 endExpression(JSPrecedence.EQUALITY_PRECEDENCE); | |
| 2362 buffer.add(" && "); | |
| 2363 beginExpression(JSPrecedence.EQUALITY_PRECEDENCE); | |
| 2364 use(input, JSPrecedence.PREFIX_PRECEDENCE); | |
| 2365 buffer.add(" !== null"); | |
| 2366 endExpression(JSPrecedence.EQUALITY_PRECEDENCE); | |
| 2367 }); | |
| 2368 } else { | 2379 } else { |
| 2369 assert(cmp == "!=="); | 2380 assert(cmp == "!=="); |
| 2370 withPrecedence(JSPrecedence.LOGICAL_OR_PRECEDENCE, () { | 2381 binary("||", |
| 2371 beginExpression(JSPrecedence.EQUALITY_PRECEDENCE); | 2382 () => checkJSType(input, "!==", "object"), |
| 2372 buffer.add('typeof '); | 2383 () => binary("===", |
| 2373 use(input, JSPrecedence.PREFIX_PRECEDENCE); | 2384 () => use(input, expectedPrecedence), |
| 2374 buffer.add(" !== 'object'"); | 2385 () => literal("null"))); |
| 2375 endExpression(JSPrecedence.EQUALITY_PRECEDENCE); | |
| 2376 buffer.add(" || "); | |
| 2377 beginExpression(JSPrecedence.EQUALITY_PRECEDENCE); | |
| 2378 use(input, JSPrecedence.PREFIX_PRECEDENCE); | |
| 2379 buffer.add(" === null"); | |
| 2380 endExpression(JSPrecedence.EQUALITY_PRECEDENCE); | |
| 2381 }); | |
| 2382 } | 2386 } |
| 2383 } | 2387 } |
| 2384 | 2388 |
| 2385 void checkArray(HInstruction input, String cmp) { | 2389 void checkArray(HInstruction input, String cmp) { |
| 2386 beginExpression(JSPrecedence.EQUALITY_PRECEDENCE); | 2390 binary(cmp, |
| 2387 use(input, JSPrecedence.MEMBER_PRECEDENCE); | 2391 () { |
| 2388 buffer.add('.constructor $cmp Array'); | 2392 use(input, JSPrecedence.MEMBER_PRECEDENCE); |
| 2389 endExpression(JSPrecedence.EQUALITY_PRECEDENCE); | 2393 buffer.add('.constructor'); |
| 2394 }, |
| 2395 () => literal("Array")); |
| 2390 } | 2396 } |
| 2391 | 2397 |
| 2392 void checkImmutableArray(HInstruction input) { | 2398 void checkImmutableArray(HInstruction input) { |
| 2393 beginExpression(JSPrecedence.PREFIX_PRECEDENCE); | 2399 prefix("!!", () { |
| 2394 buffer.add('!!'); | 2400 use(input, JSPrecedence.MEMBER_PRECEDENCE); |
| 2395 use(input, JSPrecedence.MEMBER_PRECEDENCE); | 2401 buffer.add('.immutable\$list'); |
| 2396 buffer.add('.immutable\$list'); | 2402 }); |
| 2397 endExpression(JSPrecedence.PREFIX_PRECEDENCE); | |
| 2398 } | 2403 } |
| 2399 | 2404 |
| 2400 void checkExtendableArray(HInstruction input) { | 2405 void checkExtendableArray(HInstruction input) { |
| 2401 beginExpression(JSPrecedence.PREFIX_PRECEDENCE); | 2406 prefix("!!" , () { |
| 2402 buffer.add('!!'); | 2407 use(input, JSPrecedence.MEMBER_PRECEDENCE); |
| 2403 use(input, JSPrecedence.MEMBER_PRECEDENCE); | 2408 buffer.add('.fixed\$length'); |
| 2404 buffer.add('.fixed\$length'); | 2409 }); |
| 2405 endExpression(JSPrecedence.PREFIX_PRECEDENCE); | |
| 2406 } | 2410 } |
| 2407 | 2411 |
| 2408 void checkFixedArray(HInstruction input) { | 2412 void checkFixedArray(HInstruction input) { |
| 2409 beginExpression(JSPrecedence.PREFIX_PRECEDENCE); | 2413 parenthesize(JSPrecedence.MEMBER_PRECEDENCE, () { |
| 2410 use(input, JSPrecedence.MEMBER_PRECEDENCE); | 2414 use(input, JSPrecedence.MEMBER_PRECEDENCE); |
| 2411 buffer.add('.fixed\$length'); | 2415 buffer.add('.fixed\$length'); |
| 2412 endExpression(JSPrecedence.PREFIX_PRECEDENCE); | 2416 }); |
| 2413 } | 2417 } |
| 2414 | 2418 |
| 2415 void checkNull(HInstruction input) { | 2419 void checkNull(HInstruction input) { |
| 2416 beginExpression(JSPrecedence.EQUALITY_PRECEDENCE); | 2420 binary("==", |
| 2417 use(input, JSPrecedence.EQUALITY_PRECEDENCE); | 2421 () => use(input, expectedPrecedence), |
| 2418 buffer.add(" == null"); | 2422 () => literal("null")); |
| 2419 endExpression(JSPrecedence.EQUALITY_PRECEDENCE); | |
| 2420 } | 2423 } |
| 2421 | 2424 |
| 2422 void checkFunction(HInstruction input, Element element) { | 2425 void checkFunction(HInstruction input, Element element) { |
| 2423 withPrecedence(JSPrecedence.LOGICAL_OR_PRECEDENCE, () { | 2426 binary("||", |
| 2424 beginExpression(JSPrecedence.EQUALITY_PRECEDENCE); | 2427 () => checkJSType(input, "===", "function"), |
| 2425 buffer.add('typeof '); | 2428 () => binary('&&', |
| 2426 use(input, JSPrecedence.PREFIX_PRECEDENCE); | 2429 () => checkObject(input, '==='), |
| 2427 buffer.add(" === 'function'"); | 2430 () => checkType(input, element))); |
| 2428 endExpression(JSPrecedence.EQUALITY_PRECEDENCE); | |
| 2429 buffer.add(" || "); | |
| 2430 beginExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE); | |
| 2431 checkObject(input, '==='); | |
| 2432 buffer.add(" && "); | |
| 2433 checkType(input, element); | |
| 2434 endExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE); | |
| 2435 }); | |
| 2436 } | 2431 } |
| 2437 | 2432 |
| 2438 void checkType(HInstruction input, Element element, [bool negative = false]) { | 2433 void checkType(HInstruction input, Element element, [bool negative = false]) { |
| 2439 world.registerIsCheck(element); | 2434 world.registerIsCheck(element); |
| 2440 bool requiresNativeIsCheck = | 2435 bool requiresNativeIsCheck = |
| 2441 backend.emitter.nativeEmitter.requiresNativeIsCheck(element); | 2436 backend.emitter.nativeEmitter.requiresNativeIsCheck(element); |
| 2437 void body() { |
| 2438 assert(JSPrecedence.CALL_PRECEDENCE == JSPrecedence.MEMBER_PRECEDENCE); |
| 2439 parenthesize(JSPrecedence.CALL_PRECEDENCE, () { |
| 2440 use(input, JSPrecedence.MEMBER_PRECEDENCE); |
| 2441 buffer.add('.'); |
| 2442 buffer.add(compiler.namer.operatorIs(element)); |
| 2443 if (requiresNativeIsCheck) buffer.add('()'); |
| 2444 }); |
| 2445 } |
| 2442 if (!requiresNativeIsCheck) { | 2446 if (!requiresNativeIsCheck) { |
| 2443 if (negative) { | 2447 if (negative) { |
| 2444 buffer.add('!'); | 2448 prefix("!", body); |
| 2445 } else { | 2449 } else { |
| 2446 buffer.add('!!'); | 2450 prefix("!!", body); |
| 2447 } | 2451 } |
| 2448 } else if (negative) { | 2452 } else if (negative) { |
| 2449 buffer.add('!'); | 2453 prefix("!", body); |
| 2454 } else { |
| 2455 body(); |
| 2450 } | 2456 } |
| 2451 use(input, JSPrecedence.MEMBER_PRECEDENCE); | |
| 2452 buffer.add('.'); | |
| 2453 buffer.add(compiler.namer.operatorIs(element)); | |
| 2454 if (requiresNativeIsCheck) buffer.add('()'); | |
| 2455 } | 2457 } |
| 2456 | 2458 |
| 2457 void handleStringSupertypeCheck(HInstruction input, Element element) { | 2459 void handleStringSupertypeCheck(HInstruction input, Element element) { |
| 2458 // Make sure List and String don't share supertypes, otherwise we | 2460 // Make sure List and String don't share supertypes, otherwise we |
| 2459 // would need to check for List too. | 2461 // would need to check for List too. |
| 2460 assert(element !== compiler.listClass | 2462 assert(element !== compiler.listClass |
| 2461 && !Elements.isListSupertype(element, compiler)); | 2463 && !Elements.isListSupertype(element, compiler)); |
| 2462 withPrecedence(JSPrecedence.LOGICAL_OR_PRECEDENCE, () { | 2464 binary("||", |
| 2463 checkString(input, '==='); | 2465 () => checkString(input, '==='), |
| 2464 buffer.add(' || '); | 2466 () => binary("&&", |
| 2465 withPrecedence(JSPrecedence.LOGICAL_AND_PRECEDENCE, () { | 2467 () => checkObject(input, '==='), |
| 2466 checkObject(input, '==='); | 2468 () => checkType(input, element))); |
| 2467 buffer.add(' && '); | |
| 2468 checkType(input, element); | |
| 2469 }); | |
| 2470 }); | |
| 2471 } | 2469 } |
| 2472 | 2470 |
| 2473 void handleListOrSupertypeCheck(HInstruction input, Element element) { | 2471 void handleListOrSupertypeCheck(HInstruction input, Element element) { |
| 2474 // Make sure List and String don't share supertypes, otherwise we | 2472 // Make sure List and String don't share supertypes, otherwise we |
| 2475 // would need to check for String too. | 2473 // would need to check for String too. |
| 2476 assert(element !== compiler.stringClass | 2474 assert(element !== compiler.stringClass |
| 2477 && !Elements.isStringSupertype(element, compiler)); | 2475 && !Elements.isStringSupertype(element, compiler)); |
| 2478 beginExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE); | 2476 binary("&&", |
| 2479 checkObject(input, '==='); | 2477 () => checkObject(input, '==='), |
| 2480 buffer.add(' && ('); | 2478 () => binary("||", |
| 2481 beginExpression(JSPrecedence.LOGICAL_OR_PRECEDENCE); | 2479 () => checkArray(input, '==='), |
| 2482 checkArray(input, '==='); | 2480 () => checkType(input, element))); |
| 2483 buffer.add(' || '); | |
| 2484 checkType(input, element); | |
| 2485 buffer.add(')'); | |
| 2486 endExpression(JSPrecedence.LOGICAL_OR_PRECEDENCE); | |
| 2487 endExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE); | |
| 2488 } | 2481 } |
| 2489 | 2482 |
| 2490 void visitIs(HIs node) { | 2483 void visitIs(HIs node) { |
| 2491 Type type = node.typeExpression; | 2484 Type type = node.typeExpression; |
| 2492 Element element = type.element; | 2485 Element element = type.element; |
| 2493 if (element.kind === ElementKind.TYPE_VARIABLE) { | 2486 if (element.kind === ElementKind.TYPE_VARIABLE) { |
| 2494 compiler.unimplemented("visitIs for type variables", instruction: node); | 2487 compiler.unimplemented("visitIs for type variables", instruction: node); |
| 2495 } else if (element.kind === ElementKind.TYPEDEF) { | 2488 } else if (element.kind === ElementKind.TYPEDEF) { |
| 2496 compiler.unimplemented("visitIs for typedefs", instruction: node); | 2489 compiler.unimplemented("visitIs for typedefs", instruction: node); |
| 2497 } | 2490 } |
| 2498 LibraryElement coreLibrary = compiler.coreLibrary; | 2491 LibraryElement coreLibrary = compiler.coreLibrary; |
| 2499 ClassElement objectClass = compiler.objectClass; | 2492 ClassElement objectClass = compiler.objectClass; |
| 2500 HInstruction input = node.expression; | 2493 HInstruction input = node.expression; |
| 2501 | 2494 |
| 2502 int oldPrecedence; | 2495 void plainTypeCheck() { |
| 2503 if (node.nullOk) { | 2496 if (element === objectClass || element === compiler.dynamicClass) { |
| 2504 oldPrecedence = expectedPrecedence; | 2497 // The constant folder also does this optimization, but we make |
| 2505 beginExpression(JSPrecedence.LOGICAL_OR_PRECEDENCE); | 2498 // it safe by assuming it may have not run. |
| 2506 expectedPrecedence = JSPrecedence.LOGICAL_OR_PRECEDENCE; | 2499 literal('true'); |
| 2507 checkNull(input); | 2500 } else if (element == compiler.stringClass) { |
| 2508 buffer.add(' || '); | 2501 checkString(input, '==='); |
| 2502 } else if (element == compiler.doubleClass) { |
| 2503 checkDouble(input, '==='); |
| 2504 } else if (element == compiler.numClass) { |
| 2505 checkNum(input, '==='); |
| 2506 } else if (element == compiler.boolClass) { |
| 2507 checkBool(input, '==='); |
| 2508 } else if (element == compiler.functionClass) { |
| 2509 checkFunction(input, element); |
| 2510 } else if (element == compiler.intClass) { |
| 2511 binary("&&", |
| 2512 () => checkNum(input, '==='), |
| 2513 () => checkInt(input, '===')); |
| 2514 } else if (Elements.isStringSupertype(element, compiler)) { |
| 2515 handleStringSupertypeCheck(input, element); |
| 2516 } else if (element === compiler.listClass |
| 2517 || Elements.isListSupertype(element, compiler)) { |
| 2518 handleListOrSupertypeCheck(input, element); |
| 2519 } else if (input.propagatedType.canBePrimitive() |
| 2520 || input.propagatedType.canBeNull()) { |
| 2521 binary("&&", |
| 2522 () => checkObject(input, '==='), |
| 2523 () => checkType(input, element)); |
| 2524 } else { |
| 2525 checkType(input, element); |
| 2526 } |
| 2509 } | 2527 } |
| 2510 if (element === objectClass || element === compiler.dynamicClass) { | 2528 |
| 2511 // The constant folder also does this optimization, but we make | 2529 void typeArgumentCheck() { |
| 2512 // it safe by assuming it may have not run. | 2530 if (compiler.codegenWorld.rti.hasTypeArguments(type)) { |
| 2513 buffer.add('true'); | 2531 InterfaceType interfaceType = type; |
| 2514 } else if (element == compiler.stringClass) { | 2532 ClassElement cls = type.element; |
| 2515 checkString(input, '==='); | 2533 Link<Type> arguments = interfaceType.arguments; |
| 2516 } else if (element == compiler.doubleClass) { | 2534 binary("&&", plainTypeCheck, () { |
| 2517 checkDouble(input, '==='); | 2535 var base = () => checkObject(node.typeInfoCall, '==='); |
| 2518 } else if (element == compiler.numClass) { | 2536 // Do left-fold on elements with [base] as initial value. |
| 2519 checkNum(input, '==='); | 2537 cls.typeParameters.forEach((name, _) { |
| 2520 } else if (element == compiler.boolClass) { | 2538 Type argument = arguments.head; |
| 2521 checkBool(input, '==='); | 2539 // TODO(lrn): Should we advance arguments here? |
| 2522 } else if (element == compiler.functionClass) { | 2540 // What if there aren't any? |
| 2523 checkFunction(input, element); | 2541 var oldBase = base; |
| 2524 } else if (element == compiler.intClass) { | 2542 base = () => binary("&&", oldBase, () { |
| 2525 beginExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE); | 2543 parenthesize(JSPrecedence.ASSIGNMENT_PRECEDENCE, () { |
| 2526 checkNum(input, '==='); | 2544 use(node.typeInfoCall, JSPrecedence.MEMBER_PRECEDENCE); |
| 2527 buffer.add(' && '); | 2545 buffer.add(".${name.slowToString()} === '${argument}'"); |
| 2528 checkInt(input, '==='); | 2546 }); |
| 2529 endExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE); | 2547 }); |
| 2530 } else if (Elements.isStringSupertype(element, compiler)) { | 2548 }); |
| 2531 handleStringSupertypeCheck(input, element); | 2549 base(); |
| 2532 } else if (element === compiler.listClass | 2550 }); |
| 2533 || Elements.isListSupertype(element, compiler)) { | 2551 } else { |
| 2534 handleListOrSupertypeCheck(input, element); | 2552 plainTypeCheck(); |
| 2535 } else if (input.propagatedType.canBePrimitive() | 2553 } |
| 2536 || input.propagatedType.canBeNull()) { | |
| 2537 beginExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE); | |
| 2538 checkObject(input, '==='); | |
| 2539 buffer.add(' && '); | |
| 2540 checkType(input, element); | |
| 2541 endExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE); | |
| 2542 } else { | |
| 2543 checkType(input, element); | |
| 2544 } | |
| 2545 if (compiler.codegenWorld.rti.hasTypeArguments(type)) { | |
| 2546 InterfaceType interfaceType = type; | |
| 2547 ClassElement cls = type.element; | |
| 2548 Link<Type> arguments = interfaceType.arguments; | |
| 2549 buffer.add(' && '); | |
| 2550 checkObject(node.typeInfoCall, '==='); | |
| 2551 cls.typeParameters.forEach((name, _) { | |
| 2552 buffer.add(' && '); | |
| 2553 beginExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE); | |
| 2554 use(node.typeInfoCall, JSPrecedence.EQUALITY_PRECEDENCE); | |
| 2555 buffer.add(".${name.slowToString()} === '${arguments.head}'"); | |
| 2556 endExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE); | |
| 2557 }); | |
| 2558 } | 2554 } |
| 2559 if (node.nullOk) { | 2555 if (node.nullOk) { |
| 2560 expectedPrecedence = oldPrecedence; | 2556 binary("||", () => checkNull(input), typeArgumentCheck); |
| 2561 endExpression(JSPrecedence.LOGICAL_OR_PRECEDENCE); | 2557 } else { |
| 2558 typeArgumentCheck(); |
| 2562 } | 2559 } |
| 2563 } | 2560 } |
| 2564 | 2561 |
| 2565 void visitTypeConversion(HTypeConversion node) { | 2562 void visitTypeConversion(HTypeConversion node) { |
| 2566 Map<String, SourceString> castNames = const <SourceString> { | 2563 Map<String, SourceString> castNames = const <SourceString> { |
| 2567 "stringTypeCheck": | 2564 "stringTypeCheck": |
| 2568 const SourceString("stringTypeCast"), | 2565 const SourceString("stringTypeCast"), |
| 2569 "doubleTypeCheck": | 2566 "doubleTypeCheck": |
| 2570 const SourceString("doubleTypeCast"), | 2567 const SourceString("doubleTypeCast"), |
| 2571 "numTypeCheck": | 2568 "numTypeCheck": |
| (...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2745 bailout(node, 'Not a boolean'); | 2742 bailout(node, 'Not a boolean'); |
| 2746 } else if (node.isString()) { | 2743 } else if (node.isString()) { |
| 2747 // if (input is !string) bailout | 2744 // if (input is !string) bailout |
| 2748 buffer.add('if ('); | 2745 buffer.add('if ('); |
| 2749 checkString(input, '!=='); | 2746 checkString(input, '!=='); |
| 2750 buffer.add(') '); | 2747 buffer.add(') '); |
| 2751 bailout(node, 'Not a string'); | 2748 bailout(node, 'Not a string'); |
| 2752 } else if (node.isExtendableArray()) { | 2749 } else if (node.isExtendableArray()) { |
| 2753 // if (input is !Object || input is !Array || input.isFixed) bailout | 2750 // if (input is !Object || input is !Array || input.isFixed) bailout |
| 2754 buffer.add('if ('); | 2751 buffer.add('if ('); |
| 2755 checkObject(input, '!=='); | 2752 binary("||", |
| 2756 buffer.add('||'); | 2753 () => binary("||", |
| 2757 checkArray(input, '!=='); | 2754 () => checkObject(input, '!=='), |
| 2758 buffer.add('||'); | 2755 () => checkArray(input, '!==')), |
| 2759 checkFixedArray(input); | 2756 () => checkFixedArray(input)); |
| 2760 buffer.add(') '); | 2757 buffer.add(') '); |
| 2761 bailout(node, 'Not an extendable array'); | 2758 bailout(node, 'Not an extendable array'); |
| 2762 } else if (node.isMutableArray()) { | 2759 } else if (node.isMutableArray()) { |
| 2763 // if (input is !Object | 2760 // if (input is !Object |
| 2764 // || ((input is !Array || input.isImmutable) | 2761 // || ((input is !Array || input.isImmutable) |
| 2765 // && input is !JsIndexingBehavior)) bailout | 2762 // && input is !JsIndexingBehavior)) bailout |
| 2766 buffer.add('if ('); | 2763 buffer.add('if ('); |
| 2767 checkObject(input, '!=='); | 2764 binary("||", |
| 2768 buffer.add(' || (('); | 2765 () => checkObject(input, '!=='), |
| 2769 checkArray(input, '!=='); | 2766 () => binary("&&", |
| 2770 buffer.add(' || '); | 2767 () => binary("||", |
| 2771 checkImmutableArray(input); | 2768 () => checkArray(input, '!=='), |
| 2772 buffer.add(') && '); | 2769 () => checkImmutableArray(input)), |
| 2773 checkType(input, indexingBehavior, negative: true); | 2770 () => checkType(input, indexingBehavior, |
| 2774 buffer.add(')) '); | 2771 negative: true))); |
| 2772 buffer.add(") "); |
| 2775 bailout(node, 'Not a mutable array'); | 2773 bailout(node, 'Not a mutable array'); |
| 2776 } else if (node.isReadableArray()) { | 2774 } else if (node.isReadableArray()) { |
| 2777 // if (input is !Object | 2775 // if (input is !Object |
| 2778 // || (input is !Array && input is !JsIndexingBehavior)) bailout | 2776 // || (input is !Array && input is !JsIndexingBehavior)) bailout |
| 2779 buffer.add('if ('); | 2777 buffer.add('if ('); |
| 2780 checkObject(input, '!=='); | 2778 binary("||", |
| 2781 buffer.add(' || ('); | 2779 () => checkObject(input, '!=='), |
| 2782 checkArray(input, '!=='); | 2780 () => binary("&&", |
| 2783 buffer.add(' && '); | 2781 () => checkArray(input, '!=='), |
| 2784 checkType(input, indexingBehavior, negative: true); | 2782 () => checkType(input, indexingBehavior, |
| 2785 buffer.add(')) '); | 2783 negative: true))); |
| 2784 buffer.add(') '); |
| 2786 bailout(node, 'Not an array'); | 2785 bailout(node, 'Not an array'); |
| 2787 } else if (node.isIndexablePrimitive()) { | 2786 } else if (node.isIndexablePrimitive()) { |
| 2788 // if (input is !String | 2787 // if (input is !String |
| 2789 // && (input is !Object | 2788 // && (input is !Object |
| 2790 // || (input is !Array && input is !JsIndexingBehavior))) bailout | 2789 // || (input is !Array && input is !JsIndexingBehavior))) bailout |
| 2791 buffer.add('if ('); | 2790 buffer.add('if ('); |
| 2792 checkString(input, '!=='); | 2791 binary("&&", |
| 2793 buffer.add(' && ('); | 2792 () => checkString(input, '!=='), |
| 2794 checkObject(input, '!=='); | 2793 () => binary("||", |
| 2795 buffer.add(' || ('); | 2794 () => checkObject(input, '!=='), |
| 2796 checkArray(input, '!=='); | 2795 () => binary("&&", |
| 2797 buffer.add(' && '); | 2796 () => checkArray(input, '!=='), |
| 2798 checkType(input, indexingBehavior, negative: true); | 2797 () => checkType(input, |
| 2799 buffer.add('))) '); | 2798 indexingBehavior, |
| 2799 negative: true)))); |
| 2800 buffer.add(') '); |
| 2800 bailout(node, 'Not a string or array'); | 2801 bailout(node, 'Not a string or array'); |
| 2801 } else { | 2802 } else { |
| 2802 compiler.internalError('Unexpected type guard', instruction: input); | 2803 compiler.internalError('Unexpected type guard', instruction: input); |
| 2803 } | 2804 } |
| 2804 buffer.add(';\n'); | 2805 buffer.add(';\n'); |
| 2805 } | 2806 } |
| 2806 | 2807 |
| 2807 void beginLoop(HBasicBlock block) { | 2808 void beginLoop(HBasicBlock block) { |
| 2808 addIndentation(); | 2809 addIndentation(); |
| 2809 HLoopInformation info = block.loopInformation; | 2810 HLoopInformation info = block.loopInformation; |
| (...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3055 int elseKind = analyzeGraphForCodegen(elseGraph); | 3056 int elseKind = analyzeGraphForCodegen(elseGraph); |
| 3056 bool emptyElse = !node.hasElse || elseKind == SsaCodeGenerator.EMPTY; | 3057 bool emptyElse = !node.hasElse || elseKind == SsaCodeGenerator.EMPTY; |
| 3057 | 3058 |
| 3058 startBailoutCase(thenGraph.start.guards, | 3059 startBailoutCase(thenGraph.start.guards, |
| 3059 node.hasElse ? elseGraph.start.guards : const <HTypeGuard>[]); | 3060 node.hasElse ? elseGraph.start.guards : const <HTypeGuard>[]); |
| 3060 | 3061 |
| 3061 addIndented('if ('); | 3062 addIndented('if ('); |
| 3062 int precedence = JSPrecedence.EXPRESSION_PRECEDENCE; | 3063 int precedence = JSPrecedence.EXPRESSION_PRECEDENCE; |
| 3063 // TODO(ngeoffray): Put the condition initialization in the | 3064 // TODO(ngeoffray): Put the condition initialization in the |
| 3064 // [setup] buffer. | 3065 // [setup] buffer. |
| 3066 |
| 3067 void stateTest() { |
| 3068 binary("&&", |
| 3069 () => binary("==", () => literal("state"), () => literal("0")), |
| 3070 () => use(node.inputs[0], expectedPrecedence)); |
| 3071 } |
| 3072 |
| 3065 List<HTypeGuard> guards = node.thenBlock.guards; | 3073 List<HTypeGuard> guards = node.thenBlock.guards; |
| 3066 for (int i = 0, len = guards.length; i < len; i++) { | 3074 if (guards.length > 0) { |
| 3067 buffer.add('state == ${guards[i].state} || '); | 3075 // Fold guards from the left using '||'. |
| 3076 Function buildGuard(int i) => () { |
| 3077 binary("==", |
| 3078 () => literal("state"), |
| 3079 () => literal("${guards[i].state}")); |
| 3080 } |
| 3081 Function guard = buildGuard(0); |
| 3082 for (int i = 1, len = guards.length; i < len; i++) { |
| 3083 int index = i; |
| 3084 Function oldGuard = guard; |
| 3085 guard = () => binary("||", oldGuard, buildGuard(index)); |
| 3086 } |
| 3087 binary("||", guard, stateTest); |
| 3088 } else { |
| 3089 stateTest(); |
| 3068 } | 3090 } |
| 3069 buffer.add('(state == 0 && '); | |
| 3070 precedence = JSPrecedence.BITWISE_OR_PRECEDENCE; | |
| 3071 use(node.inputs[0], precedence); | |
| 3072 | 3091 |
| 3073 buffer.add(')) {\n'); | 3092 buffer.add(') {\n'); |
| 3074 | 3093 |
| 3075 indent++; | 3094 indent++; |
| 3076 if (thenHasGuards) startBailoutSwitch(); | 3095 if (thenHasGuards) startBailoutSwitch(); |
| 3077 generateStatements(thenGraph); | 3096 generateStatements(thenGraph); |
| 3078 if (thenHasGuards) endBailoutSwitch(); | 3097 if (thenHasGuards) endBailoutSwitch(); |
| 3079 indent--; | 3098 indent--; |
| 3080 | 3099 |
| 3081 if (!emptyElse) { | 3100 if (!emptyElse) { |
| 3082 addIndented('} else {\n'); | 3101 addIndented('} else {\n'); |
| 3083 indent++; | 3102 indent++; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 3103 startBailoutSwitch(); | 3122 startBailoutSwitch(); |
| 3104 } | 3123 } |
| 3105 } | 3124 } |
| 3106 | 3125 |
| 3107 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { | 3126 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { |
| 3108 if (labeledBlockInfo.body.start.hasGuards()) { | 3127 if (labeledBlockInfo.body.start.hasGuards()) { |
| 3109 endBailoutSwitch(); | 3128 endBailoutSwitch(); |
| 3110 } | 3129 } |
| 3111 } | 3130 } |
| 3112 } | 3131 } |
| OLD | NEW |