OLD | NEW |
---|---|
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 #include <set> | 5 #include <set> |
6 | 6 |
7 #include "vm/kernel_to_il.h" | 7 #include "vm/kernel_to_il.h" |
8 | 8 |
9 #include "vm/compiler.h" | 9 #include "vm/compiler.h" |
10 #include "vm/intermediate_language.h" | 10 #include "vm/intermediate_language.h" |
(...skipping 12 matching lines...) Expand all Loading... | |
23 DECLARE_FLAG(bool, support_externalizable_strings); | 23 DECLARE_FLAG(bool, support_externalizable_strings); |
24 | 24 |
25 namespace kernel { | 25 namespace kernel { |
26 | 26 |
27 #define Z (zone_) | 27 #define Z (zone_) |
28 #define H (translation_helper_) | 28 #define H (translation_helper_) |
29 #define T (type_translator_) | 29 #define T (type_translator_) |
30 #define I Isolate::Current() | 30 #define I Isolate::Current() |
31 | 31 |
32 | 32 |
33 static void DiscoverEnclosingElements(Zone* zone, | |
34 const Function& function, | |
35 Function* outermost_function, | |
36 TreeNode** outermost_node, | |
37 Class** klass) { | |
38 // Find out if there is an enclosing kernel class (which will be used to | |
39 // resolve type parameters). | |
40 *outermost_function = function.raw(); | |
41 while (outermost_function->parent_function() != Object::null()) { | |
42 *outermost_function = outermost_function->parent_function(); | |
43 } | |
44 *outermost_node = | |
45 static_cast<TreeNode*>(outermost_function->kernel_function()); | |
46 if (*outermost_node != NULL) { | |
47 TreeNode* parent = NULL; | |
48 if ((*outermost_node)->IsProcedure()) { | |
49 parent = Procedure::Cast(*outermost_node)->parent(); | |
50 } else if ((*outermost_node)->IsConstructor()) { | |
51 parent = Constructor::Cast(*outermost_node)->parent(); | |
52 } else if ((*outermost_node)->IsField()) { | |
53 parent = Field::Cast(*outermost_node)->parent(); | |
54 } | |
55 if (parent != NULL && parent->IsClass()) *klass = Class::Cast(parent); | |
56 } | |
57 } | |
58 | |
59 | |
60 static bool IsStaticInitializer(const Function& function, Zone* zone) { | |
61 return (function.kind() == RawFunction::kImplicitStaticFinalGetter) && | |
62 dart::String::Handle(zone, function.name()) | |
63 .StartsWith(Symbols::InitPrefix()); | |
64 } | |
65 | |
66 | |
67 Fragment& Fragment::operator+=(const Fragment& other) { | 33 Fragment& Fragment::operator+=(const Fragment& other) { |
68 if (entry == NULL) { | 34 if (entry == NULL) { |
69 entry = other.entry; | 35 entry = other.entry; |
70 current = other.current; | 36 current = other.current; |
71 } else if (current != NULL && other.entry != NULL) { | 37 } else if (current != NULL && other.entry != NULL) { |
72 current->LinkTo(other.entry); | 38 current->LinkTo(other.entry); |
73 current = other.current; | 39 current = other.current; |
74 } | 40 } |
75 return *this; | 41 return *this; |
76 } | 42 } |
(...skipping 600 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
677 if (named->length() == 0) return Array::ZoneHandle(Z); | 643 if (named->length() == 0) return Array::ZoneHandle(Z); |
678 | 644 |
679 const Array& names = | 645 const Array& names = |
680 Array::ZoneHandle(Z, Array::New(named->length(), Heap::kOld)); | 646 Array::ZoneHandle(Z, Array::New(named->length(), Heap::kOld)); |
681 for (intptr_t i = 0; i < named->length(); ++i) { | 647 for (intptr_t i = 0; i < named->length(); ++i) { |
682 names.SetAt(i, DartSymbol((*named)[i]->name())); | 648 names.SetAt(i, DartSymbol((*named)[i]->name())); |
683 } | 649 } |
684 return names; | 650 return names; |
685 } | 651 } |
686 | 652 |
687 ConstantEvaluator::ConstantEvaluator(FlowGraphBuilder* builder, | |
688 Zone* zone, | |
689 TranslationHelper* h, | |
690 DartTypeTranslator* type_translator) | |
691 : builder_(builder), | |
692 isolate_(Isolate::Current()), | |
693 zone_(zone), | |
694 translation_helper_(*h), | |
695 type_translator_(*type_translator), | |
696 script_(Script::Handle( | |
697 zone, | |
698 builder == NULL ? Script::null() | |
699 : builder_->parsed_function_->function().script())), | |
700 result_(Instance::Handle(zone)) {} | |
701 | |
702 | |
703 Instance& ConstantEvaluator::EvaluateExpression(Expression* expression) { | |
704 if (!GetCachedConstant(expression, &result_)) { | |
705 expression->AcceptExpressionVisitor(this); | |
706 CacheConstantValue(expression, result_); | |
707 } | |
708 // We return a new `ZoneHandle` here on purpose: The intermediate language | |
709 // instructions do not make a copy of the handle, so we do it. | |
710 return Instance::ZoneHandle(Z, result_.raw()); | |
711 } | |
712 | |
713 | |
714 Object& ConstantEvaluator::EvaluateExpressionSafe(Expression* expression) { | |
715 LongJumpScope jump; | |
716 if (setjmp(*jump.Set()) == 0) { | |
717 return EvaluateExpression(expression); | |
718 } else { | |
719 Thread* thread = H.thread(); | |
720 Error& error = Error::Handle(Z); | |
721 error = thread->sticky_error(); | |
722 thread->clear_sticky_error(); | |
723 return error; | |
724 } | |
725 } | |
726 | |
727 | |
728 Instance& ConstantEvaluator::EvaluateConstructorInvocation( | |
729 ConstructorInvocation* node) { | |
730 if (!GetCachedConstant(node, &result_)) { | |
731 VisitConstructorInvocation(node); | |
732 CacheConstantValue(node, result_); | |
733 } | |
734 // We return a new `ZoneHandle` here on purpose: The intermediate language | |
735 // instructions do not make a copy of the handle, so we do it. | |
736 return Instance::ZoneHandle(Z, result_.raw()); | |
737 } | |
738 | |
739 | |
740 Instance& ConstantEvaluator::EvaluateListLiteral(ListLiteral* node) { | |
741 if (!GetCachedConstant(node, &result_)) { | |
742 VisitListLiteral(node); | |
743 CacheConstantValue(node, result_); | |
744 } | |
745 // We return a new `ZoneHandle` here on purpose: The intermediate language | |
746 // instructions do not make a copy of the handle, so we do it. | |
747 return Instance::ZoneHandle(Z, result_.raw()); | |
748 } | |
749 | |
750 | |
751 Instance& ConstantEvaluator::EvaluateMapLiteral(MapLiteral* node) { | |
752 if (!GetCachedConstant(node, &result_)) { | |
753 VisitMapLiteral(node); | |
754 CacheConstantValue(node, result_); | |
755 } | |
756 // We return a new `ZoneHandle` here on purpose: The intermediate language | |
757 // instructions do not make a copy of the handle, so we do it. | |
758 return Instance::ZoneHandle(Z, result_.raw()); | |
759 } | |
760 | |
761 | |
762 void ConstantEvaluator::VisitBigintLiteral(BigintLiteral* node) { | |
763 const dart::String& value = H.DartString(node->value()); | |
764 result_ = Integer::New(value, Heap::kOld); | |
765 result_ = H.Canonicalize(result_); | |
766 } | |
767 | |
768 | |
769 void ConstantEvaluator::VisitBoolLiteral(BoolLiteral* node) { | |
770 result_ = Bool::Get(node->value()).raw(); | |
771 } | |
772 | |
773 | |
774 void ConstantEvaluator::VisitDoubleLiteral(DoubleLiteral* node) { | |
775 result_ = Double::New(H.DartString(node->value()), Heap::kOld); | |
776 result_ = H.Canonicalize(result_); | |
777 } | |
778 | |
779 | |
780 void ConstantEvaluator::VisitIntLiteral(IntLiteral* node) { | |
781 result_ = Integer::New(node->value(), Heap::kOld); | |
782 result_ = H.Canonicalize(result_); | |
783 } | |
784 | |
785 | |
786 void ConstantEvaluator::VisitNullLiteral(NullLiteral* node) { | |
787 result_ = Instance::null(); | |
788 } | |
789 | |
790 | |
791 void ConstantEvaluator::VisitStringLiteral(StringLiteral* node) { | |
792 result_ = H.DartSymbol(node->value()).raw(); | |
793 } | |
794 | |
795 | |
796 void ConstantEvaluator::VisitTypeLiteral(TypeLiteral* node) { | |
797 const AbstractType& type = T.TranslateType(node->type()); | |
798 if (type.IsMalformed()) { | |
799 H.ReportError("Malformed type literal in constant expression."); | |
800 } | |
801 result_ = type.raw(); | |
802 } | |
803 | |
804 | |
805 RawObject* ConstantEvaluator::EvaluateConstConstructorCall( | |
806 const dart::Class& type_class, | |
807 const TypeArguments& type_arguments, | |
808 const Function& constructor, | |
809 const Object& argument) { | |
810 // Factories have one extra argument: the type arguments. | |
811 // Constructors have 1 extra arguments: receiver. | |
812 const int kNumArgs = 1; | |
813 const int kNumExtraArgs = 1; | |
814 const int num_arguments = kNumArgs + kNumExtraArgs; | |
815 const Array& arg_values = | |
816 Array::Handle(Z, Array::New(num_arguments, Heap::kOld)); | |
817 Instance& instance = Instance::Handle(Z); | |
818 if (!constructor.IsFactory()) { | |
819 instance = Instance::New(type_class, Heap::kOld); | |
820 if (!type_arguments.IsNull()) { | |
821 ASSERT(type_arguments.IsInstantiated()); | |
822 instance.SetTypeArguments( | |
823 TypeArguments::Handle(Z, type_arguments.Canonicalize())); | |
824 } | |
825 arg_values.SetAt(0, instance); | |
826 } else { | |
827 // Prepend type_arguments to list of arguments to factory. | |
828 ASSERT(type_arguments.IsZoneHandle()); | |
829 arg_values.SetAt(0, type_arguments); | |
830 } | |
831 arg_values.SetAt((0 + kNumExtraArgs), argument); | |
832 const Array& args_descriptor = Array::Handle( | |
833 Z, ArgumentsDescriptor::New(num_arguments, Object::empty_array())); | |
834 const Object& result = Object::Handle( | |
835 Z, DartEntry::InvokeFunction(constructor, arg_values, args_descriptor)); | |
836 ASSERT(!result.IsError()); | |
837 if (constructor.IsFactory()) { | |
838 // The factory method returns the allocated object. | |
839 instance ^= result.raw(); | |
840 } | |
841 return H.Canonicalize(instance); | |
842 } | |
843 | |
844 | |
845 bool ConstantEvaluator::GetCachedConstant(TreeNode* node, Instance* value) { | |
846 if (builder_ == NULL) return false; | |
847 | |
848 const Function& function = builder_->parsed_function_->function(); | |
849 if (function.kind() == RawFunction::kImplicitStaticFinalGetter) { | |
850 // Don't cache constants in initializer expressions. They get | |
851 // evaluated only once. | |
852 return false; | |
853 } | |
854 | |
855 bool is_present = false; | |
856 ASSERT(!script_.InVMHeap()); | |
857 if (script_.compile_time_constants() == Array::null()) { | |
858 return false; | |
859 } | |
860 KernelConstantsMap constants(script_.compile_time_constants()); | |
861 *value ^= constants.GetOrNull(node->kernel_offset(), &is_present); | |
862 // Mutator compiler thread may add constants while background compiler | |
863 // is running, and thus change the value of 'compile_time_constants'; | |
864 // do not assert that 'compile_time_constants' has not changed. | |
865 constants.Release(); | |
866 if (FLAG_compiler_stats && is_present) { | |
867 H.thread()->compiler_stats()->num_const_cache_hits++; | |
868 } | |
869 return is_present; | |
870 } | |
871 | |
872 | |
873 void ConstantEvaluator::CacheConstantValue(TreeNode* node, | |
874 const Instance& value) { | |
875 ASSERT(Thread::Current()->IsMutatorThread()); | |
876 | |
877 if (builder_ == NULL) return; | |
878 | |
879 const Function& function = builder_->parsed_function_->function(); | |
880 if (function.kind() == RawFunction::kImplicitStaticFinalGetter) { | |
881 // Don't cache constants in initializer expressions. They get | |
882 // evaluated only once. | |
883 return; | |
884 } | |
885 const intptr_t kInitialConstMapSize = 16; | |
886 ASSERT(!script_.InVMHeap()); | |
887 if (script_.compile_time_constants() == Array::null()) { | |
888 const Array& array = Array::Handle( | |
889 HashTables::New<KernelConstantsMap>(kInitialConstMapSize, Heap::kNew)); | |
890 script_.set_compile_time_constants(array); | |
891 } | |
892 KernelConstantsMap constants(script_.compile_time_constants()); | |
893 constants.InsertNewOrGetValue(node->kernel_offset(), value); | |
894 script_.set_compile_time_constants(constants.Release()); | |
895 } | |
896 | |
897 | |
898 void ConstantEvaluator::VisitSymbolLiteral(SymbolLiteral* node) { | |
899 const dart::String& symbol_value = H.DartSymbol(node->value()); | |
900 | |
901 const dart::Class& symbol_class = | |
902 dart::Class::ZoneHandle(Z, I->object_store()->symbol_class()); | |
903 ASSERT(!symbol_class.IsNull()); | |
904 const Function& symbol_constructor = Function::ZoneHandle( | |
905 Z, symbol_class.LookupConstructor(Symbols::SymbolCtor())); | |
906 ASSERT(!symbol_constructor.IsNull()); | |
907 result_ ^= EvaluateConstConstructorCall( | |
908 symbol_class, TypeArguments::Handle(Z), symbol_constructor, symbol_value); | |
909 } | |
910 | |
911 | |
912 void ConstantEvaluator::VisitListLiteral(ListLiteral* node) { | |
913 DartType* types[] = {node->type()}; | |
914 const TypeArguments& type_arguments = T.TranslateTypeArguments(types, 1); | |
915 | |
916 intptr_t length = node->expressions().length(); | |
917 const Array& const_list = | |
918 Array::ZoneHandle(Z, Array::New(length, Heap::kOld)); | |
919 const_list.SetTypeArguments(type_arguments); | |
920 for (intptr_t i = 0; i < length; i++) { | |
921 const Instance& expression = EvaluateExpression(node->expressions()[i]); | |
922 const_list.SetAt(i, expression); | |
923 } | |
924 const_list.MakeImmutable(); | |
925 result_ = H.Canonicalize(const_list); | |
926 } | |
927 | |
928 | |
929 void ConstantEvaluator::VisitMapLiteral(MapLiteral* node) { | |
930 DartType* types[] = {node->key_type(), node->value_type()}; | |
931 const TypeArguments& type_arguments = T.TranslateTypeArguments(types, 2); | |
932 | |
933 intptr_t length = node->entries().length(); | |
934 | |
935 Array& const_kv_array = | |
936 Array::ZoneHandle(Z, Array::New(2 * length, Heap::kOld)); | |
937 for (intptr_t i = 0; i < length; i++) { | |
938 const_kv_array.SetAt(2 * i + 0, | |
939 EvaluateExpression(node->entries()[i]->key())); | |
940 const_kv_array.SetAt(2 * i + 1, | |
941 EvaluateExpression(node->entries()[i]->value())); | |
942 } | |
943 | |
944 const_kv_array.MakeImmutable(); | |
945 const_kv_array ^= H.Canonicalize(const_kv_array); | |
946 | |
947 const dart::Class& map_class = dart::Class::Handle( | |
948 Z, dart::Library::LookupCoreClass(Symbols::ImmutableMap())); | |
949 ASSERT(!map_class.IsNull()); | |
950 ASSERT(map_class.NumTypeArguments() == 2); | |
951 | |
952 const dart::Field& field = dart::Field::Handle( | |
953 Z, map_class.LookupInstanceFieldAllowPrivate(H.DartSymbol("_kvPairs"))); | |
954 ASSERT(!field.IsNull()); | |
955 | |
956 // NOTE: This needs to be kept in sync with `runtime/lib/immutable_map.dart`! | |
957 result_ = Instance::New(map_class, Heap::kOld); | |
958 ASSERT(!result_.IsNull()); | |
959 result_.SetTypeArguments(type_arguments); | |
960 result_.SetField(field, const_kv_array); | |
961 result_ = H.Canonicalize(result_); | |
962 } | |
963 | |
964 | |
965 void ConstantEvaluator::VisitConstructorInvocation( | |
966 ConstructorInvocation* node) { | |
967 Arguments* kernel_arguments = node->arguments(); | |
968 | |
969 const Function& constructor = Function::Handle( | |
970 Z, H.LookupConstructorByKernelConstructor(node->target())); | |
971 dart::Class& klass = dart::Class::Handle(Z, constructor.Owner()); | |
972 | |
973 // Build the type arguments vector (if necessary). | |
974 const TypeArguments* type_arguments = | |
975 TranslateTypeArguments(constructor, &klass, kernel_arguments); | |
976 | |
977 // Prepare either the instance or the type argument vector for the constructor | |
978 // call. | |
979 Instance* receiver = NULL; | |
980 const TypeArguments* type_arguments_argument = NULL; | |
981 if (!constructor.IsFactory()) { | |
982 receiver = &Instance::ZoneHandle(Z, Instance::New(klass, Heap::kOld)); | |
983 if (type_arguments != NULL) { | |
984 receiver->SetTypeArguments(*type_arguments); | |
985 } | |
986 } else { | |
987 type_arguments_argument = type_arguments; | |
988 } | |
989 | |
990 const Object& result = RunFunction(constructor, kernel_arguments, receiver, | |
991 type_arguments_argument); | |
992 if (constructor.IsFactory()) { | |
993 // Factories return the new object. | |
994 result_ ^= result.raw(); | |
995 result_ = H.Canonicalize(result_); | |
996 } else { | |
997 ASSERT(!receiver->IsNull()); | |
998 result_ = H.Canonicalize(*receiver); | |
999 } | |
1000 } | |
1001 | |
1002 | |
1003 void ConstantEvaluator::VisitMethodInvocation(MethodInvocation* node) { | |
1004 Arguments* kernel_arguments = node->arguments(); | |
1005 | |
1006 // Dart does not support generic methods yet. | |
1007 ASSERT(kernel_arguments->types().length() == 0); | |
1008 | |
1009 const Instance& receiver = EvaluateExpression(node->receiver()); | |
1010 dart::Class& klass = dart::Class::Handle( | |
1011 Z, isolate_->class_table()->At(receiver.GetClassId())); | |
1012 ASSERT(!klass.IsNull()); | |
1013 | |
1014 // Search the superclass chain for the selector. | |
1015 Function& function = Function::Handle(Z); | |
1016 const dart::String& method_name = H.DartMethodName(node->name()); | |
1017 while (!klass.IsNull()) { | |
1018 function = klass.LookupDynamicFunctionAllowPrivate(method_name); | |
1019 if (!function.IsNull()) break; | |
1020 klass = klass.SuperClass(); | |
1021 } | |
1022 | |
1023 // The frontend should guarantee that [MethodInvocation]s inside constant | |
1024 // expressions are always valid. | |
1025 ASSERT(!function.IsNull()); | |
1026 | |
1027 // Run the method and canonicalize the result. | |
1028 const Object& result = RunFunction(function, kernel_arguments, &receiver); | |
1029 result_ ^= result.raw(); | |
1030 result_ = H.Canonicalize(result_); | |
1031 } | |
1032 | |
1033 | |
1034 void ConstantEvaluator::VisitStaticGet(StaticGet* node) { | |
1035 NameIndex target = node->target(); | |
1036 if (H.IsField(target)) { | |
1037 const dart::Field& field = | |
1038 dart::Field::Handle(Z, H.LookupFieldByKernelField(target)); | |
1039 if (field.StaticValue() == Object::sentinel().raw() || | |
1040 field.StaticValue() == Object::transition_sentinel().raw()) { | |
1041 field.EvaluateInitializer(); | |
1042 result_ = field.StaticValue(); | |
1043 result_ = H.Canonicalize(result_); | |
1044 field.SetStaticValue(result_, true); | |
1045 } else { | |
1046 result_ = field.StaticValue(); | |
1047 } | |
1048 } else if (H.IsProcedure(target)) { | |
1049 const Function& function = | |
1050 Function::ZoneHandle(Z, H.LookupStaticMethodByKernelProcedure(target)); | |
1051 | |
1052 if (H.IsMethod(target)) { | |
1053 Function& closure_function = | |
1054 Function::ZoneHandle(Z, function.ImplicitClosureFunction()); | |
1055 closure_function.set_kernel_function(function.kernel_function()); | |
1056 result_ = closure_function.ImplicitStaticClosure(); | |
1057 result_ = H.Canonicalize(result_); | |
1058 } else if (H.IsGetter(target)) { | |
1059 UNIMPLEMENTED(); | |
1060 } else { | |
1061 UNIMPLEMENTED(); | |
1062 } | |
1063 } | |
1064 } | |
1065 | |
1066 | |
1067 void ConstantEvaluator::VisitVariableGet(VariableGet* node) { | |
1068 // When we see a [VariableGet] the corresponding [VariableDeclaration] must've | |
1069 // been executed already. It therefore must have a constant object associated | |
1070 // with it. | |
1071 LocalVariable* variable = builder_->LookupVariable(node->variable()); | |
1072 ASSERT(variable->IsConst()); | |
1073 result_ = variable->ConstValue()->raw(); | |
1074 } | |
1075 | |
1076 | |
1077 void ConstantEvaluator::VisitLet(Let* node) { | |
1078 VariableDeclaration* variable = node->variable(); | |
1079 LocalVariable* local = builder_->LookupVariable(variable); | |
1080 local->SetConstValue(EvaluateExpression(variable->initializer())); | |
1081 node->body()->AcceptExpressionVisitor(this); | |
1082 } | |
1083 | |
1084 | |
1085 void ConstantEvaluator::VisitStaticInvocation(StaticInvocation* node) { | |
1086 const Function& function = Function::ZoneHandle( | |
1087 Z, H.LookupStaticMethodByKernelProcedure(node->procedure())); | |
1088 dart::Class& klass = dart::Class::Handle(Z, function.Owner()); | |
1089 | |
1090 // Build the type arguments vector (if necessary). | |
1091 const TypeArguments* type_arguments = | |
1092 TranslateTypeArguments(function, &klass, node->arguments()); | |
1093 | |
1094 const Object& result = | |
1095 RunFunction(function, node->arguments(), NULL, type_arguments); | |
1096 result_ ^= result.raw(); | |
1097 result_ = H.Canonicalize(result_); | |
1098 } | |
1099 | |
1100 | |
1101 void ConstantEvaluator::VisitStringConcatenation(StringConcatenation* node) { | |
1102 intptr_t length = node->expressions().length(); | |
1103 | |
1104 bool all_string = true; | |
1105 const Array& strings = Array::Handle(Z, Array::New(length)); | |
1106 for (intptr_t i = 0; i < length; i++) { | |
1107 EvaluateExpression(node->expressions()[i]); | |
1108 strings.SetAt(i, result_); | |
1109 all_string = all_string && result_.IsString(); | |
1110 } | |
1111 if (all_string) { | |
1112 result_ = dart::String::ConcatAll(strings, Heap::kOld); | |
1113 result_ = H.Canonicalize(result_); | |
1114 } else { | |
1115 // Get string interpolation function. | |
1116 const dart::Class& cls = dart::Class::Handle( | |
1117 Z, dart::Library::LookupCoreClass(Symbols::StringBase())); | |
1118 ASSERT(!cls.IsNull()); | |
1119 const Function& func = Function::Handle( | |
1120 Z, cls.LookupStaticFunction( | |
1121 dart::Library::PrivateCoreLibName(Symbols::Interpolate()))); | |
1122 ASSERT(!func.IsNull()); | |
1123 | |
1124 // Build argument array to pass to the interpolation function. | |
1125 const Array& interpolate_arg = Array::Handle(Z, Array::New(1, Heap::kOld)); | |
1126 interpolate_arg.SetAt(0, strings); | |
1127 | |
1128 // Run and canonicalize. | |
1129 const Object& result = | |
1130 RunFunction(func, interpolate_arg, Array::null_array()); | |
1131 result_ = H.Canonicalize(dart::String::Cast(result)); | |
1132 } | |
1133 } | |
1134 | |
1135 | |
1136 void ConstantEvaluator::VisitConditionalExpression( | |
1137 ConditionalExpression* node) { | |
1138 if (EvaluateBooleanExpression(node->condition())) { | |
1139 EvaluateExpression(node->then()); | |
1140 } else { | |
1141 EvaluateExpression(node->otherwise()); | |
1142 } | |
1143 } | |
1144 | |
1145 | |
1146 void ConstantEvaluator::VisitLogicalExpression(LogicalExpression* node) { | |
1147 if (node->op() == LogicalExpression::kAnd) { | |
1148 if (EvaluateBooleanExpression(node->left())) { | |
1149 EvaluateBooleanExpression(node->right()); | |
1150 } | |
1151 } else { | |
1152 ASSERT(node->op() == LogicalExpression::kOr); | |
1153 if (!EvaluateBooleanExpression(node->left())) { | |
1154 EvaluateBooleanExpression(node->right()); | |
1155 } | |
1156 } | |
1157 } | |
1158 | |
1159 | |
1160 void ConstantEvaluator::VisitNot(Not* node) { | |
1161 result_ ^= Bool::Get(!EvaluateBooleanExpression(node->expression())).raw(); | |
1162 } | |
1163 | |
1164 | |
1165 void ConstantEvaluator::VisitPropertyGet(PropertyGet* node) { | |
1166 StringIndex string_index = node->name()->string_index(); | |
1167 if (H.StringEquals(string_index, "length")) { | |
1168 node->receiver()->AcceptExpressionVisitor(this); | |
1169 if (result_.IsString()) { | |
1170 const dart::String& str = | |
1171 dart::String::Handle(Z, dart::String::RawCast(result_.raw())); | |
1172 result_ = Integer::New(str.Length()); | |
1173 } else { | |
1174 H.ReportError( | |
1175 "Constant expressions can only call " | |
1176 "'length' on string constants."); | |
1177 } | |
1178 } else { | |
1179 VisitDefaultExpression(node); | |
1180 } | |
1181 } | |
1182 | |
1183 | |
1184 const TypeArguments* ConstantEvaluator::TranslateTypeArguments( | |
1185 const Function& target, | |
1186 dart::Class* target_klass, | |
1187 Arguments* kernel_arguments) { | |
1188 List<DartType>& kernel_type_arguments = kernel_arguments->types(); | |
1189 | |
1190 const TypeArguments* type_arguments = NULL; | |
1191 if (kernel_type_arguments.length() > 0) { | |
1192 type_arguments = &T.TranslateInstantiatedTypeArguments( | |
1193 *target_klass, kernel_type_arguments.raw_array(), | |
1194 kernel_type_arguments.length()); | |
1195 | |
1196 if (!(type_arguments->IsNull() || type_arguments->IsInstantiated())) { | |
1197 H.ReportError("Type must be constant in const constructor."); | |
1198 } | |
1199 } else if (target.IsFactory() && type_arguments == NULL) { | |
1200 // All factories take a type arguments vector as first argument (independent | |
1201 // of whether the class is generic or not). | |
1202 type_arguments = &TypeArguments::ZoneHandle(Z, TypeArguments::null()); | |
1203 } | |
1204 return type_arguments; | |
1205 } | |
1206 | |
1207 | |
1208 const Object& ConstantEvaluator::RunFunction(const Function& function, | |
1209 Arguments* kernel_arguments, | |
1210 const Instance* receiver, | |
1211 const TypeArguments* type_args) { | |
1212 // We do not support generic methods yet. | |
1213 ASSERT((receiver == NULL) || (type_args == NULL)); | |
1214 intptr_t extra_arguments = | |
1215 (receiver != NULL ? 1 : 0) + (type_args != NULL ? 1 : 0); | |
1216 | |
1217 // Build up arguments. | |
1218 const Array& arguments = Array::ZoneHandle( | |
1219 Z, Array::New(extra_arguments + kernel_arguments->count())); | |
1220 const Array& names = | |
1221 Array::ZoneHandle(Z, Array::New(kernel_arguments->named().length())); | |
1222 intptr_t pos = 0; | |
1223 if (receiver != NULL) { | |
1224 arguments.SetAt(pos++, *receiver); | |
1225 } | |
1226 if (type_args != NULL) { | |
1227 arguments.SetAt(pos++, *type_args); | |
1228 } | |
1229 for (intptr_t i = 0; i < kernel_arguments->positional().length(); i++) { | |
1230 EvaluateExpression(kernel_arguments->positional()[i]); | |
1231 arguments.SetAt(pos++, result_); | |
1232 } | |
1233 for (intptr_t i = 0; i < kernel_arguments->named().length(); i++) { | |
1234 NamedExpression* named_expression = kernel_arguments->named()[i]; | |
1235 EvaluateExpression(named_expression->expression()); | |
1236 arguments.SetAt(pos++, result_); | |
1237 names.SetAt(i, H.DartSymbol(named_expression->name())); | |
1238 } | |
1239 return RunFunction(function, arguments, names); | |
1240 } | |
1241 | |
1242 | |
1243 const Object& ConstantEvaluator::RunFunction(const Function& function, | |
1244 const Array& arguments, | |
1245 const Array& names) { | |
1246 const Array& args_descriptor = | |
1247 Array::Handle(Z, ArgumentsDescriptor::New(arguments.Length(), names)); | |
1248 const Object& result = Object::Handle( | |
1249 Z, DartEntry::InvokeFunction(function, arguments, args_descriptor)); | |
1250 if (result.IsError()) { | |
1251 H.ReportError(Error::Cast(result), "error evaluating constant constructor"); | |
1252 } | |
1253 return result; | |
1254 } | |
1255 | |
1256 | 653 |
1257 FlowGraphBuilder::FlowGraphBuilder( | 654 FlowGraphBuilder::FlowGraphBuilder( |
1258 TreeNode* node, | 655 intptr_t kernel_offset, |
1259 ParsedFunction* parsed_function, | 656 ParsedFunction* parsed_function, |
1260 const ZoneGrowableArray<const ICData*>& ic_data_array, | 657 const ZoneGrowableArray<const ICData*>& ic_data_array, |
1261 InlineExitCollector* exit_collector, | 658 InlineExitCollector* exit_collector, |
1262 intptr_t osr_id, | 659 intptr_t osr_id, |
1263 intptr_t first_block_id) | 660 intptr_t first_block_id) |
1264 : translation_helper_(Thread::Current()), | 661 : translation_helper_(Thread::Current()), |
1265 zone_(translation_helper_.zone()), | 662 zone_(translation_helper_.zone()), |
1266 node_(node), | 663 kernel_offset_(kernel_offset), |
1267 parsed_function_(parsed_function), | 664 parsed_function_(parsed_function), |
1268 osr_id_(osr_id), | 665 osr_id_(osr_id), |
1269 ic_data_array_(ic_data_array), | 666 ic_data_array_(ic_data_array), |
1270 exit_collector_(exit_collector), | 667 exit_collector_(exit_collector), |
1271 next_block_id_(first_block_id), | 668 next_block_id_(first_block_id), |
1272 next_function_id_(0), | 669 next_function_id_(0), |
1273 context_depth_(0), | 670 context_depth_(0), |
1274 loop_depth_(0), | 671 loop_depth_(0), |
1275 try_depth_(0), | 672 try_depth_(0), |
1276 catch_depth_(0), | 673 catch_depth_(0), |
1277 for_in_depth_(0), | 674 for_in_depth_(0), |
1278 stack_(NULL), | 675 stack_(NULL), |
1279 pending_argument_count_(0), | 676 pending_argument_count_(0), |
1280 graph_entry_(NULL), | 677 graph_entry_(NULL), |
1281 scopes_(NULL), | 678 scopes_(NULL), |
1282 breakable_block_(NULL), | 679 breakable_block_(NULL), |
1283 switch_block_(NULL), | 680 switch_block_(NULL), |
1284 try_finally_block_(NULL), | 681 try_finally_block_(NULL), |
1285 try_catch_block_(NULL), | 682 try_catch_block_(NULL), |
1286 next_used_try_index_(0), | 683 next_used_try_index_(0), |
1287 catch_block_(NULL), | 684 catch_block_(NULL), |
1288 type_translator_(&translation_helper_, | 685 type_translator_(&translation_helper_, |
1289 &active_class_, | 686 &active_class_, |
1290 /* finalize= */ true), | 687 /* finalize= */ true), |
1291 constant_evaluator_(this, zone_, &translation_helper_, &type_translator_), | |
1292 streaming_flow_graph_builder_(NULL) { | 688 streaming_flow_graph_builder_(NULL) { |
1293 Script& script = Script::Handle(Z, parsed_function->function().script()); | 689 Script& script = Script::Handle(Z, parsed_function->function().script()); |
1294 H.SetStringOffsets(TypedData::Handle(Z, script.kernel_string_offsets())); | 690 H.SetStringOffsets(TypedData::Handle(Z, script.kernel_string_offsets())); |
1295 H.SetStringData(TypedData::Handle(Z, script.kernel_string_data())); | 691 H.SetStringData(TypedData::Handle(Z, script.kernel_string_data())); |
1296 H.SetCanonicalNames(TypedData::Handle(Z, script.kernel_canonical_names())); | 692 H.SetCanonicalNames(TypedData::Handle(Z, script.kernel_canonical_names())); |
1297 } | 693 } |
1298 | 694 |
1299 | 695 |
1300 FlowGraphBuilder::~FlowGraphBuilder() { | 696 FlowGraphBuilder::~FlowGraphBuilder() { |
1301 if (streaming_flow_graph_builder_ != NULL) { | 697 if (streaming_flow_graph_builder_ != NULL) { |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1336 JoinEntryInstr* entry = BuildJoinEntry(); | 732 JoinEntryInstr* entry = BuildJoinEntry(); |
1337 instructions += Goto(entry); | 733 instructions += Goto(entry); |
1338 instructions = Fragment(instructions.entry, entry); | 734 instructions = Fragment(instructions.entry, entry); |
1339 } | 735 } |
1340 | 736 |
1341 Statement* finalizer = try_finally_block_->finalizer(); | 737 Statement* finalizer = try_finally_block_->finalizer(); |
1342 intptr_t finalizer_kernel_offset = | 738 intptr_t finalizer_kernel_offset = |
1343 try_finally_block_->finalizer_kernel_offset(); | 739 try_finally_block_->finalizer_kernel_offset(); |
1344 try_finally_block_ = try_finally_block_->outer(); | 740 try_finally_block_ = try_finally_block_->outer(); |
1345 if (finalizer != NULL) { | 741 if (finalizer != NULL) { |
1346 // This will potentially have exceptional cases as described in | 742 UNREACHABLE(); |
1347 // [VisitTryFinally] and will handle them. | |
1348 instructions += TranslateStatement(finalizer); | |
1349 } else { | 743 } else { |
1350 instructions += streaming_flow_graph_builder_->BuildStatementAt( | 744 instructions += streaming_flow_graph_builder_->BuildStatementAt( |
1351 finalizer_kernel_offset); | 745 finalizer_kernel_offset); |
1352 } | 746 } |
1353 | 747 |
1354 // We only need to make sure that if the finalizer ended normally, we | 748 // We only need to make sure that if the finalizer ended normally, we |
1355 // continue towards the next outer try-finally. | 749 // continue towards the next outer try-finally. |
1356 if (!instructions.is_open()) break; | 750 if (!instructions.is_open()) break; |
1357 } | 751 } |
1358 | 752 |
1359 if (instructions.is_open() && target_context_depth != -1) { | 753 if (instructions.is_open() && target_context_depth != -1) { |
1360 // A target context depth of -1 indicates that the code after this | 754 // A target context depth of -1 indicates that the code after this |
1361 // will not care about the context chain so we can leave it any way we | 755 // will not care about the context chain so we can leave it any way we |
1362 // want after the last finalizer. That is used when returning. | 756 // want after the last finalizer. That is used when returning. |
1363 instructions += AdjustContextTo(target_context_depth); | 757 instructions += AdjustContextTo(target_context_depth); |
1364 } | 758 } |
1365 | 759 |
1366 try_finally_block_ = saved_block; | 760 try_finally_block_ = saved_block; |
1367 try_catch_block_ = saved_try_catch_block; | 761 try_catch_block_ = saved_try_catch_block; |
1368 context_depth_ = saved_depth; | 762 context_depth_ = saved_depth; |
1369 try_depth_ = saved_try_depth; | 763 try_depth_ = saved_try_depth; |
1370 | 764 |
1371 return instructions; | 765 return instructions; |
1372 } | 766 } |
1373 | 767 |
1374 | 768 |
1375 Fragment FlowGraphBuilder::EnterScope(TreeNode* node, bool* new_context) { | |
1376 return EnterScope(node->kernel_offset(), new_context); | |
1377 } | |
1378 | |
1379 | |
1380 Fragment FlowGraphBuilder::EnterScope(intptr_t kernel_offset, | 769 Fragment FlowGraphBuilder::EnterScope(intptr_t kernel_offset, |
1381 bool* new_context) { | 770 bool* new_context) { |
1382 Fragment instructions; | 771 Fragment instructions; |
1383 const intptr_t context_size = | 772 const intptr_t context_size = |
1384 scopes_->scopes.Lookup(kernel_offset)->num_context_variables(); | 773 scopes_->scopes.Lookup(kernel_offset)->num_context_variables(); |
1385 if (context_size > 0) { | 774 if (context_size > 0) { |
1386 instructions += PushContext(context_size); | 775 instructions += PushContext(context_size); |
1387 instructions += Drop(); | 776 instructions += Drop(); |
1388 if (new_context != NULL) { | 777 if (new_context != NULL) { |
1389 *new_context = true; | 778 *new_context = true; |
1390 } | 779 } |
1391 } | 780 } |
1392 return instructions; | 781 return instructions; |
1393 } | 782 } |
1394 | 783 |
1395 | 784 |
1396 Fragment FlowGraphBuilder::ExitScope(TreeNode* node) { | |
1397 return ExitScope(node->kernel_offset()); | |
1398 } | |
1399 | |
1400 | |
1401 Fragment FlowGraphBuilder::ExitScope(intptr_t kernel_offset) { | 785 Fragment FlowGraphBuilder::ExitScope(intptr_t kernel_offset) { |
1402 Fragment instructions; | 786 Fragment instructions; |
1403 const intptr_t context_size = | 787 const intptr_t context_size = |
1404 scopes_->scopes.Lookup(kernel_offset)->num_context_variables(); | 788 scopes_->scopes.Lookup(kernel_offset)->num_context_variables(); |
1405 if (context_size > 0) { | 789 if (context_size > 0) { |
1406 instructions += PopContext(); | 790 instructions += PopContext(); |
1407 } | 791 } |
1408 return instructions; | 792 return instructions; |
1409 } | 793 } |
1410 | 794 |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1461 #ifdef DEBUG | 845 #ifdef DEBUG |
1462 Function& function = | 846 Function& function = |
1463 Function::Handle(Z, parsed_function_->function().raw()); | 847 Function::Handle(Z, parsed_function_->function().raw()); |
1464 while (function.IsClosureFunction()) { | 848 while (function.IsClosureFunction()) { |
1465 function = function.parent_function(); | 849 function = function.parent_function(); |
1466 } | 850 } |
1467 ASSERT(function.IsFactory()); | 851 ASSERT(function.IsFactory()); |
1468 #endif | 852 #endif |
1469 instructions += LoadLocal(scopes_->type_arguments_variable); | 853 instructions += LoadLocal(scopes_->type_arguments_variable); |
1470 } else if (scopes_->this_variable != NULL && | 854 } else if (scopes_->this_variable != NULL && |
1471 active_class_.kernel_class != NULL && | 855 active_class_.class_type_parameters > 0) { |
1472 active_class_.kernel_class->type_parameters().length() > 0) { | |
1473 ASSERT(!parsed_function_->function().IsFactory()); | 856 ASSERT(!parsed_function_->function().IsFactory()); |
1474 intptr_t type_arguments_field_offset = | 857 intptr_t type_arguments_field_offset = |
1475 active_class_.klass->type_arguments_field_offset(); | 858 active_class_.klass->type_arguments_field_offset(); |
1476 ASSERT(type_arguments_field_offset != dart::Class::kNoTypeArguments); | 859 ASSERT(type_arguments_field_offset != dart::Class::kNoTypeArguments); |
1477 | 860 |
1478 instructions += LoadLocal(scopes_->this_variable); | 861 instructions += LoadLocal(scopes_->this_variable); |
1479 instructions += LoadField(type_arguments_field_offset); | 862 instructions += LoadField(type_arguments_field_offset); |
1480 } else { | 863 } else { |
1481 instructions += NullConstant(); | 864 instructions += NullConstant(); |
1482 } | 865 } |
(...skipping 902 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2385 parsed_function_->Bailout("kernel::FlowGraphBuilder", reason); | 1768 parsed_function_->Bailout("kernel::FlowGraphBuilder", reason); |
2386 } | 1769 } |
2387 } | 1770 } |
2388 | 1771 |
2389 | 1772 |
2390 FlowGraph* FlowGraphBuilder::BuildGraph() { | 1773 FlowGraph* FlowGraphBuilder::BuildGraph() { |
2391 const Function& function = parsed_function_->function(); | 1774 const Function& function = parsed_function_->function(); |
2392 | 1775 |
2393 if (function.IsConstructorClosureFunction()) return NULL; | 1776 if (function.IsConstructorClosureFunction()) return NULL; |
2394 | 1777 |
2395 TreeNode* library_node = node_; | |
2396 if (node_ != NULL) { | |
2397 const Function* parent = &function; | |
2398 while (true) { | |
2399 library_node = static_cast<kernel::TreeNode*>(parent->kernel_function()); | |
2400 while (library_node != NULL && !library_node->IsLibrary()) { | |
2401 if (library_node->IsMember()) { | |
2402 library_node = Member::Cast(library_node)->parent(); | |
2403 } else if (library_node->IsClass()) { | |
2404 library_node = Class::Cast(library_node)->parent(); | |
2405 break; | |
2406 } else { | |
2407 library_node = NULL; | |
2408 break; | |
2409 } | |
2410 } | |
2411 if (library_node != NULL) break; | |
2412 parent = &Function::Handle(parent->parent_function()); | |
2413 } | |
2414 } | |
2415 if (streaming_flow_graph_builder_ != NULL) { | 1778 if (streaming_flow_graph_builder_ != NULL) { |
2416 delete streaming_flow_graph_builder_; | 1779 delete streaming_flow_graph_builder_; |
2417 streaming_flow_graph_builder_ = NULL; | 1780 streaming_flow_graph_builder_ = NULL; |
2418 } | 1781 } |
2419 if (library_node != NULL && library_node->IsLibrary()) { | |
2420 Library* library = Library::Cast(library_node); | |
2421 streaming_flow_graph_builder_ = new StreamingFlowGraphBuilder( | |
2422 this, library->kernel_data(), library->kernel_data_size()); | |
2423 } | |
2424 | 1782 |
2425 dart::Class& klass = | 1783 Script& script = Script::Handle(Z, function.script()); |
2426 dart::Class::Handle(zone_, parsed_function_->function().Owner()); | 1784 streaming_flow_graph_builder_ = new StreamingFlowGraphBuilder( |
1785 this, script.kernel_data(), script.kernel_data_size()); | |
2427 | 1786 |
2428 Function& outermost_function = Function::Handle(Z); | 1787 return streaming_flow_graph_builder_->BuildGraph(kernel_offset_); |
2429 TreeNode* outermost_node = NULL; | |
2430 Class* kernel_class = NULL; | |
2431 DiscoverEnclosingElements(Z, function, &outermost_function, &outermost_node, | |
2432 &kernel_class); | |
2433 | |
2434 // Mark that we are using [klass]/[kernell_klass] as active class. Resolving | |
2435 // of type parameters will get resolved via [kernell_klass] unless we are | |
2436 // nested inside a static factory in which case we will use [member]. | |
2437 ActiveClassScope active_class_scope(&active_class_, kernel_class, &klass); | |
2438 Member* member = ((outermost_node != NULL) && outermost_node->IsMember()) | |
2439 ? Member::Cast(outermost_node) | |
2440 : NULL; | |
2441 ActiveMemberScope active_member(&active_class_, member); | |
2442 | |
2443 // The IR builder will create its own local variables and scopes, and it | |
2444 // will not need an AST. The code generator will assume that there is a | |
2445 // local variable stack slot allocated for the current context and (I | |
2446 // think) that the runtime will expect it to be at a fixed offset which | |
2447 // requires allocating an unused expression temporary variable. | |
2448 scopes_ = parsed_function_->EnsureKernelScopes(); | |
2449 | |
2450 switch (function.kind()) { | |
2451 case RawFunction::kClosureFunction: | |
2452 case RawFunction::kRegularFunction: | |
2453 case RawFunction::kGetterFunction: | |
2454 case RawFunction::kSetterFunction: { | |
2455 FunctionNode* kernel_function = node_->IsProcedure() | |
2456 ? Procedure::Cast(node_)->function() | |
2457 : FunctionNode::Cast(node_); | |
2458 return function.IsImplicitClosureFunction() | |
2459 ? BuildGraphOfImplicitClosureFunction(kernel_function, | |
2460 function) | |
2461 : BuildGraphOfFunction(kernel_function); | |
2462 } | |
2463 case RawFunction::kConstructor: { | |
2464 bool is_factory = function.IsFactory(); | |
2465 if (is_factory) { | |
2466 Procedure* procedure = Procedure::Cast(node_); | |
2467 FunctionNode* function = procedure->function(); | |
2468 return BuildGraphOfFunction(function, NULL); | |
2469 } else { | |
2470 Constructor* constructor = Constructor::Cast(node_); | |
2471 FunctionNode* function = constructor->function(); | |
2472 return BuildGraphOfFunction(function, constructor); | |
2473 } | |
2474 } | |
2475 case RawFunction::kImplicitGetter: | |
2476 case RawFunction::kImplicitStaticFinalGetter: | |
2477 case RawFunction::kImplicitSetter: { | |
2478 Field* field = Field::Cast(node_); | |
2479 return IsStaticInitializer(function, Z) | |
2480 ? BuildGraphOfStaticFieldInitializer(field) | |
2481 : BuildGraphOfFieldAccessor(field, scopes_->setter_value); | |
2482 } | |
2483 case RawFunction::kMethodExtractor: | |
2484 return BuildGraphOfMethodExtractor(function); | |
2485 case RawFunction::kNoSuchMethodDispatcher: | |
2486 return BuildGraphOfNoSuchMethodDispatcher(function); | |
2487 case RawFunction::kInvokeFieldDispatcher: | |
2488 return BuildGraphOfInvokeFieldDispatcher(function); | |
2489 case RawFunction::kSignatureFunction: | |
2490 case RawFunction::kIrregexpFunction: | |
2491 break; | |
2492 } | |
2493 UNREACHABLE(); | |
2494 return NULL; | |
2495 } | 1788 } |
2496 | 1789 |
2497 | 1790 |
2498 FlowGraph* FlowGraphBuilder::BuildGraphOfFunction(FunctionNode* function, | 1791 Fragment FlowGraphBuilder::NativeFunctionBody(intptr_t first_positional_offset, |
2499 Constructor* constructor) { | |
2500 const Function& dart_function = parsed_function_->function(); | |
2501 TargetEntryInstr* normal_entry = BuildTargetEntry(); | |
2502 graph_entry_ = | |
2503 new (Z) GraphEntryInstr(*parsed_function_, normal_entry, osr_id_); | |
2504 | |
2505 SetupDefaultParameterValues(function); | |
2506 | |
2507 Fragment body; | |
2508 if (!dart_function.is_native()) body += CheckStackOverflowInPrologue(); | |
2509 intptr_t context_size = | |
2510 parsed_function_->node_sequence()->scope()->num_context_variables(); | |
2511 if (context_size > 0) { | |
2512 body += PushContext(context_size); | |
2513 LocalVariable* context = MakeTemporary(); | |
2514 | |
2515 // Copy captured parameters from the stack into the context. | |
2516 LocalScope* scope = parsed_function_->node_sequence()->scope(); | |
2517 intptr_t parameter_count = dart_function.NumParameters(); | |
2518 intptr_t parameter_index = parsed_function_->first_parameter_index(); | |
2519 for (intptr_t i = 0; i < parameter_count; ++i, --parameter_index) { | |
2520 LocalVariable* variable = scope->VariableAt(i); | |
2521 if (variable->is_captured()) { | |
2522 // There is no LocalVariable describing the on-stack parameter so | |
2523 // create one directly and use the same type. | |
2524 LocalVariable* parameter = new (Z) | |
2525 LocalVariable(TokenPosition::kNoSource, TokenPosition::kNoSource, | |
2526 Symbols::TempParam(), variable->type()); | |
2527 parameter->set_index(parameter_index); | |
2528 // Mark the stack variable so it will be ignored by the code for | |
2529 // try/catch. | |
2530 parameter->set_is_captured_parameter(true); | |
2531 | |
2532 // Copy the parameter from the stack to the context. Overwrite it | |
2533 // with a null constant on the stack so the original value is | |
2534 // eligible for garbage collection. | |
2535 body += LoadLocal(context); | |
2536 body += LoadLocal(parameter); | |
2537 body += StoreInstanceField(TokenPosition::kNoSource, | |
2538 Context::variable_offset(variable->index())); | |
2539 body += NullConstant(); | |
2540 body += StoreLocal(TokenPosition::kNoSource, parameter); | |
2541 body += Drop(); | |
2542 } | |
2543 } | |
2544 body += Drop(); // The context. | |
2545 } | |
2546 if (constructor != NULL) { | |
2547 // TODO(27590): Currently the [VariableDeclaration]s from the | |
2548 // initializers will be visible inside the entire body of the constructor. | |
2549 // We should make a separate scope for them. | |
2550 Class* kernel_class = Class::Cast(constructor->parent()); | |
2551 body += TranslateInitializers(kernel_class, &constructor->initializers()); | |
2552 } | |
2553 | |
2554 // The specification defines the result of `a == b` to be: | |
2555 // | |
2556 // a) if either side is `null` then the result is `identical(a, b)`. | |
2557 // b) else the result is `a.operator==(b)` | |
2558 // | |
2559 // For user-defined implementations of `operator==` we need therefore | |
2560 // implement the handling of a). | |
2561 // | |
2562 // The default `operator==` implementation in `Object` is implemented in terms | |
2563 // of identical (which we assume here!) which means that case a) is actually | |
2564 // included in b). So we just use the normal implementation in the body. | |
2565 if ((dart_function.NumParameters() == 2) && | |
2566 (dart_function.name() == Symbols::EqualOperator().raw()) && | |
2567 (dart_function.Owner() != I->object_store()->object_class())) { | |
2568 LocalVariable* parameter = | |
2569 LookupVariable(function->positional_parameters()[0]); | |
2570 | |
2571 TargetEntryInstr* null_entry; | |
2572 TargetEntryInstr* non_null_entry; | |
2573 | |
2574 body += LoadLocal(parameter); | |
2575 body += BranchIfNull(&null_entry, &non_null_entry); | |
2576 | |
2577 // The argument was `null` and the receiver is not the null class (we only | |
2578 // go into this branch for user-defined == operators) so we can return | |
2579 // false. | |
2580 Fragment null_fragment(null_entry); | |
2581 null_fragment += Constant(Bool::False()); | |
2582 null_fragment += Return(dart_function.end_token_pos()); | |
2583 | |
2584 body = Fragment(body.entry, non_null_entry); | |
2585 } | |
2586 | |
2587 // If we run in checked mode, we have to check the type of the passed | |
2588 // arguments. | |
2589 if (I->type_checks()) { | |
2590 List<VariableDeclaration>& positional = function->positional_parameters(); | |
2591 List<VariableDeclaration>& named = function->named_parameters(); | |
2592 | |
2593 for (intptr_t i = 0; i < positional.length(); i++) { | |
2594 VariableDeclaration* variable = positional[i]; | |
2595 body += LoadLocal(LookupVariable(variable)); | |
2596 body += CheckVariableTypeInCheckedMode(variable); | |
2597 body += Drop(); | |
2598 } | |
2599 for (intptr_t i = 0; i < named.length(); i++) { | |
2600 VariableDeclaration* variable = named[i]; | |
2601 body += LoadLocal(LookupVariable(variable)); | |
2602 body += CheckVariableTypeInCheckedMode(variable); | |
2603 body += Drop(); | |
2604 } | |
2605 } | |
2606 | |
2607 if (FLAG_causal_async_stacks && | |
2608 (dart_function.IsAsyncFunction() || dart_function.IsAsyncGenerator())) { | |
2609 LocalScope* scope = parsed_function_->node_sequence()->scope(); | |
2610 // :async_stack_trace = _asyncStackTraceHelper(:async_op); | |
2611 const dart::Library& async_lib = | |
2612 dart::Library::Handle(dart::Library::AsyncLibrary()); | |
2613 const Function& target = Function::ZoneHandle( | |
2614 Z, | |
2615 async_lib.LookupFunctionAllowPrivate(Symbols::AsyncStackTraceHelper())); | |
2616 ASSERT(!target.IsNull()); | |
2617 | |
2618 // TODO(johnmccutchan): Why does this have the null value? | |
2619 LocalVariable* async_op = | |
2620 scope->child()->LookupVariable(Symbols::AsyncOperation(), false); | |
2621 ASSERT(async_op != NULL); | |
2622 ASSERT(async_op->is_captured()); | |
2623 body += LoadLocal(async_op); | |
2624 body += PushArgument(); | |
2625 body += StaticCall(TokenPosition::kNoSource, target, 1); | |
2626 LocalVariable* async_stack_trace_var = | |
2627 scope->LookupVariable(Symbols::AsyncStackTraceVar(), false); | |
2628 ASSERT(async_stack_trace_var != NULL); | |
2629 body += StoreLocal(TokenPosition::kNoSource, async_stack_trace_var); | |
2630 body += Drop(); | |
2631 } | |
2632 | |
2633 if (dart_function.is_native()) { | |
2634 body += NativeFunctionBody(function, dart_function); | |
2635 } else if (function->body() != NULL) { | |
2636 body += TranslateStatement(function->body()); | |
2637 } | |
2638 if (body.is_open()) { | |
2639 body += NullConstant(); | |
2640 body += Return(dart_function.end_token_pos()); | |
2641 } | |
2642 | |
2643 // If functions body contains any yield points build switch statement that | |
2644 // selects a continuation point based on the value of :await_jump_var. | |
2645 if (!yield_continuations_.is_empty()) { | |
2646 // The code we are building will be executed right after we enter | |
2647 // the function and before any nested contexts are allocated. | |
2648 // Reset current context_depth_ to match this. | |
2649 const intptr_t current_context_depth = context_depth_; | |
2650 context_depth_ = scopes_->yield_jump_variable->owner()->context_level(); | |
2651 | |
2652 // Prepend an entry corresponding to normal entry to the function. | |
2653 yield_continuations_.InsertAt( | |
2654 0, YieldContinuation(new (Z) DropTempsInstr(0, NULL), | |
2655 CatchClauseNode::kInvalidTryIndex)); | |
2656 yield_continuations_[0].entry->LinkTo(body.entry); | |
2657 | |
2658 // Build a switch statement. | |
2659 Fragment dispatch; | |
2660 | |
2661 // Load :await_jump_var into a temporary. | |
2662 dispatch += LoadLocal(scopes_->yield_jump_variable); | |
2663 dispatch += StoreLocal(TokenPosition::kNoSource, scopes_->switch_variable); | |
2664 dispatch += Drop(); | |
2665 | |
2666 BlockEntryInstr* block = NULL; | |
2667 for (intptr_t i = 0; i < yield_continuations_.length(); i++) { | |
2668 if (i == 1) { | |
2669 // This is not a normal entry but a resumption. Restore | |
2670 // :current_context_var from :await_ctx_var. | |
2671 // Note: after this point context_depth_ does not match current context | |
2672 // depth so we should not access any local variables anymore. | |
2673 dispatch += LoadLocal(scopes_->yield_context_variable); | |
2674 dispatch += StoreLocal(TokenPosition::kNoSource, | |
2675 parsed_function_->current_context_var()); | |
2676 dispatch += Drop(); | |
2677 } | |
2678 if (i == (yield_continuations_.length() - 1)) { | |
2679 // We reached the last possility, no need to build more ifs. | |
2680 // Continue to the last continuation. | |
2681 // Note: continuations start with nop DropTemps instruction | |
2682 // which acts like an anchor, so we need to skip it. | |
2683 block->set_try_index(yield_continuations_[i].try_index); | |
2684 dispatch <<= yield_continuations_[i].entry->next(); | |
2685 break; | |
2686 } | |
2687 | |
2688 // Build comparison: | |
2689 // | |
2690 // if (:await_ctx_var == i) { | |
2691 // -> yield_continuations_[i] | |
2692 // } else ... | |
2693 // | |
2694 TargetEntryInstr* then; | |
2695 TargetEntryInstr* otherwise; | |
2696 dispatch += LoadLocal(scopes_->switch_variable); | |
2697 dispatch += IntConstant(i); | |
2698 dispatch += BranchIfStrictEqual(&then, &otherwise); | |
2699 | |
2700 // True branch is linked to appropriate continuation point. | |
2701 // Note: continuations start with nop DropTemps instruction | |
2702 // which acts like an anchor, so we need to skip it. | |
2703 then->LinkTo(yield_continuations_[i].entry->next()); | |
2704 then->set_try_index(yield_continuations_[i].try_index); | |
2705 // False branch will contain the next comparison. | |
2706 dispatch = Fragment(dispatch.entry, otherwise); | |
2707 block = otherwise; | |
2708 } | |
2709 body = dispatch; | |
2710 | |
2711 context_depth_ = current_context_depth; | |
2712 } | |
2713 | |
2714 if (FLAG_causal_async_stacks && | |
2715 (dart_function.IsAsyncClosure() || dart_function.IsAsyncGenClosure())) { | |
2716 // The code we are building will be executed right after we enter | |
2717 // the function and before any nested contexts are allocated. | |
2718 // Reset current context_depth_ to match this. | |
2719 const intptr_t current_context_depth = context_depth_; | |
2720 context_depth_ = scopes_->yield_jump_variable->owner()->context_level(); | |
2721 | |
2722 Fragment instructions; | |
2723 LocalScope* scope = parsed_function_->node_sequence()->scope(); | |
2724 | |
2725 const Function& target = Function::ZoneHandle( | |
2726 Z, I->object_store()->async_set_thread_stack_trace()); | |
2727 ASSERT(!target.IsNull()); | |
2728 | |
2729 // Fetch and load :async_stack_trace | |
2730 LocalVariable* async_stack_trace_var = | |
2731 scope->LookupVariable(Symbols::AsyncStackTraceVar(), false); | |
2732 ASSERT((async_stack_trace_var != NULL) && | |
2733 async_stack_trace_var->is_captured()); | |
2734 instructions += LoadLocal(async_stack_trace_var); | |
2735 instructions += PushArgument(); | |
2736 | |
2737 // Call _asyncSetThreadStackTrace | |
2738 instructions += StaticCall(TokenPosition::kNoSource, target, 1); | |
2739 instructions += Drop(); | |
2740 | |
2741 body = instructions + body; | |
2742 context_depth_ = current_context_depth; | |
2743 } | |
2744 | |
2745 if (NeedsDebugStepCheck(dart_function, function->position())) { | |
2746 // If a switch was added above: Start the switch by injecting a debuggable | |
2747 // safepoint so stepping over an await works. | |
2748 // If not, still start the body with a debuggable safepoint to ensure | |
2749 // breaking on a method always happens, even if there are no | |
2750 // assignments/calls/runtimecalls in the first basic block. | |
2751 // Place this check at the last parameter to ensure parameters | |
2752 // are in scope in the debugger at method entry. | |
2753 const int num_params = dart_function.NumParameters(); | |
2754 TokenPosition check_pos = TokenPosition::kNoSource; | |
2755 if (num_params > 0) { | |
2756 LocalScope* scope = parsed_function_->node_sequence()->scope(); | |
2757 const LocalVariable& parameter = *scope->VariableAt(num_params - 1); | |
2758 check_pos = parameter.token_pos(); | |
2759 } | |
2760 if (!check_pos.IsDebugPause()) { | |
2761 // No parameters or synthetic parameters. | |
2762 check_pos = function->position(); | |
2763 ASSERT(check_pos.IsDebugPause()); | |
2764 } | |
2765 body = DebugStepCheck(check_pos) + body; | |
2766 } | |
2767 | |
2768 normal_entry->LinkTo(body.entry); | |
2769 | |
2770 // When compiling for OSR, use a depth first search to prune instructions | |
2771 // unreachable from the OSR entry. Catch entries are always considered | |
2772 // reachable, even if they become unreachable after OSR. | |
2773 if (osr_id_ != Compiler::kNoOSRDeoptId) { | |
2774 BitVector* block_marks = new (Z) BitVector(Z, next_block_id_); | |
2775 bool found = graph_entry_->PruneUnreachable(graph_entry_, NULL, osr_id_, | |
2776 block_marks); | |
2777 ASSERT(found); | |
2778 } | |
2779 return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1); | |
2780 } | |
2781 | |
2782 | |
2783 Fragment FlowGraphBuilder::NativeFunctionBody(FunctionNode* kernel_function, | |
2784 const Function& function) { | 1792 const Function& function) { |
2785 ASSERT(function.is_native()); | 1793 ASSERT(function.is_native()); |
2786 // We explicitly build the graph for native functions in the same way that the | 1794 // We explicitly build the graph for native functions in the same way that the |
2787 // from-source backend does. We should find a way to have a single component | 1795 // from-source backend does. We should find a way to have a single component |
2788 // to build these graphs so that this code is not duplicated. | 1796 // to build these graphs so that this code is not duplicated. |
2789 | 1797 |
2790 Fragment body; | 1798 Fragment body; |
2791 MethodRecognizer::Kind kind = MethodRecognizer::RecognizeKind(function); | 1799 MethodRecognizer::Kind kind = MethodRecognizer::RecognizeKind(function); |
2792 switch (kind) { | 1800 switch (kind) { |
2793 case MethodRecognizer::kObjectEquals: | 1801 case MethodRecognizer::kObjectEquals: |
2794 body += LoadLocal(scopes_->this_variable); | 1802 body += LoadLocal(scopes_->this_variable); |
2795 body += LoadLocal( | 1803 body += LoadLocal(LookupVariable(first_positional_offset)); |
2796 LookupVariable(kernel_function->positional_parameters()[0])); | |
2797 body += StrictCompare(Token::kEQ_STRICT); | 1804 body += StrictCompare(Token::kEQ_STRICT); |
2798 break; | 1805 break; |
2799 case MethodRecognizer::kStringBaseLength: | 1806 case MethodRecognizer::kStringBaseLength: |
2800 case MethodRecognizer::kStringBaseIsEmpty: | 1807 case MethodRecognizer::kStringBaseIsEmpty: |
2801 // Depending on FLAG_support_externalizable_strings, treat string length | 1808 // Depending on FLAG_support_externalizable_strings, treat string length |
2802 // loads as mutable so that the class check that precedes them will not be | 1809 // loads as mutable so that the class check that precedes them will not be |
2803 // hoisted. This is unsafe because string externalization can change the | 1810 // hoisted. This is unsafe because string externalization can change the |
2804 // class. | 1811 // class. |
2805 body += LoadLocal(scopes_->this_variable); | 1812 body += LoadLocal(scopes_->this_variable); |
2806 body += LoadNativeField(MethodRecognizer::kStringBaseLength, | 1813 body += LoadNativeField(MethodRecognizer::kStringBaseLength, |
(...skipping 17 matching lines...) Expand all Loading... | |
2824 LoadNativeField(kind, Array::length_offset(), | 1831 LoadNativeField(kind, Array::length_offset(), |
2825 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid, true); | 1832 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid, true); |
2826 break; | 1833 break; |
2827 case MethodRecognizer::kTypedDataLength: | 1834 case MethodRecognizer::kTypedDataLength: |
2828 body += LoadLocal(scopes_->this_variable); | 1835 body += LoadLocal(scopes_->this_variable); |
2829 body += | 1836 body += |
2830 LoadNativeField(kind, TypedData::length_offset(), | 1837 LoadNativeField(kind, TypedData::length_offset(), |
2831 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid, true); | 1838 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid, true); |
2832 break; | 1839 break; |
2833 case MethodRecognizer::kClassIDgetID: | 1840 case MethodRecognizer::kClassIDgetID: |
2834 body += LoadLocal( | 1841 body += LoadLocal(LookupVariable(first_positional_offset)); |
2835 LookupVariable(kernel_function->positional_parameters()[0])); | |
2836 body += LoadClassId(); | 1842 body += LoadClassId(); |
2837 break; | 1843 break; |
2838 case MethodRecognizer::kGrowableArrayCapacity: | 1844 case MethodRecognizer::kGrowableArrayCapacity: |
2839 body += LoadLocal(scopes_->this_variable); | 1845 body += LoadLocal(scopes_->this_variable); |
2840 body += LoadField(Array::data_offset(), kArrayCid); | 1846 body += LoadField(Array::data_offset(), kArrayCid); |
2841 body += LoadNativeField(MethodRecognizer::kObjectArrayLength, | 1847 body += LoadNativeField(MethodRecognizer::kObjectArrayLength, |
2842 Array::length_offset(), | 1848 Array::length_offset(), |
2843 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid); | 1849 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid); |
2844 break; | 1850 break; |
2845 case MethodRecognizer::kObjectArrayAllocate: | 1851 case MethodRecognizer::kObjectArrayAllocate: |
2846 body += LoadLocal(scopes_->type_arguments_variable); | 1852 body += LoadLocal(scopes_->type_arguments_variable); |
2847 body += LoadLocal( | 1853 body += LoadLocal(LookupVariable(first_positional_offset)); |
2848 LookupVariable(kernel_function->positional_parameters()[0])); | |
2849 body += CreateArray(); | 1854 body += CreateArray(); |
2850 break; | 1855 break; |
2851 case MethodRecognizer::kBigint_getDigits: | 1856 case MethodRecognizer::kBigint_getDigits: |
2852 body += LoadLocal(scopes_->this_variable); | 1857 body += LoadLocal(scopes_->this_variable); |
2853 body += LoadNativeField(kind, Bigint::digits_offset(), | 1858 body += LoadNativeField(kind, Bigint::digits_offset(), |
2854 Object::dynamic_type(), kTypedDataUint32ArrayCid); | 1859 Object::dynamic_type(), kTypedDataUint32ArrayCid); |
2855 break; | 1860 break; |
2856 case MethodRecognizer::kBigint_getUsed: | 1861 case MethodRecognizer::kBigint_getUsed: |
2857 body += LoadLocal(scopes_->this_variable); | 1862 body += LoadLocal(scopes_->this_variable); |
2858 body += LoadNativeField(kind, Bigint::used_offset(), | 1863 body += LoadNativeField(kind, Bigint::used_offset(), |
2859 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid); | 1864 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid); |
2860 break; | 1865 break; |
2861 case MethodRecognizer::kLinkedHashMap_getIndex: | 1866 case MethodRecognizer::kLinkedHashMap_getIndex: |
2862 body += LoadLocal(scopes_->this_variable); | 1867 body += LoadLocal(scopes_->this_variable); |
2863 body += LoadNativeField(kind, LinkedHashMap::index_offset(), | 1868 body += LoadNativeField(kind, LinkedHashMap::index_offset(), |
2864 Object::dynamic_type(), kDynamicCid); | 1869 Object::dynamic_type(), kDynamicCid); |
2865 break; | 1870 break; |
2866 case MethodRecognizer::kLinkedHashMap_setIndex: | 1871 case MethodRecognizer::kLinkedHashMap_setIndex: |
2867 body += LoadLocal(scopes_->this_variable); | 1872 body += LoadLocal(scopes_->this_variable); |
2868 body += LoadLocal( | 1873 body += LoadLocal(LookupVariable(first_positional_offset)); |
2869 LookupVariable(kernel_function->positional_parameters()[0])); | |
2870 body += StoreInstanceField(TokenPosition::kNoSource, | 1874 body += StoreInstanceField(TokenPosition::kNoSource, |
2871 LinkedHashMap::index_offset()); | 1875 LinkedHashMap::index_offset()); |
2872 body += NullConstant(); | 1876 body += NullConstant(); |
2873 break; | 1877 break; |
2874 case MethodRecognizer::kLinkedHashMap_getData: | 1878 case MethodRecognizer::kLinkedHashMap_getData: |
2875 body += LoadLocal(scopes_->this_variable); | 1879 body += LoadLocal(scopes_->this_variable); |
2876 body += LoadNativeField(kind, LinkedHashMap::data_offset(), | 1880 body += LoadNativeField(kind, LinkedHashMap::data_offset(), |
2877 Object::dynamic_type(), kArrayCid); | 1881 Object::dynamic_type(), kArrayCid); |
2878 break; | 1882 break; |
2879 case MethodRecognizer::kLinkedHashMap_setData: | 1883 case MethodRecognizer::kLinkedHashMap_setData: |
2880 body += LoadLocal(scopes_->this_variable); | 1884 body += LoadLocal(scopes_->this_variable); |
2881 body += LoadLocal( | 1885 body += LoadLocal(LookupVariable(first_positional_offset)); |
2882 LookupVariable(kernel_function->positional_parameters()[0])); | |
2883 body += StoreInstanceField(TokenPosition::kNoSource, | 1886 body += StoreInstanceField(TokenPosition::kNoSource, |
2884 LinkedHashMap::data_offset()); | 1887 LinkedHashMap::data_offset()); |
2885 body += NullConstant(); | 1888 body += NullConstant(); |
2886 break; | 1889 break; |
2887 case MethodRecognizer::kLinkedHashMap_getHashMask: | 1890 case MethodRecognizer::kLinkedHashMap_getHashMask: |
2888 body += LoadLocal(scopes_->this_variable); | 1891 body += LoadLocal(scopes_->this_variable); |
2889 body += LoadNativeField(kind, LinkedHashMap::hash_mask_offset(), | 1892 body += LoadNativeField(kind, LinkedHashMap::hash_mask_offset(), |
2890 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid); | 1893 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid); |
2891 break; | 1894 break; |
2892 case MethodRecognizer::kLinkedHashMap_setHashMask: | 1895 case MethodRecognizer::kLinkedHashMap_setHashMask: |
2893 body += LoadLocal(scopes_->this_variable); | 1896 body += LoadLocal(scopes_->this_variable); |
2894 body += LoadLocal( | 1897 body += LoadLocal(LookupVariable(first_positional_offset)); |
2895 LookupVariable(kernel_function->positional_parameters()[0])); | |
2896 body += StoreInstanceField(TokenPosition::kNoSource, | 1898 body += StoreInstanceField(TokenPosition::kNoSource, |
2897 LinkedHashMap::hash_mask_offset(), | 1899 LinkedHashMap::hash_mask_offset(), |
2898 kNoStoreBarrier); | 1900 kNoStoreBarrier); |
2899 body += NullConstant(); | 1901 body += NullConstant(); |
2900 break; | 1902 break; |
2901 case MethodRecognizer::kLinkedHashMap_getUsedData: | 1903 case MethodRecognizer::kLinkedHashMap_getUsedData: |
2902 body += LoadLocal(scopes_->this_variable); | 1904 body += LoadLocal(scopes_->this_variable); |
2903 body += LoadNativeField(kind, LinkedHashMap::used_data_offset(), | 1905 body += LoadNativeField(kind, LinkedHashMap::used_data_offset(), |
2904 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid); | 1906 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid); |
2905 break; | 1907 break; |
2906 case MethodRecognizer::kLinkedHashMap_setUsedData: | 1908 case MethodRecognizer::kLinkedHashMap_setUsedData: |
2907 body += LoadLocal(scopes_->this_variable); | 1909 body += LoadLocal(scopes_->this_variable); |
2908 body += LoadLocal( | 1910 body += LoadLocal(LookupVariable(first_positional_offset)); |
2909 LookupVariable(kernel_function->positional_parameters()[0])); | |
2910 body += StoreInstanceField(TokenPosition::kNoSource, | 1911 body += StoreInstanceField(TokenPosition::kNoSource, |
2911 LinkedHashMap::used_data_offset(), | 1912 LinkedHashMap::used_data_offset(), |
2912 kNoStoreBarrier); | 1913 kNoStoreBarrier); |
2913 body += NullConstant(); | 1914 body += NullConstant(); |
2914 break; | 1915 break; |
2915 case MethodRecognizer::kLinkedHashMap_getDeletedKeys: | 1916 case MethodRecognizer::kLinkedHashMap_getDeletedKeys: |
2916 body += LoadLocal(scopes_->this_variable); | 1917 body += LoadLocal(scopes_->this_variable); |
2917 body += LoadNativeField(kind, LinkedHashMap::deleted_keys_offset(), | 1918 body += LoadNativeField(kind, LinkedHashMap::deleted_keys_offset(), |
2918 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid); | 1919 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid); |
2919 break; | 1920 break; |
2920 case MethodRecognizer::kLinkedHashMap_setDeletedKeys: | 1921 case MethodRecognizer::kLinkedHashMap_setDeletedKeys: |
2921 body += LoadLocal(scopes_->this_variable); | 1922 body += LoadLocal(scopes_->this_variable); |
2922 body += LoadLocal( | 1923 body += LoadLocal(LookupVariable(first_positional_offset)); |
2923 LookupVariable(kernel_function->positional_parameters()[0])); | |
2924 body += StoreInstanceField(TokenPosition::kNoSource, | 1924 body += StoreInstanceField(TokenPosition::kNoSource, |
2925 LinkedHashMap::deleted_keys_offset(), | 1925 LinkedHashMap::deleted_keys_offset(), |
2926 kNoStoreBarrier); | 1926 kNoStoreBarrier); |
2927 body += NullConstant(); | 1927 body += NullConstant(); |
2928 break; | 1928 break; |
2929 case MethodRecognizer::kBigint_getNeg: | 1929 case MethodRecognizer::kBigint_getNeg: |
2930 body += LoadLocal(scopes_->this_variable); | 1930 body += LoadLocal(scopes_->this_variable); |
2931 body += LoadNativeField(kind, Bigint::neg_offset(), | 1931 body += LoadNativeField(kind, Bigint::neg_offset(), |
2932 Type::ZoneHandle(Z, Type::BoolType()), kBoolCid); | 1932 Type::ZoneHandle(Z, Type::BoolType()), kBoolCid); |
2933 break; | 1933 break; |
2934 default: { | 1934 default: { |
2935 dart::String& name = dart::String::ZoneHandle(Z, function.native_name()); | 1935 dart::String& name = dart::String::ZoneHandle(Z, function.native_name()); |
2936 body += NativeCall(&name, &function); | 1936 body += NativeCall(&name, &function); |
2937 break; | 1937 break; |
2938 } | 1938 } |
2939 } | 1939 } |
2940 return body + Return(TokenPosition::kNoSource); | 1940 return body + Return(TokenPosition::kNoSource); |
2941 } | 1941 } |
2942 | 1942 |
2943 | 1943 |
2944 FlowGraph* FlowGraphBuilder::BuildGraphOfFieldAccessor( | |
2945 Field* kernel_field, | |
2946 LocalVariable* setter_value) { | |
2947 const Function& function = parsed_function_->function(); | |
2948 | |
2949 bool is_setter = function.IsImplicitSetterFunction(); | |
2950 bool is_method = !function.IsStaticFunction(); | |
2951 dart::Field& field = dart::Field::ZoneHandle( | |
2952 Z, H.LookupFieldByKernelField(kernel_field->canonical_name())); | |
2953 | |
2954 TargetEntryInstr* normal_entry = BuildTargetEntry(); | |
2955 graph_entry_ = new (Z) | |
2956 GraphEntryInstr(*parsed_function_, normal_entry, Compiler::kNoOSRDeoptId); | |
2957 | |
2958 Fragment body(normal_entry); | |
2959 if (is_setter) { | |
2960 if (is_method) { | |
2961 body += LoadLocal(scopes_->this_variable); | |
2962 body += LoadLocal(setter_value); | |
2963 body += StoreInstanceFieldGuarded(field, false); | |
2964 } else { | |
2965 body += LoadLocal(setter_value); | |
2966 body += StoreStaticField(TokenPosition::kNoSource, field); | |
2967 } | |
2968 body += NullConstant(); | |
2969 } else if (is_method) { | |
2970 body += LoadLocal(scopes_->this_variable); | |
2971 body += LoadField(field); | |
2972 } else if (field.is_const()) { | |
2973 // If the parser needs to know the value of an uninitialized constant field | |
2974 // it will set the value to the transition sentinel (used to detect circular | |
2975 // initialization) and then call the implicit getter. Thus, the getter | |
2976 // cannot contain the InitStaticField instruction that normal static getters | |
2977 // contain because it would detect spurious circular initialization when it | |
2978 // checks for the transition sentinel. | |
2979 Expression* initializer = kernel_field->initializer(); | |
2980 ASSERT(initializer != NULL); | |
2981 body += Constant(constant_evaluator_.EvaluateExpression(initializer)); | |
2982 } else { | |
2983 // The field always has an initializer because static fields without | |
2984 // initializers are initialized eagerly and do not have implicit getters. | |
2985 ASSERT(field.has_initializer()); | |
2986 body += Constant(field); | |
2987 body += InitStaticField(field); | |
2988 body += Constant(field); | |
2989 body += LoadStaticField(); | |
2990 } | |
2991 body += Return(TokenPosition::kNoSource); | |
2992 | |
2993 return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1); | |
2994 } | |
2995 | |
2996 | |
2997 FlowGraph* FlowGraphBuilder::BuildGraphOfStaticFieldInitializer( | |
2998 Field* kernel_field) { | |
2999 ASSERT(kernel_field->IsStatic()); | |
3000 | |
3001 Expression* initializer = kernel_field->initializer(); | |
3002 | |
3003 TargetEntryInstr* normal_entry = BuildTargetEntry(); | |
3004 graph_entry_ = new (Z) | |
3005 GraphEntryInstr(*parsed_function_, normal_entry, Compiler::kNoOSRDeoptId); | |
3006 | |
3007 Fragment body(normal_entry); | |
3008 body += CheckStackOverflowInPrologue(); | |
3009 if (kernel_field->IsConst()) { | |
3010 body += Constant(constant_evaluator_.EvaluateExpression(initializer)); | |
3011 } else { | |
3012 body += TranslateExpression(initializer); | |
3013 } | |
3014 body += Return(TokenPosition::kNoSource); | |
3015 | |
3016 return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1); | |
3017 } | |
3018 | |
3019 | |
3020 Fragment FlowGraphBuilder::BuildImplicitClosureCreation( | 1944 Fragment FlowGraphBuilder::BuildImplicitClosureCreation( |
3021 const Function& target) { | 1945 const Function& target) { |
3022 Fragment fragment; | 1946 Fragment fragment; |
3023 const dart::Class& closure_class = | 1947 const dart::Class& closure_class = |
3024 dart::Class::ZoneHandle(Z, I->object_store()->closure_class()); | 1948 dart::Class::ZoneHandle(Z, I->object_store()->closure_class()); |
3025 fragment += AllocateObject(closure_class, target); | 1949 fragment += AllocateObject(closure_class, target); |
3026 LocalVariable* closure = MakeTemporary(); | 1950 LocalVariable* closure = MakeTemporary(); |
3027 | 1951 |
3028 // Allocate a context that closes over `this`. | 1952 // Allocate a context that closes over `this`. |
3029 fragment += AllocateContext(1); | 1953 fragment += AllocateContext(1); |
(...skipping 27 matching lines...) Expand all Loading... | |
3057 } | 1981 } |
3058 | 1982 |
3059 | 1983 |
3060 Fragment FlowGraphBuilder::GuardFieldClass(const dart::Field& field, | 1984 Fragment FlowGraphBuilder::GuardFieldClass(const dart::Field& field, |
3061 intptr_t deopt_id) { | 1985 intptr_t deopt_id) { |
3062 return Fragment(new (Z) GuardFieldClassInstr(Pop(), field, deopt_id)); | 1986 return Fragment(new (Z) GuardFieldClassInstr(Pop(), field, deopt_id)); |
3063 } | 1987 } |
3064 | 1988 |
3065 | 1989 |
3066 Fragment FlowGraphBuilder::CheckVariableTypeInCheckedMode( | 1990 Fragment FlowGraphBuilder::CheckVariableTypeInCheckedMode( |
3067 VariableDeclaration* variable) { | |
3068 if (I->type_checks()) { | |
3069 const AbstractType& dst_type = T.TranslateType(variable->type()); | |
3070 if (dst_type.IsMalformed()) { | |
3071 return ThrowTypeError(); | |
3072 } | |
3073 return CheckAssignableInCheckedMode(dst_type, | |
3074 H.DartSymbol(variable->name())); | |
3075 } | |
3076 return Fragment(); | |
3077 } | |
3078 | |
3079 Fragment FlowGraphBuilder::CheckVariableTypeInCheckedMode( | |
3080 const AbstractType& dst_type, | 1991 const AbstractType& dst_type, |
3081 const dart::String& name_symbol) { | 1992 const dart::String& name_symbol) { |
3082 if (I->type_checks()) { | 1993 if (I->type_checks()) { |
3083 if (dst_type.IsMalformed()) { | 1994 if (dst_type.IsMalformed()) { |
3084 return ThrowTypeError(); | 1995 return ThrowTypeError(); |
3085 } | 1996 } |
3086 return CheckAssignableInCheckedMode(dst_type, name_symbol); | 1997 return CheckAssignableInCheckedMode(dst_type, name_symbol); |
3087 } | 1998 } |
3088 return Fragment(); | 1999 return Fragment(); |
3089 } | 2000 } |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3213 GraphEntryInstr(*parsed_function_, normal_entry, Compiler::kNoOSRDeoptId); | 2124 GraphEntryInstr(*parsed_function_, normal_entry, Compiler::kNoOSRDeoptId); |
3214 Fragment body(normal_entry); | 2125 Fragment body(normal_entry); |
3215 body += CheckStackOverflowInPrologue(); | 2126 body += CheckStackOverflowInPrologue(); |
3216 body += BuildImplicitClosureCreation(function); | 2127 body += BuildImplicitClosureCreation(function); |
3217 body += Return(TokenPosition::kNoSource); | 2128 body += Return(TokenPosition::kNoSource); |
3218 | 2129 |
3219 return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1); | 2130 return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1); |
3220 } | 2131 } |
3221 | 2132 |
3222 | 2133 |
3223 FlowGraph* FlowGraphBuilder::BuildGraphOfImplicitClosureFunction( | |
3224 FunctionNode* kernel_function, | |
3225 const Function& function) { | |
3226 const Function& target = Function::ZoneHandle(Z, function.parent_function()); | |
3227 | |
3228 TargetEntryInstr* normal_entry = BuildTargetEntry(); | |
3229 graph_entry_ = new (Z) | |
3230 GraphEntryInstr(*parsed_function_, normal_entry, Compiler::kNoOSRDeoptId); | |
3231 SetupDefaultParameterValues(kernel_function); | |
3232 | |
3233 Fragment body(normal_entry); | |
3234 body += CheckStackOverflowInPrologue(); | |
3235 | |
3236 // Load all the arguments. | |
3237 if (!target.is_static()) { | |
3238 // The context has a fixed shape: a single variable which is the | |
3239 // closed-over receiver. | |
3240 body += LoadLocal(parsed_function_->current_context_var()); | |
3241 body += LoadField(Context::variable_offset(0)); | |
3242 body += PushArgument(); | |
3243 } | |
3244 intptr_t positional_argument_count = | |
3245 kernel_function->positional_parameters().length(); | |
3246 for (intptr_t i = 0; i < positional_argument_count; i++) { | |
3247 body += | |
3248 LoadLocal(LookupVariable(kernel_function->positional_parameters()[i])); | |
3249 body += PushArgument(); | |
3250 } | |
3251 intptr_t named_argument_count = kernel_function->named_parameters().length(); | |
3252 Array& argument_names = Array::ZoneHandle(Z); | |
3253 if (named_argument_count > 0) { | |
3254 argument_names = Array::New(named_argument_count); | |
3255 for (intptr_t i = 0; i < named_argument_count; i++) { | |
3256 VariableDeclaration* variable = kernel_function->named_parameters()[i]; | |
3257 body += LoadLocal(LookupVariable(variable)); | |
3258 body += PushArgument(); | |
3259 argument_names.SetAt(i, H.DartSymbol(variable->name())); | |
3260 } | |
3261 } | |
3262 // Forward them to the target. | |
3263 intptr_t argument_count = positional_argument_count + named_argument_count; | |
3264 if (!target.is_static()) ++argument_count; | |
3265 body += StaticCall(TokenPosition::kNoSource, target, argument_count, | |
3266 argument_names); | |
3267 | |
3268 // Return the result. | |
3269 body += Return(kernel_function->end_position()); | |
3270 | |
3271 return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1); | |
3272 } | |
3273 | |
3274 | |
3275 FlowGraph* FlowGraphBuilder::BuildGraphOfNoSuchMethodDispatcher( | 2134 FlowGraph* FlowGraphBuilder::BuildGraphOfNoSuchMethodDispatcher( |
3276 const Function& function) { | 2135 const Function& function) { |
3277 // This function is specialized for a receiver class, a method name, and | 2136 // This function is specialized for a receiver class, a method name, and |
3278 // the arguments descriptor at a call site. | 2137 // the arguments descriptor at a call site. |
3279 | 2138 |
3280 TargetEntryInstr* normal_entry = BuildTargetEntry(); | 2139 TargetEntryInstr* normal_entry = BuildTargetEntry(); |
3281 graph_entry_ = new (Z) | 2140 graph_entry_ = new (Z) |
3282 GraphEntryInstr(*parsed_function_, normal_entry, Compiler::kNoOSRDeoptId); | 2141 GraphEntryInstr(*parsed_function_, normal_entry, Compiler::kNoOSRDeoptId); |
3283 | 2142 |
3284 // The backend will expect an array of default values for all the named | 2143 // The backend will expect an array of default values for all the named |
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3453 body += InstanceCall(TokenPosition::kMinSource, Symbols::Call(), | 2312 body += InstanceCall(TokenPosition::kMinSource, Symbols::Call(), |
3454 Token::kILLEGAL, descriptor.Count(), argument_names); | 2313 Token::kILLEGAL, descriptor.Count(), argument_names); |
3455 } | 2314 } |
3456 | 2315 |
3457 body += Return(TokenPosition::kNoSource); | 2316 body += Return(TokenPosition::kNoSource); |
3458 | 2317 |
3459 return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1); | 2318 return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1); |
3460 } | 2319 } |
3461 | 2320 |
3462 | 2321 |
3463 void FlowGraphBuilder::SetupDefaultParameterValues(FunctionNode* function) { | |
3464 intptr_t num_optional_parameters = | |
3465 parsed_function_->function().NumOptionalParameters(); | |
3466 if (num_optional_parameters > 0) { | |
3467 ZoneGrowableArray<const Instance*>* default_values = | |
3468 new ZoneGrowableArray<const Instance*>(Z, num_optional_parameters); | |
3469 | |
3470 if (parsed_function_->function().HasOptionalNamedParameters()) { | |
3471 ASSERT(!parsed_function_->function().HasOptionalPositionalParameters()); | |
3472 for (intptr_t i = 0; i < num_optional_parameters; i++) { | |
3473 VariableDeclaration* variable = function->named_parameters()[i]; | |
3474 Instance* default_value; | |
3475 if (variable->initializer() != NULL) { | |
3476 default_value = | |
3477 &constant_evaluator_.EvaluateExpression(variable->initializer()); | |
3478 } else { | |
3479 default_value = &Instance::ZoneHandle(Z, Instance::null()); | |
3480 } | |
3481 default_values->Add(default_value); | |
3482 } | |
3483 } else { | |
3484 ASSERT(parsed_function_->function().HasOptionalPositionalParameters()); | |
3485 intptr_t required = function->required_parameter_count(); | |
3486 for (intptr_t i = 0; i < num_optional_parameters; i++) { | |
3487 VariableDeclaration* variable = | |
3488 function->positional_parameters()[required + i]; | |
3489 Instance* default_value; | |
3490 if (variable->initializer() != NULL) { | |
3491 default_value = | |
3492 &constant_evaluator_.EvaluateExpression(variable->initializer()); | |
3493 } else { | |
3494 default_value = &Instance::ZoneHandle(Z, Instance::null()); | |
3495 } | |
3496 default_values->Add(default_value); | |
3497 } | |
3498 } | |
3499 parsed_function_->set_default_parameter_values(default_values); | |
3500 } | |
3501 } | |
3502 | |
3503 | |
3504 TargetEntryInstr* FlowGraphBuilder::BuildTargetEntry() { | 2322 TargetEntryInstr* FlowGraphBuilder::BuildTargetEntry() { |
3505 return new (Z) TargetEntryInstr(AllocateBlockId(), CurrentTryIndex()); | 2323 return new (Z) TargetEntryInstr(AllocateBlockId(), CurrentTryIndex()); |
3506 } | 2324 } |
3507 | 2325 |
3508 | 2326 |
3509 JoinEntryInstr* FlowGraphBuilder::BuildJoinEntry(intptr_t try_index) { | 2327 JoinEntryInstr* FlowGraphBuilder::BuildJoinEntry(intptr_t try_index) { |
3510 return new (Z) JoinEntryInstr(AllocateBlockId(), try_index); | 2328 return new (Z) JoinEntryInstr(AllocateBlockId(), try_index); |
3511 } | 2329 } |
3512 | 2330 |
3513 | 2331 |
3514 JoinEntryInstr* FlowGraphBuilder::BuildJoinEntry() { | 2332 JoinEntryInstr* FlowGraphBuilder::BuildJoinEntry() { |
3515 return new (Z) JoinEntryInstr(AllocateBlockId(), CurrentTryIndex()); | 2333 return new (Z) JoinEntryInstr(AllocateBlockId(), CurrentTryIndex()); |
3516 } | 2334 } |
3517 | 2335 |
3518 | |
3519 Fragment FlowGraphBuilder::TranslateFieldInitializer(NameIndex canonical_name, | |
3520 Expression* init) { | |
3521 dart::Field& field = | |
3522 dart::Field::ZoneHandle(Z, H.LookupFieldByKernelField(canonical_name)); | |
3523 if (init->IsNullLiteral()) { | |
3524 field.RecordStore(Object::null_object()); | |
3525 return Fragment(); | |
3526 } | |
3527 Fragment instructions; | |
3528 instructions += LoadLocal(scopes_->this_variable); | |
3529 instructions += TranslateExpression(init); | |
3530 instructions += StoreInstanceFieldGuarded(field, true); | |
3531 return instructions; | |
3532 } | |
3533 | |
3534 | |
3535 Fragment FlowGraphBuilder::TranslateInitializers( | |
3536 Class* kernel_class, | |
3537 List<Initializer>* initializers) { | |
3538 Fragment instructions; | |
3539 | |
3540 // These come from: | |
3541 // class A { | |
3542 // var x = (expr); | |
3543 // } | |
3544 for (intptr_t i = 0; i < kernel_class->fields().length(); i++) { | |
3545 Field* kernel_field = kernel_class->fields()[i]; | |
3546 Expression* init = kernel_field->initializer(); | |
3547 if (!kernel_field->IsStatic() && init != NULL) { | |
3548 EnterScope(kernel_field); | |
3549 instructions += | |
3550 TranslateFieldInitializer(kernel_field->canonical_name(), init); | |
3551 ExitScope(kernel_field); | |
3552 } | |
3553 } | |
3554 | |
3555 // These to come from: | |
3556 // class A { | |
3557 // var x; | |
3558 // var y; | |
3559 // A(this.x) : super(expr), y = (expr); | |
3560 // } | |
3561 for (intptr_t i = 0; i < initializers->length(); i++) { | |
3562 Initializer* initializer = (*initializers)[i]; | |
3563 if (initializer->IsFieldInitializer()) { | |
3564 FieldInitializer* init = FieldInitializer::Cast(initializer); | |
3565 instructions += TranslateFieldInitializer(init->field(), init->value()); | |
3566 } else if (initializer->IsSuperInitializer()) { | |
3567 SuperInitializer* init = SuperInitializer::Cast(initializer); | |
3568 | |
3569 instructions += LoadLocal(scopes_->this_variable); | |
3570 instructions += PushArgument(); | |
3571 | |
3572 ASSERT(init->arguments()->types().length() == 0); | |
3573 Array& argument_names = Array::ZoneHandle(Z); | |
3574 instructions += TranslateArguments(init->arguments(), &argument_names); | |
3575 | |
3576 const Function& target = Function::ZoneHandle( | |
3577 Z, H.LookupConstructorByKernelConstructor(init->target())); | |
3578 intptr_t argument_count = init->arguments()->count() + 1; | |
3579 instructions += StaticCall(TokenPosition::kNoSource, target, | |
3580 argument_count, argument_names); | |
3581 instructions += Drop(); | |
3582 } else if (initializer->IsRedirectingInitializer()) { | |
3583 RedirectingInitializer* init = RedirectingInitializer::Cast(initializer); | |
3584 | |
3585 instructions += LoadLocal(scopes_->this_variable); | |
3586 instructions += PushArgument(); | |
3587 | |
3588 ASSERT(init->arguments()->types().length() == 0); | |
3589 Array& argument_names = Array::ZoneHandle(Z); | |
3590 instructions += TranslateArguments(init->arguments(), &argument_names); | |
3591 | |
3592 const Function& target = Function::ZoneHandle( | |
3593 Z, H.LookupConstructorByKernelConstructor(init->target())); | |
3594 intptr_t argument_count = init->arguments()->count() + 1; | |
3595 instructions += StaticCall(TokenPosition::kNoSource, target, | |
3596 argument_count, argument_names); | |
3597 instructions += Drop(); | |
3598 } else if (initializer->IsLocalInitializer()) { | |
3599 // The other initializers following this one might read the variable. This | |
3600 // is used e.g. for evaluating the arguments to a super call first, run | |
3601 // normal field initializers next and then make the actual super call: | |
3602 // | |
3603 // The frontend converts | |
3604 // | |
3605 // class A { | |
3606 // var x; | |
3607 // A(a, b) : super(a + b), x = 2*b {} | |
3608 // } | |
3609 // | |
3610 // to | |
3611 // | |
3612 // class A { | |
3613 // var x; | |
3614 // A(a, b) : tmp = a + b, x = 2*b, super(tmp) {} | |
3615 // } | |
3616 // | |
3617 // (This is strictly speaking not what one should do in terms of the | |
3618 // specification but that is how it is currently implemented.) | |
3619 LocalInitializer* init = LocalInitializer::Cast(initializer); | |
3620 | |
3621 VariableDeclaration* declaration = init->variable(); | |
3622 LocalVariable* variable = LookupVariable(declaration); | |
3623 Expression* initializer = init->variable()->initializer(); | |
3624 ASSERT(initializer != NULL); | |
3625 ASSERT(!declaration->IsConst()); | |
3626 | |
3627 instructions += TranslateExpression(initializer); | |
3628 instructions += StoreLocal(TokenPosition::kNoSource, variable); | |
3629 instructions += Drop(); | |
3630 | |
3631 fragment_ = instructions; | |
3632 } else { | |
3633 UNIMPLEMENTED(); | |
3634 } | |
3635 } | |
3636 return instructions; | |
3637 } | |
3638 | |
3639 | |
3640 Fragment FlowGraphBuilder::TranslateStatement(Statement* statement) { | |
3641 #ifdef DEBUG | |
3642 intptr_t original_context_depth = context_depth_; | |
3643 #endif | |
3644 | |
3645 // TODO(jensj): VariableDeclaration doesn't necessarily have a tag. | |
3646 if (statement->can_stream() && | |
3647 statement->Type() != Node::kTypeVariableDeclaration) { | |
3648 fragment_ = streaming_flow_graph_builder_->BuildStatementAt( | |
3649 statement->kernel_offset()); | |
3650 } else { | |
3651 statement->AcceptStatementVisitor(this); | |
3652 } | |
3653 DEBUG_ASSERT(context_depth_ == original_context_depth); | |
3654 return fragment_; | |
3655 } | |
3656 | |
3657 | |
3658 Fragment FlowGraphBuilder::TranslateCondition(Expression* expression, | |
3659 bool* negate) { | |
3660 *negate = expression->IsNot(); | |
3661 Fragment instructions; | |
3662 if (*negate) { | |
3663 instructions += TranslateExpression(Not::Cast(expression)->expression()); | |
3664 } else { | |
3665 instructions += TranslateExpression(expression); | |
3666 } | |
3667 instructions += CheckBooleanInCheckedMode(); | |
3668 return instructions; | |
3669 } | |
3670 | |
3671 | |
3672 Fragment FlowGraphBuilder::TranslateExpression(Expression* expression) { | |
3673 if (expression->can_stream()) { | |
3674 fragment_ = streaming_flow_graph_builder_->BuildExpressionAt( | |
3675 expression->kernel_offset()); | |
3676 } else { | |
3677 expression->AcceptExpressionVisitor(this); | |
3678 } | |
3679 return fragment_; | |
3680 } | |
3681 | |
3682 | |
3683 ArgumentArray FlowGraphBuilder::GetArguments(int count) { | 2336 ArgumentArray FlowGraphBuilder::GetArguments(int count) { |
3684 ArgumentArray arguments = | 2337 ArgumentArray arguments = |
3685 new (Z) ZoneGrowableArray<PushArgumentInstr*>(Z, count); | 2338 new (Z) ZoneGrowableArray<PushArgumentInstr*>(Z, count); |
3686 arguments->SetLength(count); | 2339 arguments->SetLength(count); |
3687 for (intptr_t i = count - 1; i >= 0; --i) { | 2340 for (intptr_t i = count - 1; i >= 0; --i) { |
3688 ASSERT(stack_->definition()->IsPushArgument()); | 2341 ASSERT(stack_->definition()->IsPushArgument()); |
3689 ASSERT(!stack_->definition()->HasSSATemp()); | 2342 ASSERT(!stack_->definition()->HasSSATemp()); |
3690 arguments->data()[i] = stack_->definition()->AsPushArgument(); | 2343 arguments->data()[i] = stack_->definition()->AsPushArgument(); |
3691 Drop(); | 2344 Drop(); |
3692 } | 2345 } |
3693 pending_argument_count_ -= count; | 2346 pending_argument_count_ -= count; |
3694 ASSERT(pending_argument_count_ >= 0); | 2347 ASSERT(pending_argument_count_ >= 0); |
3695 return arguments; | 2348 return arguments; |
3696 } | 2349 } |
3697 | 2350 |
3698 | 2351 |
3699 #define STREAM_EXPRESSION_IF_POSSIBLE(node) \ | 2352 #define STREAM_EXPRESSION_IF_POSSIBLE(node) \ |
3700 if (node->can_stream()) { \ | 2353 if (node->can_stream()) { \ |
3701 fragment_ = streaming_flow_graph_builder_->BuildExpressionAt( \ | 2354 fragment_ = streaming_flow_graph_builder_->BuildExpressionAt( \ |
3702 node->kernel_offset()); \ | 2355 node->kernel_offset()); \ |
3703 return; \ | 2356 return; \ |
3704 } | 2357 } |
3705 | 2358 |
3706 | 2359 |
3707 void FlowGraphBuilder::VisitInvalidExpression(InvalidExpression* node) { | |
3708 fragment_ = | |
3709 streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset()); | |
3710 } | |
3711 | |
3712 | |
3713 void FlowGraphBuilder::VisitNullLiteral(NullLiteral* node) { | |
3714 fragment_ = | |
3715 streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset()); | |
3716 } | |
3717 | |
3718 | |
3719 void FlowGraphBuilder::VisitBoolLiteral(BoolLiteral* node) { | |
3720 fragment_ = | |
3721 streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset()); | |
3722 } | |
3723 | |
3724 | |
3725 void FlowGraphBuilder::VisitIntLiteral(IntLiteral* node) { | |
3726 fragment_ = | |
3727 streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset()); | |
3728 } | |
3729 | |
3730 | |
3731 void FlowGraphBuilder::VisitBigintLiteral(BigintLiteral* node) { | |
3732 fragment_ = | |
3733 streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset()); | |
3734 } | |
3735 | |
3736 | |
3737 void FlowGraphBuilder::VisitDoubleLiteral(DoubleLiteral* node) { | |
3738 fragment_ = | |
3739 streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset()); | |
3740 } | |
3741 | |
3742 | |
3743 void FlowGraphBuilder::VisitStringLiteral(StringLiteral* node) { | |
3744 fragment_ = | |
3745 streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset()); | |
3746 } | |
3747 | |
3748 | |
3749 void FlowGraphBuilder::VisitSymbolLiteral(SymbolLiteral* node) { | |
3750 fragment_ = | |
3751 streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset()); | |
3752 } | |
3753 | |
3754 | |
3755 AbstractType& DartTypeTranslator::TranslateType(DartType* node) { | 2360 AbstractType& DartTypeTranslator::TranslateType(DartType* node) { |
3756 node->AcceptDartTypeVisitor(this); | 2361 node->AcceptDartTypeVisitor(this); |
3757 | 2362 |
3758 // We return a new `ZoneHandle` here on purpose: The intermediate language | 2363 // We return a new `ZoneHandle` here on purpose: The intermediate language |
3759 // instructions do not make a copy of the handle, so we do it. | 2364 // instructions do not make a copy of the handle, so we do it. |
3760 return AbstractType::ZoneHandle(Z, result_.raw()); | 2365 return AbstractType::ZoneHandle(Z, result_.raw()); |
3761 } | 2366 } |
3762 | 2367 |
3763 | 2368 |
3764 AbstractType& DartTypeTranslator::TranslateTypeWithoutFinalization( | 2369 AbstractType& DartTypeTranslator::TranslateTypeWithoutFinalization( |
(...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4044 } | 2649 } |
4045 type = Type::New(klass, TypeArguments::Handle(Z, klass.type_parameters()), | 2650 type = Type::New(klass, TypeArguments::Handle(Z, klass.type_parameters()), |
4046 klass.token_pos()); | 2651 klass.token_pos()); |
4047 if (klass.is_type_finalized()) { | 2652 if (klass.is_type_finalized()) { |
4048 type ^= ClassFinalizer::FinalizeType(klass, type); | 2653 type ^= ClassFinalizer::FinalizeType(klass, type); |
4049 klass.SetCanonicalType(type); | 2654 klass.SetCanonicalType(type); |
4050 } | 2655 } |
4051 return type; | 2656 return type; |
4052 } | 2657 } |
4053 | 2658 |
4054 void FlowGraphBuilder::VisitTypeLiteral(TypeLiteral* node) { | |
4055 STREAM_EXPRESSION_IF_POSSIBLE(node); | |
4056 | |
4057 const AbstractType& type = T.TranslateType(node->type()); | |
4058 if (type.IsMalformed()) H.ReportError("Malformed type literal"); | |
4059 | |
4060 Fragment instructions; | |
4061 if (type.IsInstantiated()) { | |
4062 instructions += Constant(type); | |
4063 } else { | |
4064 if (!type.IsInstantiated(kCurrentClass)) { | |
4065 instructions += LoadInstantiatorTypeArguments(); | |
4066 } else { | |
4067 instructions += NullConstant(); | |
4068 } | |
4069 if (!type.IsInstantiated(kFunctions)) { | |
4070 instructions += LoadFunctionTypeArguments(); | |
4071 } else { | |
4072 instructions += NullConstant(); | |
4073 } | |
4074 instructions += InstantiateType(type); | |
4075 } | |
4076 fragment_ = instructions; | |
4077 } | |
4078 | |
4079 | |
4080 void FlowGraphBuilder::VisitVariableGet(VariableGet* node) { | |
4081 fragment_ = | |
4082 streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset()); | |
4083 } | |
4084 | |
4085 | |
4086 void FlowGraphBuilder::VisitVariableSet(VariableSet* node) { | |
4087 STREAM_EXPRESSION_IF_POSSIBLE(node); | |
4088 | |
4089 Fragment instructions = TranslateExpression(node->expression()); | |
4090 if (NeedsDebugStepCheck(stack_, node->position())) { | |
4091 instructions = DebugStepCheck(node->position()) + instructions; | |
4092 } | |
4093 instructions += CheckVariableTypeInCheckedMode(node->variable()); | |
4094 instructions += | |
4095 StoreLocal(node->position(), LookupVariable(node->variable())); | |
4096 fragment_ = instructions; | |
4097 } | |
4098 | |
4099 | |
4100 void FlowGraphBuilder::VisitStaticGet(StaticGet* node) { | |
4101 STREAM_EXPRESSION_IF_POSSIBLE(node); | |
4102 | |
4103 // A StaticGet will always have a kernel_offset, except for the StaticGet that | |
4104 // was manually created for _getMainClosure in dart:_builtin. Compile that | |
4105 // one specially here. | |
4106 const dart::Library& builtin = | |
4107 dart::Library::Handle(Z, I->object_store()->builtin_library()); | |
4108 const Object& main = | |
4109 Object::Handle(Z, builtin.LookupObjectAllowPrivate(dart::String::Handle( | |
4110 Z, dart::String::New("main")))); | |
4111 if (main.IsField()) { | |
4112 UNIMPLEMENTED(); | |
4113 } else if (main.IsFunction()) { | |
4114 const Function& function = Function::Cast(main); | |
4115 if (function.kind() == RawFunction::kRegularFunction) { | |
4116 const Function& closure_function = | |
4117 Function::Handle(Z, function.ImplicitClosureFunction()); | |
4118 closure_function.set_kernel_function(function.kernel_function()); | |
4119 const Instance& closure = | |
4120 Instance::ZoneHandle(Z, closure_function.ImplicitStaticClosure()); | |
4121 fragment_ = Constant(closure); | |
4122 } else { | |
4123 UNIMPLEMENTED(); | |
4124 } | |
4125 } else { | |
4126 UNIMPLEMENTED(); | |
4127 } | |
4128 } | |
4129 | |
4130 | |
4131 void FlowGraphBuilder::VisitStaticSet(StaticSet* node) { | |
4132 STREAM_EXPRESSION_IF_POSSIBLE(node); | |
4133 | |
4134 NameIndex target = node->target(); | |
4135 if (H.IsField(target)) { | |
4136 const dart::Field& field = | |
4137 dart::Field::ZoneHandle(Z, H.LookupFieldByKernelField(target)); | |
4138 const AbstractType& dst_type = AbstractType::ZoneHandle(Z, field.type()); | |
4139 Fragment instructions = TranslateExpression(node->expression()); | |
4140 if (NeedsDebugStepCheck(stack_, node->position())) { | |
4141 instructions = DebugStepCheck(node->position()) + instructions; | |
4142 } | |
4143 instructions += CheckAssignableInCheckedMode( | |
4144 dst_type, dart::String::ZoneHandle(Z, field.name())); | |
4145 LocalVariable* variable = MakeTemporary(); | |
4146 instructions += LoadLocal(variable); | |
4147 fragment_ = instructions + StoreStaticField(node->position(), field); | |
4148 } else { | |
4149 ASSERT(H.IsProcedure(target)); | |
4150 | |
4151 // Evaluate the expression on the right hand side. | |
4152 Fragment instructions = TranslateExpression(node->expression()); | |
4153 LocalVariable* variable = MakeTemporary(); | |
4154 | |
4155 // Prepare argument. | |
4156 instructions += LoadLocal(variable); | |
4157 instructions += PushArgument(); | |
4158 | |
4159 // Invoke the setter function. | |
4160 const Function& function = | |
4161 Function::ZoneHandle(Z, H.LookupStaticMethodByKernelProcedure(target)); | |
4162 instructions += StaticCall(node->position(), function, 1); | |
4163 | |
4164 // Drop the unused result & leave the stored value on the stack. | |
4165 fragment_ = instructions + Drop(); | |
4166 } | |
4167 } | |
4168 | |
4169 | |
4170 void FlowGraphBuilder::VisitPropertyGet(PropertyGet* node) { | |
4171 STREAM_EXPRESSION_IF_POSSIBLE(node); | |
4172 | |
4173 Fragment instructions = TranslateExpression(node->receiver()); | |
4174 instructions += PushArgument(); | |
4175 const dart::String& getter_name = H.DartGetterName(node->name()); | |
4176 fragment_ = instructions + | |
4177 InstanceCall(node->position(), getter_name, Token::kGET, 1); | |
4178 } | |
4179 | |
4180 | |
4181 void FlowGraphBuilder::VisitPropertySet(PropertySet* node) { | |
4182 STREAM_EXPRESSION_IF_POSSIBLE(node); | |
4183 | |
4184 Fragment instructions(NullConstant()); | |
4185 LocalVariable* variable = MakeTemporary(); | |
4186 instructions += TranslateExpression(node->receiver()); | |
4187 instructions += PushArgument(); | |
4188 instructions += TranslateExpression(node->value()); | |
4189 instructions += StoreLocal(TokenPosition::kNoSource, variable); | |
4190 instructions += PushArgument(); | |
4191 | |
4192 const dart::String& setter_name = H.DartSetterName(node->name()); | |
4193 instructions += InstanceCall(node->position(), setter_name, Token::kSET, 2); | |
4194 fragment_ = instructions + Drop(); | |
4195 } | |
4196 | |
4197 | |
4198 void FlowGraphBuilder::VisitDirectPropertyGet(DirectPropertyGet* node) { | |
4199 STREAM_EXPRESSION_IF_POSSIBLE(node); | |
4200 | |
4201 Function& target = Function::ZoneHandle(Z); | |
4202 NameIndex kernel_name = node->target(); | |
4203 if (H.IsProcedure(kernel_name)) { | |
4204 if (H.IsGetter(kernel_name)) { | |
4205 target = LookupMethodByMember(kernel_name, H.DartGetterName(kernel_name)); | |
4206 } else { | |
4207 target = LookupMethodByMember(kernel_name, H.DartMethodName(kernel_name)); | |
4208 target = target.ImplicitClosureFunction(); | |
4209 ASSERT(!target.IsNull()); | |
4210 fragment_ = BuildImplicitClosureCreation(target); | |
4211 return; | |
4212 } | |
4213 } else { | |
4214 ASSERT(H.IsField(kernel_name)); | |
4215 const dart::String& getter_name = H.DartGetterName(kernel_name); | |
4216 target = LookupMethodByMember(kernel_name, getter_name); | |
4217 ASSERT(target.IsGetterFunction() || target.IsImplicitGetterFunction()); | |
4218 } | |
4219 | |
4220 Fragment instructions = TranslateExpression(node->receiver()); | |
4221 instructions += PushArgument(); | |
4222 fragment_ = instructions + StaticCall(node->position(), target, 1); | |
4223 } | |
4224 | |
4225 | |
4226 void FlowGraphBuilder::VisitDirectPropertySet(DirectPropertySet* node) { | |
4227 STREAM_EXPRESSION_IF_POSSIBLE(node); | |
4228 | |
4229 const dart::String& method_name = H.DartSetterName(node->target()); | |
4230 const Function& target = Function::ZoneHandle( | |
4231 Z, LookupMethodByMember(node->target(), method_name)); | |
4232 ASSERT(target.IsSetterFunction() || target.IsImplicitSetterFunction()); | |
4233 | |
4234 Fragment instructions(NullConstant()); | |
4235 LocalVariable* value = MakeTemporary(); | |
4236 instructions += TranslateExpression(node->receiver()); | |
4237 instructions += PushArgument(); | |
4238 instructions += TranslateExpression(node->value()); | |
4239 instructions += StoreLocal(TokenPosition::kNoSource, value); | |
4240 instructions += PushArgument(); | |
4241 instructions += StaticCall(node->position(), target, 2); | |
4242 | |
4243 fragment_ = instructions + Drop(); | |
4244 } | |
4245 | |
4246 | |
4247 void FlowGraphBuilder::VisitStaticInvocation(StaticInvocation* node) { | |
4248 STREAM_EXPRESSION_IF_POSSIBLE(node); | |
4249 | |
4250 const Function& target = Function::ZoneHandle( | |
4251 Z, H.LookupStaticMethodByKernelProcedure(node->procedure())); | |
4252 const dart::Class& klass = dart::Class::ZoneHandle(Z, target.Owner()); | |
4253 intptr_t argument_count = node->arguments()->count(); | |
4254 if (target.IsGenerativeConstructor() || target.IsFactory()) { | |
4255 // The VM requires a TypeArguments object as first parameter for | |
4256 // every factory constructor. | |
4257 ++argument_count; | |
4258 } | |
4259 | |
4260 List<NamedExpression>& named = node->arguments()->named(); | |
4261 const Array& argument_names = H.ArgumentNames(&named); | |
4262 | |
4263 // The frontend ensures we the [StaticInvocation] has matching arguments. | |
4264 ASSERT(target.AreValidArguments(argument_count, argument_names, NULL)); | |
4265 | |
4266 Fragment instructions; | |
4267 LocalVariable* instance_variable = NULL; | |
4268 | |
4269 // If we cross the Kernel -> VM core library boundary, a [StaticInvocation] | |
4270 // can appear, but the thing we're calling is not a static method, but a | |
4271 // factory constructor. | |
4272 // The `H.LookupStaticmethodByKernelProcedure` will potentially resolve to the | |
4273 // forwarded constructor. | |
4274 // In that case we'll make an instance and pass it as first argument. | |
4275 // | |
4276 // TODO(27590): Get rid of this after we're using core libraries compiled | |
4277 // into Kernel. | |
4278 if (target.IsGenerativeConstructor()) { | |
4279 if (klass.NumTypeArguments() > 0) { | |
4280 List<DartType>& kernel_type_arguments = node->arguments()->types(); | |
4281 const TypeArguments& type_arguments = | |
4282 T.TranslateInstantiatedTypeArguments( | |
4283 klass, kernel_type_arguments.raw_array(), | |
4284 kernel_type_arguments.length()); | |
4285 instructions += TranslateInstantiatedTypeArguments(type_arguments); | |
4286 instructions += PushArgument(); | |
4287 instructions += AllocateObject(klass, 1); | |
4288 } else { | |
4289 instructions += AllocateObject(klass, 0); | |
4290 } | |
4291 | |
4292 instance_variable = MakeTemporary(); | |
4293 | |
4294 instructions += LoadLocal(instance_variable); | |
4295 instructions += PushArgument(); | |
4296 } else if (target.IsFactory()) { | |
4297 // The VM requires currently a TypeArguments object as first parameter for | |
4298 // every factory constructor :-/ ! | |
4299 // | |
4300 // TODO(27590): Get rid of this after we're using core libraries compiled | |
4301 // into Kernel. | |
4302 List<DartType>& kernel_type_arguments = node->arguments()->types(); | |
4303 | |
4304 const TypeArguments& type_arguments = T.TranslateInstantiatedTypeArguments( | |
4305 klass, kernel_type_arguments.raw_array(), | |
4306 kernel_type_arguments.length()); | |
4307 | |
4308 instructions += TranslateInstantiatedTypeArguments(type_arguments); | |
4309 instructions += PushArgument(); | |
4310 } else { | |
4311 // TODO(28109) Support generic methods in the VM or reify them away. | |
4312 } | |
4313 | |
4314 // Special case identical(x, y) call. | |
4315 // TODO(27590) consider moving this into the inliner and force inline it | |
4316 // there. | |
4317 if (klass.IsTopLevel() && (klass.library() == dart::Library::CoreLibrary()) && | |
4318 (target.name() == Symbols::Identical().raw())) { | |
4319 ASSERT(argument_count == 2); | |
4320 | |
4321 List<Expression>& positional = node->arguments()->positional(); | |
4322 for (intptr_t i = 0; i < positional.length(); ++i) { | |
4323 instructions += TranslateExpression(positional[i]); | |
4324 } | |
4325 instructions += StrictCompare(Token::kEQ_STRICT, /*number_check=*/true); | |
4326 } else { | |
4327 instructions += TranslateArguments(node->arguments(), NULL); | |
4328 instructions += | |
4329 StaticCall(node->position(), target, argument_count, argument_names); | |
4330 | |
4331 if (target.IsGenerativeConstructor()) { | |
4332 // Drop the result of the constructor call and leave [instance_variable] | |
4333 // on top-of-stack. | |
4334 instructions += Drop(); | |
4335 } | |
4336 } | |
4337 | |
4338 fragment_ = instructions; | |
4339 } | |
4340 | |
4341 | |
4342 static bool IsNumberLiteral(Node* node) { | |
4343 return node->IsIntLiteral() || node->IsDoubleLiteral(); | |
4344 } | |
4345 | |
4346 template <class Invocation> | |
4347 bool FlowGraphBuilder::RecognizeComparisonWithNull(Token::Kind token_kind, | |
4348 Invocation* node) { | |
4349 if (token_kind == Token::kEQ || token_kind == Token::kNE) { | |
4350 if (node->arguments()->positional().length() != 1) return false; | |
4351 Fragment instructions; | |
4352 Expression* left = node->receiver(); | |
4353 Expression* right = node->arguments()->positional()[0]; | |
4354 if (left->IsNullLiteral() || right->IsNullLiteral()) { | |
4355 instructions += TranslateExpression(left); | |
4356 instructions += TranslateExpression(right); | |
4357 Token::Kind strict_cmp_kind = | |
4358 token_kind == Token::kEQ ? Token::kEQ_STRICT : Token::kNE_STRICT; | |
4359 fragment_ = instructions + StrictCompare(strict_cmp_kind, | |
4360 /*number_check = */ true); | |
4361 return true; | |
4362 } | |
4363 } | |
4364 return false; | |
4365 } | |
4366 | |
4367 | |
4368 void FlowGraphBuilder::VisitMethodInvocation(MethodInvocation* node) { | |
4369 STREAM_EXPRESSION_IF_POSSIBLE(node); | |
4370 | |
4371 const dart::String& name = H.DartMethodName(node->name()); | |
4372 const intptr_t argument_count = node->arguments()->count() + 1; | |
4373 const Token::Kind token_kind = MethodKind(name); | |
4374 if (IsNumberLiteral(node->receiver())) { | |
4375 if ((argument_count == 1) && (token_kind == Token::kNEGATE)) { | |
4376 const Object& result = constant_evaluator_.EvaluateExpressionSafe(node); | |
4377 if (!result.IsError()) { | |
4378 fragment_ = Constant(result); | |
4379 return; | |
4380 } | |
4381 } else if ((argument_count == 2) && | |
4382 Token::IsBinaryArithmeticOperator(token_kind) && | |
4383 IsNumberLiteral(node->arguments()->positional()[0])) { | |
4384 const Object& result = constant_evaluator_.EvaluateExpressionSafe(node); | |
4385 if (!result.IsError()) { | |
4386 fragment_ = Constant(result); | |
4387 return; | |
4388 } | |
4389 } | |
4390 } | |
4391 | |
4392 if (RecognizeComparisonWithNull(token_kind, node)) return; | |
4393 | |
4394 Fragment instructions = TranslateExpression(node->receiver()); | |
4395 instructions += PushArgument(); | |
4396 | |
4397 // TODO(28109) Support generic methods in the VM or reify them away. | |
4398 Array& argument_names = Array::ZoneHandle(Z); | |
4399 instructions += TranslateArguments(node->arguments(), &argument_names); | |
4400 | |
4401 intptr_t num_args_checked = 1; | |
4402 // If we have a special operation (e.g. +/-/==) we mark both arguments as | |
4403 // to be checked. | |
4404 if (token_kind != Token::kILLEGAL) { | |
4405 ASSERT(argument_count <= 2); | |
4406 num_args_checked = argument_count; | |
4407 } | |
4408 | |
4409 fragment_ = instructions + InstanceCall(node->position(), name, token_kind, | |
4410 argument_count, argument_names, | |
4411 num_args_checked); | |
4412 // Later optimization passes assume that result of a x.[]=(...) call is not | |
4413 // used. We must guarantee this invariant because violation will lead to an | |
4414 // illegal IL once we replace x.[]=(...) with a sequence that does not | |
4415 // actually produce any value. See http://dartbug.com/29135 for more details. | |
4416 if (name.raw() == Symbols::AssignIndexToken().raw()) { | |
4417 fragment_ += Drop(); | |
4418 fragment_ += NullConstant(); | |
4419 } | |
4420 } | |
4421 | |
4422 | |
4423 void FlowGraphBuilder::VisitDirectMethodInvocation( | |
4424 DirectMethodInvocation* node) { | |
4425 STREAM_EXPRESSION_IF_POSSIBLE(node); | |
4426 | |
4427 const dart::String& method_name = H.DartProcedureName(node->target()); | |
4428 const Token::Kind token_kind = MethodKind(method_name); | |
4429 | |
4430 if (RecognizeComparisonWithNull(token_kind, node)) return; | |
4431 | |
4432 const Function& target = Function::ZoneHandle( | |
4433 Z, LookupMethodByMember(node->target(), method_name)); | |
4434 | |
4435 intptr_t argument_count = node->arguments()->count() + 1; | |
4436 Array& argument_names = Array::ZoneHandle(Z); | |
4437 | |
4438 // TODO(28109) Support generic methods in the VM or reify them away. | |
4439 Fragment instructions = TranslateExpression(node->receiver()); | |
4440 instructions += PushArgument(); | |
4441 instructions += TranslateArguments(node->arguments(), &argument_names); | |
4442 fragment_ = instructions + StaticCall(node->position(), target, | |
4443 argument_count, argument_names); | |
4444 } | |
4445 | |
4446 | |
4447 void FlowGraphBuilder::VisitConstructorInvocation(ConstructorInvocation* node) { | |
4448 STREAM_EXPRESSION_IF_POSSIBLE(node); | |
4449 | |
4450 if (node->is_const()) { | |
4451 fragment_ = | |
4452 Constant(constant_evaluator_.EvaluateConstructorInvocation(node)); | |
4453 return; | |
4454 } | |
4455 | |
4456 dart::Class& klass = dart::Class::ZoneHandle( | |
4457 Z, H.LookupClassByKernelClass(H.EnclosingName(node->target()))); | |
4458 | |
4459 Fragment instructions; | |
4460 | |
4461 // Check for malbounded-ness of type. | |
4462 if (I->type_checks()) { | |
4463 List<DartType>& kernel_type_arguments = node->arguments()->types(); | |
4464 const TypeArguments& type_arguments = T.TranslateTypeArguments( | |
4465 kernel_type_arguments.raw_array(), kernel_type_arguments.length()); | |
4466 | |
4467 AbstractType& type = AbstractType::Handle( | |
4468 Z, Type::New(klass, type_arguments, TokenPosition::kNoSource)); | |
4469 type = ClassFinalizer::FinalizeType(klass, type); | |
4470 | |
4471 if (type.IsMalbounded()) { | |
4472 // Evaluate expressions for correctness. | |
4473 List<Expression>& positional = node->arguments()->positional(); | |
4474 List<NamedExpression>& named = node->arguments()->named(); | |
4475 for (intptr_t i = 0; i < positional.length(); ++i) { | |
4476 instructions += TranslateExpression(positional[i]); | |
4477 instructions += Drop(); | |
4478 } | |
4479 for (intptr_t i = 0; i < named.length(); ++i) { | |
4480 instructions += TranslateExpression(named[i]->expression()); | |
4481 instructions += Drop(); | |
4482 } | |
4483 | |
4484 // Throw an error & keep the [Value] on the stack. | |
4485 instructions += ThrowTypeError(); | |
4486 | |
4487 // Bail out early. | |
4488 fragment_ = instructions; | |
4489 return; | |
4490 } | |
4491 } | |
4492 | |
4493 if (klass.NumTypeArguments() > 0) { | |
4494 List<DartType>& kernel_type_arguments = node->arguments()->types(); | |
4495 const TypeArguments& type_arguments = T.TranslateInstantiatedTypeArguments( | |
4496 klass, kernel_type_arguments.raw_array(), | |
4497 kernel_type_arguments.length()); | |
4498 if (!klass.IsGeneric()) { | |
4499 Type& type = Type::ZoneHandle(Z, T.ReceiverType(klass).raw()); | |
4500 | |
4501 // TODO(27590): Can we move this code into [ReceiverType]? | |
4502 type ^= ClassFinalizer::FinalizeType(*active_class_.klass, type, | |
4503 ClassFinalizer::kFinalize); | |
4504 ASSERT(!type.IsMalformedOrMalbounded()); | |
4505 | |
4506 TypeArguments& canonicalized_type_arguments = | |
4507 TypeArguments::ZoneHandle(Z, type.arguments()); | |
4508 canonicalized_type_arguments = | |
4509 canonicalized_type_arguments.Canonicalize(); | |
4510 instructions += Constant(canonicalized_type_arguments); | |
4511 } else { | |
4512 instructions += TranslateInstantiatedTypeArguments(type_arguments); | |
4513 } | |
4514 | |
4515 instructions += PushArgument(); | |
4516 instructions += AllocateObject(klass, 1); | |
4517 } else { | |
4518 instructions += AllocateObject(klass, 0); | |
4519 } | |
4520 LocalVariable* variable = MakeTemporary(); | |
4521 | |
4522 instructions += LoadLocal(variable); | |
4523 instructions += PushArgument(); | |
4524 | |
4525 Array& argument_names = Array::ZoneHandle(Z); | |
4526 instructions += TranslateArguments(node->arguments(), &argument_names); | |
4527 | |
4528 const Function& target = Function::ZoneHandle( | |
4529 Z, H.LookupConstructorByKernelConstructor(klass, node->target())); | |
4530 intptr_t argument_count = node->arguments()->count() + 1; | |
4531 instructions += | |
4532 StaticCall(node->position(), target, argument_count, argument_names); | |
4533 fragment_ = instructions + Drop(); | |
4534 } | |
4535 | |
4536 | |
4537 void FlowGraphBuilder::VisitIsExpression(IsExpression* node) { | |
4538 STREAM_EXPRESSION_IF_POSSIBLE(node); | |
4539 | |
4540 Fragment instructions = TranslateExpression(node->operand()); | |
4541 | |
4542 // The VM does not like an instanceOf call with a dynamic type. We need to | |
4543 // special case this situation. | |
4544 const Type& object_type = Type::Handle(Z, Type::ObjectType()); | |
4545 const AbstractType& type = T.TranslateType(node->type()); | |
4546 if (type.IsMalformed()) { | |
4547 instructions += Drop(); | |
4548 instructions += ThrowTypeError(); | |
4549 fragment_ = instructions; | |
4550 return; | |
4551 } | |
4552 | |
4553 if (type.IsInstantiated() && | |
4554 object_type.IsSubtypeOf(type, NULL, NULL, Heap::kOld)) { | |
4555 // Evaluate the expression on the left but ignore it's result. | |
4556 instructions += Drop(); | |
4557 | |
4558 // Let condition be always true. | |
4559 instructions += Constant(Bool::True()); | |
4560 } else { | |
4561 instructions += PushArgument(); | |
4562 | |
4563 // See if simple instanceOf is applicable. | |
4564 if (dart::FlowGraphBuilder::SimpleInstanceOfType(type)) { | |
4565 instructions += Constant(type); | |
4566 instructions += PushArgument(); // Type. | |
4567 instructions += InstanceCall( | |
4568 node->position(), | |
4569 dart::Library::PrivateCoreLibName(Symbols::_simpleInstanceOf()), | |
4570 Token::kIS, 2, 2); // 2 checked arguments. | |
4571 fragment_ = instructions; | |
4572 return; | |
4573 } | |
4574 | |
4575 if (!type.IsInstantiated(kCurrentClass)) { | |
4576 instructions += LoadInstantiatorTypeArguments(); | |
4577 } else { | |
4578 instructions += NullConstant(); | |
4579 } | |
4580 instructions += PushArgument(); // Instantiator type arguments. | |
4581 | |
4582 if (!type.IsInstantiated(kFunctions)) { | |
4583 instructions += LoadFunctionTypeArguments(); | |
4584 } else { | |
4585 instructions += NullConstant(); | |
4586 } | |
4587 instructions += PushArgument(); // Function type arguments. | |
4588 | |
4589 instructions += Constant(type); | |
4590 instructions += PushArgument(); // Type. | |
4591 | |
4592 instructions += | |
4593 InstanceCall(node->position(), | |
4594 dart::Library::PrivateCoreLibName(Symbols::_instanceOf()), | |
4595 Token::kIS, 4); | |
4596 } | |
4597 | |
4598 fragment_ = instructions; | |
4599 } | |
4600 | |
4601 | |
4602 void FlowGraphBuilder::VisitAsExpression(AsExpression* node) { | |
4603 STREAM_EXPRESSION_IF_POSSIBLE(node); | |
4604 | |
4605 Fragment instructions = TranslateExpression(node->operand()); | |
4606 | |
4607 // The VM does not like an Object_as call with a dynamic type. We need to | |
4608 // special case this situation. | |
4609 const Type& object_type = Type::Handle(Z, Type::ObjectType()); | |
4610 const AbstractType& type = T.TranslateType(node->type()); | |
4611 if (type.IsMalformed()) { | |
4612 instructions += Drop(); | |
4613 instructions += ThrowTypeError(); | |
4614 fragment_ = instructions; | |
4615 return; | |
4616 } | |
4617 | |
4618 if (type.IsInstantiated() && | |
4619 object_type.IsSubtypeOf(type, NULL, NULL, Heap::kOld)) { | |
4620 // We already evaluated the operand on the left and just leave it there as | |
4621 // the result of the `obj as dynamic` expression. | |
4622 } else { | |
4623 instructions += PushArgument(); | |
4624 | |
4625 if (!type.IsInstantiated(kCurrentClass)) { | |
4626 instructions += LoadInstantiatorTypeArguments(); | |
4627 } else { | |
4628 instructions += NullConstant(); | |
4629 } | |
4630 instructions += PushArgument(); // Instantiator type arguments. | |
4631 | |
4632 if (!type.IsInstantiated(kFunctions)) { | |
4633 instructions += LoadFunctionTypeArguments(); | |
4634 } else { | |
4635 instructions += NullConstant(); | |
4636 } | |
4637 instructions += PushArgument(); // Function type arguments. | |
4638 | |
4639 instructions += Constant(type); | |
4640 instructions += PushArgument(); // Type. | |
4641 | |
4642 instructions += InstanceCall( | |
4643 node->position(), dart::Library::PrivateCoreLibName(Symbols::_as()), | |
4644 Token::kAS, 4); | |
4645 } | |
4646 | |
4647 fragment_ = instructions; | |
4648 } | |
4649 | |
4650 | |
4651 void FlowGraphBuilder::VisitConditionalExpression(ConditionalExpression* node) { | |
4652 STREAM_EXPRESSION_IF_POSSIBLE(node); | |
4653 | |
4654 bool negate; | |
4655 Fragment instructions = TranslateCondition(node->condition(), &negate); | |
4656 | |
4657 TargetEntryInstr* then_entry; | |
4658 TargetEntryInstr* otherwise_entry; | |
4659 instructions += BranchIfTrue(&then_entry, &otherwise_entry, negate); | |
4660 | |
4661 Value* top = stack_; | |
4662 Fragment then_fragment(then_entry); | |
4663 then_fragment += TranslateExpression(node->then()); | |
4664 then_fragment += StoreLocal(TokenPosition::kNoSource, | |
4665 parsed_function_->expression_temp_var()); | |
4666 then_fragment += Drop(); | |
4667 ASSERT(stack_ == top); | |
4668 | |
4669 Fragment otherwise_fragment(otherwise_entry); | |
4670 otherwise_fragment += TranslateExpression(node->otherwise()); | |
4671 otherwise_fragment += StoreLocal(TokenPosition::kNoSource, | |
4672 parsed_function_->expression_temp_var()); | |
4673 otherwise_fragment += Drop(); | |
4674 ASSERT(stack_ == top); | |
4675 | |
4676 JoinEntryInstr* join = BuildJoinEntry(); | |
4677 then_fragment += Goto(join); | |
4678 otherwise_fragment += Goto(join); | |
4679 | |
4680 fragment_ = Fragment(instructions.entry, join) + | |
4681 LoadLocal(parsed_function_->expression_temp_var()); | |
4682 } | |
4683 | |
4684 | |
4685 void FlowGraphBuilder::VisitLogicalExpression(LogicalExpression* node) { | |
4686 STREAM_EXPRESSION_IF_POSSIBLE(node); | |
4687 | |
4688 bool negate; | |
4689 Fragment instructions = TranslateCondition(node->left(), &negate); | |
4690 TargetEntryInstr* right_entry; | |
4691 TargetEntryInstr* constant_entry; | |
4692 | |
4693 if (node->op() == LogicalExpression::kAnd) { | |
4694 instructions += BranchIfTrue(&right_entry, &constant_entry, negate); | |
4695 } else { | |
4696 instructions += BranchIfTrue(&constant_entry, &right_entry, negate); | |
4697 } | |
4698 | |
4699 Value* top = stack_; | |
4700 Fragment right_fragment(right_entry); | |
4701 right_fragment += TranslateCondition(node->right(), &negate); | |
4702 right_fragment += Constant(Bool::True()); | |
4703 right_fragment += | |
4704 StrictCompare(negate ? Token::kNE_STRICT : Token::kEQ_STRICT); | |
4705 right_fragment += StoreLocal(TokenPosition::kNoSource, | |
4706 parsed_function_->expression_temp_var()); | |
4707 right_fragment += Drop(); | |
4708 | |
4709 ASSERT(top == stack_); | |
4710 Fragment constant_fragment(constant_entry); | |
4711 constant_fragment += | |
4712 Constant(Bool::Get(node->op() == LogicalExpression::kOr)); | |
4713 constant_fragment += StoreLocal(TokenPosition::kNoSource, | |
4714 parsed_function_->expression_temp_var()); | |
4715 constant_fragment += Drop(); | |
4716 | |
4717 JoinEntryInstr* join = BuildJoinEntry(); | |
4718 right_fragment += Goto(join); | |
4719 constant_fragment += Goto(join); | |
4720 | |
4721 fragment_ = Fragment(instructions.entry, join) + | |
4722 LoadLocal(parsed_function_->expression_temp_var()); | |
4723 } | |
4724 | |
4725 | |
4726 void FlowGraphBuilder::VisitNot(Not* node) { | |
4727 STREAM_EXPRESSION_IF_POSSIBLE(node); | |
4728 | |
4729 Fragment instructions = TranslateExpression(node->expression()); | |
4730 instructions += CheckBooleanInCheckedMode(); | |
4731 instructions += BooleanNegate(); | |
4732 fragment_ = instructions; | |
4733 } | |
4734 | |
4735 | |
4736 void FlowGraphBuilder::VisitThisExpression(ThisExpression* node) { | |
4737 fragment_ = | |
4738 streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset()); | |
4739 } | |
4740 | |
4741 | |
4742 void FlowGraphBuilder::VisitStringConcatenation(StringConcatenation* node) { | |
4743 STREAM_EXPRESSION_IF_POSSIBLE(node); | |
4744 | |
4745 List<Expression>& expressions = node->expressions(); | |
4746 | |
4747 Fragment instructions; | |
4748 | |
4749 if (node->expressions().length() == 1) { | |
4750 instructions += TranslateExpression(node->expressions()[0]); | |
4751 instructions += StringInterpolateSingle(node->position()); | |
4752 } else { | |
4753 // The type arguments for CreateArray. | |
4754 instructions += Constant(TypeArguments::ZoneHandle(Z)); | |
4755 instructions += IntConstant(expressions.length()); | |
4756 instructions += CreateArray(); | |
4757 LocalVariable* array = MakeTemporary(); | |
4758 | |
4759 for (intptr_t i = 0; i < node->expressions().length(); i++) { | |
4760 instructions += LoadLocal(array); | |
4761 instructions += IntConstant(i); | |
4762 instructions += TranslateExpression(node->expressions()[i]); | |
4763 instructions += StoreIndexed(kArrayCid); | |
4764 instructions += Drop(); | |
4765 } | |
4766 | |
4767 instructions += StringInterpolate(node->position()); | |
4768 } | |
4769 fragment_ = instructions; | |
4770 } | |
4771 | |
4772 | |
4773 void FlowGraphBuilder::VisitListLiteral(ListLiteral* node) { | |
4774 STREAM_EXPRESSION_IF_POSSIBLE(node); | |
4775 | |
4776 if (node->is_const()) { | |
4777 fragment_ = Constant(constant_evaluator_.EvaluateListLiteral(node)); | |
4778 return; | |
4779 } | |
4780 | |
4781 DartType* types[] = {node->type()}; | |
4782 const TypeArguments& type_arguments = T.TranslateTypeArguments(types, 1); | |
4783 | |
4784 // The type argument for the factory call. | |
4785 Fragment instructions = TranslateInstantiatedTypeArguments(type_arguments); | |
4786 instructions += PushArgument(); | |
4787 List<Expression>& expressions = node->expressions(); | |
4788 if (expressions.length() == 0) { | |
4789 instructions += Constant(Object::empty_array()); | |
4790 } else { | |
4791 // The type arguments for CreateArray. | |
4792 instructions += Constant(TypeArguments::ZoneHandle(Z)); | |
4793 instructions += IntConstant(expressions.length()); | |
4794 instructions += CreateArray(); | |
4795 | |
4796 LocalVariable* array = MakeTemporary(); | |
4797 for (intptr_t i = 0; i < expressions.length(); ++i) { | |
4798 instructions += LoadLocal(array); | |
4799 instructions += IntConstant(i); | |
4800 instructions += TranslateExpression(expressions[i]); | |
4801 instructions += StoreIndexed(kArrayCid); | |
4802 instructions += Drop(); | |
4803 } | |
4804 } | |
4805 instructions += PushArgument(); // The array. | |
4806 | |
4807 const dart::Class& factory_class = | |
4808 dart::Class::Handle(Z, dart::Library::LookupCoreClass(Symbols::List())); | |
4809 const Function& factory_method = Function::ZoneHandle( | |
4810 Z, factory_class.LookupFactory( | |
4811 dart::Library::PrivateCoreLibName(Symbols::ListLiteralFactory()))); | |
4812 fragment_ = instructions + StaticCall(node->position(), factory_method, 2); | |
4813 } | |
4814 | |
4815 | |
4816 void FlowGraphBuilder::VisitMapLiteral(MapLiteral* node) { | |
4817 STREAM_EXPRESSION_IF_POSSIBLE(node); | |
4818 | |
4819 if (node->is_const()) { | |
4820 fragment_ = Constant(constant_evaluator_.EvaluateMapLiteral(node)); | |
4821 return; | |
4822 } | |
4823 | |
4824 const dart::Class& map_class = | |
4825 dart::Class::Handle(Z, dart::Library::LookupCoreClass(Symbols::Map())); | |
4826 const Function& factory_method = Function::ZoneHandle( | |
4827 Z, map_class.LookupFactory( | |
4828 dart::Library::PrivateCoreLibName(Symbols::MapLiteralFactory()))); | |
4829 | |
4830 DartType* types[] = {node->key_type(), node->value_type()}; | |
4831 const TypeArguments& type_arguments = T.TranslateTypeArguments(types, 2); | |
4832 | |
4833 // The type argument for the factory call `new Map<K, V>._fromLiteral(List)`. | |
4834 Fragment instructions = TranslateInstantiatedTypeArguments(type_arguments); | |
4835 instructions += PushArgument(); | |
4836 | |
4837 List<MapEntry>& entries = node->entries(); | |
4838 if (entries.length() == 0) { | |
4839 instructions += Constant(Object::empty_array()); | |
4840 } else { | |
4841 // The type arguments for `new List<X>(int len)`. | |
4842 instructions += Constant(TypeArguments::ZoneHandle(Z)); | |
4843 | |
4844 // We generate a list of tuples, i.e. [key1, value1, ..., keyN, valueN]. | |
4845 instructions += IntConstant(2 * entries.length()); | |
4846 instructions += CreateArray(); | |
4847 | |
4848 LocalVariable* array = MakeTemporary(); | |
4849 for (intptr_t i = 0; i < entries.length(); ++i) { | |
4850 instructions += LoadLocal(array); | |
4851 instructions += IntConstant(2 * i); | |
4852 instructions += TranslateExpression(entries[i]->key()); | |
4853 instructions += StoreIndexed(kArrayCid); | |
4854 instructions += Drop(); | |
4855 | |
4856 instructions += LoadLocal(array); | |
4857 instructions += IntConstant(2 * i + 1); | |
4858 instructions += TranslateExpression(entries[i]->value()); | |
4859 instructions += StoreIndexed(kArrayCid); | |
4860 instructions += Drop(); | |
4861 } | |
4862 } | |
4863 instructions += PushArgument(); // The array. | |
4864 | |
4865 fragment_ = instructions + StaticCall(node->position(), factory_method, 2); | |
4866 } | |
4867 | |
4868 | |
4869 void FlowGraphBuilder::VisitFunctionExpression(FunctionExpression* node) { | |
4870 fragment_ = TranslateFunctionNode(node->function(), node); | |
4871 } | |
4872 | |
4873 | |
4874 void FlowGraphBuilder::VisitLet(Let* node) { | |
4875 STREAM_EXPRESSION_IF_POSSIBLE(node); | |
4876 | |
4877 Fragment instructions = TranslateStatement(node->variable()); | |
4878 instructions += TranslateExpression(node->body()); | |
4879 fragment_ = instructions; | |
4880 } | |
4881 | |
4882 | |
4883 void FlowGraphBuilder::VisitThrow(Throw* node) { | |
4884 STREAM_EXPRESSION_IF_POSSIBLE(node); | |
4885 | |
4886 Fragment instructions; | |
4887 | |
4888 instructions += TranslateExpression(node->expression()); | |
4889 if (NeedsDebugStepCheck(stack_, node->position())) { | |
4890 instructions = DebugStepCheck(node->position()) + instructions; | |
4891 } | |
4892 instructions += PushArgument(); | |
4893 instructions += ThrowException(node->position()); | |
4894 ASSERT(instructions.is_closed()); | |
4895 | |
4896 fragment_ = instructions; | |
4897 } | |
4898 | |
4899 | |
4900 void FlowGraphBuilder::VisitRethrow(Rethrow* node) { | |
4901 fragment_ = | |
4902 streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset()); | |
4903 } | |
4904 | |
4905 | |
4906 Fragment FlowGraphBuilder::TranslateArguments(Arguments* node, | |
4907 Array* argument_names) { | |
4908 Fragment instructions; | |
4909 | |
4910 List<Expression>& positional = node->positional(); | |
4911 for (intptr_t i = 0; i < positional.length(); ++i) { | |
4912 instructions += TranslateExpression(positional[i]); | |
4913 instructions += PushArgument(); | |
4914 } | |
4915 | |
4916 List<NamedExpression>& named = node->named(); | |
4917 if (argument_names != NULL) { | |
4918 *argument_names = H.ArgumentNames(&named).raw(); | |
4919 } | |
4920 for (intptr_t i = 0; i < named.length(); ++i) { | |
4921 NamedExpression* named_expression = named[i]; | |
4922 instructions += TranslateExpression(named_expression->expression()); | |
4923 instructions += PushArgument(); | |
4924 } | |
4925 return instructions; | |
4926 } | |
4927 | |
4928 #define STREAM_STATEMENT_IF_POSSIBLE(node) \ | |
4929 if (node->can_stream()) { \ | |
4930 fragment_ = streaming_flow_graph_builder_->BuildStatementAt( \ | |
4931 node->kernel_offset()); \ | |
4932 return; \ | |
4933 } | |
4934 | |
4935 | |
4936 void FlowGraphBuilder::VisitInvalidStatement(InvalidStatement* node) { | |
4937 fragment_ = | |
4938 streaming_flow_graph_builder_->BuildStatementAt(node->kernel_offset()); | |
4939 } | |
4940 | |
4941 | |
4942 void FlowGraphBuilder::VisitEmptyStatement(EmptyStatement* node) { | |
4943 fragment_ = | |
4944 streaming_flow_graph_builder_->BuildStatementAt(node->kernel_offset()); | |
4945 } | |
4946 | |
4947 | |
4948 void FlowGraphBuilder::VisitBlock(Block* node) { | |
4949 STREAM_STATEMENT_IF_POSSIBLE(node); | |
4950 | |
4951 Fragment instructions; | |
4952 | |
4953 instructions += EnterScope(node); | |
4954 List<Statement>& statements = node->statements(); | |
4955 for (intptr_t i = 0; (i < statements.length()) && instructions.is_open(); | |
4956 ++i) { | |
4957 instructions += TranslateStatement(statements[i]); | |
4958 } | |
4959 instructions += ExitScope(node); | |
4960 | |
4961 fragment_ = instructions; | |
4962 } | |
4963 | |
4964 | |
4965 void FlowGraphBuilder::VisitReturnStatement(ReturnStatement* node) { | |
4966 STREAM_STATEMENT_IF_POSSIBLE(node); | |
4967 | |
4968 bool inside_try_finally = try_finally_block_ != NULL; | |
4969 | |
4970 Fragment instructions = node->expression() == NULL | |
4971 ? NullConstant() | |
4972 : TranslateExpression(node->expression()); | |
4973 if (instructions.is_open()) { | |
4974 if (inside_try_finally) { | |
4975 ASSERT(scopes_->finally_return_variable != NULL); | |
4976 const Function& function = parsed_function_->function(); | |
4977 if (NeedsDebugStepCheck(function, node->position())) { | |
4978 instructions += DebugStepCheck(node->position()); | |
4979 } | |
4980 instructions += | |
4981 StoreLocal(node->position(), scopes_->finally_return_variable); | |
4982 instructions += Drop(); | |
4983 instructions += TranslateFinallyFinalizers(NULL, -1); | |
4984 if (instructions.is_open()) { | |
4985 instructions += LoadLocal(scopes_->finally_return_variable); | |
4986 instructions += Return(TokenPosition::kNoSource); | |
4987 } | |
4988 } else { | |
4989 instructions += Return(node->position()); | |
4990 } | |
4991 } else { | |
4992 Pop(); | |
4993 } | |
4994 fragment_ = instructions; | |
4995 } | |
4996 | |
4997 | |
4998 void FlowGraphBuilder::VisitExpressionStatement(ExpressionStatement* node) { | |
4999 STREAM_STATEMENT_IF_POSSIBLE(node); | |
5000 | |
5001 Fragment instructions = TranslateExpression(node->expression()); | |
5002 instructions += Drop(); | |
5003 fragment_ = instructions; | |
5004 } | |
5005 | |
5006 | |
5007 void FlowGraphBuilder::VisitVariableDeclaration(VariableDeclaration* node) { | |
5008 LocalVariable* variable = LookupVariable(node); | |
5009 Expression* initializer = node->initializer(); | |
5010 | |
5011 Fragment instructions; | |
5012 if (initializer == NULL) { | |
5013 instructions += NullConstant(); | |
5014 } else { | |
5015 if (node->IsConst()) { | |
5016 const Instance& constant_value = | |
5017 constant_evaluator_.EvaluateExpression(initializer); | |
5018 variable->SetConstValue(constant_value); | |
5019 instructions += Constant(constant_value); | |
5020 } else { | |
5021 instructions += TranslateExpression(initializer); | |
5022 instructions += CheckVariableTypeInCheckedMode(node); | |
5023 } | |
5024 } | |
5025 // Use position of equal sign if it exists. If the equal sign does not exist | |
5026 // use the position of the identifier. | |
5027 TokenPosition debug_position = | |
5028 Utils::Maximum(node->position(), node->equals_position()); | |
5029 if (NeedsDebugStepCheck(stack_, debug_position)) { | |
5030 instructions = DebugStepCheck(debug_position) + instructions; | |
5031 } | |
5032 instructions += StoreLocal(node->position(), variable); | |
5033 instructions += Drop(); | |
5034 fragment_ = instructions; | |
5035 } | |
5036 | |
5037 | |
5038 void FlowGraphBuilder::VisitFunctionDeclaration(FunctionDeclaration* node) { | |
5039 Fragment instructions = DebugStepCheck(node->position()); | |
5040 instructions += TranslateFunctionNode(node->function(), node); | |
5041 instructions += | |
5042 StoreLocal(node->position(), LookupVariable(node->variable())); | |
5043 instructions += Drop(); | |
5044 fragment_ = instructions; | |
5045 } | |
5046 | |
5047 | |
5048 void FlowGraphBuilder::VisitIfStatement(IfStatement* node) { | |
5049 STREAM_STATEMENT_IF_POSSIBLE(node); | |
5050 | |
5051 bool negate; | |
5052 Fragment instructions = TranslateCondition(node->condition(), &negate); | |
5053 TargetEntryInstr* then_entry; | |
5054 TargetEntryInstr* otherwise_entry; | |
5055 instructions += BranchIfTrue(&then_entry, &otherwise_entry, negate); | |
5056 | |
5057 Fragment then_fragment(then_entry); | |
5058 then_fragment += TranslateStatement(node->then()); | |
5059 | |
5060 Fragment otherwise_fragment(otherwise_entry); | |
5061 otherwise_fragment += TranslateStatement(node->otherwise()); | |
5062 | |
5063 if (then_fragment.is_open()) { | |
5064 if (otherwise_fragment.is_open()) { | |
5065 JoinEntryInstr* join = BuildJoinEntry(); | |
5066 then_fragment += Goto(join); | |
5067 otherwise_fragment += Goto(join); | |
5068 fragment_ = Fragment(instructions.entry, join); | |
5069 } else { | |
5070 fragment_ = Fragment(instructions.entry, then_fragment.current); | |
5071 } | |
5072 } else if (otherwise_fragment.is_open()) { | |
5073 fragment_ = Fragment(instructions.entry, otherwise_fragment.current); | |
5074 } else { | |
5075 fragment_ = instructions.closed(); | |
5076 } | |
5077 } | |
5078 | |
5079 | |
5080 void FlowGraphBuilder::VisitWhileStatement(WhileStatement* node) { | |
5081 STREAM_STATEMENT_IF_POSSIBLE(node); | |
5082 | |
5083 ++loop_depth_; | |
5084 bool negate; | |
5085 Fragment condition = TranslateCondition(node->condition(), &negate); | |
5086 TargetEntryInstr* body_entry; | |
5087 TargetEntryInstr* loop_exit; | |
5088 condition += BranchIfTrue(&body_entry, &loop_exit, negate); | |
5089 | |
5090 Fragment body(body_entry); | |
5091 body += TranslateStatement(node->body()); | |
5092 | |
5093 Instruction* entry; | |
5094 if (body.is_open()) { | |
5095 JoinEntryInstr* join = BuildJoinEntry(); | |
5096 body += Goto(join); | |
5097 | |
5098 Fragment loop(join); | |
5099 loop += CheckStackOverflow(); | |
5100 loop += condition; | |
5101 entry = new (Z) GotoInstr(join); | |
5102 } else { | |
5103 entry = condition.entry; | |
5104 } | |
5105 | |
5106 | |
5107 fragment_ = Fragment(entry, loop_exit); | |
5108 --loop_depth_; | |
5109 } | |
5110 | |
5111 | |
5112 void FlowGraphBuilder::VisitDoStatement(DoStatement* node) { | |
5113 STREAM_STATEMENT_IF_POSSIBLE(node); | |
5114 | |
5115 ++loop_depth_; | |
5116 Fragment body = TranslateStatement(node->body()); | |
5117 | |
5118 if (body.is_closed()) { | |
5119 fragment_ = body; | |
5120 --loop_depth_; | |
5121 return; | |
5122 } | |
5123 | |
5124 bool negate; | |
5125 JoinEntryInstr* join = BuildJoinEntry(); | |
5126 Fragment loop(join); | |
5127 loop += CheckStackOverflow(); | |
5128 loop += body; | |
5129 loop += TranslateCondition(node->condition(), &negate); | |
5130 TargetEntryInstr* loop_repeat; | |
5131 TargetEntryInstr* loop_exit; | |
5132 loop += BranchIfTrue(&loop_repeat, &loop_exit, negate); | |
5133 | |
5134 Fragment repeat(loop_repeat); | |
5135 repeat += Goto(join); | |
5136 | |
5137 fragment_ = Fragment(new (Z) GotoInstr(join), loop_exit); | |
5138 --loop_depth_; | |
5139 } | |
5140 | |
5141 | |
5142 void FlowGraphBuilder::VisitForStatement(ForStatement* node) { | |
5143 STREAM_STATEMENT_IF_POSSIBLE(node); | |
5144 | |
5145 Fragment declarations; | |
5146 | |
5147 bool new_context = false; | |
5148 declarations += EnterScope(node, &new_context); | |
5149 | |
5150 List<VariableDeclaration>& variables = node->variables(); | |
5151 for (intptr_t i = 0; i < variables.length(); ++i) { | |
5152 declarations += TranslateStatement(variables[i]); | |
5153 } | |
5154 | |
5155 ++loop_depth_; | |
5156 bool negate = false; | |
5157 Fragment condition = node->condition() == NULL | |
5158 ? Constant(Bool::True()) | |
5159 : TranslateCondition(node->condition(), &negate); | |
5160 TargetEntryInstr* body_entry; | |
5161 TargetEntryInstr* loop_exit; | |
5162 condition += BranchIfTrue(&body_entry, &loop_exit, negate); | |
5163 | |
5164 Fragment body(body_entry); | |
5165 body += TranslateStatement(node->body()); | |
5166 | |
5167 if (body.is_open()) { | |
5168 // We allocated a fresh context before the loop which contains captured | |
5169 // [ForStatement] variables. Before jumping back to the loop entry we clone | |
5170 // the context object (at same depth) which ensures the next iteration of | |
5171 // the body gets a fresh set of [ForStatement] variables (with the old | |
5172 // (possibly updated) values). | |
5173 if (new_context) body += CloneContext(); | |
5174 | |
5175 List<Expression>& updates = node->updates(); | |
5176 for (intptr_t i = 0; i < updates.length(); ++i) { | |
5177 body += TranslateExpression(updates[i]); | |
5178 body += Drop(); | |
5179 } | |
5180 JoinEntryInstr* join = BuildJoinEntry(); | |
5181 declarations += Goto(join); | |
5182 body += Goto(join); | |
5183 | |
5184 Fragment loop(join); | |
5185 loop += CheckStackOverflow(); | |
5186 loop += condition; | |
5187 } else { | |
5188 declarations += condition; | |
5189 } | |
5190 | |
5191 Fragment loop(declarations.entry, loop_exit); | |
5192 --loop_depth_; | |
5193 | |
5194 loop += ExitScope(node); | |
5195 | |
5196 fragment_ = loop; | |
5197 } | |
5198 | |
5199 | |
5200 void FlowGraphBuilder::VisitForInStatement(ForInStatement* node) { | |
5201 STREAM_STATEMENT_IF_POSSIBLE(node); | |
5202 | |
5203 Fragment instructions = TranslateExpression(node->iterable()); | |
5204 instructions += PushArgument(); | |
5205 | |
5206 const dart::String& iterator_getter = dart::String::ZoneHandle( | |
5207 Z, dart::Field::GetterSymbol(Symbols::Iterator())); | |
5208 instructions += InstanceCall(node->iterable()->position(), iterator_getter, | |
5209 Token::kGET, 1); | |
5210 LocalVariable* iterator = scopes_->iterator_variables[for_in_depth_]; | |
5211 instructions += StoreLocal(TokenPosition::kNoSource, iterator); | |
5212 instructions += Drop(); | |
5213 | |
5214 ++for_in_depth_; | |
5215 ++loop_depth_; | |
5216 Fragment condition = LoadLocal(iterator); | |
5217 condition += PushArgument(); | |
5218 condition += InstanceCall(node->iterable()->position(), Symbols::MoveNext(), | |
5219 Token::kILLEGAL, 1); | |
5220 TargetEntryInstr* body_entry; | |
5221 TargetEntryInstr* loop_exit; | |
5222 condition += BranchIfTrue(&body_entry, &loop_exit); | |
5223 | |
5224 Fragment body(body_entry); | |
5225 body += EnterScope(node); | |
5226 body += LoadLocal(iterator); | |
5227 body += PushArgument(); | |
5228 const dart::String& current_getter = dart::String::ZoneHandle( | |
5229 Z, dart::Field::GetterSymbol(Symbols::Current())); | |
5230 body += InstanceCall(node->position(), current_getter, Token::kGET, 1); | |
5231 body += | |
5232 StoreLocal(TokenPosition::kNoSource, LookupVariable(node->variable())); | |
5233 body += Drop(); | |
5234 body += TranslateStatement(node->body()); | |
5235 body += ExitScope(node); | |
5236 | |
5237 if (body.is_open()) { | |
5238 JoinEntryInstr* join = BuildJoinEntry(); | |
5239 instructions += Goto(join); | |
5240 body += Goto(join); | |
5241 | |
5242 Fragment loop(join); | |
5243 loop += CheckStackOverflow(); | |
5244 loop += condition; | |
5245 } else { | |
5246 instructions += condition; | |
5247 } | |
5248 | |
5249 fragment_ = Fragment(instructions.entry, loop_exit); | |
5250 --loop_depth_; | |
5251 --for_in_depth_; | |
5252 } | |
5253 | |
5254 | |
5255 void FlowGraphBuilder::VisitLabeledStatement(LabeledStatement* node) { | |
5256 STREAM_STATEMENT_IF_POSSIBLE(node); | |
5257 | |
5258 // There can be serveral cases: | |
5259 // | |
5260 // * the body contains a break | |
5261 // * the body doesn't contain a break | |
5262 // | |
5263 // * translating the body results in a closed fragment | |
5264 // * translating the body results in a open fragment | |
5265 // | |
5266 // => We will only know which case we are in after the body has been | |
5267 // traversed. | |
5268 | |
5269 BreakableBlock block(this); | |
5270 Fragment instructions = TranslateStatement(node->body()); | |
5271 if (block.HadJumper()) { | |
5272 if (instructions.is_open()) { | |
5273 instructions += Goto(block.destination()); | |
5274 } | |
5275 fragment_ = Fragment(instructions.entry, block.destination()); | |
5276 } else { | |
5277 fragment_ = instructions; | |
5278 } | |
5279 } | |
5280 | |
5281 | |
5282 void FlowGraphBuilder::VisitBreakStatement(BreakStatement* node) { | |
5283 fragment_ = | |
5284 streaming_flow_graph_builder_->BuildStatementAt(node->kernel_offset()); | |
5285 } | |
5286 | |
5287 | |
5288 void FlowGraphBuilder::VisitSwitchStatement(SwitchStatement* node) { | |
5289 STREAM_STATEMENT_IF_POSSIBLE(node); | |
5290 | |
5291 SwitchBlock block(this, node->cases().length()); | |
5292 | |
5293 // Instead of using a variable we should reuse the expression on the stack, | |
5294 // since it won't be assigned again, we don't need phi nodes. | |
5295 Fragment head_instructions = TranslateExpression(node->condition()); | |
5296 head_instructions += | |
5297 StoreLocal(TokenPosition::kNoSource, scopes_->switch_variable); | |
5298 head_instructions += Drop(); | |
5299 | |
5300 // Phase 1: Generate bodies and try to find out whether a body will be target | |
5301 // of a jump due to: | |
5302 // * `continue case_label` | |
5303 // * `case e1: case e2: body` | |
5304 Fragment* body_fragments = new Fragment[node->cases().length()]; | |
5305 | |
5306 intptr_t num_cases = node->cases().length(); | |
5307 for (intptr_t i = 0; i < num_cases; i++) { | |
5308 SwitchCase* switch_case = node->cases()[i]; | |
5309 Fragment& body_fragment = body_fragments[i] = | |
5310 TranslateStatement(switch_case->body()); | |
5311 | |
5312 if (body_fragment.entry == NULL) { | |
5313 // Make a NOP in order to ensure linking works properly. | |
5314 body_fragment = NullConstant(); | |
5315 body_fragment += Drop(); | |
5316 } | |
5317 | |
5318 // The Dart language specification mandates fall-throughs in [SwitchCase]es | |
5319 // to be runtime errors. | |
5320 if (!switch_case->is_default() && body_fragment.is_open() && | |
5321 (i < (node->cases().length() - 1))) { | |
5322 const dart::Class& klass = dart::Class::ZoneHandle( | |
5323 Z, dart::Library::LookupCoreClass(Symbols::FallThroughError())); | |
5324 ASSERT(!klass.IsNull()); | |
5325 const Function& constructor = Function::ZoneHandle( | |
5326 Z, klass.LookupConstructorAllowPrivate( | |
5327 H.DartSymbol("FallThroughError._create"))); | |
5328 ASSERT(!constructor.IsNull()); | |
5329 const dart::String& url = H.DartString( | |
5330 parsed_function_->function().ToLibNamePrefixedQualifiedCString(), | |
5331 Heap::kOld); | |
5332 | |
5333 // Create instance of _FallThroughError | |
5334 body_fragment += AllocateObject(klass, 0); | |
5335 LocalVariable* instance = MakeTemporary(); | |
5336 | |
5337 // Call _FallThroughError._create constructor. | |
5338 body_fragment += LoadLocal(instance); | |
5339 body_fragment += PushArgument(); // this | |
5340 | |
5341 body_fragment += Constant(url); | |
5342 body_fragment += PushArgument(); // url | |
5343 | |
5344 body_fragment += NullConstant(); | |
5345 body_fragment += PushArgument(); // line | |
5346 | |
5347 body_fragment += StaticCall(TokenPosition::kNoSource, constructor, 3); | |
5348 body_fragment += Drop(); | |
5349 | |
5350 // Throw the exception | |
5351 body_fragment += PushArgument(); | |
5352 body_fragment += ThrowException(TokenPosition::kNoSource); | |
5353 body_fragment += Drop(); | |
5354 } | |
5355 | |
5356 // If there is an implicit fall-through we have one [SwitchCase] and | |
5357 // multiple expressions, e.g. | |
5358 // | |
5359 // switch(expr) { | |
5360 // case a: | |
5361 // case b: | |
5362 // <stmt-body> | |
5363 // } | |
5364 // | |
5365 // This means that the <stmt-body> will have more than 1 incoming edge (one | |
5366 // from `a == expr` and one from `a != expr && b == expr`). The | |
5367 // `block.Destination()` records the additional jump. | |
5368 if (switch_case->expressions().length() > 1) { | |
5369 block.DestinationDirect(i); | |
5370 } | |
5371 } | |
5372 | |
5373 // Phase 2: Generate everything except the real bodies: | |
5374 // * jump directly to a body (if there is no jumper) | |
5375 // * jump to a wrapper block which jumps to the body (if there is a jumper) | |
5376 Fragment current_instructions = head_instructions; | |
5377 for (intptr_t i = 0; i < num_cases; i++) { | |
5378 SwitchCase* switch_case = node->cases()[i]; | |
5379 | |
5380 if (switch_case->is_default()) { | |
5381 ASSERT(i == (node->cases().length() - 1)); | |
5382 | |
5383 // Evaluate the conditions for the default [SwitchCase] just for the | |
5384 // purpose of potentially triggering a compile-time error. | |
5385 for (intptr_t k = 0; k < switch_case->expressions().length(); k++) { | |
5386 constant_evaluator_.EvaluateExpression(switch_case->expressions()[k]); | |
5387 } | |
5388 | |
5389 if (block.HadJumper(i)) { | |
5390 // There are several branches to the body, so we will make a goto to | |
5391 // the join block (and prepend a join instruction to the real body). | |
5392 JoinEntryInstr* join = block.DestinationDirect(i); | |
5393 current_instructions += Goto(join); | |
5394 | |
5395 current_instructions = Fragment(current_instructions.entry, join); | |
5396 current_instructions += body_fragments[i]; | |
5397 } else { | |
5398 current_instructions += body_fragments[i]; | |
5399 } | |
5400 } else { | |
5401 JoinEntryInstr* body_join = NULL; | |
5402 if (block.HadJumper(i)) { | |
5403 body_join = block.DestinationDirect(i); | |
5404 body_fragments[i] = Fragment(body_join) + body_fragments[i]; | |
5405 } | |
5406 | |
5407 for (intptr_t j = 0; j < switch_case->expressions().length(); j++) { | |
5408 TargetEntryInstr* then; | |
5409 TargetEntryInstr* otherwise; | |
5410 | |
5411 Expression* expression = switch_case->expressions()[j]; | |
5412 current_instructions += | |
5413 Constant(constant_evaluator_.EvaluateExpression(expression)); | |
5414 current_instructions += PushArgument(); | |
5415 current_instructions += LoadLocal(scopes_->switch_variable); | |
5416 current_instructions += PushArgument(); | |
5417 current_instructions += InstanceCall( | |
5418 expression->position(), Symbols::EqualOperator(), Token::kEQ, | |
5419 /*argument_count=*/2, | |
5420 /*num_args_checked=*/2); | |
5421 current_instructions += BranchIfTrue(&then, &otherwise); | |
5422 | |
5423 Fragment then_fragment(then); | |
5424 | |
5425 if (body_join != NULL) { | |
5426 // There are several branches to the body, so we will make a goto to | |
5427 // the join block (the real body has already been prepended with a | |
5428 // join instruction). | |
5429 then_fragment += Goto(body_join); | |
5430 } else { | |
5431 // There is only a signle branch to the body, so we will just append | |
5432 // the body fragment. | |
5433 then_fragment += body_fragments[i]; | |
5434 } | |
5435 | |
5436 current_instructions = Fragment(otherwise); | |
5437 } | |
5438 } | |
5439 } | |
5440 | |
5441 bool has_no_default = | |
5442 num_cases > 0 && !node->cases()[num_cases - 1]->is_default(); | |
5443 if (has_no_default) { | |
5444 // There is no default, which means we have an open [current_instructions] | |
5445 // (which is a [TargetEntryInstruction] for the last "otherwise" branch). | |
5446 // | |
5447 // Furthermore the last [SwitchCase] can be open as well. If so, we need | |
5448 // to join these two. | |
5449 Fragment& last_body = body_fragments[node->cases().length() - 1]; | |
5450 if (last_body.is_open()) { | |
5451 ASSERT(current_instructions.is_open()); | |
5452 ASSERT(current_instructions.current->IsTargetEntry()); | |
5453 | |
5454 // Join the last "otherwise" branch and the last [SwitchCase] fragment. | |
5455 JoinEntryInstr* join = BuildJoinEntry(); | |
5456 current_instructions += Goto(join); | |
5457 last_body += Goto(join); | |
5458 | |
5459 current_instructions = Fragment(join); | |
5460 } | |
5461 } else { | |
5462 // All non-default cases will be closed (i.e. break/continue/throw/return) | |
5463 // So it is fine to just let more statements after the switch append to the | |
5464 // default case. | |
5465 } | |
5466 | |
5467 delete[] body_fragments; | |
5468 | |
5469 fragment_ = Fragment(head_instructions.entry, current_instructions.current); | |
5470 } | |
5471 | |
5472 | |
5473 void FlowGraphBuilder::VisitContinueSwitchStatement( | |
5474 ContinueSwitchStatement* node) { | |
5475 fragment_ = | |
5476 streaming_flow_graph_builder_->BuildStatementAt(node->kernel_offset()); | |
5477 } | |
5478 | |
5479 | |
5480 void FlowGraphBuilder::VisitAssertStatement(AssertStatement* node) { | |
5481 STREAM_STATEMENT_IF_POSSIBLE(node); | |
5482 | |
5483 if (!I->asserts()) { | |
5484 fragment_ = Fragment(); | |
5485 return; | |
5486 } | |
5487 | |
5488 TargetEntryInstr* then; | |
5489 TargetEntryInstr* otherwise; | |
5490 | |
5491 Fragment instructions; | |
5492 // Asserts can be of the following two kinds: | |
5493 // | |
5494 // * `assert(expr)` | |
5495 // * `assert(() { ... })` | |
5496 // | |
5497 // The call to `_AssertionError._evaluateAssertion()` will take care of both | |
5498 // and returns a boolean. | |
5499 instructions += TranslateExpression(node->condition()); | |
5500 instructions += PushArgument(); | |
5501 instructions += EvaluateAssertion(); | |
5502 instructions += CheckBooleanInCheckedMode(); | |
5503 instructions += Constant(Bool::True()); | |
5504 instructions += BranchIfEqual(&then, &otherwise, false); | |
5505 | |
5506 const dart::Class& klass = dart::Class::ZoneHandle( | |
5507 Z, dart::Library::LookupCoreClass(Symbols::AssertionError())); | |
5508 ASSERT(!klass.IsNull()); | |
5509 const Function& constructor = | |
5510 Function::ZoneHandle(Z, klass.LookupConstructorAllowPrivate( | |
5511 H.DartSymbol("_AssertionError._create"))); | |
5512 ASSERT(!constructor.IsNull()); | |
5513 | |
5514 const dart::String& url = H.DartString( | |
5515 parsed_function_->function().ToLibNamePrefixedQualifiedCString(), | |
5516 Heap::kOld); | |
5517 | |
5518 // Create instance of _AssertionError | |
5519 Fragment otherwise_fragment(otherwise); | |
5520 otherwise_fragment += AllocateObject(klass, 0); | |
5521 LocalVariable* instance = MakeTemporary(); | |
5522 | |
5523 // Call _AssertionError._create constructor. | |
5524 otherwise_fragment += LoadLocal(instance); | |
5525 otherwise_fragment += PushArgument(); // this | |
5526 | |
5527 otherwise_fragment += Constant(H.DartString("<no message>", Heap::kOld)); | |
5528 otherwise_fragment += PushArgument(); // failedAssertion | |
5529 | |
5530 otherwise_fragment += Constant(url); | |
5531 otherwise_fragment += PushArgument(); // url | |
5532 | |
5533 otherwise_fragment += IntConstant(0); | |
5534 otherwise_fragment += PushArgument(); // line | |
5535 | |
5536 otherwise_fragment += IntConstant(0); | |
5537 otherwise_fragment += PushArgument(); // column | |
5538 | |
5539 otherwise_fragment += | |
5540 node->message() != NULL | |
5541 ? TranslateExpression(node->message()) | |
5542 : Constant(H.DartString("<no message>", Heap::kOld)); | |
5543 otherwise_fragment += PushArgument(); // message | |
5544 | |
5545 otherwise_fragment += StaticCall(TokenPosition::kNoSource, constructor, 6); | |
5546 otherwise_fragment += Drop(); | |
5547 | |
5548 // Throw _AssertionError exception. | |
5549 otherwise_fragment += PushArgument(); | |
5550 otherwise_fragment += ThrowException(TokenPosition::kNoSource); | |
5551 otherwise_fragment += Drop(); | |
5552 | |
5553 fragment_ = Fragment(instructions.entry, then); | |
5554 } | |
5555 | |
5556 | |
5557 void FlowGraphBuilder::VisitTryFinally(TryFinally* node) { | |
5558 STREAM_STATEMENT_IF_POSSIBLE(node); | |
5559 | |
5560 InlineBailout("kernel::FlowgraphBuilder::VisitTryFinally"); | |
5561 | |
5562 // There are 5 different cases where we need to execute the finally block: | |
5563 // | |
5564 // a) 1/2/3th case: Special control flow going out of `node->body()`: | |
5565 // | |
5566 // * [BreakStatement] transfers control to a [LabledStatement] | |
5567 // * [ContinueSwitchStatement] transfers control to a [SwitchCase] | |
5568 // * [ReturnStatement] returns a value | |
5569 // | |
5570 // => All three cases will automatically append all finally blocks | |
5571 // between the branching point and the destination (so we don't need to | |
5572 // do anything here). | |
5573 // | |
5574 // b) 4th case: Translating the body resulted in an open fragment (i.e. body | |
5575 // executes without any control flow out of it) | |
5576 // | |
5577 // => We are responsible for jumping out of the body to a new block (with | |
5578 // different try index) and execute the finalizer. | |
5579 // | |
5580 // c) 5th case: An exception occured inside the body. | |
5581 // | |
5582 // => We are responsible for catching it, executing the finally block and | |
5583 // rethrowing the exception. | |
5584 intptr_t try_handler_index = AllocateTryIndex(); | |
5585 Fragment try_body = TryCatch(try_handler_index); | |
5586 JoinEntryInstr* after_try = BuildJoinEntry(); | |
5587 | |
5588 // Fill in the body of the try. | |
5589 ++try_depth_; | |
5590 { | |
5591 TryFinallyBlock tfb(this, node->finalizer(), -1); | |
5592 TryCatchBlock tcb(this, try_handler_index); | |
5593 try_body += TranslateStatement(node->body()); | |
5594 } | |
5595 --try_depth_; | |
5596 | |
5597 if (try_body.is_open()) { | |
5598 // Please note: The try index will be on level out of this block, | |
5599 // thereby ensuring if there's an exception in the finally block we | |
5600 // won't run it twice. | |
5601 JoinEntryInstr* finally_entry = BuildJoinEntry(); | |
5602 | |
5603 try_body += Goto(finally_entry); | |
5604 | |
5605 Fragment finally_body(finally_entry); | |
5606 finally_body += TranslateStatement(node->finalizer()); | |
5607 finally_body += Goto(after_try); | |
5608 } | |
5609 | |
5610 // Fill in the body of the catch. | |
5611 ++catch_depth_; | |
5612 const Array& handler_types = Array::ZoneHandle(Z, Array::New(1, Heap::kOld)); | |
5613 handler_types.SetAt(0, Object::dynamic_type()); | |
5614 // Note: rethrow will actually force mark the handler as needing a stacktrace. | |
5615 Fragment finally_body = CatchBlockEntry(handler_types, try_handler_index, | |
5616 /* needs_stacktrace = */ false); | |
5617 finally_body += TranslateStatement(node->finalizer()); | |
5618 if (finally_body.is_open()) { | |
5619 finally_body += LoadLocal(CurrentException()); | |
5620 finally_body += PushArgument(); | |
5621 finally_body += LoadLocal(CurrentStackTrace()); | |
5622 finally_body += PushArgument(); | |
5623 finally_body += | |
5624 RethrowException(TokenPosition::kNoSource, try_handler_index); | |
5625 Drop(); | |
5626 } | |
5627 --catch_depth_; | |
5628 | |
5629 fragment_ = Fragment(try_body.entry, after_try); | |
5630 } | |
5631 | |
5632 | |
5633 void FlowGraphBuilder::VisitTryCatch(class TryCatch* node) { | |
5634 STREAM_STATEMENT_IF_POSSIBLE(node); | |
5635 | |
5636 InlineBailout("kernel::FlowgraphBuilder::VisitTryCatch"); | |
5637 | |
5638 intptr_t try_handler_index = AllocateTryIndex(); | |
5639 Fragment try_body = TryCatch(try_handler_index); | |
5640 JoinEntryInstr* after_try = BuildJoinEntry(); | |
5641 | |
5642 // Fill in the body of the try. | |
5643 ++try_depth_; | |
5644 { | |
5645 TryCatchBlock block(this, try_handler_index); | |
5646 try_body += TranslateStatement(node->body()); | |
5647 try_body += Goto(after_try); | |
5648 } | |
5649 --try_depth_; | |
5650 | |
5651 ++catch_depth_; | |
5652 const Array& handler_types = | |
5653 Array::ZoneHandle(Z, Array::New(node->catches().length(), Heap::kOld)); | |
5654 bool needs_stacktrace = false; | |
5655 for (intptr_t i = 0; i < node->catches().length(); i++) { | |
5656 if (node->catches()[i]->stack_trace() != NULL) { | |
5657 needs_stacktrace = true; | |
5658 break; | |
5659 } | |
5660 } | |
5661 Fragment catch_body = | |
5662 CatchBlockEntry(handler_types, try_handler_index, needs_stacktrace); | |
5663 // Fill in the body of the catch. | |
5664 for (intptr_t i = 0; i < node->catches().length(); i++) { | |
5665 Catch* catch_clause = node->catches()[i]; | |
5666 | |
5667 Fragment catch_handler_body; | |
5668 | |
5669 catch_handler_body += EnterScope(catch_clause); | |
5670 | |
5671 if (catch_clause->exception() != NULL) { | |
5672 catch_handler_body += LoadLocal(CurrentException()); | |
5673 catch_handler_body += StoreLocal( | |
5674 TokenPosition::kNoSource, LookupVariable(catch_clause->exception())); | |
5675 catch_handler_body += Drop(); | |
5676 } | |
5677 if (catch_clause->stack_trace() != NULL) { | |
5678 catch_handler_body += LoadLocal(CurrentStackTrace()); | |
5679 catch_handler_body += | |
5680 StoreLocal(TokenPosition::kNoSource, | |
5681 LookupVariable(catch_clause->stack_trace())); | |
5682 catch_handler_body += Drop(); | |
5683 } | |
5684 AbstractType* type_guard = NULL; | |
5685 if (catch_clause->guard() != NULL && | |
5686 !catch_clause->guard()->IsDynamicType()) { | |
5687 type_guard = &T.TranslateType(catch_clause->guard()); | |
5688 handler_types.SetAt(i, *type_guard); | |
5689 } else { | |
5690 handler_types.SetAt(i, Object::dynamic_type()); | |
5691 } | |
5692 | |
5693 { | |
5694 CatchBlock block(this, CurrentException(), CurrentStackTrace(), | |
5695 try_handler_index); | |
5696 | |
5697 catch_handler_body += TranslateStatement(catch_clause->body()); | |
5698 | |
5699 // Note: ExitScope adjusts context_depth_ so even if catch_handler_body | |
5700 // is closed we still need to execute ExitScope for its side effect. | |
5701 catch_handler_body += ExitScope(catch_clause); | |
5702 if (catch_handler_body.is_open()) { | |
5703 catch_handler_body += Goto(after_try); | |
5704 } | |
5705 } | |
5706 | |
5707 if (type_guard != NULL) { | |
5708 if (type_guard->IsMalformed()) { | |
5709 catch_body += ThrowTypeError(); | |
5710 catch_body += Drop(); | |
5711 } else { | |
5712 catch_body += LoadLocal(CurrentException()); | |
5713 catch_body += PushArgument(); // exception | |
5714 catch_body += NullConstant(); | |
5715 catch_body += PushArgument(); // instantiator type arguments | |
5716 catch_body += NullConstant(); | |
5717 catch_body += PushArgument(); // function type arguments | |
5718 catch_body += Constant(*type_guard); | |
5719 catch_body += PushArgument(); // guard type | |
5720 catch_body += InstanceCall( | |
5721 TokenPosition::kNoSource, | |
5722 dart::Library::PrivateCoreLibName(Symbols::_instanceOf()), | |
5723 Token::kIS, 4); | |
5724 | |
5725 TargetEntryInstr* catch_entry; | |
5726 TargetEntryInstr* next_catch_entry; | |
5727 catch_body += BranchIfTrue(&catch_entry, &next_catch_entry); | |
5728 | |
5729 Fragment(catch_entry) + catch_handler_body; | |
5730 catch_body = Fragment(next_catch_entry); | |
5731 } | |
5732 } else { | |
5733 catch_body += catch_handler_body; | |
5734 } | |
5735 } | |
5736 | |
5737 // In case the last catch body was not handling the exception and branching to | |
5738 // after the try block, we will rethrow the exception (i.e. no default catch | |
5739 // handler). | |
5740 if (catch_body.is_open()) { | |
5741 catch_body += LoadLocal(CurrentException()); | |
5742 catch_body += PushArgument(); | |
5743 catch_body += LoadLocal(CurrentStackTrace()); | |
5744 catch_body += PushArgument(); | |
5745 catch_body += RethrowException(TokenPosition::kNoSource, try_handler_index); | |
5746 Drop(); | |
5747 } | |
5748 --catch_depth_; | |
5749 | |
5750 fragment_ = Fragment(try_body.entry, after_try); | |
5751 } | |
5752 | |
5753 | |
5754 void FlowGraphBuilder::VisitYieldStatement(YieldStatement* node) { | |
5755 STREAM_STATEMENT_IF_POSSIBLE(node); | |
5756 | |
5757 ASSERT(node->is_native()); // Must have been desugared. | |
5758 // Setup yield/continue point: | |
5759 // | |
5760 // ... | |
5761 // :await_jump_var = index; | |
5762 // :await_ctx_var = :current_context_var | |
5763 // return <expr> | |
5764 // | |
5765 // Continuation<index>: | |
5766 // Drop(1) | |
5767 // ... | |
5768 // | |
5769 // BuildGraphOfFunction will create a dispatch that jumps to | |
5770 // Continuation<:await_jump_var> upon entry to the function. | |
5771 // | |
5772 Fragment instructions = IntConstant(yield_continuations_.length() + 1); | |
5773 instructions += | |
5774 StoreLocal(TokenPosition::kNoSource, scopes_->yield_jump_variable); | |
5775 instructions += Drop(); | |
5776 instructions += LoadLocal(parsed_function_->current_context_var()); | |
5777 instructions += | |
5778 StoreLocal(TokenPosition::kNoSource, scopes_->yield_context_variable); | |
5779 instructions += Drop(); | |
5780 instructions += TranslateExpression(node->expression()); | |
5781 instructions += Return(TokenPosition::kNoSource); | |
5782 | |
5783 // Note: DropTempsInstr serves as an anchor instruction. It will not | |
5784 // be linked into the resulting graph. | |
5785 DropTempsInstr* anchor = new (Z) DropTempsInstr(0, NULL); | |
5786 yield_continuations_.Add(YieldContinuation(anchor, CurrentTryIndex())); | |
5787 | |
5788 Fragment continuation(instructions.entry, anchor); | |
5789 | |
5790 if (parsed_function_->function().IsAsyncClosure() || | |
5791 parsed_function_->function().IsAsyncGenClosure()) { | |
5792 // If function is async closure or async gen closure it takes three | |
5793 // parameters where the second and the third are exception and stack_trace. | |
5794 // Check if exception is non-null and rethrow it. | |
5795 // | |
5796 // :async_op([:result, :exception, :stack_trace]) { | |
5797 // ... | |
5798 // Continuation<index>: | |
5799 // if (:exception != null) rethrow(:exception, :stack_trace); | |
5800 // ... | |
5801 // } | |
5802 // | |
5803 LocalScope* scope = parsed_function_->node_sequence()->scope(); | |
5804 LocalVariable* exception_var = scope->VariableAt(2); | |
5805 LocalVariable* stack_trace_var = scope->VariableAt(3); | |
5806 ASSERT(exception_var->name().raw() == Symbols::ExceptionParameter().raw()); | |
5807 ASSERT(stack_trace_var->name().raw() == | |
5808 Symbols::StackTraceParameter().raw()); | |
5809 | |
5810 TargetEntryInstr* no_error; | |
5811 TargetEntryInstr* error; | |
5812 | |
5813 continuation += LoadLocal(exception_var); | |
5814 continuation += BranchIfNull(&no_error, &error); | |
5815 | |
5816 Fragment rethrow(error); | |
5817 rethrow += LoadLocal(exception_var); | |
5818 rethrow += PushArgument(); | |
5819 rethrow += LoadLocal(stack_trace_var); | |
5820 rethrow += PushArgument(); | |
5821 rethrow += | |
5822 RethrowException(node->position(), CatchClauseNode::kInvalidTryIndex); | |
5823 Drop(); | |
5824 | |
5825 | |
5826 continuation = Fragment(continuation.entry, no_error); | |
5827 } | |
5828 | |
5829 fragment_ = continuation; | |
5830 } | |
5831 | |
5832 | |
5833 Fragment FlowGraphBuilder::TranslateFunctionNode(FunctionNode* node, | |
5834 TreeNode* parent) { | |
5835 // The VM has a per-isolate table of functions indexed by the enclosing | |
5836 // function and token position. | |
5837 Function& function = Function::ZoneHandle(Z); | |
5838 for (intptr_t i = 0; i < scopes_->function_scopes.length(); ++i) { | |
5839 if (scopes_->function_scopes[i].kernel_offset != node->kernel_offset()) { | |
5840 continue; | |
5841 } | |
5842 | |
5843 TokenPosition position = node->position(); | |
5844 if (parent->IsFunctionDeclaration()) { | |
5845 position = FunctionDeclaration::Cast(parent)->position(); | |
5846 } | |
5847 if (!position.IsReal()) { | |
5848 // Positions has to be unique in regards to the parent. | |
5849 // A non-real at this point is probably -1, we cannot blindly use that | |
5850 // as others might use it too. Create a new dummy non-real TokenPosition. | |
5851 position = TokenPosition(i).ToSynthetic(); | |
5852 } | |
5853 | |
5854 // NOTE: This is not TokenPosition in the general sense! | |
5855 function = I->LookupClosureFunction(parsed_function_->function(), position); | |
5856 if (function.IsNull()) { | |
5857 const dart::String* name; | |
5858 if (parent->IsFunctionExpression()) { | |
5859 name = &Symbols::AnonymousClosure(); | |
5860 } else { | |
5861 ASSERT(parent->IsFunctionDeclaration()); | |
5862 name = &H.DartSymbol( | |
5863 FunctionDeclaration::Cast(parent)->variable()->name()); | |
5864 } | |
5865 // NOTE: This is not TokenPosition in the general sense! | |
5866 function = Function::NewClosureFunction( | |
5867 *name, parsed_function_->function(), position); | |
5868 | |
5869 function.set_is_debuggable(node->dart_async_marker() == | |
5870 FunctionNode::kSync); | |
5871 switch (node->dart_async_marker()) { | |
5872 case FunctionNode::kSyncStar: | |
5873 function.set_modifier(RawFunction::kSyncGen); | |
5874 break; | |
5875 case FunctionNode::kAsync: | |
5876 function.set_modifier(RawFunction::kAsync); | |
5877 function.set_is_inlinable(!FLAG_causal_async_stacks); | |
5878 break; | |
5879 case FunctionNode::kAsyncStar: | |
5880 function.set_modifier(RawFunction::kAsyncGen); | |
5881 function.set_is_inlinable(!FLAG_causal_async_stacks); | |
5882 break; | |
5883 default: | |
5884 // no special modifier | |
5885 break; | |
5886 } | |
5887 function.set_is_generated_body(node->async_marker() == | |
5888 FunctionNode::kSyncYielding); | |
5889 if (function.IsAsyncClosure() || function.IsAsyncGenClosure()) { | |
5890 function.set_is_inlinable(!FLAG_causal_async_stacks); | |
5891 } | |
5892 | |
5893 function.set_end_token_pos(node->end_position()); | |
5894 LocalScope* scope = scopes_->function_scopes[i].scope; | |
5895 const ContextScope& context_scope = | |
5896 ContextScope::Handle(Z, scope->PreserveOuterScope(context_depth_)); | |
5897 function.set_context_scope(context_scope); | |
5898 function.set_kernel_function(node); | |
5899 KernelReader::SetupFunctionParameters(H, T, dart::Class::Handle(Z), | |
5900 function, node, | |
5901 false, // is_method | |
5902 true); // is_closure | |
5903 // Finalize function type. | |
5904 Type& signature_type = Type::Handle(Z, function.SignatureType()); | |
5905 signature_type ^= | |
5906 ClassFinalizer::FinalizeType(*active_class_.klass, signature_type); | |
5907 function.SetSignatureType(signature_type); | |
5908 | |
5909 I->AddClosureFunction(function); | |
5910 } | |
5911 break; | |
5912 } | |
5913 | |
5914 const dart::Class& closure_class = | |
5915 dart::Class::ZoneHandle(Z, I->object_store()->closure_class()); | |
5916 ASSERT(!closure_class.IsNull()); | |
5917 Fragment instructions = AllocateObject(closure_class, function); | |
5918 LocalVariable* closure = MakeTemporary(); | |
5919 | |
5920 // TODO(27590): Generic closures need type arguments. | |
5921 | |
5922 // Store the function and the context in the closure. | |
5923 instructions += LoadLocal(closure); | |
5924 instructions += Constant(function); | |
5925 instructions += | |
5926 StoreInstanceField(TokenPosition::kNoSource, Closure::function_offset()); | |
5927 | |
5928 instructions += LoadLocal(closure); | |
5929 instructions += LoadLocal(parsed_function_->current_context_var()); | |
5930 instructions += | |
5931 StoreInstanceField(TokenPosition::kNoSource, Closure::context_offset()); | |
5932 | |
5933 return instructions; | |
5934 } | |
5935 | |
5936 | |
5937 RawObject* EvaluateMetadata(const dart::Field& metadata_field) { | 2659 RawObject* EvaluateMetadata(const dart::Field& metadata_field) { |
2660 // TODO(jensj) | |
Kevin Millikin (Google)
2017/06/12 12:01:51
TODO what?
jensj
2017/06/13 13:42:14
(as below)
| |
5938 LongJumpScope jump; | 2661 LongJumpScope jump; |
5939 if (setjmp(*jump.Set()) == 0) { | 2662 if (setjmp(*jump.Set()) == 0) { |
5940 Thread* thread = Thread::Current(); | 2663 Thread* thread = Thread::Current(); |
5941 Zone* zone_ = thread->zone(); | 2664 Zone* zone_ = thread->zone(); |
5942 | |
5943 TreeNode* kernel_node = | |
5944 reinterpret_cast<TreeNode*>(metadata_field.kernel_field()); | |
5945 List<Expression>* metadata_expressions = NULL; | |
5946 if (kernel_node->IsClass()) { | |
5947 metadata_expressions = &Class::Cast(kernel_node)->annotations(); | |
5948 } else if (kernel_node->IsProcedure()) { | |
5949 metadata_expressions = &Procedure::Cast(kernel_node)->annotations(); | |
5950 } else if (kernel_node->IsField()) { | |
5951 metadata_expressions = &Field::Cast(kernel_node)->annotations(); | |
5952 } else if (kernel_node->IsConstructor()) { | |
5953 metadata_expressions = &Constructor::Cast(kernel_node)->annotations(); | |
5954 } else { | |
5955 FATAL1("No support for metadata on this type of kernel node %p\n", | |
5956 kernel_node); | |
5957 } | |
5958 | |
5959 TranslationHelper helper(thread); | 2665 TranslationHelper helper(thread); |
5960 Script& script = Script::Handle(Z, metadata_field.Script()); | 2666 Script& script = Script::Handle(Z, metadata_field.Script()); |
5961 helper.SetStringOffsets( | 2667 helper.SetStringOffsets( |
5962 TypedData::Handle(Z, script.kernel_string_offsets())); | 2668 TypedData::Handle(Z, script.kernel_string_offsets())); |
5963 helper.SetStringData(TypedData::Handle(Z, script.kernel_string_data())); | 2669 helper.SetStringData(TypedData::Handle(Z, script.kernel_string_data())); |
5964 helper.SetCanonicalNames( | 2670 helper.SetCanonicalNames( |
5965 TypedData::Handle(Z, script.kernel_canonical_names())); | 2671 TypedData::Handle(Z, script.kernel_canonical_names())); |
5966 DartTypeTranslator type_translator(&helper, NULL, true); | |
5967 ConstantEvaluator constant_evaluator(/* flow_graph_builder = */ NULL, Z, | |
5968 &helper, &type_translator); | |
5969 | 2672 |
5970 const Array& metadata_values = | 2673 StreamingFlowGraphBuilder streaming_flow_graph_builder( |
5971 Array::Handle(Z, Array::New(metadata_expressions->length())); | 2674 &helper, zone_, script.kernel_data(), script.kernel_data_size()); |
5972 | 2675 return streaming_flow_graph_builder.EvaluateMetadata( |
5973 for (intptr_t i = 0; i < metadata_expressions->length(); i++) { | 2676 metadata_field.kernel_offset()); |
5974 const Instance& value = | |
5975 constant_evaluator.EvaluateExpression((*metadata_expressions)[i]); | |
5976 metadata_values.SetAt(i, value); | |
5977 } | |
5978 | |
5979 return metadata_values.raw(); | |
5980 } else { | 2677 } else { |
5981 Thread* thread = Thread::Current(); | 2678 Thread* thread = Thread::Current(); |
5982 Error& error = Error::Handle(); | 2679 Error& error = Error::Handle(); |
5983 error = thread->sticky_error(); | 2680 error = thread->sticky_error(); |
5984 thread->clear_sticky_error(); | 2681 thread->clear_sticky_error(); |
5985 return error.raw(); | 2682 return error.raw(); |
5986 } | 2683 } |
5987 } | 2684 } |
5988 | 2685 |
5989 | 2686 |
5990 RawObject* BuildParameterDescriptor(const Function& function) { | 2687 RawObject* BuildParameterDescriptor(const Function& function) { |
2688 // TODO(jensj) | |
Kevin Millikin (Google)
2017/06/12 12:01:51
TODO what?
jensj
2017/06/13 13:42:14
Should have been
```
// TODO(jensj): Delete this
| |
5991 LongJumpScope jump; | 2689 LongJumpScope jump; |
5992 if (setjmp(*jump.Set()) == 0) { | 2690 if (setjmp(*jump.Set()) == 0) { |
5993 TreeNode* kernel_node = | |
5994 reinterpret_cast<TreeNode*>(function.kernel_function()); | |
5995 FunctionNode* function_node = NULL; | |
5996 if (kernel_node->IsProcedure()) { | |
5997 function_node = Procedure::Cast(kernel_node)->function(); | |
5998 } else if (kernel_node->IsConstructor()) { | |
5999 function_node = Constructor::Cast(kernel_node)->function(); | |
6000 } else if (kernel_node->IsFunctionNode()) { | |
6001 function_node = FunctionNode::Cast(kernel_node); | |
6002 } else { | |
6003 UNIMPLEMENTED(); | |
6004 return NULL; | |
6005 } | |
6006 | |
6007 Thread* thread = Thread::Current(); | 2691 Thread* thread = Thread::Current(); |
6008 Zone* zone_ = thread->zone(); | 2692 Zone* zone_ = thread->zone(); |
6009 TranslationHelper helper(thread); | 2693 TranslationHelper helper(thread); |
6010 Script& script = Script::Handle(Z, function.script()); | 2694 Script& script = Script::Handle(Z, function.script()); |
6011 helper.SetStringOffsets( | 2695 helper.SetStringOffsets( |
6012 TypedData::Handle(Z, script.kernel_string_offsets())); | 2696 TypedData::Handle(Z, script.kernel_string_offsets())); |
6013 helper.SetStringData(TypedData::Handle(Z, script.kernel_string_data())); | 2697 helper.SetStringData(TypedData::Handle(Z, script.kernel_string_data())); |
6014 helper.SetCanonicalNames( | 2698 helper.SetCanonicalNames( |
6015 TypedData::Handle(Z, script.kernel_canonical_names())); | 2699 TypedData::Handle(Z, script.kernel_canonical_names())); |
6016 DartTypeTranslator type_translator(&helper, NULL, true); | |
6017 ConstantEvaluator constant_evaluator(/* flow_graph_builder = */ NULL, Z, | |
6018 &helper, &type_translator); | |
6019 | 2700 |
6020 const intptr_t positional_count = | 2701 StreamingFlowGraphBuilder streaming_flow_graph_builder( |
6021 function_node->positional_parameters().length(); | 2702 &helper, zone_, script.kernel_data(), script.kernel_data_size()); |
6022 const intptr_t param_count = | 2703 return streaming_flow_graph_builder.BuildParameterDescriptor( |
6023 positional_count + function_node->named_parameters().length(); | 2704 function.kernel_offset()); |
6024 const Array& param_descriptor = Array::Handle( | |
6025 Array::New(param_count * Parser::kParameterEntrySize, Heap::kOld)); | |
6026 for (intptr_t i = 0; i < param_count; ++i) { | |
6027 const intptr_t entry_start = i * Parser::kParameterEntrySize; | |
6028 | |
6029 VariableDeclaration* variable; | |
6030 if (i < positional_count) { | |
6031 variable = function_node->positional_parameters()[i]; | |
6032 } else { | |
6033 variable = function_node->named_parameters()[i - positional_count]; | |
6034 } | |
6035 | |
6036 param_descriptor.SetAt( | |
6037 entry_start + Parser::kParameterIsFinalOffset, | |
6038 variable->IsFinal() ? Bool::True() : Bool::False()); | |
6039 | |
6040 if (variable->initializer() != NULL) { | |
6041 param_descriptor.SetAt( | |
6042 entry_start + Parser::kParameterDefaultValueOffset, | |
6043 constant_evaluator.EvaluateExpression(variable->initializer())); | |
6044 } else { | |
6045 param_descriptor.SetAt( | |
6046 entry_start + Parser::kParameterDefaultValueOffset, | |
6047 Object::null_instance()); | |
6048 } | |
6049 | |
6050 param_descriptor.SetAt(entry_start + Parser::kParameterMetadataOffset, | |
6051 /* Issue(28434): Missing parameter metadata. */ | |
6052 Object::null_instance()); | |
6053 } | |
6054 return param_descriptor.raw(); | |
6055 } else { | 2705 } else { |
6056 Thread* thread = Thread::Current(); | 2706 Thread* thread = Thread::Current(); |
6057 Error& error = Error::Handle(); | 2707 Error& error = Error::Handle(); |
6058 error = thread->sticky_error(); | 2708 error = thread->sticky_error(); |
6059 thread->clear_sticky_error(); | 2709 thread->clear_sticky_error(); |
6060 return error.raw(); | 2710 return error.raw(); |
6061 } | 2711 } |
6062 } | 2712 } |
6063 | 2713 |
6064 | 2714 |
6065 } // namespace kernel | 2715 } // namespace kernel |
6066 } // namespace dart | 2716 } // namespace dart |
6067 | 2717 |
6068 #endif // !defined(DART_PRECOMPILED_RUNTIME) | 2718 #endif // !defined(DART_PRECOMPILED_RUNTIME) |
OLD | NEW |