| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 class SsaCodeGeneratorTask extends CompilerTask { | 5 class SsaCodeGeneratorTask extends CompilerTask { |
| 6 | 6 |
| 7 final JavaScriptBackend backend; | 7 final JavaScriptBackend backend; |
| 8 | 8 |
| 9 SsaCodeGeneratorTask(JavaScriptBackend backend) | 9 SsaCodeGeneratorTask(JavaScriptBackend backend) |
| 10 : this.backend = backend, | 10 : this.backend = backend, |
| (...skipping 659 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 670 visitStatement(HInstruction node) { | 670 visitStatement(HInstruction node) { |
| 671 assert(!isGeneratingExpression); | 671 assert(!isGeneratingExpression); |
| 672 visit(node); | 672 visit(node); |
| 673 if (!expressionStack.isEmpty()) { | 673 if (!expressionStack.isEmpty()) { |
| 674 assert(expressionStack.length == 1); | 674 assert(expressionStack.length == 1); |
| 675 pushExpressionAsStatement(pop()); | 675 pushExpressionAsStatement(pop()); |
| 676 } | 676 } |
| 677 } | 677 } |
| 678 | 678 |
| 679 void continueAsBreak(LabelElement target) { | 679 void continueAsBreak(LabelElement target) { |
| 680 pushStatement(new js.Break(compiler.namer.continueLabelName(target))); | 680 pushStatement(new js.Break(backend.namer.continueLabelName(target))); |
| 681 } | 681 } |
| 682 | 682 |
| 683 void implicitContinueAsBreak(TargetElement target) { | 683 void implicitContinueAsBreak(TargetElement target) { |
| 684 pushStatement(new js.Break( | 684 pushStatement(new js.Break( |
| 685 compiler.namer.implicitContinueLabelName(target))); | 685 backend.namer.implicitContinueLabelName(target))); |
| 686 } | 686 } |
| 687 | 687 |
| 688 void implicitBreakWithLabel(TargetElement target) { | 688 void implicitBreakWithLabel(TargetElement target) { |
| 689 pushStatement(new js.Break(compiler.namer.implicitBreakLabelName(target))); | 689 pushStatement(new js.Break(backend.namer.implicitBreakLabelName(target))); |
| 690 } | 690 } |
| 691 | 691 |
| 692 js.Statement wrapIntoLabels(js.Statement result, List<LabelElement> labels) { | 692 js.Statement wrapIntoLabels(js.Statement result, List<LabelElement> labels) { |
| 693 for (LabelElement label in labels) { | 693 for (LabelElement label in labels) { |
| 694 if (label.isTarget) { | 694 if (label.isTarget) { |
| 695 String breakLabelString = compiler.namer.breakLabelName(label); | 695 String breakLabelString = backend.namer.breakLabelName(label); |
| 696 result = new js.LabeledStatement(breakLabelString, result); | 696 result = new js.LabeledStatement(breakLabelString, result); |
| 697 } | 697 } |
| 698 } | 698 } |
| 699 return result; | 699 return result; |
| 700 } | 700 } |
| 701 | 701 |
| 702 | 702 |
| 703 // The regular [visitIf] method implements the needed logic. | 703 // The regular [visitIf] method implements the needed logic. |
| 704 bool visitIfInfo(HIfBlockInformation info) => false; | 704 bool visitIfInfo(HIfBlockInformation info) => false; |
| 705 | 705 |
| (...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 945 | 945 |
| 946 currentContainer = body; | 946 currentContainer = body; |
| 947 | 947 |
| 948 // If [labeledBlockInfo.isContinue], the block is an artificial | 948 // If [labeledBlockInfo.isContinue], the block is an artificial |
| 949 // block around the body of a loop with an update block, so that | 949 // block around the body of a loop with an update block, so that |
| 950 // continues of the loop can be written as breaks of the body | 950 // continues of the loop can be written as breaks of the body |
| 951 // block. | 951 // block. |
| 952 if (labeledBlockInfo.isContinue) { | 952 if (labeledBlockInfo.isContinue) { |
| 953 for (LabelElement label in labeledBlockInfo.labels) { | 953 for (LabelElement label in labeledBlockInfo.labels) { |
| 954 if (label.isContinueTarget) { | 954 if (label.isContinueTarget) { |
| 955 String labelName = compiler.namer.continueLabelName(label); | 955 String labelName = backend.namer.continueLabelName(label); |
| 956 result = new js.LabeledStatement(labelName, result); | 956 result = new js.LabeledStatement(labelName, result); |
| 957 continueAction[label] = continueAsBreak; | 957 continueAction[label] = continueAsBreak; |
| 958 continueOverrides = continueOverrides.prepend(label); | 958 continueOverrides = continueOverrides.prepend(label); |
| 959 } | 959 } |
| 960 } | 960 } |
| 961 // For handling unlabeled continues from the body of a loop. | 961 // For handling unlabeled continues from the body of a loop. |
| 962 // TODO(lrn): Consider recording whether the target is in fact | 962 // TODO(lrn): Consider recording whether the target is in fact |
| 963 // a target of an unlabeled continue, and not generate this if it isn't. | 963 // a target of an unlabeled continue, and not generate this if it isn't. |
| 964 TargetElement target = labeledBlockInfo.target; | 964 TargetElement target = labeledBlockInfo.target; |
| 965 String labelName = compiler.namer.implicitContinueLabelName(target); | 965 String labelName = backend.namer.implicitContinueLabelName(target); |
| 966 result = new js.LabeledStatement(labelName, result); | 966 result = new js.LabeledStatement(labelName, result); |
| 967 continueAction[target] = implicitContinueAsBreak; | 967 continueAction[target] = implicitContinueAsBreak; |
| 968 continueOverrides = continueOverrides.prepend(target); | 968 continueOverrides = continueOverrides.prepend(target); |
| 969 } else { | 969 } else { |
| 970 for (LabelElement label in labeledBlockInfo.labels) { | 970 for (LabelElement label in labeledBlockInfo.labels) { |
| 971 if (label.isBreakTarget) { | 971 if (label.isBreakTarget) { |
| 972 String labelName = compiler.namer.breakLabelName(label); | 972 String labelName = backend.namer.breakLabelName(label); |
| 973 result = new js.LabeledStatement(labelName, result); | 973 result = new js.LabeledStatement(labelName, result); |
| 974 } | 974 } |
| 975 } | 975 } |
| 976 TargetElement target = labeledBlockInfo.target; | 976 TargetElement target = labeledBlockInfo.target; |
| 977 if (target.isSwitch) { | 977 if (target.isSwitch) { |
| 978 // This is an extra block around a switch that is generated | 978 // This is an extra block around a switch that is generated |
| 979 // as a nested if/else chain. We add an extra break target | 979 // as a nested if/else chain. We add an extra break target |
| 980 // so that case code can break. | 980 // so that case code can break. |
| 981 String labelName = compiler.namer.implicitBreakLabelName(target); | 981 String labelName = backend.namer.implicitBreakLabelName(target); |
| 982 result = new js.LabeledStatement(labelName, result); | 982 result = new js.LabeledStatement(labelName, result); |
| 983 breakAction[target] = implicitBreakWithLabel; | 983 breakAction[target] = implicitBreakWithLabel; |
| 984 } | 984 } |
| 985 } | 985 } |
| 986 | 986 |
| 987 currentContainer = body; | 987 currentContainer = body; |
| 988 startLabeledBlock(labeledBlockInfo); | 988 startLabeledBlock(labeledBlockInfo); |
| 989 generateStatements(labeledBlockInfo.body); | 989 generateStatements(labeledBlockInfo.body); |
| 990 endLabeledBlock(labeledBlockInfo); | 990 endLabeledBlock(labeledBlockInfo); |
| 991 | 991 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 1007 // to (if necessary). | 1007 // to (if necessary). |
| 1008 void wrapLoopBodyForContinue(HLoopBlockInformation info) { | 1008 void wrapLoopBodyForContinue(HLoopBlockInformation info) { |
| 1009 TargetElement target = info.target; | 1009 TargetElement target = info.target; |
| 1010 if (target !== null && target.isContinueTarget) { | 1010 if (target !== null && target.isContinueTarget) { |
| 1011 js.Block oldContainer = currentContainer; | 1011 js.Block oldContainer = currentContainer; |
| 1012 js.Block body = new js.Block.empty(); | 1012 js.Block body = new js.Block.empty(); |
| 1013 currentContainer = body; | 1013 currentContainer = body; |
| 1014 js.Statement result = body; | 1014 js.Statement result = body; |
| 1015 for (LabelElement label in info.labels) { | 1015 for (LabelElement label in info.labels) { |
| 1016 if (label.isContinueTarget) { | 1016 if (label.isContinueTarget) { |
| 1017 String labelName = compiler.namer.continueLabelName(label); | 1017 String labelName = backend.namer.continueLabelName(label); |
| 1018 result = new js.LabeledStatement(labelName, result); | 1018 result = new js.LabeledStatement(labelName, result); |
| 1019 continueAction[label] = continueAsBreak; | 1019 continueAction[label] = continueAsBreak; |
| 1020 } | 1020 } |
| 1021 } | 1021 } |
| 1022 String labelName = compiler.namer.implicitContinueLabelName(target); | 1022 String labelName = backend.namer.implicitContinueLabelName(target); |
| 1023 result = new js.LabeledStatement(labelName, result); | 1023 result = new js.LabeledStatement(labelName, result); |
| 1024 continueAction[info.target] = implicitContinueAsBreak; | 1024 continueAction[info.target] = implicitContinueAsBreak; |
| 1025 visitBodyIgnoreLabels(info); | 1025 visitBodyIgnoreLabels(info); |
| 1026 continueAction.remove(info.target); | 1026 continueAction.remove(info.target); |
| 1027 for (LabelElement label in info.labels) { | 1027 for (LabelElement label in info.labels) { |
| 1028 if (label.isContinueTarget) { | 1028 if (label.isContinueTarget) { |
| 1029 continueAction.remove(label); | 1029 continueAction.remove(label); |
| 1030 } | 1030 } |
| 1031 } | 1031 } |
| 1032 currentContainer = oldContainer; | 1032 currentContainer = oldContainer; |
| (...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1331 if (action === null) return false; | 1331 if (action === null) return false; |
| 1332 action(element); | 1332 action(element); |
| 1333 return true; | 1333 return true; |
| 1334 } | 1334 } |
| 1335 | 1335 |
| 1336 visitBreak(HBreak node) { | 1336 visitBreak(HBreak node) { |
| 1337 assert(currentBlock.successors.length == 1); | 1337 assert(currentBlock.successors.length == 1); |
| 1338 if (node.label !== null) { | 1338 if (node.label !== null) { |
| 1339 LabelElement label = node.label; | 1339 LabelElement label = node.label; |
| 1340 if (!tryCallAction(breakAction, label)) { | 1340 if (!tryCallAction(breakAction, label)) { |
| 1341 pushStatement(new js.Break(compiler.namer.breakLabelName(label)), node); | 1341 pushStatement(new js.Break(backend.namer.breakLabelName(label)), node); |
| 1342 } | 1342 } |
| 1343 } else { | 1343 } else { |
| 1344 TargetElement target = node.target; | 1344 TargetElement target = node.target; |
| 1345 if (!tryCallAction(breakAction, target)) { | 1345 if (!tryCallAction(breakAction, target)) { |
| 1346 pushStatement(new js.Break(null), node); | 1346 pushStatement(new js.Break(null), node); |
| 1347 } | 1347 } |
| 1348 } | 1348 } |
| 1349 } | 1349 } |
| 1350 | 1350 |
| 1351 visitContinue(HContinue node) { | 1351 visitContinue(HContinue node) { |
| 1352 assert(currentBlock.successors.length == 1); | 1352 assert(currentBlock.successors.length == 1); |
| 1353 if (node.label !== null) { | 1353 if (node.label !== null) { |
| 1354 LabelElement label = node.label; | 1354 LabelElement label = node.label; |
| 1355 if (!tryCallAction(continueAction, label)) { | 1355 if (!tryCallAction(continueAction, label)) { |
| 1356 // TODO(floitsch): should this really be the breakLabelName? | 1356 // TODO(floitsch): should this really be the breakLabelName? |
| 1357 pushStatement(new js.Continue(compiler.namer.breakLabelName(label)), | 1357 pushStatement(new js.Continue(backend.namer.breakLabelName(label)), |
| 1358 node); | 1358 node); |
| 1359 } | 1359 } |
| 1360 } else { | 1360 } else { |
| 1361 TargetElement target = node.target; | 1361 TargetElement target = node.target; |
| 1362 if (!tryCallAction(continueAction, target)) { | 1362 if (!tryCallAction(continueAction, target)) { |
| 1363 pushStatement(new js.Continue(null), node); | 1363 pushStatement(new js.Continue(null), node); |
| 1364 } | 1364 } |
| 1365 } | 1365 } |
| 1366 } | 1366 } |
| 1367 | 1367 |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1455 List<js.Expression> arguments; | 1455 List<js.Expression> arguments; |
| 1456 | 1456 |
| 1457 // Avoid adding the generative constructor name to the list of | 1457 // Avoid adding the generative constructor name to the list of |
| 1458 // seen selectors. | 1458 // seen selectors. |
| 1459 if (node.inputs[0] is HForeignNew) { | 1459 if (node.inputs[0] is HForeignNew) { |
| 1460 // TODO(ahe): The constructor name was statically resolved in | 1460 // TODO(ahe): The constructor name was statically resolved in |
| 1461 // SsaBuilder.buildFactory. Is there a cleaner way to do this? | 1461 // SsaBuilder.buildFactory. Is there a cleaner way to do this? |
| 1462 methodName = name.slowToString(); | 1462 methodName = name.slowToString(); |
| 1463 arguments = visitArguments(node.inputs); | 1463 arguments = visitArguments(node.inputs); |
| 1464 } else { | 1464 } else { |
| 1465 methodName = compiler.namer.instanceMethodInvocationName( | 1465 methodName = backend.namer.instanceMethodInvocationName( |
| 1466 node.selector.library, name, node.selector); | 1466 node.selector.library, name, node.selector); |
| 1467 arguments = visitArguments(node.inputs); | 1467 arguments = visitArguments(node.inputs); |
| 1468 bool inLoop = node.block.enclosingLoopHeader !== null; | 1468 bool inLoop = node.block.enclosingLoopHeader !== null; |
| 1469 | 1469 |
| 1470 // Register this invocation to collect the types used at all call sites. | 1470 // Register this invocation to collect the types used at all call sites. |
| 1471 Selector selector = getOptimizedSelectorFor(node, node.selector); | 1471 Selector selector = getOptimizedSelectorFor(node, node.selector); |
| 1472 backend.registerDynamicInvocation(node, selector, types); | 1472 backend.registerDynamicInvocation(node, selector, types); |
| 1473 | 1473 |
| 1474 // If we don't know what we're calling or if we are calling a getter, | 1474 // If we don't know what we're calling or if we are calling a getter, |
| 1475 // we need to register that fact that we may be calling a closure | 1475 // we need to register that fact that we may be calling a closure |
| (...skipping 29 matching lines...) Expand all Loading... |
| 1505 if (receiverType !== null) { | 1505 if (receiverType !== null) { |
| 1506 return new TypedSelector(receiverType, defaultSelector); | 1506 return new TypedSelector(receiverType, defaultSelector); |
| 1507 } else { | 1507 } else { |
| 1508 return defaultSelector; | 1508 return defaultSelector; |
| 1509 } | 1509 } |
| 1510 } | 1510 } |
| 1511 | 1511 |
| 1512 visitInvokeDynamicSetter(HInvokeDynamicSetter node) { | 1512 visitInvokeDynamicSetter(HInvokeDynamicSetter node) { |
| 1513 use(node.receiver); | 1513 use(node.receiver); |
| 1514 Selector setter = node.selector; | 1514 Selector setter = node.selector; |
| 1515 String name = compiler.namer.setterName(setter.library, setter.name); | 1515 String name = backend.namer.setterName(setter.library, setter.name); |
| 1516 push(jsPropertyCall(pop(), name, visitArguments(node.inputs)), node); | 1516 push(jsPropertyCall(pop(), name, visitArguments(node.inputs)), node); |
| 1517 world.registerDynamicSetter( | 1517 world.registerDynamicSetter( |
| 1518 setter.name, getOptimizedSelectorFor(node, setter)); | 1518 setter.name, getOptimizedSelectorFor(node, setter)); |
| 1519 } | 1519 } |
| 1520 | 1520 |
| 1521 visitInvokeDynamicGetter(HInvokeDynamicGetter node) { | 1521 visitInvokeDynamicGetter(HInvokeDynamicGetter node) { |
| 1522 use(node.receiver); | 1522 use(node.receiver); |
| 1523 Selector getter = node.selector; | 1523 Selector getter = node.selector; |
| 1524 String name = compiler.namer.getterName(getter.library, getter.name); | 1524 String name = backend.namer.getterName(getter.library, getter.name); |
| 1525 push(jsPropertyCall(pop(), name, visitArguments(node.inputs)), node); | 1525 push(jsPropertyCall(pop(), name, visitArguments(node.inputs)), node); |
| 1526 world.registerDynamicGetter( | 1526 world.registerDynamicGetter( |
| 1527 getter.name, getOptimizedSelectorFor(node, getter)); | 1527 getter.name, getOptimizedSelectorFor(node, getter)); |
| 1528 } | 1528 } |
| 1529 | 1529 |
| 1530 visitInvokeClosure(HInvokeClosure node) { | 1530 visitInvokeClosure(HInvokeClosure node) { |
| 1531 use(node.receiver); | 1531 use(node.receiver); |
| 1532 push(jsPropertyCall(pop(), | 1532 push(jsPropertyCall(pop(), |
| 1533 compiler.namer.closureInvocationName(node.selector), | 1533 backend.namer.closureInvocationName(node.selector), |
| 1534 visitArguments(node.inputs)), | 1534 visitArguments(node.inputs)), |
| 1535 node); | 1535 node); |
| 1536 Selector call = new Selector.callClosureFrom(node.selector); | 1536 Selector call = new Selector.callClosureFrom(node.selector); |
| 1537 world.registerDynamicInvocation(call.name, call); | 1537 world.registerDynamicInvocation(call.name, call); |
| 1538 } | 1538 } |
| 1539 | 1539 |
| 1540 visitInvokeStatic(HInvokeStatic node) { | 1540 visitInvokeStatic(HInvokeStatic node) { |
| 1541 if (true && | 1541 if (true && |
| 1542 (node.typeCode() == HInstruction.INVOKE_STATIC_TYPECODE || | 1542 (node.typeCode() == HInstruction.INVOKE_STATIC_TYPECODE || |
| 1543 node.typeCode() == HInstruction.INVOKE_INTERCEPTOR_TYPECODE)) { | 1543 node.typeCode() == HInstruction.INVOKE_INTERCEPTOR_TYPECODE)) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1554 // Remove the element and 'this'. | 1554 // Remove the element and 'this'. |
| 1555 int argumentCount = node.inputs.length - 2; | 1555 int argumentCount = node.inputs.length - 2; |
| 1556 if (superMethod.kind == ElementKind.FIELD) { | 1556 if (superMethod.kind == ElementKind.FIELD) { |
| 1557 ClassElement currentClass = work.element.getEnclosingClass(); | 1557 ClassElement currentClass = work.element.getEnclosingClass(); |
| 1558 if (currentClass.isClosure()) { | 1558 if (currentClass.isClosure()) { |
| 1559 ClosureClassElement closure = currentClass; | 1559 ClosureClassElement closure = currentClass; |
| 1560 currentClass = closure.methodElement.getEnclosingClass(); | 1560 currentClass = closure.methodElement.getEnclosingClass(); |
| 1561 } | 1561 } |
| 1562 String fieldName; | 1562 String fieldName; |
| 1563 if (currentClass.isShadowedByField(superMethod)) { | 1563 if (currentClass.isShadowedByField(superMethod)) { |
| 1564 fieldName = compiler.namer.shadowedFieldName(superMethod); | 1564 fieldName = backend.namer.shadowedFieldName(superMethod); |
| 1565 } else { | 1565 } else { |
| 1566 LibraryElement library = superMethod.getLibrary(); | 1566 LibraryElement library = superMethod.getLibrary(); |
| 1567 SourceString name = superMethod.name; | 1567 SourceString name = superMethod.name; |
| 1568 fieldName = compiler.namer.instanceFieldName(library, name); | 1568 fieldName = backend.namer.instanceFieldName(library, name); |
| 1569 } | 1569 } |
| 1570 use(node.inputs[1]); | 1570 use(node.inputs[1]); |
| 1571 js.PropertyAccess access = | 1571 js.PropertyAccess access = |
| 1572 new js.PropertyAccess.field(pop(), fieldName); | 1572 new js.PropertyAccess.field(pop(), fieldName); |
| 1573 if (node.isSetter) { | 1573 if (node.isSetter) { |
| 1574 use(node.value); | 1574 use(node.value); |
| 1575 push(new js.Assignment(access, pop()), node); | 1575 push(new js.Assignment(access, pop()), node); |
| 1576 } else { | 1576 } else { |
| 1577 push(access, node); | 1577 push(access, node); |
| 1578 } | 1578 } |
| 1579 } else { | 1579 } else { |
| 1580 String methodName; | 1580 String methodName; |
| 1581 if (superMethod.kind == ElementKind.FUNCTION || | 1581 if (superMethod.kind == ElementKind.FUNCTION || |
| 1582 superMethod.kind == ElementKind.GENERATIVE_CONSTRUCTOR) { | 1582 superMethod.kind == ElementKind.GENERATIVE_CONSTRUCTOR) { |
| 1583 methodName = compiler.namer.instanceMethodName( | 1583 methodName = backend.namer.instanceMethodName( |
| 1584 currentLibrary, superMethod.name, argumentCount); | 1584 currentLibrary, superMethod.name, argumentCount); |
| 1585 } else if (superMethod.kind == ElementKind.GETTER) { | 1585 } else if (superMethod.kind == ElementKind.GETTER) { |
| 1586 methodName = | 1586 methodName = |
| 1587 compiler.namer.getterName(currentLibrary, superMethod.name); | 1587 backend.namer.getterName(currentLibrary, superMethod.name); |
| 1588 } else { | 1588 } else { |
| 1589 assert(superMethod.kind == ElementKind.SETTER); | 1589 assert(superMethod.kind == ElementKind.SETTER); |
| 1590 methodName = | 1590 methodName = |
| 1591 compiler.namer.setterName(currentLibrary, superMethod.name); | 1591 backend.namer.setterName(currentLibrary, superMethod.name); |
| 1592 } | 1592 } |
| 1593 String className = compiler.namer.isolateAccess(superClass); | 1593 String className = backend.namer.isolateAccess(superClass); |
| 1594 js.VariableUse classReference = new js.VariableUse(className); | 1594 js.VariableUse classReference = new js.VariableUse(className); |
| 1595 js.PropertyAccess prototype = | 1595 js.PropertyAccess prototype = |
| 1596 new js.PropertyAccess.field(classReference, "prototype"); | 1596 new js.PropertyAccess.field(classReference, "prototype"); |
| 1597 js.PropertyAccess method = | 1597 js.PropertyAccess method = |
| 1598 new js.PropertyAccess.field(prototype, methodName); | 1598 new js.PropertyAccess.field(prototype, methodName); |
| 1599 push(jsPropertyCall(method, "call", visitArguments(node.inputs)), node); | 1599 push(jsPropertyCall(method, "call", visitArguments(node.inputs)), node); |
| 1600 } | 1600 } |
| 1601 world.registerStaticUse(superMethod); | 1601 world.registerStaticUse(superMethod); |
| 1602 } | 1602 } |
| 1603 | 1603 |
| 1604 visitFieldGet(HFieldGet node) { | 1604 visitFieldGet(HFieldGet node) { |
| 1605 String name = compiler.namer.getName(node.element); | 1605 String name = backend.namer.getName(node.element); |
| 1606 use(node.receiver); | 1606 use(node.receiver); |
| 1607 push(new js.PropertyAccess.field(pop(), name), node); | 1607 push(new js.PropertyAccess.field(pop(), name), node); |
| 1608 HType receiverHType = types[node.receiver]; | 1608 HType receiverHType = types[node.receiver]; |
| 1609 DartType type = receiverHType.computeType(compiler); | 1609 DartType type = receiverHType.computeType(compiler); |
| 1610 if (type != null) { | 1610 if (type != null) { |
| 1611 world.registerFieldGetter( | 1611 world.registerFieldGetter( |
| 1612 node.element.name, node.element.getLibrary(), type); | 1612 node.element.name, node.element.getLibrary(), type); |
| 1613 } | 1613 } |
| 1614 } | 1614 } |
| 1615 | 1615 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1627 } | 1627 } |
| 1628 | 1628 |
| 1629 visitFieldSet(HFieldSet node) { | 1629 visitFieldSet(HFieldSet node) { |
| 1630 if (work.element.isGenerativeConstructorBody() && | 1630 if (work.element.isGenerativeConstructorBody() && |
| 1631 node.element.isMember() && | 1631 node.element.isMember() && |
| 1632 node.value.hasGuaranteedType() && | 1632 node.value.hasGuaranteedType() && |
| 1633 node.block.dominates(currentGraph.exit)) { | 1633 node.block.dominates(currentGraph.exit)) { |
| 1634 backend.updateFieldConstructorSetters(node.element, | 1634 backend.updateFieldConstructorSetters(node.element, |
| 1635 node.value.guaranteedType); | 1635 node.value.guaranteedType); |
| 1636 } | 1636 } |
| 1637 String name = compiler.namer.getName(node.element); | 1637 String name = backend.namer.getName(node.element); |
| 1638 DartType type = types[node.receiver].computeType(compiler); | 1638 DartType type = types[node.receiver].computeType(compiler); |
| 1639 if (type != null) { | 1639 if (type != null) { |
| 1640 if (!work.element.isGenerativeConstructorBody()) { | 1640 if (!work.element.isGenerativeConstructorBody()) { |
| 1641 world.registerFieldSetter( | 1641 world.registerFieldSetter( |
| 1642 node.element.name, node.element.getLibrary(), type); | 1642 node.element.name, node.element.getLibrary(), type); |
| 1643 } | 1643 } |
| 1644 // Determine the types seen so far for the field. If only number | 1644 // Determine the types seen so far for the field. If only number |
| 1645 // types have been seen and the value of the field set is a | 1645 // types have been seen and the value of the field set is a |
| 1646 // simple number computation only depending on that field, we | 1646 // simple number computation only depending on that field, we |
| 1647 // can safely keep the number type for the field. | 1647 // can safely keep the number type for the field. |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1693 | 1693 |
| 1694 visitForeignNew(HForeignNew node) { | 1694 visitForeignNew(HForeignNew node) { |
| 1695 int j = 0; | 1695 int j = 0; |
| 1696 node.element.forEachInstanceField( | 1696 node.element.forEachInstanceField( |
| 1697 includeBackendMembers: true, | 1697 includeBackendMembers: true, |
| 1698 includeSuperMembers: true, | 1698 includeSuperMembers: true, |
| 1699 f: (ClassElement enclosingClass, Element member) { | 1699 f: (ClassElement enclosingClass, Element member) { |
| 1700 backend.updateFieldInitializers(member, types[node.inputs[j]]); | 1700 backend.updateFieldInitializers(member, types[node.inputs[j]]); |
| 1701 j++; | 1701 j++; |
| 1702 }); | 1702 }); |
| 1703 String jsClassReference = compiler.namer.isolateAccess(node.element); | 1703 String jsClassReference = backend.namer.isolateAccess(node.element); |
| 1704 List<HInstruction> inputs = node.inputs; | 1704 List<HInstruction> inputs = node.inputs; |
| 1705 // We can't use 'visitArguments', since our arguments start at input[0]. | 1705 // We can't use 'visitArguments', since our arguments start at input[0]. |
| 1706 List<js.Expression> arguments = <js.Expression>[]; | 1706 List<js.Expression> arguments = <js.Expression>[]; |
| 1707 for (int i = 0; i < inputs.length; i++) { | 1707 for (int i = 0; i < inputs.length; i++) { |
| 1708 use(inputs[i]); | 1708 use(inputs[i]); |
| 1709 arguments.add(pop()); | 1709 arguments.add(pop()); |
| 1710 } | 1710 } |
| 1711 // TODO(floitsch): jsClassReference is an Access. We shouldn't treat it | 1711 // TODO(floitsch): jsClassReference is an Access. We shouldn't treat it |
| 1712 // as if it was a string. | 1712 // as if it was a string. |
| 1713 push(new js.New(new js.VariableUse(jsClassReference), arguments), node); | 1713 push(new js.New(new js.VariableUse(jsClassReference), arguments), node); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 1729 push(new js.LiteralNull()); | 1729 push(new js.LiteralNull()); |
| 1730 } else if (constant.isString()) { | 1730 } else if (constant.isString()) { |
| 1731 // TODO(floitsch): get rid of the code buffer. | 1731 // TODO(floitsch): get rid of the code buffer. |
| 1732 CodeBuffer buffer = new CodeBuffer(); | 1732 CodeBuffer buffer = new CodeBuffer(); |
| 1733 handler.writeConstant(buffer, constant); | 1733 handler.writeConstant(buffer, constant); |
| 1734 push(new js.LiteralString(buffer.toString())); | 1734 push(new js.LiteralString(buffer.toString())); |
| 1735 } else if (constant.isFunction()) { | 1735 } else if (constant.isFunction()) { |
| 1736 FunctionConstant function = constant; | 1736 FunctionConstant function = constant; |
| 1737 world.registerStaticUse(function.element); | 1737 world.registerStaticUse(function.element); |
| 1738 push(new js.VariableUse( | 1738 push(new js.VariableUse( |
| 1739 compiler.namer.isolateAccess(function.element))); | 1739 backend.namer.isolateAccess(function.element))); |
| 1740 } else if (constant.isSentinel()) { | 1740 } else if (constant.isSentinel()) { |
| 1741 // TODO(floitsch): get rid of the code buffer. | 1741 // TODO(floitsch): get rid of the code buffer. |
| 1742 CodeBuffer buffer = new CodeBuffer(); | 1742 CodeBuffer buffer = new CodeBuffer(); |
| 1743 handler.writeConstant(buffer, constant); | 1743 handler.writeConstant(buffer, constant); |
| 1744 push(new js.VariableUse(buffer.toString())); | 1744 push(new js.VariableUse(buffer.toString())); |
| 1745 } else { | 1745 } else { |
| 1746 compiler.internalError( | 1746 compiler.internalError( |
| 1747 "The compiler does not know how generate code for " | 1747 "The compiler does not know how generate code for " |
| 1748 "constant $constant"); | 1748 "constant $constant"); |
| 1749 } | 1749 } |
| 1750 } else { | 1750 } else { |
| 1751 js.VariableUse currentIsolateUse = | 1751 js.VariableUse currentIsolateUse = |
| 1752 new js.VariableUse(compiler.namer.CURRENT_ISOLATE); | 1752 new js.VariableUse(backend.namer.CURRENT_ISOLATE); |
| 1753 push(new js.PropertyAccess.field(currentIsolateUse, name)); | 1753 push(new js.PropertyAccess.field(currentIsolateUse, name)); |
| 1754 } | 1754 } |
| 1755 } | 1755 } |
| 1756 | 1756 |
| 1757 visitConstant(HConstant node) { | 1757 visitConstant(HConstant node) { |
| 1758 assert(isGenerateAtUseSite(node)); | 1758 assert(isGenerateAtUseSite(node)); |
| 1759 generateConstant(node.constant); | 1759 generateConstant(node.constant); |
| 1760 } | 1760 } |
| 1761 | 1761 |
| 1762 visitLoopBranch(HLoopBranch node) { | 1762 visitLoopBranch(HLoopBranch node) { |
| (...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1951 pushStatement(new js.If.noElse(test, thenBody), node); | 1951 pushStatement(new js.If.noElse(test, thenBody), node); |
| 1952 } else { | 1952 } else { |
| 1953 generateThrowWithHelper('iae', node.value); | 1953 generateThrowWithHelper('iae', node.value); |
| 1954 } | 1954 } |
| 1955 } | 1955 } |
| 1956 | 1956 |
| 1957 void generateThrowWithHelper(String helperName, HInstruction argument) { | 1957 void generateThrowWithHelper(String helperName, HInstruction argument) { |
| 1958 Element helper = compiler.findHelper(new SourceString(helperName)); | 1958 Element helper = compiler.findHelper(new SourceString(helperName)); |
| 1959 world.registerStaticUse(helper); | 1959 world.registerStaticUse(helper); |
| 1960 js.VariableUse jsHelper = | 1960 js.VariableUse jsHelper = |
| 1961 new js.VariableUse(compiler.namer.isolateAccess(helper)); | 1961 new js.VariableUse(backend.namer.isolateAccess(helper)); |
| 1962 js.Call value = new js.Call(jsHelper, visitArguments([null, argument])); | 1962 js.Call value = new js.Call(jsHelper, visitArguments([null, argument])); |
| 1963 attachLocation(value, argument); | 1963 attachLocation(value, argument); |
| 1964 // BUG(4906): Using throw here adds to the size of the generated code | 1964 // BUG(4906): Using throw here adds to the size of the generated code |
| 1965 // but it has the advantage of explicitly telling the JS engine that | 1965 // but it has the advantage of explicitly telling the JS engine that |
| 1966 // this code path will terminate abruptly. Needs more work. | 1966 // this code path will terminate abruptly. Needs more work. |
| 1967 pushStatement(new js.Throw(value)); | 1967 pushStatement(new js.Throw(value)); |
| 1968 } | 1968 } |
| 1969 | 1969 |
| 1970 void visitSwitch(HSwitch node) { | 1970 void visitSwitch(HSwitch node) { |
| 1971 // Switches are handled using [visitSwitchInfo]. | 1971 // Switches are handled using [visitSwitchInfo]. |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1984 // which will also be non call static use. | 1984 // which will also be non call static use. |
| 1985 for (int i = 1; i < node.inputs.length; i++) { | 1985 for (int i = 1; i < node.inputs.length; i++) { |
| 1986 if (node.inputs === node) { | 1986 if (node.inputs === node) { |
| 1987 backend.registerNonCallStaticUse(node); | 1987 backend.registerNonCallStaticUse(node); |
| 1988 break; | 1988 break; |
| 1989 } | 1989 } |
| 1990 } | 1990 } |
| 1991 } | 1991 } |
| 1992 }); | 1992 }); |
| 1993 world.registerStaticUse(node.element); | 1993 world.registerStaticUse(node.element); |
| 1994 push(new js.VariableUse(compiler.namer.isolateAccess(node.element))); | 1994 push(new js.VariableUse(backend.namer.isolateAccess(node.element))); |
| 1995 } | 1995 } |
| 1996 | 1996 |
| 1997 void visitLazyStatic(HLazyStatic node) { | 1997 void visitLazyStatic(HLazyStatic node) { |
| 1998 Element element = node.element; | 1998 Element element = node.element; |
| 1999 world.registerStaticUse(element); | 1999 world.registerStaticUse(element); |
| 2000 String lazyGetter = compiler.namer.isolateLazyInitializerAccess(element); | 2000 String lazyGetter = backend.namer.isolateLazyInitializerAccess(element); |
| 2001 js.VariableUse target = new js.VariableUse(lazyGetter); | 2001 js.VariableUse target = new js.VariableUse(lazyGetter); |
| 2002 js.Call call = new js.Call(target, <js.Expression>[]); | 2002 js.Call call = new js.Call(target, <js.Expression>[]); |
| 2003 push(call, node); | 2003 push(call, node); |
| 2004 } | 2004 } |
| 2005 | 2005 |
| 2006 void visitStaticStore(HStaticStore node) { | 2006 void visitStaticStore(HStaticStore node) { |
| 2007 world.registerStaticUse(node.element); | 2007 world.registerStaticUse(node.element); |
| 2008 js.VariableUse variableUse = | 2008 js.VariableUse variableUse = |
| 2009 new js.VariableUse(compiler.namer.isolateAccess(node.element)); | 2009 new js.VariableUse(backend.namer.isolateAccess(node.element)); |
| 2010 use(node.inputs[0]); | 2010 use(node.inputs[0]); |
| 2011 push(new js.Assignment(variableUse, pop()), node); | 2011 push(new js.Assignment(variableUse, pop()), node); |
| 2012 } | 2012 } |
| 2013 | 2013 |
| 2014 void visitStringConcat(HStringConcat node) { | 2014 void visitStringConcat(HStringConcat node) { |
| 2015 if (isEmptyString(node.left)) { | 2015 if (isEmptyString(node.left)) { |
| 2016 useStringified(node.right); | 2016 useStringified(node.right); |
| 2017 } else if (isEmptyString(node.right)) { | 2017 } else if (isEmptyString(node.right)) { |
| 2018 useStringified(node.left); | 2018 useStringified(node.left); |
| 2019 } else { | 2019 } else { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 2031 return string.value.length == 0; | 2031 return string.value.length == 0; |
| 2032 } | 2032 } |
| 2033 | 2033 |
| 2034 void useStringified(HInstruction node) { | 2034 void useStringified(HInstruction node) { |
| 2035 if (node.isString(types)) { | 2035 if (node.isString(types)) { |
| 2036 use(node); | 2036 use(node); |
| 2037 } else { | 2037 } else { |
| 2038 Element convertToString = compiler.findHelper(const SourceString("S")); | 2038 Element convertToString = compiler.findHelper(const SourceString("S")); |
| 2039 world.registerStaticUse(convertToString); | 2039 world.registerStaticUse(convertToString); |
| 2040 js.VariableUse variableUse = | 2040 js.VariableUse variableUse = |
| 2041 new js.VariableUse(compiler.namer.isolateAccess(convertToString)); | 2041 new js.VariableUse(backend.namer.isolateAccess(convertToString)); |
| 2042 use(node); | 2042 use(node); |
| 2043 push(new js.Call(variableUse, <js.Expression>[pop()]), node); | 2043 push(new js.Call(variableUse, <js.Expression>[pop()]), node); |
| 2044 } | 2044 } |
| 2045 } | 2045 } |
| 2046 | 2046 |
| 2047 void visitLiteralList(HLiteralList node) { | 2047 void visitLiteralList(HLiteralList node) { |
| 2048 generateArrayLiteral(node); | 2048 generateArrayLiteral(node); |
| 2049 } | 2049 } |
| 2050 | 2050 |
| 2051 void generateArrayLiteral(HLiteralList node) { | 2051 void generateArrayLiteral(HLiteralList node) { |
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2224 checkType(input, element); | 2224 checkType(input, element); |
| 2225 push(new js.Binary('||', | 2225 push(new js.Binary('||', |
| 2226 functionTest, | 2226 functionTest, |
| 2227 new js.Binary('&&', objectTest, pop()))); | 2227 new js.Binary('&&', objectTest, pop()))); |
| 2228 } | 2228 } |
| 2229 | 2229 |
| 2230 void checkType(HInstruction input, Element element, [bool negative = false]) { | 2230 void checkType(HInstruction input, Element element, [bool negative = false]) { |
| 2231 world.registerIsCheck(element); | 2231 world.registerIsCheck(element); |
| 2232 use(input); | 2232 use(input); |
| 2233 js.PropertyAccess field = | 2233 js.PropertyAccess field = |
| 2234 new js.PropertyAccess.field(pop(), compiler.namer.operatorIs(element)); | 2234 new js.PropertyAccess.field(pop(), backend.namer.operatorIs(element)); |
| 2235 if (backend.emitter.nativeEmitter.requiresNativeIsCheck(element)) { | 2235 if (backend.emitter.nativeEmitter.requiresNativeIsCheck(element)) { |
| 2236 push(new js.Call(field, <js.Expression>[])); | 2236 push(new js.Call(field, <js.Expression>[])); |
| 2237 if (negative) push(new js.Prefix('!', pop())); | 2237 if (negative) push(new js.Prefix('!', pop())); |
| 2238 } else { | 2238 } else { |
| 2239 // We always negate at least once so that the result is boolified. | 2239 // We always negate at least once so that the result is boolified. |
| 2240 push(new js.Prefix('!', field)); | 2240 push(new js.Prefix('!', field)); |
| 2241 // If the result is not negated, put another '!' in front. | 2241 // If the result is not negated, put another '!' in front. |
| 2242 if (!negative) push(new js.Prefix('!', pop())); | 2242 if (!negative) push(new js.Prefix('!', pop())); |
| 2243 } | 2243 } |
| 2244 } | 2244 } |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2397 currentContainer = body; | 2397 currentContainer = body; |
| 2398 generateThrowWithHelper('iae', node.checkedInput); | 2398 generateThrowWithHelper('iae', node.checkedInput); |
| 2399 currentContainer = oldContainer; | 2399 currentContainer = oldContainer; |
| 2400 body = unwrapStatement(body); | 2400 body = unwrapStatement(body); |
| 2401 pushStatement(new js.If.noElse(test, body), node); | 2401 pushStatement(new js.If.noElse(test, body), node); |
| 2402 return; | 2402 return; |
| 2403 } | 2403 } |
| 2404 | 2404 |
| 2405 assert(node.isCheckedModeCheck || node.isCastTypeCheck); | 2405 assert(node.isCheckedModeCheck || node.isCastTypeCheck); |
| 2406 SourceString helper = backend.getCheckedModeHelper(type); | 2406 SourceString helper = backend.getCheckedModeHelper(type); |
| 2407 String additionalArgument = compiler.namer.operatorIs(element); | 2407 String additionalArgument = backend.namer.operatorIs(element); |
| 2408 if (node.isCastTypeCheck) { | 2408 if (node.isCastTypeCheck) { |
| 2409 helper = castNames[helper.stringValue]; | 2409 helper = castNames[helper.stringValue]; |
| 2410 } | 2410 } |
| 2411 Element helperElement = compiler.findHelper(helper); | 2411 Element helperElement = compiler.findHelper(helper); |
| 2412 world.registerStaticUse(helperElement); | 2412 world.registerStaticUse(helperElement); |
| 2413 List<js.Expression> arguments = <js.Expression>[]; | 2413 List<js.Expression> arguments = <js.Expression>[]; |
| 2414 use(node.checkedInput); | 2414 use(node.checkedInput); |
| 2415 arguments.add(pop()); | 2415 arguments.add(pop()); |
| 2416 arguments.add(new js.LiteralString("'$additionalArgument'")); | 2416 arguments.add(new js.LiteralString("'$additionalArgument'")); |
| 2417 String helperName = compiler.namer.isolateAccess(helperElement); | 2417 String helperName = backend.namer.isolateAccess(helperElement); |
| 2418 push(new js.Call(new js.VariableUse(helperName), arguments)); | 2418 push(new js.Call(new js.VariableUse(helperName), arguments)); |
| 2419 } else { | 2419 } else { |
| 2420 use(node.checkedInput); | 2420 use(node.checkedInput); |
| 2421 } | 2421 } |
| 2422 } | 2422 } |
| 2423 } | 2423 } |
| 2424 | 2424 |
| 2425 class SsaOptimizedCodeGenerator extends SsaCodeGenerator { | 2425 class SsaOptimizedCodeGenerator extends SsaCodeGenerator { |
| 2426 SsaOptimizedCodeGenerator(backend, work, parameters, parameterNames) | 2426 SsaOptimizedCodeGenerator(backend, work, parameters, parameterNames) |
| 2427 : super(backend, work, parameterNames) { | 2427 : super(backend, work, parameterNames) { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 2443 work.guards.forEach((HTypeGuard workGuard) { | 2443 work.guards.forEach((HTypeGuard workGuard) { |
| 2444 HBailoutTarget target = workGuard.bailoutTarget; | 2444 HBailoutTarget target = workGuard.bailoutTarget; |
| 2445 int inputLength = target.inputs.length; | 2445 int inputLength = target.inputs.length; |
| 2446 if (inputLength > maxBailoutParameters) { | 2446 if (inputLength > maxBailoutParameters) { |
| 2447 maxBailoutParameters = inputLength; | 2447 maxBailoutParameters = inputLength; |
| 2448 } | 2448 } |
| 2449 }); | 2449 }); |
| 2450 } | 2450 } |
| 2451 HInstruction input = guard.guarded; | 2451 HInstruction input = guard.guarded; |
| 2452 HBailoutTarget target = guard.bailoutTarget; | 2452 HBailoutTarget target = guard.bailoutTarget; |
| 2453 Namer namer = compiler.namer; | 2453 Namer namer = backend.namer; |
| 2454 Element element = work.element; | 2454 Element element = work.element; |
| 2455 List<js.Expression> arguments = <js.Expression>[]; | 2455 List<js.Expression> arguments = <js.Expression>[]; |
| 2456 arguments.add(new js.LiteralNumber("${guard.state}")); | 2456 arguments.add(new js.LiteralNumber("${guard.state}")); |
| 2457 // TODO(ngeoffray): try to put a variable at a deterministic | 2457 // TODO(ngeoffray): try to put a variable at a deterministic |
| 2458 // location, so that multiple bailout calls put the variable at | 2458 // location, so that multiple bailout calls put the variable at |
| 2459 // the same parameter index. | 2459 // the same parameter index. |
| 2460 int i = 0; | 2460 int i = 0; |
| 2461 for (; i < target.inputs.length; i++) { | 2461 for (; i < target.inputs.length; i++) { |
| 2462 assert(guard.inputs.indexOf(target.inputs[i]) >= 0); | 2462 assert(guard.inputs.indexOf(target.inputs[i]) >= 0); |
| 2463 use(target.inputs[i]); | 2463 use(target.inputs[i]); |
| (...skipping 470 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2934 if (leftType.canBeNull() && rightType.canBeNull()) { | 2934 if (leftType.canBeNull() && rightType.canBeNull()) { |
| 2935 if (left.isConstantNull() || right.isConstantNull() || | 2935 if (left.isConstantNull() || right.isConstantNull() || |
| 2936 (leftType.isPrimitive() && leftType == rightType)) { | 2936 (leftType.isPrimitive() && leftType == rightType)) { |
| 2937 return '=='; | 2937 return '=='; |
| 2938 } | 2938 } |
| 2939 return null; | 2939 return null; |
| 2940 } else { | 2940 } else { |
| 2941 return '==='; | 2941 return '==='; |
| 2942 } | 2942 } |
| 2943 } | 2943 } |
| OLD | NEW |