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

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

Issue 12051056: Allow native classes to mixin behavior from an ordinary Dart class. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Refactor. Created 7 years, 11 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
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 /** 7 /**
8 * A function element that represents a closure call. The signature is copied 8 * A function element that represents a closure call. The signature is copied
9 * from the given element. 9 * from the given element.
10 */ 10 */
(...skipping 717 matching lines...) Expand 10 before | Expand all | Expand 10 after
728 void emitInstanceMembers(ClassElement classElement, 728 void emitInstanceMembers(ClassElement classElement,
729 ClassBuilder builder) { 729 ClassBuilder builder) {
730 assert(invariant(classElement, classElement.isDeclaration)); 730 assert(invariant(classElement, classElement.isDeclaration));
731 JavaScriptBackend backend = compiler.backend; 731 JavaScriptBackend backend = compiler.backend;
732 if (classElement == backend.objectInterceptorClass) { 732 if (classElement == backend.objectInterceptorClass) {
733 emitInterceptorMethods(builder); 733 emitInterceptorMethods(builder);
734 // The ObjectInterceptor does not have any instance methods. 734 // The ObjectInterceptor does not have any instance methods.
735 return; 735 return;
736 } 736 }
737 737
738 void visitMember(ClassElement enclosing, Element member) {
739 assert(invariant(classElement, member.isDeclaration));
740 if (member.isInstanceMember()) {
741 addInstanceMember(member, builder);
742 }
743 }
744
745 // TODO(kasperl): We should make sure to only emit one version of
746 // overridden methods. Right now, we rely on the ordering so the
747 // methods pulled in from mixins are replaced with the members
748 // from the class definition.
749
750 // If the class is a native class, we have to add the instance
751 // members defined in the non-native mixin applications used by
752 // the class.
753 visitNativeMixins(classElement, (MixinApplicationElement mixin) {
ngeoffray 2013/01/24 11:55:53 visitMixinsOfNativeClasses?
754 mixin.forEachMember(
755 visitMember,
756 includeBackendMembers: true,
757 includeSuperMembers: false);
758 });
759
738 classElement.implementation.forEachMember( 760 classElement.implementation.forEachMember(
739 (ClassElement enclosing, Element member) { 761 visitMember,
740 assert(invariant(classElement, member.isDeclaration)); 762 includeBackendMembers: true,
741 if (member.isInstanceMember()) { 763 includeSuperMembers: false);
742 addInstanceMember(member, builder);
743 }
744 },
745 includeBackendMembers: true);
746 764
747 generateIsTestsOn(classElement, (Element other) { 765 generateIsTestsOn(classElement, (Element other) {
748 js.Expression code; 766 js.Expression code;
749 if (compiler.objectClass == other) return; 767 if (compiler.objectClass == other) return;
750 if (nativeEmitter.requiresNativeIsCheck(other)) { 768 if (nativeEmitter.requiresNativeIsCheck(other)) {
751 code = js.fun([], js.block1(js.return_(new js.LiteralBool(true)))); 769 code = js.fun([], js.block1(js.return_(new js.LiteralBool(true))));
752 } else { 770 } else {
753 code = new js.LiteralBool(true); 771 code = new js.LiteralBool(true);
754 } 772 }
755 builder.addProperty(namer.operatorIs(other), code); 773 builder.addProperty(namer.operatorIs(other), code);
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
819 // class. 837 // class.
820 continue; 838 continue;
821 } 839 }
822 String holder = namer.isolateAccess(cls); 840 String holder = namer.isolateAccess(cls);
823 for (ClassElement check in typeChecks[cls]) { 841 for (ClassElement check in typeChecks[cls]) {
824 buffer.add('$holder.${namer.operatorIs(check)}$_=${_}true$N'); 842 buffer.add('$holder.${namer.operatorIs(check)}$_=${_}true$N');
825 }; 843 };
826 } 844 }
827 } 845 }
828 846
847 void visitNativeMixins(ClassElement classElement,
848 void visit(MixinApplicationElement mixinApplication)) {
849 if (!classElement.isNative()) return;
850 // Use recursion to make sure to visit the superclasses before the
851 // subclasses. Once we start keeping track of the emitted fields
852 // and members, we're going to want to visit these in the other
853 // order so we get the most specialized definition first.
854 void recurse(ClassElement cls) {
855 if (cls == null || !cls.isMixinApplication) return;
856 recurse(cls.superclass);
857 assert(!cls.isNative());
858 visit(cls);
859 }
860 recurse(classElement.superclass);
861 }
862
829 /** 863 /**
830 * Documentation wanted -- johnniwinther 864 * Documentation wanted -- johnniwinther
831 * 865 *
832 * Invariant: [classElement] must be a declaration element. 866 * Invariant: [classElement] must be a declaration element.
833 */ 867 */
834 void visitClassFields(ClassElement classElement, 868 void visitClassFields(ClassElement classElement,
835 void addField(Element member, 869 void addField(Element member,
836 String name, 870 String name,
837 String accessorName, 871 String accessorName,
838 bool needsGetter, 872 bool needsGetter,
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
884 // Getters and setters with suffixes will be generated dynamically. 918 // Getters and setters with suffixes will be generated dynamically.
885 addField(member, 919 addField(member,
886 fieldName, 920 fieldName,
887 accessorName, 921 accessorName,
888 needsGetter, 922 needsGetter,
889 needsSetter, 923 needsSetter,
890 needsCheckedSetter); 924 needsCheckedSetter);
891 } 925 }
892 } 926 }
893 927
928 // TODO(kasperl): We should make sure to only emit one version of
929 // overridden fields. Right now, we rely on the ordering so the
930 // fields pulled in from mixins are replaced with the fields from
931 // the class definition.
932
933 // If the class is a native class, we have to add the fields
934 // defined in the non-native mixin applications used by the class.
935 visitNativeMixins(classElement, (MixinApplicationElement mixin) {
936 mixin.forEachInstanceField(
937 visitField,
938 includeBackendMembers: true,
939 includeSuperMembers: false);
940 });
941
894 // If a class is not instantiated then we add the field just so we can 942 // If a class is not instantiated then we add the field just so we can
895 // generate the field getter/setter dynamically. Since this is only 943 // generate the field getter/setter dynamically. Since this is only
896 // allowed on fields that are in [classElement] we don't need to visit 944 // allowed on fields that are in [classElement] we don't need to visit
897 // superclasses for non-instantiated classes. 945 // superclasses for non-instantiated classes.
898 classElement.implementation.forEachInstanceField( 946 classElement.implementation.forEachInstanceField(
899 visitField, 947 visitField,
900 includeBackendMembers: true, 948 includeBackendMembers: true,
901 includeSuperMembers: isInstantiated && !classElement.isNative()); 949 includeSuperMembers: isInstantiated && !classElement.isNative());
902 } 950 }
903 951
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
1061 return; 1109 return;
1062 } else { 1110 } else {
1063 // TODO(ngeoffray): Instead of switching between buffer, we 1111 // TODO(ngeoffray): Instead of switching between buffer, we
1064 // should create code sections, and decide where to emit them at 1112 // should create code sections, and decide where to emit them at
1065 // the end. 1113 // the end.
1066 buffer = mainBuffer; 1114 buffer = mainBuffer;
1067 } 1115 }
1068 1116
1069 needsDefineClass = true; 1117 needsDefineClass = true;
1070 String className = namer.getName(classElement); 1118 String className = namer.getName(classElement);
1119
1120 // Find the first non-native superclass.
1071 ClassElement superclass = classElement.superclass; 1121 ClassElement superclass = classElement.superclass;
1122 while (superclass != null && superclass.isNative()) {
1123 superclass = superclass.superclass;
1124 }
1125
1072 String superName = ""; 1126 String superName = "";
1073 if (superclass != null) { 1127 if (superclass != null) {
1074 superName = namer.getName(superclass); 1128 superName = namer.getName(superclass);
1075 } 1129 }
1076 1130
1077 ClassBuilder builder = new ClassBuilder(); 1131 ClassBuilder builder = new ClassBuilder();
1078 1132
1079 emitClassConstructor(classElement, builder); 1133 emitClassConstructor(classElement, builder);
1080 emitSuper(superName, builder); 1134 emitSuper(superName, builder);
1081 emitClassFields(classElement, builder, 1135 emitClassFields(classElement, builder,
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
1155 // If [cls] is a closure, it has a synthetic call operator method. 1209 // If [cls] is a closure, it has a synthetic call operator method.
1156 call = cls.lookupBackendMember(Compiler.CALL_OPERATOR_NAME); 1210 call = cls.lookupBackendMember(Compiler.CALL_OPERATOR_NAME);
1157 } 1211 }
1158 if (call != null) { 1212 if (call != null) {
1159 generateInterfacesIsTests(compiler.functionClass, 1213 generateInterfacesIsTests(compiler.functionClass,
1160 emitIsTest, 1214 emitIsTest,
1161 generated); 1215 generated);
1162 getTypedefChecksOn(call.computeType(compiler)).forEach(emitIsTest); 1216 getTypedefChecksOn(call.computeType(compiler)).forEach(emitIsTest);
1163 } 1217 }
1164 } 1218 }
1219
1165 for (DartType interfaceType in cls.interfaces) { 1220 for (DartType interfaceType in cls.interfaces) {
1166 generateInterfacesIsTests(interfaceType.element, emitIsTest, generated); 1221 generateInterfacesIsTests(interfaceType.element, emitIsTest, generated);
1167 } 1222 }
1223
1224 // For native classes, we also have to run through their mixin
1225 // applications and make sure we deal with 'is' tests correctly
1226 // for those.
1227 visitNativeMixins(cls, (MixinApplicationElement mixin) {
1228 for (DartType interfaceType in mixin.interfaces) {
1229 ClassElement interfaceElement = interfaceType.element;
1230 generateInterfacesIsTests(interfaceType.element, emitIsTest, generated);
1231 }
1232 });
1168 } 1233 }
1169 1234
1170 /** 1235 /**
1171 * Generate "is tests" where [cls] is being implemented. 1236 * Generate "is tests" where [cls] is being implemented.
1172 */ 1237 */
1173 void generateInterfacesIsTests(ClassElement cls, 1238 void generateInterfacesIsTests(ClassElement cls,
1174 void emitIsTest(ClassElement element), 1239 void emitIsTest(ClassElement element),
1175 Set<Element> alreadyGenerated) { 1240 Set<Element> alreadyGenerated) {
1176 void tryEmitTest(ClassElement cls) { 1241 void tryEmitTest(ClassElement cls) {
1177 if (!alreadyGenerated.contains(cls) && checkedClasses.contains(cls)) { 1242 if (!alreadyGenerated.contains(cls) && checkedClasses.contains(cls)) {
(...skipping 1000 matching lines...) Expand 10 before | Expand all | Expand 10 after
2178 """; 2243 """;
2179 const String HOOKS_API_USAGE = """ 2244 const String HOOKS_API_USAGE = """
2180 // The code supports the following hooks: 2245 // The code supports the following hooks:
2181 // dartPrint(message) - if this function is defined it is called 2246 // dartPrint(message) - if this function is defined it is called
2182 // instead of the Dart [print] method. 2247 // instead of the Dart [print] method.
2183 // dartMainRunner(main) - if this function is defined, the Dart [main] 2248 // dartMainRunner(main) - if this function is defined, the Dart [main]
2184 // method will not be invoked directly. 2249 // method will not be invoked directly.
2185 // Instead, a closure that will invoke [main] is 2250 // Instead, a closure that will invoke [main] is
2186 // passed to [dartMainRunner]. 2251 // passed to [dartMainRunner].
2187 """; 2252 """;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698