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

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

Powered by Google App Engine
This is Rietveld 408576698