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 30 matching lines...) Expand all Loading... |
41 CodeBuffer boundClosureBuffer; | 41 CodeBuffer boundClosureBuffer; |
42 CodeBuffer mainBuffer; | 42 CodeBuffer mainBuffer; |
43 /** Shorter access to [isolatePropertiesName]. Both here in the code, as | 43 /** Shorter access to [isolatePropertiesName]. Both here in the code, as |
44 well as in the generated code. */ | 44 well as in the generated code. */ |
45 String isolateProperties; | 45 String isolateProperties; |
46 String classesCollector; | 46 String classesCollector; |
47 Set<ClassElement> neededClasses; | 47 Set<ClassElement> neededClasses; |
48 // TODO(ngeoffray): remove this field. | 48 // TODO(ngeoffray): remove this field. |
49 Set<ClassElement> instantiatedClasses; | 49 Set<ClassElement> instantiatedClasses; |
50 | 50 |
| 51 List<js.Expression> libraryMirrorsParametersList; |
| 52 Map<String, int> libraryMirrorsIndices; |
| 53 |
51 String get _ => compiler.enableMinification ? "" : " "; | 54 String get _ => compiler.enableMinification ? "" : " "; |
52 String get n => compiler.enableMinification ? "" : "\n"; | 55 String get n => compiler.enableMinification ? "" : "\n"; |
53 String get N => compiler.enableMinification ? "\n" : ";\n"; | 56 String get N => compiler.enableMinification ? "\n" : ";\n"; |
54 | 57 |
55 /** | 58 /** |
56 * A cache of closures that are used to closurize instance methods. | 59 * A cache of closures that are used to closurize instance methods. |
57 * A closure is dynamically bound to the instance used when | 60 * A closure is dynamically bound to the instance used when |
58 * closurized. | 61 * closurized. |
59 */ | 62 */ |
60 final Map<int, String> boundClosureCache; | 63 final Map<int, String> boundClosureCache; |
(...skipping 962 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1023 generateGetter(member, name, accessorName, buffer); | 1026 generateGetter(member, name, accessorName, buffer); |
1024 } | 1027 } |
1025 if (needsSetter) { | 1028 if (needsSetter) { |
1026 emitComma(); | 1029 emitComma(); |
1027 generateSetter(member, name, accessorName, buffer); | 1030 generateSetter(member, name, accessorName, buffer); |
1028 } | 1031 } |
1029 } | 1032 } |
1030 }); | 1033 }); |
1031 } | 1034 } |
1032 | 1035 |
| 1036 void emitClassLibraryGetter(ClassElement classElement, CodeBuffer buffer) { |
| 1037 var name = classElement.getLibrary().getLibraryOrScriptName(); |
| 1038 // Some builtin classes come from js_helper libraries, which are |
| 1039 // not in libraryMirrorsIndices collection. At this point we |
| 1040 // will ignore them. |
| 1041 if (libraryMirrorsIndices.containsKey(name)) { |
| 1042 buffer.add(",$n$_${_}builtin\$library:$_${libraryMirrorsIndices[name]}"); |
| 1043 } |
| 1044 } |
| 1045 |
1033 /** | 1046 /** |
1034 * Documentation wanted -- johnniwinther | 1047 * Documentation wanted -- johnniwinther |
1035 * | 1048 * |
1036 * Invariant: [classElement] must be a declaration element. | 1049 * Invariant: [classElement] must be a declaration element. |
1037 */ | 1050 */ |
1038 void generateClass(ClassElement classElement, CodeBuffer buffer) { | 1051 void generateClass(ClassElement classElement, CodeBuffer buffer) { |
1039 assert(invariant(classElement, classElement.isDeclaration)); | 1052 assert(invariant(classElement, classElement.isDeclaration)); |
1040 if (classElement.isNative()) { | 1053 if (classElement.isNative()) { |
1041 nativeEmitter.generateNativeClass(classElement); | 1054 nativeEmitter.generateNativeClass(classElement); |
1042 return; | 1055 return; |
(...skipping 15 matching lines...) Expand all Loading... |
1058 buffer.add('$classesCollector.$className$_=$_{'); | 1071 buffer.add('$classesCollector.$className$_=$_{'); |
1059 emitClassConstructor(classElement, buffer); | 1072 emitClassConstructor(classElement, buffer); |
1060 emitSuper(superName, buffer); | 1073 emitSuper(superName, buffer); |
1061 emitClassFields(classElement, buffer, false, | 1074 emitClassFields(classElement, buffer, false, |
1062 superClass: superName, classIsNative: false); | 1075 superClass: superName, classIsNative: false); |
1063 // TODO(floitsch): the emitInstanceMember should simply always emit a ',\n'. | 1076 // TODO(floitsch): the emitInstanceMember should simply always emit a ',\n'. |
1064 // That does currently not work because the native classes have a different | 1077 // That does currently not work because the native classes have a different |
1065 // syntax. | 1078 // syntax. |
1066 emitClassGettersSetters(classElement, buffer, true); | 1079 emitClassGettersSetters(classElement, buffer, true); |
1067 emitInstanceMembers(classElement, buffer, true); | 1080 emitInstanceMembers(classElement, buffer, true); |
| 1081 if (compiler.hasMirrorsSupport()) { |
| 1082 emitClassLibraryGetter(classElement, buffer); |
| 1083 } |
1068 buffer.add('$n}$N$n'); | 1084 buffer.add('$n}$N$n'); |
1069 } | 1085 } |
1070 | 1086 |
1071 bool get getterAndSetterCanBeImplementedByFieldSpec => true; | 1087 bool get getterAndSetterCanBeImplementedByFieldSpec => true; |
1072 | 1088 |
1073 void emitInterceptorMethods( | 1089 void emitInterceptorMethods( |
1074 void defineInstanceMember(String name, StringBuffer memberBuffer)) { | 1090 void defineInstanceMember(String name, StringBuffer memberBuffer)) { |
1075 JavaScriptBackend backend = compiler.backend; | 1091 JavaScriptBackend backend = compiler.backend; |
1076 // Emit forwarders for the ObjectInterceptor class. We need to | 1092 // Emit forwarders for the ObjectInterceptor class. We need to |
1077 // emit all possible sends on intercepted methods. | 1093 // emit all possible sends on intercepted methods. |
(...skipping 1022 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2100 for (ClassElement element in instantiatedClasses) { | 2116 for (ClassElement element in instantiatedClasses) { |
2101 for (ClassElement superclass = element.superclass; | 2117 for (ClassElement superclass = element.superclass; |
2102 superclass != null; | 2118 superclass != null; |
2103 superclass = superclass.superclass) { | 2119 superclass = superclass.superclass) { |
2104 if (neededClasses.contains(superclass)) break; | 2120 if (neededClasses.contains(superclass)) break; |
2105 neededClasses.add(superclass); | 2121 neededClasses.add(superclass); |
2106 } | 2122 } |
2107 } | 2123 } |
2108 } | 2124 } |
2109 | 2125 |
| 2126 Collection<js.Expression> extract(listElements, filterToApply) { |
| 2127 return new js.ArrayInitializer.from( |
| 2128 listElements |
| 2129 .filter(filterToApply) |
| 2130 .map((member) => js.string(namer.getName(member)))); |
| 2131 } |
| 2132 |
| 2133 Collection extractClasses(listElements) { |
| 2134 var classDescriptions = []; |
| 2135 var classes = listElements.filter((e) => Elements.isClass(e)); |
| 2136 for (Element classElement in classes) { |
| 2137 var classMembers = []; |
| 2138 for (var classMember in classElement.localMembers) { |
| 2139 var prefixType; |
| 2140 var name; |
| 2141 if (classMember.isGetter()) { |
| 2142 prefixType = 'G'; |
| 2143 name = qualifiedFunctionName(classMember); |
| 2144 } else if (classMember.isSetter()) { |
| 2145 prefixType = 'S'; |
| 2146 name = qualifiedFunctionName(classMember); |
| 2147 } else if (classMember.isField()) { |
| 2148 prefixType = 'V'; |
| 2149 name = qualifiedVariableName(classMember); |
| 2150 } else if (classMember.isConstructor()) { |
| 2151 prefixType = 'C'; |
| 2152 name = namer.getName(classMember); |
| 2153 } else if (classMember.isTypeVariable()) { |
| 2154 prefixType = 'T'; |
| 2155 name = namer.getName(classMember); |
| 2156 } else if (classMember.isParameter()) { |
| 2157 prefixType = 'A'; |
| 2158 name = namer.getName(classMember); |
| 2159 } else { |
| 2160 prefixType = 'M'; |
| 2161 name = qualifiedFunctionName(classMember); |
| 2162 } |
| 2163 var originalName = classMember.name.slowToString(); |
| 2164 if (name != originalName) { |
| 2165 name = "$name[$originalName]"; |
| 2166 } |
| 2167 classMembers.add(js.string("$prefixType:$name")); |
| 2168 } |
| 2169 classDescriptions.add( |
| 2170 new js.ArrayInitializer.from( |
| 2171 [js.string(namer.getName(classElement)), |
| 2172 new js.ArrayInitializer.from(classMembers)])); |
| 2173 } |
| 2174 return new js.ArrayInitializer.from(classDescriptions); |
| 2175 } |
| 2176 |
| 2177 String qualifiedFunctionName(Element functionElement) { |
| 2178 String prefixType; |
| 2179 if (functionElement.modifiers.isStatic()) { |
| 2180 prefixType = 'S'; |
| 2181 } else { |
| 2182 prefixType = 'I'; |
| 2183 } |
| 2184 var typeName = ""; |
| 2185 var libraryID = ""; |
| 2186 assert(functionElement.type != null); |
| 2187 DartType dt = functionElement.type; |
| 2188 // Ignore types that weren't computed. |
| 2189 if (dt != null) { |
| 2190 if (dt.kind == TypeKind.FUNCTION) { |
| 2191 typeName = dt.returnType.name.slowToString(); |
| 2192 if (typeName == 'void' || typeName == 'dynamic') { |
| 2193 libraryID = ""; |
| 2194 } else { |
| 2195 var library = dt.returnType.element.getLibrary(); |
| 2196 var libraryName = library.getLibraryOrScriptName(); |
| 2197 libraryID = libraryMirrorsIndices[libraryName]; |
| 2198 } |
| 2199 } |
| 2200 } |
| 2201 return "$prefixType:$libraryID:$typeName:${namer.getName(functionElement)}"; |
| 2202 } |
| 2203 |
| 2204 Collection extractMethods(listElements, filterToApply) { |
| 2205 var methodsDescription = |
| 2206 listElements |
| 2207 .filter(filterToApply) |
| 2208 .map((e) => js.string(qualifiedFunctionName(e))); |
| 2209 return new js.ArrayInitializer.from(methodsDescription); |
| 2210 } |
| 2211 |
| 2212 String qualifiedVariableName(Element fieldElement) { |
| 2213 String prefixType; |
| 2214 if (fieldElement.modifiers.isStatic()) { |
| 2215 prefixType = 'S'; |
| 2216 } else { |
| 2217 prefixType = 'I'; |
| 2218 } |
| 2219 // Use case to indicate whether field is final or not. |
| 2220 // Is it too fancy? |
| 2221 if (fieldElement.modifiers.isFinal()) { |
| 2222 prefixType = prefixType.toLowerCase(); |
| 2223 } |
| 2224 var name = namer.getName(fieldElement); |
| 2225 var originalName = fieldElement.name.slowToString(); |
| 2226 if (name != originalName) { |
| 2227 name = "$name[$originalName]"; |
| 2228 } |
| 2229 return "$prefixType:$name"; |
| 2230 } |
| 2231 |
| 2232 Collection extractVariables(listElements) { |
| 2233 var fieldsDescription = |
| 2234 listElements |
| 2235 .filter((e) => e.isField()) |
| 2236 .map((e) => js.string(qualifiedVariableName(e))); |
| 2237 return new js.ArrayInitializer.from(fieldsDescription); |
| 2238 } |
| 2239 |
| 2240 Collection extractClosures(Collection<ClosureClassMap> listClosures) { |
| 2241 var closuresDescriptions = |
| 2242 listClosures.map( |
| 2243 (map) => js.string( |
| 2244 "${namer.getName(map.closureClassElement)}:" |
| 2245 "${namer.getName(map.callElement)}:" |
| 2246 "${map.callElement.functionSignature.requiredParameterCount}:" |
| 2247 "${map.callElement.functionSignature.optionalParameterCount}:")); |
| 2248 return new js.ArrayInitializer.from(closuresDescriptions); |
| 2249 } |
| 2250 |
| 2251 void computeLibraryMirrors() { |
| 2252 int index = 0; |
| 2253 libraryMirrorsParametersList = new List<js.Expression>(); |
| 2254 libraryMirrorsIndices = new Map<String, int>(); |
| 2255 for (LibraryElement libraryElement in compiler.libraries.values) { |
| 2256 // |
| 2257 // [lib1, |
| 2258 // [[class1, classConstructor, [member1,...]] |
| 2259 // ...], |
| 2260 // [function1...], |
| 2261 // [getter1...] |
| 2262 // [setter1...] |
| 2263 // [variable1...] |
| 2264 // [closure1...] |
| 2265 // ]... |
| 2266 // |
| 2267 var elements = |
| 2268 new List<Element>.from(libraryElement.localMembers); |
| 2269 var libraryName = libraryElement.getLibraryOrScriptName(); |
| 2270 libraryMirrorsParametersList.add( |
| 2271 new js.ArrayInitializer.from( |
| 2272 <js.Expression>[ |
| 2273 js.string(libraryName), |
| 2274 extractClasses(elements), |
| 2275 extractMethods(elements, (e) => e.isFunction()), |
| 2276 extractMethods(elements, (e) => e.isGetter()), |
| 2277 extractMethods(elements, (e) => e.isSetter()), |
| 2278 extractVariables(elements), |
| 2279 extractClosures( |
| 2280 new List<ClassElement>.from( |
| 2281 compiler.closureToClassMapper |
| 2282 .closureMappingCache.values |
| 2283 .filter((map) => map.closureElement != null |
| 2284 && map.closureElement.getLibrary() |
| 2285 == libraryElement))) |
| 2286 ])); |
| 2287 libraryMirrorsIndices[libraryName] = index++; |
| 2288 } |
| 2289 } |
| 2290 |
| 2291 void emitMirrorsSupport(CodeBuffer buffer) { |
| 2292 Element createMirrorSystem = |
| 2293 compiler.mirrorsLibrary.find(Compiler.CREATE_MIRROR_SYSTEM); |
| 2294 String isolateCreateMirrorSystem = |
| 2295 namer.isolateAccess(createMirrorSystem); |
| 2296 |
| 2297 // createMirrorSystem([library1, library2, ...]) |
| 2298 var createMirrorSystemCall = |
| 2299 new js.ExpressionStatement( |
| 2300 js.call( |
| 2301 js.use(isolateCreateMirrorSystem), |
| 2302 [new js.ArrayInitializer.from(libraryMirrorsParametersList)])); |
| 2303 mainBuffer.add(js.prettyPrint(createMirrorSystemCall, compiler)); |
| 2304 } |
| 2305 |
2110 String assembleProgram() { | 2306 String assembleProgram() { |
2111 measure(() { | 2307 measure(() { |
2112 computeNeededClasses(); | 2308 computeNeededClasses(); |
| 2309 if (compiler.hasMirrorsSupport()) { |
| 2310 // Create library mirror structure up front so that we can refer to |
| 2311 // library elements during class construction by array index. |
| 2312 computeLibraryMirrors(); |
| 2313 } |
2113 | 2314 |
2114 mainBuffer.add(GENERATED_BY); | 2315 mainBuffer.add(GENERATED_BY); |
2115 if (!compiler.enableMinification) mainBuffer.add(HOOKS_API_USAGE); | 2316 if (!compiler.enableMinification) mainBuffer.add(HOOKS_API_USAGE); |
2116 mainBuffer.add('function ${namer.isolateName}()$_{}\n'); | 2317 mainBuffer.add('function ${namer.isolateName}()$_{}\n'); |
2117 mainBuffer.add('init()$N$n'); | 2318 mainBuffer.add('init()$N$n'); |
2118 // Shorten the code by using "$$" as temporary. | 2319 // Shorten the code by using "$$" as temporary. |
2119 classesCollector = r"$$"; | 2320 classesCollector = r"$$"; |
2120 mainBuffer.add('var $classesCollector$_=$_{}$N'); | 2321 mainBuffer.add('var $classesCollector$_=$_{}$N'); |
2121 // Shorten the code by using [namer.CURRENT_ISOLATE] as temporary. | 2322 // Shorten the code by using [namer.CURRENT_ISOLATE] as temporary. |
2122 isolateProperties = namer.CURRENT_ISOLATE; | 2323 isolateProperties = namer.CURRENT_ISOLATE; |
2123 mainBuffer.add( | 2324 mainBuffer.add( |
2124 'var $isolateProperties$_=$_$isolatePropertiesName$N'); | 2325 'var $isolateProperties$_=$_$isolatePropertiesName$N'); |
2125 emitClasses(mainBuffer); | 2326 emitClasses(mainBuffer); |
2126 mainBuffer.add(boundClosureBuffer); | 2327 mainBuffer.add(boundClosureBuffer); |
2127 // Clear the buffer, so that we can reuse it for the native classes. | 2328 // Clear the buffer, so that we can reuse it for the native classes. |
2128 boundClosureBuffer.clear(); | 2329 boundClosureBuffer.clear(); |
2129 emitStaticFunctions(mainBuffer); | 2330 emitStaticFunctions(mainBuffer); |
2130 emitStaticFunctionGetters(mainBuffer); | 2331 emitStaticFunctionGetters(mainBuffer); |
2131 // We need to finish the classes before we construct compile time | 2332 // We need to finish the classes before we construct compile time |
2132 // constants. | 2333 // constants. |
2133 emitFinishClassesInvocationIfNecessary(mainBuffer); | 2334 emitFinishClassesInvocationIfNecessary(mainBuffer); |
2134 emitRuntimeClassesAndTests(mainBuffer); | 2335 emitRuntimeClassesAndTests(mainBuffer); |
2135 emitCompileTimeConstants(mainBuffer); | 2336 emitCompileTimeConstants(mainBuffer); |
2136 // Static field initializations require the classes and compile-time | 2337 // Static field initializations require the classes and compile-time |
2137 // constants to be set up. | 2338 // constants to be set up. |
2138 emitStaticNonFinalFieldInitializations(mainBuffer); | 2339 emitStaticNonFinalFieldInitializations(mainBuffer); |
2139 emitGetInterceptorMethods(mainBuffer); | 2340 emitGetInterceptorMethods(mainBuffer); |
2140 emitLazilyInitializedStaticFields(mainBuffer); | 2341 emitLazilyInitializedStaticFields(mainBuffer); |
2141 | 2342 |
| 2343 if (compiler.hasMirrorsSupport()) { |
| 2344 emitMirrorsSupport(mainBuffer); |
| 2345 } |
| 2346 |
2142 isolateProperties = isolatePropertiesName; | 2347 isolateProperties = isolatePropertiesName; |
2143 // The following code should not use the short-hand for the | 2348 // The following code should not use the short-hand for the |
2144 // initialStatics. | 2349 // initialStatics. |
2145 mainBuffer.add('var ${namer.CURRENT_ISOLATE}$_=${_}null$N'); | 2350 mainBuffer.add('var ${namer.CURRENT_ISOLATE}$_=${_}null$N'); |
2146 mainBuffer.add(boundClosureBuffer); | 2351 mainBuffer.add(boundClosureBuffer); |
2147 emitFinishClassesInvocationIfNecessary(mainBuffer); | 2352 emitFinishClassesInvocationIfNecessary(mainBuffer); |
2148 // After this assignment we will produce invalid JavaScript code if we use | 2353 // After this assignment we will produce invalid JavaScript code if we use |
2149 // the classesCollector variable. | 2354 // the classesCollector variable. |
2150 classesCollector = 'classesCollector should not be used from now on'; | 2355 classesCollector = 'classesCollector should not be used from now on'; |
2151 | 2356 |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2190 """; | 2395 """; |
2191 const String HOOKS_API_USAGE = """ | 2396 const String HOOKS_API_USAGE = """ |
2192 // The code supports the following hooks: | 2397 // The code supports the following hooks: |
2193 // dartPrint(message) - if this function is defined it is called | 2398 // dartPrint(message) - if this function is defined it is called |
2194 // instead of the Dart [print] method. | 2399 // instead of the Dart [print] method. |
2195 // dartMainRunner(main) - if this function is defined, the Dart [main] | 2400 // dartMainRunner(main) - if this function is defined, the Dart [main] |
2196 // method will not be invoked directly. | 2401 // method will not be invoked directly. |
2197 // Instead, a closure that will invoke [main] is | 2402 // Instead, a closure that will invoke [main] is |
2198 // passed to [dartMainRunner]. | 2403 // passed to [dartMainRunner]. |
2199 """; | 2404 """; |
OLD | NEW |