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

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: Address comments. 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 if (o != null) {
325 // TODO(29574): should we do something different for Firefox?
326 // If we recommend that the program triggers the load by itself before
327 // classes are needed, then this line should rarely be hit.
328 // Also, it is only hit at most once (per soft-deferred chunk).
329 o.__proto__ = o.constructor.prototype;
330 }
331 }
332 }
333
334 if (#isTrackingAllocations) {
335 var allocations = #deferredGlobal['allocations'] = {};
336 }
337
316 // Creates the holders. 338 // Creates the holders.
317 #holders; 339 #holders;
318 340
319 // If the name is not set on the functions, do it now. 341 // If the name is not set on the functions, do it now.
320 setFunctionNamesIfNecessary(#holdersList); 342 setFunctionNamesIfNecessary(holders);
321 343
322 // TODO(floitsch): we should build this object as a literal. 344 // TODO(floitsch): we should build this object as a literal.
323 var #staticStateDeclaration = {}; 345 var #staticStateDeclaration = {};
324 346
325 // Sets the prototypes of classes. 347 // Sets the prototypes of classes.
326 #prototypes; 348 #prototypes;
327 // Sets aliases of methods (on the prototypes of classes). 349 // Sets aliases of methods (on the prototypes of classes).
328 #aliases; 350 #aliases;
329 // Installs the tear-offs of functions. 351 // Installs the tear-offs of functions.
330 #tearOffs; 352 #tearOffs;
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
422 #staticNonFinalFields; 444 #staticNonFinalFields;
423 // Creates lazy getters for statics that must run initializers on first access. 445 // Creates lazy getters for statics that must run initializers on first access.
424 #lazyStatics; 446 #lazyStatics;
425 447
426 updateTypes(#types); 448 updateTypes(#types);
427 449
428 // Native-support uses setOrUpdateInterceptorsByTag and setOrUpdateLeafTags. 450 // Native-support uses setOrUpdateInterceptorsByTag and setOrUpdateLeafTags.
429 #nativeSupport; 451 #nativeSupport;
430 }'''; 452 }''';
431 453
454 /// Soft-deferred fragments are built similarly to the main fragment.
455 ///
456 /// However, they don't contribute anything to global namespace, but just
457 /// initialize existing classes. For example, they update the inheritance
458 /// hierarchy, and add methods the prototypes.
459 const String softDeferredBoilerplate = '''
460 #deferredGlobal[#softId] =
461 function(holdersList, #embeddedGlobalsObject, #staticState, inherit, mixin,
462 installTearOff) {
463
464 // Installs the holders as local variables.
465 #installHoldersAsLocals;
466 // Sets the prototypes of the new classes.
467 #prototypes;
468 // Sets aliases of methods (on the prototypes of classes).
469 #aliases;
470 // Installs the tear-offs of functions.
471 #tearOffs;
472 // Builds the inheritance structure.
473 #inheritance;
474 }''';
475
432 /** 476 /**
433 * This class builds a JavaScript tree for a given fragment. 477 * This class builds a JavaScript tree for a given fragment.
434 * 478 *
435 * A fragment is generally written into a separate file so that it can be 479 * A fragment is generally written into a separate file so that it can be
436 * loaded dynamically when a deferred library is loaded. 480 * loaded dynamically when a deferred library is loaded.
437 * 481 *
438 * This class is stateless and can be reused for different fragments. 482 * This class is stateless and can be reused for different fragments.
439 */ 483 */
440 class FragmentEmitter { 484 class FragmentEmitter {
441 final Compiler compiler; 485 final Compiler compiler;
(...skipping 15 matching lines...) Expand all
457 return js.js('#.#', [cls.holder.name, cls.name]); 501 return js.js('#.#', [cls.holder.name, cls.name]);
458 } 502 }
459 503
460 js.Statement emitMainFragment(Program program, 504 js.Statement emitMainFragment(Program program,
461 Map<DeferredFragment, _DeferredFragmentHash> deferredLoadHashes) { 505 Map<DeferredFragment, _DeferredFragmentHash> deferredLoadHashes) {
462 MainFragment fragment = program.fragments.first; 506 MainFragment fragment = program.fragments.first;
463 507
464 Iterable<Holder> nonStaticStateHolders = 508 Iterable<Holder> nonStaticStateHolders =
465 program.holders.where((Holder holder) => !holder.isStaticStateHolder); 509 program.holders.where((Holder holder) => !holder.isStaticStateHolder);
466 510
467 return js.js.statement(mainBoilerplate, { 511 String softDeferredId = "softDeferred${new Random().nextInt(0x7FFFFFFF)}";
512
513 js.Statement mainCode = js.js.statement(mainBoilerplate, {
468 'directAccessTestExpression': js.js(directAccessTestExpression), 514 'directAccessTestExpression': js.js(directAccessTestExpression),
469 'typeNameProperty': js.string(ModelEmitter.typeNameProperty), 515 'typeNameProperty': js.string(ModelEmitter.typeNameProperty),
470 'cyclicThrow': backend.emitter 516 'cyclicThrow': backend.emitter
471 .staticFunctionAccess(compiler.commonElements.cyclicThrowHelper), 517 .staticFunctionAccess(compiler.commonElements.cyclicThrowHelper),
472 'operatorIsPrefix': js.string(namer.operatorIsPrefix), 518 'operatorIsPrefix': js.string(namer.operatorIsPrefix),
473 'tearOffCode': new js.Block(buildTearOffCode(compiler.options, 519 'tearOffCode': new js.Block(buildTearOffCode(compiler.options,
474 backend.emitter.emitter, backend.namer, compiler.commonElements)), 520 backend.emitter.emitter, backend.namer, compiler.commonElements)),
475 'embeddedTypes': generateEmbeddedGlobalAccess(TYPES), 521 'embeddedTypes': generateEmbeddedGlobalAccess(TYPES),
476 'embeddedInterceptorTags': 522 'embeddedInterceptorTags':
477 generateEmbeddedGlobalAccess(INTERCEPTORS_BY_TAG), 523 generateEmbeddedGlobalAccess(INTERCEPTORS_BY_TAG),
478 'embeddedLeafTags': generateEmbeddedGlobalAccess(LEAF_TAGS), 524 'embeddedLeafTags': generateEmbeddedGlobalAccess(LEAF_TAGS),
479 'embeddedGlobalsObject': js.js("init"), 525 'embeddedGlobalsObject': js.js("init"),
480 'holdersList': new js.ArrayInitializer(nonStaticStateHolders
481 .map((holder) => js.js("#", holder.name))
482 .toList(growable: false)),
483 'staticStateDeclaration': new js.VariableDeclaration( 526 'staticStateDeclaration': new js.VariableDeclaration(
484 namer.staticStateHolder, 527 namer.staticStateHolder,
485 allowRename: false), 528 allowRename: false),
486 'staticState': js.js('#', namer.staticStateHolder), 529 'staticState': js.js('#', namer.staticStateHolder),
487 'constantHolderReference': buildConstantHolderReference(program), 530 'constantHolderReference': buildConstantHolderReference(program),
488 'holders': emitHolders(program.holders, fragment), 531 'holders': emitHolders(program.holders, fragment),
489 'callName': js.string(namer.callNameField), 532 'callName': js.string(namer.callNameField),
490 'stubName': js.string(namer.stubNameField), 533 'stubName': js.string(namer.stubNameField),
491 'argumentCount': js.string(namer.requiredParameterField), 534 'argumentCount': js.string(namer.requiredParameterField),
492 'defaultArgumentValues': js.string(namer.defaultValuesField), 535 'defaultArgumentValues': js.string(namer.defaultValuesField),
536 'deferredGlobal': ModelEmitter.deferredInitializersGlobal,
537 'hasSoftDeferredClasses': program.hasSoftDeferredClasses,
538 'softId': js.string(softDeferredId),
539 'isTrackingAllocations': compiler.options.experimentalTrackAllocations,
493 'prototypes': emitPrototypes(fragment), 540 'prototypes': emitPrototypes(fragment),
494 'inheritance': emitInheritance(fragment), 541 'inheritance': emitInheritance(fragment),
495 'aliases': emitInstanceMethodAliases(fragment), 542 'aliases': emitInstanceMethodAliases(fragment),
496 'tearOffs': emitInstallTearOffs(fragment), 543 'tearOffs': emitInstallTearOffs(fragment),
497 'constants': emitConstants(fragment), 544 'constants': emitConstants(fragment),
498 'staticNonFinalFields': emitStaticNonFinalFields(fragment), 545 'staticNonFinalFields': emitStaticNonFinalFields(fragment),
499 'lazyStatics': emitLazilyInitializedStatics(fragment), 546 'lazyStatics': emitLazilyInitializedStatics(fragment),
500 'embeddedGlobals': emitEmbeddedGlobals(program, deferredLoadHashes), 547 'embeddedGlobals': emitEmbeddedGlobals(program, deferredLoadHashes),
501 'nativeSupport': program.needsNativeSupport 548 'nativeSupport': program.needsNativeSupport
502 ? emitNativeSupport(fragment) 549 ? emitNativeSupport(fragment)
503 : new js.EmptyStatement(), 550 : new js.EmptyStatement(),
504 'jsInteropSupport': backend.nativeBasicData.isJsInteropUsed 551 'jsInteropSupport': backend.nativeBasicData.isJsInteropUsed
505 ? backend.jsInteropAnalysis.buildJsInteropBootstrap() 552 ? backend.jsInteropAnalysis.buildJsInteropBootstrap()
506 : new js.EmptyStatement(), 553 : new js.EmptyStatement(),
507 'invokeMain': fragment.invokeMain, 554 'invokeMain': fragment.invokeMain,
508 }); 555 });
556 if (program.hasSoftDeferredClasses) {
557 return new js.Block([
558 js.js.statement(softDeferredBoilerplate, {
559 'deferredGlobal': ModelEmitter.deferredInitializersGlobal,
560 'softId': js.string(softDeferredId),
561 // TODO(floitsch): don't just reference 'init'.
562 'embeddedGlobalsObject': new js.Parameter('init'),
563 'staticState': new js.Parameter(namer.staticStateHolder),
564 'installHoldersAsLocals':
565 emitInstallHoldersAsLocals(nonStaticStateHolders),
566 'prototypes': emitPrototypes(fragment, softDeferred: true),
567 'aliases': emitInstanceMethodAliases(fragment, softDeferred: true),
568 'tearOffs': emitInstallTearOffs(fragment, softDeferred: true),
569 'inheritance': emitInheritance(fragment, softDeferred: true),
570 }),
571 mainCode
572 ]);
573 }
574 return mainCode;
575 }
576
577 js.Statement emitInstallHoldersAsLocals(Iterable<Holder> holders) {
578 List<js.Statement> holderInits = <js.Statement>[];
579 int counter = 0;
580 for (Holder holder in holders) {
581 holderInits.add(new js.ExpressionStatement(new js.VariableInitialization(
582 new js.VariableDeclaration(holder.name, allowRename: false),
583 js.js("holdersList[#]", js.number(counter++)))));
584 }
585 return new js.Block(holderInits);
509 } 586 }
510 587
511 js.Expression emitDeferredFragment(DeferredFragment fragment, 588 js.Expression emitDeferredFragment(DeferredFragment fragment,
512 js.Expression deferredTypes, List<Holder> holders) { 589 js.Expression deferredTypes, List<Holder> holders) {
513 List<Holder> nonStaticStateHolders = holders 590 List<Holder> nonStaticStateHolders = holders
514 .where((Holder holder) => !holder.isStaticStateHolder) 591 .where((Holder holder) => !holder.isStaticStateHolder)
515 .toList(growable: false); 592 .toList(growable: false);
516 593
517 List<js.Statement> updateHolderAssignments = <js.Statement>[]; 594 List<js.Statement> updateHolderAssignments = <js.Statement>[];
518 for (int i = 0; i < nonStaticStateHolders.length; i++) { 595 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 727 // 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. 728 // or RTI. In either case we don't need its fields.
652 if (cls.isNative || !cls.isDirectlyInstantiated) { 729 if (cls.isNative || !cls.isDirectlyInstantiated) {
653 return js.js('function #() { }', name); 730 return js.js('function #() { }', name);
654 } 731 }
655 732
656 var statements = <js.Statement>[]; 733 var statements = <js.Statement>[];
657 var parameters = <js.Name>[]; 734 var parameters = <js.Name>[];
658 var thisRef; 735 var thisRef;
659 736
737 if (cls.isSoftDeferred) {
738 statements.add(js.js.statement('softDef(this)'));
739 } else if (compiler.options.experimentalTrackAllocations) {
740 String qualifiedName =
741 "${cls.element.library.canonicalUri}:${cls.element.name}";
742 statements.add(js.js.statement('allocations["$qualifiedName"] = true'));
743 }
744
660 // If there are many references to `this`, cache it in a local. 745 // If there are many references to `this`, cache it in a local.
661 if (cls.fields.length + (cls.hasRtiField ? 1 : 0) >= 4) { 746 if (cls.fields.length + (cls.hasRtiField ? 1 : 0) >= 4) {
662 // TODO(29455): Fix js_ast printer and minifier to avoid conflicts between 747 // 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 748 // js.Name and string-named variables, then use '_' in the js template
664 // text. 749 // text.
665 750
666 // We pick '_' in minified mode because no field minifies to '_'. This 751 // 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 752 // 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 753 // 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. 754 // '$_', which is an impossible member name since we escape '$'s in names.
(...skipping 20 matching lines...) Expand all
690 .statement('#.# = #', [thisRef, namer.rtiFieldJsName, paramName])); 775 .statement('#.# = #', [thisRef, namer.rtiFieldJsName, paramName]));
691 } 776 }
692 777
693 return js.js('function #(#) { # }', [name, parameters, statements]); 778 return js.js('function #(#) { # }', [name, parameters, statements]);
694 } 779 }
695 780
696 /// Emits the prototype-section of the fragment. 781 /// Emits the prototype-section of the fragment.
697 /// 782 ///
698 /// This section updates the prototype-property of all constructors in the 783 /// This section updates the prototype-property of all constructors in the
699 /// global holders. 784 /// global holders.
700 js.Statement emitPrototypes(Fragment fragment) { 785 js.Statement emitPrototypes(Fragment fragment, {softDeferred = false}) {
701 List<js.Statement> assignments = fragment.libraries 786 List<js.Statement> assignments = fragment.libraries
702 .expand((Library library) => library.classes) 787 .expand((Library library) => library.classes)
788 .where((Class cls) => cls.isSoftDeferred == softDeferred)
703 .map((Class cls) { 789 .map((Class cls) {
704 var proto = js.js.statement( 790 var proto = js.js.statement(
705 '#.prototype = #;', [classReference(cls), emitPrototype(cls)]); 791 '#.prototype = #;', [classReference(cls), emitPrototype(cls)]);
706 ClassElement element = cls.element; 792 ClassElement element = cls.element;
707 compiler.dumpInfoTask.registerElementAst(element, proto); 793 compiler.dumpInfoTask.registerElementAst(element, proto);
708 compiler.dumpInfoTask.registerElementAst(element.library, proto); 794 compiler.dumpInfoTask.registerElementAst(element.library, proto);
709 return proto; 795 return proto;
710 }).toList(growable: false); 796 }).toList(growable: false);
711 797
712 return new js.Block(assignments); 798 return new js.Block(assignments);
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
857 } 943 }
858 } 944 }
859 945
860 return properties; 946 return properties;
861 } 947 }
862 948
863 /// Emits the inheritance block of the fragment. 949 /// Emits the inheritance block of the fragment.
864 /// 950 ///
865 /// In this section prototype chains are updated and mixin functions are 951 /// In this section prototype chains are updated and mixin functions are
866 /// copied. 952 /// copied.
867 js.Statement emitInheritance(Fragment fragment) { 953 js.Statement emitInheritance(Fragment fragment, {bool softDeferred = false}) {
868 List<js.Statement> inheritCalls = <js.Statement>[]; 954 List<js.Statement> inheritCalls = <js.Statement>[];
869 List<js.Statement> mixinCalls = <js.Statement>[]; 955 List<js.Statement> mixinCalls = <js.Statement>[];
870 956
871 Set<Class> classesInFragment = new Set<Class>(); 957 Set<Class> classesInFragment = new Set<Class>();
872 for (Library library in fragment.libraries) { 958 for (Library library in fragment.libraries) {
873 classesInFragment.addAll(library.classes); 959 classesInFragment.addAll(library.classes
960 .where(((Class cls) => cls.isSoftDeferred == softDeferred)));
874 } 961 }
875 962
876 Map<Class, List<Class>> subclasses = <Class, List<Class>>{}; 963 Map<Class, List<Class>> subclasses = <Class, List<Class>>{};
877 Set<Class> seen = new Set<Class>(); 964 Set<Class> seen = new Set<Class>();
878 965
879 void collect(cls) { 966 void collect(cls) {
880 if (cls == null || seen.contains(cls)) return; 967 if (cls == null || seen.contains(cls)) return;
881 968
882 Class superclass = cls.superclass; 969 Class superclass = cls.superclass;
883 if (classesInFragment.contains(superclass)) { 970 if (classesInFragment.contains(superclass)) {
884 collect(superclass); 971 collect(superclass);
885 } 972 }
886 973
887 subclasses.putIfAbsent(superclass, () => <Class>[]).add(cls); 974 subclasses.putIfAbsent(superclass, () => <Class>[]).add(cls);
888 975
889 seen.add(cls); 976 seen.add(cls);
890 } 977 }
891 978
892 for (Library library in fragment.libraries) { 979 for (Library library in fragment.libraries) {
893 for (Class cls in library.classes) { 980 for (Class cls in library.classes) {
981 if (cls.isSoftDeferred != softDeferred) continue;
894 collect(cls); 982 collect(cls);
895 983
896 if (cls.isMixinApplication) { 984 if (cls.isMixinApplication) {
897 MixinApplication mixin = cls; 985 MixinApplication mixin = cls;
898 mixinCalls.add(js.js.statement('mixin(#, #)', 986 mixinCalls.add(js.js.statement('mixin(#, #)',
899 [classReference(cls), classReference(mixin.mixinClass)])); 987 [classReference(cls), classReference(mixin.mixinClass)]));
900 } 988 }
901 } 989 }
902 } 990 }
903 991
(...skipping 26 matching lines...) Expand all
930 } 1018 }
931 1019
932 return wrapPhase( 1020 return wrapPhase(
933 'inheritance', js.js.statement('{#; #;}', [inheritCalls, mixinCalls])); 1021 'inheritance', js.js.statement('{#; #;}', [inheritCalls, mixinCalls]));
934 } 1022 }
935 1023
936 /// Emits the setup of method aliases. 1024 /// Emits the setup of method aliases.
937 /// 1025 ///
938 /// This step consists of simply copying JavaScript functions to their 1026 /// This step consists of simply copying JavaScript functions to their
939 /// aliased names so they point to the same function. 1027 /// aliased names so they point to the same function.
940 js.Statement emitInstanceMethodAliases(Fragment fragment) { 1028 js.Statement emitInstanceMethodAliases(Fragment fragment,
1029 {bool softDeferred = false}) {
941 List<js.Statement> assignments = <js.Statement>[]; 1030 List<js.Statement> assignments = <js.Statement>[];
942 1031
943 for (Library library in fragment.libraries) { 1032 for (Library library in fragment.libraries) {
944 for (Class cls in library.classes) { 1033 for (Class cls in library.classes) {
1034 if (cls.isSoftDeferred != softDeferred) continue;
945 for (InstanceMethod method in cls.methods) { 1035 for (InstanceMethod method in cls.methods) {
946 if (method.aliasName != null) { 1036 if (method.aliasName != null) {
947 assignments.add(js.js.statement('#.prototype.# = #.prototype.#', [ 1037 assignments.add(js.js.statement('#.prototype.# = #.prototype.#', [
948 classReference(cls), 1038 classReference(cls),
949 js.quoteName(method.aliasName), 1039 js.quoteName(method.aliasName),
950 classReference(cls), 1040 classReference(cls),
951 js.quoteName(method.name) 1041 js.quoteName(method.name)
952 ])); 1042 ]));
953 } 1043 }
954 } 1044 }
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
1059 } 1149 }
1060 1150
1061 /// Wraps the statement in a named function to that it shows up as a unit in 1151 /// Wraps the statement in a named function to that it shows up as a unit in
1062 /// profiles. 1152 /// profiles.
1063 // TODO(sra): Should this be conditional? 1153 // TODO(sra): Should this be conditional?
1064 js.Statement wrapPhase(String name, js.Statement statement) { 1154 js.Statement wrapPhase(String name, js.Statement statement) {
1065 return js.js.statement('(function #(){#})();', [name, statement]); 1155 return js.js.statement('(function #(){#})();', [name, statement]);
1066 } 1156 }
1067 1157
1068 /// Emits the section that installs tear-off getters. 1158 /// Emits the section that installs tear-off getters.
1069 js.Statement emitInstallTearOffs(Fragment fragment) { 1159 js.Statement emitInstallTearOffs(Fragment fragment,
1160 {bool softDeferred = false}) {
1070 List<js.Statement> inits = <js.Statement>[]; 1161 List<js.Statement> inits = <js.Statement>[];
1071 js.Expression temp; 1162 js.Expression temp;
1072 1163
1073 for (Library library in fragment.libraries) { 1164 for (Library library in fragment.libraries) {
1074 for (StaticMethod method in library.statics) { 1165 for (StaticMethod method in library.statics) {
1075 // TODO(floitsch): can there be anything else than a StaticDartMethod? 1166 // TODO(floitsch): can there be anything else than a StaticDartMethod?
1076 if (method is StaticDartMethod) { 1167 if (method is StaticDartMethod) {
1077 if (method.needsTearOff) { 1168 if (method.needsTearOff) {
1078 Holder holder = method.holder; 1169 Holder holder = method.holder;
1079 inits.add( 1170 inits.add(
1080 emitInstallTearOff(new js.VariableUse(holder.name), method)); 1171 emitInstallTearOff(new js.VariableUse(holder.name), method));
1081 } 1172 }
1082 } 1173 }
1083 } 1174 }
1084 for (Class cls in library.classes) { 1175 for (Class cls in library.classes) {
1176 if (cls.isSoftDeferred != softDeferred) continue;
1085 var methods = cls.methods.where((m) => m.needsTearOff).toList(); 1177 var methods = cls.methods.where((m) => m.needsTearOff).toList();
1086 js.Expression container = js.js("#.prototype", classReference(cls)); 1178 js.Expression container = js.js("#.prototype", classReference(cls));
1087 js.Expression reference = container; 1179 js.Expression reference = container;
1088 if (methods.length > 1) { 1180 if (methods.length > 1) {
1089 if (temp == null) { 1181 if (temp == null) {
1090 inits.add(js.js.statement('var _;')); 1182 inits.add(js.js.statement('var _;'));
1091 temp = js.js('_'); 1183 temp = js.js('_');
1092 } 1184 }
1093 // First call uses assignment to temp to cache the container. 1185 // First call uses assignment to temp to cache the container.
1094 reference = js.js('# = #', [temp, container]); 1186 reference = js.js('# = #', [temp, container]);
(...skipping 371 matching lines...) Expand 10 before | Expand all | Expand 10 after
1466 } 1558 }
1467 statements.add(js.js.statement("setOrUpdateInterceptorsByTag(#);", 1559 statements.add(js.js.statement("setOrUpdateInterceptorsByTag(#);",
1468 js.objectLiteral(interceptorsByTag))); 1560 js.objectLiteral(interceptorsByTag)));
1469 statements.add( 1561 statements.add(
1470 js.js.statement("setOrUpdateLeafTags(#);", js.objectLiteral(leafTags))); 1562 js.js.statement("setOrUpdateLeafTags(#);", js.objectLiteral(leafTags)));
1471 statements.addAll(subclassAssignments); 1563 statements.addAll(subclassAssignments);
1472 1564
1473 return wrapPhase('nativeSupport', new js.Block(statements)); 1565 return wrapPhase('nativeSupport', new js.Block(statements));
1474 } 1566 }
1475 } 1567 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698