| 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 |