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

Side by Side 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, 6 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
« no previous file with comments | « no previous file | tests/language/closure7_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 /** 5 /**
6 * A function element that represents a closure call. The signature is copied 6 * A function element that represents a closure call. The signature is copied
7 * from the given element. 7 * from the given element.
8 */ 8 */
9 class ClosureInvocationElement extends FunctionElement { 9 class ClosureInvocationElement extends FunctionElement {
10 ClosureInvocationElement(SourceString name, 10 ClosureInvocationElement(SourceString name,
(...skipping 13 matching lines...) Expand all
24 bool needsInheritFunction = false; 24 bool needsInheritFunction = false;
25 bool needsDefineClass = false; 25 bool needsDefineClass = false;
26 bool needsClosureClass = false; 26 bool needsClosureClass = false;
27 final Namer namer; 27 final Namer namer;
28 NativeEmitter nativeEmitter; 28 NativeEmitter nativeEmitter;
29 StringBuffer boundClosureBuffer; 29 StringBuffer boundClosureBuffer;
30 StringBuffer mainBuffer; 30 StringBuffer mainBuffer;
31 /** Shorter access to [isolatePropertiesName]. Both here in the code, as 31 /** Shorter access to [isolatePropertiesName]. Both here in the code, as
32 well as in the generated code. */ 32 well as in the generated code. */
33 String isolateProperties; 33 String isolateProperties;
34 final Map<int, String> boundClosureCache;
34 35
35 CodeEmitterTask(Compiler compiler) 36 CodeEmitterTask(Compiler compiler)
36 : namer = compiler.namer, 37 : namer = compiler.namer,
37 boundClosureBuffer = new StringBuffer(), 38 boundClosureBuffer = new StringBuffer(),
38 mainBuffer = new StringBuffer(), 39 mainBuffer = new StringBuffer(),
40 boundClosureCache = new Map<int, String>(),
39 super(compiler) { 41 super(compiler) {
40 nativeEmitter = new NativeEmitter(this); 42 nativeEmitter = new NativeEmitter(this);
41 } 43 }
42 44
43 String get name() => 'CodeEmitter'; 45 String get name() => 'CodeEmitter';
44 46
45 String get defineClassName() 47 String get defineClassName()
46 => '${namer.ISOLATE}.\$defineClass'; 48 => '${namer.ISOLATE}.\$defineClass';
47 String get finishClassesName() 49 String get finishClassesName()
48 => '${namer.ISOLATE}.\$finishClasses'; 50 => '${namer.ISOLATE}.\$finishClasses';
(...skipping 572 matching lines...) Expand 10 before | Expand all | Expand 10 after
621 }); 623 });
622 } 624 }
623 } 625 }
624 626
625 void emitDynamicFunctionGetter(FunctionElement member, 627 void emitDynamicFunctionGetter(FunctionElement member,
626 defineInstanceMember(String invocationName, 628 defineInstanceMember(String invocationName,
627 String definition)) { 629 String definition)) {
628 // For every method that has the same name as a property-get we create a 630 // For every method that has the same name as a property-get we create a
629 // getter that returns a bound closure. Say we have a class 'A' with method 631 // getter that returns a bound closure. Say we have a class 'A' with method
630 // 'foo' and somewhere in the code there is a dynamic property get of 632 // 'foo' and somewhere in the code there is a dynamic property get of
631 // 'foo'. Then we generate the following code (in pseudo Dart): 633 // 'foo'. Then we generate the following code (in pseudo Dart/JavaScript):
632 // 634 //
633 // class A { 635 // class A {
634 // foo(x, y, z) { ... } // Original function. 636 // foo(x, y, z) { ... } // Original function.
635 // get foo() { return new BoundClosure499(this); } 637 // get foo() { return new BoundClosure499(this, "foo"); }
636 // } 638 // }
637 // class BoundClosure499 extends Closure { 639 // class BoundClosure499 extends Closure {
638 // var self; 640 // var self;
639 // BoundClosure499(this.self); 641 // BoundClosure499(this.self, this.name);
640 // $call3(x, y, z) { return self.foo(x, y, z); } 642 // $call3(x, y, z) { return self[name](x, y, z); }
641 // } 643 // }
642 644
643 // TODO(floitsch): share the closure classes with other classes 645 // TODO(floitsch): share the closure classes with other classes
644 // if they share methods with the same signature. 646 // if they share methods with the same signature. Currently we do this only
647 // if there are no optional parameters. Closures with optional parameters
648 // are more difficult to canonicalize because they would need to have the
649 // same default values.
645 650
646 // The closure class. 651 bool hasOptionalParameters = member.optionalParameterCount(compiler) != 0;
647 SourceString name = const SourceString("BoundClosure"); 652 int parameterCount = member.parameterCount(compiler);
648 ClassElement closureClassElement =
649 new ClosureClassElement(compiler, member.getCompilationUnit());
650 String mangledName = namer.getName(closureClassElement);
651 String superName = namer.getName(closureClassElement.superclass);
652 needsClosureClass = true;
653 653
654 // Define the constructor with a name so that Object.toString can 654 String closureClass =
655 // find the class name of the closure class. 655 hasOptionalParameters ? null : boundClosureCache[parameterCount];
656 boundClosureBuffer.add("$defineClassName('$mangledName', '$superName', "); 656 if (closureClass === null) {
657 boundClosureBuffer.add("function $name(self) { this.self = self; }, {\n"); 657 // Either the class was not cached yet, or there are optional parameters.
658 // Create a new closure class.
659 SourceString name = const SourceString("BoundClosure");
660 ClassElement closureClassElement =
661 new ClosureClassElement(compiler, member.getCompilationUnit());
662 String mangledName = namer.getName(closureClassElement);
663 String superName = namer.getName(closureClassElement.superclass);
664 needsClosureClass = true;
658 665
659 // Now add the methods on the closure class. The instance method does not 666 // Define the constructor with a name so that Object.toString can
660 // have the correct name. Since [addParameterStubs] use the name to create 667 // find the class name of the closure class.
661 // its stubs we simply create a fake element with the correct name. 668 boundClosureBuffer.add("$defineClassName('$mangledName', '$superName', ");
662 // Note: the callElement will not have any enclosingElement. 669 boundClosureBuffer.add("['self', 'target'], {\n");
663 FunctionElement callElement =
664 new ClosureInvocationElement(Namer.CLOSURE_INVOCATION_NAME, member);
665 670
666 int parameterCount = member.parameterCount(compiler); 671 // Now add the methods on the closure class. The instance method does not
667 String invocationName = 672 // have the correct name. Since [addParameterStubs] use the name to create
668 namer.instanceMethodName(member.getLibrary(), 673 // its stubs we simply create a fake element with the correct name.
669 callElement.name, parameterCount); 674 // Note: the callElement will not have any enclosingElement.
670 String targetName = namer.instanceMethodName(member.getLibrary(), 675 FunctionElement callElement =
671 member.name, parameterCount); 676 new ClosureInvocationElement(Namer.CLOSURE_INVOCATION_NAME, member);
672 List<String> arguments = new List<String>(parameterCount); 677
673 for (int i = 0; i < parameterCount; i++) { 678 String invocationName =
674 arguments[i] = "arg$i"; 679 namer.instanceMethodName(member.getLibrary(),
680 callElement.name, parameterCount);
681 List<String> arguments = new List<String>(parameterCount);
682 for (int i = 0; i < parameterCount; i++) {
683 arguments[i] = "p$i";
684 }
685 String joinedArgs = Strings.join(arguments, ", ");
686 boundClosureBuffer.add(
687 "$invocationName: function($joinedArgs) {");
688 boundClosureBuffer.add(" return this.self[this.target]($joinedArgs);");
689 boundClosureBuffer.add(" }");
690 addParameterStubs(callElement, (String stubName, String memberValue) {
691 boundClosureBuffer.add(',\n $stubName: $memberValue');
692 });
693 boundClosureBuffer.add("\n});\n");
694
695 closureClass = namer.isolateAccess(closureClassElement);
696
697 // Cache it.
698 if (!hasOptionalParameters) {
699 boundClosureCache[parameterCount] = closureClass;
700 }
675 } 701 }
676 String joinedArgs = Strings.join(arguments, ", ");
677 boundClosureBuffer.add(
678 " $invocationName: function($joinedArgs) {");
679 boundClosureBuffer.add(" return this.self.$targetName($joinedArgs);");
680 boundClosureBuffer.add(" }");
681 addParameterStubs(callElement, (String stubName, String memberValue) {
682 boundClosureBuffer.add(',\n $stubName: $memberValue');
683 });
684 boundClosureBuffer.add("\n});\n");
685 702
686 // And finally the getter. 703 // And finally the getter.
687 String getterName = namer.getterName(member.getLibrary(), member.name); 704 String getterName = namer.getterName(member.getLibrary(), member.name);
688 String closureClass = namer.isolateAccess(closureClassElement); 705 String targetName = namer.instanceMethodName(member.getLibrary(),
689 defineInstanceMember(getterName, 706 member.name, parameterCount);
690 "function() { return new $closureClass(this); }"); 707 defineInstanceMember(
708 getterName,
709 "function() { return new $closureClass(this, '$targetName'); }");
691 } 710 }
692 711
693 void emitCallStubForGetter(Element member, 712 void emitCallStubForGetter(Element member,
694 Set<Selector> selectors, 713 Set<Selector> selectors,
695 void defineInstanceMember(String invocationName, 714 void defineInstanceMember(String invocationName,
696 String definition)) { 715 String definition)) {
697 String getter; 716 String getter;
698 if (member.kind == ElementKind.GETTER) { 717 if (member.kind == ElementKind.GETTER) {
699 getter = "this.${namer.getterName(member.getLibrary(), member.name)}()"; 718 getter = "this.${namer.getterName(member.getLibrary(), member.name)}()";
700 } else { 719 } else {
(...skipping 269 matching lines...) Expand 10 before | Expand all | Expand 10 after
970 mainBuffer.add('function init() {\n'); 989 mainBuffer.add('function init() {\n');
971 mainBuffer.add(' $isolateProperties = {};\n'); 990 mainBuffer.add(' $isolateProperties = {};\n');
972 addDefineClassAndFinishClassFunctionsIfNecessary(mainBuffer); 991 addDefineClassAndFinishClassFunctionsIfNecessary(mainBuffer);
973 emitFinishIsolateConstructor(mainBuffer); 992 emitFinishIsolateConstructor(mainBuffer);
974 mainBuffer.add('}\n'); 993 mainBuffer.add('}\n');
975 compiler.assembledCode = mainBuffer.toString(); 994 compiler.assembledCode = mainBuffer.toString();
976 }); 995 });
977 return compiler.assembledCode; 996 return compiler.assembledCode;
978 } 997 }
979 } 998 }
OLDNEW
« 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