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 |