| 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 |