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