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 /** | 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 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 128 } | 128 } |
| 129 if (needsSetter) { | 129 if (needsSetter) { |
| 130 var setterString = "this." + field + " = v;"; | 130 var setterString = "this." + field + " = v;"; |
| 131 prototype["set\$" + field] = new Function("v", setterString); | 131 prototype["set\$" + field] = new Function("v", setterString); |
| 132 } | 132 } |
| 133 return field; | 133 return field; |
| 134 }"""; | 134 }"""; |
| 135 } | 135 } |
| 136 | 136 |
| 137 String get defineClassFunction { | 137 String get defineClassFunction { |
| 138 // First the class name, then the super class name, followed by the fields | 138 // First the class name, then the field names in an array and the members |
| 139 // (in an array) and the members (inside an Object literal). | 139 // (inside an Object literal). |
| 140 // The caller can also pass in the constructor as a function if needed. | 140 // The caller can also pass in the constructor as a function if needed. |
| 141 // | 141 // |
| 142 // Example: | 142 // Example: |
| 143 // defineClass("A", "B", ["x", "y"], { | 143 // defineClass("A", ["x", "y"], { |
|
karlklose
2012/11/30 11:43:34
Shouldn't this be
defineClass("A":"B@x.y", {
?
erikcorry
2012/11/30 12:05:57
No, this is called from finishClassesFunction, whe
ngeoffray
2012/11/30 12:11:46
So where is B in defineClass now?
erikcorry
2012/11/30 12:20:02
We don't need the superclass here, so it's nowhere
| |
| 144 // foo$1: function(y) { | 144 // foo$1: function(y) { |
| 145 // print(this.x + y); | 145 // print(this.x + y); |
| 146 // }, | 146 // }, |
| 147 // bar$2: function(t, v) { | 147 // bar$2: function(t, v) { |
| 148 // this.x = t - v; | 148 // this.x = t - v; |
| 149 // }, | 149 // }, |
| 150 // }); | 150 // }); |
| 151 return """ | 151 return """ |
| 152 function(cls, fields, prototype) { | 152 function(cls, fields, prototype) { |
| 153 var generateGetterSetter = $generateGetterSetterFunction; | 153 var generateGetterSetter = $generateGetterSetterFunction; |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 207 // constructor. | 207 // constructor. |
| 208 // For engines where we have access to the '__proto__' we can manipulate | 208 // For engines where we have access to the '__proto__' we can manipulate |
| 209 // the object literal directly. For other engines we have to create a new | 209 // the object literal directly. For other engines we have to create a new |
| 210 // object and copy over the members. | 210 // object and copy over the members. |
| 211 return ''' | 211 return ''' |
| 212 function(collectedClasses) { | 212 function(collectedClasses) { |
| 213 var hasOwnProperty = Object.prototype.hasOwnProperty; | 213 var hasOwnProperty = Object.prototype.hasOwnProperty; |
| 214 for (var cls in collectedClasses) { | 214 for (var cls in collectedClasses) { |
| 215 if (hasOwnProperty.call(collectedClasses, cls)) { | 215 if (hasOwnProperty.call(collectedClasses, cls)) { |
| 216 var desc = collectedClasses[cls]; | 216 var desc = collectedClasses[cls]; |
| 217 '''/* If the class does not have any declared fields (in the '' | 217 '''/* Get the superclass and the fields in the format Super@field1.field2 from |
| 218 property of the description), then provide an empty list of fields. */''' | 218 the null-string property on the descriptor. */''' |
| 219 $isolatePropertiesName[cls] = $defineClassName(cls, desc[''] || [], desc); | 219 var s = desc[''].split('@'), supr = s[0]; |
| 220 if (desc['super'] !== "") $pendingClassesName[cls] = desc['super']; | 220 var fields = s[1] == '' ? [] : s[1].split('.'); |
| 221 $isolatePropertiesName[cls] = $defineClassName(cls, fields, desc); | |
| 222 if (supr) $pendingClassesName[cls] = supr; | |
| 221 } | 223 } |
| 222 } | 224 } |
| 223 var pendingClasses = $pendingClassesName; | 225 var pendingClasses = $pendingClassesName; |
| 224 '''/* FinishClasses can be called multiple times. This means that we need to | 226 '''/* FinishClasses can be called multiple times. This means that we need to |
| 225 clear the pendingClasses property. */''' | 227 clear the pendingClasses property. */''' |
| 226 $pendingClassesName = {}; | 228 $pendingClassesName = {}; |
| 227 var finishedClasses = {}; | 229 var finishedClasses = {}; |
| 228 function finishClass(cls) { | 230 function finishClass(cls) { |
| 229 '''/* Opera does not support 'getOwnPropertyNames'. Therefore we use | 231 '''/* Opera does not support 'getOwnPropertyNames'. Therefore we use |
| 230 hasOwnProperty instead. */''' | 232 hasOwnProperty instead. */''' |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 241 if ($supportsProtoName) { | 243 if ($supportsProtoName) { |
| 242 prototype.__proto__ = superConstructor.prototype; | 244 prototype.__proto__ = superConstructor.prototype; |
| 243 prototype.constructor = constructor; | 245 prototype.constructor = constructor; |
| 244 } else { | 246 } else { |
| 245 function tmp() {}; | 247 function tmp() {}; |
| 246 tmp.prototype = superConstructor.prototype; | 248 tmp.prototype = superConstructor.prototype; |
| 247 var newPrototype = new tmp(); | 249 var newPrototype = new tmp(); |
| 248 constructor.prototype = newPrototype; | 250 constructor.prototype = newPrototype; |
| 249 newPrototype.constructor = constructor; | 251 newPrototype.constructor = constructor; |
| 250 for (var member in prototype) { | 252 for (var member in prototype) { |
| 251 if (member == '' || member == 'super') continue; | 253 if (!member) continue; '''/* if (member == '') */''' |
|
ngeoffray
2012/11/30 12:11:46
What is this comment about?
erikcorry
2012/11/30 12:20:02
The comment shows the intent, the actual code does
| |
| 252 if (hasOwnProperty.call(prototype, member)) { | 254 if (hasOwnProperty.call(prototype, member)) { |
| 253 newPrototype[member] = prototype[member]; | 255 newPrototype[member] = prototype[member]; |
| 254 } | 256 } |
| 255 } | 257 } |
| 256 } | 258 } |
| 257 } | 259 } |
| 258 for (var cls in pendingClasses) finishClass(cls); | 260 for (var cls in pendingClasses) finishClass(cls); |
| 259 }'''; | 261 }'''; |
| 260 } | 262 } |
| 261 | 263 |
| (...skipping 557 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 819 buffer.add("$setterName: function(v) { " | 821 buffer.add("$setterName: function(v) { " |
| 820 "this.$fieldName = $helperName(v$additionalArgument); }"); | 822 "this.$fieldName = $helperName(v$additionalArgument); }"); |
| 821 } | 823 } |
| 822 | 824 |
| 823 void emitClassConstructor(ClassElement classElement, CodeBuffer buffer) { | 825 void emitClassConstructor(ClassElement classElement, CodeBuffer buffer) { |
| 824 /* Do nothing. */ | 826 /* Do nothing. */ |
| 825 } | 827 } |
| 826 | 828 |
| 827 void emitClassFields(ClassElement classElement, | 829 void emitClassFields(ClassElement classElement, |
| 828 CodeBuffer buffer, | 830 CodeBuffer buffer, |
| 829 bool emitEndingComma) { | 831 { String superClass: "", |
| 832 bool isNative: false, | |
| 833 bool emitEndingComma: false}) { | |
|
ngeoffray
2012/11/30 12:11:46
Please don't put emitEndingComma optional. Other m
erikcorry
2012/11/30 12:20:02
I'll revert this in a later CL.
| |
| 834 assert(!isNative || superClass != ""); | |
| 830 bool isFirstField = true; | 835 bool isFirstField = true; |
| 836 bool isAnythingOutput = false; | |
| 837 if (!isNative) { | |
| 838 buffer.add('"":"$superClass@'); | |
| 839 isAnythingOutput = true; | |
| 840 } | |
| 831 visitClassFields(classElement, (Element member, | 841 visitClassFields(classElement, (Element member, |
| 832 String name, | 842 String name, |
| 833 bool needsGetter, | 843 bool needsGetter, |
| 834 bool needsSetter, | 844 bool needsSetter, |
| 835 bool needsCheckedSetter) { | 845 bool needsCheckedSetter) { |
| 836 | |
| 837 if (!getterAndSetterCanBeImplementedByFieldSpec( | 846 if (!getterAndSetterCanBeImplementedByFieldSpec( |
| 838 member, name, needsGetter, needsSetter)) { | 847 member, name, needsGetter, needsSetter)) { |
| 839 return; | 848 return; |
| 840 } | 849 } |
| 841 | 850 if (!isNative || needsCheckedSetter || needsGetter || needsSetter) { |
| 842 if (isFirstField) { | 851 if (isFirstField) { |
| 843 buffer.add('"": ['); | 852 isFirstField = false; |
| 844 isFirstField = false; | 853 if (!isAnythingOutput) { |
| 845 } else { | 854 buffer.add('"":"'); |
| 846 buffer.add(", "); | 855 isAnythingOutput = true; |
| 856 } | |
| 857 } else { | |
| 858 buffer.add("."); | |
| 859 } | |
| 860 buffer.add('$name'); | |
| 861 if (needsGetter && needsSetter) { | |
| 862 buffer.add(GETTER_SETTER_SUFFIX); | |
| 863 } else if (needsGetter) { | |
| 864 buffer.add(GETTER_SUFFIX); | |
| 865 } else if (needsSetter) { | |
| 866 buffer.add(SETTER_SUFFIX); | |
| 867 } | |
| 847 } | 868 } |
| 848 buffer.add('"$name'); | 869 }); |
| 849 if (needsGetter && needsSetter) { | 870 if (isAnythingOutput) { |
| 850 buffer.add(GETTER_SETTER_SUFFIX); | |
| 851 } else if (needsGetter) { | |
| 852 buffer.add(GETTER_SUFFIX); | |
| 853 } else if (needsSetter) { | |
| 854 buffer.add(SETTER_SUFFIX); | |
| 855 } | |
| 856 buffer.add('"'); | 871 buffer.add('"'); |
| 857 }); | |
| 858 if (!isFirstField) { | |
| 859 // There was at least one field. | |
| 860 buffer.add(']'); | |
| 861 if (emitEndingComma) { | 872 if (emitEndingComma) { |
| 862 buffer.add(','); | 873 buffer.add(','); |
| 863 } | 874 } |
| 864 } | 875 } |
| 865 } | 876 } |
| 866 | 877 |
| 867 /** Each getter/setter must be prefixed with a ",\n ". */ | 878 /** Each getter/setter must be prefixed with a ",\n ". */ |
| 868 void emitClassGettersSetters(ClassElement classElement, | 879 void emitClassGettersSetters(ClassElement classElement, |
| 869 CodeBuffer buffer, | 880 CodeBuffer buffer, |
| 870 bool emitLeadingComma) { | 881 bool emitLeadingComma) { |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 940 needsDefineClass = true; | 951 needsDefineClass = true; |
| 941 String className = namer.getName(classElement); | 952 String className = namer.getName(classElement); |
| 942 ClassElement superclass = classElement.superclass; | 953 ClassElement superclass = classElement.superclass; |
| 943 String superName = ""; | 954 String superName = ""; |
| 944 if (superclass != null) { | 955 if (superclass != null) { |
| 945 superName = namer.getName(superclass); | 956 superName = namer.getName(superclass); |
| 946 } | 957 } |
| 947 | 958 |
| 948 buffer.add('$classesCollector.$className = {'); | 959 buffer.add('$classesCollector.$className = {'); |
| 949 emitClassConstructor(classElement, buffer); | 960 emitClassConstructor(classElement, buffer); |
| 950 emitClassFields(classElement, buffer, true); | 961 emitClassFields(classElement, buffer, superClass: superName, |
| 962 isNative: false, emitEndingComma: false); | |
| 951 // TODO(floitsch): the emitInstanceMember should simply always emit a ',\n'. | 963 // TODO(floitsch): the emitInstanceMember should simply always emit a ',\n'. |
| 952 // That does currently not work because the native classes have a different | 964 // That does currently not work because the native classes have a different |
| 953 // syntax. | 965 // syntax. |
| 954 buffer.add('\n "super": "$superName"'); | 966 emitClassGettersSetters(classElement, buffer, false); |
| 955 emitClassGettersSetters(classElement, buffer, true); | |
| 956 emitInstanceMembers(classElement, buffer, true); | 967 emitInstanceMembers(classElement, buffer, true); |
| 957 buffer.add('\n};\n\n'); | 968 buffer.add('\n};\n\n'); |
| 958 } | 969 } |
| 959 | 970 |
| 960 void emitInterceptorMethods( | 971 void emitInterceptorMethods( |
| 961 void defineInstanceMember(String name, StringBuffer memberBuffer)) { | 972 void defineInstanceMember(String name, StringBuffer memberBuffer)) { |
| 962 JavaScriptBackend backend = compiler.backend; | 973 JavaScriptBackend backend = compiler.backend; |
| 963 // Emit forwarders for the ObjectInterceptor class. We need to | 974 // Emit forwarders for the ObjectInterceptor class. We need to |
| 964 // emit all possible sends on intercepted methods. | 975 // emit all possible sends on intercepted methods. |
| 965 for (Selector selector in backend.usedInterceptors) { | 976 for (Selector selector in backend.usedInterceptors) { |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1153 // in case it is used in spawnFunction. | 1164 // in case it is used in spawnFunction. |
| 1154 String fieldName = namer.STATIC_CLOSURE_NAME_NAME; | 1165 String fieldName = namer.STATIC_CLOSURE_NAME_NAME; |
| 1155 buffer.add('$fieldAccess.$fieldName = "$staticName";\n'); | 1166 buffer.add('$fieldAccess.$fieldName = "$staticName";\n'); |
| 1156 } | 1167 } |
| 1157 } | 1168 } |
| 1158 | 1169 |
| 1159 void emitBoundClosureClassHeader(String mangledName, | 1170 void emitBoundClosureClassHeader(String mangledName, |
| 1160 String superName, | 1171 String superName, |
| 1161 String extraArgument, | 1172 String extraArgument, |
| 1162 CodeBuffer buffer) { | 1173 CodeBuffer buffer) { |
| 1163 extraArgument = extraArgument.isEmpty ? '' : ", '$extraArgument'"; | 1174 extraArgument = extraArgument.isEmpty ? '' : ".$extraArgument"; |
| 1164 buffer.add(""" | 1175 buffer.add(""" |
| 1165 $classesCollector.$mangledName = {'': | 1176 $classesCollector.$mangledName = {'': |
| 1166 ['self'$extraArgument, 'target'], | 1177 \"$superName@self$extraArgument.target\", |
| 1167 'super': '$superName', | |
| 1168 """); | 1178 """); |
| 1169 } | 1179 } |
| 1170 | 1180 |
| 1171 /** | 1181 /** |
| 1172 * Documentation wanted -- johnniwinther | 1182 * Documentation wanted -- johnniwinther |
| 1173 * | 1183 * |
| 1174 * Invariant: [member] must be a declaration element. | 1184 * Invariant: [member] must be a declaration element. |
| 1175 */ | 1185 */ |
| 1176 void emitDynamicFunctionGetter(FunctionElement member, | 1186 void emitDynamicFunctionGetter(FunctionElement member, |
| 1177 DefineMemberFunction defineInstanceMember) { | 1187 DefineMemberFunction defineInstanceMember) { |
| (...skipping 638 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1816 const String HOOKS_API_USAGE = """ | 1826 const String HOOKS_API_USAGE = """ |
| 1817 // Generated by dart2js, the Dart to JavaScript compiler. | 1827 // Generated by dart2js, the Dart to JavaScript compiler. |
| 1818 // The code supports the following hooks: | 1828 // The code supports the following hooks: |
| 1819 // dartPrint(message) - if this function is defined it is called | 1829 // dartPrint(message) - if this function is defined it is called |
| 1820 // instead of the Dart [print] method. | 1830 // instead of the Dart [print] method. |
| 1821 // dartMainRunner(main) - if this function is defined, the Dart [main] | 1831 // dartMainRunner(main) - if this function is defined, the Dart [main] |
| 1822 // method will not be invoked directly. | 1832 // method will not be invoked directly. |
| 1823 // Instead, a closure that will invoke [main] is | 1833 // Instead, a closure that will invoke [main] is |
| 1824 // passed to [dartMainRunner]. | 1834 // passed to [dartMainRunner]. |
| 1825 """; | 1835 """; |
| OLD | NEW |