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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart

Issue 11602016: Emit classes using ASTs (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 11 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
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 part of js_backend; 5 part of js_backend;
6 6
7 /** 7 /**
8 * A function element that represents a closure call. The signature is copied 8 * A function element that represents a closure call. The signature is copied
9 * from the given element. 9 * from the given element.
10 */ 10 */
11 class ClosureInvocationElement extends FunctionElement { 11 class ClosureInvocationElement extends FunctionElement {
12 ClosureInvocationElement(SourceString name, 12 ClosureInvocationElement(SourceString name,
13 FunctionElement other) 13 FunctionElement other)
14 : super.from(name, other, other.enclosingElement), 14 : super.from(name, other, other.enclosingElement),
15 methodElement = other; 15 methodElement = other;
16 16
17 isInstanceMember() => true; 17 isInstanceMember() => true;
18 18
19 Element getOutermostEnclosingMemberOrTopLevel() => methodElement; 19 Element getOutermostEnclosingMemberOrTopLevel() => methodElement;
20 20
21 /** 21 /**
22 * The [member] this invocation refers to. 22 * The [member] this invocation refers to.
23 */ 23 */
24 Element methodElement; 24 Element methodElement;
25 } 25 }
26 26
27 /** 27 /**
28 * A convenient type alias for some functions that emit keyed values.
29 */
30 typedef void DefineStubFunction(String invocationName, js.Expression value);
31
32 /**
33 * A data structure for collecting fragments of a class definition.
34 */
35 class ClassBuilder {
36 final List<js.Property> properties = <js.Property>[];
37
38 // Has the same signature as [DefineStubFunction].
39 void addProperty(String name, js.Expression value) {
floitsch 2013/01/04 10:31:03 Since this is a class-builder, I would call this "
40 properties.add(new js.Property(js.string(name), value));
41 }
42
43 js.Expression toObjectInitializer() => new js.ObjectInitializer(properties);
44 }
45
46 /**
28 * Generates the code for all used classes in the program. Static fields (even 47 * Generates the code for all used classes in the program. Static fields (even
29 * in classes) are ignored, since they can be treated as non-class elements. 48 * in classes) are ignored, since they can be treated as non-class elements.
30 * 49 *
31 * The code for the containing (used) methods must exist in the [:universe:]. 50 * The code for the containing (used) methods must exist in the [:universe:].
32 */ 51 */
33 class CodeEmitterTask extends CompilerTask { 52 class CodeEmitterTask extends CompilerTask {
34 bool needsInheritFunction = false; 53 bool needsInheritFunction = false;
35 bool needsDefineClass = false; 54 bool needsDefineClass = false;
36 bool needsClosureClass = false; 55 bool needsClosureClass = false;
37 bool needsLazyInitializer = false; 56 bool needsLazyInitializer = false;
(...skipping 382 matching lines...) Expand 10 before | Expand all | Expand 10 after
420 /** 439 /**
421 * Generate stubs to handle invocation of methods with optional 440 * Generate stubs to handle invocation of methods with optional
422 * arguments. 441 * arguments.
423 * 442 *
424 * A method like [: foo([x]) :] may be invoked by the following 443 * A method like [: foo([x]) :] may be invoked by the following
425 * calls: [: foo(), foo(1), foo(x: 1) :]. See the sources of this 444 * calls: [: foo(), foo(1), foo(x: 1) :]. See the sources of this
426 * function for detailed examples. 445 * function for detailed examples.
427 */ 446 */
428 void addParameterStub(FunctionElement member, 447 void addParameterStub(FunctionElement member,
429 Selector selector, 448 Selector selector,
430 DefineMemberFunction defineInstanceMember, 449 DefineStubFunction defineStub,
431 Set<String> alreadyGenerated) { 450 Set<String> alreadyGenerated) {
432 FunctionSignature parameters = member.computeSignature(compiler); 451 FunctionSignature parameters = member.computeSignature(compiler);
433 int positionalArgumentCount = selector.positionalArgumentCount; 452 int positionalArgumentCount = selector.positionalArgumentCount;
434 if (positionalArgumentCount == parameters.parameterCount) { 453 if (positionalArgumentCount == parameters.parameterCount) {
435 assert(selector.namedArgumentCount == 0); 454 assert(selector.namedArgumentCount == 0);
436 return; 455 return;
437 } 456 }
438 if (parameters.optionalParametersAreNamed 457 if (parameters.optionalParametersAreNamed
439 && selector.namedArgumentCount == parameters.optionalParameterCount) { 458 && selector.namedArgumentCount == parameters.optionalParameterCount) {
440 // If the selector has the same number of named arguments as 459 // If the selector has the same number of named arguments as
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
524 } else { 543 } else {
525 body = <js.Statement>[ 544 body = <js.Statement>[
526 new js.Return( 545 new js.Return(
527 new js.VariableUse('this') 546 new js.VariableUse('this')
528 .dot(namer.getName(member)) 547 .dot(namer.getName(member))
529 .callWith(argumentsBuffer))]; 548 .callWith(argumentsBuffer))];
530 } 549 }
531 550
532 js.Fun function = new js.Fun(parametersBuffer, new js.Block(body)); 551 js.Fun function = new js.Fun(parametersBuffer, new js.Block(body));
533 552
534 CodeBuffer buffer = new CodeBuffer(); 553 defineStub(invocationName, function);
535 buffer.add(js.prettyPrint(function, compiler));
536 defineInstanceMember(invocationName, buffer);
537 } 554 }
538 555
539 void addParameterStubs(FunctionElement member, 556 void addParameterStubs(FunctionElement member,
540 DefineMemberFunction defineInstanceMember) { 557 DefineStubFunction defineStub) {
541 // We fill the lists depending on the selector. For example, 558 // We fill the lists depending on the selector. For example,
542 // take method foo: 559 // take method foo:
543 // foo(a, b, {c, d}); 560 // foo(a, b, {c, d});
544 // 561 //
545 // We may have multiple ways of calling foo: 562 // We may have multiple ways of calling foo:
546 // (1) foo(1, 2); 563 // (1) foo(1, 2);
547 // (2) foo(1, 2, c: 3); 564 // (2) foo(1, 2, c: 3);
548 // (3) foo(1, 2, d: 4); 565 // (3) foo(1, 2, d: 4);
549 // (4) foo(1, 2, c: 3, d: 4); 566 // (4) foo(1, 2, c: 3, d: 4);
550 // (5) foo(1, 2, d: 4, c: 3); 567 // (5) foo(1, 2, d: 4, c: 3);
(...skipping 19 matching lines...) Expand all
570 Set<String> generatedStubNames = new Set<String>(); 587 Set<String> generatedStubNames = new Set<String>();
571 if (compiler.enabledFunctionApply 588 if (compiler.enabledFunctionApply
572 && member.name == namer.closureInvocationSelectorName) { 589 && member.name == namer.closureInvocationSelectorName) {
573 // If [Function.apply] is called, we pessimistically compile all 590 // If [Function.apply] is called, we pessimistically compile all
574 // possible stubs for this closure. 591 // possible stubs for this closure.
575 FunctionSignature signature = member.computeSignature(compiler); 592 FunctionSignature signature = member.computeSignature(compiler);
576 Set<Selector> selectors = signature.optionalParametersAreNamed 593 Set<Selector> selectors = signature.optionalParametersAreNamed
577 ? computeNamedSelectors(signature, member) 594 ? computeNamedSelectors(signature, member)
578 : computeOptionalSelectors(signature, member); 595 : computeOptionalSelectors(signature, member);
579 for (Selector selector in selectors) { 596 for (Selector selector in selectors) {
580 addParameterStub( 597 addParameterStub(member, selector, defineStub, generatedStubNames);
581 member, selector, defineInstanceMember, generatedStubNames);
582 } 598 }
583 } else { 599 } else {
584 Set<Selector> selectors = compiler.codegenWorld.invokedNames[member.name]; 600 Set<Selector> selectors = compiler.codegenWorld.invokedNames[member.name];
585 if (selectors == null) return; 601 if (selectors == null) return;
586 for (Selector selector in selectors) { 602 for (Selector selector in selectors) {
587 if (!selector.applies(member, compiler)) continue; 603 if (!selector.applies(member, compiler)) continue;
588 addParameterStub( 604 addParameterStub(member, selector, defineStub, generatedStubNames);
589 member, selector, defineInstanceMember, generatedStubNames);
590 } 605 }
591 } 606 }
592 } 607 }
593 608
594 /** 609 /**
595 * Compute the set of possible selectors in the presence of named 610 * Compute the set of possible selectors in the presence of named
596 * parameters. 611 * parameters.
597 */ 612 */
598 Set<Selector> computeNamedSelectors(FunctionSignature signature, 613 Set<Selector> computeNamedSelectors(FunctionSignature signature,
599 FunctionElement element) { 614 FunctionElement element) {
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
666 return member.hasFixedBackendName() 681 return member.hasFixedBackendName()
667 ? member.fixedBackendName() 682 ? member.fixedBackendName()
668 : namer.getName(member); 683 : namer.getName(member);
669 } 684 }
670 685
671 /** 686 /**
672 * Documentation wanted -- johnniwinther 687 * Documentation wanted -- johnniwinther
673 * 688 *
674 * Invariant: [member] must be a declaration element. 689 * Invariant: [member] must be a declaration element.
675 */ 690 */
676 void addInstanceMember(Element member, 691 void addInstanceMember(Element member, ClassBuilder builder) {
677 DefineMemberFunction defineInstanceMember) {
678 assert(invariant(member, member.isDeclaration)); 692 assert(invariant(member, member.isDeclaration));
679 // TODO(floitsch): we don't need to deal with members of 693 // TODO(floitsch): we don't need to deal with members of
680 // uninstantiated classes, that have been overwritten by subclasses. 694 // uninstantiated classes, that have been overwritten by subclasses.
681 695
682 if (member.isFunction() 696 if (member.isFunction()
683 || member.isGenerativeConstructorBody() 697 || member.isGenerativeConstructorBody()
684 || member.isAccessor()) { 698 || member.isAccessor()) {
685 if (member.isAbstract(compiler)) return; 699 if (member.isAbstract(compiler)) return;
686 CodeBuffer codeBuffer = compiler.codegenWorld.generatedCode[member]; 700 js.Expression code = compiler.codegenWorld.generatedCode[member];
687 if (codeBuffer == null) return; 701 if (code == null) return;
688 defineInstanceMember(namer.getName(member), codeBuffer); 702 builder.addProperty(namer.getName(member), code);
689 codeBuffer = compiler.codegenWorld.generatedBailoutCode[member]; 703 code = compiler.codegenWorld.generatedBailoutCode[member];
690 if (codeBuffer != null) { 704 if (code != null) {
691 defineInstanceMember(namer.getBailoutName(member), codeBuffer); 705 builder.addProperty(namer.getBailoutName(member), code);
692 } 706 }
693 FunctionElement function = member; 707 FunctionElement function = member;
694 FunctionSignature parameters = function.computeSignature(compiler); 708 FunctionSignature parameters = function.computeSignature(compiler);
695 if (!parameters.optionalParameters.isEmpty) { 709 if (!parameters.optionalParameters.isEmpty) {
696 addParameterStubs(member, defineInstanceMember); 710 addParameterStubs(member, builder.addProperty);
697 } 711 }
698 } else if (!member.isField()) { 712 } else if (!member.isField()) {
699 compiler.internalError('unexpected kind: "${member.kind}"', 713 compiler.internalError('unexpected kind: "${member.kind}"',
700 element: member); 714 element: member);
701 } 715 }
702 emitExtraAccessors(member, defineInstanceMember); 716 emitExtraAccessors(member, builder);
703 } 717 }
704 718
705 /** 719 /**
706 * Documentation wanted -- johnniwinther 720 * Documentation wanted -- johnniwinther
707 * 721 *
708 * Invariant: [classElement] must be a declaration element. 722 * Invariant: [classElement] must be a declaration element.
709 */ 723 */
710 void emitInstanceMembers(ClassElement classElement, 724 void emitInstanceMembers(ClassElement classElement,
711 CodeBuffer buffer, 725 ClassBuilder builder) {
712 bool emitLeadingComma) {
713 assert(invariant(classElement, classElement.isDeclaration)); 726 assert(invariant(classElement, classElement.isDeclaration));
714 void defineInstanceMember(String name, StringBuffer memberBuffer) {
715 if (emitLeadingComma) buffer.add(',');
716 emitLeadingComma = true;
717 buffer.add('\n');
718 buffer.add('$_$name:$_');
719 buffer.add(memberBuffer);
720 }
721
722 JavaScriptBackend backend = compiler.backend; 727 JavaScriptBackend backend = compiler.backend;
723 if (classElement == backend.objectInterceptorClass) { 728 if (classElement == backend.objectInterceptorClass) {
724 emitInterceptorMethods(defineInstanceMember); 729 emitInterceptorMethods(builder);
725 // The ObjectInterceptor does not have any instance methods. 730 // The ObjectInterceptor does not have any instance methods.
726 return; 731 return;
727 } 732 }
728 733
729 classElement.implementation.forEachMember( 734 classElement.implementation.forEachMember(
730 (ClassElement enclosing, Element member) { 735 (ClassElement enclosing, Element member) {
731 assert(invariant(classElement, member.isDeclaration)); 736 assert(invariant(classElement, member.isDeclaration));
732 if (member.isInstanceMember()) { 737 if (member.isInstanceMember()) {
733 addInstanceMember(member, defineInstanceMember); 738 addInstanceMember(member, builder);
734 } 739 }
735 }, 740 },
736 includeBackendMembers: true); 741 includeBackendMembers: true);
737 742
738 generateIsTestsOn(classElement, (Element other) { 743 generateIsTestsOn(classElement, (Element other) {
739 String code; 744 js.Expression code;
740 if (compiler.objectClass == other) return; 745 if (compiler.objectClass == other) return;
741 if (nativeEmitter.requiresNativeIsCheck(other)) { 746 if (nativeEmitter.requiresNativeIsCheck(other)) {
742 code = 'function()$_{${_}return true;$_}'; 747 code = js.fun([], js.block1(js.return_(new js.LiteralBool(true))));
743 } else { 748 } else {
744 code = 'true'; 749 code = new js.LiteralBool(true);
745 } 750 }
746 CodeBuffer typeTestBuffer = new CodeBuffer(); 751 builder.addProperty(namer.operatorIs(other), code);
747 typeTestBuffer.add(code);
748 defineInstanceMember(namer.operatorIs(other), typeTestBuffer);
749 }); 752 });
750 753
751 if (identical(classElement, compiler.objectClass) 754 if (identical(classElement, compiler.objectClass)
752 && compiler.enabledNoSuchMethod) { 755 && compiler.enabledNoSuchMethod) {
753 // Emit the noSuchMethod handlers on the Object prototype now, 756 // Emit the noSuchMethod handlers on the Object prototype now,
754 // so that the code in the dynamicFunction helper can find 757 // so that the code in the dynamicFunction helper can find
755 // them. Note that this helper is invoked before analyzing the 758 // them. Note that this helper is invoked before analyzing the
756 // full JS script. 759 // full JS script.
757 if (!nativeEmitter.handleNoSuchMethod) { 760 if (!nativeEmitter.handleNoSuchMethod) {
758 emitNoSuchMethodHandlers(defineInstanceMember); 761 emitNoSuchMethodHandlers(builder.addProperty);
759 } 762 }
760 } 763 }
761 } 764 }
762 765
763 void emitRuntimeClassesAndTests(CodeBuffer buffer) { 766 void emitRuntimeClassesAndTests(CodeBuffer buffer) {
764 JavaScriptBackend backend = compiler.backend; 767 JavaScriptBackend backend = compiler.backend;
765 RuntimeTypeInformation rti = backend.rti; 768 RuntimeTypeInformation rti = backend.rti;
766 769
767 TypeChecks typeChecks = rti.computeRequiredChecks(); 770 TypeChecks typeChecks = rti.computeRequiredChecks();
768 771
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
872 // generate the field getter/setter dynamically. Since this is only 875 // generate the field getter/setter dynamically. Since this is only
873 // allowed on fields that are in [classElement] we don't need to visit 876 // allowed on fields that are in [classElement] we don't need to visit
874 // superclasses for non-instantiated classes. 877 // superclasses for non-instantiated classes.
875 classElement.implementation.forEachInstanceField( 878 classElement.implementation.forEachInstanceField(
876 visitField, 879 visitField,
877 includeBackendMembers: true, 880 includeBackendMembers: true,
878 includeSuperMembers: isInstantiated && !classElement.isNative()); 881 includeSuperMembers: isInstantiated && !classElement.isNative());
879 } 882 }
880 883
881 void generateGetter(Element member, String fieldName, String accessorName, 884 void generateGetter(Element member, String fieldName, String accessorName,
882 CodeBuffer buffer) { 885 ClassBuilder builder) {
883 String getterName = namer.getterNameFromAccessorName(accessorName); 886 String getterName = namer.getterNameFromAccessorName(accessorName);
884 buffer.add("$getterName: function() { return this.$fieldName; }"); 887 builder.addProperty(getterName,
888 js.fun([], js.block1(js.return_(js.use('this').dot(fieldName)))));
885 } 889 }
886 890
887 void generateSetter(Element member, String fieldName, String accessorName, 891 void generateSetter(Element member, String fieldName, String accessorName,
888 CodeBuffer buffer) { 892 ClassBuilder builder) {
889 String setterName = namer.setterNameFromAccessorName(accessorName); 893 String setterName = namer.setterNameFromAccessorName(accessorName);
890 buffer.add("$setterName: function(v) { this.$fieldName = v; }"); 894 builder.addProperty(setterName,
895 js.fun(['v'],
896 js.block1(
897 new js.ExpressionStatement(
898 js.assign(js.use('this').dot(fieldName), js.use('v'))))));
891 } 899 }
892 900
893 bool canGenerateCheckedSetter(Element member) { 901 bool canGenerateCheckedSetter(Element member) {
894 DartType type = member.computeType(compiler); 902 DartType type = member.computeType(compiler);
895 if (type.element.isTypeVariable() 903 if (type.element.isTypeVariable()
896 || type.element == compiler.dynamicClass 904 || type.element == compiler.dynamicClass
897 || type.element == compiler.objectClass) { 905 || type.element == compiler.objectClass) {
898 // TODO(ngeoffray): Support type checks on type parameters. 906 // TODO(ngeoffray): Support type checks on type parameters.
899 return false; 907 return false;
900 } 908 }
901 return true; 909 return true;
902 } 910 }
903 911
904 void generateCheckedSetter(Element member, 912 void generateCheckedSetter(Element member,
905 String fieldName, 913 String fieldName,
906 String accessorName, 914 String accessorName,
907 CodeBuffer buffer) { 915 ClassBuilder builder) {
908 assert(canGenerateCheckedSetter(member)); 916 assert(canGenerateCheckedSetter(member));
909 DartType type = member.computeType(compiler); 917 DartType type = member.computeType(compiler);
910 SourceString helper = compiler.backend.getCheckedModeHelper(type); 918 SourceString helper = compiler.backend.getCheckedModeHelper(type);
911 FunctionElement helperElement = compiler.findHelper(helper); 919 FunctionElement helperElement = compiler.findHelper(helper);
912 String helperName = namer.isolateAccess(helperElement); 920 String helperName = namer.isolateAccess(helperElement);
913 String additionalArgument = ''; 921 List<js.Expression> arguments = <js.Expression>[js.use('v')];
914 if (helperElement.computeSignature(compiler).parameterCount != 1) { 922 if (helperElement.computeSignature(compiler).parameterCount != 1) {
915 additionalArgument = ",$_'${namer.operatorIs(type.element)}'"; 923 arguments.add(js.string(namer.operatorIs(type.element)));
floitsch 2013/01/04 10:31:03 maybe add an "assert" that the result of 'namer.op
916 } 924 }
925
917 String setterName = namer.setterNameFromAccessorName(accessorName); 926 String setterName = namer.setterNameFromAccessorName(accessorName);
918 buffer.add("$setterName:${_}function(v)$_{$_" 927 builder.addProperty(setterName,
919 "this.$fieldName$_=$_$helperName(v$additionalArgument);}"); 928 js.fun(['v'],
929 js.block1(
930 new js.ExpressionStatement(
931 js.assign(
932 js.use('this').dot(fieldName),
933 js.call(js.use(helperName), arguments))))));
920 } 934 }
921 935
922 void emitClassConstructor(ClassElement classElement, CodeBuffer buffer) { 936 void emitClassConstructor(ClassElement classElement, ClassBuilder builder) {
923 /* Do nothing. */ 937 /* Do nothing. */
924 } 938 }
925 939
926 void emitSuper(String superName, CodeBuffer buffer) { 940 void emitSuper(String superName, ClassBuilder builder) {
927 /* Do nothing. */ 941 /* Do nothing. */
928 } 942 }
929 943
930 void emitClassFields(ClassElement classElement, 944 void emitClassFields(ClassElement classElement,
931 CodeBuffer buffer, 945 ClassBuilder builder,
932 bool emitEndingComma,
933 { String superClass: "", 946 { String superClass: "",
934 bool classIsNative: false}) { 947 bool classIsNative: false}) {
935 bool isFirstField = true; 948 bool isFirstField = true;
936 bool isAnythingOutput = false; 949 StringBuffer buffer = new StringBuffer();
937 if (!classIsNative) { 950 if (!classIsNative) {
938 buffer.add('"":"$superClass;'); 951 buffer.add('$superClass;');
939 isAnythingOutput = true;
940 } 952 }
941 visitClassFields(classElement, (Element member, 953 visitClassFields(classElement, (Element member,
942 String name, 954 String name,
943 String accessorName, 955 String accessorName,
944 bool needsGetter, 956 bool needsGetter,
945 bool needsSetter, 957 bool needsSetter,
946 bool needsCheckedSetter) { 958 bool needsCheckedSetter) {
947 // Ignore needsCheckedSetter - that is handled below. 959 // Ignore needsCheckedSetter - that is handled below.
948 bool needsAccessor = (needsGetter || needsSetter); 960 bool needsAccessor = (needsGetter || needsSetter);
949 // We need to output the fields for non-native classes so we can auto- 961 // We need to output the fields for non-native classes so we can auto-
950 // generate the constructor. For native classes there are no 962 // generate the constructor. For native classes there are no
951 // constructors, so we don't need the fields unless we are generating 963 // constructors, so we don't need the fields unless we are generating
952 // accessors at runtime. 964 // accessors at runtime.
953 if (!classIsNative || needsAccessor) { 965 if (!classIsNative || needsAccessor) {
954 // Emit correct commas. 966 // Emit correct commas.
955 if (isFirstField) { 967 if (isFirstField) {
956 isFirstField = false; 968 isFirstField = false;
957 if (!isAnythingOutput) {
958 buffer.add('"":"');
959 isAnythingOutput = true;
960 }
961 } else { 969 } else {
962 buffer.add(","); 970 buffer.add(',');
963 } 971 }
964 int flag = 0; 972 int flag = 0;
965 if (!needsAccessor) { 973 if (!needsAccessor) {
966 // Emit field for constructor generation. 974 // Emit field for constructor generation.
967 assert(!classIsNative); 975 assert(!classIsNative);
968 buffer.add(name); 976 buffer.add(name);
969 } else { 977 } else {
970 // Emit (possibly renaming) field name so we can add accessors at 978 // Emit (possibly renaming) field name so we can add accessors at
971 // runtime. 979 // runtime.
972 buffer.add(accessorName); 980 buffer.add(accessorName);
973 if (name != accessorName) { 981 if (name != accessorName) {
974 buffer.add(':$name'); 982 buffer.add(':$name');
975 // Only the native classes can have renaming accessors. 983 // Only the native classes can have renaming accessors.
976 assert(classIsNative); 984 assert(classIsNative);
977 flag = RENAMING_FLAG; 985 flag = RENAMING_FLAG;
978 } 986 }
979 } 987 }
980 if (needsGetter && needsSetter) { 988 if (needsGetter && needsSetter) {
981 buffer.addCharCode(GETTER_SETTER_CODE + flag); 989 buffer.addCharCode(GETTER_SETTER_CODE + flag);
982 } else if (needsGetter) { 990 } else if (needsGetter) {
983 buffer.addCharCode(GETTER_CODE + flag); 991 buffer.addCharCode(GETTER_CODE + flag);
984 } else if (needsSetter) { 992 } else if (needsSetter) {
985 buffer.addCharCode(SETTER_CODE + flag); 993 buffer.addCharCode(SETTER_CODE + flag);
986 } 994 }
987 } 995 }
988 }); 996 });
989 if (isAnythingOutput) { 997
990 buffer.add('"'); 998 String compactClassData = buffer.toString();
991 if (emitEndingComma) { 999 if (compactClassData.length > 0) {
992 buffer.add(','); 1000 builder.addProperty('', js.string(compactClassData));
993 }
994 } 1001 }
995 } 1002 }
996 1003
997 /** Each getter/setter must be prefixed with a ",\n ". */
998 void emitClassGettersSetters(ClassElement classElement, 1004 void emitClassGettersSetters(ClassElement classElement,
999 CodeBuffer buffer, 1005 ClassBuilder builder) {
1000 bool emitLeadingComma) {
1001 emitComma() {
1002 if (emitLeadingComma) {
1003 buffer.add(",\n$_");
1004 } else {
1005 emitLeadingComma = true;
1006 }
1007 }
1008 1006
1009 visitClassFields(classElement, (Element member, 1007 visitClassFields(classElement, (Element member,
1010 String name, 1008 String name,
1011 String accessorName, 1009 String accessorName,
1012 bool needsGetter, 1010 bool needsGetter,
1013 bool needsSetter, 1011 bool needsSetter,
1014 bool needsCheckedSetter) { 1012 bool needsCheckedSetter) {
1015 if (needsCheckedSetter) { 1013 if (needsCheckedSetter) {
1016 assert(!needsSetter); 1014 assert(!needsSetter);
1017 emitComma(); 1015 generateCheckedSetter(member, name, accessorName, builder);
1018 generateCheckedSetter(member, name, accessorName, buffer);
1019 } 1016 }
1020 if (!getterAndSetterCanBeImplementedByFieldSpec) { 1017 if (!getterAndSetterCanBeImplementedByFieldSpec) {
1021 if (needsGetter) { 1018 if (needsGetter) {
1022 emitComma(); 1019 generateGetter(member, name, accessorName, builder);
1023 generateGetter(member, name, accessorName, buffer);
1024 } 1020 }
1025 if (needsSetter) { 1021 if (needsSetter) {
1026 emitComma(); 1022 generateSetter(member, name, accessorName, builder);
1027 generateSetter(member, name, accessorName, buffer);
1028 } 1023 }
1029 } 1024 }
1030 }); 1025 });
1031 } 1026 }
1032 1027
1033 /** 1028 /**
1034 * Documentation wanted -- johnniwinther 1029 * Documentation wanted -- johnniwinther
1035 * 1030 *
1036 * Invariant: [classElement] must be a declaration element. 1031 * Invariant: [classElement] must be a declaration element.
1037 */ 1032 */
(...skipping 10 matching lines...) Expand all
1048 } 1043 }
1049 1044
1050 needsDefineClass = true; 1045 needsDefineClass = true;
1051 String className = namer.getName(classElement); 1046 String className = namer.getName(classElement);
1052 ClassElement superclass = classElement.superclass; 1047 ClassElement superclass = classElement.superclass;
1053 String superName = ""; 1048 String superName = "";
1054 if (superclass != null) { 1049 if (superclass != null) {
1055 superName = namer.getName(superclass); 1050 superName = namer.getName(superclass);
1056 } 1051 }
1057 1052
1058 buffer.add('$classesCollector.$className$_=$_{'); 1053 ClassBuilder builder = new ClassBuilder();
1059 emitClassConstructor(classElement, buffer); 1054
1060 emitSuper(superName, buffer); 1055 emitClassConstructor(classElement, builder);
1061 emitClassFields(classElement, buffer, false, 1056 emitSuper(superName, builder);
1057 emitClassFields(classElement, builder,
1062 superClass: superName, classIsNative: false); 1058 superClass: superName, classIsNative: false);
1063 // TODO(floitsch): the emitInstanceMember should simply always emit a ',\n'. 1059 emitClassGettersSetters(classElement, builder);
1064 // That does currently not work because the native classes have a different 1060 emitInstanceMembers(classElement, builder);
1065 // syntax. 1061
1066 emitClassGettersSetters(classElement, buffer, true); 1062 js.Expression init =
1067 emitInstanceMembers(classElement, buffer, true); 1063 js.assign(
1068 buffer.add('$n}$N$n'); 1064 js.use(classesCollector).dot(className),
1065 builder.toObjectInitializer());
1066 buffer.add(js.prettyPrint(init, compiler));
1067 buffer.add('$N$n');
1069 } 1068 }
1070 1069
1071 bool get getterAndSetterCanBeImplementedByFieldSpec => true; 1070 bool get getterAndSetterCanBeImplementedByFieldSpec => true;
1072 1071
1073 void emitInterceptorMethods( 1072 void emitInterceptorMethods(ClassBuilder builder) {
1074 void defineInstanceMember(String name, StringBuffer memberBuffer)) {
1075 JavaScriptBackend backend = compiler.backend; 1073 JavaScriptBackend backend = compiler.backend;
1076 // Emit forwarders for the ObjectInterceptor class. We need to 1074 // Emit forwarders for the ObjectInterceptor class. We need to
1077 // emit all possible sends on intercepted methods. 1075 // emit all possible sends on intercepted methods.
1078 for (Selector selector in backend.usedInterceptors) { 1076 for (Selector selector in backend.usedInterceptors) {
1079 1077
1080 List<js.Parameter> parameters = <js.Parameter>[]; 1078 List<js.Parameter> parameters = <js.Parameter>[];
1081 List<js.Expression> arguments = <js.Expression>[]; 1079 List<js.Expression> arguments = <js.Expression>[];
1082 parameters.add(new js.Parameter('receiver')); 1080 parameters.add(new js.Parameter('receiver'));
1083 1081
1084 String name; 1082 String name;
(...skipping 13 matching lines...) Expand all
1098 } 1096 }
1099 } 1097 }
1100 js.Fun function = 1098 js.Fun function =
1101 new js.Fun(parameters, 1099 new js.Fun(parameters,
1102 new js.Block( 1100 new js.Block(
1103 <js.Statement>[ 1101 <js.Statement>[
1104 new js.Return( 1102 new js.Return(
1105 new js.VariableUse('receiver') 1103 new js.VariableUse('receiver')
1106 .dot(name) 1104 .dot(name)
1107 .callWith(arguments))])); 1105 .callWith(arguments))]));
1108 1106 builder.addProperty(name, function);
1109 CodeBuffer code = new CodeBuffer();
1110 code.add(js.prettyPrint(function, compiler));
1111 defineInstanceMember(name, code);
1112 } 1107 }
1113 } 1108 }
1114 1109
1115 Collection<Element> getTypedefChecksOn(DartType type) { 1110 Collection<Element> getTypedefChecksOn(DartType type) {
1116 return checkedTypedefs.filter((TypedefElement typedef) { 1111 return checkedTypedefs.filter((TypedefElement typedef) {
1117 FunctionType typedefType = 1112 FunctionType typedefType =
1118 typedef.computeType(compiler).unalias(compiler); 1113 typedef.computeType(compiler).unalias(compiler);
1119 return compiler.types.isSubtype(type, typedefType); 1114 return compiler.types.isSubtype(type, typedefType);
1120 }); 1115 });
1121 } 1116 }
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after
1267 } 1262 }
1268 1263
1269 void emitFinishClassesInvocationIfNecessary(CodeBuffer buffer) { 1264 void emitFinishClassesInvocationIfNecessary(CodeBuffer buffer) {
1270 if (needsDefineClass) { 1265 if (needsDefineClass) {
1271 buffer.add("$finishClassesName($classesCollector)$N"); 1266 buffer.add("$finishClassesName($classesCollector)$N");
1272 // Reset the map. 1267 // Reset the map.
1273 buffer.add("$classesCollector$_=$_{}$N"); 1268 buffer.add("$classesCollector$_=$_{}$N");
1274 } 1269 }
1275 } 1270 }
1276 1271
1277 void emitStaticFunctionWithNamer(CodeBuffer buffer, 1272 void emitStaticFunction(CodeBuffer buffer,
1278 Element element, 1273 String name,
1279 CodeBuffer functionBuffer, 1274 js.Expression functionExpression) {
1280 String functionNamer(Element element)) { 1275 js.Expression assignment =
1281 String functionName = functionNamer(element); 1276 js.assign(js.use(isolateProperties).dot(name), functionExpression);
1282 buffer.add('$isolateProperties.$functionName$_=$_'); 1277 buffer.add(js.prettyPrint(assignment, compiler));
1283 buffer.add(functionBuffer);
1284 buffer.add('$N$n'); 1278 buffer.add('$N$n');
1285 } 1279 }
1286 1280
1287 void emitStaticFunctions(CodeBuffer buffer) { 1281 void emitStaticFunctions(CodeBuffer buffer) {
1288 bool isStaticFunction(Element element) => 1282 bool isStaticFunction(Element element) =>
1289 !element.isInstanceMember() && !element.isField(); 1283 !element.isInstanceMember() && !element.isField();
1290 1284
1291 Collection<Element> elements = 1285 Collection<Element> elements =
1292 compiler.codegenWorld.generatedCode.keys.filter(isStaticFunction); 1286 compiler.codegenWorld.generatedCode.keys.filter(isStaticFunction);
1293 Set<Element> pendingElementsWithBailouts = 1287 Set<Element> pendingElementsWithBailouts =
1294 new Set<Element>.from( 1288 new Set<Element>.from(
1295 compiler.codegenWorld.generatedBailoutCode.keys.filter( 1289 compiler.codegenWorld.generatedBailoutCode.keys.filter(
1296 isStaticFunction)); 1290 isStaticFunction));
1297 1291
1298 for (Element element in Elements.sortedByPosition(elements)) { 1292 for (Element element in Elements.sortedByPosition(elements)) {
1299 CodeBuffer code = compiler.codegenWorld.generatedCode[element]; 1293 js.Expression code = compiler.codegenWorld.generatedCode[element];
1300 emitStaticFunctionWithNamer(buffer, element, code, namer.getName); 1294 emitStaticFunction(buffer, namer.getName(element), code);
1301 CodeBuffer bailoutCode = 1295 js.Expression bailoutCode =
1302 compiler.codegenWorld.generatedBailoutCode[element]; 1296 compiler.codegenWorld.generatedBailoutCode[element];
1303 if (bailoutCode != null) { 1297 if (bailoutCode != null) {
1304 pendingElementsWithBailouts.remove(element); 1298 pendingElementsWithBailouts.remove(element);
1305 emitStaticFunctionWithNamer( 1299 emitStaticFunction(buffer, namer.getBailoutName(element), bailoutCode);
1306 buffer, element, bailoutCode, namer.getBailoutName);
1307 } 1300 }
1308 } 1301 }
1309 1302
1310 // Is it possible the primary function was inlined but the bailout was not? 1303 // Is it possible the primary function was inlined but the bailout was not?
1311 for (Element element in 1304 for (Element element in
1312 Elements.sortedByPosition(pendingElementsWithBailouts)) { 1305 Elements.sortedByPosition(pendingElementsWithBailouts)) {
1313 CodeBuffer bailoutCode = 1306 CodeBuffer bailoutCode =
1314 compiler.codegenWorld.generatedBailoutCode[element]; 1307 compiler.codegenWorld.generatedBailoutCode[element];
1315 emitStaticFunctionWithNamer( 1308 emitStaticFunction(buffer, namer.getBailoutName(element), bailoutCode);
1316 buffer, element, bailoutCode, namer.getBailoutName);
1317 } 1309 }
1318 } 1310 }
1319 1311
1320 void emitStaticFunctionGetters(CodeBuffer buffer) { 1312 void emitStaticFunctionGetters(CodeBuffer buffer) {
1321 Set<FunctionElement> functionsNeedingGetter = 1313 Set<FunctionElement> functionsNeedingGetter =
1322 compiler.codegenWorld.staticFunctionsNeedingGetter; 1314 compiler.codegenWorld.staticFunctionsNeedingGetter;
1323 for (FunctionElement element in 1315 for (FunctionElement element in functionsNeedingGetter) {
1324 Elements.sortedByPosition(functionsNeedingGetter)) {
1325 // The static function does not have the correct name. Since 1316 // The static function does not have the correct name. Since
1326 // [addParameterStubs] use the name to create its stubs we simply 1317 // [addParameterStubs] use the name to create its stubs we simply
1327 // create a fake element with the correct name. 1318 // create a fake element with the correct name.
1328 // Note: the callElement will not have any enclosingElement. 1319 // Note: the callElement will not have any enclosingElement.
1329 FunctionElement callElement = 1320 FunctionElement callElement =
1330 new ClosureInvocationElement(namer.closureInvocationSelectorName, 1321 new ClosureInvocationElement(namer.closureInvocationSelectorName,
1331 element); 1322 element);
1332 String staticName = namer.getName(element); 1323 String staticName = namer.getName(element);
1333 String invocationName = namer.instanceMethodName(callElement); 1324 String invocationName = namer.instanceMethodName(callElement);
1334 String fieldAccess = '$isolateProperties.$staticName'; 1325 String fieldAccess = '$isolateProperties.$staticName';
1335 buffer.add("$fieldAccess.$invocationName$_=$_$fieldAccess$N"); 1326 buffer.add("$fieldAccess.$invocationName$_=$_$fieldAccess$N");
1336 addParameterStubs(callElement, (String name, CodeBuffer value) { 1327
1337 buffer.add('$fieldAccess.$name$_=$_$value$N'); 1328 addParameterStubs(callElement, (String name, js.Expression value) {
1329 js.Expression assignment =
1330 js.assign(
1331 js.use(isolateProperties).dot(staticName).dot(name),
1332 value);
1333 buffer.add(
1334 js.prettyPrint(new js.ExpressionStatement(assignment), compiler));
1335 buffer.add('$N');
1338 }); 1336 });
1337
1339 // If a static function is used as a closure we need to add its name 1338 // If a static function is used as a closure we need to add its name
1340 // in case it is used in spawnFunction. 1339 // in case it is used in spawnFunction.
1341 String fieldName = namer.STATIC_CLOSURE_NAME_NAME; 1340 String fieldName = namer.STATIC_CLOSURE_NAME_NAME;
1342 buffer.add('$fieldAccess.$fieldName$_=$_"$staticName"$N'); 1341 buffer.add('$fieldAccess.$fieldName$_=$_"$staticName"$N');
1343 getTypedefChecksOn(element.computeType(compiler)).forEach( 1342 getTypedefChecksOn(element.computeType(compiler)).forEach(
1344 (Element typedef) { 1343 (Element typedef) {
1345 String operator = namer.operatorIs(typedef); 1344 String operator = namer.operatorIs(typedef);
1346 buffer.add('$fieldAccess.$operator$_=${_}true$N'); 1345 buffer.add('$fieldAccess.$operator$_=${_}true$N');
1347 } 1346 }
1348 ); 1347 );
1349 } 1348 }
1350 } 1349 }
1351 1350
1352 void emitBoundClosureClassHeader(String mangledName, 1351 void emitBoundClosureClassHeader(String mangledName,
1353 String superName, 1352 String superName,
1354 List<String> fieldNames, 1353 List<String> fieldNames,
1355 CodeBuffer buffer) { 1354 ClassBuilder builder) {
1356 buffer.add('$classesCollector.$mangledName$_=$_' 1355 builder.addProperty('',
1357 '{"":"$superName;${Strings.join(fieldNames,',')}",'); 1356 js.string("$superName;${Strings.join(fieldNames,',')}"));
1358 } 1357 }
1359 1358
1360 /** 1359 /**
1361 * Documentation wanted -- johnniwinther 1360 * Documentation wanted -- johnniwinther
1362 * 1361 *
1363 * Invariant: [member] must be a declaration element. 1362 * Invariant: [member] must be a declaration element.
1364 */ 1363 */
1365 void emitDynamicFunctionGetter(FunctionElement member, 1364 void emitDynamicFunctionGetter(FunctionElement member,
1366 DefineMemberFunction defineInstanceMember) { 1365 DefineStubFunction defineStub) {
1367 assert(invariant(member, member.isDeclaration)); 1366 assert(invariant(member, member.isDeclaration));
1368 // For every method that has the same name as a property-get we create a 1367 // For every method that has the same name as a property-get we create a
1369 // getter that returns a bound closure. Say we have a class 'A' with method 1368 // getter that returns a bound closure. Say we have a class 'A' with method
1370 // 'foo' and somewhere in the code there is a dynamic property get of 1369 // 'foo' and somewhere in the code there is a dynamic property get of
1371 // 'foo'. Then we generate the following code (in pseudo Dart/JavaScript): 1370 // 'foo'. Then we generate the following code (in pseudo Dart/JavaScript):
1372 // 1371 //
1373 // class A { 1372 // class A {
1374 // foo(x, y, z) { ... } // Original function. 1373 // foo(x, y, z) { ... } // Original function.
1375 // get foo { return new BoundClosure499(this, "foo"); } 1374 // get foo { return new BoundClosure499(this, "foo"); }
1376 // } 1375 // }
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
1419 // Create a new closure class. 1418 // Create a new closure class.
1420 SourceString name = const SourceString("BoundClosure"); 1419 SourceString name = const SourceString("BoundClosure");
1421 ClassElement closureClassElement = new ClosureClassElement( 1420 ClassElement closureClassElement = new ClosureClassElement(
1422 name, compiler, member, member.getCompilationUnit()); 1421 name, compiler, member, member.getCompilationUnit());
1423 String mangledName = namer.getName(closureClassElement); 1422 String mangledName = namer.getName(closureClassElement);
1424 String superName = namer.getName(closureClassElement.superclass); 1423 String superName = namer.getName(closureClassElement.superclass);
1425 needsClosureClass = true; 1424 needsClosureClass = true;
1426 1425
1427 // Define the constructor with a name so that Object.toString can 1426 // Define the constructor with a name so that Object.toString can
1428 // find the class name of the closure class. 1427 // find the class name of the closure class.
1428 ClassBuilder boundClosureBuilder = new ClassBuilder();
1429 emitBoundClosureClassHeader( 1429 emitBoundClosureClassHeader(
1430 mangledName, superName, fieldNames, boundClosureBuffer); 1430 mangledName, superName, fieldNames, boundClosureBuilder);
1431 // Now add the methods on the closure class. The instance method does not 1431 // Now add the methods on the closure class. The instance method does not
1432 // have the correct name. Since [addParameterStubs] use the name to create 1432 // have the correct name. Since [addParameterStubs] use the name to create
1433 // its stubs we simply create a fake element with the correct name. 1433 // its stubs we simply create a fake element with the correct name.
1434 // Note: the callElement will not have any enclosingElement. 1434 // Note: the callElement will not have any enclosingElement.
1435 FunctionElement callElement = 1435 FunctionElement callElement =
1436 new ClosureInvocationElement(namer.closureInvocationSelectorName, 1436 new ClosureInvocationElement(namer.closureInvocationSelectorName,
1437 member); 1437 member);
1438 1438
1439 String invocationName = namer.instanceMethodName(callElement); 1439 String invocationName = namer.instanceMethodName(callElement);
1440 1440
(...skipping 10 matching lines...) Expand all
1451 1451
1452 js.Expression fun = 1452 js.Expression fun =
1453 new js.Fun(parameters, 1453 new js.Fun(parameters,
1454 new js.Block( 1454 new js.Block(
1455 <js.Statement>[ 1455 <js.Statement>[
1456 new js.Return( 1456 new js.Return(
1457 new js.PropertyAccess( 1457 new js.PropertyAccess(
1458 new js.This().dot(fieldNames[0]), 1458 new js.This().dot(fieldNames[0]),
1459 new js.This().dot(fieldNames[1])) 1459 new js.This().dot(fieldNames[1]))
1460 .callWith(arguments))])); 1460 .callWith(arguments))]));
1461 boundClosureBuilder.addProperty(invocationName, fun);
1461 1462
1462 boundClosureBuffer.add( 1463 addParameterStubs(callElement, boundClosureBuilder.addProperty);
1463 '$_$invocationName:$_${js.prettyPrint(fun,compiler)}'); 1464 typedefChecks.forEach((Element typedef) {
1464 1465 String operator = namer.operatorIs(typedef);
1465 addParameterStubs(callElement, (String stubName, CodeBuffer memberValue) { 1466 boundClosureBuilder.addProperty(operator, new js.LiteralBool(true));
1466 boundClosureBuffer.add(',\n$_$stubName:$_$memberValue');
1467 }); 1467 });
1468 1468
1469 typedefChecks.forEach((Element typedef) { 1469 js.Expression init =
1470 String operator = namer.operatorIs(typedef); 1470 js.assign(
1471 boundClosureBuffer.add(',\n$_$operator$_:${_}true'); 1471 js.use(classesCollector).dot(mangledName),
1472 }); 1472 boundClosureBuilder.toObjectInitializer());
1473 1473 boundClosureBuffer.add(js.prettyPrint(init, compiler));
1474 boundClosureBuffer.add("$n}$N"); 1474 boundClosureBuffer.add("$N");
1475 1475
1476 closureClass = namer.isolateAccess(closureClassElement); 1476 closureClass = namer.isolateAccess(closureClassElement);
1477 1477
1478 // Cache it. 1478 // Cache it.
1479 if (canBeShared) { 1479 if (canBeShared) {
1480 cache[parameterCount] = closureClass; 1480 cache[parameterCount] = closureClass;
1481 } 1481 }
1482 } 1482 }
1483 1483
1484 // And finally the getter. 1484 // And finally the getter.
1485 String getterName = namer.getterName(member.getLibrary(), member.name); 1485 String getterName = namer.getterName(member.getLibrary(), member.name);
1486 String targetName = namer.instanceMethodName(member); 1486 String targetName = namer.instanceMethodName(member);
1487 1487
1488 List<js.Parameter> parameters = <js.Parameter>[]; 1488 List<js.Parameter> parameters = <js.Parameter>[];
1489 List<js.Expression> arguments = <js.Expression>[]; 1489 List<js.Expression> arguments = <js.Expression>[];
1490 arguments.add(new js.This()); 1490 arguments.add(new js.This());
1491 arguments.add(new js.LiteralString("'$targetName'")); 1491 arguments.add(js.string(targetName));
1492 if (inInterceptor) { 1492 if (inInterceptor) {
1493 parameters.add(new js.Parameter(extraArg)); 1493 parameters.add(new js.Parameter(extraArg));
1494 arguments.add(new js.VariableUse(extraArg)); 1494 arguments.add(new js.VariableUse(extraArg));
1495 } 1495 }
1496 1496
1497 js.Expression getterFunction = 1497 js.Expression getterFunction =
1498 new js.Fun(parameters, 1498 new js.Fun(parameters,
1499 new js.Block( 1499 new js.Block(
1500 <js.Statement>[ 1500 <js.Statement>[
1501 new js.Return( 1501 new js.Return(
1502 new js.New( 1502 new js.New(
1503 new js.VariableUse(closureClass), 1503 new js.VariableUse(closureClass),
1504 arguments))])); 1504 arguments))]));
1505 1505
1506 CodeBuffer getterBuffer = new CodeBuffer(); 1506 defineStub(getterName, getterFunction);
1507 getterBuffer.add(js.prettyPrint(getterFunction, compiler));
1508 defineInstanceMember(getterName, getterBuffer);
1509 } 1507 }
1510 1508
1511 /** 1509 /**
1512 * Documentation wanted -- johnniwinther 1510 * Documentation wanted -- johnniwinther
1513 * 1511 *
1514 * Invariant: [member] must be a declaration element. 1512 * Invariant: [member] must be a declaration element.
1515 */ 1513 */
1516 void emitCallStubForGetter(Element member, 1514 void emitCallStubForGetter(Element member,
1517 Set<Selector> selectors, 1515 Set<Selector> selectors,
1518 DefineMemberFunction defineInstanceMember) { 1516 DefineStubFunction defineStub) {
1519 assert(invariant(member, member.isDeclaration)); 1517 assert(invariant(member, member.isDeclaration));
1520 LibraryElement memberLibrary = member.getLibrary(); 1518 LibraryElement memberLibrary = member.getLibrary();
1521 JavaScriptBackend backend = compiler.backend; 1519 JavaScriptBackend backend = compiler.backend;
1522 // If the class is an interceptor class, the stub gets the 1520 // If the class is an interceptor class, the stub gets the
1523 // receiver explicitely and we need to pass it to the getter call. 1521 // receiver explicitely and we need to pass it to the getter call.
1524 bool isInterceptorClass = 1522 bool isInterceptorClass =
1525 backend.isInterceptorClass(member.getEnclosingClass()); 1523 backend.isInterceptorClass(member.getEnclosingClass());
1526 1524
1527 const String receiverArgumentName = r'$receiver'; 1525 const String receiverArgumentName = r'$receiver';
1528 1526
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
1564 } 1562 }
1565 1563
1566 js.Fun function = 1564 js.Fun function =
1567 new js.Fun(parameters, 1565 new js.Fun(parameters,
1568 new js.Block( 1566 new js.Block(
1569 <js.Statement>[ 1567 <js.Statement>[
1570 new js.Return( 1568 new js.Return(
1571 buildGetter().dot(closureCallName) 1569 buildGetter().dot(closureCallName)
1572 .callWith(arguments))])); 1570 .callWith(arguments))]));
1573 1571
1574 CodeBuffer getterBuffer = new CodeBuffer(); 1572 defineStub(invocationName, function);
1575 getterBuffer.add(js.prettyPrint(function, compiler));
1576 defineInstanceMember(invocationName, getterBuffer);
1577 } 1573 }
1578 } 1574 }
1579 } 1575 }
1580 1576
1581 void emitStaticNonFinalFieldInitializations(CodeBuffer buffer) { 1577 void emitStaticNonFinalFieldInitializations(CodeBuffer buffer) {
1582 ConstantHandler handler = compiler.constantHandler; 1578 ConstantHandler handler = compiler.constantHandler;
1583 List<VariableElement> staticNonFinalFields = 1579 List<VariableElement> staticNonFinalFields =
1584 handler.getStaticNonFinalFieldsForEmission(); 1580 handler.getStaticNonFinalFieldsForEmission();
1585 for (Element element in staticNonFinalFields) { 1581 for (Element element in staticNonFinalFields) {
1586 compiler.withCurrentElement(element, () { 1582 compiler.withCurrentElement(element, () {
(...skipping 11 matching lines...) Expand all
1598 } 1594 }
1599 1595
1600 void emitLazilyInitializedStaticFields(CodeBuffer buffer) { 1596 void emitLazilyInitializedStaticFields(CodeBuffer buffer) {
1601 ConstantHandler handler = compiler.constantHandler; 1597 ConstantHandler handler = compiler.constantHandler;
1602 List<VariableElement> lazyFields = 1598 List<VariableElement> lazyFields =
1603 handler.getLazilyInitializedFieldsForEmission(); 1599 handler.getLazilyInitializedFieldsForEmission();
1604 if (!lazyFields.isEmpty) { 1600 if (!lazyFields.isEmpty) {
1605 needsLazyInitializer = true; 1601 needsLazyInitializer = true;
1606 for (VariableElement element in lazyFields) { 1602 for (VariableElement element in lazyFields) {
1607 assert(compiler.codegenWorld.generatedBailoutCode[element] == null); 1603 assert(compiler.codegenWorld.generatedBailoutCode[element] == null);
1608 StringBuffer code = compiler.codegenWorld.generatedCode[element]; 1604 js.Expression code = compiler.codegenWorld.generatedCode[element];
1609 assert(code != null); 1605 assert(code != null);
1610 // The code only computes the initial value. We build the lazy-check 1606 // The code only computes the initial value. We build the lazy-check
1611 // here: 1607 // here:
1612 // lazyInitializer(prototype, 'name', fieldName, getterName, initial); 1608 // lazyInitializer(prototype, 'name', fieldName, getterName, initial);
1613 // The name is used for error reporting. The 'initial' must be a 1609 // The name is used for error reporting. The 'initial' must be a
1614 // closure that constructs the initial value. 1610 // closure that constructs the initial value.
1615 buffer.add("$lazyInitializerName("); 1611 buffer.add("$lazyInitializerName(");
1616 buffer.add(isolateProperties); 1612 buffer.add(isolateProperties);
1617 buffer.add(",$_'"); 1613 buffer.add(",$_'");
1618 buffer.add(element.name.slowToString()); 1614 buffer.add(element.name.slowToString());
1619 buffer.add("',$_'"); 1615 buffer.add("',$_'");
1620 buffer.add(namer.getName(element)); 1616 buffer.add(namer.getName(element));
1621 buffer.add("',$_'"); 1617 buffer.add("',$_'");
1622 buffer.add(namer.getLazyInitializerName(element)); 1618 buffer.add(namer.getLazyInitializerName(element));
1623 buffer.add("',$_"); 1619 buffer.add("',$_");
1624 buffer.add(code); 1620 buffer.add(js.prettyPrint(code, compiler));
1625 emitLazyInitializedGetter(element, buffer); 1621 emitLazyInitializedGetter(element, buffer);
1626 buffer.add(")$N"); 1622 buffer.add(")$N");
1627 } 1623 }
1628 } 1624 }
1629 } 1625 }
1630 1626
1631 void emitLazyInitializedGetter(VariableElement element, CodeBuffer buffer) { 1627 void emitLazyInitializedGetter(VariableElement element, CodeBuffer buffer) {
1632 // Nothing to do, the 'lazy' function will create the getter. 1628 // Nothing to do, the 'lazy' function will create the getter.
1633 } 1629 }
1634 1630
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
1670 return list; 1666 return list;
1671 }; 1667 };
1672 '''); 1668 ''');
1673 } 1669 }
1674 1670
1675 /** 1671 /**
1676 * Documentation wanted -- johnniwinther 1672 * Documentation wanted -- johnniwinther
1677 * 1673 *
1678 * Invariant: [member] must be a declaration element. 1674 * Invariant: [member] must be a declaration element.
1679 */ 1675 */
1680 void emitExtraAccessors(Element member, 1676 void emitExtraAccessors(Element member, ClassBuilder builder) {
1681 DefineMemberFunction defineInstanceMember) {
1682 assert(invariant(member, member.isDeclaration)); 1677 assert(invariant(member, member.isDeclaration));
1683 if (member.isGetter() || member.isField()) { 1678 if (member.isGetter() || member.isField()) {
1684 Set<Selector> selectors = compiler.codegenWorld.invokedNames[member.name]; 1679 Set<Selector> selectors = compiler.codegenWorld.invokedNames[member.name];
1685 if (selectors != null && !selectors.isEmpty) { 1680 if (selectors != null && !selectors.isEmpty) {
1686 emitCallStubForGetter(member, selectors, defineInstanceMember); 1681 emitCallStubForGetter(member, selectors, builder.addProperty);
1687 } 1682 }
1688 } else if (member.isFunction()) { 1683 } else if (member.isFunction()) {
1689 if (compiler.codegenWorld.hasInvokedGetter(member, compiler)) { 1684 if (compiler.codegenWorld.hasInvokedGetter(member, compiler)) {
1690 emitDynamicFunctionGetter(member, defineInstanceMember); 1685 emitDynamicFunctionGetter(member, builder.addProperty);
1691 } 1686 }
1692 } 1687 }
1693 } 1688 }
1694 1689
1695 void emitNoSuchMethodHandlers(DefineMemberFunction defineInstanceMember) { 1690 void emitNoSuchMethodHandlers(DefineStubFunction defineStub) {
1696 // Do not generate no such method handlers if there is no class. 1691 // Do not generate no such method handlers if there is no class.
1697 if (compiler.codegenWorld.instantiatedClasses.isEmpty) return; 1692 if (compiler.codegenWorld.instantiatedClasses.isEmpty) return;
1698 1693
1699 String noSuchMethodName = namer.publicInstanceMethodNameByArity( 1694 String noSuchMethodName = namer.publicInstanceMethodNameByArity(
1700 Compiler.NO_SUCH_METHOD, Compiler.NO_SUCH_METHOD_ARG_COUNT); 1695 Compiler.NO_SUCH_METHOD, Compiler.NO_SUCH_METHOD_ARG_COUNT);
1701 1696
1702 Element createInvocationMirrorElement = 1697 Element createInvocationMirrorElement =
1703 compiler.findHelper(const SourceString("createInvocationMirror")); 1698 compiler.findHelper(const SourceString("createInvocationMirror"));
1704 String createInvocationMirrorName = 1699 String createInvocationMirrorName =
1705 namer.getName(createInvocationMirrorElement); 1700 namer.getName(createInvocationMirrorElement);
(...skipping 25 matching lines...) Expand all
1731 int type = selector.invocationMirrorKind; 1726 int type = selector.invocationMirrorKind;
1732 String methodName = selector.invocationMirrorMemberName; 1727 String methodName = selector.invocationMirrorMemberName;
1733 List<js.Parameter> parameters = <js.Parameter>[]; 1728 List<js.Parameter> parameters = <js.Parameter>[];
1734 CodeBuffer args = new CodeBuffer(); 1729 CodeBuffer args = new CodeBuffer();
1735 for (int i = 0; i < selector.argumentCount; i++) { 1730 for (int i = 0; i < selector.argumentCount; i++) {
1736 parameters.add(new js.Parameter('\$$i')); 1731 parameters.add(new js.Parameter('\$$i'));
1737 } 1732 }
1738 1733
1739 List<js.Expression> argNames = 1734 List<js.Expression> argNames =
1740 selector.getOrderedNamedArguments().map((SourceString name) => 1735 selector.getOrderedNamedArguments().map((SourceString name) =>
1741 new js.LiteralString('"${name.slowToString()}"')); 1736 js.string(name.slowToString()));
1742 1737
1743 String internalName = namer.invocationMirrorInternalName(selector); 1738 String internalName = namer.invocationMirrorInternalName(selector);
1744 1739
1745 String createInvocationMirror = namer.getName( 1740 String createInvocationMirror = namer.getName(
1746 compiler.createInvocationMirrorElement); 1741 compiler.createInvocationMirrorElement);
1747 1742
1748 js.Expression expression = 1743 js.Expression expression =
1749 new js.This() 1744 new js.This()
1750 .dot(noSuchMethodName) 1745 .dot(noSuchMethodName)
1751 .callWith( 1746 .callWith(
1752 <js.Expression>[ 1747 <js.Expression>[
1753 new js.VariableUse(namer.CURRENT_ISOLATE) 1748 new js.VariableUse(namer.CURRENT_ISOLATE)
1754 .dot(createInvocationMirror) 1749 .dot(createInvocationMirror)
1755 .callWith( 1750 .callWith(
1756 <js.Expression>[ 1751 <js.Expression>[
1757 new js.LiteralString('"$methodName"'), 1752 js.string(methodName),
1758 new js.LiteralString('"$internalName"'), 1753 js.string(internalName),
1759 new js.LiteralNumber('$type'), 1754 new js.LiteralNumber('$type'),
1760 new js.ArrayInitializer.from( 1755 new js.ArrayInitializer.from(
1761 parameters.map((param) => 1756 parameters.map((param) => js.use(param.name))),
1762 new js.VariableUse(param.name))),
1763 new js.ArrayInitializer.from(argNames)])]); 1757 new js.ArrayInitializer.from(argNames)])]);
1764 js.Expression function = 1758 js.Expression function =
1765 new js.Fun(parameters, 1759 new js.Fun(parameters,
1766 new js.Block(<js.Statement>[new js.Return(expression)])); 1760 new js.Block(<js.Statement>[new js.Return(expression)]));
1767 return function; 1761 return function;
1768 } 1762 }
1769 1763
1770 void addNoSuchMethodHandlers(SourceString ignore, Set<Selector> selectors) { 1764 void addNoSuchMethodHandlers(SourceString ignore, Set<Selector> selectors) {
1771 // Cache the object class and type. 1765 // Cache the object class and type.
1772 ClassElement objectClass = compiler.objectClass; 1766 ClassElement objectClass = compiler.objectClass;
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
1850 // bar through inheritance. 1844 // bar through inheritance.
1851 // 1845 //
1852 // If we're calling bar on an object of type A we do need the 1846 // If we're calling bar on an object of type A we do need the
1853 // handler because we may have to call B.noSuchMethod since B 1847 // handler because we may have to call B.noSuchMethod since B
1854 // does not implement bar. 1848 // does not implement bar.
1855 Set<ClassElement> holders = noSuchMethodHoldersFor(receiverType); 1849 Set<ClassElement> holders = noSuchMethodHoldersFor(receiverType);
1856 if (holders.every(hasMatchingMember)) continue; 1850 if (holders.every(hasMatchingMember)) continue;
1857 String jsName = namer.invocationMirrorInternalName(selector); 1851 String jsName = namer.invocationMirrorInternalName(selector);
1858 if (!addedJsNames.contains(jsName)) { 1852 if (!addedJsNames.contains(jsName)) {
1859 js.Expression method = generateMethod(jsName, selector); 1853 js.Expression method = generateMethod(jsName, selector);
1860 CodeBuffer jsCode = new CodeBuffer(); 1854 defineStub(jsName, method);
1861 jsCode.add(js.prettyPrint(method, compiler));
1862 defineInstanceMember(jsName, jsCode);
1863 addedJsNames.add(jsName); 1855 addedJsNames.add(jsName);
1864 } 1856 }
1865 } 1857 }
1866 } 1858 }
1867 1859
1868 compiler.codegenWorld.invokedNames.forEach(addNoSuchMethodHandlers); 1860 compiler.codegenWorld.invokedNames.forEach(addNoSuchMethodHandlers);
1869 compiler.codegenWorld.invokedGetters.forEach(addNoSuchMethodHandlers); 1861 compiler.codegenWorld.invokedGetters.forEach(addNoSuchMethodHandlers);
1870 compiler.codegenWorld.invokedSetters.forEach(addNoSuchMethodHandlers); 1862 compiler.codegenWorld.invokedSetters.forEach(addNoSuchMethodHandlers);
1871 } 1863 }
1872 1864
(...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after
2154 '${_}new ${namer.isolateName}()$N'); 2146 '${_}new ${namer.isolateName}()$N');
2155 2147
2156 nativeEmitter.assembleCode(mainBuffer); 2148 nativeEmitter.assembleCode(mainBuffer);
2157 emitMain(mainBuffer); 2149 emitMain(mainBuffer);
2158 mainBuffer.add('function init()$_{\n'); 2150 mainBuffer.add('function init()$_{\n');
2159 mainBuffer.add('$isolateProperties$_=$_{}$N'); 2151 mainBuffer.add('$isolateProperties$_=$_{}$N');
2160 addDefineClassAndFinishClassFunctionsIfNecessary(mainBuffer); 2152 addDefineClassAndFinishClassFunctionsIfNecessary(mainBuffer);
2161 addLazyInitializerFunctionIfNecessary(mainBuffer); 2153 addLazyInitializerFunctionIfNecessary(mainBuffer);
2162 emitFinishIsolateConstructor(mainBuffer); 2154 emitFinishIsolateConstructor(mainBuffer);
2163 mainBuffer.add('}\n'); 2155 mainBuffer.add('}\n');
2164 compiler.assembledCode = mainBuffer.toString(); 2156 compiler.assembledCode = mainBuffer.getText();
2165 2157
2166 if (generateSourceMap) { 2158 if (generateSourceMap) {
2167 SourceFile compiledFile = new SourceFile(null, compiler.assembledCode); 2159 SourceFile compiledFile = new SourceFile(null, compiler.assembledCode);
2168 String sourceMap = buildSourceMap(mainBuffer, compiledFile); 2160 String sourceMap = buildSourceMap(mainBuffer, compiledFile);
2169 // TODO(podivilov): We should find a better way to return source maps to 2161 // TODO(podivilov): We should find a better way to return source maps to
2170 // compiler. Using diagnostic handler for that purpose is a temporary 2162 // compiler. Using diagnostic handler for that purpose is a temporary
2171 // hack. 2163 // hack.
2172 compiler.reportDiagnostic( 2164 compiler.reportDiagnostic(
2173 null, sourceMap, new api.Diagnostic(-1, 'source map')); 2165 null, sourceMap, new api.Diagnostic(-1, 'source map'));
2174 } 2166 }
2175 }); 2167 });
2176 return compiler.assembledCode; 2168 return compiler.assembledCode;
2177 } 2169 }
2178 2170
2179 String buildSourceMap(CodeBuffer buffer, SourceFile compiledFile) { 2171 String buildSourceMap(CodeBuffer buffer, SourceFile compiledFile) {
2180 SourceMapBuilder sourceMapBuilder = new SourceMapBuilder(); 2172 SourceMapBuilder sourceMapBuilder = new SourceMapBuilder();
2181 buffer.forEachSourceLocation(sourceMapBuilder.addMapping); 2173 buffer.forEachSourceLocation(sourceMapBuilder.addMapping);
2182 return sourceMapBuilder.build(compiledFile); 2174 return sourceMapBuilder.build(compiledFile);
2183 } 2175 }
2184 } 2176 }
2185 2177
2186 typedef void DefineMemberFunction(String invocationName, CodeBuffer definition);
2187
2188 const String GENERATED_BY = """ 2178 const String GENERATED_BY = """
2189 // Generated by dart2js, the Dart to JavaScript compiler. 2179 // Generated by dart2js, the Dart to JavaScript compiler.
2190 """; 2180 """;
2191 const String HOOKS_API_USAGE = """ 2181 const String HOOKS_API_USAGE = """
2192 // The code supports the following hooks: 2182 // The code supports the following hooks:
2193 // dartPrint(message) - if this function is defined it is called 2183 // dartPrint(message) - if this function is defined it is called
2194 // instead of the Dart [print] method. 2184 // instead of the Dart [print] method.
2195 // dartMainRunner(main) - if this function is defined, the Dart [main] 2185 // dartMainRunner(main) - if this function is defined, the Dart [main]
2196 // method will not be invoked directly. 2186 // method will not be invoked directly.
2197 // Instead, a closure that will invoke [main] is 2187 // Instead, a closure that will invoke [main] is
2198 // passed to [dartMainRunner]. 2188 // passed to [dartMainRunner].
2199 """; 2189 """;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698