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

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

Issue 1859343004: dartfmt pkg/compiler (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 8 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) 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 library dart2js.cps_ir.type_propagation; 4 library dart2js.cps_ir.type_propagation;
5 5
6 import 'optimizers.dart'; 6 import 'optimizers.dart';
7 7
8 import '../closure.dart' show 8 import '../closure.dart' show ClosureClassElement;
9 ClosureClassElement;
10 import '../common.dart'; 9 import '../common.dart';
11 import '../common/names.dart' show 10 import '../common/names.dart' show Identifiers, Selectors;
12 Identifiers, 11 import '../compiler.dart' as dart2js show Compiler;
13 Selectors;
14 import '../compiler.dart' as dart2js show
15 Compiler;
16 import '../constants/constant_system.dart'; 12 import '../constants/constant_system.dart';
17 import '../constants/values.dart'; 13 import '../constants/values.dart';
18 import '../dart_types.dart' as types; 14 import '../dart_types.dart' as types;
19 import '../elements/elements.dart'; 15 import '../elements/elements.dart';
20 import '../io/source_information.dart' show 16 import '../io/source_information.dart' show SourceInformation;
21 SourceInformation; 17 import '../js_backend/backend_helpers.dart' show BackendHelpers;
22 import '../js_backend/backend_helpers.dart' show 18 import '../js_backend/js_backend.dart' show JavaScriptBackend;
23 BackendHelpers; 19 import '../js_backend/codegen/task.dart' show CpsFunctionCompiler;
24 import '../js_backend/js_backend.dart' show
25 JavaScriptBackend;
26 import '../js_backend/codegen/task.dart' show
27 CpsFunctionCompiler;
28 import '../resolution/operators.dart'; 20 import '../resolution/operators.dart';
29 import '../tree/tree.dart' as ast; 21 import '../tree/tree.dart' as ast;
30 import '../types/types.dart'; 22 import '../types/types.dart';
31 import '../types/abstract_value_domain.dart' show 23 import '../types/abstract_value_domain.dart' show AbstractBool;
32 AbstractBool; 24 import '../universe/selector.dart' show Selector;
33 import '../universe/selector.dart' show
34 Selector;
35 import '../world.dart' show World; 25 import '../world.dart' show World;
36 import 'cps_fragment.dart'; 26 import 'cps_fragment.dart';
37 import 'cps_ir_nodes.dart'; 27 import 'cps_ir_nodes.dart';
38 import 'type_mask_system.dart'; 28 import 'type_mask_system.dart';
39 import 'effects.dart'; 29 import 'effects.dart';
40 30
41 class ConstantPropagationLattice { 31 class ConstantPropagationLattice {
42 final TypeMaskSystem typeSystem; 32 final TypeMaskSystem typeSystem;
43 final ConstantSystem constantSystem; 33 final ConstantSystem constantSystem;
44 final types.DartTypes dartTypes; 34 final types.DartTypes dartTypes;
45 final AbstractConstantValue anything; 35 final AbstractConstantValue anything;
46 final AbstractConstantValue nothing = new AbstractConstantValue.nothing(); 36 final AbstractConstantValue nothing = new AbstractConstantValue.nothing();
47 final AbstractConstantValue nullValue; 37 final AbstractConstantValue nullValue;
48 final AbstractConstantValue trueValue; 38 final AbstractConstantValue trueValue;
49 final AbstractConstantValue falseValue; 39 final AbstractConstantValue falseValue;
50 40
51 ConstantPropagationLattice(CpsFunctionCompiler functionCompiler) 41 ConstantPropagationLattice(CpsFunctionCompiler functionCompiler)
52 : typeSystem = functionCompiler.typeSystem, 42 : typeSystem = functionCompiler.typeSystem,
53 constantSystem = functionCompiler.compiler.backend.constantSystem, 43 constantSystem = functionCompiler.compiler.backend.constantSystem,
54 dartTypes = functionCompiler.compiler.types, 44 dartTypes = functionCompiler.compiler.types,
55 anything = new AbstractConstantValue.nonConstant( 45 anything = new AbstractConstantValue.nonConstant(
56 functionCompiler.typeSystem.dynamicType), 46 functionCompiler.typeSystem.dynamicType),
57 nullValue = new AbstractConstantValue.constantValue( 47 nullValue = new AbstractConstantValue.constantValue(
58 new NullConstantValue(), new TypeMask.empty()), 48 new NullConstantValue(), new TypeMask.empty()),
59 trueValue = new AbstractConstantValue.constantValue( 49 trueValue = new AbstractConstantValue.constantValue(
60 new TrueConstantValue(), functionCompiler.typeSystem.boolType), 50 new TrueConstantValue(), functionCompiler.typeSystem.boolType),
61 falseValue = new AbstractConstantValue.constantValue( 51 falseValue = new AbstractConstantValue.constantValue(
62 new FalseConstantValue(), functionCompiler.typeSystem.boolType); 52 new FalseConstantValue(), functionCompiler.typeSystem.boolType);
63 53
64 AbstractConstantValue constant(ConstantValue value, [TypeMask type]) { 54 AbstractConstantValue constant(ConstantValue value, [TypeMask type]) {
65 if (type == null) type = typeSystem.getTypeOf(value); 55 if (type == null) type = typeSystem.getTypeOf(value);
66 return new AbstractConstantValue.constantValue(value, type); 56 return new AbstractConstantValue.constantValue(value, type);
67 } 57 }
68 58
69 AbstractConstantValue nonConstant([TypeMask type]) { 59 AbstractConstantValue nonConstant([TypeMask type]) {
70 if (type == null) type = typeSystem.dynamicType; 60 if (type == null) type = typeSystem.dynamicType;
71 return new AbstractConstantValue.nonConstant(type); 61 return new AbstractConstantValue.nonConstant(type);
72 } 62 }
(...skipping 11 matching lines...) Expand all
84 return x; 74 return x;
85 } else { 75 } else {
86 return new AbstractConstantValue.nonConstant( 76 return new AbstractConstantValue.nonConstant(
87 typeSystem.join(x.type, y.type)); 77 typeSystem.join(x.type, y.type));
88 } 78 }
89 } 79 }
90 80
91 /// True if all members of this value are booleans. 81 /// True if all members of this value are booleans.
92 bool isDefinitelyBool(AbstractConstantValue value, {bool allowNull: false}) { 82 bool isDefinitelyBool(AbstractConstantValue value, {bool allowNull: false}) {
93 return value.isNothing || 83 return value.isNothing ||
94 typeSystem.isDefinitelyBool(value.type, allowNull: allowNull); 84 typeSystem.isDefinitelyBool(value.type, allowNull: allowNull);
95 } 85 }
96 86
97 /// True if all members of this value are numbers. 87 /// True if all members of this value are numbers.
98 bool isDefinitelyNum(AbstractConstantValue value, {bool allowNull: false}) { 88 bool isDefinitelyNum(AbstractConstantValue value, {bool allowNull: false}) {
99 return value.isNothing || 89 return value.isNothing ||
100 typeSystem.isDefinitelyNum(value.type, allowNull: allowNull); 90 typeSystem.isDefinitelyNum(value.type, allowNull: allowNull);
101 } 91 }
102 92
103 /// True if all members of this value are strings. 93 /// True if all members of this value are strings.
104 bool isDefinitelyString(AbstractConstantValue value, 94 bool isDefinitelyString(AbstractConstantValue value,
105 {bool allowNull: false}) { 95 {bool allowNull: false}) {
106 return value.isNothing || 96 return value.isNothing ||
107 typeSystem.isDefinitelyString(value.type, allowNull: allowNull); 97 typeSystem.isDefinitelyString(value.type, allowNull: allowNull);
108 } 98 }
109 99
110 /// True if all members of this value are numbers, strings, or booleans. 100 /// True if all members of this value are numbers, strings, or booleans.
111 bool isDefinitelyNumStringBool(AbstractConstantValue value, 101 bool isDefinitelyNumStringBool(AbstractConstantValue value,
112 {bool allowNull: false}) { 102 {bool allowNull: false}) {
113 return value.isNothing || 103 return value.isNothing ||
114 typeSystem.isDefinitelyNumStringBool(value.type, allowNull: allowNull); 104 typeSystem.isDefinitelyNumStringBool(value.type, allowNull: allowNull);
115 } 105 }
116 106
117 /// True if this value cannot be a string, number, or boolean. 107 /// True if this value cannot be a string, number, or boolean.
118 bool isDefinitelyNotNumStringBool(AbstractConstantValue value) { 108 bool isDefinitelyNotNumStringBool(AbstractConstantValue value) {
119 return value.isNothing || 109 return value.isNothing ||
120 typeSystem.isDefinitelyNotNumStringBool(value.type); 110 typeSystem.isDefinitelyNotNumStringBool(value.type);
121 } 111 }
122 112
123 /// True if this value cannot be a non-integer double. 113 /// True if this value cannot be a non-integer double.
124 /// 114 ///
125 /// In other words, if true is returned, and the value is a number, then 115 /// In other words, if true is returned, and the value is a number, then
126 /// it is a whole number and is not NaN, Infinity, or minus Infinity. 116 /// it is a whole number and is not NaN, Infinity, or minus Infinity.
127 bool isDefinitelyNotNonIntegerDouble(AbstractConstantValue value) { 117 bool isDefinitelyNotNonIntegerDouble(AbstractConstantValue value) {
128 return value.isNothing || 118 return value.isNothing ||
129 value.isConstant && !value.constant.isDouble || 119 value.isConstant && !value.constant.isDouble ||
130 typeSystem.isDefinitelyNotNonIntegerDouble(value.type); 120 typeSystem.isDefinitelyNotNonIntegerDouble(value.type);
131 } 121 }
132 122
133 bool isDefinitelyInt(AbstractConstantValue value, 123 bool isDefinitelyInt(AbstractConstantValue value, {bool allowNull: false}) {
134 {bool allowNull: false}) {
135 return value.isNothing || 124 return value.isNothing ||
136 typeSystem.isDefinitelyInt(value.type, allowNull: allowNull); 125 typeSystem.isDefinitelyInt(value.type, allowNull: allowNull);
137 } 126 }
138 127
139 bool isDefinitelyUint31(AbstractConstantValue value, 128 bool isDefinitelyUint31(AbstractConstantValue value,
140 {bool allowNull: false}) { 129 {bool allowNull: false}) {
141 return value.isNothing || 130 return value.isNothing ||
142 typeSystem.isDefinitelyUint31(value.type, allowNull: allowNull); 131 typeSystem.isDefinitelyUint31(value.type, allowNull: allowNull);
143 } 132 }
144 133
145 bool isDefinitelyUint32(AbstractConstantValue value, 134 bool isDefinitelyUint32(AbstractConstantValue value,
146 {bool allowNull: false}) { 135 {bool allowNull: false}) {
147 return value.isNothing || 136 return value.isNothing ||
148 typeSystem.isDefinitelyUint32(value.type, allowNull: allowNull); 137 typeSystem.isDefinitelyUint32(value.type, allowNull: allowNull);
149 } 138 }
150 139
151 bool isDefinitelyUint(AbstractConstantValue value, 140 bool isDefinitelyUint(AbstractConstantValue value, {bool allowNull: false}) {
152 {bool allowNull: false}) {
153 return value.isNothing || 141 return value.isNothing ||
154 typeSystem.isDefinitelyUint(value.type, allowNull: allowNull); 142 typeSystem.isDefinitelyUint(value.type, allowNull: allowNull);
155 } 143 }
156 144
157 bool isDefinitelyArray(AbstractConstantValue value, 145 bool isDefinitelyArray(AbstractConstantValue value, {bool allowNull: false}) {
158 {bool allowNull: false}) {
159 return value.isNothing || 146 return value.isNothing ||
160 typeSystem.isDefinitelyArray(value.type, allowNull: allowNull); 147 typeSystem.isDefinitelyArray(value.type, allowNull: allowNull);
161 } 148 }
162 149
163 bool isDefinitelyMutableArray(AbstractConstantValue value, 150 bool isDefinitelyMutableArray(AbstractConstantValue value,
164 {bool allowNull: false}) { 151 {bool allowNull: false}) {
165 return value.isNothing || 152 return value.isNothing ||
166 typeSystem.isDefinitelyMutableArray(value.type, 153 typeSystem.isDefinitelyMutableArray(value.type, allowNull: allowNull);
167 allowNull: allowNull);
168 } 154 }
169 155
170 bool isDefinitelyFixedArray(AbstractConstantValue value, 156 bool isDefinitelyFixedArray(AbstractConstantValue value,
171 {bool allowNull: false}) { 157 {bool allowNull: false}) {
172 return value.isNothing || 158 return value.isNothing ||
173 typeSystem.isDefinitelyFixedArray(value.type, 159 typeSystem.isDefinitelyFixedArray(value.type, allowNull: allowNull);
174 allowNull: allowNull);
175 } 160 }
176 161
177 bool isDefinitelyExtendableArray(AbstractConstantValue value, 162 bool isDefinitelyExtendableArray(AbstractConstantValue value,
178 {bool allowNull: false}) { 163 {bool allowNull: false}) {
179 return value.isNothing || 164 return value.isNothing ||
180 typeSystem.isDefinitelyExtendableArray(value.type, 165 typeSystem.isDefinitelyExtendableArray(value.type,
181 allowNull: allowNull); 166 allowNull: allowNull);
182 } 167 }
183 168
184 bool isDefinitelyIndexable(AbstractConstantValue value, 169 bool isDefinitelyIndexable(AbstractConstantValue value,
185 {bool allowNull: false}) { 170 {bool allowNull: false}) {
186 return value.isNothing || 171 return value.isNothing ||
187 typeSystem.isDefinitelyIndexable(value.type, allowNull: allowNull); 172 typeSystem.isDefinitelyIndexable(value.type, allowNull: allowNull);
188 } 173 }
189 174
190 /// Returns `true` if [value] represents an int value that must be in the 175 /// Returns `true` if [value] represents an int value that must be in the
191 /// inclusive range. 176 /// inclusive range.
192 bool isDefinitelyIntInRange(AbstractConstantValue value, {int min, int max}) { 177 bool isDefinitelyIntInRange(AbstractConstantValue value, {int min, int max}) {
193 if (value.isNothing) return true; 178 if (value.isNothing) return true;
194 if (!isDefinitelyInt(value)) return false; 179 if (!isDefinitelyInt(value)) return false;
195 PrimitiveConstantValue constant = value.constant; 180 PrimitiveConstantValue constant = value.constant;
196 if (constant == null) return false; 181 if (constant == null) return false;
197 if (!constant.isInt) return false; 182 if (!constant.isInt) return false;
198 if (min != null && constant.primitiveValue < min) return false; 183 if (min != null && constant.primitiveValue < min) return false;
199 if (max != null && constant.primitiveValue > max) return false; 184 if (max != null && constant.primitiveValue > max) return false;
200 return true; 185 return true;
201 } 186 }
202 187
203 /// Returns whether the given [value] is an instance of [type]. 188 /// Returns whether the given [value] is an instance of [type].
204 /// 189 ///
205 /// Since [value] and [type] are not always known, [AbstractBool.Maybe] is 190 /// Since [value] and [type] are not always known, [AbstractBool.Maybe] is
206 /// returned if the answer is not known. 191 /// returned if the answer is not known.
207 /// 192 ///
208 /// [AbstractBool.Nothing] is returned if [value] is nothing. 193 /// [AbstractBool.Nothing] is returned if [value] is nothing.
209 /// 194 ///
210 /// If [allowNull] is true, `null` is considered an instance of anything, 195 /// If [allowNull] is true, `null` is considered an instance of anything,
211 /// otherwise it is only considered an instance of [Object], [dynamic], and 196 /// otherwise it is only considered an instance of [Object], [dynamic], and
212 /// [Null]. 197 /// [Null].
213 AbstractBool isSubtypeOf(AbstractConstantValue value, 198 AbstractBool isSubtypeOf(AbstractConstantValue value, types.DartType type,
214 types.DartType type, 199 {bool allowNull}) {
215 {bool allowNull}) {
216 assert(allowNull != null); 200 assert(allowNull != null);
217 if (value.isNothing) { 201 if (value.isNothing) {
218 return AbstractBool.Nothing; 202 return AbstractBool.Nothing;
219 } 203 }
220 if (value.isConstant) { 204 if (value.isConstant) {
221 if (value.constant.isNull) { 205 if (value.constant.isNull) {
222 if (allowNull || 206 if (allowNull ||
223 type.isObject || 207 type.isObject ||
224 type.isDynamic || 208 type.isDynamic ||
225 type == dartTypes.coreTypes.nullType) { 209 type == dartTypes.coreTypes.nullType) {
226 return AbstractBool.True; 210 return AbstractBool.True;
227 } 211 }
228 if (type is types.TypeVariableType) { 212 if (type is types.TypeVariableType) {
229 return AbstractBool.Maybe; 213 return AbstractBool.Maybe;
230 } 214 }
231 return AbstractBool.False; 215 return AbstractBool.False;
232 } 216 }
233 if (type == dartTypes.coreTypes.intType) { 217 if (type == dartTypes.coreTypes.intType) {
234 return constantSystem.isInt(value.constant) 218 return constantSystem.isInt(value.constant)
235 ? AbstractBool.True 219 ? AbstractBool.True
236 : AbstractBool.False; 220 : AbstractBool.False;
237 } 221 }
238 types.DartType valueType = value.constant.getType(dartTypes.coreTypes); 222 types.DartType valueType = value.constant.getType(dartTypes.coreTypes);
239 if (constantSystem.isSubtype(dartTypes, valueType, type)) { 223 if (constantSystem.isSubtype(dartTypes, valueType, type)) {
240 return AbstractBool.True; 224 return AbstractBool.True;
241 } 225 }
242 if (!dartTypes.isPotentialSubtype(valueType, type)) { 226 if (!dartTypes.isPotentialSubtype(valueType, type)) {
243 return AbstractBool.False; 227 return AbstractBool.False;
244 } 228 }
245 return AbstractBool.Maybe; 229 return AbstractBool.Maybe;
246 } 230 }
247 return typeSystem.isSubtypeOf(value.type, type, allowNull: allowNull); 231 return typeSystem.isSubtypeOf(value.type, type, allowNull: allowNull);
248 } 232 }
249 233
250 /// Returns the possible results of applying [operator] to [value], 234 /// Returns the possible results of applying [operator] to [value],
251 /// assuming the operation does not throw. 235 /// assuming the operation does not throw.
252 /// 236 ///
253 /// Because we do not explicitly track thrown values, we currently use the 237 /// Because we do not explicitly track thrown values, we currently use the
254 /// convention that constant values are returned from this method only 238 /// convention that constant values are returned from this method only
255 /// if the operation is known not to throw. 239 /// if the operation is known not to throw.
256 /// 240 ///
257 /// This method returns `null` if a good result could not be found. In that 241 /// This method returns `null` if a good result could not be found. In that
258 /// case, it is best to fall back on interprocedural type information. 242 /// case, it is best to fall back on interprocedural type information.
259 AbstractConstantValue unaryOp(UnaryOperator operator, 243 AbstractConstantValue unaryOp(
260 AbstractConstantValue value) { 244 UnaryOperator operator, AbstractConstantValue value) {
261 switch (operator.kind) { 245 switch (operator.kind) {
262 case UnaryOperatorKind.COMPLEMENT: 246 case UnaryOperatorKind.COMPLEMENT:
263 return bitNotSpecial(value); 247 return bitNotSpecial(value);
264 case UnaryOperatorKind.NEGATE: 248 case UnaryOperatorKind.NEGATE:
265 return negateSpecial(value); 249 return negateSpecial(value);
266 default: 250 default:
267 break; 251 break;
268 } 252 }
269 // TODO(asgerf): Also return information about whether this can throw? 253 // TODO(asgerf): Also return information about whether this can throw?
270 if (value.isNothing) { 254 if (value.isNothing) {
(...skipping 11 matching lines...) Expand all
282 /// Returns the possible results of applying [operator] to [left], [right], 266 /// Returns the possible results of applying [operator] to [left], [right],
283 /// assuming the operation does not throw. 267 /// assuming the operation does not throw.
284 /// 268 ///
285 /// Because we do not explicitly track thrown values, we currently use the 269 /// Because we do not explicitly track thrown values, we currently use the
286 /// convention that constant values are returned from this method only 270 /// convention that constant values are returned from this method only
287 /// if the operation is known not to throw. 271 /// if the operation is known not to throw.
288 /// 272 ///
289 /// This method returns `null` if a good result could not be found. In that 273 /// This method returns `null` if a good result could not be found. In that
290 /// case, it is best to fall back on interprocedural type information. 274 /// case, it is best to fall back on interprocedural type information.
291 AbstractConstantValue binaryOp(BinaryOperator operator, 275 AbstractConstantValue binaryOp(BinaryOperator operator,
292 AbstractConstantValue left, 276 AbstractConstantValue left, AbstractConstantValue right) {
293 AbstractConstantValue right) {
294 switch (operator.kind) { 277 switch (operator.kind) {
295 case BinaryOperatorKind.ADD: 278 case BinaryOperatorKind.ADD:
296 return addSpecial(left, right); 279 return addSpecial(left, right);
297 280
298 case BinaryOperatorKind.SUB: 281 case BinaryOperatorKind.SUB:
299 return subtractSpecial(left, right); 282 return subtractSpecial(left, right);
300 283
301 case BinaryOperatorKind.MUL: 284 case BinaryOperatorKind.MUL:
302 return multiplySpecial(left, right); 285 return multiplySpecial(left, right);
303 286
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
348 return nothing; 331 return nothing;
349 } 332 }
350 if (left.isConstant && right.isConstant) { 333 if (left.isConstant && right.isConstant) {
351 BinaryOperation operation = constantSystem.lookupBinary(operator); 334 BinaryOperation operation = constantSystem.lookupBinary(operator);
352 ConstantValue result = operation.fold(left.constant, right.constant); 335 ConstantValue result = operation.fold(left.constant, right.constant);
353 if (result != null) return constant(result); 336 if (result != null) return constant(result);
354 } 337 }
355 return null; // The caller will use return type from type inference. 338 return null; // The caller will use return type from type inference.
356 } 339 }
357 340
358 AbstractConstantValue foldUnary(UnaryOperation operation, 341 AbstractConstantValue foldUnary(
359 AbstractConstantValue value) { 342 UnaryOperation operation, AbstractConstantValue value) {
360 if (value.isNothing) return nothing; 343 if (value.isNothing) return nothing;
361 if (value.isConstant) { 344 if (value.isConstant) {
362 ConstantValue result = operation.fold(value.constant); 345 ConstantValue result = operation.fold(value.constant);
363 if (result != null) return constant(result); 346 if (result != null) return constant(result);
364 } 347 }
365 return null; 348 return null;
366 } 349 }
367 350
368 AbstractConstantValue bitNotSpecial(AbstractConstantValue value) { 351 AbstractConstantValue bitNotSpecial(AbstractConstantValue value) {
369 return foldUnary(constantSystem.bitNot, value); 352 return foldUnary(constantSystem.bitNot, value);
370 } 353 }
371 354
372 AbstractConstantValue negateSpecial(AbstractConstantValue value) { 355 AbstractConstantValue negateSpecial(AbstractConstantValue value) {
373 AbstractConstantValue folded = foldUnary(constantSystem.negate, value); 356 AbstractConstantValue folded = foldUnary(constantSystem.negate, value);
374 if (folded != null) return folded; 357 if (folded != null) return folded;
375 if (isDefinitelyInt(value, allowNull: true)) { 358 if (isDefinitelyInt(value, allowNull: true)) {
376 return nonConstant(typeSystem.intType); 359 return nonConstant(typeSystem.intType);
377 } 360 }
378 return null; 361 return null;
379 } 362 }
380 363
381
382 AbstractConstantValue foldBinary(BinaryOperation operation, 364 AbstractConstantValue foldBinary(BinaryOperation operation,
383 AbstractConstantValue left, AbstractConstantValue right) { 365 AbstractConstantValue left, AbstractConstantValue right) {
384 if (left.isNothing || right.isNothing) return nothing; 366 if (left.isNothing || right.isNothing) return nothing;
385 if (left.isConstant && right.isConstant) { 367 if (left.isConstant && right.isConstant) {
386 ConstantValue result = operation.fold(left.constant, right.constant); 368 ConstantValue result = operation.fold(left.constant, right.constant);
387 if (result != null) return constant(result); 369 if (result != null) return constant(result);
388 } 370 }
389 return null; 371 return null;
390 } 372 }
391 373
392 AbstractConstantValue closedOnInt(AbstractConstantValue left, 374 AbstractConstantValue closedOnInt(
393 AbstractConstantValue right) { 375 AbstractConstantValue left, AbstractConstantValue right) {
394 if (isDefinitelyInt(left, allowNull: true) && 376 if (isDefinitelyInt(left, allowNull: true) &&
395 isDefinitelyInt(right, allowNull: true)) { 377 isDefinitelyInt(right, allowNull: true)) {
396 return nonConstant(typeSystem.intType); 378 return nonConstant(typeSystem.intType);
397 } 379 }
398 return null; 380 return null;
399 } 381 }
400 382
401 AbstractConstantValue closedOnUint(AbstractConstantValue left, 383 AbstractConstantValue closedOnUint(
402 AbstractConstantValue right) { 384 AbstractConstantValue left, AbstractConstantValue right) {
403 if (isDefinitelyUint(left, allowNull: true) && 385 if (isDefinitelyUint(left, allowNull: true) &&
404 isDefinitelyUint(right, allowNull: true)) { 386 isDefinitelyUint(right, allowNull: true)) {
405 return nonConstant(typeSystem.uintType); 387 return nonConstant(typeSystem.uintType);
406 } 388 }
407 return null; 389 return null;
408 } 390 }
409 391
410 AbstractConstantValue closedOnUint31(AbstractConstantValue left, 392 AbstractConstantValue closedOnUint31(
411 AbstractConstantValue right) { 393 AbstractConstantValue left, AbstractConstantValue right) {
412 if (isDefinitelyUint31(left, allowNull: true) && 394 if (isDefinitelyUint31(left, allowNull: true) &&
413 isDefinitelyUint31(right, allowNull: true)) { 395 isDefinitelyUint31(right, allowNull: true)) {
414 return nonConstant(typeSystem.uint31Type); 396 return nonConstant(typeSystem.uint31Type);
415 } 397 }
416 return null; 398 return null;
417 } 399 }
418 400
419 AbstractConstantValue addSpecial(AbstractConstantValue left, 401 AbstractConstantValue addSpecial(
420 AbstractConstantValue right) { 402 AbstractConstantValue left, AbstractConstantValue right) {
421 AbstractConstantValue folded = foldBinary(constantSystem.add, left, right); 403 AbstractConstantValue folded = foldBinary(constantSystem.add, left, right);
422 if (folded != null) return folded; 404 if (folded != null) return folded;
423 if (isDefinitelyNum(left, allowNull: true)) { 405 if (isDefinitelyNum(left, allowNull: true)) {
424 if (isDefinitelyUint31(left, allowNull: true) && 406 if (isDefinitelyUint31(left, allowNull: true) &&
425 isDefinitelyUint31(right, allowNull: true)) { 407 isDefinitelyUint31(right, allowNull: true)) {
426 return nonConstant(typeSystem.uint32Type); 408 return nonConstant(typeSystem.uint32Type);
427 } 409 }
428 return closedOnUint(left, right) ?? closedOnInt(left, right); 410 return closedOnUint(left, right) ?? closedOnInt(left, right);
429 } 411 }
430 return null; 412 return null;
431 } 413 }
432 414
433 AbstractConstantValue subtractSpecial(AbstractConstantValue left, 415 AbstractConstantValue subtractSpecial(
434 AbstractConstantValue right) { 416 AbstractConstantValue left, AbstractConstantValue right) {
435 AbstractConstantValue folded = 417 AbstractConstantValue folded =
436 foldBinary(constantSystem.subtract, left, right); 418 foldBinary(constantSystem.subtract, left, right);
437 return folded ?? closedOnInt(left, right); 419 return folded ?? closedOnInt(left, right);
438 } 420 }
439 421
440 AbstractConstantValue multiplySpecial(AbstractConstantValue left, 422 AbstractConstantValue multiplySpecial(
441 AbstractConstantValue right) { 423 AbstractConstantValue left, AbstractConstantValue right) {
442 AbstractConstantValue folded = 424 AbstractConstantValue folded =
443 foldBinary(constantSystem.multiply, left, right); 425 foldBinary(constantSystem.multiply, left, right);
444 return folded ?? closedOnUint(left, right) ?? closedOnInt(left, right); 426 return folded ?? closedOnUint(left, right) ?? closedOnInt(left, right);
445 } 427 }
446 428
447 AbstractConstantValue divideSpecial(AbstractConstantValue left, 429 AbstractConstantValue divideSpecial(
448 AbstractConstantValue right) { 430 AbstractConstantValue left, AbstractConstantValue right) {
449 return foldBinary(constantSystem.divide, left, right); 431 return foldBinary(constantSystem.divide, left, right);
450 } 432 }
451 433
452 AbstractConstantValue truncatingDivideSpecial( 434 AbstractConstantValue truncatingDivideSpecial(
453 AbstractConstantValue left, AbstractConstantValue right) { 435 AbstractConstantValue left, AbstractConstantValue right) {
454 AbstractConstantValue folded = 436 AbstractConstantValue folded =
455 foldBinary(constantSystem.truncatingDivide, left, right); 437 foldBinary(constantSystem.truncatingDivide, left, right);
456 if (folded != null) return folded; 438 if (folded != null) return folded;
457 if (isDefinitelyNum(left, allowNull: true)) { 439 if (isDefinitelyNum(left, allowNull: true)) {
458 if (isDefinitelyUint32(left, allowNull: true) && 440 if (isDefinitelyUint32(left, allowNull: true) &&
(...skipping 10 matching lines...) Expand all
469 } 451 }
470 if (isDefinitelyUint(left, allowNull: true)) { 452 if (isDefinitelyUint(left, allowNull: true)) {
471 return nonConstant(typeSystem.uintType); 453 return nonConstant(typeSystem.uintType);
472 } 454 }
473 } 455 }
474 return nonConstant(typeSystem.intType); 456 return nonConstant(typeSystem.intType);
475 } 457 }
476 return null; 458 return null;
477 } 459 }
478 460
479 AbstractConstantValue moduloSpecial(AbstractConstantValue left, 461 AbstractConstantValue moduloSpecial(
480 AbstractConstantValue right) { 462 AbstractConstantValue left, AbstractConstantValue right) {
481 AbstractConstantValue folded = 463 AbstractConstantValue folded =
482 foldBinary(constantSystem.modulo, left, right); 464 foldBinary(constantSystem.modulo, left, right);
483 return folded ?? closedOnUint(left, right) ?? closedOnInt(left, right); 465 return folded ?? closedOnUint(left, right) ?? closedOnInt(left, right);
484 } 466 }
485 467
486 AbstractConstantValue remainderSpecial(AbstractConstantValue left, 468 AbstractConstantValue remainderSpecial(
487 AbstractConstantValue right) { 469 AbstractConstantValue left, AbstractConstantValue right) {
488 if (left.isNothing || right.isNothing) return nothing; 470 if (left.isNothing || right.isNothing) return nothing;
489 AbstractConstantValue folded = null; // Remainder not in constant system. 471 AbstractConstantValue folded = null; // Remainder not in constant system.
490 return folded ?? closedOnUint(left, right) ?? closedOnInt(left, right); 472 return folded ?? closedOnUint(left, right) ?? closedOnInt(left, right);
491 } 473 }
492 474
493 AbstractConstantValue codeUnitAtSpecial(AbstractConstantValue left, 475 AbstractConstantValue codeUnitAtSpecial(
494 AbstractConstantValue right) { 476 AbstractConstantValue left, AbstractConstantValue right) {
495 return foldBinary(constantSystem.codeUnitAt, left, right); 477 return foldBinary(constantSystem.codeUnitAt, left, right);
496 } 478 }
497 479
498 AbstractConstantValue equalSpecial(AbstractConstantValue left, 480 AbstractConstantValue equalSpecial(
499 AbstractConstantValue right) { 481 AbstractConstantValue left, AbstractConstantValue right) {
500 AbstractConstantValue folded = 482 AbstractConstantValue folded =
501 foldBinary(constantSystem.equal, left, right); 483 foldBinary(constantSystem.equal, left, right);
502 if (folded != null) return folded; 484 if (folded != null) return folded;
503 bool behavesLikeIdentity = 485 bool behavesLikeIdentity =
504 isDefinitelyNumStringBool(left, allowNull: true) || 486 isDefinitelyNumStringBool(left, allowNull: true) ||
505 right.isNullConstant; 487 right.isNullConstant;
506 if (behavesLikeIdentity && 488 if (behavesLikeIdentity && typeSystem.areDisjoint(left.type, right.type)) {
507 typeSystem.areDisjoint(left.type, right.type)) {
508 return constant(new FalseConstantValue()); 489 return constant(new FalseConstantValue());
509 } 490 }
510 return null; 491 return null;
511 } 492 }
512 493
513 AbstractConstantValue andSpecial(AbstractConstantValue left, 494 AbstractConstantValue andSpecial(
514 AbstractConstantValue right) { 495 AbstractConstantValue left, AbstractConstantValue right) {
515 AbstractConstantValue folded = 496 AbstractConstantValue folded =
516 foldBinary(constantSystem.bitAnd, left, right); 497 foldBinary(constantSystem.bitAnd, left, right);
517 if (folded != null) return folded; 498 if (folded != null) return folded;
518 if (isDefinitelyNum(left, allowNull: true)) { 499 if (isDefinitelyNum(left, allowNull: true)) {
519 if (isDefinitelyUint31(left, allowNull: true) || 500 if (isDefinitelyUint31(left, allowNull: true) ||
520 isDefinitelyUint31(right, allowNull: true)) { 501 isDefinitelyUint31(right, allowNull: true)) {
521 // Either 31-bit argument will truncate the other. 502 // Either 31-bit argument will truncate the other.
522 return nonConstant(typeSystem.uint31Type); 503 return nonConstant(typeSystem.uint31Type);
523 } 504 }
524 } 505 }
525 return null; 506 return null;
526 } 507 }
527 508
528 AbstractConstantValue orSpecial(AbstractConstantValue left, 509 AbstractConstantValue orSpecial(
529 AbstractConstantValue right) { 510 AbstractConstantValue left, AbstractConstantValue right) {
530 AbstractConstantValue folded = 511 AbstractConstantValue folded =
531 foldBinary(constantSystem.bitOr, left, right); 512 foldBinary(constantSystem.bitOr, left, right);
532 return folded ?? closedOnUint31(left, right); 513 return folded ?? closedOnUint31(left, right);
533 } 514 }
534 515
535 AbstractConstantValue xorSpecial(AbstractConstantValue left, 516 AbstractConstantValue xorSpecial(
536 AbstractConstantValue right) { 517 AbstractConstantValue left, AbstractConstantValue right) {
537 AbstractConstantValue folded = 518 AbstractConstantValue folded =
538 foldBinary(constantSystem.bitXor, left, right); 519 foldBinary(constantSystem.bitXor, left, right);
539 return folded ?? closedOnUint31(left, right); 520 return folded ?? closedOnUint31(left, right);
540 } 521 }
541 522
542 AbstractConstantValue shiftLeftSpecial(AbstractConstantValue left, 523 AbstractConstantValue shiftLeftSpecial(
543 AbstractConstantValue right) { 524 AbstractConstantValue left, AbstractConstantValue right) {
544 return foldBinary(constantSystem.shiftLeft, left, right); 525 return foldBinary(constantSystem.shiftLeft, left, right);
545 } 526 }
546 527
547 AbstractConstantValue shiftRightSpecial(AbstractConstantValue left, 528 AbstractConstantValue shiftRightSpecial(
548 AbstractConstantValue right) { 529 AbstractConstantValue left, AbstractConstantValue right) {
549 AbstractConstantValue folded = 530 AbstractConstantValue folded =
550 foldBinary(constantSystem.shiftRight, left, right); 531 foldBinary(constantSystem.shiftRight, left, right);
551 if (folded != null) return folded; 532 if (folded != null) return folded;
552 if (isDefinitelyUint31(left, allowNull: true)) { 533 if (isDefinitelyUint31(left, allowNull: true)) {
553 return nonConstant(typeSystem.uint31Type); 534 return nonConstant(typeSystem.uint31Type);
554 } else if (isDefinitelyUint32(left, allowNull: true)) { 535 } else if (isDefinitelyUint32(left, allowNull: true)) {
555 if (isDefinitelyIntInRange(right, min: 1, max: 31)) { 536 if (isDefinitelyIntInRange(right, min: 1, max: 31)) {
556 // A zero will be shifted into the 'sign' bit. 537 // A zero will be shifted into the 'sign' bit.
557 return nonConstant(typeSystem.uint31Type); 538 return nonConstant(typeSystem.uint31Type);
558 } 539 }
559 return nonConstant(typeSystem.uint32Type); 540 return nonConstant(typeSystem.uint32Type);
560 } 541 }
561 return null; 542 return null;
562 } 543 }
563 544
564 AbstractConstantValue lessSpecial(AbstractConstantValue left, 545 AbstractConstantValue lessSpecial(
565 AbstractConstantValue right) { 546 AbstractConstantValue left, AbstractConstantValue right) {
566 if (isDefinitelyUint(left) && right.isZeroOrNegativeConstant) { 547 if (isDefinitelyUint(left) && right.isZeroOrNegativeConstant) {
567 return falseValue; // "uint < 0" is false. 548 return falseValue; // "uint < 0" is false.
568 } else if (left.isNegativeConstant && isDefinitelyUint(right)) { 549 } else if (left.isNegativeConstant && isDefinitelyUint(right)) {
569 return trueValue; // "-1 < uint" is true. 550 return trueValue; // "-1 < uint" is true.
570 } 551 }
571 return foldBinary(constantSystem.less, left, right); 552 return foldBinary(constantSystem.less, left, right);
572 } 553 }
573 554
574 AbstractConstantValue lessEqualSpecial(AbstractConstantValue left, 555 AbstractConstantValue lessEqualSpecial(
575 AbstractConstantValue right) { 556 AbstractConstantValue left, AbstractConstantValue right) {
576 if (isDefinitelyUint(left) && right.isNegativeConstant) { 557 if (isDefinitelyUint(left) && right.isNegativeConstant) {
577 return falseValue; // "uint <= -1" is false. 558 return falseValue; // "uint <= -1" is false.
578 } else if (left.isZeroOrNegativeConstant && isDefinitelyUint(right)) { 559 } else if (left.isZeroOrNegativeConstant && isDefinitelyUint(right)) {
579 return trueValue; // "0 <= uint" is true. 560 return trueValue; // "0 <= uint" is true.
580 } 561 }
581 return foldBinary(constantSystem.lessEqual, left, right); 562 return foldBinary(constantSystem.lessEqual, left, right);
582 } 563 }
583 564
584 AbstractConstantValue greaterSpecial(AbstractConstantValue left, 565 AbstractConstantValue greaterSpecial(
585 AbstractConstantValue right) { 566 AbstractConstantValue left, AbstractConstantValue right) {
586 if (left.isZeroOrNegativeConstant && isDefinitelyUint(right)) { 567 if (left.isZeroOrNegativeConstant && isDefinitelyUint(right)) {
587 return falseValue; // "0 > uint" is false 568 return falseValue; // "0 > uint" is false
588 } else if (isDefinitelyUint(left) && right.isNegativeConstant) { 569 } else if (isDefinitelyUint(left) && right.isNegativeConstant) {
589 return trueValue; // "uint > -1" is true 570 return trueValue; // "uint > -1" is true
590 } 571 }
591 return foldBinary(constantSystem.greater, left, right); 572 return foldBinary(constantSystem.greater, left, right);
592 } 573 }
593 574
594 AbstractConstantValue greaterEqualSpecial(AbstractConstantValue left, 575 AbstractConstantValue greaterEqualSpecial(
595 AbstractConstantValue right) { 576 AbstractConstantValue left, AbstractConstantValue right) {
596 if (left.isNegativeConstant && isDefinitelyUint(right)) { 577 if (left.isNegativeConstant && isDefinitelyUint(right)) {
597 return falseValue; // "-1 >= uint" is false 578 return falseValue; // "-1 >= uint" is false
598 } else if (isDefinitelyUint(left) && right.isZeroOrNegativeConstant) { 579 } else if (isDefinitelyUint(left) && right.isZeroOrNegativeConstant) {
599 return trueValue; // "uint >= 0" is true 580 return trueValue; // "uint >= 0" is true
600 } 581 }
601 return foldBinary(constantSystem.greaterEqual, left, right); 582 return foldBinary(constantSystem.greaterEqual, left, right);
602 } 583 }
603 584
604 AbstractConstantValue intConstant(int value) { 585 AbstractConstantValue intConstant(int value) {
605 return constant(new IntConstantValue(value)); 586 return constant(new IntConstantValue(value));
606 } 587 }
607 588
608 AbstractConstantValue lengthSpecial(AbstractConstantValue input) { 589 AbstractConstantValue lengthSpecial(AbstractConstantValue input) {
609 if (input.isConstant) { 590 if (input.isConstant) {
610 ConstantValue constant = input.constant; 591 ConstantValue constant = input.constant;
611 if (constant is StringConstantValue) { 592 if (constant is StringConstantValue) {
612 return intConstant(constant.length); 593 return intConstant(constant.length);
613 } else if (constant is ListConstantValue) { 594 } else if (constant is ListConstantValue) {
614 return intConstant(constant.length); 595 return intConstant(constant.length);
615 } 596 }
616 } 597 }
617 int length = typeSystem.getContainerLength(input.type); 598 int length = typeSystem.getContainerLength(input.type);
618 if (length != null) { 599 if (length != null) {
619 return intConstant(length); 600 return intConstant(length);
620 } 601 }
621 return null; // The caller will use return type from type inference. 602 return null; // The caller will use return type from type inference.
622 } 603 }
623 604
624 AbstractConstantValue stringConstant(String value) { 605 AbstractConstantValue stringConstant(String value) {
625 return constant(new StringConstantValue(new ast.DartString.literal(value))); 606 return constant(new StringConstantValue(new ast.DartString.literal(value)));
626 } 607 }
627 608
628 AbstractConstantValue indexSpecial(AbstractConstantValue left, 609 AbstractConstantValue indexSpecial(
629 AbstractConstantValue right) { 610 AbstractConstantValue left, AbstractConstantValue right) {
630 if (left.isNothing || right.isNothing) return nothing; 611 if (left.isNothing || right.isNothing) return nothing;
631 if (right.isConstant) { 612 if (right.isConstant) {
632 ConstantValue index = right.constant; 613 ConstantValue index = right.constant;
633 if (left.isConstant) { 614 if (left.isConstant) {
634 ConstantValue receiver = left.constant; 615 ConstantValue receiver = left.constant;
635 if (receiver is StringConstantValue) { 616 if (receiver is StringConstantValue) {
636 if (index is IntConstantValue) { 617 if (index is IntConstantValue) {
637 String stringValue = receiver.primitiveValue.slowToString(); 618 String stringValue = receiver.primitiveValue.slowToString();
638 int indexValue = index.primitiveValue; 619 int indexValue = index.primitiveValue;
639 if (0 <= indexValue && indexValue < stringValue.length) { 620 if (0 <= indexValue && indexValue < stringValue.length) {
640 return stringConstant(stringValue[indexValue]); 621 return stringConstant(stringValue[indexValue]);
641 } else { 622 } else {
642 return nothing; // Will throw. 623 return nothing; // Will throw.
643 } 624 }
644 } 625 }
645 } else if (receiver is ListConstantValue) { 626 } else if (receiver is ListConstantValue) {
646 if (index is IntConstantValue) { 627 if (index is IntConstantValue) {
647 int indexValue = index.primitiveValue; 628 int indexValue = index.primitiveValue;
648 if (0 <= indexValue && indexValue < receiver.length) { 629 if (0 <= indexValue && indexValue < receiver.length) {
649 return constant(receiver.entries[indexValue]); 630 return constant(receiver.entries[indexValue]);
650 } else { 631 } else {
651 return nothing; // Will throw. 632 return nothing; // Will throw.
652 } 633 }
653 } 634 }
654 } else if (receiver is MapConstantValue) { 635 } else if (receiver is MapConstantValue) {
655 ConstantValue result = receiver.lookup(index); 636 ConstantValue result = receiver.lookup(index);
656 if (result != null) { 637 if (result != null) {
657 return constant(result); 638 return constant(result);
658 } 639 }
659 return constant(new NullConstantValue()); 640 return constant(new NullConstantValue());
660 } 641 }
661 } 642 }
662 TypeMask type = typeSystem.indexWithConstant(left.type, index); 643 TypeMask type = typeSystem.indexWithConstant(left.type, index);
663 if (type != null) return nonConstant(type); 644 if (type != null) return nonConstant(type);
664 } 645 }
665 // TODO(asgerf): Handle case where 'left' is a List or Map constant but 646 // TODO(asgerf): Handle case where 'left' is a List or Map constant but
666 // the index is unknown. 647 // the index is unknown.
667 return null; // The caller will use return type from type inference. 648 return null; // The caller will use return type from type inference.
668 } 649 }
669 650
670 AbstractConstantValue stringify(AbstractConstantValue value) { 651 AbstractConstantValue stringify(AbstractConstantValue value) {
671 if (value.isNothing) return nothing; 652 if (value.isNothing) return nothing;
672 if (value.isNonConst) return nonConstant(typeSystem.stringType); 653 if (value.isNonConst) return nonConstant(typeSystem.stringType);
673 ConstantValue constantValue = value.constant; 654 ConstantValue constantValue = value.constant;
674 if (constantValue is StringConstantValue) { 655 if (constantValue is StringConstantValue) {
675 return value; 656 return value;
676 } else if (constantValue is PrimitiveConstantValue) { 657 } else if (constantValue is PrimitiveConstantValue) {
677 // Note: The primitiveValue for a StringConstantValue is not suitable 658 // Note: The primitiveValue for a StringConstantValue is not suitable
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
719 if (constantValue != null) return constant(constantValue, mask); 700 if (constantValue != null) return constant(constantValue, mask);
720 return nonConstant(mask); 701 return nonConstant(mask);
721 } 702 }
722 703
723 AbstractConstantValue nonNullable(AbstractConstantValue value) { 704 AbstractConstantValue nonNullable(AbstractConstantValue value) {
724 if (value.isNullConstant) return nothing; 705 if (value.isNullConstant) return nothing;
725 if (!value.isNullable) return value; 706 if (!value.isNullable) return value;
726 return nonConstant(value.type.nonNullable()); 707 return nonConstant(value.type.nonNullable());
727 } 708 }
728 709
729 AbstractConstantValue intersectWithType(AbstractConstantValue value, 710 AbstractConstantValue intersectWithType(
730 TypeMask type) { 711 AbstractConstantValue value, TypeMask type) {
731 if (value.isNothing || typeSystem.areDisjoint(value.type, type)) { 712 if (value.isNothing || typeSystem.areDisjoint(value.type, type)) {
732 return nothing; 713 return nothing;
733 } else if (value.isConstant) { 714 } else if (value.isConstant) {
734 return value; 715 return value;
735 } else { 716 } else {
736 return nonConstant(typeSystem.intersection(value.type, type)); 717 return nonConstant(typeSystem.intersection(value.type, type));
737 } 718 }
738 } 719 }
739 720
740 /// If [value] is an integer constant, returns its value, otherwise `null`. 721 /// If [value] is an integer constant, returns its value, otherwise `null`.
(...skipping 13 matching lines...) Expand all
754 * 735 *
755 * Should be followed by the [ShrinkingReducer] pass. 736 * Should be followed by the [ShrinkingReducer] pass.
756 * 737 *
757 * Implemented according to 'Constant Propagation with Conditional Branches' 738 * Implemented according to 'Constant Propagation with Conditional Branches'
758 * by Wegman, Zadeck. 739 * by Wegman, Zadeck.
759 */ 740 */
760 class TypePropagator extends Pass { 741 class TypePropagator extends Pass {
761 String get passName => 'Type propagation'; 742 String get passName => 'Type propagation';
762 743
763 final CpsFunctionCompiler _functionCompiler; 744 final CpsFunctionCompiler _functionCompiler;
764 final Map<Variable, ConstantValue> _values= <Variable, ConstantValue>{}; 745 final Map<Variable, ConstantValue> _values = <Variable, ConstantValue>{};
765 final ConstantPropagationLattice _lattice; 746 final ConstantPropagationLattice _lattice;
766 final bool recomputeAll; 747 final bool recomputeAll;
767 748
768 TypePropagator(CpsFunctionCompiler functionCompiler, 749 TypePropagator(CpsFunctionCompiler functionCompiler,
769 {this.recomputeAll: false}) 750 {this.recomputeAll: false})
770 : _functionCompiler = functionCompiler, 751 : _functionCompiler = functionCompiler,
771 _lattice = new ConstantPropagationLattice(functionCompiler); 752 _lattice = new ConstantPropagationLattice(functionCompiler);
772 753
773 dart2js.Compiler get _compiler => _functionCompiler.compiler; 754 dart2js.Compiler get _compiler => _functionCompiler.compiler;
774 InternalErrorFunction get _internalError => _compiler.reporter.internalError; 755 InternalErrorFunction get _internalError => _compiler.reporter.internalError;
775 756
776 @override 757 @override
777 void rewrite(FunctionDefinition root) { 758 void rewrite(FunctionDefinition root) {
778 // Analyze. In this phase, the entire term is analyzed for reachability 759 // Analyze. In this phase, the entire term is analyzed for reachability
779 // and the abstract value of each expression. 760 // and the abstract value of each expression.
780 TypePropagationVisitor analyzer = new TypePropagationVisitor( 761 TypePropagationVisitor analyzer =
781 _lattice, 762 new TypePropagationVisitor(_lattice, _values, _internalError);
782 _values,
783 _internalError);
784 763
785 analyzer.analyze(root, recomputeAll); 764 analyzer.analyze(root, recomputeAll);
786 765
787 // Transform. Uses the data acquired in the previous analysis phase to 766 // Transform. Uses the data acquired in the previous analysis phase to
788 // replace branches with fixed targets and side-effect-free expressions 767 // replace branches with fixed targets and side-effect-free expressions
789 // with constant results or existing values that are in scope. 768 // with constant results or existing values that are in scope.
790 TransformingVisitor transformer = new TransformingVisitor( 769 TransformingVisitor transformer = new TransformingVisitor(
791 _compiler, 770 _compiler, _functionCompiler, _lattice, analyzer, _internalError);
792 _functionCompiler,
793 _lattice,
794 analyzer,
795 _internalError);
796 transformer.transform(root); 771 transformer.transform(root);
797 } 772 }
798 } 773 }
799 774
800 final Map<String, BuiltinOperator> NumBinaryBuiltins = 775 final Map<String, BuiltinOperator> NumBinaryBuiltins =
801 const <String, BuiltinOperator>{ 776 const <String, BuiltinOperator>{
802 '+': BuiltinOperator.NumAdd, 777 '+': BuiltinOperator.NumAdd,
803 '-': BuiltinOperator.NumSubtract, 778 '-': BuiltinOperator.NumSubtract,
804 '*': BuiltinOperator.NumMultiply, 779 '*': BuiltinOperator.NumMultiply,
805 '/': BuiltinOperator.NumDivide, 780 '/': BuiltinOperator.NumDivide,
806 '&': BuiltinOperator.NumAnd, 781 '&': BuiltinOperator.NumAnd,
807 '|': BuiltinOperator.NumOr, 782 '|': BuiltinOperator.NumOr,
808 '^': BuiltinOperator.NumXor, 783 '^': BuiltinOperator.NumXor,
809 '<': BuiltinOperator.NumLt, 784 '<': BuiltinOperator.NumLt,
810 '<=': BuiltinOperator.NumLe, 785 '<=': BuiltinOperator.NumLe,
811 '>': BuiltinOperator.NumGt, 786 '>': BuiltinOperator.NumGt,
812 '>=': BuiltinOperator.NumGe 787 '>=': BuiltinOperator.NumGe
813 }; 788 };
814 789
815 /** 790 /**
816 * Uses the information from a preceding analysis pass in order to perform the 791 * Uses the information from a preceding analysis pass in order to perform the
817 * actual transformations on the CPS graph. 792 * actual transformations on the CPS graph.
818 */ 793 */
819 class TransformingVisitor extends DeepRecursiveVisitor { 794 class TransformingVisitor extends DeepRecursiveVisitor {
820 final TypePropagationVisitor analyzer; 795 final TypePropagationVisitor analyzer;
821 final ConstantPropagationLattice lattice; 796 final ConstantPropagationLattice lattice;
822 final dart2js.Compiler compiler; 797 final dart2js.Compiler compiler;
823 final CpsFunctionCompiler functionCompiler; 798 final CpsFunctionCompiler functionCompiler;
824 799
825 JavaScriptBackend get backend => compiler.backend; 800 JavaScriptBackend get backend => compiler.backend;
826 BackendHelpers get helpers => backend.helpers; 801 BackendHelpers get helpers => backend.helpers;
827 TypeMaskSystem get typeSystem => lattice.typeSystem; 802 TypeMaskSystem get typeSystem => lattice.typeSystem;
828 types.DartTypes get dartTypes => lattice.dartTypes; 803 types.DartTypes get dartTypes => lattice.dartTypes;
829 World get classWorld => typeSystem.classWorld; 804 World get classWorld => typeSystem.classWorld;
830 Map<Variable, ConstantValue> get values => analyzer.values; 805 Map<Variable, ConstantValue> get values => analyzer.values;
831 806
832 final InternalErrorFunction internalError; 807 final InternalErrorFunction internalError;
833 808
834 final List<Node> stack = <Node>[]; 809 final List<Node> stack = <Node>[];
835 810
836 TypeCheckOperator checkIsNumber; 811 TypeCheckOperator checkIsNumber;
837 812
838 TransformingVisitor(this.compiler, 813 TransformingVisitor(this.compiler, this.functionCompiler, this.lattice,
839 this.functionCompiler, 814 this.analyzer, this.internalError) {
840 this.lattice,
841 this.analyzer,
842 this.internalError) {
843 checkIsNumber = new ClassTypeCheckOperator( 815 checkIsNumber = new ClassTypeCheckOperator(
844 helpers.jsNumberClass, 816 helpers.jsNumberClass, BuiltinOperator.IsNotNumber);
845 BuiltinOperator.IsNotNumber);
846 } 817 }
847 818
848 void transform(FunctionDefinition root) { 819 void transform(FunctionDefinition root) {
849 // If one of the parameters has no value, the function is unreachable. 820 // If one of the parameters has no value, the function is unreachable.
850 // We assume all values in scope have a non-empty type (otherwise the 821 // We assume all values in scope have a non-empty type (otherwise the
851 // scope is unreachable), so this optimization is required. 822 // scope is unreachable), so this optimization is required.
852 // TODO(asgerf): Can we avoid emitting the function is the first place? 823 // TODO(asgerf): Can we avoid emitting the function is the first place?
853 for (Parameter param in root.parameters) { 824 for (Parameter param in root.parameters) {
854 if (getValue(param).isNothing) { 825 if (getValue(param).isNothing) {
855 // Replace with `throw "Unreachable";` 826 // Replace with `throw "Unreachable";`
856 CpsFragment cps = new CpsFragment(null); 827 CpsFragment cps = new CpsFragment(null);
857 Primitive message = cps.makeConstant( 828 Primitive message =
858 new StringConstantValue.fromString("Unreachable")); 829 cps.makeConstant(new StringConstantValue.fromString("Unreachable"));
859 cps.put(new Throw(message)); 830 cps.put(new Throw(message));
860 replaceSubtree(root.body, cps.result); 831 replaceSubtree(root.body, cps.result);
861 return; 832 return;
862 } 833 }
863 } 834 }
864 push(root.body); 835 push(root.body);
865 while (stack.isNotEmpty) { 836 while (stack.isNotEmpty) {
866 visit(stack.removeLast()); 837 visit(stack.removeLast());
867 } 838 }
868 } 839 }
(...skipping 292 matching lines...) Expand 10 before | Expand all | Expand 10 after
1161 if (node.argumentRefs.length > 1) return null; 1132 if (node.argumentRefs.length > 1) return null;
1162 if (node.callingConvention == CallingConvention.OneShotIntercepted) { 1133 if (node.callingConvention == CallingConvention.OneShotIntercepted) {
1163 return null; 1134 return null;
1164 } 1135 }
1165 1136
1166 bool trustPrimitives = compiler.options.trustPrimitives; 1137 bool trustPrimitives = compiler.options.trustPrimitives;
1167 1138
1168 /// Check that the receiver and argument satisfy the given type checks, and 1139 /// Check that the receiver and argument satisfy the given type checks, and
1169 /// throw a [NoSuchMethodError] or [ArgumentError] if the check fails. 1140 /// throw a [NoSuchMethodError] or [ArgumentError] if the check fails.
1170 CpsFragment makeGuard(TypeCheckOperator receiverGuard, 1141 CpsFragment makeGuard(TypeCheckOperator receiverGuard,
1171 [TypeCheckOperator argumentGuard]) { 1142 [TypeCheckOperator argumentGuard]) {
1172 CpsFragment cps = new CpsFragment(node.sourceInformation); 1143 CpsFragment cps = new CpsFragment(node.sourceInformation);
1173 1144
1174 // Make no guards if trusting primitives. 1145 // Make no guards if trusting primitives.
1175 if (trustPrimitives) return cps; 1146 if (trustPrimitives) return cps;
1176 1147
1177 // Determine which guards are needed. 1148 // Determine which guards are needed.
1178 ChecksNeeded receiverChecks = 1149 ChecksNeeded receiverChecks =
1179 receiverGuard.getChecksNeeded(node.receiver, classWorld); 1150 receiverGuard.getChecksNeeded(node.receiver, classWorld);
1180 bool needReceiverGuard = receiverChecks != ChecksNeeded.None; 1151 bool needReceiverGuard = receiverChecks != ChecksNeeded.None;
1181 bool needArgumentGuard = 1152 bool needArgumentGuard = argumentGuard != null &&
1182 argumentGuard != null &&
1183 argumentGuard.needsCheck(node.argument(0), classWorld); 1153 argumentGuard.needsCheck(node.argument(0), classWorld);
1184 1154
1185 if (!needReceiverGuard && !needArgumentGuard) return cps; 1155 if (!needReceiverGuard && !needArgumentGuard) return cps;
1186 1156
1187 // If we only need the receiver check, emit the specialized receiver 1157 // If we only need the receiver check, emit the specialized receiver
1188 // check instruction. Examples: 1158 // check instruction. Examples:
1189 // 1159 //
1190 // if (typeof receiver !== "number") return receiver.$lt; 1160 // if (typeof receiver !== "number") return receiver.$lt;
1191 // if (typeof receiver !== "number") return receiver.$lt(); 1161 // if (typeof receiver !== "number") return receiver.$lt();
1192 // 1162 //
1193 if (!needArgumentGuard) { 1163 if (!needArgumentGuard) {
1194 Primitive condition = receiverGuard.makeCheck(cps, node.receiver); 1164 Primitive condition = receiverGuard.makeCheck(cps, node.receiver);
1195 cps.letPrim(new ReceiverCheck( 1165 cps.letPrim(new ReceiverCheck(
1196 node.receiver, 1166 node.receiver, node.selector, node.sourceInformation,
1197 node.selector,
1198 node.sourceInformation,
1199 condition: condition, 1167 condition: condition,
1200 useSelector: true, 1168 useSelector: true,
1201 isNullCheck: receiverChecks == ChecksNeeded.Null 1169 isNullCheck: receiverChecks == ChecksNeeded.Null));
1202 ));
1203 return cps; 1170 return cps;
1204 } 1171 }
1205 1172
1206 // TODO(asgerf): We should consider specialized instructions for 1173 // TODO(asgerf): We should consider specialized instructions for
1207 // argument checks and receiver+argument checks, to avoid breaking up 1174 // argument checks and receiver+argument checks, to avoid breaking up
1208 // basic blocks. 1175 // basic blocks.
1209 1176
1210 // Emit as `H.iae(x)` if only the argument check may fail. For example: 1177 // Emit as `H.iae(x)` if only the argument check may fail. For example:
1211 // 1178 //
1212 // if (typeof argument !== "number") return H.iae(argument); 1179 // if (typeof argument !== "number") return H.iae(argument);
1213 // 1180 //
1214 if (!needReceiverGuard) { 1181 if (!needReceiverGuard) {
1215 cps.ifTruthy(argumentGuard.makeCheck(cps, node.argument(0))) 1182 cps
1216 .invokeStaticThrower(helpers.throwIllegalArgumentException, 1183 .ifTruthy(argumentGuard.makeCheck(cps, node.argument(0)))
1217 [node.argument(0)]); 1184 .invokeStaticThrower(
1185 helpers.throwIllegalArgumentException, [node.argument(0)]);
1218 return cps; 1186 return cps;
1219 } 1187 }
1220 1188
1221 // Both receiver and argument check is needed. Emit as a combined check 1189 // Both receiver and argument check is needed. Emit as a combined check
1222 // using a one-shot interceptor to produce the exact error message in 1190 // using a one-shot interceptor to produce the exact error message in
1223 // the error case. For example: 1191 // the error case. For example:
1224 // 1192 //
1225 // if (typeof receiver !== "number" || typeof argument !== "number") 1193 // if (typeof receiver !== "number" || typeof argument !== "number")
1226 // return J.$lt(receiver, argument); 1194 // return J.$lt(receiver, argument);
1227 // 1195 //
1228 Continuation fail = cps.letCont(); 1196 Continuation fail = cps.letCont();
1229 cps.ifTruthy(receiverGuard.makeCheck(cps, node.receiver)) 1197 cps
1230 .invokeContinuation(fail); 1198 .ifTruthy(receiverGuard.makeCheck(cps, node.receiver))
1231 cps.ifTruthy(argumentGuard.makeCheck(cps, node.argument(0))) 1199 .invokeContinuation(fail);
1232 .invokeContinuation(fail); 1200 cps
1201 .ifTruthy(argumentGuard.makeCheck(cps, node.argument(0)))
1202 .invokeContinuation(fail);
1233 1203
1234 cps.insideContinuation(fail) 1204 cps.insideContinuation(fail)
1235 ..invokeMethod(node.receiver, node.selector, node.mask, 1205 ..invokeMethod(
1236 [node.argument(0)], 1206 node.receiver, node.selector, node.mask, [node.argument(0)],
1237 callingConvention: CallingConvention.OneShotIntercepted) 1207 callingConvention: CallingConvention.OneShotIntercepted)
1238 ..put(new Unreachable()); 1208 ..put(new Unreachable());
1239 1209
1240 return cps; 1210 return cps;
1241 } 1211 }
1242 1212
1243 /// Replaces the call with [operator], using the receiver and first argument 1213 /// Replaces the call with [operator], using the receiver and first argument
1244 /// as operands (in that order). 1214 /// as operands (in that order).
1245 /// 1215 ///
1246 /// If [guard] is given, the receiver and argument are both checked using 1216 /// If [guard] is given, the receiver and argument are both checked using
1247 /// that operator. 1217 /// that operator.
1248 CpsFragment makeBinary(BuiltinOperator operator, 1218 CpsFragment makeBinary(BuiltinOperator operator,
1249 {TypeCheckOperator guard: TypeCheckOperator.none}) { 1219 {TypeCheckOperator guard: TypeCheckOperator.none}) {
1250 CpsFragment cps = makeGuard(guard, guard); 1220 CpsFragment cps = makeGuard(guard, guard);
1251 Primitive left = guard.makeRefinement(cps, node.receiver, classWorld); 1221 Primitive left = guard.makeRefinement(cps, node.receiver, classWorld);
1252 Primitive right = 1222 Primitive right = guard.makeRefinement(cps, node.argument(0), classWorld);
1253 guard.makeRefinement(cps, node.argument(0), classWorld);
1254 Primitive result = cps.applyBuiltin(operator, [left, right]); 1223 Primitive result = cps.applyBuiltin(operator, [left, right]);
1255 result.hint = node.hint; 1224 result.hint = node.hint;
1256 node.replaceUsesWith(result); 1225 node.replaceUsesWith(result);
1257 return cps; 1226 return cps;
1258 } 1227 }
1259 1228
1260 /// Like [makeBinary] but for unary operators with the receiver as the 1229 /// Like [makeBinary] but for unary operators with the receiver as the
1261 /// argument. 1230 /// argument.
1262 CpsFragment makeUnary(BuiltinOperator operator, 1231 CpsFragment makeUnary(BuiltinOperator operator,
1263 {TypeCheckOperator guard: TypeCheckOperator.none}) { 1232 {TypeCheckOperator guard: TypeCheckOperator.none}) {
1264 CpsFragment cps = makeGuard(guard); 1233 CpsFragment cps = makeGuard(guard);
1265 Primitive argument = 1234 Primitive argument = guard.makeRefinement(cps, node.receiver, classWorld);
1266 guard.makeRefinement(cps, node.receiver, classWorld);
1267 Primitive result = cps.applyBuiltin(operator, [argument]); 1235 Primitive result = cps.applyBuiltin(operator, [argument]);
1268 result.hint = node.hint; 1236 result.hint = node.hint;
1269 node.replaceUsesWith(result); 1237 node.replaceUsesWith(result);
1270 return cps; 1238 return cps;
1271 } 1239 }
1272 1240
1273 Selector renameToOptimizedSelector(String name) { 1241 Selector renameToOptimizedSelector(String name) {
1274 return new Selector.call( 1242 return new Selector.call(
1275 new Name(name, backend.helpers.interceptorsLibrary), 1243 new Name(name, backend.helpers.interceptorsLibrary),
1276 node.selector.callStructure); 1244 node.selector.callStructure);
1277 } 1245 }
1278 1246
1279 /// Replaces the call with a call to [name] with the same inputs. 1247 /// Replaces the call with a call to [name] with the same inputs.
1280 InvokeMethod makeRenamedInvoke(String name) { 1248 InvokeMethod makeRenamedInvoke(String name) {
1281 return new InvokeMethod(node.receiver, 1249 return new InvokeMethod(node.receiver, renameToOptimizedSelector(name),
1282 renameToOptimizedSelector(name), 1250 node.mask, node.arguments.toList(),
1283 node.mask,
1284 node.arguments.toList(),
1285 sourceInformation: node.sourceInformation, 1251 sourceInformation: node.sourceInformation,
1286 callingConvention: node.callingConvention, 1252 callingConvention: node.callingConvention,
1287 interceptor: node.interceptor); 1253 interceptor: node.interceptor);
1288 } 1254 }
1289 1255
1290 TypeMask successType = 1256 TypeMask successType =
1291 typeSystem.receiverTypeFor(node.selector, node.receiver.type); 1257 typeSystem.receiverTypeFor(node.selector, node.receiver.type);
1292 1258
1293 if (node.selector.isOperator && node.argumentRefs.length == 1) { 1259 if (node.selector.isOperator && node.argumentRefs.length == 1) {
1294 Primitive leftArg = node.receiver; 1260 Primitive leftArg = node.receiver;
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
1341 return makeBinary(BuiltinOperator.NumShl, guard: checkIsNumber); 1307 return makeBinary(BuiltinOperator.NumShl, guard: checkIsNumber);
1342 } 1308 }
1343 // Try to insert a shift-right operator. JavaScript's right shift is 1309 // Try to insert a shift-right operator. JavaScript's right shift is
1344 // consistent with Dart's only for left operands in the unsigned 1310 // consistent with Dart's only for left operands in the unsigned
1345 // 32-bit range. 1311 // 32-bit range.
1346 if (opname == '>>') { 1312 if (opname == '>>') {
1347 if (lattice.isDefinitelyUint32(left, allowNull: true) && 1313 if (lattice.isDefinitelyUint32(left, allowNull: true) &&
1348 lattice.isDefinitelyIntInRange(right, min: 0, max: 31)) { 1314 lattice.isDefinitelyIntInRange(right, min: 0, max: 31)) {
1349 return makeBinary(BuiltinOperator.NumShr, guard: checkIsNumber); 1315 return makeBinary(BuiltinOperator.NumShr, guard: checkIsNumber);
1350 } else if (lattice.isDefinitelyUint(left) && 1316 } else if (lattice.isDefinitelyUint(left) &&
1351 lattice.isDefinitelyUint(right)) { 1317 lattice.isDefinitelyUint(right)) {
1352 return makeRenamedInvoke('_shrBothPositive'); 1318 return makeRenamedInvoke('_shrBothPositive');
1353 } else if (lattice.isDefinitelyUint(left) && 1319 } else if (lattice.isDefinitelyUint(left) &&
1354 lattice.isDefinitelyNum(right)) { 1320 lattice.isDefinitelyNum(right)) {
1355 return makeRenamedInvoke('_shrReceiverPositive'); 1321 return makeRenamedInvoke('_shrReceiverPositive');
1356 } else if (lattice.isDefinitelyNum(left) && 1322 } else if (lattice.isDefinitelyNum(left) &&
1357 lattice.isDefinitelyUint(right)) { 1323 lattice.isDefinitelyUint(right)) {
1358 return makeRenamedInvoke('_shrOtherPositive'); 1324 return makeRenamedInvoke('_shrOtherPositive');
1359 } 1325 }
1360 } 1326 }
1361 // Try to use remainder for '%'. Both operands must be non-negative 1327 // Try to use remainder for '%'. Both operands must be non-negative
1362 // and the divisor must be non-zero. 1328 // and the divisor must be non-zero.
1363 if (opname == '%' && 1329 if (opname == '%' &&
1364 lattice.isDefinitelyUint(left, allowNull: true) && 1330 lattice.isDefinitelyUint(left, allowNull: true) &&
1365 lattice.isDefinitelyUint(right) && 1331 lattice.isDefinitelyUint(right) &&
1366 lattice.isDefinitelyIntInRange(right, min: 1)) { 1332 lattice.isDefinitelyIntInRange(right, min: 1)) {
1367 return makeBinary(BuiltinOperator.NumRemainder, 1333 return makeBinary(BuiltinOperator.NumRemainder,
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
1409 guard: checkIsNumber); 1375 guard: checkIsNumber);
1410 } 1376 }
1411 } 1377 }
1412 } else if (name == 'codeUnitAt') { 1378 } else if (name == 'codeUnitAt') {
1413 if (node.argumentRefs.length == 1) { 1379 if (node.argumentRefs.length == 1) {
1414 Primitive index = node.argument(0); 1380 Primitive index = node.argument(0);
1415 if (lattice.isDefinitelyString(receiverValue) && 1381 if (lattice.isDefinitelyString(receiverValue) &&
1416 lattice.isDefinitelyInt(getValue(index))) { 1382 lattice.isDefinitelyInt(getValue(index))) {
1417 CpsFragment cps = new CpsFragment(node.sourceInformation); 1383 CpsFragment cps = new CpsFragment(node.sourceInformation);
1418 receiver = makeBoundsCheck(cps, receiver, index); 1384 receiver = makeBoundsCheck(cps, receiver, index);
1419 ApplyBuiltinOperator get = 1385 ApplyBuiltinOperator get = cps.applyBuiltin(
1420 cps.applyBuiltin(BuiltinOperator.CharCodeAt, 1386 BuiltinOperator.CharCodeAt, <Primitive>[receiver, index]);
1421 <Primitive>[receiver, index]);
1422 node.replaceUsesWith(get); 1387 node.replaceUsesWith(get);
1423 get.hint = node.hint; 1388 get.hint = node.hint;
1424 return cps; 1389 return cps;
1425 } 1390 }
1426 } 1391 }
1427 } 1392 }
1428 } 1393 }
1429 return null; 1394 return null;
1430 } 1395 }
1431 1396
(...skipping 19 matching lines...) Expand all
1451 // TODO(asgerf): Inlining native fields will make some tests pass for the 1416 // TODO(asgerf): Inlining native fields will make some tests pass for the
1452 // wrong reason, so for testing reasons avoid inlining them. 1417 // wrong reason, so for testing reasons avoid inlining them.
1453 if (backend.isNative(target) || backend.isJsInterop(target)) { 1418 if (backend.isNative(target) || backend.isJsInterop(target)) {
1454 return null; 1419 return null;
1455 } 1420 }
1456 if (node.selector.isGetter) { 1421 if (node.selector.isGetter) {
1457 return new GetField(node.receiver, target); 1422 return new GetField(node.receiver, target);
1458 } else if (node.selector.isSetter) { 1423 } else if (node.selector.isSetter) {
1459 if (target.isFinal) return null; 1424 if (target.isFinal) return null;
1460 assert(node.hasNoUses); 1425 assert(node.hasNoUses);
1461 return new SetField(node.receiver, 1426 return new SetField(node.receiver, target, node.argument(0));
1462 target,
1463 node.argument(0));
1464 } else if (node.selector.isCall) { 1427 } else if (node.selector.isCall) {
1465 CpsFragment cps = new CpsFragment(node.sourceInformation); 1428 CpsFragment cps = new CpsFragment(node.sourceInformation);
1466 Primitive fieldValue = cps.letPrim(new GetField(node.receiver, target)); 1429 Primitive fieldValue = cps.letPrim(new GetField(node.receiver, target));
1467 Primitive result = cps.invokeMethod( 1430 Primitive result = cps.invokeMethod(
1468 fieldValue, 1431 fieldValue,
1469 new Selector.callClosureFrom(node.selector), 1432 new Selector.callClosureFrom(node.selector),
1470 typeSystem.getFieldType(target), 1433 typeSystem.getFieldType(target),
1471 node.arguments.toList()); 1434 node.arguments.toList());
1472 node.replaceUsesWith(result); 1435 node.replaceUsesWith(result);
1473 return cps; 1436 return cps;
1474 } else { 1437 } else {
1475 return null; 1438 return null;
1476 } 1439 }
1477 } 1440 }
1478 1441
1479 /// Create a check that throws if [index] is not a valid index on [list]. 1442 /// Create a check that throws if [index] is not a valid index on [list].
1480 /// 1443 ///
1481 /// This function assumes that [index] is an integer. 1444 /// This function assumes that [index] is an integer.
1482 /// 1445 ///
1483 /// Returns a CPS fragment whose context is the branch where no error 1446 /// Returns a CPS fragment whose context is the branch where no error
1484 /// was thrown. 1447 /// was thrown.
1485 Primitive makeBoundsCheck(CpsFragment cps, 1448 Primitive makeBoundsCheck(CpsFragment cps, Primitive list, Primitive index,
1486 Primitive list, 1449 [int checkKind = BoundsCheck.BOTH_BOUNDS | BoundsCheck.INTEGER]) {
1487 Primitive index,
1488 [int checkKind = BoundsCheck.BOTH_BOUNDS | BoundsCheck.INTEGER]) {
1489 if (compiler.options.trustPrimitives) { 1450 if (compiler.options.trustPrimitives) {
1490 return cps.letPrim(new BoundsCheck.noCheck(list, cps.sourceInformation)); 1451 return cps.letPrim(new BoundsCheck.noCheck(list, cps.sourceInformation));
1491 } else { 1452 } else {
1492 GetLength length = cps.letPrim(new GetLength(list)); 1453 GetLength length = cps.letPrim(new GetLength(list));
1493 list = cps.refine(list, typeSystem.nonNullType); 1454 list = cps.refine(list, typeSystem.nonNullType);
1494 BoundsCheck check = cps.letPrim(new BoundsCheck(list, index, length, 1455 BoundsCheck check = cps.letPrim(new BoundsCheck(
1495 checkKind, cps.sourceInformation)); 1456 list, index, length, checkKind, cps.sourceInformation));
1496 if (check.hasIntegerCheck) { 1457 if (check.hasIntegerCheck) {
1497 if (typeSystem.isDefinitelyInt(index.type)) { 1458 if (typeSystem.isDefinitelyInt(index.type)) {
1498 check.checks &= ~BoundsCheck.INTEGER; 1459 check.checks &= ~BoundsCheck.INTEGER;
1499 } else { 1460 } else {
1500 cps.refine(index, typeSystem.uint32Type); 1461 cps.refine(index, typeSystem.uint32Type);
1501 } 1462 }
1502 } 1463 }
1503 return check; 1464 return check;
1504 } 1465 }
1505 } 1466 }
1506 1467
1507 /// Create a check that throws if the length of [list] is not equal to 1468 /// Create a check that throws if the length of [list] is not equal to
1508 /// [originalLength]. 1469 /// [originalLength].
1509 /// 1470 ///
1510 /// Returns a CPS fragment whose context is the branch where no error 1471 /// Returns a CPS fragment whose context is the branch where no error
1511 /// was thrown. 1472 /// was thrown.
1512 CpsFragment makeConcurrentModificationCheck(Primitive list, 1473 CpsFragment makeConcurrentModificationCheck(
1513 Primitive originalLength, 1474 Primitive list, Primitive originalLength, SourceInformation sourceInfo) {
1514 SourceInformation sourceInfo) {
1515 CpsFragment cps = new CpsFragment(sourceInfo); 1475 CpsFragment cps = new CpsFragment(sourceInfo);
1516 Primitive lengthChanged = cps.applyBuiltin( 1476 Primitive lengthChanged = cps.applyBuiltin(BuiltinOperator.StrictNeq,
1517 BuiltinOperator.StrictNeq,
1518 <Primitive>[originalLength, cps.letPrim(new GetLength(list))]); 1477 <Primitive>[originalLength, cps.letPrim(new GetLength(list))]);
1519 cps.ifTruthy(lengthChanged).invokeStaticThrower( 1478 cps.ifTruthy(lengthChanged).invokeStaticThrower(
1520 helpers.throwConcurrentModificationError, 1479 helpers.throwConcurrentModificationError, <Primitive>[list]);
1521 <Primitive>[list]);
1522 return cps; 1480 return cps;
1523 } 1481 }
1524 1482
1525 /// Tries to replace [node] with a direct `length` or index access. 1483 /// Tries to replace [node] with a direct `length` or index access.
1526 /// 1484 ///
1527 /// Returns `true` if the node was replaced. 1485 /// Returns `true` if the node was replaced.
1528 specializeIndexableAccess(InvokeMethod node) { 1486 specializeIndexableAccess(InvokeMethod node) {
1529 Primitive receiver = node.receiver; 1487 Primitive receiver = node.receiver;
1530 AbstractConstantValue receiverValue = getValue(receiver); 1488 AbstractConstantValue receiverValue = getValue(receiver);
1531 if (!typeSystem.isDefinitelyIndexable(receiverValue.type, 1489 if (!typeSystem.isDefinitelyIndexable(receiverValue.type,
1532 allowNull: true)) { 1490 allowNull: true)) {
1533 return null; 1491 return null;
1534 } 1492 }
1535 switch (node.selector.name) { 1493 switch (node.selector.name) {
1536 case 'length': 1494 case 'length':
1537 if (node.selector.isGetter) { 1495 if (node.selector.isGetter) {
1538 return new GetLength(receiver); 1496 return new GetLength(receiver);
1539 } 1497 }
1540 if (node.selector.isSetter) { 1498 if (node.selector.isSetter) {
1541 if (!typeSystem.isDefinitelyExtendableArray(receiver.type, 1499 if (!typeSystem.isDefinitelyExtendableArray(receiver.type,
1542 allowNull: true)) { 1500 allowNull: true)) {
1543 return null; 1501 return null;
1544 } 1502 }
1545 CpsFragment cps = new CpsFragment(node.sourceInformation); 1503 CpsFragment cps = new CpsFragment(node.sourceInformation);
1546 Primitive newLength = node.argument(0); 1504 Primitive newLength = node.argument(0);
1547 if (!typeSystem.isDefinitelyUint(newLength.type)) { 1505 if (!typeSystem.isDefinitelyUint(newLength.type)) {
1548 // TODO(asgerf): We could let the SetLength instruction throw for 1506 // TODO(asgerf): We could let the SetLength instruction throw for
1549 // negative right-hand sides (see length setter in js_array.dart). 1507 // negative right-hand sides (see length setter in js_array.dart).
1550 if (compiler.options.trustPrimitives) { 1508 if (compiler.options.trustPrimitives) {
1551 newLength = cps.refine(newLength, typeSystem.uint32Type); 1509 newLength = cps.refine(newLength, typeSystem.uint32Type);
1552 newLength.type = typeSystem.uint32Type; 1510 newLength.type = typeSystem.uint32Type;
1553 } else { 1511 } else {
1554 return null; 1512 return null;
1555 } 1513 }
1556 } 1514 }
1557 cps.letPrim(new ApplyBuiltinMethod( 1515 cps.letPrim(new ApplyBuiltinMethod(BuiltinMethod.SetLength, receiver,
1558 BuiltinMethod.SetLength, 1516 [newLength], node.sourceInformation));
1559 receiver,
1560 [newLength],
1561 node.sourceInformation));
1562 if (!typeSystem.isDefinitelyUint32(newLength.type)) { 1517 if (!typeSystem.isDefinitelyUint32(newLength.type)) {
1563 // If the setter succeeded, the length must have been a uint32. 1518 // If the setter succeeded, the length must have been a uint32.
1564 cps.refine(newLength, typeSystem.uint32Type); 1519 cps.refine(newLength, typeSystem.uint32Type);
1565 } 1520 }
1566 return cps; 1521 return cps;
1567 } 1522 }
1568 return null; 1523 return null;
1569 1524
1570 case '[]': 1525 case '[]':
1571 Primitive index = node.argument(0); 1526 Primitive index = node.argument(0);
1572 CpsFragment cps = new CpsFragment(node.sourceInformation); 1527 CpsFragment cps = new CpsFragment(node.sourceInformation);
1573 receiver = makeBoundsCheck(cps, receiver, index); 1528 receiver = makeBoundsCheck(cps, receiver, index);
1574 GetIndex get = cps.letPrim(new GetIndex(receiver, index)); 1529 GetIndex get = cps.letPrim(new GetIndex(receiver, index));
1575 node.replaceUsesWith(get); 1530 node.replaceUsesWith(get);
1576 // TODO(asgerf): Make replaceUsesWith set the hint? 1531 // TODO(asgerf): Make replaceUsesWith set the hint?
1577 get.hint = node.hint; 1532 get.hint = node.hint;
1578 return cps; 1533 return cps;
1579 1534
1580 case '[]=': 1535 case '[]=':
1581 if (!typeSystem.isDefinitelyMutableIndexable(receiverValue.type, 1536 if (!typeSystem.isDefinitelyMutableIndexable(receiverValue.type,
1582 allowNull: true)) { 1537 allowNull: true)) {
1583 return null; 1538 return null;
1584 } 1539 }
1585 Primitive index = node.argument(0); 1540 Primitive index = node.argument(0);
1586 Primitive value = node.argument(1); 1541 Primitive value = node.argument(1);
1587 CpsFragment cps = new CpsFragment(node.sourceInformation); 1542 CpsFragment cps = new CpsFragment(node.sourceInformation);
1588 receiver = makeBoundsCheck(cps, receiver, index); 1543 receiver = makeBoundsCheck(cps, receiver, index);
1589 cps.letPrim(new SetIndex(receiver, index, value)); 1544 cps.letPrim(new SetIndex(receiver, index, value));
1590 assert(node.hasNoUses); 1545 assert(node.hasNoUses);
1591 return cps; 1546 return cps;
1592 1547
1593 case 'isEmpty': 1548 case 'isEmpty':
1594 if (!node.selector.isGetter) return null; 1549 if (!node.selector.isGetter) return null;
1595 CpsFragment cps = new CpsFragment(node.sourceInformation); 1550 CpsFragment cps = new CpsFragment(node.sourceInformation);
1596 Primitive length = cps.letPrim(new GetLength(receiver)); 1551 Primitive length = cps.letPrim(new GetLength(receiver));
1597 Constant zero = cps.makeZero(); 1552 Constant zero = cps.makeZero();
1598 ApplyBuiltinOperator op = cps.applyBuiltin(BuiltinOperator.StrictEq, 1553 ApplyBuiltinOperator op =
1599 [length, zero]); 1554 cps.applyBuiltin(BuiltinOperator.StrictEq, [length, zero]);
1600 node.replaceUsesWith(op); 1555 node.replaceUsesWith(op);
1601 op.hint = node.hint; 1556 op.hint = node.hint;
1602 return cps; 1557 return cps;
1603 1558
1604 case 'isNotEmpty': 1559 case 'isNotEmpty':
1605 if (!node.selector.isGetter) return null; 1560 if (!node.selector.isGetter) return null;
1606 CpsFragment cps = new CpsFragment(node.sourceInformation); 1561 CpsFragment cps = new CpsFragment(node.sourceInformation);
1607 Primitive length = cps.letPrim(new GetLength(receiver)); 1562 Primitive length = cps.letPrim(new GetLength(receiver));
1608 Constant zero = cps.makeZero(); 1563 Constant zero = cps.makeZero();
1609 ApplyBuiltinOperator op = cps.applyBuiltin(BuiltinOperator.StrictNeq, 1564 ApplyBuiltinOperator op =
1610 [length, zero]); 1565 cps.applyBuiltin(BuiltinOperator.StrictNeq, [length, zero]);
1611 node.replaceUsesWith(op); 1566 node.replaceUsesWith(op);
1612 op.hint = node.hint; 1567 op.hint = node.hint;
1613 return cps; 1568 return cps;
1614 1569
1615 default: 1570 default:
1616 return null; 1571 return null;
1617 } 1572 }
1618 } 1573 }
1619 1574
1620 /// Tries to replace [node] with one or more direct array access operations. 1575 /// Tries to replace [node] with one or more direct array access operations.
(...skipping 14 matching lines...) Expand all
1635 switch (node.selector.name) { 1590 switch (node.selector.name) {
1636 case 'add': 1591 case 'add':
1637 if (!node.selector.isCall || 1592 if (!node.selector.isCall ||
1638 node.selector.positionalArgumentCount != 1 || 1593 node.selector.positionalArgumentCount != 1 ||
1639 node.selector.namedArgumentCount != 0) { 1594 node.selector.namedArgumentCount != 0) {
1640 return null; 1595 return null;
1641 } 1596 }
1642 if (!isExtendable) return null; 1597 if (!isExtendable) return null;
1643 Primitive addedItem = node.argument(0); 1598 Primitive addedItem = node.argument(0);
1644 CpsFragment cps = new CpsFragment(sourceInfo); 1599 CpsFragment cps = new CpsFragment(sourceInfo);
1645 cps.invokeBuiltin(BuiltinMethod.Push, 1600 cps.invokeBuiltin(BuiltinMethod.Push, list, <Primitive>[addedItem]);
1646 list,
1647 <Primitive>[addedItem]);
1648 if (node.hasAtLeastOneUse) { 1601 if (node.hasAtLeastOneUse) {
1649 node.replaceUsesWith(cps.makeNull()); 1602 node.replaceUsesWith(cps.makeNull());
1650 } 1603 }
1651 return cps; 1604 return cps;
1652 1605
1653 case 'removeLast': 1606 case 'removeLast':
1654 if (!node.selector.isCall || 1607 if (!node.selector.isCall || node.selector.argumentCount != 0) {
1655 node.selector.argumentCount != 0) {
1656 return null; 1608 return null;
1657 } 1609 }
1658 if (!isExtendable) return null; 1610 if (!isExtendable) return null;
1659 CpsFragment cps = new CpsFragment(sourceInfo); 1611 CpsFragment cps = new CpsFragment(sourceInfo);
1660 list = makeBoundsCheck(cps, list, cps.makeMinusOne(), 1612 list = makeBoundsCheck(
1661 BoundsCheck.EMPTINESS); 1613 cps, list, cps.makeMinusOne(), BoundsCheck.EMPTINESS);
1662 Primitive removedItem = cps.invokeBuiltin(BuiltinMethod.Pop, 1614 Primitive removedItem =
1663 list, 1615 cps.invokeBuiltin(BuiltinMethod.Pop, list, <Primitive>[]);
1664 <Primitive>[]);
1665 removedItem.hint = node.hint; 1616 removedItem.hint = node.hint;
1666 node.replaceUsesWith(removedItem); 1617 node.replaceUsesWith(removedItem);
1667 return cps; 1618 return cps;
1668 1619
1669 case 'addAll': 1620 case 'addAll':
1670 if (!node.selector.isCall || 1621 if (!node.selector.isCall || node.selector.argumentCount != 1) {
1671 node.selector.argumentCount != 1) {
1672 return null; 1622 return null;
1673 } 1623 }
1674 if (!isExtendable) return null; 1624 if (!isExtendable) return null;
1675 Primitive addedList = node.argument(0); 1625 Primitive addedList = node.argument(0);
1676 // Rewrite addAll([x1, ..., xN]) to push(x1), ..., push(xN). 1626 // Rewrite addAll([x1, ..., xN]) to push(x1), ..., push(xN).
1677 // Ensure that the list is not mutated between creation and use. 1627 // Ensure that the list is not mutated between creation and use.
1678 // We aim for the common case where this is the only use of the list, 1628 // We aim for the common case where this is the only use of the list,
1679 // which also guarantees that this list is not mutated before use. 1629 // which also guarantees that this list is not mutated before use.
1680 if (addedList is! LiteralList || !addedList.hasExactlyOneUse) { 1630 if (addedList is! LiteralList || !addedList.hasExactlyOneUse) {
1681 return null; 1631 return null;
1682 } 1632 }
1683 LiteralList addedLiteral = addedList; 1633 LiteralList addedLiteral = addedList;
1684 CpsFragment cps = new CpsFragment(sourceInfo); 1634 CpsFragment cps = new CpsFragment(sourceInfo);
1685 for (Reference value in addedLiteral.valueRefs) { 1635 for (Reference value in addedLiteral.valueRefs) {
1686 cps.invokeBuiltin(BuiltinMethod.Push, 1636 cps.invokeBuiltin(
1687 list, 1637 BuiltinMethod.Push, list, <Primitive>[value.definition]);
1688 <Primitive>[value.definition]);
1689 } 1638 }
1690 if (node.hasAtLeastOneUse) { 1639 if (node.hasAtLeastOneUse) {
1691 node.replaceUsesWith(cps.makeNull()); 1640 node.replaceUsesWith(cps.makeNull());
1692 } 1641 }
1693 return cps; 1642 return cps;
1694 1643
1695 case 'elementAt': 1644 case 'elementAt':
1696 if (!node.selector.isCall || 1645 if (!node.selector.isCall ||
1697 node.selector.positionalArgumentCount != 1 || 1646 node.selector.positionalArgumentCount != 1 ||
1698 node.selector.namedArgumentCount != 0) { 1647 node.selector.namedArgumentCount != 0) {
1699 return null; 1648 return null;
1700 } 1649 }
1701 if (listValue.isNullable) return null; 1650 if (listValue.isNullable) return null;
1702 Primitive index = node.argument(0); 1651 Primitive index = node.argument(0);
1703 if (!lattice.isDefinitelyInt(getValue(index))) return null; 1652 if (!lattice.isDefinitelyInt(getValue(index))) return null;
1704 CpsFragment cps = new CpsFragment(node.sourceInformation); 1653 CpsFragment cps = new CpsFragment(node.sourceInformation);
1705 list = makeBoundsCheck(cps, list, index); 1654 list = makeBoundsCheck(cps, list, index);
1706 GetIndex get = cps.letPrim(new GetIndex(list, index)); 1655 GetIndex get = cps.letPrim(new GetIndex(list, index));
1707 get.hint = node.hint; 1656 get.hint = node.hint;
1708 node.replaceUsesWith(get); 1657 node.replaceUsesWith(get);
1709 return cps; 1658 return cps;
1710 1659
1711 case 'forEach': 1660 case 'forEach':
1712 Element element = 1661 Element element =
1713 compiler.world.locateSingleElement(node.selector, listValue.type); 1662 compiler.world.locateSingleElement(node.selector, listValue.type);
1714 if (element == null || 1663 if (element == null || !element.isFunction || !node.selector.isCall)
1715 !element.isFunction || 1664 return null;
1716 !node.selector.isCall) return null;
1717 assert(node.selector.positionalArgumentCount == 1); 1665 assert(node.selector.positionalArgumentCount == 1);
1718 assert(node.selector.namedArgumentCount == 0); 1666 assert(node.selector.namedArgumentCount == 0);
1719 FunctionDefinition target = functionCompiler.compileToCpsIr(element); 1667 FunctionDefinition target = functionCompiler.compileToCpsIr(element);
1720 1668
1721 CpsFragment cps = new CpsFragment(node.sourceInformation); 1669 CpsFragment cps = new CpsFragment(node.sourceInformation);
1722 Primitive result = cps.inlineFunction(target, 1670 Primitive result = cps.inlineFunction(
1723 node.receiver, 1671 target, node.receiver, node.arguments.toList(),
1724 node.arguments.toList(), 1672 interceptor: node.interceptor, hint: node.hint);
1725 interceptor: node.interceptor,
1726 hint: node.hint);
1727 node.replaceUsesWith(result); 1673 node.replaceUsesWith(result);
1728 return cps; 1674 return cps;
1729 1675
1730 case 'iterator': 1676 case 'iterator':
1731 // TODO(asgerf): This should be done differently. 1677 // TODO(asgerf): This should be done differently.
1732 // The types are recomputed in a very error-prone manner. 1678 // The types are recomputed in a very error-prone manner.
1733 if (!node.selector.isGetter) return null; 1679 if (!node.selector.isGetter) return null;
1734 Primitive iterator = node; 1680 Primitive iterator = node;
1735 LetPrim iteratorBinding = node.parent; 1681 LetPrim iteratorBinding = node.parent;
1736 1682
(...skipping 21 matching lines...) Expand all
1758 InvokeMethod use = ref.parent; 1704 InvokeMethod use = ref.parent;
1759 if (use.selector == Selectors.current) { 1705 if (use.selector == Selectors.current) {
1760 // Rewrite iterator.current to a use of the 'current' variable. 1706 // Rewrite iterator.current to a use of the 'current' variable.
1761 if (use.hint != null) { 1707 if (use.hint != null) {
1762 // If 'current' was originally moved into a named variable, use 1708 // If 'current' was originally moved into a named variable, use
1763 // that variable name for the mutable variable. 1709 // that variable name for the mutable variable.
1764 current.hint = use.hint; 1710 current.hint = use.hint;
1765 } 1711 }
1766 use.replaceWith(new GetMutable(current)); 1712 use.replaceWith(new GetMutable(current));
1767 } else { 1713 } else {
1768 assert (use.selector == Selectors.moveNext); 1714 assert(use.selector == Selectors.moveNext);
1769 // Rewrite iterator.moveNext() to: 1715 // Rewrite iterator.moveNext() to:
1770 // 1716 //
1771 // if (index < list.length) { 1717 // if (index < list.length) {
1772 // current = null; 1718 // current = null;
1773 // continuation(false); 1719 // continuation(false);
1774 // } else { 1720 // } else {
1775 // current = list[index]; 1721 // current = list[index];
1776 // index = index + 1; 1722 // index = index + 1;
1777 // continuation(true); 1723 // continuation(true);
1778 // } 1724 // }
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
1811 // The check before the loop can often be eliminated because it 1757 // The check before the loop can often be eliminated because it
1812 // follows immediately after the 'iterator' call. 1758 // follows immediately after the 'iterator' call.
1813 InteriorNode parent = getEffectiveParent(use.parent); 1759 InteriorNode parent = getEffectiveParent(use.parent);
1814 if (!isFixedLength) { 1760 if (!isFixedLength) {
1815 if (parent is Continuation && parent.isRecursive) { 1761 if (parent is Continuation && parent.isRecursive) {
1816 // Check for concurrent modification before every invocation 1762 // Check for concurrent modification before every invocation
1817 // of the continuation. 1763 // of the continuation.
1818 // TODO(asgerf): Do this in a continuation so multiple 1764 // TODO(asgerf): Do this in a continuation so multiple
1819 // continues can share the same code. 1765 // continues can share the same code.
1820 for (Reference ref = parent.firstRef; 1766 for (Reference ref = parent.firstRef;
1821 ref != null; 1767 ref != null;
1822 ref = ref.next) { 1768 ref = ref.next) {
1823 Expression invocationCaller = ref.parent; 1769 Expression invocationCaller = ref.parent;
1824 if (getEffectiveParent(invocationCaller) == iteratorBinding) { 1770 if (getEffectiveParent(invocationCaller) == iteratorBinding) {
1825 // No need to check for concurrent modification immediately 1771 // No need to check for concurrent modification immediately
1826 // after the call to 'iterator'. 1772 // after the call to 'iterator'.
1827 continue; 1773 continue;
1828 } 1774 }
1829 CpsFragment check = makeConcurrentModificationCheck( 1775 CpsFragment check = makeConcurrentModificationCheck(
1830 list, originalLength, sourceInfo); 1776 list, originalLength, sourceInfo);
1831 insertBefore(invocationCaller, check); 1777 insertBefore(invocationCaller, check);
1832 } 1778 }
1833 } else { 1779 } else {
1834 cps.append(makeConcurrentModificationCheck( 1780 cps.append(makeConcurrentModificationCheck(
1835 list, originalLength, sourceInfo)); 1781 list, originalLength, sourceInfo));
1836 } 1782 }
1837 } 1783 }
1838 1784
1839 // Check if there are more elements. 1785 // Check if there are more elements.
1840 Primitive hasMore = cps.applyBuiltin( 1786 Primitive hasMore = cps.applyBuiltin(BuiltinOperator.NumLt,
1841 BuiltinOperator.NumLt,
1842 [cps.getMutable(index), cps.letPrim(new GetLength(list))]); 1787 [cps.getMutable(index), cps.letPrim(new GetLength(list))]);
1843 1788
1844 // Return false if there are no more. 1789 // Return false if there are no more.
1845 CpsFragment falseBranch = cps.ifFalsy(hasMore); 1790 CpsFragment falseBranch = cps.ifFalsy(hasMore);
1846 falseBranch 1791 falseBranch
1847 ..setMutable(current, falseBranch.makeNull()) 1792 ..setMutable(current, falseBranch.makeNull())
1848 ..invokeContinuation(moveNextCont, [falseBranch.makeFalse()]); 1793 ..invokeContinuation(moveNextCont, [falseBranch.makeFalse()]);
1849 1794
1850 // Return true if there are more element. 1795 // Return true if there are more element.
1851 current.type = typeSystem.elementTypeOfIndexable(listValue.type); 1796 current.type = typeSystem.elementTypeOfIndexable(listValue.type);
1852 cps.setMutable(current, 1797 cps.setMutable(current,
1853 cps.letPrim(new GetIndex(list, cps.getMutable(index)))); 1798 cps.letPrim(new GetIndex(list, cps.getMutable(index))));
1854 cps.setMutable(index, cps.applyBuiltin( 1799 cps.setMutable(
1855 BuiltinOperator.NumAdd, 1800 index,
1856 [cps.getMutable(index), cps.makeOne()])); 1801 cps.applyBuiltin(BuiltinOperator.NumAdd,
1802 [cps.getMutable(index), cps.makeOne()]));
1857 cps.invokeContinuation(moveNextCont, [cps.makeTrue()]); 1803 cps.invokeContinuation(moveNextCont, [cps.makeTrue()]);
1858 1804
1859 reanalyzeFragment(cps); 1805 reanalyzeFragment(cps);
1860 1806
1861 // Replace the moveNext() call. It will be visited later. 1807 // Replace the moveNext() call. It will be visited later.
1862 LetPrim let = use.parent; 1808 LetPrim let = use.parent;
1863 cps.context = moveNextCont; 1809 cps.context = moveNextCont;
1864 cps.insertBelow(let); 1810 cps.insertBelow(let);
1865 let.remove(); 1811 let.remove();
1866 use..replaceUsesWith(result)..destroy(); 1812 use
1813 ..replaceUsesWith(result)
1814 ..destroy();
1867 } 1815 }
1868 } 1816 }
1869 1817
1870 // All effective uses have been rewritten. 1818 // All effective uses have been rewritten.
1871 destroyRefinementsOfDeadPrimitive(iterator); 1819 destroyRefinementsOfDeadPrimitive(iterator);
1872 1820
1873 // Rewrite the iterator call to initializers for 'index' and 'current'. 1821 // Rewrite the iterator call to initializers for 'index' and 'current'.
1874 CpsFragment cps = new CpsFragment(); 1822 CpsFragment cps = new CpsFragment();
1875 cps.letMutable(index, cps.makeZero()); 1823 cps.letMutable(index, cps.makeZero());
1876 cps.letMutable(current, cps.makeNull()); 1824 cps.letMutable(current, cps.makeNull());
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
1920 1868
1921 // If the selector does not apply, don't bother (will throw at runtime). 1869 // If the selector does not apply, don't bother (will throw at runtime).
1922 if (!call.signatureApplies(target)) return null; 1870 if (!call.signatureApplies(target)) return null;
1923 1871
1924 // If some optional arguments are missing, give up. 1872 // If some optional arguments are missing, give up.
1925 // TODO(asgerf): Improve optimization by inserting default arguments. 1873 // TODO(asgerf): Improve optimization by inserting default arguments.
1926 if (call.argumentCount != signature.parameterCount) return null; 1874 if (call.argumentCount != signature.parameterCount) return null;
1927 1875
1928 // Replace with InvokeStatic. 1876 // Replace with InvokeStatic.
1929 // The tear-off will be cleaned up by shrinking reductions. 1877 // The tear-off will be cleaned up by shrinking reductions.
1930 return new InvokeStatic(target, 1878 return new InvokeStatic(target, new Selector.fromElement(target),
1931 new Selector.fromElement(target), 1879 node.arguments.toList(), node.sourceInformation);
1932 node.arguments.toList(),
1933 node.sourceInformation);
1934 } 1880 }
1935 if (tearOff is InvokeMethod && tearOff.selector.isGetter) { 1881 if (tearOff is InvokeMethod && tearOff.selector.isGetter) {
1936 Selector getter = tearOff.selector; 1882 Selector getter = tearOff.selector;
1937 1883
1938 // TODO(asgerf): Support torn-off intercepted methods. 1884 // TODO(asgerf): Support torn-off intercepted methods.
1939 if (isInterceptedSelector(getter)) return null; 1885 if (isInterceptedSelector(getter)) return null;
1940 1886
1941 LetPrim tearOffBinding = tearOff.parent; 1887 LetPrim tearOffBinding = tearOff.parent;
1942 1888
1943 Primitive object = tearOff.receiver; 1889 Primitive object = tearOff.receiver;
(...skipping 21 matching lines...) Expand all
1965 // therefore risk duplicating its side effects. 1911 // therefore risk duplicating its side effects.
1966 if (!isPure && tearOff.hasMultipleRefinedUses) return null; 1912 if (!isPure && tearOff.hasMultipleRefinedUses) return null;
1967 1913
1968 // If the getter call is impure, we risk reordering side effects, 1914 // If the getter call is impure, we risk reordering side effects,
1969 // unless it is immediately prior to the closure call. 1915 // unless it is immediately prior to the closure call.
1970 if (!isPure && getEffectiveParent(node.parent) != tearOffBinding) { 1916 if (!isPure && getEffectiveParent(node.parent) != tearOffBinding) {
1971 return null; 1917 return null;
1972 } 1918 }
1973 1919
1974 InvokeMethod invoke = new InvokeMethod( 1920 InvokeMethod invoke = new InvokeMethod(
1975 object, 1921 object,
1976 new Selector.call(getter.memberName, call.callStructure), 1922 new Selector.call(getter.memberName, call.callStructure),
1977 type, 1923 type,
1978 node.arguments.toList(), 1924 node.arguments.toList(),
1979 sourceInformation: node.sourceInformation); 1925 sourceInformation: node.sourceInformation);
1980 node.receiverRef.changeTo(new Parameter(null)); // Remove the tear off use . 1926 node.receiverRef
1927 .changeTo(new Parameter(null)); // Remove the tear off use.
1981 1928
1982 if (tearOff.hasNoRefinedUses) { 1929 if (tearOff.hasNoRefinedUses) {
1983 // Eliminate the getter call if it has no more uses. 1930 // Eliminate the getter call if it has no more uses.
1984 // This cannot be delegated to other optimizations because we need to 1931 // This cannot be delegated to other optimizations because we need to
1985 // avoid duplication of side effects. 1932 // avoid duplication of side effects.
1986 destroyRefinementsOfDeadPrimitive(tearOff); 1933 destroyRefinementsOfDeadPrimitive(tearOff);
1987 tearOff.destroy(); 1934 tearOff.destroy();
1988 tearOffBinding.remove(); 1935 tearOffBinding.remove();
1989 } else { 1936 } else {
1990 // There are more uses, so we cannot eliminate the getter call. This 1937 // There are more uses, so we cannot eliminate the getter call. This
(...skipping 10 matching lines...) Expand all
2001 /// Inlines a single-use closure if it leaves the closure object with only 1948 /// Inlines a single-use closure if it leaves the closure object with only
2002 /// field accesses. This is optimized later by [ScalarReplacer]. 1949 /// field accesses. This is optimized later by [ScalarReplacer].
2003 CpsFragment specializeSingleUseClosureCall(InvokeMethod node) { 1950 CpsFragment specializeSingleUseClosureCall(InvokeMethod node) {
2004 Selector call = node.selector; 1951 Selector call = node.selector;
2005 if (!call.isClosureCall) return null; 1952 if (!call.isClosureCall) return null;
2006 1953
2007 assert(!isInterceptedSelector(call)); 1954 assert(!isInterceptedSelector(call));
2008 assert(call.argumentCount == node.argumentRefs.length); 1955 assert(call.argumentCount == node.argumentRefs.length);
2009 1956
2010 Primitive receiver = node.receiver; 1957 Primitive receiver = node.receiver;
2011 if (receiver is !CreateInstance) return null; 1958 if (receiver is! CreateInstance) return null;
2012 CreateInstance createInstance = receiver; 1959 CreateInstance createInstance = receiver;
2013 if (!createInstance.hasExactlyOneUse) return null; 1960 if (!createInstance.hasExactlyOneUse) return null;
2014 1961
2015 // Inline only closures. This avoids inlining the 'call' method of a class 1962 // Inline only closures. This avoids inlining the 'call' method of a class
2016 // that has many allocation sites. 1963 // that has many allocation sites.
2017 if (createInstance.classElement is !ClosureClassElement) return null; 1964 if (createInstance.classElement is! ClosureClassElement) return null;
2018 1965
2019 ClosureClassElement closureClassElement = createInstance.classElement; 1966 ClosureClassElement closureClassElement = createInstance.classElement;
2020 Element element = closureClassElement.localLookup(Identifiers.call); 1967 Element element = closureClassElement.localLookup(Identifiers.call);
2021 1968
2022 if (element == null || !element.isFunction) return null; 1969 if (element == null || !element.isFunction) return null;
2023 FunctionElement functionElement = element; 1970 FunctionElement functionElement = element;
2024 if (functionElement.asyncMarker != AsyncMarker.SYNC) return null; 1971 if (functionElement.asyncMarker != AsyncMarker.SYNC) return null;
2025 1972
2026 if (!call.signatureApplies(functionElement)) return null; 1973 if (!call.signatureApplies(functionElement)) return null;
2027 // Inline only for exact match. 1974 // Inline only for exact match.
2028 // TODO(sra): Handle call with defaulted arguments. 1975 // TODO(sra): Handle call with defaulted arguments.
2029 Selector targetSelector = new Selector.fromElement(functionElement); 1976 Selector targetSelector = new Selector.fromElement(functionElement);
2030 if (call.callStructure != targetSelector.callStructure) return null; 1977 if (call.callStructure != targetSelector.callStructure) return null;
2031 1978
2032 // Don't inline if [target] contains try-catch or try-finally. JavaScript 1979 // Don't inline if [target] contains try-catch or try-finally. JavaScript
2033 // engines typically do poor optimization of the entire function containing 1980 // engines typically do poor optimization of the entire function containing
2034 // the 'try'. 1981 // the 'try'.
2035 if (functionElement.resolvedAst.elements.containsTryStatement) return null; 1982 if (functionElement.resolvedAst.elements.containsTryStatement) return null;
2036 1983
2037 FunctionDefinition target = 1984 FunctionDefinition target =
2038 functionCompiler.compileToCpsIr(functionElement); 1985 functionCompiler.compileToCpsIr(functionElement);
2039 1986
2040 // Accesses to closed-over values are field access primitives. We we don't 1987 // Accesses to closed-over values are field access primitives. We we don't
2041 // inline if there are other uses of 'this' since that could be an escape or 1988 // inline if there are other uses of 'this' since that could be an escape or
2042 // a recursive call. 1989 // a recursive call.
2043 for (Reference ref = target.receiverParameter.firstRef; 1990 for (Reference ref = target.receiverParameter.firstRef;
2044 ref != null; 1991 ref != null;
2045 ref = ref.next) { 1992 ref = ref.next) {
2046 Node use = ref.parent; 1993 Node use = ref.parent;
2047 if (use is GetField) continue; 1994 if (use is GetField) continue;
2048 // Closures do not currently have writable fields, but closure conversion 1995 // Closures do not currently have writable fields, but closure conversion
2049 // could esily be changed to allocate some cells in a closure object. 1996 // could esily be changed to allocate some cells in a closure object.
2050 if (use is SetField && ref == use.objectRef) continue; 1997 if (use is SetField && ref == use.objectRef) continue;
2051 return null; 1998 return null;
2052 } 1999 }
2053 2000
2054 CpsFragment cps = new CpsFragment(node.sourceInformation); 2001 CpsFragment cps = new CpsFragment(node.sourceInformation);
2055 Primitive returnValue = cps.inlineFunction(target, 2002 Primitive returnValue = cps.inlineFunction(
2056 node.receiver, 2003 target, node.receiver, node.arguments.toList(),
2057 node.arguments.toList(),
2058 hint: node.hint); 2004 hint: node.hint);
2059 node.replaceUsesWith(returnValue); 2005 node.replaceUsesWith(returnValue);
2060 return cps; 2006 return cps;
2061 } 2007 }
2062 2008
2063 visitInterceptor(Interceptor node) { 2009 visitInterceptor(Interceptor node) {
2064 // Replace the interceptor with its input if the value is not intercepted. 2010 // Replace the interceptor with its input if the value is not intercepted.
2065 // If the input might be null, we cannot do this since the interceptor 2011 // If the input might be null, we cannot do this since the interceptor
2066 // might have to return JSNull. That case is handled by visitInvokeMethod 2012 // might have to return JSNull. That case is handled by visitInvokeMethod
2067 // and visitInvokeMethodDirectly which can sometimes tolerate that null 2013 // and visitInvokeMethodDirectly which can sometimes tolerate that null
2068 // is used instead of JSNull. 2014 // is used instead of JSNull.
2069 Primitive input = node.input; 2015 Primitive input = node.input;
2070 if (!input.type.isNullable && 2016 if (!input.type.isNullable &&
2071 typeSystem.areDisjoint(input.type, typeSystem.interceptorType)) { 2017 typeSystem.areDisjoint(input.type, typeSystem.interceptorType)) {
2072 node.replaceUsesWith(input); 2018 node.replaceUsesWith(input);
2073 } 2019 }
2074 } 2020 }
2075 2021
2076 visitInvokeConstructor(InvokeConstructor node) { 2022 visitInvokeConstructor(InvokeConstructor node) {
2077 node.effects = 2023 node.effects =
2078 Effects.from(compiler.world.getSideEffectsOfElement(node.target)); 2024 Effects.from(compiler.world.getSideEffectsOfElement(node.target));
2079 } 2025 }
2080 2026
2081 visitInvokeMethodDirectly(InvokeMethodDirectly node) { 2027 visitInvokeMethodDirectly(InvokeMethodDirectly node) {
2082 Element target = node.target; 2028 Element target = node.target;
2083 if (target is ConstructorBodyElement) { 2029 if (target is ConstructorBodyElement) {
2084 ConstructorBodyElement constructorBody = target; 2030 ConstructorBodyElement constructorBody = target;
2085 target = constructorBody.constructor; 2031 target = constructorBody.constructor;
2086 } 2032 }
2087 node.effects = 2033 node.effects = Effects.from(compiler.world.getSideEffectsOfElement(target));
2088 Effects.from(compiler.world.getSideEffectsOfElement(target));
2089 TypeMask receiverType = node.receiver.type; 2034 TypeMask receiverType = node.receiver.type;
2090 if (node.callingConvention == CallingConvention.Intercepted && 2035 if (node.callingConvention == CallingConvention.Intercepted &&
2091 typeSystem.areDisjoint(receiverType, typeSystem.interceptorType)) { 2036 typeSystem.areDisjoint(receiverType, typeSystem.interceptorType)) {
2092 // Some direct calls take an interceptor because the target class is 2037 // Some direct calls take an interceptor because the target class is
2093 // mixed into a native class. If it is known at the call site that the 2038 // mixed into a native class. If it is known at the call site that the
2094 // receiver is non-intercepted, get rid of the interceptor. 2039 // receiver is non-intercepted, get rid of the interceptor.
2095 node.interceptorRef.changeTo(node.receiver); 2040 node.interceptorRef.changeTo(node.receiver);
2096 } 2041 }
2097 } 2042 }
2098 2043
2099 visitInvokeMethod(InvokeMethod node) { 2044 visitInvokeMethod(InvokeMethod node) {
2100 var specialized = 2045 var specialized = specializeOperatorCall(node) ??
2101 specializeOperatorCall(node) ??
2102 specializeFieldAccess(node) ?? 2046 specializeFieldAccess(node) ??
2103 specializeIndexableAccess(node) ?? 2047 specializeIndexableAccess(node) ??
2104 specializeArrayAccess(node) ?? 2048 specializeArrayAccess(node) ??
2105 specializeSingleUseClosureCall(node) ?? 2049 specializeSingleUseClosureCall(node) ??
2106 specializeClosureCall(node); 2050 specializeClosureCall(node);
2107 if (specialized != null) return specialized; 2051 if (specialized != null) return specialized;
2108 2052
2109 TypeMask receiverType = node.receiver.type; 2053 TypeMask receiverType = node.receiver.type;
2110 node.mask = typeSystem.intersection(node.mask, receiverType); 2054 node.mask = typeSystem.intersection(node.mask, receiverType);
2111 2055
2112 node.effects = Effects.from( 2056 node.effects = Effects.from(
2113 compiler.world.getSideEffectsOfSelector(node.selector, node.mask)); 2057 compiler.world.getSideEffectsOfSelector(node.selector, node.mask));
2114 2058
2115 bool canBeNonThrowingCallOnNull = 2059 bool canBeNonThrowingCallOnNull =
2116 selectorsOnNull.contains(node.selector) && 2060 selectorsOnNull.contains(node.selector) && receiverType.isNullable;
2117 receiverType.isNullable;
2118 2061
2119 if (node.callingConvention == CallingConvention.Intercepted && 2062 if (node.callingConvention == CallingConvention.Intercepted &&
2120 !canBeNonThrowingCallOnNull && 2063 !canBeNonThrowingCallOnNull &&
2121 typeSystem.areDisjoint(receiverType, typeSystem.interceptorType)) { 2064 typeSystem.areDisjoint(receiverType, typeSystem.interceptorType)) {
2122 // Use the Dart receiver as the JS receiver. This changes the wording of 2065 // Use the Dart receiver as the JS receiver. This changes the wording of
2123 // the error message when the receiver is null, but we accept this. 2066 // the error message when the receiver is null, but we accept this.
2124 node.interceptorRef.changeTo(node.receiver); 2067 node.interceptorRef.changeTo(node.receiver);
2125 2068
2126 // Replace the extra receiver argument with a dummy value if the 2069 // Replace the extra receiver argument with a dummy value if the
2127 // target definitely does not use it. 2070 // target definitely does not use it.
2128 if (typeSystem.targetIgnoresReceiverArgument(receiverType, 2071 if (typeSystem.targetIgnoresReceiverArgument(
2129 node.selector)) { 2072 receiverType, node.selector)) {
2130 node.makeDummyIntercepted(); 2073 node.makeDummyIntercepted();
2131 } 2074 }
2132 } 2075 }
2133 } 2076 }
2134 2077
2135 CpsFragment visitTypeCast(TypeCast node) { 2078 CpsFragment visitTypeCast(TypeCast node) {
2136 AbstractConstantValue value = getValue(node.value); 2079 AbstractConstantValue value = getValue(node.value);
2137 switch (lattice.isSubtypeOf(value, node.dartType, allowNull: true)) { 2080 switch (lattice.isSubtypeOf(value, node.dartType, allowNull: true)) {
2138 case AbstractBool.Maybe: 2081 case AbstractBool.Maybe:
2139 case AbstractBool.Nothing: 2082 case AbstractBool.Nothing:
(...skipping 13 matching lines...) Expand all
2153 2096
2154 /// Specialize calls to internal static methods. 2097 /// Specialize calls to internal static methods.
2155 specializeInternalMethodCall(InvokeStatic node) { 2098 specializeInternalMethodCall(InvokeStatic node) {
2156 if (node.target == backend.helpers.stringInterpolationHelper) { 2099 if (node.target == backend.helpers.stringInterpolationHelper) {
2157 Primitive argument = node.argument(0); 2100 Primitive argument = node.argument(0);
2158 AbstractConstantValue value = getValue(argument); 2101 AbstractConstantValue value = getValue(argument);
2159 if (lattice.isDefinitelyString(value)) { 2102 if (lattice.isDefinitelyString(value)) {
2160 node.replaceUsesWith(argument); 2103 node.replaceUsesWith(argument);
2161 return new CpsFragment(); 2104 return new CpsFragment();
2162 } else if (typeSystem.isDefinitelySelfInterceptor(value.type)) { 2105 } else if (typeSystem.isDefinitelySelfInterceptor(value.type)) {
2163 TypeMask toStringReturn = typeSystem.getInvokeReturnType( 2106 TypeMask toStringReturn =
2164 Selectors.toString_, value.type); 2107 typeSystem.getInvokeReturnType(Selectors.toString_, value.type);
2165 if (typeSystem.isDefinitelyString(toStringReturn)) { 2108 if (typeSystem.isDefinitelyString(toStringReturn)) {
2166 CpsFragment cps = new CpsFragment(node.sourceInformation); 2109 CpsFragment cps = new CpsFragment(node.sourceInformation);
2167 Primitive invoke = cps.invokeMethod( 2110 Primitive invoke = cps.invokeMethod(
2168 argument, 2111 argument, Selectors.toString_, value.type, [],
2169 Selectors.toString_,
2170 value.type,
2171 [],
2172 callingConvention: CallingConvention.DummyIntercepted); 2112 callingConvention: CallingConvention.DummyIntercepted);
2173 node.replaceUsesWith(invoke); 2113 node.replaceUsesWith(invoke);
2174 return cps; 2114 return cps;
2175 } 2115 }
2176 } 2116 }
2177 } else if (node.target == compiler.identicalFunction) { 2117 } else if (node.target == compiler.identicalFunction) {
2178 if (node.argumentRefs.length == 2) { 2118 if (node.argumentRefs.length == 2) {
2179 return new ApplyBuiltinOperator(BuiltinOperator.Identical, 2119 return new ApplyBuiltinOperator(BuiltinOperator.Identical,
2180 [node.argument(0), node.argument(1)], 2120 [node.argument(0), node.argument(1)], node.sourceInformation);
2181 node.sourceInformation);
2182 } 2121 }
2183 } 2122 }
2184 return null; 2123 return null;
2185 } 2124 }
2186 2125
2187 visitInvokeStatic(InvokeStatic node) { 2126 visitInvokeStatic(InvokeStatic node) {
2188 node.effects = Effects.from( 2127 node.effects =
2189 compiler.world.getSideEffectsOfElement(node.target)); 2128 Effects.from(compiler.world.getSideEffectsOfElement(node.target));
2190 return specializeInternalMethodCall(node); 2129 return specializeInternalMethodCall(node);
2191 } 2130 }
2192 2131
2193 AbstractConstantValue getValue(Variable node) { 2132 AbstractConstantValue getValue(Variable node) {
2194 assert(node.type != null); 2133 assert(node.type != null);
2195 ConstantValue constant = values[node]; 2134 ConstantValue constant = values[node];
2196 if (constant != null) { 2135 if (constant != null) {
2197 return new AbstractConstantValue.constantValue(constant, node.type); 2136 return new AbstractConstantValue.constantValue(constant, node.type);
2198 } 2137 }
2199 return new AbstractConstantValue.nonConstant(node.type); 2138 return new AbstractConstantValue.nonConstant(node.type);
2200 } 2139 }
2201 2140
2202
2203 /*************************** PRIMITIVES **************************/ 2141 /*************************** PRIMITIVES **************************/
2204 // 2142 //
2205 // The visit method for a primitive may return one of the following: 2143 // The visit method for a primitive may return one of the following:
2206 // - Primitive: 2144 // - Primitive:
2207 // The visited primitive will be replaced by the returned primitive. 2145 // The visited primitive will be replaced by the returned primitive.
2208 // The type of the primitive will be recomputed. 2146 // The type of the primitive will be recomputed.
2209 // - CpsFragment: 2147 // - CpsFragment:
2210 // The primitive binding will be destroyed and replaced by the given 2148 // The primitive binding will be destroyed and replaced by the given
2211 // code fragment. All types in the fragment will be recomputed. 2149 // code fragment. All types in the fragment will be recomputed.
2212 // - Null: 2150 // - Null:
(...skipping 10 matching lines...) Expand all
2223 // Concatenate consecutive constants. 2161 // Concatenate consecutive constants.
2224 bool argumentsWereRemoved = false; 2162 bool argumentsWereRemoved = false;
2225 int i = 0; 2163 int i = 0;
2226 while (i < node.argumentRefs.length - 1) { 2164 while (i < node.argumentRefs.length - 1) {
2227 int startOfSequence = i; 2165 int startOfSequence = i;
2228 AbstractConstantValue firstValue = getValue(node.argument(i++)); 2166 AbstractConstantValue firstValue = getValue(node.argument(i++));
2229 if (!firstValue.isConstant) continue; 2167 if (!firstValue.isConstant) continue;
2230 AbstractConstantValue secondValue = getValue(node.argument(i++)); 2168 AbstractConstantValue secondValue = getValue(node.argument(i++));
2231 if (!secondValue.isConstant) continue; 2169 if (!secondValue.isConstant) continue;
2232 2170
2233 ast.DartString string = 2171 ast.DartString string = new ast.ConsDartString(
2234 new ast.ConsDartString(getString(firstValue), 2172 getString(firstValue), getString(secondValue));
2235 getString(secondValue));
2236 2173
2237 // We found a sequence of at least two constants. 2174 // We found a sequence of at least two constants.
2238 // Look for the end of the sequence. 2175 // Look for the end of the sequence.
2239 while (i < node.argumentRefs.length) { 2176 while (i < node.argumentRefs.length) {
2240 AbstractConstantValue value = getValue(node.argument(i)); 2177 AbstractConstantValue value = getValue(node.argument(i));
2241 if (!value.isConstant) break; 2178 if (!value.isConstant) break;
2242 string = new ast.ConsDartString(string, getString(value)); 2179 string = new ast.ConsDartString(string, getString(value));
2243 ++i; 2180 ++i;
2244 } 2181 }
2245 Constant prim = 2182 Constant prim =
(...skipping 27 matching lines...) Expand all
2273 BuiltinOperator newOperator; 2210 BuiltinOperator newOperator;
2274 if (left.isNullConstant || right.isNullConstant) { 2211 if (left.isNullConstant || right.isNullConstant) {
2275 // Use `==` for comparing against null, so JS undefined and JS null 2212 // Use `==` for comparing against null, so JS undefined and JS null
2276 // are considered equal. 2213 // are considered equal.
2277 newOperator = BuiltinOperator.LooseEq; 2214 newOperator = BuiltinOperator.LooseEq;
2278 } else if (!left.isNullable || !right.isNullable) { 2215 } else if (!left.isNullable || !right.isNullable) {
2279 // If at most one operand can be Dart null, we can use `===`. 2216 // If at most one operand can be Dart null, we can use `===`.
2280 // This is not safe when we might compare JS null and JS undefined. 2217 // This is not safe when we might compare JS null and JS undefined.
2281 newOperator = BuiltinOperator.StrictEq; 2218 newOperator = BuiltinOperator.StrictEq;
2282 } else if (lattice.isDefinitelyNum(left, allowNull: true) && 2219 } else if (lattice.isDefinitelyNum(left, allowNull: true) &&
2283 lattice.isDefinitelyNum(right, allowNull: true)) { 2220 lattice.isDefinitelyNum(right, allowNull: true)) {
2284 // If both operands can be null, but otherwise are of the same type, 2221 // If both operands can be null, but otherwise are of the same type,
2285 // we can use `==` for comparison. 2222 // we can use `==` for comparison.
2286 // This is not safe e.g. for comparing strings against numbers. 2223 // This is not safe e.g. for comparing strings against numbers.
2287 newOperator = BuiltinOperator.LooseEq; 2224 newOperator = BuiltinOperator.LooseEq;
2288 } else if (lattice.isDefinitelyString(left, allowNull: true) && 2225 } else if (lattice.isDefinitelyString(left, allowNull: true) &&
2289 lattice.isDefinitelyString(right, allowNull: true)) { 2226 lattice.isDefinitelyString(right, allowNull: true)) {
2290 newOperator = BuiltinOperator.LooseEq; 2227 newOperator = BuiltinOperator.LooseEq;
2291 } else if (lattice.isDefinitelyBool(left, allowNull: true) && 2228 } else if (lattice.isDefinitelyBool(left, allowNull: true) &&
2292 lattice.isDefinitelyBool(right, allowNull: true)) { 2229 lattice.isDefinitelyBool(right, allowNull: true)) {
2293 newOperator = BuiltinOperator.LooseEq; 2230 newOperator = BuiltinOperator.LooseEq;
2294 } 2231 }
2295 if (newOperator != null) { 2232 if (newOperator != null) {
2296 return new ApplyBuiltinOperator(newOperator, 2233 return new ApplyBuiltinOperator(
2297 node.arguments.toList(), 2234 newOperator, node.arguments.toList(), node.sourceInformation);
2298 node.sourceInformation);
2299 } 2235 }
2300 break; 2236 break;
2301 2237
2302 case BuiltinOperator.StrictEq: 2238 case BuiltinOperator.StrictEq:
2303 case BuiltinOperator.LooseEq: 2239 case BuiltinOperator.LooseEq:
2304 case BuiltinOperator.StrictNeq: 2240 case BuiltinOperator.StrictNeq:
2305 case BuiltinOperator.LooseNeq: 2241 case BuiltinOperator.LooseNeq:
2306 bool negated = 2242 bool negated = node.operator == BuiltinOperator.StrictNeq ||
2307 node.operator == BuiltinOperator.StrictNeq ||
2308 node.operator == BuiltinOperator.LooseNeq; 2243 node.operator == BuiltinOperator.LooseNeq;
2309 for (int firstIndex in [0, 1]) { 2244 for (int firstIndex in [0, 1]) {
2310 int secondIndex = 1 - firstIndex; 2245 int secondIndex = 1 - firstIndex;
2311 Primitive firstArg = node.argument(firstIndex); 2246 Primitive firstArg = node.argument(firstIndex);
2312 Primitive secondArg = node.argument(secondIndex); 2247 Primitive secondArg = node.argument(secondIndex);
2313 AbstractConstantValue first = getValue(firstArg); 2248 AbstractConstantValue first = getValue(firstArg);
2314 if (!lattice.isDefinitelyBool(first)) continue; 2249 if (!lattice.isDefinitelyBool(first)) continue;
2315 AbstractConstantValue second = getValue(secondArg); 2250 AbstractConstantValue second = getValue(secondArg);
2316 if (!second.isConstant || !second.constant.isBool) continue; 2251 if (!second.isConstant || !second.constant.isBool) continue;
2317 bool isTrueConstant = second.constant.isTrue; 2252 bool isTrueConstant = second.constant.isTrue;
2318 if (isTrueConstant == !negated) { 2253 if (isTrueConstant == !negated) {
2319 // (x === true) ==> x 2254 // (x === true) ==> x
2320 // (x !== false) ==> x 2255 // (x !== false) ==> x
2321 node.replaceUsesWith(firstArg); 2256 node.replaceUsesWith(firstArg);
2322 return null; 2257 return null;
2323 } else { 2258 } else {
2324 // (x === false) ==> !x 2259 // (x === false) ==> !x
2325 // (x !== true) ==> !x 2260 // (x !== true) ==> !x
2326 return new ApplyBuiltinOperator( 2261 return new ApplyBuiltinOperator(
2327 BuiltinOperator.IsFalsy, 2262 BuiltinOperator.IsFalsy, [firstArg], node.sourceInformation);
2328 [firstArg],
2329 node.sourceInformation);
2330 } 2263 }
2331 } 2264 }
2332 break; 2265 break;
2333 2266
2334 default: 2267 default:
2335 } 2268 }
2336 return null; 2269 return null;
2337 } 2270 }
2338 2271
2339 void visitApplyBuiltinMethod(ApplyBuiltinMethod node) { 2272 void visitApplyBuiltinMethod(ApplyBuiltinMethod node) {}
2340 }
2341 2273
2342 visitTypeTest(TypeTest node) { 2274 visitTypeTest(TypeTest node) {
2343 Primitive prim = node.value; 2275 Primitive prim = node.value;
2344 2276
2345 Primitive unaryBuiltinOperator(BuiltinOperator operator) => 2277 Primitive unaryBuiltinOperator(BuiltinOperator operator) =>
2346 new ApplyBuiltinOperator( 2278 new ApplyBuiltinOperator(
2347 operator, <Primitive>[prim], node.sourceInformation); 2279 operator, <Primitive>[prim], node.sourceInformation);
2348 2280
2349 AbstractConstantValue value = getValue(prim); 2281 AbstractConstantValue value = getValue(prim);
2350 types.DartType dartType = node.dartType; 2282 types.DartType dartType = node.dartType;
2351 2283
2352 if (!(dartType.isInterfaceType && dartType.isRaw)) { 2284 if (!(dartType.isInterfaceType && dartType.isRaw)) {
2353 // TODO(23685): Efficient function arity check. 2285 // TODO(23685): Efficient function arity check.
2354 // TODO(sra): Pass interceptor to runtime subtype functions. 2286 // TODO(sra): Pass interceptor to runtime subtype functions.
2355 return null; 2287 return null;
2356 } 2288 }
2357 2289
2358 if (dartType == dartTypes.coreTypes.intType) { 2290 if (dartType == dartTypes.coreTypes.intType) {
2359 // Compile as typeof x === 'number' && Math.floor(x) === x 2291 // Compile as typeof x === 'number' && Math.floor(x) === x
2360 if (lattice.isDefinitelyNum(value, allowNull: true)) { 2292 if (lattice.isDefinitelyNum(value, allowNull: true)) {
2361 // If value is null or a number, we can skip the typeof test. 2293 // If value is null or a number, we can skip the typeof test.
2362 return new ApplyBuiltinOperator( 2294 return new ApplyBuiltinOperator(BuiltinOperator.IsFloor,
2363 BuiltinOperator.IsFloor, 2295 <Primitive>[prim, prim], node.sourceInformation);
2364 <Primitive>[prim, prim],
2365 node.sourceInformation);
2366 } 2296 }
2367 if (lattice.isDefinitelyNotNonIntegerDouble(value)) { 2297 if (lattice.isDefinitelyNotNonIntegerDouble(value)) {
2368 // If the value cannot be a non-integer double, but might not be a 2298 // If the value cannot be a non-integer double, but might not be a
2369 // number at all, we can skip the Math.floor test. 2299 // number at all, we can skip the Math.floor test.
2370 return unaryBuiltinOperator(BuiltinOperator.IsNumber); 2300 return unaryBuiltinOperator(BuiltinOperator.IsNumber);
2371 } 2301 }
2372 return new ApplyBuiltinOperator( 2302 return new ApplyBuiltinOperator(BuiltinOperator.IsInteger,
2373 BuiltinOperator.IsInteger, 2303 <Primitive>[prim, prim, prim], node.sourceInformation);
2374 <Primitive>[prim, prim, prim],
2375 node.sourceInformation);
2376 } 2304 }
2377 if (node.dartType == dartTypes.coreTypes.numType || 2305 if (node.dartType == dartTypes.coreTypes.numType ||
2378 node.dartType == dartTypes.coreTypes.doubleType) { 2306 node.dartType == dartTypes.coreTypes.doubleType) {
2379 return new ApplyBuiltinOperator( 2307 return new ApplyBuiltinOperator(
2380 BuiltinOperator.IsNumber, 2308 BuiltinOperator.IsNumber, <Primitive>[prim], node.sourceInformation);
2381 <Primitive>[prim],
2382 node.sourceInformation);
2383 } 2309 }
2384 2310
2385 AbstractBool isNullableSubtype = 2311 AbstractBool isNullableSubtype =
2386 lattice.isSubtypeOf(value, node.dartType, allowNull: true); 2312 lattice.isSubtypeOf(value, node.dartType, allowNull: true);
2387 AbstractBool isNullPassingTest = 2313 AbstractBool isNullPassingTest =
2388 lattice.isSubtypeOf(lattice.nullValue, node.dartType, allowNull: false); 2314 lattice.isSubtypeOf(lattice.nullValue, node.dartType, allowNull: false);
2389 if (isNullableSubtype == AbstractBool.True && 2315 if (isNullableSubtype == AbstractBool.True &&
2390 isNullPassingTest == AbstractBool.False) { 2316 isNullPassingTest == AbstractBool.False) {
2391 // Null is the only value not satisfying the type test. 2317 // Null is the only value not satisfying the type test.
2392 // Replace the type test with a null-check. 2318 // Replace the type test with a null-check.
2393 // This has lower priority than the 'typeof'-based tests because 2319 // This has lower priority than the 'typeof'-based tests because
2394 // 'typeof' expressions might give the VM some more useful information. 2320 // 'typeof' expressions might give the VM some more useful information.
2395 Primitive nullConst = makeConstantPrimitive(new NullConstantValue()); 2321 Primitive nullConst = makeConstantPrimitive(new NullConstantValue());
2396 new LetPrim(nullConst).insertAbove(node.parent); 2322 new LetPrim(nullConst).insertAbove(node.parent);
2397 return new ApplyBuiltinOperator( 2323 return new ApplyBuiltinOperator(BuiltinOperator.LooseNeq,
2398 BuiltinOperator.LooseNeq, 2324 <Primitive>[prim, nullConst], node.sourceInformation);
2399 <Primitive>[prim, nullConst],
2400 node.sourceInformation);
2401 } 2325 }
2402 2326
2403 if (dartType.element == functionCompiler.glue.jsFixedArrayClass) { 2327 if (dartType.element == functionCompiler.glue.jsFixedArrayClass) {
2404 // TODO(sra): Check input is restricted to JSArray. 2328 // TODO(sra): Check input is restricted to JSArray.
2405 return unaryBuiltinOperator(BuiltinOperator.IsFixedLengthJSArray); 2329 return unaryBuiltinOperator(BuiltinOperator.IsFixedLengthJSArray);
2406 } 2330 }
2407 2331
2408 if (dartType.element == functionCompiler.glue.jsExtendableArrayClass) { 2332 if (dartType.element == functionCompiler.glue.jsExtendableArrayClass) {
2409 // TODO(sra): Check input is restricted to JSArray. 2333 // TODO(sra): Check input is restricted to JSArray.
2410 return unaryBuiltinOperator(BuiltinOperator.IsExtendableJSArray); 2334 return unaryBuiltinOperator(BuiltinOperator.IsExtendableJSArray);
(...skipping 30 matching lines...) Expand all
2441 return null; 2365 return null;
2442 } 2366 }
2443 2367
2444 visitBoundsCheck(BoundsCheck node) { 2368 visitBoundsCheck(BoundsCheck node) {
2445 // Eliminate bounds checks using constant folding. 2369 // Eliminate bounds checks using constant folding.
2446 // The [BoundsChecker] pass does not try to eliminate checks that could be 2370 // The [BoundsChecker] pass does not try to eliminate checks that could be
2447 // eliminated by constant folding. 2371 // eliminated by constant folding.
2448 if (node.hasNoChecks) return; 2372 if (node.hasNoChecks) return;
2449 Primitive indexPrim = node.index; 2373 Primitive indexPrim = node.index;
2450 int index = lattice.intValue(getValue(indexPrim)); 2374 int index = lattice.intValue(getValue(indexPrim));
2451 int length = node.lengthRef == null 2375 int length =
2452 ? null 2376 node.lengthRef == null ? null : lattice.intValue(getValue(node.length));
2453 : lattice.intValue(getValue(node.length));
2454 if (index != null && length != null && index < length) { 2377 if (index != null && length != null && index < length) {
2455 node.checks &= ~BoundsCheck.UPPER_BOUND; 2378 node.checks &= ~BoundsCheck.UPPER_BOUND;
2456 } 2379 }
2457 if (index != null && index >= 0) { 2380 if (index != null && index >= 0) {
2458 node.checks &= ~BoundsCheck.LOWER_BOUND; 2381 node.checks &= ~BoundsCheck.LOWER_BOUND;
2459 } 2382 }
2460 if (length != null && length > 0) { 2383 if (length != null && length > 0) {
2461 node.checks &= ~BoundsCheck.EMPTINESS; 2384 node.checks &= ~BoundsCheck.EMPTINESS;
2462 } 2385 }
2463 if (typeSystem.isDefinitelyInt(indexPrim.type)) { 2386 if (typeSystem.isDefinitelyInt(indexPrim.type)) {
2464 node.checks &= ~BoundsCheck.INTEGER; 2387 node.checks &= ~BoundsCheck.INTEGER;
2465 } 2388 }
2466 if (!node.lengthUsedInCheck && node.lengthRef != null) { 2389 if (!node.lengthUsedInCheck && node.lengthRef != null) {
2467 node..lengthRef.unlink()..lengthRef = null; 2390 node
2391 ..lengthRef.unlink()
2392 ..lengthRef = null;
2468 } 2393 }
2469 if (node.checks == BoundsCheck.NONE) { 2394 if (node.checks == BoundsCheck.NONE) {
2470 // We can't remove the bounds check node because it may still be used to 2395 // We can't remove the bounds check node because it may still be used to
2471 // restrict code motion. But the index is no longer needed. 2396 // restrict code motion. But the index is no longer needed.
2472 // TODO(asgerf): Since this was eliminated by constant folding, it should 2397 // TODO(asgerf): Since this was eliminated by constant folding, it should
2473 // be safe to remove because any path-sensitive information we relied 2398 // be safe to remove because any path-sensitive information we relied
2474 // upon to do this are expressed by other refinement nodes that also 2399 // upon to do this are expressed by other refinement nodes that also
2475 // restrict code motion. However, if we want to run this pass after 2400 // restrict code motion. However, if we want to run this pass after
2476 // [BoundsChecker] that would not be safe any more, so for now we 2401 // [BoundsChecker] that would not be safe any more, so for now we
2477 // keep the node for forward compatibilty. 2402 // keep the node for forward compatibilty.
2478 node..indexRef.unlink()..indexRef = null; 2403 node
2404 ..indexRef.unlink()
2405 ..indexRef = null;
2479 } 2406 }
2480 } 2407 }
2481 2408
2482 visitReceiverCheck(ReceiverCheck node) { 2409 visitReceiverCheck(ReceiverCheck node) {
2483 Primitive input = node.value; 2410 Primitive input = node.value;
2484 if (!input.type.isNullable && 2411 if (!input.type.isNullable &&
2485 (node.isNullCheck || 2412 (node.isNullCheck ||
2486 !input.type.needsNoSuchMethodHandling(node.selector, classWorld))) { 2413 !input.type.needsNoSuchMethodHandling(node.selector, classWorld))) {
2487 node.replaceUsesWith(input); 2414 node.replaceUsesWith(input);
2488 return new CpsFragment(); 2415 return new CpsFragment();
2489 } 2416 }
2490 return null; 2417 return null;
2491 } 2418 }
2492 2419
2493 visitGetLength(GetLength node) { 2420 visitGetLength(GetLength node) {
2494 node.isFinal = typeSystem.isDefinitelyFixedLengthIndexable( 2421 node.isFinal = typeSystem.isDefinitelyFixedLengthIndexable(node.object.type,
2495 node.object.type, allowNull: true); 2422 allowNull: true);
2496 } 2423 }
2497 2424
2498 visitReadTypeVariable(ReadTypeVariable node) { 2425 visitReadTypeVariable(ReadTypeVariable node) {
2499 // Pattern match on 2426 // Pattern match on
2500 // 2427 //
2501 // ReadTypeVariable(var, CreateInstance(..., TypeExpression(arguments))) 2428 // ReadTypeVariable(var, CreateInstance(..., TypeExpression(arguments)))
2502 // 2429 //
2503 // and extract the argument that corresponds to the type variable. This is a 2430 // and extract the argument that corresponds to the type variable. This is a
2504 // shrinking reduction. 2431 // shrinking reduction.
2505 // 2432 //
(...skipping 26 matching lines...) Expand all
2532 } 2459 }
2533 return null; 2460 return null;
2534 } 2461 }
2535 2462
2536 bool isNullConstant(Primitive prim) => prim is Constant && prim.value.isNull; 2463 bool isNullConstant(Primitive prim) => prim is Constant && prim.value.isNull;
2537 2464
2538 visitCreateInstance(CreateInstance node) { 2465 visitCreateInstance(CreateInstance node) {
2539 Primitive typeInformation = node.typeInformation; 2466 Primitive typeInformation = node.typeInformation;
2540 if (typeInformation is TypeExpression && 2467 if (typeInformation is TypeExpression &&
2541 typeInformation.arguments.every(isNullConstant)) { 2468 typeInformation.arguments.every(isNullConstant)) {
2542 node..typeInformationRef.unlink()..typeInformationRef = null; 2469 node
2470 ..typeInformationRef.unlink()
2471 ..typeInformationRef = null;
2543 } 2472 }
2544 } 2473 }
2545 } 2474 }
2546 2475
2547 /** 2476 /**
2548 * Runs an analysis pass on the given function definition in order to detect 2477 * Runs an analysis pass on the given function definition in order to detect
2549 * const-ness as well as reachability, both of which are used in the subsequent 2478 * const-ness as well as reachability, both of which are used in the subsequent
2550 * transformation pass. 2479 * transformation pass.
2551 */ 2480 */
2552 class TypePropagationVisitor implements Visitor { 2481 class TypePropagationVisitor implements Visitor {
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
2584 } 2513 }
2585 2514
2586 AbstractConstantValue constantValue(ConstantValue constant, [TypeMask type]) { 2515 AbstractConstantValue constantValue(ConstantValue constant, [TypeMask type]) {
2587 return lattice.constant(constant, type); 2516 return lattice.constant(constant, type);
2588 } 2517 }
2589 2518
2590 // Stores the current lattice value for primitives and mutable variables. 2519 // Stores the current lattice value for primitives and mutable variables.
2591 // Access through [getValue] and [setValue]. 2520 // Access through [getValue] and [setValue].
2592 final Map<Variable, ConstantValue> values; 2521 final Map<Variable, ConstantValue> values;
2593 2522
2594 TypePropagationVisitor(this.lattice, 2523 TypePropagationVisitor(this.lattice, this.values, this.internalError);
2595 this.values,
2596 this.internalError);
2597 2524
2598 void analyze(FunctionDefinition root, bool recomputeAll) { 2525 void analyze(FunctionDefinition root, bool recomputeAll) {
2599 reachableContinuations.clear(); 2526 reachableContinuations.clear();
2600 if (recomputeAll) { 2527 if (recomputeAll) {
2601 new ResetAnalysisInfo(reachableContinuations, values).visit(root); 2528 new ResetAnalysisInfo(reachableContinuations, values).visit(root);
2602 } 2529 }
2603 2530
2604 // Initially, only the root node is reachable. 2531 // Initially, only the root node is reachable.
2605 push(root); 2532 push(root);
2606 2533
(...skipping 16 matching lines...) Expand all
2623 // Process all usages of a changed definition. 2550 // Process all usages of a changed definition.
2624 Definition def = defWorklist.removeLast(); 2551 Definition def = defWorklist.removeLast();
2625 2552
2626 // Visit all uses of this definition. This might add new entries to 2553 // Visit all uses of this definition. This might add new entries to
2627 // [nodeWorklist], for example by visiting a newly-constant usage within 2554 // [nodeWorklist], for example by visiting a newly-constant usage within
2628 // a branch node. 2555 // a branch node.
2629 for (Reference ref = def.firstRef; ref != null; ref = ref.next) { 2556 for (Reference ref = def.firstRef; ref != null; ref = ref.next) {
2630 visit(ref.parent); 2557 visit(ref.parent);
2631 } 2558 }
2632 } else { 2559 } else {
2633 break; // Both worklists empty. 2560 break; // Both worklists empty.
2634 } 2561 }
2635 } 2562 }
2636 } 2563 }
2637 2564
2638 /// Adds [node] to the worklist. 2565 /// Adds [node] to the worklist.
2639 void push(Node node) { 2566 void push(Node node) {
2640 nodeWorklist.add(node); 2567 nodeWorklist.add(node);
2641 } 2568 }
2642 2569
2643 /// If the passed node is not yet reachable, mark it reachable and add it 2570 /// If the passed node is not yet reachable, mark it reachable and add it
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
2677 assert(newValue.kind >= oldValue.kind); 2604 assert(newValue.kind >= oldValue.kind);
2678 2605
2679 values[node] = newValue.isConstant ? newValue.constant : null; 2606 values[node] = newValue.isConstant ? newValue.constant : null;
2680 defWorklist.add(node); 2607 defWorklist.add(node);
2681 } 2608 }
2682 2609
2683 /// Sets the type of the given primitive. 2610 /// Sets the type of the given primitive.
2684 /// 2611 ///
2685 /// If [updateValue] is a constant and [canReplace] is true, the primitive 2612 /// If [updateValue] is a constant and [canReplace] is true, the primitive
2686 /// is also marked as safe for elimination, so it can be constant-folded. 2613 /// is also marked as safe for elimination, so it can be constant-folded.
2687 void setResult(UnsafePrimitive prim, 2614 void setResult(UnsafePrimitive prim, AbstractConstantValue updateValue,
2688 AbstractConstantValue updateValue, 2615 {bool canReplace: false}) {
2689 {bool canReplace: false}) {
2690 // TODO(asgerf): Separate constant folding from side effect analysis. 2616 // TODO(asgerf): Separate constant folding from side effect analysis.
2691 setValue(prim, updateValue); 2617 setValue(prim, updateValue);
2692 prim.isSafeForElimination = canReplace && updateValue.isConstant; 2618 prim.isSafeForElimination = canReplace && updateValue.isConstant;
2693 } 2619 }
2694 2620
2695 bool isInterceptedSelector(Selector selector) { 2621 bool isInterceptedSelector(Selector selector) {
2696 return backend.isInterceptedSelector(selector); 2622 return backend.isInterceptedSelector(selector);
2697 } 2623 }
2698 2624
2699 // -------------------------- Visitor overrides ------------------------------ 2625 // -------------------------- Visitor overrides ------------------------------
2700 void visit(Node node) { node.accept(this); } 2626 void visit(Node node) {
2627 node.accept(this);
2628 }
2701 2629
2702 void visitFunctionDefinition(FunctionDefinition node) { 2630 void visitFunctionDefinition(FunctionDefinition node) {
2703 if (node.interceptorParameter != null) { 2631 if (node.interceptorParameter != null) {
2704 setValue(node.interceptorParameter, nonConstant(typeSystem.nonNullType)); 2632 setValue(node.interceptorParameter, nonConstant(typeSystem.nonNullType));
2705 } 2633 }
2706 // If the abstract value of the function parameters is Nothing, use the 2634 // If the abstract value of the function parameters is Nothing, use the
2707 // inferred parameter type. Otherwise (e.g., when inlining) do not 2635 // inferred parameter type. Otherwise (e.g., when inlining) do not
2708 // change the abstract value. 2636 // change the abstract value.
2709 if (node.receiverParameter != null && 2637 if (node.receiverParameter != null &&
2710 getValue(node.receiverParameter).isNothing) { 2638 getValue(node.receiverParameter).isNothing) {
2711 setValue(node.receiverParameter, 2639 setValue(node.receiverParameter,
2712 nonConstant(typeSystem.getReceiverType(node.element))); 2640 nonConstant(typeSystem.getReceiverType(node.element)));
2713 } 2641 }
2714 bool hasParameterWithoutValue = false; 2642 bool hasParameterWithoutValue = false;
2715 for (Parameter param in node.parameters) { 2643 for (Parameter param in node.parameters) {
2716 if (getValue(param).isNothing) { 2644 if (getValue(param).isNothing) {
2717 TypeMask type = param.hint is ParameterElement 2645 TypeMask type = param.hint is ParameterElement
2718 ? typeSystem.getParameterType(param.hint) 2646 ? typeSystem.getParameterType(param.hint)
2719 : typeSystem.dynamicType; 2647 : typeSystem.dynamicType;
2720 setValue(param, lattice.fromMask(type)); 2648 setValue(param, lattice.fromMask(type));
2721 if (type.isEmpty) hasParameterWithoutValue = true; 2649 if (type.isEmpty) hasParameterWithoutValue = true;
2722 } 2650 }
2723 } 2651 }
2724 if (!hasParameterWithoutValue) { // Don't analyze unreachable code. 2652 if (!hasParameterWithoutValue) {
2653 // Don't analyze unreachable code.
2725 push(node.body); 2654 push(node.body);
2726 } 2655 }
2727 } 2656 }
2728 2657
2729 void visitLetPrim(LetPrim node) { 2658 void visitLetPrim(LetPrim node) {
2730 visit(node.primitive); // No reason to delay visits to primitives. 2659 visit(node.primitive); // No reason to delay visits to primitives.
2731 push(node.body); 2660 push(node.body);
2732 } 2661 }
2733 2662
2734 void visitLetCont(LetCont node) { 2663 void visitLetCont(LetCont node) {
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
2841 AbstractConstantValue right = getValue(node.argument(0)); 2770 AbstractConstantValue right = getValue(node.argument(0));
2842 BinaryOperator operator = BinaryOperator.parse(opname); 2771 BinaryOperator operator = BinaryOperator.parse(opname);
2843 AbstractConstantValue result = 2772 AbstractConstantValue result =
2844 lattice.binaryOp(operator, receiver, right); 2773 lattice.binaryOp(operator, receiver, right);
2845 return finish(result, canReplace: !receiver.isNullable); 2774 return finish(result, canReplace: !receiver.isNullable);
2846 } 2775 }
2847 return finish(null); 2776 return finish(null);
2848 } 2777 }
2849 2778
2850 void visitApplyBuiltinOperator(ApplyBuiltinOperator node) { 2779 void visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
2851
2852 void unaryOp( 2780 void unaryOp(
2853 AbstractConstantValue operation(AbstractConstantValue argument), 2781 AbstractConstantValue operation(AbstractConstantValue argument),
2854 TypeMask defaultType) { 2782 TypeMask defaultType) {
2855 AbstractConstantValue value = getValue(node.argument(0)); 2783 AbstractConstantValue value = getValue(node.argument(0));
2856 setValue(node, operation(value) ?? nonConstant(defaultType)); 2784 setValue(node, operation(value) ?? nonConstant(defaultType));
2857 } 2785 }
2858 2786
2859 void binaryOp( 2787 void binaryOp(
2860 AbstractConstantValue operation(AbstractConstantValue left, 2788 AbstractConstantValue operation(
2861 AbstractConstantValue right), 2789 AbstractConstantValue left, AbstractConstantValue right),
2862 TypeMask defaultType) { 2790 TypeMask defaultType) {
2863 AbstractConstantValue left = getValue(node.argument(0)); 2791 AbstractConstantValue left = getValue(node.argument(0));
2864 AbstractConstantValue right = getValue(node.argument(1)); 2792 AbstractConstantValue right = getValue(node.argument(1));
2865 setValue(node, operation(left, right) ?? nonConstant(defaultType)); 2793 setValue(node, operation(left, right) ?? nonConstant(defaultType));
2866 } 2794 }
2867 2795
2868 void binaryNumOp( 2796 void binaryNumOp(
2869 AbstractConstantValue operation(AbstractConstantValue left, 2797 AbstractConstantValue operation(
2870 AbstractConstantValue right)) { 2798 AbstractConstantValue left, AbstractConstantValue right)) {
2871 binaryOp(operation, typeSystem.numType); 2799 binaryOp(operation, typeSystem.numType);
2872 } 2800 }
2873 2801
2874 void binaryUint32Op( 2802 void binaryUint32Op(
2875 AbstractConstantValue operation(AbstractConstantValue left, 2803 AbstractConstantValue operation(
2876 AbstractConstantValue right)) { 2804 AbstractConstantValue left, AbstractConstantValue right)) {
2877 binaryOp(operation, typeSystem.uint32Type); 2805 binaryOp(operation, typeSystem.uint32Type);
2878 } 2806 }
2879 2807
2880 void binaryBoolOp( 2808 void binaryBoolOp(
2881 AbstractConstantValue operation(AbstractConstantValue left, 2809 AbstractConstantValue operation(
2882 AbstractConstantValue right)) { 2810 AbstractConstantValue left, AbstractConstantValue right)) {
2883 binaryOp(operation, typeSystem.boolType); 2811 binaryOp(operation, typeSystem.boolType);
2884 } 2812 }
2885 2813
2886 switch (node.operator) { 2814 switch (node.operator) {
2887 case BuiltinOperator.StringConcatenate: 2815 case BuiltinOperator.StringConcatenate:
2888 ast.DartString stringValue = const ast.LiteralDartString(''); 2816 ast.DartString stringValue = const ast.LiteralDartString('');
2889 for (Reference<Primitive> arg in node.argumentRefs) { 2817 for (Reference<Primitive> arg in node.argumentRefs) {
2890 AbstractConstantValue value = getValue(arg.definition); 2818 AbstractConstantValue value = getValue(arg.definition);
2891 if (value.isNothing) { 2819 if (value.isNothing) {
2892 setValue(node, lattice.nothing); 2820 setValue(node, lattice.nothing);
2893 return; // And come back later 2821 return; // And come back later
2894 } else if (value.isConstant && 2822 } else if (value.isConstant &&
2895 value.constant.isString && 2823 value.constant.isString &&
2896 stringValue != null) { 2824 stringValue != null) {
2897 StringConstantValue constant = value.constant; 2825 StringConstantValue constant = value.constant;
2898 stringValue = 2826 stringValue =
2899 new ast.ConsDartString(stringValue, constant.primitiveValue); 2827 new ast.ConsDartString(stringValue, constant.primitiveValue);
2900 } else { 2828 } else {
2901 stringValue = null; 2829 stringValue = null;
2902 break; 2830 break;
2903 } 2831 }
2904 } 2832 }
2905 if (stringValue == null) { 2833 if (stringValue == null) {
2906 setValue(node, nonConstant(typeSystem.stringType)); 2834 setValue(node, nonConstant(typeSystem.stringType));
2907 } else { 2835 } else {
2908 setValue(node, constantValue(new StringConstantValue(stringValue))); 2836 setValue(node, constantValue(new StringConstantValue(stringValue)));
2909 } 2837 }
2910 break; 2838 break;
2911 2839
2912 case BuiltinOperator.CharCodeAt: 2840 case BuiltinOperator.CharCodeAt:
2913 binaryOp(lattice.codeUnitAtSpecial, typeSystem.uint31Type); 2841 binaryOp(lattice.codeUnitAtSpecial, typeSystem.uint31Type);
2914 break; 2842 break;
2915 2843
2916 case BuiltinOperator.Identical: 2844 case BuiltinOperator.Identical:
2917 case BuiltinOperator.StrictEq: 2845 case BuiltinOperator.StrictEq:
2918 case BuiltinOperator.StrictNeq: 2846 case BuiltinOperator.StrictNeq:
2919 case BuiltinOperator.LooseEq: 2847 case BuiltinOperator.LooseEq:
2920 case BuiltinOperator.LooseNeq: 2848 case BuiltinOperator.LooseNeq:
2921 bool negated = 2849 bool negated = node.operator == BuiltinOperator.StrictNeq ||
2922 node.operator == BuiltinOperator.StrictNeq ||
2923 node.operator == BuiltinOperator.LooseNeq; 2850 node.operator == BuiltinOperator.LooseNeq;
2924 AbstractConstantValue left = getValue(node.argument(0)); 2851 AbstractConstantValue left = getValue(node.argument(0));
2925 AbstractConstantValue right = getValue(node.argument(1)); 2852 AbstractConstantValue right = getValue(node.argument(1));
2926 if (left.isNothing || right.isNothing) { 2853 if (left.isNothing || right.isNothing) {
2927 setValue(node, lattice.nothing); 2854 setValue(node, lattice.nothing);
2928 return; 2855 return;
2929 } 2856 }
2930 if (left.isConstant && right.isConstant) { 2857 if (left.isConstant && right.isConstant) {
2931 ConstantValue equal = lattice.constantSystem.identity.fold( 2858 ConstantValue equal = lattice.constantSystem.identity
2932 left.constant, right.constant); 2859 .fold(left.constant, right.constant);
2933 if (equal != null && equal.isBool) { 2860 if (equal != null && equal.isBool) {
2934 ConstantValue result = 2861 ConstantValue result =
2935 new BoolConstantValue(equal.isTrue == !negated); 2862 new BoolConstantValue(equal.isTrue == !negated);
2936 setValue(node, constantValue(result, typeSystem.boolType)); 2863 setValue(node, constantValue(result, typeSystem.boolType));
2937 return; 2864 return;
2938 } 2865 }
2939 } 2866 }
2940 if (typeSystem.areDisjoint(left.type, right.type)) { 2867 if (typeSystem.areDisjoint(left.type, right.type)) {
2941 ConstantValue result = new BoolConstantValue(negated); 2868 ConstantValue result = new BoolConstantValue(negated);
2942 setValue(node, constantValue(result, typeSystem.boolType)); 2869 setValue(node, constantValue(result, typeSystem.boolType));
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
3031 case BuiltinOperator.IsUnmodifiableJSArray: 2958 case BuiltinOperator.IsUnmodifiableJSArray:
3032 case BuiltinOperator.IsModifiableJSArray: 2959 case BuiltinOperator.IsModifiableJSArray:
3033 setValue(node, nonConstant(typeSystem.boolType)); 2960 setValue(node, nonConstant(typeSystem.boolType));
3034 break; 2961 break;
3035 } 2962 }
3036 } 2963 }
3037 2964
3038 void visitApplyBuiltinMethod(ApplyBuiltinMethod node) { 2965 void visitApplyBuiltinMethod(ApplyBuiltinMethod node) {
3039 AbstractConstantValue receiver = getValue(node.receiver); 2966 AbstractConstantValue receiver = getValue(node.receiver);
3040 if (node.method == BuiltinMethod.Pop) { 2967 if (node.method == BuiltinMethod.Pop) {
3041 setValue(node, nonConstant( 2968 setValue(
3042 typeSystem.elementTypeOfIndexable(receiver.type))); 2969 node, nonConstant(typeSystem.elementTypeOfIndexable(receiver.type)));
3043 } else { 2970 } else {
3044 setValue(node, nonConstant()); 2971 setValue(node, nonConstant());
3045 } 2972 }
3046 } 2973 }
3047 2974
3048 void visitInvokeMethodDirectly(InvokeMethodDirectly node) { 2975 void visitInvokeMethodDirectly(InvokeMethodDirectly node) {
3049 if (node.isConstructorBodyCall) { 2976 if (node.isConstructorBodyCall) {
3050 setResult(node, lattice.nullValue); 2977 setResult(node, lattice.nullValue);
3051 } else if (node.isTearOff) { 2978 } else if (node.isTearOff) {
3052 setResult(node, nonConstant(typeSystem.functionType)); 2979 setResult(node, nonConstant(typeSystem.functionType));
3053 } else { 2980 } else {
3054 setResult(node, nonConstant(typeSystem.getReturnType(node.target))); 2981 setResult(node, nonConstant(typeSystem.getReturnType(node.target)));
3055 } 2982 }
3056 } 2983 }
3057 2984
3058 void visitInvokeConstructor(InvokeConstructor node) { 2985 void visitInvokeConstructor(InvokeConstructor node) {
3059 if (node.allocationSiteType != null) { 2986 if (node.allocationSiteType != null) {
3060 setResult(node, nonConstant(node.allocationSiteType)); 2987 setResult(node, nonConstant(node.allocationSiteType));
3061 } else { 2988 } else {
3062 setResult(node, nonConstant(typeSystem.getReturnType(node.target))); 2989 setResult(node, nonConstant(typeSystem.getReturnType(node.target)));
3063 } 2990 }
3064 } 2991 }
3065 2992
3066 void visitThrow(Throw node) { 2993 void visitThrow(Throw node) {}
3067 }
3068 2994
3069 void visitRethrow(Rethrow node) { 2995 void visitRethrow(Rethrow node) {}
3070 }
3071 2996
3072 void visitUnreachable(Unreachable node) { 2997 void visitUnreachable(Unreachable node) {}
3073 }
3074 2998
3075 void visitBranch(Branch node) { 2999 void visitBranch(Branch node) {
3076 AbstractConstantValue conditionCell = getValue(node.condition); 3000 AbstractConstantValue conditionCell = getValue(node.condition);
3077 AbstractBool boolifiedValue = node.isStrictCheck 3001 AbstractBool boolifiedValue = node.isStrictCheck
3078 ? lattice.strictBoolify(conditionCell) 3002 ? lattice.strictBoolify(conditionCell)
3079 : lattice.boolify(conditionCell); 3003 : lattice.boolify(conditionCell);
3080 switch (boolifiedValue) { 3004 switch (boolifiedValue) {
3081 case AbstractBool.Nothing: 3005 case AbstractBool.Nothing:
3082 break; 3006 break;
3083 case AbstractBool.True: 3007 case AbstractBool.True:
(...skipping 17 matching lines...) Expand all
3101 // TODO(sra): We could see if we can find the value in the interceptor 3025 // TODO(sra): We could see if we can find the value in the interceptor
3102 // expression. It would probably have no benefit - we only see 3026 // expression. It would probably have no benefit - we only see
3103 // TypeTestViaFlag after rewriting TypeTest and the rewrite of TypeTest 3027 // TypeTestViaFlag after rewriting TypeTest and the rewrite of TypeTest
3104 // would already have done the interesting optimizations. 3028 // would already have done the interesting optimizations.
3105 setValue(node, nonConstant(typeSystem.boolType)); 3029 setValue(node, nonConstant(typeSystem.boolType));
3106 } 3030 }
3107 3031
3108 void handleTypeTest( 3032 void handleTypeTest(
3109 Primitive node, AbstractConstantValue input, types.DartType dartType) { 3033 Primitive node, AbstractConstantValue input, types.DartType dartType) {
3110 TypeMask boolType = typeSystem.boolType; 3034 TypeMask boolType = typeSystem.boolType;
3111 switch(lattice.isSubtypeOf(input, dartType, allowNull: false)) { 3035 switch (lattice.isSubtypeOf(input, dartType, allowNull: false)) {
3112 case AbstractBool.Nothing: 3036 case AbstractBool.Nothing:
3113 break; // And come back later. 3037 break; // And come back later.
3114 3038
3115 case AbstractBool.True: 3039 case AbstractBool.True:
3116 setValue(node, constantValue(new TrueConstantValue(), boolType)); 3040 setValue(node, constantValue(new TrueConstantValue(), boolType));
3117 break; 3041 break;
3118 3042
3119 case AbstractBool.False: 3043 case AbstractBool.False:
3120 setValue(node, constantValue(new FalseConstantValue(), boolType)); 3044 setValue(node, constantValue(new FalseConstantValue(), boolType));
3121 break; 3045 break;
(...skipping 15 matching lines...) Expand all
3137 setValue(node, input); 3061 setValue(node, input);
3138 break; 3062 break;
3139 3063
3140 case AbstractBool.False: 3064 case AbstractBool.False:
3141 setValue(node, lattice.nothing); // Cast fails. 3065 setValue(node, lattice.nothing); // Cast fails.
3142 break; 3066 break;
3143 3067
3144 case AbstractBool.Maybe: 3068 case AbstractBool.Maybe:
3145 // Narrow type of output to those that survive the cast. 3069 // Narrow type of output to those that survive the cast.
3146 TypeMask type = input.type.intersection( 3070 TypeMask type = input.type.intersection(
3147 typeSystem.subtypesOf(node.dartType).nullable(), 3071 typeSystem.subtypesOf(node.dartType).nullable(), classWorld);
3148 classWorld);
3149 setValue(node, nonConstant(type)); 3072 setValue(node, nonConstant(type));
3150 break; 3073 break;
3151 } 3074 }
3152 } 3075 }
3153 3076
3154 void visitSetMutable(SetMutable node) { 3077 void visitSetMutable(SetMutable node) {
3155 setValue(node.variable, getValue(node.value)); 3078 setValue(node.variable, getValue(node.value));
3156 } 3079 }
3157 3080
3158 void visitLiteralList(LiteralList node) { 3081 void visitLiteralList(LiteralList node) {
(...skipping 11 matching lines...) Expand all
3170 setValue(node, nonConstant(typeSystem.getTypeOf(value))); 3093 setValue(node, nonConstant(typeSystem.getTypeOf(value)));
3171 } else { 3094 } else {
3172 setValue(node, constantValue(value, typeSystem.getTypeOf(value))); 3095 setValue(node, constantValue(value, typeSystem.getTypeOf(value)));
3173 } 3096 }
3174 } 3097 }
3175 3098
3176 void visitGetMutable(GetMutable node) { 3099 void visitGetMutable(GetMutable node) {
3177 setValue(node, getValue(node.variable)); 3100 setValue(node, getValue(node.variable));
3178 } 3101 }
3179 3102
3180 void visitMutableVariable(MutableVariable node) { 3103 void visitMutableVariable(MutableVariable node) {}
3181 }
3182 3104
3183 void visitParameter(Parameter node) { 3105 void visitParameter(Parameter node) {}
3184 }
3185 3106
3186 void visitContinuation(Continuation node) { 3107 void visitContinuation(Continuation node) {
3187 node.parameters.forEach(visit); 3108 node.parameters.forEach(visit);
3188 3109
3189 if (node.body != null) { 3110 if (node.body != null) {
3190 push(node.body); 3111 push(node.body);
3191 } 3112 }
3192 } 3113 }
3193 3114
3194 void visitGetStatic(GetStatic node) { 3115 void visitGetStatic(GetStatic node) {
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
3270 3191
3271 void visitCreateInvocationMirror(CreateInvocationMirror node) { 3192 void visitCreateInvocationMirror(CreateInvocationMirror node) {
3272 // TODO(asgerf): Expose [Invocation] type. 3193 // TODO(asgerf): Expose [Invocation] type.
3273 setValue(node, nonConstant(typeSystem.nonNullType)); 3194 setValue(node, nonConstant(typeSystem.nonNullType));
3274 } 3195 }
3275 3196
3276 @override 3197 @override
3277 void visitForeignCode(ForeignCode node) { 3198 void visitForeignCode(ForeignCode node) {
3278 bool firstArgumentIsNullable = false; 3199 bool firstArgumentIsNullable = false;
3279 if (node.argumentRefs.length > 0) { 3200 if (node.argumentRefs.length > 0) {
3280 AbstractConstantValue first = getValue(node.argumentRefs.first.definition) ; 3201 AbstractConstantValue first =
3202 getValue(node.argumentRefs.first.definition);
3281 if (first.isNothing) { 3203 if (first.isNothing) {
3282 setValue(node, nothing); 3204 setValue(node, nothing);
3283 return; 3205 return;
3284 } 3206 }
3285 firstArgumentIsNullable = first.isNullable; 3207 firstArgumentIsNullable = first.isNullable;
3286 } 3208 }
3287 setValue(node, nonConstant(node.storedType)); 3209 setValue(node, nonConstant(node.storedType));
3288 node.isSafeForElimination = 3210 node.isSafeForElimination =
3289 !node.nativeBehavior.sideEffects.hasSideEffects() && 3211 !node.nativeBehavior.sideEffects.hasSideEffects() &&
3290 (!node.nativeBehavior.throwBehavior.canThrow || 3212 (!node.nativeBehavior.throwBehavior.canThrow ||
3291 (!firstArgumentIsNullable && 3213 (!firstArgumentIsNullable &&
3292 node.nativeBehavior.throwBehavior.isOnlyNullNSMGuard)); 3214 node.nativeBehavior.throwBehavior.isOnlyNullNSMGuard));
3293 } 3215 }
3294 3216
3295 @override 3217 @override
3296 void visitGetLength(GetLength node) { 3218 void visitGetLength(GetLength node) {
3297 AbstractConstantValue input = getValue(node.object); 3219 AbstractConstantValue input = getValue(node.object);
3298 node.objectIsNotNull = input.isDefinitelyNotNull; 3220 node.objectIsNotNull = input.isDefinitelyNotNull;
3299 AbstractConstantValue length = lattice.lengthSpecial(input); 3221 AbstractConstantValue length = lattice.lengthSpecial(input);
3300 if (length != null) { 3222 if (length != null) {
3301 // TODO(asgerf): Constant-folding the length might degrade the VM's 3223 // TODO(asgerf): Constant-folding the length might degrade the VM's
3302 // own bounds-check elimination? 3224 // own bounds-check elimination?
3303 setValue(node, length); 3225 setValue(node, length);
3304 } else { 3226 } else {
3305 setValue(node, nonConstant(typeSystem.uint32Type)); 3227 setValue(node, nonConstant(typeSystem.uint32Type));
3306 } 3228 }
3307 } 3229 }
3308 3230
3309 @override 3231 @override
3310 void visitGetIndex(GetIndex node) { 3232 void visitGetIndex(GetIndex node) {
3311 AbstractConstantValue object = getValue(node.object); 3233 AbstractConstantValue object = getValue(node.object);
3312 if (object.isNothing || object.isNullConstant) { 3234 if (object.isNothing || object.isNullConstant) {
3313 setValue(node, nothing); 3235 setValue(node, nothing);
3314 } else { 3236 } else {
3315 node.objectIsNotNull = object.isDefinitelyNotNull; 3237 node.objectIsNotNull = object.isDefinitelyNotNull;
3316 setValue(node, nonConstant(typeSystem.elementTypeOfIndexable(object.type)) ); 3238 setValue(
3239 node, nonConstant(typeSystem.elementTypeOfIndexable(object.type)));
3317 } 3240 }
3318 } 3241 }
3319 3242
3320 @override 3243 @override
3321 void visitSetIndex(SetIndex node) {} 3244 void visitSetIndex(SetIndex node) {}
3322 3245
3323 @override 3246 @override
3324 void visitAwait(Await node) { 3247 void visitAwait(Await node) {
3325 setResult(node, nonConstant()); 3248 setResult(node, nonConstant());
3326 } 3249 }
3327 3250
3328 @override 3251 @override
3329 visitYield(Yield node) { 3252 visitYield(Yield node) {
3330 setValue(node, nonConstant()); 3253 setValue(node, nonConstant());
3331 } 3254 }
3332 3255
3333 @override 3256 @override
3334 void visitRefinement(Refinement node) { 3257 void visitRefinement(Refinement node) {
3335 setValue(node, lattice.intersectWithType( 3258 setValue(
3336 getValue(node.value.definition), 3259 node,
3337 node.refineType)); 3260 lattice.intersectWithType(
3261 getValue(node.value.definition), node.refineType));
3338 } 3262 }
3339 3263
3340 @override 3264 @override
3341 void visitBoundsCheck(BoundsCheck node) { 3265 void visitBoundsCheck(BoundsCheck node) {
3342 setValue(node, getValue(node.object)); 3266 setValue(node, getValue(node.object));
3343 } 3267 }
3344 3268
3345 @override 3269 @override
3346 void visitReceiverCheck(ReceiverCheck node) { 3270 void visitReceiverCheck(ReceiverCheck node) {
3347 AbstractConstantValue value = getValue(node.value); 3271 AbstractConstantValue value = getValue(node.value);
(...skipping 14 matching lines...) Expand all
3362 /// Represents the abstract value of a primitive value at some point in the 3286 /// Represents the abstract value of a primitive value at some point in the
3363 /// program. Abstract values of all kinds have a type [T]. 3287 /// program. Abstract values of all kinds have a type [T].
3364 /// 3288 ///
3365 /// The different kinds of abstract values represents the knowledge about the 3289 /// The different kinds of abstract values represents the knowledge about the
3366 /// constness of the value: 3290 /// constness of the value:
3367 /// NOTHING: cannot have any value 3291 /// NOTHING: cannot have any value
3368 /// CONSTANT: is a constant. The value is stored in the [constant] field, 3292 /// CONSTANT: is a constant. The value is stored in the [constant] field,
3369 /// and the type of the constant is in the [type] field. 3293 /// and the type of the constant is in the [type] field.
3370 /// NONCONST: not a constant, but [type] may hold some information. 3294 /// NONCONST: not a constant, but [type] may hold some information.
3371 class AbstractConstantValue { 3295 class AbstractConstantValue {
3372 static const int NOTHING = 0; 3296 static const int NOTHING = 0;
3373 static const int CONSTANT = 1; 3297 static const int CONSTANT = 1;
3374 static const int NONCONST = 2; 3298 static const int NONCONST = 2;
3375 3299
3376 final int kind; 3300 final int kind;
3377 final ConstantValue constant; 3301 final ConstantValue constant;
3378 final TypeMask type; 3302 final TypeMask type;
3379 3303
3380 AbstractConstantValue._internal(this.kind, this.constant, this.type) { 3304 AbstractConstantValue._internal(this.kind, this.constant, this.type) {
3381 assert(kind != CONSTANT || constant != null); 3305 assert(kind != CONSTANT || constant != null);
3382 assert(constant is! SyntheticConstantValue); 3306 assert(constant is! SyntheticConstantValue);
3383 } 3307 }
3384 3308
3385 AbstractConstantValue.nothing() 3309 AbstractConstantValue.nothing()
3386 : this._internal(NOTHING, null, new TypeMask.nonNullEmpty()); 3310 : this._internal(NOTHING, null, new TypeMask.nonNullEmpty());
3387 3311
3388 AbstractConstantValue.constantValue(ConstantValue constant, TypeMask type) 3312 AbstractConstantValue.constantValue(ConstantValue constant, TypeMask type)
3389 : this._internal(CONSTANT, constant, type); 3313 : this._internal(CONSTANT, constant, type);
3390 3314
3391 factory AbstractConstantValue.nonConstant(TypeMask type) { 3315 factory AbstractConstantValue.nonConstant(TypeMask type) {
3392 if (type.isEmpty) { 3316 if (type.isEmpty) {
3393 return new AbstractConstantValue.nothing(); 3317 return new AbstractConstantValue.nothing();
3394 } else if (type.isNull) { 3318 } else if (type.isNull) {
3395 return new AbstractConstantValue.constantValue( 3319 return new AbstractConstantValue.constantValue(
3396 new NullConstantValue(), type); 3320 new NullConstantValue(), type);
3397 } else { 3321 } else {
3398 return new AbstractConstantValue._internal(NONCONST, null, type); 3322 return new AbstractConstantValue._internal(NONCONST, null, type);
3399 } 3323 }
3400 } 3324 }
3401 3325
3402 bool get isNothing => (kind == NOTHING); 3326 bool get isNothing => (kind == NOTHING);
3403 bool get isConstant => (kind == CONSTANT); 3327 bool get isConstant => (kind == CONSTANT);
3404 bool get isNonConst => (kind == NONCONST); 3328 bool get isNonConst => (kind == NONCONST);
3405 bool get isNullConstant => kind == CONSTANT && constant.isNull; 3329 bool get isNullConstant => kind == CONSTANT && constant.isNull;
3406 bool get isTrueConstant => kind == CONSTANT && constant.isTrue; 3330 bool get isTrueConstant => kind == CONSTANT && constant.isTrue;
3407 bool get isFalseConstant => kind == CONSTANT && constant.isFalse; 3331 bool get isFalseConstant => kind == CONSTANT && constant.isFalse;
3408 bool get isZeroConstant => kind == CONSTANT && constant.isZero; 3332 bool get isZeroConstant => kind == CONSTANT && constant.isZero;
3409 bool get isZeroOrNegativeConstant { 3333 bool get isZeroOrNegativeConstant {
3410 if (kind != CONSTANT || !constant.isNum) return false; 3334 if (kind != CONSTANT || !constant.isNum) return false;
3411 PrimitiveConstantValue value = constant; 3335 PrimitiveConstantValue value = constant;
3412 return value.primitiveValue <= 0; 3336 return value.primitiveValue <= 0;
3413 } 3337 }
3338
3414 bool get isNegativeConstant { 3339 bool get isNegativeConstant {
3415 if (kind != CONSTANT || !constant.isNum) return false; 3340 if (kind != CONSTANT || !constant.isNum) return false;
3416 PrimitiveConstantValue value = constant; 3341 PrimitiveConstantValue value = constant;
3417 return value.primitiveValue < 0; 3342 return value.primitiveValue < 0;
3418 } 3343 }
3419 3344
3420 bool get isNullable => kind != NOTHING && type.isNullable; 3345 bool get isNullable => kind != NOTHING && type.isNullable;
3421 bool get isDefinitelyNotNull => kind == NOTHING || !type.isNullable; 3346 bool get isDefinitelyNotNull => kind == NOTHING || !type.isNullable;
3422 3347
3423 int get hashCode { 3348 int get hashCode {
3424 int hash = kind * 31 + constant.hashCode * 59 + type.hashCode * 67; 3349 int hash = kind * 31 + constant.hashCode * 59 + type.hashCode * 67;
3425 return hash & 0x3fffffff; 3350 return hash & 0x3fffffff;
3426 } 3351 }
3427 3352
3428 bool operator ==(AbstractConstantValue that) { 3353 bool operator ==(AbstractConstantValue that) {
3429 return that.kind == this.kind && 3354 return that.kind == this.kind &&
3430 that.constant == this.constant && 3355 that.constant == this.constant &&
3431 that.type == this.type; 3356 that.type == this.type;
3432 } 3357 }
3433 3358
3434 String toString() { 3359 String toString() {
3435 switch (kind) { 3360 switch (kind) {
3436 case NOTHING: return "Nothing"; 3361 case NOTHING:
3437 case CONSTANT: return "Constant: ${constant.unparse()}: $type"; 3362 return "Nothing";
3438 case NONCONST: return "Non-constant: $type"; 3363 case CONSTANT:
3439 default: assert(false); 3364 return "Constant: ${constant.unparse()}: $type";
3365 case NONCONST:
3366 return "Non-constant: $type";
3367 default:
3368 assert(false);
3440 } 3369 }
3441 return null; 3370 return null;
3442 } 3371 }
3443 } 3372 }
3444 3373
3445 /// Suggested name for a synthesized loop index. 3374 /// Suggested name for a synthesized loop index.
3446 class LoopIndexEntity extends Entity { 3375 class LoopIndexEntity extends Entity {
3447 String get name => 'i'; 3376 String get name => 'i';
3448 } 3377 }
3449 3378
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
3566 } 3495 }
3567 3496
3568 Primitive makeCheck(CpsFragment cps, Primitive value) { 3497 Primitive makeCheck(CpsFragment cps, Primitive value) {
3569 return cps.applyBuiltin(negatedOperator, [value]); 3498 return cps.applyBuiltin(negatedOperator, [value]);
3570 } 3499 }
3571 3500
3572 Primitive makeRefinement(CpsFragment cps, Primitive value, World world) { 3501 Primitive makeRefinement(CpsFragment cps, Primitive value, World world) {
3573 return cps.refine(value, new TypeMask.nonNullSubclass(classElement, world)); 3502 return cps.refine(value, new TypeMask.nonNullSubclass(classElement, world));
3574 } 3503 }
3575 } 3504 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/cps_ir/type_mask_system.dart ('k') | pkg/compiler/lib/src/cps_ir/update_refinements.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698