Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(287)

Side by Side Diff: sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart

Issue 11447008: invocation_mirror_test passed (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: co19 status updated Created 8 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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 """;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698