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

Unified Diff: frog/leg/emitter.dart

Issue 9415005: Support implicitly bound closures (aka. tear-off closures). (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Address comments. Created 8 years, 10 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 | « frog/leg/compiler.dart ('k') | frog/leg/namer.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: frog/leg/emitter.dart
diff --git a/frog/leg/emitter.dart b/frog/leg/emitter.dart
index b8f24f4d0740599fd97c1de740e1c5e06323560e..72978c3ba56c52ee7eee034138013b934fe5eb7e 100644
--- a/frog/leg/emitter.dart
+++ b/frog/leg/emitter.dart
@@ -290,6 +290,86 @@ function(child, parent) {
}
}
+ void emitDynamicFunctionGetter(StringBuffer buffer,
+ ClassElement enclosingClass,
+ FunctionElement member) {
+ // 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):
+ //
+ // class A {
+ // foo(x, y, z) { ... } // Original function.
+ // get foo() { return new BoundClosure499(this); }
+ // }
+ // class BoundClosure499 {
+ // var self;
+ // BoundClosure499(this.self);
+ // $call3(x, y, z) { return self.foo(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");
+ CompilationUnitElement compilationUnit = member.getCompilationUnit();
+ ClassElement closureClassElement = new ClassElement(name, compilationUnit);
+ String isolateAccess = namer.isolatePropertyAccess(closureClassElement);
+ buffer.add("$isolateAccess = function(self) { this.self = self; };\n");
+ String prototype = "$isolateAccess.prototype";
+
+ // 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 the correct modifiers (in case
+ // of static functions) and will not have any enclosingElement.
+ FunctionElement callElement =
+ new FunctionElement.from(Namer.CLOSURE_INVOCATION_NAME, member, null);
+
+ int parameterCount = member.parameterCount(compiler);
+ String invocationName =
+ namer.instanceMethodName(callElement.name, parameterCount);
+ String targetName = namer.instanceMethodName(member.name, parameterCount);
+ List<String> arguments = new List<String>(parameterCount);
+ for (int i = 0; i < parameterCount; i++) {
+ arguments[i] = "arg$i";
+ }
+ String joinedArgs = Strings.join(arguments, ", ");
+ buffer.add("$prototype.$invocationName = function($joinedArgs) {\n");
+ buffer.add(" return this.self.$targetName($joinedArgs);\n");
+ buffer.add("};\n");
+ addParameterStubs(callElement, prototype, buffer);
+
+ // And finally the getter.
+ String enclosingClassAccess = namer.isolatePropertyAccess(enclosingClass);
+ String enclosingClassPrototype = "$enclosingClassAccess.prototype";
+ String getterName = namer.getterName(member.name);
+ String closureClass = namer.isolateAccess(closureClassElement);
+ buffer.add("$enclosingClassPrototype.$getterName = function() {\n");
+ buffer.add(" return new $closureClass(this);\n");
+ buffer.add("};\n");
+ }
+
+ void emitDynamicFunctionGetters(StringBuffer buffer) {
+ for (ClassElement classElement in compiler.universe.instantiatedClasses) {
+ for (ClassElement currentClass = classElement;
+ currentClass !== null;
+ currentClass = currentClass.superclass) {
+ // TODO(floitsch): we don't need to deal with members that have been
+ // overwritten by subclasses.
+ for (Element member in currentClass.members) {
+ if (!member.isInstanceMember()) continue;
+ if (member.kind == ElementKind.FUNCTION) {
+ if (compiler.universe.invokedGetters.contains(member.name)) {
+ emitDynamicFunctionGetter(buffer, currentClass, member);
+ }
+ }
+ }
+ }
+ }
+ }
+
void emitStaticNonFinalFieldInitializations(StringBuffer buffer) {
// Adds initializations inside the Isolate constructor.
// Example:
@@ -382,6 +462,7 @@ function(child, parent) {
emitNoSuchMethodCalls(buffer);
emitStaticFunctions(buffer);
emitStaticFunctionGetters(buffer);
+ emitDynamicFunctionGetters(buffer);
emitStaticFinalFieldInitializations(buffer);
buffer.add('var ${namer.CURRENT_ISOLATE} = new ${namer.ISOLATE}();\n');
Element main = compiler.mainApp.find(Compiler.MAIN);
« no previous file with comments | « frog/leg/compiler.dart ('k') | frog/leg/namer.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698