Chromium Code Reviews| 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 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 103 => '${namer.ISOLATE}.\$finishIsolateConstructor'; | 103 => '${namer.ISOLATE}.\$finishIsolateConstructor'; |
| 104 String get pendingClassesName | 104 String get pendingClassesName |
| 105 => '${namer.ISOLATE}.\$pendingClasses'; | 105 => '${namer.ISOLATE}.\$pendingClasses'; |
| 106 String get isolatePropertiesName | 106 String get isolatePropertiesName |
| 107 => '${namer.ISOLATE}.${namer.ISOLATE_PROPERTIES}'; | 107 => '${namer.ISOLATE}.${namer.ISOLATE_PROPERTIES}'; |
| 108 String get supportsProtoName | 108 String get supportsProtoName |
| 109 => 'supportsProto'; | 109 => 'supportsProto'; |
| 110 String get lazyInitializerName | 110 String get lazyInitializerName |
| 111 => '${namer.ISOLATE}.\$lazy'; | 111 => '${namer.ISOLATE}.\$lazy'; |
| 112 | 112 |
| 113 final String GETTER_SUFFIX = "?"; | 113 // Property name suffixes. If the accessors are renaming then the format |
| 114 final String SETTER_SUFFIX = "!"; | 114 // is <accessorName>:<fieldName><suffix>. We use the suffix to know whether |
| 115 final String GETTER_SETTER_SUFFIX = "="; | 115 // to look for the ':' separator in order to avoid doing the indexOf operation |
| 116 // on every single property (they are quite rare). None of these characters | |
| 117 // are legal in an identifier and they are related by bit patterns. | |
| 118 // setter < 0x3c | |
| 119 // both = 0x3d | |
| 120 // getter > 0x3e | |
| 121 // renaming setter | 0x7c | |
| 122 // renaming both } 0x7d | |
| 123 // renaming getter ~ 0x7e | |
| 124 const SUFFIX_MASK = 0x3f; | |
| 125 const FIRST_SUFFIX_CODE = 0x3c; | |
| 126 const SETTER_CODE = 0x3c; | |
| 127 const GETTER_SETTER_CODE = 0x3d; | |
| 128 const GETTER_CODE = 0x3e; | |
| 129 const RENAMING_FLAG = 0x40; | |
| 130 String needsGetterCode(String variable) => '($variable & 3) > 0'; | |
| 131 String needsSetterCode(String variable) => '($variable & 2) == 0'; | |
| 132 String isRenaming(String variable) => '($variable & $RENAMING_FLAG) != 0'; | |
| 116 | 133 |
| 117 String get generateAccessorFunction { | 134 String get generateAccessorFunction { |
| 118 return """ | 135 return """ |
| 119 function generateAccessor(field, prototype) { | 136 function generateAccessor(field, prototype) { |
| 120 var len = field.length; | 137 var len = field.length; |
| 121 var lastChar = field[len - 1]; | 138 var lastCharCode = field.charCodeAt(len - 1); |
| 122 var needsGetter = lastChar == '$GETTER_SUFFIX' || lastChar == '$GETTER_SETTER_ SUFFIX'; | 139 var needsAccessor = (lastCharCode & $SUFFIX_MASK) >= $FIRST_SUFFIX_CODE; |
| 123 var needsSetter = lastChar == '$SETTER_SUFFIX' || lastChar == '$GETTER_SETTER_ SUFFIX'; | 140 if (needsAccessor) { |
| 124 if (needsGetter || needsSetter) field = field.substring(0, len - 1); | 141 var needsGetter = ${needsGetterCode('lastCharCode')}; |
| 125 if (needsGetter) { | 142 var needsSetter = ${needsSetterCode('lastCharCode')}; |
| 126 var getterString = "return this." + field + ";"; | 143 var renaming = ${isRenaming('lastCharCode')}; |
| 127 """ | 144 var accessorName = field = field.substring(0, len - 1); |
| 128 /* The supportsProtoCheck below depends on the getter/setter convention. | 145 if (renaming) { |
| 129 When changing here, update the protoCheck too. */ | 146 var divider = field.indexOf(":"); |
| 130 """ | 147 accessorName = field.substring(0, divider); |
| 131 prototype["get\$" + field] = new Function(getterString); | 148 field = field.substring(divider + 1); |
| 149 } | |
| 150 if (needsGetter) { | |
| 151 var getterString = "return this." + field + ";"; | |
| 152 prototype["get\$" + accessorName] = new Function(getterString); | |
| 132 } | 153 } |
| 133 if (needsSetter) { | 154 if (needsSetter) { |
| 134 var setterString = "this." + field + " = v;"; | 155 var setterString = "this." + field + " = v;"; |
| 135 prototype["set\$" + field] = new Function("v", setterString); | 156 prototype["set\$" + accessorName] = new Function("v", setterString); |
| 136 } | 157 } |
| 137 return field; | 158 } |
| 138 }"""; | 159 return field; |
| 160 }"""; | |
| 139 } | 161 } |
| 140 | 162 |
| 141 String get defineClassFunction { | 163 String get defineClassFunction { |
| 142 // First the class name, then the field names in an array and the members | 164 // First the class name, then the field names in an array and the members |
| 143 // (inside an Object literal). | 165 // (inside an Object literal). |
| 144 // The caller can also pass in the constructor as a function if needed. | 166 // The caller can also pass in the constructor as a function if needed. |
| 145 // | 167 // |
| 146 // Example: | 168 // Example: |
| 147 // defineClass("A", ["x", "y"], { | 169 // defineClass("A", ["x", "y"], { |
| 148 // foo$1: function(y) { | 170 // foo$1: function(y) { |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 186 // (http://my.opera.com/desktopteam/blog/2012/07/20/more-12-01-fixes). | 208 // (http://my.opera.com/desktopteam/blog/2012/07/20/more-12-01-fixes). |
| 187 // If the browser does not support __proto__ we need to instantiate an | 209 // If the browser does not support __proto__ we need to instantiate an |
| 188 // object with the correct (internal) prototype set up correctly, and then | 210 // object with the correct (internal) prototype set up correctly, and then |
| 189 // copy the members. | 211 // copy the members. |
| 190 | 212 |
| 191 return ''' | 213 return ''' |
| 192 var $supportsProtoName = false; | 214 var $supportsProtoName = false; |
| 193 var tmp = $defineClassName('c', ['f?'], {}).prototype; | 215 var tmp = $defineClassName('c', ['f?'], {}).prototype; |
| 194 if (tmp.__proto__) { | 216 if (tmp.__proto__) { |
| 195 tmp.__proto__ = {}; | 217 tmp.__proto__ = {}; |
| 196 if (typeof tmp.get\$f !== "undefined") $supportsProtoName = true; | 218 if (typeof tmp.get\$f !== 'undefined') $supportsProtoName = true; |
| 197 } | 219 } |
| 198 '''; | 220 '''; |
| 199 } | 221 } |
| 200 | 222 |
| 201 String get finishClassesFunction { | 223 String get finishClassesFunction { |
| 202 // 'defineClass' does not require the classes to be constructed in order. | 224 // 'defineClass' does not require the classes to be constructed in order. |
| 203 // Classes are initially just stored in the 'pendingClasses' field. | 225 // Classes are initially just stored in the 'pendingClasses' field. |
| 204 // 'finishClasses' takes all pending classes and sets up the prototype. | 226 // 'finishClasses' takes all pending classes and sets up the prototype. |
| 205 // Once set up, the constructors prototype field satisfy: | 227 // Once set up, the constructors prototype field satisfy: |
| 206 // - it contains all (local) members. | 228 // - it contains all (local) members. |
| (...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 520 // (3) foo$3$d(a, b, d) => foo$4$c$d(a, b, null, d); | 542 // (3) foo$3$d(a, b, d) => foo$4$c$d(a, b, null, d); |
| 521 // (4) No stub generated, call is direct. | 543 // (4) No stub generated, call is direct. |
| 522 // (5) No stub generated, call is direct. | 544 // (5) No stub generated, call is direct. |
| 523 | 545 |
| 524 // Keep a cache of which stubs have already been generated, to | 546 // Keep a cache of which stubs have already been generated, to |
| 525 // avoid duplicates. Note that even if selectors are | 547 // avoid duplicates. Note that even if selectors are |
| 526 // canonicalized, we would still need this cache: a typed selector | 548 // canonicalized, we would still need this cache: a typed selector |
| 527 // on A and a typed selector on B could yield the same stub. | 549 // on A and a typed selector on B could yield the same stub. |
| 528 Set<String> generatedStubNames = new Set<String>(); | 550 Set<String> generatedStubNames = new Set<String>(); |
| 529 if (compiler.enabledFunctionApply | 551 if (compiler.enabledFunctionApply |
| 530 && member.name == Namer.CLOSURE_INVOCATION_NAME) { | 552 && member.name == namer.CLOSURE_INVOCATION_NAME) { |
| 531 // If [Function.apply] is called, we pessimistically compile all | 553 // If [Function.apply] is called, we pessimistically compile all |
| 532 // possible stubs for this closure. | 554 // possible stubs for this closure. |
| 533 FunctionSignature signature = member.computeSignature(compiler); | 555 FunctionSignature signature = member.computeSignature(compiler); |
| 534 Set<Selector> selectors = signature.optionalParametersAreNamed | 556 Set<Selector> selectors = signature.optionalParametersAreNamed |
| 535 ? computeNamedSelectors(signature, member) | 557 ? computeNamedSelectors(signature, member) |
| 536 : computeOptionalSelectors(signature, member); | 558 : computeOptionalSelectors(signature, member); |
| 537 for (Selector selector in selectors) { | 559 for (Selector selector in selectors) { |
| 538 addParameterStub( | 560 addParameterStub( |
| 539 member, selector, defineInstanceMember, generatedStubNames); | 561 member, selector, defineInstanceMember, generatedStubNames); |
| 540 } | 562 } |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 615 | 637 |
| 616 bool instanceFieldNeedsSetter(Element member) { | 638 bool instanceFieldNeedsSetter(Element member) { |
| 617 assert(member.isField()); | 639 assert(member.isField()); |
| 618 return (!member.modifiers.isFinalOrConst()) | 640 return (!member.modifiers.isFinalOrConst()) |
| 619 && compiler.codegenWorld.hasInvokedSetter(member, compiler); | 641 && compiler.codegenWorld.hasInvokedSetter(member, compiler); |
| 620 } | 642 } |
| 621 | 643 |
| 622 String compiledFieldName(Element member) { | 644 String compiledFieldName(Element member) { |
| 623 assert(member.isField()); | 645 assert(member.isField()); |
| 624 return member.isNative() | 646 return member.isNative() |
| 625 ? member.name.slowToString() | 647 ? member.nativeName() |
| 626 : namer.getName(member); | 648 : namer.getName(member); |
| 627 } | 649 } |
| 628 | 650 |
| 629 /** | 651 /** |
| 630 * Documentation wanted -- johnniwinther | 652 * Documentation wanted -- johnniwinther |
| 631 * | 653 * |
| 632 * Invariant: [member] must be a declaration element. | 654 * Invariant: [member] must be a declaration element. |
| 633 */ | 655 */ |
| 634 void addInstanceMember(Element member, | 656 void addInstanceMember(Element member, |
| 635 DefineMemberFunction defineInstanceMember) { | 657 DefineMemberFunction defineInstanceMember) { |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 719 } | 741 } |
| 720 | 742 |
| 721 /** | 743 /** |
| 722 * Documentation wanted -- johnniwinther | 744 * Documentation wanted -- johnniwinther |
| 723 * | 745 * |
| 724 * Invariant: [classElement] must be a declaration element. | 746 * Invariant: [classElement] must be a declaration element. |
| 725 */ | 747 */ |
| 726 void visitClassFields(ClassElement classElement, | 748 void visitClassFields(ClassElement classElement, |
| 727 void addField(Element member, | 749 void addField(Element member, |
| 728 String name, | 750 String name, |
| 751 String accessorName, | |
| 729 bool needsGetter, | 752 bool needsGetter, |
| 730 bool needsSetter, | 753 bool needsSetter, |
| 731 bool needsCheckedSetter)) { | 754 bool needsCheckedSetter)) { |
| 732 assert(invariant(classElement, classElement.isDeclaration)); | 755 assert(invariant(classElement, classElement.isDeclaration)); |
| 733 // If the class is never instantiated we still need to set it up for | 756 // If the class is never instantiated we still need to set it up for |
| 734 // inheritance purposes, but we can simplify its JavaScript constructor. | 757 // inheritance purposes, but we can simplify its JavaScript constructor. |
| 735 bool isInstantiated = | 758 bool isInstantiated = |
| 736 compiler.codegenWorld.instantiatedClasses.contains(classElement); | 759 compiler.codegenWorld.instantiatedClasses.contains(classElement); |
| 737 | 760 |
| 738 void visitField(ClassElement enclosingClass, Element member) { | 761 void visitField(ClassElement enclosingClass, Element member) { |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 757 isShadowed = classElement.isShadowedByField(member); | 780 isShadowed = classElement.isShadowedByField(member); |
| 758 } | 781 } |
| 759 | 782 |
| 760 if ((isInstantiated && !enclosingClass.isNative()) | 783 if ((isInstantiated && !enclosingClass.isNative()) |
| 761 || needsGetter | 784 || needsGetter |
| 762 || needsSetter) { | 785 || needsSetter) { |
| 763 String accessorName = isShadowed | 786 String accessorName = isShadowed |
| 764 ? namer.shadowedFieldName(member) | 787 ? namer.shadowedFieldName(member) |
| 765 : namer.getName(member); | 788 : namer.getName(member); |
| 766 String fieldName = member.isNative() | 789 String fieldName = member.isNative() |
| 767 ? member.nativeName() | 790 ? member.nativeName() |
|
floitsch
2012/12/07 12:01:01
accidental space?
erikcorry
2012/12/10 08:36:01
Done.
| |
| 768 : accessorName; | 791 : accessorName; |
| 769 bool needsCheckedSetter = false; | 792 bool needsCheckedSetter = false; |
| 770 if (needsSetter && compiler.enableTypeAssertions | 793 if (needsSetter && compiler.enableTypeAssertions |
| 771 && canGenerateCheckedSetter(member)) { | 794 && canGenerateCheckedSetter(member)) { |
| 772 needsCheckedSetter = true; | 795 needsCheckedSetter = true; |
| 773 needsSetter = false; | 796 needsSetter = false; |
| 774 } | 797 } |
| 775 // Getters and setters with suffixes will be generated dynamically. | 798 // Getters and setters with suffixes will be generated dynamically. |
| 776 addField(member, | 799 addField(member, |
| 777 fieldName, | 800 fieldName, |
| 801 accessorName, | |
| 778 needsGetter, | 802 needsGetter, |
| 779 needsSetter, | 803 needsSetter, |
| 780 needsCheckedSetter); | 804 needsCheckedSetter); |
| 781 } | 805 } |
| 782 } | 806 } |
| 783 | 807 |
| 784 // If a class is not instantiated then we add the field just so we can | 808 // If a class is not instantiated then we add the field just so we can |
| 785 // generate the field getter/setter dynamically. Since this is only | 809 // generate the field getter/setter dynamically. Since this is only |
| 786 // allowed on fields that are in [classElement] we don't need to visit | 810 // allowed on fields that are in [classElement] we don't need to visit |
| 787 // superclasses for non-instantiated classes. | 811 // superclasses for non-instantiated classes. |
| 788 classElement.implementation.forEachInstanceField( | 812 classElement.implementation.forEachInstanceField( |
| 789 visitField, | 813 visitField, |
| 790 includeBackendMembers: true, | 814 includeBackendMembers: true, |
| 791 includeSuperMembers: isInstantiated && !classElement.isNative()); | 815 includeSuperMembers: isInstantiated && !classElement.isNative()); |
| 792 } | 816 } |
| 793 | 817 |
| 794 void generateGetter(Element member, String fieldName, CodeBuffer buffer) { | |
| 795 String getterName = namer.getterName(member.getLibrary(), member.name); | |
| 796 buffer.add("$getterName: function() { return this.$fieldName; }"); | |
| 797 } | |
| 798 | |
| 799 void generateSetter(Element member, String fieldName, CodeBuffer buffer) { | |
| 800 String setterName = namer.setterName(member.getLibrary(), member.name); | |
| 801 buffer.add("$setterName: function(v) { this.$fieldName = v; }"); | |
| 802 } | |
| 803 | |
| 804 bool canGenerateCheckedSetter(Element member) { | 818 bool canGenerateCheckedSetter(Element member) { |
| 805 DartType type = member.computeType(compiler); | 819 DartType type = member.computeType(compiler); |
| 806 if (type.element.isTypeVariable() | 820 if (type.element.isTypeVariable() |
| 807 || type.element == compiler.dynamicClass | 821 || type.element == compiler.dynamicClass |
| 808 || type.element == compiler.objectClass) { | 822 || type.element == compiler.objectClass) { |
| 809 // TODO(ngeoffray): Support type checks on type parameters. | 823 // TODO(ngeoffray): Support type checks on type parameters. |
| 810 return false; | 824 return false; |
| 811 } | 825 } |
| 812 return true; | 826 return true; |
| 813 } | 827 } |
| 814 | 828 |
| 815 void generateCheckedSetter(Element member, | 829 void generateCheckedSetter(Element member, |
| 816 String fieldName, | 830 String fieldName, |
| 831 String accessorName, | |
| 817 CodeBuffer buffer) { | 832 CodeBuffer buffer) { |
| 818 assert(canGenerateCheckedSetter(member)); | 833 assert(canGenerateCheckedSetter(member)); |
| 819 DartType type = member.computeType(compiler); | 834 DartType type = member.computeType(compiler); |
| 820 SourceString helper = compiler.backend.getCheckedModeHelper(type); | 835 SourceString helper = compiler.backend.getCheckedModeHelper(type); |
| 821 FunctionElement helperElement = compiler.findHelper(helper); | 836 FunctionElement helperElement = compiler.findHelper(helper); |
| 822 String helperName = namer.isolateAccess(helperElement); | 837 String helperName = namer.isolateAccess(helperElement); |
| 823 String additionalArgument = ''; | 838 String additionalArgument = ''; |
| 824 if (helperElement.computeSignature(compiler).parameterCount != 1) { | 839 if (helperElement.computeSignature(compiler).parameterCount != 1) { |
| 825 additionalArgument = ", '${namer.operatorIs(type.element)}'"; | 840 additionalArgument = ", '${namer.operatorIs(type.element)}'"; |
| 826 } | 841 } |
| 827 String setterName = namer.setterName(member.getLibrary(), member.name); | 842 String setterName = |
| 843 namer.setterNameFromAccessorName(accessorName); | |
|
sra1
2012/12/07 06:03:18
Single line?
erikcorry
2012/12/10 08:36:01
Done.
| |
| 828 buffer.add("$setterName: function(v) { " | 844 buffer.add("$setterName: function(v) { " |
| 829 "this.$fieldName = $helperName(v$additionalArgument); }"); | 845 "this.$fieldName = $helperName(v$additionalArgument); }"); |
| 830 } | 846 } |
| 831 | 847 |
| 832 void emitClassConstructor(ClassElement classElement, CodeBuffer buffer) { | 848 void emitClassConstructor(ClassElement classElement, CodeBuffer buffer) { |
| 833 /* Do nothing. */ | 849 /* Do nothing. */ |
| 834 } | 850 } |
| 835 | 851 |
| 836 void emitClassFields(ClassElement classElement, | 852 void emitClassFields(ClassElement classElement, |
| 837 CodeBuffer buffer, | 853 CodeBuffer buffer, |
| 838 bool emitEndingComma, | 854 bool emitEndingComma, |
| 839 { String superClass: "", | 855 { String superClass: "", |
| 840 bool isNative: false}) { | 856 bool isNative: false}) { |
| 841 bool isFirstField = true; | 857 bool isFirstField = true; |
| 842 bool isAnythingOutput = false; | 858 bool isAnythingOutput = false; |
| 843 if (!isNative) { | 859 if (!isNative) { |
| 844 buffer.add('"":"$superClass;'); | 860 buffer.add('"":"$superClass;'); |
| 845 isAnythingOutput = true; | 861 isAnythingOutput = true; |
| 846 } | 862 } |
| 847 visitClassFields(classElement, (Element member, | 863 visitClassFields(classElement, (Element member, |
| 848 String name, | 864 String name, |
| 865 String accessorName, | |
| 849 bool needsGetter, | 866 bool needsGetter, |
| 850 bool needsSetter, | 867 bool needsSetter, |
| 851 bool needsCheckedSetter) { | 868 bool needsCheckedSetter) { |
| 852 if (!getterAndSetterCanBeImplementedByFieldSpec( | |
| 853 member, name, needsGetter, needsSetter)) { | |
| 854 return; | |
| 855 } | |
| 856 if (!isNative || needsCheckedSetter || needsGetter || needsSetter) { | 869 if (!isNative || needsCheckedSetter || needsGetter || needsSetter) { |
| 857 if (isFirstField) { | 870 if (isFirstField) { |
| 858 isFirstField = false; | 871 isFirstField = false; |
| 859 if (!isAnythingOutput) { | 872 if (!isAnythingOutput) { |
| 860 buffer.add('"":"'); | 873 buffer.add('"":"'); |
| 861 isAnythingOutput = true; | 874 isAnythingOutput = true; |
| 862 } | 875 } |
| 863 } else { | 876 } else { |
| 864 buffer.add(","); | 877 buffer.add(","); |
| 865 } | 878 } |
| 866 buffer.add('$name'); | 879 buffer.add('$accessorName'); |
| 880 int flag = 0; | |
| 881 if (name != accessorName) { | |
| 882 buffer.add(':$name'); | |
| 883 assert(needsGetter || needsSetter); | |
| 884 flag = RENAMING_FLAG; | |
| 885 } | |
| 867 if (needsGetter && needsSetter) { | 886 if (needsGetter && needsSetter) { |
| 868 buffer.add(GETTER_SETTER_SUFFIX); | 887 buffer.addCharCode(GETTER_SETTER_CODE + flag); |
| 869 } else if (needsGetter) { | 888 } else if (needsGetter) { |
| 870 buffer.add(GETTER_SUFFIX); | 889 buffer.addCharCode(GETTER_CODE + flag); |
| 871 } else if (needsSetter) { | 890 } else if (needsSetter) { |
| 872 buffer.add(SETTER_SUFFIX); | 891 buffer.addCharCode(SETTER_CODE + flag); |
| 873 } | 892 } |
| 874 } | 893 } |
| 875 }); | 894 }); |
| 876 if (isAnythingOutput) { | 895 if (isAnythingOutput) { |
| 877 buffer.add('"'); | 896 buffer.add('"'); |
| 878 if (emitEndingComma) { | 897 if (emitEndingComma) { |
| 879 buffer.add(','); | 898 buffer.add(','); |
| 880 } | 899 } |
| 881 } | 900 } |
| 882 } | 901 } |
| 883 | 902 |
| 884 /** Each getter/setter must be prefixed with a ",\n ". */ | 903 /** Each getter/setter must be prefixed with a ",\n ". */ |
| 885 void emitClassGettersSetters(ClassElement classElement, | 904 void emitClassGettersSetters(ClassElement classElement, |
| 886 CodeBuffer buffer, | 905 CodeBuffer buffer, |
| 887 bool emitLeadingComma) { | 906 bool emitLeadingComma) { |
| 888 emitComma() { | 907 emitComma() { |
| 889 if (emitLeadingComma) { | 908 if (emitLeadingComma) { |
| 890 buffer.add(",\n "); | 909 buffer.add(",\n "); |
| 891 } else { | 910 } else { |
| 892 emitLeadingComma = true; | 911 emitLeadingComma = true; |
| 893 } | 912 } |
| 894 } | 913 } |
| 895 | 914 |
| 896 visitClassFields(classElement, (Element member, | 915 visitClassFields(classElement, (Element member, |
| 897 String name, | 916 String name, |
| 917 String accessorName, | |
| 898 bool needsGetter, | 918 bool needsGetter, |
| 899 bool needsSetter, | 919 bool needsSetter, |
| 900 bool needsCheckedSetter) { | 920 bool needsCheckedSetter) { |
| 901 if (name == null) throw 123; | |
| 902 if (getterAndSetterCanBeImplementedByFieldSpec( | |
| 903 member, name, needsGetter, needsSetter)) { | |
| 904 needsGetter = false; | |
| 905 needsSetter = false; | |
| 906 } | |
| 907 if (needsGetter) { | |
| 908 emitComma(); | |
| 909 generateGetter(member, name, buffer); | |
| 910 } | |
| 911 if (needsSetter) { | |
| 912 emitComma(); | |
| 913 generateSetter(member, name, buffer); | |
| 914 } | |
| 915 if (needsCheckedSetter) { | 921 if (needsCheckedSetter) { |
| 916 assert(!needsSetter); | 922 assert(!needsSetter); |
| 917 emitComma(); | 923 emitComma(); |
| 918 generateCheckedSetter(member, name, buffer); | 924 generateCheckedSetter(member, name, accessorName, buffer); |
| 919 } | 925 } |
| 920 }); | 926 }); |
| 921 } | 927 } |
| 922 | 928 |
| 923 bool getterAndSetterCanBeImplementedByFieldSpec(Element member, | |
| 924 String name, | |
| 925 bool needsGetter, | |
| 926 bool needsSetter) { | |
| 927 if (needsGetter) { | |
| 928 if (namer.getterName(member.getLibrary(), member.name) != 'get\$$name') { | |
| 929 return false; | |
| 930 } | |
| 931 } | |
| 932 if (needsSetter) { | |
| 933 if (namer.setterName(member.getLibrary(), member.name) != 'set\$$name') { | |
| 934 return false; | |
| 935 } | |
| 936 } | |
| 937 return true; | |
| 938 } | |
| 939 | |
| 940 /** | 929 /** |
| 941 * Documentation wanted -- johnniwinther | 930 * Documentation wanted -- johnniwinther |
| 942 * | 931 * |
| 943 * Invariant: [classElement] must be a declaration element. | 932 * Invariant: [classElement] must be a declaration element. |
| 944 */ | 933 */ |
| 945 void generateClass(ClassElement classElement, CodeBuffer buffer) { | 934 void generateClass(ClassElement classElement, CodeBuffer buffer) { |
| 946 assert(invariant(classElement, classElement.isDeclaration)); | 935 assert(invariant(classElement, classElement.isDeclaration)); |
| 947 if (classElement.isNative()) { | 936 if (classElement.isNative()) { |
| 948 nativeEmitter.generateNativeClass(classElement); | 937 nativeEmitter.generateNativeClass(classElement); |
| 949 return; | 938 return; |
| (...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1151 | 1140 |
| 1152 void emitStaticFunctionGetters(CodeBuffer buffer) { | 1141 void emitStaticFunctionGetters(CodeBuffer buffer) { |
| 1153 Set<FunctionElement> functionsNeedingGetter = | 1142 Set<FunctionElement> functionsNeedingGetter = |
| 1154 compiler.codegenWorld.staticFunctionsNeedingGetter; | 1143 compiler.codegenWorld.staticFunctionsNeedingGetter; |
| 1155 for (FunctionElement element in functionsNeedingGetter) { | 1144 for (FunctionElement element in functionsNeedingGetter) { |
| 1156 // The static function does not have the correct name. Since | 1145 // The static function does not have the correct name. Since |
| 1157 // [addParameterStubs] use the name to create its stubs we simply | 1146 // [addParameterStubs] use the name to create its stubs we simply |
| 1158 // create a fake element with the correct name. | 1147 // create a fake element with the correct name. |
| 1159 // Note: the callElement will not have any enclosingElement. | 1148 // Note: the callElement will not have any enclosingElement. |
| 1160 FunctionElement callElement = | 1149 FunctionElement callElement = |
| 1161 new ClosureInvocationElement(Namer.CLOSURE_INVOCATION_NAME, element); | 1150 new ClosureInvocationElement(namer.CLOSURE_INVOCATION_NAME, element); |
|
kasperl
2012/12/07 10:37:45
It looks a bit fishy to try to grab a constant (we
erikcorry
2012/12/10 08:36:01
Done and changed:
ISOLATE -> isolateName
ISOLATE_
| |
| 1162 String staticName = namer.getName(element); | 1151 String staticName = namer.getName(element); |
| 1163 String invocationName = namer.instanceMethodName(callElement); | 1152 String invocationName = namer.instanceMethodName(callElement); |
| 1164 String fieldAccess = '$isolateProperties.$staticName'; | 1153 String fieldAccess = '$isolateProperties.$staticName'; |
| 1165 buffer.add("$fieldAccess.$invocationName = $fieldAccess;\n"); | 1154 buffer.add("$fieldAccess.$invocationName = $fieldAccess;\n"); |
| 1166 addParameterStubs(callElement, (String name, CodeBuffer value) { | 1155 addParameterStubs(callElement, (String name, CodeBuffer value) { |
| 1167 buffer.add('$fieldAccess.$name = $value;\n'); | 1156 buffer.add('$fieldAccess.$name = $value;\n'); |
| 1168 }); | 1157 }); |
| 1169 // If a static function is used as a closure we need to add its name | 1158 // If a static function is used as a closure we need to add its name |
| 1170 // in case it is used in spawnFunction. | 1159 // in case it is used in spawnFunction. |
| 1171 String fieldName = namer.STATIC_CLOSURE_NAME_NAME; | 1160 String fieldName = namer.STATIC_CLOSURE_NAME_NAME; |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1248 | 1237 |
| 1249 // Define the constructor with a name so that Object.toString can | 1238 // Define the constructor with a name so that Object.toString can |
| 1250 // find the class name of the closure class. | 1239 // find the class name of the closure class. |
| 1251 emitBoundClosureClassHeader( | 1240 emitBoundClosureClassHeader( |
| 1252 mangledName, superName, extraArgWithoutComma, boundClosureBuffer); | 1241 mangledName, superName, extraArgWithoutComma, boundClosureBuffer); |
| 1253 // Now add the methods on the closure class. The instance method does not | 1242 // 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 | 1243 // have the correct name. Since [addParameterStubs] use the name to create |
| 1255 // its stubs we simply create a fake element with the correct name. | 1244 // its stubs we simply create a fake element with the correct name. |
| 1256 // Note: the callElement will not have any enclosingElement. | 1245 // Note: the callElement will not have any enclosingElement. |
| 1257 FunctionElement callElement = | 1246 FunctionElement callElement = |
| 1258 new ClosureInvocationElement(Namer.CLOSURE_INVOCATION_NAME, member); | 1247 new ClosureInvocationElement(namer.CLOSURE_INVOCATION_NAME, member); |
| 1259 | 1248 |
| 1260 String invocationName = namer.instanceMethodName(callElement); | 1249 String invocationName = namer.instanceMethodName(callElement); |
| 1261 List<String> arguments = new List<String>(parameterCount); | 1250 List<String> arguments = new List<String>(parameterCount); |
| 1262 for (int i = 0; i < parameterCount; i++) { | 1251 for (int i = 0; i < parameterCount; i++) { |
| 1263 arguments[i] = "p$i"; | 1252 arguments[i] = "p$i"; |
| 1264 } | 1253 } |
| 1265 String joinedArgs = Strings.join(arguments, ", "); | 1254 String joinedArgs = Strings.join(arguments, ", "); |
| 1266 boundClosureBuffer.add( | 1255 boundClosureBuffer.add( |
| 1267 "$invocationName: function($joinedArgs) {"); | 1256 "$invocationName: function($joinedArgs) {"); |
| 1268 String callArgs = hasExtraArgument | 1257 String callArgs = hasExtraArgument |
| 1269 ? joinedArgs.isEmpty | 1258 ? joinedArgs.isEmpty |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1319 ? member.nativeName() | 1308 ? member.nativeName() |
| 1320 : namer.instanceFieldName(memberLibrary, member.name); | 1309 : namer.instanceFieldName(memberLibrary, member.name); |
| 1321 getter = "this.$name"; | 1310 getter = "this.$name"; |
| 1322 } | 1311 } |
| 1323 | 1312 |
| 1324 for (Selector selector in selectors) { | 1313 for (Selector selector in selectors) { |
| 1325 if (selector.applies(member, compiler)) { | 1314 if (selector.applies(member, compiler)) { |
| 1326 String invocationName = | 1315 String invocationName = |
| 1327 namer.instanceMethodInvocationName(memberLibrary, member.name, | 1316 namer.instanceMethodInvocationName(memberLibrary, member.name, |
| 1328 selector); | 1317 selector); |
| 1329 SourceString callName = Namer.CLOSURE_INVOCATION_NAME; | 1318 SourceString callName = namer.CLOSURE_INVOCATION_NAME; |
| 1330 String closureCallName = | 1319 String closureCallName = |
| 1331 namer.instanceMethodInvocationName(memberLibrary, callName, | 1320 namer.instanceMethodInvocationName(memberLibrary, callName, |
| 1332 selector); | 1321 selector); |
| 1333 List<String> arguments = <String>[]; | 1322 List<String> arguments = <String>[]; |
| 1334 for (int i = 0; i < selector.argumentCount; i++) { | 1323 for (int i = 0; i < selector.argumentCount; i++) { |
| 1335 arguments.add("arg$i"); | 1324 arguments.add("arg$i"); |
| 1336 } | 1325 } |
| 1337 String joined = Strings.join(arguments, ", "); | 1326 String joined = Strings.join(arguments, ", "); |
| 1338 CodeBuffer getterBuffer = new CodeBuffer(); | 1327 CodeBuffer getterBuffer = new CodeBuffer(); |
| 1339 getterBuffer.add("function("); | 1328 getterBuffer.add("function("); |
| (...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1516 CodeBuffer argNames = new CodeBuffer(); | 1505 CodeBuffer argNames = new CodeBuffer(); |
| 1517 List<SourceString> names = selector.getOrderedNamedArguments(); | 1506 List<SourceString> names = selector.getOrderedNamedArguments(); |
| 1518 for (int i = 0; i < names.length; i++) { | 1507 for (int i = 0; i < names.length; i++) { |
| 1519 if (i != 0) argNames.add(', '); | 1508 if (i != 0) argNames.add(', '); |
| 1520 argNames.add('"'); | 1509 argNames.add('"'); |
| 1521 argNames.add(names[i].slowToString()); | 1510 argNames.add(names[i].slowToString()); |
| 1522 argNames.add('"'); | 1511 argNames.add('"'); |
| 1523 } | 1512 } |
| 1524 String internalName = namer.instanceMethodInvocationName( | 1513 String internalName = namer.instanceMethodInvocationName( |
| 1525 selector.library, new SourceString(methodName), selector); | 1514 selector.library, new SourceString(methodName), selector); |
| 1515 Element createInvocationMirror = | |
| 1516 compiler.findHelper(const SourceString('createInvocationMirror')); | |
| 1526 CodeBuffer buffer = new CodeBuffer(); | 1517 CodeBuffer buffer = new CodeBuffer(); |
| 1527 buffer.add('function($args) {\n'); | 1518 buffer.add('function($args) {\n'); |
| 1528 buffer.add(' return this.$noSuchMethodName(' | 1519 buffer.add(' return this.$noSuchMethodName(' |
| 1529 '\$.createInvocationMirror("$methodName", "$internalName",' | 1520 '${namer.isolateAccess(createInvocationMirror)}(' |
| 1530 ' $type, [$args], [$argNames]));\n'); | 1521 '"$methodName", "$internalName",' |
| 1522 '$type, [$args], [$argNames]));\n'); | |
| 1531 buffer.add(' }'); | 1523 buffer.add(' }'); |
| 1532 return buffer; | 1524 return buffer; |
| 1533 } | 1525 } |
| 1534 | 1526 |
| 1535 void addNoSuchMethodHandlers(SourceString ignore, Set<Selector> selectors) { | 1527 void addNoSuchMethodHandlers(SourceString ignore, Set<Selector> selectors) { |
| 1536 // Cache the object class and type. | 1528 // Cache the object class and type. |
| 1537 ClassElement objectClass = compiler.objectClass; | 1529 ClassElement objectClass = compiler.objectClass; |
| 1538 DartType objectType = objectClass.computeType(compiler); | 1530 DartType objectType = objectClass.computeType(compiler); |
| 1539 | 1531 |
| 1540 for (Selector selector in selectors) { | 1532 for (Selector selector in selectors) { |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1693 compiler.isolateLibrary.find(Compiler.START_ROOT_ISOLATE); | 1685 compiler.isolateLibrary.find(Compiler.START_ROOT_ISOLATE); |
| 1694 mainCall = buildIsolateSetup(buffer, main, isolateMain); | 1686 mainCall = buildIsolateSetup(buffer, main, isolateMain); |
| 1695 } else { | 1687 } else { |
| 1696 mainCall = '${namer.isolateAccess(main)}()'; | 1688 mainCall = '${namer.isolateAccess(main)}()'; |
| 1697 } | 1689 } |
| 1698 buffer.add(""" | 1690 buffer.add(""" |
| 1699 | 1691 |
| 1700 // | 1692 // |
| 1701 // BEGIN invoke [main]. | 1693 // BEGIN invoke [main]. |
| 1702 // | 1694 // |
| 1703 if (typeof document != 'undefined' && document.readyState != 'complete') { | 1695 if (typeof document !== 'undefined' && document.readyState != 'complete') { |
|
floitsch
2012/12/07 12:01:01
not sure that's needed. In theory it should be cle
erikcorry
2012/12/10 08:36:01
Done.
| |
| 1704 document.addEventListener('readystatechange', function () { | 1696 document.addEventListener('readystatechange', function () { |
| 1705 if (document.readyState == 'complete') { | 1697 if (document.readyState == 'complete') { |
| 1706 if (typeof dartMainRunner == 'function') { | 1698 if (typeof dartMainRunner === 'function') { |
| 1707 dartMainRunner(function() { ${mainCall}; }); | 1699 dartMainRunner(function() { ${mainCall}; }); |
| 1708 } else { | 1700 } else { |
| 1709 ${mainCall}; | 1701 ${mainCall}; |
| 1710 } | 1702 } |
| 1711 } | 1703 } |
| 1712 }, false); | 1704 }, false); |
| 1713 } else { | 1705 } else { |
| 1714 if (typeof dartMainRunner == 'function') { | 1706 if (typeof dartMainRunner === 'function') { |
| 1715 dartMainRunner(function() { ${mainCall}; }); | 1707 dartMainRunner(function() { ${mainCall}; }); |
| 1716 } else { | 1708 } else { |
| 1717 ${mainCall}; | 1709 ${mainCall}; |
| 1718 } | 1710 } |
| 1719 } | 1711 } |
| 1720 // | 1712 // |
| 1721 // END invoke [main]. | 1713 // END invoke [main]. |
| 1722 // | 1714 // |
| 1723 | 1715 |
| 1724 """); | 1716 """); |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1847 const String HOOKS_API_USAGE = """ | 1839 const String HOOKS_API_USAGE = """ |
| 1848 // Generated by dart2js, the Dart to JavaScript compiler. | 1840 // Generated by dart2js, the Dart to JavaScript compiler. |
| 1849 // The code supports the following hooks: | 1841 // The code supports the following hooks: |
| 1850 // dartPrint(message) - if this function is defined it is called | 1842 // dartPrint(message) - if this function is defined it is called |
| 1851 // instead of the Dart [print] method. | 1843 // instead of the Dart [print] method. |
| 1852 // dartMainRunner(main) - if this function is defined, the Dart [main] | 1844 // dartMainRunner(main) - if this function is defined, the Dart [main] |
| 1853 // method will not be invoked directly. | 1845 // method will not be invoked directly. |
| 1854 // Instead, a closure that will invoke [main] is | 1846 // Instead, a closure that will invoke [main] is |
| 1855 // passed to [dartMainRunner]. | 1847 // passed to [dartMainRunner]. |
| 1856 """; | 1848 """; |
| OLD | NEW |