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 |