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

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

Issue 16042014: 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 15 matching lines...) Expand all
87 String get N => compiler.enableMinification ? "\n" : ";\n"; 86 String get N => compiler.enableMinification ? "\n" : ";\n";
88 87
89 /** 88 /**
90 * A cache of closures that are used to closurize instance methods. 89 * A cache of closures that are used to closurize instance methods.
91 * A closure is dynamically bound to the instance used when 90 * A closure is dynamically bound to the instance used when
92 * closurized. 91 * closurized.
93 */ 92 */
94 final Map<int, String> boundClosureCache; 93 final Map<int, String> boundClosureCache;
95 94
96 /** 95 /**
97 * A cache of closures that are used to closurize instance methods
98 * of interceptors. These closures are dynamically bound to the
99 * interceptor instance, and the actual receiver of the method.
100 */
101 final Map<int, String> interceptorClosureCache;
102
103 /**
104 * Raw ClassElement symbols occuring in is-checks and type assertions. If the 96 * Raw ClassElement symbols occuring in is-checks and type assertions. If the
105 * program contains parameterized checks `x is Set<int>` and 97 * program contains parameterized checks `x is Set<int>` and
106 * `x is Set<String>` then the ClassElement `Set` will occur once in 98 * `x is Set<String>` then the ClassElement `Set` will occur once in
107 * [checkedClasses]. 99 * [checkedClasses].
108 */ 100 */
109 Set<ClassElement> checkedClasses; 101 Set<ClassElement> checkedClasses;
110 102
111 /** 103 /**
112 * Raw Typedef symbols occuring in is-checks and type assertions. If the 104 * Raw Typedef symbols occuring in is-checks and type assertions. If the
113 * program contains `x is F<int>` and `x is F<bool>` then the TypedefElement 105 * program contains `x is F<int>` and `x is F<bool>` then the TypedefElement
(...skipping 12 matching lines...) Expand all
126 .map((TypeVariableType v) => v.element.getEnclosingClass()) 118 .map((TypeVariableType v) => v.element.getEnclosingClass())
127 .toList(); 119 .toList();
128 } 120 }
129 return cachedClassesUsingTypeVariableTests; 121 return cachedClassesUsingTypeVariableTests;
130 } 122 }
131 123
132 CodeEmitterTask(Compiler compiler, Namer namer, this.generateSourceMap) 124 CodeEmitterTask(Compiler compiler, Namer namer, this.generateSourceMap)
133 : mainBuffer = new CodeBuffer(), 125 : mainBuffer = new CodeBuffer(),
134 this.namer = namer, 126 this.namer = namer,
135 boundClosureCache = new Map<int, String>(), 127 boundClosureCache = new Map<int, String>(),
136 interceptorClosureCache = new Map<int, String>(),
137 constantEmitter = new ConstantEmitter(compiler, namer), 128 constantEmitter = new ConstantEmitter(compiler, namer),
138 super(compiler) { 129 super(compiler) {
139 nativeEmitter = new NativeEmitter(this); 130 nativeEmitter = new NativeEmitter(this);
140 } 131 }
141 132
142 void addComment(String comment, CodeBuffer buffer) { 133 void addComment(String comment, CodeBuffer buffer) {
143 buffer.write(jsAst.prettyPrint(js.comment(comment), compiler)); 134 buffer.write(jsAst.prettyPrint(js.comment(comment), compiler));
144 } 135 }
145 136
146 void computeRequiredTypeChecks() { 137 void computeRequiredTypeChecks() {
(...skipping 1602 matching lines...) Expand 10 before | Expand all | Expand 10 after
1749 for (ClassElement interceptor in backend.interceptedClasses) { 1740 for (ClassElement interceptor in backend.interceptedClasses) {
1750 if (!needed.contains(interceptor) 1741 if (!needed.contains(interceptor)
1751 && interceptor != compiler.objectClass) { 1742 && interceptor != compiler.objectClass) {
1752 unneededClasses.add(interceptor); 1743 unneededClasses.add(interceptor);
1753 } 1744 }
1754 } 1745 }
1755 1746
1756 return (ClassElement cls) => !unneededClasses.contains(cls); 1747 return (ClassElement cls) => !unneededClasses.contains(cls);
1757 } 1748 }
1758 1749
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) { 1750 void emitFinishClassesInvocationIfNecessary(CodeBuffer buffer) {
1773 if (needsDefineClass) { 1751 if (needsDefineClass) {
1774 buffer.write('$finishClassesName($classesCollector,' 1752 buffer.write('$finishClassesName($classesCollector,'
1775 '$_$isolateProperties,' 1753 '$_$isolateProperties,'
1776 '${_}null)$N'); 1754 '${_}null)$N');
1777 1755
1778 // Reset the map. 1756 // Reset the map.
1779 buffer.write("$classesCollector$_=${_}null$N$n"); 1757 buffer.write("$classesCollector$_=${_}null$N$n");
1780 } 1758 }
1781 } 1759 }
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
1848 } 1826 }
1849 1827
1850 void emitStaticFunctionClosures() { 1828 void emitStaticFunctionClosures() {
1851 Set<FunctionElement> functionsNeedingGetter = 1829 Set<FunctionElement> functionsNeedingGetter =
1852 compiler.codegenWorld.staticFunctionsNeedingGetter; 1830 compiler.codegenWorld.staticFunctionsNeedingGetter;
1853 for (FunctionElement element in 1831 for (FunctionElement element in
1854 Elements.sortedByPosition(functionsNeedingGetter)) { 1832 Elements.sortedByPosition(functionsNeedingGetter)) {
1855 String staticName = namer.getName(element); 1833 String staticName = namer.getName(element);
1856 String superName = namer.getName(compiler.closureClass); 1834 String superName = namer.getName(compiler.closureClass);
1857 String name = 'Closure\$${element.name.slowToString()}'; 1835 String name = 'Closure\$${element.name.slowToString()}';
1858 needsClosureClass = true;
1859 1836
1860 ClassElement closureClassElement = new ClosureClassElement( 1837 ClassElement closureClassElement = new ClosureClassElement(
1861 null, new SourceString(name), compiler, element, 1838 null, new SourceString(name), compiler, element,
1862 element.getCompilationUnit()); 1839 element.getCompilationUnit());
1863 // Now add the methods on the closure class. The instance method does not 1840 // 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 1841 // have the correct name. Since [addParameterStubs] use the name to create
1865 // its stubs we simply create a fake element with the correct name. 1842 // its stubs we simply create a fake element with the correct name.
1866 // Note: the callElement will not have any enclosingElement. 1843 // Note: the callElement will not have any enclosingElement.
1867 FunctionElement callElement = 1844 FunctionElement callElement =
1868 new ClosureInvocationElement(namer.closureInvocationSelectorName, 1845 new ClosureInvocationElement(namer.closureInvocationSelectorName,
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
1917 assert(invariant(member, member.isDeclaration)); 1894 assert(invariant(member, member.isDeclaration));
1918 // For every method that has the same name as a property-get we create a 1895 // 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 1896 // 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 1897 // '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): 1898 // 'foo'. Then we generate the following code (in pseudo Dart/JavaScript):
1922 // 1899 //
1923 // class A { 1900 // class A {
1924 // foo(x, y, z) { ... } // Original function. 1901 // foo(x, y, z) { ... } // Original function.
1925 // get foo { return new BoundClosure499(this, "foo"); } 1902 // get foo { return new BoundClosure499(this, "foo"); }
1926 // } 1903 // }
1927 // class BoundClosure499 extends Closure { 1904 // class BoundClosure499 extends BoundClosure {
1928 // var self; 1905 // BoundClosure499(this.self, this.target);
1929 // BoundClosure499(this.self, this.name); 1906 // $call3(x, y, z) { return self[target](x, y, z); }
1930 // $call3(x, y, z) { return self[name](x, y, z); }
1931 // } 1907 // }
1932 1908
1933 // TODO(floitsch): share the closure classes with other classes 1909 // TODO(floitsch): share the closure classes with other classes
1934 // if they share methods with the same signature. Currently we do this only 1910 // if they share methods with the same signature. Currently we do this only
1935 // if there are no optional parameters. Closures with optional parameters 1911 // if there are no optional parameters. Closures with optional parameters
1936 // are more difficult to canonicalize because they would need to have the 1912 // are more difficult to canonicalize because they would need to have the
1937 // same default values. 1913 // same default values.
1938 1914
1939 bool hasOptionalParameters = member.optionalParameterCount(compiler) != 0; 1915 bool hasOptionalParameters = member.optionalParameterCount(compiler) != 0;
1940 int parameterCount = member.parameterCount(compiler); 1916 int parameterCount = member.parameterCount(compiler);
1941 1917
1942 Map<int, String> cache; 1918 Map<int, String> cache = boundClosureCache;
1943 String extraArg = null;
1944 // Intercepted methods take an extra parameter, which is the 1919 // Intercepted methods take an extra parameter, which is the
1945 // receiver of the call. 1920 // receiver of the call.
1946 bool inInterceptor = backend.isInterceptedMethod(member); 1921 bool inInterceptor = backend.isInterceptedMethod(member);
1947 if (inInterceptor) { 1922 List<String> fieldNames = <String>[];
1948 cache = interceptorClosureCache; 1923 compiler.boundClosureClass.forEachInstanceField((_, field) {
1949 extraArg = 'receiver'; 1924 fieldNames.add(namer.getName(field));
1950 } else { 1925 });
1951 cache = boundClosureCache;
1952 }
1953 List<String> fieldNames = compiler.enableMinification
1954 ? inInterceptor ? const ['a', 'b', 'c']
1955 : const ['a', 'b']
1956 : inInterceptor ? const ['self', 'target', 'receiver']
1957 : const ['self', 'target'];
1958 1926
1959 Iterable<Element> typedefChecks = 1927 Iterable<Element> typedefChecks =
1960 getTypedefChecksOn(member.computeType(compiler)); 1928 getTypedefChecksOn(member.computeType(compiler));
1961 bool hasTypedefChecks = !typedefChecks.isEmpty; 1929 bool hasTypedefChecks = !typedefChecks.isEmpty;
1962 1930
1963 bool canBeShared = !hasOptionalParameters && !hasTypedefChecks; 1931 bool canBeShared = !hasOptionalParameters && !hasTypedefChecks;
1964 1932
1965 String closureClass = canBeShared ? cache[parameterCount] : null; 1933 String closureClass = canBeShared ? cache[parameterCount] : null;
1966 if (closureClass == null) { 1934 if (closureClass == null) {
1967 // Either the class was not cached yet, or there are optional parameters. 1935 // Either the class was not cached yet, or there are optional parameters.
1968 // Create a new closure class. 1936 // Create a new closure class.
1969 String name; 1937 String name;
1970 if (canBeShared) { 1938 if (canBeShared) {
1971 if (inInterceptor) { 1939 name = 'BoundClosure\$${parameterCount}';
1972 name = 'BoundClosure\$i${parameterCount}';
1973 } else {
1974 name = 'BoundClosure\$${parameterCount}';
1975 }
1976 } else { 1940 } else {
1977 name = 'Bound_${member.name.slowToString()}' 1941 name = 'Bound_${member.name.slowToString()}'
1978 '_${member.enclosingElement.name.slowToString()}'; 1942 '_${member.enclosingElement.name.slowToString()}';
1979 } 1943 }
1980 1944
1981 ClassElement closureClassElement = new ClosureClassElement( 1945 ClassElement closureClassElement = new ClosureClassElement(
1982 null, new SourceString(name), compiler, member, 1946 null, new SourceString(name), compiler, member,
1983 member.getCompilationUnit()); 1947 member.getCompilationUnit());
1984 String mangledName = namer.getName(closureClassElement); 1948 String mangledName = namer.getName(closureClassElement);
1985 String superName = namer.getName(closureClassElement.superclass); 1949 String superName = namer.getName(closureClassElement.superclass);
1986 needsClosureClass = true;
1987 1950
1988 // Define the constructor with a name so that Object.toString can 1951 // Define the constructor with a name so that Object.toString can
1989 // find the class name of the closure class. 1952 // find the class name of the closure class.
1990 ClassBuilder boundClosureBuilder = new ClassBuilder(); 1953 ClassBuilder boundClosureBuilder = new ClassBuilder();
1991 emitBoundClosureClassHeader( 1954 emitBoundClosureClassHeader(
1992 mangledName, superName, fieldNames, boundClosureBuilder); 1955 mangledName, superName, fieldNames, boundClosureBuilder);
1993 // Now add the methods on the closure class. The instance method does not 1956 // 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 1957 // have the correct name. Since [addParameterStubs] use the name to create
1995 // its stubs we simply create a fake element with the correct name. 1958 // its stubs we simply create a fake element with the correct name.
1996 // Note: the callElement will not have any enclosingElement. 1959 // Note: the callElement will not have any enclosingElement.
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
2037 2000
2038 // And finally the getter. 2001 // And finally the getter.
2039 String getterName = namer.getterName(member); 2002 String getterName = namer.getterName(member);
2040 String targetName = namer.instanceMethodName(member); 2003 String targetName = namer.instanceMethodName(member);
2041 2004
2042 List<String> parameters = <String>[]; 2005 List<String> parameters = <String>[];
2043 List<jsAst.Expression> arguments = <jsAst.Expression>[]; 2006 List<jsAst.Expression> arguments = <jsAst.Expression>[];
2044 arguments.add(js('this')); 2007 arguments.add(js('this'));
2045 arguments.add(js.string(targetName)); 2008 arguments.add(js.string(targetName));
2046 if (inInterceptor) { 2009 if (inInterceptor) {
2047 parameters.add(extraArg); 2010 parameters.add('receiver');
2048 arguments.add(js(extraArg)); 2011 arguments.add(js('receiver'));
2049 } 2012 }
2050 2013
2051 jsAst.Expression getterFunction = js.fun( 2014 jsAst.Expression getterFunction = js.fun(
2052 parameters, 2015 parameters,
2053 js.return_(js(closureClass).newWith(arguments))); 2016 js.return_(js(closureClass).newWith(arguments)));
2054 2017
2055 defineStub(getterName, getterFunction); 2018 defineStub(getterName, getterFunction);
2056 } 2019 }
2057 2020
2058 /** 2021 /**
(...skipping 931 matching lines...) Expand 10 before | Expand all | Expand 10 after
2990 nativeEmitter.assembleCode(nativeBuffer); 2953 nativeEmitter.assembleCode(nativeBuffer);
2991 2954
2992 // Might create boundClosures. 2955 // Might create boundClosures.
2993 if (!deferredClasses.isEmpty) { 2956 if (!deferredClasses.isEmpty) {
2994 for (ClassElement element in deferredClasses) { 2957 for (ClassElement element in deferredClasses) {
2995 generateClass(element, bufferForElement(element, mainBuffer)); 2958 generateClass(element, bufferForElement(element, mainBuffer));
2996 } 2959 }
2997 } 2960 }
2998 2961
2999 emitStaticFunctionClosures(); 2962 emitStaticFunctionClosures();
3000 emitClosureClassIfNeeded(mainBuffer);
3001 2963
3002 addComment('Bound closures', mainBuffer); 2964 addComment('Bound closures', mainBuffer);
3003 // Now that we have emitted all classes, we know all the bound 2965 // Now that we have emitted all classes, we know all the bound
3004 // closures that will be needed. 2966 // closures that will be needed.
3005 for (jsAst.Node node in boundClosures) { 2967 for (jsAst.Node node in boundClosures) {
3006 // TODO(ahe): Some of these can be deferred. 2968 // TODO(ahe): Some of these can be deferred.
3007 mainBuffer.add(jsAst.prettyPrint(node, compiler)); 2969 mainBuffer.add(jsAst.prettyPrint(node, compiler));
3008 mainBuffer.add("$N$n"); 2970 mainBuffer.add("$N$n");
3009 } 2971 }
3010 2972
(...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after
3251 functions.push(property); 3213 functions.push(property);
3252 } else { 3214 } else {
3253 $$[property] = element; 3215 $$[property] = element;
3254 classes.push(property); 3216 classes.push(property);
3255 classes.push(element[""]); 3217 classes.push(element[""]);
3256 } 3218 }
3257 } 3219 }
3258 libraries.push([name, uri, classes, functions]); 3220 libraries.push([name, uri, classes, functions]);
3259 } 3221 }
3260 })'''; 3222 })''';
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698