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 1238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1249 // Define the constructor with a name so that Object.toString can | 1249 // Define the constructor with a name so that Object.toString can |
1250 // find the class name of the closure class. | 1250 // find the class name of the closure class. |
1251 emitBoundClosureClassHeader( | 1251 emitBoundClosureClassHeader( |
1252 mangledName, superName, extraArgWithoutComma, boundClosureBuffer); | 1252 mangledName, superName, extraArgWithoutComma, boundClosureBuffer); |
1253 // Now add the methods on the closure class. The instance method does not | 1253 // Now add the methods on the closure class. The instance method does not |
1254 // have the correct name. Since [addParameterStubs] use the name to create | 1254 // have the correct name. Since [addParameterStubs] use the name to create |
1255 // its stubs we simply create a fake element with the correct name. | 1255 // its stubs we simply create a fake element with the correct name. |
1256 // Note: the callElement will not have any enclosingElement. | 1256 // Note: the callElement will not have any enclosingElement. |
1257 FunctionElement callElement = | 1257 FunctionElement callElement = |
1258 new ClosureInvocationElement(Namer.CLOSURE_INVOCATION_NAME, member); | 1258 new ClosureInvocationElement(Namer.CLOSURE_INVOCATION_NAME, member); |
1259 | 1259 |
1260 String invocationName = namer.instanceMethodName(callElement); | 1260 String invocationName = namer.instanceMethodName(callElement); |
1261 List<String> arguments = new List<String>(parameterCount); | 1261 List<String> arguments = new List<String>(parameterCount); |
1262 for (int i = 0; i < parameterCount; i++) { | 1262 for (int i = 0; i < parameterCount; i++) { |
1263 arguments[i] = "p$i"; | 1263 arguments[i] = "p$i"; |
1264 } | 1264 } |
1265 String joinedArgs = Strings.join(arguments, ", "); | 1265 String joinedArgs = Strings.join(arguments, ", "); |
1266 boundClosureBuffer.add( | 1266 boundClosureBuffer.add( |
1267 "$invocationName: function($joinedArgs) {"); | 1267 "$invocationName: function($joinedArgs) {"); |
1268 String callArgs = hasExtraArgument | 1268 String callArgs = hasExtraArgument |
1269 ? joinedArgs.isEmpty | 1269 ? joinedArgs.isEmpty |
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1449 } | 1449 } |
1450 } | 1450 } |
1451 | 1451 |
1452 void emitNoSuchMethodHandlers(DefineMemberFunction defineInstanceMember) { | 1452 void emitNoSuchMethodHandlers(DefineMemberFunction defineInstanceMember) { |
1453 // Do not generate no such method handlers if there is no class. | 1453 // Do not generate no such method handlers if there is no class. |
1454 if (compiler.codegenWorld.instantiatedClasses.isEmpty) return; | 1454 if (compiler.codegenWorld.instantiatedClasses.isEmpty) return; |
1455 | 1455 |
1456 String noSuchMethodName = namer.publicInstanceMethodNameByArity( | 1456 String noSuchMethodName = namer.publicInstanceMethodNameByArity( |
1457 Compiler.NO_SUCH_METHOD, Compiler.NO_SUCH_METHOD_ARG_COUNT); | 1457 Compiler.NO_SUCH_METHOD, Compiler.NO_SUCH_METHOD_ARG_COUNT); |
1458 | 1458 |
| 1459 Element createInvocationMirrorElement = |
| 1460 compiler.findHelper(const SourceString("createInvocationMirror")); |
| 1461 String createInvocationMirrorName = |
| 1462 namer.getName(createInvocationMirrorElement); |
| 1463 |
1459 // Keep track of the JavaScript names we've already added so we | 1464 // Keep track of the JavaScript names we've already added so we |
1460 // do not introduce duplicates (bad for code size). | 1465 // do not introduce duplicates (bad for code size). |
1461 Set<String> addedJsNames = new Set<String>(); | 1466 Set<String> addedJsNames = new Set<String>(); |
1462 | 1467 |
1463 // Keep track of the noSuchMethod holders for each possible | 1468 // Keep track of the noSuchMethod holders for each possible |
1464 // receiver type. | 1469 // receiver type. |
1465 Map<ClassElement, Set<ClassElement>> noSuchMethodHolders = | 1470 Map<ClassElement, Set<ClassElement>> noSuchMethodHolders = |
1466 new Map<ClassElement, Set<ClassElement>>(); | 1471 new Map<ClassElement, Set<ClassElement>>(); |
1467 Set<ClassElement> noSuchMethodHoldersFor(DartType type) { | 1472 Set<ClassElement> noSuchMethodHoldersFor(DartType type) { |
1468 ClassElement element = type.element; | 1473 ClassElement element = type.element; |
1469 Set<ClassElement> result = noSuchMethodHolders[element]; | 1474 Set<ClassElement> result = noSuchMethodHolders[element]; |
1470 if (result == null) { | 1475 if (result == null) { |
1471 // For now, we check the entire world to see if an object of | 1476 // For now, we check the entire world to see if an object of |
1472 // the given type may have a user-defined noSuchMethod | 1477 // the given type may have a user-defined noSuchMethod |
1473 // implementation. We could do better by only looking at | 1478 // implementation. We could do better by only looking at |
1474 // instantiated (or otherwise needed) classes. | 1479 // instantiated (or otherwise needed) classes. |
1475 result = compiler.world.findNoSuchMethodHolders(type); | 1480 result = compiler.world.findNoSuchMethodHolders(type); |
1476 noSuchMethodHolders[element] = result; | 1481 noSuchMethodHolders[element] = result; |
1477 } | 1482 } |
1478 return result; | 1483 return result; |
1479 } | 1484 } |
1480 | 1485 |
1481 CodeBuffer generateMethod(String methodName, Selector selector) { | 1486 CodeBuffer generateMethod(String jsName, Selector selector) { |
1482 // Values match JSInvocationMirror in js-helper library. | 1487 // Values match JSInvocationMirror in js-helper library. |
1483 const int METHOD = 0; | 1488 const int METHOD = 0; |
1484 const int GETTER = 1; | 1489 const int GETTER = 1; |
1485 const int SETTER = 2; | 1490 const int SETTER = 2; |
1486 int type = METHOD; | 1491 int type = METHOD; |
1487 if (selector.isGetter()) { | 1492 if (selector.isGetter()) { |
1488 type = GETTER; | 1493 type = GETTER; |
1489 assert(methodName.startsWith("get:")); | |
1490 methodName = methodName.substring(4); | |
1491 } else if (selector.isSetter()) { | 1494 } else if (selector.isSetter()) { |
1492 type = SETTER; | 1495 type = SETTER; |
1493 assert(methodName.startsWith("set:")); | |
1494 methodName = "${methodName.substring(4)}="; | |
1495 } | 1496 } |
| 1497 String methodName = selector.invocationMirrorMemberName; |
1496 CodeBuffer args = new CodeBuffer(); | 1498 CodeBuffer args = new CodeBuffer(); |
1497 for (int i = 0; i < selector.argumentCount; i++) { | 1499 for (int i = 0; i < selector.argumentCount; i++) { |
1498 if (i != 0) args.add(', '); | 1500 if (i != 0) args.add(', '); |
1499 args.add('\$$i'); | 1501 args.add('\$$i'); |
1500 } | 1502 } |
1501 CodeBuffer argNames = new CodeBuffer(); | 1503 CodeBuffer argNames = new CodeBuffer(); |
1502 List<SourceString> names = selector.getOrderedNamedArguments(); | 1504 List<SourceString> names = selector.getOrderedNamedArguments(); |
1503 for (int i = 0; i < names.length; i++) { | 1505 for (int i = 0; i < names.length; i++) { |
1504 if (i != 0) argNames.add(', '); | 1506 if (i != 0) argNames.add(', '); |
1505 argNames.add('"'); | 1507 argNames.add('"'); |
1506 argNames.add(names[i].slowToString()); | 1508 argNames.add(names[i].slowToString()); |
1507 argNames.add('"'); | 1509 argNames.add('"'); |
1508 } | 1510 } |
1509 String internalName = namer.instanceMethodInvocationName( | |
1510 selector.library, new SourceString(methodName), selector); | |
1511 CodeBuffer buffer = new CodeBuffer(); | 1511 CodeBuffer buffer = new CodeBuffer(); |
1512 buffer.add('function($args) {\n'); | 1512 buffer.add('function($args) {\n'); |
1513 buffer.add(' return this.$noSuchMethodName(' | 1513 buffer.add(' return this.$noSuchMethodName(' |
1514 '\$.createInvocationMirror("$methodName", "$internalName",' | 1514 '\$.$createInvocationMirrorName("$methodName", "$jsName",' |
1515 ' $type, [$args], [$argNames]));\n'); | 1515 ' $type, [$args], [$argNames]));\n'); |
1516 buffer.add(' }'); | 1516 buffer.add(' }'); |
1517 return buffer; | 1517 return buffer; |
1518 } | 1518 } |
1519 | 1519 |
1520 void addNoSuchMethodHandlers(SourceString ignore, Set<Selector> selectors) { | 1520 void addNoSuchMethodHandlers(SourceString ignore, Set<Selector> selectors) { |
1521 // Cache the object class and type. | 1521 // Cache the object class and type. |
1522 ClassElement objectClass = compiler.objectClass; | 1522 ClassElement objectClass = compiler.objectClass; |
1523 DartType objectType = objectClass.computeType(compiler); | 1523 DartType objectType = objectClass.computeType(compiler); |
1524 | 1524 |
1525 for (Selector selector in selectors) { | 1525 for (Selector selector in selectors) { |
1526 // Introduce a helper function that determines if the given | 1526 // Introduce a helper function that determines if the given |
1527 // class has a member that matches the current name and | 1527 // class has a member that matches the current name and |
1528 // selector (grabbed from the scope). | 1528 // selector (grabbed from the scope). |
1529 bool hasMatchingMember(ClassElement holder) { | 1529 bool hasMatchingMember(ClassElement holder) { |
1530 Element element = holder.lookupMember(selector.name); | 1530 Element element = holder.lookupMember(selector.name); |
1531 if (element == null) return false; | 1531 if (element == null) return false; |
1532 | 1532 |
1533 // TODO(kasperl): Consider folding this logic into the | 1533 // TODO(kasperl): Consider folding this logic into the |
1534 // Selector.applies() method. | 1534 // Selector.applies() method. |
1535 if (element is AbstractFieldElement) { | 1535 if (element is AbstractFieldElement) { |
1536 AbstractFieldElement field = element; | 1536 AbstractFieldElement field = element; |
1537 if (identical(selector.kind, SelectorKind.GETTER)) { | 1537 if (selector.isGetter()) { |
1538 return field.getter != null; | 1538 return field.getter != null; |
1539 } else if (identical(selector.kind, SelectorKind.SETTER)) { | 1539 } else if (selector.isSetter()) { |
1540 return field.setter != null; | 1540 return field.setter != null; |
1541 } else { | 1541 } else { |
1542 return false; | 1542 return false; |
1543 } | 1543 } |
| 1544 } else if (element is VariableElement) { |
| 1545 if (selector.isSetter() && element.modifiers.isFinalOrConst()) { |
| 1546 return false; |
| 1547 } |
1544 } | 1548 } |
1545 return selector.applies(element, compiler); | 1549 return selector.applies(element, compiler); |
1546 } | 1550 } |
1547 | 1551 |
1548 // If the selector is typed, we check to see if that type may | 1552 // If the selector is typed, we check to see if that type may |
1549 // have a user-defined noSuchMethod implementation. If not, we | 1553 // have a user-defined noSuchMethod implementation. If not, we |
1550 // skip the selector altogether. | 1554 // skip the selector altogether. |
1551 DartType receiverType = objectType; | 1555 DartType receiverType = objectType; |
1552 ClassElement receiverClass = objectClass; | 1556 ClassElement receiverClass = objectClass; |
1553 if (selector is TypedSelector) { | 1557 if (selector is TypedSelector) { |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1593 // | 1597 // |
1594 // If we're calling bar on an object of type D, we don't need | 1598 // If we're calling bar on an object of type D, we don't need |
1595 // the handler either because all objects of type D implement | 1599 // the handler either because all objects of type D implement |
1596 // bar through inheritance. | 1600 // bar through inheritance. |
1597 // | 1601 // |
1598 // If we're calling bar on an object of type A we do need the | 1602 // If we're calling bar on an object of type A we do need the |
1599 // handler because we may have to call B.noSuchMethod since B | 1603 // handler because we may have to call B.noSuchMethod since B |
1600 // does not implement bar. | 1604 // does not implement bar. |
1601 Set<ClassElement> holders = noSuchMethodHoldersFor(receiverType); | 1605 Set<ClassElement> holders = noSuchMethodHoldersFor(receiverType); |
1602 if (holders.every(hasMatchingMember)) continue; | 1606 if (holders.every(hasMatchingMember)) continue; |
1603 | 1607 String jsName = namer.invocationMirrorInternalName(selector); |
1604 String jsName = null; | |
1605 String methodName = null; | |
1606 String nameString = selector.name.slowToString(); | |
1607 if (selector.isGetter()) { | |
1608 jsName = namer.getterName(selector.library, selector.name); | |
1609 methodName = 'get:$nameString'; | |
1610 } else if (selector.isSetter()) { | |
1611 jsName = namer.setterName(selector.library, selector.name); | |
1612 methodName = 'set:$nameString'; | |
1613 } else if (selector.isCall()) { | |
1614 jsName = namer.instanceMethodInvocationName( | |
1615 selector.library, selector.name, selector); | |
1616 methodName = nameString; | |
1617 } else { | |
1618 // We simply ignore selectors that do not need | |
1619 // noSuchMethod handlers. | |
1620 continue; | |
1621 } | |
1622 | |
1623 if (!addedJsNames.contains(jsName)) { | 1608 if (!addedJsNames.contains(jsName)) { |
1624 CodeBuffer jsCode = generateMethod(methodName, selector); | 1609 CodeBuffer jsCode = generateMethod(jsName, selector); |
1625 defineInstanceMember(jsName, jsCode); | 1610 defineInstanceMember(jsName, jsCode); |
1626 addedJsNames.add(jsName); | 1611 addedJsNames.add(jsName); |
1627 } | 1612 } |
1628 } | 1613 } |
1629 } | 1614 } |
1630 | 1615 |
1631 compiler.codegenWorld.invokedNames.forEach(addNoSuchMethodHandlers); | 1616 compiler.codegenWorld.invokedNames.forEach(addNoSuchMethodHandlers); |
1632 compiler.codegenWorld.invokedGetters.forEach(addNoSuchMethodHandlers); | 1617 compiler.codegenWorld.invokedGetters.forEach(addNoSuchMethodHandlers); |
1633 compiler.codegenWorld.invokedSetters.forEach(addNoSuchMethodHandlers); | 1618 compiler.codegenWorld.invokedSetters.forEach(addNoSuchMethodHandlers); |
1634 } | 1619 } |
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1832 const String HOOKS_API_USAGE = """ | 1817 const String HOOKS_API_USAGE = """ |
1833 // Generated by dart2js, the Dart to JavaScript compiler. | 1818 // Generated by dart2js, the Dart to JavaScript compiler. |
1834 // The code supports the following hooks: | 1819 // The code supports the following hooks: |
1835 // dartPrint(message) - if this function is defined it is called | 1820 // dartPrint(message) - if this function is defined it is called |
1836 // instead of the Dart [print] method. | 1821 // instead of the Dart [print] method. |
1837 // dartMainRunner(main) - if this function is defined, the Dart [main] | 1822 // dartMainRunner(main) - if this function is defined, the Dart [main] |
1838 // method will not be invoked directly. | 1823 // method will not be invoked directly. |
1839 // Instead, a closure that will invoke [main] is | 1824 // Instead, a closure that will invoke [main] is |
1840 // passed to [dartMainRunner]. | 1825 // passed to [dartMainRunner]. |
1841 """; | 1826 """; |
OLD | NEW |