| OLD | NEW |
| 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 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 75 /** Shorter access to [isolatePropertiesName]. Both here in the code, as | 75 /** Shorter access to [isolatePropertiesName]. Both here in the code, as |
| 76 well as in the generated code. */ | 76 well as in the generated code. */ |
| 77 String isolateProperties; | 77 String isolateProperties; |
| 78 String classesCollector; | 78 String classesCollector; |
| 79 final Set<ClassElement> neededClasses = new Set<ClassElement>(); | 79 final Set<ClassElement> neededClasses = new Set<ClassElement>(); |
| 80 final List<ClassElement> regularClasses = <ClassElement>[]; | 80 final List<ClassElement> regularClasses = <ClassElement>[]; |
| 81 final List<ClassElement> deferredClasses = <ClassElement>[]; | 81 final List<ClassElement> deferredClasses = <ClassElement>[]; |
| 82 final List<ClassElement> nativeClasses = <ClassElement>[]; | 82 final List<ClassElement> nativeClasses = <ClassElement>[]; |
| 83 final List<Selector> trivialNsmHandlers = <Selector>[]; | 83 final List<Selector> trivialNsmHandlers = <Selector>[]; |
| 84 final Map<String, String> mangledFieldNames = <String, String>{}; | 84 final Map<String, String> mangledFieldNames = <String, String>{}; |
| 85 final Map<String, String> mangledGlobalFieldNames = <String, String>{}; |
| 85 final Set<String> recordedMangledNames = new Set<String>(); | 86 final Set<String> recordedMangledNames = new Set<String>(); |
| 86 final Set<String> interceptorInvocationNames = new Set<String>(); | 87 final Set<String> interceptorInvocationNames = new Set<String>(); |
| 87 | 88 |
| 88 /// A list of JS expressions that represent metadata, parameter names and | 89 /// A list of JS expressions that represent metadata, parameter names and |
| 89 /// type, and return types. | 90 /// type, and return types. |
| 90 final List<String> globalMetadata = []; | 91 final List<String> globalMetadata = []; |
| 91 | 92 |
| 92 /// A map used to canonicalize the entries of globalMetadata. | 93 /// A map used to canonicalize the entries of globalMetadata. |
| 93 final Map<String, int> globalMetadataMap = <String, int>{}; | 94 final Map<String, int> globalMetadataMap = <String, int>{}; |
| 94 | 95 |
| (...skipping 1355 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1450 functionTypes.forEach(addSignature); | 1451 functionTypes.forEach(addSignature); |
| 1451 }); | 1452 }); |
| 1452 } | 1453 } |
| 1453 | 1454 |
| 1454 /** | 1455 /** |
| 1455 * Documentation wanted -- johnniwinther | 1456 * Documentation wanted -- johnniwinther |
| 1456 * | 1457 * |
| 1457 * Invariant: [classElement] must be a declaration element. | 1458 * Invariant: [classElement] must be a declaration element. |
| 1458 */ | 1459 */ |
| 1459 void visitClassFields(ClassElement classElement, | 1460 void visitClassFields(ClassElement classElement, |
| 1461 bool visitStatics, |
| 1460 void addField(Element member, | 1462 void addField(Element member, |
| 1461 String name, | 1463 String name, |
| 1462 String accessorName, | 1464 String accessorName, |
| 1463 bool needsGetter, | 1465 bool needsGetter, |
| 1464 bool needsSetter, | 1466 bool needsSetter, |
| 1465 bool needsCheckedSetter)) { | 1467 bool needsCheckedSetter)) { |
| 1466 assert(invariant(classElement, classElement.isDeclaration)); | 1468 assert(invariant(classElement, classElement.isDeclaration)); |
| 1467 // If the class is never instantiated we still need to set it up for | 1469 // If the class is never instantiated we still need to set it up for |
| 1468 // inheritance purposes, but we can simplify its JavaScript constructor. | 1470 // inheritance purposes, but we can simplify its JavaScript constructor. |
| 1469 bool isInstantiated = | 1471 bool isInstantiated = |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1516 // Getters and setters with suffixes will be generated dynamically. | 1518 // Getters and setters with suffixes will be generated dynamically. |
| 1517 addField(member, | 1519 addField(member, |
| 1518 fieldName, | 1520 fieldName, |
| 1519 accessorName, | 1521 accessorName, |
| 1520 needsGetter, | 1522 needsGetter, |
| 1521 needsSetter, | 1523 needsSetter, |
| 1522 needsCheckedSetter); | 1524 needsCheckedSetter); |
| 1523 } | 1525 } |
| 1524 } | 1526 } |
| 1525 | 1527 |
| 1526 // TODO(kasperl): We should make sure to only emit one version of | 1528 if (visitStatics) { |
| 1527 // overridden fields. Right now, we rely on the ordering so the | 1529 classElement.implementation.forEachStaticField(visitField); |
| 1528 // fields pulled in from mixins are replaced with the fields from | 1530 } else { |
| 1529 // the class definition. | 1531 // TODO(kasperl): We should make sure to only emit one version of |
| 1532 // overridden fields. Right now, we rely on the ordering so the |
| 1533 // fields pulled in from mixins are replaced with the fields from |
| 1534 // the class definition. |
| 1530 | 1535 |
| 1531 // If a class is not instantiated then we add the field just so we can | 1536 // If a class is not instantiated then we add the field just so we can |
| 1532 // generate the field getter/setter dynamically. Since this is only | 1537 // generate the field getter/setter dynamically. Since this is only |
| 1533 // allowed on fields that are in [classElement] we don't need to visit | 1538 // allowed on fields that are in [classElement] we don't need to visit |
| 1534 // superclasses for non-instantiated classes. | 1539 // superclasses for non-instantiated classes. |
| 1535 classElement.implementation.forEachInstanceField( | 1540 classElement.implementation.forEachInstanceField( |
| 1536 visitField, | 1541 visitField, |
| 1537 includeSuperAndInjectedMembers: isInstantiated); | 1542 includeSuperAndInjectedMembers: isInstantiated); |
| 1543 } |
| 1538 } | 1544 } |
| 1539 | 1545 |
| 1540 void generateGetter(Element member, String fieldName, String accessorName, | 1546 void generateGetter(Element member, String fieldName, String accessorName, |
| 1541 ClassBuilder builder) { | 1547 ClassBuilder builder) { |
| 1542 String getterName = namer.getterNameFromAccessorName(accessorName); | 1548 String getterName = namer.getterNameFromAccessorName(accessorName); |
| 1543 String receiver = backend.isInterceptorClass(member.getEnclosingClass()) | 1549 String receiver = backend.isInterceptorClass(member.getEnclosingClass()) |
| 1544 ? 'receiver' : 'this'; | 1550 ? 'receiver' : 'this'; |
| 1545 List<String> args = backend.isInterceptedMethod(member) | 1551 List<String> args = backend.isInterceptedMethod(member) |
| 1546 ? ['receiver'] | 1552 ? ['receiver'] |
| 1547 : []; | 1553 : []; |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1613 } | 1619 } |
| 1614 | 1620 |
| 1615 void emitRuntimeName(String runtimeName, ClassBuilder builder) { | 1621 void emitRuntimeName(String runtimeName, ClassBuilder builder) { |
| 1616 /* Do nothing. */ | 1622 /* Do nothing. */ |
| 1617 } | 1623 } |
| 1618 | 1624 |
| 1619 void recordMangledField(Element member, | 1625 void recordMangledField(Element member, |
| 1620 String accessorName, | 1626 String accessorName, |
| 1621 String memberName) { | 1627 String memberName) { |
| 1622 if (!backend.retainGetter(member)) return; | 1628 if (!backend.retainGetter(member)) return; |
| 1623 String previousName = mangledFieldNames.putIfAbsent( | 1629 String previousName; |
| 1624 '${namer.getterPrefix}$accessorName', | 1630 if (member.isInstanceMember()) { |
| 1625 () => memberName); | 1631 previousName = mangledFieldNames.putIfAbsent( |
| 1632 '${namer.getterPrefix}$accessorName', |
| 1633 () => memberName); |
| 1634 } else { |
| 1635 previousName = mangledGlobalFieldNames.putIfAbsent( |
| 1636 accessorName, |
| 1637 () => memberName); |
| 1638 } |
| 1626 assert(invariant(member, previousName == memberName, | 1639 assert(invariant(member, previousName == memberName, |
| 1627 message: '$previousName != ${memberName}')); | 1640 message: '$previousName != ${memberName}')); |
| 1628 } | 1641 } |
| 1629 | 1642 |
| 1630 /// Returns `true` if fields added. | 1643 /// Returns `true` if fields added. |
| 1631 bool emitClassFields(ClassElement classElement, | 1644 bool emitClassFields(ClassElement classElement, |
| 1632 ClassBuilder builder, | 1645 ClassBuilder builder, |
| 1633 String superName, | 1646 String superName, |
| 1634 { bool classIsNative: false }) { | 1647 { bool classIsNative: false, |
| 1648 bool emitStatics: false }) { |
| 1635 assert(superName != null); | 1649 assert(superName != null); |
| 1636 String separator = ''; | 1650 String separator = ''; |
| 1637 String nativeName = namer.getPrimitiveInterceptorRuntimeName(classElement); | 1651 String nativeName = namer.getPrimitiveInterceptorRuntimeName(classElement); |
| 1638 StringBuffer buffer = new StringBuffer(); | 1652 StringBuffer buffer = new StringBuffer(); |
| 1639 if (nativeName != null) { | 1653 if (!emitStatics) { |
| 1640 buffer.write('$nativeName/'); | 1654 if (nativeName != null) { |
| 1655 buffer.write('$nativeName/'); |
| 1656 } |
| 1657 buffer.write('$superName;'); |
| 1641 } | 1658 } |
| 1642 buffer.write('$superName;'); | |
| 1643 int bufferClassLength = buffer.length; | 1659 int bufferClassLength = buffer.length; |
| 1644 | 1660 |
| 1645 var fieldMetadata = []; | 1661 var fieldMetadata = []; |
| 1646 bool hasMetadata = false; | 1662 bool hasMetadata = false; |
| 1647 | 1663 |
| 1648 visitClassFields(classElement, (Element member, | 1664 visitClassFields(classElement, emitStatics, |
| 1649 String name, | 1665 (Element member, |
| 1650 String accessorName, | 1666 String name, |
| 1651 bool needsGetter, | 1667 String accessorName, |
| 1652 bool needsSetter, | 1668 bool needsGetter, |
| 1653 bool needsCheckedSetter) { | 1669 bool needsSetter, |
| 1670 bool needsCheckedSetter) { |
| 1654 // Ignore needsCheckedSetter - that is handled below. | 1671 // Ignore needsCheckedSetter - that is handled below. |
| 1655 bool needsAccessor = (needsGetter || needsSetter); | 1672 bool needsAccessor = (needsGetter || needsSetter); |
| 1656 // We need to output the fields for non-native classes so we can auto- | 1673 // We need to output the fields for non-native classes so we can auto- |
| 1657 // generate the constructor. For native classes there are no | 1674 // generate the constructor. For native classes there are no |
| 1658 // constructors, so we don't need the fields unless we are generating | 1675 // constructors, so we don't need the fields unless we are generating |
| 1659 // accessors at runtime. | 1676 // accessors at runtime. |
| 1660 if (!classIsNative || needsAccessor) { | 1677 if (!classIsNative || needsAccessor) { |
| 1661 buffer.write(separator); | 1678 buffer.write(separator); |
| 1662 separator = ','; | 1679 separator = ','; |
| 1663 var metadata = buildMetadataFunction(member); | 1680 var metadata = buildMetadataFunction(member); |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1721 fieldMetadata.insert(0, classDataNode); | 1738 fieldMetadata.insert(0, classDataNode); |
| 1722 classDataNode = new jsAst.ArrayInitializer.from(fieldMetadata); | 1739 classDataNode = new jsAst.ArrayInitializer.from(fieldMetadata); |
| 1723 } | 1740 } |
| 1724 builder.addProperty('', classDataNode); | 1741 builder.addProperty('', classDataNode); |
| 1725 return fieldsAdded; | 1742 return fieldsAdded; |
| 1726 } | 1743 } |
| 1727 | 1744 |
| 1728 void emitClassGettersSetters(ClassElement classElement, | 1745 void emitClassGettersSetters(ClassElement classElement, |
| 1729 ClassBuilder builder) { | 1746 ClassBuilder builder) { |
| 1730 | 1747 |
| 1731 visitClassFields(classElement, (Element member, | 1748 visitClassFields(classElement, false, |
| 1732 String name, | 1749 (Element member, |
| 1733 String accessorName, | 1750 String name, |
| 1734 bool needsGetter, | 1751 String accessorName, |
| 1735 bool needsSetter, | 1752 bool needsGetter, |
| 1736 bool needsCheckedSetter) { | 1753 bool needsSetter, |
| 1754 bool needsCheckedSetter) { |
| 1737 compiler.withCurrentElement(member, () { | 1755 compiler.withCurrentElement(member, () { |
| 1738 if (needsCheckedSetter) { | 1756 if (needsCheckedSetter) { |
| 1739 assert(!needsSetter); | 1757 assert(!needsSetter); |
| 1740 generateCheckedSetter(member, name, accessorName, builder); | 1758 generateCheckedSetter(member, name, accessorName, builder); |
| 1741 } | 1759 } |
| 1742 if (!getterAndSetterCanBeImplementedByFieldSpec) { | 1760 if (!getterAndSetterCanBeImplementedByFieldSpec) { |
| 1743 if (needsGetter) { | 1761 if (needsGetter) { |
| 1744 generateGetter(member, name, accessorName, builder); | 1762 generateGetter(member, name, accessorName, builder); |
| 1745 } | 1763 } |
| 1746 if (needsSetter) { | 1764 if (needsSetter) { |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1786 if (metadata != null) { | 1804 if (metadata != null) { |
| 1787 builder.addProperty("@", metadata); | 1805 builder.addProperty("@", metadata); |
| 1788 } | 1806 } |
| 1789 emitClassGettersSetters(classElement, builder); | 1807 emitClassGettersSetters(classElement, builder); |
| 1790 if (!classElement.isMixinApplication) { | 1808 if (!classElement.isMixinApplication) { |
| 1791 emitInstanceMembers(classElement, builder); | 1809 emitInstanceMembers(classElement, builder); |
| 1792 } | 1810 } |
| 1793 emitIsTests(classElement, builder); | 1811 emitIsTests(classElement, builder); |
| 1794 | 1812 |
| 1795 List<CodeBuffer> classBuffers = elementBuffers[classElement]; | 1813 List<CodeBuffer> classBuffers = elementBuffers[classElement]; |
| 1814 if (classBuffers == null) { |
| 1815 classBuffers = []; |
| 1816 } else { |
| 1817 elementBuffers.remove(classElement); |
| 1818 } |
| 1796 CodeBuffer statics = new CodeBuffer(); | 1819 CodeBuffer statics = new CodeBuffer(); |
| 1820 statics.write('{$n'); |
| 1797 bool hasStatics = false; | 1821 bool hasStatics = false; |
| 1798 if (classBuffers != null) { | 1822 ClassBuilder staticsBuilder = new ClassBuilder(); |
| 1799 statics.write('{$n'); | 1823 if (emitClassFields( |
| 1800 elementBuffers.remove(classElement); | 1824 classElement, staticsBuilder, superName, emitStatics: true)) { |
| 1801 for (CodeBuffer classBuffer in classBuffers) { | 1825 hasStatics = true; |
| 1802 // TODO(ahe): What about deferred? | 1826 statics.write('"":$_'); |
| 1803 if (classBuffer != null) { | 1827 statics.write( |
| 1804 hasStatics = true; | 1828 jsAst.prettyPrint(staticsBuilder.properties.single.value, compiler)); |
| 1805 statics.addBuffer(classBuffer); | 1829 statics.write(',$n'); |
| 1806 } | 1830 } |
| 1831 for (CodeBuffer classBuffer in classBuffers) { |
| 1832 // TODO(ahe): What about deferred? |
| 1833 if (classBuffer != null) { |
| 1834 hasStatics = true; |
| 1835 statics.addBuffer(classBuffer); |
| 1807 } | 1836 } |
| 1808 statics.write('}$n'); | |
| 1809 } | 1837 } |
| 1838 statics.write('}$n'); |
| 1810 if (hasStatics) { | 1839 if (hasStatics) { |
| 1811 builder.addProperty('static', new jsAst.Blob(statics)); | 1840 builder.addProperty('static', new jsAst.Blob(statics)); |
| 1812 } | 1841 } |
| 1813 | 1842 |
| 1814 // TODO(ahe): This method (generateClass) should return a jsAst.Expression. | 1843 // TODO(ahe): This method (generateClass) should return a jsAst.Expression. |
| 1815 if (!buffer.isEmpty) { | 1844 if (!buffer.isEmpty) { |
| 1816 buffer.write(',$n$n'); | 1845 buffer.write(',$n$n'); |
| 1817 } | 1846 } |
| 1818 buffer.write('$className:$_'); | 1847 buffer.write('$className:$_'); |
| 1819 buffer.write(jsAst.prettyPrint(builder.toObjectInitializer(), compiler)); | 1848 buffer.write(jsAst.prettyPrint(builder.toObjectInitializer(), compiler)); |
| (...skipping 1667 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3487 properties.add(new jsAst.Property(js.string(key), value)); | 3516 properties.add(new jsAst.Property(js.string(key), value)); |
| 3488 } | 3517 } |
| 3489 var map = new jsAst.ObjectInitializer(properties); | 3518 var map = new jsAst.ObjectInitializer(properties); |
| 3490 mainBuffer.write( | 3519 mainBuffer.write( |
| 3491 jsAst.prettyPrint( | 3520 jsAst.prettyPrint( |
| 3492 js('init.mangledNames = #', map).toStatement(), compiler)); | 3521 js('init.mangledNames = #', map).toStatement(), compiler)); |
| 3493 if (compiler.enableMinification) { | 3522 if (compiler.enableMinification) { |
| 3494 mainBuffer.write(';'); | 3523 mainBuffer.write(';'); |
| 3495 } | 3524 } |
| 3496 } | 3525 } |
| 3526 if (!mangledGlobalFieldNames.isEmpty) { |
| 3527 var keys = mangledGlobalFieldNames.keys.toList(); |
| 3528 keys.sort(); |
| 3529 var properties = []; |
| 3530 for (String key in keys) { |
| 3531 var value = js.string('${mangledGlobalFieldNames[key]}'); |
| 3532 properties.add(new jsAst.Property(js.string(key), value)); |
| 3533 } |
| 3534 var map = new jsAst.ObjectInitializer(properties); |
| 3535 mainBuffer.write( |
| 3536 jsAst.prettyPrint( |
| 3537 js('init.mangledGlobalNames = #', map).toStatement(), |
| 3538 compiler)); |
| 3539 if (compiler.enableMinification) { |
| 3540 mainBuffer.write(';'); |
| 3541 } |
| 3542 } |
| 3497 mainBuffer | 3543 mainBuffer |
| 3498 ..write(getReflectionDataParser()) | 3544 ..write(getReflectionDataParser()) |
| 3499 ..write('([$n'); | 3545 ..write('([$n'); |
| 3500 | 3546 |
| 3501 var sortedElements = Elements.sortedByPosition(elementBuffers.keys); | 3547 var sortedElements = Elements.sortedByPosition(elementBuffers.keys); |
| 3502 bool hasPendingStatics = false; | 3548 bool hasPendingStatics = false; |
| 3503 for (Element element in sortedElements) { | 3549 for (Element element in sortedElements) { |
| 3504 if (!element.isLibrary()) { | 3550 if (!element.isLibrary()) { |
| 3505 for (var b in elementBuffers[element]) { | 3551 for (var b in elementBuffers[element]) { |
| 3506 if (b != null) { | 3552 if (b != null) { |
| (...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3754 var data = reflectionData[i]; | 3800 var data = reflectionData[i]; |
| 3755 var name = data[0]; | 3801 var name = data[0]; |
| 3756 var uri = data[1]; | 3802 var uri = data[1]; |
| 3757 var metadata = data[2]; | 3803 var metadata = data[2]; |
| 3758 var descriptor = data[3]; | 3804 var descriptor = data[3]; |
| 3759 var classes = []; | 3805 var classes = []; |
| 3760 var functions = []; | 3806 var functions = []; |
| 3761 function processStatics(descriptor) { | 3807 function processStatics(descriptor) { |
| 3762 for (var property in descriptor) { | 3808 for (var property in descriptor) { |
| 3763 if (!hasOwnProperty.call(descriptor, property)) continue; | 3809 if (!hasOwnProperty.call(descriptor, property)) continue; |
| 3810 if (property === "") continue; |
| 3764 var element = descriptor[property]; | 3811 var element = descriptor[property]; |
| 3765 var firstChar = property.substring(0, 1); | 3812 var firstChar = property.substring(0, 1); |
| 3766 var previousProperty; | 3813 var previousProperty; |
| 3767 if (firstChar === "+") { | 3814 if (firstChar === "+") { |
| 3768 mangledGlobalNames[previousProperty] = property.substring(1); | 3815 mangledGlobalNames[previousProperty] = property.substring(1); |
| 3769 } else if (firstChar === "@") { | 3816 } else if (firstChar === "@") { |
| 3770 property = property.substring(1); | 3817 property = property.substring(1); |
| 3771 ${namer.CURRENT_ISOLATE}[property][$metadataField] = element; | 3818 ${namer.CURRENT_ISOLATE}[property][$metadataField] = element; |
| 3772 } else if (typeof element === "function") { | 3819 } else if (typeof element === "function") { |
| 3773 ${namer.CURRENT_ISOLATE}[previousProperty = property] = element; | 3820 ${namer.CURRENT_ISOLATE}[previousProperty = property] = element; |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3807 | 3854 |
| 3808 const String HOOKS_API_USAGE = """ | 3855 const String HOOKS_API_USAGE = """ |
| 3809 // The code supports the following hooks: | 3856 // The code supports the following hooks: |
| 3810 // dartPrint(message) - if this function is defined it is called | 3857 // dartPrint(message) - if this function is defined it is called |
| 3811 // instead of the Dart [print] method. | 3858 // instead of the Dart [print] method. |
| 3812 // dartMainRunner(main) - if this function is defined, the Dart [main] | 3859 // dartMainRunner(main) - if this function is defined, the Dart [main] |
| 3813 // method will not be invoked directly. | 3860 // method will not be invoked directly. |
| 3814 // Instead, a closure that will invoke [main] is | 3861 // Instead, a closure that will invoke [main] is |
| 3815 // passed to [dartMainRunner]. | 3862 // passed to [dartMainRunner]. |
| 3816 """; | 3863 """; |
| OLD | NEW |