| 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 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 100 => '${namer.ISOLATE}.\$finishIsolateConstructor'; | 100 => '${namer.ISOLATE}.\$finishIsolateConstructor'; |
| 101 String get pendingClassesName | 101 String get pendingClassesName |
| 102 => '${namer.ISOLATE}.\$pendingClasses'; | 102 => '${namer.ISOLATE}.\$pendingClasses'; |
| 103 String get isolatePropertiesName | 103 String get isolatePropertiesName |
| 104 => '${namer.ISOLATE}.${namer.ISOLATE_PROPERTIES}'; | 104 => '${namer.ISOLATE}.${namer.ISOLATE_PROPERTIES}'; |
| 105 String get supportsProtoName | 105 String get supportsProtoName |
| 106 => 'supportsProto'; | 106 => 'supportsProto'; |
| 107 String get lazyInitializerName | 107 String get lazyInitializerName |
| 108 => '${namer.ISOLATE}.\$lazy'; | 108 => '${namer.ISOLATE}.\$lazy'; |
| 109 | 109 |
| 110 // Property name suffixes. If the accessors are renaming then the format | 110 final String GETTER_SUFFIX = "?"; |
| 111 // is <accessorName>:<fieldName><suffix>. We use the suffix to know whether | 111 final String SETTER_SUFFIX = "!"; |
| 112 // to look for the ':' separator in order to avoid doing the indexOf operation | 112 final String GETTER_SETTER_SUFFIX = "="; |
| 113 // on every single property (they are quite rare). None of these characters | |
| 114 // are legal in an identifier and they are related by bit patterns. | |
| 115 // setter < 0x3c | |
| 116 // both = 0x3d | |
| 117 // getter > 0x3e | |
| 118 // renaming setter | 0x7c | |
| 119 // renaming both } 0x7d | |
| 120 // renaming getter ~ 0x7e | |
| 121 const SUFFIX_MASK = 0x3f; | |
| 122 const FIRST_SUFFIX_CODE = 0x3c; | |
| 123 const SETTER_CODE = 0x3c; | |
| 124 const GETTER_SETTER_CODE = 0x3d; | |
| 125 const GETTER_CODE = 0x3e; | |
| 126 const RENAMING_FLAG = 0x40; | |
| 127 String needsGetterCode(String variable) => '($variable & 3) > 0'; | |
| 128 String needsSetterCode(String variable) => '($variable & 2) == 0'; | |
| 129 String isRenaming(String variable) => '($variable & $RENAMING_FLAG) != 0'; | |
| 130 | 113 |
| 131 String get generateGetterSetterFunction { | 114 String get generateGetterSetterFunction { |
| 132 return """ | 115 return """ |
| 133 function(field, prototype) { | 116 function(field, prototype) { |
| 134 var len = field.length; | 117 var len = field.length; |
| 135 var lastCharCode = field.charCodeAt(len - 1); | 118 var lastChar = field[len - 1]; |
| 136 var needsAccessor = (lastCharCode & $SUFFIX_MASK) >= $FIRST_SUFFIX_CODE; | 119 var needsGetter = lastChar == '$GETTER_SUFFIX' || lastChar == '$GETTER_SETTE
R_SUFFIX'; |
| 137 if (needsAccessor) { | 120 var needsSetter = lastChar == '$SETTER_SUFFIX' || lastChar == '$GETTER_SETTE
R_SUFFIX'; |
| 138 var needsGetter = ${needsGetterCode('lastCharCode')}; | 121 if (needsGetter || needsSetter) field = field.substring(0, len - 1); |
| 139 var needsSetter = ${needsSetterCode('lastCharCode')}; | 122 if (needsGetter) { |
| 140 var renaming = ${isRenaming('lastCharCode')}; | 123 var getterString = "return this." + field + ";"; |
| 141 var accessorName = field = field.substring(0, len - 1); | 124 """ |
| 142 if (renaming) { | 125 /* The supportsProtoCheck below depends on the getter/setter convention. |
| 143 var divider = field.indexOf(":"); | 126 When changing here, update the protoCheck too. */ |
| 144 accessorName = field.substring(0, divider); | 127 """ |
| 145 field = field.substring(divider + 1); | 128 prototype["get\$" + field] = new Function(getterString); |
| 146 } | 129 } |
| 147 if (needsGetter) { | 130 if (needsSetter) { |
| 148 var getterString = "return this." + field + ";"; | 131 var setterString = "this." + field + " = v;"; |
| 149 prototype["get\$" + accessorName] = new Function(getterString); | 132 prototype["set\$" + field] = new Function("v", setterString); |
| 150 } | |
| 151 if (needsSetter) { | |
| 152 var setterString = "this." + field + " = v;"; | |
| 153 prototype["set\$" + accessorName] = new Function("v", setterString); | |
| 154 } | |
| 155 } | 133 } |
| 156 return field; | 134 return field; |
| 157 }"""; | 135 }"""; |
| 158 } | 136 } |
| 159 | 137 |
| 160 String get defineClassFunction { | 138 String get defineClassFunction { |
| 161 // First the class name, then the super class name, followed by the fields | 139 // First the class name, then the super class name, followed by the fields |
| 162 // (in an array) and the members (inside an Object literal). | 140 // (in an array) and the members (inside an Object literal). |
| 163 // The caller can also pass in the constructor as a function if needed. | 141 // The caller can also pass in the constructor as a function if needed. |
| 164 // | 142 // |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 206 // (http://my.opera.com/desktopteam/blog/2012/07/20/more-12-01-fixes). | 184 // (http://my.opera.com/desktopteam/blog/2012/07/20/more-12-01-fixes). |
| 207 // If the browser does not support __proto__ we need to instantiate an | 185 // If the browser does not support __proto__ we need to instantiate an |
| 208 // object with the correct (internal) prototype set up correctly, and then | 186 // object with the correct (internal) prototype set up correctly, and then |
| 209 // copy the members. | 187 // copy the members. |
| 210 | 188 |
| 211 return ''' | 189 return ''' |
| 212 var $supportsProtoName = false; | 190 var $supportsProtoName = false; |
| 213 var tmp = $defineClassName('c', ['f?'], {}).prototype; | 191 var tmp = $defineClassName('c', ['f?'], {}).prototype; |
| 214 if (tmp.__proto__) { | 192 if (tmp.__proto__) { |
| 215 tmp.__proto__ = {}; | 193 tmp.__proto__ = {}; |
| 216 if (typeof tmp.get\$f !== 'undefined') $supportsProtoName = true; | 194 if (typeof tmp.get\$f !== "undefined") $supportsProtoName = true; |
| 217 } | 195 } |
| 218 '''; | 196 '''; |
| 219 } | 197 } |
| 220 | 198 |
| 221 String get finishClassesFunction { | 199 String get finishClassesFunction { |
| 222 // 'defineClass' does not require the classes to be constructed in order. | 200 // 'defineClass' does not require the classes to be constructed in order. |
| 223 // Classes are initially just stored in the 'pendingClasses' field. | 201 // Classes are initially just stored in the 'pendingClasses' field. |
| 224 // 'finishClasses' takes all pending classes and sets up the prototype. | 202 // 'finishClasses' takes all pending classes and sets up the prototype. |
| 225 // Once set up, the constructors prototype field satisfy: | 203 // Once set up, the constructors prototype field satisfy: |
| 226 // - it contains all (local) members. | 204 // - it contains all (local) members. |
| (...skipping 306 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 533 // (3) foo$3$d(a, b, d) => foo$4$c$d(a, b, null, d); | 511 // (3) foo$3$d(a, b, d) => foo$4$c$d(a, b, null, d); |
| 534 // (4) No stub generated, call is direct. | 512 // (4) No stub generated, call is direct. |
| 535 // (5) No stub generated, call is direct. | 513 // (5) No stub generated, call is direct. |
| 536 | 514 |
| 537 // Keep a cache of which stubs have already been generated, to | 515 // Keep a cache of which stubs have already been generated, to |
| 538 // avoid duplicates. Note that even if selectors are | 516 // avoid duplicates. Note that even if selectors are |
| 539 // canonicalized, we would still need this cache: a typed selector | 517 // canonicalized, we would still need this cache: a typed selector |
| 540 // on A and a typed selector on B could yield the same stub. | 518 // on A and a typed selector on B could yield the same stub. |
| 541 Set<String> generatedStubNames = new Set<String>(); | 519 Set<String> generatedStubNames = new Set<String>(); |
| 542 if (compiler.enabledFunctionApply | 520 if (compiler.enabledFunctionApply |
| 543 && member.name == namer.CLOSURE_INVOCATION_NAME) { | 521 && member.name == Namer.CLOSURE_INVOCATION_NAME) { |
| 544 // If [Function.apply] is called, we pessimistically compile all | 522 // If [Function.apply] is called, we pessimistically compile all |
| 545 // possible stubs for this closure. | 523 // possible stubs for this closure. |
| 546 FunctionSignature signature = member.computeSignature(compiler); | 524 FunctionSignature signature = member.computeSignature(compiler); |
| 547 Set<Selector> selectors = signature.optionalParametersAreNamed | 525 Set<Selector> selectors = signature.optionalParametersAreNamed |
| 548 ? computeNamedSelectors(signature, member) | 526 ? computeNamedSelectors(signature, member) |
| 549 : computeOptionalSelectors(signature, member); | 527 : computeOptionalSelectors(signature, member); |
| 550 for (Selector selector in selectors) { | 528 for (Selector selector in selectors) { |
| 551 addParameterStub( | 529 addParameterStub( |
| 552 member, selector, defineInstanceMember, generatedStubNames); | 530 member, selector, defineInstanceMember, generatedStubNames); |
| 553 } | 531 } |
| (...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 732 } | 710 } |
| 733 | 711 |
| 734 /** | 712 /** |
| 735 * Documentation wanted -- johnniwinther | 713 * Documentation wanted -- johnniwinther |
| 736 * | 714 * |
| 737 * Invariant: [classElement] must be a declaration element. | 715 * Invariant: [classElement] must be a declaration element. |
| 738 */ | 716 */ |
| 739 void visitClassFields(ClassElement classElement, | 717 void visitClassFields(ClassElement classElement, |
| 740 void addField(Element member, | 718 void addField(Element member, |
| 741 String name, | 719 String name, |
| 742 String accessorName, | |
| 743 bool needsGetter, | 720 bool needsGetter, |
| 744 bool needsSetter, | 721 bool needsSetter, |
| 745 bool needsCheckedSetter)) { | 722 bool needsCheckedSetter)) { |
| 746 assert(invariant(classElement, classElement.isDeclaration)); | 723 assert(invariant(classElement, classElement.isDeclaration)); |
| 747 // If the class is never instantiated we still need to set it up for | 724 // If the class is never instantiated we still need to set it up for |
| 748 // inheritance purposes, but we can simplify its JavaScript constructor. | 725 // inheritance purposes, but we can simplify its JavaScript constructor. |
| 749 bool isInstantiated = | 726 bool isInstantiated = |
| 750 compiler.codegenWorld.instantiatedClasses.contains(classElement); | 727 compiler.codegenWorld.instantiatedClasses.contains(classElement); |
| 751 | 728 |
| 752 void visitField(ClassElement enclosingClass, Element member) { | 729 void visitField(ClassElement enclosingClass, Element member) { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 768 if (identical(enclosingClass, classElement)) { | 745 if (identical(enclosingClass, classElement)) { |
| 769 needsGetter = instanceFieldNeedsGetter(member); | 746 needsGetter = instanceFieldNeedsGetter(member); |
| 770 needsSetter = instanceFieldNeedsSetter(member); | 747 needsSetter = instanceFieldNeedsSetter(member); |
| 771 } else { | 748 } else { |
| 772 isShadowed = classElement.isShadowedByField(member); | 749 isShadowed = classElement.isShadowedByField(member); |
| 773 } | 750 } |
| 774 | 751 |
| 775 if ((isInstantiated && !enclosingClass.isNative()) | 752 if ((isInstantiated && !enclosingClass.isNative()) |
| 776 || needsGetter | 753 || needsGetter |
| 777 || needsSetter) { | 754 || needsSetter) { |
| 778 String accessorName = isShadowed | 755 String fieldName = isShadowed |
| 779 ? namer.shadowedFieldName(member) | 756 ? namer.shadowedFieldName(member) |
| 780 : namer.getName(member); | 757 : namer.getName(member); |
| 781 String fieldName = enclosingClass.isNative() ? | |
| 782 member.name.slowToString() : accessorName; | |
| 783 bool needsCheckedSetter = false; | 758 bool needsCheckedSetter = false; |
| 784 if (needsSetter && compiler.enableTypeAssertions | 759 if (needsSetter && compiler.enableTypeAssertions |
| 785 && canGenerateCheckedSetter(member)) { | 760 && canGenerateCheckedSetter(member)) { |
| 786 needsCheckedSetter = true; | 761 needsCheckedSetter = true; |
| 787 needsSetter = false; | 762 needsSetter = false; |
| 788 } | 763 } |
| 789 // Getters and setters with suffixes will be generated dynamically. | 764 // Getters and setters with suffixes will be generated dynamically. |
| 790 addField(member, | 765 addField(member, |
| 791 fieldName, | 766 fieldName, |
| 792 accessorName, | |
| 793 needsGetter, | 767 needsGetter, |
| 794 needsSetter, | 768 needsSetter, |
| 795 needsCheckedSetter); | 769 needsCheckedSetter); |
| 796 } | 770 } |
| 797 } | 771 } |
| 798 | 772 |
| 799 // If a class is not instantiated then we add the field just so we can | 773 // If a class is not instantiated then we add the field just so we can |
| 800 // generate the field getter/setter dynamically. Since this is only | 774 // generate the field getter/setter dynamically. Since this is only |
| 801 // allowed on fields that are in [classElement] we don't need to visit | 775 // allowed on fields that are in [classElement] we don't need to visit |
| 802 // superclasses for non-instantiated classes. | 776 // superclasses for non-instantiated classes. |
| 803 classElement.implementation.forEachInstanceField( | 777 classElement.implementation.forEachInstanceField( |
| 804 visitField, | 778 visitField, |
| 805 includeBackendMembers: true, | 779 includeBackendMembers: true, |
| 806 includeSuperMembers: isInstantiated && !classElement.isNative()); | 780 includeSuperMembers: isInstantiated && !classElement.isNative()); |
| 807 } | 781 } |
| 808 | 782 |
| 809 void generateGetter(Element member, String fieldName, String accessorName, | 783 void generateGetter(Element member, String fieldName, CodeBuffer buffer) { |
| 810 CodeBuffer buffer) { | 784 String getterName = namer.getterName(member.getLibrary(), member.name); |
| 811 String getterName = | |
| 812 namer.getterName(member.getLibrary(), new SourceString(accessorName)); | |
| 813 buffer.add("$getterName: function() { return this.$fieldName; }"); | 785 buffer.add("$getterName: function() { return this.$fieldName; }"); |
| 814 } | 786 } |
| 815 | 787 |
| 816 void generateSetter(Element member, String fieldName, String accessorName, | 788 void generateSetter(Element member, String fieldName, CodeBuffer buffer) { |
| 817 CodeBuffer buffer) { | 789 String setterName = namer.setterName(member.getLibrary(), member.name); |
| 818 String setterName = | |
| 819 namer.setterName(member.getLibrary(), new SourceString(accessorName)); | |
| 820 buffer.add("$setterName: function(v) { this.$fieldName = v; }"); | 790 buffer.add("$setterName: function(v) { this.$fieldName = v; }"); |
| 821 } | 791 } |
| 822 | 792 |
| 823 bool canGenerateCheckedSetter(Element member) { | 793 bool canGenerateCheckedSetter(Element member) { |
| 824 DartType type = member.computeType(compiler); | 794 DartType type = member.computeType(compiler); |
| 825 if (type.element.isTypeVariable() | 795 if (type.element.isTypeVariable() |
| 826 || type.element == compiler.dynamicClass | 796 || type.element == compiler.dynamicClass |
| 827 || type.element == compiler.objectClass) { | 797 || type.element == compiler.objectClass) { |
| 828 // TODO(ngeoffray): Support type checks on type parameters. | 798 // TODO(ngeoffray): Support type checks on type parameters. |
| 829 return false; | 799 return false; |
| 830 } | 800 } |
| 831 return true; | 801 return true; |
| 832 } | 802 } |
| 833 | 803 |
| 834 void generateCheckedSetter(Element member, | 804 void generateCheckedSetter(Element member, |
| 835 String fieldName, | 805 String fieldName, |
| 836 String accessorName, | |
| 837 CodeBuffer buffer) { | 806 CodeBuffer buffer) { |
| 838 assert(canGenerateCheckedSetter(member)); | 807 assert(canGenerateCheckedSetter(member)); |
| 839 DartType type = member.computeType(compiler); | 808 DartType type = member.computeType(compiler); |
| 840 SourceString helper = compiler.backend.getCheckedModeHelper(type); | 809 SourceString helper = compiler.backend.getCheckedModeHelper(type); |
| 841 FunctionElement helperElement = compiler.findHelper(helper); | 810 FunctionElement helperElement = compiler.findHelper(helper); |
| 842 String helperName = namer.isolateAccess(helperElement); | 811 String helperName = namer.isolateAccess(helperElement); |
| 843 String additionalArgument = ''; | 812 String additionalArgument = ''; |
| 844 if (helperElement.computeSignature(compiler).parameterCount != 1) { | 813 if (helperElement.computeSignature(compiler).parameterCount != 1) { |
| 845 additionalArgument = ", '${namer.operatorIs(type.element)}'"; | 814 additionalArgument = ", '${namer.operatorIs(type.element)}'"; |
| 846 } | 815 } |
| 847 String setterName = | 816 String setterName = namer.setterName(member.getLibrary(), member.name); |
| 848 namer.publicSetterName(new SourceString(accessorName)); | |
| 849 buffer.add("$setterName: function(v) { " | 817 buffer.add("$setterName: function(v) { " |
| 850 "this.$fieldName = $helperName(v$additionalArgument); }"); | 818 "this.$fieldName = $helperName(v$additionalArgument); }"); |
| 851 } | 819 } |
| 852 | 820 |
| 853 void emitClassConstructor(ClassElement classElement, CodeBuffer buffer) { | 821 void emitClassConstructor(ClassElement classElement, CodeBuffer buffer) { |
| 854 /* Do nothing. */ | 822 /* Do nothing. */ |
| 855 } | 823 } |
| 856 | 824 |
| 857 void emitClassFields(ClassElement classElement, | 825 void emitClassFields(ClassElement classElement, |
| 858 CodeBuffer buffer, | 826 CodeBuffer buffer, |
| 859 bool emitEndingComma) { | 827 bool emitEndingComma) { |
| 860 bool isFirstField = true; | 828 bool isFirstField = true; |
| 861 visitClassFields(classElement, (Element member, | 829 visitClassFields(classElement, (Element member, |
| 862 String name, | 830 String name, |
| 863 String accessorName, | |
| 864 bool needsGetter, | 831 bool needsGetter, |
| 865 bool needsSetter, | 832 bool needsSetter, |
| 866 bool needsCheckedSetter) { | 833 bool needsCheckedSetter) { |
| 867 if (isFirstField) { | 834 if (isFirstField) { |
| 868 buffer.add('"": ['); | 835 buffer.add('"": ['); |
| 869 isFirstField = false; | 836 isFirstField = false; |
| 870 } else { | 837 } else { |
| 871 buffer.add(", "); | 838 buffer.add(", "); |
| 872 } | 839 } |
| 873 buffer.add('"$accessorName'); | 840 buffer.add('"$name'); |
| 874 int flag = 0; | |
| 875 if (name != accessorName) { | |
| 876 buffer.add(':$name'); | |
| 877 assert(needsGetter || needsSetter); | |
| 878 flag = RENAMING_FLAG; | |
| 879 } | |
| 880 if (needsGetter && needsSetter) { | 841 if (needsGetter && needsSetter) { |
| 881 buffer.addCharCode(GETTER_SETTER_CODE + flag); | 842 buffer.add(GETTER_SETTER_SUFFIX); |
| 882 } else if (needsGetter) { | 843 } else if (needsGetter) { |
| 883 buffer.addCharCode(GETTER_CODE + flag); | 844 buffer.add(GETTER_SUFFIX); |
| 884 } else if (needsSetter) { | 845 } else if (needsSetter) { |
| 885 buffer.addCharCode(SETTER_CODE + flag); | 846 buffer.add(SETTER_SUFFIX); |
| 886 } | 847 } |
| 887 buffer.add('"'); | 848 buffer.add('"'); |
| 888 }); | 849 }); |
| 889 if (!isFirstField) { | 850 if (!isFirstField) { |
| 890 // There was at least one field. | 851 // There was at least one field. |
| 891 buffer.add(']'); | 852 buffer.add(']'); |
| 892 if (emitEndingComma) { | 853 if (emitEndingComma) { |
| 893 buffer.add(','); | 854 buffer.add(','); |
| 894 } | 855 } |
| 895 } | 856 } |
| 896 } | 857 } |
| 897 | 858 |
| 898 /** Each getter/setter must be prefixed with a ",\n ". */ | 859 /** Each getter/setter must be prefixed with a ",\n ". */ |
| 899 void emitClassGettersSetters(ClassElement classElement, | 860 void emitClassGettersSetters(ClassElement classElement, |
| 900 CodeBuffer buffer, | 861 CodeBuffer buffer, |
| 901 bool emitLeadingComma) { | 862 bool emitLeadingComma) { |
| 902 visitClassFields(classElement, (Element member, | 863 visitClassFields(classElement, (Element member, |
| 903 String name, | 864 String name, |
| 904 String accessorName, | |
| 905 bool needsGetter, | 865 bool needsGetter, |
| 906 bool needsSetter, | 866 bool needsSetter, |
| 907 bool needsCheckedSetter) { | 867 bool needsCheckedSetter) { |
| 908 if (needsCheckedSetter) { | 868 if (needsCheckedSetter) { |
| 909 assert(!needsSetter); | 869 assert(!needsSetter); |
| 910 if (emitLeadingComma) { | 870 if (emitLeadingComma) { |
| 911 buffer.add(",\n "); | 871 buffer.add(",\n "); |
| 912 } else { | 872 } else { |
| 913 emitLeadingComma = true; | 873 emitLeadingComma = true; |
| 914 } | 874 } |
| 915 generateCheckedSetter(member, name, accessorName, buffer); | 875 generateCheckedSetter(member, name, buffer); |
| 916 } | 876 } |
| 917 }); | 877 }); |
| 918 } | 878 } |
| 919 | 879 |
| 920 /** | 880 /** |
| 921 * Documentation wanted -- johnniwinther | 881 * Documentation wanted -- johnniwinther |
| 922 * | 882 * |
| 923 * Invariant: [classElement] must be a declaration element. | 883 * Invariant: [classElement] must be a declaration element. |
| 924 */ | 884 */ |
| 925 void generateClass(ClassElement classElement, CodeBuffer buffer) { | 885 void generateClass(ClassElement classElement, CodeBuffer buffer) { |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1131 | 1091 |
| 1132 void emitStaticFunctionGetters(CodeBuffer buffer) { | 1092 void emitStaticFunctionGetters(CodeBuffer buffer) { |
| 1133 Set<FunctionElement> functionsNeedingGetter = | 1093 Set<FunctionElement> functionsNeedingGetter = |
| 1134 compiler.codegenWorld.staticFunctionsNeedingGetter; | 1094 compiler.codegenWorld.staticFunctionsNeedingGetter; |
| 1135 for (FunctionElement element in functionsNeedingGetter) { | 1095 for (FunctionElement element in functionsNeedingGetter) { |
| 1136 // The static function does not have the correct name. Since | 1096 // The static function does not have the correct name. Since |
| 1137 // [addParameterStubs] use the name to create its stubs we simply | 1097 // [addParameterStubs] use the name to create its stubs we simply |
| 1138 // create a fake element with the correct name. | 1098 // create a fake element with the correct name. |
| 1139 // Note: the callElement will not have any enclosingElement. | 1099 // Note: the callElement will not have any enclosingElement. |
| 1140 FunctionElement callElement = | 1100 FunctionElement callElement = |
| 1141 new ClosureInvocationElement(namer.CLOSURE_INVOCATION_NAME, element); | 1101 new ClosureInvocationElement(Namer.CLOSURE_INVOCATION_NAME, element); |
| 1142 String staticName = namer.getName(element); | 1102 String staticName = namer.getName(element); |
| 1143 String invocationName = namer.instanceMethodName(callElement); | 1103 String invocationName = namer.instanceMethodName(callElement); |
| 1144 String fieldAccess = '$isolateProperties.$staticName'; | 1104 String fieldAccess = '$isolateProperties.$staticName'; |
| 1145 buffer.add("$fieldAccess.$invocationName = $fieldAccess;\n"); | 1105 buffer.add("$fieldAccess.$invocationName = $fieldAccess;\n"); |
| 1146 addParameterStubs(callElement, (String name, CodeBuffer value) { | 1106 addParameterStubs(callElement, (String name, CodeBuffer value) { |
| 1147 buffer.add('$fieldAccess.$name = $value;\n'); | 1107 buffer.add('$fieldAccess.$name = $value;\n'); |
| 1148 }); | 1108 }); |
| 1149 // If a static function is used as a closure we need to add its name | 1109 // If a static function is used as a closure we need to add its name |
| 1150 // in case it is used in spawnFunction. | 1110 // in case it is used in spawnFunction. |
| 1151 String fieldName = namer.STATIC_CLOSURE_NAME_NAME; | 1111 String fieldName = namer.STATIC_CLOSURE_NAME_NAME; |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1229 | 1189 |
| 1230 // Define the constructor with a name so that Object.toString can | 1190 // Define the constructor with a name so that Object.toString can |
| 1231 // find the class name of the closure class. | 1191 // find the class name of the closure class. |
| 1232 emitBoundClosureClassHeader( | 1192 emitBoundClosureClassHeader( |
| 1233 mangledName, superName, extraArgWithoutComma, boundClosureBuffer); | 1193 mangledName, superName, extraArgWithoutComma, boundClosureBuffer); |
| 1234 // Now add the methods on the closure class. The instance method does not | 1194 // Now add the methods on the closure class. The instance method does not |
| 1235 // have the correct name. Since [addParameterStubs] use the name to create | 1195 // have the correct name. Since [addParameterStubs] use the name to create |
| 1236 // its stubs we simply create a fake element with the correct name. | 1196 // its stubs we simply create a fake element with the correct name. |
| 1237 // Note: the callElement will not have any enclosingElement. | 1197 // Note: the callElement will not have any enclosingElement. |
| 1238 FunctionElement callElement = | 1198 FunctionElement callElement = |
| 1239 new ClosureInvocationElement(namer.CLOSURE_INVOCATION_NAME, member); | 1199 new ClosureInvocationElement(Namer.CLOSURE_INVOCATION_NAME, member); |
| 1240 | 1200 |
| 1241 String invocationName = namer.instanceMethodName(callElement); | 1201 String invocationName = namer.instanceMethodName(callElement); |
| 1242 List<String> arguments = new List<String>(parameterCount); | 1202 List<String> arguments = new List<String>(parameterCount); |
| 1243 for (int i = 0; i < parameterCount; i++) { | 1203 for (int i = 0; i < parameterCount; i++) { |
| 1244 arguments[i] = "p$i"; | 1204 arguments[i] = "p$i"; |
| 1245 } | 1205 } |
| 1246 String joinedArgs = Strings.join(arguments, ", "); | 1206 String joinedArgs = Strings.join(arguments, ", "); |
| 1247 boundClosureBuffer.add( | 1207 boundClosureBuffer.add( |
| 1248 "$invocationName: function($joinedArgs) {"); | 1208 "$invocationName: function($joinedArgs) {"); |
| 1249 String callArgs = hasExtraArgument | 1209 String callArgs = hasExtraArgument |
| 1250 ? joinedArgs.isEmpty | 1210 ? joinedArgs.isEmpty |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1290 getter = "this.${namer.getterName(member.getLibrary(), member.name)}()"; | 1250 getter = "this.${namer.getterName(member.getLibrary(), member.name)}()"; |
| 1291 } else { | 1251 } else { |
| 1292 String name = namer.instanceFieldName(memberLibrary, member.name); | 1252 String name = namer.instanceFieldName(memberLibrary, member.name); |
| 1293 getter = "this.$name"; | 1253 getter = "this.$name"; |
| 1294 } | 1254 } |
| 1295 for (Selector selector in selectors) { | 1255 for (Selector selector in selectors) { |
| 1296 if (selector.applies(member, compiler)) { | 1256 if (selector.applies(member, compiler)) { |
| 1297 String invocationName = | 1257 String invocationName = |
| 1298 namer.instanceMethodInvocationName(memberLibrary, member.name, | 1258 namer.instanceMethodInvocationName(memberLibrary, member.name, |
| 1299 selector); | 1259 selector); |
| 1300 SourceString callName = namer.CLOSURE_INVOCATION_NAME; | 1260 SourceString callName = Namer.CLOSURE_INVOCATION_NAME; |
| 1301 String closureCallName = | 1261 String closureCallName = |
| 1302 namer.instanceMethodInvocationName(memberLibrary, callName, | 1262 namer.instanceMethodInvocationName(memberLibrary, callName, |
| 1303 selector); | 1263 selector); |
| 1304 List<String> arguments = <String>[]; | 1264 List<String> arguments = <String>[]; |
| 1305 for (int i = 0; i < selector.argumentCount; i++) { | 1265 for (int i = 0; i < selector.argumentCount; i++) { |
| 1306 arguments.add("arg$i"); | 1266 arguments.add("arg$i"); |
| 1307 } | 1267 } |
| 1308 String joined = Strings.join(arguments, ", "); | 1268 String joined = Strings.join(arguments, ", "); |
| 1309 CodeBuffer getterBuffer = new CodeBuffer(); | 1269 CodeBuffer getterBuffer = new CodeBuffer(); |
| 1310 getterBuffer.add( | 1270 getterBuffer.add( |
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1470 CodeBuffer argNames = new CodeBuffer(); | 1430 CodeBuffer argNames = new CodeBuffer(); |
| 1471 List<SourceString> names = selector.getOrderedNamedArguments(); | 1431 List<SourceString> names = selector.getOrderedNamedArguments(); |
| 1472 for (int i = 0; i < names.length; i++) { | 1432 for (int i = 0; i < names.length; i++) { |
| 1473 if (i != 0) argNames.add(', '); | 1433 if (i != 0) argNames.add(', '); |
| 1474 argNames.add('"'); | 1434 argNames.add('"'); |
| 1475 argNames.add(names[i].slowToString()); | 1435 argNames.add(names[i].slowToString()); |
| 1476 argNames.add('"'); | 1436 argNames.add('"'); |
| 1477 } | 1437 } |
| 1478 String internalName = namer.instanceMethodInvocationName( | 1438 String internalName = namer.instanceMethodInvocationName( |
| 1479 selector.library, new SourceString(methodName), selector); | 1439 selector.library, new SourceString(methodName), selector); |
| 1480 Element createInvocationMirror = | |
| 1481 compiler.findHelper(const SourceString('createInvocationMirror')); | |
| 1482 CodeBuffer buffer = new CodeBuffer(); | 1440 CodeBuffer buffer = new CodeBuffer(); |
| 1483 buffer.add('function($args) {\n'); | 1441 buffer.add('function($args) {\n'); |
| 1484 buffer.add(' return this.$noSuchMethodName(' | 1442 buffer.add(' return this.$noSuchMethodName(' |
| 1485 '${namer.isolateAccess(createInvocationMirror)}(' | 1443 '\$.createInvocationMirror("$methodName", "$internalName",' |
| 1486 '"$methodName", "$internalName",' | 1444 ' $type, [$args], [$argNames]));\n'); |
| 1487 '$type, [$args], [$argNames]));\n'); | |
| 1488 buffer.add(' }'); | 1445 buffer.add(' }'); |
| 1489 return buffer; | 1446 return buffer; |
| 1490 } | 1447 } |
| 1491 | 1448 |
| 1492 void addNoSuchMethodHandlers(SourceString ignore, Set<Selector> selectors) { | 1449 void addNoSuchMethodHandlers(SourceString ignore, Set<Selector> selectors) { |
| 1493 // Cache the object class and type. | 1450 // Cache the object class and type. |
| 1494 ClassElement objectClass = compiler.objectClass; | 1451 ClassElement objectClass = compiler.objectClass; |
| 1495 DartType objectType = objectClass.computeType(compiler); | 1452 DartType objectType = objectClass.computeType(compiler); |
| 1496 | 1453 |
| 1497 for (Selector selector in selectors) { | 1454 for (Selector selector in selectors) { |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1650 compiler.isolateLibrary.find(Compiler.START_ROOT_ISOLATE); | 1607 compiler.isolateLibrary.find(Compiler.START_ROOT_ISOLATE); |
| 1651 mainCall = buildIsolateSetup(buffer, main, isolateMain); | 1608 mainCall = buildIsolateSetup(buffer, main, isolateMain); |
| 1652 } else { | 1609 } else { |
| 1653 mainCall = '${namer.isolateAccess(main)}()'; | 1610 mainCall = '${namer.isolateAccess(main)}()'; |
| 1654 } | 1611 } |
| 1655 buffer.add(""" | 1612 buffer.add(""" |
| 1656 | 1613 |
| 1657 // | 1614 // |
| 1658 // BEGIN invoke [main]. | 1615 // BEGIN invoke [main]. |
| 1659 // | 1616 // |
| 1660 if (typeof document !== 'undefined' && document.readyState != 'complete') { | 1617 if (typeof document != 'undefined' && document.readyState != 'complete') { |
| 1661 document.addEventListener('readystatechange', function () { | 1618 document.addEventListener('readystatechange', function () { |
| 1662 if (document.readyState == 'complete') { | 1619 if (document.readyState == 'complete') { |
| 1663 if (typeof dartMainRunner === 'function') { | 1620 if (typeof dartMainRunner == 'function') { |
| 1664 dartMainRunner(function() { ${mainCall}; }); | 1621 dartMainRunner(function() { ${mainCall}; }); |
| 1665 } else { | 1622 } else { |
| 1666 ${mainCall}; | 1623 ${mainCall}; |
| 1667 } | 1624 } |
| 1668 } | 1625 } |
| 1669 }, false); | 1626 }, false); |
| 1670 } else { | 1627 } else { |
| 1671 if (typeof dartMainRunner === 'function') { | 1628 if (typeof dartMainRunner == 'function') { |
| 1672 dartMainRunner(function() { ${mainCall}; }); | 1629 dartMainRunner(function() { ${mainCall}; }); |
| 1673 } else { | 1630 } else { |
| 1674 ${mainCall}; | 1631 ${mainCall}; |
| 1675 } | 1632 } |
| 1676 } | 1633 } |
| 1677 // | 1634 // |
| 1678 // END invoke [main]. | 1635 // END invoke [main]. |
| 1679 // | 1636 // |
| 1680 | 1637 |
| 1681 """); | 1638 """); |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1756 const String HOOKS_API_USAGE = """ | 1713 const String HOOKS_API_USAGE = """ |
| 1757 // Generated by dart2js, the Dart to JavaScript compiler. | 1714 // Generated by dart2js, the Dart to JavaScript compiler. |
| 1758 // The code supports the following hooks: | 1715 // The code supports the following hooks: |
| 1759 // dartPrint(message) - if this function is defined it is called | 1716 // dartPrint(message) - if this function is defined it is called |
| 1760 // instead of the Dart [print] method. | 1717 // instead of the Dart [print] method. |
| 1761 // dartMainRunner(main) - if this function is defined, the Dart [main] | 1718 // dartMainRunner(main) - if this function is defined, the Dart [main] |
| 1762 // method will not be invoked directly. | 1719 // method will not be invoked directly. |
| 1763 // Instead, a closure that will invoke [main] is | 1720 // Instead, a closure that will invoke [main] is |
| 1764 // passed to [dartMainRunner]. | 1721 // passed to [dartMainRunner]. |
| 1765 """; | 1722 """; |
| OLD | NEW |