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

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: 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 is ClassElement) {
1497 bool needsSetter, 1533 isClass = true;
1498 bool needsCheckedSetter)) { 1534 } else if (element is LibraryElement) {
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 isShadowed = element.isShadowedByField(field);
1530 } 1570 }
1531 1571
1532 if ((isInstantiated && !enclosingClass.isNative()) 1572 if ((isInstantiated && !holder.isNative())
1533 || needsGetter 1573 || needsGetter
1534 || needsSetter) { 1574 || needsSetter) {
1535 String accessorName = isShadowed 1575 String accessorName = isShadowed
1536 ? namer.shadowedFieldName(member) 1576 ? namer.shadowedFieldName(field)
1537 : namer.getName(member); 1577 : namer.getName(field);
1538 String fieldName = member.hasFixedBackendName() 1578 String fieldName = field.hasFixedBackendName()
1539 ? member.fixedBackendName() 1579 ? field.fixedBackendName()
1540 : (isMixinNativeField ? member.name.slowToString() : accessorName); 1580 : (isMixinNativeField ? name.slowToString() : accessorName);
1541 bool needsCheckedSetter = false; 1581 bool needsCheckedSetter = false;
1542 if (needsSetter) { 1582 if (compiler.enableTypeAssertions && needsSetter
1543 if (compiler.enableTypeAssertions 1583 && canGenerateCheckedSetter(field)) {
1544 && canGenerateCheckedSetter(member)) { 1584 needsCheckedSetter = true;
1545 needsCheckedSetter = true; 1585 needsSetter = false;
1546 needsSetter = false;
1547 }
1548 } 1586 }
1549 // Getters and setters with suffixes will be generated dynamically. 1587 // Getters and setters with suffixes will be generated dynamically.
1550 addField(member, 1588 f(field, fieldName, accessorName, needsGetter, needsSetter,
1551 fieldName, 1589 needsCheckedSetter);
1552 accessorName,
1553 needsGetter,
1554 needsSetter,
1555 needsCheckedSetter);
1556 } 1590 }
1557 } 1591 }
1558 1592
1559 if (visitStatics) { 1593 if (isLibrary) {
1560 classElement.implementation.forEachStaticField(visitField); 1594 LibraryElement library = element;
1595 library.implementation.forEachLocalMember((Element member) {
1596 if (member.isField()) visitField(library, member);
1597 });
1598 } else if (visitStatics) {
1599 ClassElement cls = element;
1600 cls.implementation.forEachStaticField(visitField);
1561 } else { 1601 } else {
1602 ClassElement cls = element;
1562 // TODO(kasperl): We should make sure to only emit one version of 1603 // TODO(kasperl): We should make sure to only emit one version of
1563 // overridden fields. Right now, we rely on the ordering so the 1604 // overridden fields. Right now, we rely on the ordering so the
1564 // fields pulled in from mixins are replaced with the fields from 1605 // fields pulled in from mixins are replaced with the fields from
1565 // the class definition. 1606 // the class definition.
1566 1607
1567 // If a class is not instantiated then we add the field just so we can 1608 // 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 1609 // generate the field getter/setter dynamically. Since this is only
1569 // allowed on fields that are in [classElement] we don't need to visit 1610 // allowed on fields that are in [element] we don't need to visit
1570 // superclasses for non-instantiated classes. 1611 // superclasses for non-instantiated classes.
1571 classElement.implementation.forEachInstanceField( 1612 cls.implementation.forEachInstanceField(
1572 visitField, 1613 visitField, includeSuperAndInjectedMembers: isInstantiated);
1573 includeSuperAndInjectedMembers: isInstantiated);
1574 } 1614 }
1575 } 1615 }
1576 1616
1577 void generateGetter(Element member, String fieldName, String accessorName, 1617 void generateGetter(Element member, String fieldName, String accessorName,
1578 ClassBuilder builder) { 1618 ClassBuilder builder) {
1579 String getterName = namer.getterNameFromAccessorName(accessorName); 1619 String getterName = namer.getterNameFromAccessorName(accessorName);
1580 String receiver = backend.isInterceptorClass(member.getEnclosingClass()) 1620 String receiver = backend.isInterceptorClass(member.getEnclosingClass())
1581 ? 'receiver' : 'this'; 1621 ? 'receiver' : 'this';
1582 List<String> args = backend.isInterceptedMethod(member) 1622 List<String> args = backend.isInterceptedMethod(member)
1583 ? ['receiver'] 1623 ? ['receiver']
1584 : []; 1624 : [];
1585 builder.addProperty(getterName, 1625 builder.addProperty(getterName,
1586 js.fun(args, js.return_(js('$receiver.$fieldName')))); 1626 js.fun(args, js.return_(js('$receiver.$fieldName'))));
1587 } 1627 }
1588 1628
1589 void generateSetter(Element member, String fieldName, String accessorName, 1629 void generateSetter(Element member, String fieldName, String accessorName,
1590 ClassBuilder builder) { 1630 ClassBuilder builder) {
1591 String setterName = namer.setterNameFromAccessorName(accessorName); 1631 String setterName = namer.setterNameFromAccessorName(accessorName);
1592 String receiver = backend.isInterceptorClass(member.getEnclosingClass()) 1632 String receiver = backend.isInterceptorClass(member.getEnclosingClass())
1593 ? 'receiver' : 'this'; 1633 ? 'receiver' : 'this';
1594 List<String> args = backend.isInterceptedMethod(member) 1634 List<String> args = backend.isInterceptedMethod(member)
1595 ? ['receiver', 'v'] 1635 ? ['receiver', 'v']
1596 : ['v']; 1636 : ['v'];
1597 builder.addProperty(setterName, 1637 builder.addProperty(setterName,
1598 js.fun(args, js('$receiver.$fieldName = v'))); 1638 js.fun(args, js('$receiver.$fieldName = v')));
1599 } 1639 }
1600 1640
1601 bool canGenerateCheckedSetter(Element member) { 1641 bool canGenerateCheckedSetter(VariableElement field) {
1602 // We never generate accessors for top-level/static fields. 1642 // We never generate accessors for top-level/static fields.
1603 if (!member.isInstanceMember()) return false; 1643 if (!field.isInstanceMember()) return false;
1604 DartType type = member.computeType(compiler).unalias(compiler); 1644 DartType type = field.computeType(compiler).unalias(compiler);
1605 if (type.element.isTypeVariable() || 1645 if (type.element.isTypeVariable() ||
1606 (type is FunctionType && type.containsTypeVariables) || 1646 (type is FunctionType && type.containsTypeVariables) ||
1607 type.element == compiler.dynamicClass || 1647 type.element == compiler.dynamicClass ||
1608 type.element == compiler.objectClass) { 1648 type.element == compiler.objectClass) {
1609 // TODO(ngeoffray): Support type checks on type parameters. 1649 // TODO(ngeoffray): Support type checks on type parameters.
1610 return false; 1650 return false;
1611 } 1651 }
1612 return true; 1652 return true;
1613 } 1653 }
1614 1654
1615 void generateCheckedSetter(Element member, 1655 void generateCheckedSetter(Element member,
1616 String fieldName, 1656 String fieldName,
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
1667 } else { 1707 } else {
1668 previousName = mangledGlobalFieldNames.putIfAbsent( 1708 previousName = mangledGlobalFieldNames.putIfAbsent(
1669 accessorName, 1709 accessorName,
1670 () => memberName); 1710 () => memberName);
1671 } 1711 }
1672 assert(invariant(member, previousName == memberName, 1712 assert(invariant(member, previousName == memberName,
1673 message: '$previousName != ${memberName}')); 1713 message: '$previousName != ${memberName}'));
1674 } 1714 }
1675 1715
1676 /// Returns `true` if fields added. 1716 /// Returns `true` if fields added.
1677 bool emitClassFields(ClassElement classElement, 1717 bool emitFields(Element element,
1678 ClassBuilder builder, 1718 ClassBuilder builder,
1679 String superName, 1719 String superName,
1680 { bool classIsNative: false, 1720 { bool classIsNative: false,
1681 bool emitStatics: false }) { 1721 bool emitStatics: false }) {
1722 bool isClass = false;
1723 bool isLibrary = false;
1724 if (element is ClassElement) {
1725 isClass = true;
1726 } else if (element is LibraryElement) {
1727 isLibrary = false;
1728 assert(invariant(element, emitStatics));
1729 } else {
1730 throw new SpannableAssertionFailure(
1731 element, 'Must be a ClassElement or a LibraryElement');
1732 }
1682 StringBuffer buffer = new StringBuffer(); 1733 StringBuffer buffer = new StringBuffer();
1683 if (emitStatics) { 1734 if (emitStatics) {
1684 assert(invariant(classElement, superName == null, message: superName)); 1735 assert(invariant(element, superName == null, message: superName));
1685 } else { 1736 } else {
1686 assert(invariant(classElement, superName != null)); 1737 assert(invariant(element, superName != null));
1687 String nativeName = 1738 String nativeName =
1688 namer.getPrimitiveInterceptorRuntimeName(classElement); 1739 namer.getPrimitiveInterceptorRuntimeName(element);
1689 if (nativeName != null) { 1740 if (nativeName != null) {
1690 buffer.write('$nativeName/'); 1741 buffer.write('$nativeName/');
1691 } 1742 }
1692 buffer.write('$superName;'); 1743 buffer.write('$superName;');
1693 } 1744 }
1694 int bufferClassLength = buffer.length; 1745 int bufferClassLength = buffer.length;
1695 1746
1696 String separator = ''; 1747 String separator = '';
1697 1748
1698 var fieldMetadata = []; 1749 var fieldMetadata = [];
1699 bool hasMetadata = false; 1750 bool hasMetadata = false;
1700 1751
1701 visitClassFields(classElement, emitStatics, 1752 visitFields(element, emitStatics,
1702 (Element member, 1753 (VariableElement field,
1703 String name, 1754 String name,
1704 String accessorName, 1755 String accessorName,
1705 bool needsGetter, 1756 bool needsGetter,
1706 bool needsSetter, 1757 bool needsSetter,
1707 bool needsCheckedSetter) { 1758 bool needsCheckedSetter) {
1708 // Ignore needsCheckedSetter - that is handled below. 1759 // Ignore needsCheckedSetter - that is handled below.
1709 bool needsAccessor = (needsGetter || needsSetter); 1760 bool needsAccessor = (needsGetter || needsSetter);
1710 // We need to output the fields for non-native classes so we can auto- 1761 // We need to output the fields for non-native classes so we can auto-
1711 // generate the constructor. For native classes there are no 1762 // generate the constructor. For native classes there are no
1712 // constructors, so we don't need the fields unless we are generating 1763 // constructors, so we don't need the fields unless we are generating
1713 // accessors at runtime. 1764 // accessors at runtime.
1714 if (!classIsNative || needsAccessor) { 1765 if (!classIsNative || needsAccessor) {
1715 buffer.write(separator); 1766 buffer.write(separator);
1716 separator = ','; 1767 separator = ',';
1717 var metadata = buildMetadataFunction(member); 1768 var metadata = buildMetadataFunction(field);
1718 if (metadata != null) { 1769 if (metadata != null) {
1719 hasMetadata = true; 1770 hasMetadata = true;
1720 } else { 1771 } else {
1721 metadata = new jsAst.LiteralNull(); 1772 metadata = new jsAst.LiteralNull();
1722 } 1773 }
1723 fieldMetadata.add(metadata); 1774 fieldMetadata.add(metadata);
1724 recordMangledField(member, accessorName, member.name.slowToString()); 1775 recordMangledField(field, accessorName, field.name.slowToString());
1725 if (!needsAccessor) { 1776 if (!needsAccessor) {
1726 // Emit field for constructor generation. 1777 // Emit field for constructor generation.
1727 assert(!classIsNative); 1778 assert(!classIsNative);
1728 buffer.write(name); 1779 buffer.write(name);
1729 } else { 1780 } else {
1730 // Emit (possibly renaming) field name so we can add accessors at 1781 // Emit (possibly renaming) field name so we can add accessors at
1731 // runtime. 1782 // runtime.
1732 buffer.write(accessorName); 1783 buffer.write(accessorName);
1733 if (name != accessorName) { 1784 if (name != accessorName) {
1734 buffer.write(':$name'); 1785 buffer.write(':$name');
1735 // Only the native classes can have renaming accessors. 1786 // Only the native classes can have renaming accessors.
1736 assert(classIsNative); 1787 assert(classIsNative);
1737 } 1788 }
1738 1789
1739 int getterCode = 0; 1790 int getterCode = 0;
1740 if (needsGetter) { 1791 if (needsGetter) {
1741 // 01: function() { return this.field; } 1792 if (field.isInstanceMember()) {
1742 // 10: function(receiver) { return receiver.field; } 1793 // 01: function() { return this.field; }
1743 // 11: function(receiver) { return this.field; } 1794 // 10: function(receiver) { return receiver.field; }
1744 getterCode += backend.fieldHasInterceptedGetter(member) ? 2 : 0; 1795 // 11: function(receiver) { return this.field; }
1745 getterCode += backend.isInterceptorClass(classElement) ? 0 : 1; 1796 getterCode += backend.fieldHasInterceptedGetter(field) ? 2 : 0;
1746 // TODO(sra): 'isInterceptorClass' might not be the correct test for 1797 getterCode += backend.isInterceptorClass(element) ? 0 : 1;
1747 // methods forced to use the interceptor convention because the 1798 // TODO(sra): 'isInterceptorClass' might not be the correct test f or
1748 // method's class was elsewhere mixed-in to an interceptor. 1799 // methods forced to use the interceptor convention because the
1749 assert(!member.isInstanceMember() || getterCode != 0); 1800 // method's class was elsewhere mixed-in to an interceptor.
1801 assert(!field.isInstanceMember() || getterCode != 0);
1802 } else {
1803 getterCode = 1;
1804 }
1750 } 1805 }
1751 int setterCode = 0; 1806 int setterCode = 0;
1752 if (needsSetter) { 1807 if (needsSetter) {
1753 // 01: function(value) { this.field = value; } 1808 if (field.isInstanceMember()) {
1754 // 10: function(receiver, value) { receiver.field = value; } 1809 // 01: function(value) { this.field = value; }
1755 // 11: function(receiver, value) { this.field = value; } 1810 // 10: function(receiver, value) { receiver.field = value; }
1756 setterCode += backend.fieldHasInterceptedSetter(member) ? 2 : 0; 1811 // 11: function(receiver, value) { this.field = value; }
1757 setterCode += backend.isInterceptorClass(classElement) ? 0 : 1; 1812 setterCode += backend.fieldHasInterceptedSetter(field) ? 2 : 0;
1758 assert(!member.isInstanceMember() || setterCode != 0); 1813 setterCode += backend.isInterceptorClass(element) ? 0 : 1;
1814 assert(!field.isInstanceMember() || setterCode != 0);
1815 } else {
1816 setterCode = 1;
1817 }
1759 } 1818 }
1760 int code = getterCode + (setterCode << 2); 1819 int code = getterCode + (setterCode << 2);
1761 if (code == 0) { 1820 if (code == 0) {
1762 compiler.reportInternalError( 1821 compiler.reportInternalError(
1763 member, 'Internal error: code is 0 ($classElement/$member)'); 1822 field, 'Internal error: code is 0 ($classElement/$member)');
1764 } else { 1823 } else {
1765 buffer.write(FIELD_CODE_CHARACTERS[code - FIRST_FIELD_CODE]); 1824 buffer.write(FIELD_CODE_CHARACTERS[code - FIRST_FIELD_CODE]);
1766 } 1825 }
1767 } 1826 }
1768 } 1827 }
1769 }); 1828 });
1770 1829
1771 bool fieldsAdded = buffer.length > bufferClassLength; 1830 bool fieldsAdded = buffer.length > bufferClassLength;
1772 String compactClassData = buffer.toString(); 1831 String compactClassData = buffer.toString();
1773 jsAst.Expression classDataNode = js.string(compactClassData); 1832 jsAst.Expression classDataNode = js.string(compactClassData);
1774 if (hasMetadata) { 1833 if (hasMetadata) {
1775 fieldMetadata.insert(0, classDataNode); 1834 fieldMetadata.insert(0, classDataNode);
1776 classDataNode = new jsAst.ArrayInitializer.from(fieldMetadata); 1835 classDataNode = new jsAst.ArrayInitializer.from(fieldMetadata);
1777 } 1836 }
1778 builder.addProperty('', classDataNode); 1837 builder.addProperty('', classDataNode);
1779 return fieldsAdded; 1838 return fieldsAdded;
1780 } 1839 }
1781 1840
1782 void emitClassGettersSetters(ClassElement classElement, 1841 void emitClassGettersSetters(ClassElement classElement,
1783 ClassBuilder builder) { 1842 ClassBuilder builder) {
1784 1843
1785 visitClassFields(classElement, false, 1844 visitFields(classElement, false,
1786 (Element member, 1845 (VariableElement member,
1787 String name, 1846 String name,
1788 String accessorName, 1847 String accessorName,
1789 bool needsGetter, 1848 bool needsGetter,
1790 bool needsSetter, 1849 bool needsSetter,
1791 bool needsCheckedSetter) { 1850 bool needsCheckedSetter) {
1792 compiler.withCurrentElement(member, () { 1851 compiler.withCurrentElement(member, () {
1793 if (needsCheckedSetter) { 1852 if (needsCheckedSetter) {
1794 assert(!needsSetter); 1853 assert(!needsSetter);
1795 generateCheckedSetter(member, name, accessorName, builder); 1854 generateCheckedSetter(member, name, accessorName, builder);
1796 } 1855 }
1797 if (!getterAndSetterCanBeImplementedByFieldSpec) { 1856 if (!getterAndSetterCanBeImplementedByFieldSpec) {
1798 if (needsGetter) { 1857 if (needsGetter) {
1799 generateGetter(member, name, accessorName, builder); 1858 generateGetter(member, name, accessorName, builder);
1800 } 1859 }
1801 if (needsSetter) { 1860 if (needsSetter) {
(...skipping 27 matching lines...) Expand all
1829 if (classElement.isMixinApplication) { 1888 if (classElement.isMixinApplication) {
1830 String mixinName = namer.getName(computeMixinClass(classElement)); 1889 String mixinName = namer.getName(computeMixinClass(classElement));
1831 superName = '$superName+$mixinName'; 1890 superName = '$superName+$mixinName';
1832 needsMixinSupport = true; 1891 needsMixinSupport = true;
1833 } 1892 }
1834 1893
1835 ClassBuilder builder = new ClassBuilder(); 1894 ClassBuilder builder = new ClassBuilder();
1836 emitClassConstructor(classElement, builder); 1895 emitClassConstructor(classElement, builder);
1837 emitSuper(superName, builder); 1896 emitSuper(superName, builder);
1838 emitRuntimeName(runtimeName, builder); 1897 emitRuntimeName(runtimeName, builder);
1839 emitClassFields(classElement, builder, superName); 1898 emitFields(classElement, builder, superName);
1840 emitClassGettersSetters(classElement, builder); 1899 emitClassGettersSetters(classElement, builder);
1841 if (!classElement.isMixinApplication) { 1900 if (!classElement.isMixinApplication) {
1842 emitInstanceMembers(classElement, builder); 1901 emitInstanceMembers(classElement, builder);
1843 } 1902 }
1844 emitIsTests(classElement, builder); 1903 emitIsTests(classElement, builder);
1845 1904
1846 emitClassBuilderWithReflectionData( 1905 emitClassBuilderWithReflectionData(
1847 className, classElement, builder, buffer); 1906 className, classElement, builder, buffer);
1848 } 1907 }
1849 1908
1850 void emitClassBuilderWithReflectionData(String className, 1909 void emitClassBuilderWithReflectionData(String className,
1851 ClassElement classElement, 1910 ClassElement classElement,
1852 ClassBuilder builder, 1911 ClassBuilder builder,
1853 CodeBuffer buffer) { 1912 CodeBuffer buffer) {
1854 var metadata = buildMetadataFunction(classElement); 1913 var metadata = buildMetadataFunction(classElement);
1855 if (metadata != null) { 1914 if (metadata != null) {
1856 builder.addProperty("@", metadata); 1915 builder.addProperty("@", metadata);
1857 } 1916 }
1858 1917
1859 List<CodeBuffer> classBuffers = elementBuffers[classElement]; 1918 List<CodeBuffer> classBuffers = elementBuffers[classElement];
1860 if (classBuffers == null) { 1919 if (classBuffers == null) {
1861 classBuffers = []; 1920 classBuffers = [];
1862 } else { 1921 } else {
1863 elementBuffers.remove(classElement); 1922 elementBuffers.remove(classElement);
1864 } 1923 }
1865 CodeBuffer statics = new CodeBuffer(); 1924 CodeBuffer statics = new CodeBuffer();
1866 statics.write('{$n'); 1925 statics.write('{$n');
1867 bool hasStatics = false; 1926 bool hasStatics = false;
1868 ClassBuilder staticsBuilder = new ClassBuilder(); 1927 ClassBuilder staticsBuilder = new ClassBuilder();
1869 if (emitClassFields( 1928 if (emitFields(classElement, staticsBuilder, null, emitStatics: true)) {
1870 classElement, staticsBuilder, null, emitStatics: true)) {
1871 hasStatics = true; 1929 hasStatics = true;
1872 statics.write('"":$_'); 1930 statics.write('"":$_');
1873 statics.write( 1931 statics.write(
1874 jsAst.prettyPrint(staticsBuilder.properties.single.value, compiler)); 1932 jsAst.prettyPrint(staticsBuilder.properties.single.value, compiler));
1875 statics.write(',$n'); 1933 statics.write(',$n');
1876 } 1934 }
1877 for (CodeBuffer classBuffer in classBuffers) { 1935 for (CodeBuffer classBuffer in classBuffers) {
1878 // TODO(ahe): What about deferred? 1936 // TODO(ahe): What about deferred?
1879 if (classBuffer != null) { 1937 if (classBuffer != null) {
1880 hasStatics = true; 1938 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 3610 // After this assignment we will produce invalid JavaScript code if we use
3553 // the classesCollector variable. 3611 // the classesCollector variable.
3554 classesCollector = 'classesCollector should not be used from now on'; 3612 classesCollector = 'classesCollector should not be used from now on';
3555 3613
3556 if (!elementBuffers.isEmpty) { 3614 if (!elementBuffers.isEmpty) {
3557 var oldClassesCollector = classesCollector; 3615 var oldClassesCollector = classesCollector;
3558 classesCollector = r"$$"; 3616 classesCollector = r"$$";
3559 if (compiler.enableMinification) { 3617 if (compiler.enableMinification) {
3560 mainBuffer.write(';'); 3618 mainBuffer.write(';');
3561 } 3619 }
3620
3621 for (Element element in elementBuffers.keys) {
3622 if (element is LibraryElement) {
3623 LibraryElement library = element;
3624 ClassBuilder builder = new ClassBuilder();
3625 if (emitFields(library, builder, null, emitStatics: true)) {
3626 List<CodeBuffer> buffers = elementBuffers[library];
3627 var buffer = buffers[0];
3628 if (buffer == null) {
3629 buffers[0] = buffer = new CodeBuffer();
3630 }
3631 for (jsAst.Property property in builder.properties) {
3632 if (!buffer.isEmpty) buffer.write(',$n');
3633 buffer.addBuffer(jsAst.prettyPrint(property, compiler));
3634 }
3635 }
3636 }
3637 }
3638
3562 if (!mangledFieldNames.isEmpty) { 3639 if (!mangledFieldNames.isEmpty) {
3563 var keys = mangledFieldNames.keys.toList(); 3640 var keys = mangledFieldNames.keys.toList();
3564 keys.sort(); 3641 keys.sort();
3565 var properties = []; 3642 var properties = [];
3566 for (String key in keys) { 3643 for (String key in keys) {
3567 var value = js.string('${mangledFieldNames[key]}'); 3644 var value = js.string('${mangledFieldNames[key]}');
3568 properties.add(new jsAst.Property(js.string(key), value)); 3645 properties.add(new jsAst.Property(js.string(key), value));
3569 } 3646 }
3570 var map = new jsAst.ObjectInitializer(properties); 3647 var map = new jsAst.ObjectInitializer(properties);
3571 mainBuffer.write( 3648 mainBuffer.write(
(...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after
3848 var mangledNames = init.mangledNames; 3925 var mangledNames = init.mangledNames;
3849 var mangledGlobalNames = init.mangledGlobalNames; 3926 var mangledGlobalNames = init.mangledGlobalNames;
3850 var hasOwnProperty = Object.prototype.hasOwnProperty; 3927 var hasOwnProperty = Object.prototype.hasOwnProperty;
3851 var length = reflectionData.length; 3928 var length = reflectionData.length;
3852 for (var i = 0; i < length; i++) { 3929 for (var i = 0; i < length; i++) {
3853 var data = reflectionData[i]; 3930 var data = reflectionData[i];
3854 var name = data[0]; 3931 var name = data[0];
3855 var uri = data[1]; 3932 var uri = data[1];
3856 var metadata = data[2]; 3933 var metadata = data[2];
3857 var descriptor = data[3]; 3934 var descriptor = data[3];
3935 var fields = descriptor && descriptor[""];
3858 var classes = []; 3936 var classes = [];
3859 var functions = []; 3937 var functions = [];
3860 function processStatics(descriptor) { 3938 function processStatics(descriptor) {
3861 for (var property in descriptor) { 3939 for (var property in descriptor) {
3862 if (!hasOwnProperty.call(descriptor, property)) continue; 3940 if (!hasOwnProperty.call(descriptor, property)) continue;
3863 if (property === "") continue; 3941 if (property === "") continue;
3864 var element = descriptor[property]; 3942 var element = descriptor[property];
3865 var firstChar = property.substring(0, 1); 3943 var firstChar = property.substring(0, 1);
3866 var previousProperty; 3944 var previousProperty;
3867 if (firstChar === "+") { 3945 if (firstChar === "+") {
(...skipping 20 matching lines...) Expand all
3888 } else { 3966 } else {
3889 newDesc[previousProp = prop] = element[prop]; 3967 newDesc[previousProp = prop] = element[prop];
3890 } 3968 }
3891 } 3969 }
3892 $classesCollector[property] = newDesc; 3970 $classesCollector[property] = newDesc;
3893 classes.push(property); 3971 classes.push(property);
3894 } 3972 }
3895 } 3973 }
3896 } 3974 }
3897 processStatics(descriptor); 3975 processStatics(descriptor);
3898 libraries.push([name, uri, classes, functions, metadata]); 3976 libraries.push([name, uri, classes, functions, metadata, fields]);
3899 } 3977 }
3900 })'''; 3978 })''';
3901 } 3979 }
3902 } 3980 }
3903 3981
3904 const String GENERATED_BY = """ 3982 const String GENERATED_BY = """
3905 // Generated by dart2js, the Dart to JavaScript compiler. 3983 // Generated by dart2js, the Dart to JavaScript compiler.
3906 """; 3984 """;
3907 3985
3908 const String HOOKS_API_USAGE = """ 3986 const String HOOKS_API_USAGE = """
3909 // The code supports the following hooks: 3987 // The code supports the following hooks:
3910 // dartPrint(message) - if this function is defined it is called 3988 // dartPrint(message) - if this function is defined it is called
3911 // instead of the Dart [print] method. 3989 // instead of the Dart [print] method.
3912 // dartMainRunner(main) - if this function is defined, the Dart [main] 3990 // dartMainRunner(main) - if this function is defined, the Dart [main]
3913 // method will not be invoked directly. 3991 // method will not be invoked directly.
3914 // Instead, a closure that will invoke [main] is 3992 // Instead, a closure that will invoke [main] is
3915 // passed to [dartMainRunner]. 3993 // passed to [dartMainRunner].
3916 """; 3994 """;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698