| 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 Compiler; | 7 import '../common/backend_api.dart' show BackendClasses; |
| 8 import '../constant_system_dart.dart'; | 8 import '../constant_system_dart.dart'; |
| 9 import '../constants/constant_system.dart'; | 9 import '../constants/constant_system.dart'; |
| 10 import '../constants/values.dart'; | 10 import '../constants/values.dart'; |
| 11 import '../core_types.dart' show CommonElements; | 11 import '../core_types.dart' show CommonElements; |
| 12 import '../elements/resolution_types.dart'; | 12 import '../elements/types.dart'; |
| 13 import '../elements/elements.dart' show ClassElement, FieldElement; | 13 import '../elements/resolution_types.dart' show DartTypes; |
| 14 import '../elements/entities.dart'; |
| 14 import '../tree/dartstring.dart' show DartString, LiteralDartString; | 15 import '../tree/dartstring.dart' show DartString, LiteralDartString; |
| 15 import 'js_backend.dart'; | |
| 16 | 16 |
| 17 const JAVA_SCRIPT_CONSTANT_SYSTEM = const JavaScriptConstantSystem(); | 17 const JAVA_SCRIPT_CONSTANT_SYSTEM = const JavaScriptConstantSystem(); |
| 18 | 18 |
| 19 class JavaScriptBitNotOperation extends BitNotOperation { | 19 class JavaScriptBitNotOperation extends BitNotOperation { |
| 20 const JavaScriptBitNotOperation(); | 20 const JavaScriptBitNotOperation(); |
| 21 | 21 |
| 22 ConstantValue fold(ConstantValue constant) { | 22 ConstantValue fold(ConstantValue constant) { |
| 23 if (JAVA_SCRIPT_CONSTANT_SYSTEM.isInt(constant)) { | 23 if (JAVA_SCRIPT_CONSTANT_SYSTEM.isInt(constant)) { |
| 24 // 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. |
| 25 if (constant.isMinusZero) constant = DART_CONSTANT_SYSTEM.createInt(0); | 25 if (constant.isMinusZero) constant = DART_CONSTANT_SYSTEM.createInt(0); |
| (...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 306 NumConstantValue createDouble(double d) => | 306 NumConstantValue createDouble(double d) => |
| 307 convertToJavaScriptConstant(new DoubleConstantValue(d)); | 307 convertToJavaScriptConstant(new DoubleConstantValue(d)); |
| 308 StringConstantValue createString(DartString string) { | 308 StringConstantValue createString(DartString string) { |
| 309 return new StringConstantValue(string); | 309 return new StringConstantValue(string); |
| 310 } | 310 } |
| 311 | 311 |
| 312 BoolConstantValue createBool(bool value) => new BoolConstantValue(value); | 312 BoolConstantValue createBool(bool value) => new BoolConstantValue(value); |
| 313 NullConstantValue createNull() => new NullConstantValue(); | 313 NullConstantValue createNull() => new NullConstantValue(); |
| 314 | 314 |
| 315 @override | 315 @override |
| 316 ListConstantValue createList( | 316 ListConstantValue createList(InterfaceType type, List<ConstantValue> values) { |
| 317 ResolutionInterfaceType type, List<ConstantValue> values) { | |
| 318 return new ListConstantValue(type, values); | 317 return new ListConstantValue(type, values); |
| 319 } | 318 } |
| 320 | 319 |
| 321 @override | 320 @override |
| 322 ConstantValue createType(Compiler compiler, ResolutionDartType type) { | 321 ConstantValue createType(CommonElements commonElements, |
| 323 ResolutionInterfaceType instanceType = | 322 BackendClasses backendClasses, DartType type) { |
| 324 compiler.backend.backendClasses.typeType; | 323 InterfaceType instanceType = backendClasses.typeType; |
| 325 return new TypeConstantValue(type, instanceType); | 324 return new TypeConstantValue(type, instanceType); |
| 326 } | 325 } |
| 327 | 326 |
| 328 // Integer checks report true for -0.0, INFINITY, and -INFINITY. At | 327 // Integer checks report true for -0.0, INFINITY, and -INFINITY. At |
| 329 // runtime an 'X is int' check is implemented as: | 328 // runtime an 'X is int' check is implemented as: |
| 330 // | 329 // |
| 331 // typeof(X) === "number" && Math.floor(X) === X | 330 // typeof(X) === "number" && Math.floor(X) === X |
| 332 // | 331 // |
| 333 // We consistently match that runtime semantics at compile time as well. | 332 // We consistently match that runtime semantics at compile time as well. |
| 334 bool isInt(ConstantValue constant) { | 333 bool isInt(ConstantValue constant) { |
| 335 return constant.isInt || | 334 return constant.isInt || |
| 336 constant.isMinusZero || | 335 constant.isMinusZero || |
| 337 constant.isPositiveInfinity || | 336 constant.isPositiveInfinity || |
| 338 constant.isNegativeInfinity; | 337 constant.isNegativeInfinity; |
| 339 } | 338 } |
| 340 | 339 |
| 341 bool isDouble(ConstantValue constant) => | 340 bool isDouble(ConstantValue constant) => |
| 342 constant.isDouble && !constant.isMinusZero; | 341 constant.isDouble && !constant.isMinusZero; |
| 343 bool isString(ConstantValue constant) => constant.isString; | 342 bool isString(ConstantValue constant) => constant.isString; |
| 344 bool isBool(ConstantValue constant) => constant.isBool; | 343 bool isBool(ConstantValue constant) => constant.isBool; |
| 345 bool isNull(ConstantValue constant) => constant.isNull; | 344 bool isNull(ConstantValue constant) => constant.isNull; |
| 346 | 345 |
| 347 bool isSubtype(DartTypes types, ResolutionDartType s, ResolutionDartType t) { | 346 bool isSubtype(DartTypes types, DartType s, DartType t) { |
| 348 // At runtime, an integer is both an integer and a double: the | 347 // At runtime, an integer is both an integer and a double: the |
| 349 // integer type check is Math.floor, which will return true only | 348 // integer type check is Math.floor, which will return true only |
| 350 // for real integers, and our double type check is 'typeof number' | 349 // for real integers, and our double type check is 'typeof number' |
| 351 // which will return true for both integers and doubles. | 350 // which will return true for both integers and doubles. |
| 352 if (s == types.commonElements.intType && | 351 if (s == types.commonElements.intType && |
| 353 t == types.commonElements.doubleType) { | 352 t == types.commonElements.doubleType) { |
| 354 return true; | 353 return true; |
| 355 } | 354 } |
| 356 return types.isSubtype(s, t); | 355 return types.isSubtype(s, t); |
| 357 } | 356 } |
| 358 | 357 |
| 359 MapConstantValue createMap( | 358 MapConstantValue createMap( |
| 360 Compiler compiler, | 359 CommonElements commonElements, |
| 361 ResolutionInterfaceType sourceType, | 360 BackendClasses backendClasses, |
| 361 InterfaceType sourceType, |
| 362 List<ConstantValue> keys, | 362 List<ConstantValue> keys, |
| 363 List<ConstantValue> values) { | 363 List<ConstantValue> values) { |
| 364 JavaScriptBackend backend = compiler.backend; | |
| 365 CommonElements commonElements = compiler.commonElements; | |
| 366 | |
| 367 bool onlyStringKeys = true; | 364 bool onlyStringKeys = true; |
| 368 ConstantValue protoValue = null; | 365 ConstantValue protoValue = null; |
| 369 for (int i = 0; i < keys.length; i++) { | 366 for (int i = 0; i < keys.length; i++) { |
| 370 var key = keys[i]; | 367 var key = keys[i]; |
| 371 if (key.isString) { | 368 if (key.isString) { |
| 372 if (key.primitiveValue == JavaScriptMapConstant.PROTO_PROPERTY) { | 369 if (key.primitiveValue == JavaScriptMapConstant.PROTO_PROPERTY) { |
| 373 protoValue = values[i]; | 370 protoValue = values[i]; |
| 374 } | 371 } |
| 375 } else { | 372 } else { |
| 376 onlyStringKeys = false; | 373 onlyStringKeys = false; |
| 377 // Don't handle __proto__ values specially in the general map case. | 374 // Don't handle __proto__ values specially in the general map case. |
| 378 protoValue = null; | 375 protoValue = null; |
| 379 break; | 376 break; |
| 380 } | 377 } |
| 381 } | 378 } |
| 382 | 379 |
| 383 bool hasProtoKey = (protoValue != null); | 380 bool hasProtoKey = (protoValue != null); |
| 384 ResolutionInterfaceType keysType; | 381 InterfaceType keysType; |
| 385 if (sourceType.treatAsRaw) { | 382 if (sourceType.treatAsRaw) { |
| 386 keysType = commonElements.listType(); | 383 keysType = commonElements.listType(); |
| 387 } else { | 384 } else { |
| 388 keysType = commonElements.listType(sourceType.typeArguments.first); | 385 keysType = commonElements.listType(sourceType.typeArguments.first); |
| 389 } | 386 } |
| 390 ListConstantValue keysList = new ListConstantValue(keysType, keys); | 387 ListConstantValue keysList = new ListConstantValue(keysType, keys); |
| 391 ClassElement classElement = onlyStringKeys | 388 InterfaceType type = backendClasses.getConstantMapTypeFor(sourceType, |
| 392 ? (hasProtoKey | 389 hasProtoKey: hasProtoKey, onlyStringKeys: onlyStringKeys); |
| 393 ? backend.helpers.constantProtoMapClass | |
| 394 : backend.helpers.constantStringMapClass) | |
| 395 : backend.helpers.generalConstantMapClass; | |
| 396 classElement.ensureResolved(compiler.resolution); | |
| 397 List<ResolutionDartType> typeArgument = sourceType.typeArguments; | |
| 398 ResolutionInterfaceType type; | |
| 399 if (sourceType.treatAsRaw) { | |
| 400 type = classElement.rawType; | |
| 401 } else { | |
| 402 type = new ResolutionInterfaceType(classElement, typeArgument); | |
| 403 } | |
| 404 return new JavaScriptMapConstant( | 390 return new JavaScriptMapConstant( |
| 405 type, keysList, values, protoValue, onlyStringKeys); | 391 type, keysList, values, protoValue, onlyStringKeys); |
| 406 } | 392 } |
| 407 | 393 |
| 408 @override | 394 @override |
| 409 ConstantValue createSymbol(Compiler compiler, String text) { | 395 ConstantValue createSymbol(CommonElements commonElements, |
| 410 // TODO(johnniwinther): Create a backend agnostic value. | 396 BackendClasses backendClasses, String text) { |
| 411 JavaScriptBackend backend = compiler.backend; | 397 InterfaceType type = backendClasses.symbolType; |
| 412 ClassElement symbolClass = backend.helpers.symbolImplementationClass; | 398 FieldEntity field = backendClasses.symbolField; |
| 413 ResolutionInterfaceType type = symbolClass.rawType; | |
| 414 ConstantValue argument = createString(new DartString.literal(text)); | 399 ConstantValue argument = createString(new DartString.literal(text)); |
| 415 Map<FieldElement, ConstantValue> fields = <FieldElement, ConstantValue>{}; | 400 // TODO(johnniwinther): Use type arguments when all uses no longer expect |
| 416 symbolClass.forEachInstanceField( | 401 // a [FieldElement]. |
| 417 (ClassElement enclosingClass, FieldElement field) { | 402 Map<FieldEntity, ConstantValue> fields = /*<FieldElement, ConstantValue>*/ { |
| 418 fields[field] = argument; | 403 field: argument |
| 419 }, includeSuperAndInjectedMembers: true); | 404 }; |
| 420 assert(fields.length == 1); | |
| 421 return new ConstructedConstantValue(type, fields); | 405 return new ConstructedConstantValue(type, fields); |
| 422 } | 406 } |
| 423 } | 407 } |
| 424 | 408 |
| 425 class JavaScriptMapConstant extends MapConstantValue { | 409 class JavaScriptMapConstant extends MapConstantValue { |
| 426 /** | 410 /** |
| 427 * The [PROTO_PROPERTY] must not be used as normal property in any JavaScript | 411 * The [PROTO_PROPERTY] must not be used as normal property in any JavaScript |
| 428 * object. It would change the prototype chain. | 412 * object. It would change the prototype chain. |
| 429 */ | 413 */ |
| 430 static const LiteralDartString PROTO_PROPERTY = | 414 static const LiteralDartString PROTO_PROPERTY = |
| 431 const LiteralDartString("__proto__"); | 415 const LiteralDartString("__proto__"); |
| 432 | 416 |
| 433 /** The dart class implementing constant map literals. */ | 417 /** The dart class implementing constant map literals. */ |
| 434 static const String DART_CLASS = "ConstantMap"; | 418 static const String DART_CLASS = "ConstantMap"; |
| 435 static const String DART_STRING_CLASS = "ConstantStringMap"; | 419 static const String DART_STRING_CLASS = "ConstantStringMap"; |
| 436 static const String DART_PROTO_CLASS = "ConstantProtoMap"; | 420 static const String DART_PROTO_CLASS = "ConstantProtoMap"; |
| 437 static const String DART_GENERAL_CLASS = "GeneralConstantMap"; | 421 static const String DART_GENERAL_CLASS = "GeneralConstantMap"; |
| 438 static const String LENGTH_NAME = "_length"; | 422 static const String LENGTH_NAME = "_length"; |
| 439 static const String JS_OBJECT_NAME = "_jsObject"; | 423 static const String JS_OBJECT_NAME = "_jsObject"; |
| 440 static const String KEYS_NAME = "_keys"; | 424 static const String KEYS_NAME = "_keys"; |
| 441 static const String PROTO_VALUE = "_protoValue"; | 425 static const String PROTO_VALUE = "_protoValue"; |
| 442 static const String JS_DATA_NAME = "_jsData"; | 426 static const String JS_DATA_NAME = "_jsData"; |
| 443 | 427 |
| 444 final ListConstantValue keyList; | 428 final ListConstantValue keyList; |
| 445 final ConstantValue protoValue; | 429 final ConstantValue protoValue; |
| 446 final bool onlyStringKeys; | 430 final bool onlyStringKeys; |
| 447 | 431 |
| 448 JavaScriptMapConstant(ResolutionInterfaceType type, ListConstantValue keyList, | 432 JavaScriptMapConstant(InterfaceType type, ListConstantValue keyList, |
| 449 List<ConstantValue> values, this.protoValue, this.onlyStringKeys) | 433 List<ConstantValue> values, this.protoValue, this.onlyStringKeys) |
| 450 : this.keyList = keyList, | 434 : this.keyList = keyList, |
| 451 super(type, keyList.entries, values); | 435 super(type, keyList.entries, values); |
| 452 bool get isMap => true; | 436 bool get isMap => true; |
| 453 | 437 |
| 454 List<ConstantValue> getDependencies() { | 438 List<ConstantValue> getDependencies() { |
| 455 List<ConstantValue> result = <ConstantValue>[]; | 439 List<ConstantValue> result = <ConstantValue>[]; |
| 456 if (onlyStringKeys) { | 440 if (onlyStringKeys) { |
| 457 result.add(keyList); | 441 result.add(keyList); |
| 458 } else { | 442 } else { |
| 459 // Add the keys individually to avoid generating an unused list constant | 443 // Add the keys individually to avoid generating an unused list constant |
| 460 // for the keys. | 444 // for the keys. |
| 461 result.addAll(keys); | 445 result.addAll(keys); |
| 462 } | 446 } |
| 463 result.addAll(values); | 447 result.addAll(values); |
| 464 return result; | 448 return result; |
| 465 } | 449 } |
| 466 } | 450 } |
| OLD | NEW |