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

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

Issue 1571433002: dart2js cps: Compute intercepted classes in optimize_interceptors. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Address comments Created 4 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
« no previous file with comments | « pkg/compiler/lib/src/cps_ir/gvn.dart ('k') | pkg/compiler/lib/src/cps_ir/optimizers.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/optimize_interceptors.dart
diff --git a/pkg/compiler/lib/src/cps_ir/optimize_interceptors.dart b/pkg/compiler/lib/src/cps_ir/optimize_interceptors.dart
index 19b79d41c63c4ea8e9379429b1c7158099e0bdf9..689dac67fdd02e4163c1c5dd72904b3bcd08b059 100644
--- a/pkg/compiler/lib/src/cps_ir/optimize_interceptors.dart
+++ b/pkg/compiler/lib/src/cps_ir/optimize_interceptors.dart
@@ -14,22 +14,28 @@ import '../js_backend/backend_helpers.dart' show BackendHelpers;
import '../js_backend/js_backend.dart' show JavaScriptBackend;
import '../types/types.dart' show TypeMask;
import '../io/source_information.dart' show SourceInformation;
+import '../world.dart';
+import 'type_mask_system.dart';
/// Replaces `getInterceptor` calls with interceptor constants when possible,
/// or with "almost constant" expressions like "x && CONST" when the input
/// is either null or has a known interceptor.
-//
-// TODO(asgerf): Compute intercepted classes in this pass.
+///
+/// Narrows the set of intercepted classes for interceptor calls.
+///
+/// Replaces calls on interceptors with one-shot interceptors.
class OptimizeInterceptors extends TrampolineRecursiveVisitor implements Pass {
String get passName => 'Optimize interceptors';
- JavaScriptBackend backend;
+ final TypeMaskSystem typeSystem;
+ final JavaScriptBackend backend;
LoopHierarchy loopHierarchy;
Continuation currentLoopHeader;
- OptimizeInterceptors(this.backend);
+ OptimizeInterceptors(this.backend, this.typeSystem);
BackendHelpers get helpers => backend.helpers;
+ World get classWorld => backend.compiler.world;
Map<Interceptor, Continuation> loopHeaderFor = <Interceptor, Continuation>{};
@@ -51,17 +57,6 @@ class OptimizeInterceptors extends TrampolineRecursiveVisitor implements Pass {
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_ != helpers.jsInterceptorClass &&
class_ != helpers.jsNullClass &&
@@ -103,13 +98,113 @@ class OptimizeInterceptors extends TrampolineRecursiveVisitor implements Pass {
return prim;
}
+ void computeInterceptedClasses(Interceptor interceptor) {
+ Set<ClassElement> intercepted = interceptor.interceptedClasses;
+ intercepted.clear();
+ for (Reference ref = interceptor.firstRef; ref != null; ref = ref.next) {
+ Node use = ref.parent;
+ if (use is InvokeMethod) {
+ TypeMask type = use.dartReceiver.type;
+ bool canOccurAsReceiver(ClassElement elem) {
+ return classWorld.isInstantiated(elem) &&
+ !typeSystem.areDisjoint(type,
+ typeSystem.getInterceptorSubtypes(elem));
+ }
+ Iterable<ClassElement> classes =
+ backend.getInterceptedClassesOn(use.selector.name);
+ intercepted.addAll(classes.where(canOccurAsReceiver));
+ } else {
+ intercepted.clear();
+ intercepted.add(backend.helpers.jsInterceptorClass);
+ break;
+ }
+ }
+ if (intercepted.contains(backend.helpers.jsInterceptorClass) ||
+ intercepted.contains(backend.helpers.jsNullClass)) {
+ // If the null value is intercepted, update the type of the interceptor.
+ // The Tree IR uses this information to determine if the method lookup
+ // on an InvokeMethod might throw.
+ interceptor.type = interceptor.type.nonNullable();
+ }
+ }
+
+ /// True if [node] may return [JSNumber] instead of [JSInt] or [JSDouble].
+ bool jsNumberClassSuffices(Interceptor node) {
+ // No methods on JSNumber call 'down' to methods on JSInt or JSDouble. If
+ // all uses of the interceptor are for methods is defined only on JSNumber
+ // then JSNumber will suffice in place of choosing between JSInt or
+ // JSDouble.
+ for (Reference ref = node.firstRef; ref != null; ref = ref.next) {
+ if (ref.parent is InvokeMethod) {
+ InvokeMethod invoke = ref.parent;
+ if (invoke.receiver != ref) return false;
+ var interceptedClasses =
+ backend.getInterceptedClassesOn(invoke.selector.name);
+ if (interceptedClasses.contains(helpers.jsDoubleClass)) return false;
+ if (interceptedClasses.contains(helpers.jsIntClass)) return false;
+ continue;
+ }
+ // Other uses need full distinction.
+ return false;
+ }
+ return true;
+ }
+
+ /// True if [node] can intercept a `null` value and return the [JSNull]
+ /// interceptor.
+ bool canInterceptNull(Interceptor node) {
+ for (Reference ref = node.firstRef; ref != null; ref = ref.next) {
+ Node use = ref.parent;
+ if (use is InvokeMethod) {
+ if (selectorsOnNull.contains(use.selector) &&
+ use.dartReceiver.type.isNullable) {
+ return true;
+ }
+ } else {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /// Returns the only interceptor class that may be returned by [node], or
+ /// `null` if no such class could be found.
+ ClassElement getSingleInterceptorClass(Interceptor node) {
+ // TODO(asgerf): This could be more precise if we used the use-site type,
+ // since the interceptor may have been hoisted out of a loop, where a less
+ // precise type is known.
+ Primitive input = node.input.definition;
+ TypeMask type = input.type;
+ if (canInterceptNull(node)) return null;
+ type = type.nonNullable();
+ if (typeSystem.isDefinitelyArray(type)) {
+ return backend.helpers.jsArrayClass;
+ }
+ if (typeSystem.isDefinitelyInt(type)) {
+ return backend.helpers.jsIntClass;
+ }
+ if (typeSystem.isDefinitelyNum(type) && jsNumberClassSuffices(node)) {
+ return backend.helpers.jsNumberClass;
+ }
+ ClassElement singleClass = type.singleClass(classWorld);
+ if (singleClass != null &&
+ singleClass.isSubclassOf(backend.helpers.jsInterceptorClass)) {
+ return singleClass;
+ }
+ return null;
+ }
+
+ /// Try to replace [interceptor] with a constant, and return `true` if
+ /// successful.
bool constifyInterceptor(Interceptor interceptor) {
LetPrim let = interceptor.parent;
- InterceptorConstantValue constant = getInterceptorConstant(interceptor);
+ Primitive input = interceptor.input.definition;
+ ClassElement classElement = getSingleInterceptorClass(interceptor);
- if (constant == null) return false;
+ if (classElement == null) return false;
+ ConstantValue constant = new InterceptorConstantValue(classElement.rawType);
- if (interceptor.isAlwaysIntercepted) {
+ if (!input.type.isNullable) {
Primitive constantPrim = makeConstantFor(constant,
useSite: let,
type: interceptor.type,
@@ -117,8 +212,7 @@ class OptimizeInterceptors extends TrampolineRecursiveVisitor implements Pass {
constantPrim.useElementAsHint(interceptor.hint);
interceptor..replaceUsesWith(constantPrim)..destroy();
let.remove();
- } else if (interceptor.isAlwaysNullOrIntercepted) {
- Primitive input = interceptor.input.definition;
+ } else {
Primitive constantPrim = makeConstantFor(constant,
useSite: let,
type: interceptor.type.nonNullable(),
@@ -127,7 +221,7 @@ class OptimizeInterceptors extends TrampolineRecursiveVisitor implements Pass {
Parameter param = new Parameter(interceptor.hint);
param.type = interceptor.type;
Continuation cont = cps.letCont(<Parameter>[param]);
- if (interceptor.interceptedClasses.every(hasNoFalsyValues)) {
+ if (hasNoFalsyValues(classElement)) {
// If null is the only falsy value, compile as "x && CONST".
cps.ifFalsy(input).invokeContinuation(cont, [input]);
} else {
@@ -156,6 +250,7 @@ class OptimizeInterceptors extends TrampolineRecursiveVisitor implements Pass {
@override
void visitInterceptor(Interceptor node) {
if (constifyInterceptor(node)) return;
+ computeInterceptedClasses(node);
if (node.hasExactlyOneUse) {
// Set the loop header on single-use interceptors so [visitInvokeMethod]
// can determine if it should become a one-shot interceptor.
« no previous file with comments | « pkg/compiler/lib/src/cps_ir/gvn.dart ('k') | pkg/compiler/lib/src/cps_ir/optimizers.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698