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

Side by Side Diff: pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart

Issue 2847343002: Add support for profile-based startup optimizations. (Closed)
Patch Set: Fix forgotten cleanup. Created 3 years, 7 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
OLDNEW
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 part of dart2js.js_emitter.startup_emitter.model_emitter; 5 part of dart2js.js_emitter.startup_emitter.model_emitter;
6 6
7 /// The name of the property that stores the tear-off getter on a static 7 /// The name of the property that stores the tear-off getter on a static
8 /// function. 8 /// function.
9 /// 9 ///
10 /// This property is only used when isolates are used. 10 /// This property is only used when isolates are used.
(...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after
290 // Every deferred hunk (i.e. fragment) is a function that we can invoke to 290 // Every deferred hunk (i.e. fragment) is a function that we can invoke to
291 // initialize it. At this moment it contributes its data to the main hunk. 291 // initialize it. At this moment it contributes its data to the main hunk.
292 function initializeDeferredHunk(hunk) { 292 function initializeDeferredHunk(hunk) {
293 // Update the typesOffset for the next deferred library. 293 // Update the typesOffset for the next deferred library.
294 typesOffset = #embeddedTypes.length; 294 typesOffset = #embeddedTypes.length;
295 295
296 // TODO(floitsch): extend natives. 296 // TODO(floitsch): extend natives.
297 hunk(inherit, mixin, lazy, makeConstList, convertToFastObject, installTearOff, 297 hunk(inherit, mixin, lazy, makeConstList, convertToFastObject, installTearOff,
298 setFunctionNamesIfNecessary, updateHolder, updateTypes, 298 setFunctionNamesIfNecessary, updateHolder, updateTypes,
299 setOrUpdateInterceptorsByTag, setOrUpdateLeafTags, 299 setOrUpdateInterceptorsByTag, setOrUpdateLeafTags,
300 #embeddedGlobalsObject, #holdersList, #staticState); 300 #embeddedGlobalsObject, holders, #staticState);
301 } 301 }
302 302
303 // Returns the global with the given [name]. 303 // Returns the global with the given [name].
304 function getGlobalFromName(name) { 304 function getGlobalFromName(name) {
305 // TODO(floitsch): we are running through all holders. Since negative 305 // TODO(floitsch): we are running through all holders. Since negative
306 // lookups are expensive we might need to improve this. 306 // lookups are expensive we might need to improve this.
307 // Relies on the fact that all names are unique across all holders. 307 // Relies on the fact that all names are unique across all holders.
308 for (var i = 0; i < holders.length; i++) { 308 for (var i = 0; i < holders.length; i++) {
309 // The constant holder reuses the same names. Therefore we must skip it. 309 // The constant holder reuses the same names. Therefore we must skip it.
310 if (holders[i] == #constantHolderReference) continue; 310 if (holders[i] == #constantHolderReference) continue;
311 // Relies on the fact that all variables are unique. 311 // Relies on the fact that all variables are unique.
312 if (holders[i][name]) return holders[i][name]; 312 if (holders[i][name]) return holders[i][name];
313 } 313 }
314 } 314 }
315 315
316 if (#hasSoftDeferredClasses) {
317 // Loads the soft-deferred classes and initializes them.
318 // Updates the prototype of the given object.
319 function softDef(o) {
320 softDef = function(o) {}; // Replace ourselves.
321 #deferredGlobal[#softId](
322 holders, #embeddedGlobalsObject, #staticState, inherit, mixin,
323 installTearOff);
324 o.__proto__ = o.constructor.prototype;
sra1 2017/05/02 20:40:13 This will make Firefox angry.
floitsch 2017/05/06 19:25:43 Yes. I added a comment.
325 }
326 }
327
328 if (#isTrackingAllocations) {
329 var allocations = #deferredGlobal['allocations'] = {};
330 }
331
316 // Creates the holders. 332 // Creates the holders.
317 #holders; 333 #holders;
318 334
319 // If the name is not set on the functions, do it now. 335 // If the name is not set on the functions, do it now.
320 setFunctionNamesIfNecessary(#holdersList); 336 setFunctionNamesIfNecessary(holders);
321 337
322 // TODO(floitsch): we should build this object as a literal. 338 // TODO(floitsch): we should build this object as a literal.
323 var #staticStateDeclaration = {}; 339 var #staticStateDeclaration = {};
324 340
325 // Sets the prototypes of classes. 341 // Sets the prototypes of classes.
326 #prototypes; 342 #prototypes;
327 // Sets aliases of methods (on the prototypes of classes). 343 // Sets aliases of methods (on the prototypes of classes).
328 #aliases; 344 #aliases;
329 // Installs the tear-offs of functions. 345 // Installs the tear-offs of functions.
330 #tearOffs; 346 #tearOffs;
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
422 #staticNonFinalFields; 438 #staticNonFinalFields;
423 // Creates lazy getters for statics that must run initializers on first access. 439 // Creates lazy getters for statics that must run initializers on first access.
424 #lazyStatics; 440 #lazyStatics;
425 441
426 updateTypes(#types); 442 updateTypes(#types);
427 443
428 // Native-support uses setOrUpdateInterceptorsByTag and setOrUpdateLeafTags. 444 // Native-support uses setOrUpdateInterceptorsByTag and setOrUpdateLeafTags.
429 #nativeSupport; 445 #nativeSupport;
430 }'''; 446 }''';
431 447
448 /// Soft-deferred fragments are built similarly to the main fragment.
449 ///
450 /// However, they don't contribute anything to global namespace, but just
451 /// initialize existing classes. For example, they update the inheritance
452 /// hierarchy, and add methods the prototypes.
453 const String softDeferredBoilerplate = '''
454 #deferredGlobal[#softId] =
455 function(holdersList, #embeddedGlobalsObject, #staticState, inherit, mixin,
456 installTearOff) {
457
458 // Installs the holders as local variables.
459 #installHoldersAsLocals;
460 // Sets the prototypes of the new classes.
461 #prototypes;
462 // Sets aliases of methods (on the prototypes of classes).
463 #aliases;
464 // Installs the tear-offs of functions.
465 #tearOffs;
466 // Builds the inheritance structure.
467 #inheritance;
468 }''';
469
432 /** 470 /**
433 * This class builds a JavaScript tree for a given fragment. 471 * This class builds a JavaScript tree for a given fragment.
434 * 472 *
435 * A fragment is generally written into a separate file so that it can be 473 * A fragment is generally written into a separate file so that it can be
436 * loaded dynamically when a deferred library is loaded. 474 * loaded dynamically when a deferred library is loaded.
437 * 475 *
438 * This class is stateless and can be reused for different fragments. 476 * This class is stateless and can be reused for different fragments.
439 */ 477 */
440 class FragmentEmitter { 478 class FragmentEmitter {
441 final Compiler compiler; 479 final Compiler compiler;
(...skipping 15 matching lines...) Expand all
457 return js.js('#.#', [cls.holder.name, cls.name]); 495 return js.js('#.#', [cls.holder.name, cls.name]);
458 } 496 }
459 497
460 js.Statement emitMainFragment(Program program, 498 js.Statement emitMainFragment(Program program,
461 Map<DeferredFragment, _DeferredFragmentHash> deferredLoadHashes) { 499 Map<DeferredFragment, _DeferredFragmentHash> deferredLoadHashes) {
462 MainFragment fragment = program.fragments.first; 500 MainFragment fragment = program.fragments.first;
463 501
464 Iterable<Holder> nonStaticStateHolders = 502 Iterable<Holder> nonStaticStateHolders =
465 program.holders.where((Holder holder) => !holder.isStaticStateHolder); 503 program.holders.where((Holder holder) => !holder.isStaticStateHolder);
466 504
467 return js.js.statement(mainBoilerplate, { 505 String softDeferredId = "softDeferred${new Random().nextInt(0x7FFFFFFF)}";
468 'directAccessTestExpression': js.js(directAccessTestExpression), 506
469 'typeNameProperty': js.string(ModelEmitter.typeNameProperty), 507 return new js.Block([
470 'cyclicThrow': backend.emitter 508 program.hasSoftDeferredClasses
471 .staticFunctionAccess(compiler.commonElements.cyclicThrowHelper), 509 ? js.js.statement(softDeferredBoilerplate, {
472 'operatorIsPrefix': js.string(namer.operatorIsPrefix), 510 'deferredGlobal': ModelEmitter.deferredInitializersGlobal,
473 'tearOffCode': new js.Block(buildTearOffCode(compiler.options, 511 'softId': js.string(softDeferredId),
474 backend.emitter.emitter, backend.namer, compiler.commonElements)), 512 // TODO(floitsch): don't just reference 'init'.
475 'embeddedTypes': generateEmbeddedGlobalAccess(TYPES), 513 'embeddedGlobalsObject': new js.Parameter('init'),
476 'embeddedInterceptorTags': 514 'staticState': new js.Parameter(namer.staticStateHolder),
477 generateEmbeddedGlobalAccess(INTERCEPTORS_BY_TAG), 515 'installHoldersAsLocals':
478 'embeddedLeafTags': generateEmbeddedGlobalAccess(LEAF_TAGS), 516 emitInstallHoldersAsLocals(nonStaticStateHolders),
479 'embeddedGlobalsObject': js.js("init"), 517 'prototypes': emitPrototypes(fragment, softDeferred: true),
480 'holdersList': new js.ArrayInitializer(nonStaticStateHolders 518 'aliases':
481 .map((holder) => js.js("#", holder.name)) 519 emitInstanceMethodAliases(fragment, softDeferred: true),
482 .toList(growable: false)), 520 'tearOffs': emitInstallTearOffs(fragment, softDeferred: true),
483 'staticStateDeclaration': new js.VariableDeclaration( 521 'inheritance': emitInheritance(fragment, softDeferred: true),
484 namer.staticStateHolder, 522 })
485 allowRename: false),
486 'staticState': js.js('#', namer.staticStateHolder),
487 'constantHolderReference': buildConstantHolderReference(program),
488 'holders': emitHolders(program.holders, fragment),
489 'callName': js.string(namer.callNameField),
490 'stubName': js.string(namer.stubNameField),
491 'argumentCount': js.string(namer.requiredParameterField),
492 'defaultArgumentValues': js.string(namer.defaultValuesField),
493 'prototypes': emitPrototypes(fragment),
494 'inheritance': emitInheritance(fragment),
495 'aliases': emitInstanceMethodAliases(fragment),
496 'tearOffs': emitInstallTearOffs(fragment),
497 'constants': emitConstants(fragment),
498 'staticNonFinalFields': emitStaticNonFinalFields(fragment),
499 'lazyStatics': emitLazilyInitializedStatics(fragment),
500 'embeddedGlobals': emitEmbeddedGlobals(program, deferredLoadHashes),
501 'nativeSupport': program.needsNativeSupport
502 ? emitNativeSupport(fragment)
503 : new js.EmptyStatement(), 523 : new js.EmptyStatement(),
504 'jsInteropSupport': backend.jsInteropAnalysis.enabledJsInterop 524 js.js.statement(mainBoilerplate, {
505 ? backend.jsInteropAnalysis.buildJsInteropBootstrap() 525 'directAccessTestExpression': js.js(directAccessTestExpression),
506 : new js.EmptyStatement(), 526 'typeNameProperty': js.string(ModelEmitter.typeNameProperty),
507 'invokeMain': fragment.invokeMain, 527 'cyclicThrow': backend.emitter
508 }); 528 .staticFunctionAccess(compiler.commonElements.cyclicThrowHelper),
529 'operatorIsPrefix': js.string(namer.operatorIsPrefix),
530 'tearOffCode': new js.Block(buildTearOffCode(compiler.options,
531 backend.emitter.emitter, backend.namer, compiler.commonElements)),
532 'embeddedTypes': generateEmbeddedGlobalAccess(TYPES),
533 'embeddedInterceptorTags':
534 generateEmbeddedGlobalAccess(INTERCEPTORS_BY_TAG),
535 'embeddedLeafTags': generateEmbeddedGlobalAccess(LEAF_TAGS),
536 'embeddedGlobalsObject': js.js("init"),
537 'staticStateDeclaration': new js.VariableDeclaration(
538 namer.staticStateHolder,
539 allowRename: false),
540 'staticState': js.js('#', namer.staticStateHolder),
541 'constantHolderReference': buildConstantHolderReference(program),
542 'holders': emitHolders(program.holders, fragment),
543 'callName': js.string(namer.callNameField),
544 'stubName': js.string(namer.stubNameField),
545 'argumentCount': js.string(namer.requiredParameterField),
546 'defaultArgumentValues': js.string(namer.defaultValuesField),
547 'deferredGlobal': ModelEmitter.deferredInitializersGlobal,
548 'hasSoftDeferredClasses': program.hasSoftDeferredClasses,
549 'softId': js.string(softDeferredId),
550 'isTrackingAllocations': compiler.options.trackAllocations,
551 'prototypes': emitPrototypes(fragment),
552 'inheritance': emitInheritance(fragment),
553 'aliases': emitInstanceMethodAliases(fragment),
554 'tearOffs': emitInstallTearOffs(fragment),
555 'constants': emitConstants(fragment),
556 'staticNonFinalFields': emitStaticNonFinalFields(fragment),
557 'lazyStatics': emitLazilyInitializedStatics(fragment),
558 'embeddedGlobals': emitEmbeddedGlobals(program, deferredLoadHashes),
559 'nativeSupport': program.needsNativeSupport
560 ? emitNativeSupport(fragment)
561 : new js.EmptyStatement(),
562 'jsInteropSupport': backend.jsInteropAnalysis.enabledJsInterop
563 ? backend.jsInteropAnalysis.buildJsInteropBootstrap()
564 : new js.EmptyStatement(),
565 'invokeMain': fragment.invokeMain,
566 }),
567 ]);
568 }
569
570 js.Statement emitInstallHoldersAsLocals(Iterable<Holder> holders) {
571 List<js.Statement> holderInits = <js.Statement>[];
572 int counter = 0;
573 for (Holder holder in holders) {
574 holderInits.add(new js.ExpressionStatement(new js.VariableInitialization(
575 new js.VariableDeclaration(holder.name, allowRename: false),
576 js.js("holdersList[#]", js.number(counter++)))));
577 }
578 return new js.Block(holderInits);
509 } 579 }
510 580
511 js.Expression emitDeferredFragment(DeferredFragment fragment, 581 js.Expression emitDeferredFragment(DeferredFragment fragment,
512 js.Expression deferredTypes, List<Holder> holders) { 582 js.Expression deferredTypes, List<Holder> holders) {
513 List<Holder> nonStaticStateHolders = holders 583 List<Holder> nonStaticStateHolders = holders
514 .where((Holder holder) => !holder.isStaticStateHolder) 584 .where((Holder holder) => !holder.isStaticStateHolder)
515 .toList(growable: false); 585 .toList(growable: false);
516 586
517 List<js.Statement> updateHolderAssignments = <js.Statement>[]; 587 List<js.Statement> updateHolderAssignments = <js.Statement>[];
518 for (int i = 0; i < nonStaticStateHolders.length; i++) { 588 for (int i = 0; i < nonStaticStateHolders.length; i++) {
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
650 // If the class is not directly instantiated we only need it for inheritance 720 // If the class is not directly instantiated we only need it for inheritance
651 // or RTI. In either case we don't need its fields. 721 // or RTI. In either case we don't need its fields.
652 if (cls.isNative || !cls.isDirectlyInstantiated) { 722 if (cls.isNative || !cls.isDirectlyInstantiated) {
653 return js.js('function #() { }', name); 723 return js.js('function #() { }', name);
654 } 724 }
655 725
656 var statements = <js.Statement>[]; 726 var statements = <js.Statement>[];
657 var parameters = <js.Name>[]; 727 var parameters = <js.Name>[];
658 var thisRef; 728 var thisRef;
659 729
730 if (cls.isSoftDeferred) {
731 statements.add(js.js.statement('softDef(this)'));
732 } else if (compiler.options.trackAllocations) {
733 String qualifiedName =
734 "${cls.element.library.canonicalUri}:${cls.element.name}";
735 statements.add(js.js.statement('allocations["$qualifiedName"] = true'));
736 }
737
660 // If there are many references to `this`, cache it in a local. 738 // If there are many references to `this`, cache it in a local.
661 if (cls.fields.length + (cls.hasRtiField ? 1 : 0) >= 4) { 739 if (cls.fields.length + (cls.hasRtiField ? 1 : 0) >= 4) {
662 // TODO(29455): Fix js_ast printer and minifier to avoid conflicts between 740 // TODO(29455): Fix js_ast printer and minifier to avoid conflicts between
663 // js.Name and string-named variables, then use '_' in the js template 741 // js.Name and string-named variables, then use '_' in the js template
664 // text. 742 // text.
665 743
666 // We pick '_' in minified mode because no field minifies to '_'. This 744 // We pick '_' in minified mode because no field minifies to '_'. This
667 // avoids a conflict with one of the parameters which are named the same 745 // avoids a conflict with one of the parameters which are named the same
668 // as the fields. Unminified, a field might have the name '_', so we pick 746 // as the fields. Unminified, a field might have the name '_', so we pick
669 // '$_', which is an impossible member name since we escape '$'s in names. 747 // '$_', which is an impossible member name since we escape '$'s in names.
(...skipping 20 matching lines...) Expand all
690 .statement('#.# = #', [thisRef, namer.rtiFieldJsName, paramName])); 768 .statement('#.# = #', [thisRef, namer.rtiFieldJsName, paramName]));
691 } 769 }
692 770
693 return js.js('function #(#) { # }', [name, parameters, statements]); 771 return js.js('function #(#) { # }', [name, parameters, statements]);
694 } 772 }
695 773
696 /// Emits the prototype-section of the fragment. 774 /// Emits the prototype-section of the fragment.
697 /// 775 ///
698 /// This section updates the prototype-property of all constructors in the 776 /// This section updates the prototype-property of all constructors in the
699 /// global holders. 777 /// global holders.
700 js.Statement emitPrototypes(Fragment fragment) { 778 js.Statement emitPrototypes(Fragment fragment, {softDeferred = false}) {
701 List<js.Statement> assignments = fragment.libraries 779 List<js.Statement> assignments = fragment.libraries
702 .expand((Library library) => library.classes) 780 .expand((Library library) => library.classes)
781 .where((Class cls) => cls.isSoftDeferred == softDeferred)
703 .map((Class cls) { 782 .map((Class cls) {
704 var proto = js.js.statement( 783 var proto = js.js.statement(
705 '#.prototype = #;', [classReference(cls), emitPrototype(cls)]); 784 '#.prototype = #;', [classReference(cls), emitPrototype(cls)]);
706 ClassElement element = cls.element; 785 ClassElement element = cls.element;
707 compiler.dumpInfoTask.registerElementAst(element, proto); 786 compiler.dumpInfoTask.registerElementAst(element, proto);
708 compiler.dumpInfoTask.registerElementAst(element.library, proto); 787 compiler.dumpInfoTask.registerElementAst(element.library, proto);
709 return proto; 788 return proto;
710 }).toList(growable: false); 789 }).toList(growable: false);
711 790
712 return new js.Block(assignments); 791 return new js.Block(assignments);
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
857 } 936 }
858 } 937 }
859 938
860 return properties; 939 return properties;
861 } 940 }
862 941
863 /// Emits the inheritance block of the fragment. 942 /// Emits the inheritance block of the fragment.
864 /// 943 ///
865 /// In this section prototype chains are updated and mixin functions are 944 /// In this section prototype chains are updated and mixin functions are
866 /// copied. 945 /// copied.
867 js.Statement emitInheritance(Fragment fragment) { 946 js.Statement emitInheritance(Fragment fragment, {bool softDeferred = false}) {
868 List<js.Statement> inheritCalls = <js.Statement>[]; 947 List<js.Statement> inheritCalls = <js.Statement>[];
869 List<js.Statement> mixinCalls = <js.Statement>[]; 948 List<js.Statement> mixinCalls = <js.Statement>[];
870 949
871 Set<Class> classesInFragment = new Set<Class>(); 950 Set<Class> classesInFragment = new Set<Class>();
872 for (Library library in fragment.libraries) { 951 for (Library library in fragment.libraries) {
873 classesInFragment.addAll(library.classes); 952 classesInFragment.addAll(library.classes
953 .where(((Class cls) => cls.isSoftDeferred == softDeferred)));
874 } 954 }
875 955
876 Map<Class, List<Class>> subclasses = <Class, List<Class>>{}; 956 Map<Class, List<Class>> subclasses = <Class, List<Class>>{};
877 Set<Class> seen = new Set<Class>(); 957 Set<Class> seen = new Set<Class>();
878 958
879 void collect(cls) { 959 void collect(cls) {
880 if (cls == null || seen.contains(cls)) return; 960 if (cls == null || seen.contains(cls)) return;
881 961
882 Class superclass = cls.superclass; 962 Class superclass = cls.superclass;
883 if (classesInFragment.contains(superclass)) { 963 if (classesInFragment.contains(superclass)) {
884 collect(superclass); 964 collect(superclass);
885 } 965 }
886 966
887 subclasses.putIfAbsent(superclass, () => <Class>[]).add(cls); 967 subclasses.putIfAbsent(superclass, () => <Class>[]).add(cls);
888 968
889 seen.add(cls); 969 seen.add(cls);
890 } 970 }
891 971
892 for (Library library in fragment.libraries) { 972 for (Library library in fragment.libraries) {
893 for (Class cls in library.classes) { 973 for (Class cls in library.classes) {
974 if (cls.isSoftDeferred != softDeferred) continue;
894 collect(cls); 975 collect(cls);
895 976
896 if (cls.isMixinApplication) { 977 if (cls.isMixinApplication) {
897 MixinApplication mixin = cls; 978 MixinApplication mixin = cls;
898 mixinCalls.add(js.js.statement('mixin(#, #)', 979 mixinCalls.add(js.js.statement('mixin(#, #)',
899 [classReference(cls), classReference(mixin.mixinClass)])); 980 [classReference(cls), classReference(mixin.mixinClass)]));
900 } 981 }
901 } 982 }
902 } 983 }
903 984
(...skipping 26 matching lines...) Expand all
930 } 1011 }
931 1012
932 return wrapPhase( 1013 return wrapPhase(
933 'inheritance', js.js.statement('{#; #;}', [inheritCalls, mixinCalls])); 1014 'inheritance', js.js.statement('{#; #;}', [inheritCalls, mixinCalls]));
934 } 1015 }
935 1016
936 /// Emits the setup of method aliases. 1017 /// Emits the setup of method aliases.
937 /// 1018 ///
938 /// This step consists of simply copying JavaScript functions to their 1019 /// This step consists of simply copying JavaScript functions to their
939 /// aliased names so they point to the same function. 1020 /// aliased names so they point to the same function.
940 js.Statement emitInstanceMethodAliases(Fragment fragment) { 1021 js.Statement emitInstanceMethodAliases(Fragment fragment,
1022 {bool softDeferred = false}) {
941 List<js.Statement> assignments = <js.Statement>[]; 1023 List<js.Statement> assignments = <js.Statement>[];
942 1024
943 for (Library library in fragment.libraries) { 1025 for (Library library in fragment.libraries) {
944 for (Class cls in library.classes) { 1026 for (Class cls in library.classes) {
1027 if (cls.isSoftDeferred != softDeferred) continue;
945 for (InstanceMethod method in cls.methods) { 1028 for (InstanceMethod method in cls.methods) {
946 if (method.aliasName != null) { 1029 if (method.aliasName != null) {
947 assignments.add(js.js.statement('#.prototype.# = #.prototype.#', [ 1030 assignments.add(js.js.statement('#.prototype.# = #.prototype.#', [
948 classReference(cls), 1031 classReference(cls),
949 js.quoteName(method.aliasName), 1032 js.quoteName(method.aliasName),
950 classReference(cls), 1033 classReference(cls),
951 js.quoteName(method.name) 1034 js.quoteName(method.name)
952 ])); 1035 ]));
953 } 1036 }
954 } 1037 }
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
1059 } 1142 }
1060 1143
1061 /// Wraps the statement in a named function to that it shows up as a unit in 1144 /// Wraps the statement in a named function to that it shows up as a unit in
1062 /// profiles. 1145 /// profiles.
1063 // TODO(sra): Should this be conditional? 1146 // TODO(sra): Should this be conditional?
1064 js.Statement wrapPhase(String name, js.Statement statement) { 1147 js.Statement wrapPhase(String name, js.Statement statement) {
1065 return js.js.statement('(function #(){#})();', [name, statement]); 1148 return js.js.statement('(function #(){#})();', [name, statement]);
1066 } 1149 }
1067 1150
1068 /// Emits the section that installs tear-off getters. 1151 /// Emits the section that installs tear-off getters.
1069 js.Statement emitInstallTearOffs(Fragment fragment) { 1152 js.Statement emitInstallTearOffs(Fragment fragment,
1153 {bool softDeferred = false}) {
1070 List<js.Statement> inits = <js.Statement>[]; 1154 List<js.Statement> inits = <js.Statement>[];
1071 js.Expression temp; 1155 js.Expression temp;
1072 1156
1073 for (Library library in fragment.libraries) { 1157 for (Library library in fragment.libraries) {
1074 for (StaticMethod method in library.statics) { 1158 for (StaticMethod method in library.statics) {
1075 // TODO(floitsch): can there be anything else than a StaticDartMethod? 1159 // TODO(floitsch): can there be anything else than a StaticDartMethod?
1076 if (method is StaticDartMethod) { 1160 if (method is StaticDartMethod) {
1077 if (method.needsTearOff) { 1161 if (method.needsTearOff) {
1078 Holder holder = method.holder; 1162 Holder holder = method.holder;
1079 inits.add( 1163 inits.add(
1080 emitInstallTearOff(new js.VariableUse(holder.name), method)); 1164 emitInstallTearOff(new js.VariableUse(holder.name), method));
1081 } 1165 }
1082 } 1166 }
1083 } 1167 }
1084 for (Class cls in library.classes) { 1168 for (Class cls in library.classes) {
1169 if (cls.isSoftDeferred != softDeferred) continue;
1085 var methods = cls.methods.where((m) => m.needsTearOff).toList(); 1170 var methods = cls.methods.where((m) => m.needsTearOff).toList();
1086 js.Expression container = js.js("#.prototype", classReference(cls)); 1171 js.Expression container = js.js("#.prototype", classReference(cls));
1087 js.Expression reference = container; 1172 js.Expression reference = container;
1088 if (methods.length > 1) { 1173 if (methods.length > 1) {
1089 if (temp == null) { 1174 if (temp == null) {
1090 inits.add(js.js.statement('var _;')); 1175 inits.add(js.js.statement('var _;'));
1091 temp = js.js('_'); 1176 temp = js.js('_');
1092 } 1177 }
1093 // First call uses assignment to temp to cache the container. 1178 // First call uses assignment to temp to cache the container.
1094 reference = js.js('# = #', [temp, container]); 1179 reference = js.js('# = #', [temp, container]);
(...skipping 371 matching lines...) Expand 10 before | Expand all | Expand 10 after
1466 } 1551 }
1467 statements.add(js.js.statement("setOrUpdateInterceptorsByTag(#);", 1552 statements.add(js.js.statement("setOrUpdateInterceptorsByTag(#);",
1468 js.objectLiteral(interceptorsByTag))); 1553 js.objectLiteral(interceptorsByTag)));
1469 statements.add( 1554 statements.add(
1470 js.js.statement("setOrUpdateLeafTags(#);", js.objectLiteral(leafTags))); 1555 js.js.statement("setOrUpdateLeafTags(#);", js.objectLiteral(leafTags)));
1471 statements.addAll(subclassAssignments); 1556 statements.addAll(subclassAssignments);
1472 1557
1473 return wrapPhase('nativeSupport', new js.Block(statements)); 1558 return wrapPhase('nativeSupport', new js.Block(statements));
1474 } 1559 }
1475 } 1560 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698