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 4ca64fa9146fd54468609f8a13c39731494bf41a..f7ff67ffc8f02436e8f1703f11c181dc2d3749e0 100644 |
--- a/pkg/compiler/lib/src/js_backend/codegen/unsugar.dart |
+++ b/pkg/compiler/lib/src/js_backend/codegen/unsugar.dart |
@@ -7,7 +7,6 @@ import '../../constants/values.dart'; |
import '../../elements/elements.dart'; |
import '../../js_backend/codegen/glue.dart'; |
import '../../universe/selector.dart' show Selector; |
-import '../../cps_ir/cps_ir_builder.dart' show ThisParameterLocal; |
import '../../cps_ir/cps_fragment.dart'; |
import '../../common/names.dart'; |
@@ -38,8 +37,13 @@ class InterceptorEntity extends Entity { |
class UnsugarVisitor extends TrampolineRecursiveVisitor implements Pass { |
Glue _glue; |
- Parameter thisParameter; |
- Parameter explicitReceiverParameter; |
+ FunctionDefinition function; |
+ |
+ Parameter get receiverParameter => function.receiverParameter; |
+ |
+ /// The interceptor of the receiver. For some methods, this is the receiver |
+ /// itself, for others, it is the interceptor parameter. |
+ Parameter receiverInterceptor; |
// In a catch block, rethrow implicitly throws the block's exception |
// parameter. This is the exception parameter when nested in a catch |
@@ -50,15 +54,8 @@ class UnsugarVisitor extends TrampolineRecursiveVisitor implements Pass { |
String get passName => 'Unsugaring'; |
- bool methodUsesReceiverArgument(FunctionElement function) { |
- assert(_glue.isInterceptedMethod(function)); |
- ClassElement clazz = function.enclosingClass.declaration; |
- return _glue.isInterceptorClass(clazz) || |
- _glue.isUsedAsMixin(clazz); |
- } |
- |
void rewrite(FunctionDefinition function) { |
- thisParameter = function.thisParameter; |
+ this.function = function; |
bool inInterceptedMethod = _glue.isInterceptedMethod(function.element); |
if (function.element.name == '==' && |
@@ -70,15 +67,16 @@ class UnsugarVisitor extends TrampolineRecursiveVisitor implements Pass { |
} |
if (inInterceptedMethod) { |
- ThisParameterLocal holder = thisParameter.hint; |
- explicitReceiverParameter = new Parameter( |
- new ExplicitReceiverParameterEntity(holder.executableContext)); |
- explicitReceiverParameter.parent = function; |
- function.parameters.insert(0, explicitReceiverParameter); |
- } |
- |
- if (inInterceptedMethod && methodUsesReceiverArgument(function.element)) { |
- thisParameter.replaceUsesWith(explicitReceiverParameter); |
+ function.interceptorParameter = new Parameter(null)..parent = function; |
+ // Since the receiver won't be compiled to "this", set a hint on it |
+ // so the parameter gets a meaningful name. |
+ function.receiverParameter.hint = |
+ new ExplicitReceiverParameterEntity(function.element); |
+ // If we need an interceptor for the receiver, use the receiver itself |
+ // if possible, otherwise the interceptor argument. |
+ receiverInterceptor = _glue.methodUsesReceiverArgument(function.element) |
+ ? function.interceptorParameter |
+ : receiverParameter; |
} |
visit(function); |
@@ -211,45 +209,44 @@ class UnsugarVisitor extends TrampolineRecursiveVisitor implements Pass { |
} |
Primitive receiver = node.receiver; |
- Primitive newReceiver; |
+ Primitive interceptor; |
- if (receiver == explicitReceiverParameter) { |
- // If the receiver is the explicit receiver, we are calling a method in |
+ if (receiver == receiverParameter && receiverInterceptor != null) { |
+ // TODO(asgerf): This could be done by GVN. |
+ // If the receiver is 'this', we are calling a method in |
// the same interceptor: |
// Change 'receiver.foo()' to 'this.foo(receiver)'. |
- newReceiver = thisParameter; |
+ interceptor = receiverInterceptor; |
} else { |
- newReceiver = new Interceptor(receiver, node.sourceInformation); |
+ interceptor = new Interceptor(receiver, node.sourceInformation); |
if (receiver.hint != null) { |
- newReceiver.hint = new InterceptorEntity(receiver.hint); |
+ interceptor.hint = new InterceptorEntity(receiver.hint); |
} |
- new LetPrim(newReceiver).insertAbove(node.parent); |
+ new LetPrim(interceptor).insertAbove(node.parent); |
} |
- node.argumentRefs.insert(0, node.receiverRef); |
- node.receiverRef = new Reference<Primitive>(newReceiver)..parent = node; |
- node.callingConvention = CallingConvention.Intercepted; |
+ assert(node.interceptorRef == null); |
+ node.makeIntercepted(interceptor); |
} |
processInvokeMethodDirectly(InvokeMethodDirectly node) { |
if (!_glue.isInterceptedMethod(node.target)) return; |
Primitive receiver = node.receiver; |
- Primitive newReceiver; |
+ Primitive interceptor; |
- if (receiver == explicitReceiverParameter) { |
- // If the receiver is the explicit receiver, we are calling a method in |
+ if (receiver == receiverParameter && receiverInterceptor != null) { |
+ // If the receiver is 'this', we are calling a method in |
// the same interceptor: |
// Change 'receiver.foo()' to 'this.foo(receiver)'. |
- newReceiver = thisParameter; |
+ interceptor = receiverInterceptor; |
} else { |
- newReceiver = new Interceptor(receiver, node.sourceInformation); |
+ interceptor = new Interceptor(receiver, node.sourceInformation); |
if (receiver.hint != null) { |
- newReceiver.hint = new InterceptorEntity(receiver.hint); |
+ interceptor.hint = new InterceptorEntity(receiver.hint); |
} |
- new LetPrim(newReceiver).insertAbove(node.parent); |
+ new LetPrim(interceptor).insertAbove(node.parent); |
} |
- node.argumentRefs.insert(0, node.receiverRef); |
- node.receiverRef = new Reference<Primitive>(newReceiver)..parent = node; |
- node.callingConvention = CallingConvention.Intercepted; |
+ assert(node.interceptorRef == null); |
+ node.makeIntercepted(interceptor); |
} |
} |