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

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

Issue 10092012: Fix issue 2358: dart methods on native classes must also check if the current prototype has the met… (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 8 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 #library('native'); 5 #library('native');
6 #import('dart:uri'); 6 #import('dart:uri');
7 #import('leg.dart'); 7 #import('leg.dart');
8 #import('elements/elements.dart'); 8 #import('elements/elements.dart');
9 #import('scanner/scannerlib.dart'); 9 #import('scanner/scannerlib.dart');
10 #import('ssa/ssa.dart'); 10 #import('ssa/ssa.dart');
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
140 listener.handleIdentifier(token); 140 listener.handleIdentifier(token);
141 token = token.next; 141 token = token.next;
142 if (token.kind === STRING_TOKEN) { 142 if (token.kind === STRING_TOKEN) {
143 listener.beginLiteralString(token); 143 listener.beginLiteralString(token);
144 listener.endLiteralString(0); 144 listener.endLiteralString(0);
145 LiteralString str = listener.popNode(); 145 LiteralString str = listener.popNode();
146 listener.pushNode(new NodeList.singleton(str)); 146 listener.pushNode(new NodeList.singleton(str));
147 listener.endSend(token); 147 listener.endSend(token);
148 token = token.next; 148 token = token.next;
149 // If this native method is just redirecting to another method, 149 // If this native method is just redirecting to another method,
150 // we add a return node to match the SSA builder expactations. 150 // we add a return node to match the SSA builder expectations.
151 if (nativeRedirectionRegExp.hasMatch(str.dartString.slowToString())) { 151 if (nativeRedirectionRegExp.hasMatch(str.dartString.slowToString())) {
152 listener.endReturnStatement(true, begin, token); 152 listener.endReturnStatement(true, begin, token);
153 } else { 153 } else {
154 listener.endExpressionStatement(token); 154 listener.endExpressionStatement(token);
155 } 155 }
156 } else { 156 } else {
157 listener.pushNode(new NodeList.empty()); 157 listener.pushNode(new NodeList.empty());
158 listener.endSend(token); 158 listener.endSend(token);
159 listener.endReturnStatement(true, begin, token); 159 listener.endReturnStatement(true, begin, token);
160 } 160 }
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
249 receiver = '#.'; 249 receiver = '#.';
250 inputs.add(builder.localsHandler.readThis()); 250 inputs.add(builder.localsHandler.readThis());
251 } 251 }
252 parameters.forEachParameter((Element parameter) { 252 parameters.forEachParameter((Element parameter) {
253 Type type = parameter.computeType(compiler); 253 Type type = parameter.computeType(compiler);
254 HInstruction input = builder.localsHandler.readLocal(parameter); 254 HInstruction input = builder.localsHandler.readLocal(parameter);
255 if (type is FunctionType) input = convertDartClosure(parameter); 255 if (type is FunctionType) input = convertDartClosure(parameter);
256 inputs.add(input); 256 inputs.add(input);
257 arguments.add('#'); 257 arguments.add('#');
258 }); 258 });
259
259 String foreignParameters = Strings.join(arguments, ','); 260 String foreignParameters = Strings.join(arguments, ',');
260
261 String dartMethodName;
262 String nativeMethodCall; 261 String nativeMethodCall;
263
264 if (element.kind == ElementKind.FUNCTION) { 262 if (element.kind == ElementKind.FUNCTION) {
265 dartMethodName = builder.compiler.namer.instanceMethodName(
266 element.getLibrary(), element.name, parameters.parameterCount);
267 nativeMethodCall = '$receiver$nativeMethodName($foreignParameters)'; 263 nativeMethodCall = '$receiver$nativeMethodName($foreignParameters)';
268 } else if (element.kind == ElementKind.GETTER) { 264 } else if (element.kind == ElementKind.GETTER) {
269 dartMethodName = builder.compiler.namer.getterName(
270 element.getLibrary(), element.name);
271 nativeMethodCall = '$receiver$nativeMethodName'; 265 nativeMethodCall = '$receiver$nativeMethodName';
272 } else if (element.kind == ElementKind.SETTER) { 266 } else if (element.kind == ElementKind.SETTER) {
273 dartMethodName = builder.compiler.namer.setterName(
274 element.getLibrary(), element.name);
275 nativeMethodCall = '$receiver$nativeMethodName = $foreignParameters'; 267 nativeMethodCall = '$receiver$nativeMethodName = $foreignParameters';
276 } else { 268 } else {
277 builder.compiler.internalError('unexpected kind: "${element.kind}"', 269 builder.compiler.internalError('unexpected kind: "${element.kind}"',
278 element: element); 270 element: element);
279 } 271 }
280 272
281 HInstruction thenInstruction; 273 DartString jsCode = new DartString.literal(nativeMethodCall);
282 void visitThen() { 274 builder.push(
283 DartString jsCode = new DartString.literal(nativeMethodCall); 275 new HForeign(jsCode, const LiteralDartString('Object'), inputs));
284 thenInstruction =
285 new HForeign(jsCode, const LiteralDartString('Object'), inputs);
286 builder.add(thenInstruction);
287 }
288
289 bool isNativeLiteral = false;
290 bool isOverridden = false;
291 NativeEmitter nativeEmitter = builder.compiler.emitter.nativeEmitter;
292 if (element.enclosingElement.kind == ElementKind.CLASS) {
293 ClassElement classElement = element.enclosingElement;
294 String nativeName = classElement.nativeName.slowToString();
295 isNativeLiteral = nativeEmitter.isNativeLiteral(nativeName);
296 isOverridden = isOverriddenMethod(element, classElement, nativeEmitter);
297 }
298 if (!element.isInstanceMember() || isNativeLiteral || !isOverridden) {
299 // We generate a direct call to the native method.
300 visitThen();
301 builder.stack.add(thenInstruction);
302 } else {
303 // Record that this method is overridden. In case of optional
304 // arguments, the emitter will generate stubs to handle them,
305 // and needs to know if the method is overridden.
306 nativeEmitter.overriddenMethods.add(element);
307
308 // If the method is an instance method that is overridden, we
309 // generate the following code:
310 // function(params) {
311 // return Object.getPrototypeOf(this).hasOwnProperty(dartMethodName))
312 // ? this.methodName(params)
313 // : Object.prototype.methodName.call(this, params);
314 // }
315 //
316 // The property check at the beginning is to make sure we won't
317 // call the method from the super class, in case the prototype of
318 // 'this' does not have the method yet.
319 HInstruction elseInstruction;
320 void visitElse() {
321 String params = arguments.isEmpty() ? '' : ', $foreignParameters';
322 DartString jsCode = new DartString.literal(
323 'Object.prototype.$dartMethodName.call(#$params)');
324 elseInstruction =
325 new HForeign(jsCode, const LiteralDartString('Object'), inputs);
326 builder.add(elseInstruction);
327 }
328
329 HConstant constant = builder.graph.addConstantString(
330 new DartString.literal('$dartMethodName'));
331 DartString jsCode = new DartString.literal(
332 'Object.getPrototypeOf(#).hasOwnProperty(#)');
333 builder.push(new HForeign(
334 jsCode, const LiteralDartString('Object'),
335 <HInstruction>[builder.localsHandler.readThis(), constant]));
336
337 builder.handleIf(visitThen, visitElse);
338
339 HPhi phi = new HPhi.manyInputs(
340 null, <HInstruction>[thenInstruction, elseInstruction]);
341 builder.current.addPhi(phi);
342 builder.stack.add(phi);
343 }
344 } else { 276 } else {
345 // This is JS code written in a Dart file with the construct 277 // This is JS code written in a Dart file with the construct
346 // native """ ... """;. It does not work well with mangling, 278 // native """ ... """;. It does not work well with mangling,
347 // but there should currently be no clash between leg mangling 279 // but there should currently be no clash between leg mangling
348 // and the library where this construct is being used. This 280 // and the library where this construct is being used. This
349 // mangling problem will go away once we switch these libraries 281 // mangling problem will go away once we switch these libraries
350 // to use Leg's 'JS' function. 282 // to use Leg's 'JS' function.
351 parameters.forEachParameter((Element parameter) { 283 parameters.forEachParameter((Element parameter) {
352 Type type = parameter.computeType(compiler); 284 Type type = parameter.computeType(compiler);
353 if (type is FunctionType) { 285 if (type is FunctionType) {
354 HInstruction jsClosure = convertDartClosure(parameter); 286 HInstruction jsClosure = convertDartClosure(parameter);
355 // Because the JS code references the argument name directly, 287 // Because the JS code references the argument name directly,
356 // we must keep the name and assign the JS closure to it. 288 // we must keep the name and assign the JS closure to it.
357 builder.add(new HForeign( 289 builder.add(new HForeign(
358 new DartString.literal('${parameter.name.slowToString()} = #'), 290 new DartString.literal('${parameter.name.slowToString()} = #'),
359 const LiteralDartString('void'), 291 const LiteralDartString('void'),
360 <HInstruction>[jsClosure])); 292 <HInstruction>[jsClosure]));
361 } 293 }
362 }); 294 });
363 LiteralString jsCode = node.arguments.head; 295 LiteralString jsCode = node.arguments.head;
364 builder.push(new HForeign(jsCode.dartString, 296 builder.push(new HForeign(jsCode.dartString,
365 const LiteralDartString('Object'), 297 const LiteralDartString('Object'),
366 <HInstruction>[])); 298 <HInstruction>[]));
367 } 299 }
368 } 300 }
301
302 void generateMethodWithPrototypeCheckForElement(Compiler compiler,
303 StringBuffer buffer,
304 FunctionElement element,
305 String code,
306 String parameters) {
307 String methodName;
308 Namer namer = compiler.namer;
309 if (element.kind == ElementKind.FUNCTION) {
310 FunctionParameters parameters = element.computeParameters(compiler);
311 methodName = namer.instanceMethodName(
312 element.getLibrary(), element.name, parameters.parameterCount);
313 } else if (element.kind == ElementKind.GETTER) {
314 methodName = namer.getterName(element.getLibrary(), element.name);
315 } else if (element.kind == ElementKind.SETTER) {
316 methodName = namer.setterName(element.getLibrary(), element.name);
317 } else {
318 compiler.internalError('unexpected kind: "${element.kind}"',
319 element: element);
320 }
321
322 generateMethodWithPrototypeCheck(
323 compiler, buffer, methodName, code, parameters);
324 }
325
326
327 // If a method is overridden, we must check if the prototype of
328 // 'this' has the method available. Otherwise, we may end up
329 // calling the method from the super class. If the method is not
330 // available, we make a direct call to Object.prototype.$methodName.
331 // This method will patch the prototype of 'this' to the real method.
332 void generateMethodWithPrototypeCheck(Compiler compiler,
333 StringBuffer buffer,
334 String methodName,
335 String code,
336 String parameters) {
337 buffer.add(" if (Object.getPrototypeOf(this).hasOwnProperty");
338 buffer.add("('$methodName')) {\n");
339 buffer.add(" $code");
340 buffer.add(" } else {\n");
341 buffer.add(" return Object.prototype.$methodName.call(this");
342 buffer.add(parameters == '' ? '' : ', $parameters');
343 buffer.add(");\n");
344 buffer.add(" }\n");
345 }
OLDNEW
« no previous file with comments | « lib/compiler/implementation/native_emitter.dart ('k') | lib/compiler/implementation/ssa/codegen.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698