| 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 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  Loading... | 
| 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  Loading... | 
| 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  Loading... | 
| 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  Loading... | 
| 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  Loading... | 
| 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  Loading... | 
| 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  Loading... | 
| 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  Loading... | 
| 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  Loading... | 
| 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 } | 
| OLD | NEW | 
|---|