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

Side by Side Diff: lib/compiler/implementation/emitter.dart

Issue 10781019: Fix compilation for Opera. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Address comment. Created 8 years, 5 months 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
« no previous file with comments | « no previous file | lib/compiler/implementation/lib/native_helper.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 /** 5 /**
6 * A function element that represents a closure call. The signature is copied 6 * A function element that represents a closure call. The signature is copied
7 * from the given element. 7 * from the given element.
8 */ 8 */
9 class ClosureInvocationElement extends FunctionElement { 9 class ClosureInvocationElement extends FunctionElement {
10 ClosureInvocationElement(SourceString name, 10 ClosureInvocationElement(SourceString name,
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
53 String get defineClassName() 53 String get defineClassName()
54 => '${namer.ISOLATE}.\$defineClass'; 54 => '${namer.ISOLATE}.\$defineClass';
55 String get finishClassesName() 55 String get finishClassesName()
56 => '${namer.ISOLATE}.\$finishClasses'; 56 => '${namer.ISOLATE}.\$finishClasses';
57 String get finishIsolateConstructorName() 57 String get finishIsolateConstructorName()
58 => '${namer.ISOLATE}.\$finishIsolateConstructor'; 58 => '${namer.ISOLATE}.\$finishIsolateConstructor';
59 String get pendingClassesName() 59 String get pendingClassesName()
60 => '${namer.ISOLATE}.\$pendingClasses'; 60 => '${namer.ISOLATE}.\$pendingClasses';
61 String get isolatePropertiesName() 61 String get isolatePropertiesName()
62 => '${namer.ISOLATE}.${namer.ISOLATE_PROPERTIES}'; 62 => '${namer.ISOLATE}.${namer.ISOLATE_PROPERTIES}';
63 String get supportsProtoName()
64 => 'supportsProto';
63 65
64 final String GETTER_SUFFIX = "?"; 66 final String GETTER_SUFFIX = "?";
65 final String SETTER_SUFFIX = "!"; 67 final String SETTER_SUFFIX = "!";
66 final String GETTER_SETTER_SUFFIX = "="; 68 final String GETTER_SETTER_SUFFIX = "=";
67 69
68 String get generateGetterSetterFunction() { 70 String get generateGetterSetterFunction() {
69 return """ 71 return """
70 function(field, prototype) { 72 function(field, prototype) {
71 var len = field.length; 73 var len = field.length;
72 var lastChar = field[len - 1]; 74 var lastChar = field[len - 1];
73 var needsGetter = lastChar == '$GETTER_SUFFIX' || lastChar == '$GETTER_SETTER_ SUFFIX'; 75 var needsGetter = lastChar == '$GETTER_SUFFIX' || lastChar == '$GETTER_SETTER_ SUFFIX';
74 var needsSetter = lastChar == '$SETTER_SUFFIX' || lastChar == '$GETTER_SETTER_ SUFFIX'; 76 var needsSetter = lastChar == '$SETTER_SUFFIX' || lastChar == '$GETTER_SETTER_ SUFFIX';
75 if (needsGetter || needsSetter) field = field.substring(0, len - 1); 77 if (needsGetter || needsSetter) field = field.substring(0, len - 1);
76 if (needsGetter) { 78 if (needsGetter) {
77 var getterString = "return this." + field + ";"; 79 var getterString = "return this." + field + ";";
80 """ /* The supportsProtoCheck below depends on the getter/setter convention.
81 When changing here, update the protoCheck too. */ """
78 prototype["get\$" + field] = new Function(getterString); 82 prototype["get\$" + field] = new Function(getterString);
79 } 83 }
80 if (needsSetter) { 84 if (needsSetter) {
81 var setterString = "this." + field + " = v;"; 85 var setterString = "this." + field + " = v;";
82 prototype["set\$" + field] = new Function("v", setterString); 86 prototype["set\$" + field] = new Function("v", setterString);
83 } 87 }
84 return field; 88 return field;
85 }"""; 89 }""";
86 } 90 }
87 91
88 String get defineClassFunction() { 92 String get defineClassFunction() {
89 // First the class name, then the super class name, followed by the fields 93 // First the class name, then the super class name, followed by the fields
90 // (in an array) and the members (inside an Object literal). 94 // (in an array) and the members (inside an Object literal).
91 // The caller can also pass in the constructor as a function if needed. 95 // The caller can also pass in the constructor as a function if needed.
92 // 96 //
93 // Example: 97 // Example:
94 // defineClass("A", "B", ["x", "y"], { 98 // defineClass("A", "B", ["x", "y"], {
95 // foo$1: function(y) { 99 // foo$1: function(y) {
96 // print(this.x + y); 100 // print(this.x + y);
97 // }, 101 // },
98 // bar$2: function(t, v) { 102 // bar$2: function(t, v) {
99 // this.x = t - v; 103 // this.x = t - v;
100 // }, 104 // },
101 // }); 105 // });
102 return """ 106 return """
103 function(cls, superclass, fields, prototype) { 107 function(cls, fields, prototype) {
104 var generateGetterSetter = $generateGetterSetterFunction; 108 var generateGetterSetter = $generateGetterSetterFunction;
105 var constructor; 109 var constructor;
106 if (typeof fields == 'function') { 110 if (typeof fields == 'function') {
107 constructor = fields; 111 constructor = fields;
108 } else { 112 } else {
109 var str = "function " + cls + "("; 113 var str = "function " + cls + "(";
110 var body = ""; 114 var body = "";
111 for (var i = 0; i < fields.length; i++) { 115 for (var i = 0; i < fields.length; i++) {
112 if (i != 0) str += ", "; 116 if (i != 0) str += ", ";
113 var field = fields[i]; 117 var field = fields[i];
114 field = generateGetterSetter(field, prototype); 118 field = generateGetterSetter(field, prototype);
115 str += field; 119 str += field;
116 body += "this." + field + " = " + field + ";\\n"; 120 body += "this." + field + " = " + field + ";\\n";
117 } 121 }
118 str += ") {" + body + "}\\n"; 122 str += ") {" + body + "}\\n";
119 str += "return " + cls + ";"; 123 str += "return " + cls + ";";
120 constructor = new Function(str)(); 124 constructor = new Function(str)();
121 } 125 }
122 $isolatePropertiesName[cls] = constructor;
123 constructor.prototype = prototype; 126 constructor.prototype = prototype;
124 if (superclass !== "") { 127 return constructor;
125 $pendingClassesName[cls] = superclass; 128 }""";
126 } 129 }
127 }"""; 130
131 /** Needs defineClass to be defined. */
132 String get protoSupportCheck() {
133 // On Firefox and Webkit browsers we can manipulate the __proto__
134 // directly. Opera claims to have __proto__ support, but it is buggy.
135 // So we have to do more checks.
136 // If the browser does not support __proto__ we need to instantiate an
137 // object with the correct (internal) prototype set up correctly, and then
138 // copy the members.
139
140 return '''
141 var $supportsProtoName = false;
142 var tmp = $defineClassName('c', ['f?'], {}).prototype;
143 if (tmp.__proto__) {
144 tmp.__proto__ = {};
145 if (typeof tmp.get\$f !== "undefined") $supportsProtoName = true;
146 }
147 ''';
128 } 148 }
129 149
130 String get finishClassesFunction() { 150 String get finishClassesFunction() {
131 // 'defineClass' does not require the classes to be constructed in order. 151 // 'defineClass' does not require the classes to be constructed in order.
132 // Classes are initially just stored in the 'pendingClasses' field. 152 // Classes are initially just stored in the 'pendingClasses' field.
133 // 'finishClasses' takes all pending classes and sets up the prototype. 153 // 'finishClasses' takes all pending classes and sets up the prototype.
134 // Once set up, the constructors prototype field satisfy: 154 // Once set up, the constructors prototype field satisfy:
135 // - it contains all (local) members. 155 // - it contains all (local) members.
136 // - its internal prototype (__proto__) points to the superclass' 156 // - its internal prototype (__proto__) points to the superclass'
137 // prototype field. 157 // prototype field.
138 // - the prototype's constructor field points to the JavaScript 158 // - the prototype's constructor field points to the JavaScript
139 // constructor. 159 // constructor.
140 // For engines where we have access to the '__proto__' we can manipulate 160 // For engines where we have access to the '__proto__' we can manipulate
141 // the object literal directly. For other engines we have to create a new 161 // the object literal directly. For other engines we have to create a new
142 // object and copy over the members. 162 // object and copy over the members.
143 return ''' 163 return '''
144 function(collectedClasses) { 164 function(collectedClasses) {
145 for (var collected in collectedClasses) { 165 for (var cls in collectedClasses) {
146 if (Object.prototype.hasOwnProperty.call(collectedClasses, collected)) { 166 if (Object.prototype.hasOwnProperty.call(collectedClasses, cls)) {
147 var desc = collectedClasses[collected]; 167 var desc = collectedClasses[cls];
148 $defineClassName(collected, desc.super, desc[''], desc); 168 $isolatePropertiesName[cls] = $defineClassName(cls, desc[''], desc);
169 if (desc['super'] !== "") $pendingClassesName[cls] = desc['super'];
149 } 170 }
150 } 171 }
151 var pendingClasses = $pendingClassesName; 172 var pendingClasses = $pendingClassesName;
152 '''/* FinishClasses can be called multiple times. This means that we need to 173 '''/* FinishClasses can be called multiple times. This means that we need to
153 clear the pendingClasses property. */''' 174 clear the pendingClasses property. */'''
154 $pendingClassesName = {}; 175 $pendingClassesName = {};
155 var finishedClasses = {}; 176 var finishedClasses = {};
156 function finishClass(cls) { 177 function finishClass(cls) {
157 if (finishedClasses[cls]) return; 178 if (finishedClasses[cls]) return;
158 finishedClasses[cls] = true; 179 finishedClasses[cls] = true;
159 var superclass = pendingClasses[cls]; 180 var superclass = pendingClasses[cls];
160 '''/* The superclass is only false (empty string) for Dart's Object class. */''' 181 '''/* The superclass is only false (empty string) for Dart's Object class. */'''
161 if (!superclass) return; 182 if (!superclass) return;
162 finishClass(superclass); 183 finishClass(superclass);
163 var constructor = $isolatePropertiesName[cls]; 184 var constructor = $isolatePropertiesName[cls];
164 var superConstructor = $isolatePropertiesName[superclass]; 185 var superConstructor = $isolatePropertiesName[superclass];
165 var prototype = constructor.prototype; 186 var prototype = constructor.prototype;
166 if (prototype.__proto__) { 187 if ($supportsProtoName) {
167 '''/* On Firefox and Webkit browsers we can manipulate the __proto__
168 directly. */'''
169 prototype.__proto__ = superConstructor.prototype; 188 prototype.__proto__ = superConstructor.prototype;
170 prototype.constructor = constructor; 189 prototype.constructor = constructor;
171 } else { 190 } else {
172 '''/* On the remaining browsers we need to instantiate an object with the
173 correct (internal) prototype set up correctly, and then copy the
174 members. */'''
175 function tmp() {}; 191 function tmp() {};
176 tmp.prototype = superConstructor.prototype; 192 tmp.prototype = superConstructor.prototype;
177 var newPrototype = new tmp(); 193 var newPrototype = new tmp();
178 constructor.prototype = newPrototype; 194 constructor.prototype = newPrototype;
179 newPrototype.constructor = constructor; 195 newPrototype.constructor = constructor;
180 '''/* Opera does not support 'getOwnPropertyNames'. Therefore we use 196 '''/* Opera does not support 'getOwnPropertyNames'. Therefore we use
181 hosOwnProperty instead. */''' 197 hosOwnProperty instead. */'''
182 var hasOwnProperty = Object.prototype.hasOwnProperty; 198 var hasOwnProperty = Object.prototype.hasOwnProperty;
183 for (var member in prototype) { 199 for (var member in prototype) {
184 if (member == '' || member == 'super') continue; 200 if (member == '' || member == 'super') continue;
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
230 isolatePrototype.constructor = newIsolate; 246 isolatePrototype.constructor = newIsolate;
231 newIsolate.${namer.ISOLATE_PROPERTIES} = isolateProperties; 247 newIsolate.${namer.ISOLATE_PROPERTIES} = isolateProperties;
232 return newIsolate; 248 return newIsolate;
233 }"""; 249 }""";
234 } 250 }
235 251
236 void addDefineClassAndFinishClassFunctionsIfNecessary(CodeBuffer buffer) { 252 void addDefineClassAndFinishClassFunctionsIfNecessary(CodeBuffer buffer) {
237 if (needsDefineClass) { 253 if (needsDefineClass) {
238 String isolate = namer.ISOLATE; 254 String isolate = namer.ISOLATE;
239 buffer.add("$defineClassName = $defineClassFunction;\n"); 255 buffer.add("$defineClassName = $defineClassFunction;\n");
256 buffer.add(protoSupportCheck);
240 buffer.add("$pendingClassesName = {};\n"); 257 buffer.add("$pendingClassesName = {};\n");
241 buffer.add("$finishClassesName = $finishClassesFunction;\n"); 258 buffer.add("$finishClassesName = $finishClassesFunction;\n");
242 } 259 }
243 } 260 }
244 261
245 void emitFinishIsolateConstructor(CodeBuffer buffer) { 262 void emitFinishIsolateConstructor(CodeBuffer buffer) {
246 String name = finishIsolateConstructorName; 263 String name = finishIsolateConstructorName;
247 String value = finishIsolateConstructorFunction; 264 String value = finishIsolateConstructorFunction;
248 buffer.add("$name = $value;\n"); 265 buffer.add("$name = $value;\n");
249 } 266 }
(...skipping 454 matching lines...) Expand 10 before | Expand all | Expand 10 after
704 // Create a new closure class. 721 // Create a new closure class.
705 SourceString name = const SourceString("BoundClosure"); 722 SourceString name = const SourceString("BoundClosure");
706 ClassElement closureClassElement = 723 ClassElement closureClassElement =
707 new ClosureClassElement(name, compiler, member.getCompilationUnit()); 724 new ClosureClassElement(name, compiler, member.getCompilationUnit());
708 String mangledName = namer.getName(closureClassElement); 725 String mangledName = namer.getName(closureClassElement);
709 String superName = namer.getName(closureClassElement.superclass); 726 String superName = namer.getName(closureClassElement.superclass);
710 needsClosureClass = true; 727 needsClosureClass = true;
711 728
712 // Define the constructor with a name so that Object.toString can 729 // Define the constructor with a name so that Object.toString can
713 // find the class name of the closure class. 730 // find the class name of the closure class.
714 boundClosureBuffer.add("$defineClassName('$mangledName', '$superName', "); 731 boundClosureBuffer.add("""
715 boundClosureBuffer.add("['self', 'target'], {\n"); 732 $classesCollector.$mangledName = {'':
716 733 ['self', 'target'],
734 'super': '$superName',
735 """);
717 // Now add the methods on the closure class. The instance method does not 736 // Now add the methods on the closure class. The instance method does not
718 // have the correct name. Since [addParameterStubs] use the name to create 737 // have the correct name. Since [addParameterStubs] use the name to create
719 // its stubs we simply create a fake element with the correct name. 738 // its stubs we simply create a fake element with the correct name.
720 // Note: the callElement will not have any enclosingElement. 739 // Note: the callElement will not have any enclosingElement.
721 FunctionElement callElement = 740 FunctionElement callElement =
722 new ClosureInvocationElement(namer.CLOSURE_INVOCATION_NAME, member); 741 new ClosureInvocationElement(namer.CLOSURE_INVOCATION_NAME, member);
723 742
724 String invocationName = 743 String invocationName =
725 namer.instanceMethodName(member.getLibrary(), 744 namer.instanceMethodName(member.getLibrary(),
726 callElement.name, parameterCount); 745 callElement.name, parameterCount);
727 List<String> arguments = new List<String>(parameterCount); 746 List<String> arguments = new List<String>(parameterCount);
728 for (int i = 0; i < parameterCount; i++) { 747 for (int i = 0; i < parameterCount; i++) {
729 arguments[i] = "p$i"; 748 arguments[i] = "p$i";
730 } 749 }
731 String joinedArgs = Strings.join(arguments, ", "); 750 String joinedArgs = Strings.join(arguments, ", ");
732 boundClosureBuffer.add( 751 boundClosureBuffer.add(
733 "$invocationName: function($joinedArgs) {"); 752 "$invocationName: function($joinedArgs) {");
734 boundClosureBuffer.add(" return this.self[this.target]($joinedArgs);"); 753 boundClosureBuffer.add(" return this.self[this.target]($joinedArgs);");
735 boundClosureBuffer.add(" }"); 754 boundClosureBuffer.add(" }");
736 addParameterStubs(callElement, (String stubName, CodeBuffer memberValue) { 755 addParameterStubs(callElement, (String stubName, CodeBuffer memberValue) {
737 boundClosureBuffer.add(',\n $stubName: $memberValue'); 756 boundClosureBuffer.add(',\n $stubName: $memberValue');
738 }); 757 });
739 boundClosureBuffer.add("\n});\n"); 758 boundClosureBuffer.add("\n};\n");
740 759
741 closureClass = namer.isolateAccess(closureClassElement); 760 closureClass = namer.isolateAccess(closureClassElement);
742 761
743 // Cache it. 762 // Cache it.
744 if (!hasOptionalParameters) { 763 if (!hasOptionalParameters) {
745 boundClosureCache[parameterCount] = closureClass; 764 boundClosureCache[parameterCount] = closureClass;
746 } 765 }
747 } 766 }
748 767
749 // And finally the getter. 768 // And finally the getter.
(...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after
1033 // the classesCollector variable. 1052 // the classesCollector variable.
1034 classesCollector = 'classesCollector should not be used from now on'; 1053 classesCollector = 'classesCollector should not be used from now on';
1035 1054
1036 emitFinishIsolateConstructorInvocation(mainBuffer); 1055 emitFinishIsolateConstructorInvocation(mainBuffer);
1037 mainBuffer.add( 1056 mainBuffer.add(
1038 'var ${namer.CURRENT_ISOLATE} = new ${namer.ISOLATE}();\n'); 1057 'var ${namer.CURRENT_ISOLATE} = new ${namer.ISOLATE}();\n');
1039 1058
1040 nativeEmitter.assembleCode(mainBuffer); 1059 nativeEmitter.assembleCode(mainBuffer);
1041 emitMain(mainBuffer); 1060 emitMain(mainBuffer);
1042 mainBuffer.add('function init() {\n'); 1061 mainBuffer.add('function init() {\n');
1043 mainBuffer.add(' $isolateProperties = {};\n'); 1062 mainBuffer.add('$isolateProperties = {};\n');
1044 addDefineClassAndFinishClassFunctionsIfNecessary(mainBuffer); 1063 addDefineClassAndFinishClassFunctionsIfNecessary(mainBuffer);
1045 emitFinishIsolateConstructor(mainBuffer); 1064 emitFinishIsolateConstructor(mainBuffer);
1046 mainBuffer.add('}\n'); 1065 mainBuffer.add('}\n');
1047 compiler.assembledCode = mainBuffer.toString(); 1066 compiler.assembledCode = mainBuffer.toString();
1048 1067
1049 if (generateSourceMap) { 1068 if (generateSourceMap) {
1050 SourceFile compiledFile = new SourceFile(null, compiler.assembledCode); 1069 SourceFile compiledFile = new SourceFile(null, compiler.assembledCode);
1051 String sourceMap = sourceMapBuilder.build(compiledFile); 1070 String sourceMap = sourceMapBuilder.build(compiledFile);
1052 // TODO(podivilov): We should find a better way to return source maps to 1071 // TODO(podivilov): We should find a better way to return source maps to
1053 // compiler. Using diagnostic handler for that purpose is a temporary 1072 // compiler. Using diagnostic handler for that purpose is a temporary
(...skipping 13 matching lines...) Expand all
1067 sourceName = token.slowToString(); 1086 sourceName = token.slowToString();
1068 } 1087 }
1069 int totalOffset = bufferOffset + offset; 1088 int totalOffset = bufferOffset + offset;
1070 sourceMapBuilder.addMapping( 1089 sourceMapBuilder.addMapping(
1071 sourceFile, token.charOffset, sourceName, totalOffset); 1090 sourceFile, token.charOffset, sourceName, totalOffset);
1072 }); 1091 });
1073 } 1092 }
1074 } 1093 }
1075 1094
1076 typedef void DefineMemberFunction(String invocationName, CodeBuffer definition); 1095 typedef void DefineMemberFunction(String invocationName, CodeBuffer definition);
OLDNEW
« no previous file with comments | « no previous file | lib/compiler/implementation/lib/native_helper.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698