| 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 | 10 |
| (...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 296 new SsaLiveIntervalBuilder(compiler, generateAtUseSite); | 296 new SsaLiveIntervalBuilder(compiler, generateAtUseSite); |
| 297 intervalBuilder.visitGraph(graph); | 297 intervalBuilder.visitGraph(graph); |
| 298 SsaVariableAllocator allocator = new SsaVariableAllocator( | 298 SsaVariableAllocator allocator = new SsaVariableAllocator( |
| 299 compiler, | 299 compiler, |
| 300 intervalBuilder.liveInstructions, | 300 intervalBuilder.liveInstructions, |
| 301 intervalBuilder.liveIntervals, | 301 intervalBuilder.liveIntervals, |
| 302 generateAtUseSite); | 302 generateAtUseSite); |
| 303 allocator.visitGraph(graph); | 303 allocator.visitGraph(graph); |
| 304 variableNames = allocator.names; | 304 variableNames = allocator.names; |
| 305 shouldGroupVarDeclarations = allocator.names.numberOfVariables > 1; | 305 shouldGroupVarDeclarations = allocator.names.numberOfVariables > 1; |
| 306 | |
| 307 // Don't register a return type for lazily initialized variables. | |
| 308 if (work.element is! FunctionElement) return; | |
| 309 | |
| 310 // Register return types to the backend. | |
| 311 graph.exit.predecessors.forEach((HBasicBlock block) { | |
| 312 HInstruction last = block.last; | |
| 313 assert(last is HGoto || last is HReturn || last is HThrow); | |
| 314 if (last is HReturn) { | |
| 315 backend.registerReturnType( | |
| 316 work.element, last.inputs[0].instructionType); | |
| 317 } else if (last is HGoto) { | |
| 318 backend.registerReturnType(work.element, HType.NULL); | |
| 319 } | |
| 320 }); | |
| 321 } | 306 } |
| 322 | 307 |
| 323 void handleDelayedVariableDeclarations() { | 308 void handleDelayedVariableDeclarations() { |
| 324 // If we have only one variable declaration and the first statement is an | 309 // If we have only one variable declaration and the first statement is an |
| 325 // assignment to that variable then we can merge the two. We count the | 310 // assignment to that variable then we can merge the two. We count the |
| 326 // number of variables in the variable allocator to try to avoid this issue, | 311 // number of variables in the variable allocator to try to avoid this issue, |
| 327 // but it sometimes happens that the variable allocator introduces a | 312 // but it sometimes happens that the variable allocator introduces a |
| 328 // temporary variable that it later eliminates. | 313 // temporary variable that it later eliminates. |
| 329 if (!collectedVariableDeclarations.isEmpty) { | 314 if (!collectedVariableDeclarations.isEmpty) { |
| 330 if (collectedVariableDeclarations.length == 1 && | 315 if (collectedVariableDeclarations.length == 1 && |
| (...skipping 1225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1556 } | 1541 } |
| 1557 | 1542 |
| 1558 void registerInvoke(HInvokeDynamic node, Selector selector) { | 1543 void registerInvoke(HInvokeDynamic node, Selector selector) { |
| 1559 if (node.isInterceptedCall) { | 1544 if (node.isInterceptedCall) { |
| 1560 backend.addInterceptedSelector(selector); | 1545 backend.addInterceptedSelector(selector); |
| 1561 } | 1546 } |
| 1562 } | 1547 } |
| 1563 | 1548 |
| 1564 void registerMethodInvoke(HInvokeDynamic node) { | 1549 void registerMethodInvoke(HInvokeDynamic node) { |
| 1565 Selector selector = getOptimizedSelectorFor(node, node.selector); | 1550 Selector selector = getOptimizedSelectorFor(node, node.selector); |
| 1566 // Register this invocation to collect the types used at all call sites. | |
| 1567 backend.registerDynamicInvocation(node, selector); | |
| 1568 | 1551 |
| 1569 // If we don't know what we're calling or if we are calling a getter, | 1552 // If we don't know what we're calling or if we are calling a getter, |
| 1570 // we need to register that fact that we may be calling a closure | 1553 // we need to register that fact that we may be calling a closure |
| 1571 // with the same arguments. | 1554 // with the same arguments. |
| 1572 Element target = node.element; | 1555 Element target = node.element; |
| 1573 if (target == null || target.isGetter()) { | 1556 if (target == null || target.isGetter()) { |
| 1574 // TODO(kasperl): If we have a typed selector for the call, we | 1557 // TODO(kasperl): If we have a typed selector for the call, we |
| 1575 // may know something about the types of closures that need | 1558 // may know something about the types of closures that need |
| 1576 // the specific closure call method. | 1559 // the specific closure call method. |
| 1577 Selector call = new Selector.callClosureFrom(selector); | 1560 Selector call = new Selector.callClosureFrom(selector); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1588 } | 1571 } |
| 1589 registerInvoke(node, selector); | 1572 registerInvoke(node, selector); |
| 1590 } | 1573 } |
| 1591 | 1574 |
| 1592 void registerSetter(HInvokeDynamic node) { | 1575 void registerSetter(HInvokeDynamic node) { |
| 1593 Selector selector = getOptimizedSelectorFor(node, node.selector); | 1576 Selector selector = getOptimizedSelectorFor(node, node.selector); |
| 1594 world.registerDynamicSetter(selector.name, selector); | 1577 world.registerDynamicSetter(selector.name, selector); |
| 1595 HType valueType = node.isInterceptedCall | 1578 HType valueType = node.isInterceptedCall |
| 1596 ? node.inputs[2].instructionType | 1579 ? node.inputs[2].instructionType |
| 1597 : node.inputs[1].instructionType; | 1580 : node.inputs[1].instructionType; |
| 1598 backend.addedDynamicSetter(selector, valueType); | |
| 1599 registerInvoke(node, selector); | 1581 registerInvoke(node, selector); |
| 1600 } | 1582 } |
| 1601 | 1583 |
| 1602 void registerGetter(HInvokeDynamic node) { | 1584 void registerGetter(HInvokeDynamic node) { |
| 1603 Selector selector = getOptimizedSelectorFor(node, node.selector); | 1585 Selector selector = getOptimizedSelectorFor(node, node.selector); |
| 1604 world.registerDynamicGetter(selector.name, selector); | 1586 world.registerDynamicGetter(selector.name, selector); |
| 1605 world.registerInstantiatedClass( | 1587 world.registerInstantiatedClass( |
| 1606 compiler.functionClass, work.resolutionTree); | 1588 compiler.functionClass, work.resolutionTree); |
| 1607 registerInvoke(node, selector); | 1589 registerInvoke(node, selector); |
| 1608 } | 1590 } |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1625 Selector call = new Selector.callClosureFrom(node.selector); | 1607 Selector call = new Selector.callClosureFrom(node.selector); |
| 1626 use(node.receiver); | 1608 use(node.receiver); |
| 1627 push(jsPropertyCall(pop(), | 1609 push(jsPropertyCall(pop(), |
| 1628 backend.namer.invocationName(call), | 1610 backend.namer.invocationName(call), |
| 1629 visitArguments(node.inputs)), | 1611 visitArguments(node.inputs)), |
| 1630 node); | 1612 node); |
| 1631 world.registerDynamicInvocation(call.name, call); | 1613 world.registerDynamicInvocation(call.name, call); |
| 1632 } | 1614 } |
| 1633 | 1615 |
| 1634 visitInvokeStatic(HInvokeStatic node) { | 1616 visitInvokeStatic(HInvokeStatic node) { |
| 1635 if (node.typeCode() == HInstruction.INVOKE_STATIC_TYPECODE) { | |
| 1636 // Register this invocation to collect the types used at all call sites. | |
| 1637 backend.registerStaticInvocation(node); | |
| 1638 } | |
| 1639 Element element = node.element; | 1617 Element element = node.element; |
| 1640 world.registerStaticUse(element); | 1618 world.registerStaticUse(element); |
| 1641 ClassElement cls = element.getEnclosingClass(); | 1619 ClassElement cls = element.getEnclosingClass(); |
| 1642 if (element.isGenerativeConstructor() | 1620 if (element.isGenerativeConstructor() |
| 1643 || (element.isFactoryConstructor() && cls == compiler.listClass)) { | 1621 || (element.isFactoryConstructor() && cls == compiler.listClass)) { |
| 1644 world.registerInstantiatedClass(cls, work.resolutionTree); | 1622 world.registerInstantiatedClass(cls, work.resolutionTree); |
| 1645 } | 1623 } |
| 1646 push(new js.VariableUse(backend.namer.isolateAccess(node.element))); | 1624 push(new js.VariableUse(backend.namer.isolateAccess(node.element))); |
| 1647 push(new js.Call(pop(), visitArguments(node.inputs, start: 0)), node); | 1625 push(new js.Call(pop(), visitArguments(node.inputs, start: 0)), node); |
| 1648 } | 1626 } |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1667 } else { | 1645 } else { |
| 1668 String methodName = backend.namer.getName(superMethod); | 1646 String methodName = backend.namer.getName(superMethod); |
| 1669 String className = backend.namer.isolateAccess(superClass); | 1647 String className = backend.namer.isolateAccess(superClass); |
| 1670 js.VariableUse classReference = new js.VariableUse(className); | 1648 js.VariableUse classReference = new js.VariableUse(className); |
| 1671 js.PropertyAccess prototype = | 1649 js.PropertyAccess prototype = |
| 1672 new js.PropertyAccess.field(classReference, "prototype"); | 1650 new js.PropertyAccess.field(classReference, "prototype"); |
| 1673 js.PropertyAccess method = | 1651 js.PropertyAccess method = |
| 1674 new js.PropertyAccess.field(prototype, methodName); | 1652 new js.PropertyAccess.field(prototype, methodName); |
| 1675 push(jsPropertyCall( | 1653 push(jsPropertyCall( |
| 1676 method, "call", visitArguments(node.inputs, start: 0)), node); | 1654 method, "call", visitArguments(node.inputs, start: 0)), node); |
| 1677 // Register this invocation to collect the types used at all call sites. | |
| 1678 backend.registerDynamicInvocation(node, node.selector); | |
| 1679 } | 1655 } |
| 1680 } | 1656 } |
| 1681 | 1657 |
| 1682 visitFieldGet(HFieldGet node) { | 1658 visitFieldGet(HFieldGet node) { |
| 1683 use(node.receiver); | 1659 use(node.receiver); |
| 1684 Element element = node.element; | 1660 Element element = node.element; |
| 1685 if (element == backend.jsIndexableLength) { | 1661 if (element == backend.jsIndexableLength) { |
| 1686 // We're accessing a native JavaScript property called 'length' | 1662 // We're accessing a native JavaScript property called 'length' |
| 1687 // on a JS String or a JS array. Therefore, the name of that | 1663 // on a JS String or a JS array. Therefore, the name of that |
| 1688 // property should not be mangled. | 1664 // property should not be mangled. |
| 1689 push(new js.PropertyAccess.field(pop(), 'length'), node); | 1665 push(new js.PropertyAccess.field(pop(), 'length'), node); |
| 1690 } else { | 1666 } else { |
| 1691 String name = _fieldPropertyName(element); | 1667 String name = _fieldPropertyName(element); |
| 1692 push(new js.PropertyAccess.field(pop(), name), node); | 1668 push(new js.PropertyAccess.field(pop(), name), node); |
| 1693 world.registerFieldGetter(element); | 1669 world.registerFieldGetter(element); |
| 1694 } | 1670 } |
| 1695 } | 1671 } |
| 1696 | 1672 |
| 1697 visitFieldSet(HFieldSet node) { | 1673 visitFieldSet(HFieldSet node) { |
| 1698 Element element = node.element; | 1674 Element element = node.element; |
| 1675 world.registerFieldSetter(element); |
| 1699 String name = _fieldPropertyName(element); | 1676 String name = _fieldPropertyName(element); |
| 1700 if (!node.receiver.instructionType.isUnknown()) { | |
| 1701 // Field setters in the generative constructor body are handled in a | |
| 1702 // step "SsaConstructionFieldTypes" in the ssa optimizer. | |
| 1703 if (!work.element.isGenerativeConstructorBody()) { | |
| 1704 world.registerFieldSetter(element); | |
| 1705 backend.registerFieldSetter( | |
| 1706 work.element, element, node.value.instructionType); | |
| 1707 } | |
| 1708 } | |
| 1709 use(node.receiver); | 1677 use(node.receiver); |
| 1710 js.Expression receiver = pop(); | 1678 js.Expression receiver = pop(); |
| 1711 use(node.value); | 1679 use(node.value); |
| 1712 push(new js.Assignment(new js.PropertyAccess.field(receiver, name), pop()), | 1680 push(new js.Assignment(new js.PropertyAccess.field(receiver, name), pop()), |
| 1713 node); | 1681 node); |
| 1714 } | 1682 } |
| 1715 | 1683 |
| 1716 String _fieldPropertyName(Element element) => element.hasFixedBackendName() | 1684 String _fieldPropertyName(Element element) => element.hasFixedBackendName() |
| 1717 ? element.fixedBackendName() | 1685 ? element.fixedBackendName() |
| 1718 : backend.namer.getName(element); | 1686 : backend.namer.getName(element); |
| (...skipping 294 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2013 push(value, node); | 1981 push(value, node); |
| 2014 } | 1982 } |
| 2015 | 1983 |
| 2016 void visitSwitch(HSwitch node) { | 1984 void visitSwitch(HSwitch node) { |
| 2017 // Switches are handled using [visitSwitchInfo]. | 1985 // Switches are handled using [visitSwitchInfo]. |
| 2018 } | 1986 } |
| 2019 | 1987 |
| 2020 void visitStatic(HStatic node) { | 1988 void visitStatic(HStatic node) { |
| 2021 Element element = node.element; | 1989 Element element = node.element; |
| 2022 if (element.isFunction()) { | 1990 if (element.isFunction()) { |
| 2023 backend.registerNonCallStaticUse(node); | |
| 2024 world.registerInstantiatedClass( | 1991 world.registerInstantiatedClass( |
| 2025 compiler.functionClass, work.resolutionTree); | 1992 compiler.functionClass, work.resolutionTree); |
| 2026 push(new js.VariableUse( | 1993 push(new js.VariableUse( |
| 2027 backend.namer.isolateStaticClosureAccess(node.element))); | 1994 backend.namer.isolateStaticClosureAccess(node.element))); |
| 2028 } else { | 1995 } else { |
| 2029 push(new js.VariableUse(backend.namer.isolateAccess(node.element))); | 1996 push(new js.VariableUse(backend.namer.isolateAccess(node.element))); |
| 2030 } | 1997 } |
| 2031 world.registerStaticUse(element); | 1998 world.registerStaticUse(element); |
| 2032 } | 1999 } |
| 2033 | 2000 |
| (...skipping 1002 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3036 if (leftType.canBeNull() && rightType.canBeNull()) { | 3003 if (leftType.canBeNull() && rightType.canBeNull()) { |
| 3037 if (left.isConstantNull() || right.isConstantNull() || | 3004 if (left.isConstantNull() || right.isConstantNull() || |
| 3038 (leftType.isPrimitive() && leftType == rightType)) { | 3005 (leftType.isPrimitive() && leftType == rightType)) { |
| 3039 return '=='; | 3006 return '=='; |
| 3040 } | 3007 } |
| 3041 return null; | 3008 return null; |
| 3042 } else { | 3009 } else { |
| 3043 return '==='; | 3010 return '==='; |
| 3044 } | 3011 } |
| 3045 } | 3012 } |
| OLD | NEW |