| 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 library dart2js.constants.values; | |
| 6 | |
| 7 import '../dart_types.dart'; | |
| 8 import '../dart2jslib.dart' | |
| 9 show assertDebugMode, | |
| 10 Compiler; | |
| 11 import '../elements/elements.dart' | |
| 12 show ClassElement, | |
| 13 Element, | |
| 14 FunctionElement, | |
| 15 PrefixElement; | |
| 16 import '../tree/tree.dart' hide unparse; | |
| 17 import '../types/types.dart' as ti show TypeMask; | |
| 18 import '../util/util.dart' show SMI_MASK; | |
| 19 | |
| 20 abstract class ConstantValueVisitor<R> { | |
| 21 const ConstantValueVisitor(); | |
| 22 | |
| 23 R visitFunction(FunctionConstantValue constant); | |
| 24 R visitNull(NullConstantValue constant); | |
| 25 R visitInt(IntConstantValue constant); | |
| 26 R visitDouble(DoubleConstantValue constant); | |
| 27 R visitTrue(TrueConstantValue constant); | |
| 28 R visitFalse(FalseConstantValue constant); | |
| 29 R visitString(StringConstantValue constant); | |
| 30 R visitList(ListConstantValue constant); | |
| 31 R visitMap(MapConstantValue constant); | |
| 32 R visitConstructed(ConstructedConstantValue constant); | |
| 33 R visitType(TypeConstantValue constant); | |
| 34 R visitInterceptor(InterceptorConstantValue constant); | |
| 35 R visitDummy(DummyConstantValue constant); | |
| 36 R visitDeferred(DeferredConstantValue constant); | |
| 37 } | |
| 38 | |
| 39 abstract class ConstantValue { | |
| 40 const ConstantValue(); | |
| 41 | |
| 42 bool get isNull => false; | |
| 43 bool get isBool => false; | |
| 44 bool get isTrue => false; | |
| 45 bool get isFalse => false; | |
| 46 bool get isInt => false; | |
| 47 bool get isDouble => false; | |
| 48 bool get isNum => false; | |
| 49 bool get isString => false; | |
| 50 bool get isList => false; | |
| 51 bool get isMap => false; | |
| 52 bool get isConstructedObject => false; | |
| 53 bool get isFunction => false; | |
| 54 /** Returns true if the constant is null, a bool, a number or a string. */ | |
| 55 bool get isPrimitive => false; | |
| 56 /** Returns true if the constant is a list, a map or a constructed object. */ | |
| 57 bool get isObject => false; | |
| 58 bool get isType => false; | |
| 59 bool get isInterceptor => false; | |
| 60 bool get isDummy => false; | |
| 61 | |
| 62 bool get isNaN => false; | |
| 63 bool get isMinusZero => false; | |
| 64 bool get isZero => false; | |
| 65 bool get isOne => false; | |
| 66 | |
| 67 // TODO(johnniwinther): Replace with a 'type' getter. | |
| 68 DartType computeType(Compiler compiler); | |
| 69 | |
| 70 ti.TypeMask computeMask(Compiler compiler); | |
| 71 | |
| 72 List<ConstantValue> getDependencies(); | |
| 73 | |
| 74 accept(ConstantValueVisitor visitor); | |
| 75 | |
| 76 /// The value of this constant in Dart syntax, if possible. | |
| 77 /// | |
| 78 /// For [ConstructedConstantValue]s there is no way to create a valid const | |
| 79 /// expression from the value so the unparse of these is best effort. | |
| 80 /// | |
| 81 /// For the synthetic constants, [DeferredConstantValue], | |
| 82 /// [DummyConstantValue], [InterceptorConstantValue] the unparse is | |
| 83 /// descriptive only. | |
| 84 String unparse(); | |
| 85 | |
| 86 /// Returns a structured representation of this constant suited for debugging. | |
| 87 String toStructuredString(); | |
| 88 | |
| 89 String toString() { | |
| 90 assertDebugMode("Use Constant.unparse() or Constant.toStructuredString() " | |
| 91 "instead of Constant.toString()."); | |
| 92 return toStructuredString(); | |
| 93 } | |
| 94 } | |
| 95 | |
| 96 class FunctionConstantValue extends ConstantValue { | |
| 97 Element element; | |
| 98 | |
| 99 FunctionConstantValue(this.element); | |
| 100 | |
| 101 bool get isFunction => true; | |
| 102 | |
| 103 bool operator ==(var other) { | |
| 104 if (other is !FunctionConstantValue) return false; | |
| 105 return identical(other.element, element); | |
| 106 } | |
| 107 | |
| 108 List<ConstantValue> getDependencies() => const <ConstantValue>[]; | |
| 109 | |
| 110 DartString toDartString() { | |
| 111 return new DartString.literal(element.name); | |
| 112 } | |
| 113 | |
| 114 // TODO(johnniwinther): remove computeType. | |
| 115 DartType computeType(Compiler compiler) => element.computeType(compiler); | |
| 116 | |
| 117 ti.TypeMask computeMask(Compiler compiler) { | |
| 118 return compiler.typesTask.functionType; | |
| 119 } | |
| 120 | |
| 121 int get hashCode => (17 * element.hashCode) & 0x7fffffff; | |
| 122 | |
| 123 accept(ConstantValueVisitor visitor) => visitor.visitFunction(this); | |
| 124 | |
| 125 String unparse() { | |
| 126 if (element.isStatic) { | |
| 127 return '${element.enclosingClass.name}.${element.name}'; | |
| 128 } else { | |
| 129 return '${element.name}'; | |
| 130 } | |
| 131 } | |
| 132 | |
| 133 String toStructuredString() { | |
| 134 return 'FunctionConstant(${unparse()})'; | |
| 135 } | |
| 136 } | |
| 137 | |
| 138 abstract class PrimitiveConstantValue extends ConstantValue { | |
| 139 get primitiveValue; | |
| 140 | |
| 141 const PrimitiveConstantValue(); | |
| 142 | |
| 143 bool get isPrimitive => true; | |
| 144 | |
| 145 bool operator ==(var other) { | |
| 146 if (other is !PrimitiveConstantValue) return false; | |
| 147 PrimitiveConstantValue otherPrimitive = other; | |
| 148 // We use == instead of 'identical' so that DartStrings compare correctly. | |
| 149 return primitiveValue == otherPrimitive.primitiveValue; | |
| 150 } | |
| 151 | |
| 152 int get hashCode => throw new UnsupportedError('PrimitiveConstant.hashCode'); | |
| 153 | |
| 154 // Primitive constants don't have dependencies. | |
| 155 List<ConstantValue> getDependencies() => const <ConstantValue>[]; | |
| 156 | |
| 157 DartString toDartString(); | |
| 158 | |
| 159 /// This value in Dart syntax. | |
| 160 String unparse() => primitiveValue.toString(); | |
| 161 } | |
| 162 | |
| 163 class NullConstantValue extends PrimitiveConstantValue { | |
| 164 /** The value a Dart null is compiled to in JavaScript. */ | |
| 165 static const String JsNull = "null"; | |
| 166 | |
| 167 factory NullConstantValue() => const NullConstantValue._internal(); | |
| 168 | |
| 169 const NullConstantValue._internal(); | |
| 170 | |
| 171 bool get isNull => true; | |
| 172 | |
| 173 get primitiveValue => null; | |
| 174 | |
| 175 DartType computeType(Compiler compiler) { | |
| 176 return compiler.nullClass.computeType(compiler); | |
| 177 } | |
| 178 | |
| 179 ti.TypeMask computeMask(Compiler compiler) { | |
| 180 return compiler.typesTask.nullType; | |
| 181 } | |
| 182 | |
| 183 // The magic constant has no meaning. It is just a random value. | |
| 184 int get hashCode => 785965825; | |
| 185 | |
| 186 DartString toDartString() => const LiteralDartString("null"); | |
| 187 | |
| 188 accept(ConstantValueVisitor visitor) => visitor.visitNull(this); | |
| 189 | |
| 190 String toStructuredString() => 'NullConstant'; | |
| 191 } | |
| 192 | |
| 193 abstract class NumConstantValue extends PrimitiveConstantValue { | |
| 194 const NumConstantValue(); | |
| 195 | |
| 196 num get primitiveValue; | |
| 197 | |
| 198 bool get isNum => true; | |
| 199 } | |
| 200 | |
| 201 class IntConstantValue extends NumConstantValue { | |
| 202 final int primitiveValue; | |
| 203 | |
| 204 factory IntConstantValue(int value) { | |
| 205 switch (value) { | |
| 206 case 0: return const IntConstantValue._internal(0); | |
| 207 case 1: return const IntConstantValue._internal(1); | |
| 208 case 2: return const IntConstantValue._internal(2); | |
| 209 case 3: return const IntConstantValue._internal(3); | |
| 210 case 4: return const IntConstantValue._internal(4); | |
| 211 case 5: return const IntConstantValue._internal(5); | |
| 212 case 6: return const IntConstantValue._internal(6); | |
| 213 case 7: return const IntConstantValue._internal(7); | |
| 214 case 8: return const IntConstantValue._internal(8); | |
| 215 case 9: return const IntConstantValue._internal(9); | |
| 216 case 10: return const IntConstantValue._internal(10); | |
| 217 case -1: return const IntConstantValue._internal(-1); | |
| 218 case -2: return const IntConstantValue._internal(-2); | |
| 219 default: return new IntConstantValue._internal(value); | |
| 220 } | |
| 221 } | |
| 222 | |
| 223 const IntConstantValue._internal(this.primitiveValue); | |
| 224 | |
| 225 bool get isInt => true; | |
| 226 | |
| 227 bool isUInt31() => primitiveValue >= 0 && primitiveValue < (1 << 31); | |
| 228 | |
| 229 bool isUInt32() => primitiveValue >= 0 && primitiveValue < (1 << 32); | |
| 230 | |
| 231 bool isPositive() => primitiveValue >= 0; | |
| 232 | |
| 233 bool get isZero => primitiveValue == 0; | |
| 234 | |
| 235 bool get isOne => primitiveValue == 1; | |
| 236 | |
| 237 DartType computeType(Compiler compiler) { | |
| 238 return compiler.intClass.rawType; | |
| 239 } | |
| 240 | |
| 241 ti.TypeMask computeMask(Compiler compiler) { | |
| 242 if (isUInt31()) return compiler.typesTask.uint31Type; | |
| 243 if (isUInt32()) return compiler.typesTask.uint32Type; | |
| 244 if (isPositive()) return compiler.typesTask.positiveIntType; | |
| 245 return compiler.typesTask.intType; | |
| 246 } | |
| 247 | |
| 248 // We have to override the equality operator so that ints and doubles are | |
| 249 // treated as separate constants. | |
| 250 // The is [:!IntConstant:] check at the beginning of the function makes sure | |
| 251 // that we compare only equal to integer constants. | |
| 252 bool operator ==(var other) { | |
| 253 if (other is !IntConstantValue) return false; | |
| 254 IntConstantValue otherInt = other; | |
| 255 return primitiveValue == otherInt.primitiveValue; | |
| 256 } | |
| 257 | |
| 258 int get hashCode => primitiveValue & SMI_MASK; | |
| 259 | |
| 260 DartString toDartString() { | |
| 261 return new DartString.literal(primitiveValue.toString()); | |
| 262 } | |
| 263 | |
| 264 accept(ConstantValueVisitor visitor) => visitor.visitInt(this); | |
| 265 | |
| 266 String toStructuredString() => 'IntConstant(${unparse()})'; | |
| 267 } | |
| 268 | |
| 269 class DoubleConstantValue extends NumConstantValue { | |
| 270 final double primitiveValue; | |
| 271 | |
| 272 factory DoubleConstantValue(double value) { | |
| 273 if (value.isNaN) { | |
| 274 return const DoubleConstantValue._internal(double.NAN); | |
| 275 } else if (value == double.INFINITY) { | |
| 276 return const DoubleConstantValue._internal(double.INFINITY); | |
| 277 } else if (value == -double.INFINITY) { | |
| 278 return const DoubleConstantValue._internal(-double.INFINITY); | |
| 279 } else if (value == 0.0 && !value.isNegative) { | |
| 280 return const DoubleConstantValue._internal(0.0); | |
| 281 } else if (value == 1.0) { | |
| 282 return const DoubleConstantValue._internal(1.0); | |
| 283 } else { | |
| 284 return new DoubleConstantValue._internal(value); | |
| 285 } | |
| 286 } | |
| 287 | |
| 288 const DoubleConstantValue._internal(this.primitiveValue); | |
| 289 | |
| 290 bool get isDouble => true; | |
| 291 | |
| 292 bool get isNaN => primitiveValue.isNaN; | |
| 293 | |
| 294 // We need to check for the negative sign since -0.0 == 0.0. | |
| 295 bool get isMinusZero => primitiveValue == 0.0 && primitiveValue.isNegative; | |
| 296 | |
| 297 bool get isZero => primitiveValue == 0.0; | |
| 298 | |
| 299 bool get isOne => primitiveValue == 1.0; | |
| 300 | |
| 301 DartType computeType(Compiler compiler) { | |
| 302 return compiler.doubleClass.rawType; | |
| 303 } | |
| 304 | |
| 305 ti.TypeMask computeMask(Compiler compiler) { | |
| 306 // We have to distinguish -0.0 from 0, but for all practical purposes | |
| 307 // -0.0 is an integer. | |
| 308 // TODO(17235): this kind of special casing should only happen in the | |
| 309 // backend. | |
| 310 if (isMinusZero && compiler.backend.constantSystem.isInt(this)) { | |
| 311 return compiler.typesTask.uint31Type; | |
| 312 } | |
| 313 assert(!compiler.backend.constantSystem.isInt(this)); | |
| 314 return compiler.typesTask.doubleType; | |
| 315 } | |
| 316 | |
| 317 bool operator ==(var other) { | |
| 318 if (other is !DoubleConstantValue) return false; | |
| 319 DoubleConstantValue otherDouble = other; | |
| 320 double otherValue = otherDouble.primitiveValue; | |
| 321 if (primitiveValue == 0.0 && otherValue == 0.0) { | |
| 322 return primitiveValue.isNegative == otherValue.isNegative; | |
| 323 } else if (primitiveValue.isNaN) { | |
| 324 return otherValue.isNaN; | |
| 325 } else { | |
| 326 return primitiveValue == otherValue; | |
| 327 } | |
| 328 } | |
| 329 | |
| 330 int get hashCode => primitiveValue.hashCode; | |
| 331 | |
| 332 DartString toDartString() { | |
| 333 return new DartString.literal(primitiveValue.toString()); | |
| 334 } | |
| 335 | |
| 336 accept(ConstantValueVisitor visitor) => visitor.visitDouble(this); | |
| 337 | |
| 338 String toStructuredString() => 'DoubleConstant(${unparse()})'; | |
| 339 } | |
| 340 | |
| 341 abstract class BoolConstantValue extends PrimitiveConstantValue { | |
| 342 factory BoolConstantValue(value) { | |
| 343 return value ? new TrueConstantValue() : new FalseConstantValue(); | |
| 344 } | |
| 345 | |
| 346 const BoolConstantValue._internal(); | |
| 347 | |
| 348 bool get isBool => true; | |
| 349 | |
| 350 DartType computeType(Compiler compiler) { | |
| 351 return compiler.boolClass.rawType; | |
| 352 } | |
| 353 | |
| 354 ti.TypeMask computeMask(Compiler compiler) { | |
| 355 return compiler.typesTask.boolType; | |
| 356 } | |
| 357 | |
| 358 BoolConstantValue negate(); | |
| 359 | |
| 360 String toStructuredString() => 'BoolConstant(${unparse()})'; | |
| 361 } | |
| 362 | |
| 363 class TrueConstantValue extends BoolConstantValue { | |
| 364 factory TrueConstantValue() => const TrueConstantValue._internal(); | |
| 365 | |
| 366 const TrueConstantValue._internal() : super._internal(); | |
| 367 | |
| 368 bool get isTrue => true; | |
| 369 | |
| 370 bool get primitiveValue => true; | |
| 371 | |
| 372 FalseConstantValue negate() => new FalseConstantValue(); | |
| 373 | |
| 374 bool operator ==(var other) => identical(this, other); | |
| 375 | |
| 376 // The magic constant is just a random value. It does not have any | |
| 377 // significance. | |
| 378 int get hashCode => 499; | |
| 379 | |
| 380 DartString toDartString() => const LiteralDartString("true"); | |
| 381 | |
| 382 accept(ConstantValueVisitor visitor) => visitor.visitTrue(this); | |
| 383 } | |
| 384 | |
| 385 class FalseConstantValue extends BoolConstantValue { | |
| 386 factory FalseConstantValue() => const FalseConstantValue._internal(); | |
| 387 | |
| 388 const FalseConstantValue._internal() : super._internal(); | |
| 389 | |
| 390 bool get isFalse => true; | |
| 391 | |
| 392 bool get primitiveValue => false; | |
| 393 | |
| 394 TrueConstantValue negate() => new TrueConstantValue(); | |
| 395 | |
| 396 bool operator ==(var other) => identical(this, other); | |
| 397 | |
| 398 // The magic constant is just a random value. It does not have any | |
| 399 // significance. | |
| 400 int get hashCode => 536555975; | |
| 401 | |
| 402 DartString toDartString() => const LiteralDartString("false"); | |
| 403 | |
| 404 accept(ConstantValueVisitor visitor) => visitor.visitFalse(this); | |
| 405 } | |
| 406 | |
| 407 class StringConstantValue extends PrimitiveConstantValue { | |
| 408 final DartString primitiveValue; | |
| 409 | |
| 410 final int hashCode; | |
| 411 | |
| 412 // TODO(floitsch): cache StringConstants. | |
| 413 // TODO(floitsch): compute hashcode without calling toString() on the | |
| 414 // DartString. | |
| 415 StringConstantValue(DartString value) | |
| 416 : this.primitiveValue = value, | |
| 417 this.hashCode = value.slowToString().hashCode; | |
| 418 | |
| 419 bool get isString => true; | |
| 420 | |
| 421 DartType computeType(Compiler compiler) { | |
| 422 return compiler.stringClass.rawType; | |
| 423 } | |
| 424 | |
| 425 ti.TypeMask computeMask(Compiler compiler) { | |
| 426 return compiler.typesTask.stringType; | |
| 427 } | |
| 428 | |
| 429 bool operator ==(var other) { | |
| 430 if (other is !StringConstantValue) return false; | |
| 431 StringConstantValue otherString = other; | |
| 432 return hashCode == otherString.hashCode && | |
| 433 primitiveValue == otherString.primitiveValue; | |
| 434 } | |
| 435 | |
| 436 DartString toDartString() => primitiveValue; | |
| 437 | |
| 438 int get length => primitiveValue.length; | |
| 439 | |
| 440 accept(ConstantValueVisitor visitor) => visitor.visitString(this); | |
| 441 | |
| 442 // TODO(johnniwinther): Ensure correct escaping. | |
| 443 String unparse() => '"${primitiveValue.slowToString()}"'; | |
| 444 | |
| 445 String toStructuredString() => 'StringConstant(${unparse()})'; | |
| 446 } | |
| 447 | |
| 448 abstract class ObjectConstantValue extends ConstantValue { | |
| 449 final InterfaceType type; | |
| 450 | |
| 451 ObjectConstantValue(this.type); | |
| 452 | |
| 453 bool get isObject => true; | |
| 454 | |
| 455 DartType computeType(Compiler compiler) => type; | |
| 456 | |
| 457 void _unparseTypeArguments(StringBuffer sb) { | |
| 458 if (!type.treatAsRaw) { | |
| 459 sb.write('<'); | |
| 460 sb.write(type.typeArguments.join(', ')); | |
| 461 sb.write('>'); | |
| 462 } | |
| 463 } | |
| 464 } | |
| 465 | |
| 466 class TypeConstantValue extends ObjectConstantValue { | |
| 467 /// The user type that this constant represents. | |
| 468 final DartType representedType; | |
| 469 | |
| 470 TypeConstantValue(this.representedType, InterfaceType type) : super(type); | |
| 471 | |
| 472 bool get isType => true; | |
| 473 | |
| 474 bool operator ==(other) { | |
| 475 return other is TypeConstantValue && | |
| 476 representedType == other.representedType; | |
| 477 } | |
| 478 | |
| 479 ti.TypeMask computeMask(Compiler compiler) { | |
| 480 return compiler.typesTask.typeType; | |
| 481 } | |
| 482 | |
| 483 int get hashCode => representedType.hashCode * 13; | |
| 484 | |
| 485 List<ConstantValue> getDependencies() => const <ConstantValue>[]; | |
| 486 | |
| 487 accept(ConstantValueVisitor visitor) => visitor.visitType(this); | |
| 488 | |
| 489 String unparse() => '$representedType'; | |
| 490 | |
| 491 String toStructuredString() => 'TypeConstant(${representedType})'; | |
| 492 } | |
| 493 | |
| 494 class ListConstantValue extends ObjectConstantValue { | |
| 495 final List<ConstantValue> entries; | |
| 496 final int hashCode; | |
| 497 | |
| 498 ListConstantValue(InterfaceType type, List<ConstantValue> entries) | |
| 499 : this.entries = entries, | |
| 500 hashCode = _computeHash(type, entries), | |
| 501 super(type); | |
| 502 | |
| 503 bool get isList => true; | |
| 504 | |
| 505 static int _computeHash(DartType type, List<ConstantValue> entries) { | |
| 506 // TODO(floitsch): create a better hash. | |
| 507 int hash = 7; | |
| 508 for (ConstantValue input in entries) { | |
| 509 hash ^= input.hashCode; | |
| 510 } | |
| 511 hash ^= type.hashCode; | |
| 512 return hash; | |
| 513 } | |
| 514 | |
| 515 bool operator ==(var other) { | |
| 516 if (other is !ListConstantValue) return false; | |
| 517 ListConstantValue otherList = other; | |
| 518 if (hashCode != otherList.hashCode) return false; | |
| 519 if (type != otherList.type) return false; | |
| 520 if (entries.length != otherList.entries.length) return false; | |
| 521 for (int i = 0; i < entries.length; i++) { | |
| 522 if (entries[i] != otherList.entries[i]) return false; | |
| 523 } | |
| 524 return true; | |
| 525 } | |
| 526 | |
| 527 List<ConstantValue> getDependencies() => entries; | |
| 528 | |
| 529 int get length => entries.length; | |
| 530 | |
| 531 ti.TypeMask computeMask(Compiler compiler) { | |
| 532 return compiler.typesTask.constListType; | |
| 533 } | |
| 534 | |
| 535 accept(ConstantValueVisitor visitor) => visitor.visitList(this); | |
| 536 | |
| 537 String unparse() { | |
| 538 StringBuffer sb = new StringBuffer(); | |
| 539 _unparseTypeArguments(sb); | |
| 540 sb.write('['); | |
| 541 for (int i = 0 ; i < length ; i++) { | |
| 542 if (i > 0) sb.write(','); | |
| 543 sb.write(entries[i].unparse()); | |
| 544 } | |
| 545 sb.write(']'); | |
| 546 return sb.toString(); | |
| 547 } | |
| 548 | |
| 549 String toStructuredString() { | |
| 550 StringBuffer sb = new StringBuffer(); | |
| 551 sb.write('ListConstant(['); | |
| 552 for (int i = 0 ; i < length ; i++) { | |
| 553 if (i > 0) sb.write(','); | |
| 554 sb.write(entries[i].toStructuredString()); | |
| 555 } | |
| 556 sb.write('])'); | |
| 557 return sb.toString(); | |
| 558 } | |
| 559 } | |
| 560 | |
| 561 class MapConstantValue extends ObjectConstantValue { | |
| 562 final List<ConstantValue> keys; | |
| 563 final List<ConstantValue> values; | |
| 564 final int hashCode; | |
| 565 | |
| 566 MapConstantValue(InterfaceType type, | |
| 567 List<ConstantValue> keys, | |
| 568 List<ConstantValue> values) | |
| 569 : this.keys = keys, | |
| 570 this.values = values, | |
| 571 this.hashCode = computeHash(type, keys, values), | |
| 572 super(type) { | |
| 573 assert(keys.length == values.length); | |
| 574 } | |
| 575 | |
| 576 bool get isMap => true; | |
| 577 | |
| 578 static int computeHash(DartType type, | |
| 579 List<ConstantValue> keys, | |
| 580 List<ConstantValue> values) { | |
| 581 // TODO(floitsch): create a better hash. | |
| 582 int hash = 0; | |
| 583 for (ConstantValue key in keys) { | |
| 584 hash ^= key.hashCode; | |
| 585 } | |
| 586 for (ConstantValue value in values) { | |
| 587 hash ^= value.hashCode; | |
| 588 } | |
| 589 hash ^= type.hashCode; | |
| 590 return hash; | |
| 591 } | |
| 592 | |
| 593 ti.TypeMask computeMask(Compiler compiler) { | |
| 594 return compiler.typesTask.constMapType; | |
| 595 } | |
| 596 | |
| 597 bool operator ==(var other) { | |
| 598 if (other is !MapConstantValue) return false; | |
| 599 MapConstantValue otherMap = other; | |
| 600 if (hashCode != otherMap.hashCode) return false; | |
| 601 if (type != other.type) return false; | |
| 602 if (length != other.length) return false; | |
| 603 for (int i = 0; i < length; i++) { | |
| 604 if (keys[i] != otherMap.keys[i]) return false; | |
| 605 if (values[i] != otherMap.values[i]) return false; | |
| 606 } | |
| 607 return true; | |
| 608 } | |
| 609 | |
| 610 List<ConstantValue> getDependencies() { | |
| 611 List<ConstantValue> result = <ConstantValue>[]; | |
| 612 result.addAll(keys); | |
| 613 result.addAll(values); | |
| 614 return result; | |
| 615 } | |
| 616 | |
| 617 int get length => keys.length; | |
| 618 | |
| 619 accept(ConstantValueVisitor visitor) => visitor.visitMap(this); | |
| 620 | |
| 621 String unparse() { | |
| 622 StringBuffer sb = new StringBuffer(); | |
| 623 _unparseTypeArguments(sb); | |
| 624 sb.write('{'); | |
| 625 for (int i = 0 ; i < length ; i++) { | |
| 626 if (i > 0) sb.write(','); | |
| 627 sb.write(keys[i].unparse()); | |
| 628 sb.write(':'); | |
| 629 sb.write(values[i].unparse()); | |
| 630 } | |
| 631 sb.write('}'); | |
| 632 return sb.toString(); | |
| 633 } | |
| 634 | |
| 635 String toStructuredString() { | |
| 636 StringBuffer sb = new StringBuffer(); | |
| 637 sb.write('MapConstant({'); | |
| 638 for (int i = 0; i < length; i++) { | |
| 639 if (i > 0) sb.write(','); | |
| 640 sb.write(keys[i].toStructuredString()); | |
| 641 sb.write(':'); | |
| 642 sb.write(values[i].toStructuredString()); | |
| 643 } | |
| 644 sb.write('})'); | |
| 645 return sb.toString(); | |
| 646 } | |
| 647 } | |
| 648 | |
| 649 class InterceptorConstantValue extends ConstantValue { | |
| 650 /// The type for which this interceptor holds the methods. The constant | |
| 651 /// is a dispatch table for this type. | |
| 652 final DartType dispatchedType; | |
| 653 | |
| 654 InterceptorConstantValue(this.dispatchedType); | |
| 655 | |
| 656 bool get isInterceptor => true; | |
| 657 | |
| 658 bool operator ==(other) { | |
| 659 return other is InterceptorConstantValue | |
| 660 && dispatchedType == other.dispatchedType; | |
| 661 } | |
| 662 | |
| 663 int get hashCode => dispatchedType.hashCode * 43; | |
| 664 | |
| 665 List<ConstantValue> getDependencies() => const <ConstantValue>[]; | |
| 666 | |
| 667 accept(ConstantValueVisitor visitor) => visitor.visitInterceptor(this); | |
| 668 | |
| 669 DartType computeType(Compiler compiler) => const DynamicType(); | |
| 670 | |
| 671 ti.TypeMask computeMask(Compiler compiler) { | |
| 672 return compiler.typesTask.nonNullType; | |
| 673 } | |
| 674 | |
| 675 String unparse() { | |
| 676 return 'interceptor($dispatchedType)'; | |
| 677 } | |
| 678 | |
| 679 String toStructuredString() { | |
| 680 return 'InterceptorConstant(${dispatchedType.getStringAsDeclared("o")})'; | |
| 681 } | |
| 682 } | |
| 683 | |
| 684 class DummyConstantValue extends ConstantValue { | |
| 685 final ti.TypeMask typeMask; | |
| 686 | |
| 687 DummyConstantValue(this.typeMask); | |
| 688 | |
| 689 bool get isDummy => true; | |
| 690 | |
| 691 bool operator ==(other) { | |
| 692 return other is DummyConstantValue | |
| 693 && typeMask == other.typeMask; | |
| 694 } | |
| 695 | |
| 696 get hashCode => typeMask.hashCode; | |
| 697 | |
| 698 List<ConstantValue> getDependencies() => const <ConstantValue>[]; | |
| 699 | |
| 700 accept(ConstantValueVisitor visitor) => visitor.visitDummy(this); | |
| 701 | |
| 702 DartType computeType(Compiler compiler) => const DynamicType(); | |
| 703 | |
| 704 ti.TypeMask computeMask(Compiler compiler) => typeMask; | |
| 705 | |
| 706 String unparse() => 'dummy($typeMask)'; | |
| 707 | |
| 708 String toStructuredString() => 'DummyConstant($typeMask)'; | |
| 709 } | |
| 710 | |
| 711 class ConstructedConstantValue extends ObjectConstantValue { | |
| 712 final List<ConstantValue> fields; | |
| 713 final int hashCode; | |
| 714 | |
| 715 ConstructedConstantValue(InterfaceType type, List<ConstantValue> fields) | |
| 716 : this.fields = fields, | |
| 717 hashCode = computeHash(type, fields), | |
| 718 super(type) { | |
| 719 assert(type != null); | |
| 720 } | |
| 721 | |
| 722 bool get isConstructedObject => true; | |
| 723 | |
| 724 static int computeHash(DartType type, List<ConstantValue> fields) { | |
| 725 // TODO(floitsch): create a better hash. | |
| 726 int hash = 0; | |
| 727 for (ConstantValue field in fields) { | |
| 728 hash ^= field.hashCode; | |
| 729 } | |
| 730 hash ^= type.hashCode; | |
| 731 return hash; | |
| 732 } | |
| 733 | |
| 734 bool operator ==(var otherVar) { | |
| 735 if (otherVar is !ConstructedConstantValue) return false; | |
| 736 ConstructedConstantValue other = otherVar; | |
| 737 if (hashCode != other.hashCode) return false; | |
| 738 if (type != other.type) return false; | |
| 739 if (fields.length != other.fields.length) return false; | |
| 740 for (int i = 0; i < fields.length; i++) { | |
| 741 if (fields[i] != other.fields[i]) return false; | |
| 742 } | |
| 743 return true; | |
| 744 } | |
| 745 | |
| 746 List<ConstantValue> getDependencies() => fields; | |
| 747 | |
| 748 ti.TypeMask computeMask(Compiler compiler) { | |
| 749 if (compiler.backend.isInterceptorClass(type.element)) { | |
| 750 return compiler.typesTask.nonNullType; | |
| 751 } | |
| 752 return new ti.TypeMask.nonNullExact(type.element, compiler.world); | |
| 753 } | |
| 754 | |
| 755 accept(ConstantValueVisitor visitor) => visitor.visitConstructed(this); | |
| 756 | |
| 757 Map<Element, ConstantValue> get fieldElements { | |
| 758 // TODO(ahe): Refactor constant system to store this information directly. | |
| 759 ClassElement classElement = type.element; | |
| 760 int count = 0; | |
| 761 Map<Element, ConstantValue> result = new Map<Element, ConstantValue>(); | |
| 762 classElement.implementation.forEachInstanceField((holder, field) { | |
| 763 result[field] = fields[count++]; | |
| 764 }, includeSuperAndInjectedMembers: true); | |
| 765 return result; | |
| 766 } | |
| 767 | |
| 768 String unparse() { | |
| 769 StringBuffer sb = new StringBuffer(); | |
| 770 sb.write(type.name); | |
| 771 _unparseTypeArguments(sb); | |
| 772 sb.write('('); | |
| 773 int i = 0; | |
| 774 fieldElements.forEach((Element field, ConstantValue value) { | |
| 775 if (i > 0) sb.write(','); | |
| 776 sb.write(field.name); | |
| 777 sb.write('='); | |
| 778 sb.write(value.unparse()); | |
| 779 i++; | |
| 780 }); | |
| 781 sb.write(')'); | |
| 782 return sb.toString(); | |
| 783 } | |
| 784 | |
| 785 String toStructuredString() { | |
| 786 StringBuffer sb = new StringBuffer(); | |
| 787 sb.write('ConstructedConstant('); | |
| 788 sb.write(type); | |
| 789 sb.write('('); | |
| 790 int i = 0; | |
| 791 fieldElements.forEach((Element field, ConstantValue value) { | |
| 792 if (i > 0) sb.write(','); | |
| 793 sb.write(field.name); | |
| 794 sb.write('='); | |
| 795 sb.write(value.toStructuredString()); | |
| 796 i++; | |
| 797 }); | |
| 798 sb.write('))'); | |
| 799 return sb.toString(); | |
| 800 } | |
| 801 } | |
| 802 | |
| 803 /// A reference to a constant in another output unit. | |
| 804 /// Used for referring to deferred constants. | |
| 805 class DeferredConstantValue extends ConstantValue { | |
| 806 DeferredConstantValue(this.referenced, this.prefix); | |
| 807 | |
| 808 final ConstantValue referenced; | |
| 809 final PrefixElement prefix; | |
| 810 | |
| 811 bool get isReference => true; | |
| 812 | |
| 813 bool operator ==(other) { | |
| 814 return other is DeferredConstantValue | |
| 815 && referenced == other.referenced | |
| 816 && prefix == other.prefix; | |
| 817 } | |
| 818 | |
| 819 get hashCode => (referenced.hashCode * 17 + prefix.hashCode) & 0x3fffffff; | |
| 820 | |
| 821 List<ConstantValue> getDependencies() => <ConstantValue>[referenced]; | |
| 822 | |
| 823 accept(ConstantValueVisitor visitor) => visitor.visitDeferred(this); | |
| 824 | |
| 825 DartType computeType(Compiler compiler) => referenced.computeType(compiler); | |
| 826 | |
| 827 ti.TypeMask computeMask(Compiler compiler) { | |
| 828 return referenced.computeMask(compiler); | |
| 829 } | |
| 830 | |
| 831 String unparse() => 'deferred(${referenced.unparse()})'; | |
| 832 | |
| 833 String toStructuredString() => 'DeferredConstant($referenced)'; | |
| 834 } | |
| OLD | NEW |