| 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 |