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

Side by Side Diff: pkg/compiler/lib/src/ssa/builder_kernel.dart

Issue 2404123002: Build CFG for various JS() foreign methods (Closed)
Patch Set: Created 4 years, 2 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
OLDNEW
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2016, 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 import 'package:kernel/ast.dart' as ir; 5 import 'package:kernel/ast.dart' as ir;
6 6
7 import '../common.dart'; 7 import '../common.dart';
8 import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem; 8 import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem;
9 import '../common/names.dart'; 9 import '../common/names.dart';
10 import '../common/tasks.dart' show CompilerTask; 10 import '../common/tasks.dart' show CompilerTask;
11 import '../compiler.dart'; 11 import '../compiler.dart';
12 import '../constants/values.dart' show StringConstantValue;
12 import '../dart_types.dart'; 13 import '../dart_types.dart';
13 import '../elements/elements.dart'; 14 import '../elements/elements.dart';
14 import '../io/source_information.dart'; 15 import '../io/source_information.dart';
16 import '../js/js.dart' as js;
15 import '../js_backend/backend.dart' show JavaScriptBackend; 17 import '../js_backend/backend.dart' show JavaScriptBackend;
16 import '../kernel/kernel.dart'; 18 import '../kernel/kernel.dart';
19 import '../native/native.dart' as native;
17 import '../resolution/tree_elements.dart'; 20 import '../resolution/tree_elements.dart';
18 import '../tree/dartstring.dart'; 21 import '../tree/dartstring.dart';
19 import '../types/masks.dart'; 22 import '../types/masks.dart';
20 import '../universe/selector.dart'; 23 import '../universe/selector.dart';
24 import '../universe/side_effects.dart' show SideEffects;
21 import 'graph_builder.dart'; 25 import 'graph_builder.dart';
22 import 'kernel_ast_adapter.dart'; 26 import 'kernel_ast_adapter.dart';
23 import 'kernel_string_builder.dart'; 27 import 'kernel_string_builder.dart';
24 import 'locals_handler.dart'; 28 import 'locals_handler.dart';
25 import 'loop_handler.dart'; 29 import 'loop_handler.dart';
26 import 'nodes.dart'; 30 import 'nodes.dart';
27 import 'ssa_branch_builder.dart'; 31 import 'ssa_branch_builder.dart';
28 32
29 class SsaKernelBuilderTask extends CompilerTask { 33 class SsaKernelBuilderTask extends CompilerTask {
30 final JavaScriptBackend backend; 34 final JavaScriptBackend backend;
(...skipping 529 matching lines...) Expand 10 before | Expand all | Expand 10 after
560 @override 564 @override
561 void visitMapEntry(ir.MapEntry mapEntry) { 565 void visitMapEntry(ir.MapEntry mapEntry) {
562 // Visit value before the key because each will push an expression to the 566 // Visit value before the key because each will push an expression to the
563 // stack, so when we pop them off, the key is popped first, then the value. 567 // stack, so when we pop them off, the key is popped first, then the value.
564 mapEntry.value.accept(this); 568 mapEntry.value.accept(this);
565 mapEntry.key.accept(this); 569 mapEntry.key.accept(this);
566 } 570 }
567 571
568 @override 572 @override
569 void visitStaticGet(ir.StaticGet staticGet) { 573 void visitStaticGet(ir.StaticGet staticGet) {
570 var staticTarget = staticGet.target; 574 ir.Member staticTarget = staticGet.target;
571 if (staticTarget is ir.Procedure && 575 if (staticTarget is ir.Procedure &&
572 staticTarget.kind == ir.ProcedureKind.Getter) { 576 staticTarget.kind == ir.ProcedureKind.Getter) {
573 // Invoke the getter 577 // Invoke the getter
574 _pushStaticInvocation(staticTarget, const <HInstruction>[], 578 _pushStaticInvocation(staticTarget, const <HInstruction>[],
575 astAdapter.returnTypeOf(staticTarget)); 579 astAdapter.returnTypeOf(staticTarget));
580 } else if (staticTarget is ir.Field && staticTarget.isConst) {
581 assert(staticTarget.initializer != null);
582 stack.add(graph.addConstant(
583 astAdapter.getConstantFor(staticTarget.initializer), compiler));
576 } else { 584 } else {
577 Element element = astAdapter.getElement(staticTarget).declaration; 585 Element element = astAdapter.getElement(staticTarget).declaration;
578 push(new HStatic(element, astAdapter.inferredTypeOf(staticTarget))); 586 push(new HStatic(element, astAdapter.inferredTypeOf(staticTarget)));
579 } 587 }
580 } 588 }
581 589
582 @override 590 @override
583 void visitStaticSet(ir.StaticSet staticSet) { 591 void visitStaticSet(ir.StaticSet staticSet) {
584 staticSet.value.accept(this); 592 staticSet.value.accept(this);
585 HInstruction value = pop(); 593 HInstruction value = pop();
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
664 argument.value.accept(this); 672 argument.value.accept(this);
665 result.add(pop()); 673 result.add(pop());
666 } 674 }
667 675
668 return result; 676 return result;
669 } 677 }
670 678
671 @override 679 @override
672 void visitStaticInvocation(ir.StaticInvocation invocation) { 680 void visitStaticInvocation(ir.StaticInvocation invocation) {
673 ir.Procedure target = invocation.target; 681 ir.Procedure target = invocation.target;
682 if (astAdapter.isInForeignLibrary(target)) {
683 handleInvokeStaticForeign(invocation, target);
684 return;
685 }
674 TypeMask typeMask = astAdapter.returnTypeOf(target); 686 TypeMask typeMask = astAdapter.returnTypeOf(target);
675 687
676 List<HInstruction> arguments = _visitArguments(invocation.arguments); 688 List<HInstruction> arguments = _visitArguments(invocation.arguments);
677 689
678 _pushStaticInvocation(target, arguments, typeMask); 690 _pushStaticInvocation(target, arguments, typeMask);
679 } 691 }
680 692
693 void handleInvokeStaticForeign(
694 ir.StaticInvocation invocation, ir.Procedure target) {
695 String name = target.name.name;
696 if (name == 'JS') {
697 handleForeignJs(invocation);
698 } else if (name == 'JS_CURRENT_ISOLATE_CONTEXT') {
699 handleForeignJsCurrentIsolateContext(invocation);
700 } else if (name == 'JS_CALL_IN_ISOLATE') {
701 handleForeignJsCallInIsolate(invocation);
702 } else if (name == 'DART_CLOSURE_TO_JS') {
703 handleForeignDartClosureToJs(invocation, 'DART_CLOSURE_TO_JS');
704 } else if (name == 'RAW_DART_FUNCTION_REF') {
705 handleForeignRawFunctionRef(invocation, 'RAW_DART_FUNCTION_REF');
706 } else if (name == 'JS_SET_STATIC_STATE') {
707 handleForeignJsSetStaticState(invocation);
708 } else if (name == 'JS_GET_STATIC_STATE') {
709 handleForeignJsGetStaticState(invocation);
710 } else if (name == 'JS_GET_NAME') {
711 handleForeignJsGetName(invocation);
712 } else if (name == 'JS_EMBEDDED_GLOBAL') {
713 handleForeignJsEmbeddedGlobal(invocation);
714 } else if (name == 'JS_BUILTIN') {
715 handleForeignJsBuiltin(invocation);
716 } else if (name == 'JS_GET_FLAG') {
717 handleForeignJsGetFlag(invocation);
718 } else if (name == 'JS_EFFECT') {
719 stack.add(graph.addConstantNull(compiler));
720 } else if (name == 'JS_INTERCEPTOR_CONSTANT') {
721 handleJsInterceptorConstant(invocation);
722 } else if (name == 'JS_STRING_CONCAT') {
723 handleJsStringConcat(invocation);
724 } else {
725 compiler.reporter.internalError(
726 astAdapter.getNode(invocation), "Unknown foreign: ${name}");
727 }
728 }
729
730 bool _unexpectedForeignArguments(
731 ir.StaticInvocation invocation, String name, int minPositional,
732 [int maxPositional]) {
733 ir.Arguments arguments = invocation.arguments;
734 bool bad = false;
735 if (arguments.types.isNotEmpty) {
736 compiler.reporter.reportErrorMessage(
737 astAdapter.getNode(invocation),
738 MessageKind.GENERIC,
739 {'text': "Error: '$name' does not take type arguments."});
740 bad = true;
741 }
742 String pluralize(int count, String singular, String plural) {
743 if (count == 0) return 'no $plural';
744 if (count == 1) return 'one $singular';
745 if (count == 2) return 'two $plural';
746 return '$count ${plural}s';
Harry Terkelsen 2016/10/12 16:42:59 should be '$count $plural'
sra1 2016/10/13 19:02:01 Done.
747 }
748
749 if (arguments.positional.length < minPositional) {
750 String phrase = pluralize(minPositional, 'argument', 'arguments');
751 if (maxPositional != minPositional) phrase = 'at least $phrase';
752 compiler.reporter.reportErrorMessage(
753 astAdapter.getNode(invocation),
754 MessageKind.GENERIC,
755 {'text': "Error: Too few arguments. '$name' takes $phrase."});
756 bad = true;
757 }
758 if (maxPositional != null && arguments.positional.length > maxPositional) {
759 String phrase = pluralize(maxPositional, 'argument', 'arguments');
760 if (maxPositional != minPositional) phrase = 'at most $phrase';
761 compiler.reporter.reportErrorMessage(
762 astAdapter.getNode(invocation),
763 MessageKind.GENERIC,
764 {'text': "Error: Too many arguments. '$name' takes $phrase."});
765 bad = true;
766 }
767 if (arguments.named.isNotEmpty) {
768 compiler.reporter.reportErrorMessage(
769 astAdapter.getNode(invocation),
770 MessageKind.GENERIC,
771 {'text': "Error: '$name' does not take named arguments."});
772 bad = true;
773 }
774 return bad;
775 }
776
777 /// Returns the value of the string argument. The argument must evaluate to a
778 /// constant. If there is an error, the error is reported and `null` is
779 /// returned.
780 String _foreignConstantStringArgument(
781 ir.StaticInvocation invocation, int position, String methodName,
782 [String adjective = '']) {
783 ir.Expression argument = invocation.arguments.positional[position];
784 argument.accept(this);
785 HInstruction instruction = pop();
786
787 if (!instruction.isConstantString()) {
788 compiler.reporter.reportErrorMessage(
789 astAdapter.getNode(argument), MessageKind.GENERIC, {
790 'text': "Error: Expected String constant as ${adjective}argument "
791 "to '$methodName'."
792 });
793 return null;
794 }
795
796 HConstant hConstant = instruction;
797 StringConstantValue stringConstant = hConstant.constant;
798 return stringConstant.primitiveValue.slowToString();
799 }
800
801 dynamic _foreignConstantEnumArgument(
Harry Terkelsen 2016/10/12 16:42:59 this seems unused?
sra1 2016/10/13 19:02:01 Removed
802 ir.StaticInvocation invocation, int position, String methodName,
803 [String adjective = '']) {
804 ir.Expression argument = invocation.arguments.positional[position];
805 argument.accept(this);
806 HInstruction instruction = pop();
807
808 if (!instruction.isConstant()) {
809 compiler.reporter.reportErrorMessage(
810 astAdapter.getNode(argument), MessageKind.GENERIC, {
811 'text': "Error: Expected String constant as ${adjective}argument "
Harry Terkelsen 2016/10/12 16:42:59 should it be 'Expected enum constant ...'?
sra1 2016/10/13 19:02:01 Acknowledged.
812 "to '$methodName'."
813 });
814 return null;
815 }
816
817 HConstant hConstant = instruction;
818 StringConstantValue stringConstant = hConstant.constant;
Harry Terkelsen 2016/10/12 16:42:59 should this be an EnumConstantValue?
sra1 2016/10/13 19:02:01 Acknowledged.
819 return stringConstant.primitiveValue.slowToString();
820 }
821
822 // TODO(sra): Remove when handleInvokeStaticForeign fully implemented.
823 void unhandledForeign(ir.StaticInvocation invocation) {
824 ir.Procedure target = invocation.target;
825 TypeMask typeMask = astAdapter.returnTypeOf(target);
826 List<HInstruction> arguments = _visitArguments(invocation.arguments);
827 _pushStaticInvocation(target, arguments, typeMask);
828 }
829
830 void handleForeignJsCurrentIsolateContext(ir.StaticInvocation invocation) {
831 unhandledForeign(invocation);
832 }
833
834 void handleForeignJsCallInIsolate(ir.StaticInvocation invocation) {
835 unhandledForeign(invocation);
836 }
837
838 void handleForeignDartClosureToJs(
839 ir.StaticInvocation invocation, String name) {
840 unhandledForeign(invocation);
841 }
842
843 void handleForeignRawFunctionRef(
844 ir.StaticInvocation invocation, String name) {
845 unhandledForeign(invocation);
846 }
847
848 void handleForeignJsSetStaticState(ir.StaticInvocation invocation) {
849 if (_unexpectedForeignArguments(invocation, 'JS_SET_STATIC_STATE', 0, 0)) {
850 stack.add(graph.addConstantNull(compiler)); // Result expected on stack.
851 return;
852 }
853 _visitArguments(invocation.arguments);
854 String isolateName = backend.namer.staticStateHolder;
855 SideEffects sideEffects = new SideEffects.empty();
856 sideEffects.setAllSideEffects();
857 push(new HForeignCode(js.js.parseForeignJS("$isolateName = #"),
858 backend.dynamicType, <HInstruction>[pop()],
859 nativeBehavior: native.NativeBehavior.CHANGES_OTHER,
860 effects: sideEffects));
861 }
862
863 void handleForeignJsGetStaticState(ir.StaticInvocation invocation) {
864 if (_unexpectedForeignArguments(invocation, 'JS_GET_STATIC_STATE', 0, 0)) {
865 stack.add(graph.addConstantNull(compiler)); // Result expected on stack.
866 return;
867 }
868
869 push(new HForeignCode(js.js.parseForeignJS(backend.namer.staticStateHolder),
870 backend.dynamicType, <HInstruction>[],
871 nativeBehavior: native.NativeBehavior.DEPENDS_OTHER));
872 }
873
874 void handleForeignJsGetName(ir.StaticInvocation invocation) {
875 if (_unexpectedForeignArguments(invocation, 'JS_GET_NAME', 1, 1)) {
876 stack.add(graph.addConstantNull(compiler)); // Result expected on stack.
877 return;
878 }
879
880 ir.Node argument = invocation.arguments.positional.first;
881 argument.accept(this);
882 HInstruction instruction = pop();
883
884 if (instruction is HConstant) {
885 js.Name name =
886 astAdapter.getNameForJsGetName(argument, instruction.constant);
887 stack.add(graph.addConstantStringFromName(name, compiler));
888 return;
889 }
890
891 compiler.reporter.reportErrorMessage(
892 astAdapter.getNode(argument),
893 MessageKind.GENERIC,
894 {'text': 'Error: Expected a JsGetName enum value.'});
895 stack.add(graph.addConstantNull(compiler)); // Result expected on stack.
896 }
897
898 void handleForeignJsEmbeddedGlobal(ir.StaticInvocation invocation) {
899 if (_unexpectedForeignArguments(invocation, 'JS_EMBEDDED_GLOBAL', 2, 2)) {
900 stack.add(graph.addConstantNull(compiler)); // Result expected on stack.
901 return;
902 }
903 String globalName = _foreignConstantStringArgument(
904 invocation, 1, 'JS_EMBEDDED_GLOBAL', 'second ');
905 js.Template expr = js.js.expressionTemplateYielding(
906 backend.emitter.generateEmbeddedGlobalAccess(globalName));
907
908 native.NativeBehavior nativeBehavior =
909 astAdapter.getNativeBehavior(invocation);
910 assert(invariant(astAdapter.getNode(invocation), nativeBehavior != null,
911 message: "No NativeBehavior for $invocation"));
912
913 TypeMask ssaType = astAdapter.typeFromNativeBehavior(nativeBehavior);
914 push(new HForeignCode(expr, ssaType, const <HInstruction>[],
915 nativeBehavior: nativeBehavior));
916 }
917
918 void handleForeignJsBuiltin(ir.StaticInvocation invocation) {
919 if (_unexpectedForeignArguments(invocation, 'JS_BUILTIN', 2)) {
920 stack.add(graph.addConstantNull(compiler)); // Result expected on stack.
921 return;
922 }
923
924 List<ir.Expression> arguments = invocation.arguments.positional;
925 ir.Expression nameArgument = arguments[1];
926
927 nameArgument.accept(this);
928 HInstruction instruction = pop();
929
930 js.Template template;
931 if (instruction is HConstant) {
932 template = astAdapter.getJsBuiltinTemplate(instruction.constant);
933 }
934 if (template == null) {
935 compiler.reporter.reportErrorMessage(
936 astAdapter.getNode(nameArgument),
937 MessageKind.GENERIC,
938 {'text': 'Error: Expected a JsBuiltin enum value.'});
939 stack.add(graph.addConstantNull(compiler)); // Result expected on stack.
940 return;
941 }
942
943 List<HInstruction> inputs = <HInstruction>[];
944 for (ir.Expression argument in arguments.skip(2)) {
945 argument.accept(this);
946 inputs.add(pop());
947 }
948
949 native.NativeBehavior nativeBehavior =
950 astAdapter.getNativeBehavior(invocation);
951 assert(invariant(astAdapter.getNode(invocation), nativeBehavior != null,
952 message: "No NativeBehavior for $invocation"));
953
954 TypeMask ssaType = astAdapter.typeFromNativeBehavior(nativeBehavior);
955 push(new HForeignCode(template, ssaType, inputs,
956 nativeBehavior: nativeBehavior));
957 }
958
959 void handleForeignJsGetFlag(ir.StaticInvocation invocation) {
960 if (_unexpectedForeignArguments(invocation, 'JS_GET_FLAG', 1, 1)) {
961 stack.add(
962 graph.addConstantBool(false, compiler)); // Result expected on stack.
963 return;
964 }
965 String name = _foreignConstantStringArgument(invocation, 0, 'JS_GET_FLAG');
966 bool value = false;
967 switch (name) {
968 case 'MUST_RETAIN_METADATA':
969 value = backend.mustRetainMetadata;
970 break;
971 case 'USE_CONTENT_SECURITY_POLICY':
972 value = compiler.options.useContentSecurityPolicy;
973 break;
974 default:
975 compiler.reporter.reportErrorMessage(
976 astAdapter.getNode(invocation),
977 MessageKind.GENERIC,
978 {'text': 'Error: Unknown internal flag "$name".'});
979 }
980 stack.add(graph.addConstantBool(value, compiler));
981 }
982
983 void handleJsInterceptorConstant(ir.StaticInvocation invocation) {
984 unhandledForeign(invocation);
985 }
986
987 void handleForeignJs(ir.StaticInvocation invocation) {
988 if (_unexpectedForeignArguments(invocation, 'JS', 2)) {
989 stack.add(graph.addConstantNull(compiler)); // Result expected on stack.
990 return;
991 }
992
993 native.NativeBehavior nativeBehavior =
994 astAdapter.getNativeBehavior(invocation);
995 assert(nativeBehavior != null);
Harry Terkelsen 2016/10/12 16:42:59 remove this assert since it makes the next one unr
sra1 2016/10/13 19:02:01 Done.
996 assert(invariant(astAdapter.getNode(invocation), nativeBehavior != null,
997 message: "No NativeBehavior for $invocation"));
998
999 List<HInstruction> inputs = <HInstruction>[];
1000 for (ir.Expression argument in invocation.arguments.positional.skip(2)) {
1001 argument.accept(this);
1002 inputs.add(pop());
1003 }
1004
1005 if (nativeBehavior.codeTemplate.positionalArgumentCount != inputs.length) {
1006 compiler.reporter.reportErrorMessage(
1007 astAdapter.getNode(invocation), MessageKind.GENERIC, {
1008 'text': 'Mismatch between number of placeholders'
1009 ' and number of arguments.'
1010 });
1011 stack.add(graph.addConstantNull(compiler)); // Result expected on stack.
1012 return;
1013 }
1014
1015 if (native.HasCapturedPlaceholders.check(nativeBehavior.codeTemplate.ast)) {
1016 compiler.reporter.reportErrorMessage(
1017 astAdapter.getNode(invocation), MessageKind.JS_PLACEHOLDER_CAPTURE);
1018 }
1019
1020 TypeMask ssaType = astAdapter.typeFromNativeBehavior(nativeBehavior);
1021
1022 SourceInformation sourceInformation = null;
1023 if (nativeBehavior.codeTemplate.isExpression) {
Harry Terkelsen 2016/10/12 16:42:58 maybe rewrite this entire if statement as: push(n
sra1 2016/10/13 19:02:01 Done.
1024 push(new HForeignCode(nativeBehavior.codeTemplate, ssaType, inputs,
1025 effects: nativeBehavior.sideEffects, nativeBehavior: nativeBehavior)
1026 ..sourceInformation = sourceInformation);
1027 } else {
1028 push(new HForeignCode(nativeBehavior.codeTemplate, ssaType, inputs,
1029 isStatement: true,
1030 effects: nativeBehavior.sideEffects,
1031 nativeBehavior: nativeBehavior)
1032 ..sourceInformation = sourceInformation);
1033 }
1034 }
1035
1036 void handleJsStringConcat(ir.StaticInvocation invocation) {
1037 if (_unexpectedForeignArguments(invocation, 'JS_STRING_CONCAT', 2)) {
1038 stack.add(graph.addConstantNull(compiler)); // Result expected on stack.
1039 return;
1040 }
1041 List<HInstruction> inputs = _visitArguments(invocation.arguments);
1042 assert(inputs.length == 2);
1043 push(new HStringConcat(inputs[0], inputs[1], backend.stringType));
1044 }
1045
681 void _pushStaticInvocation( 1046 void _pushStaticInvocation(
682 ir.Node target, List<HInstruction> arguments, TypeMask typeMask) { 1047 ir.Node target, List<HInstruction> arguments, TypeMask typeMask) {
683 HInstruction instruction = new HInvokeStatic( 1048 HInstruction instruction = new HInvokeStatic(
684 astAdapter.getElement(target).declaration, arguments, typeMask, 1049 astAdapter.getElement(target).declaration, arguments, typeMask,
685 targetCanThrow: astAdapter.getCanThrow(target)); 1050 targetCanThrow: astAdapter.getCanThrow(target));
686 instruction.sideEffects = astAdapter.getSideEffects(target); 1051 instruction.sideEffects = astAdapter.getSideEffects(target);
687 1052
688 push(instruction); 1053 push(instruction);
689 } 1054 }
690 1055
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
817 push(new HNot(popBoolified(), backend.boolType)); 1182 push(new HNot(popBoolified(), backend.boolType));
818 } 1183 }
819 1184
820 @override 1185 @override
821 void visitStringConcatenation(ir.StringConcatenation stringConcat) { 1186 void visitStringConcatenation(ir.StringConcatenation stringConcat) {
822 KernelStringBuilder stringBuilder = new KernelStringBuilder(this); 1187 KernelStringBuilder stringBuilder = new KernelStringBuilder(this);
823 stringConcat.accept(stringBuilder); 1188 stringConcat.accept(stringBuilder);
824 stack.add(stringBuilder.result); 1189 stack.add(stringBuilder.result);
825 } 1190 }
826 } 1191 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698