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 // TODO(8522): Restore --disallow-unsafe-eval. | 739 // TODO(8522): Restore --disallow-unsafe-eval. |
742 ? null // new CodeEmitterNoEvalTask(compiler, namer, generateSourceMap) | 740 ? null // new CodeEmitterNoEvalTask(compiler, namer, generateSourceMap) |
743 : new CodeEmitterTask(compiler, namer, generateSourceMap); | 741 : new CodeEmitterTask(compiler, namer, generateSourceMap); |
744 builder = new SsaBuilderTask(this); | 742 builder = new SsaBuilderTask(this); |
745 optimizer = new SsaOptimizerTask(this); | 743 optimizer = new SsaOptimizerTask(this); |
746 generator = new SsaCodeGeneratorTask(this); | 744 generator = new SsaCodeGeneratorTask(this); |
747 argumentTypes = new ArgumentTypesRegistry(this); | 745 argumentTypes = new ArgumentTypesRegistry(this); |
748 fieldTypes = new FieldTypesRegistry(this); | 746 fieldTypes = new FieldTypesRegistry(this); |
749 } | 747 } |
750 | 748 |
751 static Namer determineNamer(Compiler compiler) { | 749 static Namer determineNamer(Compiler compiler) { |
752 return compiler.enableMinification ? | 750 return compiler.enableMinification ? |
753 new MinifyNamer(compiler) : | 751 new MinifyNamer(compiler) : |
754 new Namer(compiler); | 752 new Namer(compiler); |
755 } | 753 } |
756 | 754 |
757 bool isInterceptorClass(Element element) { | 755 bool isInterceptorClass(Element element) { |
758 if (element == null) return false; | 756 if (element == null) return false; |
759 return interceptedClasses.containsKey(element); | 757 return interceptedClasses.contains(element); |
760 } | 758 } |
761 | 759 |
762 void addInterceptedSelector(Selector selector) { | 760 void addInterceptedSelector(Selector selector) { |
763 usedInterceptors.add(selector); | 761 usedInterceptors.add(selector); |
764 } | 762 } |
765 | 763 |
766 String registerOneShotInterceptor(Selector selector) { | 764 String registerOneShotInterceptor(Selector selector) { |
767 Set<ClassElement> classes = getInterceptedClassesOn(selector); | 765 Set<ClassElement> classes = getInterceptedClassesOn(selector.name); |
768 String name = namer.getOneShotInterceptorName(selector, classes); | 766 String name = namer.getOneShotInterceptorName(selector, classes); |
769 if (!oneShotInterceptors.containsKey(name)) { | 767 if (!oneShotInterceptors.containsKey(name)) { |
770 registerSpecializedGetInterceptor(classes); | 768 registerSpecializedGetInterceptor(classes); |
771 oneShotInterceptors[name] = selector; | 769 oneShotInterceptors[name] = selector; |
772 } | 770 } |
773 return name; | 771 return name; |
774 } | 772 } |
775 | 773 |
776 final Map<Selector, Set<ClassElement>> interceptedClassesCache = | 774 bool isInterceptedMethod(Element element) { |
777 new Map<Selector, Set<ClassElement>>(); | 775 return element.isInstanceMember() |
778 final Map<Selector, Set<ClassElement>> interceptedClassesNonNullCache = | 776 && interceptedElements[element.name] != null; |
779 new Map<Selector, Set<ClassElement>>(); | 777 } |
778 | |
779 bool isInterceptedName(SourceString name) { | |
780 return interceptedElements[name] != null; | |
781 } | |
782 | |
783 final Map<SourceString, Set<ClassElement>> interceptedClassesCache = | |
784 new Map<SourceString, Set<ClassElement>>(); | |
780 | 785 |
781 /** | 786 /** |
782 * Returns a set of interceptor classes that contain a member whose | 787 * Returns a set of interceptor classes that contain a member named |
783 * signature matches the given [selector]. Returns [:null:] if there | 788 * [name]. Returns [:null:] if there is no class. |
784 * is no class. | |
785 */ | 789 */ |
786 Set<ClassElement> getInterceptedClassesOn(Selector selector, | 790 Set<ClassElement> getInterceptedClassesOn(SourceString name) { |
787 {bool canBeNull: true}) { | 791 Set<Element> intercepted = interceptedElements[name]; |
788 Set<Element> intercepted = interceptedElements[selector.name]; | |
789 if (intercepted == null) return null; | 792 if (intercepted == null) return null; |
790 // Pick the right cache and query it. | 793 if (interceptedClassesCache.containsKey(name)) { |
791 Map<Selector, Set<ClassElement>> cache = canBeNull | 794 return interceptedClassesCache[name]; |
792 ? interceptedClassesCache | 795 } |
793 : interceptedClassesNonNullCache; | |
794 if (cache.containsKey(selector)) return cache[selector]; | |
795 // Populate the cache by running through all the elements and | 796 // Populate the cache by running through all the elements and |
796 // determine if the given selector applies to them. | 797 // determine if the given selector applies to them. |
797 Set<ClassElement> result = new Set<ClassElement>(); | 798 Set<ClassElement> result = new Set<ClassElement>(); |
798 for (Element element in intercepted) { | 799 for (Element element in intercepted) { |
799 ClassElement enclosing = element.getEnclosingClass(); | 800 result.add(element.getEnclosingClass()); |
800 // We have to treat null as a bottom type, so we use the untyped | |
801 // applies method for those elements that are implemented on the | |
802 // null class. | |
803 bool applies = (enclosing == jsNullClass) | |
804 ? canBeNull && selector.appliesUntyped(element, compiler) | |
805 : selector.applies(element, compiler); | |
806 if (applies) result.add(enclosing); | |
807 } | 801 } |
808 if (result.isEmpty) result = null; | 802 interceptedClassesCache[name] = result; |
kasperl
2013/03/01 09:06:47
So if we're not using the trick of storing null in
ngeoffray
2013/03/01 10:46:56
Done.
| |
809 cache[selector] = result; | |
810 assert(cache.containsKey(selector)); | |
811 return result; | 803 return result; |
812 } | 804 } |
813 | 805 |
814 void initializeHelperClasses() { | 806 void initializeHelperClasses() { |
815 objectInterceptorClass = | |
816 compiler.findInterceptor(const SourceString('ObjectInterceptor')); | |
817 getInterceptorMethod = | 807 getInterceptorMethod = |
818 compiler.findInterceptor(const SourceString('getInterceptor')); | 808 compiler.findInterceptor(const SourceString('getInterceptor')); |
809 interceptedNames = | |
810 compiler.findInterceptor(const SourceString('interceptedNames')); | |
819 List<ClassElement> classes = [ | 811 List<ClassElement> classes = [ |
812 compiler.objectClass, | |
820 jsStringClass = compiler.findInterceptor(const SourceString('JSString')), | 813 jsStringClass = compiler.findInterceptor(const SourceString('JSString')), |
821 jsArrayClass = compiler.findInterceptor(const SourceString('JSArray')), | 814 jsArrayClass = compiler.findInterceptor(const SourceString('JSArray')), |
822 // The int class must be before the double class, because the | 815 // The int class must be before the double class, because the |
823 // emitter relies on this list for the order of type checks. | 816 // emitter relies on this list for the order of type checks. |
824 jsIntClass = compiler.findInterceptor(const SourceString('JSInt')), | 817 jsIntClass = compiler.findInterceptor(const SourceString('JSInt')), |
825 jsDoubleClass = compiler.findInterceptor(const SourceString('JSDouble')), | 818 jsDoubleClass = compiler.findInterceptor(const SourceString('JSDouble')), |
826 jsNumberClass = compiler.findInterceptor(const SourceString('JSNumber')), | 819 jsNumberClass = compiler.findInterceptor(const SourceString('JSNumber')), |
827 jsNullClass = compiler.findInterceptor(const SourceString('JSNull')), | 820 jsNullClass = compiler.findInterceptor(const SourceString('JSNull')), |
828 jsFunctionClass = | 821 jsFunctionClass = |
829 compiler.findInterceptor(const SourceString('JSFunction')), | 822 compiler.findInterceptor(const SourceString('JSFunction')), |
(...skipping 11 matching lines...) Expand all Loading... | |
841 jsStringLength = compiler.lookupElementIn( | 834 jsStringLength = compiler.lookupElementIn( |
842 jsStringClass, const SourceString('length')); | 835 jsStringClass, const SourceString('length')); |
843 jsStringSplit = compiler.lookupElementIn( | 836 jsStringSplit = compiler.lookupElementIn( |
844 jsStringClass, const SourceString('split')); | 837 jsStringClass, const SourceString('split')); |
845 jsStringConcat = compiler.lookupElementIn( | 838 jsStringConcat = compiler.lookupElementIn( |
846 jsStringClass, const SourceString('concat')); | 839 jsStringClass, const SourceString('concat')); |
847 jsStringToString = compiler.lookupElementIn( | 840 jsStringToString = compiler.lookupElementIn( |
848 jsStringClass, const SourceString('toString')); | 841 jsStringClass, const SourceString('toString')); |
849 | 842 |
850 for (ClassElement cls in classes) { | 843 for (ClassElement cls in classes) { |
851 if (cls != null) interceptedClasses[cls] = null; | 844 if (cls != null) interceptedClasses.add(cls); |
852 } | 845 } |
853 } | 846 } |
854 | 847 |
855 void addInterceptors(ClassElement cls, Enqueuer enqueuer) { | 848 void addInterceptors(ClassElement cls, Enqueuer enqueuer) { |
856 if (enqueuer.isResolutionQueue) { | 849 if (enqueuer.isResolutionQueue) { |
857 cls.ensureResolved(compiler); | 850 cls.ensureResolved(compiler); |
858 cls.forEachMember((ClassElement classElement, Element member) { | 851 cls.forEachMember((ClassElement classElement, Element member) { |
859 Set<Element> set = interceptedElements.putIfAbsent( | 852 Set<Element> set = interceptedElements.putIfAbsent( |
860 member.name, () => new Set<Element>()); | 853 member.name, () => new Set<Element>()); |
861 set.add(member); | 854 set.add(member); |
862 }, | 855 }, |
863 includeSuperMembers: true); | 856 includeSuperMembers: true); |
864 } | 857 } |
865 enqueuer.registerInstantiatedClass(cls); | 858 enqueuer.registerInstantiatedClass(cls); |
866 } | 859 } |
867 | 860 |
868 void registerSpecializedGetInterceptor(Set<ClassElement> classes) { | 861 void registerSpecializedGetInterceptor(Set<ClassElement> classes) { |
869 compiler.enqueuer.codegen.registerInstantiatedClass(objectInterceptorClass); | |
870 String name = namer.getInterceptorName(getInterceptorMethod, classes); | 862 String name = namer.getInterceptorName(getInterceptorMethod, classes); |
871 if (classes.contains(compiler.objectClass)) { | 863 if (classes.contains(compiler.objectClass)) { |
872 // We can't use a specialized [getInterceptorMethod], so we make | 864 // We can't use a specialized [getInterceptorMethod], so we make |
873 // sure we emit the one with all checks. | 865 // sure we emit the one with all checks. |
874 specializedGetInterceptors.putIfAbsent(name, () { | 866 specializedGetInterceptors[name] = interceptedClasses; |
875 // It is important to take the order provided by the map, | |
876 // because we want the int type check to happen before the | |
877 // double type check: the double type check covers the int | |
878 // type check. Also we don't need to do a number type check | |
879 // because that is covered by the double type check. | |
880 List<ClassElement> keys = <ClassElement>[]; | |
881 interceptedClasses.forEach((ClassElement cls, _) { | |
882 if (cls != jsNumberClass) keys.add(cls); | |
883 }); | |
884 return keys; | |
885 }); | |
886 } else { | 867 } else { |
887 specializedGetInterceptors[name] = classes; | 868 specializedGetInterceptors[name] = classes; |
888 } | 869 } |
889 } | 870 } |
890 | 871 |
891 void initializeNoSuchMethod() { | 872 void initializeNoSuchMethod() { |
892 // In case the emitter generates noSuchMethod calls, we need to | 873 // In case the emitter generates noSuchMethod calls, we need to |
893 // make sure all [noSuchMethod] methods know they might take a | 874 // make sure all [noSuchMethod] methods know they might take a |
894 // [JsInvocationMirror] as parameter. | 875 // [JsInvocationMirror] as parameter. |
895 HTypeList types = new HTypeList(1); | 876 HTypeList types = new HTypeList(1); |
(...skipping 602 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1498 * | 1479 * |
1499 * Invariant: [element] must be a declaration element. | 1480 * Invariant: [element] must be a declaration element. |
1500 */ | 1481 */ |
1501 void eagerRecompile(Element element) { | 1482 void eagerRecompile(Element element) { |
1502 assert(invariant(element, element.isDeclaration)); | 1483 assert(invariant(element, element.isDeclaration)); |
1503 generatedCode.remove(element); | 1484 generatedCode.remove(element); |
1504 generatedBailoutCode.remove(element); | 1485 generatedBailoutCode.remove(element); |
1505 compiler.enqueuer.codegen.addToWorkList(element); | 1486 compiler.enqueuer.codegen.addToWorkList(element); |
1506 } | 1487 } |
1507 } | 1488 } |
OLD | NEW |