Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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/Js): |
|
kasperl
2012/05/30 08:15:51
Js -> JavaScript
floitsch
2012/05/30 13:24:07
Done.
| |
| 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. | |
|
ngeoffray
2012/05/30 10:23:33
Explain why.
floitsch
2012/05/30 13:24:07
Done.
| |
| 645 | 648 |
| 646 // The closure class. | 649 bool hasOptionalParameters = member.optionalParameterCount(compiler) != 0; |
| 647 SourceString name = const SourceString("BoundClosure"); | 650 int parameterCount = member.parameterCount(compiler); |
| 648 ClassElement closureClassElement = | 651 member.parameterCount(compiler); |
|
kasperl
2012/05/30 08:15:51
This looks fishy.
floitsch
2012/05/30 13:24:07
removed.
| |
| 649 new ClosureClassElement(compiler, member.getCompilationUnit()); | |
| 650 String mangledName = namer.getName(closureClassElement); | |
| 651 String superName = namer.getName(closureClassElement.superclass); | |
| 652 needsClosureClass = true; | |
| 653 | 652 |
| 654 // Define the constructor with a name so that Object.toString can | 653 String closureClass = null; |
|
kasperl
2012/05/30 08:15:51
Maybe use something ala:
String closureClass =
floitsch
2012/05/30 13:24:07
Done.
| |
| 655 // find the class name of the closure class. | 654 if (!hasOptionalParameters) { |
| 656 boundClosureBuffer.add("$defineClassName('$mangledName', '$superName', "); | 655 closureClass = boundClosureCache[parameterCount]; |
| 657 boundClosureBuffer.add("function $name(self) { this.self = self; }, {\n"); | 656 } |
| 657 if (closureClass === null) { | |
| 658 // Either the class was not cached yet, or there are optional parameters. | |
| 659 // Create a new closure class. | |
| 660 SourceString name = const SourceString("BoundClosure"); | |
| 661 ClassElement closureClassElement = | |
| 662 new ClosureClassElement(compiler, member.getCompilationUnit()); | |
| 663 String mangledName = namer.getName(closureClassElement); | |
| 664 String superName = namer.getName(closureClassElement.superclass); | |
| 665 needsClosureClass = true; | |
| 658 | 666 |
| 659 // Now add the methods on the closure class. The instance method does not | 667 // Define the constructor with a name so that Object.toString can |
| 660 // have the correct name. Since [addParameterStubs] use the name to create | 668 // find the class name of the closure class. |
| 661 // its stubs we simply create a fake element with the correct name. | 669 boundClosureBuffer.add("$defineClassName('$mangledName', '$superName', "); |
| 662 // Note: the callElement will not have any enclosingElement. | 670 boundClosureBuffer.add("['self', 'target'], {\n"); |
| 663 FunctionElement callElement = | |
| 664 new ClosureInvocationElement(Namer.CLOSURE_INVOCATION_NAME, member); | |
| 665 | 671 |
| 666 int parameterCount = member.parameterCount(compiler); | 672 // Now add the methods on the closure class. The instance method does not |
| 667 String invocationName = | 673 // have the correct name. Since [addParameterStubs] use the name to create |
| 668 namer.instanceMethodName(member.getLibrary(), | 674 // its stubs we simply create a fake element with the correct name. |
| 669 callElement.name, parameterCount); | 675 // Note: the callElement will not have any enclosingElement. |
| 670 String targetName = namer.instanceMethodName(member.getLibrary(), | 676 FunctionElement callElement = |
|
floitsch
2012/05/25 14:17:21
This line has been moved down.
| |
| 671 member.name, parameterCount); | 677 new ClosureInvocationElement(Namer.CLOSURE_INVOCATION_NAME, member); |
| 672 List<String> arguments = new List<String>(parameterCount); | 678 |
| 673 for (int i = 0; i < parameterCount; i++) { | 679 String invocationName = |
| 674 arguments[i] = "arg$i"; | 680 namer.instanceMethodName(member.getLibrary(), |
| 681 callElement.name, parameterCount); | |
| 682 List<String> arguments = new List<String>(parameterCount); | |
| 683 for (int i = 0; i < parameterCount; i++) { | |
| 684 arguments[i] = "arg$i"; | |
|
kasperl
2012/05/30 08:15:51
I wonder if a shorter name wouldn't be as nice. p0
floitsch
2012/05/30 13:24:07
Done.
| |
| 685 } | |
| 686 String joinedArgs = Strings.join(arguments, ", "); | |
| 687 boundClosureBuffer.add( | |
| 688 "$invocationName: function($joinedArgs) {"); | |
| 689 boundClosureBuffer.add(" return this.self[this.target]($joinedArgs);"); | |
| 690 boundClosureBuffer.add(" }"); | |
| 691 addParameterStubs(callElement, (String stubName, String memberValue) { | |
| 692 boundClosureBuffer.add(',\n $stubName: $memberValue'); | |
| 693 }); | |
| 694 boundClosureBuffer.add("\n});\n"); | |
| 695 | |
| 696 closureClass = namer.isolateAccess(closureClassElement); | |
|
floitsch
2012/05/25 14:17:21
Starting at 696 we have lines that weren't in the
| |
| 697 | |
| 698 // Cache it. | |
| 699 if (!hasOptionalParameters) { | |
| 700 boundClosureCache[parameterCount] = closureClass; | |
| 701 } | |
| 675 } | 702 } |
| 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 | 703 |
| 686 // And finally the getter. | 704 // And finally the getter. |
| 687 String getterName = namer.getterName(member.getLibrary(), member.name); | 705 String getterName = namer.getterName(member.getLibrary(), member.name); |
| 688 String closureClass = namer.isolateAccess(closureClassElement); | 706 String targetName = namer.instanceMethodName(member.getLibrary(), |
| 689 defineInstanceMember(getterName, | 707 member.name, parameterCount); |
| 690 "function() { return new $closureClass(this); }"); | 708 defineInstanceMember( |
| 709 getterName, | |
| 710 "function() { return new $closureClass(this, '$targetName'); }"); | |
| 691 } | 711 } |
| 692 | 712 |
| 693 void emitCallStubForGetter(Element member, | 713 void emitCallStubForGetter(Element member, |
| 694 Set<Selector> selectors, | 714 Set<Selector> selectors, |
| 695 void defineInstanceMember(String invocationName, | 715 void defineInstanceMember(String invocationName, |
| 696 String definition)) { | 716 String definition)) { |
| 697 String getter; | 717 String getter; |
| 698 if (member.kind == ElementKind.GETTER) { | 718 if (member.kind == ElementKind.GETTER) { |
| 699 getter = "this.${namer.getterName(member.getLibrary(), member.name)}()"; | 719 getter = "this.${namer.getterName(member.getLibrary(), member.name)}()"; |
| 700 } else { | 720 } else { |
| (...skipping 269 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 970 mainBuffer.add('function init() {\n'); | 990 mainBuffer.add('function init() {\n'); |
| 971 mainBuffer.add(' $isolateProperties = {};\n'); | 991 mainBuffer.add(' $isolateProperties = {};\n'); |
| 972 addDefineClassAndFinishClassFunctionsIfNecessary(mainBuffer); | 992 addDefineClassAndFinishClassFunctionsIfNecessary(mainBuffer); |
| 973 emitFinishIsolateConstructor(mainBuffer); | 993 emitFinishIsolateConstructor(mainBuffer); |
| 974 mainBuffer.add('}\n'); | 994 mainBuffer.add('}\n'); |
| 975 compiler.assembledCode = mainBuffer.toString(); | 995 compiler.assembledCode = mainBuffer.toString(); |
| 976 }); | 996 }); |
| 977 return compiler.assembledCode; | 997 return compiler.assembledCode; |
| 978 } | 998 } |
| 979 } | 999 } |
| OLD | NEW |