| 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 /** | 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 Loading... |
| 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) { |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 1044 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2222 """; | 2287 """; |
| 2223 const String HOOKS_API_USAGE = """ | 2288 const String HOOKS_API_USAGE = """ |
| 2224 // The code supports the following hooks: | 2289 // The code supports the following hooks: |
| 2225 // dartPrint(message) - if this function is defined it is called | 2290 // dartPrint(message) - if this function is defined it is called |
| 2226 // instead of the Dart [print] method. | 2291 // instead of the Dart [print] method. |
| 2227 // dartMainRunner(main) - if this function is defined, the Dart [main] | 2292 // dartMainRunner(main) - if this function is defined, the Dart [main] |
| 2228 // method will not be invoked directly. | 2293 // method will not be invoked directly. |
| 2229 // Instead, a closure that will invoke [main] is | 2294 // Instead, a closure that will invoke [main] is |
| 2230 // passed to [dartMainRunner]. | 2295 // passed to [dartMainRunner]. |
| 2231 """; | 2296 """; |
| OLD | NEW |