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

Side by Side Diff: pkg/compiler/lib/src/js_emitter/new_emitter/model_emitter.dart

Issue 903283002: dart2js: fix deferred loading in the new emitter. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Rebase and clean up. Created 5 years, 10 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) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, 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.new_js_emitter.model_emitter; 5 library dart2js.new_js_emitter.model_emitter;
6 6
7 import '../../dart2jslib.dart' show Compiler; 7 import '../../dart2jslib.dart' show Compiler;
8 import '../../dart_types.dart' show DartType; 8 import '../../dart_types.dart' show DartType;
9 import '../../elements/elements.dart' show ClassElement; 9 import '../../elements/elements.dart' show ClassElement;
10 import '../../js/js.dart' as js; 10 import '../../js/js.dart' as js;
11 import '../../js_backend/js_backend.dart' show 11 import '../../js_backend/js_backend.dart' show
12 JavaScriptBackend, 12 JavaScriptBackend,
13 Namer, 13 Namer,
14 ConstantEmitter; 14 ConstantEmitter;
15 15
16 import '../js_emitter.dart' show 16 import '../js_emitter.dart' show
17 NativeEmitter; 17 NativeEmitter;
18 18
19 import 'package:_internal/compiler/js_lib/shared/embedded_names.dart' show 19 import 'package:_internal/compiler/js_lib/shared/embedded_names.dart' show
20 CREATE_NEW_ISOLATE,
20 DEFERRED_LIBRARY_URIS, 21 DEFERRED_LIBRARY_URIS,
21 DEFERRED_LIBRARY_HASHES, 22 DEFERRED_LIBRARY_HASHES,
22 GET_TYPE_FROM_NAME, 23 GET_TYPE_FROM_NAME,
23 INITIALIZE_LOADED_HUNK, 24 INITIALIZE_LOADED_HUNK,
24 INTERCEPTORS_BY_TAG, 25 INTERCEPTORS_BY_TAG,
25 IS_HUNK_INITIALIZED, 26 IS_HUNK_INITIALIZED,
26 IS_HUNK_LOADED, 27 IS_HUNK_LOADED,
27 LEAF_TAGS, 28 LEAF_TAGS,
28 MANGLED_GLOBAL_NAMES, 29 MANGLED_GLOBAL_NAMES,
29 METADATA, 30 METADATA,
(...skipping 24 matching lines...) Expand all
54 new ConstantEmitter(compiler, namer, makeConstantListTemplate); 55 new ConstantEmitter(compiler, namer, makeConstantListTemplate);
55 56
56 js.Expression generateEmbeddedGlobalAccess(String global) { 57 js.Expression generateEmbeddedGlobalAccess(String global) {
57 // TODO(floitsch): We should not use "init" for globals. 58 // TODO(floitsch): We should not use "init" for globals.
58 return js.js("init.$global"); 59 return js.js("init.$global");
59 } 60 }
60 61
61 int emitProgram(Program program) { 62 int emitProgram(Program program) {
62 List<Fragment> fragments = program.fragments; 63 List<Fragment> fragments = program.fragments;
63 MainFragment mainFragment = fragments.first; 64 MainFragment mainFragment = fragments.first;
64 js.Statement mainAst = emitMainFragment(program);
65 String mainCode = js.prettyPrint(mainAst, compiler).getText();
66 compiler.outputProvider(mainFragment.outputFileName, 'js')
67 ..add(buildGeneratedBy(compiler))
68 ..add(mainCode)
69 ..close();
70 int totalSize = mainCode.length;
71 65
66 int totalSize = 0;
67
68 // We have to emit the deferred fragments first, since we need their
69 // deferred hash (which depends on the output) when emitting the main
70 // fragment.
72 fragments.skip(1).forEach((DeferredFragment deferredUnit) { 71 fragments.skip(1).forEach((DeferredFragment deferredUnit) {
73 js.Expression ast = 72 js.Expression ast =
74 emitDeferredFragment(deferredUnit, mainFragment.holders); 73 emitDeferredFragment(deferredUnit, mainFragment.holders);
75 String code = js.prettyPrint(ast, compiler).getText(); 74 String code = js.prettyPrint(ast, compiler).getText();
76 totalSize += code.length; 75 totalSize += code.length;
77 compiler.outputProvider(deferredUnit.outputFileName, deferredExtension) 76 compiler.outputProvider(deferredUnit.outputFileName, deferredExtension)
78 ..add(code) 77 ..add(code)
79 ..close(); 78 ..close();
80 }); 79 });
80
81 js.Statement mainAst = emitMainFragment(program);
82 String mainCode = js.prettyPrint(mainAst, compiler).getText();
83 compiler.outputProvider(mainFragment.outputFileName, 'js')
84 ..add(buildGeneratedBy(compiler))
85 ..add(mainCode)
86 ..close();
87 totalSize += mainCode.length;
88
81 return totalSize; 89 return totalSize;
82 } 90 }
83 91
84 js.LiteralString unparse(Compiler compiler, js.Expression value) { 92 js.LiteralString unparse(Compiler compiler, js.Node value) {
85 String text = js.prettyPrint(value, compiler).getText(); 93 String text = js.prettyPrint(value, compiler).getText();
86 if (value is js.Fun) text = '($text)'; 94 if (value is js.Fun) text = '($text)';
87 return js.js.escapedString(text); 95 return js.js.escapedString(text);
88 } 96 }
89 97
90 String buildGeneratedBy(compiler) { 98 String buildGeneratedBy(compiler) {
91 var suffix = ''; 99 var suffix = '';
92 if (compiler.hasBuildId) suffix = ' version: ${compiler.buildId}'; 100 if (compiler.hasBuildId) suffix = ' version: ${compiler.buildId}';
93 return '// Generated by dart2js, the Dart to JavaScript compiler$suffix.\n'; 101 return '// Generated by dart2js, the Dart to JavaScript compiler$suffix.\n';
94 } 102 }
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
193 static js.Template get makeConstantListTemplate { 201 static js.Template get makeConstantListTemplate {
194 // TODO(floitsch): remove hard-coded name. 202 // TODO(floitsch): remove hard-coded name.
195 // TODO(floitsch): there is no harm in caching the template. 203 // TODO(floitsch): there is no harm in caching the template.
196 return js.js.uncachedExpressionTemplate('makeConstList(#)'); 204 return js.js.uncachedExpressionTemplate('makeConstList(#)');
197 } 205 }
198 206
199 js.Block emitEmbeddedGlobals(Program program) { 207 js.Block emitEmbeddedGlobals(Program program) {
200 List<js.Property> globals = <js.Property>[]; 208 List<js.Property> globals = <js.Property>[];
201 209
202 if (program.loadMap.isNotEmpty) { 210 if (program.loadMap.isNotEmpty) {
203 globals.addAll(emitLoadUrisAndHashes(program.loadMap)); 211 globals.addAll(emitEmbeddedGlobalsForDeferredLoading(program.loadMap));
204 globals.add(emitIsHunkLoadedFunction());
205 globals.add(emitInitializeLoadedHunk());
206 } 212 }
207 213
208 if (program.typeToInterceptorMap != null) { 214 if (program.typeToInterceptorMap != null) {
209 globals.add(new js.Property(js.string(TYPE_TO_INTERCEPTOR_MAP), 215 globals.add(new js.Property(js.string(TYPE_TO_INTERCEPTOR_MAP),
210 program.typeToInterceptorMap)); 216 program.typeToInterceptorMap));
211 } 217 }
212 218
219 if (program.hasIsolateSupport) {
220 String isolateName = namer.currentIsolate;
221 globals.add(
222 new js.Property(js.string(CREATE_NEW_ISOLATE),
223 js.js('function () { return $isolateName; }')));
224 // TODO(floitsch): add remaining isolate functions.
225 }
226
213 globals.add(emitMangledGlobalNames()); 227 globals.add(emitMangledGlobalNames());
214 228
215 globals.add(emitGetTypeFromName()); 229 globals.add(emitGetTypeFromName());
216 230
217 globals.add(emitMetadata(program)); 231 globals.add(emitMetadata(program));
218 232
219 if (program.outputContainsNativeClasses) { 233 if (program.outputContainsNativeClasses) {
220 globals.add(new js.Property(js.string(INTERCEPTORS_BY_TAG), 234 globals.add(new js.Property(js.string(INTERCEPTORS_BY_TAG),
221 js.js('Object.create(null)', []))); 235 js.js('Object.create(null)', [])));
222 globals.add(new js.Property(js.string(LEAF_TAGS), 236 globals.add(new js.Property(js.string(LEAF_TAGS),
(...skipping 22 matching lines...) Expand all
245 compiler.listClass]; 259 compiler.listClass];
246 nativeClassesNeedingUnmangledName.forEach((element) { 260 nativeClassesNeedingUnmangledName.forEach((element) {
247 names.add(new js.Property(js.string(namer.getNameOfClass(element)), 261 names.add(new js.Property(js.string(namer.getNameOfClass(element)),
248 js.string(element.name))); 262 js.string(element.name)));
249 }); 263 });
250 264
251 return new js.Property(js.string(MANGLED_GLOBAL_NAMES), 265 return new js.Property(js.string(MANGLED_GLOBAL_NAMES),
252 new js.ObjectInitializer(names)); 266 new js.ObjectInitializer(names));
253 } 267 }
254 268
255 List<js.Property> emitLoadUrisAndHashes(Map<String, List<Fragment>> loadMap) { 269 js.Statement emitDeferredInitializerGlobal(Map loadMap) {
256 js.ArrayInitializer outputUris(List<Fragment> fragments) { 270 if (loadMap.isEmpty) return new js.Block.empty();
271
272 return js.js.statement("""
273 if (typeof($deferredInitializersGlobal) === 'undefined')
274 var $deferredInitializersGlobal = Object.create(null);""");
275 }
276
277 Iterable<js.Property> emitEmbeddedGlobalsForDeferredLoading(
278 Map<String, List<Fragment>> loadMap) {
279
280 List<js.Property> globals = <js.Property>[];
281
282 js.ArrayInitializer fragmentUris(List<Fragment> fragments) {
257 return js.stringArray(fragments.map((DeferredFragment fragment) => 283 return js.stringArray(fragments.map((DeferredFragment fragment) =>
258 "${fragment.outputFileName}$deferredExtension")); 284 "${fragment.outputFileName}.$deferredExtension"));
259 } 285 }
260 js.ArrayInitializer outputHashes(List<Fragment> fragments) { 286 js.ArrayInitializer fragmentHashes(List<Fragment> fragments) {
261 // TODO(floitsch): the hash must depend on the generated code. 287 // TODO(floitsch): the hash must depend on the generated code.
262 return js.numArray( 288 return js.numArray(
263 fragments.map((DeferredFragment fragment) => fragment.hashCode)); 289 fragments.map((DeferredFragment fragment) => fragment.hashCode));
264 } 290 }
265 291
266 List<js.Property> uris = new List<js.Property>(loadMap.length); 292 List<js.Property> uris = new List<js.Property>(loadMap.length);
267 List<js.Property> hashes = new List<js.Property>(loadMap.length); 293 List<js.Property> hashes = new List<js.Property>(loadMap.length);
268 int count = 0; 294 int count = 0;
269 loadMap.forEach((String loadId, List<Fragment> fragmentList) { 295 loadMap.forEach((String loadId, List<Fragment> fragmentList) {
270 uris[count] = 296 uris[count] =
271 new js.Property(js.string(loadId), outputUris(fragmentList)); 297 new js.Property(js.string(loadId), fragmentUris(fragmentList));
272 hashes[count] = 298 hashes[count] =
273 new js.Property(js.string(loadId), outputHashes(fragmentList)); 299 new js.Property(js.string(loadId), fragmentHashes(fragmentList));
274 count++; 300 count++;
275 }); 301 });
276 302
277 return <js.Property>[ 303 globals.add(new js.Property(js.string(DEFERRED_LIBRARY_URIS),
278 new js.Property(js.string(DEFERRED_LIBRARY_URIS), 304 new js.ObjectInitializer(uris)));
279 new js.ObjectInitializer(uris)), 305 globals.add(new js.Property(js.string(DEFERRED_LIBRARY_HASHES),
280 new js.Property(js.string(DEFERRED_LIBRARY_HASHES), 306 new js.ObjectInitializer(hashes)));
281 new js.ObjectInitializer(hashes))
282 ];
283 }
284 307
285 js.Statement emitDeferredInitializerGlobal(Map loadMap) { 308 js.Expression isHunkLoadedFunction =
286 if (loadMap.isEmpty) return new js.Block.empty(); 309 js.js("function(hash) { return !!$deferredInitializersGlobal[hash]; }");
310 globals.add(new js.Property(js.string(IS_HUNK_LOADED),
311 isHunkLoadedFunction));
287 312
288 return js.js.statement(""" 313 js.Expression isHunkInitializedFunction =
289 if (typeof($deferredInitializersGlobal) === 'undefined') 314 js.js("function(hash) { return false; }");
290 var $deferredInitializersGlobal = Object.create(null);"""); 315 globals.add(new js.Property(js.string(IS_HUNK_INITIALIZED),
291 } 316 isHunkInitializedFunction));
292 317
293 js.Property emitIsHunkLoadedFunction() { 318 /// See [emitEmbeddedGlobalsForDeferredLoading] for the format of the
294 js.Expression function = 319 /// deferred hunk.
295 js.js("function(hash) { return !!$deferredInitializersGlobal[hash]; }"); 320 js.Expression initializeLoadedHunkFunction =
296 return new js.Property(js.string(IS_HUNK_LOADED), function); 321 js.js("""
297 } 322 function(hash) {
323 var hunk = $deferredInitializersGlobal[hash];
324 $setupProgramName(hunk[0]);
325 eval(hunk[1]);
326 }""");
298 327
299 js.Property emitInitializeLoadedHunk() { 328 globals.add(new js.Property(js.string(INITIALIZE_LOADED_HUNK),
300 js.Expression function = 329 initializeLoadedHunkFunction));
301 js.js("function(hash) { eval($deferredInitializersGlobal[hash]); }"); 330
302 return new js.Property(js.string(INITIALIZE_LOADED_HUNK), function); 331 return globals;
303 } 332 }
304 333
305 js.Property emitGetTypeFromName() { 334 js.Property emitGetTypeFromName() {
306 js.Expression function = 335 js.Expression function =
307 js.js( """function(name) { 336 js.js( """function(name) {
308 return holdersMap[name][name].ensureResolved(); 337 return holdersMap[name][name].ensureResolved();
309 }"""); 338 }""");
310 return new js.Property(js.string(GET_TYPE_FROM_NAME), function); 339 return new js.Property(js.string(GET_TYPE_FROM_NAME), function);
311 } 340 }
312 341
313 js.Property emitMetadata(Program program) { 342 js.Property emitMetadata(Program program) {
314 String metadataList = "[${program.metadata.join(",")}]"; 343 String metadataList = "[${program.metadata.join(",")}]";
315 js.Expression metadata = 344 js.Expression metadata =
316 js.js.uncachedExpressionTemplate(metadataList).instantiate([]); 345 js.js.uncachedExpressionTemplate(metadataList).instantiate([]);
317 346
318 return new js.Property(js.string(METADATA), metadata); 347 return new js.Property(js.string(METADATA), metadata);
319 } 348 }
320 349
321 js.Expression emitDeferredFragment(DeferredFragment fragment, 350 js.Expression emitDeferredFragment(DeferredFragment fragment,
322 List<Holder> holders) { 351 List<Holder> holders) {
323 // TODO(floitsch): initialize eager classes. 352 // TODO(floitsch): initialize eager classes.
324 // TODO(floitsch): the hash must depend on the output. 353 // TODO(floitsch): the hash must depend on the output.
325 int hash = this.hashCode; 354 int hash = fragment.hashCode;
326 if (fragment.constants.isNotEmpty) { 355
327 throw new UnimplementedError("constants in deferred units"); 356 List<js.Expression> deferredCode =
328 } 357 fragment.libraries.map(emitLibrary).toList();
329 js.ArrayInitializer content = 358
330 new js.ArrayInitializer(fragment.libraries.map(emitLibrary) 359 deferredCode.add(
331 .toList(growable: false)); 360 emitLazilyInitializedStatics(fragment.staticLazilyInitializedFields));
332 return js.js("$deferredInitializersGlobal[$hash] = #", content); 361
362 js.ArrayInitializer deferredArray = new js.ArrayInitializer(deferredCode);
363
364 // This is the code that must be evaluated after all deferred classes have
365 // been setup.
366 js.Statement immediateCode = js.js.statement('''{
367 #constants;
368 #eagerClasses;
369 }''',
370 {'constants': emitConstants(fragment.constants),
371 'eagerClasses': emitEagerClassInitializations(fragment.libraries)});
372
373 js.LiteralString immediateString = unparse(compiler, immediateCode);
374 js.ArrayInitializer hunk =
375 new js.ArrayInitializer([deferredArray, immediateString]);
376
377 return js.js("$deferredInitializersGlobal[$hash] = #", hunk);
333 } 378 }
334 379
335 js.Block emitConstants(List<Constant> constants) { 380 js.Block emitConstants(List<Constant> constants) {
336 Iterable<js.Statement> statements = constants.map((Constant constant) { 381 Iterable<js.Statement> statements = constants.map((Constant constant) {
337 js.Expression code = 382 js.Expression code =
338 constantEmitter.initializationExpression(constant.value); 383 constantEmitter.initializationExpression(constant.value);
339 return js.js.statement("#.# = #;", 384 return js.js.statement("#.# = #;",
340 [constant.holder.name, constant.name, code]); 385 [constant.holder.name, constant.name, code]);
341 }); 386 });
342 return new js.Block(statements.toList()); 387 return new js.Block(statements.toList());
(...skipping 309 matching lines...) Expand 10 before | Expand all | Expand 10 after
652 data.addAll(method.parameterStubs.expand(makeNameCallNameCodeTriplet)); 697 data.addAll(method.parameterStubs.expand(makeNameCallNameCodeTriplet));
653 return [js.string(method.name), holderIndex, 698 return [js.string(method.name), holderIndex,
654 new js.ArrayInitializer(data)]; 699 new js.ArrayInitializer(data)];
655 } else { 700 } else {
656 method.parameterStubs.forEach(_addMethod); 701 method.parameterStubs.forEach(_addMethod);
657 } 702 }
658 } 703 }
659 return output; 704 return output;
660 } 705 }
661 706
707 static final String setupProgramName = "setupProgram";
708
662 static final String boilerplate = """ 709 static final String boilerplate = """
663 { 710 {
664 // Declare deferred-initializer global. 711 // Declare deferred-initializer global.
665 #deferredInitializer; 712 #deferredInitializer;
666 713
667 !function(start, program) { 714 !function(start, program) {
668 // Initialize holder objects. 715 // Initialize holder objects.
669 #holders; 716 #holders;
670 var nativeInfos = Object.create(null); 717 var nativeInfos = Object.create(null);
671 718
672 // Counter to generate unique names for tear offs. 719 // Counter to generate unique names for tear offs.
673 var functionCounter = 0; 720 var functionCounter = 0;
674 721
675 function setupProgram() { 722 function $setupProgramName(program) {
676 for (var i = 0; i < program.length - 1; i++) { 723 for (var i = 0; i < program.length - 1; i++) {
677 setupLibrary(program[i]); 724 setupLibrary(program[i]);
678 } 725 }
679 setupLazyStatics(program[i]); 726 setupLazyStatics(program[i]);
680 } 727 }
681 728
682 function setupLibrary(library) { 729 function setupLibrary(library) {
683 var statics = library[0]; 730 var statics = library[0];
684 for (var i = 0; i < statics.length; i += 3) { 731 for (var i = 0; i < statics.length; i += 3) {
685 var holderIndex = statics[i + 1]; 732 var holderIndex = statics[i + 1];
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after
898 if (#hasNativeClasses) { 945 if (#hasNativeClasses) {
899 function handleNativeClassInfos() { 946 function handleNativeClassInfos() {
900 for (var nativeClass in nativeInfos) { 947 for (var nativeClass in nativeInfos) {
901 var constructor = holdersMap[nativeClass][nativeClass].ensureResolved(); 948 var constructor = holdersMap[nativeClass][nativeClass].ensureResolved();
902 var nativeInfo = nativeInfos[nativeClass]; 949 var nativeInfo = nativeInfos[nativeClass];
903 #nativeInfoHandler; 950 #nativeInfoHandler;
904 } 951 }
905 } 952 }
906 } 953 }
907 954
908 setupProgram(); 955 $setupProgramName(program);
909 956
910 // Initialize constants. 957 // Initialize constants.
911 #constants; 958 #constants;
912 959
913 // Initialize globals. 960 // Initialize globals.
914 #embeddedGlobals; 961 #embeddedGlobals;
915 962
916 // TODO(floitsch): this order means that native classes may not be 963 // TODO(floitsch): this order means that native classes may not be
917 // referenced from constants. I'm mostly afraid of things like using them as 964 // referenced from constants. I'm mostly afraid of things like using them as
918 // generic arguments (which should be fine, but maybe there are other 965 // generic arguments (which should be fine, but maybe there are other
919 // similar things). 966 // similar things).
920 // Initialize natives. 967 // Initialize natives.
921 if (#hasNativeClasses) handleNativeClassInfos(); 968 if (#hasNativeClasses) handleNativeClassInfos();
922 969
923 // Initialize static non-final fields. 970 // Initialize static non-final fields.
924 #staticNonFinals; 971 #staticNonFinals;
925 972
926 // Add native boilerplate code. 973 // Add native boilerplate code.
927 #nativeIsolateAffinityTagInitialization; 974 #nativeIsolateAffinityTagInitialization;
928 975
929 // Initialize eager classes. 976 // Initialize eager classes.
930 #eagerClasses; 977 #eagerClasses;
931 978
932 var end = Date.now(); 979 var end = Date.now();
933 print('Setup: ' + (end - start) + ' ms.'); 980 // print('Setup: ' + (end - start) + ' ms.');
zarah 2015/02/10 15:05:24 Why comment it out?
floitsch 2015/02/10 15:13:34 Because it doesn't work in the browser.
934 981
935 #invokeMain; // Start main. 982 #invokeMain; // Start main.
936 983
937 }(Date.now(), #code) 984 }(Date.now(), #code)
938 }"""; 985 }""";
939 986
940 } 987 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/js_emitter/model.dart ('k') | pkg/compiler/lib/src/js_emitter/program_builder.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698