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

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

Issue 11492006: Minify methods, classes and fields. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Responses to Nicolas' late comments and restore missing '!' from last commit. Created 8 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 part of js_backend; 5 part of js_backend;
6 6
7 /** 7 /**
8 * A function element that represents a closure call. The signature is copied 8 * A function element that represents a closure call. The signature is copied
9 * from the given element. 9 * from the given element.
10 */ 10 */
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
85 return constantEmitter.reference(value); 85 return constantEmitter.reference(value);
86 } 86 }
87 87
88 js.Expression constantInitializerExpression(Constant value) { 88 js.Expression constantInitializerExpression(Constant value) {
89 return constantEmitter.initializationExpression(value); 89 return constantEmitter.initializationExpression(value);
90 } 90 }
91 91
92 String get name => 'CodeEmitter'; 92 String get name => 'CodeEmitter';
93 93
94 String get defineClassName 94 String get defineClassName
95 => '${namer.ISOLATE}.\$defineClass'; 95 => '${namer.isolateName}.\$defineClass';
96 String get currentGenerateAccessorName 96 String get currentGenerateAccessorName
97 => '${namer.CURRENT_ISOLATE}.\$generateAccessor'; 97 => '${namer.CURRENT_ISOLATE}.\$generateAccessor';
98 String get generateAccessorHolder 98 String get generateAccessorHolder
99 => '$isolatePropertiesName.\$generateAccessor'; 99 => '$isolatePropertiesName.\$generateAccessor';
100 String get finishClassesName 100 String get finishClassesName
101 => '${namer.ISOLATE}.\$finishClasses'; 101 => '${namer.isolateName}.\$finishClasses';
102 String get finishIsolateConstructorName 102 String get finishIsolateConstructorName
103 => '${namer.ISOLATE}.\$finishIsolateConstructor'; 103 => '${namer.isolateName}.\$finishIsolateConstructor';
104 String get pendingClassesName 104 String get pendingClassesName
105 => '${namer.ISOLATE}.\$pendingClasses'; 105 => '${namer.isolateName}.\$pendingClasses';
106 String get isolatePropertiesName 106 String get isolatePropertiesName
107 => '${namer.ISOLATE}.${namer.ISOLATE_PROPERTIES}'; 107 => '${namer.isolateName}.${namer.isolatePropertiesName}';
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.isolateName}.\$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
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 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
265 newPrototype[member] = prototype[member]; 287 newPrototype[member] = prototype[member];
266 } 288 }
267 } 289 }
268 } 290 }
269 } 291 }
270 for (var cls in pendingClasses) finishClass(cls); 292 for (var cls in pendingClasses) finishClass(cls);
271 }'''; 293 }''';
272 } 294 }
273 295
274 String get finishIsolateConstructorFunction { 296 String get finishIsolateConstructorFunction {
275 String isolate = namer.ISOLATE; 297 String isolate = namer.isolateName;
276 // We replace the old Isolate function with a new one that initializes 298 // We replace the old Isolate function with a new one that initializes
277 // all its field with the initial (and often final) value of all globals. 299 // all its field with the initial (and often final) value of all globals.
278 // This has two advantages: 300 // This has two advantages:
279 // 1. the properties are in the object itself (thus avoiding to go through 301 // 1. the properties are in the object itself (thus avoiding to go through
280 // the prototype when looking up globals. 302 // the prototype when looking up globals.
281 // 2. a new isolate goes through a (usually well optimized) constructor 303 // 2. a new isolate goes through a (usually well optimized) constructor
282 // function of the form: "function() { this.x = ...; this.y = ...; }". 304 // function of the form: "function() { this.x = ...; this.y = ...; }".
283 // 305 //
284 // Example: If [isolateProperties] is an object containing: x = 3 and 306 // Example: If [isolateProperties] is an object containing: x = 3 and
285 // A = function A() { /* constructor of class A. */ }, then we generate: 307 // A = function A() { /* constructor of class A. */ }, then we generate:
286 // str = "{ 308 // str = "{
287 // var isolateProperties = Isolate.$isolateProperties; 309 // var isolateProperties = Isolate.$isolateProperties;
288 // this.x = isolateProperties.x; 310 // this.x = isolateProperties.x;
289 // this.A = isolateProperties.A; 311 // this.A = isolateProperties.A;
290 // }"; 312 // }";
291 // which is then dynamically evaluated: 313 // which is then dynamically evaluated:
292 // var newIsolate = new Function(str); 314 // var newIsolate = new Function(str);
293 // 315 //
294 // We also copy over old values like the prototype, and the 316 // We also copy over old values like the prototype, and the
295 // isolateProperties themselves. 317 // isolateProperties themselves.
296 return """function(oldIsolate) { 318 return """function(oldIsolate) {
297 var isolateProperties = oldIsolate.${namer.ISOLATE_PROPERTIES}; 319 var isolateProperties = oldIsolate.${namer.isolatePropertiesName};
298 var isolatePrototype = oldIsolate.prototype; 320 var isolatePrototype = oldIsolate.prototype;
299 var str = "{\\n"; 321 var str = "{\\n";
300 str += "var properties = $isolate.${namer.ISOLATE_PROPERTIES};\\n"; 322 str += "var properties = $isolate.${namer.isolatePropertiesName};\\n";
301 for (var staticName in isolateProperties) { 323 for (var staticName in isolateProperties) {
302 if (Object.prototype.hasOwnProperty.call(isolateProperties, staticName)) { 324 if (Object.prototype.hasOwnProperty.call(isolateProperties, staticName)) {
303 str += "this." + staticName + "= properties." + staticName + ";\\n"; 325 str += "this." + staticName + "= properties." + staticName + ";\\n";
304 } 326 }
305 } 327 }
306 str += "}\\n"; 328 str += "}\\n";
307 var newIsolate = new Function(str); 329 var newIsolate = new Function(str);
308 newIsolate.prototype = isolatePrototype; 330 newIsolate.prototype = isolatePrototype;
309 isolatePrototype.constructor = newIsolate; 331 isolatePrototype.constructor = newIsolate;
310 newIsolate.${namer.ISOLATE_PROPERTIES} = isolateProperties; 332 newIsolate.${namer.isolatePropertiesName} = isolateProperties;
311 return newIsolate; 333 return newIsolate;
312 }"""; 334 }""";
313 } 335 }
314 336
315 String get lazyInitializerFunction { 337 String get lazyInitializerFunction {
316 String isolate = namer.CURRENT_ISOLATE; 338 String isolate = namer.CURRENT_ISOLATE;
317 return """ 339 return """
318 function(prototype, staticName, fieldName, getterName, lazyValue) { 340 function(prototype, staticName, fieldName, getterName, lazyValue) {
319 var getter = new Function("{ return $isolate." + fieldName + ";}"); 341 var getter = new Function("{ return $isolate." + fieldName + ";}");
320 $lazyInitializerLogic 342 $lazyInitializerLogic
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
371 } 393 }
372 } 394 }
373 395
374 void emitFinishIsolateConstructor(CodeBuffer buffer) { 396 void emitFinishIsolateConstructor(CodeBuffer buffer) {
375 String name = finishIsolateConstructorName; 397 String name = finishIsolateConstructorName;
376 String value = finishIsolateConstructorFunction; 398 String value = finishIsolateConstructorFunction;
377 buffer.add("$name = $value;\n"); 399 buffer.add("$name = $value;\n");
378 } 400 }
379 401
380 void emitFinishIsolateConstructorInvocation(CodeBuffer buffer) { 402 void emitFinishIsolateConstructorInvocation(CodeBuffer buffer) {
381 String isolate = namer.ISOLATE; 403 String isolate = namer.isolateName;
382 buffer.add("$isolate = $finishIsolateConstructorName($isolate);\n"); 404 buffer.add("$isolate = $finishIsolateConstructorName($isolate);\n");
383 } 405 }
384 406
385 /** 407 /**
386 * Generate stubs to handle invocation of methods with optional 408 * Generate stubs to handle invocation of methods with optional
387 * arguments. 409 * arguments.
388 * 410 *
389 * A method like [: foo([x]) :] may be invoked by the following 411 * A method like [: foo([x]) :] may be invoked by the following
390 * calls: [: foo(), foo(1), foo(x: 1) :]. See the sources of this 412 * calls: [: foo(), foo(1), foo(x: 1) :]. See the sources of this
391 * function for detailed examples. 413 * function for detailed examples.
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
527 // (3) foo$3$d(a, b, d) => foo$4$c$d(a, b, null, d); 549 // (3) foo$3$d(a, b, d) => foo$4$c$d(a, b, null, d);
528 // (4) No stub generated, call is direct. 550 // (4) No stub generated, call is direct.
529 // (5) No stub generated, call is direct. 551 // (5) No stub generated, call is direct.
530 552
531 // Keep a cache of which stubs have already been generated, to 553 // Keep a cache of which stubs have already been generated, to
532 // avoid duplicates. Note that even if selectors are 554 // avoid duplicates. Note that even if selectors are
533 // canonicalized, we would still need this cache: a typed selector 555 // canonicalized, we would still need this cache: a typed selector
534 // on A and a typed selector on B could yield the same stub. 556 // on A and a typed selector on B could yield the same stub.
535 Set<String> generatedStubNames = new Set<String>(); 557 Set<String> generatedStubNames = new Set<String>();
536 if (compiler.enabledFunctionApply 558 if (compiler.enabledFunctionApply
537 && member.name == Namer.CLOSURE_INVOCATION_NAME) { 559 && member.name == namer.closureInvocationSelectorName) {
538 // If [Function.apply] is called, we pessimistically compile all 560 // If [Function.apply] is called, we pessimistically compile all
539 // possible stubs for this closure. 561 // possible stubs for this closure.
540 FunctionSignature signature = member.computeSignature(compiler); 562 FunctionSignature signature = member.computeSignature(compiler);
541 Set<Selector> selectors = signature.optionalParametersAreNamed 563 Set<Selector> selectors = signature.optionalParametersAreNamed
542 ? computeNamedSelectors(signature, member) 564 ? computeNamedSelectors(signature, member)
543 : computeOptionalSelectors(signature, member); 565 : computeOptionalSelectors(signature, member);
544 for (Selector selector in selectors) { 566 for (Selector selector in selectors) {
545 addParameterStub( 567 addParameterStub(
546 member, selector, defineInstanceMember, generatedStubNames); 568 member, selector, defineInstanceMember, generatedStubNames);
547 } 569 }
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
622 644
623 bool instanceFieldNeedsSetter(Element member) { 645 bool instanceFieldNeedsSetter(Element member) {
624 assert(member.isField()); 646 assert(member.isField());
625 return (!member.modifiers.isFinalOrConst()) 647 return (!member.modifiers.isFinalOrConst())
626 && compiler.codegenWorld.hasInvokedSetter(member, compiler); 648 && compiler.codegenWorld.hasInvokedSetter(member, compiler);
627 } 649 }
628 650
629 String compiledFieldName(Element member) { 651 String compiledFieldName(Element member) {
630 assert(member.isField()); 652 assert(member.isField());
631 return member.isNative() 653 return member.isNative()
632 ? member.name.slowToString() 654 ? member.nativeName()
633 : namer.getName(member); 655 : namer.getName(member);
634 } 656 }
635 657
636 /** 658 /**
637 * Documentation wanted -- johnniwinther 659 * Documentation wanted -- johnniwinther
638 * 660 *
639 * Invariant: [member] must be a declaration element. 661 * Invariant: [member] must be a declaration element.
640 */ 662 */
641 void addInstanceMember(Element member, 663 void addInstanceMember(Element member,
642 DefineMemberFunction defineInstanceMember) { 664 DefineMemberFunction defineInstanceMember) {
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
726 } 748 }
727 749
728 /** 750 /**
729 * Documentation wanted -- johnniwinther 751 * Documentation wanted -- johnniwinther
730 * 752 *
731 * Invariant: [classElement] must be a declaration element. 753 * Invariant: [classElement] must be a declaration element.
732 */ 754 */
733 void visitClassFields(ClassElement classElement, 755 void visitClassFields(ClassElement classElement,
734 void addField(Element member, 756 void addField(Element member,
735 String name, 757 String name,
758 String accessorName,
736 bool needsGetter, 759 bool needsGetter,
737 bool needsSetter, 760 bool needsSetter,
738 bool needsCheckedSetter)) { 761 bool needsCheckedSetter)) {
739 assert(invariant(classElement, classElement.isDeclaration)); 762 assert(invariant(classElement, classElement.isDeclaration));
740 // If the class is never instantiated we still need to set it up for 763 // If the class is never instantiated we still need to set it up for
741 // inheritance purposes, but we can simplify its JavaScript constructor. 764 // inheritance purposes, but we can simplify its JavaScript constructor.
742 bool isInstantiated = 765 bool isInstantiated =
743 compiler.codegenWorld.instantiatedClasses.contains(classElement); 766 compiler.codegenWorld.instantiatedClasses.contains(classElement);
744 767
745 void visitField(ClassElement enclosingClass, Element member) { 768 void visitField(ClassElement enclosingClass, Element member) {
(...skipping 29 matching lines...) Expand all
775 : accessorName; 798 : accessorName;
776 bool needsCheckedSetter = false; 799 bool needsCheckedSetter = false;
777 if (needsSetter && compiler.enableTypeAssertions 800 if (needsSetter && compiler.enableTypeAssertions
778 && canGenerateCheckedSetter(member)) { 801 && canGenerateCheckedSetter(member)) {
779 needsCheckedSetter = true; 802 needsCheckedSetter = true;
780 needsSetter = false; 803 needsSetter = false;
781 } 804 }
782 // Getters and setters with suffixes will be generated dynamically. 805 // Getters and setters with suffixes will be generated dynamically.
783 addField(member, 806 addField(member,
784 fieldName, 807 fieldName,
808 accessorName,
785 needsGetter, 809 needsGetter,
786 needsSetter, 810 needsSetter,
787 needsCheckedSetter); 811 needsCheckedSetter);
788 } 812 }
789 } 813 }
790 814
791 // If a class is not instantiated then we add the field just so we can 815 // If a class is not instantiated then we add the field just so we can
792 // generate the field getter/setter dynamically. Since this is only 816 // generate the field getter/setter dynamically. Since this is only
793 // allowed on fields that are in [classElement] we don't need to visit 817 // allowed on fields that are in [classElement] we don't need to visit
794 // superclasses for non-instantiated classes. 818 // superclasses for non-instantiated classes.
795 classElement.implementation.forEachInstanceField( 819 classElement.implementation.forEachInstanceField(
796 visitField, 820 visitField,
797 includeBackendMembers: true, 821 includeBackendMembers: true,
798 includeSuperMembers: isInstantiated && !classElement.isNative()); 822 includeSuperMembers: isInstantiated && !classElement.isNative());
799 } 823 }
800 824
801 void generateGetter(Element member, String fieldName, CodeBuffer buffer) {
802 String getterName = namer.getterName(member.getLibrary(), member.name);
803 buffer.add("$getterName: function() { return this.$fieldName; }");
804 }
805
806 void generateSetter(Element member, String fieldName, CodeBuffer buffer) {
807 String setterName = namer.setterName(member.getLibrary(), member.name);
808 buffer.add("$setterName: function(v) { this.$fieldName = v; }");
809 }
810
811 bool canGenerateCheckedSetter(Element member) { 825 bool canGenerateCheckedSetter(Element member) {
812 DartType type = member.computeType(compiler); 826 DartType type = member.computeType(compiler);
813 if (type.element.isTypeVariable() 827 if (type.element.isTypeVariable()
814 || type.element == compiler.dynamicClass 828 || type.element == compiler.dynamicClass
815 || type.element == compiler.objectClass) { 829 || type.element == compiler.objectClass) {
816 // TODO(ngeoffray): Support type checks on type parameters. 830 // TODO(ngeoffray): Support type checks on type parameters.
817 return false; 831 return false;
818 } 832 }
819 return true; 833 return true;
820 } 834 }
821 835
822 void generateCheckedSetter(Element member, 836 void generateCheckedSetter(Element member,
823 String fieldName, 837 String fieldName,
838 String accessorName,
824 CodeBuffer buffer) { 839 CodeBuffer buffer) {
825 assert(canGenerateCheckedSetter(member)); 840 assert(canGenerateCheckedSetter(member));
826 DartType type = member.computeType(compiler); 841 DartType type = member.computeType(compiler);
827 SourceString helper = compiler.backend.getCheckedModeHelper(type); 842 SourceString helper = compiler.backend.getCheckedModeHelper(type);
828 FunctionElement helperElement = compiler.findHelper(helper); 843 FunctionElement helperElement = compiler.findHelper(helper);
829 String helperName = namer.isolateAccess(helperElement); 844 String helperName = namer.isolateAccess(helperElement);
830 String additionalArgument = ''; 845 String additionalArgument = '';
831 if (helperElement.computeSignature(compiler).parameterCount != 1) { 846 if (helperElement.computeSignature(compiler).parameterCount != 1) {
832 additionalArgument = ", '${namer.operatorIs(type.element)}'"; 847 additionalArgument = ", '${namer.operatorIs(type.element)}'";
833 } 848 }
834 String setterName = namer.setterName(member.getLibrary(), member.name); 849 String setterName = namer.setterNameFromAccessorName(accessorName);
835 buffer.add("$setterName: function(v) { " 850 buffer.add("$setterName: function(v) { "
836 "this.$fieldName = $helperName(v$additionalArgument); }"); 851 "this.$fieldName = $helperName(v$additionalArgument); }");
837 } 852 }
838 853
839 void emitClassConstructor(ClassElement classElement, CodeBuffer buffer) { 854 void emitClassConstructor(ClassElement classElement, CodeBuffer buffer) {
840 /* Do nothing. */ 855 /* Do nothing. */
841 } 856 }
842 857
843 void emitSuper(String superName, CodeBuffer buffer) { 858 void emitSuper(String superName, CodeBuffer buffer) {
844 /* Do nothing. */ 859 /* Do nothing. */
845 } 860 }
846 861
847 void emitClassFields(ClassElement classElement, 862 void emitClassFields(ClassElement classElement,
848 CodeBuffer buffer, 863 CodeBuffer buffer,
849 bool emitEndingComma, 864 bool emitEndingComma,
850 { String superClass: "", 865 { String superClass: "",
851 bool isNative: false}) { 866 bool isNative: false}) {
852 bool isFirstField = true; 867 bool isFirstField = true;
853 bool isAnythingOutput = false; 868 bool isAnythingOutput = false;
854 if (!isNative) { 869 if (!isNative) {
855 buffer.add('"":"$superClass;'); 870 buffer.add('"":"$superClass;');
856 isAnythingOutput = true; 871 isAnythingOutput = true;
857 } 872 }
858 visitClassFields(classElement, (Element member, 873 visitClassFields(classElement, (Element member,
859 String name, 874 String name,
875 String accessorName,
860 bool needsGetter, 876 bool needsGetter,
861 bool needsSetter, 877 bool needsSetter,
862 bool needsCheckedSetter) { 878 bool needsCheckedSetter) {
863 if (!getterAndSetterCanBeImplementedByFieldSpec(
864 member, name, needsGetter, needsSetter)) {
865 return;
866 }
867 if (!isNative || needsCheckedSetter || needsGetter || needsSetter) { 879 if (!isNative || needsCheckedSetter || needsGetter || needsSetter) {
868 if (isFirstField) { 880 if (isFirstField) {
869 isFirstField = false; 881 isFirstField = false;
870 if (!isAnythingOutput) { 882 if (!isAnythingOutput) {
871 buffer.add('"":"'); 883 buffer.add('"":"');
872 isAnythingOutput = true; 884 isAnythingOutput = true;
873 } 885 }
874 } else { 886 } else {
875 buffer.add(","); 887 buffer.add(",");
876 } 888 }
877 buffer.add('$name'); 889 buffer.add('$accessorName');
890 int flag = 0;
891 if (name != accessorName) {
892 buffer.add(':$name');
893 assert(needsGetter || needsSetter);
894 flag = RENAMING_FLAG;
895 }
878 if (needsGetter && needsSetter) { 896 if (needsGetter && needsSetter) {
879 buffer.add(GETTER_SETTER_SUFFIX); 897 buffer.addCharCode(GETTER_SETTER_CODE + flag);
880 } else if (needsGetter) { 898 } else if (needsGetter) {
881 buffer.add(GETTER_SUFFIX); 899 buffer.addCharCode(GETTER_CODE + flag);
882 } else if (needsSetter) { 900 } else if (needsSetter) {
883 buffer.add(SETTER_SUFFIX); 901 buffer.addCharCode(SETTER_CODE + flag);
884 } 902 }
885 } 903 }
886 }); 904 });
887 if (isAnythingOutput) { 905 if (isAnythingOutput) {
888 buffer.add('"'); 906 buffer.add('"');
889 if (emitEndingComma) { 907 if (emitEndingComma) {
890 buffer.add(','); 908 buffer.add(',');
891 } 909 }
892 } 910 }
893 } 911 }
894 912
895 /** Each getter/setter must be prefixed with a ",\n ". */ 913 /** Each getter/setter must be prefixed with a ",\n ". */
896 void emitClassGettersSetters(ClassElement classElement, 914 void emitClassGettersSetters(ClassElement classElement,
897 CodeBuffer buffer, 915 CodeBuffer buffer,
898 bool emitLeadingComma) { 916 bool emitLeadingComma) {
899 emitComma() { 917 emitComma() {
900 if (emitLeadingComma) { 918 if (emitLeadingComma) {
901 buffer.add(",\n "); 919 buffer.add(",\n ");
902 } else { 920 } else {
903 emitLeadingComma = true; 921 emitLeadingComma = true;
904 } 922 }
905 } 923 }
906 924
907 visitClassFields(classElement, (Element member, 925 visitClassFields(classElement, (Element member,
908 String name, 926 String name,
927 String accessorName,
909 bool needsGetter, 928 bool needsGetter,
910 bool needsSetter, 929 bool needsSetter,
911 bool needsCheckedSetter) { 930 bool needsCheckedSetter) {
912 if (name == null) throw 123;
913 if (getterAndSetterCanBeImplementedByFieldSpec(
914 member, name, needsGetter, needsSetter)) {
915 needsGetter = false;
916 needsSetter = false;
917 }
918 if (needsGetter) {
919 emitComma();
920 generateGetter(member, name, buffer);
921 }
922 if (needsSetter) {
923 emitComma();
924 generateSetter(member, name, buffer);
925 }
926 if (needsCheckedSetter) { 931 if (needsCheckedSetter) {
927 assert(!needsSetter); 932 assert(!needsSetter);
928 emitComma(); 933 emitComma();
929 generateCheckedSetter(member, name, buffer); 934 generateCheckedSetter(member, name, accessorName, buffer);
930 } 935 }
931 }); 936 });
932 } 937 }
933 938
934 bool getterAndSetterCanBeImplementedByFieldSpec(Element member,
935 String name,
936 bool needsGetter,
937 bool needsSetter) {
938 if (needsGetter) {
939 if (namer.getterName(member.getLibrary(), member.name) != 'get\$$name') {
940 return false;
941 }
942 }
943 if (needsSetter) {
944 if (namer.setterName(member.getLibrary(), member.name) != 'set\$$name') {
945 return false;
946 }
947 }
948 return true;
949 }
950
951 /** 939 /**
952 * Documentation wanted -- johnniwinther 940 * Documentation wanted -- johnniwinther
953 * 941 *
954 * Invariant: [classElement] must be a declaration element. 942 * Invariant: [classElement] must be a declaration element.
955 */ 943 */
956 void generateClass(ClassElement classElement, CodeBuffer buffer) { 944 void generateClass(ClassElement classElement, CodeBuffer buffer) {
957 assert(invariant(classElement, classElement.isDeclaration)); 945 assert(invariant(classElement, classElement.isDeclaration));
958 if (classElement.isNative()) { 946 if (classElement.isNative()) {
959 nativeEmitter.generateNativeClass(classElement); 947 nativeEmitter.generateNativeClass(classElement);
960 return; 948 return;
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after
1173 1161
1174 void emitStaticFunctionGetters(CodeBuffer buffer) { 1162 void emitStaticFunctionGetters(CodeBuffer buffer) {
1175 Set<FunctionElement> functionsNeedingGetter = 1163 Set<FunctionElement> functionsNeedingGetter =
1176 compiler.codegenWorld.staticFunctionsNeedingGetter; 1164 compiler.codegenWorld.staticFunctionsNeedingGetter;
1177 for (FunctionElement element in functionsNeedingGetter) { 1165 for (FunctionElement element in functionsNeedingGetter) {
1178 // The static function does not have the correct name. Since 1166 // The static function does not have the correct name. Since
1179 // [addParameterStubs] use the name to create its stubs we simply 1167 // [addParameterStubs] use the name to create its stubs we simply
1180 // create a fake element with the correct name. 1168 // create a fake element with the correct name.
1181 // Note: the callElement will not have any enclosingElement. 1169 // Note: the callElement will not have any enclosingElement.
1182 FunctionElement callElement = 1170 FunctionElement callElement =
1183 new ClosureInvocationElement(Namer.CLOSURE_INVOCATION_NAME, element); 1171 new ClosureInvocationElement(namer.closureInvocationSelectorName,
1172 element);
1184 String staticName = namer.getName(element); 1173 String staticName = namer.getName(element);
1185 String invocationName = namer.instanceMethodName(callElement); 1174 String invocationName = namer.instanceMethodName(callElement);
1186 String fieldAccess = '$isolateProperties.$staticName'; 1175 String fieldAccess = '$isolateProperties.$staticName';
1187 buffer.add("$fieldAccess.$invocationName = $fieldAccess;\n"); 1176 buffer.add("$fieldAccess.$invocationName = $fieldAccess;\n");
1188 addParameterStubs(callElement, (String name, CodeBuffer value) { 1177 addParameterStubs(callElement, (String name, CodeBuffer value) {
1189 buffer.add('$fieldAccess.$name = $value;\n'); 1178 buffer.add('$fieldAccess.$name = $value;\n');
1190 }); 1179 });
1191 // If a static function is used as a closure we need to add its name 1180 // If a static function is used as a closure we need to add its name
1192 // in case it is used in spawnFunction. 1181 // in case it is used in spawnFunction.
1193 String fieldName = namer.STATIC_CLOSURE_NAME_NAME; 1182 String fieldName = namer.STATIC_CLOSURE_NAME_NAME;
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
1268 1257
1269 // Define the constructor with a name so that Object.toString can 1258 // Define the constructor with a name so that Object.toString can
1270 // find the class name of the closure class. 1259 // find the class name of the closure class.
1271 emitBoundClosureClassHeader( 1260 emitBoundClosureClassHeader(
1272 mangledName, superName, fieldNames, boundClosureBuffer); 1261 mangledName, superName, fieldNames, boundClosureBuffer);
1273 // Now add the methods on the closure class. The instance method does not 1262 // Now add the methods on the closure class. The instance method does not
1274 // have the correct name. Since [addParameterStubs] use the name to create 1263 // have the correct name. Since [addParameterStubs] use the name to create
1275 // its stubs we simply create a fake element with the correct name. 1264 // its stubs we simply create a fake element with the correct name.
1276 // Note: the callElement will not have any enclosingElement. 1265 // Note: the callElement will not have any enclosingElement.
1277 FunctionElement callElement = 1266 FunctionElement callElement =
1278 new ClosureInvocationElement(Namer.CLOSURE_INVOCATION_NAME, member); 1267 new ClosureInvocationElement(namer.closureInvocationSelectorName,
1279 1268 member);
1269
1280 String invocationName = namer.instanceMethodName(callElement); 1270 String invocationName = namer.instanceMethodName(callElement);
1281 1271
1282 List<js.Parameter> parameters = <js.Parameter>[]; 1272 List<js.Parameter> parameters = <js.Parameter>[];
1283 List<js.Expression> arguments = <js.Expression>[]; 1273 List<js.Expression> arguments = <js.Expression>[];
1284 if (inInterceptor) { 1274 if (inInterceptor) {
1285 arguments.add(new js.This().dot(fieldNames[2])); 1275 arguments.add(new js.This().dot(fieldNames[2]));
1286 } 1276 }
1287 for (int i = 0; i < parameterCount; i++) { 1277 for (int i = 0; i < parameterCount; i++) {
1288 String name = 'p$i'; 1278 String name = 'p$i';
1289 parameters.add(new js.Parameter(name)); 1279 parameters.add(new js.Parameter(name));
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
1374 : namer.instanceFieldName(memberLibrary, member.name); 1364 : namer.instanceFieldName(memberLibrary, member.name);
1375 return new js.VariableUse('this').dot(fieldName); 1365 return new js.VariableUse('this').dot(fieldName);
1376 } 1366 }
1377 } 1367 }
1378 1368
1379 for (Selector selector in selectors) { 1369 for (Selector selector in selectors) {
1380 if (selector.applies(member, compiler)) { 1370 if (selector.applies(member, compiler)) {
1381 String invocationName = 1371 String invocationName =
1382 namer.instanceMethodInvocationName(memberLibrary, member.name, 1372 namer.instanceMethodInvocationName(memberLibrary, member.name,
1383 selector); 1373 selector);
1384 SourceString callName = Namer.CLOSURE_INVOCATION_NAME; 1374 SourceString callName = namer.closureInvocationSelectorName;
1385 String closureCallName = 1375 String closureCallName =
1386 namer.instanceMethodInvocationName(memberLibrary, callName, 1376 namer.instanceMethodInvocationName(memberLibrary, callName,
1387 selector); 1377 selector);
1388 1378
1389 List<js.Parameter> parameters = <js.Parameter>[]; 1379 List<js.Parameter> parameters = <js.Parameter>[];
1390 List<js.Expression> arguments = <js.Expression>[]; 1380 List<js.Expression> arguments = <js.Expression>[];
1391 if (isInterceptorClass) { 1381 if (isInterceptorClass) {
1392 parameters.add(new js.Parameter(receiverArgumentName)); 1382 parameters.add(new js.Parameter(receiverArgumentName));
1393 } 1383 }
1394 1384
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
1491 new js.PropertyAccess.field( 1481 new js.PropertyAccess.field(
1492 new js.VariableUse(isolateProperties), 1482 new js.VariableUse(isolateProperties),
1493 name), 1483 name),
1494 constantInitializerExpression(constant)); 1484 constantInitializerExpression(constant));
1495 buffer.add(js.prettyPrint(init, compiler)); 1485 buffer.add(js.prettyPrint(init, compiler));
1496 buffer.add(';\n'); 1486 buffer.add(';\n');
1497 } 1487 }
1498 } 1488 }
1499 1489
1500 void emitMakeConstantList(CodeBuffer buffer) { 1490 void emitMakeConstantList(CodeBuffer buffer) {
1501 buffer.add(namer.ISOLATE); 1491 buffer.add(namer.isolateName);
1502 buffer.add(r'''.makeConstantList = function(list) { 1492 buffer.add(r'''.makeConstantList = function(list) {
1503 list.immutable$list = true; 1493 list.immutable$list = true;
1504 list.fixed$length = true; 1494 list.fixed$length = true;
1505 return list; 1495 return list;
1506 }; 1496 };
1507 '''); 1497 ''');
1508 } 1498 }
1509 1499
1510 /** 1500 /**
1511 * Documentation wanted -- johnniwinther 1501 * Documentation wanted -- johnniwinther
(...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after
1745 buffer.add(""" 1735 buffer.add("""
1746 var \$globalThis = $currentIsolate; 1736 var \$globalThis = $currentIsolate;
1747 var \$globalState; 1737 var \$globalState;
1748 var \$globals; 1738 var \$globals;
1749 var \$isWorker = false; 1739 var \$isWorker = false;
1750 var \$supportsWorkers = false; 1740 var \$supportsWorkers = false;
1751 var \$thisScriptUrl; 1741 var \$thisScriptUrl;
1752 function \$static_init(){}; 1742 function \$static_init(){};
1753 1743
1754 function \$initGlobals(context) { 1744 function \$initGlobals(context) {
1755 context.isolateStatics = new ${namer.ISOLATE}(); 1745 context.isolateStatics = new ${namer.isolateName}();
1756 } 1746 }
1757 function \$setGlobals(context) { 1747 function \$setGlobals(context) {
1758 $currentIsolate = context.isolateStatics; 1748 $currentIsolate = context.isolateStatics;
1759 \$globalThis = $currentIsolate; 1749 \$globalThis = $currentIsolate;
1760 } 1750 }
1761 $mainEnsureGetter 1751 $mainEnsureGetter
1762 """); 1752 """);
1763 return "${namer.isolateAccess(isolateMain)}($mainAccess)"; 1753 return "${namer.isolateAccess(isolateMain)}($mainAccess)";
1764 } 1754 }
1765 1755
1766 emitMain(CodeBuffer buffer) { 1756 emitMain(CodeBuffer buffer) {
1767 if (compiler.isMockCompilation) return; 1757 if (compiler.isMockCompilation) return;
1768 Element main = compiler.mainApp.find(Compiler.MAIN); 1758 Element main = compiler.mainApp.find(Compiler.MAIN);
1769 String mainCall = null; 1759 String mainCall = null;
1770 if (compiler.isolateLibrary != null) { 1760 if (compiler.isolateLibrary != null) {
1771 Element isolateMain = 1761 Element isolateMain =
1772 compiler.isolateLibrary.find(Compiler.START_ROOT_ISOLATE); 1762 compiler.isolateLibrary.find(Compiler.START_ROOT_ISOLATE);
1773 mainCall = buildIsolateSetup(buffer, main, isolateMain); 1763 mainCall = buildIsolateSetup(buffer, main, isolateMain);
1774 } else { 1764 } else {
1775 mainCall = '${namer.isolateAccess(main)}()'; 1765 mainCall = '${namer.isolateAccess(main)}()';
1776 } 1766 }
1777 buffer.add(""" 1767 buffer.add("""
1778 1768
1779 // 1769 //
1780 // BEGIN invoke [main]. 1770 // BEGIN invoke [main].
1781 // 1771 //
1782 if (typeof document != 'undefined' && document.readyState != 'complete') { 1772 if (typeof document !== 'undefined' && document.readyState !== 'complete') {
1783 document.addEventListener('readystatechange', function () { 1773 document.addEventListener('readystatechange', function () {
1784 if (document.readyState == 'complete') { 1774 if (document.readyState == 'complete') {
1785 if (typeof dartMainRunner == 'function') { 1775 if (typeof dartMainRunner === 'function') {
1786 dartMainRunner(function() { ${mainCall}; }); 1776 dartMainRunner(function() { ${mainCall}; });
1787 } else { 1777 } else {
1788 ${mainCall}; 1778 ${mainCall};
1789 } 1779 }
1790 } 1780 }
1791 }, false); 1781 }, false);
1792 } else { 1782 } else {
1793 if (typeof dartMainRunner == 'function') { 1783 if (typeof dartMainRunner === 'function') {
1794 dartMainRunner(function() { ${mainCall}; }); 1784 dartMainRunner(function() { ${mainCall}; });
1795 } else { 1785 } else {
1796 ${mainCall}; 1786 ${mainCall};
1797 } 1787 }
1798 } 1788 }
1799 // 1789 //
1800 // END invoke [main]. 1790 // END invoke [main].
1801 // 1791 //
1802 1792
1803 """); 1793 """);
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
1846 emitInterceptorCheck(cls, buffer); 1836 emitInterceptorCheck(cls, buffer);
1847 } 1837 }
1848 } 1838 }
1849 buffer.add('\n return $objectName.prototype;\n};\n'); 1839 buffer.add('\n return $objectName.prototype;\n};\n');
1850 }); 1840 });
1851 } 1841 }
1852 1842
1853 String assembleProgram() { 1843 String assembleProgram() {
1854 measure(() { 1844 measure(() {
1855 mainBuffer.add(HOOKS_API_USAGE); 1845 mainBuffer.add(HOOKS_API_USAGE);
1856 mainBuffer.add('function ${namer.ISOLATE}() {}\n'); 1846 mainBuffer.add('function ${namer.isolateName}() {}\n');
1857 mainBuffer.add('init();\n\n'); 1847 mainBuffer.add('init();\n\n');
1858 // Shorten the code by using "$$" as temporary. 1848 // Shorten the code by using "$$" as temporary.
1859 classesCollector = r"$$"; 1849 classesCollector = r"$$";
1860 mainBuffer.add('var $classesCollector = {};\n'); 1850 mainBuffer.add('var $classesCollector = {};\n');
1861 // Shorten the code by using [namer.CURRENT_ISOLATE] as temporary. 1851 // Shorten the code by using [namer.CURRENT_ISOLATE] as temporary.
1862 isolateProperties = namer.CURRENT_ISOLATE; 1852 isolateProperties = namer.CURRENT_ISOLATE;
1863 mainBuffer.add('var $isolateProperties = $isolatePropertiesName;\n'); 1853 mainBuffer.add('var $isolateProperties = $isolatePropertiesName;\n');
1864 emitClasses(mainBuffer); 1854 emitClasses(mainBuffer);
1865 mainBuffer.add(boundClosureBuffer); 1855 mainBuffer.add(boundClosureBuffer);
1866 // Clear the buffer, so that we can reuse it for the native classes. 1856 // Clear the buffer, so that we can reuse it for the native classes.
(...skipping 15 matching lines...) Expand all
1882 // initialStatics. 1872 // initialStatics.
1883 mainBuffer.add('var ${namer.CURRENT_ISOLATE} = null;\n'); 1873 mainBuffer.add('var ${namer.CURRENT_ISOLATE} = null;\n');
1884 mainBuffer.add(boundClosureBuffer); 1874 mainBuffer.add(boundClosureBuffer);
1885 emitFinishClassesInvocationIfNecessary(mainBuffer); 1875 emitFinishClassesInvocationIfNecessary(mainBuffer);
1886 // After this assignment we will produce invalid JavaScript code if we use 1876 // After this assignment we will produce invalid JavaScript code if we use
1887 // the classesCollector variable. 1877 // the classesCollector variable.
1888 classesCollector = 'classesCollector should not be used from now on'; 1878 classesCollector = 'classesCollector should not be used from now on';
1889 1879
1890 emitFinishIsolateConstructorInvocation(mainBuffer); 1880 emitFinishIsolateConstructorInvocation(mainBuffer);
1891 mainBuffer.add( 1881 mainBuffer.add(
1892 'var ${namer.CURRENT_ISOLATE} = new ${namer.ISOLATE}();\n'); 1882 'var ${namer.CURRENT_ISOLATE} = new ${namer.isolateName}();\n');
1893 1883
1894 nativeEmitter.assembleCode(mainBuffer); 1884 nativeEmitter.assembleCode(mainBuffer);
1895 emitMain(mainBuffer); 1885 emitMain(mainBuffer);
1896 mainBuffer.add('function init() {\n'); 1886 mainBuffer.add('function init() {\n');
1897 mainBuffer.add('$isolateProperties = {};\n'); 1887 mainBuffer.add('$isolateProperties = {};\n');
1898 addDefineClassAndFinishClassFunctionsIfNecessary(mainBuffer); 1888 addDefineClassAndFinishClassFunctionsIfNecessary(mainBuffer);
1899 addLazyInitializerFunctionIfNecessary(mainBuffer); 1889 addLazyInitializerFunctionIfNecessary(mainBuffer);
1900 emitFinishIsolateConstructor(mainBuffer); 1890 emitFinishIsolateConstructor(mainBuffer);
1901 mainBuffer.add('}\n'); 1891 mainBuffer.add('}\n');
1902 compiler.assembledCode = mainBuffer.toString(); 1892 compiler.assembledCode = mainBuffer.toString();
(...skipping 23 matching lines...) Expand all
1926 const String HOOKS_API_USAGE = """ 1916 const String HOOKS_API_USAGE = """
1927 // Generated by dart2js, the Dart to JavaScript compiler. 1917 // Generated by dart2js, the Dart to JavaScript compiler.
1928 // The code supports the following hooks: 1918 // The code supports the following hooks:
1929 // dartPrint(message) - if this function is defined it is called 1919 // dartPrint(message) - if this function is defined it is called
1930 // instead of the Dart [print] method. 1920 // instead of the Dart [print] method.
1931 // dartMainRunner(main) - if this function is defined, the Dart [main] 1921 // dartMainRunner(main) - if this function is defined, the Dart [main]
1932 // method will not be invoked directly. 1922 // method will not be invoked directly.
1933 // Instead, a closure that will invoke [main] is 1923 // Instead, a closure that will invoke [main] is
1934 // passed to [dartMainRunner]. 1924 // passed to [dartMainRunner].
1935 """; 1925 """;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698