OLD | NEW |
| (Empty) |
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 | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 class EnqueueTask extends CompilerTask { | |
6 final Map<String, Link<Element>> instanceMembersByName; | |
7 final Set<ClassElement> seenClasses; | |
8 | |
9 String get name() => 'Enqueue'; | |
10 | |
11 EnqueueTask(Compiler compiler) | |
12 : instanceMembersByName = new Map<String, Link<Element>>(), | |
13 seenClasses = new Set<ClassElement>(), | |
14 super(compiler); | |
15 | |
16 bool checkNoEnqueuedInvokedInstanceMethods() { | |
17 measure(() { | |
18 // Run through the classes and see if we need to compile methods. | |
19 for (ClassElement classElement in compiler.universe.instantiatedClasses) { | |
20 for (ClassElement currentClass = classElement; | |
21 currentClass !== null; | |
22 currentClass = currentClass.superclass) { | |
23 processInstantiatedClass(currentClass); | |
24 } | |
25 } | |
26 }); | |
27 return true; | |
28 } | |
29 | |
30 void processInstantiatedClass(ClassElement cls) { | |
31 cls.members.forEach(processInstantiatedClassMember); | |
32 } | |
33 | |
34 void registerFieldClosureInvocations() { | |
35 measure(() { | |
36 // Make sure that the closure understands a call with the given | |
37 // selector. For a method-invocation of the form o.foo(a: 499), we | |
38 // need to make sure that closures can handle the optional argument if | |
39 // there exists a field or getter 'foo'. | |
40 var names = compiler.universe.instantiatedClassInstanceFields; | |
41 // TODO(ahe): Might be enough to use invokedGetters. | |
42 for (SourceString name in names) { | |
43 Set<Selector> invokedSelectors = compiler.universe.invokedNames[name]; | |
44 if (invokedSelectors != null) { | |
45 for (Selector selector in invokedSelectors) { | |
46 compiler.registerDynamicInvocation(Namer.CLOSURE_INVOCATION_NAME, | |
47 selector); | |
48 } | |
49 } | |
50 } | |
51 }); | |
52 } | |
53 | |
54 void processInstantiatedClassMember(Element member) { | |
55 if (compiler.universe.generatedCode.containsKey(member)) return; | |
56 | |
57 if (!member.isInstanceMember()) return; | |
58 | |
59 String memberName = member.name.slowToString(); | |
60 Link<Element> members = instanceMembersByName.putIfAbsent( | |
61 memberName, () => const EmptyLink<Element>()); | |
62 instanceMembersByName[memberName] = members.prepend(member); | |
63 | |
64 if (member.kind === ElementKind.GETTER || | |
65 member.kind === ElementKind.FIELD) { | |
66 compiler.universe.instantiatedClassInstanceFields.add(member.name); | |
67 } | |
68 | |
69 if (member.kind == ElementKind.FUNCTION) { | |
70 if (member.name == Compiler.NO_SUCH_METHOD) { | |
71 compiler.enableNoSuchMethod(member); | |
72 } | |
73 Set<Selector> selectors = compiler.universe.invokedNames[member.name]; | |
74 if (selectors != null) { | |
75 FunctionElement functionMember = member; | |
76 FunctionParameters parameters = | |
77 functionMember.computeParameters(compiler); | |
78 for (Selector selector in selectors) { | |
79 if (selector.applies(parameters)) { | |
80 return compiler.addToWorkList(member); | |
81 } | |
82 } | |
83 } | |
84 // If there is a property access with the same name as a method we | |
85 // need to emit the method. | |
86 if (compiler.universe.invokedGetters.contains(member.name)) { | |
87 // We will emit a closure, so make sure the closure class is | |
88 // generated. | |
89 compiler.closureClass.ensureResolved(compiler); | |
90 compiler.registerInstantiatedClass(compiler.closureClass); | |
91 return compiler.addToWorkList(member); | |
92 } | |
93 } else if (member.kind == ElementKind.GETTER) { | |
94 if (compiler.universe.invokedGetters.contains(member.name)) { | |
95 return compiler.addToWorkList(member); | |
96 } | |
97 // A method invocation like in o.foo(x, y) might actually be an | |
98 // invocation of the getter foo followed by an invocation of the | |
99 // returned closure. | |
100 Set<Selector> invokedSelectors = | |
101 compiler.universe.invokedNames[member.name]; | |
102 // We don't know what selectors the returned closure accepts. If | |
103 // the set contains any selector we have to assume that it matches. | |
104 if (invokedSelectors !== null && !invokedSelectors.isEmpty()) { | |
105 return compiler.addToWorkList(member); | |
106 } | |
107 } else if (member.kind === ElementKind.SETTER) { | |
108 if (compiler.universe.invokedSetters.contains(member.name)) { | |
109 return compiler.addToWorkList(member); | |
110 } | |
111 } | |
112 } | |
113 | |
114 void onRegisterInstantiatedClass(ClassElement cls) => measure(() { | |
115 while (cls !== null) { | |
116 if (seenClasses.contains(cls)) return; | |
117 seenClasses.add(cls); | |
118 // TODO(ahe): Don't call resolveType, instead, call this method | |
119 // when resolveType is called. | |
120 compiler.resolveType(cls); | |
121 cls.members.forEach(processInstantiatedClassMember); | |
122 cls = cls.superclass; | |
123 } | |
124 }); | |
125 | |
126 void registerInvocation(SourceString methodName, Selector selector) { | |
127 measure(() { | |
128 Map<SourceString, Set<Selector>> invokedNames = | |
129 compiler.universe.invokedNames; | |
130 Set<Selector> selectors = | |
131 invokedNames.putIfAbsent(methodName, () => new Set<Selector>()); | |
132 if (!selectors.contains(selector)) { | |
133 selectors.add(selector); | |
134 handleUnseenInvocation(methodName, selector); | |
135 } | |
136 }); | |
137 } | |
138 | |
139 void registerGetter(SourceString methodName) { | |
140 measure(() { | |
141 if (!compiler.universe.invokedGetters.contains(methodName)) { | |
142 compiler.universe.invokedGetters.add(methodName); | |
143 handleUnseenGetter(methodName); | |
144 } | |
145 }); | |
146 } | |
147 | |
148 void registerSetter(SourceString methodName) { | |
149 measure(() { | |
150 if (!compiler.universe.invokedSetters.contains(methodName)) { | |
151 compiler.universe.invokedSetters.add(methodName); | |
152 handleUnseenSetter(methodName); | |
153 } | |
154 }); | |
155 } | |
156 | |
157 processInstanceMembers(SourceString n, bool f(Element e)) { | |
158 String memberName = n.slowToString(); | |
159 Link<Element> members = instanceMembersByName[memberName]; | |
160 if (members !== null) { | |
161 LinkBuilder<Element> remaining = new LinkBuilder<Element>(); | |
162 for (; !members.isEmpty(); members = members.tail) { | |
163 if (!f(members.head)) remaining.addLast(members.head); | |
164 } | |
165 instanceMembersByName[memberName] = remaining.toLink(); | |
166 } | |
167 } | |
168 | |
169 void handleUnseenInvocation(SourceString methodName, Selector selector) { | |
170 processInstanceMembers(methodName, (Element member) { | |
171 if (member.isGetter()) { | |
172 compiler.addToWorkList(member); | |
173 return true; | |
174 } else if (member.isFunction()) { | |
175 FunctionElement functionMember = member; | |
176 FunctionParameters parameters = | |
177 functionMember.computeParameters(compiler); | |
178 if (selector.applies(parameters)) { | |
179 compiler.addToWorkList(member); | |
180 return true; | |
181 } | |
182 } | |
183 return false; | |
184 }); | |
185 } | |
186 | |
187 void handleUnseenGetter(SourceString methodName) { | |
188 processInstanceMembers(methodName, (Element member) { | |
189 if (member.isGetter() || member.isFunction()) { | |
190 compiler.addToWorkList(member); | |
191 return true; | |
192 } else { | |
193 return false; | |
194 } | |
195 }); | |
196 } | |
197 | |
198 void handleUnseenSetter(SourceString methodName) { | |
199 processInstanceMembers(methodName, (Element member) { | |
200 if (member.isSetter()) { | |
201 compiler.addToWorkList(member); | |
202 return true; | |
203 } else { | |
204 return false; | |
205 } | |
206 }); | |
207 } | |
208 } | |
OLD | NEW |