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

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

Issue 10696194: Introduce CodeBuffer as StringBuffer replacement in compiler. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: . 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
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 class NativeEmitter { 5 class NativeEmitter {
6 6
7 CodeEmitterTask emitter; 7 CodeEmitterTask emitter;
8 StringBuffer nativeBuffer; 8 CodeBuffer nativeBuffer;
9 9
10 // Classes that participate in dynamic dispatch. These are the 10 // Classes that participate in dynamic dispatch. These are the
11 // classes that contain used members. 11 // classes that contain used members.
12 Set<ClassElement> classesWithDynamicDispatch; 12 Set<ClassElement> classesWithDynamicDispatch;
13 13
14 // Native classes found in the application. 14 // Native classes found in the application.
15 Set<ClassElement> nativeClasses; 15 Set<ClassElement> nativeClasses;
16 16
17 // Caches the native subtypes of a native class. 17 // Caches the native subtypes of a native class.
18 Map<ClassElement, List<ClassElement>> subtypes; 18 Map<ClassElement, List<ClassElement>> subtypes;
(...skipping 14 matching lines...) Expand all
33 Map<FunctionElement, String> redirectingMethods; 33 Map<FunctionElement, String> redirectingMethods;
34 34
35 NativeEmitter(this.emitter) 35 NativeEmitter(this.emitter)
36 : classesWithDynamicDispatch = new Set<ClassElement>(), 36 : classesWithDynamicDispatch = new Set<ClassElement>(),
37 nativeClasses = new Set<ClassElement>(), 37 nativeClasses = new Set<ClassElement>(),
38 subtypes = new Map<ClassElement, List<ClassElement>>(), 38 subtypes = new Map<ClassElement, List<ClassElement>>(),
39 directSubtypes = new Map<ClassElement, List<ClassElement>>(), 39 directSubtypes = new Map<ClassElement, List<ClassElement>>(),
40 overriddenMethods = new Set<FunctionElement>(), 40 overriddenMethods = new Set<FunctionElement>(),
41 nativeMethods = new Set<FunctionElement>(), 41 nativeMethods = new Set<FunctionElement>(),
42 redirectingMethods = new Map<FunctionElement, String>(), 42 redirectingMethods = new Map<FunctionElement, String>(),
43 nativeBuffer = new StringBuffer(); 43 nativeBuffer = new CodeBuffer();
44 44
45 Compiler get compiler() => emitter.compiler; 45 Compiler get compiler() => emitter.compiler;
46 46
47 void addRedirectingMethod(FunctionElement element, String name) { 47 void addRedirectingMethod(FunctionElement element, String name) {
48 redirectingMethods[element] = name; 48 redirectingMethods[element] = name;
49 } 49 }
50 50
51 String get dynamicName() { 51 String get dynamicName() {
52 Element element = compiler.findHelper( 52 Element element = compiler.findHelper(
53 const SourceString('dynamicFunction')); 53 const SourceString('dynamicFunction'));
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
96 96
97 void generateNativeLiteral(ClassElement classElement) { 97 void generateNativeLiteral(ClassElement classElement) {
98 String quotedNative = classElement.nativeName.slowToString(); 98 String quotedNative = classElement.nativeName.slowToString();
99 String nativeCode = quotedNative.substring(2, quotedNative.length - 1); 99 String nativeCode = quotedNative.substring(2, quotedNative.length - 1);
100 String className = compiler.namer.getName(classElement); 100 String className = compiler.namer.getName(classElement);
101 nativeBuffer.add(className); 101 nativeBuffer.add(className);
102 nativeBuffer.add(' = '); 102 nativeBuffer.add(' = ');
103 nativeBuffer.add(nativeCode); 103 nativeBuffer.add(nativeCode);
104 nativeBuffer.add(';\n'); 104 nativeBuffer.add(';\n');
105 105
106 void defineInstanceMember(String name, 106 void defineInstanceMember(String name, CodeBuffer value) {
107 String value,
108 [List<SourceMappingEntry> sourceMappings]) {
109 nativeBuffer.add("$className.$name = $value;\n"); 107 nativeBuffer.add("$className.$name = $value;\n");
110 } 108 }
111 109
112 for (Element member in classElement.members) { 110 for (Element member in classElement.members) {
113 if (member.isInstanceMember()) { 111 if (member.isInstanceMember()) {
114 emitter.addInstanceMember(member, defineInstanceMember); 112 emitter.addInstanceMember(member, defineInstanceMember);
115 } 113 }
116 } 114 }
117 } 115 }
118 116
(...skipping 20 matching lines...) Expand all
139 137
140 assert(classElement.backendMembers.isEmpty()); 138 assert(classElement.backendMembers.isEmpty());
141 String quotedName = classElement.nativeName.slowToString(); 139 String quotedName = classElement.nativeName.slowToString();
142 if (isNativeLiteral(quotedName)) { 140 if (isNativeLiteral(quotedName)) {
143 generateNativeLiteral(classElement); 141 generateNativeLiteral(classElement);
144 // The native literal kind needs to be dealt with specially when 142 // The native literal kind needs to be dealt with specially when
145 // generating code for it. 143 // generating code for it.
146 return; 144 return;
147 } 145 }
148 146
149 StringBuffer fieldBuffer = new StringBuffer(); 147 CodeBuffer fieldBuffer = new CodeBuffer();
150 emitter.emitClassFields(classElement, fieldBuffer); 148 emitter.emitClassFields(classElement, fieldBuffer);
151 149
152 StringBuffer methodBuffer = new StringBuffer(); 150 CodeBuffer methodBuffer = new CodeBuffer();
153 emitter.emitInstanceMembers(classElement, methodBuffer, false); 151 emitter.emitInstanceMembers(classElement, methodBuffer, false);
154 152
155 if (methodBuffer.isEmpty() && fieldBuffer.isEmpty()) return; 153 if (methodBuffer.isEmpty() && fieldBuffer.isEmpty()) return;
156 154
157 String nativeName = toNativeName(classElement); 155 String nativeName = toNativeName(classElement);
158 nativeBuffer.add("$defineNativeClassName('$nativeName', ["); 156 nativeBuffer.add("$defineNativeClassName('$nativeName', [");
159 nativeBuffer.add(fieldBuffer); 157 nativeBuffer.add(fieldBuffer);
160 nativeBuffer.add('], {'); 158 nativeBuffer.add('], {');
161 nativeBuffer.add(methodBuffer); 159 nativeBuffer.add(methodBuffer);
162 nativeBuffer.add('\n});\n\n'); 160 nativeBuffer.add('\n});\n\n');
163 161
164 classesWithDynamicDispatch.add(classElement); 162 classesWithDynamicDispatch.add(classElement);
165 } 163 }
166 164
167 List<ClassElement> getDirectSubclasses(ClassElement cls) { 165 List<ClassElement> getDirectSubclasses(ClassElement cls) {
168 List<ClassElement> result = directSubtypes[cls]; 166 List<ClassElement> result = directSubtypes[cls];
169 return result === null ? const<ClassElement>[] : result; 167 return result === null ? const<ClassElement>[] : result;
170 } 168 }
171 169
172 void potentiallyConvertDartClosuresToJs(StringBuffer code, 170 void potentiallyConvertDartClosuresToJs(CodeBuffer code,
173 FunctionElement member, 171 FunctionElement member,
174 List<String> argumentsBuffer) { 172 List<String> argumentsBuffer) {
175 FunctionSignature parameters = member.computeSignature(compiler); 173 FunctionSignature parameters = member.computeSignature(compiler);
176 Element converter = 174 Element converter =
177 compiler.findHelper(const SourceString('convertDartClosureToJS')); 175 compiler.findHelper(const SourceString('convertDartClosureToJS'));
178 String closureConverter = compiler.namer.isolateAccess(converter); 176 String closureConverter = compiler.namer.isolateAccess(converter);
179 parameters.forEachParameter((Element parameter) { 177 parameters.forEachParameter((Element parameter) {
180 String name = parameter.name.slowToString(); 178 String name = parameter.name.slowToString();
181 // If [name] is not in [argumentsBuffer], then the parameter is 179 // If [name] is not in [argumentsBuffer], then the parameter is
182 // an optional parameter that was not provided for that stub. 180 // an optional parameter that was not provided for that stub.
183 if (argumentsBuffer.indexOf(name) == -1) return; 181 if (argumentsBuffer.indexOf(name) == -1) return;
184 Type type = parameter.computeType(compiler); 182 Type type = parameter.computeType(compiler);
185 if (type is FunctionType) { 183 if (type is FunctionType) {
186 int arity = type.computeArity(); 184 int arity = type.computeArity();
187 code.add(' $name = $closureConverter($name, $arity);\n'); 185 code.add(' $name = $closureConverter($name, $arity);\n');
188 } 186 }
189 }); 187 });
190 } 188 }
191 189
192 String generateParameterStub(Element member, 190 String generateParameterStub(Element member,
193 String invocationName, 191 String invocationName,
194 String stubParameters, 192 String stubParameters,
195 List<String> argumentsBuffer, 193 List<String> argumentsBuffer,
196 int indexOfLastOptionalArgumentInParameters, 194 int indexOfLastOptionalArgumentInParameters,
197 StringBuffer buffer) { 195 CodeBuffer buffer) {
198 // The target JS function may check arguments.length so we need to 196 // The target JS function may check arguments.length so we need to
199 // make sure not to pass any unspecified optional arguments to it. 197 // make sure not to pass any unspecified optional arguments to it.
200 // For example, for the following Dart method: 198 // For example, for the following Dart method:
201 // foo([x, y, z]); 199 // foo([x, y, z]);
202 // The call: 200 // The call:
203 // foo(y: 1) 201 // foo(y: 1)
204 // must be turned into a JS call to: 202 // must be turned into a JS call to:
205 // foo(null, y). 203 // foo(null, y).
206 204
207 List<String> nativeArgumentsBuffer = argumentsBuffer.getRange( 205 List<String> nativeArgumentsBuffer = argumentsBuffer.getRange(
208 0, indexOfLastOptionalArgumentInParameters + 1); 206 0, indexOfLastOptionalArgumentInParameters + 1);
209 207
210 ClassElement classElement = member.enclosingElement; 208 ClassElement classElement = member.enclosingElement;
211 String nativeName = classElement.nativeName.slowToString(); 209 String nativeName = classElement.nativeName.slowToString();
212 String nativeArguments = Strings.join(nativeArgumentsBuffer, ","); 210 String nativeArguments = Strings.join(nativeArgumentsBuffer, ",");
213 211
214 StringBuffer code = new StringBuffer(); 212 CodeBuffer code = new CodeBuffer();
215 potentiallyConvertDartClosuresToJs(code, member, argumentsBuffer); 213 potentiallyConvertDartClosuresToJs(code, member, argumentsBuffer);
216 214
217 if (!nativeMethods.contains(member)) { 215 if (!nativeMethods.contains(member)) {
218 // When calling a method that has a native body, we call it 216 // When calling a method that has a native body, we call it
219 // with our calling conventions. 217 // with our calling conventions.
220 String arguments = Strings.join(argumentsBuffer, ","); 218 String arguments = Strings.join(argumentsBuffer, ",");
221 code.add(' return this.${compiler.namer.getName(member)}($arguments)'); 219 code.add(' return this.${compiler.namer.getName(member)}($arguments)');
222 } else { 220 } else {
223 // When calling a JS method, we call it with the native name. 221 // When calling a JS method, we call it with the native name.
224 String name = redirectingMethods[member]; 222 String name = redirectingMethods[member];
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after
367 return subtypes[element] !== null; 365 return subtypes[element] !== null;
368 } 366 }
369 367
370 bool requiresNativeIsCheck(Element element) { 368 bool requiresNativeIsCheck(Element element) {
371 if (!element.isClass()) return false; 369 if (!element.isClass()) return false;
372 ClassElement cls = element; 370 ClassElement cls = element;
373 if (cls.isNative()) return true; 371 if (cls.isNative()) return true;
374 return isSupertypeOfNativeClass(element); 372 return isSupertypeOfNativeClass(element);
375 } 373 }
376 374
377 void emitIsChecks(StringBuffer checkBuffer) { 375 void emitIsChecks(CodeBuffer checkBuffer) {
378 for (Element type in compiler.codegenWorld.isChecks) { 376 for (Element type in compiler.codegenWorld.isChecks) {
379 if (!requiresNativeIsCheck(type)) continue; 377 if (!requiresNativeIsCheck(type)) continue;
380 String name = compiler.namer.operatorIs(type); 378 String name = compiler.namer.operatorIs(type);
381 checkBuffer.add("$defPropName(Object.prototype, '$name', "); 379 checkBuffer.add("$defPropName(Object.prototype, '$name', ");
382 checkBuffer.add('function() { return false; });\n'); 380 checkBuffer.add('function() { return false; });\n');
383 } 381 }
384 } 382 }
385 383
386 void assembleCode(StringBuffer targetBuffer) { 384 void assembleCode(CodeBuffer targetBuffer) {
387 if (nativeClasses.isEmpty()) return; 385 if (nativeClasses.isEmpty()) return;
388 emitDynamicDispatchMetadata(); 386 emitDynamicDispatchMetadata();
389 387
390 // Because of native classes, we have to generate some is checks 388 // Because of native classes, we have to generate some is checks
391 // by calling a method, instead of accessing a property. So we 389 // by calling a method, instead of accessing a property. So we
392 // attach to the JS Object prototype these methods that return 390 // attach to the JS Object prototype these methods that return
393 // false, and will be overridden by subclasses when they have to 391 // false, and will be overridden by subclasses when they have to
394 // return true. 392 // return true.
395 StringBuffer objectProperties = new StringBuffer(); 393 CodeBuffer objectProperties = new CodeBuffer();
396 emitIsChecks(objectProperties); 394 emitIsChecks(objectProperties);
397 395
398 // In order to have the toString method on every native class, 396 // In order to have the toString method on every native class,
399 // we must patch the JS Object prototype with a helper method. 397 // we must patch the JS Object prototype with a helper method.
400 String toStringName = compiler.namer.instanceMethodName( 398 String toStringName = compiler.namer.instanceMethodName(
401 null, const SourceString('toString'), 0); 399 null, const SourceString('toString'), 0);
402 objectProperties.add("$defPropName(Object.prototype, '$toStringName', "); 400 objectProperties.add("$defPropName(Object.prototype, '$toStringName', ");
403 objectProperties.add( 401 objectProperties.add(
404 'function() { return $toStringHelperName(this); });\n'); 402 'function() { return $toStringHelperName(this); });\n');
405 403
406 targetBuffer.add('$defineNativeClassName = $defineNativeClassFunction;\n'); 404 targetBuffer.add('$defineNativeClassName = $defineNativeClassFunction;\n');
407 targetBuffer.add('$objectProperties$nativeBuffer\n'); 405 targetBuffer.add('$objectProperties$nativeBuffer\n');
408 } 406 }
409 } 407 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698