OLD | NEW |
---|---|
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 js_backend; | 5 part of js_backend; |
6 | 6 |
7 typedef void Recompile(Element element); | 7 typedef void Recompile(Element element); |
8 | 8 |
9 class ReturnInfo { | 9 class ReturnInfo { |
10 HType returnType; | 10 HType returnType; |
(...skipping 617 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
628 ClassElement jsNumberClass; | 628 ClassElement jsNumberClass; |
629 ClassElement jsIntClass; | 629 ClassElement jsIntClass; |
630 ClassElement jsDoubleClass; | 630 ClassElement jsDoubleClass; |
631 ClassElement jsFunctionClass; | 631 ClassElement jsFunctionClass; |
632 ClassElement jsNullClass; | 632 ClassElement jsNullClass; |
633 ClassElement jsBoolClass; | 633 ClassElement jsBoolClass; |
634 ClassElement objectInterceptorClass; | 634 ClassElement objectInterceptorClass; |
635 Element jsArrayLength; | 635 Element jsArrayLength; |
636 Element jsStringLength; | 636 Element jsStringLength; |
637 Element getInterceptorMethod; | 637 Element getInterceptorMethod; |
638 Element arrayInterceptor; | |
639 Element boolInterceptor; | |
640 Element doubleInterceptor; | |
641 Element functionInterceptor; | |
642 Element intInterceptor; | |
643 Element nullInterceptor; | |
644 Element numberInterceptor; | |
645 Element stringInterceptor; | |
646 bool _interceptorsAreInitialized = false; | 638 bool _interceptorsAreInitialized = false; |
647 | 639 |
648 final Namer namer; | 640 final Namer namer; |
649 | 641 |
650 /** | 642 /** |
651 * Interface used to determine if an object has the JavaScript | 643 * Interface used to determine if an object has the JavaScript |
652 * indexing behavior. The interface is only visible to specific | 644 * indexing behavior. The interface is only visible to specific |
653 * libraries. | 645 * libraries. |
654 */ | 646 */ |
655 ClassElement jsIndexingBehaviorInterface; | 647 ClassElement jsIndexingBehaviorInterface; |
(...skipping 16 matching lines...) Expand all Loading... | |
672 * emitter uses this set to generate the [:ObjectInterceptor:] class | 664 * emitter uses this set to generate the [:ObjectInterceptor:] class |
673 * whose members just forward the call to the intercepted receiver. | 665 * whose members just forward the call to the intercepted receiver. |
674 */ | 666 */ |
675 final Set<Selector> usedInterceptors; | 667 final Set<Selector> usedInterceptors; |
676 | 668 |
677 /** | 669 /** |
678 * The members of instantiated interceptor classes: maps a member | 670 * The members of instantiated interceptor classes: maps a member |
679 * name to the list of members that have that name. This map is used | 671 * name to the list of members that have that name. This map is used |
680 * by the codegen to know whether a send must be intercepted or not. | 672 * by the codegen to know whether a send must be intercepted or not. |
681 */ | 673 */ |
682 final Map<SourceString, Set<Element>> interceptedElements; | 674 final Map<SourceString, Set<Element>> interceptedElements; |
675 | |
676 /** | |
677 * A map of specialized versions of the [getInterceptorMethod]. | |
678 * Since [getInterceptorMethod] is a hot method at runtime, we're | |
679 * always specializing it based on the incoming type. The keys in | |
680 * the map are the names of these specialized versions. Note that | |
681 * the generic version that contains all possible type checks is | |
682 * also stored in this map. | |
683 */ | |
684 final Map<String, Collection<ClassElement>> specializedGetInterceptors; | |
ahe
2012/11/27 14:29:45
What is the key?
ngeoffray
2012/11/27 15:50:54
It's in the comment above: the name of the special
| |
685 | |
686 /** | |
687 * Set of classes whose instances are intercepted. | |
688 */ | |
689 final Set<ClassElement> interceptedClasses; | |
683 | 690 |
684 List<CompilerTask> get tasks { | 691 List<CompilerTask> get tasks { |
685 return <CompilerTask>[builder, optimizer, generator, emitter]; | 692 return <CompilerTask>[builder, optimizer, generator, emitter]; |
686 } | 693 } |
687 | 694 |
688 final RuntimeTypeInformation rti; | 695 final RuntimeTypeInformation rti; |
689 | 696 |
690 JavaScriptBackend(Compiler compiler, bool generateSourceMap, bool disableEval) | 697 JavaScriptBackend(Compiler compiler, bool generateSourceMap, bool disableEval) |
691 : namer = determineNamer(compiler), | 698 : namer = determineNamer(compiler), |
692 returnInfo = new Map<Element, ReturnInfo>(), | 699 returnInfo = new Map<Element, ReturnInfo>(), |
693 invalidateAfterCodegen = new List<Element>(), | 700 invalidateAfterCodegen = new List<Element>(), |
694 interceptors = new Interceptors(compiler), | 701 interceptors = new Interceptors(compiler), |
695 usedInterceptors = new Set<Selector>(), | 702 usedInterceptors = new Set<Selector>(), |
696 interceptedElements = new Map<SourceString, Set<Element>>(), | 703 interceptedElements = new Map<SourceString, Set<Element>>(), |
697 rti = new RuntimeTypeInformation(compiler), | 704 rti = new RuntimeTypeInformation(compiler), |
705 specializedGetInterceptors = | |
706 new Map<String, Collection<ClassElement>>(), | |
707 interceptedClasses = new Set<ClassElement>(), | |
698 super(compiler, JAVA_SCRIPT_CONSTANT_SYSTEM) { | 708 super(compiler, JAVA_SCRIPT_CONSTANT_SYSTEM) { |
699 emitter = disableEval | 709 emitter = disableEval |
700 ? new CodeEmitterNoEvalTask(compiler, namer, generateSourceMap) | 710 ? new CodeEmitterNoEvalTask(compiler, namer, generateSourceMap) |
701 : new CodeEmitterTask(compiler, namer, generateSourceMap); | 711 : new CodeEmitterTask(compiler, namer, generateSourceMap); |
702 builder = new SsaBuilderTask(this); | 712 builder = new SsaBuilderTask(this); |
703 optimizer = new SsaOptimizerTask(this); | 713 optimizer = new SsaOptimizerTask(this); |
704 generator = new SsaCodeGeneratorTask(this); | 714 generator = new SsaCodeGeneratorTask(this); |
705 argumentTypes = new ArgumentTypesRegistry(this); | 715 argumentTypes = new ArgumentTypesRegistry(this); |
706 fieldTypes = new FieldTypesRegistry(this); | 716 fieldTypes = new FieldTypesRegistry(this); |
707 } | 717 } |
708 | 718 |
709 static Namer determineNamer(Compiler compiler) { | 719 static Namer determineNamer(Compiler compiler) { |
710 return compiler.enableMinification ? | 720 return compiler.enableMinification ? |
711 new MinifyNamer(compiler) : | 721 new MinifyNamer(compiler) : |
712 new Namer(compiler); | 722 new Namer(compiler); |
713 } | 723 } |
714 | 724 |
715 bool isInterceptorClass(Element element) { | 725 bool isInterceptorClass(Element element) { |
716 if (element == null) return false; | 726 if (element == null) return false; |
717 return element == jsStringClass | 727 return interceptedClasses.contains(element); |
718 || element == jsArrayClass | |
719 || element == jsIntClass | |
720 || element == jsDoubleClass | |
721 || element == jsNullClass | |
722 || element == jsFunctionClass | |
723 || element == jsBoolClass | |
724 || element == jsNumberClass; | |
725 } | 728 } |
726 | 729 |
727 void addInterceptedSelector(Selector selector) { | 730 void addInterceptedSelector(Selector selector) { |
728 usedInterceptors.add(selector); | 731 usedInterceptors.add(selector); |
729 } | 732 } |
730 | 733 |
731 /** | 734 /** |
732 * Returns a set of interceptor classes that contain a member whose | 735 * Returns a set of interceptor classes that contain a member whose |
733 * signature matches the given [selector]. Returns [:null:] if there | 736 * signature matches the given [selector]. Returns [:null:] if there |
734 * is no class. | 737 * is no class. |
735 */ | 738 */ |
736 Set<ClassElement> getInterceptedClassesOn(Selector selector) { | 739 Set<ClassElement> getInterceptedClassesOn(Selector selector) { |
737 Set<Element> intercepted = interceptedElements[selector.name]; | 740 Set<Element> intercepted = interceptedElements[selector.name]; |
738 if (intercepted == null) return null; | 741 if (intercepted == null) return null; |
739 Set<ClassElement> result = new Set<ClassElement>(); | 742 Set<ClassElement> result = new Set<ClassElement>(); |
740 for (Element element in intercepted) { | 743 for (Element element in intercepted) { |
741 if (selector.applies(element, compiler)) { | 744 if (selector.applies(element, compiler)) { |
742 result.add(element.getEnclosingClass()); | 745 result.add(element.getEnclosingClass()); |
743 } | 746 } |
744 } | 747 } |
745 if (result.isEmpty) return null; | 748 if (result.isEmpty) return null; |
746 return result; | 749 return result; |
747 } | 750 } |
748 | 751 |
752 List<ClassElement> getListOfInterceptedClasses() { | |
753 return <ClassElement>[jsStringClass, jsArrayClass, jsIntClass, | |
ahe
2012/11/27 14:29:45
I suggest you create this list in initializeInterc
ngeoffray
2012/11/27 15:50:54
Done.
| |
754 jsDoubleClass, jsNumberClass, jsNullClass, | |
755 jsFunctionClass, jsBoolClass]; | |
756 } | |
757 | |
749 void initializeInterceptorElements() { | 758 void initializeInterceptorElements() { |
750 objectInterceptorClass = | 759 objectInterceptorClass = |
751 compiler.findInterceptor(const SourceString('ObjectInterceptor')); | 760 compiler.findInterceptor(const SourceString('ObjectInterceptor')); |
752 getInterceptorMethod = | 761 getInterceptorMethod = |
753 compiler.findInterceptor(const SourceString('getInterceptor')); | 762 compiler.findInterceptor(const SourceString('getInterceptor')); |
754 jsStringClass = | 763 jsStringClass = |
755 compiler.findInterceptor(const SourceString('JSString')); | 764 compiler.findInterceptor(const SourceString('JSString')); |
756 jsArrayClass = | 765 jsArrayClass = |
757 compiler.findInterceptor(const SourceString('JSArray')); | 766 compiler.findInterceptor(const SourceString('JSArray')); |
758 jsNumberClass = | 767 jsNumberClass = |
759 compiler.findInterceptor(const SourceString('JSNumber')); | 768 compiler.findInterceptor(const SourceString('JSNumber')); |
760 jsIntClass = | 769 jsIntClass = |
761 compiler.findInterceptor(const SourceString('JSInt')); | 770 compiler.findInterceptor(const SourceString('JSInt')); |
762 jsDoubleClass = | 771 jsDoubleClass = |
763 compiler.findInterceptor(const SourceString('JSDouble')); | 772 compiler.findInterceptor(const SourceString('JSDouble')); |
764 jsNullClass = | 773 jsNullClass = |
765 compiler.findInterceptor(const SourceString('JSNull')); | 774 compiler.findInterceptor(const SourceString('JSNull')); |
766 jsFunctionClass = | 775 jsFunctionClass = |
767 compiler.findInterceptor(const SourceString('JSFunction')); | 776 compiler.findInterceptor(const SourceString('JSFunction')); |
768 jsBoolClass = | 777 jsBoolClass = |
769 compiler.findInterceptor(const SourceString('JSBool')); | 778 compiler.findInterceptor(const SourceString('JSBool')); |
770 jsArrayClass.ensureResolved(compiler); | 779 jsArrayClass.ensureResolved(compiler); |
771 jsArrayLength = | 780 jsArrayLength = |
772 jsArrayClass.lookupLocalMember(const SourceString('length')); | 781 jsArrayClass.lookupLocalMember(const SourceString('length')); |
773 jsStringClass.ensureResolved(compiler); | 782 jsStringClass.ensureResolved(compiler); |
774 jsStringLength = | 783 jsStringLength = |
775 jsStringClass.lookupLocalMember(const SourceString('length')); | 784 jsStringClass.lookupLocalMember(const SourceString('length')); |
776 | 785 |
777 arrayInterceptor = | 786 interceptedClasses.addAll(getListOfInterceptedClasses()); |
778 compiler.findInterceptor(const SourceString('arrayInterceptor')); | |
779 boolInterceptor = | |
780 compiler.findInterceptor(const SourceString('boolInterceptor')); | |
781 doubleInterceptor = | |
782 compiler.findInterceptor(const SourceString('doubleInterceptor')); | |
783 functionInterceptor = | |
784 compiler.findInterceptor(const SourceString('functionInterceptor')); | |
785 intInterceptor = | |
786 compiler.findInterceptor(const SourceString('intInterceptor')); | |
787 nullInterceptor = | |
788 compiler.findInterceptor(const SourceString('nullInterceptor')); | |
789 stringInterceptor = | |
790 compiler.findInterceptor(const SourceString('stringInterceptor')); | |
791 numberInterceptor = | |
792 compiler.findInterceptor(const SourceString('numberInterceptor')); | |
793 } | 787 } |
794 | 788 |
795 void addInterceptors(ClassElement cls) { | 789 void addInterceptors(ClassElement cls) { |
796 cls.ensureResolved(compiler); | 790 cls.ensureResolved(compiler); |
797 cls.forEachMember((ClassElement classElement, Element member) { | 791 cls.forEachMember((ClassElement classElement, Element member) { |
798 Set<Element> set = interceptedElements.putIfAbsent( | 792 Set<Element> set = interceptedElements.putIfAbsent( |
799 member.name, () => new Set<Element>()); | 793 member.name, () => new Set<Element>()); |
800 set.add(member); | 794 set.add(member); |
801 }, | 795 }, |
802 includeSuperMembers: true); | 796 includeSuperMembers: true); |
803 } | 797 } |
804 | 798 |
799 String registerSpecializedGetInterceptor( | |
800 Set<ClassElement> interceptedClasses) { | |
801 compiler.enqueuer.codegen.registerInstantiatedClass(objectInterceptorClass); | |
802 if (interceptedClasses.contains(compiler.objectClass)) { | |
803 // We can't use a specialized [getInterceptorMethod], so we make | |
804 // sure we emit the one with all checks. | |
805 String name = namer.getName(getInterceptorMethod); | |
806 specializedGetInterceptors.putIfAbsent(name, () { | |
ahe
2012/11/27 14:29:45
I don't understand why you do this. Why shouldn't
ngeoffray
2012/11/27 15:50:54
Because I did not want to call getListOfIntercepte
| |
807 // It is important to take the order provided by this list, | |
808 // because we want the int type check to happen before the | |
809 // double type check: the double type check covers the int | |
810 // type check. | |
811 return getListOfInterceptedClasses(); | |
812 }); | |
813 return namer.isolateAccess(getInterceptorMethod); | |
814 } else { | |
815 String name = namer.getSpecializedName(getInterceptorMethod, | |
816 interceptedClasses); | |
817 specializedGetInterceptors[name] = interceptedClasses; | |
818 return '${namer.CURRENT_ISOLATE}.$name'; | |
819 } | |
820 } | |
821 | |
805 void registerInstantiatedClass(ClassElement cls, Enqueuer enqueuer) { | 822 void registerInstantiatedClass(ClassElement cls, Enqueuer enqueuer) { |
806 ClassElement result = null; | 823 ClassElement result = null; |
807 if (!_interceptorsAreInitialized) { | 824 if (!_interceptorsAreInitialized) { |
808 initializeInterceptorElements(); | 825 initializeInterceptorElements(); |
809 _interceptorsAreInitialized = true; | 826 _interceptorsAreInitialized = true; |
810 // The null interceptor and the function interceptor are | |
811 // currently always instantiated if a new class is instantiated. | |
812 // TODO(ngeoffray): do this elsewhere for the function | |
813 // interceptor? | |
814 if (jsNullClass != null) { | |
815 addInterceptors(jsNullClass); | |
816 enqueuer.registerInstantiatedClass(jsNullClass); | |
817 } | |
818 if (jsFunctionClass != null) { | |
819 addInterceptors(jsFunctionClass); | |
820 enqueuer.registerInstantiatedClass(jsFunctionClass); | |
821 } | |
822 enqueuer.addToWorkList(getInterceptorMethod); | |
823 } | 827 } |
824 if (cls == compiler.stringClass) { | 828 if (cls == compiler.stringClass) { |
825 result = jsStringClass; | 829 result = jsStringClass; |
826 } else if (cls == compiler.listClass) { | 830 } else if (cls == compiler.listClass) { |
827 result = jsArrayClass; | 831 result = jsArrayClass; |
828 } else if (cls == compiler.intClass) { | 832 } else if (cls == compiler.intClass) { |
829 result = jsIntClass; | 833 result = jsIntClass; |
834 enqueuer.registerInstantiatedClass(jsNumberClass); | |
830 } else if (cls == compiler.doubleClass) { | 835 } else if (cls == compiler.doubleClass) { |
831 result = jsDoubleClass; | 836 result = jsDoubleClass; |
837 enqueuer.registerInstantiatedClass(jsNumberClass); | |
832 } else if (cls == compiler.functionClass) { | 838 } else if (cls == compiler.functionClass) { |
833 result = jsFunctionClass; | 839 result = jsFunctionClass; |
834 } else if (cls == compiler.boolClass) { | 840 } else if (cls == compiler.boolClass) { |
835 result = jsBoolClass; | 841 result = jsBoolClass; |
842 } else if (cls == compiler.nullClass) { | |
843 result = jsNullClass; | |
836 } | 844 } |
837 | 845 |
838 if (result == null) return; | 846 if (result == null) return; |
839 if (enqueuer.isResolutionQueue) addInterceptors(result); | 847 if (enqueuer.isResolutionQueue) addInterceptors(result); |
840 enqueuer.registerInstantiatedClass(result); | 848 enqueuer.registerInstantiatedClass(result); |
841 } | 849 } |
842 | 850 |
843 Element get cyclicThrowHelper { | 851 Element get cyclicThrowHelper { |
844 return compiler.findHelper(const SourceString("throwCyclicInit")); | 852 return compiler.findHelper(const SourceString("throwCyclicInit")); |
845 } | 853 } |
(...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1102 print("Inferred return types:"); | 1110 print("Inferred return types:"); |
1103 print("----------------------"); | 1111 print("----------------------"); |
1104 dumpReturnTypes(); | 1112 dumpReturnTypes(); |
1105 print(""); | 1113 print(""); |
1106 print("Inferred field types:"); | 1114 print("Inferred field types:"); |
1107 print("------------------------"); | 1115 print("------------------------"); |
1108 fieldTypes.dump(); | 1116 fieldTypes.dump(); |
1109 print(""); | 1117 print(""); |
1110 } | 1118 } |
1111 } | 1119 } |
OLD | NEW |