@@ -17,8 +17,10 @@ import '../elements/elements.dart';
17
17
import '../io/source_information.dart' show SourceInformation;
18
18
import '../js_backend/js_backend.dart' show JavaScriptBackend;
19
19
import '../js_backend/codegen/task.dart' show CpsFunctionCompiler;
20
+ import '../resolution/access_semantics.dart' ;
20
21
import '../resolution/operators.dart' ;
21
- import '../tree/tree.dart' show DartString, ConsDartString, LiteralDartString;
22
+ import '../resolution/send_structure.dart' ;
23
+ import '../tree/tree.dart' as ast;
22
24
import '../types/types.dart' ;
23
25
import '../types/constants.dart' show computeTypeMask;
24
26
import '../universe/universe.dart' ;
@@ -479,7 +481,7 @@ class ConstantPropagationLattice {
479
481
}
480
482
481
483
AbstractValue stringConstant (String value) {
482
- return constant (new StringConstantValue (new DartString .literal (value)));
484
+ return constant (new StringConstantValue (new ast. DartString .literal (value)));
483
485
}
484
486
485
487
AbstractValue stringify (AbstractValue value) {
@@ -1651,9 +1653,77 @@ class TransformingVisitor extends LeafVisitor {
1651
1653
return false ;
1652
1654
}
1653
1655
1656
+ /// Try to inline static invocations.
1657
+ ///
1658
+ /// Performs the inlining and returns true if the call was inlined. Inlining
1659
+ /// uses a fixed heuristic:
1660
+ ///
1661
+ /// * Inline functions with a single expression statement or return statement
1662
+ /// provided that the subexpression is an invocation of foreign code.
1663
+ bool inlineInvokeStatic (InvokeStatic node) {
1664
+ // The target might not have an AST, for example if it deferred.
1665
+ if (! node.target.hasNode) return false ;
1666
+
1667
+ // An expression is non-expansive (in a sense) if it is just a call to
1668
+ // a foreign function.
1669
+ bool isNonExpansive (ast.Expression expr) {
1670
+ if (expr is ast.Send ) {
1671
+ SendStructure structure =
1672
+ node.target.treeElements.getSendStructure (expr);
1673
+ if (structure is InvokeStructure ) {
1674
+ return structure.semantics.kind == AccessKind .TOPLEVEL_METHOD &&
1675
+ compiler.backend.isForeign (structure.semantics.element);
1676
+ }
1677
+ }
1678
+ return false ;
1679
+ }
1680
+
1681
+ ast.Statement body = node.target.node.body;
1682
+ bool shouldInline () {
1683
+ // At compile time, 'getInterceptor' from the Javascript runtime has a
1684
+ // foreign body that returns undefined. It is later mutated by replacing
1685
+ // it with a specialized version. Inlining undefined would be wrong.
1686
+ // TODO(kmillikin): matching the name prevents inlining other functions
1687
+ // with the same name.
1688
+ if (node.target.name == 'getInterceptor' ) return false ;
1689
+
1690
+ // Inline functions that are a single return statement, expression
1691
+ // statement, or block containing a return statement or expression
1692
+ // statement.
1693
+ if (body is ast.Return ) {
1694
+ return isNonExpansive (body.expression);
1695
+ } else if (body is ast.ExpressionStatement ) {
1696
+ return isNonExpansive (body.expression);
1697
+ } else if (body is ast.Block ) {
1698
+ var link = body.statements.nodes;
1699
+ if (link.isNotEmpty && link.tail.isEmpty) {
1700
+ if (link.head is ast.Return ) {
1701
+ return isNonExpansive (link.head.expression);
1702
+ } else if (link.head is ast.ExpressionStatement ) {
1703
+ return isNonExpansive (link.head.expression);
1704
+ }
1705
+ }
1706
+ }
1707
+ return false ;
1708
+ }
1709
+
1710
+ if (! shouldInline ()) return false ;
1711
+
1712
+ FunctionDefinition target = functionCompiler.compileToCpsIR (node.target);
1713
+ for (int i = 0 ; i < node.arguments.length; ++ i) {
1714
+ node.arguments[i].definition.substituteFor (target.parameters[i]);
1715
+ }
1716
+ node.continuation.definition.substituteFor (target.returnContinuation);
1717
+
1718
+ replaceSubtree (node, target.body);
1719
+ push (target.body);
1720
+ return true ;
1721
+ }
1722
+
1654
1723
void visitInvokeStatic (InvokeStatic node) {
1655
1724
if (constifyExpression (node)) return ;
1656
1725
if (specializeInternalMethodCall (node)) return ;
1726
+ if (inlineInvokeStatic (node)) return ;
1657
1727
}
1658
1728
1659
1729
AbstractValue getValue (Primitive primitive) {
@@ -1670,7 +1740,7 @@ class TransformingVisitor extends LeafVisitor {
1670
1740
//
1671
1741
1672
1742
void visitApplyBuiltinOperator (ApplyBuiltinOperator node) {
1673
- DartString getString (AbstractValue value) {
1743
+ ast. DartString getString (AbstractValue value) {
1674
1744
StringConstantValue constant = value.constant;
1675
1745
return constant.primitiveValue;
1676
1746
}
@@ -1686,15 +1756,16 @@ class TransformingVisitor extends LeafVisitor {
1686
1756
AbstractValue secondValue = getValue (node.arguments[i++ ].definition);
1687
1757
if (! secondValue.isConstant) continue ;
1688
1758
1689
- DartString string =
1690
- new ConsDartString (getString (firstValue), getString (secondValue));
1759
+ ast.DartString string =
1760
+ new ast.ConsDartString (getString (firstValue),
1761
+ getString (secondValue));
1691
1762
1692
1763
// We found a sequence of at least two constants.
1693
1764
// Look for the end of the sequence.
1694
1765
while (i < node.arguments.length) {
1695
1766
AbstractValue value = getValue (node.arguments[i].definition);
1696
1767
if (! value.isConstant) break ;
1697
- string = new ConsDartString (string, getString (value));
1768
+ string = new ast. ConsDartString (string, getString (value));
1698
1769
++ i;
1699
1770
}
1700
1771
Constant prim =
@@ -2154,7 +2225,7 @@ class TypePropagationVisitor implements Visitor {
2154
2225
void visitApplyBuiltinOperator (ApplyBuiltinOperator node) {
2155
2226
switch (node.operator ) {
2156
2227
case BuiltinOperator .StringConcatenate :
2157
- DartString stringValue = const LiteralDartString ('' );
2228
+ ast. DartString stringValue = const ast. LiteralDartString ('' );
2158
2229
for (Reference <Primitive > arg in node.arguments) {
2159
2230
AbstractValue value = getValue (arg.definition);
2160
2231
if (value.isNothing) {
@@ -2164,7 +2235,7 @@ class TypePropagationVisitor implements Visitor {
2164
2235
stringValue != null ) {
2165
2236
StringConstantValue constant = value.constant;
2166
2237
stringValue =
2167
- new ConsDartString (stringValue, constant.primitiveValue);
2238
+ new ast. ConsDartString (stringValue, constant.primitiveValue);
2168
2239
} else {
2169
2240
stringValue = null ;
2170
2241
break ;
0 commit comments