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) { |
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()) |
| 2303 && send.receiver == null) { |
| 2304 instruction = thisInstruction; |
| 2305 } else { |
2294 HStatic target = new HStatic(interceptor); | 2306 HStatic target = new HStatic(interceptor); |
2295 add(target); | 2307 add(target); |
2296 HInstruction instruction = | 2308 instruction = new HInvokeStatic(<HInstruction>[target, receiver]); |
2297 new HInvokeStatic(<HInstruction>[target, receiver]); | |
2298 add(instruction); | 2309 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 } | 2310 } |
| 2311 instruction = new HInvokeDynamicGetter( |
| 2312 selector, null, instruction, !hasGetter); |
| 2313 // Add the receiver as an argument to the getter call on the |
| 2314 // interceptor. |
| 2315 instruction.inputs.add(receiver); |
| 2316 pushWithPosition(instruction, send); |
| 2317 } else if (elements[send] == null && interceptor != null) { |
| 2318 // Use the old, deprecated interceptor mechanism. |
| 2319 HStatic target = new HStatic(interceptor); |
| 2320 add(target); |
| 2321 List<HInstruction> inputs = <HInstruction>[target, receiver]; |
| 2322 pushWithPosition(new HInvokeInterceptor(selector, inputs, !hasGetter), |
| 2323 send); |
2313 } else { | 2324 } else { |
2314 pushWithPosition( | 2325 pushWithPosition( |
2315 new HInvokeDynamicGetter(selector, null, receiver, !hasGetter), send); | 2326 new HInvokeDynamicGetter(selector, null, receiver, !hasGetter), send); |
2316 } | 2327 } |
2317 } | 2328 } |
2318 | 2329 |
2319 void generateGetter(Send send, Element element) { | 2330 void generateGetter(Send send, Element element) { |
2320 if (Elements.isStaticOrTopLevelField(element)) { | 2331 if (Elements.isStaticOrTopLevelField(element)) { |
2321 Constant value; | 2332 Constant value; |
2322 if (element.isField() && !element.isAssignable()) { | 2333 if (element.isField() && !element.isAssignable()) { |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2355 } | 2366 } |
2356 } | 2367 } |
2357 | 2368 |
2358 void generateInstanceSetterWithCompiledReceiver(Send send, | 2369 void generateInstanceSetterWithCompiledReceiver(Send send, |
2359 HInstruction receiver, | 2370 HInstruction receiver, |
2360 HInstruction value) { | 2371 HInstruction value) { |
2361 assert(Elements.isInstanceSend(send, elements)); | 2372 assert(Elements.isInstanceSend(send, elements)); |
2362 Selector selector = elements.getSelector(send); | 2373 Selector selector = elements.getSelector(send); |
2363 assert(selector.isSetter()); | 2374 assert(selector.isSetter()); |
2364 SourceString setterName = selector.name; | 2375 SourceString setterName = selector.name; |
2365 Element staticInterceptor = null; | 2376 Element interceptor = null; |
2366 if (elements[send] == null && methodInterceptionEnabled) { | 2377 if (methodInterceptionEnabled) { |
2367 staticInterceptor = interceptors.getStaticInterceptor(selector); | 2378 interceptor = interceptors.getStaticInterceptor(selector); |
2368 } | 2379 } |
2369 bool hasSetter = compiler.world.hasAnyUserDefinedSetter(selector); | 2380 bool hasSetter = compiler.world.hasAnyUserDefinedSetter(selector); |
2370 if (staticInterceptor != null) { | 2381 if (interceptor != null && interceptor == backend.getInterceptorMethod) { |
2371 HStatic target = new HStatic(staticInterceptor); | 2382 compiler.internalError( |
| 2383 'Unimplemented intercepted setter call with interceptor classes'); |
| 2384 } else if (interceptor != null && elements[send] == null) { |
| 2385 HStatic target = new HStatic(interceptor); |
2372 add(target); | 2386 add(target); |
2373 List<HInstruction> inputs = <HInstruction>[target, receiver, value]; | 2387 List<HInstruction> inputs = <HInstruction>[target, receiver, value]; |
2374 addWithPosition(new HInvokeInterceptor(selector, inputs), send); | 2388 addWithPosition(new HInvokeInterceptor(selector, inputs), send); |
2375 } else { | 2389 } else { |
2376 addWithPosition( | 2390 addWithPosition( |
2377 new HInvokeDynamicSetter(selector, null, receiver, value, !hasSetter), | 2391 new HInvokeDynamicSetter(selector, null, receiver, value, !hasSetter), |
2378 send); | 2392 send); |
2379 } | 2393 } |
2380 stack.add(value); | 2394 stack.add(value); |
2381 } | 2395 } |
(...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2626 } else if (node.selector.asOperator() != null) { | 2640 } else if (node.selector.asOperator() != null) { |
2627 SourceString name = node.selector.asIdentifier().source; | 2641 SourceString name = node.selector.asIdentifier().source; |
2628 isNotEquals = identical(name.stringValue, '!='); | 2642 isNotEquals = identical(name.stringValue, '!='); |
2629 dartMethodName = Elements.constructOperatorName( | 2643 dartMethodName = Elements.constructOperatorName( |
2630 name, node.argumentsNode is Prefix); | 2644 name, node.argumentsNode is Prefix); |
2631 } else { | 2645 } else { |
2632 dartMethodName = node.selector.asIdentifier().source; | 2646 dartMethodName = node.selector.asIdentifier().source; |
2633 } | 2647 } |
2634 | 2648 |
2635 Element interceptor = null; | 2649 Element interceptor = null; |
2636 if (methodInterceptionEnabled && elements[node] == null) { | 2650 if (methodInterceptionEnabled) { |
2637 interceptor = interceptors.getStaticInterceptor(selector); | 2651 interceptor = interceptors.getStaticInterceptor(selector); |
2638 } | 2652 } |
| 2653 |
2639 if (interceptor != null) { | 2654 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) { | 2655 if (interceptor == backend.getInterceptorMethod) { |
2645 HStatic target = new HStatic(interceptor); | 2656 if (backend.isInterceptorClass(currentElement.getEnclosingClass()) |
2646 add(target); | 2657 && node.receiver == null) { |
2647 visit(node.receiver); | 2658 inputs.add(thisInstruction); |
2648 HInstruction receiver = pop(); | 2659 inputs.add(localsHandler.readThis()); |
2649 HInstruction instruction = | 2660 } else { |
2650 new HInvokeStatic(<HInstruction>[target, receiver]); | 2661 HStatic target = new HStatic(interceptor); |
2651 add(instruction); | 2662 add(target); |
2652 inputs.add(instruction); | 2663 visit(node.receiver); |
2653 inputs.add(receiver); | 2664 HInstruction receiver = pop(); |
| 2665 HInstruction instruction = |
| 2666 new HInvokeStatic(<HInstruction>[target, receiver]); |
| 2667 add(instruction); |
| 2668 inputs.add(instruction); |
| 2669 inputs.add(receiver); |
| 2670 } |
2654 addDynamicSendArgumentsToList(node, inputs); | 2671 addDynamicSendArgumentsToList(node, inputs); |
2655 // The first entry in the inputs list is the interceptor. The | 2672 // The first entry in the inputs list is the interceptor. The |
2656 // second is the receiver, and the others are the arguments. | 2673 // second is the receiver, and the others are the arguments. |
2657 instruction = new HInvokeDynamicMethod(selector, inputs); | 2674 HInstruction instruction = new HInvokeDynamicMethod(selector, inputs); |
2658 pushWithPosition(instruction, node); | 2675 pushWithPosition(instruction, node); |
2659 } else { | 2676 return; |
| 2677 } else if (elements[node] == null) { |
2660 HStatic target = new HStatic(interceptor); | 2678 HStatic target = new HStatic(interceptor); |
2661 add(target); | 2679 add(target); |
2662 inputs.add(target); | 2680 inputs.add(target); |
2663 visit(node.receiver); | 2681 visit(node.receiver); |
2664 inputs.add(pop()); | 2682 inputs.add(pop()); |
2665 addGenericSendArgumentsToList(node.arguments, inputs); | 2683 addGenericSendArgumentsToList(node.arguments, inputs); |
2666 pushWithPosition(new HInvokeInterceptor(selector, inputs), node); | 2684 pushWithPosition(new HInvokeInterceptor(selector, inputs), node); |
| 2685 return; |
2667 } | 2686 } |
2668 return; | |
2669 } | 2687 } |
2670 | 2688 |
2671 Element element = elements[node]; | 2689 Element element = elements[node]; |
2672 if (element != null && compiler.world.hasNoOverridingMember(element)) { | 2690 if (element != null && compiler.world.hasNoOverridingMember(element)) { |
2673 if (tryInlineMethod(element, selector, node.arguments)) { | 2691 if (tryInlineMethod(element, selector, node.arguments)) { |
2674 return; | 2692 return; |
2675 } | 2693 } |
2676 } | 2694 } |
2677 | 2695 |
2678 if (node.receiver == null) { | 2696 if (node.receiver == null) { |
(...skipping 2131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4810 new HSubGraphBlockInformation(elseBranch.graph)); | 4828 new HSubGraphBlockInformation(elseBranch.graph)); |
4811 | 4829 |
4812 HBasicBlock conditionStartBlock = conditionBranch.block; | 4830 HBasicBlock conditionStartBlock = conditionBranch.block; |
4813 conditionStartBlock.setBlockFlow(info, joinBlock); | 4831 conditionStartBlock.setBlockFlow(info, joinBlock); |
4814 SubGraph conditionGraph = conditionBranch.graph; | 4832 SubGraph conditionGraph = conditionBranch.graph; |
4815 HIf branch = conditionGraph.end.last; | 4833 HIf branch = conditionGraph.end.last; |
4816 assert(branch is HIf); | 4834 assert(branch is HIf); |
4817 branch.blockInformation = conditionStartBlock.blockFlow; | 4835 branch.blockInformation = conditionStartBlock.blockFlow; |
4818 } | 4836 } |
4819 } | 4837 } |
OLD | NEW |