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

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

Issue 3002313002: Use KernelTypeGraphBuilder in KernelInferrerEngine (Closed)
Patch Set: Created 3 years, 3 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 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';
11 import '../elements/entities.dart'; 11 import '../elements/entities.dart';
12 import '../elements/types.dart';
12 import '../tree/tree.dart'; 13 import '../tree/tree.dart';
13 import '../util/util.dart'; 14 import '../util/util.dart';
14 import 'inferrer_engine.dart'; 15 import 'inferrer_engine.dart';
15 import 'type_graph_nodes.dart'; 16 import 'type_graph_nodes.dart';
16 import 'type_system.dart'; 17 import 'type_system.dart';
17 18
18 /** 19 /**
19 * A variable scope holds types for variables. It has a link to a 20 * A variable scope holds types for variables. It has a link to a
20 * parent scope, but never changes the types in that parent. Instead, 21 * parent scope, but never changes the types in that parent. Instead,
21 * updates to locals of a parent scope are put in the current scope. 22 * updates to locals of a parent scope are put in the current scope.
22 * The inferrer makes sure updates get merged into the parent scope, 23 * The inferrer makes sure updates get merged into the parent scope,
23 * once the control flow block has been visited. 24 * once the control flow block has been visited.
24 */ 25 */
25 class VariableScope { 26 class VariableScope<T> {
26 Map<Local, TypeInformation> variables; 27 Map<Local, TypeInformation> variables;
27 28
28 /// The parent of this scope. Null for the root scope. 29 /// The parent of this scope. Null for the root scope.
29 final VariableScope parent; 30 final VariableScope parent;
30 31
31 /// The [Node] that created this scope. 32 /// The [Node] that created this scope.
32 final Node block; 33 final T block;
33 34
34 VariableScope(this.block, [parent]) 35 VariableScope(this.block, [parent])
35 : this.variables = null, 36 : this.variables = null,
36 this.parent = parent; 37 this.parent = parent;
37 38
38 VariableScope.deepCopyOf(VariableScope other) 39 VariableScope.deepCopyOf(VariableScope<T> other)
39 : variables = other.variables == null 40 : variables = other.variables == null
40 ? null 41 ? null
41 : new Map<Local, TypeInformation>.from(other.variables), 42 : new Map<Local, TypeInformation>.from(other.variables),
42 block = other.block, 43 block = other.block,
43 parent = other.parent == null 44 parent = other.parent == null
44 ? null 45 ? null
45 : new VariableScope.deepCopyOf(other.parent); 46 : new VariableScope.deepCopyOf(other.parent);
46 47
47 VariableScope.topLevelCopyOf(VariableScope other) 48 VariableScope.topLevelCopyOf(VariableScope<T> other)
48 : variables = other.variables == null 49 : variables = other.variables == null
49 ? null 50 ? null
50 : new Map<Local, TypeInformation>.from(other.variables), 51 : new Map<Local, TypeInformation>.from(other.variables),
51 block = other.block, 52 block = other.block,
52 parent = other.parent; 53 parent = other.parent;
53 54
54 TypeInformation operator [](Local variable) { 55 TypeInformation operator [](Local variable) {
55 TypeInformation result; 56 TypeInformation result;
56 if (variables == null || (result = variables[variable]) == null) { 57 if (variables == null || (result = variables[variable]) == null) {
57 return parent == null ? null : parent[variable]; 58 return parent == null ? null : parent[variable];
58 } 59 }
59 return result; 60 return result;
60 } 61 }
61 62
62 void operator []=(Local variable, TypeInformation mask) { 63 void operator []=(Local variable, TypeInformation mask) {
63 assert(mask != null); 64 assert(mask != null);
64 if (variables == null) { 65 if (variables == null) {
65 variables = new Map<Local, TypeInformation>(); 66 variables = new Map<Local, TypeInformation>();
66 } 67 }
67 variables[variable] = mask; 68 variables[variable] = mask;
68 } 69 }
69 70
70 void forEachOwnLocal(void f(Local variable, TypeInformation type)) { 71 void forEachOwnLocal(void f(Local variable, TypeInformation type)) {
71 if (variables == null) return; 72 if (variables == null) return;
72 variables.forEach(f); 73 variables.forEach(f);
73 } 74 }
74 75
75 void forEachLocalUntilNode( 76 void forEachLocalUntilNode(
76 Node node, void f(Local variable, TypeInformation type), 77 T node, void f(Local variable, TypeInformation type),
77 [Setlet<Local> seenLocals]) { 78 [Setlet<Local> seenLocals]) {
78 if (seenLocals == null) seenLocals = new Setlet<Local>(); 79 if (seenLocals == null) seenLocals = new Setlet<Local>();
79 if (variables != null) { 80 if (variables != null) {
80 variables.forEach((variable, type) { 81 variables.forEach((variable, type) {
81 if (seenLocals.contains(variable)) return; 82 if (seenLocals.contains(variable)) return;
82 seenLocals.add(variable); 83 seenLocals.add(variable);
83 f(variable, type); 84 f(variable, type);
84 }); 85 });
85 } 86 }
86 if (block == node) return; 87 if (block == node) return;
87 if (parent != null) parent.forEachLocalUntilNode(node, f, seenLocals); 88 if (parent != null) parent.forEachLocalUntilNode(node, f, seenLocals);
88 } 89 }
89 90
90 void forEachLocal(void f(Local variable, TypeInformation type)) { 91 void forEachLocal(void f(Local variable, TypeInformation type)) {
91 forEachLocalUntilNode(null, f); 92 forEachLocalUntilNode(null, f);
92 } 93 }
93 94
94 bool updates(Local variable) { 95 bool updates(Local variable) {
95 if (variables == null) return false; 96 if (variables == null) return false;
96 return variables.containsKey(variable); 97 return variables.containsKey(variable);
97 } 98 }
98 99
99 String toString() { 100 String toString() {
100 String rest = parent == null ? "null" : parent.toString(); 101 String rest = parent == null ? "null" : parent.toString();
101 return '$variables $rest'; 102 return '$variables $rest';
102 } 103 }
103 } 104 }
104 105
105 /// Tracks initializers via initializations and assignments. 106 /// Tracks initializers via initializations and assignments.
106 class FieldInitializationScope { 107 class FieldInitializationScope<T> {
107 final TypeSystem<Node> types; 108 final TypeSystem<T> types;
108 Map<Element, TypeInformation> fields; 109 Map<FieldEntity, TypeInformation> fields;
109 bool isThisExposed; 110 bool isThisExposed;
110 111
111 /// `true` when control flow prevents accumulating definite assignments, 112 /// `true` when control flow prevents accumulating definite assignments,
112 /// e.g. an early return or caught exception. 113 /// e.g. an early return or caught exception.
113 bool isIndefinite; 114 bool isIndefinite;
114 115
115 FieldInitializationScope(this.types) 116 FieldInitializationScope(this.types)
116 : isThisExposed = false, 117 : isThisExposed = false,
117 isIndefinite = false; 118 isIndefinite = false;
118 119
119 FieldInitializationScope.internalFrom(FieldInitializationScope other) 120 FieldInitializationScope.internalFrom(FieldInitializationScope<T> other)
120 : types = other.types, 121 : types = other.types,
121 isThisExposed = other.isThisExposed, 122 isThisExposed = other.isThisExposed,
122 isIndefinite = other.isIndefinite; 123 isIndefinite = other.isIndefinite;
123 124
124 factory FieldInitializationScope.from(FieldInitializationScope other) { 125 factory FieldInitializationScope.from(FieldInitializationScope<T> other) {
125 if (other == null) return null; 126 if (other == null) return null;
126 return new FieldInitializationScope.internalFrom(other); 127 return new FieldInitializationScope<T>.internalFrom(other);
127 } 128 }
128 129
129 void updateField(Element field, TypeInformation type) { 130 void updateField(FieldEntity field, TypeInformation type) {
130 if (isThisExposed) return; 131 if (isThisExposed) return;
131 if (isIndefinite) return; 132 if (isIndefinite) return;
132 fields ??= new Map<Element, TypeInformation>(); 133 fields ??= new Map<FieldEntity, TypeInformation>();
133 fields[field] = type; 134 fields[field] = type;
134 } 135 }
135 136
136 TypeInformation readField(Element field) { 137 TypeInformation readField(FieldEntity field) {
137 return fields == null ? null : fields[field]; 138 return fields == null ? null : fields[field];
138 } 139 }
139 140
140 void forEach(void f(Element element, TypeInformation type)) { 141 void forEach(void f(FieldEntity element, TypeInformation type)) {
141 fields?.forEach(f); 142 fields?.forEach(f);
142 } 143 }
143 144
144 void mergeDiamondFlow( 145 void mergeDiamondFlow(FieldInitializationScope<T> thenScope,
145 FieldInitializationScope thenScope, FieldInitializationScope elseScope) { 146 FieldInitializationScope<T> elseScope) {
146 // Quick bailout check. If [isThisExposed] or [isIndefinite] is true, we 147 // Quick bailout check. If [isThisExposed] or [isIndefinite] is true, we
147 // know the code following won'TypeInformation do anything. 148 // know the code following won'TypeInformation do anything.
148 if (isThisExposed) return; 149 if (isThisExposed) return;
149 if (isIndefinite) return; 150 if (isIndefinite) return;
150 151
151 FieldInitializationScope otherScope = 152 FieldInitializationScope<T> otherScope =
152 (elseScope == null || elseScope.fields == null) ? this : elseScope; 153 (elseScope == null || elseScope.fields == null) ? this : elseScope;
153 154
154 thenScope.forEach((Element field, TypeInformation type) { 155 thenScope.forEach((FieldEntity field, TypeInformation type) {
155 TypeInformation otherType = otherScope.readField(field); 156 TypeInformation otherType = otherScope.readField(field);
156 if (otherType == null) return; 157 if (otherType == null) return;
157 updateField(field, types.allocateDiamondPhi(type, otherType)); 158 updateField(field, types.allocateDiamondPhi(type, otherType));
158 }); 159 });
159 160
160 isThisExposed = thenScope.isThisExposed || elseScope.isThisExposed; 161 isThisExposed = thenScope.isThisExposed || elseScope.isThisExposed;
161 isIndefinite = thenScope.isIndefinite || elseScope.isIndefinite; 162 isIndefinite = thenScope.isIndefinite || elseScope.isIndefinite;
162 } 163 }
163 } 164 }
164 165
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
234 return true; 235 return true;
235 } 236 }
236 _iteratePositional = false; 237 _iteratePositional = false;
237 return named.moveNext(); 238 return named.moveNext();
238 } 239 }
239 } 240 }
240 241
241 /** 242 /**
242 * Placeholder for inferred types of local variables. 243 * Placeholder for inferred types of local variables.
243 */ 244 */
244 class LocalsHandler { 245 class LocalsHandler<T> {
245 final CompilerOptions options; 246 final CompilerOptions options;
246 final TypeSystem<Node> types; 247 final TypeSystem<T> types;
247 final InferrerEngine inferrer; 248 final InferrerEngine<T> inferrer;
248 final VariableScope locals; 249 final VariableScope<T> locals;
249 final Map<Local, FieldEntity> captured; 250 final Map<Local, FieldEntity> captured;
250 final Map<Local, FieldEntity> capturedAndBoxed; 251 final Map<Local, FieldEntity> capturedAndBoxed;
251 final FieldInitializationScope fieldScope; 252 final FieldInitializationScope<T> fieldScope;
252 LocalsHandler tryBlock; 253 LocalsHandler<T> tryBlock;
253 bool seenReturnOrThrow = false; 254 bool seenReturnOrThrow = false;
254 bool seenBreakOrContinue = false; 255 bool seenBreakOrContinue = false;
255 256
256 bool get aborts { 257 bool get aborts {
257 return seenReturnOrThrow || seenBreakOrContinue; 258 return seenReturnOrThrow || seenBreakOrContinue;
258 } 259 }
259 260
260 bool get inTryBlock => tryBlock != null; 261 bool get inTryBlock => tryBlock != null;
261 262
262 LocalsHandler(this.inferrer, this.types, this.options, Node block, 263 LocalsHandler(this.inferrer, this.types, this.options, T block,
263 [this.fieldScope]) 264 [this.fieldScope])
264 : locals = new VariableScope(block), 265 : locals = new VariableScope<T>(block),
265 captured = new Map<Local, FieldEntity>(), 266 captured = new Map<Local, FieldEntity>(),
266 capturedAndBoxed = new Map<Local, FieldEntity>(), 267 capturedAndBoxed = new Map<Local, FieldEntity>(),
267 tryBlock = null; 268 tryBlock = null;
268 269
269 LocalsHandler.from(LocalsHandler other, Node block, 270 LocalsHandler.from(LocalsHandler<T> other, T block,
270 {bool useOtherTryBlock: true}) 271 {bool useOtherTryBlock: true})
271 : locals = new VariableScope(block, other.locals), 272 : locals = new VariableScope<T>(block, other.locals),
272 fieldScope = new FieldInitializationScope.from(other.fieldScope), 273 fieldScope = new FieldInitializationScope<T>.from(other.fieldScope),
273 captured = other.captured, 274 captured = other.captured,
274 capturedAndBoxed = other.capturedAndBoxed, 275 capturedAndBoxed = other.capturedAndBoxed,
275 types = other.types, 276 types = other.types,
276 inferrer = other.inferrer, 277 inferrer = other.inferrer,
277 options = other.options { 278 options = other.options {
278 tryBlock = useOtherTryBlock ? other.tryBlock : this; 279 tryBlock = useOtherTryBlock ? other.tryBlock : this;
279 } 280 }
280 281
281 LocalsHandler.deepCopyOf(LocalsHandler other) 282 LocalsHandler.deepCopyOf(LocalsHandler<T> other)
282 : locals = new VariableScope.deepCopyOf(other.locals), 283 : locals = new VariableScope<T>.deepCopyOf(other.locals),
283 fieldScope = new FieldInitializationScope.from(other.fieldScope), 284 fieldScope = new FieldInitializationScope<T>.from(other.fieldScope),
284 captured = other.captured, 285 captured = other.captured,
285 capturedAndBoxed = other.capturedAndBoxed, 286 capturedAndBoxed = other.capturedAndBoxed,
286 tryBlock = other.tryBlock, 287 tryBlock = other.tryBlock,
287 types = other.types, 288 types = other.types,
288 inferrer = other.inferrer, 289 inferrer = other.inferrer,
289 options = other.options; 290 options = other.options;
290 291
291 LocalsHandler.topLevelCopyOf(LocalsHandler other) 292 LocalsHandler.topLevelCopyOf(LocalsHandler<T> other)
292 : locals = new VariableScope.topLevelCopyOf(other.locals), 293 : locals = new VariableScope<T>.topLevelCopyOf(other.locals),
293 fieldScope = new FieldInitializationScope.from(other.fieldScope), 294 fieldScope = new FieldInitializationScope<T>.from(other.fieldScope),
294 captured = other.captured, 295 captured = other.captured,
295 capturedAndBoxed = other.capturedAndBoxed, 296 capturedAndBoxed = other.capturedAndBoxed,
296 tryBlock = other.tryBlock, 297 tryBlock = other.tryBlock,
297 types = other.types, 298 types = other.types,
298 inferrer = other.inferrer, 299 inferrer = other.inferrer,
299 options = other.options; 300 options = other.options;
300 301
301 TypeInformation use(Local local) { 302 TypeInformation use(Local local) {
302 assert(!(local is LocalElement && !local.isImplementation)); 303 assert(!(local is LocalElement && !local.isImplementation));
303 if (capturedAndBoxed.containsKey(local)) { 304 if (capturedAndBoxed.containsKey(local)) {
304 FieldElement field = capturedAndBoxed[local]; 305 FieldElement field = capturedAndBoxed[local];
305 return inferrer.typeOfMember(field); 306 return inferrer.typeOfMember(field);
306 } else { 307 } else {
307 return locals[local]; 308 return locals[local];
308 } 309 }
309 } 310 }
310 311
311 void update(LocalElement local, TypeInformation type, Node node) { 312 void update(Local local, TypeInformation type, T node, DartType staticType,
313 {bool isSetIfNull: false}) {
312 assert(type != null); 314 assert(type != null);
313 if (options.trustTypeAnnotations || options.enableTypeAssertions) { 315 if (options.trustTypeAnnotations || options.enableTypeAssertions) {
314 type = types.narrowType(type, local.type); 316 type = types.narrowType(type, staticType);
315 } 317 }
316 updateLocal() { 318 updateLocal() {
317 TypeInformation currentType = locals[local]; 319 TypeInformation currentType = locals[local];
318 320
319 SendSet send = node != null ? node.asSendSet() : null; 321 if (isSetIfNull && currentType != null) {
320 if (send != null && send.isIfNullAssignment && currentType != null) {
321 // If-null assignments may return either the new or the original value 322 // If-null assignments may return either the new or the original value
322 // narrowed to non-null. 323 // narrowed to non-null.
323 type = types.addPhiInput( 324 type = types.addPhiInput(
324 local, 325 local,
325 types.allocatePhi( 326 types.allocatePhi(
326 locals.block, local, types.narrowNotNull(currentType), 327 locals.block, local, types.narrowNotNull(currentType),
327 isTry: locals.block is TryStatement), 328 isTry: locals.block is TryStatement),
328 type); 329 type);
329 } 330 }
330 locals[local] = type; 331 locals[local] = type;
(...skipping 16 matching lines...) Expand all
347 tryBlock.locals.parent[local] = inputType; 348 tryBlock.locals.parent[local] = inputType;
348 } 349 }
349 // Update the current handler unconditionnally with the new 350 // Update the current handler unconditionnally with the new
350 // type. 351 // type.
351 updateLocal(); 352 updateLocal();
352 } else { 353 } else {
353 updateLocal(); 354 updateLocal();
354 } 355 }
355 } 356 }
356 357
358 void narrow(Local local, DartType type, T node, {bool isSetIfNull: false}) {
359 TypeInformation existing = use(local);
360 TypeInformation newType =
361 types.narrowType(existing, type, isNullable: false);
362 update(local, newType, node, type, isSetIfNull: isSetIfNull);
363 }
364
357 void setCaptured(Local local, FieldEntity field) { 365 void setCaptured(Local local, FieldEntity field) {
358 captured[local] = field; 366 captured[local] = field;
359 } 367 }
360 368
361 void setCapturedAndBoxed(Local local, FieldEntity field) { 369 void setCapturedAndBoxed(Local local, FieldEntity field) {
362 capturedAndBoxed[local] = field; 370 capturedAndBoxed[local] = field;
363 } 371 }
364 372
365 void mergeDiamondFlow(LocalsHandler thenBranch, LocalsHandler elseBranch) { 373 void mergeDiamondFlow(
374 LocalsHandler<T> thenBranch, LocalsHandler<T> elseBranch) {
366 if (fieldScope != null && elseBranch != null) { 375 if (fieldScope != null && elseBranch != null) {
367 fieldScope.mergeDiamondFlow(thenBranch.fieldScope, elseBranch.fieldScope); 376 fieldScope.mergeDiamondFlow(thenBranch.fieldScope, elseBranch.fieldScope);
368 } 377 }
369 seenReturnOrThrow = thenBranch.seenReturnOrThrow && 378 seenReturnOrThrow = thenBranch.seenReturnOrThrow &&
370 elseBranch != null && 379 elseBranch != null &&
371 elseBranch.seenReturnOrThrow; 380 elseBranch.seenReturnOrThrow;
372 seenBreakOrContinue = thenBranch.seenBreakOrContinue && 381 seenBreakOrContinue = thenBranch.seenBreakOrContinue &&
373 elseBranch != null && 382 elseBranch != null &&
374 elseBranch.seenBreakOrContinue; 383 elseBranch.seenBreakOrContinue;
375 if (aborts) return; 384 if (aborts) return;
376 385
377 void mergeOneBranch(LocalsHandler other) { 386 void mergeOneBranch(LocalsHandler<T> other) {
378 other.locals.forEachOwnLocal((Local local, TypeInformation type) { 387 other.locals.forEachOwnLocal((Local local, TypeInformation type) {
379 TypeInformation myType = locals[local]; 388 TypeInformation myType = locals[local];
380 if (myType == null) return; // Variable is only defined in [other]. 389 if (myType == null) return; // Variable is only defined in [other].
381 if (type == myType) return; 390 if (type == myType) return;
382 locals[local] = types.allocateDiamondPhi(myType, type); 391 locals[local] = types.allocateDiamondPhi(myType, type);
383 }); 392 });
384 } 393 }
385 394
386 void inPlaceUpdateOneBranch(LocalsHandler other) { 395 void inPlaceUpdateOneBranch(LocalsHandler<T> other) {
387 other.locals.forEachOwnLocal((Local local, TypeInformation type) { 396 other.locals.forEachOwnLocal((Local local, TypeInformation type) {
388 TypeInformation myType = locals[local]; 397 TypeInformation myType = locals[local];
389 if (myType == null) return; // Variable is only defined in [other]. 398 if (myType == null) return; // Variable is only defined in [other].
390 if (type == myType) return; 399 if (type == myType) return;
391 locals[local] = type; 400 locals[local] = type;
392 }); 401 });
393 } 402 }
394 403
395 if (thenBranch.aborts) { 404 if (thenBranch.aborts) {
396 if (elseBranch == null) return; 405 if (elseBranch == null) return;
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
446 * 455 *
447 * [: L: { 456 * [: L: {
448 * if (...) break; 457 * if (...) break;
449 * ... 458 * ...
450 * } 459 * }
451 * :] 460 * :]
452 * 461 *
453 * where [:this:] is the [LocalsHandler] for the paths through the 462 * where [:this:] is the [LocalsHandler] for the paths through the
454 * labeled statement that do not break out. 463 * labeled statement that do not break out.
455 */ 464 */
456 void mergeAfterBreaks(List<LocalsHandler> handlers, 465 void mergeAfterBreaks(List<LocalsHandler<T>> handlers,
457 {bool keepOwnLocals: true}) { 466 {bool keepOwnLocals: true}) {
458 Node level = locals.block; 467 T level = locals.block;
459 // Use a separate locals handler to perform the merge in, so that Phi 468 // Use a separate locals handler to perform the merge in, so that Phi
460 // creation does not invalidate previous type knowledge while we might 469 // creation does not invalidate previous type knowledge while we might
461 // still look it up. 470 // still look it up.
462 LocalsHandler merged = new LocalsHandler.from(this, level); 471 LocalsHandler<T> merged = new LocalsHandler<T>.from(this, level);
463 Set<Local> seenLocals = new Setlet<Local>(); 472 Set<Local> seenLocals = new Setlet<Local>();
464 bool allBranchesAbort = true; 473 bool allBranchesAbort = true;
465 // Merge all other handlers. 474 // Merge all other handlers.
466 for (LocalsHandler handler in handlers) { 475 for (LocalsHandler<T> handler in handlers) {
467 allBranchesAbort = allBranchesAbort && handler.seenReturnOrThrow; 476 allBranchesAbort = allBranchesAbort && handler.seenReturnOrThrow;
468 merged.mergeHandler(handler, seenLocals); 477 merged.mergeHandler(handler, seenLocals);
469 } 478 }
470 // If we want to keep own locals, we merge [seenLocals] from [this] into 479 // If we want to keep own locals, we merge [seenLocals] from [this] into
471 // [merged] to update the Phi nodes with original values. 480 // [merged] to update the Phi nodes with original values.
472 if (keepOwnLocals && !seenReturnOrThrow) { 481 if (keepOwnLocals && !seenReturnOrThrow) {
473 for (Local variable in seenLocals) { 482 for (Local variable in seenLocals) {
474 TypeInformation originalType = locals[variable]; 483 TypeInformation originalType = locals[variable];
475 if (originalType != null) { 484 if (originalType != null) {
476 merged.locals[variable] = types.addPhiInput( 485 merged.locals[variable] = types.addPhiInput(
477 variable, merged.locals[variable], originalType); 486 variable, merged.locals[variable], originalType);
478 } 487 }
479 } 488 }
480 } 489 }
481 // Clean up Phi nodes with single input and store back result into 490 // Clean up Phi nodes with single input and store back result into
482 // actual locals handler. 491 // actual locals handler.
483 merged.locals.forEachOwnLocal((Local variable, TypeInformation type) { 492 merged.locals.forEachOwnLocal((Local variable, TypeInformation type) {
484 locals[variable] = types.simplifyPhi(level, variable, type); 493 locals[variable] = types.simplifyPhi(level, variable, type);
485 }); 494 });
486 seenReturnOrThrow = 495 seenReturnOrThrow =
487 allBranchesAbort && (!keepOwnLocals || seenReturnOrThrow); 496 allBranchesAbort && (!keepOwnLocals || seenReturnOrThrow);
488 } 497 }
489 498
490 /** 499 /**
491 * Merge [other] into this handler. Returns whether a local in this 500 * Merge [other] into this handler. Returns whether a local in this
492 * has changed. If [seen] is not null, we allocate new Phi nodes 501 * has changed. If [seen] is not null, we allocate new Phi nodes
493 * unless the local is already present in the set [seen]. This effectively 502 * unless the local is already present in the set [seen]. This effectively
494 * overwrites the current type knowledge in this handler. 503 * overwrites the current type knowledge in this handler.
495 */ 504 */
496 bool mergeHandler(LocalsHandler other, [Set<Local> seen]) { 505 bool mergeHandler(LocalsHandler<T> other, [Set<Local> seen]) {
497 if (other.seenReturnOrThrow) return false; 506 if (other.seenReturnOrThrow) return false;
498 bool changed = false; 507 bool changed = false;
499 other.locals.forEachLocalUntilNode(locals.block, (local, otherType) { 508 other.locals.forEachLocalUntilNode(locals.block, (local, otherType) {
500 TypeInformation myType = locals[local]; 509 TypeInformation myType = locals[local];
501 if (myType == null) return; 510 if (myType == null) return;
502 TypeInformation newType; 511 TypeInformation newType;
503 if (seen != null && !seen.contains(local)) { 512 if (seen != null && !seen.contains(local)) {
504 newType = types.allocatePhi(locals.block, local, otherType, 513 newType = types.allocatePhi(locals.block, local, otherType,
505 isTry: locals.block is TryStatement); 514 isTry: locals.block is TryStatement);
506 seen.add(local); 515 seen.add(local);
(...skipping 14 matching lines...) Expand all
521 */ 530 */
522 bool mergeAll(List<LocalsHandler> handlers) { 531 bool mergeAll(List<LocalsHandler> handlers) {
523 bool changed = false; 532 bool changed = false;
524 assert(!seenReturnOrThrow); 533 assert(!seenReturnOrThrow);
525 handlers.forEach((other) { 534 handlers.forEach((other) {
526 changed = mergeHandler(other) || changed; 535 changed = mergeHandler(other) || changed;
527 }); 536 });
528 return changed; 537 return changed;
529 } 538 }
530 539
531 void startLoop(Node loop) { 540 void startLoop(T loop) {
532 locals.forEachLocal((Local variable, TypeInformation type) { 541 locals.forEachLocal((Local variable, TypeInformation type) {
533 TypeInformation newType = types.allocateLoopPhi(loop, variable, type, 542 TypeInformation newType = types.allocateLoopPhi(loop, variable, type,
534 isTry: loop is TryStatement); 543 isTry: loop is TryStatement);
535 if (newType != type) { 544 if (newType != type) {
536 locals[variable] = newType; 545 locals[variable] = newType;
537 } 546 }
538 }); 547 });
539 } 548 }
540 549
541 void endLoop(Node loop) { 550 void endLoop(T loop) {
542 locals.forEachLocal((Local variable, TypeInformation type) { 551 locals.forEachLocal((Local variable, TypeInformation type) {
543 TypeInformation newType = types.simplifyPhi(loop, variable, type); 552 TypeInformation newType = types.simplifyPhi(loop, variable, type);
544 if (newType != type) { 553 if (newType != type) {
545 locals[variable] = newType; 554 locals[variable] = newType;
546 } 555 }
547 }); 556 });
548 } 557 }
549 558
550 void updateField(Element element, TypeInformation type) { 559 void updateField(FieldEntity element, TypeInformation type) {
551 fieldScope.updateField(element, type); 560 fieldScope.updateField(element, type);
552 } 561 }
553 } 562 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698