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

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

Issue 19676002: Implement top-level getters. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge
Patch Set: Merged with r25274 Created 7 years, 5 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 part of js_backend; 5 part of js_backend;
6 6
7 /** 7 /**
8 * A function element that represents a closure call. The signature is copied 8 * A function element that represents a closure call. The signature is copied
9 * from the given element. 9 * from the given element.
10 */ 10 */
(...skipping 12 matching lines...) Expand all
23 */ 23 */
24 Element methodElement; 24 Element methodElement;
25 } 25 }
26 26
27 /** 27 /**
28 * A convenient type alias for some functions that emit keyed values. 28 * A convenient type alias for some functions that emit keyed values.
29 */ 29 */
30 typedef void DefineStubFunction(String invocationName, jsAst.Expression value); 30 typedef void DefineStubFunction(String invocationName, jsAst.Expression value);
31 31
32 /** 32 /**
33 * [member] is a field (instance, static, or top level).
34 *
35 * [name] is the field name that the [Namer] has picked for this field's
36 * storage, that is, the JavaScript property name.
37 *
38 * [accessorName] is the name of the accessor. For instance fields this is
39 * mostly the same as [name] except when [member] is shadowing a field in its
40 * superclass. For other fields, they are rarely the same.
41 *
42 * [needsGetter] and [needsSetter] represent if a getter or a setter
43 * respectively is needed. There are many factors in this, for example, if the
44 * accessor can be inlined.
45 *
46 * [needsCheckedSetter] indicates that a checked getter is needed, and in this
47 * case, [needsSetter] is always false. [needsCheckedSetter] is only true when
48 * type assertions are enabled (checked mode).
49 */
50 typedef void AcceptField(VariableElement member,
51 String name,
52 String accessorName,
53 bool needsGetter,
54 bool needsSetter,
55 bool needsCheckedSetter);
56
57 /**
33 * A data structure for collecting fragments of a class definition. 58 * A data structure for collecting fragments of a class definition.
34 */ 59 */
35 class ClassBuilder { 60 class ClassBuilder {
36 final List<jsAst.Property> properties = <jsAst.Property>[]; 61 final List<jsAst.Property> properties = <jsAst.Property>[];
37 62
38 /// Set to true by user if class is indistinguishable from its superclass. 63 /// Set to true by user if class is indistinguishable from its superclass.
39 bool isTrivial = false; 64 bool isTrivial = false;
40 65
41 // Has the same signature as [DefineStubFunction]. 66 // Has the same signature as [DefineStubFunction].
42 void addProperty(String name, jsAst.Expression value) { 67 void addProperty(String name, jsAst.Expression value) {
(...skipping 1142 matching lines...) Expand 10 before | Expand all | Expand 10 after
1185 for (int i = 1; i <= signature.optionalParameterCount; i++) { 1210 for (int i = 1; i <= signature.optionalParameterCount; i++) {
1186 selectors.add(new Selector(SelectorKind.CALL, 1211 selectors.add(new Selector(SelectorKind.CALL,
1187 element.name, 1212 element.name,
1188 element.getLibrary(), 1213 element.getLibrary(),
1189 signature.requiredParameterCount + i, 1214 signature.requiredParameterCount + i,
1190 <SourceString>[])); 1215 <SourceString>[]));
1191 } 1216 }
1192 return selectors; 1217 return selectors;
1193 } 1218 }
1194 1219
1195 bool instanceFieldNeedsGetter(Element member) { 1220 bool fieldNeedsGetter(VariableElement field) {
1196 assert(member.isField()); 1221 assert(field.isField());
1197 if (fieldAccessNeverThrows(member)) return false; 1222 if (fieldAccessNeverThrows(field)) return false;
1198 return backend.retainGetter(member) 1223 return backend.retainGetter(field)
1199 || compiler.codegenWorld.hasInvokedGetter(member, compiler); 1224 || compiler.codegenWorld.hasInvokedGetter(field, compiler);
1200 } 1225 }
1201 1226
1202 bool instanceFieldNeedsSetter(Element member) { 1227 bool fieldNeedsSetter(VariableElement field) {
1203 assert(member.isField()); 1228 assert(field.isField());
1204 if (fieldAccessNeverThrows(member)) return false; 1229 if (fieldAccessNeverThrows(field)) return false;
1205 return (!member.modifiers.isFinalOrConst()) 1230 return (!field.modifiers.isFinalOrConst())
1206 && (backend.retainSetter(member) 1231 && (backend.retainSetter(field)
1207 || compiler.codegenWorld.hasInvokedSetter(member, compiler)); 1232 || compiler.codegenWorld.hasInvokedSetter(field, compiler));
1208 } 1233 }
1209 1234
1210 // We never access a field in a closure (a captured variable) without knowing 1235 // We never access a field in a closure (a captured variable) without knowing
1211 // that it is there. Therefore we don't need to use a getter (that will throw 1236 // that it is there. Therefore we don't need to use a getter (that will throw
1212 // if the getter method is missing), but can always access the field directly. 1237 // if the getter method is missing), but can always access the field directly.
1213 static bool fieldAccessNeverThrows(Element element) { 1238 static bool fieldAccessNeverThrows(VariableElement field) {
1214 return element is ClosureFieldElement; 1239 return field is ClosureFieldElement;
1215 } 1240 }
1216 1241
1217 String compiledFieldName(Element member) { 1242 String compiledFieldName(Element member) {
1218 assert(member.isField()); 1243 assert(member.isField());
1219 return member.hasFixedBackendName() 1244 return member.hasFixedBackendName()
1220 ? member.fixedBackendName() 1245 ? member.fixedBackendName()
1221 : namer.getName(member); 1246 : namer.getName(member);
1222 } 1247 }
1223 1248
1224 /** 1249 /**
(...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after
1478 for (ClassElement cls in typeChecks) { 1503 for (ClassElement cls in typeChecks) {
1479 for (TypeCheck check in typeChecks[cls]) { 1504 for (TypeCheck check in typeChecks[cls]) {
1480 result.add(backend.getImplementationClass(cls)); 1505 result.add(backend.getImplementationClass(cls));
1481 break; 1506 break;
1482 } 1507 }
1483 } 1508 }
1484 return result; 1509 return result;
1485 } 1510 }
1486 1511
1487 /** 1512 /**
1488 * Documentation wanted -- johnniwinther 1513 * Calls [addField] for each of the fields of [element].
1489 * 1514 *
1490 * Invariant: [classElement] must be a declaration element. 1515 * [element] must be a [ClassElement] or a [LibraryElement].
1516 *
1517 * If [element] is a [ClassElement], the static fields of the class are
1518 * visited if [visitStatics] is true and the instance fields are visited if
1519 * [visitStatics] is false.
1520 *
1521 * If [element] is a [LibraryElement], [visitStatics] must be true.
1522 *
1523 * When visiting the instance fields of a class, the fields of its superclass
1524 * are also visited if the class is instantiated.
1525 *
1526 * Invariant: [element] must be a declaration element.
1491 */ 1527 */
1492 void visitClassFields(ClassElement classElement, 1528 void visitFields(Element element, bool visitStatics, AcceptField f) {
1493 bool visitStatics, 1529 assert(invariant(element, element.isDeclaration));
1494 void addField(Element member, 1530
1495 String name, 1531 bool isClass = false;
1496 String accessorName, 1532 bool isLibrary = false;
1497 bool needsGetter, 1533 if (element.isClass()) {
1498 bool needsSetter, 1534 isClass = true;
1499 bool needsCheckedSetter)) { 1535 } else if (element.isLibrary()) {
1500 assert(invariant(classElement, classElement.isDeclaration)); 1536 isLibrary = true;
1537 assert(invariant(element, visitStatics));
1538 } else {
1539 throw new SpannableAssertionFailure(
1540 element, 'Expected a ClassElement or a LibraryElement.');
1541 }
1542
1501 // If the class is never instantiated we still need to set it up for 1543 // If the class is never instantiated we still need to set it up for
1502 // inheritance purposes, but we can simplify its JavaScript constructor. 1544 // inheritance purposes, but we can simplify its JavaScript constructor.
1503 bool isInstantiated = 1545 bool isInstantiated =
1504 compiler.codegenWorld.instantiatedClasses.contains(classElement); 1546 compiler.codegenWorld.instantiatedClasses.contains(element);
1505 1547
1506 void visitField(ClassElement enclosingClass, Element member) { 1548 void visitField(Element holder, VariableElement field) {
1507 assert(invariant(classElement, member.isDeclaration)); 1549 assert(invariant(element, field.isDeclaration));
1508 LibraryElement library = member.getLibrary(); 1550 SourceString name = field.name;
1509 SourceString name = member.name;
1510 bool isPrivate = name.isPrivate();
1511 1551
1512 // Keep track of whether or not we're dealing with a field mixin 1552 // Keep track of whether or not we're dealing with a field mixin
1513 // into a native class. 1553 // into a native class.
1514 bool isMixinNativeField = 1554 bool isMixinNativeField =
1515 classElement.isNative() && enclosingClass.isMixinApplication; 1555 isClass && element.isNative() && holder.isMixinApplication;
1516 1556
1517 // See if we can dynamically create getters and setters. 1557 // See if we can dynamically create getters and setters.
1518 // We can only generate getters and setters for [classElement] since 1558 // We can only generate getters and setters for [element] since
1519 // the fields of super classes could be overwritten with getters or 1559 // the fields of super classes could be overwritten with getters or
1520 // setters. 1560 // setters.
1521 bool needsGetter = false; 1561 bool needsGetter = false;
1522 bool needsSetter = false; 1562 bool needsSetter = false;
1523 // We need to name shadowed fields differently, so they don't clash with 1563 // We need to name shadowed fields differently, so they don't clash with
1524 // the non-shadowed field. 1564 // the non-shadowed field.
1525 bool isShadowed = false; 1565 bool isShadowed = false;
1526 if (isMixinNativeField || identical(enclosingClass, classElement)) { 1566 if (isLibrary || isMixinNativeField || holder == element) {
1527 needsGetter = instanceFieldNeedsGetter(member); 1567 needsGetter = fieldNeedsGetter(field);
1528 needsSetter = instanceFieldNeedsSetter(member); 1568 needsSetter = fieldNeedsSetter(field);
1529 } else { 1569 } else {
1530 isShadowed = classElement.isShadowedByField(member); 1570 ClassElement cls = element;
1571 isShadowed = cls.isShadowedByField(field);
1531 } 1572 }
1532 1573
1533 if ((isInstantiated && !enclosingClass.isNative()) 1574 if ((isInstantiated && !holder.isNative())
1534 || needsGetter 1575 || needsGetter
1535 || needsSetter) { 1576 || needsSetter) {
1536 String accessorName = isShadowed 1577 String accessorName = isShadowed
1537 ? namer.shadowedFieldName(member) 1578 ? namer.shadowedFieldName(field)
1538 : namer.getName(member); 1579 : namer.getName(field);
1539 String fieldName = member.hasFixedBackendName() 1580 String fieldName = field.hasFixedBackendName()
1540 ? member.fixedBackendName() 1581 ? field.fixedBackendName()
1541 : (isMixinNativeField ? member.name.slowToString() : accessorName); 1582 : (isMixinNativeField ? name.slowToString() : accessorName);
1542 bool needsCheckedSetter = false; 1583 bool needsCheckedSetter = false;
1543 if (needsSetter) { 1584 if (compiler.enableTypeAssertions
1544 if (compiler.enableTypeAssertions 1585 && needsSetter
1545 && canGenerateCheckedSetter(member)) { 1586 && canGenerateCheckedSetter(field)) {
1546 needsCheckedSetter = true; 1587 needsCheckedSetter = true;
1547 needsSetter = false; 1588 needsSetter = false;
1548 }
1549 } 1589 }
1550 // Getters and setters with suffixes will be generated dynamically. 1590 // Getters and setters with suffixes will be generated dynamically.
1551 addField(member, 1591 f(field, fieldName, accessorName, needsGetter, needsSetter,
1552 fieldName, 1592 needsCheckedSetter);
1553 accessorName,
1554 needsGetter,
1555 needsSetter,
1556 needsCheckedSetter);
1557 } 1593 }
1558 } 1594 }
1559 1595
1560 if (visitStatics) { 1596 if (isLibrary) {
1561 classElement.implementation.forEachStaticField(visitField); 1597 LibraryElement library = element;
1598 library.implementation.forEachLocalMember((Element member) {
1599 if (member.isField()) visitField(library, member);
1600 });
1601 } else if (visitStatics) {
1602 ClassElement cls = element;
1603 cls.implementation.forEachStaticField(visitField);
1562 } else { 1604 } else {
1605 ClassElement cls = element;
1563 // TODO(kasperl): We should make sure to only emit one version of 1606 // TODO(kasperl): We should make sure to only emit one version of
1564 // overridden fields. Right now, we rely on the ordering so the 1607 // overridden fields. Right now, we rely on the ordering so the
1565 // fields pulled in from mixins are replaced with the fields from 1608 // fields pulled in from mixins are replaced with the fields from
1566 // the class definition. 1609 // the class definition.
1567 1610
1568 // If a class is not instantiated then we add the field just so we can 1611 // If a class is not instantiated then we add the field just so we can
1569 // generate the field getter/setter dynamically. Since this is only 1612 // generate the field getter/setter dynamically. Since this is only
1570 // allowed on fields that are in [classElement] we don't need to visit 1613 // allowed on fields that are in [element] we don't need to visit
1571 // superclasses for non-instantiated classes. 1614 // superclasses for non-instantiated classes.
1572 classElement.implementation.forEachInstanceField( 1615 cls.implementation.forEachInstanceField(
1573 visitField, 1616 visitField, includeSuperAndInjectedMembers: isInstantiated);
1574 includeSuperAndInjectedMembers: isInstantiated);
1575 } 1617 }
1576 } 1618 }
1577 1619
1578 void generateGetter(Element member, String fieldName, String accessorName, 1620 void generateGetter(Element member, String fieldName, String accessorName,
1579 ClassBuilder builder) { 1621 ClassBuilder builder) {
1580 String getterName = namer.getterNameFromAccessorName(accessorName); 1622 String getterName = namer.getterNameFromAccessorName(accessorName);
1581 String receiver = backend.isInterceptorClass(member.getEnclosingClass()) 1623 String receiver = backend.isInterceptorClass(member.getEnclosingClass())
1582 ? 'receiver' : 'this'; 1624 ? 'receiver' : 'this';
1583 List<String> args = backend.isInterceptedMethod(member) 1625 List<String> args = backend.isInterceptedMethod(member)
1584 ? ['receiver'] 1626 ? ['receiver']
1585 : []; 1627 : [];
1586 builder.addProperty(getterName, 1628 builder.addProperty(getterName,
1587 js.fun(args, js.return_(js('$receiver.$fieldName')))); 1629 js.fun(args, js.return_(js('$receiver.$fieldName'))));
1588 } 1630 }
1589 1631
1590 void generateSetter(Element member, String fieldName, String accessorName, 1632 void generateSetter(Element member, String fieldName, String accessorName,
1591 ClassBuilder builder) { 1633 ClassBuilder builder) {
1592 String setterName = namer.setterNameFromAccessorName(accessorName); 1634 String setterName = namer.setterNameFromAccessorName(accessorName);
1593 String receiver = backend.isInterceptorClass(member.getEnclosingClass()) 1635 String receiver = backend.isInterceptorClass(member.getEnclosingClass())
1594 ? 'receiver' : 'this'; 1636 ? 'receiver' : 'this';
1595 List<String> args = backend.isInterceptedMethod(member) 1637 List<String> args = backend.isInterceptedMethod(member)
1596 ? ['receiver', 'v'] 1638 ? ['receiver', 'v']
1597 : ['v']; 1639 : ['v'];
1598 builder.addProperty(setterName, 1640 builder.addProperty(setterName,
1599 js.fun(args, js('$receiver.$fieldName = v'))); 1641 js.fun(args, js('$receiver.$fieldName = v')));
1600 } 1642 }
1601 1643
1602 bool canGenerateCheckedSetter(Element member) { 1644 bool canGenerateCheckedSetter(VariableElement field) {
1603 // We never generate accessors for top-level/static fields. 1645 // We never generate accessors for top-level/static fields.
1604 if (!member.isInstanceMember()) return false; 1646 if (!field.isInstanceMember()) return false;
1605 DartType type = member.computeType(compiler).unalias(compiler); 1647 DartType type = field.computeType(compiler).unalias(compiler);
1606 if (type.element.isTypeVariable() || 1648 if (type.element.isTypeVariable() ||
1607 (type is FunctionType && type.containsTypeVariables) || 1649 (type is FunctionType && type.containsTypeVariables) ||
1608 type.element == compiler.dynamicClass || 1650 type.element == compiler.dynamicClass ||
1609 type.element == compiler.objectClass) { 1651 type.element == compiler.objectClass) {
1610 // TODO(ngeoffray): Support type checks on type parameters. 1652 // TODO(ngeoffray): Support type checks on type parameters.
1611 return false; 1653 return false;
1612 } 1654 }
1613 return true; 1655 return true;
1614 } 1656 }
1615 1657
1616 void generateCheckedSetter(Element member, 1658 void generateCheckedSetter(Element member,
1617 String fieldName, 1659 String fieldName,
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
1668 } else { 1710 } else {
1669 previousName = mangledGlobalFieldNames.putIfAbsent( 1711 previousName = mangledGlobalFieldNames.putIfAbsent(
1670 accessorName, 1712 accessorName,
1671 () => memberName); 1713 () => memberName);
1672 } 1714 }
1673 assert(invariant(member, previousName == memberName, 1715 assert(invariant(member, previousName == memberName,
1674 message: '$previousName != ${memberName}')); 1716 message: '$previousName != ${memberName}'));
1675 } 1717 }
1676 1718
1677 /// Returns `true` if fields added. 1719 /// Returns `true` if fields added.
1678 bool emitClassFields(ClassElement classElement, 1720 bool emitFields(Element element,
1679 ClassBuilder builder, 1721 ClassBuilder builder,
1680 String superName, 1722 String superName,
1681 { bool classIsNative: false, 1723 { bool classIsNative: false,
1682 bool emitStatics: false, 1724 bool emitStatics: false,
1683 bool onlyForRti: false }) { 1725 bool onlyForRti: false }) {
1684 assert(!emitStatics || !onlyForRti); 1726 assert(!emitStatics || !onlyForRti);
1727 bool isClass = false;
1728 bool isLibrary = false;
1729 if (element.isClass()) {
1730 isClass = true;
1731 } else if (element.isLibrary()) {
1732 isLibrary = false;
1733 assert(invariant(element, emitStatics));
1734 } else {
1735 throw new SpannableAssertionFailure(
1736 element, 'Must be a ClassElement or a LibraryElement');
1737 }
1685 StringBuffer buffer = new StringBuffer(); 1738 StringBuffer buffer = new StringBuffer();
1686 if (emitStatics) { 1739 if (emitStatics) {
1687 assert(invariant(classElement, superName == null, message: superName)); 1740 assert(invariant(element, superName == null, message: superName));
1688 } else { 1741 } else {
1689 assert(invariant(classElement, superName != null)); 1742 assert(invariant(element, superName != null));
1690 String nativeName = 1743 String nativeName =
1691 namer.getPrimitiveInterceptorRuntimeName(classElement); 1744 namer.getPrimitiveInterceptorRuntimeName(element);
1692 if (nativeName != null) { 1745 if (nativeName != null) {
1693 buffer.write('$nativeName/'); 1746 buffer.write('$nativeName/');
1694 } 1747 }
1695 buffer.write('$superName;'); 1748 buffer.write('$superName;');
1696 } 1749 }
1697 int bufferClassLength = buffer.length; 1750 int bufferClassLength = buffer.length;
1698 1751
1699 String separator = ''; 1752 String separator = '';
1700 1753
1701 var fieldMetadata = []; 1754 var fieldMetadata = [];
1702 bool hasMetadata = false; 1755 bool hasMetadata = false;
1703 1756
1704 if (!onlyForRti) { 1757 if (!onlyForRti) {
1705 visitClassFields(classElement, emitStatics, 1758 visitFields(element, emitStatics,
1706 (Element member, 1759 (VariableElement field,
1707 String name, 1760 String name,
1708 String accessorName, 1761 String accessorName,
1709 bool needsGetter, 1762 bool needsGetter,
1710 bool needsSetter, 1763 bool needsSetter,
1711 bool needsCheckedSetter) { 1764 bool needsCheckedSetter) {
1712 // Ignore needsCheckedSetter - that is handled below. 1765 // Ignore needsCheckedSetter - that is handled below.
1713 bool needsAccessor = (needsGetter || needsSetter); 1766 bool needsAccessor = (needsGetter || needsSetter);
1714 // We need to output the fields for non-native classes so we can auto- 1767 // We need to output the fields for non-native classes so we can auto-
1715 // generate the constructor. For native classes there are no 1768 // generate the constructor. For native classes there are no
1716 // constructors, so we don't need the fields unless we are generating 1769 // constructors, so we don't need the fields unless we are generating
1717 // accessors at runtime. 1770 // accessors at runtime.
1718 if (!classIsNative || needsAccessor) { 1771 if (!classIsNative || needsAccessor) {
1719 buffer.write(separator); 1772 buffer.write(separator);
1720 separator = ','; 1773 separator = ',';
1721 var metadata = buildMetadataFunction(member); 1774 var metadata = buildMetadataFunction(field);
1722 if (metadata != null) { 1775 if (metadata != null) {
1723 hasMetadata = true; 1776 hasMetadata = true;
1724 } else { 1777 } else {
1725 metadata = new jsAst.LiteralNull(); 1778 metadata = new jsAst.LiteralNull();
1726 } 1779 }
1727 fieldMetadata.add(metadata); 1780 fieldMetadata.add(metadata);
1728 recordMangledField(member, accessorName, member.name.slowToString()); 1781 recordMangledField(field, accessorName, field.name.slowToString());
1729 if (!needsAccessor) { 1782 if (!needsAccessor) {
1730 // Emit field for constructor generation. 1783 // Emit field for constructor generation.
1731 assert(!classIsNative); 1784 assert(!classIsNative);
1732 buffer.write(name); 1785 buffer.write(name);
1733 } else { 1786 } else {
1734 // Emit (possibly renaming) field name so we can add accessors at 1787 // Emit (possibly renaming) field name so we can add accessors at
1735 // runtime. 1788 // runtime.
1736 buffer.write(accessorName); 1789 buffer.write(accessorName);
1737 if (name != accessorName) { 1790 if (name != accessorName) {
1738 buffer.write(':$name'); 1791 buffer.write(':$name');
1739 // Only the native classes can have renaming accessors. 1792 // Only the native classes can have renaming accessors.
1740 assert(classIsNative); 1793 assert(classIsNative);
1741 } 1794 }
1742 1795
1743 int getterCode = 0; 1796 int getterCode = 0;
1744 if (needsGetter) { 1797 if (needsGetter) {
1745 // 01: function() { return this.field; } 1798 if (field.isInstanceMember()) {
1746 // 10: function(receiver) { return receiver.field; } 1799 // 01: function() { return this.field; }
1747 // 11: function(receiver) { return this.field; } 1800 // 10: function(receiver) { return receiver.field; }
1748 if (member.isInstanceMember()) { 1801 // 11: function(receiver) { return this.field; }
1749 getterCode += backend.fieldHasInterceptedGetter(member) ? 2 : 0; 1802 getterCode += backend.fieldHasInterceptedGetter(field) ? 2 : 0;
1750 getterCode += backend.isInterceptorClass(classElement) ? 0 : 1; 1803 getterCode += backend.isInterceptorClass(element) ? 0 : 1;
1751 // TODO(sra): 'isInterceptorClass' might not be the correct 1804 // TODO(sra): 'isInterceptorClass' might not be the correct test
1752 // test for methods forced to use the interceptor convention 1805 // for methods forced to use the interceptor convention because
1753 // because the method's class was elsewhere mixed-in to an 1806 // the method's class was elsewhere mixed-in to an interceptor.
1754 // interceptor. 1807 assert(!field.isInstanceMember() || getterCode != 0);
1755 assert(getterCode != 0);
1756 } else { 1808 } else {
1757 getterCode = 1; 1809 getterCode = 1;
1758 } 1810 }
1759 } 1811 }
1760 int setterCode = 0; 1812 int setterCode = 0;
1761 if (needsSetter) { 1813 if (needsSetter) {
1762 // 01: function(value) { this.field = value; } 1814 if (field.isInstanceMember()) {
1763 // 10: function(receiver, value) { receiver.field = value; } 1815 // 01: function(value) { this.field = value; }
1764 // 11: function(receiver, value) { this.field = value; } 1816 // 10: function(receiver, value) { receiver.field = value; }
1765 if (member.isInstanceMember()) { 1817 // 11: function(receiver, value) { this.field = value; }
1766 setterCode += backend.fieldHasInterceptedSetter(member) ? 2 : 0; 1818 setterCode += backend.fieldHasInterceptedSetter(field) ? 2 : 0;
1767 setterCode += backend.isInterceptorClass(classElement) ? 0 : 1; 1819 setterCode += backend.isInterceptorClass(element) ? 0 : 1;
1768 assert(setterCode != 0); 1820 assert(!field.isInstanceMember() || setterCode != 0);
1769 } else { 1821 } else {
1770 setterCode = 1; 1822 setterCode = 1;
1771 } 1823 }
1772 } 1824 }
1773 int code = getterCode + (setterCode << 2); 1825 int code = getterCode + (setterCode << 2);
1774 if (code == 0) { 1826 if (code == 0) {
1775 compiler.reportInternalError( 1827 compiler.reportInternalError(
1776 member, 'Internal error: code is 0 ($classElement/$member)'); 1828 field, 'Internal error: code is 0 ($element/$field)');
1777 } else { 1829 } else {
1778 buffer.write(FIELD_CODE_CHARACTERS[code - FIRST_FIELD_CODE]); 1830 buffer.write(FIELD_CODE_CHARACTERS[code - FIRST_FIELD_CODE]);
1779 } 1831 }
1780 } 1832 }
1781 } 1833 }
1782 }); 1834 });
1783 } 1835 }
1784 1836
1785 bool fieldsAdded = buffer.length > bufferClassLength; 1837 bool fieldsAdded = buffer.length > bufferClassLength;
1786 String compactClassData = buffer.toString(); 1838 String compactClassData = buffer.toString();
1787 jsAst.Expression classDataNode = js.string(compactClassData); 1839 jsAst.Expression classDataNode = js.string(compactClassData);
1788 if (hasMetadata) { 1840 if (hasMetadata) {
1789 fieldMetadata.insert(0, classDataNode); 1841 fieldMetadata.insert(0, classDataNode);
1790 classDataNode = new jsAst.ArrayInitializer.from(fieldMetadata); 1842 classDataNode = new jsAst.ArrayInitializer.from(fieldMetadata);
1791 } 1843 }
1792 builder.addProperty('', classDataNode); 1844 builder.addProperty('', classDataNode);
1793 return fieldsAdded; 1845 return fieldsAdded;
1794 } 1846 }
1795 1847
1796 void emitClassGettersSetters(ClassElement classElement, 1848 void emitClassGettersSetters(ClassElement classElement,
1797 ClassBuilder builder) { 1849 ClassBuilder builder) {
1798 1850
1799 visitClassFields(classElement, false, 1851 visitFields(classElement, false,
1800 (Element member, 1852 (VariableElement member,
1801 String name, 1853 String name,
1802 String accessorName, 1854 String accessorName,
1803 bool needsGetter, 1855 bool needsGetter,
1804 bool needsSetter, 1856 bool needsSetter,
1805 bool needsCheckedSetter) { 1857 bool needsCheckedSetter) {
1806 compiler.withCurrentElement(member, () { 1858 compiler.withCurrentElement(member, () {
1807 if (needsCheckedSetter) { 1859 if (needsCheckedSetter) {
1808 assert(!needsSetter); 1860 assert(!needsSetter);
1809 generateCheckedSetter(member, name, accessorName, builder); 1861 generateCheckedSetter(member, name, accessorName, builder);
1810 } 1862 }
1811 if (!getterAndSetterCanBeImplementedByFieldSpec) { 1863 if (!getterAndSetterCanBeImplementedByFieldSpec) {
1812 if (needsGetter) { 1864 if (needsGetter) {
1813 generateGetter(member, name, accessorName, builder); 1865 generateGetter(member, name, accessorName, builder);
1814 } 1866 }
1815 if (needsSetter) { 1867 if (needsSetter) {
(...skipping 29 matching lines...) Expand all
1845 if (classElement.isMixinApplication) { 1897 if (classElement.isMixinApplication) {
1846 String mixinName = namer.getName(computeMixinClass(classElement)); 1898 String mixinName = namer.getName(computeMixinClass(classElement));
1847 superName = '$superName+$mixinName'; 1899 superName = '$superName+$mixinName';
1848 needsMixinSupport = true; 1900 needsMixinSupport = true;
1849 } 1901 }
1850 1902
1851 ClassBuilder builder = new ClassBuilder(); 1903 ClassBuilder builder = new ClassBuilder();
1852 emitClassConstructor(classElement, builder); 1904 emitClassConstructor(classElement, builder);
1853 emitSuper(superName, builder); 1905 emitSuper(superName, builder);
1854 emitRuntimeName(runtimeName, builder); 1906 emitRuntimeName(runtimeName, builder);
1855 emitClassFields(classElement, builder, superName, onlyForRti: onlyForRti); 1907 emitFields(classElement, builder, superName, onlyForRti: onlyForRti);
1856 emitClassGettersSetters(classElement, builder); 1908 emitClassGettersSetters(classElement, builder);
1857 if (!classElement.isMixinApplication) { 1909 if (!classElement.isMixinApplication) {
1858 emitInstanceMembers(classElement, builder); 1910 emitInstanceMembers(classElement, builder);
1859 } 1911 }
1860 emitIsTests(classElement, builder); 1912 emitIsTests(classElement, builder);
1861 1913
1862 emitClassBuilderWithReflectionData( 1914 emitClassBuilderWithReflectionData(
1863 className, classElement, builder, buffer); 1915 className, classElement, builder, buffer);
1864 } 1916 }
1865 1917
1866 void emitClassBuilderWithReflectionData(String className, 1918 void emitClassBuilderWithReflectionData(String className,
1867 ClassElement classElement, 1919 ClassElement classElement,
1868 ClassBuilder builder, 1920 ClassBuilder builder,
1869 CodeBuffer buffer) { 1921 CodeBuffer buffer) {
1870 var metadata = buildMetadataFunction(classElement); 1922 var metadata = buildMetadataFunction(classElement);
1871 if (metadata != null) { 1923 if (metadata != null) {
1872 builder.addProperty("@", metadata); 1924 builder.addProperty("@", metadata);
1873 } 1925 }
1874 1926
1875 List<CodeBuffer> classBuffers = elementBuffers[classElement]; 1927 List<CodeBuffer> classBuffers = elementBuffers[classElement];
1876 if (classBuffers == null) { 1928 if (classBuffers == null) {
1877 classBuffers = []; 1929 classBuffers = [];
1878 } else { 1930 } else {
1879 elementBuffers.remove(classElement); 1931 elementBuffers.remove(classElement);
1880 } 1932 }
1881 CodeBuffer statics = new CodeBuffer(); 1933 CodeBuffer statics = new CodeBuffer();
1882 statics.write('{$n'); 1934 statics.write('{$n');
1883 bool hasStatics = false; 1935 bool hasStatics = false;
1884 ClassBuilder staticsBuilder = new ClassBuilder(); 1936 ClassBuilder staticsBuilder = new ClassBuilder();
1885 if (emitClassFields( 1937 if (emitFields(classElement, staticsBuilder, null, emitStatics: true)) {
1886 classElement, staticsBuilder, null, emitStatics: true)) {
1887 hasStatics = true; 1938 hasStatics = true;
1888 statics.write('"":$_'); 1939 statics.write('"":$_');
1889 statics.write( 1940 statics.write(
1890 jsAst.prettyPrint(staticsBuilder.properties.single.value, compiler)); 1941 jsAst.prettyPrint(staticsBuilder.properties.single.value, compiler));
1891 statics.write(',$n'); 1942 statics.write(',$n');
1892 } 1943 }
1893 for (CodeBuffer classBuffer in classBuffers) { 1944 for (CodeBuffer classBuffer in classBuffers) {
1894 // TODO(ahe): What about deferred? 1945 // TODO(ahe): What about deferred?
1895 if (classBuffer != null) { 1946 if (classBuffer != null) {
1896 hasStatics = true; 1947 hasStatics = true;
(...skipping 1707 matching lines...) Expand 10 before | Expand all | Expand 10 after
3604 // After this assignment we will produce invalid JavaScript code if we use 3655 // After this assignment we will produce invalid JavaScript code if we use
3605 // the classesCollector variable. 3656 // the classesCollector variable.
3606 classesCollector = 'classesCollector should not be used from now on'; 3657 classesCollector = 'classesCollector should not be used from now on';
3607 3658
3608 if (!elementBuffers.isEmpty) { 3659 if (!elementBuffers.isEmpty) {
3609 var oldClassesCollector = classesCollector; 3660 var oldClassesCollector = classesCollector;
3610 classesCollector = r"$$"; 3661 classesCollector = r"$$";
3611 if (compiler.enableMinification) { 3662 if (compiler.enableMinification) {
3612 mainBuffer.write(';'); 3663 mainBuffer.write(';');
3613 } 3664 }
3665
3666 for (Element element in elementBuffers.keys) {
3667 // TODO(ahe): Should iterate over all libraries. Otherwise, we will
3668 // not see libraries that only have fields.
3669 if (element.isLibrary()) {
3670 LibraryElement library = element;
3671 ClassBuilder builder = new ClassBuilder();
3672 if (emitFields(library, builder, null, emitStatics: true)) {
3673 List<CodeBuffer> buffers = elementBuffers[library];
3674 var buffer = buffers[0];
3675 if (buffer == null) {
3676 buffers[0] = buffer = new CodeBuffer();
3677 }
3678 for (jsAst.Property property in builder.properties) {
3679 if (!buffer.isEmpty) buffer.write(',$n');
3680 buffer.addBuffer(jsAst.prettyPrint(property, compiler));
3681 }
3682 }
3683 }
3684 }
3685
3614 if (!mangledFieldNames.isEmpty) { 3686 if (!mangledFieldNames.isEmpty) {
3615 var keys = mangledFieldNames.keys.toList(); 3687 var keys = mangledFieldNames.keys.toList();
3616 keys.sort(); 3688 keys.sort();
3617 var properties = []; 3689 var properties = [];
3618 for (String key in keys) { 3690 for (String key in keys) {
3619 var value = js.string('${mangledFieldNames[key]}'); 3691 var value = js.string('${mangledFieldNames[key]}');
3620 properties.add(new jsAst.Property(js.string(key), value)); 3692 properties.add(new jsAst.Property(js.string(key), value));
3621 } 3693 }
3622 var map = new jsAst.ObjectInitializer(properties); 3694 var map = new jsAst.ObjectInitializer(properties);
3623 mainBuffer.write( 3695 mainBuffer.write(
(...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after
3900 var mangledNames = init.mangledNames; 3972 var mangledNames = init.mangledNames;
3901 var mangledGlobalNames = init.mangledGlobalNames; 3973 var mangledGlobalNames = init.mangledGlobalNames;
3902 var hasOwnProperty = Object.prototype.hasOwnProperty; 3974 var hasOwnProperty = Object.prototype.hasOwnProperty;
3903 var length = reflectionData.length; 3975 var length = reflectionData.length;
3904 for (var i = 0; i < length; i++) { 3976 for (var i = 0; i < length; i++) {
3905 var data = reflectionData[i]; 3977 var data = reflectionData[i];
3906 var name = data[0]; 3978 var name = data[0];
3907 var uri = data[1]; 3979 var uri = data[1];
3908 var metadata = data[2]; 3980 var metadata = data[2];
3909 var descriptor = data[3]; 3981 var descriptor = data[3];
3982 var fields = descriptor && descriptor[""];
3910 var classes = []; 3983 var classes = [];
3911 var functions = []; 3984 var functions = [];
3912 function processStatics(descriptor) { 3985 function processStatics(descriptor) {
3913 for (var property in descriptor) { 3986 for (var property in descriptor) {
3914 if (!hasOwnProperty.call(descriptor, property)) continue; 3987 if (!hasOwnProperty.call(descriptor, property)) continue;
3915 if (property === "") continue; 3988 if (property === "") continue;
3916 var element = descriptor[property]; 3989 var element = descriptor[property];
3917 var firstChar = property.substring(0, 1); 3990 var firstChar = property.substring(0, 1);
3918 var previousProperty; 3991 var previousProperty;
3919 if (firstChar === "+") { 3992 if (firstChar === "+") {
(...skipping 20 matching lines...) Expand all
3940 } else { 4013 } else {
3941 newDesc[previousProp = prop] = element[prop]; 4014 newDesc[previousProp = prop] = element[prop];
3942 } 4015 }
3943 } 4016 }
3944 $classesCollector[property] = newDesc; 4017 $classesCollector[property] = newDesc;
3945 classes.push(property); 4018 classes.push(property);
3946 } 4019 }
3947 } 4020 }
3948 } 4021 }
3949 processStatics(descriptor); 4022 processStatics(descriptor);
3950 libraries.push([name, uri, classes, functions, metadata]); 4023 libraries.push([name, uri, classes, functions, metadata, fields]);
3951 } 4024 }
3952 })'''; 4025 })''';
3953 } 4026 }
3954 } 4027 }
3955 4028
3956 const String GENERATED_BY = """ 4029 const String GENERATED_BY = """
3957 // Generated by dart2js, the Dart to JavaScript compiler. 4030 // Generated by dart2js, the Dart to JavaScript compiler.
3958 """; 4031 """;
3959 4032
3960 const String HOOKS_API_USAGE = """ 4033 const String HOOKS_API_USAGE = """
3961 // The code supports the following hooks: 4034 // The code supports the following hooks:
3962 // dartPrint(message) - if this function is defined it is called 4035 // dartPrint(message) - if this function is defined it is called
3963 // instead of the Dart [print] method. 4036 // instead of the Dart [print] method.
3964 // dartMainRunner(main) - if this function is defined, the Dart [main] 4037 // dartMainRunner(main) - if this function is defined, the Dart [main]
3965 // method will not be invoked directly. 4038 // method will not be invoked directly.
3966 // Instead, a closure that will invoke [main] is 4039 // Instead, a closure that will invoke [main] is
3967 // passed to [dartMainRunner]. 4040 // passed to [dartMainRunner].
3968 """; 4041 """;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698