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