Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, 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 /** | 5 /** |
| 6 * Top level generator object for writing code and keeping track of | 6 * Top level generator object for writing code and keeping track of |
| 7 * dependencies. | 7 * dependencies. |
| 8 * | 8 * |
| 9 * Should have two compilation models, but only one implemented so far. | 9 * Should have two compilation models, but only one implemented so far. |
| 10 * | 10 * |
| 11 * 1. Do a top-level resolution of all types and their members. | 11 * 1. Do a top-level resolution of all types and their members. |
| 12 * 2. Start from main and walk the call-graph compiling members as needed. | 12 * 2. Start from main and walk the call-graph compiling members as needed. |
| 13 * 2a. That includes compiling overriding methods and calling methods by | 13 * 2a. That includes compiling overriding methods and calling methods by |
| 14 * selector when invoked on var. | 14 * selector when invoked on var. |
| 15 * 3. Spit out all required code. | 15 * 3. Spit out all required code. |
| 16 */ | 16 */ |
| 17 class WorldGenerator { | 17 class WorldGenerator { |
| 18 MethodMember main; | 18 MethodMember main; |
| 19 CodeWriter writer; | 19 CodeWriter writer; |
| 20 CodeWriter _mixins; | |
| 20 Map<String, GlobalValue> globals; | 21 Map<String, GlobalValue> globals; |
| 21 CoreJs corejs; | 22 CoreJs corejs; |
| 22 bool _inheritsGenerated = false; | 23 bool _inheritsGenerated = false; |
| 23 | 24 |
| 24 WorldGenerator(this.main, this.writer): globals = {}, corejs = new CoreJs(); | 25 WorldGenerator(this.main, this.writer): globals = {}, corejs = new CoreJs(); |
| 25 | 26 |
| 26 run() { | 27 run() { |
| 27 var metaGen = new MethodGenerator(main, null); | 28 var metaGen = new MethodGenerator(main, null); |
| 28 var mainCall = main.invoke(metaGen, null, null, Arguments.EMPTY); | 29 var mainCall = main.invoke(metaGen, null, null, Arguments.EMPTY); |
| 29 main.declaringType.markUsed(); | 30 main.declaringType.markUsed(); |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 45 new Arguments(null, [main._get(metaGen, main.definition, null)])); | 46 new Arguments(null, [main._get(metaGen, main.definition, null)])); |
| 46 } | 47 } |
| 47 | 48 |
| 48 writeTypes(world.coreimpl); | 49 writeTypes(world.coreimpl); |
| 49 writeTypes(world.corelib); | 50 writeTypes(world.corelib); |
| 50 | 51 |
| 51 // Write the main library. This will cause all libraries to be written in | 52 // Write the main library. This will cause all libraries to be written in |
| 52 // the topographic sort order. | 53 // the topographic sort order. |
| 53 writeTypes(main.declaringType.library); | 54 writeTypes(main.declaringType.library); |
| 54 | 55 |
| 56 // Write out any inherited concrete members. | |
| 57 if (_mixins != null) writer.write(_mixins.text); | |
| 58 | |
| 55 _writeGlobals(); | 59 _writeGlobals(); |
| 56 writer.writeln('${mainCall.code};'); | 60 writer.writeln('${mainCall.code};'); |
| 57 } | 61 } |
| 58 | 62 |
| 59 GlobalValue globalForStaticField(FieldMember field, Value fieldValue, | 63 GlobalValue globalForStaticField(FieldMember field, Value fieldValue, |
| 60 List<Value> dependencies) { | 64 List<Value> dependencies) { |
| 61 var fullname = "${field.declaringType.jsname}.${field.jsname}"; | 65 var fullname = "${field.declaringType.jsname}.${field.jsname}"; |
| 62 if (!globals.containsKey(fullname)) { | 66 if (!globals.containsKey(fullname)) { |
| 63 globals[fullname] = new GlobalValue.fromStatic( | 67 globals[fullname] = new GlobalValue.fromStatic( |
| 64 field, fieldValue, dependencies); | 68 field, fieldValue, dependencies); |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 185 | 189 |
| 186 for (var c in type.constructors.getValues()) { | 190 for (var c in type.constructors.getValues()) { |
| 187 if (c.generator != null && c != standardConstructor) { | 191 if (c.generator != null && c != standardConstructor) { |
| 188 c.generator.writeDefinition(writer, null); | 192 c.generator.writeDefinition(writer, null); |
| 189 } | 193 } |
| 190 } | 194 } |
| 191 } | 195 } |
| 192 | 196 |
| 193 if (!type.isTop) { | 197 if (!type.isTop) { |
| 194 if (type is ConcreteType) { | 198 if (type is ConcreteType) { |
| 199 ConcreteType c = type; | |
| 195 _ensureInheritsHelper(); | 200 _ensureInheritsHelper(); |
| 196 writer.writeln( | 201 writer.writeln('\$inherits(${c.jsname}, ${c.genericType.jsname});'); |
| 197 '\$inherits(${type.jsname}, ${type.genericType.jsname});'); | 202 |
| 203 // Mixin members from concrete specializations of base types too. | |
| 204 // TODO(jmesserly): emit this sooner instead of at the end. | |
| 205 // But it needs to come after we've emitted both types. | |
| 206 // TODO(jmesserly): HACK: using _parent instead of parent so we don't | |
| 207 // try to inherit things that we didn't actually use. | |
| 208 for (var p = c._parent; p is ConcreteType; p = p._parent) { | |
| 209 _ensureInheritMembersHelper(); | |
| 210 _mixins.writeln('\$inheritsMembers(${c.jsname}, ${p.jsname});'); | |
| 211 } | |
| 198 } else if (!type.isNativeType) { | 212 } else if (!type.isNativeType) { |
| 199 if (type.parent != null && !type.parent.isObject) { | 213 if (type.parent != null && !type.parent.isObject) { |
| 200 _ensureInheritsHelper(); | 214 _ensureInheritsHelper(); |
| 201 writer.writeln('\$inherits(${type.jsname}, ${type.parent.jsname});'); | 215 writer.writeln('\$inherits(${type.jsname}, ${type.parent.jsname});'); |
| 202 } | 216 } |
| 203 } | 217 } |
| 204 } | 218 } |
| 205 | 219 |
| 206 // Concrete types (like List<String>) will have this already defined on | 220 // Concrete types (like List<String>) will have this already defined on |
| 207 // their prototype from the generic type (like List) | 221 // their prototype from the generic type (like List) |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 271 child.prototype.__proto__ = parent.prototype; | 285 child.prototype.__proto__ = parent.prototype; |
| 272 } else { | 286 } else { |
| 273 function tmp() {}; | 287 function tmp() {}; |
| 274 tmp.prototype = parent.prototype; | 288 tmp.prototype = parent.prototype; |
| 275 child.prototype = new tmp(); | 289 child.prototype = new tmp(); |
| 276 child.prototype.constructor = child; | 290 child.prototype.constructor = child; |
| 277 } | 291 } |
| 278 }"""); | 292 }"""); |
| 279 } | 293 } |
| 280 | 294 |
| 295 /** | |
| 296 * Generates the $inheritsMembers function when it's first used. | |
| 297 * This is used to mix in specialized generic members from the base class. | |
| 298 */ | |
| 299 _ensureInheritMembersHelper() { | |
| 300 if (_mixins != null) return; | |
| 301 _mixins = new CodeWriter(); | |
| 302 _mixins.comment('// ********** Generic Type Inheritance **************'); | |
| 303 _mixins.writeln(@""" | |
| 304 /** Implements extends for generic types. */ | |
| 305 function $inheritsMembers(child, parent) { | |
| 306 child = child.prototype; | |
| 307 parent = parent.prototype; | |
| 308 Object.getOwnPropertyNames(parent).forEach(function(name) { | |
|
Jennifer Messerly
2011/11/18 18:51:29
Not sure if it makes sense to do this on the JS si
| |
| 309 if (typeof(child[name]) == 'undefined') child[name] = parent[name]; | |
| 310 }); | |
| 311 }"""); | |
| 312 } | |
| 313 | |
| 281 _writeDynamicStubs(Type type) { | 314 _writeDynamicStubs(Type type) { |
| 282 if (type.varStubs != null) { | 315 if (type.varStubs != null) { |
| 283 for (var stub in orderValuesByKeys(type.varStubs)) { | 316 for (var stub in orderValuesByKeys(type.varStubs)) { |
| 284 stub.generate(writer); | 317 stub.generate(writer); |
| 285 } | 318 } |
| 286 } | 319 } |
| 287 } | 320 } |
| 288 | 321 |
| 289 _writeStaticField(FieldMember field) { | 322 _writeStaticField(FieldMember field) { |
| 290 // Final static fields must be constants which will be folded and inlined. | 323 // Final static fields must be constants which will be folded and inlined. |
| (...skipping 489 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 780 var optional = "['" + Strings.join(optNames, "', '") + "']"; | 813 var optional = "['" + Strings.join(optNames, "', '") + "']"; |
| 781 defWriter.writeln('${start}${meth.jsname}.\$optional = $optional'); | 814 defWriter.writeln('${start}${meth.jsname}.\$optional = $optional'); |
| 782 } | 815 } |
| 783 } | 816 } |
| 784 } | 817 } |
| 785 } | 818 } |
| 786 | 819 |
| 787 writeBody() { | 820 writeBody() { |
| 788 var initializers = null; | 821 var initializers = null; |
| 789 var initializedFields = null; // to check that final fields are initialized | 822 var initializedFields = null; // to check that final fields are initialized |
| 823 var allMembers = null; | |
| 790 if (method.isConstructor) { | 824 if (method.isConstructor) { |
| 791 initializers = []; | 825 initializers = []; |
| 792 initializedFields = new Set(); | 826 initializedFields = new Set(); |
| 793 for (var f in world.gen._orderValues(method.declaringType.getAllMembers()) ) { | 827 allMembers = world.gen._orderValues(method.declaringType.getAllMembers()); |
| 794 if (f is FieldMember && !f.isStatic) { | 828 for (var f in allMembers) { |
| 829 if (f.isField && !f.isStatic) { | |
|
Jennifer Messerly
2011/11/18 18:51:29
these can be ConcreteMembers too
| |
| 795 var cv = f.computeValue(); | 830 var cv = f.computeValue(); |
| 796 if (cv != null) { | 831 if (cv != null) { |
| 797 initializers.add('this.${f.jsname} = ${cv.code}'); | 832 initializers.add('this.${f.jsname} = ${cv.code}'); |
| 798 initializedFields.add(f.name); | 833 initializedFields.add(f.name); |
| 799 } | 834 } |
| 800 } | 835 } |
| 801 } | 836 } |
| 802 } | 837 } |
| 803 | 838 |
| 804 // Collects parameters for writing signature in the future. | 839 // Collects parameters for writing signature in the future. |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 909 world.error( | 944 world.error( |
| 910 'no initialization allowed on redirecting constructors', | 945 'no initialization allowed on redirecting constructors', |
| 911 init.span); | 946 init.span); |
| 912 } | 947 } |
| 913 initializedFields = null; | 948 initializedFields = null; |
| 914 } | 949 } |
| 915 } | 950 } |
| 916 | 951 |
| 917 // check that initialization was correct | 952 // check that initialization was correct |
| 918 if (initializedFields != null) { | 953 if (initializedFields != null) { |
| 919 for (var name in method.declaringType.members.getKeys()) { | 954 for (var member in allMembers) { |
|
Jennifer Messerly
2011/11/18 18:51:29
this fixes an inconsistency: the loop above was us
| |
| 920 var member = method.declaringType.members[name]; | 955 if (member.isField && member.isFinal && !member.isStatic |
| 921 if (member is FieldMember && member.isFinal && !member.isStatic | 956 && !initializedFields.contains(member.name)) { |
| 922 && !initializedFields.contains(name)) { | 957 world.error('Field "${member.name}" is final and was not initialized', |
| 923 world.error('Field "${name}" is final and was not initialized', | |
| 924 method.definition.span); | 958 method.definition.span); |
| 925 } | 959 } |
| 926 } | 960 } |
| 927 } | 961 } |
| 928 | 962 |
| 929 visitStatementsInBlock(body); | 963 visitStatementsInBlock(body); |
| 930 } | 964 } |
| 931 | 965 |
| 932 /** | 966 /** |
| 933 * Calls another constructor (super, super.name, this, this.name). Returns | 967 * Calls another constructor (super, super.name, this, this.name). Returns |
| (...skipping 1350 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2284 result.add(new Value(world.varType, '\$$i', null, /*needsTemp:*/false)); | 2318 result.add(new Value(world.varType, '\$$i', null, /*needsTemp:*/false)); |
| 2285 } | 2319 } |
| 2286 for (int i = bareCount; i < length; i++) { | 2320 for (int i = bareCount; i < length; i++) { |
| 2287 var name = getName(i); | 2321 var name = getName(i); |
| 2288 if (name == null) name = '\$$i'; | 2322 if (name == null) name = '\$$i'; |
| 2289 result.add(new Value(world.varType, name, null, /*needsTemp:*/false)); | 2323 result.add(new Value(world.varType, name, null, /*needsTemp:*/false)); |
| 2290 } | 2324 } |
| 2291 return new Arguments(nodes, result); | 2325 return new Arguments(nodes, result); |
| 2292 } | 2326 } |
| 2293 } | 2327 } |
| OLD | NEW |