OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library dart2js.constant_system.dart; | 5 library dart2js.constant_system.dart; |
6 | 6 |
7 import 'compiler.dart' show | 7 import 'compiler.dart' show Compiler; |
8 Compiler; | |
9 import 'constants/constant_system.dart'; | 8 import 'constants/constant_system.dart'; |
10 import 'constants/values.dart'; | 9 import 'constants/values.dart'; |
11 import 'dart_types.dart'; | 10 import 'dart_types.dart'; |
12 import 'tree/tree.dart' show | 11 import 'tree/tree.dart' show DartString; |
13 DartString; | |
14 | 12 |
15 const DART_CONSTANT_SYSTEM = const DartConstantSystem(); | 13 const DART_CONSTANT_SYSTEM = const DartConstantSystem(); |
16 | 14 |
17 class BitNotOperation implements UnaryOperation { | 15 class BitNotOperation implements UnaryOperation { |
18 final String name = '~'; | 16 final String name = '~'; |
19 const BitNotOperation(); | 17 const BitNotOperation(); |
20 ConstantValue fold(ConstantValue constant) { | 18 ConstantValue fold(ConstantValue constant) { |
21 if (constant.isInt) { | 19 if (constant.isInt) { |
22 IntConstantValue intConstant = constant; | 20 IntConstantValue intConstant = constant; |
23 return DART_CONSTANT_SYSTEM.createInt(~intConstant.primitiveValue); | 21 return DART_CONSTANT_SYSTEM.createInt(~intConstant.primitiveValue); |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
70 } | 68 } |
71 return null; | 69 return null; |
72 } | 70 } |
73 | 71 |
74 int foldInts(int left, int right); | 72 int foldInts(int left, int right); |
75 } | 73 } |
76 | 74 |
77 class BitOrOperation extends BinaryBitOperation { | 75 class BitOrOperation extends BinaryBitOperation { |
78 final String name = '|'; | 76 final String name = '|'; |
79 const BitOrOperation(); | 77 const BitOrOperation(); |
80 int foldInts(int left, int right) => left | right; | 78 int foldInts(int left, int right) => left | right; |
81 apply(left, right) => left | right; | 79 apply(left, right) => left | right; |
82 } | 80 } |
83 | 81 |
84 class BitAndOperation extends BinaryBitOperation { | 82 class BitAndOperation extends BinaryBitOperation { |
85 final String name = '&'; | 83 final String name = '&'; |
86 const BitAndOperation(); | 84 const BitAndOperation(); |
87 int foldInts(int left, int right) => left & right; | 85 int foldInts(int left, int right) => left & right; |
88 apply(left, right) => left & right; | 86 apply(left, right) => left & right; |
89 } | 87 } |
90 | 88 |
91 class BitXorOperation extends BinaryBitOperation { | 89 class BitXorOperation extends BinaryBitOperation { |
92 final String name = '^'; | 90 final String name = '^'; |
93 const BitXorOperation(); | 91 const BitXorOperation(); |
94 int foldInts(int left, int right) => left ^ right; | 92 int foldInts(int left, int right) => left ^ right; |
95 apply(left, right) => left ^ right; | 93 apply(left, right) => left ^ right; |
96 } | 94 } |
97 | 95 |
98 class ShiftLeftOperation extends BinaryBitOperation { | 96 class ShiftLeftOperation extends BinaryBitOperation { |
99 final String name = '<<'; | 97 final String name = '<<'; |
100 const ShiftLeftOperation(); | 98 const ShiftLeftOperation(); |
101 int foldInts(int left, int right) { | 99 int foldInts(int left, int right) { |
102 // TODO(floitsch): find a better way to guard against excessive shifts to | 100 // TODO(floitsch): find a better way to guard against excessive shifts to |
103 // the left. | 101 // the left. |
104 if (right > 100 || right < 0) return null; | 102 if (right > 100 || right < 0) return null; |
105 return left << right; | 103 return left << right; |
106 } | 104 } |
| 105 |
107 apply(left, right) => left << right; | 106 apply(left, right) => left << right; |
108 } | 107 } |
109 | 108 |
110 class ShiftRightOperation extends BinaryBitOperation { | 109 class ShiftRightOperation extends BinaryBitOperation { |
111 final String name = '>>'; | 110 final String name = '>>'; |
112 const ShiftRightOperation(); | 111 const ShiftRightOperation(); |
113 int foldInts(int left, int right) { | 112 int foldInts(int left, int right) { |
114 if (right < 0) return null; | 113 if (right < 0) return null; |
115 return left >> right; | 114 return left >> right; |
116 } | 115 } |
| 116 |
117 apply(left, right) => left >> right; | 117 apply(left, right) => left >> right; |
118 } | 118 } |
119 | 119 |
120 abstract class BinaryBoolOperation implements BinaryOperation { | 120 abstract class BinaryBoolOperation implements BinaryOperation { |
121 const BinaryBoolOperation(); | 121 const BinaryBoolOperation(); |
122 ConstantValue fold(ConstantValue left, ConstantValue right) { | 122 ConstantValue fold(ConstantValue left, ConstantValue right) { |
123 if (left.isBool && right.isBool) { | 123 if (left.isBool && right.isBool) { |
124 BoolConstantValue leftBool = left; | 124 BoolConstantValue leftBool = left; |
125 BoolConstantValue rightBool = right; | 125 BoolConstantValue rightBool = right; |
126 bool resultValue = | 126 bool resultValue = |
(...skipping 27 matching lines...) Expand all Loading... |
154 NumConstantValue leftNum = left; | 154 NumConstantValue leftNum = left; |
155 NumConstantValue rightNum = right; | 155 NumConstantValue rightNum = right; |
156 num foldedValue; | 156 num foldedValue; |
157 if (left.isInt && right.isInt) { | 157 if (left.isInt && right.isInt) { |
158 foldedValue = foldInts(leftNum.primitiveValue, rightNum.primitiveValue); | 158 foldedValue = foldInts(leftNum.primitiveValue, rightNum.primitiveValue); |
159 } else { | 159 } else { |
160 foldedValue = foldNums(leftNum.primitiveValue, rightNum.primitiveValue); | 160 foldedValue = foldNums(leftNum.primitiveValue, rightNum.primitiveValue); |
161 } | 161 } |
162 // A division by 0 means that we might not have a folded value. | 162 // A division by 0 means that we might not have a folded value. |
163 if (foldedValue == null) return null; | 163 if (foldedValue == null) return null; |
164 if (left.isInt && right.isInt && !isDivide() || | 164 if (left.isInt && right.isInt && !isDivide() || isTruncatingDivide()) { |
165 isTruncatingDivide()) { | |
166 assert(foldedValue is int); | 165 assert(foldedValue is int); |
167 return DART_CONSTANT_SYSTEM.createInt(foldedValue); | 166 return DART_CONSTANT_SYSTEM.createInt(foldedValue); |
168 } else { | 167 } else { |
169 return DART_CONSTANT_SYSTEM.createDouble(foldedValue); | 168 return DART_CONSTANT_SYSTEM.createDouble(foldedValue); |
170 } | 169 } |
171 } | 170 } |
172 return null; | 171 return null; |
173 } | 172 } |
174 | 173 |
175 bool isDivide() => false; | 174 bool isDivide() => false; |
(...skipping 16 matching lines...) Expand all Loading... |
192 apply(left, right) => left * right; | 191 apply(left, right) => left * right; |
193 } | 192 } |
194 | 193 |
195 class ModuloOperation extends ArithmeticNumOperation { | 194 class ModuloOperation extends ArithmeticNumOperation { |
196 final String name = '%'; | 195 final String name = '%'; |
197 const ModuloOperation(); | 196 const ModuloOperation(); |
198 int foldInts(int left, int right) { | 197 int foldInts(int left, int right) { |
199 if (right == 0) return null; | 198 if (right == 0) return null; |
200 return left % right; | 199 return left % right; |
201 } | 200 } |
| 201 |
202 num foldNums(num left, num right) => left % right; | 202 num foldNums(num left, num right) => left % right; |
203 apply(left, right) => left % right; | 203 apply(left, right) => left % right; |
204 } | 204 } |
205 | 205 |
206 class TruncatingDivideOperation extends ArithmeticNumOperation { | 206 class TruncatingDivideOperation extends ArithmeticNumOperation { |
207 final String name = '~/'; | 207 final String name = '~/'; |
208 const TruncatingDivideOperation(); | 208 const TruncatingDivideOperation(); |
209 int foldInts(int left, int right) { | 209 int foldInts(int left, int right) { |
210 if (right == 0) return null; | 210 if (right == 0) return null; |
211 return left ~/ right; | 211 return left ~/ right; |
212 } | 212 } |
| 213 |
213 num foldNums(num left, num right) { | 214 num foldNums(num left, num right) { |
214 num ratio = left / right; | 215 num ratio = left / right; |
215 if (ratio.isNaN || ratio.isInfinite) return null; | 216 if (ratio.isNaN || ratio.isInfinite) return null; |
216 return ratio.truncate().toInt(); | 217 return ratio.truncate().toInt(); |
217 } | 218 } |
| 219 |
218 apply(left, right) => left ~/ right; | 220 apply(left, right) => left ~/ right; |
219 bool isTruncatingDivide() => true; | 221 bool isTruncatingDivide() => true; |
220 } | 222 } |
221 | 223 |
222 class DivideOperation extends ArithmeticNumOperation { | 224 class DivideOperation extends ArithmeticNumOperation { |
223 final String name = '/'; | 225 final String name = '/'; |
224 const DivideOperation(); | 226 const DivideOperation(); |
225 num foldNums(num left, num right) => left / right; | 227 num foldNums(num left, num right) => left / right; |
226 bool isDivide() => true; | 228 bool isDivide() => true; |
227 apply(left, right) => left / right; | 229 apply(left, right) => left / right; |
228 } | 230 } |
229 | 231 |
230 class AddOperation implements BinaryOperation { | 232 class AddOperation implements BinaryOperation { |
231 final String name = '+'; | 233 final String name = '+'; |
232 const AddOperation(); | 234 const AddOperation(); |
233 ConstantValue fold(ConstantValue left, ConstantValue right) { | 235 ConstantValue fold(ConstantValue left, ConstantValue right) { |
234 if (left.isInt && right.isInt) { | 236 if (left.isInt && right.isInt) { |
235 IntConstantValue leftInt = left; | 237 IntConstantValue leftInt = left; |
236 IntConstantValue rightInt = right; | 238 IntConstantValue rightInt = right; |
237 int result = leftInt.primitiveValue + rightInt.primitiveValue; | 239 int result = leftInt.primitiveValue + rightInt.primitiveValue; |
238 return DART_CONSTANT_SYSTEM.createInt(result); | 240 return DART_CONSTANT_SYSTEM.createInt(result); |
239 } else if (left.isNum && right.isNum) { | 241 } else if (left.isNum && right.isNum) { |
240 NumConstantValue leftNum = left; | 242 NumConstantValue leftNum = left; |
241 NumConstantValue rightNum = right; | 243 NumConstantValue rightNum = right; |
242 double result = leftNum.primitiveValue + rightNum.primitiveValue; | 244 double result = leftNum.primitiveValue + rightNum.primitiveValue; |
243 return DART_CONSTANT_SYSTEM.createDouble(result); | 245 return DART_CONSTANT_SYSTEM.createDouble(result); |
244 } else if (left.isString && right.isString) { | 246 } else if (left.isString && right.isString) { |
245 StringConstantValue leftString = left; | 247 StringConstantValue leftString = left; |
246 StringConstantValue rightString = right; | 248 StringConstantValue rightString = right; |
247 DartString result = new DartString.concat(leftString.primitiveValue, | 249 DartString result = new DartString.concat( |
248 rightString.primitiveValue); | 250 leftString.primitiveValue, rightString.primitiveValue); |
249 return DART_CONSTANT_SYSTEM.createString(result); | 251 return DART_CONSTANT_SYSTEM.createString(result); |
250 } else { | 252 } else { |
251 return null; | 253 return null; |
252 } | 254 } |
253 } | 255 } |
| 256 |
254 apply(left, right) => left + right; | 257 apply(left, right) => left + right; |
255 } | 258 } |
256 | 259 |
257 abstract class RelationalNumOperation implements BinaryOperation { | 260 abstract class RelationalNumOperation implements BinaryOperation { |
258 const RelationalNumOperation(); | 261 const RelationalNumOperation(); |
259 ConstantValue fold(ConstantValue left, ConstantValue right) { | 262 ConstantValue fold(ConstantValue left, ConstantValue right) { |
260 if (!left.isNum || !right.isNum) return null; | 263 if (!left.isNum || !right.isNum) return null; |
261 NumConstantValue leftNum = left; | 264 NumConstantValue leftNum = left; |
262 NumConstantValue rightNum = right; | 265 NumConstantValue rightNum = right; |
263 bool foldedValue = | 266 bool foldedValue = |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
309 bool result = leftNum.primitiveValue == rightNum.primitiveValue; | 312 bool result = leftNum.primitiveValue == rightNum.primitiveValue; |
310 return DART_CONSTANT_SYSTEM.createBool(result); | 313 return DART_CONSTANT_SYSTEM.createBool(result); |
311 } | 314 } |
312 if (left.isConstructedObject) { | 315 if (left.isConstructedObject) { |
313 // Unless we know that the user-defined object does not implement the | 316 // Unless we know that the user-defined object does not implement the |
314 // equality operator we cannot fold here. | 317 // equality operator we cannot fold here. |
315 return null; | 318 return null; |
316 } | 319 } |
317 return DART_CONSTANT_SYSTEM.createBool(left == right); | 320 return DART_CONSTANT_SYSTEM.createBool(left == right); |
318 } | 321 } |
| 322 |
319 apply(left, right) => left == right; | 323 apply(left, right) => left == right; |
320 } | 324 } |
321 | 325 |
322 class IdentityOperation implements BinaryOperation { | 326 class IdentityOperation implements BinaryOperation { |
323 final String name = '==='; | 327 final String name = '==='; |
324 const IdentityOperation(); | 328 const IdentityOperation(); |
325 BoolConstantValue fold(ConstantValue left, ConstantValue right) { | 329 BoolConstantValue fold(ConstantValue left, ConstantValue right) { |
326 // In order to preserve runtime semantics which says that NaN !== NaN don't | 330 // In order to preserve runtime semantics which says that NaN !== NaN don't |
327 // constant fold NaN === NaN. Otherwise the output depends on inlined | 331 // constant fold NaN === NaN. Otherwise the output depends on inlined |
328 // variables and other optimizations. | 332 // variables and other optimizations. |
329 if (left.isNaN && right.isNaN) return null; | 333 if (left.isNaN && right.isNaN) return null; |
330 return DART_CONSTANT_SYSTEM.createBool(left == right); | 334 return DART_CONSTANT_SYSTEM.createBool(left == right); |
331 } | 335 } |
| 336 |
332 apply(left, right) => identical(left, right); | 337 apply(left, right) => identical(left, right); |
333 } | 338 } |
334 | 339 |
335 class IfNullOperation implements BinaryOperation { | 340 class IfNullOperation implements BinaryOperation { |
336 final String name = '??'; | 341 final String name = '??'; |
337 const IfNullOperation(); | 342 const IfNullOperation(); |
338 ConstantValue fold(ConstantValue left, ConstantValue right) { | 343 ConstantValue fold(ConstantValue left, ConstantValue right) { |
339 if (left.isNull) return right; | 344 if (left.isNull) return right; |
340 return left; | 345 return left; |
341 } | 346 } |
| 347 |
342 apply(left, right) => left ?? right; | 348 apply(left, right) => left ?? right; |
343 } | 349 } |
344 | 350 |
345 abstract class CodeUnitAtOperation implements BinaryOperation { | 351 abstract class CodeUnitAtOperation implements BinaryOperation { |
346 final String name = 'charCodeAt'; | 352 final String name = 'charCodeAt'; |
347 const CodeUnitAtOperation(); | 353 const CodeUnitAtOperation(); |
348 apply(left, right) => left.codeUnitAt(right); | 354 apply(left, right) => left.codeUnitAt(right); |
349 } | 355 } |
350 | 356 |
351 class CodeUnitAtConstantOperation extends CodeUnitAtOperation { | 357 class CodeUnitAtConstantOperation extends CodeUnitAtOperation { |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
400 final negate = const NegateOperation(); | 406 final negate = const NegateOperation(); |
401 final not = const NotOperation(); | 407 final not = const NotOperation(); |
402 final shiftLeft = const ShiftLeftOperation(); | 408 final shiftLeft = const ShiftLeftOperation(); |
403 final shiftRight = const ShiftRightOperation(); | 409 final shiftRight = const ShiftRightOperation(); |
404 final subtract = const SubtractOperation(); | 410 final subtract = const SubtractOperation(); |
405 final truncatingDivide = const TruncatingDivideOperation(); | 411 final truncatingDivide = const TruncatingDivideOperation(); |
406 final codeUnitAt = const CodeUnitAtConstantOperation(); | 412 final codeUnitAt = const CodeUnitAtConstantOperation(); |
407 | 413 |
408 const DartConstantSystem(); | 414 const DartConstantSystem(); |
409 | 415 |
410 | |
411 @override | 416 @override |
412 IntConstantValue createInt(int i) => new IntConstantValue(i); | 417 IntConstantValue createInt(int i) => new IntConstantValue(i); |
413 | 418 |
414 @override | 419 @override |
415 DoubleConstantValue createDouble(double d) => new DoubleConstantValue(d); | 420 DoubleConstantValue createDouble(double d) => new DoubleConstantValue(d); |
416 | 421 |
417 @override | 422 @override |
418 StringConstantValue createString(DartString string) { | 423 StringConstantValue createString(DartString string) { |
419 return new StringConstantValue(string); | 424 return new StringConstantValue(string); |
420 } | 425 } |
421 | 426 |
422 @override | 427 @override |
423 BoolConstantValue createBool(bool value) => new BoolConstantValue(value); | 428 BoolConstantValue createBool(bool value) => new BoolConstantValue(value); |
424 | 429 |
425 @override | 430 @override |
426 NullConstantValue createNull() => new NullConstantValue(); | 431 NullConstantValue createNull() => new NullConstantValue(); |
427 | 432 |
428 @override | 433 @override |
429 ListConstantValue createList(InterfaceType type, | 434 ListConstantValue createList(InterfaceType type, List<ConstantValue> values) { |
430 List<ConstantValue> values) { | |
431 return new ListConstantValue(type, values); | 435 return new ListConstantValue(type, values); |
432 } | 436 } |
433 | 437 |
434 @override | 438 @override |
435 MapConstantValue createMap(Compiler compiler, | 439 MapConstantValue createMap(Compiler compiler, InterfaceType type, |
436 InterfaceType type, | 440 List<ConstantValue> keys, List<ConstantValue> values) { |
437 List<ConstantValue> keys, | |
438 List<ConstantValue> values) { | |
439 return new MapConstantValue(type, keys, values); | 441 return new MapConstantValue(type, keys, values); |
440 } | 442 } |
441 | 443 |
442 @override | 444 @override |
443 ConstantValue createType(Compiler compiler, DartType type) { | 445 ConstantValue createType(Compiler compiler, DartType type) { |
444 // TODO(johnniwinther): Change the `Type` type to | 446 // TODO(johnniwinther): Change the `Type` type to |
445 // `compiler.coreTypes.typeType` and check the backend specific value in | 447 // `compiler.coreTypes.typeType` and check the backend specific value in |
446 // [checkConstMapKeysDontOverrideEquals] in 'members.dart'. | 448 // [checkConstMapKeysDontOverrideEquals] in 'members.dart'. |
447 return new TypeConstantValue(type, | 449 return new TypeConstantValue(type, |
448 compiler.backend.typeImplementation.computeType(compiler.resolution)); | 450 compiler.backend.typeImplementation.computeType(compiler.resolution)); |
449 } | 451 } |
450 | 452 |
451 bool isInt(ConstantValue constant) => constant.isInt; | 453 bool isInt(ConstantValue constant) => constant.isInt; |
452 bool isDouble(ConstantValue constant) => constant.isDouble; | 454 bool isDouble(ConstantValue constant) => constant.isDouble; |
453 bool isString(ConstantValue constant) => constant.isString; | 455 bool isString(ConstantValue constant) => constant.isString; |
454 bool isBool(ConstantValue constant) => constant.isBool; | 456 bool isBool(ConstantValue constant) => constant.isBool; |
455 bool isNull(ConstantValue constant) => constant.isNull; | 457 bool isNull(ConstantValue constant) => constant.isNull; |
456 | 458 |
457 bool isSubtype(DartTypes types, DartType s, DartType t) { | 459 bool isSubtype(DartTypes types, DartType s, DartType t) { |
458 return types.isSubtype(s, t); | 460 return types.isSubtype(s, t); |
459 } | 461 } |
460 } | 462 } |
OLD | NEW |