Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(350)

Side by Side Diff: sdk/lib/_internal/compiler/implementation/inferrer/container_tracer.dart

Issue 104893007: Trace lists when they are stored into other lists. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | sdk/lib/_internal/compiler/implementation/inferrer/type_graph_inferrer.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 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 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 type_graph_inferrer; 5 part of type_graph_inferrer;
6 6
7 /** 7 /**
8 * A set of selector names that [List] implements, that we know do not 8 * A set of selector names that [List] implements, that we know do not
9 * change the element type of the list, or let the list escape to code 9 * change the element type of the list, or let the list escape to code
10 * that might change the element type. 10 * that might change the element type.
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
118 'lastIndexOf', 118 'lastIndexOf',
119 'sublist', 119 'sublist',
120 'getRange', 120 'getRange',
121 'asMap', 121 'asMap',
122 122
123 // From JSArray. 123 // From JSArray.
124 'checkMutable', 124 'checkMutable',
125 'checkGrowable', 125 'checkGrowable',
126 ]); 126 ]);
127 127
128 // A set of selectors we know do not escape the elements inside the
129 // list.
130 Set<String> doesNotEscapeElementSet = new Set<String>.from(
kasperl 2013/12/06 11:29:57 Would it be possible to maintain this as annotatio
ngeoffray 2013/12/06 11:36:26 For some yes, but how would you do it for methods
131 const <String>[
132 // From Object.
133 '==',
134 'hashCode',
135 'toString',
136 'noSuchMethod',
137 'runtimeType',
138
139 // From Iterable.
140 'isEmpty',
141 'isNotEmpty',
142 'length',
143 'any',
144 'contains',
145 'every',
146 'join',
147
148 // From List.
149 'add',
150 'addAll',
151 'clear',
152 'fillRange',
153 'indexOf',
154 'insert',
155 'insertAll',
156 'lastIndexOf',
157 'remove',
158 'removeRange',
159 'replaceRange',
160 'setAll',
161 'setRange',
162 'shuffle',
163 '[]=',
164
165 // From JSArray.
166 'checkMutable',
167 'checkGrowable',
168 ]);
169
128 bool _VERBOSE = false; 170 bool _VERBOSE = false;
129 171
130 class ContainerTracerVisitor implements TypeInformationVisitor { 172 class ContainerTracerVisitor implements TypeInformationVisitor {
131 final ContainerTypeInformation container; 173 final ContainerTypeInformation container;
132 final TypeGraphInferrerEngine inferrer; 174 final TypeGraphInferrerEngine inferrer;
133 final Compiler compiler; 175 final Compiler compiler;
134 176
135 // The set of [TypeInformation] where the traced container could
136 // flow in, and operations done on them.
137 final Setlet<TypeInformation> flowsInto = new Setlet<TypeInformation>();
138 177
139 // Work list that gets populated with [TypeInformation] that could 178 // Work list that gets populated with [TypeInformation] that could
140 // contain the container. 179 // contain the container.
141 final List<TypeInformation> workList = <TypeInformation>[]; 180 final List<TypeInformation> workList = <TypeInformation>[];
142 181
182 // Work list of containers to analyze after analyzing the users of a
183 // [TypeInformation] that may be [container]. We know [container]
184 // has been stored in these containers and we must check how
185 // [container] escapes from these containers.
186 final List<ContainerTypeInformation> containersToAnalyze =
187 <ContainerTypeInformation>[];
188
143 // The current [TypeInformation] in the analysis. 189 // The current [TypeInformation] in the analysis.
144 TypeInformation currentUser; 190 TypeInformation currentUser;
145 191
146 // The list of found assignments to the container. 192 // The list of found assignments to the container.
147 final List<TypeInformation> assignments = <TypeInformation>[]; 193 final List<TypeInformation> assignments = <TypeInformation>[];
148 194
149 bool callsGrowableMethod = false; 195 bool callsGrowableMethod = false;
150 bool continueAnalyzing = true; 196 bool continueAnalyzing = true;
151 197
152 static const int MAX_ANALYSIS_COUNT = 16; 198 static const int MAX_ANALYSIS_COUNT = 16;
153 final Setlet<Element> analyzedElements = new Setlet<Element>(); 199 final Setlet<Element> analyzedElements = new Setlet<Element>();
154 200
155 ContainerTracerVisitor(this.container, inferrer) 201 ContainerTracerVisitor(this.container, inferrer)
156 : this.inferrer = inferrer, this.compiler = inferrer.compiler; 202 : this.inferrer = inferrer, this.compiler = inferrer.compiler;
157 203
158 void addNewEscapeInformation(TypeInformation info) { 204 void addNewEscapeInformation(TypeInformation info) {
159 if (flowsInto.contains(info)) return; 205 if (container.flowsInto.contains(info)) return;
160 flowsInto.add(info); 206 container.flowsInto.add(info);
161 workList.add(info); 207 workList.add(info);
162 } 208 }
163 209
164 List<TypeInformation> run() { 210 List<TypeInformation> run() {
165 // Collect the [TypeInformation] where the container can flow in, 211 // Collect the [TypeInformation] where the container can flow in,
166 // as well as the operations done on all these [TypeInformation]s. 212 // as well as the operations done on all these [TypeInformation]s.
167 addNewEscapeInformation(container); 213 addNewEscapeInformation(container);
168 while (!workList.isEmpty) { 214 while (!workList.isEmpty) {
169 currentUser = workList.removeLast(); 215 currentUser = workList.removeLast();
170 currentUser.users.forEach((TypeInformation info) { 216 currentUser.users.forEach((TypeInformation info) {
171 analyzedElements.add(info.owner); 217 analyzedElements.add(info.owner);
172 info.accept(this); 218 info.accept(this);
173 }); 219 });
220 while (!containersToAnalyze.isEmpty) {
221 analyzeStoredIntoContainer(containersToAnalyze.removeLast());
222 }
174 if (!continueAnalyzing) break; 223 if (!continueAnalyzing) break;
175 if (analyzedElements.length > MAX_ANALYSIS_COUNT) { 224 if (analyzedElements.length > MAX_ANALYSIS_COUNT) {
176 bailout('Too many users'); 225 bailout('Too many users');
177 break; 226 break;
178 } 227 }
179 } 228 }
180 229
181 if (continueAnalyzing) { 230 if (continueAnalyzing) {
182 if (!callsGrowableMethod && container.inferredLength == null) { 231 if (!callsGrowableMethod && container.inferredLength == null) {
183 container.inferredLength = container.originalLength; 232 container.inferredLength = container.originalLength;
(...skipping 20 matching lines...) Expand all
204 visitPhiElementTypeInformation(PhiElementTypeInformation info) { 253 visitPhiElementTypeInformation(PhiElementTypeInformation info) {
205 addNewEscapeInformation(info); 254 addNewEscapeInformation(info);
206 } 255 }
207 256
208 visitElementInContainerTypeInformation( 257 visitElementInContainerTypeInformation(
209 ElementInContainerTypeInformation info) { 258 ElementInContainerTypeInformation info) {
210 addNewEscapeInformation(info); 259 addNewEscapeInformation(info);
211 } 260 }
212 261
213 visitContainerTypeInformation(ContainerTypeInformation info) { 262 visitContainerTypeInformation(ContainerTypeInformation info) {
214 if (container != info) { 263 containersToAnalyze.add(info);
215 bailout('Stored in a container');
216 }
217 } 264 }
218 265
219 visitConcreteTypeInformation(ConcreteTypeInformation info) {} 266 visitConcreteTypeInformation(ConcreteTypeInformation info) {}
220 267
221 visitClosureCallSiteTypeInformation(ClosureCallSiteTypeInformation info) { 268 visitClosureCallSiteTypeInformation(ClosureCallSiteTypeInformation info) {
222 bailout('Passed to a closure'); 269 bailout('Passed to a closure');
223 } 270 }
224 271
225 visitStaticCallSiteTypeInformation(StaticCallSiteTypeInformation info) { 272 visitStaticCallSiteTypeInformation(StaticCallSiteTypeInformation info) {
226 Element called = info.calledElement; 273 Element called = info.calledElement;
227 if (called.isForeign(compiler) && called.name == 'JS') { 274 if (called.isForeign(compiler) && called.name == 'JS') {
228 bailout('Used in JS ${info.call}'); 275 bailout('Used in JS ${info.call}');
229 } 276 }
230 if (inferrer.types.getInferredTypeOf(called) == currentUser) { 277 if (inferrer.types.getInferredTypeOf(called) == currentUser) {
231 addNewEscapeInformation(info); 278 addNewEscapeInformation(info);
232 } 279 }
233 } 280 }
234 281
282 void analyzeStoredIntoContainer(ContainerTypeInformation container) {
283 inferrer.analyzeContainer(container);
284 if (container.bailedOut) {
285 bailout('Stored in a container that bailed out');
286 } else {
287 container.flowsInto.forEach((flow) {
288 flow.users.forEach((user) {
289 if (user is !DynamicCallSiteTypeInformation) return;
290 if (user.receiver != flow) return;
291 if (returnsElementTypeSet.contains(user.selector)) {
292 addNewEscapeInformation(user);
293 } else if (!doesNotEscapeElementSet.contains(user.selector.name)) {
294 bailout('Escape from a container');
295 }
296 });
297 });
298 }
299 }
300
301 bool isAddedToContainer(DynamicCallSiteTypeInformation info) {
302 var receiverType = info.receiver.type;
303 if (!receiverType.isContainer) return false;
304 String selectorName = info.selector.name;
305 List<TypeInformation> arguments = info.arguments.positional;
306 return (selectorName == '[]=' && currentUser == arguments[1])
307 || (selectorName == 'insert' && currentUser == arguments[0])
308 || (selectorName == 'add' && currentUser == arguments[0]);
309 }
310
235 visitDynamicCallSiteTypeInformation(DynamicCallSiteTypeInformation info) { 311 visitDynamicCallSiteTypeInformation(DynamicCallSiteTypeInformation info) {
236 Selector selector = info.selector; 312 Selector selector = info.selector;
237 String selectorName = selector.name; 313 String selectorName = selector.name;
238 if (currentUser == info.receiver) { 314 if (currentUser == info.receiver) {
239 if (!okSelectorsSet.contains(selectorName)) { 315 if (!okSelectorsSet.contains(selectorName)) {
240 if (selector.isCall()) { 316 if (selector.isCall()) {
241 int positionalLength = info.arguments.positional.length; 317 int positionalLength = info.arguments.positional.length;
242 if (selectorName == 'add') { 318 if (selectorName == 'add') {
243 if (positionalLength == 1) { 319 if (positionalLength == 1) {
244 assignments.add(info.arguments.positional[0]); 320 assignments.add(info.arguments.positional[0]);
(...skipping 17 matching lines...) Expand all
262 callsGrowableMethod = true; 338 callsGrowableMethod = true;
263 } 339 }
264 if (selectorName == 'length' && selector.isSetter()) { 340 if (selectorName == 'length' && selector.isSetter()) {
265 callsGrowableMethod = true; 341 callsGrowableMethod = true;
266 assignments.add(inferrer.types.nullType); 342 assignments.add(inferrer.types.nullType);
267 } 343 }
268 } else if (selector.isCall() 344 } else if (selector.isCall()
269 && !info.targets.every((element) => element.isFunction())) { 345 && !info.targets.every((element) => element.isFunction())) {
270 bailout('Passed to a closure'); 346 bailout('Passed to a closure');
271 return; 347 return;
348 } else if (isAddedToContainer(info)) {
349 ContainerTypeMask mask = info.receiver.type;
350 if (mask.allocationNode != null) {
351 ContainerTypeInformation container =
352 inferrer.types.allocatedContainers[mask.allocationNode];
353 containersToAnalyze.add(container);
354 } else {
355 bailout('Stored in too many containers');
kasperl 2013/12/06 11:29:57 Add a comment that explains why a null allocationN
ngeoffray 2013/12/06 11:36:26 Done.
356 }
272 } 357 }
273 358
274 if (info.targets 359 if (info.targets
275 .map((element) => inferrer.types.getInferredTypeOf(element)) 360 .map((element) => inferrer.types.getInferredTypeOf(element))
276 .any((other) => other == currentUser)) { 361 .any((other) => other == currentUser)) {
277 addNewEscapeInformation(info); 362 addNewEscapeInformation(info);
278 } 363 }
279
280 } 364 }
281 365
282 bool isClosure(Element element) { 366 bool isClosure(Element element) {
283 if (!element.isFunction()) return false; 367 if (!element.isFunction()) return false;
284 Element outermost = element.getOutermostEnclosingMemberOrTopLevel(); 368 Element outermost = element.getOutermostEnclosingMemberOrTopLevel();
285 return outermost.declaration != element.declaration; 369 return outermost.declaration != element.declaration;
286 } 370 }
287 371
372 bool isParameterOfListAddingMethod(Element element) {
373 if (!element.isParameter()) return false;
374 if (element.getEnclosingClass() != compiler.backend.listImplementation) {
375 return false;
376 }
377 Element method = element.enclosingElement;
378 return (method.name == '[]=')
379 || (method.name == 'add')
380 || (method.name == 'insert');
381 }
382
288 visitElementTypeInformation(ElementTypeInformation info) { 383 visitElementTypeInformation(ElementTypeInformation info) {
289 if (isClosure(info.element)) { 384 if (isClosure(info.element)) {
290 bailout('Returned from a closure'); 385 bailout('Returned from a closure');
291 } 386 }
292 if (compiler.backend.isNeededForReflection(info.element)) { 387 if (compiler.backend.isNeededForReflection(info.element)) {
293 bailout('Escape in reflection'); 388 bailout('Escape in reflection');
294 } 389 }
390 if (isParameterOfListAddingMethod(info.element)) {
391 // These elements are being handled in
392 // [visitDynamicCallSiteTypeInformation].
393 return;
394 }
295 addNewEscapeInformation(info); 395 addNewEscapeInformation(info);
296 } 396 }
297 } 397 }
OLDNEW
« no previous file with comments | « no previous file | sdk/lib/_internal/compiler/implementation/inferrer/type_graph_inferrer.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698