Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(364)

Side by Side Diff: lib/compiler/implementation/ssa/codegen.dart

Issue 10697031: Generate JS operators using helper functions with thunks for operands. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | lib/compiler/implementation/ssa/codegen_helpers.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « no previous file | lib/compiler/implementation/ssa/codegen_helpers.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698