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; |
| 685 |
| 686 /** |
| 687 * Set of classes whose instances are intercepted. Implemented as a |
| 688 * [LinkedHashMap] to preserve the insertion order. |
| 689 * TODO(ngeoffray): Use a BitSet instead. |
| 690 */ |
| 691 final Map<ClassElement, ClassElement> interceptedClasses; |
683 | 692 |
684 List<CompilerTask> get tasks { | 693 List<CompilerTask> get tasks { |
685 return <CompilerTask>[builder, optimizer, generator, emitter]; | 694 return <CompilerTask>[builder, optimizer, generator, emitter]; |
686 } | 695 } |
687 | 696 |
688 final RuntimeTypeInformation rti; | 697 final RuntimeTypeInformation rti; |
689 | 698 |
690 JavaScriptBackend(Compiler compiler, bool generateSourceMap, bool disableEval) | 699 JavaScriptBackend(Compiler compiler, bool generateSourceMap, bool disableEval) |
691 : namer = determineNamer(compiler), | 700 : namer = determineNamer(compiler), |
692 returnInfo = new Map<Element, ReturnInfo>(), | 701 returnInfo = new Map<Element, ReturnInfo>(), |
693 invalidateAfterCodegen = new List<Element>(), | 702 invalidateAfterCodegen = new List<Element>(), |
694 interceptors = new Interceptors(compiler), | 703 interceptors = new Interceptors(compiler), |
695 usedInterceptors = new Set<Selector>(), | 704 usedInterceptors = new Set<Selector>(), |
696 interceptedElements = new Map<SourceString, Set<Element>>(), | 705 interceptedElements = new Map<SourceString, Set<Element>>(), |
697 rti = new RuntimeTypeInformation(compiler), | 706 rti = new RuntimeTypeInformation(compiler), |
| 707 specializedGetInterceptors = |
| 708 new Map<String, Collection<ClassElement>>(), |
| 709 interceptedClasses = new LinkedHashMap<ClassElement, ClassElement>(), |
698 super(compiler, JAVA_SCRIPT_CONSTANT_SYSTEM) { | 710 super(compiler, JAVA_SCRIPT_CONSTANT_SYSTEM) { |
699 emitter = disableEval | 711 emitter = disableEval |
700 ? new CodeEmitterNoEvalTask(compiler, namer, generateSourceMap) | 712 ? new CodeEmitterNoEvalTask(compiler, namer, generateSourceMap) |
701 : new CodeEmitterTask(compiler, namer, generateSourceMap); | 713 : new CodeEmitterTask(compiler, namer, generateSourceMap); |
702 builder = new SsaBuilderTask(this); | 714 builder = new SsaBuilderTask(this); |
703 optimizer = new SsaOptimizerTask(this); | 715 optimizer = new SsaOptimizerTask(this); |
704 generator = new SsaCodeGeneratorTask(this); | 716 generator = new SsaCodeGeneratorTask(this); |
705 argumentTypes = new ArgumentTypesRegistry(this); | 717 argumentTypes = new ArgumentTypesRegistry(this); |
706 fieldTypes = new FieldTypesRegistry(this); | 718 fieldTypes = new FieldTypesRegistry(this); |
707 } | 719 } |
708 | 720 |
709 static Namer determineNamer(Compiler compiler) { | 721 static Namer determineNamer(Compiler compiler) { |
710 return compiler.enableMinification ? | 722 return compiler.enableMinification ? |
711 new MinifyNamer(compiler) : | 723 new MinifyNamer(compiler) : |
712 new Namer(compiler); | 724 new Namer(compiler); |
713 } | 725 } |
714 | 726 |
715 bool isInterceptorClass(Element element) { | 727 bool isInterceptorClass(Element element) { |
716 if (element == null) return false; | 728 if (element == null) return false; |
717 return element == jsStringClass | 729 return interceptedClasses.containsKey(element); |
718 || element == jsArrayClass | |
719 || element == jsIntClass | |
720 || element == jsDoubleClass | |
721 || element == jsNullClass | |
722 || element == jsFunctionClass | |
723 || element == jsBoolClass | |
724 || element == jsNumberClass; | |
725 } | 730 } |
726 | 731 |
727 void addInterceptedSelector(Selector selector) { | 732 void addInterceptedSelector(Selector selector) { |
728 usedInterceptors.add(selector); | 733 usedInterceptors.add(selector); |
729 } | 734 } |
730 | 735 |
731 /** | 736 /** |
732 * Returns a set of interceptor classes that contain a member whose | 737 * Returns a set of interceptor classes that contain a member whose |
733 * signature matches the given [selector]. Returns [:null:] if there | 738 * signature matches the given [selector]. Returns [:null:] if there |
734 * is no class. | 739 * is no class. |
735 */ | 740 */ |
736 Set<ClassElement> getInterceptedClassesOn(Selector selector) { | 741 Set<ClassElement> getInterceptedClassesOn(Selector selector) { |
737 Set<Element> intercepted = interceptedElements[selector.name]; | 742 Set<Element> intercepted = interceptedElements[selector.name]; |
738 if (intercepted == null) return null; | 743 if (intercepted == null) return null; |
739 Set<ClassElement> result = new Set<ClassElement>(); | 744 Set<ClassElement> result = new Set<ClassElement>(); |
740 for (Element element in intercepted) { | 745 for (Element element in intercepted) { |
741 if (selector.applies(element, compiler)) { | 746 if (selector.applies(element, compiler)) { |
742 result.add(element.getEnclosingClass()); | 747 result.add(element.getEnclosingClass()); |
743 } | 748 } |
744 } | 749 } |
745 if (result.isEmpty) return null; | 750 if (result.isEmpty) return null; |
746 return result; | 751 return result; |
747 } | 752 } |
748 | 753 |
| 754 List<ClassElement> getListOfInterceptedClasses() { |
| 755 return <ClassElement>[jsStringClass, jsArrayClass, jsIntClass, |
| 756 jsDoubleClass, jsNumberClass, jsNullClass, |
| 757 jsFunctionClass, jsBoolClass]; |
| 758 } |
| 759 |
749 void initializeInterceptorElements() { | 760 void initializeInterceptorElements() { |
750 objectInterceptorClass = | 761 objectInterceptorClass = |
751 compiler.findInterceptor(const SourceString('ObjectInterceptor')); | 762 compiler.findInterceptor(const SourceString('ObjectInterceptor')); |
752 getInterceptorMethod = | 763 getInterceptorMethod = |
753 compiler.findInterceptor(const SourceString('getInterceptor')); | 764 compiler.findInterceptor(const SourceString('getInterceptor')); |
754 jsStringClass = | 765 List<ClassElement> classes = [ |
755 compiler.findInterceptor(const SourceString('JSString')); | 766 jsStringClass = compiler.findInterceptor(const SourceString('JSString')), |
756 jsArrayClass = | 767 jsArrayClass = compiler.findInterceptor(const SourceString('JSArray')), |
757 compiler.findInterceptor(const SourceString('JSArray')); | 768 jsNumberClass = compiler.findInterceptor(const SourceString('JSNumber')), |
758 jsNumberClass = | 769 jsIntClass = compiler.findInterceptor(const SourceString('JSInt')), |
759 compiler.findInterceptor(const SourceString('JSNumber')); | 770 jsDoubleClass = compiler.findInterceptor(const SourceString('JSDouble')), |
760 jsIntClass = | 771 jsNullClass = compiler.findInterceptor(const SourceString('JSNull')), |
761 compiler.findInterceptor(const SourceString('JSInt')); | 772 jsFunctionClass = |
762 jsDoubleClass = | 773 compiler.findInterceptor(const SourceString('JSFunction')), |
763 compiler.findInterceptor(const SourceString('JSDouble')); | 774 jsBoolClass = compiler.findInterceptor(const SourceString('JSBool'))]; |
764 jsNullClass = | 775 |
765 compiler.findInterceptor(const SourceString('JSNull')); | |
766 jsFunctionClass = | |
767 compiler.findInterceptor(const SourceString('JSFunction')); | |
768 jsBoolClass = | |
769 compiler.findInterceptor(const SourceString('JSBool')); | |
770 jsArrayClass.ensureResolved(compiler); | 776 jsArrayClass.ensureResolved(compiler); |
771 jsArrayLength = | 777 jsArrayLength = |
772 jsArrayClass.lookupLocalMember(const SourceString('length')); | 778 jsArrayClass.lookupLocalMember(const SourceString('length')); |
| 779 |
773 jsStringClass.ensureResolved(compiler); | 780 jsStringClass.ensureResolved(compiler); |
774 jsStringLength = | 781 jsStringLength = |
775 jsStringClass.lookupLocalMember(const SourceString('length')); | 782 jsStringClass.lookupLocalMember(const SourceString('length')); |
776 | 783 |
777 arrayInterceptor = | 784 for (ClassElement cls in classes) { |
778 compiler.findInterceptor(const SourceString('arrayInterceptor')); | 785 interceptedClasses[cls] = null; |
779 boolInterceptor = | 786 } |
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(Set<ClassElement> classes) { |
| 800 compiler.enqueuer.codegen.registerInstantiatedClass(objectInterceptorClass); |
| 801 if (classes.contains(compiler.objectClass)) { |
| 802 // We can't use a specialized [getInterceptorMethod], so we make |
| 803 // sure we emit the one with all checks. |
| 804 String name = namer.getName(getInterceptorMethod); |
| 805 specializedGetInterceptors.putIfAbsent(name, () { |
| 806 // It is important to take the order provided by this list, |
| 807 // because we want the int type check to happen before the |
| 808 // double type check: the double type check covers the int |
| 809 // type check. |
| 810 return interceptedClasses.keys; |
| 811 }); |
| 812 return namer.isolateAccess(getInterceptorMethod); |
| 813 } else { |
| 814 String name = namer.getSpecializedName(getInterceptorMethod, classes); |
| 815 specializedGetInterceptors[name] = classes; |
| 816 return '${namer.CURRENT_ISOLATE}.$name'; |
| 817 } |
| 818 } |
| 819 |
805 void registerInstantiatedClass(ClassElement cls, Enqueuer enqueuer) { | 820 void registerInstantiatedClass(ClassElement cls, Enqueuer enqueuer) { |
806 ClassElement result = null; | 821 ClassElement result = null; |
807 if (!_interceptorsAreInitialized) { | 822 if (!_interceptorsAreInitialized) { |
808 initializeInterceptorElements(); | 823 initializeInterceptorElements(); |
809 _interceptorsAreInitialized = true; | 824 _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 } | 825 } |
824 if (cls == compiler.stringClass) { | 826 if (cls == compiler.stringClass) { |
825 result = jsStringClass; | 827 result = jsStringClass; |
826 } else if (cls == compiler.listClass) { | 828 } else if (cls == compiler.listClass) { |
827 result = jsArrayClass; | 829 result = jsArrayClass; |
828 } else if (cls == compiler.intClass) { | 830 } else if (cls == compiler.intClass) { |
829 result = jsIntClass; | 831 result = jsIntClass; |
| 832 enqueuer.registerInstantiatedClass(jsNumberClass); |
830 } else if (cls == compiler.doubleClass) { | 833 } else if (cls == compiler.doubleClass) { |
831 result = jsDoubleClass; | 834 result = jsDoubleClass; |
| 835 enqueuer.registerInstantiatedClass(jsNumberClass); |
832 } else if (cls == compiler.functionClass) { | 836 } else if (cls == compiler.functionClass) { |
833 result = jsFunctionClass; | 837 result = jsFunctionClass; |
834 } else if (cls == compiler.boolClass) { | 838 } else if (cls == compiler.boolClass) { |
835 result = jsBoolClass; | 839 result = jsBoolClass; |
| 840 } else if (cls == compiler.nullClass) { |
| 841 result = jsNullClass; |
836 } | 842 } |
837 | 843 |
838 if (result == null) return; | 844 if (result == null) return; |
839 if (enqueuer.isResolutionQueue) addInterceptors(result); | 845 if (enqueuer.isResolutionQueue) addInterceptors(result); |
840 enqueuer.registerInstantiatedClass(result); | 846 enqueuer.registerInstantiatedClass(result); |
841 } | 847 } |
842 | 848 |
843 Element get cyclicThrowHelper { | 849 Element get cyclicThrowHelper { |
844 return compiler.findHelper(const SourceString("throwCyclicInit")); | 850 return compiler.findHelper(const SourceString("throwCyclicInit")); |
845 } | 851 } |
(...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1102 print("Inferred return types:"); | 1108 print("Inferred return types:"); |
1103 print("----------------------"); | 1109 print("----------------------"); |
1104 dumpReturnTypes(); | 1110 dumpReturnTypes(); |
1105 print(""); | 1111 print(""); |
1106 print("Inferred field types:"); | 1112 print("Inferred field types:"); |
1107 print("------------------------"); | 1113 print("------------------------"); |
1108 fieldTypes.dump(); | 1114 fieldTypes.dump(); |
1109 print(""); | 1115 print(""); |
1110 } | 1116 } |
1111 } | 1117 } |
OLD | NEW |