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

Unified Diff: pkg/compiler/lib/src/cps_ir/share_interceptors.dart

Issue 1409803003: dart2js cps: More interceptor optimizations and fixes. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Fix indentation Created 5 years, 2 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
« no previous file with comments | « pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart ('k') | pkg/compiler/lib/src/cps_ir/type_mask_system.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/compiler/lib/src/cps_ir/share_interceptors.dart
diff --git a/pkg/compiler/lib/src/cps_ir/share_interceptors.dart b/pkg/compiler/lib/src/cps_ir/share_interceptors.dart
index 3706725e3d102a8c63b652ec7fe196761d9e435c..bdfc0830e1d4746abfcaef62978292c262e693ab 100644
--- a/pkg/compiler/lib/src/cps_ir/share_interceptors.dart
+++ b/pkg/compiler/lib/src/cps_ir/share_interceptors.dart
@@ -7,10 +7,15 @@ library dart2js.cps_ir.share_interceptors;
import 'optimizers.dart';
import 'cps_ir_nodes.dart';
import 'loop_hierarchy.dart';
+import 'cps_fragment.dart';
import '../constants/values.dart';
+import '../elements/elements.dart';
+import '../js_backend/js_backend.dart' show JavaScriptBackend;
+import '../types/types.dart' show TypeMask;
+import '../io/source_information.dart' show SourceInformation;
/// Removes redundant `getInterceptor` calls.
-///
+///
/// The pass performs three optimizations for interceptors:
///- pull interceptors out of loops
///- replace interceptors with constants
@@ -23,31 +28,27 @@ class ShareInterceptors extends TrampolineRecursiveVisitor implements Pass {
<Primitive, Continuation>{};
/// An interceptor currently in scope for a given primitive.
- final Map<Primitive, Primitive> interceptorFor =
- <Primitive, Primitive>{};
+ final Map<Primitive, Interceptor> interceptorFor = <Primitive, Interceptor>{};
- /// A primitive currently in scope holding a given interceptor constant.
- final Map<ConstantValue, Primitive> sharedConstantFor =
- <ConstantValue, Primitive>{};
-
- /// Interceptors to be hoisted out of the given loop.
- final Map<Continuation, List<Primitive>> loopHoistedInterceptors =
- <Continuation, List<Primitive>>{};
+ /// Interceptors that have been hoisted out of a given loop.
+ final Map<Continuation, List<Interceptor>> loopHoistedInterceptors =
+ <Continuation, List<Interceptor>>{};
+ JavaScriptBackend backend;
LoopHierarchy loopHierarchy;
Continuation currentLoopHeader;
+ ShareInterceptors(this.backend);
+
void rewrite(FunctionDefinition node) {
loopHierarchy = new LoopHierarchy(node);
visit(node.body);
+ new ShareConstants().visit(node);
}
@override
Expression traverseContinuation(Continuation cont) {
Continuation oldLoopHeader = currentLoopHeader;
- pushAction(() {
- currentLoopHeader = oldLoopHeader;
- });
currentLoopHeader = loopHierarchy.getLoopHeader(cont);
for (Parameter param in cont.parameters) {
loopHeaderFor[param] = currentLoopHeader;
@@ -57,26 +58,118 @@ class ShareInterceptors extends TrampolineRecursiveVisitor implements Pass {
// After the loop body has been processed, all interceptors hoisted
// to this loop fall out of scope and should be removed from the
// environment.
- List<Primitive> hoisted = loopHoistedInterceptors[cont];
+ List<Interceptor> hoisted = loopHoistedInterceptors[cont];
if (hoisted != null) {
- for (Primitive interceptor in hoisted) {
- if (interceptor is Interceptor) {
- Primitive input = interceptor.input.definition;
- assert(interceptorFor[input] == interceptor);
- interceptorFor.remove(input);
- } else if (interceptor is Constant) {
- assert(sharedConstantFor[interceptor.value] == interceptor);
- sharedConstantFor.remove(interceptor.value);
- } else {
- throw "Unexpected interceptor: $interceptor";
- }
+ for (Interceptor interceptor in hoisted) {
+ Primitive input = interceptor.input.definition;
+ assert(interceptorFor[input] == interceptor);
+ interceptorFor.remove(input);
+ constifyInterceptor(interceptor);
}
}
});
}
+ pushAction(() {
+ currentLoopHeader = oldLoopHeader;
+ });
return cont.body;
}
+ /// If only one method table can be returned by the given interceptor,
+ /// returns a constant for that method table.
+ InterceptorConstantValue getInterceptorConstant(Interceptor node) {
+ if (node.interceptedClasses.length == 1 &&
+ node.isInterceptedClassAlwaysExact) {
+ ClassElement interceptorClass = node.interceptedClasses.single;
+ return new InterceptorConstantValue(interceptorClass.rawType);
+ }
+ return null;
+ }
+
+ bool hasNoFalsyValues(ClassElement class_) {
+ return class_ != backend.jsInterceptorClass &&
+ class_ != backend.jsNullClass &&
+ class_ != backend.jsBoolClass &&
+ class_ != backend.jsStringClass &&
+ !class_.isSubclassOf(backend.jsNumberClass);
+ }
+
+ Continuation getCurrentOuterLoop({Continuation scope}) {
+ Continuation inner = null, outer = currentLoopHeader;
+ while (outer != scope) {
+ inner = outer;
+ outer = loopHierarchy.getEnclosingLoop(outer);
+ }
+ return inner;
+ }
+
+ /// Binds the given constant in a primitive, in scope of the [useSite].
+ ///
+ /// The constant will be hoisted out of loops, and shared with other requests
+ /// for the same constant as long as it is in scope.
+ Primitive makeConstantFor(ConstantValue constant,
+ {Expression useSite,
+ TypeMask type,
+ SourceInformation sourceInformation,
+ Entity hint}) {
+ Constant prim =
+ new Constant(constant, sourceInformation: sourceInformation);
+ prim.hint = hint;
+ prim.type = type;
+ LetPrim letPrim = new LetPrim(prim);
+ Continuation loop = getCurrentOuterLoop();
+ if (loop != null) {
+ LetCont loopBinding = loop.parent;
+ letPrim.insertAbove(loopBinding);
+ } else {
+ letPrim.insertAbove(useSite);
+ }
+ return prim;
+ }
+
+ void constifyInterceptor(Interceptor interceptor) {
+ LetPrim let = interceptor.parent;
+ InterceptorConstantValue constant = getInterceptorConstant(interceptor);
+
+ if (constant == null) return;
+
+ if (interceptor.isAlwaysIntercepted) {
+ Primitive constantPrim = makeConstantFor(constant,
+ useSite: let,
+ type: interceptor.type,
+ sourceInformation: interceptor.sourceInformation);
+ constantPrim.useElementAsHint(interceptor.hint);
+ constantPrim.substituteFor(interceptor);
+ interceptor.destroy();
+ let.remove();
+ } else if (interceptor.isAlwaysNullOrIntercepted) {
+ Primitive input = interceptor.input.definition;
+ Primitive constantPrim = makeConstantFor(constant,
+ useSite: let,
+ type: interceptor.type.nonNullable(),
+ sourceInformation: interceptor.sourceInformation);
+ CpsFragment cps = new CpsFragment(interceptor.sourceInformation);
+ Parameter param = new Parameter(interceptor.hint);
+ Continuation cont = cps.letCont(<Parameter>[param]);
+ if (interceptor.interceptedClasses.every(hasNoFalsyValues)) {
+ // If null is the only falsy value, compile as "x && CONST".
+ cps.ifFalsy(input).invokeContinuation(cont, [input]);
+ } else {
+ // If there are other falsy values compile as "x == null ? x : CONST".
+ Primitive condition = cps.applyBuiltin(
+ BuiltinOperator.LooseEq,
+ [input, cps.makeNull()]);
+ cps.ifTruthy(condition).invokeContinuation(cont, [input]);
+ }
+ cps.invokeContinuation(cont, [constantPrim]);
+ cps.context = cont;
+ cps.insertAbove(let);
+ param.substituteFor(interceptor);
+ interceptor.destroy();
+ let.remove();
+ }
+ }
+
@override
Expression traverseLetPrim(LetPrim node) {
loopHeaderFor[node.primitive] = currentLoopHeader;
@@ -88,88 +181,45 @@ class ShareInterceptors extends TrampolineRecursiveVisitor implements Pass {
Primitive input = interceptor.input.definition;
// Try to reuse an existing interceptor for the same input.
- Primitive existing = interceptorFor[input];
+ Interceptor existing = interceptorFor[input];
if (existing != null) {
- if (existing is Interceptor) {
- existing.interceptedClasses.addAll(interceptor.interceptedClasses);
- }
+ existing.interceptedClasses.addAll(interceptor.interceptedClasses);
+ existing.flags |= interceptor.flags;
existing.substituteFor(interceptor);
interceptor.destroy();
node.remove();
return next;
}
- // There is no interceptor obtained from this particular input, but
- // there might one obtained from another input that is known to
- // have the same result, so try to reuse that.
- InterceptorConstantValue constant = interceptor.constantValue;
- if (constant != null) {
- existing = sharedConstantFor[constant];
- if (existing != null) {
- existing.substituteFor(interceptor);
- interceptor.destroy();
- node.remove();
- return next;
- }
-
- // The interceptor could not be shared. Replace it with a constant.
- Constant constantPrim = new Constant(constant);
- node.primitive = constantPrim;
- constantPrim.parent = node;
- constantPrim.hint = interceptor.hint;
- constantPrim.type = interceptor.type;
- constantPrim.substituteFor(interceptor);
- interceptor.destroy();
- sharedConstantFor[constant] = constantPrim;
- } else {
- interceptorFor[input] = interceptor;
- }
+ // Put this interceptor in the environment.
+ interceptorFor[input] = interceptor;
- // Determine the outermost loop where the input to the interceptor call
- // is available. Constant interceptors take no input and can thus be
- // hoisted all way to the top-level.
- Continuation referencedLoop = constant != null
- ? null
- : lowestCommonAncestor(loopHeaderFor[input], currentLoopHeader);
+ // Determine how far the interceptor can be lifted. The outermost loop
+ // that contains the input binding should also contain the interceptor
+ // binding.
+ Continuation referencedLoop =
+ lowestCommonAncestor(loopHeaderFor[input], currentLoopHeader);
if (referencedLoop != currentLoopHeader) {
- // [referencedLoop] contains the binding for [input], so we cannot hoist
- // the interceptor outside that loop. Find the loop nested one level
- // inside referencedLoop, and hoist the interceptor just outside that one.
- Continuation loop = currentLoopHeader;
- Continuation enclosing = loopHierarchy.getEnclosingLoop(loop);
- while (enclosing != referencedLoop) {
- assert(loop != null);
- loop = enclosing;
- enclosing = loopHierarchy.getEnclosingLoop(loop);
- }
- assert(loop != null);
-
- // Move the LetPrim above the loop binding.
- LetCont loopBinding = loop.parent;
+ Continuation hoistTarget = getCurrentOuterLoop(scope: referencedLoop);
+ LetCont loopBinding = hoistTarget.parent;
node.remove();
node.insertAbove(loopBinding);
-
- // A different loop now contains the interceptor.
- loopHeaderFor[node.primitive] = enclosing;
-
- // Register the interceptor as hoisted to that loop, so it will be
- // removed from the environment when it falls out of scope.
+ // Remove the interceptor from the environment after processing the loop.
loopHoistedInterceptors
- .putIfAbsent(loop, () => <Primitive>[])
- .add(node.primitive);
- } else if (constant != null) {
- // The LetPrim was not hoisted. Remove the bound interceptor from the
- // environment when leaving the LetPrim body.
- pushAction(() {
- assert(sharedConstantFor[constant] == node.primitive);
- sharedConstantFor.remove(constant);
- });
+ .putIfAbsent(hoistTarget, () => <Interceptor>[])
+ .add(interceptor);
} else {
+ // Remove the interceptor from the environment when it falls out of scope.
pushAction(() {
- assert(interceptorFor[input] == node.primitive);
+ assert(interceptorFor[input] == interceptor);
interceptorFor.remove(input);
+
+ // Now that the final set of intercepted classes has been seen, try to
+ // replace it with a constant.
+ constifyInterceptor(interceptor);
});
}
+
return next;
}
@@ -194,3 +244,32 @@ class ShareInterceptors extends TrampolineRecursiveVisitor implements Pass {
return loopHierarchy.loopDepth[loop];
}
}
+
+class ShareConstants extends TrampolineRecursiveVisitor {
+ Map<ConstantValue, Constant> sharedConstantFor = <ConstantValue, Constant>{};
+
+ Expression traverseLetPrim(LetPrim node) {
+ Expression next = node.body;
+ if (node.primitive is Constant && shouldShareConstant(node.primitive)) {
+ Constant prim = node.primitive;
+ Constant existing = sharedConstantFor[prim.value];
+ if (existing != null) {
+ existing.substituteFor(prim);
+ existing.useElementAsHint(prim.hint);
+ prim.destroy();
+ node.remove();
+ return next;
+ }
+ sharedConstantFor[prim.value] = prim;
+ pushAction(() {
+ assert(sharedConstantFor[prim.value] == prim);
+ sharedConstantFor.remove(prim.value);
+ });
+ }
+ return next;
+ }
+
+ bool shouldShareConstant(Constant constant) {
+ return constant.value.isInterceptor;
+ }
+}
« no previous file with comments | « pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart ('k') | pkg/compiler/lib/src/cps_ir/type_mask_system.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698