OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 library dart2js.new_js_emitter.model_emitter; | 5 library dart2js.new_js_emitter.model_emitter; |
6 | 6 |
| 7 import '../../constants/values.dart' show ConstantValue; |
7 import '../../dart2jslib.dart' show Compiler; | 8 import '../../dart2jslib.dart' show Compiler; |
8 import '../../dart_types.dart' show DartType; | 9 import '../../dart_types.dart' show DartType; |
9 import '../../elements/elements.dart' show ClassElement; | 10 import '../../elements/elements.dart' show ClassElement; |
10 import '../../js/js.dart' as js; | 11 import '../../js/js.dart' as js; |
11 import '../../js_backend/js_backend.dart' show | 12 import '../../js_backend/js_backend.dart' show |
12 JavaScriptBackend, | 13 JavaScriptBackend, |
13 Namer, | 14 Namer, |
14 ConstantEmitter; | 15 ConstantEmitter; |
15 | 16 |
16 import '../js_emitter.dart' show | 17 import '../js_emitter.dart' show |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
106 elements.add( | 107 elements.add( |
107 emitLazilyInitializedStatics(fragment.staticLazilyInitializedFields)); | 108 emitLazilyInitializedStatics(fragment.staticLazilyInitializedFields)); |
108 | 109 |
109 js.Expression code = new js.ArrayInitializer(elements); | 110 js.Expression code = new js.ArrayInitializer(elements); |
110 | 111 |
111 Map<String, dynamic> holes = | 112 Map<String, dynamic> holes = |
112 {'deferredInitializer': emitDeferredInitializerGlobal(program.loadMap), | 113 {'deferredInitializer': emitDeferredInitializerGlobal(program.loadMap), |
113 'holders': emitHolders(program.holders), | 114 'holders': emitHolders(program.holders), |
114 'tearOff': buildTearOffCode(backend), | 115 'tearOff': buildTearOffCode(backend), |
115 'parseFunctionDescriptor': | 116 'parseFunctionDescriptor': |
116 js.js.statement(parseFunctionDescriptorBoilerplate), | 117 js.js.statement(parseFunctionDescriptorBoilerplate, |
| 118 {'argCnt': js.string(namer.requiredParameterField), |
| 119 'defArgValues': js.string(namer.defaultValuesField), |
| 120 'callName': js.string(namer.callNameField)}), |
| 121 |
117 'cyclicThrow': | 122 'cyclicThrow': |
118 backend.emitter.staticFunctionAccess(backend.getCyclicThrowHelper()), | 123 backend.emitter.staticFunctionAccess(backend.getCyclicThrowHelper()), |
119 'outputContainsConstantList': program.outputContainsConstantList, | 124 'outputContainsConstantList': program.outputContainsConstantList, |
120 'embeddedGlobals': emitEmbeddedGlobals(program), | 125 'embeddedGlobals': emitEmbeddedGlobals(program), |
121 'constants': emitConstants(fragment.constants), | 126 'constants': emitConstants(fragment.constants), |
122 'staticNonFinals': | 127 'staticNonFinals': |
123 emitStaticNonFinalFields(fragment.staticNonFinalFields), | 128 emitStaticNonFinalFields(fragment.staticNonFinalFields), |
124 'operatorIsPrefix': js.string(namer.operatorIsPrefix), | 129 'operatorIsPrefix': js.string(namer.operatorIsPrefix), |
| 130 'callName': js.string(namer.callNameField), |
125 'eagerClasses': emitEagerClassInitializations(fragment.libraries), | 131 'eagerClasses': emitEagerClassInitializations(fragment.libraries), |
126 'invokeMain': fragment.invokeMain, | 132 'invokeMain': fragment.invokeMain, |
127 'code': code}; | 133 'code': code}; |
128 | 134 |
129 holes.addAll(nativeHoles(program)); | 135 holes.addAll(nativeHoles(program)); |
130 | 136 |
131 return js.js.statement(boilerplate, holes); | 137 return js.js.statement(boilerplate, holes); |
132 } | 138 } |
133 | 139 |
134 Map<String, dynamic> nativeHoles(Program program) { | 140 Map<String, dynamic> nativeHoles(Program program) { |
(...skipping 410 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
545 assert(field.isLazy); | 551 assert(field.isLazy); |
546 return unparse(compiler, field.code); | 552 return unparse(compiler, field.code); |
547 } | 553 } |
548 | 554 |
549 /// JavaScript code template that implements parsing of a function descriptor. | 555 /// JavaScript code template that implements parsing of a function descriptor. |
550 /// Descriptors are used in place of the actual JavaScript function | 556 /// Descriptors are used in place of the actual JavaScript function |
551 /// definition in the output if additional information needs to be passed to | 557 /// definition in the output if additional information needs to be passed to |
552 /// facilitate the generation of tearOffs at runtime. The format is an array | 558 /// facilitate the generation of tearOffs at runtime. The format is an array |
553 /// with the following fields: | 559 /// with the following fields: |
554 /// | 560 /// |
555 /// [InstanceMethod.aliasName] (optional). | 561 /// * [InstanceMethod.aliasName] (optional). |
556 /// [Method.code] | 562 /// * [Method.code] |
557 /// [DartMethod.callName] | 563 /// * [DartMethod.callName] |
558 /// isInterceptedMethod (optional, present if [DartMethod.needsTearOff]). | 564 /// * isInterceptedMethod (optional, present if [DartMethod.needsTearOff]). |
559 /// [DartMethod.tearOffName] (optional, present if [DartMethod.needsTearOff]). | 565 /// * [DartMethod.tearOffName] (optional, present if |
560 /// functionType (optional, present if [DartMethod.needsTearOff]). | 566 /// [DartMethod.needsTearOff]). |
| 567 /// * functionType (optional, present if [DartMethod.needsTearOff]). |
561 /// | 568 /// |
562 /// followed by | 569 /// followed by |
563 /// | 570 /// |
564 /// [ParameterStubMethod.name] | 571 /// * [ParameterStubMethod.name] |
565 /// [ParameterStubMethod.code] | 572 /// * [ParameterStubMethod.callName] |
| 573 /// * [ParameterStubMethod.code] |
566 /// | 574 /// |
567 /// for each stub in [DartMethod.parameterStubs]. | 575 /// for each stub in [DartMethod.parameterStubs]. |
| 576 /// |
| 577 /// If the closure could be used in `Function.apply` (i.e. |
| 578 /// [DartMethod.canBeApplied] is true) then the following fields are appended: |
| 579 /// |
| 580 /// * [DartMethod.requiredParameterCount] |
| 581 /// * [DartMethod.optionalParameterDefaultValues] |
568 | 582 |
569 static final String parseFunctionDescriptorBoilerplate = r""" | 583 static final String parseFunctionDescriptorBoilerplate = r""" |
570 function parseFunctionDescriptor(proto, name, descriptor) { | 584 function parseFunctionDescriptor(proto, name, descriptor) { |
571 if (descriptor instanceof Array) { | 585 if (descriptor instanceof Array) { |
572 // 'pos' points to the last read entry. | 586 // 'pos' points to the last read entry. |
573 var f, pos = -1; | 587 var f, pos = -1; |
574 var aliasOrFunction = descriptor[++pos]; | 588 var aliasOrFunction = descriptor[++pos]; |
575 if (typeof aliasOrFunction == "string") { | 589 if (typeof aliasOrFunction == "string") { |
576 // Install the alias for super calls on the prototype chain. | 590 // Install the alias for super calls on the prototype chain. |
577 proto[aliasOrFunction] = f = descriptor[++pos]; | 591 proto[aliasOrFunction] = f = descriptor[++pos]; |
578 } else { | 592 } else { |
579 f = aliasOrFunction; | 593 f = aliasOrFunction; |
580 } | 594 } |
581 | 595 |
582 proto[name] = f; | 596 proto[name] = f; |
583 var funs = [f]; | 597 var funs = [f]; |
584 f.$callName = descriptor[++pos]; | 598 f[#callName] = descriptor[++pos]; |
585 | 599 |
586 var isInterceptedOrParameterStubName = descriptor[pos + 1]; | 600 var isInterceptedOrParameterStubName = descriptor[pos + 1]; |
587 var isIntercepted, tearOffName, reflectionInfo; | 601 var isIntercepted, tearOffName, reflectionInfo; |
588 if (typeof isInterceptedOrParameterStubName == "boolean") { | 602 if (typeof isInterceptedOrParameterStubName == "boolean") { |
589 isIntercepted = descriptor[++pos]; | 603 isIntercepted = descriptor[++pos]; |
590 tearOffName = descriptor[++pos]; | 604 tearOffName = descriptor[++pos]; |
591 reflectionInfo = descriptor[++pos]; | 605 reflectionInfo = descriptor[++pos]; |
592 } | 606 } |
593 | 607 |
594 for (++pos; pos < descriptor.length; pos += 3) { | 608 // We iterate in blocks of 3 but have to stop before we reach the (optional) |
| 609 // two trailing items. To accomplish this, we only iterate until we reach |
| 610 // length - 2. |
| 611 for (++pos; pos < descriptor.length - 2; pos += 3) { |
595 var stub = descriptor[pos + 2]; | 612 var stub = descriptor[pos + 2]; |
596 stub.$callName = descriptor[pos + 1]; | 613 stub[#callName] = descriptor[pos + 1]; |
597 proto[descriptor[pos]] = stub; | 614 proto[descriptor[pos]] = stub; |
598 funs.push(stub); | 615 funs.push(stub); |
599 } | 616 } |
600 | 617 |
601 if (tearOffName) { | 618 if (tearOffName) { |
602 proto[tearOffName] = | 619 proto[tearOffName] = |
603 tearOff(funs, reflectionInfo, false, name, isIntercepted); | 620 tearOff(funs, reflectionInfo, false, name, isIntercepted); |
604 } | 621 } |
605 | 622 if (descriptor[pos] != null) { |
| 623 f[#argCnt] = descriptor[pos]; |
| 624 f[#defArgValues] = descriptor[pos + 1]; |
| 625 } |
606 } else { | 626 } else { |
607 proto[name] = descriptor; | 627 proto[name] = descriptor; |
608 } | 628 } |
609 } | 629 } |
610 """; | 630 """; |
611 | 631 |
612 js.Expression _generateFunctionType(DartType memberType) { | 632 js.Expression _generateFunctionType(DartType memberType) { |
613 if (memberType.containsTypeVariables) { | 633 if (memberType.containsTypeVariables) { |
614 js.Expression thisAccess = js.js(r'this.$receiver'); | 634 js.Expression thisAccess = js.js(r'this.$receiver'); |
615 return backend.rti.getSignatureEncoding(memberType, thisAccess); | 635 return backend.rti.getSignatureEncoding(memberType, thisAccess); |
616 } else { | 636 } else { |
617 return js.number(backend.emitter.metadataCollector.reifyType(memberType)); | 637 return js.number(backend.emitter.metadataCollector.reifyType(memberType)); |
618 } | 638 } |
619 } | 639 } |
620 | 640 |
| 641 js.Expression _encodeOptionalParameterDefaultValues(DartMethod method) { |
| 642 js.Expression result; |
| 643 // TODO(herhut): Replace [js.LiteralNull] with [js.ArrayHole]. |
| 644 if (method.optionalParameterDefaultValues is List) { |
| 645 List<ConstantValue> defs = method.optionalParameterDefaultValues; |
| 646 Iterable<js.Expression> elements = defs.map(constantEmitter.reference); |
| 647 return new js.ArrayInitializer(elements.toList()); |
| 648 } else { |
| 649 Map<String, ConstantValue> defs = method.optionalParameterDefaultValues; |
| 650 List<js.Property> properties = <js.Property>[]; |
| 651 defs.forEach((String name, ConstantValue value) { |
| 652 properties.add(new js.Property(js.string(name), |
| 653 constantEmitter.reference(value))); |
| 654 }); |
| 655 return new js.ObjectInitializer(properties); |
| 656 } |
| 657 } |
| 658 |
621 Iterable<js.Expression> emitInstanceMethod(Method method) { | 659 Iterable<js.Expression> emitInstanceMethod(Method method) { |
622 | 660 |
623 List<js.Expression> makeNameCodePair(Method method) { | 661 List<js.Expression> makeNameCodePair(Method method) { |
624 return [js.string(method.name), method.code]; | 662 return [js.string(method.name), method.code]; |
625 } | 663 } |
626 | 664 |
627 List<js.Expression> makeNameCallNameCodeTriplet(ParameterStubMethod stub) { | 665 List<js.Expression> makeNameCallNameCodeTriplet(ParameterStubMethod stub) { |
628 js.Expression callName = stub.callName == null | 666 js.Expression callName = stub.callName == null |
629 ? new js.LiteralNull() | 667 ? new js.LiteralNull() |
630 : js.string(stub.callName); | 668 : js.string(stub.callName); |
(...skipping 14 matching lines...) Expand all Loading... |
645 data.add(js.string(method.callName)); | 683 data.add(js.string(method.callName)); |
646 | 684 |
647 if (method.needsTearOff) { | 685 if (method.needsTearOff) { |
648 bool isIntercepted = backend.isInterceptedMethod(method.element); | 686 bool isIntercepted = backend.isInterceptedMethod(method.element); |
649 data.add(new js.LiteralBool(isIntercepted)); | 687 data.add(new js.LiteralBool(isIntercepted)); |
650 data.add(js.string(method.tearOffName)); | 688 data.add(js.string(method.tearOffName)); |
651 data.add(_generateFunctionType(method.type)); | 689 data.add(_generateFunctionType(method.type)); |
652 } | 690 } |
653 | 691 |
654 data.addAll(method.parameterStubs.expand(makeNameCallNameCodeTriplet)); | 692 data.addAll(method.parameterStubs.expand(makeNameCallNameCodeTriplet)); |
| 693 if (method.canBeApplied) { |
| 694 data.add(js.number(method.requiredParameterCount)); |
| 695 data.add(_encodeOptionalParameterDefaultValues(method)); |
| 696 } |
655 return [js.string(method.name), new js.ArrayInitializer(data)]; | 697 return [js.string(method.name), new js.ArrayInitializer(data)]; |
656 } else { | 698 } else { |
657 // TODO(floitsch): not the most efficient way... | 699 // TODO(floitsch): not the most efficient way... |
658 return ([method]..addAll(method.parameterStubs)) | 700 return ([method]..addAll(method.parameterStubs)) |
659 .expand(makeNameCodePair); | 701 .expand(makeNameCodePair); |
660 } | 702 } |
661 } else { | 703 } else { |
662 return makeNameCodePair(method); | 704 return makeNameCodePair(method); |
663 } | 705 } |
664 } | 706 } |
(...skipping 23 matching lines...) Expand all Loading... |
688 /// The format emitted is the same as for the parser specified at | 730 /// The format emitted is the same as for the parser specified at |
689 /// [parseFunctionDescriptorBoilerplate] except for the missing | 731 /// [parseFunctionDescriptorBoilerplate] except for the missing |
690 /// field whether the method is intercepted. | 732 /// field whether the method is intercepted. |
691 // [name, [function, callName, tearOffName, functionType, | 733 // [name, [function, callName, tearOffName, functionType, |
692 // stub1_name, stub1_callName, stub1_code, ...] | 734 // stub1_name, stub1_callName, stub1_code, ...] |
693 var data = [unparse(compiler, method.code)]; | 735 var data = [unparse(compiler, method.code)]; |
694 data.add(js.string(method.callName)); | 736 data.add(js.string(method.callName)); |
695 data.add(js.string(method.tearOffName)); | 737 data.add(js.string(method.tearOffName)); |
696 data.add(_generateFunctionType(method.type)); | 738 data.add(_generateFunctionType(method.type)); |
697 data.addAll(method.parameterStubs.expand(makeNameCallNameCodeTriplet)); | 739 data.addAll(method.parameterStubs.expand(makeNameCallNameCodeTriplet)); |
| 740 if (method.canBeApplied) { |
| 741 data.add(js.number(method.requiredParameterCount)); |
| 742 data.add(_encodeOptionalParameterDefaultValues(method)); |
| 743 } |
698 return [js.string(method.name), holderIndex, | 744 return [js.string(method.name), holderIndex, |
699 new js.ArrayInitializer(data)]; | 745 new js.ArrayInitializer(data)]; |
700 } else { | 746 } else { |
701 method.parameterStubs.forEach(_addMethod); | 747 method.parameterStubs.forEach(_addMethod); |
702 } | 748 } |
703 } | 749 } |
704 return output; | 750 return output; |
705 } | 751 } |
706 | 752 |
707 static final String setupProgramName = "setupProgram"; | 753 static final String setupProgramName = "setupProgram"; |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
775 var method = compile(name, descriptor); | 821 var method = compile(name, descriptor); |
776 holder[name] = method; | 822 holder[name] = method; |
777 return method.apply(this, arguments); | 823 return method.apply(this, arguments); |
778 }; | 824 }; |
779 } else { | 825 } else { |
780 // Parse the tear off information and generate compile handlers. | 826 // Parse the tear off information and generate compile handlers. |
781 // TODO(herhut): Share parser with instance methods. | 827 // TODO(herhut): Share parser with instance methods. |
782 function compileAllStubs() { | 828 function compileAllStubs() { |
783 var funs; | 829 var funs; |
784 var fun = compile(name, descriptor[0]); | 830 var fun = compile(name, descriptor[0]); |
785 fun.\$callName = descriptor[1]; | 831 fun[#callName] = descriptor[1]; |
786 holder[name] = fun; | 832 holder[name] = fun; |
787 funs = [fun]; | 833 funs = [fun]; |
788 for (var pos = 4; pos < descriptor.length; pos += 3) { | 834 for (var pos = 4; pos < descriptor.length; pos += 3) { |
789 var stubName = descriptor[pos]; | 835 var stubName = descriptor[pos]; |
790 fun = compile(stubName, descriptor[pos + 2]); | 836 fun = compile(stubName, descriptor[pos + 2]); |
791 fun.\$callName = descriptor[pos + 1]; | 837 fun[#callName] = descriptor[pos + 1]; |
792 holder[stubName] = fun; | 838 holder[stubName] = fun; |
793 funs.push(fun); | 839 funs.push(fun); |
794 } | 840 } |
795 if (descriptor[2] != null) { // tear-off name. | 841 if (descriptor[2] != null) { // tear-off name. |
796 // functions, reflectionInfo, isStatic, name, isIntercepted. | 842 // functions, reflectionInfo, isStatic, name, isIntercepted. |
797 holder[descriptor[2]] = | 843 holder[descriptor[2]] = |
798 tearOff(funs, descriptor[3], true, name, false); | 844 tearOff(funs, descriptor[3], true, name, false); |
799 } | 845 } |
800 } | 846 } |
801 | 847 |
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
978 | 1024 |
979 var end = Date.now(); | 1025 var end = Date.now(); |
980 // print('Setup: ' + (end - start) + ' ms.'); | 1026 // print('Setup: ' + (end - start) + ' ms.'); |
981 | 1027 |
982 #invokeMain; // Start main. | 1028 #invokeMain; // Start main. |
983 | 1029 |
984 }(Date.now(), #code) | 1030 }(Date.now(), #code) |
985 }"""; | 1031 }"""; |
986 | 1032 |
987 } | 1033 } |
OLD | NEW |