OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 dart2js.js_emitter; | 5 part of dart2js.js_emitter; |
6 | 6 |
7 | 7 |
8 class OldEmitter implements Emitter { | 8 class OldEmitter implements Emitter { |
9 final Compiler compiler; | 9 final Compiler compiler; |
10 final CodeEmitterTask task; | 10 final CodeEmitterTask task; |
(...skipping 1676 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1687 } | 1687 } |
1688 | 1688 |
1689 /// Used by incremental compilation to patch up an object ([holder]) with a | 1689 /// Used by incremental compilation to patch up an object ([holder]) with a |
1690 /// new (or updated) method. [arrayOrFunction] is either the new method, or | 1690 /// new (or updated) method. [arrayOrFunction] is either the new method, or |
1691 /// an array containing the method (see | 1691 /// an array containing the method (see |
1692 /// [ContainerBuilder.addMemberMethodFromInfo]). [name] is the name of the | 1692 /// [ContainerBuilder.addMemberMethodFromInfo]). [name] is the name of the |
1693 /// new method. [isStatic] tells if method is static (or | 1693 /// new method. [isStatic] tells if method is static (or |
1694 /// top-level). [globalFunctionsAccess] is a reference to | 1694 /// top-level). [globalFunctionsAccess] is a reference to |
1695 /// [embeddedNames.GLOBAL_FUNCTIONS]. | 1695 /// [embeddedNames.GLOBAL_FUNCTIONS]. |
1696 jsAst.Fun buildIncrementalAddMethod() { | 1696 jsAst.Fun buildIncrementalAddMethod() { |
1697 return js(r''' | 1697 return js(r""" |
1698 function(originalDescriptor, name, holder, isStatic, globalFunctionsAccess) { | 1698 function(originalDescriptor, name, holder, isStatic, globalFunctionsAccess) { |
1699 var arrayOrFunction = originalDescriptor[name]; | 1699 var arrayOrFunction = originalDescriptor[name]; |
1700 var method; | 1700 var method; |
1701 if (arrayOrFunction.constructor === Array) { | 1701 if (arrayOrFunction.constructor === Array) { |
1702 var existing = holder[name]; | 1702 var existing = holder[name]; |
1703 var array = arrayOrFunction; | 1703 var array = arrayOrFunction; |
1704 var descriptor = Object.create(null); | 1704 var descriptor = Object.create(null); |
1705 this.addStubs( | 1705 this.addStubs( |
1706 descriptor, arrayOrFunction, name, isStatic, originalDescriptor, []); | 1706 descriptor, arrayOrFunction, name, isStatic, originalDescriptor, []); |
1707 method = descriptor[name]; | 1707 method = descriptor[name]; |
1708 for (var property in descriptor) { | 1708 for (var property in descriptor) { |
1709 if (!Object.prototype.hasOwnProperty.call(descriptor, property)) continue; | 1709 if (!Object.prototype.hasOwnProperty.call(descriptor, property)) continue; |
1710 var stub = descriptor[property]; | 1710 var stub = descriptor[property]; |
1711 var existingStub = holder[property]; | 1711 var existingStub = holder[property]; |
1712 if (stub === method || !existingStub) { | 1712 if (stub === method || !existingStub || !stub.$getterStub) { |
1713 // Not replacing an existing stub. | 1713 // Not replacing an existing getter stub. |
1714 holder[property] = method; | 1714 holder[property] = stub; |
1715 continue; | 1715 continue; |
1716 } | 1716 } |
1717 if (!stub.$getterStub) { | 1717 if (!stub.$getterStub) { |
1718 var error = new Error("Unexpected stub."); | 1718 var error = new Error('Unexpected stub.'); |
1719 error.stub = stub; | 1719 error.stub = stub; |
1720 throw error; | 1720 throw error; |
1721 } | 1721 } |
1722 // Invoke the existing stub to obtain the tear-off closure. | 1722 |
1723 existingStub = existingStub(); | 1723 // Existing getter stubs need special treatment as they may already have |
1724 // A stub already exist. Update all its references to [existing] to | 1724 // been called and produced a closure. |
1725 // [method]. | 1725 this.pendingStubs = this.pendingStubs || []; |
1726 for (var reference in existingStub) { | 1726 // It isn't safe to invoke the stub yet. |
1727 if (existingStub[reference] === existing) { | 1727 this.pendingStubs.push((function(holder, stub, existingStub, existing, |
1728 existingStub[reference] = method; | 1728 method) { |
| 1729 return function() { |
| 1730 var receiver = isStatic ? holder : new holder.constructor(); |
| 1731 // Invoke the existing stub to obtain the tear-off closure. |
| 1732 existingStub = existingStub.call(receiver); |
| 1733 // Invoke the new stub to create a tear-off closure we can use as a |
| 1734 // prototype. |
| 1735 stub = stub.call(receiver); |
| 1736 |
| 1737 var newProto = stub.constructor.prototype; |
| 1738 var existingProto = existingStub.constructor.prototype; |
| 1739 for (var stubProperty in newProto) { |
| 1740 if (!Object.prototype.hasOwnProperty.call(newProto, stubProperty)) |
| 1741 continue; |
| 1742 existingProto[stubProperty] = newProto[stubProperty]; |
| 1743 } |
| 1744 |
| 1745 // Update all the existing stub's references to [existing] to |
| 1746 // [method]. Instance tear-offs are call-by-name, so this isn't |
| 1747 // necessary for those. |
| 1748 if (!isStatic) return; |
| 1749 for (var reference in existingStub) { |
| 1750 if (existingStub[reference] === existing) { |
| 1751 existingStub[reference] = method; |
| 1752 } |
| 1753 } |
1729 } | 1754 } |
1730 } | 1755 })(holder, stub, existingStub, existing, method)); |
1731 } | 1756 } |
1732 } else { | 1757 } else { |
1733 method = arrayOrFunction; | 1758 method = arrayOrFunction; |
1734 holder[name] = method; | 1759 holder[name] = method; |
1735 } | 1760 } |
1736 if (isStatic) globalFunctionsAccess[name] = method; | 1761 if (isStatic) globalFunctionsAccess[name] = method; |
1737 }'''); | 1762 }"""); |
1738 } | 1763 } |
1739 | 1764 |
1740 /// Returns a map from OutputUnit to a hash of its content. The hash uniquely | 1765 /// Returns a map from OutputUnit to a hash of its content. The hash uniquely |
1741 /// identifies the code of the output-unit. It does not include | 1766 /// identifies the code of the output-unit. It does not include |
1742 /// boilerplate JS code, like the sourcemap directives or the hash | 1767 /// boilerplate JS code, like the sourcemap directives or the hash |
1743 /// itself. | 1768 /// itself. |
1744 Map<OutputUnit, String> emitDeferredOutputUnits() { | 1769 Map<OutputUnit, String> emitDeferredOutputUnits() { |
1745 if (!compiler.deferredLoadTask.isProgramSplit) return const {}; | 1770 if (!compiler.deferredLoadTask.isProgramSplit) return const {}; |
1746 | 1771 |
1747 Map<OutputUnit, CodeBuffer> outputBuffers = | 1772 Map<OutputUnit, CodeBuffer> outputBuffers = |
(...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2068 for (Element element in compiler.enqueuer.codegen.newlyEnqueuedElements) { | 2093 for (Element element in compiler.enqueuer.codegen.newlyEnqueuedElements) { |
2069 if (element.isInstanceMember) { | 2094 if (element.isInstanceMember) { |
2070 cachedClassBuilders.remove(element.enclosingClass); | 2095 cachedClassBuilders.remove(element.enclosingClass); |
2071 | 2096 |
2072 nativeEmitter.cachedBuilders.remove(element.enclosingClass); | 2097 nativeEmitter.cachedBuilders.remove(element.enclosingClass); |
2073 | 2098 |
2074 } | 2099 } |
2075 } | 2100 } |
2076 } | 2101 } |
2077 } | 2102 } |
OLD | NEW |