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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart

Issue 15888010: Re-apply "Implement operator== and hashCode for bound closures." (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 6 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 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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(compiler.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(compiler.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;
1944 // Intercepted methods take an extra parameter, which is the 1929 // Intercepted methods take an extra parameter, which is the
1945 // receiver of the call. 1930 // receiver of the call.
1946 bool inInterceptor = backend.isInterceptedMethod(member); 1931 bool inInterceptor = backend.isInterceptedMethod(member);
1947 if (inInterceptor) { 1932 if (inInterceptor) {
1948 cache = interceptorClosureCache; 1933 cache = interceptorClosureCache;
1949 extraArg = 'receiver';
1950 } else { 1934 } else {
1951 cache = boundClosureCache; 1935 cache = boundClosureCache;
1952 } 1936 }
1953 List<String> fieldNames = compiler.enableMinification 1937 List<String> fieldNames = <String>[];
1954 ? inInterceptor ? const ['a', 'b', 'c'] 1938 compiler.boundClosureClass.forEachInstanceField((_, Element field) {
1955 : const ['a', 'b'] 1939 fieldNames.add(namer.getName(field));
1956 : inInterceptor ? const ['self', 'target', 'receiver'] 1940 });
1957 : const ['self', 'target'];
1958 1941
1959 Iterable<Element> typedefChecks = 1942 Iterable<Element> typedefChecks =
1960 getTypedefChecksOn(member.computeType(compiler)); 1943 getTypedefChecksOn(member.computeType(compiler));
1961 bool hasTypedefChecks = !typedefChecks.isEmpty; 1944 bool hasTypedefChecks = !typedefChecks.isEmpty;
1962 1945
1963 bool canBeShared = !hasOptionalParameters && !hasTypedefChecks; 1946 bool canBeShared = !hasOptionalParameters && !hasTypedefChecks;
1964 1947
1965 String closureClass = canBeShared ? cache[parameterCount] : null; 1948 String closureClass = canBeShared ? cache[parameterCount] : null;
1966 if (closureClass == null) { 1949 if (closureClass == null) {
1967 // Either the class was not cached yet, or there are optional parameters. 1950 // Either the class was not cached yet, or there are optional parameters.
1968 // Create a new closure class. 1951 // Create a new closure class.
1969 String name; 1952 String name;
1970 if (canBeShared) { 1953 if (canBeShared) {
1971 if (inInterceptor) { 1954 if (inInterceptor) {
1972 name = 'BoundClosure\$i${parameterCount}'; 1955 name = 'BoundClosure\$i${parameterCount}';
1973 } else { 1956 } else {
1974 name = 'BoundClosure\$${parameterCount}'; 1957 name = 'BoundClosure\$${parameterCount}';
1975 } 1958 }
1976 } else { 1959 } else {
1977 name = 'Bound_${member.name.slowToString()}' 1960 name = 'Bound_${member.name.slowToString()}'
1978 '_${member.enclosingElement.name.slowToString()}'; 1961 '_${member.enclosingElement.name.slowToString()}';
1979 } 1962 }
1980 1963
1981 ClassElement closureClassElement = new ClosureClassElement( 1964 ClassElement closureClassElement = new ClosureClassElement(
1982 null, new SourceString(name), compiler, member, 1965 null, new SourceString(name), compiler, member,
1983 member.getCompilationUnit()); 1966 member.getCompilationUnit());
1984 String mangledName = namer.getName(closureClassElement); 1967 String mangledName = namer.getName(closureClassElement);
1985 String superName = namer.getName(closureClassElement.superclass); 1968 String superName = namer.getName(closureClassElement.superclass);
1986 needsClosureClass = true;
1987 1969
1988 // Define the constructor with a name so that Object.toString can 1970 // Define the constructor with a name so that Object.toString can
1989 // find the class name of the closure class. 1971 // find the class name of the closure class.
1990 ClassBuilder boundClosureBuilder = new ClassBuilder(); 1972 ClassBuilder boundClosureBuilder = new ClassBuilder();
1991 emitBoundClosureClassHeader( 1973 emitClosureClassHeader(
1992 mangledName, superName, fieldNames, boundClosureBuilder); 1974 mangledName, superName, fieldNames, boundClosureBuilder);
1993 // Now add the methods on the closure class. The instance method does not 1975 // 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 1976 // have the correct name. Since [addParameterStubs] use the name to create
1995 // its stubs we simply create a fake element with the correct name. 1977 // its stubs we simply create a fake element with the correct name.
1996 // Note: the callElement will not have any enclosingElement. 1978 // Note: the callElement will not have any enclosingElement.
1997 FunctionElement callElement = 1979 FunctionElement callElement =
1998 new ClosureInvocationElement(namer.closureInvocationSelectorName, 1980 new ClosureInvocationElement(namer.closureInvocationSelectorName,
1999 member); 1981 member);
2000 1982
2001 String invocationName = namer.instanceMethodName(callElement); 1983 String invocationName = namer.instanceMethodName(callElement);
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
2037 2019
2038 // And finally the getter. 2020 // And finally the getter.
2039 String getterName = namer.getterName(member); 2021 String getterName = namer.getterName(member);
2040 String targetName = namer.instanceMethodName(member); 2022 String targetName = namer.instanceMethodName(member);
2041 2023
2042 List<String> parameters = <String>[]; 2024 List<String> parameters = <String>[];
2043 List<jsAst.Expression> arguments = <jsAst.Expression>[]; 2025 List<jsAst.Expression> arguments = <jsAst.Expression>[];
2044 arguments.add(js('this')); 2026 arguments.add(js('this'));
2045 arguments.add(js.string(targetName)); 2027 arguments.add(js.string(targetName));
2046 if (inInterceptor) { 2028 if (inInterceptor) {
2047 parameters.add(extraArg); 2029 String receiverArg = fieldNames[2];
2048 arguments.add(js(extraArg)); 2030 parameters.add(receiverArg);
2031 arguments.add(js(receiverArg));
2032 } else {
2033 // Put null in the intercepted receiver field.
2034 arguments.add(new jsAst.LiteralNull());
2049 } 2035 }
2050 2036
2051 jsAst.Expression getterFunction = js.fun( 2037 jsAst.Expression getterFunction = js.fun(
2052 parameters, 2038 parameters,
2053 js.return_(js(closureClass).newWith(arguments))); 2039 js.return_(js(closureClass).newWith(arguments)));
2054 2040
2055 defineStub(getterName, getterFunction); 2041 defineStub(getterName, getterFunction);
2056 } 2042 }
2057 2043
2058 /** 2044 /**
(...skipping 931 matching lines...) Expand 10 before | Expand all | Expand 10 after
2990 nativeEmitter.assembleCode(nativeBuffer); 2976 nativeEmitter.assembleCode(nativeBuffer);
2991 2977
2992 // Might create boundClosures. 2978 // Might create boundClosures.
2993 if (!deferredClasses.isEmpty) { 2979 if (!deferredClasses.isEmpty) {
2994 for (ClassElement element in deferredClasses) { 2980 for (ClassElement element in deferredClasses) {
2995 generateClass(element, bufferForElement(element, mainBuffer)); 2981 generateClass(element, bufferForElement(element, mainBuffer));
2996 } 2982 }
2997 } 2983 }
2998 2984
2999 emitStaticFunctionClosures(); 2985 emitStaticFunctionClosures();
3000 emitClosureClassIfNeeded(mainBuffer);
3001 2986
3002 addComment('Bound closures', mainBuffer); 2987 addComment('Bound closures', mainBuffer);
3003 // Now that we have emitted all classes, we know all the bound 2988 // Now that we have emitted all classes, we know all the bound
3004 // closures that will be needed. 2989 // closures that will be needed.
3005 for (jsAst.Node node in boundClosures) { 2990 for (jsAst.Node node in boundClosures) {
3006 // TODO(ahe): Some of these can be deferred. 2991 // TODO(ahe): Some of these can be deferred.
3007 mainBuffer.add(jsAst.prettyPrint(node, compiler)); 2992 mainBuffer.add(jsAst.prettyPrint(node, compiler));
3008 mainBuffer.add("$N$n"); 2993 mainBuffer.add("$N$n");
3009 } 2994 }
3010 2995
(...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after
3253 functions.push(property); 3238 functions.push(property);
3254 } else { 3239 } else {
3255 $$[property] = element; 3240 $$[property] = element;
3256 classes.push(property); 3241 classes.push(property);
3257 classes.push(element[""]); 3242 classes.push(element[""]);
3258 } 3243 }
3259 } 3244 }
3260 libraries.push([name, uri, classes, functions]); 3245 libraries.push([name, uri, classes, functions]);
3261 } 3246 }
3262 })'''; 3247 })''';
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698