| 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 409 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 420 js.Expression generateEmbeddedGlobalAccess(String global) => | 420 js.Expression generateEmbeddedGlobalAccess(String global) => |
| 421 modelEmitter.generateEmbeddedGlobalAccess(global); | 421 modelEmitter.generateEmbeddedGlobalAccess(global); |
| 422 | 422 |
| 423 js.Expression generateConstantReference(ConstantValue value) => | 423 js.Expression generateConstantReference(ConstantValue value) => |
| 424 modelEmitter.generateConstantReference(value); | 424 modelEmitter.generateConstantReference(value); |
| 425 | 425 |
| 426 js.Expression classReference(Class cls) { | 426 js.Expression classReference(Class cls) { |
| 427 return js.js('#.#', [cls.holder.name, cls.name]); | 427 return js.js('#.#', [cls.holder.name, cls.name]); |
| 428 } | 428 } |
| 429 | 429 |
| 430 js.Statement emitMainFragment( | 430 js.Statement emitMainFragment(Program program, |
| 431 Program program, | |
| 432 Map<DeferredFragment, _DeferredFragmentHash> deferredLoadHashes) { | 431 Map<DeferredFragment, _DeferredFragmentHash> deferredLoadHashes) { |
| 433 MainFragment fragment = program.fragments.first; | 432 MainFragment fragment = program.fragments.first; |
| 434 | 433 |
| 435 Iterable<Holder> nonStaticStateHolders = program.holders | 434 Iterable<Holder> nonStaticStateHolders = |
| 436 .where((Holder holder) => !holder.isStaticStateHolder); | 435 program.holders.where((Holder holder) => !holder.isStaticStateHolder); |
| 437 | 436 |
| 438 return js.js.statement(mainBoilerplate, | 437 return js.js.statement(mainBoilerplate, { |
| 439 {'typeNameProperty': js.string(ModelEmitter.typeNameProperty), | 438 'typeNameProperty': js.string(ModelEmitter.typeNameProperty), |
| 440 'cyclicThrow': backend.emitter.staticFunctionAccess( | 439 'cyclicThrow': backend.emitter |
| 441 backend.helpers.cyclicThrowHelper), | 440 .staticFunctionAccess(backend.helpers.cyclicThrowHelper), |
| 442 'operatorIsPrefix': js.string(namer.operatorIsPrefix), | 441 'operatorIsPrefix': js.string(namer.operatorIsPrefix), |
| 443 'tearOffCode': new js.Block(buildTearOffCode(backend)), | 442 'tearOffCode': new js.Block(buildTearOffCode(backend)), |
| 444 'embeddedTypes': generateEmbeddedGlobalAccess(TYPES), | 443 'embeddedTypes': generateEmbeddedGlobalAccess(TYPES), |
| 445 'embeddedInterceptorTags': | 444 'embeddedInterceptorTags': |
| 446 generateEmbeddedGlobalAccess(INTERCEPTORS_BY_TAG), | 445 generateEmbeddedGlobalAccess(INTERCEPTORS_BY_TAG), |
| 447 'embeddedLeafTags': generateEmbeddedGlobalAccess(LEAF_TAGS), | 446 'embeddedLeafTags': generateEmbeddedGlobalAccess(LEAF_TAGS), |
| 448 'embeddedGlobalsObject': js.js("init"), | 447 'embeddedGlobalsObject': js.js("init"), |
| 449 'holdersList': new js.ArrayInitializer(nonStaticStateHolders | 448 'holdersList': new js.ArrayInitializer(nonStaticStateHolders |
| 450 .map((holder) => js.js("#", holder.name)) | 449 .map((holder) => js.js("#", holder.name)) |
| 451 .toList(growable: false)), | 450 .toList(growable: false)), |
| 452 'staticStateDeclaration': new js.VariableDeclaration( | 451 'staticStateDeclaration': new js.VariableDeclaration( |
| 453 namer.staticStateHolder, allowRename: false), | 452 namer.staticStateHolder, |
| 454 'staticState': js.js('#', namer.staticStateHolder), | 453 allowRename: false), |
| 455 'constantHolderReference': buildConstantHolderReference(program), | 454 'staticState': js.js('#', namer.staticStateHolder), |
| 456 'holders': emitHolders(program.holders, fragment), | 455 'constantHolderReference': buildConstantHolderReference(program), |
| 457 'callName': js.string(namer.callNameField), | 456 'holders': emitHolders(program.holders, fragment), |
| 458 'argumentCount': js.string(namer.requiredParameterField), | 457 'callName': js.string(namer.callNameField), |
| 459 'defaultArgumentValues': js.string(namer.defaultValuesField), | 458 'argumentCount': js.string(namer.requiredParameterField), |
| 460 'prototypes': emitPrototypes(fragment), | 459 'defaultArgumentValues': js.string(namer.defaultValuesField), |
| 461 'inheritance': emitInheritance(fragment), | 460 'prototypes': emitPrototypes(fragment), |
| 462 'aliases': emitInstanceMethodAliases(fragment), | 461 'inheritance': emitInheritance(fragment), |
| 463 'tearOffs': emitInstallTearOffs(fragment), | 462 'aliases': emitInstanceMethodAliases(fragment), |
| 464 'constants': emitConstants(fragment), | 463 'tearOffs': emitInstallTearOffs(fragment), |
| 465 'staticNonFinalFields': emitStaticNonFinalFields(fragment), | 464 'constants': emitConstants(fragment), |
| 466 'lazyStatics': emitLazilyInitializedStatics(fragment), | 465 'staticNonFinalFields': emitStaticNonFinalFields(fragment), |
| 467 'embeddedGlobals': emitEmbeddedGlobals(program, deferredLoadHashes), | 466 'lazyStatics': emitLazilyInitializedStatics(fragment), |
| 468 'nativeSupport': program.needsNativeSupport | 467 'embeddedGlobals': emitEmbeddedGlobals(program, deferredLoadHashes), |
| 469 ? emitNativeSupport(fragment) | 468 'nativeSupport': program.needsNativeSupport |
| 470 : new js.EmptyStatement(), | 469 ? emitNativeSupport(fragment) |
| 471 'invokeMain': fragment.invokeMain, | 470 : new js.EmptyStatement(), |
| 472 }); | 471 'invokeMain': fragment.invokeMain, |
| 472 }); |
| 473 } | 473 } |
| 474 | 474 |
| 475 js.Expression emitDeferredFragment(DeferredFragment fragment, | 475 js.Expression emitDeferredFragment(DeferredFragment fragment, |
| 476 js.Expression deferredTypes, | 476 js.Expression deferredTypes, List<Holder> holders) { |
| 477 List<Holder> holders) { | |
| 478 List<Holder> nonStaticStateHolders = holders | 477 List<Holder> nonStaticStateHolders = holders |
| 479 .where((Holder holder) => !holder.isStaticStateHolder) | 478 .where((Holder holder) => !holder.isStaticStateHolder) |
| 480 .toList(growable: false); | 479 .toList(growable: false); |
| 481 | 480 |
| 482 List<js.Statement> updateHolderAssignments = <js.Statement>[]; | 481 List<js.Statement> updateHolderAssignments = <js.Statement>[]; |
| 483 for (int i = 0; i < nonStaticStateHolders.length; i++) { | 482 for (int i = 0; i < nonStaticStateHolders.length; i++) { |
| 484 Holder holder = nonStaticStateHolders[i]; | 483 Holder holder = nonStaticStateHolders[i]; |
| 485 updateHolderAssignments.add(js.js.statement( | 484 updateHolderAssignments.add(js.js.statement( |
| 486 '#holder = updateHolder(holdersList[#index], #holder)', | 485 '#holder = updateHolder(holdersList[#index], #holder)', |
| 487 {'index': js.number(i), | 486 {'index': js.number(i), 'holder': new js.VariableUse(holder.name)})); |
| 488 'holder': new js.VariableUse(holder.name)})); | |
| 489 } | 487 } |
| 490 | 488 |
| 491 // TODO(floitsch): don't just reference 'init'. | 489 // TODO(floitsch): don't just reference 'init'. |
| 492 return js.js(deferredBoilerplate, | 490 return js.js(deferredBoilerplate, { |
| 493 {'embeddedGlobalsObject': new js.Parameter('init'), | 491 'embeddedGlobalsObject': new js.Parameter('init'), |
| 494 'staticState': new js.Parameter(namer.staticStateHolder), | 492 'staticState': new js.Parameter(namer.staticStateHolder), |
| 495 'holders': emitHolders(holders, fragment), | 493 'holders': emitHolders(holders, fragment), |
| 496 'deferredHoldersList': new js.ArrayInitializer(nonStaticStateHolders | 494 'deferredHoldersList': new js.ArrayInitializer(nonStaticStateHolders |
| 497 .map((holder) => js.js("#", holder.name)) | 495 .map((holder) => js.js("#", holder.name)) |
| 498 .toList(growable: false)), | 496 .toList(growable: false)), |
| 499 'updateHolders': new js.Block(updateHolderAssignments), | 497 'updateHolders': new js.Block(updateHolderAssignments), |
| 500 'prototypes': emitPrototypes(fragment), | 498 'prototypes': emitPrototypes(fragment), |
| 501 'inheritance': emitInheritance(fragment), | 499 'inheritance': emitInheritance(fragment), |
| 502 'aliases': emitInstanceMethodAliases(fragment), | 500 'aliases': emitInstanceMethodAliases(fragment), |
| 503 'tearOffs': emitInstallTearOffs(fragment), | 501 'tearOffs': emitInstallTearOffs(fragment), |
| 504 'constants': emitConstants(fragment), | 502 'constants': emitConstants(fragment), |
| 505 'staticNonFinalFields': emitStaticNonFinalFields(fragment), | 503 'staticNonFinalFields': emitStaticNonFinalFields(fragment), |
| 506 'lazyStatics': emitLazilyInitializedStatics(fragment), | 504 'lazyStatics': emitLazilyInitializedStatics(fragment), |
| 507 'types': deferredTypes, | 505 'types': deferredTypes, |
| 508 // TODO(floitsch): only call emitNativeSupport if we need native. | 506 // TODO(floitsch): only call emitNativeSupport if we need native. |
| 509 'nativeSupport': emitNativeSupport(fragment), | 507 'nativeSupport': emitNativeSupport(fragment), |
| 510 }); | 508 }); |
| 511 } | 509 } |
| 512 | 510 |
| 513 /// Emits all holders, except for the static-state holder. | 511 /// Emits all holders, except for the static-state holder. |
| 514 /// | 512 /// |
| 515 /// The emitted holders contain classes (only the constructors) and all | 513 /// The emitted holders contain classes (only the constructors) and all |
| 516 /// static functions. | 514 /// static functions. |
| 517 js.Statement emitHolders(List<Holder> holders, Fragment fragment) { | 515 js.Statement emitHolders(List<Holder> holders, Fragment fragment) { |
| 518 // Skip the static-state holder in this function. | 516 // Skip the static-state holder in this function. |
| 519 holders = holders | 517 holders = holders |
| (...skipping 30 matching lines...) Expand all Loading... |
| 550 } | 548 } |
| 551 | 549 |
| 552 // The generated code looks like this: | 550 // The generated code looks like this: |
| 553 // | 551 // |
| 554 // { | 552 // { |
| 555 // var H = {...}, ..., G = {...}; | 553 // var H = {...}, ..., G = {...}; |
| 556 // var holders = [ H, ..., G ]; | 554 // var holders = [ H, ..., G ]; |
| 557 // } | 555 // } |
| 558 | 556 |
| 559 List<js.Statement> statements = [ | 557 List<js.Statement> statements = [ |
| 560 new js.ExpressionStatement( | 558 new js.ExpressionStatement(new js.VariableDeclarationList( |
| 561 new js.VariableDeclarationList(holders | 559 holders.map(emitHolderInitialization).toList())), |
| 562 .map(emitHolderInitialization) | 560 js.js.statement( |
| 563 .toList())), | 561 'var holders = #', |
| 564 js.js.statement('var holders = #', new js.ArrayInitializer( | 562 new js.ArrayInitializer(holders |
| 565 holders | |
| 566 .map((holder) => new js.VariableUse(holder.name)) | 563 .map((holder) => new js.VariableUse(holder.name)) |
| 567 .toList(growable: false)))]; | 564 .toList(growable: false))) |
| 565 ]; |
| 568 return new js.Block(statements); | 566 return new js.Block(statements); |
| 569 } | 567 } |
| 570 | 568 |
| 571 /// Returns a reference to the constant holder, or the JS-literal `null`. | 569 /// Returns a reference to the constant holder, or the JS-literal `null`. |
| 572 js.Expression buildConstantHolderReference(Program program) { | 570 js.Expression buildConstantHolderReference(Program program) { |
| 573 Holder constantHolder = program.holders | 571 Holder constantHolder = program.holders.firstWhere( |
| 574 .firstWhere((Holder holder) => holder.isConstantsHolder, | 572 (Holder holder) => holder.isConstantsHolder, |
| 575 orElse: () => null); | 573 orElse: () => null); |
| 576 if (constantHolder == null) return new js.LiteralNull(); | 574 if (constantHolder == null) return new js.LiteralNull(); |
| 577 return new js.VariableUse(constantHolder.name); | 575 return new js.VariableUse(constantHolder.name); |
| 578 } | 576 } |
| 579 | 577 |
| 580 /// Emits the given [method]. | 578 /// Emits the given [method]. |
| 581 /// | 579 /// |
| 582 /// A Dart method might result in several JavaScript functions, if it | 580 /// A Dart method might result in several JavaScript functions, if it |
| 583 /// requires stubs. The returned map contains the original method and all | 581 /// requires stubs. The returned map contains the original method and all |
| 584 /// the stubs it needs. | 582 /// the stubs it needs. |
| 585 Map<js.Name, js.Expression> emitStaticMethod(StaticMethod method) { | 583 Map<js.Name, js.Expression> emitStaticMethod(StaticMethod method) { |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 619 } | 617 } |
| 620 | 618 |
| 621 /// Emits the prototype-section of the fragment. | 619 /// Emits the prototype-section of the fragment. |
| 622 /// | 620 /// |
| 623 /// This section updates the prototype-property of all constructors in the | 621 /// This section updates the prototype-property of all constructors in the |
| 624 /// global holders. | 622 /// global holders. |
| 625 js.Statement emitPrototypes(Fragment fragment) { | 623 js.Statement emitPrototypes(Fragment fragment) { |
| 626 List<js.Statement> assignments = fragment.libraries | 624 List<js.Statement> assignments = fragment.libraries |
| 627 .expand((Library library) => library.classes) | 625 .expand((Library library) => library.classes) |
| 628 .map((Class cls) => js.js.statement( | 626 .map((Class cls) => js.js.statement( |
| 629 '#.prototype = #;', | 627 '#.prototype = #;', [classReference(cls), emitPrototype(cls)])) |
| 630 [classReference(cls), emitPrototype(cls)])) | |
| 631 .toList(growable: false); | 628 .toList(growable: false); |
| 632 | 629 |
| 633 return new js.Block(assignments); | 630 return new js.Block(assignments); |
| 634 } | 631 } |
| 635 | 632 |
| 636 /// Emits the prototype of the given class [cls]. | 633 /// Emits the prototype of the given class [cls]. |
| 637 /// | 634 /// |
| 638 /// The prototype is generated as object literal. Inheritance is ignored. | 635 /// The prototype is generated as object literal. Inheritance is ignored. |
| 639 /// | 636 /// |
| 640 /// The prototype also includes the `is-property` that every class must have. | 637 /// The prototype also includes the `is-property` that every class must have. |
| 641 // TODO(floitsch): we could avoid that property if we knew that it wasn't | 638 // TODO(floitsch): we could avoid that property if we knew that it wasn't |
| 642 // needed. | 639 // needed. |
| 643 js.Expression emitPrototype(Class cls) { | 640 js.Expression emitPrototype(Class cls) { |
| 644 Iterable<Method> methods = cls.methods; | 641 Iterable<Method> methods = cls.methods; |
| 645 Iterable<Method> checkedSetters = cls.checkedSetters; | 642 Iterable<Method> checkedSetters = cls.checkedSetters; |
| 646 Iterable<Method> isChecks = cls.isChecks; | 643 Iterable<Method> isChecks = cls.isChecks; |
| 647 Iterable<Method> callStubs = cls.callStubs; | 644 Iterable<Method> callStubs = cls.callStubs; |
| 648 Iterable<Method> typeVariableReaderStubs = cls.typeVariableReaderStubs; | 645 Iterable<Method> typeVariableReaderStubs = cls.typeVariableReaderStubs; |
| 649 Iterable<Method> noSuchMethodStubs = cls.noSuchMethodStubs; | 646 Iterable<Method> noSuchMethodStubs = cls.noSuchMethodStubs; |
| 650 Iterable<Method> gettersSetters = generateGettersSetters(cls); | 647 Iterable<Method> gettersSetters = generateGettersSetters(cls); |
| 651 Iterable<Method> allMethods = | 648 Iterable<Method> allMethods = [ |
| 652 [methods, checkedSetters, isChecks, callStubs, typeVariableReaderStubs, | 649 methods, |
| 653 noSuchMethodStubs, gettersSetters].expand((x) => x); | 650 checkedSetters, |
| 651 isChecks, |
| 652 callStubs, |
| 653 typeVariableReaderStubs, |
| 654 noSuchMethodStubs, |
| 655 gettersSetters |
| 656 ].expand((x) => x); |
| 654 | 657 |
| 655 List<js.Property> properties = <js.Property>[]; | 658 List<js.Property> properties = <js.Property>[]; |
| 656 | 659 |
| 657 if (cls.superclass == null) { | 660 if (cls.superclass == null) { |
| 658 properties.add(new js.Property(js.string("constructor"), | 661 properties |
| 659 classReference(cls))); | 662 .add(new js.Property(js.string("constructor"), classReference(cls))); |
| 660 properties.add(new js.Property(namer.operatorIs(cls.element), | 663 properties |
| 661 js.number(1))); | 664 .add(new js.Property(namer.operatorIs(cls.element), js.number(1))); |
| 662 } | 665 } |
| 663 | 666 |
| 664 allMethods.forEach((Method method) { | 667 allMethods.forEach((Method method) { |
| 665 emitInstanceMethod(method) | 668 emitInstanceMethod(method) |
| 666 .forEach((js.Expression name, js.Expression code) { | 669 .forEach((js.Expression name, js.Expression code) { |
| 667 properties.add(new js.Property(name, code)); | 670 properties.add(new js.Property(name, code)); |
| 668 }); | 671 }); |
| 669 }); | 672 }); |
| 670 | 673 |
| 671 return new js.ObjectInitializer(properties); | 674 return new js.ObjectInitializer(properties); |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 740 for (ParameterStubMethod stubMethod in method.parameterStubs) { | 743 for (ParameterStubMethod stubMethod in method.parameterStubs) { |
| 741 properties[stubMethod.name] = stubMethod.code; | 744 properties[stubMethod.name] = stubMethod.code; |
| 742 } | 745 } |
| 743 | 746 |
| 744 if (method.isClosureCallMethod && method.canBeApplied) { | 747 if (method.isClosureCallMethod && method.canBeApplied) { |
| 745 properties[js.string(namer.callCatchAllName)] = | 748 properties[js.string(namer.callCatchAllName)] = |
| 746 js.quoteName(method.name); | 749 js.quoteName(method.name); |
| 747 properties[js.string(namer.requiredParameterField)] = | 750 properties[js.string(namer.requiredParameterField)] = |
| 748 js.number(method.requiredParameterCount); | 751 js.number(method.requiredParameterCount); |
| 749 properties[js.string(namer.defaultValuesField)] = | 752 properties[js.string(namer.defaultValuesField)] = |
| 750 _encodeOptionalParameterDefaultValues(method); | 753 _encodeOptionalParameterDefaultValues(method); |
| 751 } | 754 } |
| 752 } | 755 } |
| 753 | 756 |
| 754 return properties; | 757 return properties; |
| 755 } | 758 } |
| 756 | 759 |
| 757 /// Emits the inheritance block of the fragment. | 760 /// Emits the inheritance block of the fragment. |
| 758 /// | 761 /// |
| 759 /// In this section prototype chains are updated and mixin functions are | 762 /// In this section prototype chains are updated and mixin functions are |
| 760 /// copied. | 763 /// copied. |
| 761 js.Statement emitInheritance(Fragment fragment) { | 764 js.Statement emitInheritance(Fragment fragment) { |
| 762 List<js.Expression> inheritCalls = <js.Expression>[]; | 765 List<js.Expression> inheritCalls = <js.Expression>[]; |
| 763 List<js.Expression> mixinCalls = <js.Expression>[]; | 766 List<js.Expression> mixinCalls = <js.Expression>[]; |
| 764 | 767 |
| 765 Set<Class> emittedClasses = new Set<Class>(); | 768 Set<Class> emittedClasses = new Set<Class>(); |
| 766 | 769 |
| 767 void emitInheritanceForClass(cls) { | 770 void emitInheritanceForClass(cls) { |
| 768 if (cls == null || emittedClasses.contains(cls)) return; | 771 if (cls == null || emittedClasses.contains(cls)) return; |
| 769 | 772 |
| 770 Class superclass = cls.superclass; | 773 Class superclass = cls.superclass; |
| 771 emitInheritanceForClass(superclass); | 774 emitInheritanceForClass(superclass); |
| 772 | 775 |
| 773 js.Expression superclassReference = (superclass == null) | 776 js.Expression superclassReference = (superclass == null) |
| 774 ? new js.LiteralNull() | 777 ? new js.LiteralNull() |
| 775 : classReference(superclass); | 778 : classReference(superclass); |
| 776 | 779 |
| 777 inheritCalls.add(js.js('inherit(#, #)', | 780 inheritCalls.add( |
| 778 [classReference(cls), superclassReference])); | 781 js.js('inherit(#, #)', [classReference(cls), superclassReference])); |
| 779 | 782 |
| 780 emittedClasses.add(cls); | 783 emittedClasses.add(cls); |
| 781 } | 784 } |
| 782 | 785 |
| 783 for (Library library in fragment.libraries) { | 786 for (Library library in fragment.libraries) { |
| 784 for (Class cls in library.classes) { | 787 for (Class cls in library.classes) { |
| 785 emitInheritanceForClass(cls); | 788 emitInheritanceForClass(cls); |
| 786 | 789 |
| 787 if (cls.isMixinApplication) { | 790 if (cls.isMixinApplication) { |
| 788 MixinApplication mixin = cls; | 791 MixinApplication mixin = cls; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 802 /// | 805 /// |
| 803 /// This step consists of simply copying JavaScript functions to their | 806 /// This step consists of simply copying JavaScript functions to their |
| 804 /// aliased names so they point to the same function. | 807 /// aliased names so they point to the same function. |
| 805 js.Statement emitInstanceMethodAliases(Fragment fragment) { | 808 js.Statement emitInstanceMethodAliases(Fragment fragment) { |
| 806 List<js.Statement> assignments = <js.Statement>[]; | 809 List<js.Statement> assignments = <js.Statement>[]; |
| 807 | 810 |
| 808 for (Library library in fragment.libraries) { | 811 for (Library library in fragment.libraries) { |
| 809 for (Class cls in library.classes) { | 812 for (Class cls in library.classes) { |
| 810 for (InstanceMethod method in cls.methods) { | 813 for (InstanceMethod method in cls.methods) { |
| 811 if (method.aliasName != null) { | 814 if (method.aliasName != null) { |
| 812 assignments.add(js.js.statement( | 815 assignments.add(js.js.statement('#.prototype.# = #.prototype.#', [ |
| 813 '#.prototype.# = #.prototype.#', | 816 classReference(cls), |
| 814 [classReference(cls), js.quoteName(method.aliasName), | 817 js.quoteName(method.aliasName), |
| 815 classReference(cls), js.quoteName(method.name)])); | 818 classReference(cls), |
| 816 | 819 js.quoteName(method.name) |
| 820 ])); |
| 817 } | 821 } |
| 818 } | 822 } |
| 819 } | 823 } |
| 820 } | 824 } |
| 821 return new js.Block(assignments); | 825 return new js.Block(assignments); |
| 822 } | 826 } |
| 823 | 827 |
| 824 /// Encodes the optional default values so that the runtime Function.apply | 828 /// Encodes the optional default values so that the runtime Function.apply |
| 825 /// can use them. | 829 /// can use them. |
| 826 js.Expression _encodeOptionalParameterDefaultValues(DartMethod method) { | 830 js.Expression _encodeOptionalParameterDefaultValues(DartMethod method) { |
| 827 // TODO(herhut): Replace [js.LiteralNull] with [js.ArrayHole]. | 831 // TODO(herhut): Replace [js.LiteralNull] with [js.ArrayHole]. |
| 828 if (method.optionalParameterDefaultValues is List) { | 832 if (method.optionalParameterDefaultValues is List) { |
| 829 List<ConstantValue> defaultValues = method.optionalParameterDefaultValues; | 833 List<ConstantValue> defaultValues = method.optionalParameterDefaultValues; |
| 830 Iterable<js.Expression> elements = | 834 Iterable<js.Expression> elements = |
| 831 defaultValues.map(generateConstantReference); | 835 defaultValues.map(generateConstantReference); |
| 832 return js.js('function() { return #; }', | 836 return js.js('function() { return #; }', |
| 833 new js.ArrayInitializer(elements.toList())); | 837 new js.ArrayInitializer(elements.toList())); |
| 834 } else { | 838 } else { |
| 835 Map<String, ConstantValue> defaultValues = | 839 Map<String, ConstantValue> defaultValues = |
| 836 method.optionalParameterDefaultValues; | 840 method.optionalParameterDefaultValues; |
| 837 List<js.Property> properties = <js.Property>[]; | 841 List<js.Property> properties = <js.Property>[]; |
| 838 List<String> names = defaultValues.keys.toList(growable: false); | 842 List<String> names = defaultValues.keys.toList(growable: false); |
| 839 // Sort the names the same way we sort them for the named-argument calling | 843 // Sort the names the same way we sort them for the named-argument calling |
| 840 // convention. | 844 // convention. |
| 841 names.sort(); | 845 names.sort(); |
| 842 | 846 |
| 843 for (String name in names) { | 847 for (String name in names) { |
| 844 ConstantValue value = defaultValues[name]; | 848 ConstantValue value = defaultValues[name]; |
| 845 properties.add(new js.Property(js.string(name), | 849 properties.add( |
| 846 generateConstantReference(value))); | 850 new js.Property(js.string(name), generateConstantReference(value))); |
| 847 } | 851 } |
| 848 return js.js('function() { return #; }', | 852 return js.js( |
| 849 new js.ObjectInitializer(properties)); | 853 'function() { return #; }', new js.ObjectInitializer(properties)); |
| 850 } | 854 } |
| 851 } | 855 } |
| 852 | 856 |
| 853 /// Emits the statement that installs a tear off for a method. | 857 /// Emits the statement that installs a tear off for a method. |
| 854 /// | 858 /// |
| 855 /// Tear-offs might be passed to `Function.apply` which means that all | 859 /// Tear-offs might be passed to `Function.apply` which means that all |
| 856 /// calling-conventions (with or without optional positional/named arguments) | 860 /// calling-conventions (with or without optional positional/named arguments) |
| 857 /// are possible. As such, the tear-off needs enough information to fill in | 861 /// are possible. As such, the tear-off needs enough information to fill in |
| 858 /// missing parameters. | 862 /// missing parameters. |
| 859 js.Statement emitInstallTearOff(js.Expression container, DartMethod method) { | 863 js.Statement emitInstallTearOff(js.Expression container, DartMethod method) { |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 892 isIntercepted = backend.isInterceptedMethod(method.element); | 896 isIntercepted = backend.isInterceptedMethod(method.element); |
| 893 } | 897 } |
| 894 int requiredParameterCount = 0; | 898 int requiredParameterCount = 0; |
| 895 js.Expression optionalParameterDefaultValues = new js.LiteralNull(); | 899 js.Expression optionalParameterDefaultValues = new js.LiteralNull(); |
| 896 if (method.canBeApplied) { | 900 if (method.canBeApplied) { |
| 897 requiredParameterCount = method.requiredParameterCount; | 901 requiredParameterCount = method.requiredParameterCount; |
| 898 optionalParameterDefaultValues = | 902 optionalParameterDefaultValues = |
| 899 _encodeOptionalParameterDefaultValues(method); | 903 _encodeOptionalParameterDefaultValues(method); |
| 900 } | 904 } |
| 901 | 905 |
| 902 return js.js.statement(''' | 906 return js.js.statement( |
| 907 ''' |
| 903 installTearOff(#container, #getterName, #isStatic, #isIntercepted, | 908 installTearOff(#container, #getterName, #isStatic, #isIntercepted, |
| 904 #requiredParameterCount, #optionalParameterDefaultValues, | 909 #requiredParameterCount, #optionalParameterDefaultValues, |
| 905 #callNames, #funsOrNames, #funType)''', | 910 #callNames, #funsOrNames, #funType)''', |
| 906 { | 911 { |
| 907 "container": container, | 912 "container": container, |
| 908 "getterName": js.quoteName(method.tearOffName), | 913 "getterName": js.quoteName(method.tearOffName), |
| 909 "isStatic": new js.LiteralBool(method.isStatic), | 914 "isStatic": new js.LiteralBool(method.isStatic), |
| 910 "isIntercepted": new js.LiteralBool(isIntercepted), | 915 "isIntercepted": new js.LiteralBool(isIntercepted), |
| 911 "requiredParameterCount": js.number(requiredParameterCount), | 916 "requiredParameterCount": js.number(requiredParameterCount), |
| 912 "optionalParameterDefaultValues": optionalParameterDefaultValues, | 917 "optionalParameterDefaultValues": optionalParameterDefaultValues, |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 944 } | 949 } |
| 945 | 950 |
| 946 /// Emits the constants section. | 951 /// Emits the constants section. |
| 947 js.Statement emitConstants(Fragment fragment) { | 952 js.Statement emitConstants(Fragment fragment) { |
| 948 List<js.Statement> assignments = <js.Statement>[]; | 953 List<js.Statement> assignments = <js.Statement>[]; |
| 949 for (Constant constant in fragment.constants) { | 954 for (Constant constant in fragment.constants) { |
| 950 // TODO(floitsch): instead of just updating the constant holder, we should | 955 // TODO(floitsch): instead of just updating the constant holder, we should |
| 951 // find the constants that don't have any dependency on other constants | 956 // find the constants that don't have any dependency on other constants |
| 952 // and create an object-literal with them (and assign it to the | 957 // and create an object-literal with them (and assign it to the |
| 953 // constant-holder variable). | 958 // constant-holder variable). |
| 954 assignments.add(js.js.statement('#.# = #', | 959 assignments.add(js.js.statement('#.# = #', [ |
| 955 [constant.holder.name, | 960 constant.holder.name, |
| 956 constant.name, | 961 constant.name, |
| 957 constantEmitter.generate(constant.value)])); | 962 constantEmitter.generate(constant.value) |
| 963 ])); |
| 958 } | 964 } |
| 959 return new js.Block(assignments); | 965 return new js.Block(assignments); |
| 960 } | 966 } |
| 961 | 967 |
| 962 | |
| 963 /// Emits the static non-final fields section. | 968 /// Emits the static non-final fields section. |
| 964 /// | 969 /// |
| 965 /// This section initializes all static non-final fields that don't require | 970 /// This section initializes all static non-final fields that don't require |
| 966 /// an initializer. | 971 /// an initializer. |
| 967 js.Block emitStaticNonFinalFields(Fragment fragment) { | 972 js.Block emitStaticNonFinalFields(Fragment fragment) { |
| 968 List<StaticField> fields = fragment.staticNonFinalFields; | 973 List<StaticField> fields = fragment.staticNonFinalFields; |
| 969 // TODO(floitsch): instead of assigning the fields one-by-one we should | 974 // TODO(floitsch): instead of assigning the fields one-by-one we should |
| 970 // create a literal and assign it to the static-state holder. | 975 // create a literal and assign it to the static-state holder. |
| 971 // TODO(floitsch): if we don't make a literal we should at least initialize | 976 // TODO(floitsch): if we don't make a literal we should at least initialize |
| 972 // statics that have the same initial value in the same expression: | 977 // statics that have the same initial value in the same expression: |
| 973 // `$.x = $.y = $.z = null;`. | 978 // `$.x = $.y = $.z = null;`. |
| 974 Iterable<js.Statement> statements = fields.map((StaticField field) { | 979 Iterable<js.Statement> statements = fields.map((StaticField field) { |
| 975 assert(field.holder.isStaticStateHolder); | 980 assert(field.holder.isStaticStateHolder); |
| 976 return js.js.statement("#.# = #;", | 981 return js.js |
| 977 [field.holder.name, field.name, field.code]); | 982 .statement("#.# = #;", [field.holder.name, field.name, field.code]); |
| 978 }); | 983 }); |
| 979 return new js.Block(statements.toList()); | 984 return new js.Block(statements.toList()); |
| 980 } | 985 } |
| 981 | 986 |
| 982 /// Emits lazy fields. | 987 /// Emits lazy fields. |
| 983 /// | 988 /// |
| 984 /// This section initializes all static (final and non-final) fields that | 989 /// This section initializes all static (final and non-final) fields that |
| 985 /// require an initializer. | 990 /// require an initializer. |
| 986 js.Block emitLazilyInitializedStatics(Fragment fragment) { | 991 js.Block emitLazilyInitializedStatics(Fragment fragment) { |
| 987 List<StaticField> fields = fragment.staticLazilyInitializedFields; | 992 List<StaticField> fields = fragment.staticLazilyInitializedFields; |
| 988 Iterable<js.Statement> statements = fields.map((StaticField field) { | 993 Iterable<js.Statement> statements = fields.map((StaticField field) { |
| 989 assert(field.holder.isStaticStateHolder); | 994 assert(field.holder.isStaticStateHolder); |
| 990 return js.js.statement("lazy(#, #, #, #);", | 995 return js.js.statement("lazy(#, #, #, #);", [ |
| 991 [field.holder.name, | 996 field.holder.name, |
| 992 js.quoteName(field.name), | 997 js.quoteName(field.name), |
| 993 js.quoteName(namer.deriveLazyInitializerName(field.name)), | 998 js.quoteName(namer.deriveLazyInitializerName(field.name)), |
| 994 field.code]); | 999 field.code |
| 1000 ]); |
| 995 }); | 1001 }); |
| 996 | 1002 |
| 997 return new js.Block(statements.toList()); | 1003 return new js.Block(statements.toList()); |
| 998 } | 1004 } |
| 999 | 1005 |
| 1000 /// Emits the embedded globals that are needed for deferred loading. | 1006 /// Emits the embedded globals that are needed for deferred loading. |
| 1001 /// | 1007 /// |
| 1002 /// This function is only invoked for the main fragment. | 1008 /// This function is only invoked for the main fragment. |
| 1003 /// | 1009 /// |
| 1004 /// The [loadMap] contains a map from load-ids (for each deferred library) | 1010 /// The [loadMap] contains a map from load-ids (for each deferred library) |
| 1005 /// to the list of generated fragments that must be installed when the | 1011 /// to the list of generated fragments that must be installed when the |
| 1006 /// deferred library is loaded. | 1012 /// deferred library is loaded. |
| 1007 Iterable<js.Property> emitEmbeddedGlobalsForDeferredLoading( | 1013 Iterable<js.Property> emitEmbeddedGlobalsForDeferredLoading( |
| 1008 Map<String, List<Fragment>> loadMap, | 1014 Map<String, List<Fragment>> loadMap, |
| 1009 Map<DeferredFragment, _DeferredFragmentHash> deferredLoadHashes) { | 1015 Map<DeferredFragment, _DeferredFragmentHash> deferredLoadHashes) { |
| 1010 if (loadMap.isEmpty) return []; | 1016 if (loadMap.isEmpty) return []; |
| 1011 | 1017 |
| 1012 List<js.Property> globals = <js.Property>[]; | 1018 List<js.Property> globals = <js.Property>[]; |
| 1013 | 1019 |
| 1014 js.ArrayInitializer fragmentUris(List<Fragment> fragments) { | 1020 js.ArrayInitializer fragmentUris(List<Fragment> fragments) { |
| 1015 return js.stringArray(fragments.map((DeferredFragment fragment) => | 1021 return js.stringArray(fragments.map((DeferredFragment fragment) => |
| 1016 "${fragment.outputFileName}.${ModelEmitter.deferredExtension}")); | 1022 "${fragment.outputFileName}.${ModelEmitter.deferredExtension}")); |
| 1017 } | 1023 } |
| 1018 js.ArrayInitializer fragmentHashes(List<Fragment> fragments) { | 1024 js.ArrayInitializer fragmentHashes(List<Fragment> fragments) { |
| 1019 return new js.ArrayInitializer( | 1025 return new js.ArrayInitializer(fragments |
| 1020 fragments | 1026 .map((fragment) => deferredLoadHashes[fragment]) |
| 1021 .map((fragment) => deferredLoadHashes[fragment]) | 1027 .toList(growable: false)); |
| 1022 .toList(growable: false)); | |
| 1023 } | 1028 } |
| 1024 | 1029 |
| 1025 List<js.Property> uris = new List<js.Property>(loadMap.length); | 1030 List<js.Property> uris = new List<js.Property>(loadMap.length); |
| 1026 List<js.Property> hashes = new List<js.Property>(loadMap.length); | 1031 List<js.Property> hashes = new List<js.Property>(loadMap.length); |
| 1027 int count = 0; | 1032 int count = 0; |
| 1028 loadMap.forEach((String loadId, List<Fragment> fragmentList) { | 1033 loadMap.forEach((String loadId, List<Fragment> fragmentList) { |
| 1029 uris[count] = | 1034 uris[count] = |
| 1030 new js.Property(js.string(loadId), fragmentUris(fragmentList)); | 1035 new js.Property(js.string(loadId), fragmentUris(fragmentList)); |
| 1031 hashes[count] = | 1036 hashes[count] = |
| 1032 new js.Property(js.string(loadId), fragmentHashes(fragmentList)); | 1037 new js.Property(js.string(loadId), fragmentHashes(fragmentList)); |
| 1033 count++; | 1038 count++; |
| 1034 }); | 1039 }); |
| 1035 | 1040 |
| 1036 globals.add(new js.Property(js.string(DEFERRED_LIBRARY_URIS), | 1041 globals.add(new js.Property( |
| 1037 new js.ObjectInitializer(uris))); | 1042 js.string(DEFERRED_LIBRARY_URIS), new js.ObjectInitializer(uris))); |
| 1038 globals.add(new js.Property(js.string(DEFERRED_LIBRARY_HASHES), | 1043 globals.add(new js.Property( |
| 1039 new js.ObjectInitializer(hashes))); | 1044 js.string(DEFERRED_LIBRARY_HASHES), new js.ObjectInitializer(hashes))); |
| 1040 globals.add(new js.Property(js.string(DEFERRED_INITIALIZED), | 1045 globals.add(new js.Property( |
| 1041 js.js("Object.create(null)"))); | 1046 js.string(DEFERRED_INITIALIZED), js.js("Object.create(null)"))); |
| 1042 | 1047 |
| 1043 String deferredGlobal = ModelEmitter.deferredInitializersGlobal; | 1048 String deferredGlobal = ModelEmitter.deferredInitializersGlobal; |
| 1044 js.Expression isHunkLoadedFunction = | 1049 js.Expression isHunkLoadedFunction = |
| 1045 js.js("function(hash) { return !!$deferredGlobal[hash]; }"); | 1050 js.js("function(hash) { return !!$deferredGlobal[hash]; }"); |
| 1046 globals.add(new js.Property(js.string(IS_HUNK_LOADED), | 1051 globals |
| 1047 isHunkLoadedFunction)); | 1052 .add(new js.Property(js.string(IS_HUNK_LOADED), isHunkLoadedFunction)); |
| 1048 | 1053 |
| 1049 js.Expression isHunkInitializedFunction = | 1054 js.Expression isHunkInitializedFunction = js.js( |
| 1050 js.js("function(hash) { return !!#deferredInitialized[hash]; }", | 1055 "function(hash) { return !!#deferredInitialized[hash]; }", { |
| 1051 {'deferredInitialized': | 1056 'deferredInitialized': generateEmbeddedGlobalAccess(DEFERRED_INITIALIZED) |
| 1052 generateEmbeddedGlobalAccess(DEFERRED_INITIALIZED)}); | 1057 }); |
| 1053 globals.add(new js.Property(js.string(IS_HUNK_INITIALIZED), | 1058 globals.add(new js.Property( |
| 1054 isHunkInitializedFunction)); | 1059 js.string(IS_HUNK_INITIALIZED), isHunkInitializedFunction)); |
| 1055 | 1060 |
| 1056 /// See [emitEmbeddedGlobalsForDeferredLoading] for the format of the | 1061 /// See [emitEmbeddedGlobalsForDeferredLoading] for the format of the |
| 1057 /// deferred hunk. | 1062 /// deferred hunk. |
| 1058 js.Expression initializeLoadedHunkFunction = | 1063 js.Expression initializeLoadedHunkFunction = js.js( |
| 1059 js.js(""" | 1064 """ |
| 1060 function(hash) { | 1065 function(hash) { |
| 1061 initializeDeferredHunk($deferredGlobal[hash]); | 1066 initializeDeferredHunk($deferredGlobal[hash]); |
| 1062 #deferredInitialized[hash] = true; | 1067 #deferredInitialized[hash] = true; |
| 1063 }""", {'deferredInitialized': | 1068 }""", |
| 1064 generateEmbeddedGlobalAccess(DEFERRED_INITIALIZED)}); | 1069 { |
| 1070 'deferredInitialized': |
| 1071 generateEmbeddedGlobalAccess(DEFERRED_INITIALIZED) |
| 1072 }); |
| 1065 | 1073 |
| 1066 globals.add(new js.Property(js.string(INITIALIZE_LOADED_HUNK), | 1074 globals.add(new js.Property( |
| 1067 initializeLoadedHunkFunction)); | 1075 js.string(INITIALIZE_LOADED_HUNK), initializeLoadedHunkFunction)); |
| 1068 | 1076 |
| 1069 return globals; | 1077 return globals; |
| 1070 } | 1078 } |
| 1071 | 1079 |
| 1072 /// Emits the [MANGLED_GLOBAL_NAMES] embedded global. | 1080 /// Emits the [MANGLED_GLOBAL_NAMES] embedded global. |
| 1073 /// | 1081 /// |
| 1074 /// This global maps minified names for selected classes (some important | 1082 /// This global maps minified names for selected classes (some important |
| 1075 /// core classes, and some native classes) to their unminified names. | 1083 /// core classes, and some native classes) to their unminified names. |
| 1076 js.Property emitMangledGlobalNames() { | 1084 js.Property emitMangledGlobalNames() { |
| 1077 List<js.Property> names = <js.Property>[]; | 1085 List<js.Property> names = <js.Property>[]; |
| 1078 | 1086 |
| 1079 CoreClasses coreClasses = compiler.coreClasses; | 1087 CoreClasses coreClasses = compiler.coreClasses; |
| 1080 // We want to keep the original names for the most common core classes when | 1088 // We want to keep the original names for the most common core classes when |
| 1081 // calling toString on them. | 1089 // calling toString on them. |
| 1082 List<ClassElement> nativeClassesNeedingUnmangledName = | 1090 List<ClassElement> nativeClassesNeedingUnmangledName = [ |
| 1083 [coreClasses.intClass, coreClasses.doubleClass, coreClasses.numClass, | 1091 coreClasses.intClass, |
| 1084 coreClasses.stringClass, coreClasses.boolClass, coreClasses.nullClass, | 1092 coreClasses.doubleClass, |
| 1085 coreClasses.listClass]; | 1093 coreClasses.numClass, |
| 1094 coreClasses.stringClass, |
| 1095 coreClasses.boolClass, |
| 1096 coreClasses.nullClass, |
| 1097 coreClasses.listClass |
| 1098 ]; |
| 1086 // TODO(floitsch): this should probably be on a per-fragment basis. | 1099 // TODO(floitsch): this should probably be on a per-fragment basis. |
| 1087 nativeClassesNeedingUnmangledName.forEach((element) { | 1100 nativeClassesNeedingUnmangledName.forEach((element) { |
| 1088 names.add(new js.Property(js.quoteName(namer.className(element)), | 1101 names.add(new js.Property( |
| 1089 js.string(element.name))); | 1102 js.quoteName(namer.className(element)), js.string(element.name))); |
| 1090 }); | 1103 }); |
| 1091 | 1104 |
| 1092 return new js.Property(js.string(MANGLED_GLOBAL_NAMES), | 1105 return new js.Property( |
| 1093 new js.ObjectInitializer(names)); | 1106 js.string(MANGLED_GLOBAL_NAMES), new js.ObjectInitializer(names)); |
| 1094 } | 1107 } |
| 1095 | 1108 |
| 1096 /// Emits the [GET_TYPE_FROM_NAME] embedded global. | 1109 /// Emits the [GET_TYPE_FROM_NAME] embedded global. |
| 1097 /// | 1110 /// |
| 1098 /// This embedded global provides a way to go from a class name (which is | 1111 /// This embedded global provides a way to go from a class name (which is |
| 1099 /// also the constructor's name) to the constructor itself. | 1112 /// also the constructor's name) to the constructor itself. |
| 1100 js.Property emitGetTypeFromName() { | 1113 js.Property emitGetTypeFromName() { |
| 1101 js.Expression function = js.js("getGlobalFromName"); | 1114 js.Expression function = js.js("getGlobalFromName"); |
| 1102 return new js.Property(js.string(GET_TYPE_FROM_NAME), function); | 1115 return new js.Property(js.string(GET_TYPE_FROM_NAME), function); |
| 1103 } | 1116 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1115 | 1128 |
| 1116 metadataGlobals.add(createGlobal(program.metadata, METADATA)); | 1129 metadataGlobals.add(createGlobal(program.metadata, METADATA)); |
| 1117 js.Expression types = | 1130 js.Expression types = |
| 1118 program.metadataTypesForOutputUnit(program.mainFragment.outputUnit); | 1131 program.metadataTypesForOutputUnit(program.mainFragment.outputUnit); |
| 1119 metadataGlobals.add(createGlobal(types, TYPES)); | 1132 metadataGlobals.add(createGlobal(types, TYPES)); |
| 1120 | 1133 |
| 1121 return metadataGlobals; | 1134 return metadataGlobals; |
| 1122 } | 1135 } |
| 1123 | 1136 |
| 1124 /// Emits all embedded globals. | 1137 /// Emits all embedded globals. |
| 1125 js.Statement emitEmbeddedGlobals( | 1138 js.Statement emitEmbeddedGlobals(Program program, |
| 1126 Program program, | |
| 1127 Map<DeferredFragment, _DeferredFragmentHash> deferredLoadHashes) { | 1139 Map<DeferredFragment, _DeferredFragmentHash> deferredLoadHashes) { |
| 1128 List<js.Property> globals = <js.Property>[]; | 1140 List<js.Property> globals = <js.Property>[]; |
| 1129 | 1141 |
| 1130 if (program.loadMap.isNotEmpty) { | 1142 if (program.loadMap.isNotEmpty) { |
| 1131 globals.addAll(emitEmbeddedGlobalsForDeferredLoading( | 1143 globals.addAll(emitEmbeddedGlobalsForDeferredLoading( |
| 1132 program.loadMap, deferredLoadHashes)); | 1144 program.loadMap, deferredLoadHashes)); |
| 1133 } | 1145 } |
| 1134 | 1146 |
| 1135 if (program.typeToInterceptorMap != null) { | 1147 if (program.typeToInterceptorMap != null) { |
| 1136 globals.add(new js.Property(js.string(TYPE_TO_INTERCEPTOR_MAP), | 1148 globals.add(new js.Property( |
| 1137 program.typeToInterceptorMap)); | 1149 js.string(TYPE_TO_INTERCEPTOR_MAP), program.typeToInterceptorMap)); |
| 1138 } | 1150 } |
| 1139 | 1151 |
| 1140 if (program.hasIsolateSupport) { | 1152 if (program.hasIsolateSupport) { |
| 1141 String staticStateName = namer.staticStateHolder; | 1153 String staticStateName = namer.staticStateHolder; |
| 1142 // TODO(floitsch): this doesn't create a new isolate, but just reuses | 1154 // TODO(floitsch): this doesn't create a new isolate, but just reuses |
| 1143 // the current static state. Since we don't run multiple isolates in the | 1155 // the current static state. Since we don't run multiple isolates in the |
| 1144 // same JavaScript context (except for testing) this shouldn't have any | 1156 // same JavaScript context (except for testing) this shouldn't have any |
| 1145 // impact on real-world programs, though. | 1157 // impact on real-world programs, though. |
| 1146 globals.add( | 1158 globals.add(new js.Property(js.string(CREATE_NEW_ISOLATE), |
| 1147 new js.Property(js.string(CREATE_NEW_ISOLATE), | 1159 js.js('function () { return $staticStateName; }'))); |
| 1148 js.js('function () { return $staticStateName; }'))); | |
| 1149 | 1160 |
| 1150 js.Expression nameToClosureFunction = js.js(''' | 1161 js.Expression nameToClosureFunction = js.js(''' |
| 1151 // First fetch the static function. From there we can execute its | 1162 // First fetch the static function. From there we can execute its |
| 1152 // getter function which builds a Dart closure. | 1163 // getter function which builds a Dart closure. |
| 1153 function(name) { | 1164 function(name) { |
| 1154 var staticFunction = getGlobalFromName(name); | 1165 var staticFunction = getGlobalFromName(name); |
| 1155 var getterFunction = staticFunction.$tearOffPropertyName; | 1166 var getterFunction = staticFunction.$tearOffPropertyName; |
| 1156 return getterFunction(); | 1167 return getterFunction(); |
| 1157 }'''); | 1168 }'''); |
| 1158 globals.add(new js.Property(js.string(STATIC_FUNCTION_NAME_TO_CLOSURE), | 1169 globals.add(new js.Property( |
| 1159 nameToClosureFunction)); | 1170 js.string(STATIC_FUNCTION_NAME_TO_CLOSURE), nameToClosureFunction)); |
| 1160 | 1171 |
| 1161 globals.add( | 1172 globals.add(new js.Property(js.string(CLASS_ID_EXTRACTOR), |
| 1162 new js.Property(js.string(CLASS_ID_EXTRACTOR), | 1173 js.js('function(o) { return o.constructor.name; }'))); |
| 1163 js.js('function(o) { return o.constructor.name; }'))); | |
| 1164 | 1174 |
| 1165 js.Expression extractFieldsFunction = js.js(''' | 1175 js.Expression extractFieldsFunction = js.js(''' |
| 1166 function(o) { | 1176 function(o) { |
| 1167 var constructor = o.constructor; | 1177 var constructor = o.constructor; |
| 1168 var fieldNames = constructor.$cachedClassFieldNames; | 1178 var fieldNames = constructor.$cachedClassFieldNames; |
| 1169 if (!fieldNames) { | 1179 if (!fieldNames) { |
| 1170 // Extract the fields from an empty unmodified object. | 1180 // Extract the fields from an empty unmodified object. |
| 1171 var empty = new constructor(); | 1181 var empty = new constructor(); |
| 1172 // This gives us the keys that the constructor sets. | 1182 // This gives us the keys that the constructor sets. |
| 1173 fieldNames = constructor.$cachedClassFieldNames = Object.keys(empty); | 1183 fieldNames = constructor.$cachedClassFieldNames = Object.keys(empty); |
| 1174 } | 1184 } |
| 1175 var result = new Array(fieldNames.length); | 1185 var result = new Array(fieldNames.length); |
| 1176 for (var i = 0; i < fieldNames.length; i++) { | 1186 for (var i = 0; i < fieldNames.length; i++) { |
| 1177 result[i] = o[fieldNames[i]]; | 1187 result[i] = o[fieldNames[i]]; |
| 1178 } | 1188 } |
| 1179 return result; | 1189 return result; |
| 1180 }'''); | 1190 }'''); |
| 1181 globals.add(new js.Property(js.string(CLASS_FIELDS_EXTRACTOR), | 1191 globals.add(new js.Property( |
| 1182 extractFieldsFunction)); | 1192 js.string(CLASS_FIELDS_EXTRACTOR), extractFieldsFunction)); |
| 1183 | 1193 |
| 1184 js.Expression createInstanceFromClassIdFunction = js.js(''' | 1194 js.Expression createInstanceFromClassIdFunction = js.js(''' |
| 1185 function(name) { | 1195 function(name) { |
| 1186 var constructor = getGlobalFromName(name); | 1196 var constructor = getGlobalFromName(name); |
| 1187 return new constructor(); | 1197 return new constructor(); |
| 1188 } | 1198 } |
| 1189 '''); | 1199 '''); |
| 1190 globals.add(new js.Property(js.string(INSTANCE_FROM_CLASS_ID), | 1200 globals.add(new js.Property(js.string(INSTANCE_FROM_CLASS_ID), |
| 1191 createInstanceFromClassIdFunction)); | 1201 createInstanceFromClassIdFunction)); |
| 1192 | 1202 |
| 1193 js.Expression initializeEmptyInstanceFunction = js.js(''' | 1203 js.Expression initializeEmptyInstanceFunction = js.js(''' |
| 1194 function(name, o, fields) { | 1204 function(name, o, fields) { |
| 1195 var constructor = o.constructor; | 1205 var constructor = o.constructor; |
| 1196 // By construction the object `o` is an empty object with the same | 1206 // By construction the object `o` is an empty object with the same |
| 1197 // keys as the one we used in the extract-fields function. | 1207 // keys as the one we used in the extract-fields function. |
| 1198 var fieldNames = Object.keys(o); | 1208 var fieldNames = Object.keys(o); |
| 1199 if (fieldNames.length != fields.length) { | 1209 if (fieldNames.length != fields.length) { |
| 1200 throw new Error("Mismatch during deserialization."); | 1210 throw new Error("Mismatch during deserialization."); |
| 1201 } | 1211 } |
| 1202 for (var i = 0; i < fields.length; i++) { | 1212 for (var i = 0; i < fields.length; i++) { |
| 1203 o[fieldNames[i]] = fields[i]; | 1213 o[fieldNames[i]] = fields[i]; |
| 1204 } | 1214 } |
| 1205 return o; | 1215 return o; |
| 1206 }'''); | 1216 }'''); |
| 1207 globals.add(new js.Property(js.string(INITIALIZE_EMPTY_INSTANCE), | 1217 globals.add(new js.Property(js.string(INITIALIZE_EMPTY_INSTANCE), |
| 1208 initializeEmptyInstanceFunction)); | 1218 initializeEmptyInstanceFunction)); |
| 1209 } | 1219 } |
| 1210 | 1220 |
| 1211 globals.add(emitMangledGlobalNames()); | 1221 globals.add(emitMangledGlobalNames()); |
| 1212 | 1222 |
| 1213 // The [MANGLED_NAMES] table must contain the mapping for const symbols. | 1223 // The [MANGLED_NAMES] table must contain the mapping for const symbols. |
| 1214 // Without const symbols, the table is only relevant for reflection and | 1224 // Without const symbols, the table is only relevant for reflection and |
| 1215 // therefore unused in this emitter. | 1225 // therefore unused in this emitter. |
| 1216 List<js.Property> mangledNamesProperties = <js.Property>[]; | 1226 List<js.Property> mangledNamesProperties = <js.Property>[]; |
| 1217 program.symbolsMap.forEach((js.Name mangledName, String unmangledName) { | 1227 program.symbolsMap.forEach((js.Name mangledName, String unmangledName) { |
| 1218 mangledNamesProperties.add( | 1228 mangledNamesProperties |
| 1219 new js.Property(mangledName, js.string(unmangledName))); | 1229 .add(new js.Property(mangledName, js.string(unmangledName))); |
| 1220 }); | 1230 }); |
| 1221 globals.add(new js.Property( | 1231 globals.add(new js.Property(js.string(MANGLED_NAMES), |
| 1222 js.string(MANGLED_NAMES), | |
| 1223 new js.ObjectInitializer(mangledNamesProperties))); | 1232 new js.ObjectInitializer(mangledNamesProperties))); |
| 1224 | 1233 |
| 1225 globals.add(emitGetTypeFromName()); | 1234 globals.add(emitGetTypeFromName()); |
| 1226 | 1235 |
| 1227 globals.addAll(emitMetadata(program)); | 1236 globals.addAll(emitMetadata(program)); |
| 1228 | 1237 |
| 1229 if (program.needsNativeSupport) { | 1238 if (program.needsNativeSupport) { |
| 1230 globals.add(new js.Property(js.string(INTERCEPTORS_BY_TAG), | 1239 globals.add(new js.Property( |
| 1231 new js.LiteralNull())); | 1240 js.string(INTERCEPTORS_BY_TAG), new js.LiteralNull())); |
| 1232 globals.add(new js.Property(js.string(LEAF_TAGS), | 1241 globals.add(new js.Property(js.string(LEAF_TAGS), new js.LiteralNull())); |
| 1233 new js.LiteralNull())); | |
| 1234 } | 1242 } |
| 1235 | 1243 |
| 1236 js.ObjectInitializer globalsObject = new js.ObjectInitializer(globals); | 1244 js.ObjectInitializer globalsObject = new js.ObjectInitializer(globals); |
| 1237 | 1245 |
| 1238 return js.js.statement('var init = #;', globalsObject); | 1246 return js.js.statement('var init = #;', globalsObject); |
| 1239 } | 1247 } |
| 1240 | 1248 |
| 1241 /// Emits data needed for native classes. | 1249 /// Emits data needed for native classes. |
| 1242 /// | 1250 /// |
| 1243 /// We don't try to reduce the size of the native data, but rather build | 1251 /// We don't try to reduce the size of the native data, but rather build |
| 1244 /// JavaScript object literals that contain all the information directly. | 1252 /// JavaScript object literals that contain all the information directly. |
| 1245 /// This means that the output size is bigger, but that the startup is faster. | 1253 /// This means that the output size is bigger, but that the startup is faster. |
| 1246 /// | 1254 /// |
| 1247 /// This function is the static equivalent of | 1255 /// This function is the static equivalent of |
| 1248 /// [NativeGenerator.buildNativeInfoHandler]. | 1256 /// [NativeGenerator.buildNativeInfoHandler]. |
| 1249 js.Statement emitNativeSupport(Fragment fragment) { | 1257 js.Statement emitNativeSupport(Fragment fragment) { |
| 1250 List<js.Statement> statements = <js.Statement>[]; | 1258 List<js.Statement> statements = <js.Statement>[]; |
| 1251 | 1259 |
| 1252 // The isolate-affinity tag must only be initialized once per program. | 1260 // The isolate-affinity tag must only be initialized once per program. |
| 1253 if (fragment.isMainFragment && | 1261 if (fragment.isMainFragment && |
| 1254 NativeGenerator.needsIsolateAffinityTagInitialization(backend)) { | 1262 NativeGenerator.needsIsolateAffinityTagInitialization(backend)) { |
| 1255 statements.add(NativeGenerator.generateIsolateAffinityTagInitialization( | 1263 statements.add(NativeGenerator.generateIsolateAffinityTagInitialization( |
| 1256 backend, | 1264 backend, |
| 1257 generateEmbeddedGlobalAccess, | 1265 generateEmbeddedGlobalAccess, |
| 1258 js.js(""" | 1266 js.js( |
| 1267 """ |
| 1259 // On V8, the 'intern' function converts a string to a symbol, which | 1268 // On V8, the 'intern' function converts a string to a symbol, which |
| 1260 // makes property access much faster. | 1269 // makes property access much faster. |
| 1261 function (s) { | 1270 function (s) { |
| 1262 var o = {}; | 1271 var o = {}; |
| 1263 o[s] = 1; | 1272 o[s] = 1; |
| 1264 return Object.keys(convertToFastObject(o))[0]; | 1273 return Object.keys(convertToFastObject(o))[0]; |
| 1265 }""", []))); | 1274 }""", |
| 1275 []))); |
| 1266 } | 1276 } |
| 1267 | 1277 |
| 1268 Map<String, js.Expression> interceptorsByTag = <String, js.Expression>{}; | 1278 Map<String, js.Expression> interceptorsByTag = <String, js.Expression>{}; |
| 1269 Map<String, js.Expression> leafTags = <String, js.Expression>{}; | 1279 Map<String, js.Expression> leafTags = <String, js.Expression>{}; |
| 1270 js.Statement subclassAssignment = new js.EmptyStatement(); | 1280 js.Statement subclassAssignment = new js.EmptyStatement(); |
| 1271 | 1281 |
| 1272 for (Library library in fragment.libraries) { | 1282 for (Library library in fragment.libraries) { |
| 1273 for (Class cls in library.classes) { | 1283 for (Class cls in library.classes) { |
| 1274 if (cls.nativeLeafTags != null) { | 1284 if (cls.nativeLeafTags != null) { |
| 1275 for (String tag in cls.nativeLeafTags) { | 1285 for (String tag in cls.nativeLeafTags) { |
| 1276 interceptorsByTag[tag] = classReference(cls); | 1286 interceptorsByTag[tag] = classReference(cls); |
| 1277 leafTags[tag] = new js.LiteralBool(true); | 1287 leafTags[tag] = new js.LiteralBool(true); |
| 1278 } | 1288 } |
| 1279 } | 1289 } |
| 1280 if (cls.nativeNonLeafTags != null) { | 1290 if (cls.nativeNonLeafTags != null) { |
| 1281 for (String tag in cls.nativeNonLeafTags) { | 1291 for (String tag in cls.nativeNonLeafTags) { |
| 1282 interceptorsByTag[tag] = classReference(cls); | 1292 interceptorsByTag[tag] = classReference(cls); |
| 1283 leafTags[tag] = new js.LiteralBool(false); | 1293 leafTags[tag] = new js.LiteralBool(false); |
| 1284 } | 1294 } |
| 1285 if (cls.nativeExtensions != null) { | 1295 if (cls.nativeExtensions != null) { |
| 1286 List<Class> subclasses = cls.nativeExtensions; | 1296 List<Class> subclasses = cls.nativeExtensions; |
| 1287 js.Expression value = js.string(cls.nativeNonLeafTags[0]); | 1297 js.Expression value = js.string(cls.nativeNonLeafTags[0]); |
| 1288 for (Class subclass in subclasses) { | 1298 for (Class subclass in subclasses) { |
| 1289 value = js.js('#.# = #', | 1299 value = js.js('#.# = #', [ |
| 1290 [classReference(subclass), | 1300 classReference(subclass), |
| 1291 NATIVE_SUPERCLASS_TAG_NAME, | 1301 NATIVE_SUPERCLASS_TAG_NAME, |
| 1292 js.string(cls.nativeNonLeafTags[0])]); | 1302 js.string(cls.nativeNonLeafTags[0]) |
| 1303 ]); |
| 1293 } | 1304 } |
| 1294 subclassAssignment = new js.ExpressionStatement(value); | 1305 subclassAssignment = new js.ExpressionStatement(value); |
| 1295 } | 1306 } |
| 1296 } | 1307 } |
| 1297 } | 1308 } |
| 1298 } | 1309 } |
| 1299 statements.add(js.js.statement("setOrUpdateInterceptorsByTag(#);", | 1310 statements.add(js.js.statement("setOrUpdateInterceptorsByTag(#);", |
| 1300 js.objectLiteral(interceptorsByTag))); | 1311 js.objectLiteral(interceptorsByTag))); |
| 1301 statements.add(js.js.statement("setOrUpdateLeafTags(#);", | 1312 statements.add( |
| 1302 js.objectLiteral(leafTags))); | 1313 js.js.statement("setOrUpdateLeafTags(#);", js.objectLiteral(leafTags))); |
| 1303 statements.add(subclassAssignment); | 1314 statements.add(subclassAssignment); |
| 1304 | 1315 |
| 1305 return new js.Block(statements); | 1316 return new js.Block(statements); |
| 1306 } | 1317 } |
| 1307 } | 1318 } |
| OLD | NEW |