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