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 library locals_handler; | 5 library locals_handler; |
6 | 6 |
7 import 'dart:collection' show IterableMixin; | 7 import 'dart:collection' show IterableMixin; |
8 | 8 |
9 import '../options.dart' show CompilerOptions; | 9 import '../options.dart' show CompilerOptions; |
10 import '../elements/elements.dart'; | 10 import '../elements/elements.dart'; |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
97 } | 97 } |
98 | 98 |
99 String toString() { | 99 String toString() { |
100 String rest = parent == null ? "null" : parent.toString(); | 100 String rest = parent == null ? "null" : parent.toString(); |
101 return '$variables $rest'; | 101 return '$variables $rest'; |
102 } | 102 } |
103 } | 103 } |
104 | 104 |
105 /// Tracks initializers via initializations and assignments. | 105 /// Tracks initializers via initializations and assignments. |
106 class FieldInitializationScope { | 106 class FieldInitializationScope { |
107 final TypeSystem types; | 107 final TypeSystem<Node> types; |
108 Map<Element, TypeInformation> fields; | 108 Map<Element, TypeInformation> fields; |
109 bool isThisExposed; | 109 bool isThisExposed; |
110 | 110 |
111 /// `true` when control flow prevents accumulating definite assignments, | 111 /// `true` when control flow prevents accumulating definite assignments, |
112 /// e.g. an early return or caught exception. | 112 /// e.g. an early return or caught exception. |
113 bool isIndefinite; | 113 bool isIndefinite; |
114 | 114 |
115 FieldInitializationScope(this.types) | 115 FieldInitializationScope(this.types) |
116 : isThisExposed = false, | 116 : isThisExposed = false, |
117 isIndefinite = false; | 117 isIndefinite = false; |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
236 _iteratePositional = false; | 236 _iteratePositional = false; |
237 return named.moveNext(); | 237 return named.moveNext(); |
238 } | 238 } |
239 } | 239 } |
240 | 240 |
241 /** | 241 /** |
242 * Placeholder for inferred types of local variables. | 242 * Placeholder for inferred types of local variables. |
243 */ | 243 */ |
244 class LocalsHandler { | 244 class LocalsHandler { |
245 final CompilerOptions options; | 245 final CompilerOptions options; |
246 final TypeSystem types; | 246 final TypeSystem<Node> types; |
247 final InferrerEngine inferrer; | 247 final InferrerEngine inferrer; |
248 final VariableScope locals; | 248 final VariableScope locals; |
249 final Map<Local, FieldEntity> captured; | 249 final Map<Local, FieldEntity> captured; |
250 final Map<Local, FieldEntity> capturedAndBoxed; | 250 final Map<Local, FieldEntity> capturedAndBoxed; |
251 final FieldInitializationScope fieldScope; | 251 final FieldInitializationScope fieldScope; |
252 LocalsHandler tryBlock; | 252 LocalsHandler tryBlock; |
253 bool seenReturnOrThrow = false; | 253 bool seenReturnOrThrow = false; |
254 bool seenBreakOrContinue = false; | 254 bool seenBreakOrContinue = false; |
255 | 255 |
256 bool get aborts { | 256 bool get aborts { |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
319 updateLocal() { | 319 updateLocal() { |
320 TypeInformation currentType = locals[local]; | 320 TypeInformation currentType = locals[local]; |
321 | 321 |
322 SendSet send = node != null ? node.asSendSet() : null; | 322 SendSet send = node != null ? node.asSendSet() : null; |
323 if (send != null && send.isIfNullAssignment && currentType != null) { | 323 if (send != null && send.isIfNullAssignment && currentType != null) { |
324 // If-null assignments may return either the new or the original value | 324 // If-null assignments may return either the new or the original value |
325 // narrowed to non-null. | 325 // narrowed to non-null. |
326 type = types.addPhiInput( | 326 type = types.addPhiInput( |
327 local, | 327 local, |
328 types.allocatePhi( | 328 types.allocatePhi( |
329 locals.block, local, types.narrowNotNull(currentType)), | 329 locals.block, local, types.narrowNotNull(currentType), |
| 330 isTry: locals.block is TryStatement), |
330 type); | 331 type); |
331 } | 332 } |
332 locals[local] = type; | 333 locals[local] = type; |
333 if (currentType != type) { | 334 if (currentType != type) { |
334 inferrer.recordLocalUpdate(local, type); | 335 inferrer.recordLocalUpdate(local, type); |
335 } | 336 } |
336 } | 337 } |
337 | 338 |
338 if (capturedAndBoxed.containsKey(local)) { | 339 if (capturedAndBoxed.containsKey(local)) { |
339 inferrer.recordTypeOfNonFinalField(capturedAndBoxed[local], type); | 340 inferrer.recordTypeOfNonFinalField(capturedAndBoxed[local], type); |
340 } else if (inTryBlock) { | 341 } else if (inTryBlock) { |
341 // We don'TypeInformation know if an assignment in a try block | 342 // We don'TypeInformation know if an assignment in a try block |
342 // will be executed, so all assignments in that block are | 343 // will be executed, so all assignments in that block are |
343 // potential types after we have left it. We update the parent | 344 // potential types after we have left it. We update the parent |
344 // of the try block so that, at exit of the try block, we get | 345 // of the try block so that, at exit of the try block, we get |
345 // the right phi for it. | 346 // the right phi for it. |
346 TypeInformation existing = tryBlock.locals.parent[local]; | 347 TypeInformation existing = tryBlock.locals.parent[local]; |
347 if (existing != null) { | 348 if (existing != null) { |
348 TypeInformation phiType = | 349 TypeInformation phiType = types.allocatePhi( |
349 types.allocatePhi(tryBlock.locals.block, local, existing); | 350 tryBlock.locals.block, local, existing, |
| 351 isTry: tryBlock.locals.block is TryStatement); |
350 TypeInformation inputType = types.addPhiInput(local, phiType, type); | 352 TypeInformation inputType = types.addPhiInput(local, phiType, type); |
351 tryBlock.locals.parent[local] = inputType; | 353 tryBlock.locals.parent[local] = inputType; |
352 } | 354 } |
353 // Update the current handler unconditionnally with the new | 355 // Update the current handler unconditionnally with the new |
354 // type. | 356 // type. |
355 updateLocal(); | 357 updateLocal(); |
356 } else { | 358 } else { |
357 updateLocal(); | 359 updateLocal(); |
358 } | 360 } |
359 } | 361 } |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
498 * overwrites the current type knowledge in this handler. | 500 * overwrites the current type knowledge in this handler. |
499 */ | 501 */ |
500 bool mergeHandler(LocalsHandler other, [Set<Local> seen]) { | 502 bool mergeHandler(LocalsHandler other, [Set<Local> seen]) { |
501 if (other.seenReturnOrThrow) return false; | 503 if (other.seenReturnOrThrow) return false; |
502 bool changed = false; | 504 bool changed = false; |
503 other.locals.forEachLocalUntilNode(locals.block, (local, otherType) { | 505 other.locals.forEachLocalUntilNode(locals.block, (local, otherType) { |
504 TypeInformation myType = locals[local]; | 506 TypeInformation myType = locals[local]; |
505 if (myType == null) return; | 507 if (myType == null) return; |
506 TypeInformation newType; | 508 TypeInformation newType; |
507 if (seen != null && !seen.contains(local)) { | 509 if (seen != null && !seen.contains(local)) { |
508 newType = types.allocatePhi(locals.block, local, otherType); | 510 newType = types.allocatePhi(locals.block, local, otherType, |
| 511 isTry: locals.block is TryStatement); |
509 seen.add(local); | 512 seen.add(local); |
510 } else { | 513 } else { |
511 newType = types.addPhiInput(local, myType, otherType); | 514 newType = types.addPhiInput(local, myType, otherType); |
512 } | 515 } |
513 if (newType != myType) { | 516 if (newType != myType) { |
514 changed = true; | 517 changed = true; |
515 locals[local] = newType; | 518 locals[local] = newType; |
516 } | 519 } |
517 }); | 520 }); |
518 return changed; | 521 return changed; |
519 } | 522 } |
520 | 523 |
521 /** | 524 /** |
522 * Merge all [LocalsHandler] in [handlers] into this handler. | 525 * Merge all [LocalsHandler] in [handlers] into this handler. |
523 * Returns whether a local in this handler has changed. | 526 * Returns whether a local in this handler has changed. |
524 */ | 527 */ |
525 bool mergeAll(List<LocalsHandler> handlers) { | 528 bool mergeAll(List<LocalsHandler> handlers) { |
526 bool changed = false; | 529 bool changed = false; |
527 assert(!seenReturnOrThrow); | 530 assert(!seenReturnOrThrow); |
528 handlers.forEach((other) { | 531 handlers.forEach((other) { |
529 changed = mergeHandler(other) || changed; | 532 changed = mergeHandler(other) || changed; |
530 }); | 533 }); |
531 return changed; | 534 return changed; |
532 } | 535 } |
533 | 536 |
534 void startLoop(Node loop) { | 537 void startLoop(Node loop) { |
535 locals.forEachLocal((Local variable, TypeInformation type) { | 538 locals.forEachLocal((Local variable, TypeInformation type) { |
536 TypeInformation newType = types.allocateLoopPhi(loop, variable, type); | 539 TypeInformation newType = types.allocateLoopPhi(loop, variable, type, |
| 540 isTry: loop is TryStatement); |
537 if (newType != type) { | 541 if (newType != type) { |
538 locals[variable] = newType; | 542 locals[variable] = newType; |
539 } | 543 } |
540 }); | 544 }); |
541 } | 545 } |
542 | 546 |
543 void endLoop(Node loop) { | 547 void endLoop(Node loop) { |
544 locals.forEachLocal((Local variable, TypeInformation type) { | 548 locals.forEachLocal((Local variable, TypeInformation type) { |
545 TypeInformation newType = types.simplifyPhi(loop, variable, type); | 549 TypeInformation newType = types.simplifyPhi(loop, variable, type); |
546 if (newType != type) { | 550 if (newType != type) { |
547 locals[variable] = newType; | 551 locals[variable] = newType; |
548 } | 552 } |
549 }); | 553 }); |
550 } | 554 } |
551 | 555 |
552 void updateField(Element element, TypeInformation type) { | 556 void updateField(Element element, TypeInformation type) { |
553 fieldScope.updateField(element, type); | 557 fieldScope.updateField(element, type); |
554 } | 558 } |
555 } | 559 } |
OLD | NEW |