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

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