Index: pkg/compiler/lib/src/js_backend/codegen/unsugar.dart |
diff --git a/pkg/compiler/lib/src/js_backend/codegen/unsugar.dart b/pkg/compiler/lib/src/js_backend/codegen/unsugar.dart |
index bbe998f1f396f742fb02e2570ed10aa6e2a32156..110d156acc756a234b9a77331c9cf80e70068a9f 100644 |
--- a/pkg/compiler/lib/src/js_backend/codegen/unsugar.dart |
+++ b/pkg/compiler/lib/src/js_backend/codegen/unsugar.dart |
@@ -5,12 +5,7 @@ import '../../cps_ir/cps_ir_nodes.dart'; |
import '../../cps_ir/optimizers.dart' show ParentVisitor; |
import '../../constants/expressions.dart'; |
import '../../constants/values.dart'; |
-import '../../elements/elements.dart' show |
- ClassElement, |
- FieldElement, |
- FunctionElement, |
- Local, |
- ExecutableElement; |
+import '../../elements/elements.dart'; |
import '../../js_backend/codegen/glue.dart'; |
import '../../dart2jslib.dart' show Selector, World; |
import '../../cps_ir/cps_ir_builder.dart' show ThisParameterLocal; |
@@ -22,6 +17,16 @@ class ExplicitReceiverParameterEntity implements Local { |
toString() => 'ExplicitReceiverParameterEntity($executableContext)'; |
} |
+/// Suggested name for an interceptor. |
+class InterceptorEntity extends Entity { |
+ Entity interceptedVariable; |
+ |
+ InterceptorEntity(this.interceptedVariable); |
+ |
+ String get name => interceptedVariable.name + '_'; |
+} |
+ |
+ |
/// Rewrites the initial CPS IR to make Dart semantics explicit and inserts |
/// special nodes that respect JavaScript behavior. |
/// |
@@ -38,6 +43,8 @@ class UnsugarVisitor extends RecursiveVisitor { |
Parameter thisParameter; |
Parameter explicitReceiverParameter; |
+ Map<Primitive, Interceptor> interceptors = <Primitive, Interceptor>{}; |
+ |
// In a catch block, rethrow implicitly throws the block's exception |
// parameter. This is the exception parameter when nested in a catch |
// block and null otherwise. |
@@ -227,6 +234,32 @@ class UnsugarVisitor extends RecursiveVisitor { |
// worry about unlinking. |
} |
+ /// Returns an interceptor for the given value, capable of responding to |
+ /// [selector]. |
+ /// |
+ /// A single getInterceptor call will be created per primitive, bound |
+ /// immediately after the primitive is bound. |
+ /// |
+ /// The type propagation pass will later narrow the set of interceptors |
+ /// based on the input type, and the let sinking pass will propagate the |
+ /// getInterceptor call closer to its use when this is profitable. |
+ Interceptor getInterceptorFor(Primitive prim, Selector selector) { |
+ Interceptor interceptor = interceptors[prim]; |
+ if (interceptor == null) { |
+ interceptor = new Interceptor(prim); |
+ interceptors[prim] = interceptor; |
+ InteriorNode parent = prim.parent; |
+ insertLetPrim(interceptor, parent.body); |
+ if (prim.hint != null) { |
+ interceptor.hint = new InterceptorEntity(prim.hint); |
+ } |
+ } |
+ // Add the interceptor classes that can respond to the given selector. |
+ interceptor.interceptedClasses.addAll( |
+ _glue.getInterceptedClassesOn(selector)); |
+ return interceptor; |
+ } |
+ |
processInvokeMethod(InvokeMethod node) { |
Selector selector = node.selector; |
if (!_glue.isInterceptedSelector(selector)) return; |
@@ -240,13 +273,7 @@ class UnsugarVisitor extends RecursiveVisitor { |
// Change 'receiver.foo()' to 'this.foo(receiver)'. |
newReceiver = thisParameter; |
} else { |
- // TODO(sra): Move the computation of interceptedClasses to a much later |
- // phase and take into account the remaining uses of the interceptor. |
- Set<ClassElement> interceptedClasses = |
- _glue.getInterceptedClassesOn(selector); |
- _glue.registerSpecializedGetInterceptor(interceptedClasses); |
- newReceiver = new Interceptor(receiver, interceptedClasses); |
- insertLetPrim(newReceiver, node); |
+ newReceiver = getInterceptorFor(receiver, node.selector); |
} |
node.arguments.insert(0, node.receiver); |