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.js; | 5 library dart2js.constant_system.js; |
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 '../constant_system_dart.dart'; | 10 import '../constant_system_dart.dart'; |
12 import '../core_types.dart' show | 11 import '../core_types.dart' show CoreTypes; |
13 CoreTypes; | |
14 import '../dart_types.dart'; | 12 import '../dart_types.dart'; |
15 import '../elements/elements.dart' show | 13 import '../elements/elements.dart' show ClassElement; |
16 ClassElement; | 14 import '../tree/tree.dart' show DartString, LiteralDartString; |
17 import '../tree/tree.dart' show | |
18 DartString, | |
19 LiteralDartString; | |
20 import 'js_backend.dart'; | 15 import 'js_backend.dart'; |
21 | 16 |
22 const JAVA_SCRIPT_CONSTANT_SYSTEM = const JavaScriptConstantSystem(); | 17 const JAVA_SCRIPT_CONSTANT_SYSTEM = const JavaScriptConstantSystem(); |
23 | 18 |
24 class JavaScriptBitNotOperation extends BitNotOperation { | 19 class JavaScriptBitNotOperation extends BitNotOperation { |
25 const JavaScriptBitNotOperation(); | 20 const JavaScriptBitNotOperation(); |
26 | 21 |
27 ConstantValue fold(ConstantValue constant) { | 22 ConstantValue fold(ConstantValue constant) { |
28 if (JAVA_SCRIPT_CONSTANT_SYSTEM.isInt(constant)) { | 23 if (JAVA_SCRIPT_CONSTANT_SYSTEM.isInt(constant)) { |
29 // In JavaScript we don't check for -0 and treat it as if it was zero. | 24 // In JavaScript we don't check for -0 and treat it as if it was zero. |
30 if (constant.isMinusZero) constant = DART_CONSTANT_SYSTEM.createInt(0); | 25 if (constant.isMinusZero) constant = DART_CONSTANT_SYSTEM.createInt(0); |
31 IntConstantValue intConstant = constant; | 26 IntConstantValue intConstant = constant; |
32 // We convert the result of bit-operations to 32 bit unsigned integers. | 27 // We convert the result of bit-operations to 32 bit unsigned integers. |
33 return | 28 return JAVA_SCRIPT_CONSTANT_SYSTEM |
34 JAVA_SCRIPT_CONSTANT_SYSTEM.createInt32(~intConstant.primitiveValue); | 29 .createInt32(~intConstant.primitiveValue); |
35 } | 30 } |
36 return null; | 31 return null; |
37 } | 32 } |
38 } | 33 } |
39 | 34 |
40 /** | 35 /** |
41 * In JavaScript we truncate the result to an unsigned 32 bit integer. Also, -0 | 36 * In JavaScript we truncate the result to an unsigned 32 bit integer. Also, -0 |
42 * is treated as if it was the integer 0. | 37 * is treated as if it was the integer 0. |
43 */ | 38 */ |
44 class JavaScriptBinaryBitOperation implements BinaryOperation { | 39 class JavaScriptBinaryBitOperation implements BinaryOperation { |
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
229 } | 224 } |
230 // If the integer loses precision with JavaScript numbers, use | 225 // If the integer loses precision with JavaScript numbers, use |
231 // the floored version JavaScript will use. | 226 // the floored version JavaScript will use. |
232 int floorValue = intValue.toDouble().floor().toInt(); | 227 int floorValue = intValue.toDouble().floor().toInt(); |
233 if (floorValue != intValue) { | 228 if (floorValue != intValue) { |
234 return new IntConstantValue(floorValue); | 229 return new IntConstantValue(floorValue); |
235 } | 230 } |
236 } else if (constant.isDouble) { | 231 } else if (constant.isDouble) { |
237 DoubleConstantValue doubleResult = constant; | 232 DoubleConstantValue doubleResult = constant; |
238 double doubleValue = doubleResult.primitiveValue; | 233 double doubleValue = doubleResult.primitiveValue; |
239 if (!doubleValue.isInfinite && !doubleValue.isNaN && | 234 if (!doubleValue.isInfinite && |
| 235 !doubleValue.isNaN && |
240 !constant.isMinusZero) { | 236 !constant.isMinusZero) { |
241 int intValue = doubleValue.truncate(); | 237 int intValue = doubleValue.truncate(); |
242 if (intValue == doubleValue) { | 238 if (intValue == doubleValue) { |
243 return new IntConstantValue(intValue); | 239 return new IntConstantValue(intValue); |
244 } | 240 } |
245 } | 241 } |
246 } | 242 } |
247 return constant; | 243 return constant; |
248 } | 244 } |
249 | 245 |
250 @override | 246 @override |
251 NumConstantValue createInt(int i) { | 247 NumConstantValue createInt(int i) { |
252 return convertToJavaScriptConstant(new IntConstantValue(i)); | 248 return convertToJavaScriptConstant(new IntConstantValue(i)); |
253 } | 249 } |
254 | 250 |
255 NumConstantValue createInt32(int i) => new IntConstantValue(i & BITS32); | 251 NumConstantValue createInt32(int i) => new IntConstantValue(i & BITS32); |
256 NumConstantValue createDouble(double d) | 252 NumConstantValue createDouble(double d) => |
257 => convertToJavaScriptConstant(new DoubleConstantValue(d)); | 253 convertToJavaScriptConstant(new DoubleConstantValue(d)); |
258 StringConstantValue createString(DartString string) { | 254 StringConstantValue createString(DartString string) { |
259 return new StringConstantValue(string); | 255 return new StringConstantValue(string); |
260 } | 256 } |
| 257 |
261 BoolConstantValue createBool(bool value) => new BoolConstantValue(value); | 258 BoolConstantValue createBool(bool value) => new BoolConstantValue(value); |
262 NullConstantValue createNull() => new NullConstantValue(); | 259 NullConstantValue createNull() => new NullConstantValue(); |
263 | 260 |
264 @override | 261 @override |
265 ListConstantValue createList(InterfaceType type, | 262 ListConstantValue createList(InterfaceType type, List<ConstantValue> values) { |
266 List<ConstantValue> values) { | |
267 return new ListConstantValue(type, values); | 263 return new ListConstantValue(type, values); |
268 } | 264 } |
269 | 265 |
270 @override | 266 @override |
271 ConstantValue createType(Compiler compiler, DartType type) { | 267 ConstantValue createType(Compiler compiler, DartType type) { |
272 return new TypeConstantValue( | 268 return new TypeConstantValue(type, |
273 type, | |
274 compiler.backend.typeImplementation.computeType(compiler.resolution)); | 269 compiler.backend.typeImplementation.computeType(compiler.resolution)); |
275 } | 270 } |
276 | 271 |
277 // Integer checks report true for -0.0, INFINITY, and -INFINITY. At | 272 // Integer checks report true for -0.0, INFINITY, and -INFINITY. At |
278 // runtime an 'X is int' check is implemented as: | 273 // runtime an 'X is int' check is implemented as: |
279 // | 274 // |
280 // typeof(X) === "number" && Math.floor(X) === X | 275 // typeof(X) === "number" && Math.floor(X) === X |
281 // | 276 // |
282 // We consistently match that runtime semantics at compile time as well. | 277 // We consistently match that runtime semantics at compile time as well. |
283 bool isInt(ConstantValue constant) { | 278 bool isInt(ConstantValue constant) { |
284 return constant.isInt || constant.isMinusZero || | 279 return constant.isInt || |
| 280 constant.isMinusZero || |
285 constant.isPositiveInfinity || | 281 constant.isPositiveInfinity || |
286 constant.isNegativeInfinity; | 282 constant.isNegativeInfinity; |
287 } | 283 } |
288 bool isDouble(ConstantValue constant) | 284 |
289 => constant.isDouble && !constant.isMinusZero; | 285 bool isDouble(ConstantValue constant) => |
| 286 constant.isDouble && !constant.isMinusZero; |
290 bool isString(ConstantValue constant) => constant.isString; | 287 bool isString(ConstantValue constant) => constant.isString; |
291 bool isBool(ConstantValue constant) => constant.isBool; | 288 bool isBool(ConstantValue constant) => constant.isBool; |
292 bool isNull(ConstantValue constant) => constant.isNull; | 289 bool isNull(ConstantValue constant) => constant.isNull; |
293 | 290 |
294 bool isSubtype(DartTypes types, DartType s, DartType t) { | 291 bool isSubtype(DartTypes types, DartType s, DartType t) { |
295 // At runtime, an integer is both an integer and a double: the | 292 // At runtime, an integer is both an integer and a double: the |
296 // integer type check is Math.floor, which will return true only | 293 // integer type check is Math.floor, which will return true only |
297 // for real integers, and our double type check is 'typeof number' | 294 // for real integers, and our double type check is 'typeof number' |
298 // which will return true for both integers and doubles. | 295 // which will return true for both integers and doubles. |
299 if (s == types.coreTypes.intType && t == types.coreTypes.doubleType) { | 296 if (s == types.coreTypes.intType && t == types.coreTypes.doubleType) { |
300 return true; | 297 return true; |
301 } | 298 } |
302 return types.isSubtype(s, t); | 299 return types.isSubtype(s, t); |
303 } | 300 } |
304 | 301 |
305 MapConstantValue createMap(Compiler compiler, | 302 MapConstantValue createMap(Compiler compiler, InterfaceType sourceType, |
306 InterfaceType sourceType, | 303 List<ConstantValue> keys, List<ConstantValue> values) { |
307 List<ConstantValue> keys, | |
308 List<ConstantValue> values) { | |
309 JavaScriptBackend backend = compiler.backend; | 304 JavaScriptBackend backend = compiler.backend; |
310 CoreTypes coreTypes = compiler.coreTypes; | 305 CoreTypes coreTypes = compiler.coreTypes; |
311 | 306 |
312 bool onlyStringKeys = true; | 307 bool onlyStringKeys = true; |
313 ConstantValue protoValue = null; | 308 ConstantValue protoValue = null; |
314 for (int i = 0; i < keys.length ; i++) { | 309 for (int i = 0; i < keys.length; i++) { |
315 var key = keys[i]; | 310 var key = keys[i]; |
316 if (key.isString) { | 311 if (key.isString) { |
317 if (key.primitiveValue == JavaScriptMapConstant.PROTO_PROPERTY) { | 312 if (key.primitiveValue == JavaScriptMapConstant.PROTO_PROPERTY) { |
318 protoValue = values[i]; | 313 protoValue = values[i]; |
319 } | 314 } |
320 } else { | 315 } else { |
321 onlyStringKeys = false; | 316 onlyStringKeys = false; |
322 // Don't handle __proto__ values specially in the general map case. | 317 // Don't handle __proto__ values specially in the general map case. |
323 protoValue = null; | 318 protoValue = null; |
324 break; | 319 break; |
325 } | 320 } |
326 } | 321 } |
327 | 322 |
328 bool hasProtoKey = (protoValue != null); | 323 bool hasProtoKey = (protoValue != null); |
329 DartType keysType; | 324 DartType keysType; |
330 if (sourceType.treatAsRaw) { | 325 if (sourceType.treatAsRaw) { |
331 keysType = coreTypes.listType(); | 326 keysType = coreTypes.listType(); |
332 } else { | 327 } else { |
333 keysType = coreTypes.listType(sourceType.typeArguments.first); | 328 keysType = coreTypes.listType(sourceType.typeArguments.first); |
334 } | 329 } |
335 ListConstantValue keysList = new ListConstantValue(keysType, keys); | 330 ListConstantValue keysList = new ListConstantValue(keysType, keys); |
336 String className = onlyStringKeys | 331 String className = onlyStringKeys |
337 ? (hasProtoKey ? JavaScriptMapConstant.DART_PROTO_CLASS | 332 ? (hasProtoKey |
338 : JavaScriptMapConstant.DART_STRING_CLASS) | 333 ? JavaScriptMapConstant.DART_PROTO_CLASS |
| 334 : JavaScriptMapConstant.DART_STRING_CLASS) |
339 : JavaScriptMapConstant.DART_GENERAL_CLASS; | 335 : JavaScriptMapConstant.DART_GENERAL_CLASS; |
340 ClassElement classElement = backend.helpers.jsHelperLibrary.find(className); | 336 ClassElement classElement = backend.helpers.jsHelperLibrary.find(className); |
341 classElement.ensureResolved(compiler.resolution); | 337 classElement.ensureResolved(compiler.resolution); |
342 List<DartType> typeArgument = sourceType.typeArguments; | 338 List<DartType> typeArgument = sourceType.typeArguments; |
343 InterfaceType type; | 339 InterfaceType type; |
344 if (sourceType.treatAsRaw) { | 340 if (sourceType.treatAsRaw) { |
345 type = classElement.rawType; | 341 type = classElement.rawType; |
346 } else { | 342 } else { |
347 type = new InterfaceType(classElement, typeArgument); | 343 type = new InterfaceType(classElement, typeArgument); |
348 } | 344 } |
349 return new JavaScriptMapConstant( | 345 return new JavaScriptMapConstant( |
350 type, keysList, values, protoValue, onlyStringKeys); | 346 type, keysList, values, protoValue, onlyStringKeys); |
351 | |
352 } | 347 } |
353 } | 348 } |
354 | 349 |
355 class JavaScriptMapConstant extends MapConstantValue { | 350 class JavaScriptMapConstant extends MapConstantValue { |
356 /** | 351 /** |
357 * The [PROTO_PROPERTY] must not be used as normal property in any JavaScript | 352 * The [PROTO_PROPERTY] must not be used as normal property in any JavaScript |
358 * object. It would change the prototype chain. | 353 * object. It would change the prototype chain. |
359 */ | 354 */ |
360 static const LiteralDartString PROTO_PROPERTY = | 355 static const LiteralDartString PROTO_PROPERTY = |
361 const LiteralDartString("__proto__"); | 356 const LiteralDartString("__proto__"); |
362 | 357 |
363 /** The dart class implementing constant map literals. */ | 358 /** The dart class implementing constant map literals. */ |
364 static const String DART_CLASS = "ConstantMap"; | 359 static const String DART_CLASS = "ConstantMap"; |
365 static const String DART_STRING_CLASS = "ConstantStringMap"; | 360 static const String DART_STRING_CLASS = "ConstantStringMap"; |
366 static const String DART_PROTO_CLASS = "ConstantProtoMap"; | 361 static const String DART_PROTO_CLASS = "ConstantProtoMap"; |
367 static const String DART_GENERAL_CLASS = "GeneralConstantMap"; | 362 static const String DART_GENERAL_CLASS = "GeneralConstantMap"; |
368 static const String LENGTH_NAME = "_length"; | 363 static const String LENGTH_NAME = "_length"; |
369 static const String JS_OBJECT_NAME = "_jsObject"; | 364 static const String JS_OBJECT_NAME = "_jsObject"; |
370 static const String KEYS_NAME = "_keys"; | 365 static const String KEYS_NAME = "_keys"; |
371 static const String PROTO_VALUE = "_protoValue"; | 366 static const String PROTO_VALUE = "_protoValue"; |
372 static const String JS_DATA_NAME = "_jsData"; | 367 static const String JS_DATA_NAME = "_jsData"; |
373 | 368 |
374 final ListConstantValue keyList; | 369 final ListConstantValue keyList; |
375 final ConstantValue protoValue; | 370 final ConstantValue protoValue; |
376 final bool onlyStringKeys; | 371 final bool onlyStringKeys; |
377 | 372 |
378 JavaScriptMapConstant(InterfaceType type, | 373 JavaScriptMapConstant(InterfaceType type, ListConstantValue keyList, |
379 ListConstantValue keyList, | 374 List<ConstantValue> values, this.protoValue, this.onlyStringKeys) |
380 List<ConstantValue> values, | |
381 this.protoValue, | |
382 this.onlyStringKeys) | |
383 : this.keyList = keyList, | 375 : this.keyList = keyList, |
384 super(type, keyList.entries, values); | 376 super(type, keyList.entries, values); |
385 bool get isMap => true; | 377 bool get isMap => true; |
386 | 378 |
387 List<ConstantValue> getDependencies() { | 379 List<ConstantValue> getDependencies() { |
388 List<ConstantValue> result = <ConstantValue>[]; | 380 List<ConstantValue> result = <ConstantValue>[]; |
389 if (onlyStringKeys) { | 381 if (onlyStringKeys) { |
390 result.add(keyList); | 382 result.add(keyList); |
391 } else { | 383 } else { |
392 // Add the keys individually to avoid generating an unused list constant | 384 // Add the keys individually to avoid generating an unused list constant |
393 // for the keys. | 385 // for the keys. |
394 result.addAll(keys); | 386 result.addAll(keys); |
395 } | 387 } |
396 result.addAll(values); | 388 result.addAll(values); |
397 return result; | 389 return result; |
398 } | 390 } |
399 } | 391 } |
OLD | NEW |