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