| 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 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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 needsLazyInitializer = false; | 61 bool needsLazyInitializer = false; |
| 62 final Namer namer; | 62 final Namer namer; |
| 63 ConstantEmitter constantEmitter; | 63 ConstantEmitter constantEmitter; |
| 64 NativeEmitter nativeEmitter; | 64 NativeEmitter nativeEmitter; |
| 65 CodeBuffer mainBuffer; | 65 CodeBuffer mainBuffer; |
| 66 final CodeBuffer deferredBuffer = new CodeBuffer(); | 66 final CodeBuffer deferredLibraries = new CodeBuffer(); |
| 67 final CodeBuffer deferredConstants = 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; |
| 71 final Set<ClassElement> neededClasses = new Set<ClassElement>(); | 72 final Set<ClassElement> neededClasses = new Set<ClassElement>(); |
| 72 final List<ClassElement> regularClasses = <ClassElement>[]; | 73 final List<ClassElement> regularClasses = <ClassElement>[]; |
| 73 final List<ClassElement> deferredClasses = <ClassElement>[]; | 74 final List<ClassElement> deferredClasses = <ClassElement>[]; |
| 74 final List<ClassElement> nativeClasses = <ClassElement>[]; | 75 final List<ClassElement> nativeClasses = <ClassElement>[]; |
| 75 final List<Selector> trivialNsmHandlers = <Selector>[]; | 76 final List<Selector> trivialNsmHandlers = <Selector>[]; |
| 76 final Map<String, String> mangledFieldNames = <String, String>{}; | 77 final Map<String, String> mangledFieldNames = <String, String>{}; |
| (...skipping 1817 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1894 emitStaticFunction(buffer, namer.getBailoutName(element), bailoutCode); | 1895 emitStaticFunction(buffer, namer.getBailoutName(element), bailoutCode); |
| 1895 } | 1896 } |
| 1896 } | 1897 } |
| 1897 | 1898 |
| 1898 final Map<Element, Element> staticGetters = new Map<Element, Element>(); | 1899 final Map<Element, Element> staticGetters = new Map<Element, Element>(); |
| 1899 | 1900 |
| 1900 void emitStaticFunctionGetters(CodeBuffer eagerBuffer) { | 1901 void emitStaticFunctionGetters(CodeBuffer eagerBuffer) { |
| 1901 for (FunctionElement element in | 1902 for (FunctionElement element in |
| 1902 Elements.sortedByPosition(staticGetters.keys)) { | 1903 Elements.sortedByPosition(staticGetters.keys)) { |
| 1903 Element closure = staticGetters[element]; | 1904 Element closure = staticGetters[element]; |
| 1904 // TODO(ahe): This should be emitted as a constant. Currently, | 1905 CodeBuffer buffer = isDeferred(element) ? deferredConstants : eagerBuffer; |
| 1905 // this breaks deferred loading. | |
| 1906 CodeBuffer buffer = eagerBuffer; | |
| 1907 String closureClass = namer.isolateAccess(closure); | 1906 String closureClass = namer.isolateAccess(closure); |
| 1908 String name = namer.getStaticClosureName(element); | 1907 String name = namer.getStaticClosureName(element); |
| 1909 String staticName = namer.getName(element); | 1908 String staticName = namer.getName(element); |
| 1910 | 1909 |
| 1911 String closureName = namer.getStaticClosureName(element); | 1910 String closureName = namer.getStaticClosureName(element); |
| 1912 jsAst.Node assignment = js('$isolateProperties.$name = ' | 1911 jsAst.Node assignment = js('$isolateProperties.$name = ' |
| 1913 'new $closureClass($isolateProperties.$staticName, "$closureName")'); | 1912 'new $closureClass($isolateProperties.$staticName, "$closureName")'); |
| 1914 buffer.write(jsAst.prettyPrint(assignment, compiler)); | 1913 buffer.write(jsAst.prettyPrint(assignment, compiler)); |
| 1915 buffer.write('$N'); | 1914 buffer.write('$N'); |
| 1916 } | 1915 } |
| (...skipping 1203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3120 mainBuffer.write( | 3119 mainBuffer.write( |
| 3121 jsAst.prettyPrint( | 3120 jsAst.prettyPrint( |
| 3122 js('init.mangledNames = #', map).toStatement(), compiler)); | 3121 js('init.mangledNames = #', map).toStatement(), compiler)); |
| 3123 if (compiler.enableMinification) { | 3122 if (compiler.enableMinification) { |
| 3124 mainBuffer.write(';'); | 3123 mainBuffer.write(';'); |
| 3125 } | 3124 } |
| 3126 } | 3125 } |
| 3127 mainBuffer | 3126 mainBuffer |
| 3128 ..write(getReflectionDataParser()) | 3127 ..write(getReflectionDataParser()) |
| 3129 ..write('([$n'); | 3128 ..write('([$n'); |
| 3130 emitDeferredPreambleWhenEmpty(deferredBuffer); | |
| 3131 deferredBuffer.add('\$\$$_=$_{};$n'); | |
| 3132 | 3129 |
| 3133 deferredBuffer | |
| 3134 ..write(getReflectionDataParser()) | |
| 3135 ..write('([$n'); | |
| 3136 var sortedLibraries = Elements.sortedByPosition(libraryBuffers.keys); | 3130 var sortedLibraries = Elements.sortedByPosition(libraryBuffers.keys); |
| 3137 for (LibraryElement library in sortedLibraries) { | 3131 for (LibraryElement library in sortedLibraries) { |
| 3138 List<CodeBuffer> buffers = libraryBuffers[library]; | 3132 List<CodeBuffer> buffers = libraryBuffers[library]; |
| 3139 var buffer = buffers[0]; | 3133 var buffer = buffers[0]; |
| 3140 var uri = library.canonicalUri; | 3134 var uri = library.canonicalUri; |
| 3141 if (uri.scheme == 'file' && compiler.sourceMapUri != null) { | 3135 if (uri.scheme == 'file' && compiler.sourceMapUri != null) { |
| 3142 // TODO(ahe): It is a hack to use compiler.sourceMapUri | 3136 // TODO(ahe): It is a hack to use compiler.sourceMapUri |
| 3143 // here. It should be relative to the main JavaScript | 3137 // here. It should be relative to the main JavaScript |
| 3144 // output file. | 3138 // output file. |
| 3145 uri = relativize( | 3139 uri = relativize( |
| 3146 compiler.sourceMapUri, library.canonicalUri, false); | 3140 compiler.sourceMapUri, library.canonicalUri, false); |
| 3147 } | 3141 } |
| 3148 if (buffer != null) { | 3142 if (buffer != null) { |
| 3149 var metadata = buildMetadataFunction(library); | 3143 var metadata = buildMetadataFunction(library); |
| 3150 mainBuffer | 3144 mainBuffer |
| 3151 ..write('["${library.getLibraryOrScriptName()}",$_') | 3145 ..write('["${library.getLibraryOrScriptName()}",$_') |
| 3152 ..write('"${uri}",$_') | 3146 ..write('"${uri}",$_') |
| 3153 ..write(metadata == null | 3147 ..write(metadata == null |
| 3154 ? "" : jsAst.prettyPrint(metadata, compiler)) | 3148 ? "" : jsAst.prettyPrint(metadata, compiler)) |
| 3155 ..write(',$_') | 3149 ..write(',$_') |
| 3156 ..write('{$n') | 3150 ..write('{$n') |
| 3157 ..addBuffer(buffer) | 3151 ..addBuffer(buffer) |
| 3158 ..write('}],$n'); | 3152 ..write('}],$n'); |
| 3159 } | 3153 } |
| 3160 buffer = buffers[1]; | 3154 buffer = buffers[1]; |
| 3161 if (buffer != null) { | 3155 if (buffer != null) { |
| 3162 deferredBuffer | 3156 deferredLibraries |
| 3163 ..write('["${library.getLibraryOrScriptName()}",$_') | 3157 ..write('["${library.getLibraryOrScriptName()}",$_') |
| 3164 ..write('"${uri}",$_') | 3158 ..write('"${uri}",$_') |
| 3165 ..write('[],$_') | 3159 ..write('[],$_') |
| 3166 ..write('{$n') | 3160 ..write('{$n') |
| 3167 ..addBuffer(buffer) | 3161 ..addBuffer(buffer) |
| 3168 ..write('}],$n'); | 3162 ..write('}],$n'); |
| 3169 } | 3163 } |
| 3170 libraryBuffers[library] = const []; | 3164 libraryBuffers[library] = const []; |
| 3171 } | 3165 } |
| 3172 mainBuffer.write('])$N'); | 3166 mainBuffer.write('])$N'); |
| 3173 | 3167 |
| 3174 deferredBuffer.write('])$N'); | |
| 3175 if (!deferredClasses.isEmpty) { | |
| 3176 deferredBuffer.add('$finishClassesName(\$\$,' | |
| 3177 '$_${namer.CURRENT_ISOLATE},' | |
| 3178 '$_$isolatePropertiesName)$N'); | |
| 3179 } | |
| 3180 | |
| 3181 // Reset the map. | |
| 3182 deferredBuffer.add("\$\$$_=${_}null$N$n"); | |
| 3183 emitFinishClassesInvocationIfNecessary(mainBuffer); | 3168 emitFinishClassesInvocationIfNecessary(mainBuffer); |
| 3184 classesCollector = oldClassesCollector; | 3169 classesCollector = oldClassesCollector; |
| 3185 } | 3170 } |
| 3186 | 3171 |
| 3187 emitStaticFunctionGetters(mainBuffer); | 3172 emitStaticFunctionGetters(mainBuffer); |
| 3188 | 3173 |
| 3189 emitRuntimeTypeSupport(mainBuffer); | 3174 emitRuntimeTypeSupport(mainBuffer); |
| 3190 emitCompileTimeConstants(mainBuffer); | 3175 emitCompileTimeConstants(mainBuffer); |
| 3191 // Static field initializations require the classes and compile-time | 3176 // Static field initializations require the classes and compile-time |
| 3192 // constants to be set up. | 3177 // constants to be set up. |
| (...skipping 13 matching lines...) Expand all Loading... |
| 3206 | 3191 |
| 3207 emitFinishIsolateConstructorInvocation(mainBuffer); | 3192 emitFinishIsolateConstructorInvocation(mainBuffer); |
| 3208 mainBuffer.add('var ${namer.CURRENT_ISOLATE}$_=' | 3193 mainBuffer.add('var ${namer.CURRENT_ISOLATE}$_=' |
| 3209 '${_}new ${namer.isolateName}()$N'); | 3194 '${_}new ${namer.isolateName}()$N'); |
| 3210 | 3195 |
| 3211 emitMain(mainBuffer); | 3196 emitMain(mainBuffer); |
| 3212 emitInitFunction(mainBuffer); | 3197 emitInitFunction(mainBuffer); |
| 3213 compiler.assembledCode = mainBuffer.getText(); | 3198 compiler.assembledCode = mainBuffer.getText(); |
| 3214 outputSourceMap(mainBuffer, compiler.assembledCode, ''); | 3199 outputSourceMap(mainBuffer, compiler.assembledCode, ''); |
| 3215 | 3200 |
| 3216 emitDeferredCode(deferredBuffer); | 3201 emitDeferredCode(); |
| 3217 | 3202 |
| 3218 }); | 3203 }); |
| 3219 return compiler.assembledCode; | 3204 return compiler.assembledCode; |
| 3220 } | 3205 } |
| 3221 | 3206 |
| 3222 final Map<LibraryElement, List<CodeBuffer>> libraryBuffers = | 3207 final Map<LibraryElement, List<CodeBuffer>> libraryBuffers = |
| 3223 new Map<LibraryElement, List<CodeBuffer>>(); | 3208 new Map<LibraryElement, List<CodeBuffer>>(); |
| 3224 | 3209 |
| 3225 CodeBuffer bufferForElement(Element element, CodeBuffer eagerBuffer) { | 3210 CodeBuffer bufferForElement(Element element, CodeBuffer eagerBuffer) { |
| 3226 LibraryElement library = element.getLibrary(); | 3211 LibraryElement library = element.getLibrary(); |
| 3227 List<CodeBuffer> buffers = libraryBuffers.putIfAbsent( | 3212 List<CodeBuffer> buffers = libraryBuffers.putIfAbsent( |
| 3228 library, () => <CodeBuffer>[null, null]); | 3213 library, () => <CodeBuffer>[null, null]); |
| 3229 bool deferred = isDeferred(element); | 3214 bool deferred = isDeferred(element); |
| 3230 int index = deferred ? 1 : 0; | 3215 int index = deferred ? 1 : 0; |
| 3231 CodeBuffer buffer = buffers[index]; | 3216 CodeBuffer buffer = buffers[index]; |
| 3232 if (buffer == null) { | 3217 if (buffer == null) { |
| 3233 buffer = buffers[index] = new CodeBuffer(); | 3218 buffer = buffers[index] = new CodeBuffer(); |
| 3234 } | 3219 } |
| 3235 return buffer; | 3220 return buffer; |
| 3236 } | 3221 } |
| 3237 | 3222 |
| 3238 bool firstDeferredConstant = true; | |
| 3239 | |
| 3240 /** | 3223 /** |
| 3241 * Returns the appropriate buffer for [constant]. If [constant] is | 3224 * Returns the appropriate buffer for [constant]. If [constant] is |
| 3242 * itself an instance of a deferred type (or built from constants | 3225 * itself an instance of a deferred type (or built from constants |
| 3243 * that are instances of deferred types) attempting to use | 3226 * that are instances of deferred types) attempting to use |
| 3244 * [constant] before the deferred type has been loaded will not | 3227 * [constant] before the deferred type has been loaded will not |
| 3245 * work, and [constant] itself must be deferred. | 3228 * work, and [constant] itself must be deferred. |
| 3246 */ | 3229 */ |
| 3247 CodeBuffer bufferForConstant(Constant constant, CodeBuffer eagerBuffer) { | 3230 CodeBuffer bufferForConstant(Constant constant, CodeBuffer eagerBuffer) { |
| 3248 var queue = new Queue()..add(constant); | 3231 var queue = new Queue()..add(constant); |
| 3249 while (!queue.isEmpty) { | 3232 while (!queue.isEmpty) { |
| 3250 constant = queue.removeFirst(); | 3233 constant = queue.removeFirst(); |
| 3251 if (isDeferred(constant.computeType(compiler).element)) { | 3234 if (isDeferred(constant.computeType(compiler).element)) { |
| 3252 emitDeferredPreambleWhenEmpty(deferredBuffer); | 3235 return deferredConstants; |
| 3253 if (firstDeferredConstant) { | |
| 3254 deferredBuffer.write( | |
| 3255 '${namer.CURRENT_ISOLATE}$_=${_}old${namer.CURRENT_ISOLATE}$N'); | |
| 3256 deferredBuffer.write( | |
| 3257 'old${namer.CURRENT_ISOLATE}$_=${_}${namer.CURRENT_ISOLATE}$N'); | |
| 3258 } | |
| 3259 firstDeferredConstant = false; | |
| 3260 return deferredBuffer; | |
| 3261 } | 3236 } |
| 3262 queue.addAll(constant.getDependencies()); | 3237 queue.addAll(constant.getDependencies()); |
| 3263 } | 3238 } |
| 3264 return eagerBuffer; | 3239 return eagerBuffer; |
| 3265 } | 3240 } |
| 3266 | 3241 |
| 3267 void emitDeferredCode(CodeBuffer buffer) { | |
| 3268 if (buffer.isEmpty) return; | |
| 3269 | 3242 |
| 3270 buffer.write(n); | 3243 |
| 3244 void emitDeferredCode() { |
| 3245 if (deferredLibraries.isEmpty && deferredConstants.isEmpty) return; |
| 3246 |
| 3247 var oldClassesCollector = classesCollector; |
| 3248 classesCollector = r"$$"; |
| 3249 |
| 3250 // It does not make sense to defer constants if there are no |
| 3251 // deferred elements. |
| 3252 assert(!deferredLibraries.isEmpty); |
| 3253 |
| 3254 var buffer = new CodeBuffer() |
| 3255 ..write(buildGeneratedBy()) |
| 3256 ..write('var old${namer.CURRENT_ISOLATE}$_=' |
| 3257 '$_${namer.CURRENT_ISOLATE}$N' |
| 3258 // TODO(ahe): This defines a lot of properties on the |
| 3259 // Isolate.prototype object. We know this will turn it into a |
| 3260 // slow object in V8, so instead we should do something similar |
| 3261 // to Isolate.$finishIsolateConstructor. |
| 3262 '${namer.CURRENT_ISOLATE}$_=' |
| 3263 '$_${namer.isolateName}.prototype$N$n' |
| 3264 // The classesCollector object ($$). |
| 3265 '$classesCollector$_=$_{};$n') |
| 3266 ..write(getReflectionDataParser()) |
| 3267 ..write('([$n') |
| 3268 ..addBuffer(deferredLibraries) |
| 3269 ..write('])$N'); |
| 3270 |
| 3271 if (!deferredClasses.isEmpty) { |
| 3272 buffer.write( |
| 3273 '$finishClassesName($classesCollector,$_${namer.CURRENT_ISOLATE},' |
| 3274 '$_$isolatePropertiesName)$N'); |
| 3275 } |
| 3271 | 3276 |
| 3272 buffer.write( | 3277 buffer.write( |
| 3278 // Reset the classesCollector ($$). |
| 3279 '$classesCollector$_=${_}null$N$n' |
| 3273 '${namer.CURRENT_ISOLATE}$_=${_}old${namer.CURRENT_ISOLATE}$N'); | 3280 '${namer.CURRENT_ISOLATE}$_=${_}old${namer.CURRENT_ISOLATE}$N'); |
| 3274 | 3281 |
| 3282 classesCollector = oldClassesCollector; |
| 3283 |
| 3284 if (!deferredConstants.isEmpty) { |
| 3285 buffer.addBuffer(deferredConstants); |
| 3286 } |
| 3287 |
| 3275 String code = buffer.getText(); | 3288 String code = buffer.getText(); |
| 3276 compiler.outputProvider('part', 'js') | 3289 compiler.outputProvider('part', 'js') |
| 3277 ..add(code) | 3290 ..add(code) |
| 3278 ..close(); | 3291 ..close(); |
| 3279 outputSourceMap(buffer, compiler.assembledCode, 'part'); | 3292 outputSourceMap(buffer, compiler.assembledCode, 'part'); |
| 3280 } | 3293 } |
| 3281 | 3294 |
| 3282 void emitDeferredPreambleWhenEmpty(CodeBuffer buffer) { | |
| 3283 if (!buffer.isEmpty) return; | |
| 3284 | |
| 3285 buffer.write(buildGeneratedBy()); | |
| 3286 | |
| 3287 buffer.write('var old${namer.CURRENT_ISOLATE}$_=' | |
| 3288 '$_${namer.CURRENT_ISOLATE}$N'); | |
| 3289 | |
| 3290 // TODO(ahe): This defines a lot of properties on the | |
| 3291 // Isolate.prototype object. We know this will turn it into a | |
| 3292 // slow object in V8, so instead we should do something similar to | |
| 3293 // Isolate.$finishIsolateConstructor. | |
| 3294 buffer.write('${namer.CURRENT_ISOLATE}$_=' | |
| 3295 '$_${namer.isolateName}.prototype$N$n'); | |
| 3296 } | |
| 3297 | |
| 3298 String buildGeneratedBy() { | 3295 String buildGeneratedBy() { |
| 3299 var suffix = ''; | 3296 var suffix = ''; |
| 3300 if (compiler.hasBuildId) suffix = ' version: ${compiler.buildId}'; | 3297 if (compiler.hasBuildId) suffix = ' version: ${compiler.buildId}'; |
| 3301 return '// Generated by dart2js, the Dart to JavaScript compiler$suffix.\n'; | 3298 return '// Generated by dart2js, the Dart to JavaScript compiler$suffix.\n'; |
| 3302 } | 3299 } |
| 3303 | 3300 |
| 3304 String buildSourceMap(CodeBuffer buffer, SourceFile compiledFile) { | 3301 String buildSourceMap(CodeBuffer buffer, SourceFile compiledFile) { |
| 3305 SourceMapBuilder sourceMapBuilder = | 3302 SourceMapBuilder sourceMapBuilder = |
| 3306 new SourceMapBuilder(compiler.sourceMapUri); | 3303 new SourceMapBuilder(compiler.sourceMapUri); |
| 3307 buffer.forEachSourceLocation(sourceMapBuilder.addMapping); | 3304 buffer.forEachSourceLocation(sourceMapBuilder.addMapping); |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3386 | 3383 |
| 3387 const String HOOKS_API_USAGE = """ | 3384 const String HOOKS_API_USAGE = """ |
| 3388 // The code supports the following hooks: | 3385 // The code supports the following hooks: |
| 3389 // dartPrint(message) - if this function is defined it is called | 3386 // dartPrint(message) - if this function is defined it is called |
| 3390 // instead of the Dart [print] method. | 3387 // instead of the Dart [print] method. |
| 3391 // dartMainRunner(main) - if this function is defined, the Dart [main] | 3388 // dartMainRunner(main) - if this function is defined, the Dart [main] |
| 3392 // method will not be invoked directly. | 3389 // method will not be invoked directly. |
| 3393 // Instead, a closure that will invoke [main] is | 3390 // Instead, a closure that will invoke [main] is |
| 3394 // passed to [dartMainRunner]. | 3391 // passed to [dartMainRunner]. |
| 3395 """; | 3392 """; |
| OLD | NEW |