| Index: sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
|
| ===================================================================
|
| --- sdk/lib/_internal/compiler/implementation/ssa/optimize.dart (revision 17466)
|
| +++ sdk/lib/_internal/compiler/implementation/ssa/optimize.dart (working copy)
|
| @@ -58,6 +58,7 @@
|
| // Previous optimizations may have generated new
|
| // opportunities for constant folding.
|
| new SsaConstantFolder(constantSystem, backend, work, types),
|
| + new SsaSimplifyInterceptors(constantSystem),
|
| new SsaDeadCodeEliminator(types)];
|
| runPhases(graph, phases);
|
| if (!speculative) {
|
| @@ -671,6 +672,8 @@
|
| if (node.isConstant()) return node;
|
| HType type = types[node.inputs[0]];
|
| ClassElement constantInterceptor;
|
| + // TODO(ngeoffray): We should also do this optimization for one
|
| + // shot interceptors.
|
| if (type.isInteger()) {
|
| constantInterceptor = backend.jsIntClass;
|
| } else if (type.isDouble()) {
|
| @@ -1445,3 +1448,51 @@
|
|
|
| // TODO(ngeoffray): Also implement it for non-intercepted calls.
|
| }
|
| +
|
| +/**
|
| + * This phase replaces all interceptors that are used only once with
|
| + * one-shot interceptors. It saves code size and makes the receiver of
|
| + * an intercepted call a candidate for being generated at use site.
|
| + */
|
| +class SsaSimplifyInterceptors extends HBaseVisitor
|
| + implements OptimizationPhase {
|
| + final String name = "SsaSimplifyInterceptors";
|
| + final ConstantSystem constantSystem;
|
| + HGraph graph;
|
| +
|
| + SsaSimplifyInterceptors(this.constantSystem);
|
| +
|
| + void visitGraph(HGraph graph) {
|
| + this.graph = graph;
|
| + visitDominatorTree(graph);
|
| + }
|
| +
|
| + void visitInterceptor(HInterceptor node) {
|
| + if (node.usedBy.length != 1) return;
|
| + // [HBailoutTarget] instructions might have the interceptor as
|
| + // input. In such situation we let the dead code analyzer find out
|
| + // the interceptor is not needed.
|
| + if (node.usedBy[0] is !HInvokeDynamic) return;
|
| +
|
| + HInvokeDynamic user = node.usedBy[0];
|
| +
|
| + // If [node] was loop hoisted, we keep the interceptor.
|
| + if (!user.bothNotInLoopOrInSameLoop(node)) return;
|
| +
|
| + // Replace the user with a [HOneShotInterceptor].
|
| + HConstant nullConstant = graph.addConstantNull(constantSystem);
|
| + List<HInstruction> inputs = new List<HInstruction>.from(user.inputs);
|
| + inputs[0] = nullConstant;
|
| + HOneShotInterceptor interceptor = new HOneShotInterceptor(
|
| + user.selector, inputs, node.interceptedClasses);
|
| +
|
| + HBasicBlock block = user.block;
|
| + block.addAfter(user, interceptor);
|
| + block.rewrite(user, interceptor);
|
| + block.remove(user);
|
| +
|
| + // The interceptor will be removed in the dead code elimination
|
| + // phase. Note that removing it here would not work because of how
|
| + // the [visitBasicBlock] is implemented.
|
| + }
|
| +}
|
|
|