Index: pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart |
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart |
index cbb45f0e81aa9504dbe05bdf5a26d544672b77a4..1df27b6739fb4e551e378f0aa142018eb6f18a1e 100644 |
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart |
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart |
@@ -1184,22 +1184,85 @@ class CreateInstance extends Primitive { |
} |
} |
+/// Obtains the interceptor for the given value. This is a method table |
+/// corresponding to the Dart class of the value. |
+/// |
+/// All values are either intercepted or self-intercepted. The interceptor for |
+/// an "intercepted value" is one of the subclasses of Interceptor. |
+/// The interceptor for a "self-intercepted value" is the value itself. |
+/// |
+/// If the input is an intercepted value, and any of its superclasses is in |
+/// [interceptedClasses], the method table for the input is returned. |
+/// Otherwise, the input itself is returned. |
+/// |
+/// There are thus three significant cases: |
+/// - the input is a self-interceptor |
+/// - the input is an intercepted value and is caught by [interceptedClasses] |
+/// - the input is an intercepted value but is bypassed by [interceptedClasses] |
+/// |
+/// The [flags] field indicates which of the above cases may happen, with |
+/// additional special cases for null (which can either by intercepted or |
+/// bypassed). |
class Interceptor extends Primitive { |
final Reference<Primitive> input; |
final Set<ClassElement> interceptedClasses = new Set<ClassElement>(); |
final SourceInformation sourceInformation; |
- /// If non-null, all uses of this the interceptor call are guaranteed to |
- /// see this value. |
- /// |
- /// The interceptor call is not immediately replaced by the constant, because |
- /// that might prevent the interceptor from being shared. |
- /// |
- /// The precise input type is not known when sharing interceptors, because |
- /// refinement nodes have been removed by then. So this field carries the |
- /// known constant until we know if it should be shared or replaced by |
- /// the constant. |
- values.InterceptorConstantValue constantValue; |
+ /// The input was a self-interceptor. |
+ static const int SELF_INTERCEPT = 1 << 0; |
+ |
+ /// A non-null value was mapped to an interceptor that was mentioned in |
+ /// [interceptedClasses]. |
+ static const int NON_NULL_INTERCEPT_EXACT = 1 << 1; |
+ |
+ /// A non-null value was mapped to an interceptor that is a subclass of |
+ /// one mentioned in [interceptedClasses]. |
+ static const int NON_NULL_INTERCEPT_SUBCLASS = 1 << 2; |
+ |
+ /// A non-null intercepted value was bypassed because none of its supertypes |
+ /// were mentioned in [interceptedClasses]. |
+ static const int NON_NULL_BYPASS = 1 << 3; |
+ |
+ /// Null was returned as-is. |
+ static const int NULL_BYPASS = 1 << 4; |
+ |
+ /// Null was mapped to JSNull, which was mentioned in [interceptedClasses]. |
+ static const int NULL_INTERCEPT_EXACT = 1 << 5; |
+ |
+ /// Null was mapped to JSNull, because a superclass thereof (the interceptor |
+ /// root class) was mentioned in [interceptedClasses]. |
+ static const int NULL_INTERCEPT_SUBCLASS = 1 << 6; |
+ |
+ static const int NON_NULL_INTERCEPT = NON_NULL_INTERCEPT_EXACT | |
+ NON_NULL_INTERCEPT_SUBCLASS; |
+ static const int NULL_INTERCEPT = NULL_INTERCEPT_EXACT | |
+ NULL_INTERCEPT_SUBCLASS; |
+ static const int NULL = NULL_BYPASS | |
+ NULL_INTERCEPT; |
+ static const int INTERCEPT_EXACT = NON_NULL_INTERCEPT_EXACT | |
+ NULL_INTERCEPT_EXACT; |
+ static const int INTERCEPT_SUBCLASS = NON_NULL_INTERCEPT_SUBCLASS | |
+ NULL_INTERCEPT_SUBCLASS; |
+ static const int INTERCEPT = NULL_INTERCEPT | NON_NULL_INTERCEPT; |
+ static const int BYPASS = NULL_BYPASS | NON_NULL_BYPASS; |
+ |
+ static const int ALL_FLAGS = SELF_INTERCEPT | BYPASS | INTERCEPT; |
+ |
+ /// Which of the above cases may happen at runtime. Set by type propagation. |
+ int flags = ALL_FLAGS; |
+ |
+ void clearFlag(int flag) { |
+ flags &= ~flag; |
+ } |
+ |
+ bool get isAlwaysIntercepted => flags & ~INTERCEPT == 0; |
+ bool get isAlwaysNullOrIntercepted => flags & ~(NULL | INTERCEPT) == 0; |
+ |
+ /// If the value is intercepted, it always matches exactly a class in |
+ /// [interceptedClasses]. |
+ bool get isInterceptedClassAlwaysExact { |
+ return flags & (INTERCEPT & ~INTERCEPT_EXACT) == 0; |
+ } |
Interceptor(Primitive input, this.sourceInformation) |
: this.input = new Reference<Primitive>(input); |