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

Side by Side Diff: pkg/compiler/lib/src/cps_ir/constant_propagation.dart

Issue 800433003: First version of typr propagation in the new IR. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Add type arguments, fix join and tests. Created 6 years 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, 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 dart2js.optimizers; 5 part of dart2js.optimizers;
6 6
7 abstract class TypeSystem<T> {
8 T get dynamicType;
9 T get typeType;
10 T get functionType;
11 T get boolType;
12 T get intType;
13 T get stringType;
14 T get listType;
15 T get mapType;
16
17 T getReturnType(FunctionElement element);
18 T getParameterType(ParameterElement element);
19 bool areEqual(T a, T b);
20 bool areAssignable(T a, T b);
21 T join(T a, T b);
22 T typeOf(ConstantValue constant);
23 }
24
25 class TypeMaskSystem implements TypeSystem<TypeMask> {
26 final TypesTask inferrer;
27 final ClassWorld classWorld;
28
29 TypeMask get dynamicType => inferrer.dynamicType;
30 TypeMask get typeType => inferrer.typeType;
31 TypeMask get functionType => inferrer.functionType;
32 TypeMask get boolType => inferrer.boolType;
33 TypeMask get intType => inferrer.intType;
34 TypeMask get stringType => inferrer.stringType;
35 TypeMask get listType => inferrer.listType;
36 TypeMask get mapType => inferrer.mapType;
37
38 // TODO(karlklose): the map should be per continuation.
39 Map<Node, TypeMask> map = <Node, TypeMask>{};
40
41 TypeMaskSystem(dart2js.Compiler compiler)
42 : inferrer = compiler.typesTask,
43 classWorld = compiler.world;
44
45 TypeMask getType(Node node) => map[node];
46
47 setType(Primitive node, TypeMask type) => map[node] = type;
48
49 TypeMask getParameterType(ParameterElement parameter) {
50 return inferrer.getGuaranteedTypeOfElement(parameter);
51 }
52
53 TypeMask getReturnType(FunctionElement function) {
54 return inferrer.getGuaranteedReturnTypeOfElement(function);
55 }
56
57 @override
58 bool areEqual(TypeMask a, TypeMask b) {
59 return identical(a, b) ||
60 a.isInMask(b, classWorld) ||
Kevin Millikin (Google) 2014/12/12 11:00:23 Typo: || should be &&.
karlklose 2014/12/12 11:43:48 Obsolete, removed the method from the TypeSystem i
61 a.containsMask(b, classWorld);
62 }
63
64 @override
65 bool areAssignable(TypeMask a, TypeMask b) {
66 return a.containsMask(b, classWorld) || b.containsMask(a, classWorld);
67 }
68
69 @override
70 TypeMask join(TypeMask a, TypeMask b) {
71 return a.union(b, classWorld);
72 }
73
74 @override
75 TypeMask typeOf(ConstantValue constant) {
76 return constant.computeMask(inferrer.compiler);
77 }
78 }
79
80 typedef void InternalErrorFunction(Spannable location, String message);
81
7 /** 82 /**
8 * Propagates constants throughout the IR, and replaces branches with fixed 83 * Propagates types (including value types for constants) throughout the IR, and
9 * jumps as well as side-effect free expressions with known constant results. 84 * replaces branches with fixed jumps as well as side-effect free expressions
85 * with known constant results.
86 *
10 * Should be followed by the [ShrinkingReducer] pass. 87 * Should be followed by the [ShrinkingReducer] pass.
11 * 88 *
12 * Implemented according to 'Constant Propagation with Conditional Branches' 89 * Implemented according to 'Constant Propagation with Conditional Branches'
13 * by Wegman, Zadeck. 90 * by Wegman, Zadeck.
14 */ 91 */
15 class ConstantPropagator extends Pass { 92 class TypePropagator<T> extends Pass {
16 93 // TODO(karlklose): remove reference to _compiler. It is currently used to
17 // Required for type determination in analysis of TypeOperator expressions. 94 // compute [TypeMask]s.
18 final dart2js.Compiler _compiler; 95 final dart2js.Compiler _compiler;
19 96
20 // The constant system is used for evaluation of expressions with constant 97 // The constant system is used for evaluation of expressions with constant
21 // arguments. 98 // arguments.
22 final dart2js.ConstantSystem _constantSystem; 99 final dart2js.ConstantSystem _constantSystem;
100 final TypeSystem _typeSystem;
101 final InternalErrorFunction _internalError;
102 final Map<Node, _AbstractValue> _types;
23 103
24 ConstantPropagator(this._compiler, this._constantSystem); 104
105 TypePropagator(this._compiler,
106 this._constantSystem,
107 this._typeSystem,
108 this._internalError)
109 : _types = <Node, _AbstractValue>{};
25 110
26 void _rewriteExecutableDefinition(ExecutableDefinition root) { 111 void _rewriteExecutableDefinition(ExecutableDefinition root) {
27 // Set all parent pointers. 112 // Set all parent pointers.
28 new ParentVisitor().visit(root); 113 new ParentVisitor().visit(root);
29 114
30 // Analyze. In this phase, the entire term is analyzed for reachability 115 // Analyze. In this phase, the entire term is analyzed for reachability
31 // and the constant status of each expression. 116 // and the constant status of each expression.
Kevin Millikin (Google) 2014/12/12 11:00:23 'constant status' ==> 'abstract value'?
karlklose 2014/12/12 11:43:48 Done.
117 _ConstPropagationVisitor<T> analyzer = new _ConstPropagationVisitor<T>(
118 _constantSystem,
119 _typeSystem,
120 _types,
121 _internalError,
122 _compiler);
32 123
33 _ConstPropagationVisitor analyzer =
34 new _ConstPropagationVisitor(_compiler, _constantSystem);
35 analyzer.analyze(root); 124 analyzer.analyze(root);
36 125
37 // Transform. Uses the data acquired in the previous analysis phase to 126 // Transform. Uses the data acquired in the previous analysis phase to
38 // replace branches with fixed targets and side-effect-free expressions 127 // replace branches with fixed targets and side-effect-free expressions
39 // with constant results. 128 // with constant results.
40
41 _TransformingVisitor transformer = new _TransformingVisitor( 129 _TransformingVisitor transformer = new _TransformingVisitor(
42 analyzer.reachableNodes, analyzer.node2value); 130 analyzer.reachableNodes, analyzer.values, _internalError);
43 transformer.transform(root); 131 transformer.transform(root);
44 } 132 }
45 133
46 void rewriteFunctionDefinition(FunctionDefinition root) { 134 void rewriteFunctionDefinition(FunctionDefinition root) {
47 if (root.isAbstract) return; 135 if (root.isAbstract) return;
48 _rewriteExecutableDefinition(root); 136 _rewriteExecutableDefinition(root);
49 } 137 }
50 138
51 void rewriteFieldDefinition(FieldDefinition root) { 139 void rewriteFieldDefinition(FieldDefinition root) {
52 if (!root.hasInitializer) return; 140 if (!root.hasInitializer) return;
53 _rewriteExecutableDefinition(root); 141 _rewriteExecutableDefinition(root);
54 } 142 }
55 143
144 getType(Node node) => _types[node];
56 } 145 }
57 146
58 /** 147 /**
59 * Uses the information from a preceding analysis pass in order to perform the 148 * Uses the information from a preceding analysis pass in order to perform the
60 * actual transformations on the CPS graph. 149 * actual transformations on the CPS graph.
61 */ 150 */
62 class _TransformingVisitor extends RecursiveVisitor { 151 class _TransformingVisitor extends RecursiveVisitor {
152 final Set<Node> reachable;
153 final Map<Node, _AbstractValue> values;
63 154
64 final Set<Node> reachable; 155 final InternalErrorFunction internalError;
65 final Map<Node, _ConstnessLattice> node2value;
66 156
67 _TransformingVisitor(this.reachable, this.node2value); 157 _TransformingVisitor(this.reachable, this.values, this.internalError);
68 158
69 void transform(ExecutableDefinition root) { 159 void transform(ExecutableDefinition root) {
70 visit(root); 160 visit(root);
71 } 161 }
72 162
73 /// Given an expression with a known constant result and a continuation, 163 /// Given an expression with a known constant result and a continuation,
74 /// replaces the expression by a new LetPrim / InvokeContinuation construct. 164 /// replaces the expression by a new LetPrim / InvokeContinuation construct.
75 /// `unlink` is a closure responsible for unlinking all removed references. 165 /// `unlink` is a closure responsible for unlinking all removed references.
76 LetPrim constifyExpression(Expression node, 166 LetPrim constifyExpression(Expression node,
77 Continuation continuation, 167 Continuation continuation,
78 void unlink()) { 168 void unlink()) {
79 _ConstnessLattice cell = node2value[node]; 169 _AbstractValue value = values[node];
80 if (cell == null || !cell.isConstant) { 170 if (value == null || !value.isConstant) {
81 return null; 171 return null;
82 } 172 }
83 173
84 assert(continuation.parameters.length == 1); 174 assert(continuation.parameters.length == 1);
85 175
86 // Set up the replacement structure. 176 // Set up the replacement structure.
87 177 PrimitiveConstantValue primitiveConstant = value.constant;
88 PrimitiveConstantValue primitiveConstant = cell.constant;
89 ConstantExpression constExp = 178 ConstantExpression constExp =
90 new PrimitiveConstantExpression(primitiveConstant); 179 new PrimitiveConstantExpression(primitiveConstant);
91 Constant constant = new Constant(constExp); 180 Constant constant = new Constant(constExp);
92 LetPrim letPrim = new LetPrim(constant); 181 LetPrim letPrim = new LetPrim(constant);
93 InvokeContinuation invoke = 182 InvokeContinuation invoke =
94 new InvokeContinuation(continuation, <Primitive>[constant]); 183 new InvokeContinuation(continuation, <Primitive>[constant]);
95 184
96 invoke.parent = constant.parent = letPrim; 185 invoke.parent = constant.parent = letPrim;
97 letPrim.body = invoke; 186 letPrim.body = invoke;
98 187
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
200 visitLetPrim(letPrim); 289 visitLetPrim(letPrim);
201 } 290 }
202 } 291 }
203 } 292 }
204 293
205 /** 294 /**
206 * Runs an analysis pass on the given function definition in order to detect 295 * Runs an analysis pass on the given function definition in order to detect
207 * const-ness as well as reachability, both of which are used in the subsequent 296 * const-ness as well as reachability, both of which are used in the subsequent
208 * transformation pass. 297 * transformation pass.
209 */ 298 */
210 class _ConstPropagationVisitor extends Visitor { 299 class _ConstPropagationVisitor<T> extends Visitor {
211 // The node worklist stores nodes that are both reachable and need to be 300 // The node worklist stores nodes that are both reachable and need to be
212 // processed, but have not been processed yet. Using a worklist avoids deep 301 // processed, but have not been processed yet. Using a worklist avoids deep
213 // recursion. 302 // recursion.
214 // The node worklist and the reachable set operate in concert: nodes are 303 // The node worklist and the reachable set operate in concert: nodes are
215 // only ever added to the worklist when they have not yet been marked as 304 // only ever added to the worklist when they have not yet been marked as
216 // reachable, and adding a node to the worklist is always followed by marking 305 // reachable, and adding a node to the worklist is always followed by marking
217 // it reachable. 306 // it reachable.
218 // TODO(jgruber): Storing reachability per-edge instead of per-node would 307 // TODO(jgruber): Storing reachability per-edge instead of per-node would
219 // allow for further optimizations. 308 // allow for further optimizations.
220 final List<Node> nodeWorklist = <Node>[]; 309 final List<Node> nodeWorklist = <Node>[];
221 final Set<Node> reachableNodes = new Set<Node>(); 310 final Set<Node> reachableNodes = new Set<Node>();
222 311
223 // The definition workset stores all definitions which need to be reprocessed 312 // The definition workset stores all definitions which need to be reprocessed
224 // since their lattice value has changed. 313 // since their lattice value has changed.
225 final Set<Definition> defWorkset = new Set<Definition>(); 314 final Set<Definition> defWorkset = new Set<Definition>();
226 315
227 final dart2js.Compiler compiler;
228 final dart2js.ConstantSystem constantSystem; 316 final dart2js.ConstantSystem constantSystem;
317 final TypeSystem typeSystem;
318 final InternalErrorFunction internalError;
319 final Compiler compiler;
320
321 _AbstractValue unknownDynamic;
322
323 _AbstractValue unknown([T t]) {
324 if (t == null) {
325 return unknownDynamic;
326 } else {
327 return new _AbstractValue.unknown(t);
328 }
329 }
330
331 _AbstractValue nonConst([T type]) {
332 if (type == null) {
333 type = typeSystem.dynamicType;
334 }
335 return new _AbstractValue.nonConst(type);
336 }
337
338 _AbstractValue constantValue(ConstantValue constant, T type) {
339 return new _AbstractValue(constant, type);
340 }
229 341
230 // Stores the current lattice value for nodes. Note that it contains not only 342 // Stores the current lattice value for nodes. Note that it contains not only
231 // definitions as keys, but also expressions such as method invokes. 343 // definitions as keys, but also expressions such as method invokes.
232 // Access through [getValue] and [setValue]. 344 // Access through [getValue] and [setValue].
233 final Map<Node, _ConstnessLattice> node2value = <Node, _ConstnessLattice>{}; 345 final Map<Node, _AbstractValue> values;
234 346
235 _ConstPropagationVisitor(this.compiler, this.constantSystem); 347 _ConstPropagationVisitor(this.constantSystem, TypeSystem typeSystem,
348 this.values,
349 this.internalError, this.compiler)
350 : this.unknownDynamic = new _AbstractValue.unknown(typeSystem.dynamicType),
351 this.typeSystem = typeSystem;
236 352
237 void analyze(ExecutableDefinition root) { 353 void analyze(ExecutableDefinition root) {
238 reachableNodes.clear(); 354 reachableNodes.clear();
239 defWorkset.clear(); 355 defWorkset.clear();
240 nodeWorklist.clear(); 356 nodeWorklist.clear();
241 357
242 // Initially, only the root node is reachable. 358 // Initially, only the root node is reachable.
243 setReachable(root); 359 setReachable(root);
244 360
245 while (true) { 361 while (true) {
(...skipping 23 matching lines...) Expand all
269 void setReachable(Node node) { 385 void setReachable(Node node) {
270 if (!reachableNodes.contains(node)) { 386 if (!reachableNodes.contains(node)) {
271 reachableNodes.add(node); 387 reachableNodes.add(node);
272 nodeWorklist.add(node); 388 nodeWorklist.add(node);
273 } 389 }
274 } 390 }
275 391
276 /// Returns the lattice value corresponding to [node], defaulting to unknown. 392 /// Returns the lattice value corresponding to [node], defaulting to unknown.
277 /// 393 ///
278 /// Never returns null. 394 /// Never returns null.
279 _ConstnessLattice getValue(Node node) { 395 _AbstractValue getValue(Node node) {
280 _ConstnessLattice value = node2value[node]; 396 _AbstractValue value = values[node];
281 return (value == null) ? _ConstnessLattice.Unknown : value; 397 return (value == null) ? unknown() : value;
282 } 398 }
283 399
284 /// Joins the passed lattice [updateValue] to the current value of [node], 400 /// Joins the passed lattice [updateValue] to the current value of [node],
285 /// and adds it to the definition work set if it has changed and [node] is 401 /// and adds it to the definition work set if it has changed and [node] is
286 /// a definition. 402 /// a definition.
287 void setValue(Node node, _ConstnessLattice updateValue) { 403 void setValue(Node node, _AbstractValue updateValue) {
288 _ConstnessLattice oldValue = getValue(node); 404 _AbstractValue oldValue = getValue(node);
289 _ConstnessLattice newValue = updateValue.join(oldValue); 405 _AbstractValue newValue = updateValue.join(oldValue, typeSystem);
290 if (oldValue == newValue) { 406 if (oldValue == newValue) {
291 return; 407 return;
292 } 408 }
293 409
294 // Values may only move in the direction UNKNOWN -> CONSTANT -> NONCONST. 410 // Values may only move in the direction UNKNOWN -> CONSTANT -> NONCONST.
295 assert(newValue.kind >= oldValue.kind); 411 assert(newValue.kind >= oldValue.kind);
296 412
297 node2value[node] = newValue; 413 values[node] = newValue;
298 if (node is Definition) { 414 if (node is Definition) {
299 defWorkset.add(node); 415 defWorkset.add(node);
300 } 416 }
301 } 417 }
302 418
303 // -------------------------- Visitor overrides ------------------------------ 419 // -------------------------- Visitor overrides ------------------------------
304 420
305 void visitNode(Node node) { 421 void visitNode(Node node) {
306 compiler.internalError(NO_LOCATION_SPANNABLE, 422 internalError(NO_LOCATION_SPANNABLE,
307 "_ConstPropagationVisitor is stale, add missing visit overrides"); 423 "_ConstPropagationVisitor is stale, add missing visit overrides");
308 } 424 }
309 425
310 void visitFunctionDefinition(FunctionDefinition node) { 426 void visitFunctionDefinition(FunctionDefinition node) {
311 node.parameters.forEach(visit); 427 node.parameters.forEach(visit);
312 setReachable(node.body); 428 setReachable(node.body);
313 } 429 }
314 430
315 void visitFieldDefinition(FieldDefinition node) { 431 void visitFieldDefinition(FieldDefinition node) {
316 if (node.hasInitializer) { 432 if (node.hasInitializer) {
(...skipping 12 matching lines...) Expand all
329 // The continuation is only marked as reachable on use. 445 // The continuation is only marked as reachable on use.
330 setReachable(node.body); 446 setReachable(node.body);
331 } 447 }
332 448
333 void visitInvokeStatic(InvokeStatic node) { 449 void visitInvokeStatic(InvokeStatic node) {
334 Continuation cont = node.continuation.definition; 450 Continuation cont = node.continuation.definition;
335 setReachable(cont); 451 setReachable(cont);
336 452
337 assert(cont.parameters.length == 1); 453 assert(cont.parameters.length == 1);
338 Parameter returnValue = cont.parameters[0]; 454 Parameter returnValue = cont.parameters[0];
339 setValue(returnValue, _ConstnessLattice.NonConst); 455 Entity target = node.target;
456 T returnType = target is FieldElement
457 ? typeSystem.dynamicType
458 : typeSystem.getReturnType(node.target);
459 setValue(returnValue, nonConst(returnType));
340 } 460 }
341 461
342 void visitInvokeContinuation(InvokeContinuation node) { 462 void visitInvokeContinuation(InvokeContinuation node) {
343 Continuation cont = node.continuation.definition; 463 Continuation cont = node.continuation.definition;
344 setReachable(cont); 464 setReachable(cont);
345 465
346 // Forward the constant status of all continuation invokes to the 466 // Forward the constant status of all continuation invokes to the
347 // continuation. Note that this is effectively a phi node in SSA terms. 467 // continuation. Note that this is effectively a phi node in SSA terms.
348 for (int i = 0; i < node.arguments.length; i++) { 468 for (int i = 0; i < node.arguments.length; i++) {
349 Definition def = node.arguments[i].definition; 469 Definition def = node.arguments[i].definition;
350 _ConstnessLattice cell = getValue(def); 470 _AbstractValue cell = getValue(def);
351 setValue(cont.parameters[i], cell); 471 setValue(cont.parameters[i], cell);
352 } 472 }
353 } 473 }
354 474
355 void visitInvokeMethod(InvokeMethod node) { 475 void visitInvokeMethod(InvokeMethod node) {
356 Continuation cont = node.continuation.definition; 476 Continuation cont = node.continuation.definition;
357 setReachable(cont); 477 setReachable(cont);
358 478
359 /// Sets the value of both the current node and the target continuation 479 /// Sets the value of both the current node and the target continuation
360 /// parameter. 480 /// parameter.
361 void setValues(_ConstnessLattice updateValue) { 481 void setValues(_AbstractValue updateValue) {
362 setValue(node, updateValue); 482 setValue(node, updateValue);
363 Parameter returnValue = cont.parameters[0]; 483 Parameter returnValue = cont.parameters[0];
364 setValue(returnValue, updateValue); 484 setValue(returnValue, updateValue);
365 } 485 }
366 486
367 _ConstnessLattice lhs = getValue(node.receiver.definition); 487 _AbstractValue lhs = getValue(node.receiver.definition);
368 if (lhs.isUnknown) { 488 if (lhs.isUnknown) {
369 // This may seem like a missed opportunity for evaluating short-circuiting 489 // This may seem like a missed opportunity for evaluating short-circuiting
370 // boolean operations; we are currently skipping these intentionally since 490 // boolean operations; we are currently skipping these intentionally since
371 // expressions such as `(new Foo() || true)` may introduce type errors 491 // expressions such as `(new Foo() || true)` may introduce type errors
372 // and thus evaluation to `true` would not be correct. 492 // and thus evaluation to `true` would not be correct.
373 // TODO(jgruber): Handle such cases while ensuring that new Foo() and 493 // TODO(jgruber): Handle such cases while ensuring that new Foo() and
374 // a type-check (in checked mode) are still executed. 494 // a type-check (in checked mode) are still executed.
375 return; // And come back later. 495 return; // And come back later.
376 } else if (lhs.isNonConst) { 496 } else if (lhs.isNonConst) {
377 setValues(_ConstnessLattice.NonConst); 497 setValues(nonConst());
378 return; 498 return;
379 } else if (!node.selector.isOperator) { 499 } else if (!node.selector.isOperator) {
380 // TODO(jgruber): Handle known methods on constants such as String.length. 500 // TODO(jgruber): Handle known methods on constants such as String.length.
381 setValues(_ConstnessLattice.NonConst); 501 setValues(nonConst());
382 return; 502 return;
383 } 503 }
384 504
385 // Calculate the resulting constant if possible. 505 // Calculate the resulting constant if possible.
386 ConstantValue result; 506 ConstantValue result;
387 String opname = node.selector.name; 507 String opname = node.selector.name;
388 if (node.selector.argumentCount == 0) { 508 if (node.selector.argumentCount == 0) {
389 // Unary operator. 509 // Unary operator.
390 510
391 if (opname == "unary-") { 511 if (opname == "unary-") {
392 opname = "-"; 512 opname = "-";
393 } 513 }
394 dart2js.UnaryOperation operation = constantSystem.lookupUnary(opname); 514 dart2js.UnaryOperation operation = constantSystem.lookupUnary(opname);
395 if (operation != null) { 515 if (operation != null) {
396 result = operation.fold(lhs.constant); 516 result = operation.fold(lhs.constant);
397 } 517 }
398 } else if (node.selector.argumentCount == 1) { 518 } else if (node.selector.argumentCount == 1) {
399 // Binary operator. 519 // Binary operator.
400 520
401 _ConstnessLattice rhs = getValue(node.arguments[0].definition); 521 _AbstractValue rhs = getValue(node.arguments[0].definition);
402 if (!rhs.isConstant) { 522 if (!rhs.isConstant) {
403 setValues(rhs); 523 setValues(rhs);
404 return; 524 return;
405 } 525 }
406 526
407 dart2js.BinaryOperation operation = constantSystem.lookupBinary(opname); 527 dart2js.BinaryOperation operation = constantSystem.lookupBinary(opname);
408 if (operation != null) { 528 if (operation != null) {
409 result = operation.fold(lhs.constant, rhs.constant); 529 result = operation.fold(lhs.constant, rhs.constant);
410 } 530 }
411 } 531 }
412 532
413 // Update value of the continuation parameter. Again, this is effectively 533 // Update value of the continuation parameter. Again, this is effectively
414 // a phi. 534 // a phi.
415 535 if (result == null) {
416 setValues((result == null) ? 536 setValues(nonConst());
417 _ConstnessLattice.NonConst : new _ConstnessLattice(result)); 537 } else {
538 T type = typeSystem.typeOf(result);
539 setValues(new _AbstractValue(result, type));
540 }
418 } 541 }
419 542
420 void visitInvokeSuperMethod(InvokeSuperMethod node) { 543 void visitInvokeSuperMethod(InvokeSuperMethod node) {
421 Continuation cont = node.continuation.definition; 544 Continuation cont = node.continuation.definition;
422 setReachable(cont); 545 setReachable(cont);
423 546
424 assert(cont.parameters.length == 1); 547 assert(cont.parameters.length == 1);
425 Parameter returnValue = cont.parameters[0]; 548 Parameter returnValue = cont.parameters[0];
426 setValue(returnValue, _ConstnessLattice.NonConst); 549 // TODO(karlklose): lookup the function and get ites return type.
550 setValue(returnValue, nonConst());
427 } 551 }
428 552
429 void visitInvokeConstructor(InvokeConstructor node) { 553 void visitInvokeConstructor(InvokeConstructor node) {
430 Continuation cont = node.continuation.definition; 554 Continuation cont = node.continuation.definition;
431 setReachable(cont); 555 setReachable(cont);
432 556
433 assert(cont.parameters.length == 1); 557 assert(cont.parameters.length == 1);
434 Parameter returnValue = cont.parameters[0]; 558 Parameter returnValue = cont.parameters[0];
435 setValue(returnValue, _ConstnessLattice.NonConst); 559 setValue(returnValue, nonConst());
436 } 560 }
437 561
438 void visitConcatenateStrings(ConcatenateStrings node) { 562 void visitConcatenateStrings(ConcatenateStrings node) {
439 Continuation cont = node.continuation.definition; 563 Continuation cont = node.continuation.definition;
440 setReachable(cont); 564 setReachable(cont);
441 565
442 void setValues(_ConstnessLattice updateValue) { 566 void setValues(_AbstractValue updateValue) {
443 setValue(node, updateValue); 567 setValue(node, updateValue);
444 Parameter returnValue = cont.parameters[0]; 568 Parameter returnValue = cont.parameters[0];
445 setValue(returnValue, updateValue); 569 setValue(returnValue, updateValue);
446 } 570 }
447 571
448 // TODO(jgruber): Currently we only optimize if all arguments are string 572 // TODO(jgruber): Currently we only optimize if all arguments are string
449 // constants, but we could also handle cases such as "foo${42}". 573 // constants, but we could also handle cases such as "foo${42}".
450 bool allStringConstants = node.arguments.every((Reference ref) { 574 bool allStringConstants = node.arguments.every((Reference ref) {
451 if (!(ref.definition is Constant)) { 575 if (!(ref.definition is Constant)) {
452 return false; 576 return false;
453 } 577 }
454 Constant constant = ref.definition; 578 Constant constant = ref.definition;
455 return constant != null && constant.value.isString; 579 return constant != null && constant.value.isString;
456 }); 580 });
457 581
582 T type = typeSystem.stringType;
458 assert(cont.parameters.length == 1); 583 assert(cont.parameters.length == 1);
459 if (allStringConstants) { 584 if (allStringConstants) {
460 // All constant, we can concatenate ourselves. 585 // All constant, we can concatenate ourselves.
461 Iterable<String> allStrings = node.arguments.map((Reference ref) { 586 Iterable<String> allStrings = node.arguments.map((Reference ref) {
462 Constant constant = ref.definition; 587 Constant constant = ref.definition;
463 StringConstantValue stringConstant = constant.value; 588 StringConstantValue stringConstant = constant.value;
464 return stringConstant.primitiveValue.slowToString(); 589 return stringConstant.primitiveValue.slowToString();
465 }); 590 });
466 LiteralDartString dartString = new LiteralDartString(allStrings.join()); 591 LiteralDartString dartString = new LiteralDartString(allStrings.join());
467 ConstantValue constant = new StringConstantValue(dartString); 592 ConstantValue constant = new StringConstantValue(dartString);
468 setValues(new _ConstnessLattice(constant)); 593 setValues(new _AbstractValue(constant, type));
469 } else { 594 } else {
470 setValues(_ConstnessLattice.NonConst); 595 setValues(nonConst(type));
471 } 596 }
472 } 597 }
473 598
474 void visitBranch(Branch node) { 599 void visitBranch(Branch node) {
475 IsTrue isTrue = node.condition; 600 IsTrue isTrue = node.condition;
476 _ConstnessLattice conditionCell = getValue(isTrue.value.definition); 601 _AbstractValue conditionCell = getValue(isTrue.value.definition);
477 602
478 if (conditionCell.isUnknown) { 603 if (conditionCell.isUnknown) {
479 return; // And come back later. 604 return; // And come back later.
480 } else if (conditionCell.isNonConst) { 605 } else if (conditionCell.isNonConst) {
481 setReachable(node.trueContinuation.definition); 606 setReachable(node.trueContinuation.definition);
482 setReachable(node.falseContinuation.definition); 607 setReachable(node.falseContinuation.definition);
483 } else if (conditionCell.isConstant && 608 } else if (conditionCell.isConstant &&
484 !(conditionCell.constant.isBool)) { 609 !(conditionCell.constant.isBool)) {
485 // Treat non-bool constants in condition as non-const since they result 610 // Treat non-bool constants in condition as non-const since they result
486 // in type errors in checked mode. 611 // in type errors in checked mode.
487 // TODO(jgruber): Default to false in unchecked mode. 612 // TODO(jgruber): Default to false in unchecked mode.
488 setReachable(node.trueContinuation.definition); 613 setReachable(node.trueContinuation.definition);
489 setReachable(node.falseContinuation.definition); 614 setReachable(node.falseContinuation.definition);
490 setValue(isTrue.value.definition, _ConstnessLattice.NonConst); 615 setValue(isTrue.value.definition, nonConst(typeSystem.boolType));
491 } else if (conditionCell.isConstant && 616 } else if (conditionCell.isConstant &&
492 conditionCell.constant.isBool) { 617 conditionCell.constant.isBool) {
493 BoolConstantValue boolConstant = conditionCell.constant; 618 BoolConstantValue boolConstant = conditionCell.constant;
494 setReachable((boolConstant.isTrue) ? 619 setReachable((boolConstant.isTrue) ?
495 node.trueContinuation.definition : node.falseContinuation.definition); 620 node.trueContinuation.definition : node.falseContinuation.definition);
496 } 621 }
497 } 622 }
498 623
499 void visitTypeOperator(TypeOperator node) { 624 void visitTypeOperator(TypeOperator node) {
500 Continuation cont = node.continuation.definition; 625 Continuation cont = node.continuation.definition;
501 setReachable(cont); 626 setReachable(cont);
502 627
503 void setValues(_ConstnessLattice updateValue) { 628 void setValues(_AbstractValue updateValue) {
504 setValue(node, updateValue); 629 setValue(node, updateValue);
505 Parameter returnValue = cont.parameters[0]; 630 Parameter returnValue = cont.parameters[0];
506 setValue(returnValue, updateValue); 631 setValue(returnValue, updateValue);
507 } 632 }
508 633
509 if (node.isTypeCast) { 634 if (node.isTypeCast) {
510 // TODO(jgruber): Add support for `as` casts. 635 // TODO(jgruber): Add support for `as` casts.
511 setValues(_ConstnessLattice.NonConst); 636 setValues(nonConst());
512 } 637 }
513 638
514 _ConstnessLattice cell = getValue(node.receiver.definition); 639 _AbstractValue cell = getValue(node.receiver.definition);
515 if (cell.isUnknown) { 640 if (cell.isUnknown) {
516 return; // And come back later. 641 return; // And come back later.
517 } else if (cell.isNonConst) { 642 } else if (cell.isNonConst) {
518 setValues(_ConstnessLattice.NonConst); 643 setValues(nonConst(cell.type));
519 } else if (node.type.kind == types.TypeKind.INTERFACE) { 644 } else if (node.type.kind == types.TypeKind.INTERFACE) {
520 // Receiver is a constant, perform is-checks at compile-time. 645 // Receiver is a constant, perform is-checks at compile-time.
521 646
522 types.InterfaceType checkedType = node.type; 647 types.InterfaceType checkedType = node.type;
523 ConstantValue constant = cell.constant; 648 ConstantValue constant = cell.constant;
649 // TODO(karlklose): remove call to computeType.
524 types.DartType constantType = constant.computeType(compiler); 650 types.DartType constantType = constant.computeType(compiler);
525 651
526 _ConstnessLattice result = _ConstnessLattice.NonConst; 652 T type = typeSystem.boolType;
653 _AbstractValue result;
527 if (constant.isNull && 654 if (constant.isNull &&
528 checkedType.element != compiler.nullClass && 655 checkedType.element != compiler.nullClass &&
529 checkedType.element != compiler.objectClass) { 656 checkedType.element != compiler.objectClass) {
530 // `(null is Type)` is true iff Type is in { Null, Object }. 657 // `(null is Type)` is true iff Type is in { Null, Object }.
531 result = new _ConstnessLattice(new FalseConstantValue()); 658 result = constantValue(new FalseConstantValue(), type);
532 } else { 659 } else {
533 // Otherwise, perform a standard subtype check. 660 // Otherwise, perform a standard subtype check.
534 result = new _ConstnessLattice( 661 result = constantValue(
535 constantSystem.isSubtype(compiler, constantType, checkedType) 662 constantSystem.isSubtype(compiler, constantType, checkedType)
536 ? new TrueConstantValue() 663 ? new TrueConstantValue()
537 : new FalseConstantValue()); 664 : new FalseConstantValue(),
665 type);
538 } 666 }
539
540 setValues(result); 667 setValues(result);
541 } 668 }
542 } 669 }
543 670
544 void visitSetClosureVariable(SetClosureVariable node) { 671 void visitSetClosureVariable(SetClosureVariable node) {
545 setReachable(node.body); 672 setReachable(node.body);
546 } 673 }
547 674
548 void visitDeclareFunction(DeclareFunction node) { 675 void visitDeclareFunction(DeclareFunction node) {
549 setReachable(node.definition); 676 setReachable(node.definition);
550 setReachable(node.body); 677 setReachable(node.body);
551 } 678 }
552 679
553 // Definitions. 680 // Definitions.
554 void visitLiteralList(LiteralList node) { 681 void visitLiteralList(LiteralList node) {
555 // Constant lists are translated into (Constant ListConstant(...)) IR nodes, 682 // Constant lists are translated into (Constant ListConstant(...)) IR nodes,
556 // and thus LiteralList nodes are NonConst. 683 // and thus LiteralList nodes are NonConst.
557 setValue(node, _ConstnessLattice.NonConst); 684 setValue(node, nonConst(typeSystem.listType));
558 } 685 }
559 686
560 void visitLiteralMap(LiteralMap node) { 687 void visitLiteralMap(LiteralMap node) {
561 // Constant maps are translated into (Constant MapConstant(...)) IR nodes, 688 // Constant maps are translated into (Constant MapConstant(...)) IR nodes,
562 // and thus LiteralMap nodes are NonConst. 689 // and thus LiteralMap nodes are NonConst.
563 setValue(node, _ConstnessLattice.NonConst); 690 setValue(node, nonConst(typeSystem.mapType));
564 } 691 }
565 692
566 void visitConstant(Constant node) { 693 void visitConstant(Constant node) {
567 setValue(node, new _ConstnessLattice(node.value)); 694 ConstantValue value = node.value;
695 setValue(node, constantValue(value, typeSystem.typeOf(value)));
568 } 696 }
569 697
570 void visitThis(This node) { 698 void visitThis(This node) {
571 setValue(node, _ConstnessLattice.NonConst); 699 // TODO(karlklose): Add the type.
700 setValue(node, nonConst());
572 } 701 }
573 702
574 void visitReifyTypeVar(ReifyTypeVar node) { 703 void visitReifyTypeVar(ReifyTypeVar node) {
575 setValue(node, _ConstnessLattice.NonConst); 704 setValue(node, nonConst(typeSystem.typeType));
576 } 705 }
577 706
578 void visitCreateFunction(CreateFunction node) { 707 void visitCreateFunction(CreateFunction node) {
579 setReachable(node.definition); 708 setReachable(node.definition);
580 ConstantValue constant = 709 ConstantValue constant =
581 new FunctionConstantValue(node.definition.element); 710 new FunctionConstantValue(node.definition.element);
582 setValue(node, new _ConstnessLattice(constant)); 711 setValue(node, constantValue(constant, typeSystem.functionType));
583 } 712 }
584 713
585 void visitGetClosureVariable(GetClosureVariable node) { 714 void visitGetClosureVariable(GetClosureVariable node) {
586 setValue(node, _ConstnessLattice.NonConst); 715 setValue(node, nonConst());
587 } 716 }
588 717
589 void visitClosureVariable(ClosureVariable node) { 718 void visitClosureVariable(ClosureVariable node) {
590 } 719 }
591 720
592 void visitParameter(Parameter node) { 721 void visitParameter(Parameter node) {
722 T type = typeSystem.getParameterType(node.hint);
593 if (node.parent is FunctionDefinition) { 723 if (node.parent is FunctionDefinition) {
594 // Functions may escape and thus their parameters must be initialized to 724 // Functions may escape and thus their parameters must be initialized to
595 // NonConst. 725 // NonConst.
596 setValue(node, _ConstnessLattice.NonConst); 726 setValue(node, nonConst(type));
597 } else if (node.parent is Continuation) { 727 } else if (node.parent is Continuation) {
598 // Continuations on the other hand are local, and parameters are 728 // Continuations on the other hand are local, and parameters are
599 // initialized to Unknown. 729 // initialized to Unknown.
600 setValue(node, _ConstnessLattice.Unknown); 730 setValue(node, unknown());
601 } else { 731 } else {
602 compiler.internalError(node.hint, "Unexpected parent of Parameter"); 732 internalError(node.hint, "Unexpected parent of Parameter");
603 } 733 }
604 } 734 }
605 735
606 void visitContinuation(Continuation node) { 736 void visitContinuation(Continuation node) {
607 node.parameters.forEach((Parameter p) { 737 node.parameters.forEach((Parameter p) {
608 setValue(p, _ConstnessLattice.Unknown); 738 // TODO(karlklose): join parameter types from use sites.
739 setValue(p, unknown());
609 defWorkset.add(p); 740 defWorkset.add(p);
610 }); 741 });
611 742
612 if (node.body != null) { 743 if (node.body != null) {
613 setReachable(node.body); 744 setReachable(node.body);
614 } 745 }
615 } 746 }
616 747
617 // Conditions. 748 // Conditions.
618 749
619 void visitIsTrue(IsTrue node) { 750 void visitIsTrue(IsTrue node) {
620 Branch branch = node.parent; 751 Branch branch = node.parent;
621 visitBranch(branch); 752 visitBranch(branch);
622 } 753 }
623 754
624 // JavaScript specific nodes. 755 // JavaScript specific nodes.
625 756
626 void visitIdentical(Identical node) { 757 void visitIdentical(Identical node) {
627 _ConstnessLattice leftConst = getValue(node.left.definition); 758 _AbstractValue leftConst = getValue(node.left.definition);
628 _ConstnessLattice rightConst = getValue(node.left.definition); 759 _AbstractValue rightConst = getValue(node.right.definition);
629 ConstantValue leftValue = leftConst.constant; 760 ConstantValue leftValue = leftConst.constant;
630 ConstantValue rightValue = rightConst.constant; 761 ConstantValue rightValue = rightConst.constant;
631 if (leftConst.isUnknown || rightConst.isUnknown) { 762 if (leftConst.isUnknown || rightConst.isUnknown) {
632 // Come back later. 763 // Come back later.
633 return; 764 return;
634 } else if (!leftConst.isConstant || !rightConst.isConstant) { 765 } else if (!leftConst.isConstant || !rightConst.isConstant) {
635 setValue(node, _ConstnessLattice.NonConst); 766 T leftType = leftConst.type;
767 T rightType = rightConst.type;
768 if (!typeSystem.areAssignable(leftType, rightType)) {
769 setValue(node,
770 constantValue(new FalseConstantValue(), typeSystem.boolType));
771 } else {
772 setValue(node, nonConst(typeSystem.boolType));
773 }
636 } else if (leftValue.isPrimitive && rightValue.isPrimitive) { 774 } else if (leftValue.isPrimitive && rightValue.isPrimitive) {
637 assert(leftConst.isConstant && rightConst.isConstant); 775 assert(leftConst.isConstant && rightConst.isConstant);
638 PrimitiveConstantValue left = leftValue; 776 PrimitiveConstantValue left = leftValue;
639 PrimitiveConstantValue right = rightValue; 777 PrimitiveConstantValue right = rightValue;
640 ConstantValue result = 778 ConstantValue result =
641 new BoolConstantValue(left.primitiveValue == right.primitiveValue); 779 new BoolConstantValue(left.primitiveValue == right.primitiveValue);
642 setValue(node, new _ConstnessLattice(result)); 780 setValue(node, new _AbstractValue(result, typeSystem.boolType));
643 } 781 }
644 } 782 }
645 } 783 }
646 784
647 /// Represents the constant-state of a variable at some point in the program. 785 /// Represents the constant-state of a variable at some point in the program.
648 /// UNKNOWN: may be some as yet undetermined constant. 786 /// UNKNOWN: may be some as yet undetermined constant.
649 /// CONSTANT: is a constant as stored in the local field. 787 /// CONSTANT: is a constant as stored in the local field.
650 /// NONCONST: not a constant. 788 /// NONCONST: not a constant.
651 class _ConstnessLattice { 789 class _AbstractValue<T> {
652 static const int UNKNOWN = 0; 790 static const int UNKNOWN = 0;
653 static const int CONSTANT = 1; 791 static const int CONSTANT = 1;
654 static const int NONCONST = 2; 792 static const int NONCONST = 2;
655 793
656 final int kind; 794 final int kind;
657 final ConstantValue constant; 795 final ConstantValue constant;
796 final T type;
658 797
659 static final _ConstnessLattice Unknown = 798 _AbstractValue._internal(this.kind, this.constant, this.type) {
660 new _ConstnessLattice._internal(UNKNOWN, null); 799 assert(kind != CONSTANT || constant != null);
661 static final _ConstnessLattice NonConst = 800 assert(type != null);
662 new _ConstnessLattice._internal(NONCONST, null); 801 }
663 802
664 _ConstnessLattice._internal(this.kind, this.constant); 803 _AbstractValue(ConstantValue constant, T type)
665 _ConstnessLattice(this.constant) : kind = CONSTANT { 804 : this._internal(CONSTANT, constant, type);
666 assert(this.constant != null); 805
667 } 806 _AbstractValue.unknown(T type)
807 : this._internal(UNKNOWN, null, type);
808
809 _AbstractValue.nonConst(T type)
810 : this._internal(NONCONST, null, type);
668 811
669 bool get isUnknown => (kind == UNKNOWN); 812 bool get isUnknown => (kind == UNKNOWN);
670 bool get isConstant => (kind == CONSTANT); 813 bool get isConstant => (kind == CONSTANT);
671 bool get isNonConst => (kind == NONCONST); 814 bool get isNonConst => (kind == NONCONST);
672 815
673 int get hashCode => kind | (constant.hashCode << 2); 816 int get hashCode {
674 bool operator==(_ConstnessLattice that) => 817 return kind | (constant.hashCode * 5) | type.hashCode * 7;
675 (that.kind == this.kind && that.constant == this.constant); 818 }
819
820 bool operator ==(_AbstractValue that) {
821 return that.kind == this.kind &&
822 that.constant == this.constant &&
823 that.type == this.type;
824 }
676 825
677 String toString() { 826 String toString() {
678 switch (kind) { 827 switch (kind) {
679 case UNKNOWN: return "Unknown"; 828 case UNKNOWN: return "Unknown";
680 case CONSTANT: return "Constant: $constant"; 829 case CONSTANT: return "Constant: $constant: $type";
681 case NONCONST: return "Non-constant"; 830 case NONCONST: return "Non-constant: $type";
682 default: assert(false); 831 default: assert(false);
683 } 832 }
684 return null; 833 return null;
685 } 834 }
686 835
687 /// Compute the join of two values in the lattice. 836 /// Compute the join of two values in the lattice.
688 _ConstnessLattice join(_ConstnessLattice that) { 837 _AbstractValue join(_AbstractValue that, TypeSystem typeSystem) {
838 bool isDynamic(T type) {
839 return typeSystem.areEqual(type, typeSystem.dynamicType);
840 }
841
689 assert(that != null); 842 assert(that != null);
690 843
691 if (this.isNonConst || that.isUnknown) { 844 if (isDynamic(this.type) && isDynamic(that.type)) {
692 return this; 845 if (this.isNonConst || that.isUnknown) {
846 return this;
847 }
848
849 if (this.isUnknown || that.isNonConst) {
850 return that;
851 }
852
853 if (this.constant == that.constant) {
854 return this;
855 }
856
857 return new _AbstractValue.nonConst(typeSystem.dynamicType);
693 } 858 }
694 859
695 if (this.isUnknown || that.isNonConst) { 860 if (this.isUnknown) {
696 return that; 861 return that;
862 } else if (that.isUnknown) {
863 return this;
864 } else if (this.isConstant && that.isConstant &&
865 this.constant == that.constant) {
866 return this;
867 } else {
868 return new _AbstractValue.nonConst(typeSystem.join(this.type, that.type));
Kevin Millikin (Google) 2014/12/12 11:00:23 If we drop the optimization to avoid joining dynam
karlklose 2014/12/12 11:43:48 Done.
697 } 869 }
698
699 if (this.constant == that.constant) {
700 return this;
701 }
702
703 return NonConst;
704 } 870 }
705 } 871 }
OLDNEW
« no previous file with comments | « no previous file | pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698