| 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 /** | 5 /** |
| 6 * A function element that represents a closure call. The signature is copied | 6 * A function element that represents a closure call. The signature is copied |
| 7 * from the given element. | 7 * from the given element. |
| 8 */ | 8 */ |
| 9 class ClosureInvocationElement extends FunctionElement { | 9 class ClosureInvocationElement extends FunctionElement { |
| 10 ClosureInvocationElement(SourceString name, | 10 ClosureInvocationElement(SourceString name, |
| (...skipping 480 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 491 && compiler.codegenWorld.hasInvokedSetter(member, compiler); | 491 && compiler.codegenWorld.hasInvokedSetter(member, compiler); |
| 492 } | 492 } |
| 493 | 493 |
| 494 String compiledFieldName(Element member) { | 494 String compiledFieldName(Element member) { |
| 495 assert(member.isField()); | 495 assert(member.isField()); |
| 496 return member.isNative() | 496 return member.isNative() |
| 497 ? member.name.slowToString() | 497 ? member.name.slowToString() |
| 498 : namer.getName(member); | 498 : namer.getName(member); |
| 499 } | 499 } |
| 500 | 500 |
| 501 /** |
| 502 * Documentation wanted -- johnniwinther |
| 503 * |
| 504 * Invariant: [member] must be a declaration element. |
| 505 */ |
| 501 void addInstanceMember(Element member, | 506 void addInstanceMember(Element member, |
| 502 DefineMemberFunction defineInstanceMember) { | 507 DefineMemberFunction defineInstanceMember) { |
| 508 assert(invariant(member, member.isDeclaration)); |
| 503 // TODO(floitsch): we don't need to deal with members of | 509 // TODO(floitsch): we don't need to deal with members of |
| 504 // uninstantiated classes, that have been overwritten by subclasses. | 510 // uninstantiated classes, that have been overwritten by subclasses. |
| 505 | 511 |
| 506 if (member.isFunction() | 512 if (member.isFunction() |
| 507 || member.isGenerativeConstructorBody() | 513 || member.isGenerativeConstructorBody() |
| 508 || member.isGetter() | 514 || member.isGetter() |
| 509 || member.isSetter()) { | 515 || member.isSetter()) { |
| 510 if (member.modifiers !== null && member.modifiers.isAbstract()) return; | 516 if (member.modifiers !== null && member.modifiers.isAbstract()) return; |
| 511 CodeBuffer codeBuffer = compiler.codegenWorld.generatedCode[member]; | 517 CodeBuffer codeBuffer = compiler.codegenWorld.generatedCode[member]; |
| 512 if (codeBuffer == null) return; | 518 if (codeBuffer == null) return; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 537 } else { | 543 } else { |
| 538 SourceString helper = compiler.backend.getCheckedModeHelper(type); | 544 SourceString helper = compiler.backend.getCheckedModeHelper(type); |
| 539 Element helperElement = compiler.findHelper(helper); | 545 Element helperElement = compiler.findHelper(helper); |
| 540 String helperName = namer.isolateAccess(helperElement); | 546 String helperName = namer.isolateAccess(helperElement); |
| 541 String additionalArgument = namer.operatorIs(type.element); | 547 String additionalArgument = namer.operatorIs(type.element); |
| 542 return " set\$$fieldName: function(v) { " | 548 return " set\$$fieldName: function(v) { " |
| 543 "this.$fieldName = $helperName(v, '$additionalArgument'); }"; | 549 "this.$fieldName = $helperName(v, '$additionalArgument'); }"; |
| 544 } | 550 } |
| 545 } | 551 } |
| 546 | 552 |
| 553 /** |
| 554 * Documentation wanted -- johnniwinther |
| 555 * |
| 556 * Invariant: [classElement] must be a declaration element. |
| 557 */ |
| 547 List<String> emitClassFields(ClassElement classElement, CodeBuffer buffer) { | 558 List<String> emitClassFields(ClassElement classElement, CodeBuffer buffer) { |
| 559 assert(invariant(classElement, classElement.isDeclaration)); |
| 548 // If the class is never instantiated we still need to set it up for | 560 // If the class is never instantiated we still need to set it up for |
| 549 // inheritance purposes, but we can simplify its JavaScript constructor. | 561 // inheritance purposes, but we can simplify its JavaScript constructor. |
| 550 bool isInstantiated = | 562 bool isInstantiated = |
| 551 compiler.codegenWorld.instantiatedClasses.contains(classElement); | 563 compiler.codegenWorld.instantiatedClasses.contains(classElement); |
| 552 List<String> checkedSetters = <String>[]; | 564 List<String> checkedSetters = <String>[]; |
| 553 | 565 |
| 554 bool isFirstField = true; | 566 bool isFirstField = true; |
| 555 void addField(ClassElement enclosingClass, Element member) { | 567 void addField(ClassElement enclosingClass, Element member) { |
| 556 assert(!member.isNative()); | 568 assert(!member.isNative()); |
| 569 assert(invariant(classElement, member.isDeclaration)); |
| 557 | 570 |
| 558 LibraryElement library = member.getLibrary(); | 571 LibraryElement library = member.getLibrary(); |
| 559 SourceString name = member.name; | 572 SourceString name = member.name; |
| 560 bool isPrivate = name.isPrivate(); | 573 bool isPrivate = name.isPrivate(); |
| 561 // See if we can dynamically create getters and setters. | 574 // See if we can dynamically create getters and setters. |
| 562 // We can only generate getters and setters for [classElement] since | 575 // We can only generate getters and setters for [classElement] since |
| 563 // the fields of super classes could be overwritten with getters or | 576 // the fields of super classes could be overwritten with getters or |
| 564 // setters. | 577 // setters. |
| 565 bool needsDynamicGetter = false; | 578 bool needsDynamicGetter = false; |
| 566 bool needsDynamicSetter = false; | 579 bool needsDynamicSetter = false; |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 611 // generate the field getter/setter dynamically. Since this is only | 624 // generate the field getter/setter dynamically. Since this is only |
| 612 // allowed on fields that are in [classElement] we don't need to visit | 625 // allowed on fields that are in [classElement] we don't need to visit |
| 613 // superclasses for non-instantiated classes. | 626 // superclasses for non-instantiated classes. |
| 614 classElement.forEachInstanceField( | 627 classElement.forEachInstanceField( |
| 615 addField, | 628 addField, |
| 616 includeBackendMembers: true, | 629 includeBackendMembers: true, |
| 617 includeSuperMembers: isInstantiated && !classElement.isNative()); | 630 includeSuperMembers: isInstantiated && !classElement.isNative()); |
| 618 return checkedSetters; | 631 return checkedSetters; |
| 619 } | 632 } |
| 620 | 633 |
| 634 /** |
| 635 * Documentation wanted -- johnniwinther |
| 636 * |
| 637 * Invariant: [classElement] must be a declaration element. |
| 638 */ |
| 621 void emitInstanceMembers(ClassElement classElement, | 639 void emitInstanceMembers(ClassElement classElement, |
| 622 CodeBuffer buffer, | 640 CodeBuffer buffer, |
| 623 bool needsLeadingComma) { | 641 bool needsLeadingComma) { |
| 642 assert(invariant(classElement, classElement.isDeclaration)); |
| 624 bool needsComma = needsLeadingComma; | 643 bool needsComma = needsLeadingComma; |
| 625 void defineInstanceMember(String name, CodeBuffer memberBuffer) { | 644 void defineInstanceMember(String name, CodeBuffer memberBuffer) { |
| 626 if (needsComma) buffer.add(','); | 645 if (needsComma) buffer.add(','); |
| 627 needsComma = true; | 646 needsComma = true; |
| 628 buffer.add('\n'); | 647 buffer.add('\n'); |
| 629 buffer.add(' $name: '); | 648 buffer.add(' $name: '); |
| 630 buffer.add(memberBuffer); | 649 buffer.add(memberBuffer); |
| 631 } | 650 } |
| 632 | 651 |
| 633 classElement.forEachMember(includeBackendMembers: true, | 652 classElement.forEachMember(includeBackendMembers: true, |
| 634 f: (ClassElement enclosing, Element member) { | 653 f: (ClassElement enclosing, Element member) { |
| 654 assert(invariant(classElement, member.isDeclaration)); |
| 635 if (member.isInstanceMember()) { | 655 if (member.isInstanceMember()) { |
| 636 addInstanceMember(member, defineInstanceMember); | 656 addInstanceMember(member, defineInstanceMember); |
| 637 } | 657 } |
| 638 }); | 658 }); |
| 639 | 659 |
| 640 generateIsTestsOn(classElement, (Element other) { | 660 generateIsTestsOn(classElement, (Element other) { |
| 641 String code; | 661 String code; |
| 642 if (nativeEmitter.requiresNativeIsCheck(other)) { | 662 if (nativeEmitter.requiresNativeIsCheck(other)) { |
| 643 code = 'function() { return true; }'; | 663 code = 'function() { return true; }'; |
| 644 } else { | 664 } else { |
| 645 code = 'true'; | 665 code = 'true'; |
| 646 } | 666 } |
| 647 CodeBuffer typeTestBuffer = new CodeBuffer(); | 667 CodeBuffer typeTestBuffer = new CodeBuffer(); |
| 648 typeTestBuffer.add(code); | 668 typeTestBuffer.add(code); |
| 649 defineInstanceMember(namer.operatorIs(other), typeTestBuffer); | 669 defineInstanceMember(namer.operatorIs(other), typeTestBuffer); |
| 650 }); | 670 }); |
| 651 | 671 |
| 652 if (classElement === compiler.objectClass && compiler.enabledNoSuchMethod) { | 672 if (classElement === compiler.objectClass && compiler.enabledNoSuchMethod) { |
| 653 // Emit the noSuchMethod handlers on the Object prototype now, | 673 // Emit the noSuchMethod handlers on the Object prototype now, |
| 654 // so that the code in the dynamicFunction helper can find | 674 // so that the code in the dynamicFunction helper can find |
| 655 // them. Note that this helper is invoked before analyzing the | 675 // them. Note that this helper is invoked before analyzing the |
| 656 // full JS script. | 676 // full JS script. |
| 657 if (!nativeEmitter.handleNoSuchMethod) { | 677 if (!nativeEmitter.handleNoSuchMethod) { |
| 658 emitNoSuchMethodHandlers(defineInstanceMember); | 678 emitNoSuchMethodHandlers(defineInstanceMember); |
| 659 } | 679 } |
| 660 } | 680 } |
| 661 } | 681 } |
| 662 | 682 |
| 683 /** |
| 684 * Documentation wanted -- johnniwinther |
| 685 * |
| 686 * Invariant: [classElement] must be a declaration element. |
| 687 */ |
| 663 void generateClass(ClassElement classElement, CodeBuffer buffer) { | 688 void generateClass(ClassElement classElement, CodeBuffer buffer) { |
| 689 assert(invariant(classElement, classElement.isDeclaration)); |
| 664 if (classElement.isNative()) { | 690 if (classElement.isNative()) { |
| 665 nativeEmitter.generateNativeClass(classElement); | 691 nativeEmitter.generateNativeClass(classElement); |
| 666 return; | 692 return; |
| 667 } else { | 693 } else { |
| 668 // TODO(ngeoffray): Instead of switching between buffer, we | 694 // TODO(ngeoffray): Instead of switching between buffer, we |
| 669 // should create code sections, and decide where to emit them at | 695 // should create code sections, and decide where to emit them at |
| 670 // the end. | 696 // the end. |
| 671 buffer = mainBuffer; | 697 buffer = mainBuffer; |
| 672 } | 698 } |
| 673 | 699 |
| (...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 849 addParameterStubs(callElement, (String name, CodeBuffer value) { | 875 addParameterStubs(callElement, (String name, CodeBuffer value) { |
| 850 buffer.add('$fieldAccess.$name = $value;\n'); | 876 buffer.add('$fieldAccess.$name = $value;\n'); |
| 851 }); | 877 }); |
| 852 // If a static function is used as a closure we need to add its name | 878 // If a static function is used as a closure we need to add its name |
| 853 // in case it is used in spawnFunction. | 879 // in case it is used in spawnFunction. |
| 854 String fieldName = namer.STATIC_CLOSURE_NAME_NAME; | 880 String fieldName = namer.STATIC_CLOSURE_NAME_NAME; |
| 855 buffer.add('$fieldAccess.$fieldName = "$staticName";\n'); | 881 buffer.add('$fieldAccess.$fieldName = "$staticName";\n'); |
| 856 } | 882 } |
| 857 } | 883 } |
| 858 | 884 |
| 885 /** |
| 886 * Documentation wanted -- johnniwinther |
| 887 * |
| 888 * Invariant: [member] must be a declaration element. |
| 889 */ |
| 859 void emitDynamicFunctionGetter(FunctionElement member, | 890 void emitDynamicFunctionGetter(FunctionElement member, |
| 860 DefineMemberFunction defineInstanceMember) { | 891 DefineMemberFunction defineInstanceMember) { |
| 892 assert(invariant(member, member.isDeclaration)); |
| 861 // For every method that has the same name as a property-get we create a | 893 // For every method that has the same name as a property-get we create a |
| 862 // getter that returns a bound closure. Say we have a class 'A' with method | 894 // getter that returns a bound closure. Say we have a class 'A' with method |
| 863 // 'foo' and somewhere in the code there is a dynamic property get of | 895 // 'foo' and somewhere in the code there is a dynamic property get of |
| 864 // 'foo'. Then we generate the following code (in pseudo Dart/JavaScript): | 896 // 'foo'. Then we generate the following code (in pseudo Dart/JavaScript): |
| 865 // | 897 // |
| 866 // class A { | 898 // class A { |
| 867 // foo(x, y, z) { ... } // Original function. | 899 // foo(x, y, z) { ... } // Original function. |
| 868 // get foo { return new BoundClosure499(this, "foo"); } | 900 // get foo { return new BoundClosure499(this, "foo"); } |
| 869 // } | 901 // } |
| 870 // class BoundClosure499 extends Closure { | 902 // class BoundClosure499 extends Closure { |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 933 | 965 |
| 934 // And finally the getter. | 966 // And finally the getter. |
| 935 String getterName = namer.getterName(member.getLibrary(), member.name); | 967 String getterName = namer.getterName(member.getLibrary(), member.name); |
| 936 String targetName = namer.instanceMethodName(member); | 968 String targetName = namer.instanceMethodName(member); |
| 937 CodeBuffer getterBuffer = new CodeBuffer(); | 969 CodeBuffer getterBuffer = new CodeBuffer(); |
| 938 getterBuffer.add( | 970 getterBuffer.add( |
| 939 "function() { return new $closureClass(this, '$targetName'); }"); | 971 "function() { return new $closureClass(this, '$targetName'); }"); |
| 940 defineInstanceMember(getterName, getterBuffer); | 972 defineInstanceMember(getterName, getterBuffer); |
| 941 } | 973 } |
| 942 | 974 |
| 975 /** |
| 976 * Documentation wanted -- johnniwinther |
| 977 * |
| 978 * Invariant: [member] must be a declaration element. |
| 979 */ |
| 943 void emitCallStubForGetter(Element member, | 980 void emitCallStubForGetter(Element member, |
| 944 Set<Selector> selectors, | 981 Set<Selector> selectors, |
| 945 DefineMemberFunction defineInstanceMember) { | 982 DefineMemberFunction defineInstanceMember) { |
| 983 assert(invariant(member, member.isDeclaration)); |
| 984 LibraryElement memberLibrary = member.getLibrary(); |
| 946 String getter; | 985 String getter; |
| 947 if (member.isGetter()) { | 986 if (member.isGetter()) { |
| 948 getter = "this.${namer.getterName(member.getLibrary(), member.name)}()"; | 987 getter = "this.${namer.getterName(member.getLibrary(), member.name)}()"; |
| 949 } else { | 988 } else { |
| 950 String name = namer.instanceFieldName(member.getLibrary(), member.name); | 989 String name = namer.instanceFieldName(memberLibrary, member.name); |
| 951 getter = "this.$name"; | 990 getter = "this.$name"; |
| 952 } | 991 } |
| 953 for (Selector selector in selectors) { | 992 for (Selector selector in selectors) { |
| 954 if (selector.applies(member, compiler)) { | 993 if (selector.applies(member, compiler)) { |
| 955 String invocationName = | 994 String invocationName = |
| 956 namer.instanceMethodInvocationName(member.getLibrary(), member.name, | 995 namer.instanceMethodInvocationName(memberLibrary, member.name, |
| 957 selector); | 996 selector); |
| 958 SourceString callName = Namer.CLOSURE_INVOCATION_NAME; | 997 SourceString callName = Namer.CLOSURE_INVOCATION_NAME; |
| 959 String closureCallName = | 998 String closureCallName = |
| 960 namer.instanceMethodInvocationName(member.getLibrary(), callName, | 999 namer.instanceMethodInvocationName(memberLibrary, callName, |
| 961 selector); | 1000 selector); |
| 962 List<String> arguments = <String>[]; | 1001 List<String> arguments = <String>[]; |
| 963 for (int i = 0; i < selector.argumentCount; i++) { | 1002 for (int i = 0; i < selector.argumentCount; i++) { |
| 964 arguments.add("arg$i"); | 1003 arguments.add("arg$i"); |
| 965 } | 1004 } |
| 966 String joined = Strings.join(arguments, ", "); | 1005 String joined = Strings.join(arguments, ", "); |
| 967 CodeBuffer getterBuffer = new CodeBuffer(); | 1006 CodeBuffer getterBuffer = new CodeBuffer(); |
| 968 getterBuffer.add( | 1007 getterBuffer.add( |
| 969 "function($joined) { return $getter.$closureCallName($joined); }"); | 1008 "function($joined) { return $getter.$closureCallName($joined); }"); |
| 970 defineInstanceMember(invocationName, getterBuffer); | 1009 defineInstanceMember(invocationName, getterBuffer); |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1042 void emitMakeConstantList(CodeBuffer buffer) { | 1081 void emitMakeConstantList(CodeBuffer buffer) { |
| 1043 buffer.add(namer.ISOLATE); | 1082 buffer.add(namer.ISOLATE); |
| 1044 buffer.add(@'''.makeConstantList = function(list) { | 1083 buffer.add(@'''.makeConstantList = function(list) { |
| 1045 list.immutable$list = true; | 1084 list.immutable$list = true; |
| 1046 list.fixed$length = true; | 1085 list.fixed$length = true; |
| 1047 return list; | 1086 return list; |
| 1048 }; | 1087 }; |
| 1049 '''); | 1088 '''); |
| 1050 } | 1089 } |
| 1051 | 1090 |
| 1091 /** |
| 1092 * Documentation wanted -- johnniwinther |
| 1093 * |
| 1094 * Invariant: [member] must be a declaration element. |
| 1095 */ |
| 1052 void emitExtraAccessors(Element member, | 1096 void emitExtraAccessors(Element member, |
| 1053 DefineMemberFunction defineInstanceMember) { | 1097 DefineMemberFunction defineInstanceMember) { |
| 1098 assert(invariant(member, member.isDeclaration)); |
| 1054 if (member.isGetter() || member.isField()) { | 1099 if (member.isGetter() || member.isField()) { |
| 1055 Set<Selector> selectors = compiler.codegenWorld.invokedNames[member.name]; | 1100 Set<Selector> selectors = compiler.codegenWorld.invokedNames[member.name]; |
| 1056 if (selectors !== null && !selectors.isEmpty()) { | 1101 if (selectors !== null && !selectors.isEmpty()) { |
| 1057 emitCallStubForGetter(member, selectors, defineInstanceMember); | 1102 emitCallStubForGetter(member, selectors, defineInstanceMember); |
| 1058 } | 1103 } |
| 1059 } else if (member.isFunction()) { | 1104 } else if (member.isFunction()) { |
| 1060 if (compiler.codegenWorld.hasInvokedGetter(member, compiler)) { | 1105 if (compiler.codegenWorld.hasInvokedGetter(member, compiler)) { |
| 1061 emitDynamicFunctionGetter(member, defineInstanceMember); | 1106 emitDynamicFunctionGetter(member, defineInstanceMember); |
| 1062 } | 1107 } |
| 1063 } | 1108 } |
| (...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1377 const String HOOKS_API_USAGE = """ | 1422 const String HOOKS_API_USAGE = """ |
| 1378 // Generated by dart2js, the Dart to JavaScript compiler. | 1423 // Generated by dart2js, the Dart to JavaScript compiler. |
| 1379 // The code supports the following hooks: | 1424 // The code supports the following hooks: |
| 1380 // dartPrint(message) - if this function is defined it is called | 1425 // dartPrint(message) - if this function is defined it is called |
| 1381 // instead of the Dart [print] method. | 1426 // instead of the Dart [print] method. |
| 1382 // dartMainRunner(main) - if this function is defined, the Dart [main] | 1427 // dartMainRunner(main) - if this function is defined, the Dart [main] |
| 1383 // method will not be invoked directly. | 1428 // method will not be invoked directly. |
| 1384 // Instead, a closure that will invoke [main] is | 1429 // Instead, a closure that will invoke [main] is |
| 1385 // passed to [dartMainRunner]. | 1430 // passed to [dartMainRunner]. |
| 1386 """; | 1431 """; |
| OLD | NEW |