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