Chromium Code Reviews| 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 |