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

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

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

Powered by Google App Engine
This is Rietveld 408576698