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

Unified 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « lib/compiler/implementation/native_emitter.dart ('k') | lib/compiler/implementation/ssa/codegen.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/compiler/implementation/native_handler.dart
===================================================================
--- lib/compiler/implementation/native_handler.dart (revision 6616)
+++ lib/compiler/implementation/native_handler.dart (working copy)
@@ -147,7 +147,7 @@
listener.endSend(token);
token = token.next;
// If this native method is just redirecting to another method,
- // we add a return node to match the SSA builder expactations.
+ // we add a return node to match the SSA builder expectations.
if (nativeRedirectionRegExp.hasMatch(str.dartString.slowToString())) {
listener.endReturnStatement(true, begin, token);
} else {
@@ -256,91 +256,23 @@
inputs.add(input);
arguments.add('#');
});
- String foreignParameters = Strings.join(arguments, ',');
- String dartMethodName;
+ String foreignParameters = Strings.join(arguments, ',');
String nativeMethodCall;
-
if (element.kind == ElementKind.FUNCTION) {
- dartMethodName = builder.compiler.namer.instanceMethodName(
- element.getLibrary(), element.name, parameters.parameterCount);
nativeMethodCall = '$receiver$nativeMethodName($foreignParameters)';
} else if (element.kind == ElementKind.GETTER) {
- dartMethodName = builder.compiler.namer.getterName(
- element.getLibrary(), element.name);
nativeMethodCall = '$receiver$nativeMethodName';
} else if (element.kind == ElementKind.SETTER) {
- dartMethodName = builder.compiler.namer.setterName(
- element.getLibrary(), element.name);
nativeMethodCall = '$receiver$nativeMethodName = $foreignParameters';
} else {
builder.compiler.internalError('unexpected kind: "${element.kind}"',
element: element);
}
- HInstruction thenInstruction;
- void visitThen() {
- DartString jsCode = new DartString.literal(nativeMethodCall);
- thenInstruction =
- new HForeign(jsCode, const LiteralDartString('Object'), inputs);
- builder.add(thenInstruction);
- }
-
- bool isNativeLiteral = false;
- bool isOverridden = false;
- NativeEmitter nativeEmitter = builder.compiler.emitter.nativeEmitter;
- if (element.enclosingElement.kind == ElementKind.CLASS) {
- ClassElement classElement = element.enclosingElement;
- String nativeName = classElement.nativeName.slowToString();
- isNativeLiteral = nativeEmitter.isNativeLiteral(nativeName);
- isOverridden = isOverriddenMethod(element, classElement, nativeEmitter);
- }
- if (!element.isInstanceMember() || isNativeLiteral || !isOverridden) {
- // We generate a direct call to the native method.
- visitThen();
- builder.stack.add(thenInstruction);
- } else {
- // Record that this method is overridden. In case of optional
- // arguments, the emitter will generate stubs to handle them,
- // and needs to know if the method is overridden.
- nativeEmitter.overriddenMethods.add(element);
-
- // If the method is an instance method that is overridden, we
- // generate the following code:
- // function(params) {
- // return Object.getPrototypeOf(this).hasOwnProperty(dartMethodName))
- // ? this.methodName(params)
- // : Object.prototype.methodName.call(this, params);
- // }
- //
- // The property check at the beginning is to make sure we won't
- // call the method from the super class, in case the prototype of
- // 'this' does not have the method yet.
- HInstruction elseInstruction;
- void visitElse() {
- String params = arguments.isEmpty() ? '' : ', $foreignParameters';
- DartString jsCode = new DartString.literal(
- 'Object.prototype.$dartMethodName.call(#$params)');
- elseInstruction =
- new HForeign(jsCode, const LiteralDartString('Object'), inputs);
- builder.add(elseInstruction);
- }
-
- HConstant constant = builder.graph.addConstantString(
- new DartString.literal('$dartMethodName'));
- DartString jsCode = new DartString.literal(
- 'Object.getPrototypeOf(#).hasOwnProperty(#)');
- builder.push(new HForeign(
- jsCode, const LiteralDartString('Object'),
- <HInstruction>[builder.localsHandler.readThis(), constant]));
-
- builder.handleIf(visitThen, visitElse);
-
- HPhi phi = new HPhi.manyInputs(
- null, <HInstruction>[thenInstruction, elseInstruction]);
- builder.current.addPhi(phi);
- builder.stack.add(phi);
- }
+ DartString jsCode = new DartString.literal(nativeMethodCall);
+ builder.push(
+ new HForeign(jsCode, const LiteralDartString('Object'), inputs));
} else {
// This is JS code written in a Dart file with the construct
// native """ ... """;. It does not work well with mangling,
@@ -366,3 +298,48 @@
<HInstruction>[]));
}
}
+
+void generateMethodWithPrototypeCheckForElement(Compiler compiler,
+ StringBuffer buffer,
+ FunctionElement element,
+ String code,
+ String parameters) {
+ String methodName;
+ Namer namer = compiler.namer;
+ if (element.kind == ElementKind.FUNCTION) {
+ FunctionParameters parameters = element.computeParameters(compiler);
+ methodName = namer.instanceMethodName(
+ element.getLibrary(), element.name, parameters.parameterCount);
+ } else if (element.kind == ElementKind.GETTER) {
+ methodName = namer.getterName(element.getLibrary(), element.name);
+ } else if (element.kind == ElementKind.SETTER) {
+ methodName = namer.setterName(element.getLibrary(), element.name);
+ } else {
+ compiler.internalError('unexpected kind: "${element.kind}"',
+ element: element);
+ }
+
+ generateMethodWithPrototypeCheck(
+ compiler, buffer, methodName, code, parameters);
+}
+
+
+// If a method is overridden, we must check if the prototype of
+// 'this' has the method available. Otherwise, we may end up
+// calling the method from the super class. If the method is not
+// available, we make a direct call to Object.prototype.$methodName.
+// This method will patch the prototype of 'this' to the real method.
+void generateMethodWithPrototypeCheck(Compiler compiler,
+ StringBuffer buffer,
+ String methodName,
+ String code,
+ String parameters) {
+ buffer.add(" if (Object.getPrototypeOf(this).hasOwnProperty");
+ buffer.add("('$methodName')) {\n");
+ buffer.add(" $code");
+ buffer.add(" } else {\n");
+ buffer.add(" return Object.prototype.$methodName.call(this");
+ buffer.add(parameters == '' ? '' : ', $parameters');
+ buffer.add(");\n");
+ buffer.add(" }\n");
+}
« 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