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

Unified Diff: lib/compiler/implementation/emitter.dart

Issue 10448025: Canonicalize bound closures for non-optional-arg methods. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Address comments. Created 8 years, 7 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 | « no previous file | tests/language/closure7_test.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/compiler/implementation/emitter.dart
diff --git a/lib/compiler/implementation/emitter.dart b/lib/compiler/implementation/emitter.dart
index 8fe1f1ba8521f39d62c01c3995be705ece9b0ba5..399b0c47b64fd087f716c2b73fabbd79b45a3331 100644
--- a/lib/compiler/implementation/emitter.dart
+++ b/lib/compiler/implementation/emitter.dart
@@ -31,11 +31,13 @@ class CodeEmitterTask extends CompilerTask {
/** Shorter access to [isolatePropertiesName]. Both here in the code, as
well as in the generated code. */
String isolateProperties;
+ final Map<int, String> boundClosureCache;
CodeEmitterTask(Compiler compiler)
: namer = compiler.namer,
boundClosureBuffer = new StringBuffer(),
mainBuffer = new StringBuffer(),
+ boundClosureCache = new Map<int, String>(),
super(compiler) {
nativeEmitter = new NativeEmitter(this);
}
@@ -628,66 +630,83 @@ function() {
// For every method that has the same name as a property-get we create a
// getter that returns a bound closure. Say we have a class 'A' with method
// 'foo' and somewhere in the code there is a dynamic property get of
- // 'foo'. Then we generate the following code (in pseudo Dart):
+ // 'foo'. Then we generate the following code (in pseudo Dart/JavaScript):
//
// class A {
// foo(x, y, z) { ... } // Original function.
- // get foo() { return new BoundClosure499(this); }
+ // get foo() { return new BoundClosure499(this, "foo"); }
// }
// class BoundClosure499 extends Closure {
// var self;
- // BoundClosure499(this.self);
- // $call3(x, y, z) { return self.foo(x, y, z); }
+ // BoundClosure499(this.self, this.name);
+ // $call3(x, y, z) { return self[name](x, y, z); }
// }
// TODO(floitsch): share the closure classes with other classes
- // if they share methods with the same signature.
-
- // The closure class.
- SourceString name = const SourceString("BoundClosure");
- ClassElement closureClassElement =
- new ClosureClassElement(compiler, member.getCompilationUnit());
- String mangledName = namer.getName(closureClassElement);
- String superName = namer.getName(closureClassElement.superclass);
- needsClosureClass = true;
-
- // Define the constructor with a name so that Object.toString can
- // find the class name of the closure class.
- boundClosureBuffer.add("$defineClassName('$mangledName', '$superName', ");
- boundClosureBuffer.add("function $name(self) { this.self = self; }, {\n");
-
- // Now add the methods on the closure class. The instance method does not
- // have the correct name. Since [addParameterStubs] use the name to create
- // its stubs we simply create a fake element with the correct name.
- // Note: the callElement will not have any enclosingElement.
- FunctionElement callElement =
- new ClosureInvocationElement(Namer.CLOSURE_INVOCATION_NAME, member);
+ // if they share methods with the same signature. Currently we do this only
+ // if there are no optional parameters. Closures with optional parameters
+ // are more difficult to canonicalize because they would need to have the
+ // same default values.
+ bool hasOptionalParameters = member.optionalParameterCount(compiler) != 0;
int parameterCount = member.parameterCount(compiler);
- String invocationName =
- namer.instanceMethodName(member.getLibrary(),
- callElement.name, parameterCount);
- String targetName = namer.instanceMethodName(member.getLibrary(),
- member.name, parameterCount);
- List<String> arguments = new List<String>(parameterCount);
- for (int i = 0; i < parameterCount; i++) {
- arguments[i] = "arg$i";
+
+ String closureClass =
+ hasOptionalParameters ? null : boundClosureCache[parameterCount];
+ if (closureClass === null) {
+ // Either the class was not cached yet, or there are optional parameters.
+ // Create a new closure class.
+ SourceString name = const SourceString("BoundClosure");
+ ClassElement closureClassElement =
+ new ClosureClassElement(compiler, member.getCompilationUnit());
+ String mangledName = namer.getName(closureClassElement);
+ String superName = namer.getName(closureClassElement.superclass);
+ needsClosureClass = true;
+
+ // Define the constructor with a name so that Object.toString can
+ // find the class name of the closure class.
+ boundClosureBuffer.add("$defineClassName('$mangledName', '$superName', ");
+ boundClosureBuffer.add("['self', 'target'], {\n");
+
+ // Now add the methods on the closure class. The instance method does not
+ // have the correct name. Since [addParameterStubs] use the name to create
+ // its stubs we simply create a fake element with the correct name.
+ // Note: the callElement will not have any enclosingElement.
+ FunctionElement callElement =
+ new ClosureInvocationElement(Namer.CLOSURE_INVOCATION_NAME, member);
+
+ String invocationName =
+ namer.instanceMethodName(member.getLibrary(),
+ callElement.name, parameterCount);
+ List<String> arguments = new List<String>(parameterCount);
+ for (int i = 0; i < parameterCount; i++) {
+ arguments[i] = "p$i";
+ }
+ String joinedArgs = Strings.join(arguments, ", ");
+ boundClosureBuffer.add(
+ "$invocationName: function($joinedArgs) {");
+ boundClosureBuffer.add(" return this.self[this.target]($joinedArgs);");
+ boundClosureBuffer.add(" }");
+ addParameterStubs(callElement, (String stubName, String memberValue) {
+ boundClosureBuffer.add(',\n $stubName: $memberValue');
+ });
+ boundClosureBuffer.add("\n});\n");
+
+ closureClass = namer.isolateAccess(closureClassElement);
+
+ // Cache it.
+ if (!hasOptionalParameters) {
+ boundClosureCache[parameterCount] = closureClass;
+ }
}
- String joinedArgs = Strings.join(arguments, ", ");
- boundClosureBuffer.add(
- " $invocationName: function($joinedArgs) {");
- boundClosureBuffer.add(" return this.self.$targetName($joinedArgs);");
- boundClosureBuffer.add(" }");
- addParameterStubs(callElement, (String stubName, String memberValue) {
- boundClosureBuffer.add(',\n $stubName: $memberValue');
- });
- boundClosureBuffer.add("\n});\n");
// And finally the getter.
String getterName = namer.getterName(member.getLibrary(), member.name);
- String closureClass = namer.isolateAccess(closureClassElement);
- defineInstanceMember(getterName,
- "function() { return new $closureClass(this); }");
+ String targetName = namer.instanceMethodName(member.getLibrary(),
+ member.name, parameterCount);
+ defineInstanceMember(
+ getterName,
+ "function() { return new $closureClass(this, '$targetName'); }");
}
void emitCallStubForGetter(Element member,
« no previous file with comments | « no previous file | tests/language/closure7_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698