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

Side by Side Diff: pkg/compiler/lib/src/cps_ir/type_propagation.dart

Issue 1252883003: dart2js cps: Fix performance issues in optimization passes. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Update status file Created 5 years, 4 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
« no previous file with comments | « pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart ('k') | tests/co19/co19-dart2js.status » ('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) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, 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 import 'optimizers.dart'; 5 import 'optimizers.dart';
6 6
7 import '../constants/constant_system.dart'; 7 import '../constants/constant_system.dart';
8 import '../resolution/operators.dart'; 8 import '../resolution/operators.dart';
9 import '../constants/values.dart'; 9 import '../constants/values.dart';
10 import '../dart_types.dart' as types; 10 import '../dart_types.dart' as types;
(...skipping 537 matching lines...) Expand 10 before | Expand all | Expand 10 after
548 */ 548 */
549 class TransformingVisitor extends LeafVisitor { 549 class TransformingVisitor extends LeafVisitor {
550 final TypePropagationVisitor analyzer; 550 final TypePropagationVisitor analyzer;
551 final Map<Expression, ConstantValue> replacements; 551 final Map<Expression, ConstantValue> replacements;
552 final ConstantPropagationLattice lattice; 552 final ConstantPropagationLattice lattice;
553 final dart2js.Compiler compiler; 553 final dart2js.Compiler compiler;
554 554
555 JavaScriptBackend get backend => compiler.backend; 555 JavaScriptBackend get backend => compiler.backend;
556 TypeMaskSystem get typeSystem => lattice.typeSystem; 556 TypeMaskSystem get typeSystem => lattice.typeSystem;
557 types.DartTypes get dartTypes => lattice.dartTypes; 557 types.DartTypes get dartTypes => lattice.dartTypes;
558 Set<Node> get reachable => analyzer.reachableNodes;
559 Map<Node, AbstractValue> get values => analyzer.values; 558 Map<Node, AbstractValue> get values => analyzer.values;
560 559
561 final dart2js.InternalErrorFunction internalError; 560 final dart2js.InternalErrorFunction internalError;
562 561
563 final List<Node> stack = <Node>[]; 562 final List<Node> stack = <Node>[];
564 563
565 TransformingVisitor(this.compiler, 564 TransformingVisitor(this.compiler,
566 this.lattice, 565 this.lattice,
567 this.analyzer, 566 this.analyzer,
568 this.replacements, 567 this.replacements,
(...skipping 875 matching lines...) Expand 10 before | Expand all | Expand 10 after
1444 case AbstractBool.True: 1443 case AbstractBool.True:
1445 // Cast always succeeds, replace it with InvokeContinuation. 1444 // Cast always succeeds, replace it with InvokeContinuation.
1446 InvokeContinuation invoke = 1445 InvokeContinuation invoke =
1447 new InvokeContinuation(cont, <Primitive>[node.value.definition]); 1446 new InvokeContinuation(cont, <Primitive>[node.value.definition]);
1448 replaceSubtree(node, invoke); 1447 replaceSubtree(node, invoke);
1449 push(invoke); 1448 push(invoke);
1450 return; 1449 return;
1451 1450
1452 case AbstractBool.False: 1451 case AbstractBool.False:
1453 // Cast always fails, remove unreachable continuation body. 1452 // Cast always fails, remove unreachable continuation body.
1454 assert(!reachable.contains(cont));
1455 replaceSubtree(cont.body, new Unreachable()); 1453 replaceSubtree(cont.body, new Unreachable());
1456 break; 1454 break;
1457 } 1455 }
1458 } 1456 }
1459 1457
1460 /// Specialize calls to internal static methods. 1458 /// Specialize calls to internal static methods.
1461 /// 1459 ///
1462 /// Returns true if the call was replaced. 1460 /// Returns true if the call was replaced.
1463 bool specializeInternalMethodCall(InvokeStatic node) { 1461 bool specializeInternalMethodCall(InvokeStatic node) {
1464 // TODO(asgerf): This is written to easily scale to more cases, 1462 // TODO(asgerf): This is written to easily scale to more cases,
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after
1626 // The node worklist stores nodes that are both reachable and need to be 1624 // The node worklist stores nodes that are both reachable and need to be
1627 // processed, but have not been processed yet. Using a worklist avoids deep 1625 // processed, but have not been processed yet. Using a worklist avoids deep
1628 // recursion. 1626 // recursion.
1629 // The node worklist and the reachable set operate in concert: nodes are 1627 // The node worklist and the reachable set operate in concert: nodes are
1630 // only ever added to the worklist when they have not yet been marked as 1628 // only ever added to the worklist when they have not yet been marked as
1631 // reachable, and adding a node to the worklist is always followed by marking 1629 // reachable, and adding a node to the worklist is always followed by marking
1632 // it reachable. 1630 // it reachable.
1633 // TODO(jgruber): Storing reachability per-edge instead of per-node would 1631 // TODO(jgruber): Storing reachability per-edge instead of per-node would
1634 // allow for further optimizations. 1632 // allow for further optimizations.
1635 final List<Node> nodeWorklist = <Node>[]; 1633 final List<Node> nodeWorklist = <Node>[];
1636 final Set<Node> reachableNodes = new Set<Node>(); 1634 final Set<Continuation> reachableContinuations = new Set<Continuation>();
1637 1635
1638 // The definition workset stores all definitions which need to be reprocessed 1636 // The definition workset stores all definitions which need to be reprocessed
1639 // since their lattice value has changed. 1637 // since their lattice value has changed.
1640 final Set<Definition> defWorkset = new Set<Definition>(); 1638 final List<Definition> defWorklist = <Definition>[];
1641 1639
1642 final ConstantPropagationLattice lattice; 1640 final ConstantPropagationLattice lattice;
1643 final dart2js.InternalErrorFunction internalError; 1641 final dart2js.InternalErrorFunction internalError;
1644 1642
1645 TypeMaskSystem get typeSystem => lattice.typeSystem; 1643 TypeMaskSystem get typeSystem => lattice.typeSystem;
1646 1644
1647 AbstractValue get nothing => lattice.nothing; 1645 AbstractValue get nothing => lattice.nothing;
1648 1646
1649 AbstractValue nonConstant([TypeMask type]) => lattice.nonConstant(type); 1647 AbstractValue nonConstant([TypeMask type]) => lattice.nonConstant(type);
1650 1648
1651 AbstractValue constantValue(ConstantValue constant, [TypeMask type]) { 1649 AbstractValue constantValue(ConstantValue constant, [TypeMask type]) {
1652 return lattice.constant(constant, type); 1650 return lattice.constant(constant, type);
1653 } 1651 }
1654 1652
1655 // Stores the current lattice value for primitives and mutable variables. 1653 // Stores the current lattice value for primitives and mutable variables.
1656 // Access through [getValue] and [setValue]. 1654 // Access through [getValue] and [setValue].
1657 final Map<Definition, AbstractValue> values; 1655 final Map<Definition, AbstractValue> values;
1658 1656
1659 /// Expressions that invoke their call continuation with a constant value 1657 /// Expressions that invoke their call continuation with a constant value
1660 /// and without any side effects. These can be replaced by the constant. 1658 /// and without any side effects. These can be replaced by the constant.
1661 final Map<Expression, ConstantValue> replacements; 1659 final Map<Expression, ConstantValue> replacements;
1662 1660
1663 TypePropagationVisitor(this.lattice, 1661 TypePropagationVisitor(this.lattice,
1664 this.values, 1662 this.values,
1665 this.replacements, 1663 this.replacements,
1666 this.internalError); 1664 this.internalError);
1667 1665
1668 void analyze(FunctionDefinition root) { 1666 void analyze(FunctionDefinition root) {
1669 reachableNodes.clear(); 1667 reachableContinuations.clear();
1670 1668
1671 // Initially, only the root node is reachable. 1669 // Initially, only the root node is reachable.
1672 setReachable(root); 1670 push(root);
1673 1671
1674 iterateWorklist(); 1672 iterateWorklist();
1675 } 1673 }
1676 1674
1677 void reanalyzeSubtree(Node node) { 1675 void reanalyzeSubtree(Node node) {
1678 new ResetAnalysisInfo(reachableNodes, values).visit(node); 1676 new ResetAnalysisInfo(reachableContinuations, values).visit(node);
1679 setReachable(node); 1677 push(node);
1680 iterateWorklist(); 1678 iterateWorklist();
1681 } 1679 }
1682 1680
1683 void iterateWorklist() { 1681 void iterateWorklist() {
1684 while (true) { 1682 while (true) {
1685 if (nodeWorklist.isNotEmpty) { 1683 if (nodeWorklist.isNotEmpty) {
1686 // Process a new reachable expression. 1684 // Process a new reachable expression.
1687 Node node = nodeWorklist.removeLast(); 1685 Node node = nodeWorklist.removeLast();
1688 visit(node); 1686 visit(node);
1689 } else if (defWorkset.isNotEmpty) { 1687 } else if (defWorklist.isNotEmpty) {
1690 // Process all usages of a changed definition. 1688 // Process all usages of a changed definition.
1691 Definition def = defWorkset.first; 1689 Definition def = defWorklist.removeLast();
1692 defWorkset.remove(def);
1693 1690
1694 // Visit all uses of this definition. This might add new entries to 1691 // Visit all uses of this definition. This might add new entries to
1695 // [nodeWorklist], for example by visiting a newly-constant usage within 1692 // [nodeWorklist], for example by visiting a newly-constant usage within
1696 // a branch node. 1693 // a branch node.
1697 for (Reference ref = def.firstRef; ref != null; ref = ref.next) { 1694 for (Reference ref = def.firstRef; ref != null; ref = ref.next) {
1698 visit(ref.parent); 1695 visit(ref.parent);
1699 } 1696 }
1700 } else { 1697 } else {
1701 break; // Both worklists empty. 1698 break; // Both worklists empty.
1702 } 1699 }
1703 } 1700 }
1704 } 1701 }
1705 1702
1703 /// Adds [node] to the worklist.
1704 void push(Node node) {
1705 nodeWorklist.add(node);
1706 }
1707
1706 /// If the passed node is not yet reachable, mark it reachable and add it 1708 /// If the passed node is not yet reachable, mark it reachable and add it
1707 /// to the work list. 1709 /// to the work list.
1708 void setReachable(Node node) { 1710 void setReachable(Continuation cont) {
1709 if (!reachableNodes.contains(node)) { 1711 if (reachableContinuations.add(cont)) {
1710 reachableNodes.add(node); 1712 push(cont);
1711 nodeWorklist.add(node);
1712 } 1713 }
1713 } 1714 }
1714 1715
1715 /// Returns the lattice value corresponding to [node], defaulting to nothing. 1716 /// Returns the lattice value corresponding to [node], defaulting to nothing.
1716 /// 1717 ///
1717 /// Never returns null. 1718 /// Never returns null.
1718 AbstractValue getValue(Definition node) { 1719 AbstractValue getValue(Definition node) {
1719 AbstractValue value = values[node]; 1720 AbstractValue value = values[node];
1720 return (value == null) ? nothing : value; 1721 return (value == null) ? nothing : value;
1721 } 1722 }
1722 1723
1723 /// Joins the passed lattice [updateValue] to the current value of [node], 1724 /// Joins the passed lattice [updateValue] to the current value of [node],
1724 /// and adds it to the definition work set if it has changed and [node] is 1725 /// and adds it to the definition work set if it has changed and [node] is
1725 /// a definition. 1726 /// a definition.
1726 void setValue(Definition node, AbstractValue updateValue) { 1727 void setValue(Definition node, AbstractValue updateValue) {
1727 AbstractValue oldValue = getValue(node); 1728 AbstractValue oldValue = getValue(node);
1728 AbstractValue newValue = lattice.join(oldValue, updateValue); 1729 AbstractValue newValue = lattice.join(oldValue, updateValue);
1729 if (oldValue == newValue) { 1730 if (oldValue == newValue) {
1730 return; 1731 return;
1731 } 1732 }
1732 1733
1733 // Values may only move in the direction NOTHING -> CONSTANT -> NONCONST. 1734 // Values may only move in the direction NOTHING -> CONSTANT -> NONCONST.
1734 assert(newValue.kind >= oldValue.kind); 1735 assert(newValue.kind >= oldValue.kind);
1735 1736
1736 values[node] = newValue; 1737 values[node] = newValue;
1737 defWorkset.add(node); 1738 defWorklist.add(node);
1738 } 1739 }
1739 1740
1740 // -------------------------- Visitor overrides ------------------------------ 1741 // -------------------------- Visitor overrides ------------------------------
1741 void visit(Node node) { node.accept(this); } 1742 void visit(Node node) { node.accept(this); }
1742 1743
1743 void visitFunctionDefinition(FunctionDefinition node) { 1744 void visitFunctionDefinition(FunctionDefinition node) {
1744 if (node.thisParameter != null) { 1745 if (node.thisParameter != null) {
1745 setValue(node.thisParameter, 1746 setValue(node.thisParameter,
1746 nonConstant(typeSystem.getReceiverType(node.element))); 1747 nonConstant(typeSystem.getReceiverType(node.element)));
1747 } 1748 }
1748 node.parameters.forEach(visit); 1749 node.parameters.forEach(visit);
1749 setReachable(node.body); 1750 push(node.body);
1750 } 1751 }
1751 1752
1752 void visitLetPrim(LetPrim node) { 1753 void visitLetPrim(LetPrim node) {
1753 visit(node.primitive); // No reason to delay visits to primitives. 1754 visit(node.primitive); // No reason to delay visits to primitives.
1754 setReachable(node.body); 1755 push(node.body);
1755 } 1756 }
1756 1757
1757 void visitLetCont(LetCont node) { 1758 void visitLetCont(LetCont node) {
1758 // The continuation is only marked as reachable on use. 1759 // The continuation is only marked as reachable on use.
1759 setReachable(node.body); 1760 push(node.body);
1760 } 1761 }
1761 1762
1762 void visitLetHandler(LetHandler node) { 1763 void visitLetHandler(LetHandler node) {
1763 setReachable(node.body); 1764 push(node.body);
1764 // The handler is assumed to be reachable (we could instead treat it as 1765 // The handler is assumed to be reachable (we could instead treat it as
1765 // unreachable unless we find something reachable that might throw in the 1766 // unreachable unless we find something reachable that might throw in the
1766 // body --- it's not clear if we want to do that here or in some other 1767 // body --- it's not clear if we want to do that here or in some other
1767 // pass). The handler parameters are assumed to be unknown. 1768 // pass). The handler parameters are assumed to be unknown.
1768 // 1769 //
1769 // TODO(kmillikin): we should set the type of the exception and stack 1770 // TODO(kmillikin): we should set the type of the exception and stack
1770 // trace here. The way we do that depends on how we handle 'on T' catch 1771 // trace here. The way we do that depends on how we handle 'on T' catch
1771 // clauses. 1772 // clauses.
1772 setReachable(node.handler); 1773 setReachable(node.handler);
1773 for (Parameter param in node.handler.parameters) { 1774 for (Parameter param in node.handler.parameters) {
1774 setValue(param, nonConstant()); 1775 setValue(param, nonConstant());
1775 } 1776 }
1776 } 1777 }
1777 1778
1778 void visitLetMutable(LetMutable node) { 1779 void visitLetMutable(LetMutable node) {
1779 setValue(node.variable, getValue(node.value.definition)); 1780 setValue(node.variable, getValue(node.value.definition));
1780 setReachable(node.body); 1781 push(node.body);
1781 } 1782 }
1782 1783
1783 void visitInvokeStatic(InvokeStatic node) { 1784 void visitInvokeStatic(InvokeStatic node) {
1784 Continuation cont = node.continuation.definition; 1785 Continuation cont = node.continuation.definition;
1785 setReachable(cont); 1786 setReachable(cont);
1786 1787
1787 assert(cont.parameters.length == 1); 1788 assert(cont.parameters.length == 1);
1788 Parameter returnValue = cont.parameters[0]; 1789 Parameter returnValue = cont.parameters[0];
1789 1790
1790 /// Sets the value of the target continuation parameter, and possibly 1791 /// Sets the value of the target continuation parameter, and possibly
(...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after
2086 ConstantValue value = node.value; 2087 ConstantValue value = node.value;
2087 if (value.isDummy || !value.isConstant) { 2088 if (value.isDummy || !value.isConstant) {
2088 // TODO(asgerf): Explain how this happens and why we don't want them. 2089 // TODO(asgerf): Explain how this happens and why we don't want them.
2089 setValue(node, nonConstant(typeSystem.getTypeOf(value))); 2090 setValue(node, nonConstant(typeSystem.getTypeOf(value)));
2090 } else { 2091 } else {
2091 setValue(node, constantValue(value, typeSystem.getTypeOf(value))); 2092 setValue(node, constantValue(value, typeSystem.getTypeOf(value)));
2092 } 2093 }
2093 } 2094 }
2094 2095
2095 void visitCreateFunction(CreateFunction node) { 2096 void visitCreateFunction(CreateFunction node) {
2096 setReachable(node.definition); 2097 throw 'CreateFunction is not used';
2097 ConstantValue constant =
2098 new FunctionConstantValue(node.definition.element);
2099 setValue(node, constantValue(constant, typeSystem.functionType));
2100 } 2098 }
2101 2099
2102 void visitGetMutable(GetMutable node) { 2100 void visitGetMutable(GetMutable node) {
2103 setValue(node, getValue(node.variable.definition)); 2101 setValue(node, getValue(node.variable.definition));
2104 } 2102 }
2105 2103
2106 void visitMutableVariable(MutableVariable node) { 2104 void visitMutableVariable(MutableVariable node) {
2107 // [MutableVariable]s are bound either as parameters to 2105 // [MutableVariable]s are bound either as parameters to
2108 // [FunctionDefinition]s, by [LetMutable]. 2106 // [FunctionDefinition]s, by [LetMutable].
2109 if (node.parent is FunctionDefinition) { 2107 if (node.parent is FunctionDefinition) {
(...skipping 26 matching lines...) Expand all
2136 // some other abstract value than non-constant. 2134 // some other abstract value than non-constant.
2137 } else { 2135 } else {
2138 internalError(node.hint, "Unexpected parent of Parameter: ${node.parent}") ; 2136 internalError(node.hint, "Unexpected parent of Parameter: ${node.parent}") ;
2139 } 2137 }
2140 } 2138 }
2141 2139
2142 void visitContinuation(Continuation node) { 2140 void visitContinuation(Continuation node) {
2143 node.parameters.forEach(visit); 2141 node.parameters.forEach(visit);
2144 2142
2145 if (node.body != null) { 2143 if (node.body != null) {
2146 setReachable(node.body); 2144 push(node.body);
2147 } 2145 }
2148 } 2146 }
2149 2147
2150 void visitGetStatic(GetStatic node) { 2148 void visitGetStatic(GetStatic node) {
2151 if (node.element.isFunction) { 2149 if (node.element.isFunction) {
2152 setValue(node, nonConstant(typeSystem.functionType)); 2150 setValue(node, nonConstant(typeSystem.functionType));
2153 } else { 2151 } else {
2154 setValue(node, nonConstant(typeSystem.getFieldType(node.element))); 2152 setValue(node, nonConstant(typeSystem.getFieldType(node.element)));
2155 } 2153 }
2156 } 2154 }
2157 2155
2158 void visitSetStatic(SetStatic node) {} 2156 void visitSetStatic(SetStatic node) {}
2159 2157
2160 void visitGetLazyStatic(GetLazyStatic node) { 2158 void visitGetLazyStatic(GetLazyStatic node) {
2161 Continuation cont = node.continuation.definition; 2159 Continuation cont = node.continuation.definition;
2162 setReachable(cont); 2160 setReachable(cont);
2163 2161
2164 assert(cont.parameters.length == 1); 2162 assert(cont.parameters.length == 1);
2165 Parameter returnValue = cont.parameters[0]; 2163 Parameter returnValue = cont.parameters[0];
2166 setValue(returnValue, nonConstant(typeSystem.getFieldType(node.element))); 2164 setValue(returnValue, nonConstant(typeSystem.getFieldType(node.element)));
2167 } 2165 }
2168 2166
2169 void visitIsTrue(IsTrue node) { 2167 void visitIsTrue(IsTrue node) {
2170 Branch branch = node.parent; 2168 Branch branch = node.parent;
2171 visitBranch(branch); 2169 visitBranch(branch);
2172 } 2170 }
2173 2171
2174 void visitInterceptor(Interceptor node) { 2172 void visitInterceptor(Interceptor node) {
2175 setReachable(node.input.definition); 2173 push(node.input.definition);
2176 AbstractValue value = getValue(node.input.definition); 2174 AbstractValue value = getValue(node.input.definition);
2177 if (!value.isNothing) { 2175 if (!value.isNothing) {
2178 setValue(node, nonConstant(typeSystem.nonNullType)); 2176 setValue(node, nonConstant(typeSystem.nonNullType));
2179 } 2177 }
2180 } 2178 }
2181 2179
2182 void visitGetField(GetField node) { 2180 void visitGetField(GetField node) {
2183 setValue(node, nonConstant(typeSystem.getFieldType(node.field))); 2181 setValue(node, nonConstant(typeSystem.getFieldType(node.field)));
2184 } 2182 }
2185 2183
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after
2328 String get name => 'current'; 2326 String get name => 'current';
2329 } 2327 }
2330 2328
2331 /// Suggested name for the original length of a list, for use in checks 2329 /// Suggested name for the original length of a list, for use in checks
2332 /// for concurrent modification. 2330 /// for concurrent modification.
2333 class OriginalLengthEntity extends Entity { 2331 class OriginalLengthEntity extends Entity {
2334 String get name => 'length'; 2332 String get name => 'length';
2335 } 2333 }
2336 2334
2337 class ResetAnalysisInfo extends RecursiveVisitor { 2335 class ResetAnalysisInfo extends RecursiveVisitor {
2338 Set<Node> reachableNodes; 2336 Set<Continuation> reachableContinuations;
2339 Map<Definition, AbstractValue> values; 2337 Map<Definition, AbstractValue> values;
2340 2338
2341 ResetAnalysisInfo(this.reachableNodes, this.values); 2339 ResetAnalysisInfo(this.reachableContinuations, this.values);
2342 2340
2343 visit(Node node) { 2341 processContinuation(Continuation cont) {
2344 reachableNodes.remove(node); 2342 reachableContinuations.remove(cont);
2345 if (node is Definition) values.remove(node); 2343 cont.parameters.forEach(values.remove);
2346 node.accept(this); 2344 }
2345
2346 processLetPrim(LetPrim node) {
2347 values.remove(node.primitive);
2348 }
2349
2350 processLetMutable(LetMutable node) {
2351 values.remove(node.variable);
2347 } 2352 }
2348 } 2353 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart ('k') | tests/co19/co19-dart2js.status » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698