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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/js_backend/constant_system_javascript.dart

Issue 694353007: Move dart2js from sdk/lib/_internal/compiler to pkg/compiler (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 1 month 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 | Annotate | Revision Log
OLDNEW
(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 js_backend;
6
7 const JAVA_SCRIPT_CONSTANT_SYSTEM = const JavaScriptConstantSystem();
8
9 class JavaScriptBitNotOperation extends BitNotOperation {
10 const JavaScriptBitNotOperation();
11
12 ConstantValue fold(ConstantValue constant) {
13 if (JAVA_SCRIPT_CONSTANT_SYSTEM.isInt(constant)) {
14 // In JavaScript we don't check for -0 and treat it as if it was zero.
15 if (constant.isMinusZero) constant = DART_CONSTANT_SYSTEM.createInt(0);
16 IntConstantValue intConstant = constant;
17 // We convert the result of bit-operations to 32 bit unsigned integers.
18 return
19 JAVA_SCRIPT_CONSTANT_SYSTEM.createInt32(~intConstant.primitiveValue);
20 }
21 return null;
22 }
23 }
24
25 /**
26 * In JavaScript we truncate the result to an unsigned 32 bit integer. Also, -0
27 * is treated as if it was the integer 0.
28 */
29 class JavaScriptBinaryBitOperation implements BinaryOperation {
30 final BinaryBitOperation dartBitOperation;
31
32 const JavaScriptBinaryBitOperation(this.dartBitOperation);
33
34 String get name => dartBitOperation.name;
35
36 ConstantValue fold(ConstantValue left, ConstantValue right) {
37 // In JavaScript we don't check for -0 and treat it as if it was zero.
38 if (left.isMinusZero) left = DART_CONSTANT_SYSTEM.createInt(0);
39 if (right.isMinusZero) right = DART_CONSTANT_SYSTEM.createInt(0);
40 IntConstantValue result = dartBitOperation.fold(left, right);
41 if (result != null) {
42 // We convert the result of bit-operations to 32 bit unsigned integers.
43 return JAVA_SCRIPT_CONSTANT_SYSTEM.createInt32(result.primitiveValue);
44 }
45 return result;
46 }
47
48 apply(left, right) => dartBitOperation.apply(left, right);
49 }
50
51 class JavaScriptShiftRightOperation extends JavaScriptBinaryBitOperation {
52 const JavaScriptShiftRightOperation() : super(const ShiftRightOperation());
53
54 ConstantValue fold(ConstantValue left, ConstantValue right) {
55 // Truncate the input value to 32 bits if necessary.
56 if (left.isInt) {
57 IntConstantValue intConstant = left;
58 int value = intConstant.primitiveValue;
59 int truncatedValue = value & JAVA_SCRIPT_CONSTANT_SYSTEM.BITS32;
60 if (value < 0) {
61 // Sign-extend if the input was negative. The current semantics don't
62 // make much sense, since we only look at bit 31.
63 // TODO(floitsch): we should treat the input to right shifts as
64 // unsigned.
65
66 // A 32 bit complement-two value x can be computed by:
67 // x_u - 2^32 (where x_u is its unsigned representation).
68 // Example: 0xFFFFFFFF - 0x100000000 => -1.
69 // We simply and with the sign-bit and multiply by two. If the sign-bit
70 // was set, then the result is 0. Otherwise it will become 2^32.
71 final int SIGN_BIT = 0x80000000;
72 truncatedValue -= 2 * (truncatedValue & SIGN_BIT);
73 }
74 if (value != truncatedValue) {
75 left = DART_CONSTANT_SYSTEM.createInt(truncatedValue);
76 }
77 }
78 return super.fold(left, right);
79 }
80 }
81
82 class JavaScriptNegateOperation implements UnaryOperation {
83 final NegateOperation dartNegateOperation = const NegateOperation();
84
85 const JavaScriptNegateOperation();
86
87 String get name => dartNegateOperation.name;
88
89 ConstantValue fold(ConstantValue constant) {
90 if (constant.isInt) {
91 IntConstantValue intConstant = constant;
92 if (intConstant.primitiveValue == 0) {
93 return JAVA_SCRIPT_CONSTANT_SYSTEM.createDouble(-0.0);
94 }
95 }
96 return dartNegateOperation.fold(constant);
97 }
98 }
99
100 class JavaScriptBinaryArithmeticOperation implements BinaryOperation {
101 final BinaryOperation dartArithmeticOperation;
102
103 const JavaScriptBinaryArithmeticOperation(this.dartArithmeticOperation);
104
105 String get name => dartArithmeticOperation.name;
106
107 ConstantValue fold(ConstantValue left, ConstantValue right) {
108 ConstantValue result = dartArithmeticOperation.fold(left, right);
109 if (result == null) return result;
110 return JAVA_SCRIPT_CONSTANT_SYSTEM.convertToJavaScriptConstant(result);
111 }
112
113 apply(left, right) => dartArithmeticOperation.apply(left, right);
114 }
115
116 class JavaScriptIdentityOperation implements BinaryOperation {
117 final IdentityOperation dartIdentityOperation = const IdentityOperation();
118
119 const JavaScriptIdentityOperation();
120
121 String get name => dartIdentityOperation.name;
122
123 BoolConstantValue fold(ConstantValue left, ConstantValue right) {
124 BoolConstantValue result = dartIdentityOperation.fold(left, right);
125 if (result == null || result.primitiveValue) return result;
126 // In JavaScript -0.0 === 0 and all doubles are equal to their integer
127 // values. Furthermore NaN !== NaN.
128 if (left.isNum && right.isNum) {
129 NumConstantValue leftNum = left;
130 NumConstantValue rightNum = right;
131 double leftDouble = leftNum.primitiveValue.toDouble();
132 double rightDouble = rightNum.primitiveValue.toDouble();
133 return new BoolConstantValue(leftDouble == rightDouble);
134 }
135 return result;
136 }
137
138 apply(left, right) => identical(left, right);
139 }
140
141 /**
142 * Constant system following the semantics for Dart code that has been
143 * compiled to JavaScript.
144 */
145 class JavaScriptConstantSystem extends ConstantSystem {
146 final int BITS31 = 0x8FFFFFFF;
147 final int BITS32 = 0xFFFFFFFF;
148
149 final add = const JavaScriptBinaryArithmeticOperation(const AddOperation());
150 final bitAnd = const JavaScriptBinaryBitOperation(const BitAndOperation());
151 final bitNot = const JavaScriptBitNotOperation();
152 final bitOr = const JavaScriptBinaryBitOperation(const BitOrOperation());
153 final bitXor = const JavaScriptBinaryBitOperation(const BitXorOperation());
154 final booleanAnd = const BooleanAndOperation();
155 final booleanOr = const BooleanOrOperation();
156 final divide =
157 const JavaScriptBinaryArithmeticOperation(const DivideOperation());
158 final equal = const EqualsOperation();
159 final greaterEqual = const GreaterEqualOperation();
160 final greater = const GreaterOperation();
161 final identity = const JavaScriptIdentityOperation();
162 final lessEqual = const LessEqualOperation();
163 final less = const LessOperation();
164 final modulo =
165 const JavaScriptBinaryArithmeticOperation(const ModuloOperation());
166 final multiply =
167 const JavaScriptBinaryArithmeticOperation(const MultiplyOperation());
168 final negate = const JavaScriptNegateOperation();
169 final not = const NotOperation();
170 final shiftLeft =
171 const JavaScriptBinaryBitOperation(const ShiftLeftOperation());
172 final shiftRight = const JavaScriptShiftRightOperation();
173 final subtract =
174 const JavaScriptBinaryArithmeticOperation(const SubtractOperation());
175 final truncatingDivide = const JavaScriptBinaryArithmeticOperation(
176 const TruncatingDivideOperation());
177 final codeUnitAt = const CodeUnitAtRuntimeOperation();
178
179 const JavaScriptConstantSystem();
180
181 /**
182 * Returns true if [value] will turn into NaN or infinity
183 * at runtime.
184 */
185 bool integerBecomesNanOrInfinity(int value) {
186 double doubleValue = value.toDouble();
187 return doubleValue.isNaN || doubleValue.isInfinite;
188 }
189
190 NumConstantValue convertToJavaScriptConstant(NumConstantValue constant) {
191 if (constant.isInt) {
192 IntConstantValue intConstant = constant;
193 int intValue = intConstant.primitiveValue;
194 if (integerBecomesNanOrInfinity(intValue)) {
195 return new DoubleConstantValue(intValue.toDouble());
196 }
197 // If the integer loses precision with JavaScript numbers, use
198 // the floored version JavaScript will use.
199 int floorValue = intValue.toDouble().floor().toInt();
200 if (floorValue != intValue) {
201 return new IntConstantValue(floorValue);
202 }
203 } else if (constant.isDouble) {
204 DoubleConstantValue doubleResult = constant;
205 double doubleValue = doubleResult.primitiveValue;
206 if (!doubleValue.isInfinite && !doubleValue.isNaN &&
207 !constant.isMinusZero) {
208 int intValue = doubleValue.truncate();
209 if (intValue == doubleValue) {
210 return new IntConstantValue(intValue);
211 }
212 }
213 }
214 return constant;
215 }
216
217 NumConstantValue createInt(int i)
218 => convertToJavaScriptConstant(new IntConstantValue(i));
219 NumConstantValue createInt32(int i) => new IntConstantValue(i & BITS32);
220 NumConstantValue createDouble(double d)
221 => convertToJavaScriptConstant(new DoubleConstantValue(d));
222 StringConstantValue createString(DartString string) {
223 return new StringConstantValue(string);
224 }
225 BoolConstantValue createBool(bool value) => new BoolConstantValue(value);
226 NullConstantValue createNull() => new NullConstantValue();
227
228 // Integer checks don't verify that the number is not -0.0.
229 bool isInt(ConstantValue constant) => constant.isInt || constant.isMinusZero;
230 bool isDouble(ConstantValue constant)
231 => constant.isDouble && !constant.isMinusZero;
232 bool isString(ConstantValue constant) => constant.isString;
233 bool isBool(ConstantValue constant) => constant.isBool;
234 bool isNull(ConstantValue constant) => constant.isNull;
235
236 bool isSubtype(Compiler compiler, DartType s, DartType t) {
237 // At runtime, an integer is both an integer and a double: the
238 // integer type check is Math.floor, which will return true only
239 // for real integers, and our double type check is 'typeof number'
240 // which will return true for both integers and doubles.
241 if (s.element == compiler.intClass && t.element == compiler.doubleClass) {
242 return true;
243 }
244 return compiler.types.isSubtype(s, t);
245 }
246
247 MapConstantValue createMap(Compiler compiler,
248 InterfaceType sourceType,
249 List<ConstantValue> keys,
250 List<ConstantValue> values) {
251 JavaScriptBackend backend = compiler.backend;
252
253 bool onlyStringKeys = true;
254 ConstantValue protoValue = null;
255 for (int i = 0; i < keys.length ; i++) {
256 var key = keys[i];
257 if (key.isString) {
258 if (key.primitiveValue == JavaScriptMapConstant.PROTO_PROPERTY) {
259 protoValue = values[i];
260 }
261 } else {
262 onlyStringKeys = false;
263 // Don't handle __proto__ values specially in the general map case.
264 protoValue = null;
265 break;
266 }
267 }
268
269 bool hasProtoKey = (protoValue != null);
270 DartType keysType;
271 if (sourceType.treatAsRaw) {
272 keysType = compiler.listClass.rawType;
273 } else {
274 List<DartType> arguments = <DartType>[sourceType.typeArguments.first];
275 keysType = new InterfaceType(compiler.listClass, arguments);
276 }
277 ListConstantValue keysList = new ListConstantValue(keysType, keys);
278 String className = onlyStringKeys
279 ? (hasProtoKey ? JavaScriptMapConstant.DART_PROTO_CLASS
280 : JavaScriptMapConstant.DART_STRING_CLASS)
281 : JavaScriptMapConstant.DART_GENERAL_CLASS;
282 ClassElement classElement = backend.jsHelperLibrary.find(className);
283 classElement.ensureResolved(compiler);
284 List<DartType> typeArgument = sourceType.typeArguments;
285 InterfaceType type;
286 if (sourceType.treatAsRaw) {
287 type = classElement.rawType;
288 } else {
289 type = new InterfaceType(classElement, typeArgument);
290 }
291 return new JavaScriptMapConstant(
292 type, keysList, values, protoValue, onlyStringKeys);
293
294 }
295 }
296
297 class JavaScriptMapConstant extends MapConstantValue {
298 /**
299 * The [PROTO_PROPERTY] must not be used as normal property in any JavaScript
300 * object. It would change the prototype chain.
301 */
302 static const LiteralDartString PROTO_PROPERTY =
303 const LiteralDartString("__proto__");
304
305 /** The dart class implementing constant map literals. */
306 static const String DART_CLASS = "ConstantMap";
307 static const String DART_STRING_CLASS = "ConstantStringMap";
308 static const String DART_PROTO_CLASS = "ConstantProtoMap";
309 static const String DART_GENERAL_CLASS = "GeneralConstantMap";
310 static const String LENGTH_NAME = "length";
311 static const String JS_OBJECT_NAME = "_jsObject";
312 static const String KEYS_NAME = "_keys";
313 static const String PROTO_VALUE = "_protoValue";
314 static const String JS_DATA_NAME = "_jsData";
315
316 final ListConstantValue keyList;
317 final ConstantValue protoValue;
318 final bool onlyStringKeys;
319
320 JavaScriptMapConstant(InterfaceType type,
321 ListConstantValue keyList,
322 List<ConstantValue> values,
323 this.protoValue,
324 this.onlyStringKeys)
325 : this.keyList = keyList,
326 super(type, keyList.entries, values);
327 bool get isMap => true;
328
329 TypeMask computeMask(Compiler compiler) {
330 return compiler.typesTask.constMapType;
331 }
332
333 List<ConstantValue> getDependencies() {
334 List<ConstantValue> result = <ConstantValue>[];
335 if (onlyStringKeys) {
336 result.add(keyList);
337 } else {
338 // Add the keys individually to avoid generating an unused list constant
339 // for the keys.
340 result.addAll(keys);
341 }
342 result.addAll(values);
343 return result;
344 }
345 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698