Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(101)

Side by Side Diff: lib/compiler/implementation/compile_time_constants.dart

Issue 9873040: Implement constant maps with __proto__ and fix maps with duplicated keys. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | lib/compiler/implementation/lib/constant_map.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 class Constant implements Hashable { 5 class Constant implements Hashable {
6 const Constant(); 6 const Constant();
7 7
8 bool isNull() => false; 8 bool isNull() => false;
9 bool isBool() => false; 9 bool isBool() => false;
10 bool isTrue() => false; 10 bool isTrue() => false;
(...skipping 292 matching lines...) Expand 10 before | Expand all | Expand 10 after
303 } 303 }
304 return true; 304 return true;
305 } 305 }
306 306
307 int hashCode() => _hashCode; 307 int hashCode() => _hashCode;
308 308
309 List<Constant> getDependencies() => entries; 309 List<Constant> getDependencies() => entries;
310 } 310 }
311 311
312 class MapConstant extends ObjectConstant { 312 class MapConstant extends ObjectConstant {
313 /**
314 * The [PROTO_PROPERTY] must not be used as normal property in any JavaScript
315 * object. It would change the prototype chain.
316 */
317 static final String PROTO_PROPERTY = "__proto__";
318
313 /** The dart class implementing constant map literals. */ 319 /** The dart class implementing constant map literals. */
314 static final SourceString DART_CLASS = const SourceString("ConstantMap"); 320 static final SourceString DART_CLASS = const SourceString("ConstantMap");
321 static final SourceString DART_PROTO_CLASS =
322 const SourceString("ConstantProtoMap");
315 static final SourceString LENGTH_NAME = const SourceString("length"); 323 static final SourceString LENGTH_NAME = const SourceString("length");
316 static final SourceString JS_OBJECT_NAME = const SourceString("_jsObject"); 324 static final SourceString JS_OBJECT_NAME = const SourceString("_jsObject");
317 static final SourceString KEYS_NAME = const SourceString("_keys"); 325 static final SourceString KEYS_NAME = const SourceString("_keys");
326 static final SourceString PROTO_VALUE = const SourceString("_protoValue");
318 327
319 final ListConstant keys; 328 final ListConstant keys;
320 final List<Constant> values; 329 final List<Constant> values;
330 final Constant protoValue;
321 int _hashCode; 331 int _hashCode;
322 332
323 MapConstant(Type type, this.keys, this.values) : super(type) { 333 MapConstant(Type type, this.keys, this.values, this.protoValue)
334 : super(type) {
324 // TODO(floitsch): create a better hash. 335 // TODO(floitsch): create a better hash.
325 int hash = 0; 336 int hash = 0;
326 for (Constant value in values) hash ^= value.hashCode(); 337 for (Constant value in values) hash ^= value.hashCode();
327 _hashCode = hash; 338 _hashCode = hash;
328 } 339 }
329 bool isMap() => true; 340 bool isMap() => true;
330 341
331 void writeJsCode(StringBuffer buffer, ConstantHandler handler) { 342 void writeJsCode(StringBuffer buffer, ConstantHandler handler) {
332 343
333 void writeJsMap() { 344 void writeJsMap() {
334 buffer.add("{"); 345 buffer.add("{");
346 int valueIndex = 0;
335 for (int i = 0; i < keys.entries.length; i++) { 347 for (int i = 0; i < keys.entries.length; i++) {
336 if (i != 0) buffer.add(", "); 348 StringConstant key = keys.entries[i];
349 if (key.value == const LiteralDartString(PROTO_PROPERTY)) continue;
350
351 if (valueIndex != 0) buffer.add(", ");
337 352
338 StringConstant key = keys.entries[i];
339 key.writeJsCode(buffer, handler); 353 key.writeJsCode(buffer, handler);
340 buffer.add(": "); 354 buffer.add(": ");
341 Constant value = values[i]; 355 Constant value = values[valueIndex++];
342 value.writeCanonicalizedJsCode(buffer, handler); 356 value.writeCanonicalizedJsCode(buffer, handler);
343 } 357 }
344 buffer.add("}"); 358 buffer.add("}");
359 if (valueIndex != values.length) {
360 handler.compiler.internalError("Bad value count.");
361 }
345 } 362 }
346 363
347 void badFieldCountError() { 364 void badFieldCountError() {
348 handler.compiler.internalError( 365 handler.compiler.internalError(
349 "Compiler and ConstantMap disagree on number of fields."); 366 "Compiler and ConstantMap disagree on number of fields.");
350 } 367 }
351 368
352 ClassElement classElement = type.element; 369 ClassElement classElement = type.element;
353 buffer.add("new "); 370 buffer.add("new ");
354 buffer.add(handler.getJsConstructor(classElement)); 371 buffer.add(handler.getJsConstructor(classElement));
355 buffer.add("("); 372 buffer.add("(");
356 // The arguments of the JavaScript constructor for any given Dart class 373 // The arguments of the JavaScript constructor for any given Dart class
357 // are in the same order as the members of the class element. 374 // are in the same order as the members of the class element.
358 int emittedArgumentCount = 0; 375 int emittedArgumentCount = 0;
359 classElement.forEachInstanceField( 376 classElement.forEachInstanceField(
360 includeBackendMembers: true, 377 includeBackendMembers: true,
361 includeSuperMembers: true, 378 includeSuperMembers: true,
362 f: (ClassElement enclosing, Element field) { 379 f: (ClassElement enclosing, Element field) {
363 if (emittedArgumentCount != 0) buffer.add(", "); 380 if (emittedArgumentCount != 0) buffer.add(", ");
364 if (field.name == LENGTH_NAME) { 381 if (field.name == LENGTH_NAME) {
365 buffer.add(keys.entries.length); 382 buffer.add(keys.entries.length);
366 } else if (field.name == JS_OBJECT_NAME) { 383 } else if (field.name == JS_OBJECT_NAME) {
367 writeJsMap(); 384 writeJsMap();
368 } else if (field.name == KEYS_NAME) { 385 } else if (field.name == KEYS_NAME) {
369 keys.writeCanonicalizedJsCode(buffer, handler); 386 keys.writeCanonicalizedJsCode(buffer, handler);
387 } else if (field.name == PROTO_VALUE) {
388 assert(protoValue !== null);
389 protoValue.writeCanonicalizedJsCode(buffer, handler);
370 } else { 390 } else {
371 badFieldCountError(); 391 badFieldCountError();
372 } 392 }
373 emittedArgumentCount++; 393 emittedArgumentCount++;
374 }); 394 });
375 if (emittedArgumentCount != 3) badFieldCountError(); 395 if ((protoValue === null && emittedArgumentCount != 3) ||
396 (protoValue !== null && emittedArgumentCount != 4)) {
397 badFieldCountError();
398 }
376 buffer.add(")"); 399 buffer.add(")");
377 } 400 }
378 401
379 bool operator ==(var other) { 402 bool operator ==(var other) {
380 if (other is !MapConstant) return false; 403 if (other is !MapConstant) return false;
381 MapConstant otherMap = other; 404 MapConstant otherMap = other;
382 if (hashCode() != otherMap.hashCode()) return false; 405 if (hashCode() != otherMap.hashCode()) return false;
383 // TODO(floitsch): verify that the generic types are the same. 406 // TODO(floitsch): verify that the generic types are the same.
384 if (keys != otherMap.keys) return false; 407 if (keys != otherMap.keys) return false;
385 for (int i = 0; i < values.length; i++) { 408 for (int i = 0; i < values.length; i++) {
(...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after
702 // TODO(floitsch): get type from somewhere. 725 // TODO(floitsch): get type from somewhere.
703 Type type = null; 726 Type type = null;
704 Constant constant = new ListConstant(type, arguments); 727 Constant constant = new ListConstant(type, arguments);
705 compiler.constantHandler.registerCompileTimeConstant(constant); 728 compiler.constantHandler.registerCompileTimeConstant(constant);
706 return constant; 729 return constant;
707 } 730 }
708 731
709 Constant visitLiteralMap(LiteralMap node) { 732 Constant visitLiteralMap(LiteralMap node) {
710 if (!node.isConst()) error(node); 733 if (!node.isConst()) error(node);
711 List<StringConstant> keys = <StringConstant>[]; 734 List<StringConstant> keys = <StringConstant>[];
712 List<Constant> values = <Constant>[]; 735 Map<StringConstant, Constant> map = new Map<StringConstant, Constant>();
713 bool hasProtoKey = false;
714 for (Link<Node> link = node.entries.nodes; 736 for (Link<Node> link = node.entries.nodes;
715 !link.isEmpty(); 737 !link.isEmpty();
716 link = link.tail) { 738 link = link.tail) {
717 LiteralMapEntry entry = link.head; 739 LiteralMapEntry entry = link.head;
718 Constant key = evaluate(entry.key); 740 Constant key = evaluate(entry.key);
719 if (!key.isString() || entry.key.asLiteralString() === null) { 741 if (!key.isString() || entry.key.asLiteralString() === null) {
720 MessageKind kind = MessageKind.KEY_NOT_A_STRING_LITERAL; 742 MessageKind kind = MessageKind.KEY_NOT_A_STRING_LITERAL;
721 compiler.reportError(entry.key, new ResolutionError(kind, const [])); 743 compiler.reportError(entry.key, new ResolutionError(kind, const []));
722 } 744 }
723 // TODO(floitsch): make this faster.
724 StringConstant keyConstant = key; 745 StringConstant keyConstant = key;
725 if (keyConstant.value == new LiteralDartString("__proto__")) { 746 if (!map.containsKey(key)) keys.add(key);
726 hasProtoKey = true; 747 map[key] = evaluate(entry.value);
748 }
749 List<Constant> values = <Constant>[];
750 Constant protoValue = null;
751 for (StringConstant key in keys) {
752 if (key.value == const LiteralDartString(MapConstant.PROTO_PROPERTY)) {
753 protoValue = map[key];
754 } else {
755 values.add(map[key]);
727 } 756 }
728 keys.add(key);
729 values.add(evaluate(entry.value));
730 } 757 }
731 if (hasProtoKey) { 758 bool hasProtoKey = (protoValue !== null);
732 compiler.unimplemented("visitLiteralMap with __proto__ key",
733 node: node);
734 }
735 // TODO(floitsch): this should be a List<String> type. 759 // TODO(floitsch): this should be a List<String> type.
736 Type keysType = null; 760 Type keysType = null;
737 ListConstant keysList = new ListConstant(keysType, keys); 761 ListConstant keysList = new ListConstant(keysType, keys);
738 compiler.constantHandler.registerCompileTimeConstant(keysList); 762 compiler.constantHandler.registerCompileTimeConstant(keysList);
739 ClassElement classElement = 763 SourceString className = hasProtoKey
740 compiler.jsHelperLibrary.find(MapConstant.DART_CLASS); 764 ? MapConstant.DART_PROTO_CLASS
765 : MapConstant.DART_CLASS;
766 ClassElement classElement = compiler.jsHelperLibrary.find(className);
741 classElement.ensureResolved(compiler); 767 classElement.ensureResolved(compiler);
742 // TODO(floitsch): copy over the generic type. 768 // TODO(floitsch): copy over the generic type.
743 Type type = new SimpleType(classElement.name, classElement); 769 Type type = new SimpleType(classElement.name, classElement);
744 compiler.registerInstantiatedClass(classElement); 770 compiler.registerInstantiatedClass(classElement);
745 Constant constant = new MapConstant(type, keysList, values); 771 Constant constant = new MapConstant(type, keysList, values, protoValue);
746 compiler.constantHandler.registerCompileTimeConstant(constant); 772 compiler.constantHandler.registerCompileTimeConstant(constant);
747 return constant; 773 return constant;
748 } 774 }
749 775
750 Constant visitLiteralNull(LiteralNull node) { 776 Constant visitLiteralNull(LiteralNull node) {
751 return new NullConstant(); 777 return new NullConstant();
752 } 778 }
753 779
754 Constant visitLiteralString(LiteralString node) { 780 Constant visitLiteralString(LiteralString node) {
755 return new StringConstant(node.dartString); 781 return new StringConstant(node.dartString);
(...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after
1098 Constant fieldValue = fieldValues[field]; 1124 Constant fieldValue = fieldValues[field];
1099 if (fieldValue === null) { 1125 if (fieldValue === null) {
1100 // Use the default value. 1126 // Use the default value.
1101 fieldValue = compiler.compileVariable(field); 1127 fieldValue = compiler.compileVariable(field);
1102 } 1128 }
1103 jsNewArguments.add(fieldValue); 1129 jsNewArguments.add(fieldValue);
1104 }); 1130 });
1105 return jsNewArguments; 1131 return jsNewArguments;
1106 } 1132 }
1107 } 1133 }
OLDNEW
« no previous file with comments | « no previous file | lib/compiler/implementation/lib/constant_map.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698