| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 library dart2js.js_emitter.startup_emitter.model_emitter; | 5 library dart2js.js_emitter.startup_emitter.model_emitter; |
| 6 | 6 |
| 7 import 'dart:convert' show JsonEncoder; | 7 import 'dart:convert' show JsonEncoder; |
| 8 | 8 |
| 9 import 'package:js_runtime/shared/embedded_names.dart' show | 9 import 'package:js_runtime/shared/embedded_names.dart' |
| 10 CLASS_FIELDS_EXTRACTOR, | 10 show |
| 11 CLASS_ID_EXTRACTOR, | 11 CLASS_FIELDS_EXTRACTOR, |
| 12 CREATE_NEW_ISOLATE, | 12 CLASS_ID_EXTRACTOR, |
| 13 DEFERRED_INITIALIZED, | 13 CREATE_NEW_ISOLATE, |
| 14 DEFERRED_LIBRARY_URIS, | 14 DEFERRED_INITIALIZED, |
| 15 DEFERRED_LIBRARY_HASHES, | 15 DEFERRED_LIBRARY_URIS, |
| 16 GET_TYPE_FROM_NAME, | 16 DEFERRED_LIBRARY_HASHES, |
| 17 INITIALIZE_EMPTY_INSTANCE, | 17 GET_TYPE_FROM_NAME, |
| 18 INITIALIZE_LOADED_HUNK, | 18 INITIALIZE_EMPTY_INSTANCE, |
| 19 INSTANCE_FROM_CLASS_ID, | 19 INITIALIZE_LOADED_HUNK, |
| 20 INTERCEPTORS_BY_TAG, | 20 INSTANCE_FROM_CLASS_ID, |
| 21 IS_HUNK_INITIALIZED, | 21 INTERCEPTORS_BY_TAG, |
| 22 IS_HUNK_LOADED, | 22 IS_HUNK_INITIALIZED, |
| 23 LEAF_TAGS, | 23 IS_HUNK_LOADED, |
| 24 MANGLED_GLOBAL_NAMES, | 24 LEAF_TAGS, |
| 25 MANGLED_NAMES, | 25 MANGLED_GLOBAL_NAMES, |
| 26 METADATA, | 26 MANGLED_NAMES, |
| 27 NATIVE_SUPERCLASS_TAG_NAME, | 27 METADATA, |
| 28 STATIC_FUNCTION_NAME_TO_CLOSURE, | 28 NATIVE_SUPERCLASS_TAG_NAME, |
| 29 TYPE_TO_INTERCEPTOR_MAP, | 29 STATIC_FUNCTION_NAME_TO_CLOSURE, |
| 30 TYPES; | 30 TYPE_TO_INTERCEPTOR_MAP, |
| 31 TYPES; |
| 31 | 32 |
| 32 import '../../common.dart'; | 33 import '../../common.dart'; |
| 33 import '../../constants/values.dart' show | 34 import '../../constants/values.dart' show ConstantValue, FunctionConstantValue; |
| 34 ConstantValue, | 35 import '../../compiler.dart' show Compiler; |
| 35 FunctionConstantValue; | 36 import '../../core_types.dart' show CoreClasses; |
| 36 import '../../compiler.dart' show | 37 import '../../elements/elements.dart' show ClassElement, FunctionElement; |
| 37 Compiler; | 38 import '../../hash/sha1.dart' show Hasher; |
| 38 import '../../core_types.dart' show | |
| 39 CoreClasses; | |
| 40 import '../../elements/elements.dart' show | |
| 41 ClassElement, | |
| 42 FunctionElement; | |
| 43 import '../../hash/sha1.dart' show | |
| 44 Hasher; | |
| 45 import '../../io/code_output.dart'; | 39 import '../../io/code_output.dart'; |
| 46 import '../../io/line_column_provider.dart' show | 40 import '../../io/line_column_provider.dart' |
| 47 LineColumnCollector, | 41 show LineColumnCollector, LineColumnProvider; |
| 48 LineColumnProvider; | 42 import '../../io/source_map_builder.dart' show SourceMapBuilder; |
| 49 import '../../io/source_map_builder.dart' show | |
| 50 SourceMapBuilder; | |
| 51 import '../../js/js.dart' as js; | 43 import '../../js/js.dart' as js; |
| 52 import '../../js_backend/js_backend.dart' show | 44 import '../../js_backend/js_backend.dart' |
| 53 JavaScriptBackend, | 45 show JavaScriptBackend, Namer, ConstantEmitter; |
| 54 Namer, | 46 import '../../util/uri_extras.dart' show relativize; |
| 55 ConstantEmitter; | |
| 56 import '../../util/uri_extras.dart' show | |
| 57 relativize; | |
| 58 | 47 |
| 59 import '../constant_ordering.dart' show deepCompareConstants; | 48 import '../constant_ordering.dart' show deepCompareConstants; |
| 60 import '../headers.dart'; | 49 import '../headers.dart'; |
| 61 import '../js_emitter.dart' show | 50 import '../js_emitter.dart' show NativeEmitter; |
| 62 NativeEmitter; | |
| 63 | 51 |
| 64 import '../js_emitter.dart' show | 52 import '../js_emitter.dart' show buildTearOffCode, NativeGenerator; |
| 65 buildTearOffCode, | |
| 66 NativeGenerator; | |
| 67 import '../model.dart'; | 53 import '../model.dart'; |
| 68 | 54 |
| 69 part 'deferred_fragment_hash.dart'; | 55 part 'deferred_fragment_hash.dart'; |
| 70 part 'fragment_emitter.dart'; | 56 part 'fragment_emitter.dart'; |
| 71 | 57 |
| 72 class ModelEmitter { | 58 class ModelEmitter { |
| 73 final Compiler compiler; | 59 final Compiler compiler; |
| 74 final Namer namer; | 60 final Namer namer; |
| 75 ConstantEmitter constantEmitter; | 61 ConstantEmitter constantEmitter; |
| 76 final NativeEmitter nativeEmitter; | 62 final NativeEmitter nativeEmitter; |
| 77 final bool shouldGenerateSourceMap; | 63 final bool shouldGenerateSourceMap; |
| 78 | 64 |
| 79 // The full code that is written to each hunk part-file. | 65 // The full code that is written to each hunk part-file. |
| 80 final Map<Fragment, CodeOutput> outputBuffers = <Fragment, CodeOutput>{}; | 66 final Map<Fragment, CodeOutput> outputBuffers = <Fragment, CodeOutput>{}; |
| 81 | 67 |
| 82 | |
| 83 JavaScriptBackend get backend => compiler.backend; | 68 JavaScriptBackend get backend => compiler.backend; |
| 84 | 69 |
| 85 /// For deferred loading we communicate the initializers via this global var. | 70 /// For deferred loading we communicate the initializers via this global var. |
| 86 static const String deferredInitializersGlobal = | 71 static const String deferredInitializersGlobal = |
| 87 r"$__dart_deferred_initializers__"; | 72 r"$__dart_deferred_initializers__"; |
| 88 | 73 |
| 89 static const String partExtension = "part"; | 74 static const String partExtension = "part"; |
| 90 static const String deferredExtension = "part.js"; | 75 static const String deferredExtension = "part.js"; |
| 91 | 76 |
| 92 static const String typeNameProperty = r"builtin$cls"; | 77 static const String typeNameProperty = r"builtin$cls"; |
| 93 | 78 |
| 94 ModelEmitter(Compiler compiler, Namer namer, this.nativeEmitter, | 79 ModelEmitter(Compiler compiler, Namer namer, this.nativeEmitter, |
| 95 this.shouldGenerateSourceMap) | 80 this.shouldGenerateSourceMap) |
| 96 : this.compiler = compiler, | 81 : this.compiler = compiler, |
| 97 this.namer = namer { | 82 this.namer = namer { |
| 98 this.constantEmitter = new ConstantEmitter( | 83 this.constantEmitter = new ConstantEmitter( |
| 99 compiler, namer, this.generateConstantReference, | 84 compiler, namer, this.generateConstantReference, constantListGenerator); |
| 100 constantListGenerator); | |
| 101 } | 85 } |
| 102 | 86 |
| 103 DiagnosticReporter get reporter => compiler.reporter; | 87 DiagnosticReporter get reporter => compiler.reporter; |
| 104 | 88 |
| 105 js.Expression constantListGenerator(js.Expression array) { | 89 js.Expression constantListGenerator(js.Expression array) { |
| 106 // TODO(floitsch): remove hard-coded name. | 90 // TODO(floitsch): remove hard-coded name. |
| 107 return js.js('makeConstList(#)', [array]); | 91 return js.js('makeConstList(#)', [array]); |
| 108 } | 92 } |
| 109 | 93 |
| 110 js.Expression generateEmbeddedGlobalAccess(String global) { | 94 js.Expression generateEmbeddedGlobalAccess(String global) { |
| 111 return js.js(generateEmbeddedGlobalAccessString(global)); | 95 return js.js(generateEmbeddedGlobalAccessString(global)); |
| 112 } | 96 } |
| 113 | 97 |
| 114 String generateEmbeddedGlobalAccessString(String global) { | 98 String generateEmbeddedGlobalAccessString(String global) { |
| 115 // TODO(floitsch): don't use 'init' as global embedder storage. | 99 // TODO(floitsch): don't use 'init' as global embedder storage. |
| 116 return 'init.$global'; | 100 return 'init.$global'; |
| 117 } | 101 } |
| 118 | 102 |
| 119 bool isConstantInlinedOrAlreadyEmitted(ConstantValue constant) { | 103 bool isConstantInlinedOrAlreadyEmitted(ConstantValue constant) { |
| 120 if (constant.isFunction) return true; // Already emitted. | 104 if (constant.isFunction) return true; // Already emitted. |
| 121 if (constant.isPrimitive) return true; // Inlined. | 105 if (constant.isPrimitive) return true; // Inlined. |
| 122 if (constant.isDummy) return true; // Inlined. | 106 if (constant.isDummy) return true; // Inlined. |
| 123 return false; | 107 return false; |
| 124 } | 108 } |
| 125 | 109 |
| 126 // TODO(floitsch): copied from OldEmitter. Adjust or share. | 110 // TODO(floitsch): copied from OldEmitter. Adjust or share. |
| 127 int compareConstants(ConstantValue a, ConstantValue b) { | 111 int compareConstants(ConstantValue a, ConstantValue b) { |
| 128 // Inlined constants don't affect the order and sometimes don't even have | 112 // Inlined constants don't affect the order and sometimes don't even have |
| 129 // names. | 113 // names. |
| 130 int cmp1 = isConstantInlinedOrAlreadyEmitted(a) ? 0 : 1; | 114 int cmp1 = isConstantInlinedOrAlreadyEmitted(a) ? 0 : 1; |
| 131 int cmp2 = isConstantInlinedOrAlreadyEmitted(b) ? 0 : 1; | 115 int cmp2 = isConstantInlinedOrAlreadyEmitted(b) ? 0 : 1; |
| 132 if (cmp1 + cmp2 < 2) return cmp1 - cmp2; | 116 if (cmp1 + cmp2 < 2) return cmp1 - cmp2; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 155 if (value.isFunction) { | 139 if (value.isFunction) { |
| 156 FunctionConstantValue functionConstant = value; | 140 FunctionConstantValue functionConstant = value; |
| 157 return generateStaticClosureAccess(functionConstant.element); | 141 return generateStaticClosureAccess(functionConstant.element); |
| 158 } | 142 } |
| 159 | 143 |
| 160 // We are only interested in the "isInlined" part, but it does not hurt to | 144 // We are only interested in the "isInlined" part, but it does not hurt to |
| 161 // test for the other predicates. | 145 // test for the other predicates. |
| 162 if (isConstantInlinedOrAlreadyEmitted(value)) { | 146 if (isConstantInlinedOrAlreadyEmitted(value)) { |
| 163 return constantEmitter.generate(value); | 147 return constantEmitter.generate(value); |
| 164 } | 148 } |
| 165 return js.js('#.#', [namer.globalObjectForConstant(value), | 149 return js.js('#.#', |
| 166 namer.constantName(value)]); | 150 [namer.globalObjectForConstant(value), namer.constantName(value)]); |
| 167 } | 151 } |
| 168 | 152 |
| 169 int emitProgram(Program program) { | 153 int emitProgram(Program program) { |
| 170 MainFragment mainFragment = program.fragments.first; | 154 MainFragment mainFragment = program.fragments.first; |
| 171 List<DeferredFragment> deferredFragments = | 155 List<DeferredFragment> deferredFragments = |
| 172 new List<DeferredFragment>.from(program.deferredFragments); | 156 new List<DeferredFragment>.from(program.deferredFragments); |
| 173 | 157 |
| 174 FragmentEmitter fragmentEmitter = | 158 FragmentEmitter fragmentEmitter = |
| 175 new FragmentEmitter(compiler, namer, backend, constantEmitter, this); | 159 new FragmentEmitter(compiler, namer, backend, constantEmitter, this); |
| 176 | 160 |
| 177 Map<DeferredFragment, _DeferredFragmentHash> deferredHashTokens = | 161 Map<DeferredFragment, _DeferredFragmentHash> deferredHashTokens = |
| 178 new Map<DeferredFragment, _DeferredFragmentHash>(); | 162 new Map<DeferredFragment, _DeferredFragmentHash>(); |
| 179 for (DeferredFragment fragment in deferredFragments) { | 163 for (DeferredFragment fragment in deferredFragments) { |
| 180 deferredHashTokens[fragment] = new _DeferredFragmentHash(fragment); | 164 deferredHashTokens[fragment] = new _DeferredFragmentHash(fragment); |
| 181 } | 165 } |
| 182 | 166 |
| 183 js.Statement mainCode = | 167 js.Statement mainCode = |
| 184 fragmentEmitter.emitMainFragment(program, deferredHashTokens); | 168 fragmentEmitter.emitMainFragment(program, deferredHashTokens); |
| 185 | 169 |
| 186 Map<DeferredFragment, js.Expression> deferredFragmentsCode = | 170 Map<DeferredFragment, js.Expression> deferredFragmentsCode = |
| 187 <DeferredFragment, js.Expression>{}; | 171 <DeferredFragment, js.Expression>{}; |
| 188 | 172 |
| 189 for (DeferredFragment fragment in deferredFragments) { | 173 for (DeferredFragment fragment in deferredFragments) { |
| 190 js.Expression types = | 174 js.Expression types = |
| 191 program.metadataTypesForOutputUnit(fragment.outputUnit); | 175 program.metadataTypesForOutputUnit(fragment.outputUnit); |
| 192 deferredFragmentsCode[fragment] = fragmentEmitter.emitDeferredFragment( | 176 deferredFragmentsCode[fragment] = fragmentEmitter.emitDeferredFragment( |
| 193 fragment, types, program.holders); | 177 fragment, types, program.holders); |
| 194 } | 178 } |
| 195 | 179 |
| 196 js.TokenCounter counter = new js.TokenCounter(); | 180 js.TokenCounter counter = new js.TokenCounter(); |
| 197 deferredFragmentsCode.values.forEach(counter.countTokens); | 181 deferredFragmentsCode.values.forEach(counter.countTokens); |
| 198 counter.countTokens(mainCode); | 182 counter.countTokens(mainCode); |
| 199 | 183 |
| 200 program.finalizers.forEach((js.TokenFinalizer f) => f.finalizeTokens()); | 184 program.finalizers.forEach((js.TokenFinalizer f) => f.finalizeTokens()); |
| 201 | 185 |
| 202 Map<DeferredFragment, String> hunkHashes = | 186 Map<DeferredFragment, String> hunkHashes = |
| 203 writeDeferredFragments(deferredFragmentsCode); | 187 writeDeferredFragments(deferredFragmentsCode); |
| 204 | 188 |
| 205 // Now that we have written the deferred hunks, we can update the hash | 189 // Now that we have written the deferred hunks, we can update the hash |
| 206 // tokens in the main-fragment. | 190 // tokens in the main-fragment. |
| 207 deferredHashTokens.forEach((DeferredFragment key, | 191 deferredHashTokens |
| 208 _DeferredFragmentHash token) { | 192 .forEach((DeferredFragment key, _DeferredFragmentHash token) { |
| 209 token.setHash(hunkHashes[key]); | 193 token.setHash(hunkHashes[key]); |
| 210 }); | 194 }); |
| 211 | 195 |
| 212 writeMainFragment(mainFragment, mainCode, | 196 writeMainFragment(mainFragment, mainCode, |
| 213 isSplit: program.deferredFragments.isNotEmpty); | 197 isSplit: program.deferredFragments.isNotEmpty); |
| 214 | 198 |
| 215 if (backend.requiresPreamble && | 199 if (backend.requiresPreamble && !backend.htmlLibraryIsLoaded) { |
| 216 !backend.htmlLibraryIsLoaded) { | 200 reporter.reportHintMessage(NO_LOCATION_SPANNABLE, MessageKind.PREAMBLE); |
| 217 reporter.reportHintMessage( | |
| 218 NO_LOCATION_SPANNABLE, MessageKind.PREAMBLE); | |
| 219 } | 201 } |
| 220 | 202 |
| 221 if (compiler.options.deferredMapUri != null) { | 203 if (compiler.options.deferredMapUri != null) { |
| 222 writeDeferredMap(); | 204 writeDeferredMap(); |
| 223 } | 205 } |
| 224 | 206 |
| 225 // Return the total program size. | 207 // Return the total program size. |
| 226 return outputBuffers.values.fold(0, (a, b) => a + b.length); | 208 return outputBuffers.values.fold(0, (a, b) => a + b.length); |
| 227 } | 209 } |
| 228 | 210 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 245 Map<DeferredFragment, String> hunkHashes = <DeferredFragment, String>{}; | 227 Map<DeferredFragment, String> hunkHashes = <DeferredFragment, String>{}; |
| 246 | 228 |
| 247 fragmentsCode.forEach((DeferredFragment fragment, js.Expression code) { | 229 fragmentsCode.forEach((DeferredFragment fragment, js.Expression code) { |
| 248 hunkHashes[fragment] = writeDeferredFragment(fragment, code); | 230 hunkHashes[fragment] = writeDeferredFragment(fragment, code); |
| 249 }); | 231 }); |
| 250 | 232 |
| 251 return hunkHashes; | 233 return hunkHashes; |
| 252 } | 234 } |
| 253 | 235 |
| 254 js.Statement buildDeferredInitializerGlobal() { | 236 js.Statement buildDeferredInitializerGlobal() { |
| 255 return js.js.statement('self.#deferredInitializers = ' | 237 return js.js.statement( |
| 238 'self.#deferredInitializers = ' |
| 256 'self.#deferredInitializers || Object.create(null);', | 239 'self.#deferredInitializers || Object.create(null);', |
| 257 {'deferredInitializers': deferredInitializersGlobal}); | 240 {'deferredInitializers': deferredInitializersGlobal}); |
| 258 } | 241 } |
| 259 | 242 |
| 260 // Writes the given [fragment]'s [code] into a file. | 243 // Writes the given [fragment]'s [code] into a file. |
| 261 // | 244 // |
| 262 // Updates the shared [outputBuffers] field with the output. | 245 // Updates the shared [outputBuffers] field with the output. |
| 263 void writeMainFragment(MainFragment fragment, js.Statement code, | 246 void writeMainFragment(MainFragment fragment, js.Statement code, |
| 264 {bool isSplit}) { | 247 {bool isSplit}) { |
| 265 LineColumnCollector lineColumnCollector; | 248 LineColumnCollector lineColumnCollector; |
| 266 List<CodeOutputListener> codeOutputListeners; | 249 List<CodeOutputListener> codeOutputListeners; |
| 267 if (shouldGenerateSourceMap) { | 250 if (shouldGenerateSourceMap) { |
| 268 lineColumnCollector = new LineColumnCollector(); | 251 lineColumnCollector = new LineColumnCollector(); |
| 269 codeOutputListeners = <CodeOutputListener>[lineColumnCollector]; | 252 codeOutputListeners = <CodeOutputListener>[lineColumnCollector]; |
| 270 } | 253 } |
| 271 | 254 |
| 272 CodeOutput mainOutput = new StreamCodeOutput( | 255 CodeOutput mainOutput = new StreamCodeOutput( |
| 273 compiler.outputProvider('', 'js'), | 256 compiler.outputProvider('', 'js'), codeOutputListeners); |
| 274 codeOutputListeners); | |
| 275 outputBuffers[fragment] = mainOutput; | 257 outputBuffers[fragment] = mainOutput; |
| 276 | 258 |
| 277 js.Program program = new js.Program([ | 259 js.Program program = new js.Program([ |
| 278 buildGeneratedBy(), | 260 buildGeneratedBy(), |
| 279 new js.Comment(HOOKS_API_USAGE), | 261 new js.Comment(HOOKS_API_USAGE), |
| 280 isSplit ? buildDeferredInitializerGlobal() : new js.Block.empty(), | 262 isSplit ? buildDeferredInitializerGlobal() : new js.Block.empty(), |
| 281 code]); | 263 code |
| 264 ]); |
| 282 | 265 |
| 283 mainOutput.addBuffer(js.createCodeBuffer(program, compiler, | 266 mainOutput.addBuffer( |
| 284 monitor: compiler.dumpInfoTask)); | 267 js.createCodeBuffer(program, compiler, monitor: compiler.dumpInfoTask)); |
| 285 | 268 |
| 286 if (shouldGenerateSourceMap) { | 269 if (shouldGenerateSourceMap) { |
| 287 mainOutput.add(generateSourceMapTag( | 270 mainOutput.add(generateSourceMapTag( |
| 288 compiler.options.sourceMapUri, compiler.options.outputUri)); | 271 compiler.options.sourceMapUri, compiler.options.outputUri)); |
| 289 } | 272 } |
| 290 | 273 |
| 291 mainOutput.close(); | 274 mainOutput.close(); |
| 292 | 275 |
| 293 if (shouldGenerateSourceMap) { | 276 if (shouldGenerateSourceMap) { |
| 294 outputSourceMap(mainOutput, lineColumnCollector, '', | 277 outputSourceMap(mainOutput, lineColumnCollector, '', |
| (...skipping 28 matching lines...) Expand all Loading... |
| 323 // The [code] contains the function that must be invoked when the deferred | 306 // The [code] contains the function that must be invoked when the deferred |
| 324 // hunk is loaded. | 307 // hunk is loaded. |
| 325 // That function must be in a map from its hashcode to the function. Since | 308 // That function must be in a map from its hashcode to the function. Since |
| 326 // we don't know the hash before we actually emit the code we store the | 309 // we don't know the hash before we actually emit the code we store the |
| 327 // function in a temporary field first: | 310 // function in a temporary field first: |
| 328 // | 311 // |
| 329 // deferredInitializer.current = <pretty-printed code>; | 312 // deferredInitializer.current = <pretty-printed code>; |
| 330 // deferredInitializer[<hash>] = deferredInitializer.current; | 313 // deferredInitializer[<hash>] = deferredInitializer.current; |
| 331 | 314 |
| 332 js.Program program = new js.Program([ | 315 js.Program program = new js.Program([ |
| 333 buildGeneratedBy(), | 316 buildGeneratedBy(), |
| 334 buildDeferredInitializerGlobal(), | 317 buildDeferredInitializerGlobal(), |
| 335 js.js.statement('$deferredInitializersGlobal.current = #', code)]); | 318 js.js.statement('$deferredInitializersGlobal.current = #', code) |
| 319 ]); |
| 336 | 320 |
| 337 output.addBuffer(js.createCodeBuffer(program, compiler, | 321 output.addBuffer( |
| 338 monitor: compiler.dumpInfoTask)); | 322 js.createCodeBuffer(program, compiler, monitor: compiler.dumpInfoTask)); |
| 339 | 323 |
| 340 // Make a unique hash of the code (before the sourcemaps are added) | 324 // Make a unique hash of the code (before the sourcemaps are added) |
| 341 // This will be used to retrieve the initializing function from the global | 325 // This will be used to retrieve the initializing function from the global |
| 342 // variable. | 326 // variable. |
| 343 String hash = hasher.getHash(); | 327 String hash = hasher.getHash(); |
| 344 | 328 |
| 345 // Now we copy the deferredInitializer.current into its correct hash. | 329 // Now we copy the deferredInitializer.current into its correct hash. |
| 346 output.add('\n${deferredInitializersGlobal}["$hash"] = ' | 330 output.add('\n${deferredInitializersGlobal}["$hash"] = ' |
| 347 '${deferredInitializersGlobal}.current'); | 331 '${deferredInitializersGlobal}.current'); |
| 348 | 332 |
| 349 if (shouldGenerateSourceMap) { | 333 if (shouldGenerateSourceMap) { |
| 350 Uri mapUri, partUri; | 334 Uri mapUri, partUri; |
| 351 Uri sourceMapUri = compiler.options.sourceMapUri; | 335 Uri sourceMapUri = compiler.options.sourceMapUri; |
| 352 Uri outputUri = compiler.options.outputUri; | 336 Uri outputUri = compiler.options.outputUri; |
| 353 String partName = "$hunkPrefix.$partExtension"; | 337 String partName = "$hunkPrefix.$partExtension"; |
| 354 String hunkFileName = "$hunkPrefix.$deferredExtension"; | 338 String hunkFileName = "$hunkPrefix.$deferredExtension"; |
| 355 | 339 |
| 356 if (sourceMapUri != null) { | 340 if (sourceMapUri != null) { |
| 357 String mapFileName = hunkFileName + ".map"; | 341 String mapFileName = hunkFileName + ".map"; |
| 358 List<String> mapSegments = sourceMapUri.pathSegments.toList(); | 342 List<String> mapSegments = sourceMapUri.pathSegments.toList(); |
| 359 mapSegments[mapSegments.length - 1] = mapFileName; | 343 mapSegments[mapSegments.length - 1] = mapFileName; |
| 360 mapUri = compiler.options.sourceMapUri | 344 mapUri = |
| 361 .replace(pathSegments: mapSegments); | 345 compiler.options.sourceMapUri.replace(pathSegments: mapSegments); |
| 362 } | 346 } |
| 363 | 347 |
| 364 if (outputUri != null) { | 348 if (outputUri != null) { |
| 365 List<String> partSegments = outputUri.pathSegments.toList(); | 349 List<String> partSegments = outputUri.pathSegments.toList(); |
| 366 partSegments[partSegments.length - 1] = hunkFileName; | 350 partSegments[partSegments.length - 1] = hunkFileName; |
| 367 partUri = compiler.options.outputUri | 351 partUri = |
| 368 .replace(pathSegments: partSegments); | 352 compiler.options.outputUri.replace(pathSegments: partSegments); |
| 369 } | 353 } |
| 370 | 354 |
| 371 output.add(generateSourceMapTag(mapUri, partUri)); | 355 output.add(generateSourceMapTag(mapUri, partUri)); |
| 372 output.close(); | 356 output.close(); |
| 373 outputSourceMap(output, lineColumnCollector, partName, mapUri, partUri); | 357 outputSourceMap(output, lineColumnCollector, partName, mapUri, partUri); |
| 374 } else { | 358 } else { |
| 375 output.close(); | 359 output.close(); |
| 376 } | 360 } |
| 377 | 361 |
| 378 return hash; | 362 return hash; |
| 379 } | 363 } |
| 380 | 364 |
| 381 String generateSourceMapTag(Uri sourceMapUri, Uri fileUri) { | 365 String generateSourceMapTag(Uri sourceMapUri, Uri fileUri) { |
| 382 if (sourceMapUri != null && fileUri != null) { | 366 if (sourceMapUri != null && fileUri != null) { |
| 383 String sourceMapFileName = relativize(fileUri, sourceMapUri, false); | 367 String sourceMapFileName = relativize(fileUri, sourceMapUri, false); |
| 384 return ''' | 368 return ''' |
| 385 | 369 |
| 386 //# sourceMappingURL=$sourceMapFileName | 370 //# sourceMappingURL=$sourceMapFileName |
| 387 '''; | 371 '''; |
| 388 } | 372 } |
| 389 return ''; | 373 return ''; |
| 390 } | 374 } |
| 391 | 375 |
| 392 | 376 void outputSourceMap( |
| 393 void outputSourceMap(CodeOutput output, | 377 CodeOutput output, LineColumnProvider lineColumnProvider, String name, |
| 394 LineColumnProvider lineColumnProvider, | 378 [Uri sourceMapUri, Uri fileUri]) { |
| 395 String name, | |
| 396 [Uri sourceMapUri, | |
| 397 Uri fileUri]) { | |
| 398 if (!shouldGenerateSourceMap) return; | 379 if (!shouldGenerateSourceMap) return; |
| 399 // Create a source file for the compilation output. This allows using | 380 // Create a source file for the compilation output. This allows using |
| 400 // [:getLine:] to transform offsets to line numbers in [SourceMapBuilder]. | 381 // [:getLine:] to transform offsets to line numbers in [SourceMapBuilder]. |
| 401 SourceMapBuilder sourceMapBuilder = | 382 SourceMapBuilder sourceMapBuilder = |
| 402 new SourceMapBuilder(sourceMapUri, fileUri, lineColumnProvider); | 383 new SourceMapBuilder(sourceMapUri, fileUri, lineColumnProvider); |
| 403 output.forEachSourceLocation(sourceMapBuilder.addMapping); | 384 output.forEachSourceLocation(sourceMapBuilder.addMapping); |
| 404 String sourceMap = sourceMapBuilder.build(); | 385 String sourceMap = sourceMapBuilder.build(); |
| 405 compiler.outputProvider(name, 'js.map') | 386 compiler.outputProvider(name, 'js.map') |
| 406 ..add(sourceMap) | 387 ..add(sourceMap) |
| 407 ..close(); | 388 ..close(); |
| 408 } | 389 } |
| 409 | 390 |
| 410 /// Writes a mapping from library-name to hunk files. | 391 /// Writes a mapping from library-name to hunk files. |
| 411 /// | 392 /// |
| 412 /// The output is written into a separate file that can be used by outside | 393 /// The output is written into a separate file that can be used by outside |
| 413 /// tools. | 394 /// tools. |
| 414 void writeDeferredMap() { | 395 void writeDeferredMap() { |
| 415 Map<String, dynamic> mapping = new Map<String, dynamic>(); | 396 Map<String, dynamic> mapping = new Map<String, dynamic>(); |
| 416 // Json does not support comments, so we embed the explanation in the | 397 // Json does not support comments, so we embed the explanation in the |
| 417 // data. | 398 // data. |
| 418 mapping["_comment"] = "This mapping shows which compiled `.js` files are " | 399 mapping["_comment"] = "This mapping shows which compiled `.js` files are " |
| 419 "needed for a given deferred library import."; | 400 "needed for a given deferred library import."; |
| 420 mapping.addAll(compiler.deferredLoadTask.computeDeferredMap()); | 401 mapping.addAll(compiler.deferredLoadTask.computeDeferredMap()); |
| 421 compiler.outputProvider( | 402 compiler.outputProvider( |
| 422 compiler.options.deferredMapUri.path, 'deferred_map') | 403 compiler.options.deferredMapUri.path, 'deferred_map') |
| 423 ..add(const JsonEncoder.withIndent(" ").convert(mapping)) | 404 ..add(const JsonEncoder.withIndent(" ").convert(mapping)) |
| 424 ..close(); | 405 ..close(); |
| 425 } | 406 } |
| 426 } | 407 } |
| OLD | NEW |