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

Unified Diff: sdk/lib/_internal/compiler/implementation/ssa/optimize.dart

Issue 12033056: Implement "one-shot" interceptors. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 11 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 side-by-side diff with in-line comments
Download patch
Index: sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
===================================================================
--- sdk/lib/_internal/compiler/implementation/ssa/optimize.dart (revision 17552)
+++ 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) {
@@ -219,7 +220,10 @@
return null;
}
- HInstruction handleInterceptorCall(HInvokeDynamicMethod node) {
+ HInstruction handleInterceptorCall(HInvokeDynamic node) {
+ // We only optimize for intercepted method calls in this method.
+ if (node.selector.isGetter() || node.selector.isSetter()) return node;
+
HInstruction input = node.inputs[1];
if (input.isString(types)
&& node.selector.name == const SourceString('toString')) {
@@ -246,9 +250,15 @@
if (interceptor is !HThis && !type.canBePrimitive()) {
// If the type can be null, and the intercepted method can be in
// the object class, keep the interceptor.
- if (type.canBeNull()
- && interceptor.interceptedClasses.contains(compiler.objectClass)) {
- return node;
+ if (type.canBeNull()) {
+ Set<ClassElement> interceptedClasses;
+ if (interceptor is HInterceptor) {
+ interceptedClasses = interceptor.interceptedClasses;
+ } else if (node is HOneShotInterceptor) {
+ var oneShotInterceptor = node;
+ interceptedClasses = oneShotInterceptor.interceptedClasses;
+ }
+ if (interceptedClasses.contains(compiler.objectClass)) return node;
}
// Change the call to a regular invoke dynamic call.
return new HInvokeDynamicMethod(
@@ -669,7 +679,15 @@
HInstruction visitInterceptor(HInterceptor node) {
if (node.isConstant()) return node;
- HType type = types[node.inputs[0]];
+ HInstruction constant = tryComputeConstantInterceptor(
+ node.inputs[0], node.interceptedClasses);
+ if (constant == null) return node;
+ return constant;
+ }
+
+ HInstruction tryComputeConstantInterceptor(HInstruction input,
+ Set<ClassElement> intercepted) {
+ HType type = types[input];
ClassElement constantInterceptor;
if (type.isInteger()) {
constantInterceptor = backend.jsIntClass;
@@ -684,7 +702,6 @@
} else if (type.isNull()) {
constantInterceptor = backend.jsIntClass;
} else if (type.isNumber()) {
- Set<ClassElement> intercepted = node.interceptedClasses;
// If the method being intercepted is not defined in [int] or
// [double] we can safely use the number interceptor.
if (!intercepted.contains(compiler.intClass)
@@ -693,7 +710,7 @@
}
}
- if (constantInterceptor == null) return node;
+ if (constantInterceptor == null) return null;
if (constantInterceptor == work.element.getEnclosingClass()) {
return graph.thisInstruction;
}
@@ -702,6 +719,35 @@
constantInterceptor.computeType(compiler), <Constant>[]);
return graph.addConstant(constant);
}
+
+ HInstruction visitOneShotInterceptor(HOneShotInterceptor node) {
+ HInstruction newInstruction = handleInterceptorCall(node);
+ if (newInstruction != null) return newInstruction;
+
+ HInstruction constant = tryComputeConstantInterceptor(
+ node.inputs[1], node.interceptedClasses);
+
+ if (constant == null) return node;
+
+ Selector selector = node.selector;
+ // TODO(ngeoffray): make one shot interceptors know whether
+ // they have side effects.
+ if (selector.isGetter()) {
+ HInstruction res = new HInvokeDynamicGetter(
+ selector, node.element, constant, false);
+ res.inputs.add(node.intputs[1]);
+ return res;
+ } else if (node.selector.isSetter()) {
+ HInstruction res = new HInvokeDynamicSetter(
+ selector, node.element, constant, node.inputs[1], false);
+ res.inputs.add(node.intputs[2]);
+ return res;
+ } else {
+ List<HInstruction> inputs = new List<HInstruction>.from(node.inputs);
+ inputs[0] = constant;
+ return new HInvokeDynamicMethod(selector, inputs, true);
+ }
+ }
}
class SsaCheckInserter extends HBaseVisitor implements OptimizationPhase {
@@ -1445,3 +1491,52 @@
// 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.hasSameLoopHeaderAs(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);
+ interceptor.sourcePosition = user.sourcePosition;
+
+ 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.
+ }
+}
« no previous file with comments | « sdk/lib/_internal/compiler/implementation/ssa/nodes.dart ('k') | sdk/lib/_internal/compiler/implementation/ssa/tracer.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698