OLD | NEW |
---|---|
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 // A set of selectors we know do not escape the elements inside the | 7 // A set of selectors we know do not escape the elements inside the |
8 // list. | 8 // list. |
9 Set<String> doesNotEscapeListSet = new Set<String>.from( | 9 Set<String> doesNotEscapeListSet = new Set<String>.from( |
10 const <String>[ | 10 const <String>[ |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
53 'hashCode', | 53 'hashCode', |
54 'toString', | 54 'toString', |
55 'noSuchMethod', | 55 'noSuchMethod', |
56 'runtimeType', | 56 'runtimeType', |
57 // from Map. | 57 // from Map. |
58 'isEmpty', | 58 'isEmpty', |
59 'isNotEmpty', | 59 'isNotEmpty', |
60 'length', | 60 'length', |
61 'clear', | 61 'clear', |
62 'containsKey', | 62 'containsKey', |
63 'containsValue' | 63 'containsValue', |
64 'keys' | |
floitsch
2014/03/28 09:53:03
Add comment.
| |
64 ]); | 65 ]); |
65 | 66 |
66 abstract class TracerVisitor implements TypeInformationVisitor { | 67 abstract class TracerVisitor implements TypeInformationVisitor { |
67 final TypeInformation tracedType; | 68 final TypeInformation tracedType; |
68 final TypeGraphInferrerEngine inferrer; | 69 final TypeGraphInferrerEngine inferrer; |
69 final Compiler compiler; | 70 final Compiler compiler; |
70 | 71 |
71 static const int MAX_ANALYSIS_COUNT = 16; | 72 static const int MAX_ANALYSIS_COUNT = 16; |
72 final Setlet<Element> analyzedElements = new Setlet<Element>(); | 73 final Setlet<Element> analyzedElements = new Setlet<Element>(); |
73 | 74 |
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
206 if (user.selector.isIndex()) { | 207 if (user.selector.isIndex()) { |
207 addNewEscapeInformation(user); | 208 addNewEscapeInformation(user); |
208 } else if (!doesNotEscapeMapSet.contains(user.selector.name)) { | 209 } else if (!doesNotEscapeMapSet.contains(user.selector.name)) { |
209 bailout('Escape from a map via [${user.selector.name}]'); | 210 bailout('Escape from a map via [${user.selector.name}]'); |
210 } | 211 } |
211 }); | 212 }); |
212 }); | 213 }); |
213 } | 214 } |
214 } | 215 } |
215 | 216 |
217 /* | |
218 * Checks whether this is a call to a list adding method. The definition | |
219 * of what list adding means has to stay in sync with | |
220 * [isParameterOfListAddingMethod]. | |
221 */ | |
216 bool isAddedToContainer(DynamicCallSiteTypeInformation info) { | 222 bool isAddedToContainer(DynamicCallSiteTypeInformation info) { |
217 if (info.arguments == null) return false; | 223 if (info.arguments == null) return false; |
218 var receiverType = info.receiver.type; | 224 var receiverType = info.receiver.type; |
219 if (!receiverType.isContainer) return false; | 225 if (!receiverType.isContainer) return false; |
220 String selectorName = info.selector.name; | 226 String selectorName = info.selector.name; |
221 List<TypeInformation> arguments = info.arguments.positional; | 227 List<TypeInformation> arguments = info.arguments.positional; |
222 return (selectorName == '[]=' && currentUser == arguments[1]) | 228 return (selectorName == '[]=' && currentUser == arguments[1]) |
223 || (selectorName == 'insert' && currentUser == arguments[0]) | 229 || (selectorName == 'insert' && currentUser == arguments[0]) |
224 || (selectorName == 'add' && currentUser == arguments[0]); | 230 || (selectorName == 'add' && currentUser == arguments[0]); |
225 } | 231 } |
226 | 232 |
227 bool isValueAddedToMap(DynamicCallSiteTypeInformation info) { | 233 bool isIndexSetOnMap(DynamicCallSiteTypeInformation info) { |
228 if (info.arguments == null) return false; | 234 if (info.arguments == null) return false; |
229 var receiverType = info.receiver.type; | 235 var receiverType = info.receiver.type; |
230 if (!receiverType.isMap) return false; | 236 if (!receiverType.isMap) return false; |
231 String selectorName = info.selector.name; | 237 String selectorName = info.selector.name; |
232 List<TypeInformation> arguments = info.arguments.positional; | 238 List<TypeInformation> arguments = info.arguments.positional; |
233 return selectorName == '[]=' && currentUser == arguments[1]; | 239 return selectorName == '[]='; |
240 } | |
241 | |
242 /* Checks whether this is a call to a map adding method for values. The | |
243 * definition of map adding method has to stay in sync with | |
244 * [isParameterOfMapAddingMethod]. | |
245 */ | |
246 bool isValueAddedToMap(DynamicCallSiteTypeInformation info) { | |
247 return isIndexSetOnMap(info) && | |
248 currentUser == info.arguments.positional[1]; | |
249 } | |
250 | |
251 /* Checks whether this is a call to a map adding method for keys. The | |
252 * definition of map adding method has to stay in sync with | |
253 * [isParameterOfMapAddingMethod]. | |
254 */ | |
255 bool isKeyAddedToMap(DynamicCallSiteTypeInformation info) { | |
256 return isIndexSetOnMap(info) && | |
257 currentUser == info.arguments.positional[0]; | |
234 } | 258 } |
235 | 259 |
236 void visitDynamicCallSiteTypeInformation( | 260 void visitDynamicCallSiteTypeInformation( |
237 DynamicCallSiteTypeInformation info) { | 261 DynamicCallSiteTypeInformation info) { |
238 if (isAddedToContainer(info)) { | 262 if (isAddedToContainer(info)) { |
239 ContainerTypeMask mask = info.receiver.type; | 263 ContainerTypeMask mask = info.receiver.type; |
240 | 264 |
241 if (mask.allocationNode != null) { | 265 if (mask.allocationNode != null) { |
242 ListTypeInformation list = | 266 ListTypeInformation list = |
243 inferrer.types.allocatedLists[mask.allocationNode]; | 267 inferrer.types.allocatedLists[mask.allocationNode]; |
244 listsToAnalyze.add(list); | 268 listsToAnalyze.add(list); |
245 } else { | 269 } else { |
246 // The [ContainerTypeMask] is a union of two containers, and | 270 // The [ContainerTypeMask] is a union of two containers, and |
247 // we lose track of where these containers have been allocated | 271 // we lose track of where these containers have been allocated |
248 // at this point. | 272 // at this point. |
249 bailout('Stored in too many containers'); | 273 bailout('Stored in too many containers'); |
250 } | 274 } |
251 } else if (isValueAddedToMap(info)) { | 275 } else if (isValueAddedToMap(info)) { |
252 MapTypeMask mask = info.receiver.type; | 276 MapTypeMask mask = info.receiver.type; |
253 if (mask.allocationNode != null) { | 277 if (mask.allocationNode != null) { |
254 MapTypeInformation map = | 278 MapTypeInformation map = |
255 inferrer.types.allocatedMaps[mask.allocationNode]; | 279 inferrer.types.allocatedMaps[mask.allocationNode]; |
256 mapsToAnalyze.add(map); | 280 mapsToAnalyze.add(map); |
257 } else { | 281 } else { |
258 // The [MapTypeMask] is a union. See comment for | 282 // The [MapTypeMask] is a union. See comment for |
259 // [ContainerTypeMask] above. | 283 // [ContainerTypeMask] above. |
260 bailout('Stored in too many maps'); | 284 bailout('Stored in too many maps'); |
261 } | 285 } |
286 } else if (isKeyAddedToMap(info)) { | |
287 bailout('Used as key in Map'); | |
262 } | 288 } |
263 | 289 |
264 Iterable<Element> inferredTargetTypes = info.targets.map((element) { | 290 Iterable<Element> inferredTargetTypes = info.targets.map((element) { |
265 return inferrer.types.getInferredTypeOf(element); | 291 return inferrer.types.getInferredTypeOf(element); |
266 }); | 292 }); |
267 if (inferredTargetTypes.any((user) => user == currentUser)) { | 293 if (inferredTargetTypes.any((user) => user == currentUser)) { |
268 addNewEscapeInformation(info); | 294 addNewEscapeInformation(info); |
269 } | 295 } |
270 } | 296 } |
271 | 297 |
298 /* | |
299 * Check whether element is the parameter of a list adding method. | |
300 * The definition of what a list adding method is has to stay in sync with | |
301 * [isAddedToContainer]. | |
302 */ | |
272 bool isParameterOfListAddingMethod(Element element) { | 303 bool isParameterOfListAddingMethod(Element element) { |
273 if (!element.isParameter()) return false; | 304 if (!element.isParameter()) return false; |
274 if (element.getEnclosingClass() != compiler.backend.listImplementation) { | 305 if (element.getEnclosingClass() != compiler.backend.listImplementation) { |
275 return false; | 306 return false; |
276 } | 307 } |
277 Element method = element.enclosingElement; | 308 Element method = element.enclosingElement; |
278 return (method.name == '[]=') | 309 return (method.name == '[]=') |
279 || (method.name == 'add') | 310 || (method.name == 'add') |
280 || (method.name == 'insert'); | 311 || (method.name == 'insert'); |
281 } | 312 } |
282 | 313 |
314 /* | |
315 * Check whether element is the parameter of a list adding method. | |
316 * The definition of what a list adding method is has to stay in sync with | |
317 * [isValueAddedToMap]. | |
318 */ | |
319 bool isParameterOfMapAddingMethod(Element element) { | |
320 if (!element.isParameter()) return false; | |
321 if (element.getEnclosingClass() != compiler.backend.mapImplementation) { | |
322 return false; | |
323 } | |
324 Element method = element.enclosingElement; | |
325 return (method.name == '[]='); | |
326 } | |
327 | |
283 bool isClosure(Element element) { | 328 bool isClosure(Element element) { |
284 if (!element.isFunction()) return false; | 329 if (!element.isFunction()) return false; |
285 Element outermost = element.getOutermostEnclosingMemberOrTopLevel(); | 330 Element outermost = element.getOutermostEnclosingMemberOrTopLevel(); |
286 return outermost.declaration != element.declaration; | 331 return outermost.declaration != element.declaration; |
287 } | 332 } |
288 | 333 |
289 void visitElementTypeInformation(ElementTypeInformation info) { | 334 void visitElementTypeInformation(ElementTypeInformation info) { |
290 Element element = info.element; | 335 Element element = info.element; |
291 if (element.isParameter() | 336 if (element.isParameter() |
292 && inferrer.isNativeElement(element.enclosingElement)) { | 337 && inferrer.isNativeElement(element.enclosingElement)) { |
293 bailout('Passed to a native method'); | 338 bailout('Passed to a native method'); |
294 } | 339 } |
295 if (info.isClosurized()) { | 340 if (info.isClosurized()) { |
296 bailout('Returned from a closurized method'); | 341 bailout('Returned from a closurized method'); |
297 } | 342 } |
298 if (isClosure(info.element)) { | 343 if (isClosure(info.element)) { |
299 bailout('Returned from a closure'); | 344 bailout('Returned from a closure'); |
300 } | 345 } |
301 if (compiler.backend.isNeededForReflection(info.element)) { | 346 if (compiler.backend.isNeededForReflection(info.element)) { |
302 bailout('Escape in reflection'); | 347 bailout('Escape in reflection'); |
303 } | 348 } |
304 if (isParameterOfListAddingMethod(info.element)) { | 349 if (isParameterOfListAddingMethod(info.element) || |
350 isParameterOfMapAddingMethod(info.element)) { | |
305 // These elements are being handled in | 351 // These elements are being handled in |
306 // [visitDynamicCallSiteTypeInformation]. | 352 // [visitDynamicCallSiteTypeInformation]. |
307 return; | 353 return; |
308 } | 354 } |
309 addNewEscapeInformation(info); | 355 addNewEscapeInformation(info); |
310 } | 356 } |
311 } | 357 } |
OLD | NEW |