Chromium Code Reviews| Index: pkg/compiler/lib/src/cps_ir/type_propagation.dart |
| diff --git a/pkg/compiler/lib/src/cps_ir/type_propagation.dart b/pkg/compiler/lib/src/cps_ir/type_propagation.dart |
| index 5605d9376d2d9f4aaf3ad1fcb55c30a472b2cc7e..73e5871b7d4fa24588b865bb792fce967d76b8b1 100644 |
| --- a/pkg/compiler/lib/src/cps_ir/type_propagation.dart |
| +++ b/pkg/compiler/lib/src/cps_ir/type_propagation.dart |
| @@ -17,8 +17,10 @@ import '../elements/elements.dart'; |
| import '../io/source_information.dart' show SourceInformation; |
| import '../js_backend/js_backend.dart' show JavaScriptBackend; |
| import '../js_backend/codegen/task.dart' show CpsFunctionCompiler; |
| +import '../resolution/access_semantics.dart'; |
| import '../resolution/operators.dart'; |
| -import '../tree/tree.dart' show DartString, ConsDartString, LiteralDartString; |
| +import '../resolution/send_structure.dart'; |
| +import '../tree/tree.dart' as ast; |
| import '../types/types.dart'; |
| import '../types/constants.dart' show computeTypeMask; |
| import '../universe/universe.dart'; |
| @@ -479,7 +481,7 @@ class ConstantPropagationLattice { |
| } |
| AbstractValue stringConstant(String value) { |
| - return constant(new StringConstantValue(new DartString.literal(value))); |
| + return constant(new StringConstantValue(new ast.DartString.literal(value))); |
| } |
| AbstractValue stringify(AbstractValue value) { |
| @@ -1651,9 +1653,77 @@ class TransformingVisitor extends LeafVisitor { |
| return false; |
| } |
| + /// Try to inline static invocations. |
| + /// |
| + /// Performs the inlining and returns true if the call was inlined. Inlining |
| + /// uses a fixed heuristic: |
| + /// |
| + /// * Inline functions with a single expression statement or return statement |
| + /// provided that the subexpression is an invocation of foreign code. |
| + bool inlineInvokeStatic(InvokeStatic node) { |
| + // The target might not have an AST, for example if it deferred. |
|
karlklose
2015/08/25 11:57:12
'if it *is* deferred.'
I think 'hasNode' is only
|
| + if (!node.target.hasNode) return false; |
| + |
| + // An expression is non-expansive (in a sense) if it is just a call to |
| + // a foreign function. |
| + bool isNonExpansive(ast.Expression expr) { |
| + if (expr is ast.Send) { |
| + SendStructure structure = |
| + node.target.treeElements.getSendStructure(expr); |
| + if (structure is InvokeStructure) { |
| + return structure.semantics.kind == AccessKind.TOPLEVEL_METHOD && |
| + compiler.backend.isForeign(structure.semantics.element); |
| + } |
| + } |
| + return false; |
| + } |
| + |
| + ast.Statement body = node.target.node.body; |
| + bool shouldInline() { |
| + // At compile time, 'getInterceptor' from the Javascript runtime has a |
| + // foreign body that returns undefined. It is later mutated by replacing |
| + // it with a specialized version. Inlining undefined would be wrong. |
| + // TODO(kmillikin): matching the name prevents inlining other functions |
| + // with the same name. |
|
sra1
2015/08/25 20:42:04
We should add a @NoInline() annotation on definiti
|
| + if (node.target.name == 'getInterceptor') return false; |
|
karlklose
2015/08/25 11:57:13
You should compare the elements instead of the nam
|
| + |
| + // Inline functions that are a single return statement, expression |
| + // statement, or block containing a return statement or expression |
| + // statement. |
| + if (body is ast.Return) { |
| + return isNonExpansive(body.expression); |
| + } else if (body is ast.ExpressionStatement) { |
| + return isNonExpansive(body.expression); |
| + } else if (body is ast.Block) { |
| + var link = body.statements.nodes; |
|
karlklose
2015/08/25 11:57:13
'var' -> 'Link<Node>'.
|
| + if (link.isNotEmpty && link.tail.isEmpty) { |
|
karlklose
2015/08/25 11:57:12
How about moving the test for interceptors out of
|
| + if (link.head is ast.Return) { |
| + return isNonExpansive(link.head.expression); |
| + } else if (link.head is ast.ExpressionStatement) { |
| + return isNonExpansive(link.head.expression); |
| + } |
| + } |
| + } |
| + return false; |
| + } |
| + |
| + if (!shouldInline()) return false; |
| + |
| + FunctionDefinition target = functionCompiler.compileToCpsIR(node.target); |
| + for (int i = 0; i < node.arguments.length; ++i) { |
| + node.arguments[i].definition.substituteFor(target.parameters[i]); |
| + } |
| + node.continuation.definition.substituteFor(target.returnContinuation); |
| + |
| + replaceSubtree(node, target.body); |
| + push(target.body); |
| + return true; |
| + } |
| + |
| void visitInvokeStatic(InvokeStatic node) { |
| if (constifyExpression(node)) return; |
| if (specializeInternalMethodCall(node)) return; |
| + if (inlineInvokeStatic(node)) return; |
| } |
| AbstractValue getValue(Primitive primitive) { |
| @@ -1670,7 +1740,7 @@ class TransformingVisitor extends LeafVisitor { |
| // |
| void visitApplyBuiltinOperator(ApplyBuiltinOperator node) { |
| - DartString getString(AbstractValue value) { |
| + ast.DartString getString(AbstractValue value) { |
| StringConstantValue constant = value.constant; |
| return constant.primitiveValue; |
| } |
| @@ -1686,15 +1756,16 @@ class TransformingVisitor extends LeafVisitor { |
| AbstractValue secondValue = getValue(node.arguments[i++].definition); |
| if (!secondValue.isConstant) continue; |
| - DartString string = |
| - new ConsDartString(getString(firstValue), getString(secondValue)); |
| + ast.DartString string = |
| + new ast.ConsDartString(getString(firstValue), |
| + getString(secondValue)); |
| // We found a sequence of at least two constants. |
| // Look for the end of the sequence. |
| while (i < node.arguments.length) { |
| AbstractValue value = getValue(node.arguments[i].definition); |
| if (!value.isConstant) break; |
| - string = new ConsDartString(string, getString(value)); |
| + string = new ast.ConsDartString(string, getString(value)); |
| ++i; |
| } |
| Constant prim = |
| @@ -2154,7 +2225,7 @@ class TypePropagationVisitor implements Visitor { |
| void visitApplyBuiltinOperator(ApplyBuiltinOperator node) { |
| switch (node.operator) { |
| case BuiltinOperator.StringConcatenate: |
| - DartString stringValue = const LiteralDartString(''); |
| + ast.DartString stringValue = const ast.LiteralDartString(''); |
| for (Reference<Primitive> arg in node.arguments) { |
| AbstractValue value = getValue(arg.definition); |
| if (value.isNothing) { |
| @@ -2164,7 +2235,7 @@ class TypePropagationVisitor implements Visitor { |
| stringValue != null) { |
| StringConstantValue constant = value.constant; |
| stringValue = |
| - new ConsDartString(stringValue, constant.primitiveValue); |
| + new ast.ConsDartString(stringValue, constant.primitiveValue); |
| } else { |
| stringValue = null; |
| break; |