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