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

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

Issue 11411215: Generate parameter stubs using ASTs. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: 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 class NativeEmitter { 7 class NativeEmitter {
8 8
9 CodeEmitterTask emitter; 9 CodeEmitterTask emitter;
10 CodeBuffer nativeBuffer; 10 CodeBuffer nativeBuffer;
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after
199 nativeBuffer.add('\n});\n\n'); 199 nativeBuffer.add('\n});\n\n');
200 200
201 classesWithDynamicDispatch.add(classElement); 201 classesWithDynamicDispatch.add(classElement);
202 } 202 }
203 203
204 List<ClassElement> getDirectSubclasses(ClassElement cls) { 204 List<ClassElement> getDirectSubclasses(ClassElement cls) {
205 List<ClassElement> result = directSubtypes[cls]; 205 List<ClassElement> result = directSubtypes[cls];
206 return result == null ? const<ClassElement>[] : result; 206 return result == null ? const<ClassElement>[] : result;
207 } 207 }
208 208
209 void potentiallyConvertDartClosuresToJs(CodeBuffer code, 209 void potentiallyConvertDartClosuresToJs(List<js.Statement> statements,
210 FunctionElement member, 210 FunctionElement member,
211 List<String> argumentsBuffer) { 211 List<js.Parameter> stubParameters) {
212 FunctionSignature parameters = member.computeSignature(compiler); 212 FunctionSignature parameters = member.computeSignature(compiler);
213 Element converter = 213 Element converter =
214 compiler.findHelper(const SourceString('convertDartClosureToJS')); 214 compiler.findHelper(const SourceString('convertDartClosureToJS'));
215 String closureConverter = backend.namer.isolateAccess(converter); 215 String closureConverter = backend.namer.isolateAccess(converter);
216 Set<String> stubParameterNames = new Set<String>.from(
217 stubParameters.map((param) => param.name));
ngeoffray 2012/11/30 09:01:56 I would to this by hand to keep the order and then
216 parameters.forEachParameter((Element parameter) { 218 parameters.forEachParameter((Element parameter) {
217 String name = parameter.name.slowToString(); 219 String name = parameter.name.slowToString();
218 // If [name] is not in [argumentsBuffer], then the parameter is 220 // If [name] is not in [stubParameters], then the parameter is an optional
219 // an optional parameter that was not provided for that stub. 221 // parameter that was not provided for this stub.
220 if (argumentsBuffer.indexOf(name) == -1) return; 222 for (js.Parameter stubParameter in stubParameters) {
221 DartType type = parameter.computeType(compiler).unalias(compiler); 223 if (stubParameter.name == name) {
222 if (type is FunctionType) { 224 DartType type = parameter.computeType(compiler).unalias(compiler);
223 // The parameter type is a function type either directly or through 225 if (type is FunctionType) {
224 // typedef(s). 226 // The parameter type is a function type either directly or through
225 int arity = type.computeArity(); 227 // typedef(s).
226 code.add(' $name = $closureConverter($name, $arity);\n'); 228 int arity = type.computeArity();
229
230 statements.add(
231 new js.ExpressionStatement(
232 new js.Assignment(
233 new js.VariableUse(name),
234 new js.VariableUse(closureConverter)
235 .callWith([new js.VariableUse(name),
236 new js.LiteralNumber('$arity')]))));
237 break;
238 }
239 }
227 } 240 }
228 }); 241 });
229 } 242 }
230 243
231 String generateParameterStub(Element member, 244 List<js.Statement> generateParameterStubStatements(
232 String invocationName, 245 Element member,
233 String stubParameters, 246 String invocationName,
234 List<String> argumentsBuffer, 247 List<js.Parameter> stubParameters,
235 int indexOfLastOptionalArgumentInParameters, 248 List<js.Expression> argumentsBuffer,
236 CodeBuffer buffer) { 249 int indexOfLastOptionalArgumentInParameters) {
237 // The target JS function may check arguments.length so we need to 250 // The target JS function may check arguments.length so we need to
238 // make sure not to pass any unspecified optional arguments to it. 251 // make sure not to pass any unspecified optional arguments to it.
239 // For example, for the following Dart method: 252 // For example, for the following Dart method:
240 // foo([x, y, z]); 253 // foo([x, y, z]);
241 // The call: 254 // The call:
242 // foo(y: 1) 255 // foo(y: 1)
243 // must be turned into a JS call to: 256 // must be turned into a JS call to:
244 // foo(null, y). 257 // foo(null, y).
245 258
246 List<String> nativeArgumentsBuffer = argumentsBuffer.getRange( 259 ClassElement classElement = member.enclosingElement;
247 0, indexOfLastOptionalArgumentInParameters + 1); 260 String nativeTagInfo = classElement.nativeName.slowToString();
248 261
249 ClassElement classElement = member.enclosingElement; 262 List<js.Statement> statements = <js.Statement>[];
250 String nativeName = classElement.nativeName.slowToString(); 263 potentiallyConvertDartClosuresToJs(statements, member, stubParameters);
251 String nativeArguments = Strings.join(nativeArgumentsBuffer, ",");
252 264
253 CodeBuffer code = new CodeBuffer(); 265 String target;
254 potentiallyConvertDartClosuresToJs(code, member, argumentsBuffer); 266 List<js.Expression> arguments;
255 267
256 if (!nativeMethods.contains(member)) { 268 if (!nativeMethods.contains(member)) {
257 // When calling a method that has a native body, we call it 269 // When calling a method that has a native body, we call it with our
258 // with our calling conventions. 270 // calling conventions.
259 String arguments = Strings.join(argumentsBuffer, ","); 271 target = backend.namer.getName(member);
260 code.add(' return this.${backend.namer.getName(member)}($arguments)'); 272 arguments = argumentsBuffer;
261 } else { 273 } else {
262 // When calling a JS method, we call it with the native name. 274 // When calling a JS method, we call it with the native name, and only the
263 String name = redirectingMethods[member]; 275 // arguments up until the last one provided.
264 if (name == null) name = member.name.slowToString(); 276 target = redirectingMethods[member];
265 code.add(' return this.$name($nativeArguments);'); 277 if (target == null) target = member.name.slowToString();
278 arguments = argumentsBuffer.getRange(
279 0, indexOfLastOptionalArgumentInParameters + 1);
280 }
281 statements.add(
282 new js.Return(
283 new js.VariableUse('this').dot(target).callWith(arguments)));
284
285 if (isNativeLiteral(nativeTagInfo) || !overriddenMethods.contains(member)) {
286 // Call the method directly.
287 return statements;
288 } else {
289 return <js.Statement>[
290 generateMethodBodyWithPrototypeCheck(
291 invocationName, new js.Block(statements), stubParameters)];
292 }
293 }
294
295 // If a method is overridden, we must check if the prototype of 'this' has the
296 // method available. Otherwise, we may end up calling the method from the
297 // super class. If the method is not available, we make a direct call to
298 // Object.prototype.$methodName. This method will patch the prototype of
299 // 'this' to the real method.
300 js.Statement generateMethodBodyWithPrototypeCheck(
301 String methodName,
302 js.Statement body,
303 List<js.Parameter> parameters) {
304 return new js.If(
305 new js.VariableUse('Object')
306 .dot('getPrototypeOf')
307 .callWith([new js.VariableUse('this')])
308 .dot('hasOwnProperty')
309 .callWith([new js.LiteralString("'$methodName'")]),
310 body,
311 new js.Block(
312 <js.Statement>[
313 new js.Return(
314 new js.VariableUse('Object')
315 .dot('prototype').dot(methodName).dot('call')
316 .callWith(
317 <js.Expression>[new js.VariableUse('this')]
318 ..addAll(parameters.map((param) =>
319 new js.VariableUse(param.name)))))
320 ]));
321 }
322
323 js.Block generateMethodBodyWithPrototypeCheckForElement(
324 FunctionElement element,
325 js.Block body,
326 List<js.Parameter> parameters) {
327 String methodName;
328 Namer namer = backend.namer;
329 if (element.kind == ElementKind.FUNCTION) {
330 methodName = namer.instanceMethodName(element);
331 } else if (element.kind == ElementKind.GETTER) {
332 methodName = namer.getterName(element.getLibrary(), element.name);
333 } else if (element.kind == ElementKind.SETTER) {
334 methodName = namer.setterName(element.getLibrary(), element.name);
335 } else {
336 compiler.internalError('unexpected kind: "${element.kind}"',
337 element: element);
266 } 338 }
267 339
268 if (isNativeLiteral(nativeName) || !overriddenMethods.contains(member)) { 340 return new js.Block(
269 // Call the method directly. 341 [generateMethodBodyWithPrototypeCheck(methodName, body, parameters)]);
270 buffer.add(code.toString());
271 } else {
272 native.generateMethodWithPrototypeCheck(
273 compiler, buffer, invocationName, code.toString(), stubParameters);
274 }
275 } 342 }
276 343
344
277 void emitDynamicDispatchMetadata() { 345 void emitDynamicDispatchMetadata() {
278 if (classesWithDynamicDispatch.isEmpty) return; 346 if (classesWithDynamicDispatch.isEmpty) return;
279 int length = classesWithDynamicDispatch.length; 347 int length = classesWithDynamicDispatch.length;
280 nativeBuffer.add('// $length dynamic classes.\n'); 348 nativeBuffer.add('// $length dynamic classes.\n');
281 349
282 // Build a pre-order traversal over all the classes and their subclasses. 350 // Build a pre-order traversal over all the classes and their subclasses.
283 Set<ClassElement> seen = new Set<ClassElement>(); 351 Set<ClassElement> seen = new Set<ClassElement>();
284 List<ClassElement> classes = <ClassElement>[]; 352 List<ClassElement> classes = <ClassElement>[];
285 void visit(ClassElement cls) { 353 void visit(ClassElement cls) {
286 if (seen.contains(cls)) return; 354 if (seen.contains(cls)) return;
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after
506 if (!first) targetBuffer.add(",\n"); 574 if (!first) targetBuffer.add(",\n");
507 targetBuffer.add(" $name: $function"); 575 targetBuffer.add(" $name: $function");
508 first = false; 576 first = false;
509 }); 577 });
510 targetBuffer.add("\n});\n\n"); 578 targetBuffer.add("\n});\n\n");
511 } 579 }
512 targetBuffer.add(nativeBuffer); 580 targetBuffer.add(nativeBuffer);
513 targetBuffer.add('\n'); 581 targetBuffer.add('\n');
514 } 582 }
515 } 583 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698