Chromium Code Reviews| 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. |
|
sra1
2013/02/27 05:13:28
[name]
ngeoffray
2013/02/28 10:39:42
Done.
| |
| 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; |
| 809 cache[selector] = result; | |
| 810 assert(cache.containsKey(selector)); | |
| 811 return result; | 803 return result; |
| 812 } | 804 } |
| 813 | 805 |
| 814 void initializeInterceptorElements() { | 806 void initializeInterceptorElements() { |
| 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 603 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1499 * | 1480 * |
| 1500 * Invariant: [element] must be a declaration element. | 1481 * Invariant: [element] must be a declaration element. |
| 1501 */ | 1482 */ |
| 1502 void eagerRecompile(Element element) { | 1483 void eagerRecompile(Element element) { |
| 1503 assert(invariant(element, element.isDeclaration)); | 1484 assert(invariant(element, element.isDeclaration)); |
| 1504 generatedCode.remove(element); | 1485 generatedCode.remove(element); |
| 1505 generatedBailoutCode.remove(element); | 1486 generatedBailoutCode.remove(element); |
| 1506 compiler.enqueuer.codegen.addToWorkList(element); | 1487 compiler.enqueuer.codegen.addToWorkList(element); |
| 1507 } | 1488 } |
| 1508 } | 1489 } |
| OLD | NEW |