| 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 1153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1164 ClassBuilder builder) { | 1164 ClassBuilder builder) { |
| 1165 assert(invariant(classElement, classElement.isDeclaration)); | 1165 assert(invariant(classElement, classElement.isDeclaration)); |
| 1166 | 1166 |
| 1167 void visitMember(ClassElement enclosing, Element member) { | 1167 void visitMember(ClassElement enclosing, Element member) { |
| 1168 assert(invariant(classElement, member.isDeclaration)); | 1168 assert(invariant(classElement, member.isDeclaration)); |
| 1169 if (member.isInstanceMember()) { | 1169 if (member.isInstanceMember()) { |
| 1170 addInstanceMember(member, builder); | 1170 addInstanceMember(member, builder); |
| 1171 } | 1171 } |
| 1172 } | 1172 } |
| 1173 | 1173 |
| 1174 // TODO(kasperl): We should make sure to only emit one version of | |
| 1175 // overridden methods. Right now, we rely on the ordering so the | |
| 1176 // methods pulled in from mixins are replaced with the members | |
| 1177 // from the class definition. | |
| 1178 | |
| 1179 // If the class is a native class, we have to add the instance | |
| 1180 // members defined in the non-native mixin applications used by | |
| 1181 // the class. | |
| 1182 visitNativeMixins(classElement, (MixinApplicationElement mixin) { | |
| 1183 mixin.forEachMember( | |
| 1184 visitMember, | |
| 1185 includeBackendMembers: true, | |
| 1186 includeSuperMembers: false); | |
| 1187 }); | |
| 1188 | |
| 1189 classElement.implementation.forEachMember( | 1174 classElement.implementation.forEachMember( |
| 1190 visitMember, | 1175 visitMember, |
| 1191 includeBackendMembers: true, | 1176 includeBackendMembers: true, |
| 1192 includeSuperMembers: false); | 1177 includeSuperMembers: false); |
| 1193 | 1178 |
| 1194 void generateIsTest(Element other) { | 1179 void generateIsTest(Element other) { |
| 1195 jsAst.Expression code; | 1180 jsAst.Expression code; |
| 1196 if (other == compiler.objectClass && other != classElement) { | 1181 if (other == compiler.objectClass && other != classElement) { |
| 1197 // Avoid emitting [:$isObject:] on all classes but [Object]. | 1182 // Avoid emitting [:$isObject:] on all classes but [Object]. |
| 1198 return; | 1183 return; |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1289 for (ClassElement check in typeChecks[cls]) { | 1274 for (ClassElement check in typeChecks[cls]) { |
| 1290 buffer.write('$holder.${namer.operatorIs(check)}$_=${_}true$N'); | 1275 buffer.write('$holder.${namer.operatorIs(check)}$_=${_}true$N'); |
| 1291 String body = rti.getSupertypeSubstitution(cls, check); | 1276 String body = rti.getSupertypeSubstitution(cls, check); |
| 1292 if (body != null) { | 1277 if (body != null) { |
| 1293 buffer.write('$holder.${namer.substitutionName(check)}$_=${_}$body$N')
; | 1278 buffer.write('$holder.${namer.substitutionName(check)}$_=${_}$body$N')
; |
| 1294 } | 1279 } |
| 1295 }; | 1280 }; |
| 1296 } | 1281 } |
| 1297 } | 1282 } |
| 1298 | 1283 |
| 1299 void visitNativeMixins(ClassElement classElement, | |
| 1300 void visit(MixinApplicationElement mixinApplication)) { | |
| 1301 if (!classElement.isNative()) return; | |
| 1302 // Use recursion to make sure to visit the superclasses before the | |
| 1303 // subclasses. Once we start keeping track of the emitted fields | |
| 1304 // and members, we're going to want to visit these in the other | |
| 1305 // order so we get the most specialized definition first. | |
| 1306 void recurse(ClassElement cls) { | |
| 1307 if (cls == null || !cls.isMixinApplication) return; | |
| 1308 recurse(cls.superclass); | |
| 1309 assert(!cls.isNative()); | |
| 1310 visit(cls); | |
| 1311 } | |
| 1312 recurse(classElement.superclass); | |
| 1313 } | |
| 1314 | |
| 1315 /** | 1284 /** |
| 1316 * Documentation wanted -- johnniwinther | 1285 * Documentation wanted -- johnniwinther |
| 1317 * | 1286 * |
| 1318 * Invariant: [classElement] must be a declaration element. | 1287 * Invariant: [classElement] must be a declaration element. |
| 1319 */ | 1288 */ |
| 1320 void visitClassFields(ClassElement classElement, | 1289 void visitClassFields(ClassElement classElement, |
| 1321 void addField(Element member, | 1290 void addField(Element member, |
| 1322 String name, | 1291 String name, |
| 1323 String accessorName, | 1292 String accessorName, |
| 1324 bool needsGetter, | 1293 bool needsGetter, |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1382 needsSetter, | 1351 needsSetter, |
| 1383 needsCheckedSetter); | 1352 needsCheckedSetter); |
| 1384 } | 1353 } |
| 1385 } | 1354 } |
| 1386 | 1355 |
| 1387 // TODO(kasperl): We should make sure to only emit one version of | 1356 // TODO(kasperl): We should make sure to only emit one version of |
| 1388 // overridden fields. Right now, we rely on the ordering so the | 1357 // overridden fields. Right now, we rely on the ordering so the |
| 1389 // fields pulled in from mixins are replaced with the fields from | 1358 // fields pulled in from mixins are replaced with the fields from |
| 1390 // the class definition. | 1359 // the class definition. |
| 1391 | 1360 |
| 1392 // If the class is a native class, we have to add the fields | |
| 1393 // defined in the non-native mixin applications used by the class. | |
| 1394 visitNativeMixins(classElement, (MixinApplicationElement mixin) { | |
| 1395 mixin.forEachInstanceField( | |
| 1396 visitField, | |
| 1397 includeBackendMembers: true, | |
| 1398 includeSuperMembers: false); | |
| 1399 }); | |
| 1400 | |
| 1401 // If a class is not instantiated then we add the field just so we can | 1361 // If a class is not instantiated then we add the field just so we can |
| 1402 // generate the field getter/setter dynamically. Since this is only | 1362 // generate the field getter/setter dynamically. Since this is only |
| 1403 // allowed on fields that are in [classElement] we don't need to visit | 1363 // allowed on fields that are in [classElement] we don't need to visit |
| 1404 // superclasses for non-instantiated classes. | 1364 // superclasses for non-instantiated classes. |
| 1405 classElement.implementation.forEachInstanceField( | 1365 classElement.implementation.forEachInstanceField( |
| 1406 visitField, | 1366 visitField, |
| 1407 includeBackendMembers: true, | 1367 includeBackendMembers: true, |
| 1408 includeSuperMembers: isInstantiated && !classElement.isNative()); | 1368 includeSuperMembers: isInstantiated); |
| 1409 } | 1369 } |
| 1410 | 1370 |
| 1411 void generateGetter(Element member, String fieldName, String accessorName, | 1371 void generateGetter(Element member, String fieldName, String accessorName, |
| 1412 ClassBuilder builder) { | 1372 ClassBuilder builder) { |
| 1413 String getterName = namer.getterNameFromAccessorName(accessorName); | 1373 String getterName = namer.getterNameFromAccessorName(accessorName); |
| 1414 String receiver = backend.isInterceptorClass(member.getEnclosingClass()) | 1374 String receiver = backend.isInterceptorClass(member.getEnclosingClass()) |
| 1415 ? 'receiver' : 'this'; | 1375 ? 'receiver' : 'this'; |
| 1416 List<String> args = backend.isInterceptedMethod(member) | 1376 List<String> args = backend.isInterceptedMethod(member) |
| 1417 ? ['receiver'] | 1377 ? ['receiver'] |
| 1418 : []; | 1378 : []; |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1583 * | 1543 * |
| 1584 * Invariant: [classElement] must be a declaration element. | 1544 * Invariant: [classElement] must be a declaration element. |
| 1585 */ | 1545 */ |
| 1586 void generateClass(ClassElement classElement, CodeBuffer buffer) { | 1546 void generateClass(ClassElement classElement, CodeBuffer buffer) { |
| 1587 assert(invariant(classElement, classElement.isDeclaration)); | 1547 assert(invariant(classElement, classElement.isDeclaration)); |
| 1588 assert(invariant(classElement, !classElement.isNative())); | 1548 assert(invariant(classElement, !classElement.isNative())); |
| 1589 | 1549 |
| 1590 needsDefineClass = true; | 1550 needsDefineClass = true; |
| 1591 String className = namer.getName(classElement); | 1551 String className = namer.getName(classElement); |
| 1592 | 1552 |
| 1593 // Find the first non-native superclass. | |
| 1594 ClassElement superclass = classElement.superclass; | 1553 ClassElement superclass = classElement.superclass; |
| 1595 while (superclass != null && superclass.isNative()) { | |
| 1596 superclass = superclass.superclass; | |
| 1597 } | |
| 1598 | |
| 1599 String superName = ""; | 1554 String superName = ""; |
| 1600 if (superclass != null) { | 1555 if (superclass != null) { |
| 1601 superName = namer.getName(superclass); | 1556 superName = namer.getName(superclass); |
| 1602 } | 1557 } |
| 1603 | 1558 |
| 1604 ClassBuilder builder = new ClassBuilder(); | 1559 ClassBuilder builder = new ClassBuilder(); |
| 1605 | 1560 |
| 1606 emitClassConstructor(classElement, builder); | 1561 emitClassConstructor(classElement, builder); |
| 1607 emitSuper(superName, builder); | 1562 emitSuper(superName, builder); |
| 1608 emitClassFields(classElement, builder, | 1563 emitClassFields(classElement, builder, |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1718 emitSubstitution, | 1673 emitSubstitution, |
| 1719 generated); | 1674 generated); |
| 1720 getTypedefChecksOn(call.computeType(compiler)).forEach(emitIsTest); | 1675 getTypedefChecksOn(call.computeType(compiler)).forEach(emitIsTest); |
| 1721 } | 1676 } |
| 1722 } | 1677 } |
| 1723 | 1678 |
| 1724 for (DartType interfaceType in cls.interfaces) { | 1679 for (DartType interfaceType in cls.interfaces) { |
| 1725 generateInterfacesIsTests(interfaceType.element, emitIsTest, | 1680 generateInterfacesIsTests(interfaceType.element, emitIsTest, |
| 1726 emitSubstitution, generated); | 1681 emitSubstitution, generated); |
| 1727 } | 1682 } |
| 1728 | |
| 1729 // For native classes, we also have to run through their mixin | |
| 1730 // applications and make sure we deal with 'is' tests correctly | |
| 1731 // for those. | |
| 1732 visitNativeMixins(cls, (MixinApplicationElement mixin) { | |
| 1733 for (DartType interfaceType in mixin.interfaces) { | |
| 1734 ClassElement interfaceElement = interfaceType.element; | |
| 1735 generateInterfacesIsTests(interfaceType.element, emitIsTest, | |
| 1736 emitSubstitution, generated); | |
| 1737 } | |
| 1738 }); | |
| 1739 } | 1683 } |
| 1740 | 1684 |
| 1741 /** | 1685 /** |
| 1742 * Generate "is tests" where [cls] is being implemented. | 1686 * Generate "is tests" where [cls] is being implemented. |
| 1743 */ | 1687 */ |
| 1744 void generateInterfacesIsTests(ClassElement cls, | 1688 void generateInterfacesIsTests(ClassElement cls, |
| 1745 void emitIsTest(ClassElement element), | 1689 void emitIsTest(ClassElement element), |
| 1746 void emitSubstitution(ClassElement element), | 1690 void emitSubstitution(ClassElement element), |
| 1747 Set<Element> alreadyGenerated) { | 1691 Set<Element> alreadyGenerated) { |
| 1748 void tryEmitTest(ClassElement check) { | 1692 void tryEmitTest(ClassElement check) { |
| (...skipping 1371 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3120 """; | 3064 """; |
| 3121 const String HOOKS_API_USAGE = """ | 3065 const String HOOKS_API_USAGE = """ |
| 3122 // The code supports the following hooks: | 3066 // The code supports the following hooks: |
| 3123 // dartPrint(message) - if this function is defined it is called | 3067 // dartPrint(message) - if this function is defined it is called |
| 3124 // instead of the Dart [print] method. | 3068 // instead of the Dart [print] method. |
| 3125 // dartMainRunner(main) - if this function is defined, the Dart [main] | 3069 // dartMainRunner(main) - if this function is defined, the Dart [main] |
| 3126 // method will not be invoked directly. | 3070 // method will not be invoked directly. |
| 3127 // Instead, a closure that will invoke [main] is | 3071 // Instead, a closure that will invoke [main] is |
| 3128 // passed to [dartMainRunner]. | 3072 // passed to [dartMainRunner]. |
| 3129 """; | 3073 """; |
| OLD | NEW |