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

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

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