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