| Index: sdk/lib/_internal/compiler/implementation/ssa/builder.dart
|
| ===================================================================
|
| --- sdk/lib/_internal/compiler/implementation/ssa/builder.dart (revision 19306)
|
| +++ sdk/lib/_internal/compiler/implementation/ssa/builder.dart (working copy)
|
| @@ -11,10 +11,8 @@
|
| */
|
| class InterceptedElement extends ElementX {
|
| final HType ssaType;
|
| - InterceptedElement(this.ssaType, Element enclosing)
|
| - : super(const SourceString('receiver'),
|
| - ElementKind.PARAMETER,
|
| - enclosing);
|
| + InterceptedElement(this.ssaType, SourceString name, Element enclosing)
|
| + : super(name, ElementKind.PARAMETER, enclosing);
|
|
|
| DartType computeType(Compiler compiler) => ssaType.computeType(compiler);
|
| }
|
| @@ -325,10 +323,12 @@
|
| }
|
|
|
| // If this method is an intercepted method, add the extra
|
| - // parameter to it, that is the actual receiver.
|
| + // parameter to it, that is the actual receiver for intercepted
|
| + // classes, or the same as [:this:] for non-intercepted classes.
|
| ClassElement cls = element.getEnclosingClass();
|
| - if (builder.backend.isInterceptorClass(cls)) {
|
| + if (builder.backend.isInterceptedMethod(element)) {
|
| HType type = HType.UNKNOWN;
|
| + SourceString name = const SourceString('receiver');
|
| if (cls == builder.backend.jsArrayClass) {
|
| type = HType.READABLE_ARRAY;
|
| } else if (cls == builder.backend.jsStringClass) {
|
| @@ -343,12 +343,21 @@
|
| type = HType.NULL;
|
| } else if (cls == builder.backend.jsBoolClass) {
|
| type = HType.BOOLEAN;
|
| + } else if (cls == builder.backend.jsFunctionClass) {
|
| + type = HType.UNKNOWN;
|
| + } else if (cls != compiler.objectClass) {
|
| + JavaScriptBackend backend = compiler.backend;
|
| + assert(!backend.isInterceptorClass(cls));
|
| + name = const SourceString('_');
|
| }
|
| - Element parameter = new InterceptedElement(type, element);
|
| + Element parameter = new InterceptedElement(type, name, element);
|
| HParameterValue value = new HParameterValue(parameter);
|
| builder.graph.entry.addAfter(
|
| directLocals[closureData.thisElement], value);
|
| - directLocals[closureData.thisElement] = value;
|
| + if (builder.backend.isInterceptorClass(cls.declaration)) {
|
| + // Only use the extra parameter in intercepted classes.
|
| + directLocals[closureData.thisElement] = value;
|
| + }
|
| value.instructionType = type;
|
| }
|
| }
|
| @@ -895,6 +904,18 @@
|
| // check at the beginning of the method. This is to avoid having
|
| // call sites do the null check.
|
| if (name == const SourceString('==')) {
|
| + if (functionElement.getEnclosingClass() == compiler.objectClass) {
|
| + // We special case [Object.operator==] because we know the
|
| + // receiver is not null and therefore can just do an identity
|
| + // check on [:this:]. The interceptor classes have their own
|
| + // synthesized [:operator==:] method.
|
| + HInstruction parameter = parameters.values.first;
|
| + HIdentity identity = new HIdentity(graph.thisInstruction, parameter);
|
| + add(identity);
|
| + HReturn ret = new HReturn(identity);
|
| + close(ret).addSuccessor(graph.exit);
|
| + return closeFunction();
|
| + }
|
| handleIf(
|
| function,
|
| () {
|
| @@ -2293,20 +2314,17 @@
|
| }
|
|
|
| /**
|
| - * Returns a set of interceptor classes that contain a member whose
|
| - * signature matches the given [selector].
|
| + * Returns a set of interceptor classes that contain the given
|
| + * [selector].
|
| */
|
| - Set<ClassElement> getInterceptedClassesOn(Selector selector) {
|
| - return backend.getInterceptedClassesOn(selector);
|
| - }
|
| -
|
| void generateInstanceGetterWithCompiledReceiver(Send send,
|
| Selector selector,
|
| HInstruction receiver) {
|
| assert(Elements.isInstanceSend(send, elements));
|
| assert(selector.isGetter());
|
| SourceString getterName = selector.name;
|
| - Set<ClassElement> interceptedClasses = getInterceptedClassesOn(selector);
|
| + Set<ClassElement> interceptedClasses =
|
| + backend.getInterceptedClassesOn(getterName);
|
|
|
| bool hasGetter = compiler.world.hasAnyUserDefinedGetter(selector);
|
| HInstruction instruction;
|
| @@ -2382,7 +2400,8 @@
|
| assert(selector.isSetter());
|
| SourceString setterName = selector.name;
|
| bool hasSetter = compiler.world.hasAnyUserDefinedSetter(selector);
|
| - Set<ClassElement> interceptedClasses = getInterceptedClassesOn(selector);
|
| + Set<ClassElement> interceptedClasses =
|
| + backend.getInterceptedClassesOn(setterName);
|
| if (interceptedClasses != null) {
|
| // If we're using an interceptor class, emit a call to the
|
| // getInterceptor method and then the actual dynamic call on the
|
| @@ -3044,10 +3063,11 @@
|
| argumentNamesInstruction,
|
| HType.UNKNOWN);
|
|
|
| - var inputs = <HInstruction>[
|
| - target,
|
| - self,
|
| - pop()];
|
| + var inputs = <HInstruction>[target, self];
|
| + if (backend.isInterceptedMethod(element)) {
|
| + inputs.add(self);
|
| + }
|
| + inputs.add(pop());
|
| push(new HInvokeSuper(inputs));
|
| }
|
|
|
| @@ -3071,6 +3091,9 @@
|
| HInstruction context = localsHandler.readThis();
|
| add(target);
|
| var inputs = <HInstruction>[target, context];
|
| + if (backend.isInterceptedMethod(element)) {
|
| + inputs.add(context);
|
| + }
|
| if (node.isPropertyAccess) {
|
| push(new HInvokeSuper(inputs));
|
| } else if (element.isFunction() || element.isGenerativeConstructor()) {
|
| @@ -3510,7 +3533,8 @@
|
| Selector selector,
|
| HInstruction receiver,
|
| List<HInstruction> arguments) {
|
| - Set<ClassElement> interceptedClasses = getInterceptedClassesOn(selector);
|
| + Set<ClassElement> interceptedClasses =
|
| + backend.getInterceptedClassesOn(selector.name);
|
| List<HInstruction> inputs = <HInstruction>[];
|
| bool isIntercepted = interceptedClasses != null;
|
| if (isIntercepted) {
|
| @@ -3868,7 +3892,8 @@
|
| HInstruction iterator;
|
| void buildInitializer() {
|
| Selector selector = elements.getIteratorSelector(node);
|
| - Set<ClassElement> interceptedClasses = getInterceptedClassesOn(selector);
|
| + Set<ClassElement> interceptedClasses =
|
| + backend.getInterceptedClassesOn(selector.name);
|
| visit(node.expression);
|
| HInstruction receiver = pop();
|
| bool hasGetter = compiler.world.hasAnyUserDefinedGetter(selector);
|
|
|