| 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/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 Loading... |
| 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 } |
| OLD | NEW |