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

Side by Side Diff: lib/compiler/implementation/js_backend/emitter.dart

Issue 10908012: Support checked mode for field setters. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 3 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
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 /** 5 /**
6 * A function element that represents a closure call. The signature is copied 6 * A function element that represents a closure call. The signature is copied
7 * from the given element. 7 * from the given element.
8 */ 8 */
9 class ClosureInvocationElement extends FunctionElement { 9 class ClosureInvocationElement extends FunctionElement {
10 ClosureInvocationElement(SourceString name, 10 ClosureInvocationElement(SourceString name,
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
62 => '${namer.ISOLATE}.${namer.ISOLATE_PROPERTIES}'; 62 => '${namer.ISOLATE}.${namer.ISOLATE_PROPERTIES}';
63 String get supportsProtoName 63 String get supportsProtoName
64 => 'supportsProto'; 64 => 'supportsProto';
65 65
66 final String GETTER_SUFFIX = "?"; 66 final String GETTER_SUFFIX = "?";
67 final String SETTER_SUFFIX = "!"; 67 final String SETTER_SUFFIX = "!";
68 final String GETTER_SETTER_SUFFIX = "="; 68 final String GETTER_SETTER_SUFFIX = "=";
69 69
70 String get generateGetterSetterFunction { 70 String get generateGetterSetterFunction {
71 return """ 71 return """
72 function(field, prototype) { 72 function(field, prototype) {
73 var len = field.length; 73 var len = field.length;
74 var lastChar = field[len - 1]; 74 var lastChar = field[len - 1];
75 var needsGetter = lastChar == '$GETTER_SUFFIX' || lastChar == '$GETTER_SETTER_ SUFFIX'; 75 var needsGetter = lastChar == '$GETTER_SUFFIX' || lastChar == '$GETTER_SETTE R_SUFFIX';
76 var needsSetter = lastChar == '$SETTER_SUFFIX' || lastChar == '$GETTER_SETTER_ SUFFIX'; 76 var needsSetter = lastChar == '$SETTER_SUFFIX' || lastChar == '$GETTER_SETTE R_SUFFIX';
77 if (needsGetter || needsSetter) field = field.substring(0, len - 1); 77 if (needsGetter || needsSetter) field = field.substring(0, len - 1);
78 if (needsGetter) { 78 if (needsGetter) {
79 var getterString = "return this." + field + ";"; 79 var getterString = "return this." + field + ";";
80 """ /* The supportsProtoCheck below depends on the getter/setter convention. 80 """
81 When changing here, update the protoCheck too. */ """ 81 /* The supportsProtoCheck below depends on the getter/setter convention.
82 prototype["get\$" + field] = new Function(getterString); 82 When changing here, update the protoCheck too. */
83 } 83 """
84 if (needsSetter) { 84 prototype["get\$" + field] = new Function(getterString);
85 var setterString = "this." + field + " = v;"; 85 }
86 prototype["set\$" + field] = new Function("v", setterString); 86 if (needsSetter) {
87 } 87 var setterString = "this." + field + " = v;";
88 return field; 88 prototype["set\$" + field] = new Function("v", setterString);
89 }"""; 89 }
90 return field;
91 }""";
90 } 92 }
91 93
92 String get defineClassFunction { 94 String get defineClassFunction {
93 // First the class name, then the super class name, followed by the fields 95 // First the class name, then the super class name, followed by the fields
94 // (in an array) and the members (inside an Object literal). 96 // (in an array) and the members (inside an Object literal).
95 // The caller can also pass in the constructor as a function if needed. 97 // The caller can also pass in the constructor as a function if needed.
96 // 98 //
97 // Example: 99 // Example:
98 // defineClass("A", "B", ["x", "y"], { 100 // defineClass("A", "B", ["x", "y"], {
99 // foo$1: function(y) { 101 // foo$1: function(y) {
(...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after
425 if (!parameters.optionalParameters.isEmpty()) { 427 if (!parameters.optionalParameters.isEmpty()) {
426 addParameterStubs(member, defineInstanceMember); 428 addParameterStubs(member, defineInstanceMember);
427 } 429 }
428 } else if (member.kind !== ElementKind.FIELD) { 430 } else if (member.kind !== ElementKind.FIELD) {
429 compiler.internalError('unexpected kind: "${member.kind}"', 431 compiler.internalError('unexpected kind: "${member.kind}"',
430 element: member); 432 element: member);
431 } 433 }
432 emitExtraAccessors(member, defineInstanceMember); 434 emitExtraAccessors(member, defineInstanceMember);
433 } 435 }
434 436
435 Set<Element> emitClassFields(ClassElement classElement, CodeBuffer buffer) { 437 String generateCheckedSetter(Element member, String fieldName) {
438 Type type = member.computeType(compiler);
439 if (type.element.isTypeVariable()
440 || type.element == compiler.dynamicClass
441 || type.element == compiler.objectClass) {
442 // TODO(ngeoffray): Support type checks on type parameters.
443 return null;
444 } else {
445 SourceString helper = compiler.backend.getCheckedModeHelper(type);
446 Element helperElement = compiler.findHelper(helper);
447 String helperName = compiler.namer.isolateAccess(helperElement);
448 String additionalArgument = compiler.namer.operatorIs(type.element);
449 return " set\$$fieldName: function(v) { "
450 "this.$fieldName = $helperName(v, '$additionalArgument'); }";
451 }
452 }
453
454 List<String> emitClassFields(ClassElement classElement, CodeBuffer buffer) {
436 // If the class is never instantiated we still need to set it up for 455 // If the class is never instantiated we still need to set it up for
437 // inheritance purposes, but we can simplify its JavaScript constructor. 456 // inheritance purposes, but we can simplify its JavaScript constructor.
438 bool isInstantiated = 457 bool isInstantiated =
439 compiler.codegenWorld.instantiatedClasses.contains(classElement); 458 compiler.codegenWorld.instantiatedClasses.contains(classElement);
459 List<String> checkedSetters = <String>[];
440 460
441 bool isFirstField = true; 461 bool isFirstField = true;
442 void addField(ClassElement enclosingClass, Element member) { 462 void addField(ClassElement enclosingClass, Element member) {
443 assert(!member.isNative()); 463 assert(!member.isNative());
444 464
445 LibraryElement library = member.getLibrary(); 465 LibraryElement library = member.getLibrary();
446 SourceString name = member.name; 466 SourceString name = member.name;
447 bool isPrivate = name.isPrivate(); 467 bool isPrivate = name.isPrivate();
448 // See if we can dynamically create getters and setters. 468 // See if we can dynamically create getters and setters.
449 // We can only generate getters and setters for [classElement] since 469 // We can only generate getters and setters for [classElement] since
(...skipping 15 matching lines...) Expand all
465 || needsDynamicGetter 485 || needsDynamicGetter
466 || needsDynamicSetter) { 486 || needsDynamicSetter) {
467 if (isFirstField) { 487 if (isFirstField) {
468 isFirstField = false; 488 isFirstField = false;
469 } else { 489 } else {
470 buffer.add(", "); 490 buffer.add(", ");
471 } 491 }
472 String fieldName = isShadowed 492 String fieldName = isShadowed
473 ? namer.shadowedFieldName(member) 493 ? namer.shadowedFieldName(member)
474 : namer.getName(member); 494 : namer.getName(member);
495 if (needsDynamicSetter && compiler.enableTypeAssertions) {
496 String setter = generateCheckedSetter(member, fieldName);
497 if (setter != null) {
498 needsDynamicSetter = false;
499 checkedSetters.add(setter);
500 }
501 }
475 // Getters and setters with suffixes will be generated dynamically. 502 // Getters and setters with suffixes will be generated dynamically.
476 buffer.add('"$fieldName'); 503 buffer.add('"$fieldName');
477 if (needsDynamicGetter || needsDynamicSetter) { 504 if (needsDynamicGetter || needsDynamicSetter) {
478 if (needsDynamicGetter && needsDynamicSetter) { 505 if (needsDynamicGetter && needsDynamicSetter) {
479 buffer.add(GETTER_SETTER_SUFFIX); 506 buffer.add(GETTER_SETTER_SUFFIX);
480 } else if (needsDynamicGetter) { 507 } else if (needsDynamicGetter) {
481 buffer.add(GETTER_SUFFIX); 508 buffer.add(GETTER_SUFFIX);
482 } else { 509 } else {
483 buffer.add(SETTER_SUFFIX); 510 buffer.add(SETTER_SUFFIX);
484 } 511 }
485 } 512 }
486 buffer.add('"'); 513 buffer.add('"');
487 } 514 }
488 } 515 }
489 516
490 // If a class is not instantiated then we add the field just so we can 517 // If a class is not instantiated then we add the field just so we can
491 // generate the field getter/setter dynamically. Since this is only 518 // generate the field getter/setter dynamically. Since this is only
492 // allowed on fields that are in [classElement] we don't need to visit 519 // allowed on fields that are in [classElement] we don't need to visit
493 // superclasses for non-instantiated classes. 520 // superclasses for non-instantiated classes.
494 classElement.forEachInstanceField( 521 classElement.forEachInstanceField(
495 addField, 522 addField,
496 includeBackendMembers: true, 523 includeBackendMembers: true,
497 includeSuperMembers: isInstantiated && !classElement.isNative()); 524 includeSuperMembers: isInstantiated && !classElement.isNative());
525 return checkedSetters;
498 } 526 }
499 527
500 void emitInstanceMembers(ClassElement classElement, 528 void emitInstanceMembers(ClassElement classElement,
501 CodeBuffer buffer, 529 CodeBuffer buffer,
502 bool needsLeadingComma) { 530 bool needsLeadingComma) {
503 bool needsComma = needsLeadingComma; 531 bool needsComma = needsLeadingComma;
504 void defineInstanceMember(String name, CodeBuffer memberBuffer) { 532 void defineInstanceMember(String name, CodeBuffer memberBuffer) {
505 if (needsComma) buffer.add(','); 533 if (needsComma) buffer.add(',');
506 needsComma = true; 534 needsComma = true;
507 buffer.add('\n'); 535 buffer.add('\n');
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
555 String className = namer.getName(classElement); 583 String className = namer.getName(classElement);
556 ClassElement superclass = classElement.superclass; 584 ClassElement superclass = classElement.superclass;
557 String superName = ""; 585 String superName = "";
558 if (superclass !== null) { 586 if (superclass !== null) {
559 superName = namer.getName(superclass); 587 superName = namer.getName(superclass);
560 } 588 }
561 String constructorName = namer.safeName(classElement.name.slowToString()); 589 String constructorName = namer.safeName(classElement.name.slowToString());
562 590
563 buffer.add('$classesCollector.$className = {"":\n'); 591 buffer.add('$classesCollector.$className = {"":\n');
564 buffer.add(' ['); 592 buffer.add(' [');
565 emitClassFields(classElement, buffer); 593 List<String> checkedSetters = emitClassFields(classElement, buffer);
566 buffer.add('],\n'); 594 buffer.add('],\n');
567 // TODO(floitsch): the emitInstanceMember should simply always emit a ',\n'. 595 // TODO(floitsch): the emitInstanceMember should simply always emit a ',\n'.
568 // That does currently not work because the native classes have a different 596 // That does currently not work because the native classes have a different
569 // syntax. 597 // syntax.
570 buffer.add(' "super": "$superName"'); 598 buffer.add(' "super": "$superName"');
599 if (!checkedSetters.isEmpty()) {
600 buffer.add(',\n');
601 buffer.add('${Strings.join(checkedSetters, ",\n")}');
602 }
571 emitInstanceMembers(classElement, buffer, true); 603 emitInstanceMembers(classElement, buffer, true);
572 buffer.add('\n};\n\n'); 604 buffer.add('\n};\n\n');
573 } 605 }
574 606
575 void generateTypeTests(ClassElement cls, 607 void generateTypeTests(ClassElement cls,
576 void generateTypeTest(ClassElement element)) { 608 void generateTypeTest(ClassElement element)) {
577 if (compiler.codegenWorld.isChecks.contains(cls)) { 609 if (compiler.codegenWorld.isChecks.contains(cls)) {
578 generateTypeTest(cls); 610 generateTypeTest(cls);
579 } 611 }
580 generateInterfacesIsTests(cls, generateTypeTest, new Set<Element>()); 612 generateInterfacesIsTests(cls, generateTypeTest, new Set<Element>());
(...skipping 586 matching lines...) Expand 10 before | Expand all | Expand 10 after
1167 sourceName = token.slowToString(); 1199 sourceName = token.slowToString();
1168 } 1200 }
1169 int totalOffset = bufferOffset + offset; 1201 int totalOffset = bufferOffset + offset;
1170 sourceMapBuilder.addMapping( 1202 sourceMapBuilder.addMapping(
1171 sourceFile, token.charOffset, sourceName, totalOffset); 1203 sourceFile, token.charOffset, sourceName, totalOffset);
1172 }); 1204 });
1173 } 1205 }
1174 } 1206 }
1175 1207
1176 typedef void DefineMemberFunction(String invocationName, CodeBuffer definition); 1208 typedef void DefineMemberFunction(String invocationName, CodeBuffer definition);
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698