Chromium Code Reviews| 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 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 51 /** | 51 /** |
| 52 * Generates the code for all used classes in the program. Static fields (even | 52 * Generates the code for all used classes in the program. Static fields (even |
| 53 * in classes) are ignored, since they can be treated as non-class elements. | 53 * in classes) are ignored, since they can be treated as non-class elements. |
| 54 * | 54 * |
| 55 * The code for the containing (used) methods must exist in the [:universe:]. | 55 * The code for the containing (used) methods must exist in the [:universe:]. |
| 56 */ | 56 */ |
| 57 class CodeEmitterTask extends CompilerTask { | 57 class CodeEmitterTask extends CompilerTask { |
| 58 bool needsInheritFunction = false; | 58 bool needsInheritFunction = false; |
| 59 bool needsDefineClass = false; | 59 bool needsDefineClass = false; |
| 60 bool needsMixinSupport = false; | 60 bool needsMixinSupport = false; |
| 61 bool needsClosureClass = false; | |
| 62 bool needsLazyInitializer = false; | 61 bool needsLazyInitializer = false; |
| 63 final Namer namer; | 62 final Namer namer; |
| 64 ConstantEmitter constantEmitter; | 63 ConstantEmitter constantEmitter; |
| 65 NativeEmitter nativeEmitter; | 64 NativeEmitter nativeEmitter; |
| 66 CodeBuffer mainBuffer; | 65 CodeBuffer mainBuffer; |
| 67 final CodeBuffer deferredBuffer = new CodeBuffer(); | 66 final CodeBuffer deferredBuffer = new CodeBuffer(); |
| 68 /** Shorter access to [isolatePropertiesName]. Both here in the code, as | 67 /** Shorter access to [isolatePropertiesName]. Both here in the code, as |
| 69 well as in the generated code. */ | 68 well as in the generated code. */ |
| 70 String isolateProperties; | 69 String isolateProperties; |
| 71 String classesCollector; | 70 String classesCollector; |
| (...skipping 1677 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1749 for (ClassElement interceptor in backend.interceptedClasses) { | 1748 for (ClassElement interceptor in backend.interceptedClasses) { |
| 1750 if (!needed.contains(interceptor) | 1749 if (!needed.contains(interceptor) |
| 1751 && interceptor != compiler.objectClass) { | 1750 && interceptor != compiler.objectClass) { |
| 1752 unneededClasses.add(interceptor); | 1751 unneededClasses.add(interceptor); |
| 1753 } | 1752 } |
| 1754 } | 1753 } |
| 1755 | 1754 |
| 1756 return (ClassElement cls) => !unneededClasses.contains(cls); | 1755 return (ClassElement cls) => !unneededClasses.contains(cls); |
| 1757 } | 1756 } |
| 1758 | 1757 |
| 1759 void emitClosureClassIfNeeded(CodeBuffer buffer) { | |
| 1760 // The closure class could have become necessary because of the generation | |
| 1761 // of stubs. | |
| 1762 ClassElement closureClass = compiler.closureClass; | |
| 1763 if (needsClosureClass && !instantiatedClasses.contains(closureClass)) { | |
| 1764 ClassElement objectClass = compiler.objectClass; | |
| 1765 if (!instantiatedClasses.contains(objectClass)) { | |
| 1766 generateClass(objectClass, bufferForElement(objectClass, buffer)); | |
| 1767 } | |
| 1768 generateClass(closureClass, bufferForElement(closureClass, buffer)); | |
| 1769 } | |
| 1770 } | |
| 1771 | |
| 1772 void emitFinishClassesInvocationIfNecessary(CodeBuffer buffer) { | 1758 void emitFinishClassesInvocationIfNecessary(CodeBuffer buffer) { |
| 1773 if (needsDefineClass) { | 1759 if (needsDefineClass) { |
| 1774 buffer.write('$finishClassesName($classesCollector,' | 1760 buffer.write('$finishClassesName($classesCollector,' |
| 1775 '$_$isolateProperties,' | 1761 '$_$isolateProperties,' |
| 1776 '${_}null)$N'); | 1762 '${_}null)$N'); |
| 1777 | 1763 |
| 1778 // Reset the map. | 1764 // Reset the map. |
| 1779 buffer.write("$classesCollector$_=${_}null$N$n"); | 1765 buffer.write("$classesCollector$_=${_}null$N$n"); |
| 1780 } | 1766 } |
| 1781 } | 1767 } |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1848 } | 1834 } |
| 1849 | 1835 |
| 1850 void emitStaticFunctionClosures() { | 1836 void emitStaticFunctionClosures() { |
| 1851 Set<FunctionElement> functionsNeedingGetter = | 1837 Set<FunctionElement> functionsNeedingGetter = |
| 1852 compiler.codegenWorld.staticFunctionsNeedingGetter; | 1838 compiler.codegenWorld.staticFunctionsNeedingGetter; |
| 1853 for (FunctionElement element in | 1839 for (FunctionElement element in |
| 1854 Elements.sortedByPosition(functionsNeedingGetter)) { | 1840 Elements.sortedByPosition(functionsNeedingGetter)) { |
| 1855 String staticName = namer.getName(element); | 1841 String staticName = namer.getName(element); |
| 1856 String superName = namer.getName(compiler.closureClass); | 1842 String superName = namer.getName(compiler.closureClass); |
| 1857 String name = 'Closure\$${element.name.slowToString()}'; | 1843 String name = 'Closure\$${element.name.slowToString()}'; |
| 1858 needsClosureClass = true; | 1844 assert(instantiatedClasses.contains(closureClass)); |
| 1859 | 1845 |
| 1860 ClassElement closureClassElement = new ClosureClassElement( | 1846 ClassElement closureClassElement = new ClosureClassElement( |
| 1861 null, new SourceString(name), compiler, element, | 1847 null, new SourceString(name), compiler, element, |
| 1862 element.getCompilationUnit()); | 1848 element.getCompilationUnit()); |
| 1863 // Now add the methods on the closure class. The instance method does not | 1849 // Now add the methods on the closure class. The instance method does not |
| 1864 // have the correct name. Since [addParameterStubs] use the name to create | 1850 // have the correct name. Since [addParameterStubs] use the name to create |
| 1865 // its stubs we simply create a fake element with the correct name. | 1851 // its stubs we simply create a fake element with the correct name. |
| 1866 // Note: the callElement will not have any enclosingElement. | 1852 // Note: the callElement will not have any enclosingElement. |
| 1867 FunctionElement callElement = | 1853 FunctionElement callElement = |
| 1868 new ClosureInvocationElement(namer.closureInvocationSelectorName, | 1854 new ClosureInvocationElement(namer.closureInvocationSelectorName, |
| 1869 element); | 1855 element); |
| 1870 | 1856 |
| 1871 String invocationName = namer.instanceMethodName(callElement); | 1857 String invocationName = namer.instanceMethodName(callElement); |
| 1872 String mangledName = namer.getName(closureClassElement); | 1858 String mangledName = namer.getName(closureClassElement); |
| 1873 | 1859 |
| 1874 // Define the constructor with a name so that Object.toString can | 1860 // Define the constructor with a name so that Object.toString can |
| 1875 // find the class name of the closure class. | 1861 // find the class name of the closure class. |
| 1876 ClassBuilder closureBuilder = new ClassBuilder(); | 1862 ClassBuilder closureBuilder = new ClassBuilder(); |
| 1877 // If a static function is used as a closure we need to add its name | 1863 // If a static function is used as a closure we need to add its name |
| 1878 // in case it is used in spawnFunction. | 1864 // in case it is used in spawnFunction. |
| 1879 String methodName = namer.STATIC_CLOSURE_NAME_NAME; | 1865 String methodName = namer.STATIC_CLOSURE_NAME_NAME; |
| 1880 emitBoundClosureClassHeader( | 1866 emitClosureClassHeader( |
| 1881 mangledName, superName, <String>[invocationName, methodName], | 1867 mangledName, superName, <String>[invocationName, methodName], |
| 1882 closureBuilder); | 1868 closureBuilder); |
| 1883 | 1869 |
| 1884 addParameterStubs(callElement, closureBuilder.addProperty); | 1870 addParameterStubs(callElement, closureBuilder.addProperty); |
| 1885 | 1871 |
| 1886 DartType type = element.computeType(compiler); | 1872 DartType type = element.computeType(compiler); |
| 1887 getTypedefChecksOn(type).forEach((Element typedef) { | 1873 getTypedefChecksOn(type).forEach((Element typedef) { |
| 1888 String operator = namer.operatorIs(typedef); | 1874 String operator = namer.operatorIs(typedef); |
| 1889 closureBuilder.addProperty(operator, js('true')); | 1875 closureBuilder.addProperty(operator, js('true')); |
| 1890 }); | 1876 }); |
| 1891 | 1877 |
| 1892 // TODO(ngeoffray): Cache common base classes for clsures, bound | 1878 // TODO(ngeoffray): Cache common base classes for closures, bound |
| 1893 // closures, and static closures that have common type checks. | 1879 // closures, and static closures that have common type checks. |
| 1894 boundClosures.add( | 1880 boundClosures.add( |
| 1895 js('$classesCollector.$mangledName = #', | 1881 js('$classesCollector.$mangledName = #', |
| 1896 closureBuilder.toObjectInitializer())); | 1882 closureBuilder.toObjectInitializer())); |
| 1897 | 1883 |
| 1898 staticGetters[element] = closureClassElement; | 1884 staticGetters[element] = closureClassElement; |
| 1899 } | 1885 } |
| 1900 } | 1886 } |
| 1901 | 1887 |
| 1902 void emitBoundClosureClassHeader(String mangledName, | 1888 void emitClosureClassHeader(String mangledName, |
| 1903 String superName, | 1889 String superName, |
| 1904 List<String> fieldNames, | 1890 List<String> fieldNames, |
| 1905 ClassBuilder builder) { | 1891 ClassBuilder builder) { |
| 1906 builder.addProperty('', | 1892 builder.addProperty('', |
| 1907 js.string("$superName;${fieldNames.join(',')}")); | 1893 js.string("$superName;${fieldNames.join(',')}")); |
| 1908 } | 1894 } |
| 1909 | 1895 |
| 1910 /** | 1896 /** |
| 1911 * Documentation wanted -- johnniwinther | 1897 * Documentation wanted -- johnniwinther |
| 1912 * | 1898 * |
| 1913 * Invariant: [member] must be a declaration element. | 1899 * Invariant: [member] must be a declaration element. |
| 1914 */ | 1900 */ |
| 1915 void emitDynamicFunctionGetter(FunctionElement member, | 1901 void emitDynamicFunctionGetter(FunctionElement member, |
| 1916 DefineStubFunction defineStub) { | 1902 DefineStubFunction defineStub) { |
| 1917 assert(invariant(member, member.isDeclaration)); | 1903 assert(invariant(member, member.isDeclaration)); |
| 1904 assert(instantiatedClasses.contains(boundClosureClass)); | |
| 1918 // For every method that has the same name as a property-get we create a | 1905 // For every method that has the same name as a property-get we create a |
| 1919 // getter that returns a bound closure. Say we have a class 'A' with method | 1906 // getter that returns a bound closure. Say we have a class 'A' with method |
| 1920 // 'foo' and somewhere in the code there is a dynamic property get of | 1907 // 'foo' and somewhere in the code there is a dynamic property get of |
| 1921 // 'foo'. Then we generate the following code (in pseudo Dart/JavaScript): | 1908 // 'foo'. Then we generate the following code (in pseudo Dart/JavaScript): |
| 1922 // | 1909 // |
| 1923 // class A { | 1910 // class A { |
| 1924 // foo(x, y, z) { ... } // Original function. | 1911 // foo(x, y, z) { ... } // Original function. |
| 1925 // get foo { return new BoundClosure499(this, "foo"); } | 1912 // get foo { return new BoundClosure499(this, "foo"); } |
| 1926 // } | 1913 // } |
| 1927 // class BoundClosure499 extends Closure { | 1914 // class BoundClosure499 extends BoundClosure { |
| 1928 // var self; | |
| 1929 // BoundClosure499(this.self, this.name); | 1915 // BoundClosure499(this.self, this.name); |
| 1930 // $call3(x, y, z) { return self[name](x, y, z); } | 1916 // $call3(x, y, z) { return self[name](x, y, z); } |
| 1931 // } | 1917 // } |
| 1932 | 1918 |
| 1933 // TODO(floitsch): share the closure classes with other classes | 1919 // TODO(floitsch): share the closure classes with other classes |
| 1934 // if they share methods with the same signature. Currently we do this only | 1920 // if they share methods with the same signature. Currently we do this only |
| 1935 // if there are no optional parameters. Closures with optional parameters | 1921 // if there are no optional parameters. Closures with optional parameters |
| 1936 // are more difficult to canonicalize because they would need to have the | 1922 // are more difficult to canonicalize because they would need to have the |
| 1937 // same default values. | 1923 // same default values. |
| 1938 | 1924 |
| 1939 bool hasOptionalParameters = member.optionalParameterCount(compiler) != 0; | 1925 bool hasOptionalParameters = member.optionalParameterCount(compiler) != 0; |
| 1940 int parameterCount = member.parameterCount(compiler); | 1926 int parameterCount = member.parameterCount(compiler); |
| 1941 | 1927 |
| 1942 Map<int, String> cache; | 1928 Map<int, String> cache; |
| 1943 String extraArg = null; | 1929 String extraArg = null; |
|
kasperl
2013/05/30 08:23:14
Where is this used?
ngeoffray
2013/05/30 08:25:07
Nowhere. Removed.
| |
| 1944 // Intercepted methods take an extra parameter, which is the | 1930 // Intercepted methods take an extra parameter, which is the |
| 1945 // receiver of the call. | 1931 // receiver of the call. |
| 1946 bool inInterceptor = backend.isInterceptedMethod(member); | 1932 bool inInterceptor = backend.isInterceptedMethod(member); |
| 1947 if (inInterceptor) { | 1933 if (inInterceptor) { |
| 1948 cache = interceptorClosureCache; | 1934 cache = interceptorClosureCache; |
| 1949 extraArg = 'receiver'; | |
| 1950 } else { | 1935 } else { |
| 1951 cache = boundClosureCache; | 1936 cache = boundClosureCache; |
| 1952 } | 1937 } |
| 1953 List<String> fieldNames = compiler.enableMinification | 1938 List<String> fieldNames = <String>[]; |
| 1954 ? inInterceptor ? const ['a', 'b', 'c'] | 1939 compiler.boundClosureClass.forEachInstanceField((_, Element field) { |
| 1955 : const ['a', 'b'] | 1940 fieldNames.add(namer.getName(field)); |
| 1956 : inInterceptor ? const ['self', 'target', 'receiver'] | 1941 }); |
| 1957 : const ['self', 'target']; | |
| 1958 | 1942 |
| 1959 Iterable<Element> typedefChecks = | 1943 Iterable<Element> typedefChecks = |
| 1960 getTypedefChecksOn(member.computeType(compiler)); | 1944 getTypedefChecksOn(member.computeType(compiler)); |
| 1961 bool hasTypedefChecks = !typedefChecks.isEmpty; | 1945 bool hasTypedefChecks = !typedefChecks.isEmpty; |
| 1962 | 1946 |
| 1963 bool canBeShared = !hasOptionalParameters && !hasTypedefChecks; | 1947 bool canBeShared = !hasOptionalParameters && !hasTypedefChecks; |
| 1964 | 1948 |
| 1965 String closureClass = canBeShared ? cache[parameterCount] : null; | 1949 String closureClass = canBeShared ? cache[parameterCount] : null; |
| 1966 if (closureClass == null) { | 1950 if (closureClass == null) { |
| 1967 // Either the class was not cached yet, or there are optional parameters. | 1951 // Either the class was not cached yet, or there are optional parameters. |
| 1968 // Create a new closure class. | 1952 // Create a new closure class. |
| 1969 String name; | 1953 String name; |
| 1970 if (canBeShared) { | 1954 if (canBeShared) { |
| 1971 if (inInterceptor) { | 1955 if (inInterceptor) { |
| 1972 name = 'BoundClosure\$i${parameterCount}'; | 1956 name = 'BoundClosure\$i${parameterCount}'; |
| 1973 } else { | 1957 } else { |
| 1974 name = 'BoundClosure\$${parameterCount}'; | 1958 name = 'BoundClosure\$${parameterCount}'; |
| 1975 } | 1959 } |
| 1976 } else { | 1960 } else { |
| 1977 name = 'Bound_${member.name.slowToString()}' | 1961 name = 'Bound_${member.name.slowToString()}' |
| 1978 '_${member.enclosingElement.name.slowToString()}'; | 1962 '_${member.enclosingElement.name.slowToString()}'; |
| 1979 } | 1963 } |
| 1980 | 1964 |
| 1981 ClassElement closureClassElement = new ClosureClassElement( | 1965 ClassElement closureClassElement = new ClosureClassElement( |
| 1982 null, new SourceString(name), compiler, member, | 1966 null, new SourceString(name), compiler, member, |
| 1983 member.getCompilationUnit()); | 1967 member.getCompilationUnit()); |
| 1984 String mangledName = namer.getName(closureClassElement); | 1968 String mangledName = namer.getName(closureClassElement); |
| 1985 String superName = namer.getName(closureClassElement.superclass); | 1969 String superName = namer.getName(closureClassElement.superclass); |
| 1986 needsClosureClass = true; | |
| 1987 | 1970 |
| 1988 // Define the constructor with a name so that Object.toString can | 1971 // Define the constructor with a name so that Object.toString can |
| 1989 // find the class name of the closure class. | 1972 // find the class name of the closure class. |
| 1990 ClassBuilder boundClosureBuilder = new ClassBuilder(); | 1973 ClassBuilder boundClosureBuilder = new ClassBuilder(); |
| 1991 emitBoundClosureClassHeader( | 1974 emitClosureClassHeader( |
| 1992 mangledName, superName, fieldNames, boundClosureBuilder); | 1975 mangledName, superName, fieldNames, boundClosureBuilder); |
| 1993 // Now add the methods on the closure class. The instance method does not | 1976 // Now add the methods on the closure class. The instance method does not |
| 1994 // have the correct name. Since [addParameterStubs] use the name to create | 1977 // have the correct name. Since [addParameterStubs] use the name to create |
| 1995 // its stubs we simply create a fake element with the correct name. | 1978 // its stubs we simply create a fake element with the correct name. |
| 1996 // Note: the callElement will not have any enclosingElement. | 1979 // Note: the callElement will not have any enclosingElement. |
| 1997 FunctionElement callElement = | 1980 FunctionElement callElement = |
| 1998 new ClosureInvocationElement(namer.closureInvocationSelectorName, | 1981 new ClosureInvocationElement(namer.closureInvocationSelectorName, |
| 1999 member); | 1982 member); |
| 2000 | 1983 |
| 2001 String invocationName = namer.instanceMethodName(callElement); | 1984 String invocationName = namer.instanceMethodName(callElement); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2037 | 2020 |
| 2038 // And finally the getter. | 2021 // And finally the getter. |
| 2039 String getterName = namer.getterName(member); | 2022 String getterName = namer.getterName(member); |
| 2040 String targetName = namer.instanceMethodName(member); | 2023 String targetName = namer.instanceMethodName(member); |
| 2041 | 2024 |
| 2042 List<String> parameters = <String>[]; | 2025 List<String> parameters = <String>[]; |
| 2043 List<jsAst.Expression> arguments = <jsAst.Expression>[]; | 2026 List<jsAst.Expression> arguments = <jsAst.Expression>[]; |
| 2044 arguments.add(js('this')); | 2027 arguments.add(js('this')); |
| 2045 arguments.add(js.string(targetName)); | 2028 arguments.add(js.string(targetName)); |
| 2046 if (inInterceptor) { | 2029 if (inInterceptor) { |
| 2047 parameters.add(extraArg); | 2030 String receiverArg = fieldNames[2]; |
| 2048 arguments.add(js(extraArg)); | 2031 parameters.add(receiverArg); |
| 2032 arguments.add(js(receiverArg)); | |
| 2033 } else { | |
| 2034 // Put null in the intercepted receiver field. | |
| 2035 arguments.add(new jsAst.LiteralNull()); | |
| 2049 } | 2036 } |
| 2050 | 2037 |
| 2051 jsAst.Expression getterFunction = js.fun( | 2038 jsAst.Expression getterFunction = js.fun( |
| 2052 parameters, | 2039 parameters, |
| 2053 js.return_(js(closureClass).newWith(arguments))); | 2040 js.return_(js(closureClass).newWith(arguments))); |
| 2054 | 2041 |
| 2055 defineStub(getterName, getterFunction); | 2042 defineStub(getterName, getterFunction); |
| 2056 } | 2043 } |
| 2057 | 2044 |
| 2058 /** | 2045 /** |
| (...skipping 931 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2990 nativeEmitter.assembleCode(nativeBuffer); | 2977 nativeEmitter.assembleCode(nativeBuffer); |
| 2991 | 2978 |
| 2992 // Might create boundClosures. | 2979 // Might create boundClosures. |
| 2993 if (!deferredClasses.isEmpty) { | 2980 if (!deferredClasses.isEmpty) { |
| 2994 for (ClassElement element in deferredClasses) { | 2981 for (ClassElement element in deferredClasses) { |
| 2995 generateClass(element, bufferForElement(element, mainBuffer)); | 2982 generateClass(element, bufferForElement(element, mainBuffer)); |
| 2996 } | 2983 } |
| 2997 } | 2984 } |
| 2998 | 2985 |
| 2999 emitStaticFunctionClosures(); | 2986 emitStaticFunctionClosures(); |
| 3000 emitClosureClassIfNeeded(mainBuffer); | |
| 3001 | 2987 |
| 3002 addComment('Bound closures', mainBuffer); | 2988 addComment('Bound closures', mainBuffer); |
| 3003 // Now that we have emitted all classes, we know all the bound | 2989 // Now that we have emitted all classes, we know all the bound |
| 3004 // closures that will be needed. | 2990 // closures that will be needed. |
| 3005 for (jsAst.Node node in boundClosures) { | 2991 for (jsAst.Node node in boundClosures) { |
| 3006 // TODO(ahe): Some of these can be deferred. | 2992 // TODO(ahe): Some of these can be deferred. |
| 3007 mainBuffer.add(jsAst.prettyPrint(node, compiler)); | 2993 mainBuffer.add(jsAst.prettyPrint(node, compiler)); |
| 3008 mainBuffer.add("$N$n"); | 2994 mainBuffer.add("$N$n"); |
| 3009 } | 2995 } |
| 3010 | 2996 |
| (...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3253 functions.push(property); | 3239 functions.push(property); |
| 3254 } else { | 3240 } else { |
| 3255 $$[property] = element; | 3241 $$[property] = element; |
| 3256 classes.push(property); | 3242 classes.push(property); |
| 3257 classes.push(element[""]); | 3243 classes.push(element[""]); |
| 3258 } | 3244 } |
| 3259 } | 3245 } |
| 3260 libraries.push([name, uri, classes, functions]); | 3246 libraries.push([name, uri, classes, functions]); |
| 3261 } | 3247 } |
| 3262 })'''; | 3248 })'''; |
| OLD | NEW |