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 const DART_CONSTANT_SYSTEM = const DartConstantSystem(); |
| 6 |
5 interface Operation { | 7 interface Operation { |
6 final SourceString name; | 8 final SourceString name; |
7 bool isUserDefinable(); | 9 bool isUserDefinable(); |
8 } | 10 } |
9 | 11 |
10 interface UnaryOperation extends Operation { | 12 interface UnaryOperation extends Operation { |
11 /** Returns [:null:] if it was unable to fold the operation. */ | 13 /** Returns [:null:] if it was unable to fold the operation. */ |
12 Constant fold(Constant constant); | 14 Constant fold(Constant constant); |
13 } | 15 } |
14 | 16 |
15 class BitNotOperation implements UnaryOperation { | 17 class BitNotOperation implements UnaryOperation { |
16 final SourceString name = const SourceString('~'); | 18 final SourceString name = const SourceString('~'); |
17 bool isUserDefinable() => true; | 19 bool isUserDefinable() => true; |
18 const BitNotOperation(); | 20 const BitNotOperation(); |
19 Constant fold(Constant constant) { | 21 Constant fold(Constant constant) { |
20 if (constant.isInt()) { | 22 if (constant.isInt()) { |
21 IntConstant intConstant = constant; | 23 IntConstant intConstant = constant; |
22 return new IntConstant(~intConstant.value); | 24 return DART_CONSTANT_SYSTEM.createInt(~intConstant.value); |
23 } | 25 } |
24 return null; | 26 return null; |
25 } | 27 } |
26 } | 28 } |
27 | 29 |
28 class NegateOperation implements UnaryOperation { | 30 class NegateOperation implements UnaryOperation { |
29 final SourceString name = const SourceString('negate'); | 31 final SourceString name = const SourceString('negate'); |
30 bool isUserDefinable() => true; | 32 bool isUserDefinable() => true; |
31 const NegateOperation(); | 33 const NegateOperation(); |
32 Constant fold(Constant constant) { | 34 Constant fold(Constant constant) { |
33 if (constant.isInt()) { | 35 if (constant.isInt()) { |
34 IntConstant intConstant = constant; | 36 IntConstant intConstant = constant; |
35 return new IntConstant(-intConstant.value); | 37 return DART_CONSTANT_SYSTEM.createInt(-intConstant.value); |
36 } | 38 } |
37 if (constant.isDouble()) { | 39 if (constant.isDouble()) { |
38 DoubleConstant doubleConstant = constant; | 40 DoubleConstant doubleConstant = constant; |
39 return new DoubleConstant(-doubleConstant.value); | 41 return DART_CONSTANT_SYSTEM.createDouble(-doubleConstant.value); |
40 } | 42 } |
41 return null; | 43 return null; |
42 } | 44 } |
43 } | 45 } |
44 | 46 |
45 class NotOperation implements UnaryOperation { | 47 class NotOperation implements UnaryOperation { |
46 final SourceString name = const SourceString('!'); | 48 final SourceString name = const SourceString('!'); |
47 bool isUserDefinable() => true; | 49 bool isUserDefinable() => true; |
48 const NotOperation(); | 50 const NotOperation(); |
49 Constant fold(Constant constant) { | 51 Constant fold(Constant constant) { |
50 if (constant.isBool()) { | 52 if (constant.isBool()) { |
51 BoolConstant boolConstant = constant; | 53 BoolConstant boolConstant = constant; |
52 return boolConstant.negate(); | 54 return DART_CONSTANT_SYSTEM.createBool(!boolConstant.value); |
53 } | 55 } |
54 return null; | 56 return null; |
55 } | 57 } |
56 } | 58 } |
57 | 59 |
58 interface BinaryOperation extends Operation { | 60 interface BinaryOperation extends Operation { |
59 /** Returns [:null:] if it was unable to fold the operation. */ | 61 /** Returns [:null:] if it was unable to fold the operation. */ |
60 Constant fold(Constant left, Constant right); | 62 Constant fold(Constant left, Constant right); |
61 } | 63 } |
62 | 64 |
63 /** | 65 /** |
64 * Operations that only work if both arguments are integers. | 66 * Operations that only work if both arguments are integers. |
65 */ | 67 */ |
66 class BinaryIntOperation implements BinaryOperation { | 68 class BinaryBitOperation implements BinaryOperation { |
67 bool isUserDefinable() => true; | 69 bool isUserDefinable() => true; |
68 const BinaryIntOperation(); | 70 const BinaryBitOperation(); |
69 Constant fold(Constant left, Constant right) { | 71 Constant fold(Constant left, Constant right) { |
70 if (left.isInt() && right.isInt()) { | 72 if (left.isInt() && right.isInt()) { |
71 IntConstant leftInt = left; | 73 IntConstant leftInt = left; |
72 IntConstant rightInt = right; | 74 IntConstant rightInt = right; |
73 int resultValue = foldInts(leftInt.value, rightInt.value); | 75 int resultValue = foldInts(leftInt.value, rightInt.value); |
74 if (resultValue === null) return null; | 76 if (resultValue === null) return null; |
75 return new IntConstant(resultValue); | 77 return DART_CONSTANT_SYSTEM.createInt(resultValue); |
76 } | 78 } |
77 return null; | 79 return null; |
78 } | 80 } |
79 | 81 |
80 abstract int foldInts(int left, int right); | 82 abstract int foldInts(int left, int right); |
81 } | 83 } |
82 | 84 |
83 class BitOrOperation extends BinaryIntOperation { | 85 class BitOrOperation extends BinaryBitOperation { |
84 final SourceString name = const SourceString('|'); | 86 final SourceString name = const SourceString('|'); |
85 const BitOrOperation(); | 87 const BitOrOperation(); |
86 int foldInts(int left, int right) => left | right; | 88 int foldInts(int left, int right) => left | right; |
87 } | 89 } |
88 | 90 |
89 class BitAndOperation extends BinaryIntOperation { | 91 class BitAndOperation extends BinaryBitOperation { |
90 final SourceString name = const SourceString('&'); | 92 final SourceString name = const SourceString('&'); |
91 const BitAndOperation(); | 93 const BitAndOperation(); |
92 int foldInts(int left, int right) => left & right; | 94 int foldInts(int left, int right) => left & right; |
93 } | 95 } |
94 | 96 |
95 class BitXorOperation extends BinaryIntOperation { | 97 class BitXorOperation extends BinaryBitOperation { |
96 final SourceString name = const SourceString('^'); | 98 final SourceString name = const SourceString('^'); |
97 const BitXorOperation(); | 99 const BitXorOperation(); |
98 int foldInts(int left, int right) => left ^ right; | 100 int foldInts(int left, int right) => left ^ right; |
99 } | 101 } |
100 | 102 |
101 class ShiftLeftOperation extends BinaryIntOperation { | 103 class ShiftLeftOperation extends BinaryBitOperation { |
102 final SourceString name = const SourceString('<<'); | 104 final SourceString name = const SourceString('<<'); |
103 const ShiftLeftOperation(); | 105 const ShiftLeftOperation(); |
104 int foldInts(int left, int right) { | 106 int foldInts(int left, int right) { |
105 // TODO(floitsch): find a better way to guard against excessive shifts to | 107 // TODO(floitsch): find a better way to guard against excessive shifts to |
106 // the left. | 108 // the left. |
107 if (right > 100 || right < 0) return null; | 109 if (right > 100 || right < 0) return null; |
108 return left << right; | 110 return left << right; |
109 } | 111 } |
110 } | 112 } |
111 | 113 |
112 class ShiftRightOperation extends BinaryIntOperation { | 114 class ShiftRightOperation extends BinaryBitOperation { |
113 final SourceString name = const SourceString('>>'); | 115 final SourceString name = const SourceString('>>'); |
114 const ShiftRightOperation(); | 116 const ShiftRightOperation(); |
115 int foldInts(int left, int right) { | 117 int foldInts(int left, int right) { |
116 if (right < 0) return null; | 118 if (right < 0) return null; |
117 return left >> right; | 119 return left >> right; |
118 } | 120 } |
119 } | 121 } |
120 | 122 |
121 class BinaryBoolOperation implements BinaryOperation { | 123 class BinaryBoolOperation implements BinaryOperation { |
122 bool isUserDefinable() => false; | 124 bool isUserDefinable() => false; |
123 const BinaryBoolOperation(); | 125 const BinaryBoolOperation(); |
124 Constant fold(Constant left, Constant right) { | 126 Constant fold(Constant left, Constant right) { |
125 if (left.isBool() && right.isBool()) { | 127 if (left.isBool() && right.isBool()) { |
126 BoolConstant leftBool = left; | 128 BoolConstant leftBool = left; |
127 BoolConstant rightBool = right; | 129 BoolConstant rightBool = right; |
128 bool resultValue = foldBools(leftBool.value, rightBool.value); | 130 bool resultValue = foldBools(leftBool.value, rightBool.value); |
129 return new BoolConstant(resultValue); | 131 return DART_CONSTANT_SYSTEM.createBool(resultValue); |
130 } | 132 } |
131 return null; | 133 return null; |
132 } | 134 } |
133 | 135 |
134 abstract bool foldBools(bool left, bool right); | 136 abstract bool foldBools(bool left, bool right); |
135 } | 137 } |
136 | 138 |
137 class BooleanAnd extends BinaryBoolOperation { | 139 class BooleanAndOperation extends BinaryBoolOperation { |
138 final SourceString name = const SourceString('&&'); | 140 final SourceString name = const SourceString('&&'); |
139 const BooleanAnd(); | 141 const BooleanAndOperation(); |
140 bool foldBools(bool left, bool right) => left && right; | 142 bool foldBools(bool left, bool right) => left && right; |
141 } | 143 } |
142 | 144 |
143 class BooleanOr extends BinaryBoolOperation { | 145 class BooleanOrOperation extends BinaryBoolOperation { |
144 final SourceString name = const SourceString('||'); | 146 final SourceString name = const SourceString('||'); |
145 const BooleanOr(); | 147 const BooleanOrOperation(); |
146 bool foldBools(bool left, bool right) => left || right; | 148 bool foldBools(bool left, bool right) => left || right; |
147 } | 149 } |
148 | 150 |
149 class ArithmeticNumOperation implements BinaryOperation { | 151 class ArithmeticNumOperation implements BinaryOperation { |
150 bool isUserDefinable() => true; | 152 bool isUserDefinable() => true; |
151 const ArithmeticNumOperation(); | 153 const ArithmeticNumOperation(); |
152 Constant fold(Constant left, Constant right) { | 154 Constant fold(Constant left, Constant right) { |
153 if (left.isNum() && right.isNum()) { | 155 if (left.isNum() && right.isNum()) { |
154 NumConstant leftNum = left; | 156 NumConstant leftNum = left; |
155 NumConstant rightNum = right; | 157 NumConstant rightNum = right; |
156 num foldedValue; | 158 num foldedValue; |
157 if (left.isInt() && right.isInt()) { | 159 if (left.isInt() && right.isInt()) { |
158 foldedValue = foldInts(leftNum.value, rightNum.value); | 160 foldedValue = foldInts(leftNum.value, rightNum.value); |
159 } else { | 161 } else { |
160 foldedValue = foldNums(leftNum.value, rightNum.value); | 162 foldedValue = foldNums(leftNum.value, rightNum.value); |
161 } | 163 } |
162 // A division by 0 means that we might not have a folded value. | 164 // A division by 0 means that we might not have a folded value. |
163 if (foldedValue === null) return null; | 165 if (foldedValue === null) return null; |
164 if (left.isInt() && right.isInt() && !isDivide()) { | 166 if (left.isInt() && right.isInt() && !isDivide()) { |
165 assert(foldedValue is int); | 167 assert(foldedValue is int); |
166 return new IntConstant(foldedValue); | 168 return DART_CONSTANT_SYSTEM.createInt(foldedValue); |
167 } else { | 169 } else { |
168 return new DoubleConstant(foldedValue); | 170 return DART_CONSTANT_SYSTEM.createDouble(foldedValue); |
169 } | 171 } |
170 } | 172 } |
171 return null; | 173 return null; |
172 } | 174 } |
173 | 175 |
174 bool isDivide() => false; | 176 bool isDivide() => false; |
175 num foldInts(int left, int right) => foldNums(left, right); | 177 num foldInts(int left, int right) => foldNums(left, right); |
176 abstract num foldNums(num left, num right); | 178 abstract num foldNums(num left, num right); |
177 } | 179 } |
178 | 180 |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
216 } | 218 } |
217 | 219 |
218 class AddOperation implements BinaryOperation { | 220 class AddOperation implements BinaryOperation { |
219 final SourceString name = const SourceString('+'); | 221 final SourceString name = const SourceString('+'); |
220 bool isUserDefinable() => true; | 222 bool isUserDefinable() => true; |
221 const AddOperation(); | 223 const AddOperation(); |
222 Constant fold(Constant left, Constant right) { | 224 Constant fold(Constant left, Constant right) { |
223 if (left.isInt() && right.isInt()) { | 225 if (left.isInt() && right.isInt()) { |
224 IntConstant leftInt = left; | 226 IntConstant leftInt = left; |
225 IntConstant rightInt = right; | 227 IntConstant rightInt = right; |
226 return new IntConstant(leftInt.value + rightInt.value); | 228 int result = leftInt.value + rightInt.value; |
| 229 return DART_CONSTANT_SYSTEM.createInt(result); |
227 } else if (left.isNum() && right.isNum()) { | 230 } else if (left.isNum() && right.isNum()) { |
228 NumConstant leftNum = left; | 231 NumConstant leftNum = left; |
229 NumConstant rightNum = right; | 232 NumConstant rightNum = right; |
230 return new DoubleConstant(leftNum.value + rightNum.value); | 233 double result = leftNum.value + rightNum.value; |
| 234 return DART_CONSTANT_SYSTEM.createDouble(result); |
231 } else { | 235 } else { |
232 return null; | 236 return null; |
233 } | 237 } |
234 } | 238 } |
235 } | 239 } |
236 | 240 |
237 class RelationalNumOperation implements BinaryOperation { | 241 class RelationalNumOperation implements BinaryOperation { |
238 bool isUserDefinable() => true; | 242 bool isUserDefinable() => true; |
239 const RelationalNumOperation(); | 243 const RelationalNumOperation(); |
240 Constant fold(Constant left, Constant right) { | 244 Constant fold(Constant left, Constant right) { |
241 if (left.isNum() && right.isNum()) { | 245 if (left.isNum() && right.isNum()) { |
242 NumConstant leftNum = left; | 246 NumConstant leftNum = left; |
243 NumConstant rightNum = right; | 247 NumConstant rightNum = right; |
244 bool foldedValue = foldNums(leftNum.value, rightNum.value); | 248 bool foldedValue = foldNums(leftNum.value, rightNum.value); |
245 assert(foldedValue != null); | 249 assert(foldedValue != null); |
246 return new BoolConstant(foldedValue); | 250 return DART_CONSTANT_SYSTEM.createBool(foldedValue); |
247 } | 251 } |
248 } | 252 } |
249 | 253 |
250 abstract bool foldNums(num left, num right); | 254 abstract bool foldNums(num left, num right); |
251 } | 255 } |
252 | 256 |
253 class LessOperation extends RelationalNumOperation { | 257 class LessOperation extends RelationalNumOperation { |
254 final SourceString name = const SourceString('<'); | 258 final SourceString name = const SourceString('<'); |
255 const LessOperation(); | 259 const LessOperation(); |
256 bool foldNums(num left, num right) => left < right; | 260 bool foldNums(num left, num right) => left < right; |
(...skipping 20 matching lines...) Expand all Loading... |
277 class EqualsOperation implements BinaryOperation { | 281 class EqualsOperation implements BinaryOperation { |
278 final SourceString name = const SourceString('=='); | 282 final SourceString name = const SourceString('=='); |
279 bool isUserDefinable() => true; | 283 bool isUserDefinable() => true; |
280 const EqualsOperation(); | 284 const EqualsOperation(); |
281 Constant fold(Constant left, Constant right) { | 285 Constant fold(Constant left, Constant right) { |
282 if (left.isNum() && right.isNum()) { | 286 if (left.isNum() && right.isNum()) { |
283 // Numbers need to be treated specially because: NaN != NaN, -0.0 == 0.0, | 287 // Numbers need to be treated specially because: NaN != NaN, -0.0 == 0.0, |
284 // and 1 == 1.0. | 288 // and 1 == 1.0. |
285 NumConstant leftNum = left; | 289 NumConstant leftNum = left; |
286 NumConstant rightNum = right; | 290 NumConstant rightNum = right; |
287 return new BoolConstant(leftNum.value == rightNum.value); | 291 bool result = leftNum.value == rightNum.value; |
| 292 return DART_CONSTANT_SYSTEM.createBool(result); |
288 } | 293 } |
289 if (left.isConstructedObject()) { | 294 if (left.isConstructedObject()) { |
290 // Unless we know that the user-defined object does not implement the | 295 // Unless we know that the user-defined object does not implement the |
291 // equality operator we cannot fold here. | 296 // equality operator we cannot fold here. |
292 return null; | 297 return null; |
293 } | 298 } |
294 return new BoolConstant(left == right); | 299 return DART_CONSTANT_SYSTEM.createBool(left == right); |
295 } | 300 } |
296 } | 301 } |
297 | 302 |
298 class IdentityOperation implements BinaryOperation { | 303 class IdentityOperation implements BinaryOperation { |
299 final SourceString name = const SourceString('==='); | 304 final SourceString name = const SourceString('==='); |
300 bool isUserDefinable() => false; | 305 bool isUserDefinable() => false; |
301 const IdentityOperation(); | 306 const IdentityOperation(); |
302 Constant fold(Constant left, Constant right) { | 307 BoolConstant fold(Constant left, Constant right) { |
303 // In order to preserve runtime semantics which says that NaN !== NaN don't | 308 // In order to preserve runtime semantics which says that NaN !== NaN don't |
304 // constant fold NaN === NaN. Otherwise the output depends on inlined | 309 // constant fold NaN === NaN. Otherwise the output depends on inlined |
305 // variables and other optimizations. | 310 // variables and other optimizations. |
306 if (left.isNaN() && right.isNaN()) return null; | 311 if (left.isNaN() && right.isNaN()) return null; |
307 return new BoolConstant(left == right); | 312 return DART_CONSTANT_SYSTEM.createBool(left == right); |
308 } | 313 } |
309 } | 314 } |
| 315 |
| 316 /** |
| 317 * A [ConstantSystem] is responsible for creating constants and folding them. |
| 318 */ |
| 319 interface ConstantSystem { |
| 320 BinaryOperation get add(); |
| 321 BinaryOperation get bitAnd(); |
| 322 UnaryOperation get bitNot(); |
| 323 BinaryOperation get bitOr(); |
| 324 BinaryOperation get bitXor(); |
| 325 BinaryOperation get booleanAnd(); |
| 326 BinaryOperation get booleanOr(); |
| 327 BinaryOperation get divide(); |
| 328 BinaryOperation get equal(); |
| 329 BinaryOperation get greaterEqual(); |
| 330 BinaryOperation get greater(); |
| 331 BinaryOperation get identity(); |
| 332 BinaryOperation get lessEqual(); |
| 333 BinaryOperation get less(); |
| 334 BinaryOperation get modulo(); |
| 335 BinaryOperation get multiply(); |
| 336 UnaryOperation get negate(); |
| 337 UnaryOperation get not(); |
| 338 BinaryOperation get shiftLeft(); |
| 339 BinaryOperation get shiftRight(); |
| 340 BinaryOperation get subtract(); |
| 341 BinaryOperation get truncatingDivide(); |
| 342 |
| 343 Constant createInt(int i); |
| 344 Constant createDouble(double d); |
| 345 // We need a diagnostic node to report errors in case the string is malformed. |
| 346 Constant createString(DartString string, Node diagnosticNode); |
| 347 Constant createBool(bool value); |
| 348 Constant createNull(); |
| 349 |
| 350 /** Returns true if the [constant] is an integer at runtime. */ |
| 351 bool isInt(Constant constant); |
| 352 /** Returns true if the [constant] is a double at runtime. */ |
| 353 bool isDouble(Constant constant); |
| 354 /** Returns true if the [constant] is a string at runtime. */ |
| 355 bool isString(Constant constant); |
| 356 /** Returns true if the [constant] is a boolean at runtime. */ |
| 357 bool isBool(Constant constant); |
| 358 /** Returns true if the [constant] is null at runtime. */ |
| 359 bool isNull(Constant constant); |
| 360 } |
| 361 |
| 362 /** |
| 363 * A constant system implementing the Dart semantics. This system relies on |
| 364 * the underlying runtime-system. That is, if dart2js is run in an environment |
| 365 * that doesn't correctly implement Dart's semantics this constant system will |
| 366 * not return the correct values. |
| 367 */ |
| 368 class DartConstantSystem implements ConstantSystem { |
| 369 const add = const AddOperation(); |
| 370 const bitAnd = const BitAndOperation(); |
| 371 const bitNot = const BitNotOperation(); |
| 372 const bitOr = const BitOrOperation(); |
| 373 const bitXor = const BitXorOperation(); |
| 374 const booleanAnd = const BooleanAndOperation(); |
| 375 const booleanOr = const BooleanOrOperation(); |
| 376 const divide = const DivideOperation(); |
| 377 const equal = const EqualsOperation(); |
| 378 const greaterEqual = const GreaterEqualOperation(); |
| 379 const greater = const GreaterOperation(); |
| 380 const identity = const IdentityOperation(); |
| 381 const lessEqual = const LessEqualOperation(); |
| 382 const less = const LessOperation(); |
| 383 const modulo = const ModuloOperation(); |
| 384 const multiply = const MultiplyOperation(); |
| 385 const negate = const NegateOperation(); |
| 386 const not = const NotOperation(); |
| 387 const shiftLeft = const ShiftLeftOperation(); |
| 388 const shiftRight = const ShiftRightOperation(); |
| 389 const subtract = const SubtractOperation(); |
| 390 const truncatingDivide = const TruncatingDivideOperation(); |
| 391 |
| 392 const DartConstantSystem(); |
| 393 |
| 394 IntConstant createInt(int i) => new IntConstant(i); |
| 395 DoubleConstant createDouble(double d) => new DoubleConstant(d); |
| 396 StringConstant createString(DartString string, Node diagnosticNode) |
| 397 => new StringConstant(string, diagnosticNode); |
| 398 BoolConstant createBool(bool value) => new BoolConstant(value); |
| 399 NullConstant createNull() => new NullConstant(); |
| 400 |
| 401 bool isInt(Constant constant) => constant.isInt(); |
| 402 bool isDouble(Constant constant) => constant.isDouble(); |
| 403 bool isString(Constant constant) => constant.isString(); |
| 404 bool isBool(Constant constant) => constant.isBool(); |
| 405 bool isNull(Constant constant) => constant.isNull(); |
| 406 } |
OLD | NEW |