OLD | NEW |
| (Empty) |
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 | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 part of dart2js; | |
6 | |
7 const DART_CONSTANT_SYSTEM = const DartConstantSystem(); | |
8 | |
9 class BitNotOperation implements UnaryOperation { | |
10 final String name = '~'; | |
11 const BitNotOperation(); | |
12 ConstantValue fold(ConstantValue constant) { | |
13 if (constant.isInt) { | |
14 IntConstantValue intConstant = constant; | |
15 return DART_CONSTANT_SYSTEM.createInt(~intConstant.primitiveValue); | |
16 } | |
17 return null; | |
18 } | |
19 } | |
20 | |
21 class NegateOperation implements UnaryOperation { | |
22 final String name = 'negate'; | |
23 const NegateOperation(); | |
24 ConstantValue fold(ConstantValue constant) { | |
25 if (constant.isInt) { | |
26 IntConstantValue intConstant = constant; | |
27 return DART_CONSTANT_SYSTEM.createInt(-intConstant.primitiveValue); | |
28 } | |
29 if (constant.isDouble) { | |
30 DoubleConstantValue doubleConstant = constant; | |
31 return DART_CONSTANT_SYSTEM.createDouble(-doubleConstant.primitiveValue); | |
32 } | |
33 return null; | |
34 } | |
35 } | |
36 | |
37 class NotOperation implements UnaryOperation { | |
38 final String name = '!'; | |
39 const NotOperation(); | |
40 ConstantValue fold(ConstantValue constant) { | |
41 if (constant.isBool) { | |
42 BoolConstantValue boolConstant = constant; | |
43 return DART_CONSTANT_SYSTEM.createBool(!boolConstant.primitiveValue); | |
44 } | |
45 return null; | |
46 } | |
47 } | |
48 | |
49 /** | |
50 * Operations that only work if both arguments are integers. | |
51 */ | |
52 abstract class BinaryBitOperation implements BinaryOperation { | |
53 const BinaryBitOperation(); | |
54 ConstantValue fold(ConstantValue left, ConstantValue right) { | |
55 if (left.isInt && right.isInt) { | |
56 IntConstantValue leftInt = left; | |
57 IntConstantValue rightInt = right; | |
58 int resultValue = | |
59 foldInts(leftInt.primitiveValue, rightInt.primitiveValue); | |
60 if (resultValue == null) return null; | |
61 return DART_CONSTANT_SYSTEM.createInt(resultValue); | |
62 } | |
63 return null; | |
64 } | |
65 | |
66 int foldInts(int left, int right); | |
67 } | |
68 | |
69 class BitOrOperation extends BinaryBitOperation { | |
70 final String name = '|'; | |
71 const BitOrOperation(); | |
72 int foldInts(int left, int right) => left | right; | |
73 apply(left, right) => left | right; | |
74 } | |
75 | |
76 class BitAndOperation extends BinaryBitOperation { | |
77 final String name = '&'; | |
78 const BitAndOperation(); | |
79 int foldInts(int left, int right) => left & right; | |
80 apply(left, right) => left & right; | |
81 } | |
82 | |
83 class BitXorOperation extends BinaryBitOperation { | |
84 final String name = '^'; | |
85 const BitXorOperation(); | |
86 int foldInts(int left, int right) => left ^ right; | |
87 apply(left, right) => left ^ right; | |
88 } | |
89 | |
90 class ShiftLeftOperation extends BinaryBitOperation { | |
91 final String name = '<<'; | |
92 const ShiftLeftOperation(); | |
93 int foldInts(int left, int right) { | |
94 // TODO(floitsch): find a better way to guard against excessive shifts to | |
95 // the left. | |
96 if (right > 100 || right < 0) return null; | |
97 return left << right; | |
98 } | |
99 apply(left, right) => left << right; | |
100 } | |
101 | |
102 class ShiftRightOperation extends BinaryBitOperation { | |
103 final String name = '>>'; | |
104 const ShiftRightOperation(); | |
105 int foldInts(int left, int right) { | |
106 if (right < 0) return null; | |
107 return left >> right; | |
108 } | |
109 apply(left, right) => left >> right; | |
110 } | |
111 | |
112 abstract class BinaryBoolOperation implements BinaryOperation { | |
113 const BinaryBoolOperation(); | |
114 ConstantValue fold(ConstantValue left, ConstantValue right) { | |
115 if (left.isBool && right.isBool) { | |
116 BoolConstantValue leftBool = left; | |
117 BoolConstantValue rightBool = right; | |
118 bool resultValue = | |
119 foldBools(leftBool.primitiveValue, rightBool.primitiveValue); | |
120 return DART_CONSTANT_SYSTEM.createBool(resultValue); | |
121 } | |
122 return null; | |
123 } | |
124 | |
125 bool foldBools(bool left, bool right); | |
126 } | |
127 | |
128 class BooleanAndOperation extends BinaryBoolOperation { | |
129 final String name = '&&'; | |
130 const BooleanAndOperation(); | |
131 bool foldBools(bool left, bool right) => left && right; | |
132 apply(left, right) => left && right; | |
133 } | |
134 | |
135 class BooleanOrOperation extends BinaryBoolOperation { | |
136 final String name = '||'; | |
137 const BooleanOrOperation(); | |
138 bool foldBools(bool left, bool right) => left || right; | |
139 apply(left, right) => left || right; | |
140 } | |
141 | |
142 abstract class ArithmeticNumOperation implements BinaryOperation { | |
143 const ArithmeticNumOperation(); | |
144 ConstantValue fold(ConstantValue left, ConstantValue right) { | |
145 if (left.isNum && right.isNum) { | |
146 NumConstantValue leftNum = left; | |
147 NumConstantValue rightNum = right; | |
148 num foldedValue; | |
149 if (left.isInt && right.isInt) { | |
150 foldedValue = foldInts(leftNum.primitiveValue, rightNum.primitiveValue); | |
151 } else { | |
152 foldedValue = foldNums(leftNum.primitiveValue, rightNum.primitiveValue); | |
153 } | |
154 // A division by 0 means that we might not have a folded value. | |
155 if (foldedValue == null) return null; | |
156 if (left.isInt && right.isInt && !isDivide() || | |
157 isTruncatingDivide()) { | |
158 assert(foldedValue is int); | |
159 return DART_CONSTANT_SYSTEM.createInt(foldedValue); | |
160 } else { | |
161 return DART_CONSTANT_SYSTEM.createDouble(foldedValue); | |
162 } | |
163 } | |
164 return null; | |
165 } | |
166 | |
167 bool isDivide() => false; | |
168 bool isTruncatingDivide() => false; | |
169 num foldInts(int left, int right) => foldNums(left, right); | |
170 num foldNums(num left, num right); | |
171 } | |
172 | |
173 class SubtractOperation extends ArithmeticNumOperation { | |
174 final String name = '-'; | |
175 const SubtractOperation(); | |
176 num foldNums(num left, num right) => left - right; | |
177 apply(left, right) => left - right; | |
178 } | |
179 | |
180 class MultiplyOperation extends ArithmeticNumOperation { | |
181 final String name = '*'; | |
182 const MultiplyOperation(); | |
183 num foldNums(num left, num right) => left * right; | |
184 apply(left, right) => left * right; | |
185 } | |
186 | |
187 class ModuloOperation extends ArithmeticNumOperation { | |
188 final String name = '%'; | |
189 const ModuloOperation(); | |
190 int foldInts(int left, int right) { | |
191 if (right == 0) return null; | |
192 return left % right; | |
193 } | |
194 num foldNums(num left, num right) => left % right; | |
195 apply(left, right) => left % right; | |
196 } | |
197 | |
198 class TruncatingDivideOperation extends ArithmeticNumOperation { | |
199 final String name = '~/'; | |
200 const TruncatingDivideOperation(); | |
201 int foldInts(int left, int right) { | |
202 if (right == 0) return null; | |
203 return left ~/ right; | |
204 } | |
205 num foldNums(num left, num right) { | |
206 num ratio = left / right; | |
207 if (ratio.isNaN || ratio.isInfinite) return null; | |
208 return ratio.truncate().toInt(); | |
209 } | |
210 apply(left, right) => left ~/ right; | |
211 bool isTruncatingDivide() => true; | |
212 } | |
213 | |
214 class DivideOperation extends ArithmeticNumOperation { | |
215 final String name = '/'; | |
216 const DivideOperation(); | |
217 num foldNums(num left, num right) => left / right; | |
218 bool isDivide() => true; | |
219 apply(left, right) => left / right; | |
220 } | |
221 | |
222 class AddOperation implements BinaryOperation { | |
223 final String name = '+'; | |
224 const AddOperation(); | |
225 ConstantValue fold(ConstantValue left, ConstantValue right) { | |
226 if (left.isInt && right.isInt) { | |
227 IntConstantValue leftInt = left; | |
228 IntConstantValue rightInt = right; | |
229 int result = leftInt.primitiveValue + rightInt.primitiveValue; | |
230 return DART_CONSTANT_SYSTEM.createInt(result); | |
231 } else if (left.isNum && right.isNum) { | |
232 NumConstantValue leftNum = left; | |
233 NumConstantValue rightNum = right; | |
234 double result = leftNum.primitiveValue + rightNum.primitiveValue; | |
235 return DART_CONSTANT_SYSTEM.createDouble(result); | |
236 } else { | |
237 return null; | |
238 } | |
239 } | |
240 apply(left, right) => left + right; | |
241 } | |
242 | |
243 abstract class RelationalNumOperation implements BinaryOperation { | |
244 const RelationalNumOperation(); | |
245 ConstantValue fold(ConstantValue left, ConstantValue right) { | |
246 if (!left.isNum || !right.isNum) return null; | |
247 NumConstantValue leftNum = left; | |
248 NumConstantValue rightNum = right; | |
249 bool foldedValue = | |
250 foldNums(leftNum.primitiveValue, rightNum.primitiveValue); | |
251 assert(foldedValue != null); | |
252 return DART_CONSTANT_SYSTEM.createBool(foldedValue); | |
253 } | |
254 | |
255 bool foldNums(num left, num right); | |
256 } | |
257 | |
258 class LessOperation extends RelationalNumOperation { | |
259 final String name = '<'; | |
260 const LessOperation(); | |
261 bool foldNums(num left, num right) => left < right; | |
262 apply(left, right) => left < right; | |
263 } | |
264 | |
265 class LessEqualOperation extends RelationalNumOperation { | |
266 final String name = '<='; | |
267 const LessEqualOperation(); | |
268 bool foldNums(num left, num right) => left <= right; | |
269 apply(left, right) => left <= right; | |
270 } | |
271 | |
272 class GreaterOperation extends RelationalNumOperation { | |
273 final String name = '>'; | |
274 const GreaterOperation(); | |
275 bool foldNums(num left, num right) => left > right; | |
276 apply(left, right) => left > right; | |
277 } | |
278 | |
279 class GreaterEqualOperation extends RelationalNumOperation { | |
280 final String name = '>='; | |
281 const GreaterEqualOperation(); | |
282 bool foldNums(num left, num right) => left >= right; | |
283 apply(left, right) => left >= right; | |
284 } | |
285 | |
286 class EqualsOperation implements BinaryOperation { | |
287 final String name = '=='; | |
288 const EqualsOperation(); | |
289 ConstantValue fold(ConstantValue left, ConstantValue right) { | |
290 if (left.isNum && right.isNum) { | |
291 // Numbers need to be treated specially because: NaN != NaN, -0.0 == 0.0, | |
292 // and 1 == 1.0. | |
293 NumConstantValue leftNum = left; | |
294 NumConstantValue rightNum = right; | |
295 bool result = leftNum.primitiveValue == rightNum.primitiveValue; | |
296 return DART_CONSTANT_SYSTEM.createBool(result); | |
297 } | |
298 if (left.isConstructedObject) { | |
299 // Unless we know that the user-defined object does not implement the | |
300 // equality operator we cannot fold here. | |
301 return null; | |
302 } | |
303 return DART_CONSTANT_SYSTEM.createBool(left == right); | |
304 } | |
305 apply(left, right) => left == right; | |
306 } | |
307 | |
308 class IdentityOperation implements BinaryOperation { | |
309 final String name = '==='; | |
310 const IdentityOperation(); | |
311 BoolConstantValue fold(ConstantValue left, ConstantValue right) { | |
312 // In order to preserve runtime semantics which says that NaN !== NaN don't | |
313 // constant fold NaN === NaN. Otherwise the output depends on inlined | |
314 // variables and other optimizations. | |
315 if (left.isNaN && right.isNaN) return null; | |
316 return DART_CONSTANT_SYSTEM.createBool(left == right); | |
317 } | |
318 apply(left, right) => identical(left, right); | |
319 } | |
320 | |
321 abstract class CodeUnitAtOperation implements BinaryOperation { | |
322 final String name = 'charCodeAt'; | |
323 const CodeUnitAtOperation(); | |
324 apply(left, right) => left.codeUnitAt(right); | |
325 } | |
326 | |
327 class CodeUnitAtConstantOperation extends CodeUnitAtOperation { | |
328 const CodeUnitAtConstantOperation(); | |
329 ConstantValue fold(ConstantValue left, ConstantValue right) { | |
330 // 'a'.codeUnitAt(0) is not a constant expression. | |
331 return null; | |
332 } | |
333 } | |
334 | |
335 class CodeUnitAtRuntimeOperation extends CodeUnitAtOperation { | |
336 const CodeUnitAtRuntimeOperation(); | |
337 IntConstantValue fold(ConstantValue left, ConstantValue right) { | |
338 if (left.isString && right.isInt) { | |
339 StringConstantValue stringConstant = left; | |
340 IntConstantValue indexConstant = right; | |
341 DartString dartString = stringConstant.primitiveValue; | |
342 int index = indexConstant.primitiveValue; | |
343 if (index < 0 || index >= dartString.length) return null; | |
344 String string = dartString.slowToString(); | |
345 int value = string.codeUnitAt(index); | |
346 return DART_CONSTANT_SYSTEM.createInt(value); | |
347 } | |
348 return null; | |
349 } | |
350 } | |
351 | |
352 /** | |
353 * A constant system implementing the Dart semantics. This system relies on | |
354 * the underlying runtime-system. That is, if dart2js is run in an environment | |
355 * that doesn't correctly implement Dart's semantics this constant system will | |
356 * not return the correct values. | |
357 */ | |
358 class DartConstantSystem extends ConstantSystem { | |
359 final add = const AddOperation(); | |
360 final bitAnd = const BitAndOperation(); | |
361 final bitNot = const BitNotOperation(); | |
362 final bitOr = const BitOrOperation(); | |
363 final bitXor = const BitXorOperation(); | |
364 final booleanAnd = const BooleanAndOperation(); | |
365 final booleanOr = const BooleanOrOperation(); | |
366 final divide = const DivideOperation(); | |
367 final equal = const EqualsOperation(); | |
368 final greaterEqual = const GreaterEqualOperation(); | |
369 final greater = const GreaterOperation(); | |
370 final identity = const IdentityOperation(); | |
371 final lessEqual = const LessEqualOperation(); | |
372 final less = const LessOperation(); | |
373 final modulo = const ModuloOperation(); | |
374 final multiply = const MultiplyOperation(); | |
375 final negate = const NegateOperation(); | |
376 final not = const NotOperation(); | |
377 final shiftLeft = const ShiftLeftOperation(); | |
378 final shiftRight = const ShiftRightOperation(); | |
379 final subtract = const SubtractOperation(); | |
380 final truncatingDivide = const TruncatingDivideOperation(); | |
381 final codeUnitAt = const CodeUnitAtConstantOperation(); | |
382 | |
383 const DartConstantSystem(); | |
384 | |
385 IntConstantValue createInt(int i) => new IntConstantValue(i); | |
386 DoubleConstantValue createDouble(double d) => new DoubleConstantValue(d); | |
387 StringConstantValue createString(DartString string) { | |
388 return new StringConstantValue(string); | |
389 } | |
390 BoolConstantValue createBool(bool value) => new BoolConstantValue(value); | |
391 NullConstantValue createNull() => new NullConstantValue(); | |
392 MapConstantValue createMap(Compiler compiler, | |
393 InterfaceType type, | |
394 List<ConstantValue> keys, | |
395 List<ConstantValue> values) { | |
396 return new MapConstantValue(type, keys, values); | |
397 } | |
398 | |
399 bool isInt(ConstantValue constant) => constant.isInt; | |
400 bool isDouble(ConstantValue constant) => constant.isDouble; | |
401 bool isString(ConstantValue constant) => constant.isString; | |
402 bool isBool(ConstantValue constant) => constant.isBool; | |
403 bool isNull(ConstantValue constant) => constant.isNull; | |
404 | |
405 bool isSubtype(Compiler compiler, DartType s, DartType t) { | |
406 return compiler.types.isSubtype(s, t); | |
407 } | |
408 } | |
OLD | NEW |