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 part of ssa; | 5 part of ssa; |
6 | 6 |
7 class SsaCodeGeneratorTask extends CompilerTask { | 7 class SsaCodeGeneratorTask extends CompilerTask { |
8 | 8 |
9 final JavaScriptBackend backend; | 9 final JavaScriptBackend backend; |
10 final SourceInformationFactory sourceInformationFactory; | 10 final SourceInformationFactory sourceInformationFactory; |
(...skipping 1475 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1486 if (node.isConditionalConstantInterceptor) { | 1486 if (node.isConditionalConstantInterceptor) { |
1487 assert(node.inputs.length == 2); | 1487 assert(node.inputs.length == 2); |
1488 use(node.receiver); | 1488 use(node.receiver); |
1489 js.Expression receiverExpression = pop(); | 1489 js.Expression receiverExpression = pop(); |
1490 use(node.conditionalConstantInterceptor); | 1490 use(node.conditionalConstantInterceptor); |
1491 js.Expression constant = pop(); | 1491 js.Expression constant = pop(); |
1492 push(js.js('# && #', [receiverExpression, constant])); | 1492 push(js.js('# && #', [receiverExpression, constant])); |
1493 } else { | 1493 } else { |
1494 assert(node.inputs.length == 1); | 1494 assert(node.inputs.length == 1); |
1495 registry.registerSpecializedGetInterceptor(node.interceptedClasses); | 1495 registry.registerSpecializedGetInterceptor(node.interceptedClasses); |
1496 String name = | 1496 js.Name name = |
1497 backend.namer.nameForGetInterceptor(node.interceptedClasses); | 1497 backend.namer.nameForGetInterceptor(node.interceptedClasses); |
1498 var isolate = new js.VariableUse( | 1498 var isolate = new js.VariableUse( |
1499 backend.namer.globalObjectFor(backend.interceptorsLibrary)); | 1499 backend.namer.globalObjectFor(backend.interceptorsLibrary)); |
1500 use(node.receiver); | 1500 use(node.receiver); |
1501 List<js.Expression> arguments = <js.Expression>[pop()]; | 1501 List<js.Expression> arguments = <js.Expression>[pop()]; |
1502 push(js.propertyCall(isolate, name, arguments), node); | 1502 push(js.propertyCall(isolate, name, arguments), node); |
1503 registry.registerUseInterceptor(); | 1503 registry.registerUseInterceptor(); |
1504 } | 1504 } |
1505 } | 1505 } |
1506 | 1506 |
1507 visitInvokeDynamicMethod(HInvokeDynamicMethod node) { | 1507 visitInvokeDynamicMethod(HInvokeDynamicMethod node) { |
1508 use(node.receiver); | 1508 use(node.receiver); |
1509 js.Expression object = pop(); | 1509 js.Expression object = pop(); |
1510 String methodName; | 1510 String methodName; |
1511 List<js.Expression> arguments = visitArguments(node.inputs); | 1511 List<js.Expression> arguments = visitArguments(node.inputs); |
1512 Element target = node.element; | 1512 Element target = node.element; |
1513 | 1513 |
| 1514 // TODO(herhut): The namer should return the appropriate backendname here. |
1514 if (target != null && !node.isInterceptedCall) { | 1515 if (target != null && !node.isInterceptedCall) { |
1515 if (target == backend.jsArrayAdd) { | 1516 if (target == backend.jsArrayAdd) { |
1516 methodName = 'push'; | 1517 methodName = 'push'; |
1517 } else if (target == backend.jsArrayRemoveLast) { | 1518 } else if (target == backend.jsArrayRemoveLast) { |
1518 methodName = 'pop'; | 1519 methodName = 'pop'; |
1519 } else if (target == backend.jsStringSplit) { | 1520 } else if (target == backend.jsStringSplit) { |
1520 methodName = 'split'; | 1521 methodName = 'split'; |
1521 // Split returns a List, so we make sure the backend knows the | 1522 // Split returns a List, so we make sure the backend knows the |
1522 // list class is instantiated. | 1523 // list class is instantiated. |
1523 registry.registerInstantiatedClass(compiler.listClass); | 1524 registry.registerInstantiatedClass(compiler.listClass); |
1524 } else if (target.isNative && target.isFunction | 1525 } else if (target.isNative && target.isFunction |
1525 && !node.isInterceptedCall) { | 1526 && !node.isInterceptedCall) { |
1526 // A direct (i.e. non-interceptor) native call is the result of | 1527 // A direct (i.e. non-interceptor) native call is the result of |
1527 // optimization. The optimization ensures any type checks or | 1528 // optimization. The optimization ensures any type checks or |
1528 // conversions have been satisified. | 1529 // conversions have been satisified. |
1529 methodName = target.fixedBackendName; | 1530 methodName = target.fixedBackendName; |
1530 } | 1531 } |
1531 } | 1532 } |
1532 | 1533 |
| 1534 js.Name methodLiteral; |
1533 if (methodName == null) { | 1535 if (methodName == null) { |
1534 methodName = backend.namer.invocationName(node.selector); | 1536 methodLiteral = backend.namer.invocationName(node.selector); |
1535 registerMethodInvoke(node); | 1537 registerMethodInvoke(node); |
| 1538 } else { |
| 1539 methodLiteral = backend.namer.asName(methodName); |
1536 } | 1540 } |
1537 push(js.propertyCall(object, methodName, arguments), node); | 1541 push(js.propertyCall(object, methodLiteral, arguments), node); |
1538 } | 1542 } |
1539 | 1543 |
1540 void visitInvokeConstructorBody(HInvokeConstructorBody node) { | 1544 void visitInvokeConstructorBody(HInvokeConstructorBody node) { |
1541 use(node.inputs[0]); | 1545 use(node.inputs[0]); |
1542 js.Expression object = pop(); | 1546 js.Expression object = pop(); |
1543 String methodName = backend.namer.instanceMethodName(node.element); | 1547 js.Name methodName = backend.namer.instanceMethodName(node.element); |
1544 List<js.Expression> arguments = visitArguments(node.inputs); | 1548 List<js.Expression> arguments = visitArguments(node.inputs); |
1545 push(js.propertyCall(object, methodName, arguments), node); | 1549 push(js.propertyCall(object, methodName, arguments), node); |
1546 registry.registerStaticUse(node.element); | 1550 registry.registerStaticUse(node.element); |
1547 } | 1551 } |
1548 | 1552 |
1549 void visitOneShotInterceptor(HOneShotInterceptor node) { | 1553 void visitOneShotInterceptor(HOneShotInterceptor node) { |
1550 List<js.Expression> arguments = visitArguments(node.inputs); | 1554 List<js.Expression> arguments = visitArguments(node.inputs); |
1551 var isolate = new js.VariableUse( | 1555 var isolate = new js.VariableUse( |
1552 backend.namer.globalObjectFor(backend.interceptorsLibrary)); | 1556 backend.namer.globalObjectFor(backend.interceptorsLibrary)); |
1553 Selector selector = node.selector; | 1557 Selector selector = node.selector; |
1554 TypeMask mask = getOptimizedSelectorFor(node, selector, node.mask); | 1558 TypeMask mask = getOptimizedSelectorFor(node, selector, node.mask); |
1555 String methodName = backend.registerOneShotInterceptor(selector); | 1559 js.Name methodName = backend.registerOneShotInterceptor(selector); |
1556 push(js.propertyCall(isolate, methodName, arguments), node); | 1560 push(js.propertyCall(isolate, methodName, arguments), node); |
1557 if (selector.isGetter) { | 1561 if (selector.isGetter) { |
1558 registerGetter(node); | 1562 registerGetter(node); |
1559 } else if (selector.isSetter) { | 1563 } else if (selector.isSetter) { |
1560 registerSetter(node); | 1564 registerSetter(node); |
1561 } else { | 1565 } else { |
1562 registerMethodInvoke(node); | 1566 registerMethodInvoke(node); |
1563 } | 1567 } |
1564 registry.registerUseInterceptor(); | 1568 registry.registerUseInterceptor(); |
1565 } | 1569 } |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1610 | 1614 |
1611 void registerGetter(HInvokeDynamic node) { | 1615 void registerGetter(HInvokeDynamic node) { |
1612 Selector selector = node.selector; | 1616 Selector selector = node.selector; |
1613 TypeMask mask = getOptimizedSelectorFor(node, selector, node.mask); | 1617 TypeMask mask = getOptimizedSelectorFor(node, selector, node.mask); |
1614 registry.registerDynamicGetter( | 1618 registry.registerDynamicGetter( |
1615 new UniverseSelector(selector, mask)); | 1619 new UniverseSelector(selector, mask)); |
1616 } | 1620 } |
1617 | 1621 |
1618 visitInvokeDynamicSetter(HInvokeDynamicSetter node) { | 1622 visitInvokeDynamicSetter(HInvokeDynamicSetter node) { |
1619 use(node.receiver); | 1623 use(node.receiver); |
1620 String name = backend.namer.invocationName(node.selector); | 1624 js.Name name = backend.namer.invocationName(node.selector); |
1621 push(js.propertyCall(pop(), name, visitArguments(node.inputs)), node); | 1625 push(js.propertyCall(pop(), name, visitArguments(node.inputs)), node); |
1622 registerSetter(node); | 1626 registerSetter(node); |
1623 } | 1627 } |
1624 | 1628 |
1625 visitInvokeDynamicGetter(HInvokeDynamicGetter node) { | 1629 visitInvokeDynamicGetter(HInvokeDynamicGetter node) { |
1626 use(node.receiver); | 1630 use(node.receiver); |
1627 String name = backend.namer.invocationName(node.selector); | 1631 js.Name name = backend.namer.invocationName(node.selector); |
1628 push(js.propertyCall(pop(), name, visitArguments(node.inputs)), node); | 1632 push(js.propertyCall(pop(), name, visitArguments(node.inputs)), node); |
1629 registerGetter(node); | 1633 registerGetter(node); |
1630 } | 1634 } |
1631 | 1635 |
1632 visitInvokeClosure(HInvokeClosure node) { | 1636 visitInvokeClosure(HInvokeClosure node) { |
1633 Selector call = new Selector.callClosureFrom(node.selector); | 1637 Selector call = new Selector.callClosureFrom(node.selector); |
1634 use(node.receiver); | 1638 use(node.receiver); |
1635 push(js.propertyCall(pop(), | 1639 push(js.propertyCall(pop(), |
1636 backend.namer.invocationName(call), | 1640 backend.namer.invocationName(call), |
1637 visitArguments(node.inputs)), | 1641 visitArguments(node.inputs)), |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1680 push(new js.Call(pop(), arguments), node); | 1684 push(new js.Call(pop(), arguments), node); |
1681 } | 1685 } |
1682 | 1686 |
1683 } | 1687 } |
1684 | 1688 |
1685 visitInvokeSuper(HInvokeSuper node) { | 1689 visitInvokeSuper(HInvokeSuper node) { |
1686 Element superMethod = node.element; | 1690 Element superMethod = node.element; |
1687 registry.registerSuperInvocation(superMethod); | 1691 registry.registerSuperInvocation(superMethod); |
1688 ClassElement superClass = superMethod.enclosingClass; | 1692 ClassElement superClass = superMethod.enclosingClass; |
1689 if (superMethod.kind == ElementKind.FIELD) { | 1693 if (superMethod.kind == ElementKind.FIELD) { |
1690 String fieldName = backend.namer.instanceFieldPropertyName(superMethod); | 1694 js.Name fieldName = |
| 1695 backend.namer.instanceFieldPropertyName(superMethod); |
1691 use(node.inputs[0]); | 1696 use(node.inputs[0]); |
1692 js.PropertyAccess access = | 1697 js.PropertyAccess access = new js.PropertyAccess(pop(), fieldName); |
1693 new js.PropertyAccess.field(pop(), fieldName); | |
1694 if (node.isSetter) { | 1698 if (node.isSetter) { |
1695 use(node.value); | 1699 use(node.value); |
1696 push(new js.Assignment(access, pop()), node); | 1700 push(new js.Assignment(access, pop()), node); |
1697 } else { | 1701 } else { |
1698 push(access, node); | 1702 push(access, node); |
1699 } | 1703 } |
1700 } else { | 1704 } else { |
1701 Selector selector = node.selector; | 1705 Selector selector = node.selector; |
1702 | 1706 |
1703 if (!backend.maybeRegisterAliasedSuperMember(superMethod, selector)) { | 1707 if (!backend.maybeRegisterAliasedSuperMember(superMethod, selector)) { |
1704 String methodName; | 1708 js.Name methodName; |
1705 if (selector.isGetter) { | 1709 if (selector.isGetter) { |
1706 // If the selector we need to register a typed getter to the | 1710 // If the selector we need to register a typed getter to the |
1707 // [world]. The emitter needs to know if it needs to emit a | 1711 // [world]. The emitter needs to know if it needs to emit a |
1708 // bound closure for a method. | 1712 // bound closure for a method. |
1709 TypeMask receiverType = | 1713 TypeMask receiverType = |
1710 new TypeMask.nonNullExact(superClass, compiler.world); | 1714 new TypeMask.nonNullExact(superClass, compiler.world); |
1711 // TODO(floitsch): we know the target. We shouldn't register a | 1715 // TODO(floitsch): we know the target. We shouldn't register a |
1712 // dynamic getter. | 1716 // dynamic getter. |
1713 registry.registerDynamicGetter( | 1717 registry.registerDynamicGetter( |
1714 new UniverseSelector(selector, receiverType)); | 1718 new UniverseSelector(selector, receiverType)); |
(...skipping 26 matching lines...) Expand all Loading... |
1741 // We access a JavaScript member we know all objects besides | 1745 // We access a JavaScript member we know all objects besides |
1742 // null and undefined have: V8 does not like accessing a member | 1746 // null and undefined have: V8 does not like accessing a member |
1743 // that does not exist. | 1747 // that does not exist. |
1744 push(new js.PropertyAccess.field(pop(), 'toString'), node); | 1748 push(new js.PropertyAccess.field(pop(), 'toString'), node); |
1745 } else if (element == backend.jsIndexableLength) { | 1749 } else if (element == backend.jsIndexableLength) { |
1746 // We're accessing a native JavaScript property called 'length' | 1750 // We're accessing a native JavaScript property called 'length' |
1747 // on a JS String or a JS array. Therefore, the name of that | 1751 // on a JS String or a JS array. Therefore, the name of that |
1748 // property should not be mangled. | 1752 // property should not be mangled. |
1749 push(new js.PropertyAccess.field(pop(), 'length'), node); | 1753 push(new js.PropertyAccess.field(pop(), 'length'), node); |
1750 } else { | 1754 } else { |
1751 String name = backend.namer.instanceFieldPropertyName(element); | 1755 js.Name name = backend.namer.instanceFieldPropertyName(element); |
1752 push(new js.PropertyAccess.field(pop(), name), node); | 1756 push(new js.PropertyAccess(pop(), name), node); |
1753 registry.registerFieldGetter(element); | 1757 registry.registerFieldGetter(element); |
1754 } | 1758 } |
1755 } | 1759 } |
1756 | 1760 |
1757 visitFieldSet(HFieldSet node) { | 1761 visitFieldSet(HFieldSet node) { |
1758 Element element = node.element; | 1762 Element element = node.element; |
1759 registry.registerFieldSetter(element); | 1763 registry.registerFieldSetter(element); |
1760 String name = backend.namer.instanceFieldPropertyName(element); | 1764 js.Name name = backend.namer.instanceFieldPropertyName(element); |
1761 use(node.receiver); | 1765 use(node.receiver); |
1762 js.Expression receiver = pop(); | 1766 js.Expression receiver = pop(); |
1763 use(node.value); | 1767 use(node.value); |
1764 push(new js.Assignment(new js.PropertyAccess.field(receiver, name), pop()), | 1768 push(new js.Assignment(new js.PropertyAccess(receiver, name), pop()), |
1765 node); | 1769 node); |
1766 } | 1770 } |
1767 | 1771 |
1768 visitReadModifyWrite(HReadModifyWrite node) { | 1772 visitReadModifyWrite(HReadModifyWrite node) { |
1769 Element element = node.element; | 1773 Element element = node.element; |
1770 registry.registerFieldSetter(element); | 1774 registry.registerFieldSetter(element); |
1771 String name = backend.namer.instanceFieldPropertyName(element); | 1775 js.Name name = backend.namer.instanceFieldPropertyName(element); |
1772 use(node.receiver); | 1776 use(node.receiver); |
1773 js.Expression fieldReference = new js.PropertyAccess.field(pop(), name); | 1777 js.Expression fieldReference = new js.PropertyAccess(pop(), name); |
1774 if (node.isPreOp) { | 1778 if (node.isPreOp) { |
1775 push(new js.Prefix(node.jsOp, fieldReference), node); | 1779 push(new js.Prefix(node.jsOp, fieldReference), node); |
1776 } else if (node.isPostOp) { | 1780 } else if (node.isPostOp) { |
1777 push(new js.Postfix(node.jsOp, fieldReference), node); | 1781 push(new js.Postfix(node.jsOp, fieldReference), node); |
1778 } else { | 1782 } else { |
1779 use(node.value); | 1783 use(node.value); |
1780 push(new js.Assignment.compound(fieldReference, node.jsOp, pop()), node); | 1784 push(new js.Assignment.compound(fieldReference, node.jsOp, pop()), node); |
1781 } | 1785 } |
1782 } | 1786 } |
1783 | 1787 |
(...skipping 573 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2357 checkTypeViaProperty(input, type, negative); | 2361 checkTypeViaProperty(input, type, negative); |
2358 } | 2362 } |
2359 } | 2363 } |
2360 | 2364 |
2361 void checkTypeViaProperty(HInstruction input, DartType type, bool negative) { | 2365 void checkTypeViaProperty(HInstruction input, DartType type, bool negative) { |
2362 registry.registerIsCheck(type); | 2366 registry.registerIsCheck(type); |
2363 | 2367 |
2364 use(input); | 2368 use(input); |
2365 | 2369 |
2366 js.PropertyAccess field = | 2370 js.PropertyAccess field = |
2367 new js.PropertyAccess.field(pop(), backend.namer.operatorIsType(type)); | 2371 new js.PropertyAccess(pop(), backend.namer.operatorIsType(type)); |
2368 // We always negate at least once so that the result is boolified. | 2372 // We always negate at least once so that the result is boolified. |
2369 push(new js.Prefix('!', field)); | 2373 push(new js.Prefix('!', field)); |
2370 // If the result is not negated, put another '!' in front. | 2374 // If the result is not negated, put another '!' in front. |
2371 if (!negative) push(new js.Prefix('!', pop())); | 2375 if (!negative) push(new js.Prefix('!', pop())); |
2372 } | 2376 } |
2373 | 2377 |
2374 void checkTypeViaInstanceof( | 2378 void checkTypeViaInstanceof( |
2375 HInstruction input, DartType type, bool negative) { | 2379 HInstruction input, DartType type, bool negative) { |
2376 registry.registerIsCheck(type); | 2380 registry.registerIsCheck(type); |
2377 | 2381 |
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2588 node.checkedInput.isIntegerOrNull(compiler)); | 2592 node.checkedInput.isIntegerOrNull(compiler)); |
2589 js.Expression test = generateReceiverOrArgumentTypeTest( | 2593 js.Expression test = generateReceiverOrArgumentTypeTest( |
2590 node.checkedInput, node.checkedType); | 2594 node.checkedInput, node.checkedType); |
2591 js.Block oldContainer = currentContainer; | 2595 js.Block oldContainer = currentContainer; |
2592 js.Statement body = new js.Block.empty(); | 2596 js.Statement body = new js.Block.empty(); |
2593 currentContainer = body; | 2597 currentContainer = body; |
2594 if (node.isArgumentTypeCheck) { | 2598 if (node.isArgumentTypeCheck) { |
2595 generateThrowWithHelper('iae', node.checkedInput); | 2599 generateThrowWithHelper('iae', node.checkedInput); |
2596 } else if (node.isReceiverTypeCheck) { | 2600 } else if (node.isReceiverTypeCheck) { |
2597 use(node.checkedInput); | 2601 use(node.checkedInput); |
2598 String methodName = | 2602 js.Name methodName = |
2599 backend.namer.invocationName(node.receiverTypeCheckSelector); | 2603 backend.namer.invocationName(node.receiverTypeCheckSelector); |
2600 js.Expression call = js.propertyCall(pop(), methodName, []); | 2604 js.Expression call = js.propertyCall(pop(), methodName, []); |
2601 pushStatement(new js.Return(call)); | 2605 pushStatement(new js.Return(call)); |
2602 } | 2606 } |
2603 currentContainer = oldContainer; | 2607 currentContainer = oldContainer; |
2604 body = unwrapStatement(body); | 2608 body = unwrapStatement(body); |
2605 pushStatement(new js.If.noElse(test, body), node); | 2609 pushStatement(new js.If.noElse(test, body), node); |
2606 return; | 2610 return; |
2607 } | 2611 } |
2608 | 2612 |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2735 js.PropertyAccess accessHelper(String name) { | 2739 js.PropertyAccess accessHelper(String name) { |
2736 Element helper = backend.findHelper(name); | 2740 Element helper = backend.findHelper(name); |
2737 if (helper == null) { | 2741 if (helper == null) { |
2738 // For mocked-up tests. | 2742 // For mocked-up tests. |
2739 return js.js('(void 0).$name'); | 2743 return js.js('(void 0).$name'); |
2740 } | 2744 } |
2741 registry.registerStaticUse(helper); | 2745 registry.registerStaticUse(helper); |
2742 return backend.emitter.staticFunctionAccess(helper); | 2746 return backend.emitter.staticFunctionAccess(helper); |
2743 } | 2747 } |
2744 } | 2748 } |
OLD | NEW |