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 class Interceptors { | 7 class Interceptors { |
8 Compiler compiler; | 8 Compiler compiler; |
9 Interceptors(Compiler this.compiler); | 9 Interceptors(Compiler this.compiler); |
10 | 10 |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
43 if (identical(name, '++')) return const SourceString('add'); | 43 if (identical(name, '++')) return const SourceString('add'); |
44 if (identical(name, '--')) return const SourceString('sub'); | 44 if (identical(name, '--')) return const SourceString('sub'); |
45 compiler.unimplemented('Unknown operator', node: op); | 45 compiler.unimplemented('Unknown operator', node: op); |
46 } | 46 } |
47 | 47 |
48 Element getStaticInterceptor(Selector selector) { | 48 Element getStaticInterceptor(Selector selector) { |
49 // Check if we have an interceptor method implemented with | 49 // Check if we have an interceptor method implemented with |
50 // interceptor classes. | 50 // interceptor classes. |
51 JavaScriptBackend backend = compiler.backend; | 51 JavaScriptBackend backend = compiler.backend; |
52 if (backend.shouldInterceptSelector(selector)) { | 52 if (backend.shouldInterceptSelector(selector)) { |
53 backend.addInterceptedSelector(selector); | |
54 return backend.getInterceptorMethod; | 53 return backend.getInterceptorMethod; |
55 } | 54 } |
56 | 55 |
57 // Fall back to the old interceptor mechanism. | 56 // Fall back to the old interceptor mechanism. |
58 String name = selector.name.slowToString(); | 57 String name = selector.name.slowToString(); |
59 if (selector.isGetter()) { | 58 if (selector.isGetter()) { |
60 // TODO(lrn): If there is no get-interceptor, but there is a | 59 // TODO(lrn): If there is no get-interceptor, but there is a |
61 // method-interceptor, we should generate a get-interceptor automatically. | 60 // method-interceptor, we should generate a get-interceptor automatically. |
62 String mangledName = "get\$$name"; | 61 String mangledName = "get\$$name"; |
63 return compiler.findInterceptor(new SourceString(mangledName)); | 62 return compiler.findInterceptor(new SourceString(mangledName)); |
(...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
402 enterScope(node, element); | 401 enterScope(node, element); |
403 | 402 |
404 // If the freeVariableMapping is not empty, then this function was a | 403 // If the freeVariableMapping is not empty, then this function was a |
405 // nested closure that captures variables. Redirect the captured | 404 // nested closure that captures variables. Redirect the captured |
406 // variables to fields in the closure. | 405 // variables to fields in the closure. |
407 closureData.freeVariableMapping.forEach((Element from, Element to) { | 406 closureData.freeVariableMapping.forEach((Element from, Element to) { |
408 redirectElement(from, to); | 407 redirectElement(from, to); |
409 }); | 408 }); |
410 if (closureData.isClosure()) { | 409 if (closureData.isClosure()) { |
411 // Inside closure redirect references to itself to [:this:]. | 410 // Inside closure redirect references to itself to [:this:]. |
412 HInstruction thisInstruction = new HThis(closureData.thisElement); | 411 builder.thisInstruction = new HThis(closureData.thisElement); |
413 builder.graph.entry.addAtEntry(thisInstruction); | 412 builder.graph.entry.addAtEntry(builder.thisInstruction); |
414 updateLocal(closureData.closureElement, thisInstruction); | 413 updateLocal(closureData.closureElement, builder.thisInstruction); |
415 } else if (element.isInstanceMember() | 414 } else if (element.isInstanceMember() |
416 || element.isGenerativeConstructor()) { | 415 || element.isGenerativeConstructor()) { |
417 // Once closures have been mapped to classes their instance members might | 416 // Once closures have been mapped to classes their instance members might |
418 // not have any thisElement if the closure was created inside a static | 417 // not have any thisElement if the closure was created inside a static |
419 // context. | 418 // context. |
420 ClassElement cls = element.getEnclosingClass(); | 419 ClassElement cls = element.getEnclosingClass(); |
421 DartType type = cls.computeType(builder.compiler); | 420 DartType type = cls.computeType(builder.compiler); |
422 HInstruction thisInstruction = new HThis(closureData.thisElement, | 421 builder.thisInstruction = new HThis(closureData.thisElement, |
423 new HBoundedType.nonNull(type)); | 422 new HBoundedType.nonNull(type)); |
424 thisInstruction.sourceElement = closureData.thisElement; | 423 builder.graph.entry.addAtEntry(builder.thisInstruction); |
425 builder.graph.entry.addAtEntry(thisInstruction); | 424 directLocals[closureData.thisElement] = builder.thisInstruction; |
426 directLocals[closureData.thisElement] = thisInstruction; | 425 } |
426 | |
427 if (builder.backend.isInterceptorClass(element.getEnclosingClass())) { | |
428 Element parameter = new Element( | |
429 const SourceString('receiver'), ElementKind.VARIABLE, element); | |
430 HParameterValue value = new HParameterValue(parameter); | |
431 builder.graph.entry.addAfter( | |
432 directLocals[closureData.thisElement], value); | |
433 directLocals[closureData.thisElement] = value; | |
427 } | 434 } |
428 } | 435 } |
429 | 436 |
430 bool hasValueForDirectLocal(Element element) { | 437 bool hasValueForDirectLocal(Element element) { |
431 assert(element != null); | 438 assert(element != null); |
432 assert(isAccessedDirectly(element)); | 439 assert(isAccessedDirectly(element)); |
433 return directLocals[element] != null; | 440 return directLocals[element] != null; |
434 } | 441 } |
435 | 442 |
436 /** | 443 /** |
(...skipping 448 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
885 final SsaBuilderTask builder; | 892 final SsaBuilderTask builder; |
886 final JavaScriptBackend backend; | 893 final JavaScriptBackend backend; |
887 final Interceptors interceptors; | 894 final Interceptors interceptors; |
888 final WorkItem work; | 895 final WorkItem work; |
889 final ConstantSystem constantSystem; | 896 final ConstantSystem constantSystem; |
890 bool methodInterceptionEnabled; | 897 bool methodInterceptionEnabled; |
891 HGraph graph; | 898 HGraph graph; |
892 LocalsHandler localsHandler; | 899 LocalsHandler localsHandler; |
893 HInstruction rethrowableException; | 900 HInstruction rethrowableException; |
894 Map<Element, HInstruction> parameters; | 901 Map<Element, HInstruction> parameters; |
902 HInstruction thisInstruction; | |
895 final RuntimeTypeInformation rti; | 903 final RuntimeTypeInformation rti; |
896 HParameterValue lastAddedParameter; | 904 HParameterValue lastAddedParameter; |
897 | 905 |
898 Map<TargetElement, JumpHandler> jumpTargets; | 906 Map<TargetElement, JumpHandler> jumpTargets; |
899 | 907 |
900 /** | 908 /** |
901 * Variables stored in the current activation. These variables are | 909 * Variables stored in the current activation. These variables are |
902 * being updated in try/catch blocks, and should be | 910 * being updated in try/catch blocks, and should be |
903 * accessed indirectly through [HLocalGet] and [HLocalSet]. | 911 * accessed indirectly through [HLocalGet] and [HLocalSet]. |
904 */ | 912 */ |
(...skipping 1370 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2275 assert(Elements.isInstanceSend(send, elements)); | 2283 assert(Elements.isInstanceSend(send, elements)); |
2276 // TODO(kasperl): This is a convoluted way of checking if we're | 2284 // TODO(kasperl): This is a convoluted way of checking if we're |
2277 // generating code for a compound assignment. If we are, we need | 2285 // generating code for a compound assignment. If we are, we need |
2278 // to get the selector from the mapping for the AST selector node. | 2286 // to get the selector from the mapping for the AST selector node. |
2279 Selector selector = (send.asSendSet() == null) | 2287 Selector selector = (send.asSendSet() == null) |
2280 ? elements.getSelector(send) | 2288 ? elements.getSelector(send) |
2281 : elements.getSelector(send.selector); | 2289 : elements.getSelector(send.selector); |
2282 assert(selector.isGetter()); | 2290 assert(selector.isGetter()); |
2283 SourceString getterName = selector.name; | 2291 SourceString getterName = selector.name; |
2284 Element interceptor = null; | 2292 Element interceptor = null; |
2285 if (elements[send] == null && methodInterceptionEnabled) { | 2293 if (methodInterceptionEnabled) { |
2286 interceptor = interceptors.getStaticInterceptor(selector); | 2294 interceptor = interceptors.getStaticInterceptor(selector); |
2287 } | 2295 } |
2288 bool hasGetter = compiler.world.hasAnyUserDefinedGetter(selector); | 2296 bool hasGetter = compiler.world.hasAnyUserDefinedGetter(selector); |
2289 if (interceptor != null) { | 2297 if (interceptor == backend.getInterceptorMethod && interceptor != null) { |
floitsch
2012/11/13 18:12:24
remove "&& interceptor != null".
ngeoffray
2012/11/14 08:44:58
No, I want to make sure we don't have to have getI
| |
2290 if (interceptor == backend.getInterceptorMethod) { | 2298 // If we're using an interceptor class, emit a call to the |
2291 // If we're using an interceptor class, emit a call to the | 2299 // interceptor method and then the actual dynamic call on the |
2292 // interceptor method and then the actual dynamic call on the | 2300 // interceptor object. |
2293 // interceptor object. | 2301 HInstruction instruction; |
2302 if (backend.isInterceptorClass(currentElement.getEnclosingClass())) { | |
floitsch
2012/11/13 18:12:24
don't you need to verify that the receiver is of t
ngeoffray
2012/11/14 08:44:58
Yes, very good catch. I need to check that the rec
| |
2303 instruction = thisInstruction; | |
2304 } else { | |
2294 HStatic target = new HStatic(interceptor); | 2305 HStatic target = new HStatic(interceptor); |
2295 add(target); | 2306 add(target); |
2296 HInstruction instruction = | 2307 instruction = new HInvokeStatic(<HInstruction>[target, receiver]); |
2297 new HInvokeStatic(<HInstruction>[target, receiver]); | |
2298 add(instruction); | 2308 add(instruction); |
2299 instruction = new HInvokeDynamicGetter( | |
2300 selector, null, instruction, !hasGetter); | |
2301 // Add the receiver as an argument to the getter call on the | |
2302 // interceptor. | |
2303 instruction.inputs.add(receiver); | |
2304 pushWithPosition(instruction, send); | |
2305 } else { | |
2306 // Use the old, deprecated interceptor mechanism. | |
2307 HStatic target = new HStatic(interceptor); | |
2308 add(target); | |
2309 List<HInstruction> inputs = <HInstruction>[target, receiver]; | |
2310 pushWithPosition(new HInvokeInterceptor(selector, inputs, !hasGetter), | |
2311 send); | |
2312 } | 2309 } |
2310 instruction = new HInvokeDynamicGetter( | |
2311 selector, null, instruction, !hasGetter); | |
2312 // Add the receiver as an argument to the getter call on the | |
2313 // interceptor. | |
2314 instruction.inputs.add(receiver); | |
2315 pushWithPosition(instruction, send); | |
2316 } else if (elements[send] == null && interceptor != null) { | |
2317 // Use the old, deprecated interceptor mechanism. | |
2318 HStatic target = new HStatic(interceptor); | |
2319 add(target); | |
2320 List<HInstruction> inputs = <HInstruction>[target, receiver]; | |
2321 pushWithPosition(new HInvokeInterceptor(selector, inputs, !hasGetter), | |
2322 send); | |
2313 } else { | 2323 } else { |
floitsch
2012/11/13 18:12:24
Eventually (once there is no old deprecated interc
| |
2314 pushWithPosition( | 2324 pushWithPosition( |
2315 new HInvokeDynamicGetter(selector, null, receiver, !hasGetter), send); | 2325 new HInvokeDynamicGetter(selector, null, receiver, !hasGetter), send); |
2316 } | 2326 } |
2317 } | 2327 } |
2318 | 2328 |
2319 void generateGetter(Send send, Element element) { | 2329 void generateGetter(Send send, Element element) { |
2320 if (Elements.isStaticOrTopLevelField(element)) { | 2330 if (Elements.isStaticOrTopLevelField(element)) { |
2321 Constant value; | 2331 Constant value; |
2322 if (element.isField() && !element.isAssignable()) { | 2332 if (element.isField() && !element.isAssignable()) { |
2323 // A static final or const. Get its constant value and inline it if | 2333 // A static final or const. Get its constant value and inline it if |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2355 } | 2365 } |
2356 } | 2366 } |
2357 | 2367 |
2358 void generateInstanceSetterWithCompiledReceiver(Send send, | 2368 void generateInstanceSetterWithCompiledReceiver(Send send, |
2359 HInstruction receiver, | 2369 HInstruction receiver, |
2360 HInstruction value) { | 2370 HInstruction value) { |
2361 assert(Elements.isInstanceSend(send, elements)); | 2371 assert(Elements.isInstanceSend(send, elements)); |
2362 Selector selector = elements.getSelector(send); | 2372 Selector selector = elements.getSelector(send); |
2363 assert(selector.isSetter()); | 2373 assert(selector.isSetter()); |
2364 SourceString setterName = selector.name; | 2374 SourceString setterName = selector.name; |
2365 Element staticInterceptor = null; | 2375 Element interceptor = null; |
2366 if (elements[send] == null && methodInterceptionEnabled) { | 2376 if (methodInterceptionEnabled) { |
2367 staticInterceptor = interceptors.getStaticInterceptor(selector); | 2377 interceptor = interceptors.getStaticInterceptor(selector); |
2368 } | 2378 } |
2369 bool hasSetter = compiler.world.hasAnyUserDefinedSetter(selector); | 2379 bool hasSetter = compiler.world.hasAnyUserDefinedSetter(selector); |
2370 if (staticInterceptor != null) { | 2380 if (interceptor != null && interceptor == backend.getInterceptorMethod) { |
floitsch
2012/11/13 18:12:24
ditto. remove "interceptor != null".
| |
2371 HStatic target = new HStatic(staticInterceptor); | 2381 compiler.internalError( |
2382 'Unimplemented intercepted setter call with interceptor classes'); | |
2383 } else if (interceptor != null && elements[send] == null) { | |
2384 HStatic target = new HStatic(interceptor); | |
2372 add(target); | 2385 add(target); |
2373 List<HInstruction> inputs = <HInstruction>[target, receiver, value]; | 2386 List<HInstruction> inputs = <HInstruction>[target, receiver, value]; |
2374 addWithPosition(new HInvokeInterceptor(selector, inputs), send); | 2387 addWithPosition(new HInvokeInterceptor(selector, inputs), send); |
2375 } else { | 2388 } else { |
2376 addWithPosition( | 2389 addWithPosition( |
2377 new HInvokeDynamicSetter(selector, null, receiver, value, !hasSetter), | 2390 new HInvokeDynamicSetter(selector, null, receiver, value, !hasSetter), |
2378 send); | 2391 send); |
2379 } | 2392 } |
2380 stack.add(value); | 2393 stack.add(value); |
2381 } | 2394 } |
(...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2626 } else if (node.selector.asOperator() != null) { | 2639 } else if (node.selector.asOperator() != null) { |
2627 SourceString name = node.selector.asIdentifier().source; | 2640 SourceString name = node.selector.asIdentifier().source; |
2628 isNotEquals = identical(name.stringValue, '!='); | 2641 isNotEquals = identical(name.stringValue, '!='); |
2629 dartMethodName = Elements.constructOperatorName( | 2642 dartMethodName = Elements.constructOperatorName( |
2630 name, node.argumentsNode is Prefix); | 2643 name, node.argumentsNode is Prefix); |
2631 } else { | 2644 } else { |
2632 dartMethodName = node.selector.asIdentifier().source; | 2645 dartMethodName = node.selector.asIdentifier().source; |
2633 } | 2646 } |
2634 | 2647 |
2635 Element interceptor = null; | 2648 Element interceptor = null; |
2636 if (methodInterceptionEnabled && elements[node] == null) { | 2649 if (methodInterceptionEnabled) { |
2637 interceptor = interceptors.getStaticInterceptor(selector); | 2650 interceptor = interceptors.getStaticInterceptor(selector); |
2638 } | 2651 } |
2652 | |
2639 if (interceptor != null) { | 2653 if (interceptor != null) { |
2640 // TODO(ngeoffray): The receiver never being null is currently the | |
2641 // case, but should be updated once we start implementing more of | |
2642 // the interceptors class. | |
2643 assert(node.receiver != null); | |
2644 if (interceptor == backend.getInterceptorMethod) { | 2654 if (interceptor == backend.getInterceptorMethod) { |
2645 HStatic target = new HStatic(interceptor); | 2655 if (backend.isInterceptorClass(currentElement.getEnclosingClass())) { |
2646 add(target); | 2656 inputs.add(thisInstruction); |
floitsch
2012/11/13 18:12:24
ditto:
- don't you need to verify that the node's
ngeoffray
2012/11/14 08:44:58
In this situation there is no receiver.
| |
2647 visit(node.receiver); | 2657 inputs.add(localsHandler.readThis()); |
2648 HInstruction receiver = pop(); | 2658 } else { |
2649 HInstruction instruction = | 2659 HStatic target = new HStatic(interceptor); |
2650 new HInvokeStatic(<HInstruction>[target, receiver]); | 2660 add(target); |
2651 add(instruction); | 2661 visit(node.receiver); |
2652 inputs.add(instruction); | 2662 HInstruction receiver = pop(); |
2653 inputs.add(receiver); | 2663 HInstruction instruction = |
2664 new HInvokeStatic(<HInstruction>[target, receiver]); | |
2665 add(instruction); | |
2666 inputs.add(instruction); | |
2667 inputs.add(receiver); | |
2668 } | |
2654 addDynamicSendArgumentsToList(node, inputs); | 2669 addDynamicSendArgumentsToList(node, inputs); |
2655 // The first entry in the inputs list is the interceptor. The | 2670 // The first entry in the inputs list is the interceptor. The |
2656 // second is the receiver, and the others are the arguments. | 2671 // second is the receiver, and the others are the arguments. |
2657 instruction = new HInvokeDynamicMethod(selector, inputs); | 2672 HInstruction instruction = new HInvokeDynamicMethod(selector, inputs); |
2658 pushWithPosition(instruction, node); | 2673 pushWithPosition(instruction, node); |
2659 } else { | 2674 return; |
2675 } else if (elements[node] == null) { | |
2660 HStatic target = new HStatic(interceptor); | 2676 HStatic target = new HStatic(interceptor); |
2661 add(target); | 2677 add(target); |
2662 inputs.add(target); | 2678 inputs.add(target); |
2663 visit(node.receiver); | 2679 visit(node.receiver); |
2664 inputs.add(pop()); | 2680 inputs.add(pop()); |
2665 addGenericSendArgumentsToList(node.arguments, inputs); | 2681 addGenericSendArgumentsToList(node.arguments, inputs); |
2666 pushWithPosition(new HInvokeInterceptor(selector, inputs), node); | 2682 pushWithPosition(new HInvokeInterceptor(selector, inputs), node); |
2683 return; | |
2667 } | 2684 } |
2668 return; | |
2669 } | 2685 } |
2670 | 2686 |
2671 Element element = elements[node]; | 2687 Element element = elements[node]; |
2672 if (element != null && compiler.world.hasNoOverridingMember(element)) { | 2688 if (element != null && compiler.world.hasNoOverridingMember(element)) { |
2673 if (tryInlineMethod(element, selector, node.arguments)) { | 2689 if (tryInlineMethod(element, selector, node.arguments)) { |
2674 return; | 2690 return; |
2675 } | 2691 } |
2676 } | 2692 } |
2677 | 2693 |
2678 if (node.receiver == null) { | 2694 if (node.receiver == null) { |
(...skipping 2131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4810 new HSubGraphBlockInformation(elseBranch.graph)); | 4826 new HSubGraphBlockInformation(elseBranch.graph)); |
4811 | 4827 |
4812 HBasicBlock conditionStartBlock = conditionBranch.block; | 4828 HBasicBlock conditionStartBlock = conditionBranch.block; |
4813 conditionStartBlock.setBlockFlow(info, joinBlock); | 4829 conditionStartBlock.setBlockFlow(info, joinBlock); |
4814 SubGraph conditionGraph = conditionBranch.graph; | 4830 SubGraph conditionGraph = conditionBranch.graph; |
4815 HIf branch = conditionGraph.end.last; | 4831 HIf branch = conditionGraph.end.last; |
4816 assert(branch is HIf); | 4832 assert(branch is HIf); |
4817 branch.blockInformation = conditionStartBlock.blockFlow; | 4833 branch.blockInformation = conditionStartBlock.blockFlow; |
4818 } | 4834 } |
4819 } | 4835 } |
OLD | NEW |