OLD | NEW |
---|---|
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 part of ssa; | 5 part of ssa; |
6 | 6 |
7 /** | 7 /** |
8 * A special element for the extra parameter taken by intercepted | 8 * A special element for the extra parameter taken by intercepted |
9 * methods. We need to override [Element.computeType] because our | 9 * methods. We need to override [Element.computeType] because our |
10 * optimizers may look at its declared type. | 10 * optimizers may look at its declared type. |
11 */ | 11 */ |
12 class InterceptedElement extends ElementX { | 12 class InterceptedElement extends ElementX { |
13 final HType ssaType; | 13 final HType ssaType; |
14 InterceptedElement(this.ssaType, Element enclosing) | 14 InterceptedElement(this.ssaType, Element enclosing) |
15 : super(const SourceString('receiver'), | 15 : super(const SourceString('receiver'), |
ngeoffray
2013/02/28 10:39:42
Changed the name to '_' in case of a non-intercept
| |
16 ElementKind.PARAMETER, | 16 ElementKind.PARAMETER, |
17 enclosing); | 17 enclosing); |
18 | 18 |
19 DartType computeType(Compiler compiler) => ssaType.computeType(compiler); | 19 DartType computeType(Compiler compiler) => ssaType.computeType(compiler); |
20 } | 20 } |
21 | 21 |
22 class SsaBuilderTask extends CompilerTask { | 22 class SsaBuilderTask extends CompilerTask { |
23 final CodeEmitterTask emitter; | 23 final CodeEmitterTask emitter; |
24 final JavaScriptBackend backend; | 24 final JavaScriptBackend backend; |
25 | 25 |
(...skipping 292 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
318 // not have any thisElement if the closure was created inside a static | 318 // not have any thisElement if the closure was created inside a static |
319 // context. | 319 // context. |
320 HThis thisInstruction = new HThis( | 320 HThis thisInstruction = new HThis( |
321 closureData.thisElement, getTypeOfThis()); | 321 closureData.thisElement, getTypeOfThis()); |
322 builder.graph.thisInstruction = thisInstruction; | 322 builder.graph.thisInstruction = thisInstruction; |
323 builder.graph.entry.addAtEntry(thisInstruction); | 323 builder.graph.entry.addAtEntry(thisInstruction); |
324 directLocals[closureData.thisElement] = thisInstruction; | 324 directLocals[closureData.thisElement] = thisInstruction; |
325 } | 325 } |
326 | 326 |
327 // If this method is an intercepted method, add the extra | 327 // If this method is an intercepted method, add the extra |
328 // parameter to it, that is the actual receiver. | 328 // parameter to it, that is the actual receiver for intercepted |
329 // classes, or the same as [:this:] for non-intercepted classes. | |
329 ClassElement cls = element.getEnclosingClass(); | 330 ClassElement cls = element.getEnclosingClass(); |
330 if (builder.backend.isInterceptorClass(cls)) { | 331 if (builder.backend.isInterceptedMethod(element)) { |
331 HType type = HType.UNKNOWN; | 332 HType type = HType.UNKNOWN; |
332 if (cls == builder.backend.jsArrayClass) { | 333 if (cls == builder.backend.jsArrayClass) { |
333 type = HType.READABLE_ARRAY; | 334 type = HType.READABLE_ARRAY; |
334 } else if (cls == builder.backend.jsStringClass) { | 335 } else if (cls == builder.backend.jsStringClass) { |
335 type = HType.STRING; | 336 type = HType.STRING; |
336 } else if (cls == builder.backend.jsNumberClass) { | 337 } else if (cls == builder.backend.jsNumberClass) { |
337 type = HType.NUMBER; | 338 type = HType.NUMBER; |
338 } else if (cls == builder.backend.jsIntClass) { | 339 } else if (cls == builder.backend.jsIntClass) { |
339 type = HType.INTEGER; | 340 type = HType.INTEGER; |
340 } else if (cls == builder.backend.jsDoubleClass) { | 341 } else if (cls == builder.backend.jsDoubleClass) { |
341 type = HType.DOUBLE; | 342 type = HType.DOUBLE; |
342 } else if (cls == builder.backend.jsNullClass) { | 343 } else if (cls == builder.backend.jsNullClass) { |
343 type = HType.NULL; | 344 type = HType.NULL; |
344 } else if (cls == builder.backend.jsBoolClass) { | 345 } else if (cls == builder.backend.jsBoolClass) { |
345 type = HType.BOOLEAN; | 346 type = HType.BOOLEAN; |
346 } | 347 } |
347 Element parameter = new InterceptedElement(type, element); | 348 Element parameter = new InterceptedElement(type, element); |
348 HParameterValue value = new HParameterValue(parameter); | 349 HParameterValue value = new HParameterValue(parameter); |
349 builder.graph.entry.addAfter( | 350 builder.graph.entry.addAfter( |
350 directLocals[closureData.thisElement], value); | 351 directLocals[closureData.thisElement], value); |
351 directLocals[closureData.thisElement] = value; | 352 if (builder.backend.isInterceptorClass(cls.declaration)) { |
353 // Only use the extra parameter in intercepted classes. | |
354 directLocals[closureData.thisElement] = value; | |
355 } | |
352 value.instructionType = type; | 356 value.instructionType = type; |
353 } | 357 } |
354 } | 358 } |
355 | 359 |
356 bool hasValueForDirectLocal(Element element) { | 360 bool hasValueForDirectLocal(Element element) { |
357 assert(element != null); | 361 assert(element != null); |
358 assert(isAccessedDirectly(element)); | 362 assert(isAccessedDirectly(element)); |
359 return directLocals[element] != null; | 363 return directLocals[element] != null; |
360 } | 364 } |
361 | 365 |
(...skipping 526 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
888 FunctionExpression function = functionElement.parseNode(compiler); | 892 FunctionExpression function = functionElement.parseNode(compiler); |
889 assert(function != null); | 893 assert(function != null); |
890 assert(!function.modifiers.isExternal()); | 894 assert(!function.modifiers.isExternal()); |
891 assert(elements[function] != null); | 895 assert(elements[function] != null); |
892 openFunction(functionElement, function); | 896 openFunction(functionElement, function); |
893 SourceString name = functionElement.name; | 897 SourceString name = functionElement.name; |
894 // If [functionElement] is operator== we explicitely add a null | 898 // If [functionElement] is operator== we explicitely add a null |
895 // check at the beginning of the method. This is to avoid having | 899 // check at the beginning of the method. This is to avoid having |
896 // call sites do the null check. | 900 // call sites do the null check. |
897 if (name == const SourceString('==')) { | 901 if (name == const SourceString('==')) { |
902 if (functionElement.getEnclosingClass() == compiler.objectClass) { | |
903 // We special case [Object.operator==] because we know the | |
904 // receiver is not null and therefore can just do an identity | |
905 // check on [:this:]. The interceptor classes have their own | |
906 // synthesized [:operator==:] method. | |
907 HInstruction parameter = parameters.values.first; | |
908 HIdentity identity = new HIdentity(graph.thisInstruction, parameter); | |
909 add(identity); | |
910 HReturn ret = new HReturn(identity); | |
911 close(ret).addSuccessor(graph.exit); | |
912 return closeFunction(); | |
913 } | |
898 handleIf( | 914 handleIf( |
899 function, | 915 function, |
900 () { | 916 () { |
901 HParameterValue parameter = parameters.values.first; | 917 HParameterValue parameter = parameters.values.first; |
902 push(new HIdentity( | 918 push(new HIdentity( |
903 parameter, graph.addConstantNull(constantSystem))); | 919 parameter, graph.addConstantNull(constantSystem))); |
904 }, | 920 }, |
905 () { | 921 () { |
906 HReturn ret = new HReturn( | 922 HReturn ret = new HReturn( |
907 graph.addConstantBool(false, constantSystem)); | 923 graph.addConstantBool(false, constantSystem)); |
(...skipping 1436 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2344 | 2360 |
2345 String getTargetName(ErroneousElement error, [String prefix]) { | 2361 String getTargetName(ErroneousElement error, [String prefix]) { |
2346 String result = error.name.slowToString(); | 2362 String result = error.name.slowToString(); |
2347 if (?prefix) { | 2363 if (?prefix) { |
2348 result = '$prefix $result'; | 2364 result = '$prefix $result'; |
2349 } | 2365 } |
2350 return result; | 2366 return result; |
2351 } | 2367 } |
2352 | 2368 |
2353 /** | 2369 /** |
2354 * Returns a set of interceptor classes that contain a member whose | 2370 * Returns a set of interceptor classes that contain the given |
2355 * signature matches the given [selector]. | 2371 * [selector]. |
2356 */ | 2372 */ |
2357 Set<ClassElement> getInterceptedClassesOn(Selector selector) { | |
2358 return backend.getInterceptedClassesOn(selector); | |
2359 } | |
2360 | |
2361 void generateInstanceGetterWithCompiledReceiver(Send send, | 2373 void generateInstanceGetterWithCompiledReceiver(Send send, |
2362 HInstruction receiver) { | 2374 HInstruction receiver) { |
2363 assert(Elements.isInstanceSend(send, elements)); | 2375 assert(Elements.isInstanceSend(send, elements)); |
2364 // TODO(kasperl): This is a convoluted way of checking if we're | 2376 // TODO(kasperl): This is a convoluted way of checking if we're |
2365 // generating code for a compound assignment. If we are, we need | 2377 // generating code for a compound assignment. If we are, we need |
2366 // to get the selector from the mapping for the AST selector node. | 2378 // to get the selector from the mapping for the AST selector node. |
2367 Selector selector = (send.asSendSet() == null) | 2379 Selector selector = (send.asSendSet() == null) |
2368 ? elements.getSelector(send) | 2380 ? elements.getSelector(send) |
2369 : elements.getSelector(send.selector); | 2381 : elements.getSelector(send.selector); |
2370 assert(selector.isGetter()); | 2382 assert(selector.isGetter()); |
2371 SourceString getterName = selector.name; | 2383 SourceString getterName = selector.name; |
2372 Set<ClassElement> interceptedClasses = getInterceptedClassesOn(selector); | 2384 Set<ClassElement> interceptedClasses = |
2385 backend.getInterceptedClassesOn(getterName); | |
2373 | 2386 |
2374 bool hasGetter = compiler.world.hasAnyUserDefinedGetter(selector); | 2387 bool hasGetter = compiler.world.hasAnyUserDefinedGetter(selector); |
2375 HInstruction instruction; | 2388 HInstruction instruction; |
2376 if (interceptedClasses != null) { | 2389 if (interceptedClasses != null) { |
2377 // If we're using an interceptor class, emit a call to the | 2390 // If we're using an interceptor class, emit a call to the |
2378 // interceptor method and then the actual dynamic call on the | 2391 // interceptor method and then the actual dynamic call on the |
2379 // interceptor object. | 2392 // interceptor object. |
2380 instruction = | 2393 instruction = |
2381 invokeInterceptor(interceptedClasses, receiver, send); | 2394 invokeInterceptor(interceptedClasses, receiver, send); |
2382 instruction = new HInvokeDynamicGetter( | 2395 instruction = new HInvokeDynamicGetter( |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2437 } | 2450 } |
2438 | 2451 |
2439 void generateInstanceSetterWithCompiledReceiver(Send send, | 2452 void generateInstanceSetterWithCompiledReceiver(Send send, |
2440 HInstruction receiver, | 2453 HInstruction receiver, |
2441 HInstruction value) { | 2454 HInstruction value) { |
2442 assert(Elements.isInstanceSend(send, elements)); | 2455 assert(Elements.isInstanceSend(send, elements)); |
2443 Selector selector = elements.getSelector(send); | 2456 Selector selector = elements.getSelector(send); |
2444 assert(selector.isSetter()); | 2457 assert(selector.isSetter()); |
2445 SourceString setterName = selector.name; | 2458 SourceString setterName = selector.name; |
2446 bool hasSetter = compiler.world.hasAnyUserDefinedSetter(selector); | 2459 bool hasSetter = compiler.world.hasAnyUserDefinedSetter(selector); |
2447 Set<ClassElement> interceptedClasses = getInterceptedClassesOn(selector); | 2460 Set<ClassElement> interceptedClasses = |
2461 backend.getInterceptedClassesOn(setterName); | |
2448 if (interceptedClasses != null) { | 2462 if (interceptedClasses != null) { |
2449 // If we're using an interceptor class, emit a call to the | 2463 // If we're using an interceptor class, emit a call to the |
2450 // getInterceptor method and then the actual dynamic call on the | 2464 // getInterceptor method and then the actual dynamic call on the |
2451 // interceptor object. | 2465 // interceptor object. |
2452 HInstruction instruction = | 2466 HInstruction instruction = |
2453 invokeInterceptor(interceptedClasses, receiver, send); | 2467 invokeInterceptor(interceptedClasses, receiver, send); |
2454 instruction = new HInvokeDynamicSetter( | 2468 instruction = new HInvokeDynamicSetter( |
2455 selector, null, instruction, receiver, !hasSetter); | 2469 selector, null, instruction, receiver, !hasSetter); |
2456 // Add the value as an argument to the setter call on the | 2470 // Add the value as an argument to the setter call on the |
2457 // interceptor. | 2471 // interceptor. |
(...skipping 636 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3094 constantSystem.createInt(selector.invocationMirrorKind); | 3108 constantSystem.createInt(selector.invocationMirrorKind); |
3095 | 3109 |
3096 pushInvokeHelper5(createInvocationMirror, | 3110 pushInvokeHelper5(createInvocationMirror, |
3097 graph.addConstant(nameConstant), | 3111 graph.addConstant(nameConstant), |
3098 graph.addConstant(internalNameConstant), | 3112 graph.addConstant(internalNameConstant), |
3099 graph.addConstant(kindConstant), | 3113 graph.addConstant(kindConstant), |
3100 argumentsInstruction, | 3114 argumentsInstruction, |
3101 argumentNamesInstruction, | 3115 argumentNamesInstruction, |
3102 HType.UNKNOWN); | 3116 HType.UNKNOWN); |
3103 | 3117 |
3104 var inputs = <HInstruction>[ | 3118 var inputs = <HInstruction>[target, self]; |
3105 target, | 3119 if (backend.isInterceptedMethod(element)) { |
3106 self, | 3120 inputs.add(self); |
3107 pop()]; | 3121 } |
3122 inputs.add(pop()); | |
3108 push(new HInvokeSuper(inputs)); | 3123 push(new HInvokeSuper(inputs)); |
3109 } | 3124 } |
3110 | 3125 |
3111 visitSend(Send node) { | 3126 visitSend(Send node) { |
3112 Element element = elements[node]; | 3127 Element element = elements[node]; |
3113 if (element != null && identical(element, currentElement)) { | 3128 if (element != null && identical(element, currentElement)) { |
3114 graph.isRecursiveMethod = true; | 3129 graph.isRecursiveMethod = true; |
3115 } | 3130 } |
3116 super.visitSend(node); | 3131 super.visitSend(node); |
3117 } | 3132 } |
3118 | 3133 |
3119 visitSuperSend(Send node) { | 3134 visitSuperSend(Send node) { |
3120 Selector selector = elements.getSelector(node); | 3135 Selector selector = elements.getSelector(node); |
3121 Element element = elements[node]; | 3136 Element element = elements[node]; |
3122 if (element == null) return generateSuperNoSuchMethodSend(node); | 3137 if (element == null) return generateSuperNoSuchMethodSend(node); |
3123 // TODO(5346): Try to avoid the need for calling [declaration] before | 3138 // TODO(5346): Try to avoid the need for calling [declaration] before |
3124 // creating an [HStatic]. | 3139 // creating an [HStatic]. |
3125 HInstruction target = new HStatic(element.declaration); | 3140 HInstruction target = new HStatic(element.declaration); |
3126 HInstruction context = localsHandler.readThis(); | 3141 HInstruction context = localsHandler.readThis(); |
3127 add(target); | 3142 add(target); |
3128 var inputs = <HInstruction>[target, context]; | 3143 var inputs = <HInstruction>[target, context]; |
3144 if (backend.isInterceptedMethod(element)) { | |
3145 inputs.add(context); | |
3146 } | |
3129 if (node.isPropertyAccess) { | 3147 if (node.isPropertyAccess) { |
3130 push(new HInvokeSuper(inputs)); | 3148 push(new HInvokeSuper(inputs)); |
3131 } else if (element.isFunction() || element.isGenerativeConstructor()) { | 3149 } else if (element.isFunction() || element.isGenerativeConstructor()) { |
3132 // TODO(5347): Try to avoid the need for calling [implementation] before | 3150 // TODO(5347): Try to avoid the need for calling [implementation] before |
3133 // calling [addStaticSendArgumentsToList]. | 3151 // calling [addStaticSendArgumentsToList]. |
3134 FunctionElement function = element.implementation; | 3152 FunctionElement function = element.implementation; |
3135 bool succeeded = addStaticSendArgumentsToList(selector, node.arguments, | 3153 bool succeeded = addStaticSendArgumentsToList(selector, node.arguments, |
3136 function, inputs); | 3154 function, inputs); |
3137 if (!succeeded) { | 3155 if (!succeeded) { |
3138 generateWrongArgumentCountError(node, element, node.arguments); | 3156 generateWrongArgumentCountError(node, element, node.arguments); |
(...skipping 419 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3558 visitNewSend(send, type); | 3576 visitNewSend(send, type); |
3559 } | 3577 } |
3560 } | 3578 } |
3561 } | 3579 } |
3562 } | 3580 } |
3563 | 3581 |
3564 HInvokeDynamicMethod buildInvokeDynamic(Node node, | 3582 HInvokeDynamicMethod buildInvokeDynamic(Node node, |
3565 Selector selector, | 3583 Selector selector, |
3566 HInstruction receiver, | 3584 HInstruction receiver, |
3567 List<HInstruction> arguments) { | 3585 List<HInstruction> arguments) { |
3568 Set<ClassElement> interceptedClasses = getInterceptedClassesOn(selector); | 3586 Set<ClassElement> interceptedClasses = |
3587 backend.getInterceptedClassesOn(selector.name); | |
3569 List<HInstruction> inputs = <HInstruction>[]; | 3588 List<HInstruction> inputs = <HInstruction>[]; |
3570 bool isIntercepted = interceptedClasses != null; | 3589 bool isIntercepted = interceptedClasses != null; |
3571 if (isIntercepted) { | 3590 if (isIntercepted) { |
3572 assert(!interceptedClasses.isEmpty); | 3591 assert(!interceptedClasses.isEmpty); |
3573 inputs.add(invokeInterceptor(interceptedClasses, receiver, node)); | 3592 inputs.add(invokeInterceptor(interceptedClasses, receiver, node)); |
3574 } | 3593 } |
3575 inputs.add(receiver); | 3594 inputs.add(receiver); |
3576 inputs.addAll(arguments); | 3595 inputs.addAll(arguments); |
3577 return new HInvokeDynamicMethod(selector, inputs, isIntercepted); | 3596 return new HInvokeDynamicMethod(selector, inputs, isIntercepted); |
3578 } | 3597 } |
(...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3912 // E <declaredIdentifier> = $iter.current; | 3931 // E <declaredIdentifier> = $iter.current; |
3913 // <body> | 3932 // <body> |
3914 // } | 3933 // } |
3915 | 3934 |
3916 // The iterator is shared between initializer, condition and body. | 3935 // The iterator is shared between initializer, condition and body. |
3917 HInstruction iterator; | 3936 HInstruction iterator; |
3918 void buildInitializer() { | 3937 void buildInitializer() { |
3919 SourceString iteratorName = const SourceString("iterator"); | 3938 SourceString iteratorName = const SourceString("iterator"); |
3920 Selector selector = | 3939 Selector selector = |
3921 new Selector.getter(iteratorName, currentElement.getLibrary()); | 3940 new Selector.getter(iteratorName, currentElement.getLibrary()); |
3922 Set<ClassElement> interceptedClasses = getInterceptedClassesOn(selector); | 3941 Set<ClassElement> interceptedClasses = |
3942 backend.getInterceptedClassesOn(selector.name); | |
3923 visit(node.expression); | 3943 visit(node.expression); |
3924 HInstruction receiver = pop(); | 3944 HInstruction receiver = pop(); |
3925 bool hasGetter = compiler.world.hasAnyUserDefinedGetter(selector); | 3945 bool hasGetter = compiler.world.hasAnyUserDefinedGetter(selector); |
3926 if (interceptedClasses == null) { | 3946 if (interceptedClasses == null) { |
3927 iterator = | 3947 iterator = |
3928 new HInvokeDynamicGetter(selector, null, receiver, !hasGetter); | 3948 new HInvokeDynamicGetter(selector, null, receiver, !hasGetter); |
3929 } else { | 3949 } else { |
3930 HInterceptor interceptor = | 3950 HInterceptor interceptor = |
3931 invokeInterceptor(interceptedClasses, receiver, null); | 3951 invokeInterceptor(interceptedClasses, receiver, null); |
3932 iterator = | 3952 iterator = |
(...skipping 1098 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5031 new HSubGraphBlockInformation(elseBranch.graph)); | 5051 new HSubGraphBlockInformation(elseBranch.graph)); |
5032 | 5052 |
5033 HBasicBlock conditionStartBlock = conditionBranch.block; | 5053 HBasicBlock conditionStartBlock = conditionBranch.block; |
5034 conditionStartBlock.setBlockFlow(info, joinBlock); | 5054 conditionStartBlock.setBlockFlow(info, joinBlock); |
5035 SubGraph conditionGraph = conditionBranch.graph; | 5055 SubGraph conditionGraph = conditionBranch.graph; |
5036 HIf branch = conditionGraph.end.last; | 5056 HIf branch = conditionGraph.end.last; |
5037 assert(branch is HIf); | 5057 assert(branch is HIf); |
5038 branch.blockInformation = conditionStartBlock.blockFlow; | 5058 branch.blockInformation = conditionStartBlock.blockFlow; |
5039 } | 5059 } |
5040 } | 5060 } |
OLD | NEW |