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 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
54 class CodeEmitterTask extends CompilerTask { | 54 class CodeEmitterTask extends CompilerTask { |
55 bool needsInheritFunction = false; | 55 bool needsInheritFunction = false; |
56 bool needsDefineClass = false; | 56 bool needsDefineClass = false; |
57 bool needsClosureClass = false; | 57 bool needsClosureClass = false; |
58 bool needsLazyInitializer = false; | 58 bool needsLazyInitializer = false; |
59 final Namer namer; | 59 final Namer namer; |
60 ConstantEmitter constantEmitter; | 60 ConstantEmitter constantEmitter; |
61 NativeEmitter nativeEmitter; | 61 NativeEmitter nativeEmitter; |
62 CodeBuffer boundClosureBuffer; | 62 CodeBuffer boundClosureBuffer; |
63 CodeBuffer mainBuffer; | 63 CodeBuffer mainBuffer; |
| 64 final CodeBuffer deferredBuffer = new CodeBuffer(); |
64 /** Shorter access to [isolatePropertiesName]. Both here in the code, as | 65 /** Shorter access to [isolatePropertiesName]. Both here in the code, as |
65 well as in the generated code. */ | 66 well as in the generated code. */ |
66 String isolateProperties; | 67 String isolateProperties; |
67 String classesCollector; | 68 String classesCollector; |
68 Set<ClassElement> neededClasses; | 69 Set<ClassElement> neededClasses; |
69 // TODO(ngeoffray): remove this field. | 70 // TODO(ngeoffray): remove this field. |
70 Set<ClassElement> instantiatedClasses; | 71 Set<ClassElement> instantiatedClasses; |
71 | 72 |
72 JavaScriptBackend get backend => compiler.backend; | 73 JavaScriptBackend get backend => compiler.backend; |
73 | 74 |
(...skipping 1637 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1711 Element member = element.lookupLocalMember(noSuchMethodName); | 1712 Element member = element.lookupLocalMember(noSuchMethodName); |
1712 if (member == null) continue; | 1713 if (member == null) continue; |
1713 if (noSuchMethodSelector.applies(member, compiler)) { | 1714 if (noSuchMethodSelector.applies(member, compiler)) { |
1714 nativeEmitter.handleNoSuchMethod = true; | 1715 nativeEmitter.handleNoSuchMethod = true; |
1715 break; | 1716 break; |
1716 } | 1717 } |
1717 } | 1718 } |
1718 } | 1719 } |
1719 | 1720 |
1720 for (ClassElement element in sortedClasses) { | 1721 for (ClassElement element in sortedClasses) { |
| 1722 if (isDeferred(element)) { |
| 1723 warnNotImplemented( |
| 1724 element, |
| 1725 'Warning: deferred loading of classes is not implemented yet.'); |
| 1726 } |
1721 generateClass(element, buffer); | 1727 generateClass(element, buffer); |
1722 } | 1728 } |
1723 | 1729 |
1724 // The closure class could have become necessary because of the generation | 1730 // The closure class could have become necessary because of the generation |
1725 // of stubs. | 1731 // of stubs. |
1726 ClassElement closureClass = compiler.closureClass; | 1732 ClassElement closureClass = compiler.closureClass; |
1727 if (needsClosureClass && !instantiatedClasses.contains(closureClass)) { | 1733 if (needsClosureClass && !instantiatedClasses.contains(closureClass)) { |
1728 generateClass(closureClass, buffer); | 1734 generateClass(closureClass, buffer); |
1729 } | 1735 } |
1730 } | 1736 } |
1731 | 1737 |
1732 void emitFinishClassesInvocationIfNecessary(CodeBuffer buffer) { | 1738 void emitFinishClassesInvocationIfNecessary(CodeBuffer buffer) { |
1733 if (needsDefineClass) { | 1739 if (needsDefineClass) { |
1734 buffer.add("$finishClassesName($classesCollector)$N"); | 1740 buffer.add("$finishClassesName($classesCollector)$N"); |
1735 // Reset the map. | 1741 // Reset the map. |
1736 buffer.add("$classesCollector$_=$_{}$N"); | 1742 buffer.add("$classesCollector$_=$_{}$N"); |
1737 } | 1743 } |
1738 } | 1744 } |
1739 | 1745 |
1740 void emitStaticFunction(CodeBuffer buffer, | 1746 void emitStaticFunction(CodeBuffer buffer, |
1741 String name, | 1747 String name, |
1742 jsAst.Expression functionExpression) { | 1748 jsAst.Expression functionExpression) { |
1743 jsAst.Expression assignment = | 1749 jsAst.Expression assignment = |
1744 js[isolateProperties][name].assign(functionExpression); | 1750 js[isolateProperties][name].assign(functionExpression); |
1745 buffer.add(jsAst.prettyPrint(assignment, compiler)); | 1751 buffer.add(jsAst.prettyPrint(assignment, compiler)); |
1746 buffer.add('$N$n'); | 1752 buffer.add('$N$n'); |
1747 } | 1753 } |
1748 | 1754 |
1749 void emitStaticFunctions(CodeBuffer buffer) { | 1755 void emitStaticFunctions(CodeBuffer eagerBuffer) { |
1750 bool isStaticFunction(Element element) => | 1756 bool isStaticFunction(Element element) => |
1751 !element.isInstanceMember() && !element.isField(); | 1757 !element.isInstanceMember() && !element.isField(); |
1752 | 1758 |
1753 Iterable<Element> elements = | 1759 Iterable<Element> elements = |
1754 backend.generatedCode.keys.where(isStaticFunction); | 1760 backend.generatedCode.keys.where(isStaticFunction); |
1755 Set<Element> pendingElementsWithBailouts = | 1761 Set<Element> pendingElementsWithBailouts = |
1756 backend.generatedBailoutCode.keys | 1762 backend.generatedBailoutCode.keys |
1757 .where(isStaticFunction) | 1763 .where(isStaticFunction) |
1758 .toSet(); | 1764 .toSet(); |
1759 | 1765 |
1760 for (Element element in Elements.sortedByPosition(elements)) { | 1766 for (Element element in Elements.sortedByPosition(elements)) { |
| 1767 CodeBuffer buffer = isDeferred(element) ? deferredBuffer : eagerBuffer; |
1761 jsAst.Expression code = backend.generatedCode[element]; | 1768 jsAst.Expression code = backend.generatedCode[element]; |
1762 emitStaticFunction(buffer, namer.getName(element), code); | 1769 emitStaticFunction(buffer, namer.getName(element), code); |
1763 jsAst.Expression bailoutCode = backend.generatedBailoutCode[element]; | 1770 jsAst.Expression bailoutCode = backend.generatedBailoutCode[element]; |
1764 if (bailoutCode != null) { | 1771 if (bailoutCode != null) { |
1765 pendingElementsWithBailouts.remove(element); | 1772 pendingElementsWithBailouts.remove(element); |
1766 emitStaticFunction(buffer, namer.getBailoutName(element), bailoutCode); | 1773 emitStaticFunction(buffer, namer.getBailoutName(element), bailoutCode); |
1767 } | 1774 } |
1768 } | 1775 } |
1769 | 1776 |
1770 // Is it possible the primary function was inlined but the bailout was not? | 1777 // Is it possible the primary function was inlined but the bailout was not? |
1771 for (Element element in | 1778 for (Element element in |
1772 Elements.sortedByPosition(pendingElementsWithBailouts)) { | 1779 Elements.sortedByPosition(pendingElementsWithBailouts)) { |
| 1780 CodeBuffer buffer = isDeferred(element) ? deferredBuffer : eagerBuffer; |
1773 jsAst.Expression bailoutCode = backend.generatedBailoutCode[element]; | 1781 jsAst.Expression bailoutCode = backend.generatedBailoutCode[element]; |
1774 emitStaticFunction(buffer, namer.getBailoutName(element), bailoutCode); | 1782 emitStaticFunction(buffer, namer.getBailoutName(element), bailoutCode); |
1775 } | 1783 } |
1776 } | 1784 } |
1777 | 1785 |
1778 void emitStaticFunctionGetters(CodeBuffer buffer) { | 1786 void emitStaticFunctionGetters(CodeBuffer buffer) { |
1779 Set<FunctionElement> functionsNeedingGetter = | 1787 Set<FunctionElement> functionsNeedingGetter = |
1780 compiler.codegenWorld.staticFunctionsNeedingGetter; | 1788 compiler.codegenWorld.staticFunctionsNeedingGetter; |
1781 for (FunctionElement element in | 1789 for (FunctionElement element in |
1782 Elements.sortedByPosition(functionsNeedingGetter)) { | 1790 Elements.sortedByPosition(functionsNeedingGetter)) { |
| 1791 // TODO(ahe): Defer loading of these getters. |
| 1792 |
1783 // The static function does not have the correct name. Since | 1793 // The static function does not have the correct name. Since |
1784 // [addParameterStubs] use the name to create its stubs we simply | 1794 // [addParameterStubs] use the name to create its stubs we simply |
1785 // create a fake element with the correct name. | 1795 // create a fake element with the correct name. |
1786 // Note: the callElement will not have any enclosingElement. | 1796 // Note: the callElement will not have any enclosingElement. |
1787 FunctionElement callElement = | 1797 FunctionElement callElement = |
1788 new ClosureInvocationElement(namer.closureInvocationSelectorName, | 1798 new ClosureInvocationElement(namer.closureInvocationSelectorName, |
1789 element); | 1799 element); |
1790 String staticName = namer.getName(element); | 1800 String staticName = namer.getName(element); |
1791 String invocationName = namer.instanceMethodName(callElement); | 1801 String invocationName = namer.instanceMethodName(callElement); |
1792 String fieldAccess = '$isolateProperties.$staticName'; | 1802 String fieldAccess = '$isolateProperties.$staticName'; |
(...skipping 821 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2614 | 2624 |
2615 emitFinishIsolateConstructorInvocation(mainBuffer); | 2625 emitFinishIsolateConstructorInvocation(mainBuffer); |
2616 mainBuffer.add('var ${namer.CURRENT_ISOLATE}$_=' | 2626 mainBuffer.add('var ${namer.CURRENT_ISOLATE}$_=' |
2617 '${_}new ${namer.isolateName}()$N'); | 2627 '${_}new ${namer.isolateName}()$N'); |
2618 | 2628 |
2619 nativeEmitter.assembleCode(mainBuffer); | 2629 nativeEmitter.assembleCode(mainBuffer); |
2620 emitMain(mainBuffer); | 2630 emitMain(mainBuffer); |
2621 emitInitFunction(mainBuffer); | 2631 emitInitFunction(mainBuffer); |
2622 compiler.assembledCode = mainBuffer.getText(); | 2632 compiler.assembledCode = mainBuffer.getText(); |
2623 | 2633 |
2624 if (generateSourceMap) { | 2634 if (!deferredBuffer.isEmpty) { |
2625 SourceFile compiledFile = new SourceFile(null, compiler.assembledCode); | 2635 String code = deferredBuffer.getText(); |
2626 String sourceMap = buildSourceMap(mainBuffer, compiledFile); | 2636 compiler.outputProvider('part', 'js') |
2627 compiler.outputProvider('', 'js.map') | 2637 ..add(code) |
2628 ..add(sourceMap) | |
2629 ..close(); | 2638 ..close(); |
| 2639 outputSourceMap(deferredBuffer, compiler.assembledCode, 'part'); |
2630 } | 2640 } |
| 2641 |
| 2642 outputSourceMap(mainBuffer, compiler.assembledCode, ''); |
2631 }); | 2643 }); |
2632 return compiler.assembledCode; | 2644 return compiler.assembledCode; |
2633 } | 2645 } |
2634 | 2646 |
2635 String buildSourceMap(CodeBuffer buffer, SourceFile compiledFile) { | 2647 String buildSourceMap(CodeBuffer buffer, SourceFile compiledFile) { |
2636 SourceMapBuilder sourceMapBuilder = new SourceMapBuilder(); | 2648 SourceMapBuilder sourceMapBuilder = new SourceMapBuilder(); |
2637 buffer.forEachSourceLocation(sourceMapBuilder.addMapping); | 2649 buffer.forEachSourceLocation(sourceMapBuilder.addMapping); |
2638 return sourceMapBuilder.build(compiledFile); | 2650 return sourceMapBuilder.build(compiledFile); |
2639 } | 2651 } |
| 2652 |
| 2653 void outputSourceMap(CodeBuffer buffer, String code, String name) { |
| 2654 if (!generateSourceMap) return; |
| 2655 SourceFile compiledFile = new SourceFile(null, compiler.assembledCode); |
| 2656 String sourceMap = buildSourceMap(mainBuffer, compiledFile); |
| 2657 compiler.outputProvider(name, 'js.map') |
| 2658 ..add(sourceMap) |
| 2659 ..close(); |
| 2660 } |
| 2661 |
| 2662 bool isDeferred(Element element) { |
| 2663 return compiler.deferredLoadTask.isDeferred(element); |
| 2664 } |
| 2665 |
| 2666 // TODO(ahe): Remove this when deferred loading is fully implemented. |
| 2667 void warnNotImplemented(Element element, String message) { |
| 2668 compiler.reportMessage(compiler.spanFromSpannable(element), |
| 2669 MessageKind.GENERIC.error({'text': message}), |
| 2670 api.Diagnostic.WARNING); |
| 2671 } |
2640 } | 2672 } |
2641 | 2673 |
2642 const String GENERATED_BY = """ | 2674 const String GENERATED_BY = """ |
2643 // Generated by dart2js, the Dart to JavaScript compiler. | 2675 // Generated by dart2js, the Dart to JavaScript compiler. |
2644 """; | 2676 """; |
2645 const String HOOKS_API_USAGE = """ | 2677 const String HOOKS_API_USAGE = """ |
2646 // The code supports the following hooks: | 2678 // The code supports the following hooks: |
2647 // dartPrint(message) - if this function is defined it is called | 2679 // dartPrint(message) - if this function is defined it is called |
2648 // instead of the Dart [print] method. | 2680 // instead of the Dart [print] method. |
2649 // dartMainRunner(main) - if this function is defined, the Dart [main] | 2681 // dartMainRunner(main) - if this function is defined, the Dart [main] |
2650 // method will not be invoked directly. | 2682 // method will not be invoked directly. |
2651 // Instead, a closure that will invoke [main] is | 2683 // Instead, a closure that will invoke [main] is |
2652 // passed to [dartMainRunner]. | 2684 // passed to [dartMainRunner]. |
2653 """; | 2685 """; |
OLD | NEW |