| 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 interface ConstantVisitor<R> { | |
| 6 R visitSentinel(SentinelConstant constant); | |
| 7 R visitFunction(FunctionConstant constant); | |
| 8 R visitNull(NullConstant constant); | |
| 9 R visitInt(IntConstant constant); | |
| 10 R visitDouble(DoubleConstant constant); | |
| 11 R visitTrue(TrueConstant constant); | |
| 12 R visitFalse(FalseConstant constant); | |
| 13 R visitString(StringConstant constant); | |
| 14 R visitList(ListConstant constant); | |
| 15 R visitMap(MapConstant constant); | |
| 16 R visitConstructed(ConstructedConstant constant); | |
| 17 } | |
| 18 | |
| 19 class Constant implements Hashable { | 5 class Constant implements Hashable { |
| 20 const Constant(); | 6 const Constant(); |
| 21 | 7 |
| 22 bool isNull() => false; | 8 bool isNull() => false; |
| 23 bool isBool() => false; | 9 bool isBool() => false; |
| 24 bool isTrue() => false; | 10 bool isTrue() => false; |
| 25 bool isFalse() => false; | 11 bool isFalse() => false; |
| 26 bool isInt() => false; | 12 bool isInt() => false; |
| 27 bool isDouble() => false; | 13 bool isDouble() => false; |
| 28 bool isNum() => false; | 14 bool isNum() => false; |
| 29 bool isString() => false; | 15 bool isString() => false; |
| 30 bool isList() => false; | 16 bool isList() => false; |
| 31 bool isMap() => false; | 17 bool isMap() => false; |
| 32 bool isConstructedObject() => false; | 18 bool isConstructedObject() => false; |
| 33 bool isFunction() => false; | 19 bool isFunction() => false; |
| 34 /** Returns true if the constant is null, a bool, a number or a string. */ | 20 /** Returns true if the constant is null, a bool, a number or a string. */ |
| 35 bool isPrimitive() => false; | 21 bool isPrimitive() => false; |
| 36 /** Returns true if the constant is a list, a map or a constructed object. */ | 22 /** Returns true if the constant is a list, a map or a constructed object. */ |
| 37 bool isObject() => false; | 23 bool isObject() => false; |
| 38 bool isSentinel() => false; | 24 bool isSentinel() => false; |
| 39 | 25 |
| 40 bool isNaN() => false; | 26 bool isNaN() => false; |
| 41 bool isMinusZero() => false; | 27 bool isMinusZero() => false; |
| 42 | 28 |
| 29 abstract void _writeJsCode(CodeBuffer buffer, ConstantHandler handler); |
| 30 /** |
| 31 * Unless the constant can be emitted multiple times (as for numbers and |
| 32 * strings) adds its canonical name to the buffer. |
| 33 */ |
| 34 abstract void _writeCanonicalizedJsCode(CodeBuffer buffer, |
| 35 ConstantHandler handler); |
| 43 abstract List<Constant> getDependencies(); | 36 abstract List<Constant> getDependencies(); |
| 44 | |
| 45 abstract accept(ConstantVisitor); | |
| 46 } | 37 } |
| 47 | 38 |
| 48 class SentinelConstant extends Constant { | 39 class SentinelConstant extends Constant { |
| 49 const SentinelConstant(); | 40 const SentinelConstant(); |
| 50 static final SENTINEL = const SentinelConstant(); | 41 static final SENTINEL = const SentinelConstant(); |
| 51 | 42 |
| 43 void _writeJsCode(CodeBuffer buffer, ConstantHandler handler) { |
| 44 handler.compiler.internalError( |
| 45 "The parameter sentinel constant does not need specific JS code"); |
| 46 } |
| 47 |
| 48 void _writeCanonicalizedJsCode(CodeBuffer buffer, ConstantHandler handler) { |
| 49 buffer.add(handler.compiler.namer.CURRENT_ISOLATE); |
| 50 } |
| 51 |
| 52 List<Constant> getDependencies() => const <Constant>[]; | 52 List<Constant> getDependencies() => const <Constant>[]; |
| 53 | 53 |
| 54 // Just use a random value. | 54 // Just use a randome value. |
| 55 int hashCode() => 24297418; | 55 int hashCode() => 926429784158; |
| 56 | 56 |
| 57 bool isSentinel() => true; | 57 bool isSentinel() => true; |
| 58 | |
| 59 accept(ConstantVisitor visitor) => visitor.visitSentinel(this); | |
| 60 } | 58 } |
| 61 | 59 |
| 62 class FunctionConstant extends Constant { | 60 class FunctionConstant extends Constant { |
| 63 Element element; | 61 Element element; |
| 64 | 62 |
| 65 FunctionConstant(this.element); | 63 FunctionConstant(this.element); |
| 66 | 64 |
| 67 bool isFunction() => true; | 65 bool isFunction() => true; |
| 68 | 66 |
| 69 bool operator ==(var other) { | 67 bool operator ==(var other) { |
| 70 if (other is !FunctionConstant) return false; | 68 if (other is !FunctionConstant) return false; |
| 71 return other.element === element; | 69 return other.element === element; |
| 72 } | 70 } |
| 73 | 71 |
| 74 String toString() => element.toString(); | 72 String toString() => element.toString(); |
| 75 List<Constant> getDependencies() => const <Constant>[]; | 73 List<Constant> getDependencies() => const <Constant>[]; |
| 76 DartString toDartString() { | 74 DartString toDartString() { |
| 77 return new DartString.literal(element.name.slowToString()); | 75 return new DartString.literal(element.name.slowToString()); |
| 78 } | 76 } |
| 79 | 77 |
| 78 void _writeJsCode(CodeBuffer buffer, ConstantHandler handler) { |
| 79 handler.compiler.internalError( |
| 80 "A constant function does not need specific JS code"); |
| 81 } |
| 82 |
| 83 void _writeCanonicalizedJsCode(CodeBuffer buffer, ConstantHandler handler) { |
| 84 buffer.add(handler.compiler.namer.isolatePropertiesAccess(element)); |
| 85 } |
| 86 |
| 80 int hashCode() => (17 * element.hashCode()) & 0x7fffffff; | 87 int hashCode() => (17 * element.hashCode()) & 0x7fffffff; |
| 81 | |
| 82 accept(ConstantVisitor visitor) => visitor.visitFunction(this); | |
| 83 } | 88 } |
| 84 | 89 |
| 85 class PrimitiveConstant extends Constant { | 90 class PrimitiveConstant extends Constant { |
| 86 abstract get value; | 91 abstract get value; |
| 87 const PrimitiveConstant(); | 92 const PrimitiveConstant(); |
| 88 bool isPrimitive() => true; | 93 bool isPrimitive() => true; |
| 89 | 94 |
| 90 bool operator ==(var other) { | 95 bool operator ==(var other) { |
| 91 if (other is !PrimitiveConstant) return false; | 96 if (other is !PrimitiveConstant) return false; |
| 92 PrimitiveConstant otherPrimitive = other; | 97 PrimitiveConstant otherPrimitive = other; |
| 93 // We use == instead of === so that DartStrings compare correctly. | 98 // We use == instead of === so that DartStrings compare correctly. |
| 94 return value == otherPrimitive.value; | 99 return value == otherPrimitive.value; |
| 95 } | 100 } |
| 96 | 101 |
| 97 String toString() => value.toString(); | 102 String toString() => value.toString(); |
| 98 // Primitive constants don't have dependencies. | 103 // Primitive constants don't have dependencies. |
| 99 List<Constant> getDependencies() => const <Constant>[]; | 104 List<Constant> getDependencies() => const <Constant>[]; |
| 100 abstract DartString toDartString(); | 105 abstract DartString toDartString(); |
| 106 |
| 107 void _writeCanonicalizedJsCode(CodeBuffer buffer, ConstantHandler handler) { |
| 108 _writeJsCode(buffer, handler); |
| 109 } |
| 101 } | 110 } |
| 102 | 111 |
| 103 class NullConstant extends PrimitiveConstant { | 112 class NullConstant extends PrimitiveConstant { |
| 104 /** The value a Dart null is compiled to in JavaScript. */ | 113 /** The value a Dart null is compiled to in JavaScript. */ |
| 105 static const String JsNull = "null"; | 114 static const String JsNull = "null"; |
| 106 | 115 |
| 107 factory NullConstant() => const NullConstant._internal(); | 116 factory NullConstant() => const NullConstant._internal(); |
| 108 const NullConstant._internal(); | 117 const NullConstant._internal(); |
| 109 bool isNull() => true; | 118 bool isNull() => true; |
| 110 get value => null; | 119 get value => null; |
| 111 | 120 |
| 112 void _writeJsCode(CodeBuffer buffer, ConstantHandler handler) { | 121 void _writeJsCode(CodeBuffer buffer, ConstantHandler handler) { |
| 113 buffer.add(JsNull); | 122 buffer.add(JsNull); |
| 114 } | 123 } |
| 115 | 124 |
| 116 // The magic constant has no meaning. It is just a random value. | 125 // The magic constant has no meaning. It is just a random value. |
| 117 int hashCode() => 785965825; | 126 int hashCode() => 785965825; |
| 118 DartString toDartString() => const LiteralDartString("null"); | 127 DartString toDartString() => const LiteralDartString("null"); |
| 119 | |
| 120 accept(ConstantVisitor visitor) => visitor.visitNull(this); | |
| 121 } | 128 } |
| 122 | 129 |
| 123 class NumConstant extends PrimitiveConstant { | 130 class NumConstant extends PrimitiveConstant { |
| 124 abstract num get value; | 131 abstract num get value; |
| 125 const NumConstant(); | 132 const NumConstant(); |
| 126 bool isNum() => true; | 133 bool isNum() => true; |
| 127 } | 134 } |
| 128 | 135 |
| 129 class IntConstant extends NumConstant { | 136 class IntConstant extends NumConstant { |
| 130 final int value; | 137 final int value; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 142 case 9: return const IntConstant._internal(9); | 149 case 9: return const IntConstant._internal(9); |
| 143 case 10: return const IntConstant._internal(10); | 150 case 10: return const IntConstant._internal(10); |
| 144 case -1: return const IntConstant._internal(-1); | 151 case -1: return const IntConstant._internal(-1); |
| 145 case -2: return const IntConstant._internal(-2); | 152 case -2: return const IntConstant._internal(-2); |
| 146 default: return new IntConstant._internal(value); | 153 default: return new IntConstant._internal(value); |
| 147 } | 154 } |
| 148 } | 155 } |
| 149 const IntConstant._internal(this.value); | 156 const IntConstant._internal(this.value); |
| 150 bool isInt() => true; | 157 bool isInt() => true; |
| 151 | 158 |
| 159 void _writeJsCode(CodeBuffer buffer, ConstantHandler handler) { |
| 160 buffer.add("$value"); |
| 161 } |
| 162 |
| 152 // We have to override the equality operator so that ints and doubles are | 163 // We have to override the equality operator so that ints and doubles are |
| 153 // treated as separate constants. | 164 // treated as separate constants. |
| 154 // The is [:!IntConstant:] check at the beginning of the function makes sure | 165 // The is [:!IntConstant:] check at the beginning of the function makes sure |
| 155 // that we compare only equal to integer constants. | 166 // that we compare only equal to integer constants. |
| 156 bool operator ==(var other) { | 167 bool operator ==(var other) { |
| 157 if (other is !IntConstant) return false; | 168 if (other is !IntConstant) return false; |
| 158 IntConstant otherInt = other; | 169 IntConstant otherInt = other; |
| 159 return value == otherInt.value; | 170 return value == otherInt.value; |
| 160 } | 171 } |
| 161 | 172 |
| 162 int hashCode() => value.hashCode(); | 173 int hashCode() => value.hashCode(); |
| 163 DartString toDartString() => new DartString.literal(value.toString()); | 174 DartString toDartString() => new DartString.literal(value.toString()); |
| 164 | |
| 165 accept(ConstantVisitor visitor) => visitor.visitInt(this); | |
| 166 } | 175 } |
| 167 | 176 |
| 168 class DoubleConstant extends NumConstant { | 177 class DoubleConstant extends NumConstant { |
| 169 final double value; | 178 final double value; |
| 170 factory DoubleConstant(double value) { | 179 factory DoubleConstant(double value) { |
| 171 if (value.isNaN()) { | 180 if (value.isNaN()) { |
| 172 return const DoubleConstant._internal(double.NAN); | 181 return const DoubleConstant._internal(double.NAN); |
| 173 } else if (value == double.INFINITY) { | 182 } else if (value == double.INFINITY) { |
| 174 return const DoubleConstant._internal(double.INFINITY); | 183 return const DoubleConstant._internal(double.INFINITY); |
| 175 } else if (value == -double.INFINITY) { | 184 } else if (value == -double.INFINITY) { |
| 176 return const DoubleConstant._internal(-double.INFINITY); | 185 return const DoubleConstant._internal(-double.INFINITY); |
| 177 } else if (value == 0.0 && !value.isNegative()) { | 186 } else if (value == 0.0 && !value.isNegative()) { |
| 178 return const DoubleConstant._internal(0.0); | 187 return const DoubleConstant._internal(0.0); |
| 179 } else if (value == 1.0) { | 188 } else if (value == 1.0) { |
| 180 return const DoubleConstant._internal(1.0); | 189 return const DoubleConstant._internal(1.0); |
| 181 } else { | 190 } else { |
| 182 return new DoubleConstant._internal(value); | 191 return new DoubleConstant._internal(value); |
| 183 } | 192 } |
| 184 } | 193 } |
| 185 const DoubleConstant._internal(this.value); | 194 const DoubleConstant._internal(this.value); |
| 186 bool isDouble() => true; | 195 bool isDouble() => true; |
| 187 bool isNaN() => value.isNaN(); | 196 bool isNaN() => value.isNaN(); |
| 188 // We need to check for the negative sign since -0.0 == 0.0. | 197 // We need to check for the negative sign since -0.0 == 0.0. |
| 189 bool isMinusZero() => value == 0.0 && value.isNegative(); | 198 bool isMinusZero() => value == 0.0 && value.isNegative(); |
| 190 | 199 |
| 200 void _writeJsCode(CodeBuffer buffer, ConstantHandler handler) { |
| 201 if (value.isNaN()) { |
| 202 buffer.add("(0/0)"); |
| 203 } else if (value == double.INFINITY) { |
| 204 buffer.add("(1/0)"); |
| 205 } else if (value == -double.INFINITY) { |
| 206 buffer.add("(-1/0)"); |
| 207 } else { |
| 208 buffer.add("$value"); |
| 209 } |
| 210 } |
| 211 |
| 191 bool operator ==(var other) { | 212 bool operator ==(var other) { |
| 192 if (other is !DoubleConstant) return false; | 213 if (other is !DoubleConstant) return false; |
| 193 DoubleConstant otherDouble = other; | 214 DoubleConstant otherDouble = other; |
| 194 double otherValue = otherDouble.value; | 215 double otherValue = otherDouble.value; |
| 195 if (value == 0.0 && otherValue == 0.0) { | 216 if (value == 0.0 && otherValue == 0.0) { |
| 196 return value.isNegative() == otherValue.isNegative(); | 217 return value.isNegative() == otherValue.isNegative(); |
| 197 } else if (value.isNaN()) { | 218 } else if (value.isNaN()) { |
| 198 return otherValue.isNaN(); | 219 return otherValue.isNaN(); |
| 199 } else { | 220 } else { |
| 200 return value == otherValue; | 221 return value == otherValue; |
| 201 } | 222 } |
| 202 } | 223 } |
| 203 | 224 |
| 204 int hashCode() => value.hashCode(); | 225 int hashCode() => value.hashCode(); |
| 205 DartString toDartString() => new DartString.literal(value.toString()); | 226 DartString toDartString() => new DartString.literal(value.toString()); |
| 206 | |
| 207 accept(ConstantVisitor visitor) => visitor.visitDouble(this); | |
| 208 } | 227 } |
| 209 | 228 |
| 210 class BoolConstant extends PrimitiveConstant { | 229 class BoolConstant extends PrimitiveConstant { |
| 211 factory BoolConstant(value) { | 230 factory BoolConstant(value) { |
| 212 return value ? new TrueConstant() : new FalseConstant(); | 231 return value ? new TrueConstant() : new FalseConstant(); |
| 213 } | 232 } |
| 214 const BoolConstant._internal(); | 233 const BoolConstant._internal(); |
| 215 bool isBool() => true; | 234 bool isBool() => true; |
| 216 | 235 |
| 217 abstract BoolConstant negate(); | 236 abstract BoolConstant negate(); |
| 218 } | 237 } |
| 219 | 238 |
| 220 class TrueConstant extends BoolConstant { | 239 class TrueConstant extends BoolConstant { |
| 221 final bool value = true; | 240 final bool value = true; |
| 222 | 241 |
| 223 factory TrueConstant() => const TrueConstant._internal(); | 242 factory TrueConstant() => const TrueConstant._internal(); |
| 224 const TrueConstant._internal() : super._internal(); | 243 const TrueConstant._internal() : super._internal(); |
| 225 bool isTrue() => true; | 244 bool isTrue() => true; |
| 226 | 245 |
| 246 void _writeJsCode(CodeBuffer buffer, ConstantHandler handler) { |
| 247 buffer.add("true"); |
| 248 } |
| 249 |
| 227 FalseConstant negate() => new FalseConstant(); | 250 FalseConstant negate() => new FalseConstant(); |
| 228 | 251 |
| 229 bool operator ==(var other) => this === other; | 252 bool operator ==(var other) => this === other; |
| 230 // The magic constant is just a random value. It does not have any | 253 // The magic constant is just a random value. It does not have any |
| 231 // significance. | 254 // significance. |
| 232 int hashCode() => 499; | 255 int hashCode() => 499; |
| 233 DartString toDartString() => const LiteralDartString("true"); | 256 DartString toDartString() => const LiteralDartString("true"); |
| 234 | |
| 235 accept(ConstantVisitor visitor) => visitor.visitTrue(this); | |
| 236 } | 257 } |
| 237 | 258 |
| 238 class FalseConstant extends BoolConstant { | 259 class FalseConstant extends BoolConstant { |
| 239 final bool value = false; | 260 final bool value = false; |
| 240 | 261 |
| 241 factory FalseConstant() => const FalseConstant._internal(); | 262 factory FalseConstant() => const FalseConstant._internal(); |
| 242 const FalseConstant._internal() : super._internal(); | 263 const FalseConstant._internal() : super._internal(); |
| 243 bool isFalse() => true; | 264 bool isFalse() => true; |
| 244 | 265 |
| 266 void _writeJsCode(CodeBuffer buffer, ConstantHandler handler) { |
| 267 buffer.add("false"); |
| 268 } |
| 269 |
| 245 TrueConstant negate() => new TrueConstant(); | 270 TrueConstant negate() => new TrueConstant(); |
| 246 | 271 |
| 247 bool operator ==(var other) => this === other; | 272 bool operator ==(var other) => this === other; |
| 248 // The magic constant is just a random value. It does not have any | 273 // The magic constant is just a random value. It does not have any |
| 249 // significance. | 274 // significance. |
| 250 int hashCode() => 536555975; | 275 int hashCode() => 536555975; |
| 251 DartString toDartString() => const LiteralDartString("false"); | 276 DartString toDartString() => const LiteralDartString("false"); |
| 252 | |
| 253 accept(ConstantVisitor visitor) => visitor.visitFalse(this); | |
| 254 } | 277 } |
| 255 | 278 |
| 256 class StringConstant extends PrimitiveConstant { | 279 class StringConstant extends PrimitiveConstant { |
| 257 final DartString value; | 280 final DartString value; |
| 258 int _hashCode; | 281 int _hashCode; |
| 259 final Node node; | 282 final Node node; |
| 260 | 283 |
| 261 StringConstant(this.value, this.node) { | 284 StringConstant(this.value, this.node) { |
| 262 // TODO(floitsch): cache StringConstants. | 285 // TODO(floitsch): cache StringConstants. |
| 263 // TODO(floitsch): compute hashcode without calling toString() on the | 286 // TODO(floitsch): compute hashcode without calling toString() on the |
| 264 // DartString. | 287 // DartString. |
| 265 _hashCode = value.slowToString().hashCode(); | 288 _hashCode = value.slowToString().hashCode(); |
| 266 } | 289 } |
| 267 bool isString() => true; | 290 bool isString() => true; |
| 268 | 291 |
| 292 void _writeJsCode(CodeBuffer buffer, ConstantHandler handler) { |
| 293 buffer.add("'"); |
| 294 ConstantHandler.writeEscapedString(value, buffer, (reason) { |
| 295 handler.compiler.reportError(node, reason); |
| 296 }); |
| 297 buffer.add("'"); |
| 298 } |
| 299 |
| 269 bool operator ==(var other) { | 300 bool operator ==(var other) { |
| 270 if (other is !StringConstant) return false; | 301 if (other is !StringConstant) return false; |
| 271 StringConstant otherString = other; | 302 StringConstant otherString = other; |
| 272 return (_hashCode == otherString._hashCode) && (value == otherString.value); | 303 return (_hashCode == otherString._hashCode) && (value == otherString.value); |
| 273 } | 304 } |
| 274 | 305 |
| 275 int hashCode() => _hashCode; | 306 int hashCode() => _hashCode; |
| 276 DartString toDartString() => value; | 307 DartString toDartString() => value; |
| 277 int get length => value.length; | 308 int get length => value.length; |
| 278 | |
| 279 accept(ConstantVisitor visitor) => visitor.visitString(this); | |
| 280 } | 309 } |
| 281 | 310 |
| 282 class ObjectConstant extends Constant { | 311 class ObjectConstant extends Constant { |
| 283 final DartType type; | 312 final DartType type; |
| 284 | 313 |
| 285 ObjectConstant(this.type); | 314 ObjectConstant(this.type); |
| 286 bool isObject() => true; | 315 bool isObject() => true; |
| 287 | 316 |
| 288 // TODO(1603): The class should be marked as abstract, but the VM doesn't | 317 // TODO(1603): The class should be marked as abstract, but the VM doesn't |
| 289 // currently allow this. | 318 // currently allow this. |
| 290 abstract int hashCode(); | 319 abstract int hashCode(); |
| 320 |
| 321 void _writeCanonicalizedJsCode(CodeBuffer buffer, ConstantHandler handler) { |
| 322 String name = handler.getNameForConstant(this); |
| 323 buffer.add(handler.compiler.namer.isolatePropertiesAccessForConstant(name)); |
| 324 } |
| 291 } | 325 } |
| 292 | 326 |
| 293 class ListConstant extends ObjectConstant { | 327 class ListConstant extends ObjectConstant { |
| 294 final List<Constant> entries; | 328 final List<Constant> entries; |
| 295 int _hashCode; | 329 int _hashCode; |
| 296 | 330 |
| 297 ListConstant(DartType type, this.entries) : super(type) { | 331 ListConstant(DartType type, this.entries) : super(type) { |
| 298 // TODO(floitsch): create a better hash. | 332 // TODO(floitsch): create a better hash. |
| 299 int hash = 0; | 333 int hash = 0; |
| 300 for (Constant input in entries) hash ^= input.hashCode(); | 334 for (Constant input in entries) hash ^= input.hashCode(); |
| 301 _hashCode = hash; | 335 _hashCode = hash; |
| 302 } | 336 } |
| 303 bool isList() => true; | 337 bool isList() => true; |
| 304 | 338 |
| 339 void _writeJsCode(CodeBuffer buffer, ConstantHandler handler) { |
| 340 // TODO(floitsch): we should not need to go through the compiler to make |
| 341 // the list constant. |
| 342 buffer.add("${handler.compiler.namer.ISOLATE}.makeConstantList"); |
| 343 buffer.add("(["); |
| 344 for (int i = 0; i < entries.length; i++) { |
| 345 if (i != 0) buffer.add(", "); |
| 346 Constant entry = entries[i]; |
| 347 handler.writeConstant(buffer, entry); |
| 348 } |
| 349 buffer.add("])"); |
| 350 } |
| 351 |
| 305 bool operator ==(var other) { | 352 bool operator ==(var other) { |
| 306 if (other is !ListConstant) return false; | 353 if (other is !ListConstant) return false; |
| 307 ListConstant otherList = other; | 354 ListConstant otherList = other; |
| 308 if (hashCode() != otherList.hashCode()) return false; | 355 if (hashCode() != otherList.hashCode()) return false; |
| 309 // TODO(floitsch): verify that the generic types are the same. | 356 // TODO(floitsch): verify that the generic types are the same. |
| 310 if (entries.length != otherList.entries.length) return false; | 357 if (entries.length != otherList.entries.length) return false; |
| 311 for (int i = 0; i < entries.length; i++) { | 358 for (int i = 0; i < entries.length; i++) { |
| 312 if (entries[i] != otherList.entries[i]) return false; | 359 if (entries[i] != otherList.entries[i]) return false; |
| 313 } | 360 } |
| 314 return true; | 361 return true; |
| 315 } | 362 } |
| 316 | 363 |
| 317 int hashCode() => _hashCode; | 364 int hashCode() => _hashCode; |
| 318 | 365 |
| 319 List<Constant> getDependencies() => entries; | 366 List<Constant> getDependencies() => entries; |
| 320 | 367 |
| 321 int get length => entries.length; | 368 int get length => entries.length; |
| 322 | |
| 323 accept(ConstantVisitor visitor) => visitor.visitList(this); | |
| 324 } | 369 } |
| 325 | 370 |
| 326 class MapConstant extends ObjectConstant { | 371 class MapConstant extends ObjectConstant { |
| 327 /** | 372 /** |
| 328 * The [PROTO_PROPERTY] must not be used as normal property in any JavaScript | 373 * The [PROTO_PROPERTY] must not be used as normal property in any JavaScript |
| 329 * object. It would change the prototype chain. | 374 * object. It would change the prototype chain. |
| 330 */ | 375 */ |
| 331 static const LiteralDartString PROTO_PROPERTY = | 376 static const String PROTO_PROPERTY = "__proto__"; |
| 332 const LiteralDartString("__proto__"); | |
| 333 | 377 |
| 334 /** The dart class implementing constant map literals. */ | 378 /** The dart class implementing constant map literals. */ |
| 335 static const SourceString DART_CLASS = const SourceString("ConstantMap"); | 379 static const SourceString DART_CLASS = const SourceString("ConstantMap"); |
| 336 static const SourceString DART_PROTO_CLASS = | 380 static const SourceString DART_PROTO_CLASS = |
| 337 const SourceString("ConstantProtoMap"); | 381 const SourceString("ConstantProtoMap"); |
| 338 static const SourceString LENGTH_NAME = const SourceString("length"); | 382 static const SourceString LENGTH_NAME = const SourceString("length"); |
| 339 static const SourceString JS_OBJECT_NAME = const SourceString("_jsObject"); | 383 static const SourceString JS_OBJECT_NAME = const SourceString("_jsObject"); |
| 340 static const SourceString KEYS_NAME = const SourceString("_keys"); | 384 static const SourceString KEYS_NAME = const SourceString("_keys"); |
| 341 static const SourceString PROTO_VALUE = const SourceString("_protoValue"); | 385 static const SourceString PROTO_VALUE = const SourceString("_protoValue"); |
| 342 | 386 |
| 343 final ListConstant keys; | 387 final ListConstant keys; |
| 344 final List<Constant> values; | 388 final List<Constant> values; |
| 345 final Constant protoValue; | 389 final Constant protoValue; |
| 346 int _hashCode; | 390 int _hashCode; |
| 347 | 391 |
| 348 MapConstant(DartType type, this.keys, this.values, this.protoValue) | 392 MapConstant(DartType type, this.keys, this.values, this.protoValue) |
| 349 : super(type) { | 393 : super(type) { |
| 350 // TODO(floitsch): create a better hash. | 394 // TODO(floitsch): create a better hash. |
| 351 int hash = 0; | 395 int hash = 0; |
| 352 for (Constant value in values) hash ^= value.hashCode(); | 396 for (Constant value in values) hash ^= value.hashCode(); |
| 353 _hashCode = hash; | 397 _hashCode = hash; |
| 354 } | 398 } |
| 355 bool isMap() => true; | 399 bool isMap() => true; |
| 356 | 400 |
| 401 void _writeJsCode(CodeBuffer buffer, ConstantHandler handler) { |
| 402 |
| 403 void writeJsMap() { |
| 404 buffer.add("{"); |
| 405 int valueIndex = 0; |
| 406 for (int i = 0; i < keys.entries.length; i++) { |
| 407 StringConstant key = keys.entries[i]; |
| 408 if (key.value == const LiteralDartString(PROTO_PROPERTY)) continue; |
| 409 |
| 410 if (valueIndex != 0) buffer.add(", "); |
| 411 |
| 412 key._writeJsCode(buffer, handler); |
| 413 buffer.add(": "); |
| 414 Constant value = values[valueIndex++]; |
| 415 handler.writeConstant(buffer, value); |
| 416 } |
| 417 buffer.add("}"); |
| 418 if (valueIndex != values.length) { |
| 419 handler.compiler.internalError("Bad value count."); |
| 420 } |
| 421 } |
| 422 |
| 423 void badFieldCountError() { |
| 424 handler.compiler.internalError( |
| 425 "Compiler and ConstantMap disagree on number of fields."); |
| 426 } |
| 427 |
| 428 ClassElement classElement = type.element; |
| 429 buffer.add("new "); |
| 430 buffer.add(handler.getJsConstructor(classElement)); |
| 431 buffer.add("("); |
| 432 // The arguments of the JavaScript constructor for any given Dart class |
| 433 // are in the same order as the members of the class element. |
| 434 int emittedArgumentCount = 0; |
| 435 classElement.forEachInstanceField( |
| 436 includeBackendMembers: true, |
| 437 includeSuperMembers: true, |
| 438 f: (ClassElement enclosing, Element field) { |
| 439 if (emittedArgumentCount != 0) buffer.add(", "); |
| 440 if (field.name == LENGTH_NAME) { |
| 441 buffer.add(keys.entries.length); |
| 442 } else if (field.name == JS_OBJECT_NAME) { |
| 443 writeJsMap(); |
| 444 } else if (field.name == KEYS_NAME) { |
| 445 handler.writeConstant(buffer, keys); |
| 446 } else if (field.name == PROTO_VALUE) { |
| 447 assert(protoValue !== null); |
| 448 handler.writeConstant(buffer, protoValue); |
| 449 } else { |
| 450 badFieldCountError(); |
| 451 } |
| 452 emittedArgumentCount++; |
| 453 }); |
| 454 if ((protoValue === null && emittedArgumentCount != 3) || |
| 455 (protoValue !== null && emittedArgumentCount != 4)) { |
| 456 badFieldCountError(); |
| 457 } |
| 458 buffer.add(")"); |
| 459 } |
| 460 |
| 357 bool operator ==(var other) { | 461 bool operator ==(var other) { |
| 358 if (other is !MapConstant) return false; | 462 if (other is !MapConstant) return false; |
| 359 MapConstant otherMap = other; | 463 MapConstant otherMap = other; |
| 360 if (hashCode() != otherMap.hashCode()) return false; | 464 if (hashCode() != otherMap.hashCode()) return false; |
| 361 // TODO(floitsch): verify that the generic types are the same. | 465 // TODO(floitsch): verify that the generic types are the same. |
| 362 if (keys != otherMap.keys) return false; | 466 if (keys != otherMap.keys) return false; |
| 363 for (int i = 0; i < values.length; i++) { | 467 for (int i = 0; i < values.length; i++) { |
| 364 if (values[i] != otherMap.values[i]) return false; | 468 if (values[i] != otherMap.values[i]) return false; |
| 365 } | 469 } |
| 366 return true; | 470 return true; |
| 367 } | 471 } |
| 368 | 472 |
| 369 int hashCode() => _hashCode; | 473 int hashCode() => _hashCode; |
| 370 | 474 |
| 371 List<Constant> getDependencies() { | 475 List<Constant> getDependencies() { |
| 372 List<Constant> result = <Constant>[keys]; | 476 List<Constant> result = <Constant>[keys]; |
| 373 result.addAll(values); | 477 result.addAll(values); |
| 374 return result; | 478 return result; |
| 375 } | 479 } |
| 376 | 480 |
| 377 int get length => keys.length; | 481 int get length => keys.length; |
| 378 | |
| 379 accept(ConstantVisitor visitor) => visitor.visitMap(this); | |
| 380 } | 482 } |
| 381 | 483 |
| 382 class ConstructedConstant extends ObjectConstant { | 484 class ConstructedConstant extends ObjectConstant { |
| 383 final List<Constant> fields; | 485 final List<Constant> fields; |
| 384 int _hashCode; | 486 int _hashCode; |
| 385 | 487 |
| 386 ConstructedConstant(DartType type, this.fields) : super(type) { | 488 ConstructedConstant(DartType type, this.fields) : super(type) { |
| 387 assert(type !== null); | 489 assert(type !== null); |
| 388 // TODO(floitsch): create a better hash. | 490 // TODO(floitsch): create a better hash. |
| 389 int hash = 0; | 491 int hash = 0; |
| 390 for (Constant field in fields) { | 492 for (Constant field in fields) { |
| 391 hash ^= field.hashCode(); | 493 hash ^= field.hashCode(); |
| 392 } | 494 } |
| 393 hash ^= type.element.hashCode(); | 495 hash ^= type.element.hashCode(); |
| 394 _hashCode = hash; | 496 _hashCode = hash; |
| 395 } | 497 } |
| 396 bool isConstructedObject() => true; | 498 bool isConstructedObject() => true; |
| 397 | 499 |
| 500 void _writeJsCode(CodeBuffer buffer, ConstantHandler handler) { |
| 501 buffer.add("new "); |
| 502 buffer.add(handler.getJsConstructor(type.element)); |
| 503 buffer.add("("); |
| 504 for (int i = 0; i < fields.length; i++) { |
| 505 if (i != 0) buffer.add(", "); |
| 506 Constant field = fields[i]; |
| 507 handler.writeConstant(buffer, field); |
| 508 } |
| 509 buffer.add(")"); |
| 510 } |
| 511 |
| 398 bool operator ==(var otherVar) { | 512 bool operator ==(var otherVar) { |
| 399 if (otherVar is !ConstructedConstant) return false; | 513 if (otherVar is !ConstructedConstant) return false; |
| 400 ConstructedConstant other = otherVar; | 514 ConstructedConstant other = otherVar; |
| 401 if (hashCode() != other.hashCode()) return false; | 515 if (hashCode() != other.hashCode()) return false; |
| 402 // TODO(floitsch): verify that the (generic) types are the same. | 516 // TODO(floitsch): verify that the (generic) types are the same. |
| 403 if (type.element != other.type.element) return false; | 517 if (type.element != other.type.element) return false; |
| 404 if (fields.length != other.fields.length) return false; | 518 if (fields.length != other.fields.length) return false; |
| 405 for (int i = 0; i < fields.length; i++) { | 519 for (int i = 0; i < fields.length; i++) { |
| 406 if (fields[i] != other.fields[i]) return false; | 520 if (fields[i] != other.fields[i]) return false; |
| 407 } | 521 } |
| 408 return true; | 522 return true; |
| 409 } | 523 } |
| 410 | 524 |
| 411 int hashCode() => _hashCode; | 525 int hashCode() => _hashCode; |
| 412 List<Constant> getDependencies() => fields; | 526 List<Constant> getDependencies() => fields; |
| 413 | |
| 414 accept(ConstantVisitor visitor) => visitor.visitConstructed(this); | |
| 415 } | 527 } |
| OLD | NEW |