Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(78)

Side by Side Diff: sdk/lib/_internal/compiler/implementation/js_backend/backend.dart

Issue 12330135: Make instance methods whose names collide with intercepted methods have the interceptor calling con… (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « no previous file | sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698