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 624 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
635 new Map<Element, jsAst.Expression>(); | 635 new Map<Element, jsAst.Expression>(); |
636 | 636 |
637 ClassElement jsStringClass; | 637 ClassElement jsStringClass; |
638 ClassElement jsArrayClass; | 638 ClassElement jsArrayClass; |
639 ClassElement jsNumberClass; | 639 ClassElement jsNumberClass; |
640 ClassElement jsIntClass; | 640 ClassElement jsIntClass; |
641 ClassElement jsDoubleClass; | 641 ClassElement jsDoubleClass; |
642 ClassElement jsFunctionClass; | 642 ClassElement jsFunctionClass; |
643 ClassElement jsNullClass; | 643 ClassElement jsNullClass; |
644 ClassElement jsBoolClass; | 644 ClassElement jsBoolClass; |
645 ClassElement objectInterceptorClass; | |
646 Element jsArrayLength; | 645 Element jsArrayLength; |
647 Element jsStringLength; | 646 Element jsStringLength; |
648 Element jsArrayRemoveLast; | 647 Element jsArrayRemoveLast; |
649 Element jsArrayAdd; | 648 Element jsArrayAdd; |
650 Element jsStringSplit; | 649 Element jsStringSplit; |
651 Element jsStringConcat; | 650 Element jsStringConcat; |
652 Element jsStringToString; | 651 Element jsStringToString; |
653 Element getInterceptorMethod; | 652 Element getInterceptorMethod; |
| 653 Element interceptedNames; |
654 Element fixedLengthListConstructor; | 654 Element fixedLengthListConstructor; |
655 bool seenAnyClass = false; | 655 bool seenAnyClass = false; |
656 | 656 |
657 final Namer namer; | 657 final Namer namer; |
658 | 658 |
659 /** | 659 /** |
660 * Interface used to determine if an object has the JavaScript | 660 * Interface used to determine if an object has the JavaScript |
661 * indexing behavior. The interface is only visible to specific | 661 * indexing behavior. The interface is only visible to specific |
662 * libraries. | 662 * libraries. |
663 */ | 663 */ |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
698 * A map of specialized versions of the [getInterceptorMethod]. | 698 * A map of specialized versions of the [getInterceptorMethod]. |
699 * Since [getInterceptorMethod] is a hot method at runtime, we're | 699 * Since [getInterceptorMethod] is a hot method at runtime, we're |
700 * always specializing it based on the incoming type. The keys in | 700 * always specializing it based on the incoming type. The keys in |
701 * the map are the names of these specialized versions. Note that | 701 * the map are the names of these specialized versions. Note that |
702 * the generic version that contains all possible type checks is | 702 * the generic version that contains all possible type checks is |
703 * also stored in this map. | 703 * also stored in this map. |
704 */ | 704 */ |
705 final Map<String, Collection<ClassElement>> specializedGetInterceptors; | 705 final Map<String, Collection<ClassElement>> specializedGetInterceptors; |
706 | 706 |
707 /** | 707 /** |
708 * Set of classes whose instances are intercepted. Implemented as a | 708 * Set of classes whose methods are intercepted. |
709 * [LinkedHashMap] to preserve the insertion order. | |
710 * TODO(ngeoffray): No need to preserve order anymore. | |
711 */ | 709 */ |
712 final Map<ClassElement, ClassElement> interceptedClasses; | 710 final Set<ClassElement> interceptedClasses; |
713 | 711 |
714 /** | 712 /** |
715 * Set of selectors that are used from within loops. Used by the | 713 * Set of selectors that are used from within loops. Used by the |
716 * builder to allow speculative optimizations for functions without | 714 * builder to allow speculative optimizations for functions without |
717 * loops themselves. | 715 * loops themselves. |
718 */ | 716 */ |
719 final Map<SourceString, Set<Selector>> selectorsCalledInLoop = | 717 final Map<SourceString, Set<Selector>> selectorsCalledInLoop = |
720 new Map<SourceString, Set<Selector>>(); | 718 new Map<SourceString, Set<Selector>>(); |
721 | 719 |
722 List<CompilerTask> get tasks { | 720 List<CompilerTask> get tasks { |
723 return <CompilerTask>[builder, optimizer, generator, emitter]; | 721 return <CompilerTask>[builder, optimizer, generator, emitter]; |
724 } | 722 } |
725 | 723 |
726 final RuntimeTypeInformation rti; | 724 final RuntimeTypeInformation rti; |
727 | 725 |
728 JavaScriptBackend(Compiler compiler, bool generateSourceMap, bool disableEval) | 726 JavaScriptBackend(Compiler compiler, bool generateSourceMap, bool disableEval) |
729 : namer = determineNamer(compiler), | 727 : namer = determineNamer(compiler), |
730 returnInfo = new Map<Element, ReturnInfo>(), | 728 returnInfo = new Map<Element, ReturnInfo>(), |
731 invalidateAfterCodegen = new List<Element>(), | 729 invalidateAfterCodegen = new List<Element>(), |
732 usedInterceptors = new Set<Selector>(), | 730 usedInterceptors = new Set<Selector>(), |
733 oneShotInterceptors = new Map<String, Selector>(), | 731 oneShotInterceptors = new Map<String, Selector>(), |
734 interceptedElements = new Map<SourceString, Set<Element>>(), | 732 interceptedElements = new Map<SourceString, Set<Element>>(), |
735 rti = new RuntimeTypeInformation(compiler), | 733 rti = new RuntimeTypeInformation(compiler), |
736 specializedGetInterceptors = | 734 specializedGetInterceptors = |
737 new Map<String, Collection<ClassElement>>(), | 735 new Map<String, Collection<ClassElement>>(), |
738 interceptedClasses = new LinkedHashMap<ClassElement, ClassElement>(), | 736 interceptedClasses = new Set<ClassElement>(), |
739 super(compiler, JAVA_SCRIPT_CONSTANT_SYSTEM) { | 737 super(compiler, JAVA_SCRIPT_CONSTANT_SYSTEM) { |
740 emitter = disableEval | 738 emitter = disableEval |
741 ? new CodeEmitterNoEvalTask(compiler, namer, generateSourceMap) | 739 ? new CodeEmitterNoEvalTask(compiler, namer, generateSourceMap) |
742 : new CodeEmitterTask(compiler, namer, generateSourceMap); | 740 : new CodeEmitterTask(compiler, namer, generateSourceMap); |
743 builder = new SsaBuilderTask(this); | 741 builder = new SsaBuilderTask(this); |
744 optimizer = new SsaOptimizerTask(this); | 742 optimizer = new SsaOptimizerTask(this); |
745 generator = new SsaCodeGeneratorTask(this); | 743 generator = new SsaCodeGeneratorTask(this); |
746 argumentTypes = new ArgumentTypesRegistry(this); | 744 argumentTypes = new ArgumentTypesRegistry(this); |
747 fieldTypes = new FieldTypesRegistry(this); | 745 fieldTypes = new FieldTypesRegistry(this); |
748 } | 746 } |
749 | 747 |
750 static Namer determineNamer(Compiler compiler) { | 748 static Namer determineNamer(Compiler compiler) { |
751 return compiler.enableMinification ? | 749 return compiler.enableMinification ? |
752 new MinifyNamer(compiler) : | 750 new MinifyNamer(compiler) : |
753 new Namer(compiler); | 751 new Namer(compiler); |
754 } | 752 } |
755 | 753 |
756 bool isInterceptorClass(Element element) { | 754 bool isInterceptorClass(Element element) { |
757 if (element == null) return false; | 755 if (element == null) return false; |
758 return interceptedClasses.containsKey(element); | 756 return interceptedClasses.contains(element); |
759 } | 757 } |
760 | 758 |
761 void addInterceptedSelector(Selector selector) { | 759 void addInterceptedSelector(Selector selector) { |
762 usedInterceptors.add(selector); | 760 usedInterceptors.add(selector); |
763 } | 761 } |
764 | 762 |
765 String registerOneShotInterceptor(Selector selector) { | 763 String registerOneShotInterceptor(Selector selector) { |
766 Set<ClassElement> classes = getInterceptedClassesOn(selector); | 764 Set<ClassElement> classes = getInterceptedClassesOn(selector.name); |
767 String name = namer.getOneShotInterceptorName(selector, classes); | 765 String name = namer.getOneShotInterceptorName(selector, classes); |
768 if (!oneShotInterceptors.containsKey(name)) { | 766 if (!oneShotInterceptors.containsKey(name)) { |
769 registerSpecializedGetInterceptor(classes); | 767 registerSpecializedGetInterceptor(classes); |
770 oneShotInterceptors[name] = selector; | 768 oneShotInterceptors[name] = selector; |
771 } | 769 } |
772 return name; | 770 return name; |
773 } | 771 } |
774 | 772 |
775 final Map<Selector, Set<ClassElement>> interceptedClassesCache = | 773 bool isInterceptedMethod(Element element) { |
776 new Map<Selector, Set<ClassElement>>(); | 774 return element.isInstanceMember() |
777 final Map<Selector, Set<ClassElement>> interceptedClassesNonNullCache = | 775 && interceptedElements[element.name] != null; |
778 new Map<Selector, Set<ClassElement>>(); | 776 } |
| 777 |
| 778 bool isInterceptedName(SourceString name) { |
| 779 return interceptedElements[name] != null; |
| 780 } |
| 781 |
| 782 final Map<SourceString, Set<ClassElement>> interceptedClassesCache = |
| 783 new Map<SourceString, Set<ClassElement>>(); |
779 | 784 |
780 /** | 785 /** |
781 * Returns a set of interceptor classes that contain a member whose | 786 * Returns a set of interceptor classes that contain a member named |
782 * signature matches the given [selector]. Returns [:null:] if there | 787 * [name]. Returns [:null:] if there is no class. |
783 * is no class. | |
784 */ | 788 */ |
785 Set<ClassElement> getInterceptedClassesOn(Selector selector, | 789 Set<ClassElement> getInterceptedClassesOn(SourceString name) { |
786 {bool canBeNull: true}) { | 790 Set<Element> intercepted = interceptedElements[name]; |
787 Set<Element> intercepted = interceptedElements[selector.name]; | |
788 if (intercepted == null) return null; | 791 if (intercepted == null) return null; |
789 // Pick the right cache and query it. | 792 Set<Element> result = interceptedClassesCache.putIfAbsent(name, () { |
790 Map<Selector, Set<ClassElement>> cache = canBeNull | 793 // Populate the cache by running through all the elements and |
791 ? interceptedClassesCache | 794 // determine if the given selector applies to them. |
792 : interceptedClassesNonNullCache; | 795 Set<ClassElement> result = new Set<ClassElement>(); |
793 if (cache.containsKey(selector)) return cache[selector]; | 796 for (Element element in intercepted) { |
794 // Populate the cache by running through all the elements and | 797 result.add(element.getEnclosingClass()); |
795 // determine if the given selector applies to them. | 798 } |
796 Set<ClassElement> result = new Set<ClassElement>(); | 799 return result; |
797 for (Element element in intercepted) { | 800 }); |
798 ClassElement enclosing = element.getEnclosingClass(); | |
799 // We have to treat null as a bottom type, so we use the untyped | |
800 // applies method for those elements that are implemented on the | |
801 // null class. | |
802 bool applies = (enclosing == jsNullClass) | |
803 ? canBeNull && selector.appliesUntyped(element, compiler) | |
804 : selector.applies(element, compiler); | |
805 if (applies) result.add(enclosing); | |
806 } | |
807 if (result.isEmpty) result = null; | |
808 cache[selector] = result; | |
809 assert(cache.containsKey(selector)); | |
810 return result; | 801 return result; |
811 } | 802 } |
812 | 803 |
813 void initializeHelperClasses() { | 804 void initializeHelperClasses() { |
814 objectInterceptorClass = | |
815 compiler.findInterceptor(const SourceString('ObjectInterceptor')); | |
816 getInterceptorMethod = | 805 getInterceptorMethod = |
817 compiler.findInterceptor(const SourceString('getInterceptor')); | 806 compiler.findInterceptor(const SourceString('getInterceptor')); |
| 807 interceptedNames = |
| 808 compiler.findInterceptor(const SourceString('interceptedNames')); |
818 List<ClassElement> classes = [ | 809 List<ClassElement> classes = [ |
| 810 compiler.objectClass, |
819 jsStringClass = compiler.findInterceptor(const SourceString('JSString')), | 811 jsStringClass = compiler.findInterceptor(const SourceString('JSString')), |
820 jsArrayClass = compiler.findInterceptor(const SourceString('JSArray')), | 812 jsArrayClass = compiler.findInterceptor(const SourceString('JSArray')), |
821 // The int class must be before the double class, because the | 813 // The int class must be before the double class, because the |
822 // emitter relies on this list for the order of type checks. | 814 // emitter relies on this list for the order of type checks. |
823 jsIntClass = compiler.findInterceptor(const SourceString('JSInt')), | 815 jsIntClass = compiler.findInterceptor(const SourceString('JSInt')), |
824 jsDoubleClass = compiler.findInterceptor(const SourceString('JSDouble')), | 816 jsDoubleClass = compiler.findInterceptor(const SourceString('JSDouble')), |
825 jsNumberClass = compiler.findInterceptor(const SourceString('JSNumber')), | 817 jsNumberClass = compiler.findInterceptor(const SourceString('JSNumber')), |
826 jsNullClass = compiler.findInterceptor(const SourceString('JSNull')), | 818 jsNullClass = compiler.findInterceptor(const SourceString('JSNull')), |
827 jsFunctionClass = | 819 jsFunctionClass = |
828 compiler.findInterceptor(const SourceString('JSFunction')), | 820 compiler.findInterceptor(const SourceString('JSFunction')), |
(...skipping 11 matching lines...) Expand all Loading... |
840 jsStringLength = compiler.lookupElementIn( | 832 jsStringLength = compiler.lookupElementIn( |
841 jsStringClass, const SourceString('length')); | 833 jsStringClass, const SourceString('length')); |
842 jsStringSplit = compiler.lookupElementIn( | 834 jsStringSplit = compiler.lookupElementIn( |
843 jsStringClass, const SourceString('split')); | 835 jsStringClass, const SourceString('split')); |
844 jsStringConcat = compiler.lookupElementIn( | 836 jsStringConcat = compiler.lookupElementIn( |
845 jsStringClass, const SourceString('concat')); | 837 jsStringClass, const SourceString('concat')); |
846 jsStringToString = compiler.lookupElementIn( | 838 jsStringToString = compiler.lookupElementIn( |
847 jsStringClass, const SourceString('toString')); | 839 jsStringClass, const SourceString('toString')); |
848 | 840 |
849 for (ClassElement cls in classes) { | 841 for (ClassElement cls in classes) { |
850 if (cls != null) interceptedClasses[cls] = null; | 842 if (cls != null) interceptedClasses.add(cls); |
851 } | 843 } |
852 } | 844 } |
853 | 845 |
854 void addInterceptors(ClassElement cls, Enqueuer enqueuer) { | 846 void addInterceptors(ClassElement cls, Enqueuer enqueuer) { |
855 if (enqueuer.isResolutionQueue) { | 847 if (enqueuer.isResolutionQueue) { |
856 cls.ensureResolved(compiler); | 848 cls.ensureResolved(compiler); |
857 cls.forEachMember((ClassElement classElement, Element member) { | 849 cls.forEachMember((ClassElement classElement, Element member) { |
858 Set<Element> set = interceptedElements.putIfAbsent( | 850 Set<Element> set = interceptedElements.putIfAbsent( |
859 member.name, () => new Set<Element>()); | 851 member.name, () => new Set<Element>()); |
860 set.add(member); | 852 set.add(member); |
861 }, | 853 }, |
862 includeSuperMembers: true); | 854 includeSuperMembers: true); |
863 } | 855 } |
864 enqueuer.registerInstantiatedClass(cls); | 856 enqueuer.registerInstantiatedClass(cls); |
865 } | 857 } |
866 | 858 |
867 void registerSpecializedGetInterceptor(Set<ClassElement> classes) { | 859 void registerSpecializedGetInterceptor(Set<ClassElement> classes) { |
868 compiler.enqueuer.codegen.registerInstantiatedClass(objectInterceptorClass); | |
869 String name = namer.getInterceptorName(getInterceptorMethod, classes); | 860 String name = namer.getInterceptorName(getInterceptorMethod, classes); |
870 if (classes.contains(compiler.objectClass)) { | 861 if (classes.contains(compiler.objectClass)) { |
871 // We can't use a specialized [getInterceptorMethod], so we make | 862 // We can't use a specialized [getInterceptorMethod], so we make |
872 // sure we emit the one with all checks. | 863 // sure we emit the one with all checks. |
873 specializedGetInterceptors.putIfAbsent(name, () { | 864 specializedGetInterceptors[name] = interceptedClasses; |
874 // It is important to take the order provided by the map, | |
875 // because we want the int type check to happen before the | |
876 // double type check: the double type check covers the int | |
877 // type check. Also we don't need to do a number type check | |
878 // because that is covered by the double type check. | |
879 List<ClassElement> keys = <ClassElement>[]; | |
880 interceptedClasses.forEach((ClassElement cls, _) { | |
881 if (cls != jsNumberClass) keys.add(cls); | |
882 }); | |
883 return keys; | |
884 }); | |
885 } else { | 865 } else { |
886 specializedGetInterceptors[name] = classes; | 866 specializedGetInterceptors[name] = classes; |
887 } | 867 } |
888 } | 868 } |
889 | 869 |
890 void initializeNoSuchMethod() { | 870 void initializeNoSuchMethod() { |
891 // In case the emitter generates noSuchMethod calls, we need to | 871 // In case the emitter generates noSuchMethod calls, we need to |
892 // make sure all [noSuchMethod] methods know they might take a | 872 // make sure all [noSuchMethod] methods know they might take a |
893 // [JsInvocationMirror] as parameter. | 873 // [JsInvocationMirror] as parameter. |
894 HTypeList types = new HTypeList(1); | 874 HTypeList types = new HTypeList(1); |
(...skipping 622 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1517 * | 1497 * |
1518 * Invariant: [element] must be a declaration element. | 1498 * Invariant: [element] must be a declaration element. |
1519 */ | 1499 */ |
1520 void eagerRecompile(Element element) { | 1500 void eagerRecompile(Element element) { |
1521 assert(invariant(element, element.isDeclaration)); | 1501 assert(invariant(element, element.isDeclaration)); |
1522 generatedCode.remove(element); | 1502 generatedCode.remove(element); |
1523 generatedBailoutCode.remove(element); | 1503 generatedBailoutCode.remove(element); |
1524 compiler.enqueuer.codegen.addToWorkList(element); | 1504 compiler.enqueuer.codegen.addToWorkList(element); |
1525 } | 1505 } |
1526 } | 1506 } |
OLD | NEW |