| 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 29 matching lines...) Expand all Loading... |
| 40 CodeBuffer mainBuffer; | 40 CodeBuffer mainBuffer; |
| 41 /** Shorter access to [isolatePropertiesName]. Both here in the code, as | 41 /** Shorter access to [isolatePropertiesName]. Both here in the code, as |
| 42 well as in the generated code. */ | 42 well as in the generated code. */ |
| 43 String isolateProperties; | 43 String isolateProperties; |
| 44 String classesCollector; | 44 String classesCollector; |
| 45 final Map<int, String> boundClosureCache; | 45 final Map<int, String> boundClosureCache; |
| 46 Set<ClassElement> checkedClasses; | 46 Set<ClassElement> checkedClasses; |
| 47 | 47 |
| 48 final bool generateSourceMap; | 48 final bool generateSourceMap; |
| 49 | 49 |
| 50 CodeEmitterTask(Compiler compiler, Namer namer, | 50 CodeEmitterTask(Compiler compiler, Namer namer, this.generateSourceMap) |
| 51 [bool generateSourceMap = false]) | |
| 52 : boundClosureBuffer = new CodeBuffer(), | 51 : boundClosureBuffer = new CodeBuffer(), |
| 53 mainBuffer = new CodeBuffer(), | 52 mainBuffer = new CodeBuffer(), |
| 54 this.namer = namer, | 53 this.namer = namer, |
| 55 boundClosureCache = new Map<int, String>(), | 54 boundClosureCache = new Map<int, String>(), |
| 56 generateSourceMap = generateSourceMap, | |
| 57 constantEmitter = new ConstantEmitter(compiler, namer), | 55 constantEmitter = new ConstantEmitter(compiler, namer), |
| 58 super(compiler) { | 56 super(compiler) { |
| 59 nativeEmitter = new NativeEmitter(this); | 57 nativeEmitter = new NativeEmitter(this); |
| 60 } | 58 } |
| 61 | 59 |
| 62 void computeRequiredTypeChecks() { | 60 void computeRequiredTypeChecks() { |
| 63 assert(checkedClasses == null); | 61 assert(checkedClasses == null); |
| 64 checkedClasses = new Set<ClassElement>(); | 62 checkedClasses = new Set<ClassElement>(); |
| 65 compiler.codegenWorld.isChecks.forEach((DartType t) { | 63 compiler.codegenWorld.isChecks.forEach((DartType t) { |
| 66 if (t is InterfaceType) checkedClasses.add(t.element); | 64 if (t is InterfaceType) checkedClasses.add(t.element); |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 158 constructor.prototype = prototype; | 156 constructor.prototype = prototype; |
| 159 return constructor; | 157 return constructor; |
| 160 }"""; | 158 }"""; |
| 161 } | 159 } |
| 162 | 160 |
| 163 /** Needs defineClass to be defined. */ | 161 /** Needs defineClass to be defined. */ |
| 164 String get protoSupportCheck { | 162 String get protoSupportCheck { |
| 165 // On Firefox and Webkit browsers we can manipulate the __proto__ | 163 // On Firefox and Webkit browsers we can manipulate the __proto__ |
| 166 // directly. Opera claims to have __proto__ support, but it is buggy. | 164 // directly. Opera claims to have __proto__ support, but it is buggy. |
| 167 // So we have to do more checks. | 165 // So we have to do more checks. |
| 166 // Opera bug was filed as DSK-370158, and fixed as CORE-47615 |
| 167 // (http://my.opera.com/desktopteam/blog/2012/07/20/more-12-01-fixes). |
| 168 // If the browser does not support __proto__ we need to instantiate an | 168 // If the browser does not support __proto__ we need to instantiate an |
| 169 // object with the correct (internal) prototype set up correctly, and then | 169 // object with the correct (internal) prototype set up correctly, and then |
| 170 // copy the members. | 170 // copy the members. |
| 171 | 171 |
| 172 return ''' | 172 return ''' |
| 173 var $supportsProtoName = false; | 173 var $supportsProtoName = false; |
| 174 var tmp = $defineClassName('c', ['f?'], {}).prototype; | 174 var tmp = $defineClassName('c', ['f?'], {}).prototype; |
| 175 if (tmp.__proto__) { | 175 if (tmp.__proto__) { |
| 176 tmp.__proto__ = {}; | 176 tmp.__proto__ = {}; |
| 177 if (typeof tmp.get\$f !== "undefined") $supportsProtoName = true; | 177 if (typeof tmp.get\$f !== "undefined") $supportsProtoName = true; |
| (...skipping 435 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 613 if (!parameters.optionalParameters.isEmpty()) { | 613 if (!parameters.optionalParameters.isEmpty()) { |
| 614 addParameterStubs(member, defineInstanceMember); | 614 addParameterStubs(member, defineInstanceMember); |
| 615 } | 615 } |
| 616 } else if (!member.isField()) { | 616 } else if (!member.isField()) { |
| 617 compiler.internalError('unexpected kind: "${member.kind}"', | 617 compiler.internalError('unexpected kind: "${member.kind}"', |
| 618 element: member); | 618 element: member); |
| 619 } | 619 } |
| 620 emitExtraAccessors(member, defineInstanceMember); | 620 emitExtraAccessors(member, defineInstanceMember); |
| 621 } | 621 } |
| 622 | 622 |
| 623 String generateCheckedSetter(Element member, String fieldName) { | 623 /** |
| 624 DartType type = member.computeType(compiler); | 624 * Documentation wanted -- johnniwinther |
| 625 if (type.element.isTypeVariable() | 625 * |
| 626 || type.element == compiler.dynamicClass | 626 * Invariant: [classElement] must be a declaration element. |
| 627 || type.element == compiler.objectClass) { | 627 */ |
| 628 // TODO(ngeoffray): Support type checks on type parameters. | 628 void emitInstanceMembers(ClassElement classElement, |
| 629 return null; | 629 CodeBuffer buffer, |
| 630 } else { | 630 bool needsLeadingComma) { |
| 631 SourceString helper = compiler.backend.getCheckedModeHelper(type); | 631 assert(invariant(classElement, classElement.isDeclaration)); |
| 632 FunctionElement helperElement = compiler.findHelper(helper); | 632 bool needsComma = needsLeadingComma; |
| 633 String helperName = namer.isolateAccess(helperElement); | 633 void defineInstanceMember(String name, CodeBuffer memberBuffer) { |
| 634 String additionalArgument = ''; | 634 if (needsComma) buffer.add(','); |
| 635 if (helperElement.computeSignature(compiler).parameterCount != 1) { | 635 needsComma = true; |
| 636 additionalArgument = ", '${namer.operatorIs(type.element)}'"; | 636 buffer.add('\n'); |
| 637 buffer.add(' $name: '); |
| 638 buffer.add(memberBuffer); |
| 639 } |
| 640 |
| 641 classElement.implementation.forEachMember( |
| 642 (ClassElement enclosing, Element member) { |
| 643 assert(invariant(classElement, member.isDeclaration)); |
| 644 if (member.isInstanceMember()) { |
| 645 addInstanceMember(member, defineInstanceMember); |
| 646 } |
| 647 }, |
| 648 includeBackendMembers: true); |
| 649 |
| 650 generateIsTestsOn(classElement, (ClassElement other) { |
| 651 String code; |
| 652 if (other.isObject(compiler)) return; |
| 653 if (nativeEmitter.requiresNativeIsCheck(other)) { |
| 654 code = 'function() { return true; }'; |
| 655 } else { |
| 656 code = 'true'; |
| 637 } | 657 } |
| 638 return " set\$$fieldName: function(v) { " | 658 CodeBuffer typeTestBuffer = new CodeBuffer(); |
| 639 "this.$fieldName = $helperName(v$additionalArgument); }"; | 659 typeTestBuffer.add(code); |
| 660 defineInstanceMember(namer.operatorIs(other), typeTestBuffer); |
| 661 }); |
| 662 |
| 663 if (identical(classElement, compiler.objectClass) |
| 664 && compiler.enabledNoSuchMethod) { |
| 665 // Emit the noSuchMethod handlers on the Object prototype now, |
| 666 // so that the code in the dynamicFunction helper can find |
| 667 // them. Note that this helper is invoked before analyzing the |
| 668 // full JS script. |
| 669 if (!nativeEmitter.handleNoSuchMethod) { |
| 670 emitNoSuchMethodHandlers(defineInstanceMember); |
| 671 } |
| 640 } | 672 } |
| 641 } | 673 } |
| 642 | 674 |
| 643 /** | 675 /** |
| 644 * Documentation wanted -- johnniwinther | 676 * Documentation wanted -- johnniwinther |
| 645 * | 677 * |
| 646 * Invariant: [classElement] must be a declaration element. | 678 * Invariant: [classElement] must be a declaration element. |
| 647 */ | 679 */ |
| 648 List<String> emitClassFields(ClassElement classElement, CodeBuffer buffer) { | 680 void visitClassFields(ClassElement classElement, |
| 681 void addField(Element member, |
| 682 String name, |
| 683 bool needsGetter, |
| 684 bool needsSetter, |
| 685 bool needsCheckedSetter)) { |
| 649 assert(invariant(classElement, classElement.isDeclaration)); | 686 assert(invariant(classElement, classElement.isDeclaration)); |
| 650 // If the class is never instantiated we still need to set it up for | 687 // If the class is never instantiated we still need to set it up for |
| 651 // inheritance purposes, but we can simplify its JavaScript constructor. | 688 // inheritance purposes, but we can simplify its JavaScript constructor. |
| 652 bool isInstantiated = | 689 bool isInstantiated = |
| 653 compiler.codegenWorld.instantiatedClasses.contains(classElement); | 690 compiler.codegenWorld.instantiatedClasses.contains(classElement); |
| 654 List<String> checkedSetters = <String>[]; | |
| 655 | 691 |
| 656 bool isFirstField = true; | 692 void visitField(ClassElement enclosingClass, Element member) { |
| 657 void addField(ClassElement enclosingClass, Element member) { | |
| 658 assert(!member.isNative()); | 693 assert(!member.isNative()); |
| 659 assert(invariant(classElement, member.isDeclaration)); | 694 assert(invariant(classElement, member.isDeclaration)); |
| 660 | 695 |
| 661 LibraryElement library = member.getLibrary(); | 696 LibraryElement library = member.getLibrary(); |
| 662 SourceString name = member.name; | 697 SourceString name = member.name; |
| 663 bool isPrivate = name.isPrivate(); | 698 bool isPrivate = name.isPrivate(); |
| 664 // See if we can dynamically create getters and setters. | 699 // See if we can dynamically create getters and setters. |
| 665 // We can only generate getters and setters for [classElement] since | 700 // We can only generate getters and setters for [classElement] since |
| 666 // the fields of super classes could be overwritten with getters or | 701 // the fields of super classes could be overwritten with getters or |
| 667 // setters. | 702 // setters. |
| 668 bool needsDynamicGetter = false; | 703 bool needsGetter = false; |
| 669 bool needsDynamicSetter = false; | 704 bool needsSetter = false; |
| 670 // We need to name shadowed fields differently, so they don't clash with | 705 // We need to name shadowed fields differently, so they don't clash with |
| 671 // the non-shadowed field. | 706 // the non-shadowed field. |
| 672 bool isShadowed = false; | 707 bool isShadowed = false; |
| 673 if (identical(enclosingClass, classElement)) { | 708 if (identical(enclosingClass, classElement)) { |
| 674 needsDynamicGetter = instanceFieldNeedsGetter(member); | 709 needsGetter = instanceFieldNeedsGetter(member); |
| 675 needsDynamicSetter = instanceFieldNeedsSetter(member); | 710 needsSetter = instanceFieldNeedsSetter(member); |
| 676 } else { | 711 } else { |
| 677 isShadowed = classElement.isShadowedByField(member); | 712 isShadowed = classElement.isShadowedByField(member); |
| 678 } | 713 } |
| 679 | 714 |
| 680 if ((isInstantiated && !enclosingClass.isNative()) | 715 if ((isInstantiated && !enclosingClass.isNative()) |
| 681 || needsDynamicGetter | 716 || needsGetter |
| 682 || needsDynamicSetter) { | 717 || needsSetter) { |
| 683 if (isFirstField) { | |
| 684 isFirstField = false; | |
| 685 } else { | |
| 686 buffer.add(", "); | |
| 687 } | |
| 688 String fieldName = isShadowed | 718 String fieldName = isShadowed |
| 689 ? namer.shadowedFieldName(member) | 719 ? namer.shadowedFieldName(member) |
| 690 : namer.getName(member); | 720 : namer.getName(member); |
| 691 if (needsDynamicSetter && compiler.enableTypeAssertions) { | 721 bool needsCheckedSetter = false; |
| 692 String setter = generateCheckedSetter(member, fieldName); | 722 if (needsSetter && compiler.enableTypeAssertions |
| 693 if (setter != null) { | 723 && canGenerateCheckedSetter(member)) { |
| 694 needsDynamicSetter = false; | 724 needsCheckedSetter = true; |
| 695 checkedSetters.add(setter); | 725 needsSetter = false; |
| 696 } | |
| 697 } | 726 } |
| 698 // Getters and setters with suffixes will be generated dynamically. | 727 // Getters and setters with suffixes will be generated dynamically. |
| 699 buffer.add('"$fieldName'); | 728 addField(member, |
| 700 if (needsDynamicGetter || needsDynamicSetter) { | 729 fieldName, |
| 701 if (needsDynamicGetter && needsDynamicSetter) { | 730 needsGetter, |
| 702 buffer.add(GETTER_SETTER_SUFFIX); | 731 needsSetter, |
| 703 } else if (needsDynamicGetter) { | 732 needsCheckedSetter); |
| 704 buffer.add(GETTER_SUFFIX); | |
| 705 } else { | |
| 706 buffer.add(SETTER_SUFFIX); | |
| 707 } | |
| 708 } | |
| 709 buffer.add('"'); | |
| 710 } | 733 } |
| 711 } | 734 } |
| 712 | 735 |
| 713 // If a class is not instantiated then we add the field just so we can | 736 // If a class is not instantiated then we add the field just so we can |
| 714 // generate the field getter/setter dynamically. Since this is only | 737 // generate the field getter/setter dynamically. Since this is only |
| 715 // allowed on fields that are in [classElement] we don't need to visit | 738 // allowed on fields that are in [classElement] we don't need to visit |
| 716 // superclasses for non-instantiated classes. | 739 // superclasses for non-instantiated classes. |
| 717 classElement.implementation.forEachInstanceField( | 740 classElement.implementation.forEachInstanceField( |
| 718 addField, | 741 visitField, |
| 719 includeBackendMembers: true, | 742 includeBackendMembers: true, |
| 720 includeSuperMembers: isInstantiated && !classElement.isNative()); | 743 includeSuperMembers: isInstantiated && !classElement.isNative()); |
| 721 return checkedSetters; | 744 } |
| 745 |
| 746 void generateGetter(Element member, String fieldName, CodeBuffer buffer) { |
| 747 String getterName = namer.getterName(member.getLibrary(), member.name); |
| 748 buffer.add("$getterName: function() { return this.$fieldName; }"); |
| 749 } |
| 750 |
| 751 void generateSetter(Element member, String fieldName, CodeBuffer buffer) { |
| 752 String setterName = namer.setterName(member.getLibrary(), member.name); |
| 753 buffer.add("$setterName: function(v) { this.$fieldName = v; }"); |
| 754 } |
| 755 |
| 756 bool canGenerateCheckedSetter(Element member) { |
| 757 DartType type = member.computeType(compiler); |
| 758 if (type.element.isTypeVariable() |
| 759 || type.element == compiler.dynamicClass |
| 760 || type.element == compiler.objectClass) { |
| 761 // TODO(ngeoffray): Support type checks on type parameters. |
| 762 return false; |
| 763 } |
| 764 return true; |
| 765 } |
| 766 |
| 767 void generateCheckedSetter(Element member, |
| 768 String fieldName, |
| 769 CodeBuffer buffer) { |
| 770 assert(canGenerateCheckedSetter(member)); |
| 771 DartType type = member.computeType(compiler); |
| 772 SourceString helper = compiler.backend.getCheckedModeHelper(type); |
| 773 FunctionElement helperElement = compiler.findHelper(helper); |
| 774 String helperName = namer.isolateAccess(helperElement); |
| 775 String additionalArgument = ''; |
| 776 if (helperElement.computeSignature(compiler).parameterCount != 1) { |
| 777 additionalArgument = ", '${namer.operatorIs(type.element)}'"; |
| 778 } |
| 779 String setterName = namer.setterName(member.getLibrary(), member.name); |
| 780 buffer.add("$setterName: function(v) { " |
| 781 "this.$fieldName = $helperName(v$additionalArgument); }"); |
| 782 } |
| 783 |
| 784 void emitClassConstructor(ClassElement classElement, CodeBuffer buffer) { |
| 785 /* Do nothing. */ |
| 786 } |
| 787 |
| 788 void emitClassFields(ClassElement classElement, CodeBuffer buffer) { |
| 789 buffer.add('"": ['); |
| 790 bool isFirstField = true; |
| 791 visitClassFields(classElement, (Element member, |
| 792 String name, |
| 793 bool needsGetter, |
| 794 bool needsSetter, |
| 795 bool needsCheckedSetter) { |
| 796 if (isFirstField) { |
| 797 isFirstField = false; |
| 798 } else { |
| 799 buffer.add(", "); |
| 800 } |
| 801 buffer.add('"$name'); |
| 802 if (needsGetter && needsSetter) { |
| 803 buffer.add(GETTER_SETTER_SUFFIX); |
| 804 } else if (needsGetter) { |
| 805 buffer.add(GETTER_SUFFIX); |
| 806 } else if (needsSetter) { |
| 807 buffer.add(SETTER_SUFFIX); |
| 808 } |
| 809 buffer.add('"'); |
| 810 }); |
| 811 buffer.add(']'); |
| 812 } |
| 813 |
| 814 /** Each getter/setter must be prefixed with a ",\n ". */ |
| 815 void emitClassGettersSetters(ClassElement classElement, CodeBuffer buffer, |
| 816 {bool omitLeadingComma: false}) { |
| 817 visitClassFields(classElement, (Element member, |
| 818 String name, |
| 819 bool needsGetter, |
| 820 bool needsSetter, |
| 821 bool needsCheckedSetter) { |
| 822 if (needsCheckedSetter) { |
| 823 assert(!needsSetter); |
| 824 if (!omitLeadingComma) { |
| 825 buffer.add(",\n "); |
| 826 } else { |
| 827 omitLeadingComma = false; |
| 828 } |
| 829 generateCheckedSetter(member, name, buffer); |
| 830 } |
| 831 }); |
| 722 } | 832 } |
| 723 | 833 |
| 724 /** | 834 /** |
| 725 * Documentation wanted -- johnniwinther | |
| 726 * | |
| 727 * Invariant: [classElement] must be a declaration element. | |
| 728 */ | |
| 729 void emitInstanceMembers(ClassElement classElement, | |
| 730 CodeBuffer buffer, | |
| 731 bool needsLeadingComma) { | |
| 732 assert(invariant(classElement, classElement.isDeclaration)); | |
| 733 bool needsComma = needsLeadingComma; | |
| 734 void defineInstanceMember(String name, CodeBuffer memberBuffer) { | |
| 735 if (needsComma) buffer.add(','); | |
| 736 needsComma = true; | |
| 737 buffer.add('\n'); | |
| 738 buffer.add(' $name: '); | |
| 739 buffer.add(memberBuffer); | |
| 740 } | |
| 741 | |
| 742 classElement.implementation.forEachMember( | |
| 743 (ClassElement enclosing, Element member) { | |
| 744 assert(invariant(classElement, member.isDeclaration)); | |
| 745 if (member.isInstanceMember()) { | |
| 746 addInstanceMember(member, defineInstanceMember); | |
| 747 } | |
| 748 }, | |
| 749 includeBackendMembers: true); | |
| 750 | |
| 751 generateIsTestsOn(classElement, (ClassElement other) { | |
| 752 String code; | |
| 753 if (other.isObject(compiler)) return; | |
| 754 if (nativeEmitter.requiresNativeIsCheck(other)) { | |
| 755 code = 'function() { return true; }'; | |
| 756 } else { | |
| 757 code = 'true'; | |
| 758 } | |
| 759 CodeBuffer typeTestBuffer = new CodeBuffer(); | |
| 760 typeTestBuffer.add(code); | |
| 761 defineInstanceMember(namer.operatorIs(other), typeTestBuffer); | |
| 762 }); | |
| 763 | |
| 764 if (identical(classElement, compiler.objectClass) | |
| 765 && compiler.enabledNoSuchMethod) { | |
| 766 // Emit the noSuchMethod handlers on the Object prototype now, | |
| 767 // so that the code in the dynamicFunction helper can find | |
| 768 // them. Note that this helper is invoked before analyzing the | |
| 769 // full JS script. | |
| 770 if (!nativeEmitter.handleNoSuchMethod) { | |
| 771 emitNoSuchMethodHandlers(defineInstanceMember); | |
| 772 } | |
| 773 } | |
| 774 } | |
| 775 | |
| 776 /** | |
| 777 * Documentation wanted -- johnniwinther | 835 * Documentation wanted -- johnniwinther |
| 778 * | 836 * |
| 779 * Invariant: [classElement] must be a declaration element. | 837 * Invariant: [classElement] must be a declaration element. |
| 780 */ | 838 */ |
| 781 void generateClass(ClassElement classElement, CodeBuffer buffer) { | 839 void generateClass(ClassElement classElement, CodeBuffer buffer) { |
| 782 assert(invariant(classElement, classElement.isDeclaration)); | 840 assert(invariant(classElement, classElement.isDeclaration)); |
| 783 if (classElement.isNative()) { | 841 if (classElement.isNative()) { |
| 784 nativeEmitter.generateNativeClass(classElement); | 842 nativeEmitter.generateNativeClass(classElement); |
| 785 return; | 843 return; |
| 786 } else { | 844 } else { |
| 787 // TODO(ngeoffray): Instead of switching between buffer, we | 845 // TODO(ngeoffray): Instead of switching between buffer, we |
| 788 // should create code sections, and decide where to emit them at | 846 // should create code sections, and decide where to emit them at |
| 789 // the end. | 847 // the end. |
| 790 buffer = mainBuffer; | 848 buffer = mainBuffer; |
| 791 } | 849 } |
| 792 | 850 |
| 793 needsDefineClass = true; | 851 needsDefineClass = true; |
| 794 String className = namer.getName(classElement); | 852 String className = namer.getName(classElement); |
| 795 ClassElement superclass = classElement.superclass; | 853 ClassElement superclass = classElement.superclass; |
| 796 String superName = ""; | 854 String superName = ""; |
| 797 if (superclass != null) { | 855 if (superclass != null) { |
| 798 superName = namer.getName(superclass); | 856 superName = namer.getName(superclass); |
| 799 } | 857 } |
| 800 String constructorName = namer.safeName(classElement.name.slowToString()); | |
| 801 | 858 |
| 802 buffer.add('$classesCollector.$className = {"":\n'); | 859 buffer.add('$classesCollector.$className = {'); |
| 803 buffer.add(' ['); | 860 emitClassConstructor(classElement, buffer); |
| 804 List<String> checkedSetters = emitClassFields(classElement, buffer); | 861 emitClassFields(classElement, buffer); |
| 805 buffer.add('],\n'); | |
| 806 // TODO(floitsch): the emitInstanceMember should simply always emit a ',\n'. | 862 // TODO(floitsch): the emitInstanceMember should simply always emit a ',\n'. |
| 807 // That does currently not work because the native classes have a different | 863 // That does currently not work because the native classes have a different |
| 808 // syntax. | 864 // syntax. |
| 809 buffer.add(' "super": "$superName"'); | 865 buffer.add(',\n "super": "$superName"'); |
| 810 if (!checkedSetters.isEmpty()) { | 866 emitClassGettersSetters(classElement, buffer); |
| 811 buffer.add(',\n'); | |
| 812 buffer.add('${Strings.join(checkedSetters, ",\n")}'); | |
| 813 } | |
| 814 emitInstanceMembers(classElement, buffer, true); | 867 emitInstanceMembers(classElement, buffer, true); |
| 815 buffer.add('\n};\n\n'); | 868 buffer.add('\n};\n\n'); |
| 816 } | 869 } |
| 817 | 870 |
| 818 /** | 871 /** |
| 819 * Generate "is tests" for [cls]: itself, and the "is tests" for the | 872 * Generate "is tests" for [cls]: itself, and the "is tests" for the |
| 820 * classes it implements. We don't need to add the "is tests" of the | 873 * classes it implements. We don't need to add the "is tests" of the |
| 821 * super class because they will be inherited at runtime. | 874 * super class because they will be inherited at runtime. |
| 822 */ | 875 */ |
| 823 void generateIsTestsOn(ClassElement cls, | 876 void generateIsTestsOn(ClassElement cls, |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 968 addParameterStubs(callElement, (String name, CodeBuffer value) { | 1021 addParameterStubs(callElement, (String name, CodeBuffer value) { |
| 969 buffer.add('$fieldAccess.$name = $value;\n'); | 1022 buffer.add('$fieldAccess.$name = $value;\n'); |
| 970 }); | 1023 }); |
| 971 // If a static function is used as a closure we need to add its name | 1024 // If a static function is used as a closure we need to add its name |
| 972 // in case it is used in spawnFunction. | 1025 // in case it is used in spawnFunction. |
| 973 String fieldName = namer.STATIC_CLOSURE_NAME_NAME; | 1026 String fieldName = namer.STATIC_CLOSURE_NAME_NAME; |
| 974 buffer.add('$fieldAccess.$fieldName = "$staticName";\n'); | 1027 buffer.add('$fieldAccess.$fieldName = "$staticName";\n'); |
| 975 } | 1028 } |
| 976 } | 1029 } |
| 977 | 1030 |
| 1031 void emitBoundClosureClassHeader(String mangledName, |
| 1032 String superName, |
| 1033 CodeBuffer buffer) { |
| 1034 buffer.add(""" |
| 1035 $classesCollector.$mangledName = {'': |
| 1036 ['self', 'target'], |
| 1037 'super': '$superName', |
| 1038 """); |
| 1039 } |
| 1040 |
| 978 /** | 1041 /** |
| 979 * Documentation wanted -- johnniwinther | 1042 * Documentation wanted -- johnniwinther |
| 980 * | 1043 * |
| 981 * Invariant: [member] must be a declaration element. | 1044 * Invariant: [member] must be a declaration element. |
| 982 */ | 1045 */ |
| 983 void emitDynamicFunctionGetter(FunctionElement member, | 1046 void emitDynamicFunctionGetter(FunctionElement member, |
| 984 DefineMemberFunction defineInstanceMember) { | 1047 DefineMemberFunction defineInstanceMember) { |
| 985 assert(invariant(member, member.isDeclaration)); | 1048 assert(invariant(member, member.isDeclaration)); |
| 986 // For every method that has the same name as a property-get we create a | 1049 // For every method that has the same name as a property-get we create a |
| 987 // getter that returns a bound closure. Say we have a class 'A' with method | 1050 // getter that returns a bound closure. Say we have a class 'A' with method |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1014 // Create a new closure class. | 1077 // Create a new closure class. |
| 1015 SourceString name = const SourceString("BoundClosure"); | 1078 SourceString name = const SourceString("BoundClosure"); |
| 1016 ClassElement closureClassElement = new ClosureClassElement( | 1079 ClassElement closureClassElement = new ClosureClassElement( |
| 1017 name, compiler, member, member.getCompilationUnit()); | 1080 name, compiler, member, member.getCompilationUnit()); |
| 1018 String mangledName = namer.getName(closureClassElement); | 1081 String mangledName = namer.getName(closureClassElement); |
| 1019 String superName = namer.getName(closureClassElement.superclass); | 1082 String superName = namer.getName(closureClassElement.superclass); |
| 1020 needsClosureClass = true; | 1083 needsClosureClass = true; |
| 1021 | 1084 |
| 1022 // Define the constructor with a name so that Object.toString can | 1085 // Define the constructor with a name so that Object.toString can |
| 1023 // find the class name of the closure class. | 1086 // find the class name of the closure class. |
| 1024 boundClosureBuffer.add(""" | 1087 emitBoundClosureClassHeader(mangledName, superName, boundClosureBuffer); |
| 1025 $classesCollector.$mangledName = {'': | |
| 1026 ['self', 'target'], | |
| 1027 'super': '$superName', | |
| 1028 """); | |
| 1029 // Now add the methods on the closure class. The instance method does not | 1088 // Now add the methods on the closure class. The instance method does not |
| 1030 // have the correct name. Since [addParameterStubs] use the name to create | 1089 // have the correct name. Since [addParameterStubs] use the name to create |
| 1031 // its stubs we simply create a fake element with the correct name. | 1090 // its stubs we simply create a fake element with the correct name. |
| 1032 // Note: the callElement will not have any enclosingElement. | 1091 // Note: the callElement will not have any enclosingElement. |
| 1033 FunctionElement callElement = | 1092 FunctionElement callElement = |
| 1034 new ClosureInvocationElement(Namer.CLOSURE_INVOCATION_NAME, member); | 1093 new ClosureInvocationElement(Namer.CLOSURE_INVOCATION_NAME, member); |
| 1035 | 1094 |
| 1036 String invocationName = namer.instanceMethodName(callElement); | 1095 String invocationName = namer.instanceMethodName(callElement); |
| 1037 List<String> arguments = new List<String>(parameterCount); | 1096 List<String> arguments = new List<String>(parameterCount); |
| 1038 for (int i = 0; i < parameterCount; i++) { | 1097 for (int i = 0; i < parameterCount; i++) { |
| (...skipping 475 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1514 const String HOOKS_API_USAGE = """ | 1573 const String HOOKS_API_USAGE = """ |
| 1515 // Generated by dart2js, the Dart to JavaScript compiler. | 1574 // Generated by dart2js, the Dart to JavaScript compiler. |
| 1516 // The code supports the following hooks: | 1575 // The code supports the following hooks: |
| 1517 // dartPrint(message) - if this function is defined it is called | 1576 // dartPrint(message) - if this function is defined it is called |
| 1518 // instead of the Dart [print] method. | 1577 // instead of the Dart [print] method. |
| 1519 // dartMainRunner(main) - if this function is defined, the Dart [main] | 1578 // dartMainRunner(main) - if this function is defined, the Dart [main] |
| 1520 // method will not be invoked directly. | 1579 // method will not be invoked directly. |
| 1521 // Instead, a closure that will invoke [main] is | 1580 // Instead, a closure that will invoke [main] is |
| 1522 // passed to [dartMainRunner]. | 1581 // passed to [dartMainRunner]. |
| 1523 """; | 1582 """; |
| OLD | NEW |