OLD | NEW |
| (Empty) |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | |
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. | |
4 | |
5 part of type_graph_inferrer; | |
6 | |
7 class ClosureTracerVisitor extends TracerVisitor<ApplyableTypeInformation> { | |
8 final Iterable<FunctionElement> tracedElements; | |
9 final List<CallSiteTypeInformation> callsToAnalyze = | |
10 new List<CallSiteTypeInformation>(); | |
11 | |
12 ClosureTracerVisitor(this.tracedElements, tracedType, inferrer) | |
13 : super(tracedType, inferrer); | |
14 | |
15 void run() { | |
16 analyze(); | |
17 if (!continueAnalyzing) return; | |
18 callsToAnalyze.forEach(analyzeCall); | |
19 for(FunctionElement e in tracedElements) { | |
20 e.functionSignature.forEachParameter((Element parameter) { | |
21 ElementTypeInformation info = | |
22 inferrer.types.getInferredTypeOf(parameter); | |
23 info.disableInferenceForClosures = false; | |
24 }); | |
25 } | |
26 } | |
27 | |
28 void tagAsFunctionApplyTarget([String reason]) { | |
29 tracedType.mightBePassedToFunctionApply = true; | |
30 if (_VERBOSE) { | |
31 print("Closure $tracedType might be passed to apply: $reason"); | |
32 } | |
33 } | |
34 | |
35 void registerCallForLaterAnalysis(CallSiteTypeInformation info) { | |
36 callsToAnalyze.add(info); | |
37 } | |
38 | |
39 void analyzeCall(CallSiteTypeInformation info) { | |
40 Selector selector = info.selector; | |
41 tracedElements.forEach((FunctionElement functionElement) { | |
42 if (!selector.signatureApplies(functionElement)) return; | |
43 inferrer.updateParameterAssignments(info, functionElement, info.arguments, | |
44 selector, remove: false, addToQueue: false); | |
45 }); | |
46 } | |
47 | |
48 visitClosureCallSiteTypeInformation(ClosureCallSiteTypeInformation info) { | |
49 super.visitClosureCallSiteTypeInformation(info); | |
50 if (info.closure == currentUser) { | |
51 registerCallForLaterAnalysis(info); | |
52 } else { | |
53 bailout('Passed to a closure'); | |
54 } | |
55 } | |
56 | |
57 visitStaticCallSiteTypeInformation(StaticCallSiteTypeInformation info) { | |
58 super.visitStaticCallSiteTypeInformation(info); | |
59 Element called = info.calledElement; | |
60 if (called.isForeign(compiler.backend)) { | |
61 String name = called.name; | |
62 if (name == 'JS' || name == 'DART_CLOSURE_TO_JS') { | |
63 bailout('Used in JS ${info.call}'); | |
64 } | |
65 } | |
66 if (called.isGetter | |
67 && info.selector != null | |
68 && info.selector.isCall | |
69 && inferrer.types.getInferredTypeOf(called) == currentUser) { | |
70 // This node can be a closure call as well. For example, `foo()` | |
71 // where `foo` is a getter. | |
72 registerCallForLaterAnalysis(info); | |
73 } | |
74 if (checkIfFunctionApply(called) && | |
75 info.arguments != null && | |
76 info.arguments.contains(currentUser)) { | |
77 tagAsFunctionApplyTarget("static call"); | |
78 } | |
79 } | |
80 | |
81 bool checkIfCurrentUser(element) { | |
82 return inferrer.types.getInferredTypeOf(element) == currentUser; | |
83 } | |
84 | |
85 bool checkIfFunctionApply(element) { | |
86 return compiler.functionApplyMethod == element; | |
87 } | |
88 | |
89 visitDynamicCallSiteTypeInformation(DynamicCallSiteTypeInformation info) { | |
90 super.visitDynamicCallSiteTypeInformation(info); | |
91 if (info.selector.isCall) { | |
92 if (info.arguments.contains(currentUser)) { | |
93 if (!info.targets.every((element) => element.isFunction)) { | |
94 bailout('Passed to a closure'); | |
95 } | |
96 if (info.targets.any(checkIfFunctionApply)) { | |
97 tagAsFunctionApplyTarget("dynamic call"); | |
98 } | |
99 } else if (info.targets.any((element) => checkIfCurrentUser(element))) { | |
100 registerCallForLaterAnalysis(info); | |
101 } | |
102 } else if (info.selector.isGetter && | |
103 info.selector.name == Compiler.CALL_OPERATOR_NAME) { | |
104 // We are potentially tearing off ourself here | |
105 addNewEscapeInformation(info); | |
106 } | |
107 } | |
108 } | |
109 | |
110 class StaticTearOffClosureTracerVisitor extends ClosureTracerVisitor { | |
111 StaticTearOffClosureTracerVisitor(tracedElement, tracedType, inferrer) | |
112 : super([tracedElement], tracedType, inferrer); | |
113 | |
114 visitStaticCallSiteTypeInformation(StaticCallSiteTypeInformation info) { | |
115 super.visitStaticCallSiteTypeInformation(info); | |
116 if (info.calledElement == tracedElements.first | |
117 && info.selector != null | |
118 && info.selector.isGetter) { | |
119 addNewEscapeInformation(info); | |
120 } | |
121 } | |
122 } | |
OLD | NEW |