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

Side by Side Diff: pkg/compiler/lib/src/inferrer/node_tracer.dart

Issue 2762493002: Type tracing bug fix for issue 28919. (Closed)
Patch Set: need to test number of arguments Created 3 years, 9 months 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
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 library compiler.src.inferrer.node_tracer; 5 library compiler.src.inferrer.node_tracer;
6 6
7 import '../common/names.dart' show Identifiers; 7 import '../common/names.dart' show Identifiers;
8 import '../compiler.dart' show Compiler; 8 import '../compiler.dart' show Compiler;
9 import '../elements/elements.dart'; 9 import '../elements/elements.dart';
10 import '../types/types.dart' show ContainerTypeMask, MapTypeMask; 10 import '../types/types.dart' show ContainerTypeMask, MapTypeMask;
(...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after
237 addNewEscapeInformation(user); 237 addNewEscapeInformation(user);
238 } else if (!doesNotEscapeMapSet.contains(user.selector.name)) { 238 } else if (!doesNotEscapeMapSet.contains(user.selector.name)) {
239 bailout('Escape from a map via [${user.selector.name}]'); 239 bailout('Escape from a map via [${user.selector.name}]');
240 } 240 }
241 }); 241 });
242 }); 242 });
243 } 243 }
244 } 244 }
245 245
246 /** 246 /**
247 * Checks whether this is a call to a list adding method. The definition 247 * Checks whether this is a call to a list adding method. The definition of
248 * of what list adding means has to stay in sync with 248 * what list adding means has to stay in sync with
249 * [isParameterOfListAddingMethod]. 249 * [isParameterOfListAddingMethod].
250 */ 250 */
251 bool isAddedToContainer(DynamicCallSiteTypeInformation info) { 251 bool mightAddToContainer(DynamicCallSiteTypeInformation info) {
252 if (info.arguments == null) return false; 252 if (info.arguments == null) return false;
253 var receiverType = info.receiver.type; 253 if (info.arguments.named.isNotEmpty) return false;
254 if (!receiverType.isContainer) return false;
255 String selectorName = info.selector.name; 254 String selectorName = info.selector.name;
256 List<TypeInformation> arguments = info.arguments.positional; 255 List<TypeInformation> arguments = info.arguments.positional;
257 return (selectorName == '[]=' && currentUser == arguments[1]) || 256 if (arguments.length == 1) {
258 (selectorName == 'insert' && currentUser == arguments[1]) || 257 return (selectorName == 'add' && currentUser == arguments[0]);
259 (selectorName == 'add' && currentUser == arguments[0]); 258 } else if (arguments.length == 2) {
259 return (selectorName == 'insert' && currentUser == arguments[1]);
260 }
261 return false;
260 } 262 }
261 263
262 bool isIndexSetOnMap(DynamicCallSiteTypeInformation info) { 264 bool isIndexSetArgument(DynamicCallSiteTypeInformation info, int index) {
263 if (info.arguments == null) return false; 265 String selectorName = info.selector.name;
264 var receiverType = info.receiver.type; 266 if (selectorName != '[]=') return false;
265 if (!receiverType.isMap) return false; 267 assert(info.arguments.length == 2);
266 return info.selector.name == '[]='; 268 List<TypeInformation> arguments = info.arguments.positional;
269 return currentUser == arguments[index];
267 } 270 }
268 271
269 /** 272 /**
270 * Checks whether this is a call to a map adding method for values. The 273 * Checks whether the call site flows the currentUser to the key argument of
271 * definition of map adding method has to stay in sync with 274 * an indexing setter. This must be kept in sync with
272 * [isParameterOfMapAddingMethod]. 275 * [isParameterOfMapAddingMethod].
273 */ 276 */
274 bool isValueAddedToMap(DynamicCallSiteTypeInformation info) { 277 bool isIndexSetKey(DynamicCallSiteTypeInformation info) {
275 return isIndexSetOnMap(info) && currentUser == info.arguments.positional[1]; 278 return isIndexSetArgument(info, 0);
276 } 279 }
277 280
278 /** 281 /**
279 * Checks whether this is a call to a map adding method for keys. The 282 * Checks whether the call site flows the currentUser to the value argument of
280 * definition of map adding method has to stay in sync with 283 * an indexing setter. This must be kept in sync with
281 * [isParameterOfMapAddingMethod]. 284 * [isParameterOfListAddingMethod] and [isParameterOfMapAddingMethod].
282 */ 285 */
283 bool isKeyAddedToMap(DynamicCallSiteTypeInformation info) { 286 bool isIndexSetValue(DynamicCallSiteTypeInformation info) {
284 return isIndexSetOnMap(info) && currentUser == info.arguments.positional[0]; 287 return isIndexSetArgument(info, 1);
288 }
289
290 void bailoutIfReaches(predicate) {
Emily Fortuna 2017/03/21 00:38:58 add function type to "predicate" ?
sra1 2017/03/21 18:17:22 Done.
291 for (var user in currentUser.users) {
292 if (user is ParameterTypeInformation) {
293 if (predicate(user.element)) {
294 bailout('Reached suppressed parameter without precise receiver');
295 break;
296 }
297 }
298 }
285 } 299 }
286 300
287 void visitDynamicCallSiteTypeInformation( 301 void visitDynamicCallSiteTypeInformation(
288 DynamicCallSiteTypeInformation info) { 302 DynamicCallSiteTypeInformation info) {
289 if (isAddedToContainer(info)) {
290 ContainerTypeMask mask = info.receiver.type;
291 303
304 void addsToContainer(ContainerTypeMask mask) {
292 if (mask.allocationNode != null) { 305 if (mask.allocationNode != null) {
293 ListTypeInformation list = 306 ListTypeInformation list =
294 inferrer.types.allocatedLists[mask.allocationNode]; 307 inferrer.types.allocatedLists[mask.allocationNode];
295 listsToAnalyze.add(list); 308 listsToAnalyze.add(list);
296 } else { 309 } else {
297 // The [ContainerTypeMask] is a union of two containers, and 310 // The [ContainerTypeMask] is a union of two containers, and we lose
298 // we lose track of where these containers have been allocated 311 // track of where these containers have been allocated at this point.
299 // at this point.
300 bailout('Stored in too many containers'); 312 bailout('Stored in too many containers');
301 } 313 }
302 } else if (isValueAddedToMap(info)) { 314 }
303 MapTypeMask mask = info.receiver.type; 315
316 void addsToMapValue(MapTypeMask mask) {
304 if (mask.allocationNode != null) { 317 if (mask.allocationNode != null) {
305 MapTypeInformation map = 318 MapTypeInformation map =
306 inferrer.types.allocatedMaps[mask.allocationNode]; 319 inferrer.types.allocatedMaps[mask.allocationNode];
307 mapsToAnalyze.add(map); 320 mapsToAnalyze.add(map);
308 } else { 321 } else {
309 // The [MapTypeMask] is a union. See comment for 322 // The [MapTypeMask] is a union. See comment for [ContainerTypeMask]
310 // [ContainerTypeMask] above. 323 // above.
311 bailout('Stored in too many maps'); 324 bailout('Stored in too many maps');
312 } 325 }
313 } else if (isKeyAddedToMap(info)) { 326 }
327
328 void addsToMapKey(MapTypeMask mask) {
314 // We do not track the use of keys from a map, so we have to bail. 329 // We do not track the use of keys from a map, so we have to bail.
315 bailout('Used as key in Map'); 330 bailout('Used as key in Map');
316 } 331 }
317 332
333 // "a[...] = x" could be a list (container) or map assignemnt.
334 if (isIndexSetValue(info)) {
335 var receiverType = info.receiver.type;
336 if (receiverType is ContainerTypeMask) {
337 addsToContainer(receiverType);
338 } else if (receiverType is MapTypeMask) {
339 addsToMapValue(receiverType);
340 } else {
341 // Not a container or mask, so the targets could be any methods. There
342 // are edges from the [currentUser] to the parameters of the targets, so
343 // tracing will continue into the targets. Tracing stops at parameters
344 // that match the targets corresponding to the receiverTypes above (to
345 // prevent imprecise results from tracing the implementation), so we
346 // need compensate if one of the targets is in the target set. If there
347 // is an edge to a parameter matching [isParameterOfListAddingMethod] or
348 // [isParameterOfMapAddingMethod] then the traced value is being stored
349 // into an untraced list or map.
350
351 // TODO(sra): It would be more precise to specifically match the `value'
352 // parameters of "operator []=".
353 bailoutIfReaches(isParameterOfListAddingMethod);
354 bailoutIfReaches(isParameterOfMapAddingMethod);
355 }
356 }
357
358 // Could be: m[x] = ...;
359 if (isIndexSetKey(info)) {
360 var receiverType = info.receiver.type;
361 if (receiverType is MapTypeMask) {
362 addsToMapKey(receiverType);
363 } else {
364 bailoutIfReaches(isParameterOfListAddingMethod);
365 bailoutIfReaches(isParameterOfMapAddingMethod);
366 }
367 }
368
369 if (mightAddToContainer(info)) {
370 var receiverType = info.receiver.type;
371 if (receiverType is ContainerTypeMask) {
372 addsToContainer(receiverType);
373 } else {
374 // Not a container, see note above.
375 bailoutIfReaches(isParameterOfListAddingMethod);
376 }
377 }
378
318 if (info.targetsIncludeComplexNoSuchMethod(inferrer) && 379 if (info.targetsIncludeComplexNoSuchMethod(inferrer) &&
319 info.arguments != null && 380 info.arguments != null &&
320 info.arguments.contains(currentUser)) { 381 info.arguments.contains(currentUser)) {
321 bailout('Passed to noSuchMethod'); 382 bailout('Passed to noSuchMethod');
322 } 383 }
323 384
324 Iterable<Element> inferredTargetTypes = info.targets.map((element) { 385 Iterable<Element> inferredTargetTypes = info.targets.map((element) {
325 return inferrer.types.getInferredTypeOf(element); 386 return inferrer.types.getInferredTypeOf(element);
326 }); 387 });
327 if (inferredTargetTypes.any((user) => user == currentUser)) { 388 if (inferredTargetTypes.any((user) => user == currentUser)) {
328 addNewEscapeInformation(info); 389 addNewEscapeInformation(info);
329 } 390 }
330 } 391 }
331 392
332 /** 393 /**
333 * Check whether element is the parameter of a list adding method. 394 * Check whether element is the parameter of a list adding method.
334 * The definition of what a list adding method is has to stay in sync with 395 * The definition of what a list adding method is has to stay in sync with
335 * [isAddedToContainer]. 396 * [mightAddToContainer].
336 */ 397 */
337 bool isParameterOfListAddingMethod(Element element) { 398 bool isParameterOfListAddingMethod(Element element) {
338 if (!element.isRegularParameter) return false; 399 if (!element.isRegularParameter) return false;
339 if (element.enclosingClass != compiler.backend.backendClasses.listClass) { 400 if (element.enclosingClass != compiler.backend.backendClasses.listClass) {
340 return false; 401 return false;
341 } 402 }
342 Element method = element.enclosingElement; 403 String name = element.enclosingElement.name;
343 return (method.name == '[]=') || 404 return (name == '[]=') || (name == 'add') || (name == 'insert');
344 (method.name == 'add') ||
345 (method.name == 'insert');
346 } 405 }
347 406
348 /** 407 /**
349 * Check whether element is the parameter of a list adding method. 408 * Check whether element is the parameter of a list adding method.
350 * The definition of what a list adding method is has to stay in sync with 409 * The definition of what a list adding method is has to stay in sync with
351 * [isValueAddedToMap] and [isKeyAddedToMap]. 410 * [isIndexSetKey] and [isIndexSetValue].
352 */ 411 */
353 bool isParameterOfMapAddingMethod(Element element) { 412 bool isParameterOfMapAddingMethod(Element element) {
354 if (!element.isRegularParameter) return false; 413 if (!element.isRegularParameter) return false;
355 if (element.enclosingClass != compiler.backend.backendClasses.mapClass) { 414 if (element.enclosingClass != compiler.backend.backendClasses.mapClass) {
356 return false; 415 return false;
357 } 416 }
358 Element method = element.enclosingElement; 417 String name = element.enclosingElement.name;
359 return (method.name == '[]='); 418 return (name == '[]=');
360 } 419 }
361 420
362 bool isClosure(Element element) { 421 bool isClosure(Element element) {
363 if (!element.isFunction) return false; 422 if (!element.isFunction) return false;
364 423
365 /// Creating an instance of a class that implements [Function] also 424 /// Creating an instance of a class that implements [Function] also
366 /// closurizes the corresponding [call] member. We do not currently 425 /// closurizes the corresponding [call] member. We do not currently
367 /// track these, thus the check for [isClosurized] on such a method will 426 /// track these, thus the check for [isClosurized] on such a method will
368 /// return false. Instead we catch that case here for now. 427 /// return false. Instead we catch that case here for now.
369 // TODO(herhut): Handle creation of closures from instances of Function. 428 // TODO(herhut): Handle creation of closures from instances of Function.
(...skipping 22 matching lines...) Expand all
392 void visitParameterTypeInformation(ParameterTypeInformation info) { 451 void visitParameterTypeInformation(ParameterTypeInformation info) {
393 ParameterElement element = info.element; 452 ParameterElement element = info.element;
394 if (inferrer.isNativeMember(element.functionDeclaration)) { 453 if (inferrer.isNativeMember(element.functionDeclaration)) {
395 bailout('Passed to a native method'); 454 bailout('Passed to a native method');
396 } 455 }
397 if (!inferrer.compiler.backend 456 if (!inferrer.compiler.backend
398 .canFunctionParametersBeUsedForGlobalOptimizations( 457 .canFunctionParametersBeUsedForGlobalOptimizations(
399 element.functionDeclaration)) { 458 element.functionDeclaration)) {
400 bailout('Escape to code that has special backend treatment'); 459 bailout('Escape to code that has special backend treatment');
401 } 460 }
402 if (isParameterOfListAddingMethod(info.element) || 461 if (isParameterOfListAddingMethod(element) ||
403 isParameterOfMapAddingMethod(info.element)) { 462 isParameterOfMapAddingMethod(element)) {
404 // These elements are being handled in 463 // These elements are being handled in
405 // [visitDynamicCallSiteTypeInformation]. 464 // [visitDynamicCallSiteTypeInformation].
406 return; 465 return;
407 } 466 }
408 addNewEscapeInformation(info); 467 addNewEscapeInformation(info);
409 } 468 }
410 } 469 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/inferrer/inferrer_engine.dart ('k') | pkg/compiler/lib/src/inferrer/type_graph_dump.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698