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

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 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
1845 buffer.write(jsAst.prettyPrint(assignment, compiler)); 1823 buffer.write(jsAst.prettyPrint(assignment, compiler));
1846 buffer.write('$N'); 1824 buffer.write('$N');
1847 } 1825 }
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)) {
1833 assert(instantiatedClasses.contains(compiler.closureClass));
1855 String staticName = namer.getName(element); 1834 String staticName = namer.getName(element);
1856 String superName = namer.getName(compiler.closureClass); 1835 String superName = namer.getName(compiler.closureClass);
1857 String name = 'Closure\$${element.name.slowToString()}'; 1836 String name = 'Closure\$${element.name.slowToString()}';
1858 needsClosureClass = true;
1859 1837
1860 ClassElement closureClassElement = new ClosureClassElement( 1838 ClassElement closureClassElement = new ClosureClassElement(
1861 null, new SourceString(name), compiler, element, 1839 null, new SourceString(name), compiler, element,
1862 element.getCompilationUnit()); 1840 element.getCompilationUnit());
1863 // Now add the methods on the closure class. The instance method does not 1841 // 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 1842 // have the correct name. Since [addParameterStubs] use the name to create
1865 // its stubs we simply create a fake element with the correct name. 1843 // its stubs we simply create a fake element with the correct name.
1866 // Note: the callElement will not have any enclosingElement. 1844 // Note: the callElement will not have any enclosingElement.
1867 FunctionElement callElement = 1845 FunctionElement callElement =
1868 new ClosureInvocationElement(namer.closureInvocationSelectorName, 1846 new ClosureInvocationElement(namer.closureInvocationSelectorName,
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
1907 js.string("$superName;${fieldNames.join(',')}")); 1885 js.string("$superName;${fieldNames.join(',')}"));
1908 } 1886 }
1909 1887
1910 /** 1888 /**
1911 * Documentation wanted -- johnniwinther 1889 * Documentation wanted -- johnniwinther
1912 * 1890 *
1913 * Invariant: [member] must be a declaration element. 1891 * Invariant: [member] must be a declaration element.
1914 */ 1892 */
1915 void emitDynamicFunctionGetter(FunctionElement member, 1893 void emitDynamicFunctionGetter(FunctionElement member,
1916 DefineStubFunction defineStub) { 1894 DefineStubFunction defineStub) {
1895 assert(instantiatedClasses.contains(compiler.boundClosureClass));
1917 assert(invariant(member, member.isDeclaration)); 1896 assert(invariant(member, member.isDeclaration));
1918 // For every method that has the same name as a property-get we create a 1897 // 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 1898 // 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 1899 // '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): 1900 // 'foo'. Then we generate the following code (in pseudo Dart/JavaScript):
1922 // 1901 //
1923 // class A { 1902 // class A {
1924 // foo(x, y, z) { ... } // Original function. 1903 // foo(x, y, z) { ... } // Original function.
1925 // get foo { return new BoundClosure499(this, "foo"); } 1904 // get foo { return new BoundClosure499(this, "foo"); }
1926 // } 1905 // }
1927 // class BoundClosure499 extends Closure { 1906 // class BoundClosure499 extends BoundClosure {
1928 // var self; 1907 // BoundClosure499(this.self, this.target);
1929 // BoundClosure499(this.self, this.name); 1908 // $call3(x, y, z) { return self[target](x, y, z); }
1930 // $call3(x, y, z) { return self[name](x, y, z); }
1931 // } 1909 // }
1932 1910
1933 // TODO(floitsch): share the closure classes with other classes 1911 // TODO(floitsch): share the closure classes with other classes
1934 // if they share methods with the same signature. Currently we do this only 1912 // if they share methods with the same signature. Currently we do this only
1935 // if there are no optional parameters. Closures with optional parameters 1913 // if there are no optional parameters. Closures with optional parameters
1936 // are more difficult to canonicalize because they would need to have the 1914 // are more difficult to canonicalize because they would need to have the
1937 // same default values. 1915 // same default values.
1938 1916
1939 bool hasOptionalParameters = member.optionalParameterCount(compiler) != 0; 1917 bool hasOptionalParameters = member.optionalParameterCount(compiler) != 0;
1940 int parameterCount = member.parameterCount(compiler); 1918 int parameterCount = member.parameterCount(compiler);
1941 1919
1942 Map<int, String> cache; 1920 Map<int, String> cache = boundClosureCache;
1943 String extraArg = null;
1944 // Intercepted methods take an extra parameter, which is the 1921 // Intercepted methods take an extra parameter, which is the
1945 // receiver of the call. 1922 // receiver of the call.
1946 bool inInterceptor = backend.isInterceptedMethod(member); 1923 bool inInterceptor = backend.isInterceptedMethod(member);
1947 if (inInterceptor) { 1924 List<String> fieldNames = <String>[];
1948 cache = interceptorClosureCache; 1925 compiler.boundClosureClass.forEachInstanceField((_, field) {
1949 extraArg = 'receiver'; 1926 fieldNames.add(namer.getName(field));
1950 } else { 1927 });
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 1928
1959 Iterable<Element> typedefChecks = 1929 Iterable<Element> typedefChecks =
1960 getTypedefChecksOn(member.computeType(compiler)); 1930 getTypedefChecksOn(member.computeType(compiler));
1961 bool hasTypedefChecks = !typedefChecks.isEmpty; 1931 bool hasTypedefChecks = !typedefChecks.isEmpty;
1962 1932
1963 bool canBeShared = !hasOptionalParameters && !hasTypedefChecks; 1933 bool canBeShared = !hasOptionalParameters && !hasTypedefChecks;
1964 1934
1965 String closureClass = canBeShared ? cache[parameterCount] : null; 1935 String closureClass = canBeShared ? cache[parameterCount] : null;
1966 if (closureClass == null) { 1936 if (closureClass == null) {
1967 // Either the class was not cached yet, or there are optional parameters. 1937 // Either the class was not cached yet, or there are optional parameters.
1968 // Create a new closure class. 1938 // Create a new closure class.
1969 String name; 1939 String name;
1970 if (canBeShared) { 1940 if (canBeShared) {
1971 if (inInterceptor) { 1941 name = 'BoundClosure\$${parameterCount}';
1972 name = 'BoundClosure\$i${parameterCount}';
1973 } else {
1974 name = 'BoundClosure\$${parameterCount}';
1975 }
1976 } else { 1942 } else {
1977 name = 'Bound_${member.name.slowToString()}' 1943 name = 'Bound_${member.name.slowToString()}'
1978 '_${member.enclosingElement.name.slowToString()}'; 1944 '_${member.enclosingElement.name.slowToString()}';
1979 } 1945 }
1980 1946
1981 ClassElement closureClassElement = new ClosureClassElement( 1947 ClassElement closureClassElement = new ClosureClassElement(
1982 null, new SourceString(name), compiler, member, 1948 null, new SourceString(name), compiler, member,
1983 member.getCompilationUnit()); 1949 member.getCompilationUnit());
1984 String mangledName = namer.getName(closureClassElement); 1950 String mangledName = namer.getName(closureClassElement);
1985 String superName = namer.getName(closureClassElement.superclass); 1951 String superName = namer.getName(closureClassElement.superclass);
1986 needsClosureClass = true;
1987 1952
1988 // Define the constructor with a name so that Object.toString can 1953 // Define the constructor with a name so that Object.toString can
1989 // find the class name of the closure class. 1954 // find the class name of the closure class.
1990 ClassBuilder boundClosureBuilder = new ClassBuilder(); 1955 ClassBuilder boundClosureBuilder = new ClassBuilder();
1991 emitBoundClosureClassHeader( 1956 emitBoundClosureClassHeader(
1992 mangledName, superName, fieldNames, boundClosureBuilder); 1957 mangledName, superName, fieldNames, boundClosureBuilder);
1993 // Now add the methods on the closure class. The instance method does not 1958 // 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 1959 // have the correct name. Since [addParameterStubs] use the name to create
1995 // its stubs we simply create a fake element with the correct name. 1960 // its stubs we simply create a fake element with the correct name.
1996 // Note: the callElement will not have any enclosingElement. 1961 // Note: the callElement will not have any enclosingElement.
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
2037 2002
2038 // And finally the getter. 2003 // And finally the getter.
2039 String getterName = namer.getterName(member); 2004 String getterName = namer.getterName(member);
2040 String targetName = namer.instanceMethodName(member); 2005 String targetName = namer.instanceMethodName(member);
2041 2006
2042 List<String> parameters = <String>[]; 2007 List<String> parameters = <String>[];
2043 List<jsAst.Expression> arguments = <jsAst.Expression>[]; 2008 List<jsAst.Expression> arguments = <jsAst.Expression>[];
2044 arguments.add(js('this')); 2009 arguments.add(js('this'));
2045 arguments.add(js.string(targetName)); 2010 arguments.add(js.string(targetName));
2046 if (inInterceptor) { 2011 if (inInterceptor) {
2047 parameters.add(extraArg); 2012 parameters.add('receiver');
2048 arguments.add(js(extraArg)); 2013 arguments.add(js('receiver'));
2049 } 2014 }
2050 2015
2051 jsAst.Expression getterFunction = js.fun( 2016 jsAst.Expression getterFunction = js.fun(
2052 parameters, 2017 parameters,
2053 js.return_(js(closureClass).newWith(arguments))); 2018 js.return_(js(closureClass).newWith(arguments)));
2054 2019
2055 defineStub(getterName, getterFunction); 2020 defineStub(getterName, getterFunction);
2056 } 2021 }
2057 2022
2058 /** 2023 /**
(...skipping 931 matching lines...) Expand 10 before | Expand all | Expand 10 after
2990 nativeEmitter.assembleCode(nativeBuffer); 2955 nativeEmitter.assembleCode(nativeBuffer);
2991 2956
2992 // Might create boundClosures. 2957 // Might create boundClosures.
2993 if (!deferredClasses.isEmpty) { 2958 if (!deferredClasses.isEmpty) {
2994 for (ClassElement element in deferredClasses) { 2959 for (ClassElement element in deferredClasses) {
2995 generateClass(element, bufferForElement(element, mainBuffer)); 2960 generateClass(element, bufferForElement(element, mainBuffer));
2996 } 2961 }
2997 } 2962 }
2998 2963
2999 emitStaticFunctionClosures(); 2964 emitStaticFunctionClosures();
3000 emitClosureClassIfNeeded(mainBuffer);
3001 2965
3002 addComment('Bound closures', mainBuffer); 2966 addComment('Bound closures', mainBuffer);
3003 // Now that we have emitted all classes, we know all the bound 2967 // Now that we have emitted all classes, we know all the bound
3004 // closures that will be needed. 2968 // closures that will be needed.
3005 for (jsAst.Node node in boundClosures) { 2969 for (jsAst.Node node in boundClosures) {
3006 // TODO(ahe): Some of these can be deferred. 2970 // TODO(ahe): Some of these can be deferred.
3007 mainBuffer.add(jsAst.prettyPrint(node, compiler)); 2971 mainBuffer.add(jsAst.prettyPrint(node, compiler));
3008 mainBuffer.add("$N$n"); 2972 mainBuffer.add("$N$n");
3009 } 2973 }
3010 2974
(...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after
3251 functions.push(property); 3215 functions.push(property);
3252 } else { 3216 } else {
3253 $$[property] = element; 3217 $$[property] = element;
3254 classes.push(property); 3218 classes.push(property);
3255 classes.push(element[""]); 3219 classes.push(element[""]);
3256 } 3220 }
3257 } 3221 }
3258 libraries.push([name, uri, classes, functions]); 3222 libraries.push([name, uri, classes, functions]);
3259 } 3223 }
3260 })'''; 3224 })''';
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698