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

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

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

Powered by Google App Engine
This is Rietveld 408576698