Skip to content

Commit 90039f6

Browse files
author
Kevin Millikin
committed
dart2js CPS: simple inlining of static invocations.
Inline static functions whose bodies are a single Dart expression that just calls a foreign (native) function. This eliminates a lot of overhead from the code in the JavaScript runtime library. [email protected] BUG= Review URL: https://codereview.chromium.org//1318453003 .
1 parent 8c346ab commit 90039f6

File tree

2 files changed

+81
-10
lines changed

2 files changed

+81
-10
lines changed

pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -427,11 +427,11 @@ class ConstantStringifier extends ConstantValueVisitor<String, Null> {
427427
}
428428

429429
String visitInterceptor(InterceptorConstantValue constant, _) {
430-
return _failWith(constant);
430+
return '(Interceptor "${constant.unparse()}")';
431431
}
432432

433433
String visitSynthetic(SyntheticConstantValue constant, _) {
434-
return _failWith(constant);
434+
return '(Synthetic "${constant.unparse()}")';
435435
}
436436

437437
String visitDeferred(DeferredConstantValue constant, _) {

pkg/compiler/lib/src/cps_ir/type_propagation.dart

Lines changed: 79 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@ import '../elements/elements.dart';
1717
import '../io/source_information.dart' show SourceInformation;
1818
import '../js_backend/js_backend.dart' show JavaScriptBackend;
1919
import '../js_backend/codegen/task.dart' show CpsFunctionCompiler;
20+
import '../resolution/access_semantics.dart';
2021
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;
2224
import '../types/types.dart';
2325
import '../types/constants.dart' show computeTypeMask;
2426
import '../universe/universe.dart';
@@ -479,7 +481,7 @@ class ConstantPropagationLattice {
479481
}
480482

481483
AbstractValue stringConstant(String value) {
482-
return constant(new StringConstantValue(new DartString.literal(value)));
484+
return constant(new StringConstantValue(new ast.DartString.literal(value)));
483485
}
484486

485487
AbstractValue stringify(AbstractValue value) {
@@ -1651,9 +1653,77 @@ class TransformingVisitor extends LeafVisitor {
16511653
return false;
16521654
}
16531655

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+
16541723
void visitInvokeStatic(InvokeStatic node) {
16551724
if (constifyExpression(node)) return;
16561725
if (specializeInternalMethodCall(node)) return;
1726+
if (inlineInvokeStatic(node)) return;
16571727
}
16581728

16591729
AbstractValue getValue(Primitive primitive) {
@@ -1670,7 +1740,7 @@ class TransformingVisitor extends LeafVisitor {
16701740
//
16711741

16721742
void visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
1673-
DartString getString(AbstractValue value) {
1743+
ast.DartString getString(AbstractValue value) {
16741744
StringConstantValue constant = value.constant;
16751745
return constant.primitiveValue;
16761746
}
@@ -1686,15 +1756,16 @@ class TransformingVisitor extends LeafVisitor {
16861756
AbstractValue secondValue = getValue(node.arguments[i++].definition);
16871757
if (!secondValue.isConstant) continue;
16881758

1689-
DartString string =
1690-
new ConsDartString(getString(firstValue), getString(secondValue));
1759+
ast.DartString string =
1760+
new ast.ConsDartString(getString(firstValue),
1761+
getString(secondValue));
16911762

16921763
// We found a sequence of at least two constants.
16931764
// Look for the end of the sequence.
16941765
while (i < node.arguments.length) {
16951766
AbstractValue value = getValue(node.arguments[i].definition);
16961767
if (!value.isConstant) break;
1697-
string = new ConsDartString(string, getString(value));
1768+
string = new ast.ConsDartString(string, getString(value));
16981769
++i;
16991770
}
17001771
Constant prim =
@@ -2154,7 +2225,7 @@ class TypePropagationVisitor implements Visitor {
21542225
void visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
21552226
switch (node.operator) {
21562227
case BuiltinOperator.StringConcatenate:
2157-
DartString stringValue = const LiteralDartString('');
2228+
ast.DartString stringValue = const ast.LiteralDartString('');
21582229
for (Reference<Primitive> arg in node.arguments) {
21592230
AbstractValue value = getValue(arg.definition);
21602231
if (value.isNothing) {
@@ -2164,7 +2235,7 @@ class TypePropagationVisitor implements Visitor {
21642235
stringValue != null) {
21652236
StringConstantValue constant = value.constant;
21662237
stringValue =
2167-
new ConsDartString(stringValue, constant.primitiveValue);
2238+
new ast.ConsDartString(stringValue, constant.primitiveValue);
21682239
} else {
21692240
stringValue = null;
21702241
break;

0 commit comments

Comments
 (0)