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

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: Address comments 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 1141 matching lines...) Expand 10 before | Expand all | Expand 10 after
1184 for (int i = 1; i <= signature.optionalParameterCount; i++) { 1209 for (int i = 1; i <= signature.optionalParameterCount; i++) {
1185 selectors.add(new Selector(SelectorKind.CALL, 1210 selectors.add(new Selector(SelectorKind.CALL,
1186 element.name, 1211 element.name,
1187 element.getLibrary(), 1212 element.getLibrary(),
1188 signature.requiredParameterCount + i, 1213 signature.requiredParameterCount + i,
1189 <SourceString>[])); 1214 <SourceString>[]));
1190 } 1215 }
1191 return selectors; 1216 return selectors;
1192 } 1217 }
1193 1218
1194 bool instanceFieldNeedsGetter(Element member) { 1219 bool fieldNeedsGetter(VariableElement field) {
1195 assert(member.isField()); 1220 assert(field.isField());
1196 if (fieldAccessNeverThrows(member)) return false; 1221 if (fieldAccessNeverThrows(field)) return false;
1197 return backend.retainGetter(member) 1222 return backend.retainGetter(field)
1198 || compiler.codegenWorld.hasInvokedGetter(member, compiler); 1223 || compiler.codegenWorld.hasInvokedGetter(field, compiler);
1199 } 1224 }
1200 1225
1201 bool instanceFieldNeedsSetter(Element member) { 1226 bool fieldNeedsSetter(VariableElement field) {
1202 assert(member.isField()); 1227 assert(field.isField());
1203 if (fieldAccessNeverThrows(member)) return false; 1228 if (fieldAccessNeverThrows(field)) return false;
1204 return (!member.modifiers.isFinalOrConst()) 1229 return (!field.modifiers.isFinalOrConst())
1205 && (backend.retainSetter(member) 1230 && (backend.retainSetter(field)
1206 || compiler.codegenWorld.hasInvokedSetter(member, compiler)); 1231 || compiler.codegenWorld.hasInvokedSetter(field, compiler));
1207 } 1232 }
1208 1233
1209 // We never access a field in a closure (a captured variable) without knowing 1234 // We never access a field in a closure (a captured variable) without knowing
1210 // that it is there. Therefore we don't need to use a getter (that will throw 1235 // that it is there. Therefore we don't need to use a getter (that will throw
1211 // if the getter method is missing), but can always access the field directly. 1236 // if the getter method is missing), but can always access the field directly.
1212 static bool fieldAccessNeverThrows(Element element) { 1237 static bool fieldAccessNeverThrows(VariableElement field) {
1213 return element is ClosureFieldElement; 1238 return field is ClosureFieldElement;
1214 } 1239 }
1215 1240
1216 String compiledFieldName(Element member) { 1241 String compiledFieldName(Element member) {
1217 assert(member.isField()); 1242 assert(member.isField());
1218 return member.hasFixedBackendName() 1243 return member.hasFixedBackendName()
1219 ? member.fixedBackendName() 1244 ? member.fixedBackendName()
1220 : namer.getName(member); 1245 : namer.getName(member);
1221 } 1246 }
1222 1247
1223 /** 1248 /**
(...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after
1477 for (ClassElement cls in typeChecks) { 1502 for (ClassElement cls in typeChecks) {
1478 for (TypeCheck check in typeChecks[cls]) { 1503 for (TypeCheck check in typeChecks[cls]) {
1479 result.add(backend.getImplementationClass(cls)); 1504 result.add(backend.getImplementationClass(cls));
1480 break; 1505 break;
1481 } 1506 }
1482 } 1507 }
1483 return result; 1508 return result;
1484 } 1509 }
1485 1510
1486 /** 1511 /**
1487 * Documentation wanted -- johnniwinther 1512 * Calls [addField] for each of the fields of [element].
1488 * 1513 *
1489 * Invariant: [classElement] must be a declaration element. 1514 * [element] must be a [ClassElement] or a [LibraryElement].
1515 *
1516 * If [element] is a [ClassElement], the static fields of the class are
1517 * visited if [visitStatics] is true and the instance fields are visited if
1518 * [visitStatics] is false.
1519 *
1520 * If [element] is a [LibraryElement], [visitStatics] must be true.
1521 *
1522 * When visiting the instance fields of a class, the fields of its superclass
1523 * are also visited if the class is instantiated.
1524 *
1525 * Invariant: [element] must be a declaration element.
1490 */ 1526 */
1491 void visitClassFields(ClassElement classElement, 1527 void visitFields(Element element, bool visitStatics, AcceptField f) {
1492 bool visitStatics, 1528 assert(invariant(element, element.isDeclaration));
1493 void addField(Element member, 1529
1494 String name, 1530 bool isClass = false;
1495 String accessorName, 1531 bool isLibrary = false;
1496 bool needsGetter, 1532 if (element.isClass()) {
1497 bool needsSetter, 1533 isClass = true;
1498 bool needsCheckedSetter)) { 1534 } else if (element.isLibrary()) {
1499 assert(invariant(classElement, classElement.isDeclaration)); 1535 isLibrary = true;
1536 assert(invariant(element, visitStatics));
1537 } else {
1538 throw new SpannableAssertionFailure(
1539 element, 'Expected a ClassElement or a LibraryElement.');
1540 }
1541
1500 // If the class is never instantiated we still need to set it up for 1542 // If the class is never instantiated we still need to set it up for
1501 // inheritance purposes, but we can simplify its JavaScript constructor. 1543 // inheritance purposes, but we can simplify its JavaScript constructor.
1502 bool isInstantiated = 1544 bool isInstantiated =
1503 compiler.codegenWorld.instantiatedClasses.contains(classElement); 1545 compiler.codegenWorld.instantiatedClasses.contains(element);
1504 1546
1505 void visitField(ClassElement enclosingClass, Element member) { 1547 void visitField(Element holder, VariableElement field) {
1506 assert(invariant(classElement, member.isDeclaration)); 1548 assert(invariant(element, field.isDeclaration));
1507 LibraryElement library = member.getLibrary(); 1549 SourceString name = field.name;
1508 SourceString name = member.name;
1509 bool isPrivate = name.isPrivate();
1510 1550
1511 // Keep track of whether or not we're dealing with a field mixin 1551 // Keep track of whether or not we're dealing with a field mixin
1512 // into a native class. 1552 // into a native class.
1513 bool isMixinNativeField = 1553 bool isMixinNativeField =
1514 classElement.isNative() && enclosingClass.isMixinApplication; 1554 isClass && element.isNative() && holder.isMixinApplication;
1515 1555
1516 // See if we can dynamically create getters and setters. 1556 // See if we can dynamically create getters and setters.
1517 // We can only generate getters and setters for [classElement] since 1557 // We can only generate getters and setters for [element] since
1518 // the fields of super classes could be overwritten with getters or 1558 // the fields of super classes could be overwritten with getters or
1519 // setters. 1559 // setters.
1520 bool needsGetter = false; 1560 bool needsGetter = false;
1521 bool needsSetter = false; 1561 bool needsSetter = false;
1522 // We need to name shadowed fields differently, so they don't clash with 1562 // We need to name shadowed fields differently, so they don't clash with
1523 // the non-shadowed field. 1563 // the non-shadowed field.
1524 bool isShadowed = false; 1564 bool isShadowed = false;
1525 if (isMixinNativeField || identical(enclosingClass, classElement)) { 1565 if (isLibrary || isMixinNativeField || holder == element) {
1526 needsGetter = instanceFieldNeedsGetter(member); 1566 needsGetter = fieldNeedsGetter(field);
1527 needsSetter = instanceFieldNeedsSetter(member); 1567 needsSetter = fieldNeedsSetter(field);
1528 } else { 1568 } else {
1529 isShadowed = classElement.isShadowedByField(member); 1569 ClassElement cls = element;
1570 isShadowed = cls.isShadowedByField(field);
1530 } 1571 }
1531 1572
1532 if ((isInstantiated && !enclosingClass.isNative()) 1573 if ((isInstantiated && !holder.isNative())
1533 || needsGetter 1574 || needsGetter
1534 || needsSetter) { 1575 || needsSetter) {
1535 String accessorName = isShadowed 1576 String accessorName = isShadowed
1536 ? namer.shadowedFieldName(member) 1577 ? namer.shadowedFieldName(field)
1537 : namer.getName(member); 1578 : namer.getName(field);
1538 String fieldName = member.hasFixedBackendName() 1579 String fieldName = field.hasFixedBackendName()
1539 ? member.fixedBackendName() 1580 ? field.fixedBackendName()
1540 : (isMixinNativeField ? member.name.slowToString() : accessorName); 1581 : (isMixinNativeField ? name.slowToString() : accessorName);
1541 bool needsCheckedSetter = false; 1582 bool needsCheckedSetter = false;
1542 if (needsSetter) { 1583 if (compiler.enableTypeAssertions
1543 if (compiler.enableTypeAssertions 1584 && needsSetter
1544 && canGenerateCheckedSetter(member)) { 1585 && canGenerateCheckedSetter(field)) {
1545 needsCheckedSetter = true; 1586 needsCheckedSetter = true;
1546 needsSetter = false; 1587 needsSetter = false;
1547 }
1548 } 1588 }
1549 // Getters and setters with suffixes will be generated dynamically. 1589 // Getters and setters with suffixes will be generated dynamically.
1550 addField(member, 1590 f(field, fieldName, accessorName, needsGetter, needsSetter,
1551 fieldName, 1591 needsCheckedSetter);
1552 accessorName,
1553 needsGetter,
1554 needsSetter,
1555 needsCheckedSetter);
1556 } 1592 }
1557 } 1593 }
1558 1594
1559 if (visitStatics) { 1595 if (isLibrary) {
1560 classElement.implementation.forEachStaticField(visitField); 1596 LibraryElement library = element;
1597 library.implementation.forEachLocalMember((Element member) {
1598 if (member.isField()) visitField(library, member);
1599 });
1600 } else if (visitStatics) {
1601 ClassElement cls = element;
1602 cls.implementation.forEachStaticField(visitField);
1561 } else { 1603 } else {
1604 ClassElement cls = element;
1562 // TODO(kasperl): We should make sure to only emit one version of 1605 // TODO(kasperl): We should make sure to only emit one version of
1563 // overridden fields. Right now, we rely on the ordering so the 1606 // overridden fields. Right now, we rely on the ordering so the
1564 // fields pulled in from mixins are replaced with the fields from 1607 // fields pulled in from mixins are replaced with the fields from
1565 // the class definition. 1608 // the class definition.
1566 1609
1567 // If a class is not instantiated then we add the field just so we can 1610 // If a class is not instantiated then we add the field just so we can
1568 // generate the field getter/setter dynamically. Since this is only 1611 // generate the field getter/setter dynamically. Since this is only
1569 // allowed on fields that are in [classElement] we don't need to visit 1612 // allowed on fields that are in [element] we don't need to visit
1570 // superclasses for non-instantiated classes. 1613 // superclasses for non-instantiated classes.
1571 classElement.implementation.forEachInstanceField( 1614 cls.implementation.forEachInstanceField(
1572 visitField, 1615 visitField, includeSuperAndInjectedMembers: isInstantiated);
1573 includeSuperAndInjectedMembers: isInstantiated);
1574 } 1616 }
1575 } 1617 }
1576 1618
1577 void generateGetter(Element member, String fieldName, String accessorName, 1619 void generateGetter(Element member, String fieldName, String accessorName,
1578 ClassBuilder builder) { 1620 ClassBuilder builder) {
1579 String getterName = namer.getterNameFromAccessorName(accessorName); 1621 String getterName = namer.getterNameFromAccessorName(accessorName);
1580 String receiver = backend.isInterceptorClass(member.getEnclosingClass()) 1622 String receiver = backend.isInterceptorClass(member.getEnclosingClass())
1581 ? 'receiver' : 'this'; 1623 ? 'receiver' : 'this';
1582 List<String> args = backend.isInterceptedMethod(member) 1624 List<String> args = backend.isInterceptedMethod(member)
1583 ? ['receiver'] 1625 ? ['receiver']
1584 : []; 1626 : [];
1585 builder.addProperty(getterName, 1627 builder.addProperty(getterName,
1586 js.fun(args, js.return_(js('$receiver.$fieldName')))); 1628 js.fun(args, js.return_(js('$receiver.$fieldName'))));
1587 } 1629 }
1588 1630
1589 void generateSetter(Element member, String fieldName, String accessorName, 1631 void generateSetter(Element member, String fieldName, String accessorName,
1590 ClassBuilder builder) { 1632 ClassBuilder builder) {
1591 String setterName = namer.setterNameFromAccessorName(accessorName); 1633 String setterName = namer.setterNameFromAccessorName(accessorName);
1592 String receiver = backend.isInterceptorClass(member.getEnclosingClass()) 1634 String receiver = backend.isInterceptorClass(member.getEnclosingClass())
1593 ? 'receiver' : 'this'; 1635 ? 'receiver' : 'this';
1594 List<String> args = backend.isInterceptedMethod(member) 1636 List<String> args = backend.isInterceptedMethod(member)
1595 ? ['receiver', 'v'] 1637 ? ['receiver', 'v']
1596 : ['v']; 1638 : ['v'];
1597 builder.addProperty(setterName, 1639 builder.addProperty(setterName,
1598 js.fun(args, js('$receiver.$fieldName = v'))); 1640 js.fun(args, js('$receiver.$fieldName = v')));
1599 } 1641 }
1600 1642
1601 bool canGenerateCheckedSetter(Element member) { 1643 bool canGenerateCheckedSetter(VariableElement field) {
1602 // We never generate accessors for top-level/static fields. 1644 // We never generate accessors for top-level/static fields.
1603 if (!member.isInstanceMember()) return false; 1645 if (!field.isInstanceMember()) return false;
1604 DartType type = member.computeType(compiler).unalias(compiler); 1646 DartType type = field.computeType(compiler).unalias(compiler);
1605 if (type.element.isTypeVariable() || 1647 if (type.element.isTypeVariable() ||
1606 (type is FunctionType && type.containsTypeVariables) || 1648 (type is FunctionType && type.containsTypeVariables) ||
1607 type.element == compiler.dynamicClass || 1649 type.element == compiler.dynamicClass ||
1608 type.element == compiler.objectClass) { 1650 type.element == compiler.objectClass) {
1609 // TODO(ngeoffray): Support type checks on type parameters. 1651 // TODO(ngeoffray): Support type checks on type parameters.
1610 return false; 1652 return false;
1611 } 1653 }
1612 return true; 1654 return true;
1613 } 1655 }
1614 1656
1615 void generateCheckedSetter(Element member, 1657 void generateCheckedSetter(Element member,
1616 String fieldName, 1658 String fieldName,
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
1667 } else { 1709 } else {
1668 previousName = mangledGlobalFieldNames.putIfAbsent( 1710 previousName = mangledGlobalFieldNames.putIfAbsent(
1669 accessorName, 1711 accessorName,
1670 () => memberName); 1712 () => memberName);
1671 } 1713 }
1672 assert(invariant(member, previousName == memberName, 1714 assert(invariant(member, previousName == memberName,
1673 message: '$previousName != ${memberName}')); 1715 message: '$previousName != ${memberName}'));
1674 } 1716 }
1675 1717
1676 /// Returns `true` if fields added. 1718 /// Returns `true` if fields added.
1677 bool emitClassFields(ClassElement classElement, 1719 bool emitFields(Element element,
1678 ClassBuilder builder, 1720 ClassBuilder builder,
1679 String superName, 1721 String superName,
1680 { bool classIsNative: false, 1722 { bool classIsNative: false,
1681 bool emitStatics: false }) { 1723 bool emitStatics: false }) {
1724 bool isClass = false;
1725 bool isLibrary = false;
1726 if (element.isClass()) {
1727 isClass = true;
1728 } else if (element.isLibrary()) {
1729 isLibrary = false;
1730 assert(invariant(element, emitStatics));
1731 } else {
1732 throw new SpannableAssertionFailure(
1733 element, 'Must be a ClassElement or a LibraryElement');
1734 }
1682 StringBuffer buffer = new StringBuffer(); 1735 StringBuffer buffer = new StringBuffer();
1683 if (emitStatics) { 1736 if (emitStatics) {
1684 assert(invariant(classElement, superName == null, message: superName)); 1737 assert(invariant(element, superName == null, message: superName));
1685 } else { 1738 } else {
1686 assert(invariant(classElement, superName != null)); 1739 assert(invariant(element, superName != null));
1687 String nativeName = 1740 String nativeName =
1688 namer.getPrimitiveInterceptorRuntimeName(classElement); 1741 namer.getPrimitiveInterceptorRuntimeName(element);
1689 if (nativeName != null) { 1742 if (nativeName != null) {
1690 buffer.write('$nativeName/'); 1743 buffer.write('$nativeName/');
1691 } 1744 }
1692 buffer.write('$superName;'); 1745 buffer.write('$superName;');
1693 } 1746 }
1694 int bufferClassLength = buffer.length; 1747 int bufferClassLength = buffer.length;
1695 1748
1696 String separator = ''; 1749 String separator = '';
1697 1750
1698 var fieldMetadata = []; 1751 var fieldMetadata = [];
1699 bool hasMetadata = false; 1752 bool hasMetadata = false;
1700 1753
1701 visitClassFields(classElement, emitStatics, 1754 visitFields(element, emitStatics,
1702 (Element member, 1755 (VariableElement field,
1703 String name, 1756 String name,
1704 String accessorName, 1757 String accessorName,
1705 bool needsGetter, 1758 bool needsGetter,
1706 bool needsSetter, 1759 bool needsSetter,
1707 bool needsCheckedSetter) { 1760 bool needsCheckedSetter) {
1708 // Ignore needsCheckedSetter - that is handled below. 1761 // Ignore needsCheckedSetter - that is handled below.
1709 bool needsAccessor = (needsGetter || needsSetter); 1762 bool needsAccessor = (needsGetter || needsSetter);
1710 // We need to output the fields for non-native classes so we can auto- 1763 // We need to output the fields for non-native classes so we can auto-
1711 // generate the constructor. For native classes there are no 1764 // generate the constructor. For native classes there are no
1712 // constructors, so we don't need the fields unless we are generating 1765 // constructors, so we don't need the fields unless we are generating
1713 // accessors at runtime. 1766 // accessors at runtime.
1714 if (!classIsNative || needsAccessor) { 1767 if (!classIsNative || needsAccessor) {
1715 buffer.write(separator); 1768 buffer.write(separator);
1716 separator = ','; 1769 separator = ',';
1717 var metadata = buildMetadataFunction(member); 1770 var metadata = buildMetadataFunction(field);
1718 if (metadata != null) { 1771 if (metadata != null) {
1719 hasMetadata = true; 1772 hasMetadata = true;
1720 } else { 1773 } else {
1721 metadata = new jsAst.LiteralNull(); 1774 metadata = new jsAst.LiteralNull();
1722 } 1775 }
1723 fieldMetadata.add(metadata); 1776 fieldMetadata.add(metadata);
1724 recordMangledField(member, accessorName, member.name.slowToString()); 1777 recordMangledField(field, accessorName, field.name.slowToString());
1725 if (!needsAccessor) { 1778 if (!needsAccessor) {
1726 // Emit field for constructor generation. 1779 // Emit field for constructor generation.
1727 assert(!classIsNative); 1780 assert(!classIsNative);
1728 buffer.write(name); 1781 buffer.write(name);
1729 } else { 1782 } else {
1730 // Emit (possibly renaming) field name so we can add accessors at 1783 // Emit (possibly renaming) field name so we can add accessors at
1731 // runtime. 1784 // runtime.
1732 buffer.write(accessorName); 1785 buffer.write(accessorName);
1733 if (name != accessorName) { 1786 if (name != accessorName) {
1734 buffer.write(':$name'); 1787 buffer.write(':$name');
1735 // Only the native classes can have renaming accessors. 1788 // Only the native classes can have renaming accessors.
1736 assert(classIsNative); 1789 assert(classIsNative);
1737 } 1790 }
1738 1791
1739 int getterCode = 0; 1792 int getterCode = 0;
1740 if (needsGetter) { 1793 if (needsGetter) {
1741 // 01: function() { return this.field; } 1794 if (field.isInstanceMember()) {
1742 // 10: function(receiver) { return receiver.field; } 1795 // 01: function() { return this.field; }
1743 // 11: function(receiver) { return this.field; } 1796 // 10: function(receiver) { return receiver.field; }
1744 getterCode += backend.fieldHasInterceptedGetter(member) ? 2 : 0; 1797 // 11: function(receiver) { return this.field; }
1745 getterCode += backend.isInterceptorClass(classElement) ? 0 : 1; 1798 getterCode += backend.fieldHasInterceptedGetter(field) ? 2 : 0;
1746 // TODO(sra): 'isInterceptorClass' might not be the correct test for 1799 getterCode += backend.isInterceptorClass(element) ? 0 : 1;
1747 // methods forced to use the interceptor convention because the 1800 // TODO(sra): 'isInterceptorClass' might not be the correct test
1748 // method's class was elsewhere mixed-in to an interceptor. 1801 // for methods forced to use the interceptor convention because
1749 assert(!member.isInstanceMember() || getterCode != 0); 1802 // the method's class was elsewhere mixed-in to an interceptor.
1803 assert(!field.isInstanceMember() || getterCode != 0);
1804 } else {
1805 getterCode = 1;
1806 }
1750 } 1807 }
1751 int setterCode = 0; 1808 int setterCode = 0;
1752 if (needsSetter) { 1809 if (needsSetter) {
1753 // 01: function(value) { this.field = value; } 1810 if (field.isInstanceMember()) {
1754 // 10: function(receiver, value) { receiver.field = value; } 1811 // 01: function(value) { this.field = value; }
1755 // 11: function(receiver, value) { this.field = value; } 1812 // 10: function(receiver, value) { receiver.field = value; }
1756 setterCode += backend.fieldHasInterceptedSetter(member) ? 2 : 0; 1813 // 11: function(receiver, value) { this.field = value; }
1757 setterCode += backend.isInterceptorClass(classElement) ? 0 : 1; 1814 setterCode += backend.fieldHasInterceptedSetter(field) ? 2 : 0;
1758 assert(!member.isInstanceMember() || setterCode != 0); 1815 setterCode += backend.isInterceptorClass(element) ? 0 : 1;
1816 assert(!field.isInstanceMember() || setterCode != 0);
1817 } else {
1818 setterCode = 1;
1819 }
1759 } 1820 }
1760 int code = getterCode + (setterCode << 2); 1821 int code = getterCode + (setterCode << 2);
1761 if (code == 0) { 1822 if (code == 0) {
1762 compiler.reportInternalError( 1823 compiler.reportInternalError(
1763 member, 'Internal error: code is 0 ($classElement/$member)'); 1824 field, 'Internal error: code is 0 ($element/$field)');
1764 } else { 1825 } else {
1765 buffer.write(FIELD_CODE_CHARACTERS[code - FIRST_FIELD_CODE]); 1826 buffer.write(FIELD_CODE_CHARACTERS[code - FIRST_FIELD_CODE]);
1766 } 1827 }
1767 } 1828 }
1768 } 1829 }
1769 }); 1830 });
1770 1831
1771 bool fieldsAdded = buffer.length > bufferClassLength; 1832 bool fieldsAdded = buffer.length > bufferClassLength;
1772 String compactClassData = buffer.toString(); 1833 String compactClassData = buffer.toString();
1773 jsAst.Expression classDataNode = js.string(compactClassData); 1834 jsAst.Expression classDataNode = js.string(compactClassData);
1774 if (hasMetadata) { 1835 if (hasMetadata) {
1775 fieldMetadata.insert(0, classDataNode); 1836 fieldMetadata.insert(0, classDataNode);
1776 classDataNode = new jsAst.ArrayInitializer.from(fieldMetadata); 1837 classDataNode = new jsAst.ArrayInitializer.from(fieldMetadata);
1777 } 1838 }
1778 builder.addProperty('', classDataNode); 1839 builder.addProperty('', classDataNode);
1779 return fieldsAdded; 1840 return fieldsAdded;
1780 } 1841 }
1781 1842
1782 void emitClassGettersSetters(ClassElement classElement, 1843 void emitClassGettersSetters(ClassElement classElement,
1783 ClassBuilder builder) { 1844 ClassBuilder builder) {
1784 1845
1785 visitClassFields(classElement, false, 1846 visitFields(classElement, false,
1786 (Element member, 1847 (VariableElement member,
1787 String name, 1848 String name,
1788 String accessorName, 1849 String accessorName,
1789 bool needsGetter, 1850 bool needsGetter,
1790 bool needsSetter, 1851 bool needsSetter,
1791 bool needsCheckedSetter) { 1852 bool needsCheckedSetter) {
1792 compiler.withCurrentElement(member, () { 1853 compiler.withCurrentElement(member, () {
1793 if (needsCheckedSetter) { 1854 if (needsCheckedSetter) {
1794 assert(!needsSetter); 1855 assert(!needsSetter);
1795 generateCheckedSetter(member, name, accessorName, builder); 1856 generateCheckedSetter(member, name, accessorName, builder);
1796 } 1857 }
1797 if (!getterAndSetterCanBeImplementedByFieldSpec) { 1858 if (!getterAndSetterCanBeImplementedByFieldSpec) {
1798 if (needsGetter) { 1859 if (needsGetter) {
1799 generateGetter(member, name, accessorName, builder); 1860 generateGetter(member, name, accessorName, builder);
1800 } 1861 }
1801 if (needsSetter) { 1862 if (needsSetter) {
(...skipping 27 matching lines...) Expand all
1829 if (classElement.isMixinApplication) { 1890 if (classElement.isMixinApplication) {
1830 String mixinName = namer.getName(computeMixinClass(classElement)); 1891 String mixinName = namer.getName(computeMixinClass(classElement));
1831 superName = '$superName+$mixinName'; 1892 superName = '$superName+$mixinName';
1832 needsMixinSupport = true; 1893 needsMixinSupport = true;
1833 } 1894 }
1834 1895
1835 ClassBuilder builder = new ClassBuilder(); 1896 ClassBuilder builder = new ClassBuilder();
1836 emitClassConstructor(classElement, builder); 1897 emitClassConstructor(classElement, builder);
1837 emitSuper(superName, builder); 1898 emitSuper(superName, builder);
1838 emitRuntimeName(runtimeName, builder); 1899 emitRuntimeName(runtimeName, builder);
1839 emitClassFields(classElement, builder, superName); 1900 emitFields(classElement, builder, superName);
1840 emitClassGettersSetters(classElement, builder); 1901 emitClassGettersSetters(classElement, builder);
1841 if (!classElement.isMixinApplication) { 1902 if (!classElement.isMixinApplication) {
1842 emitInstanceMembers(classElement, builder); 1903 emitInstanceMembers(classElement, builder);
1843 } 1904 }
1844 emitIsTests(classElement, builder); 1905 emitIsTests(classElement, builder);
1845 1906
1846 emitClassBuilderWithReflectionData( 1907 emitClassBuilderWithReflectionData(
1847 className, classElement, builder, buffer); 1908 className, classElement, builder, buffer);
1848 } 1909 }
1849 1910
1850 void emitClassBuilderWithReflectionData(String className, 1911 void emitClassBuilderWithReflectionData(String className,
1851 ClassElement classElement, 1912 ClassElement classElement,
1852 ClassBuilder builder, 1913 ClassBuilder builder,
1853 CodeBuffer buffer) { 1914 CodeBuffer buffer) {
1854 var metadata = buildMetadataFunction(classElement); 1915 var metadata = buildMetadataFunction(classElement);
1855 if (metadata != null) { 1916 if (metadata != null) {
1856 builder.addProperty("@", metadata); 1917 builder.addProperty("@", metadata);
1857 } 1918 }
1858 1919
1859 List<CodeBuffer> classBuffers = elementBuffers[classElement]; 1920 List<CodeBuffer> classBuffers = elementBuffers[classElement];
1860 if (classBuffers == null) { 1921 if (classBuffers == null) {
1861 classBuffers = []; 1922 classBuffers = [];
1862 } else { 1923 } else {
1863 elementBuffers.remove(classElement); 1924 elementBuffers.remove(classElement);
1864 } 1925 }
1865 CodeBuffer statics = new CodeBuffer(); 1926 CodeBuffer statics = new CodeBuffer();
1866 statics.write('{$n'); 1927 statics.write('{$n');
1867 bool hasStatics = false; 1928 bool hasStatics = false;
1868 ClassBuilder staticsBuilder = new ClassBuilder(); 1929 ClassBuilder staticsBuilder = new ClassBuilder();
1869 if (emitClassFields( 1930 if (emitFields(classElement, staticsBuilder, null, emitStatics: true)) {
1870 classElement, staticsBuilder, null, emitStatics: true)) {
1871 hasStatics = true; 1931 hasStatics = true;
1872 statics.write('"":$_'); 1932 statics.write('"":$_');
1873 statics.write( 1933 statics.write(
1874 jsAst.prettyPrint(staticsBuilder.properties.single.value, compiler)); 1934 jsAst.prettyPrint(staticsBuilder.properties.single.value, compiler));
1875 statics.write(',$n'); 1935 statics.write(',$n');
1876 } 1936 }
1877 for (CodeBuffer classBuffer in classBuffers) { 1937 for (CodeBuffer classBuffer in classBuffers) {
1878 // TODO(ahe): What about deferred? 1938 // TODO(ahe): What about deferred?
1879 if (classBuffer != null) { 1939 if (classBuffer != null) {
1880 hasStatics = true; 1940 hasStatics = true;
(...skipping 1671 matching lines...) Expand 10 before | Expand all | Expand 10 after
3552 // After this assignment we will produce invalid JavaScript code if we use 3612 // After this assignment we will produce invalid JavaScript code if we use
3553 // the classesCollector variable. 3613 // the classesCollector variable.
3554 classesCollector = 'classesCollector should not be used from now on'; 3614 classesCollector = 'classesCollector should not be used from now on';
3555 3615
3556 if (!elementBuffers.isEmpty) { 3616 if (!elementBuffers.isEmpty) {
3557 var oldClassesCollector = classesCollector; 3617 var oldClassesCollector = classesCollector;
3558 classesCollector = r"$$"; 3618 classesCollector = r"$$";
3559 if (compiler.enableMinification) { 3619 if (compiler.enableMinification) {
3560 mainBuffer.write(';'); 3620 mainBuffer.write(';');
3561 } 3621 }
3622
3623 for (Element element in elementBuffers.keys) {
3624 // TODO(ahe): Should to iterate over all libraries. Otherwise, we
ngeoffray 2013/07/22 12:59:06 I think you should rewrite the comment, it's not r
ahe 2013/07/22 13:27:27 Done.
3625 // wont see libraries that only has fields.
3626 if (element.isLibrary()) {
3627 LibraryElement library = element;
3628 ClassBuilder builder = new ClassBuilder();
3629 if (emitFields(library, builder, null, emitStatics: true)) {
3630 List<CodeBuffer> buffers = elementBuffers[library];
3631 var buffer = buffers[0];
3632 if (buffer == null) {
3633 buffers[0] = buffer = new CodeBuffer();
3634 }
3635 for (jsAst.Property property in builder.properties) {
3636 if (!buffer.isEmpty) buffer.write(',$n');
3637 buffer.addBuffer(jsAst.prettyPrint(property, compiler));
3638 }
3639 }
3640 }
3641 }
3642
3562 if (!mangledFieldNames.isEmpty) { 3643 if (!mangledFieldNames.isEmpty) {
3563 var keys = mangledFieldNames.keys.toList(); 3644 var keys = mangledFieldNames.keys.toList();
3564 keys.sort(); 3645 keys.sort();
3565 var properties = []; 3646 var properties = [];
3566 for (String key in keys) { 3647 for (String key in keys) {
3567 var value = js.string('${mangledFieldNames[key]}'); 3648 var value = js.string('${mangledFieldNames[key]}');
3568 properties.add(new jsAst.Property(js.string(key), value)); 3649 properties.add(new jsAst.Property(js.string(key), value));
3569 } 3650 }
3570 var map = new jsAst.ObjectInitializer(properties); 3651 var map = new jsAst.ObjectInitializer(properties);
3571 mainBuffer.write( 3652 mainBuffer.write(
(...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after
3848 var mangledNames = init.mangledNames; 3929 var mangledNames = init.mangledNames;
3849 var mangledGlobalNames = init.mangledGlobalNames; 3930 var mangledGlobalNames = init.mangledGlobalNames;
3850 var hasOwnProperty = Object.prototype.hasOwnProperty; 3931 var hasOwnProperty = Object.prototype.hasOwnProperty;
3851 var length = reflectionData.length; 3932 var length = reflectionData.length;
3852 for (var i = 0; i < length; i++) { 3933 for (var i = 0; i < length; i++) {
3853 var data = reflectionData[i]; 3934 var data = reflectionData[i];
3854 var name = data[0]; 3935 var name = data[0];
3855 var uri = data[1]; 3936 var uri = data[1];
3856 var metadata = data[2]; 3937 var metadata = data[2];
3857 var descriptor = data[3]; 3938 var descriptor = data[3];
3939 var fields = descriptor && descriptor[""];
3858 var classes = []; 3940 var classes = [];
3859 var functions = []; 3941 var functions = [];
3860 function processStatics(descriptor) { 3942 function processStatics(descriptor) {
3861 for (var property in descriptor) { 3943 for (var property in descriptor) {
3862 if (!hasOwnProperty.call(descriptor, property)) continue; 3944 if (!hasOwnProperty.call(descriptor, property)) continue;
3863 if (property === "") continue; 3945 if (property === "") continue;
3864 var element = descriptor[property]; 3946 var element = descriptor[property];
3865 var firstChar = property.substring(0, 1); 3947 var firstChar = property.substring(0, 1);
3866 var previousProperty; 3948 var previousProperty;
3867 if (firstChar === "+") { 3949 if (firstChar === "+") {
(...skipping 20 matching lines...) Expand all
3888 } else { 3970 } else {
3889 newDesc[previousProp = prop] = element[prop]; 3971 newDesc[previousProp = prop] = element[prop];
3890 } 3972 }
3891 } 3973 }
3892 $classesCollector[property] = newDesc; 3974 $classesCollector[property] = newDesc;
3893 classes.push(property); 3975 classes.push(property);
3894 } 3976 }
3895 } 3977 }
3896 } 3978 }
3897 processStatics(descriptor); 3979 processStatics(descriptor);
3898 libraries.push([name, uri, classes, functions, metadata]); 3980 libraries.push([name, uri, classes, functions, metadata, fields]);
3899 } 3981 }
3900 })'''; 3982 })''';
3901 } 3983 }
3902 } 3984 }
3903 3985
3904 const String GENERATED_BY = """ 3986 const String GENERATED_BY = """
3905 // Generated by dart2js, the Dart to JavaScript compiler. 3987 // Generated by dart2js, the Dart to JavaScript compiler.
3906 """; 3988 """;
3907 3989
3908 const String HOOKS_API_USAGE = """ 3990 const String HOOKS_API_USAGE = """
3909 // The code supports the following hooks: 3991 // The code supports the following hooks:
3910 // dartPrint(message) - if this function is defined it is called 3992 // dartPrint(message) - if this function is defined it is called
3911 // instead of the Dart [print] method. 3993 // instead of the Dart [print] method.
3912 // dartMainRunner(main) - if this function is defined, the Dart [main] 3994 // dartMainRunner(main) - if this function is defined, the Dart [main]
3913 // method will not be invoked directly. 3995 // method will not be invoked directly.
3914 // Instead, a closure that will invoke [main] is 3996 // Instead, a closure that will invoke [main] is
3915 // passed to [dartMainRunner]. 3997 // passed to [dartMainRunner].
3916 """; 3998 """;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698