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 |
33 Fragment& Fragment::operator+=(const Fragment& other) { | 67 Fragment& Fragment::operator+=(const Fragment& other) { |
34 if (entry == NULL) { | 68 if (entry == NULL) { |
35 entry = other.entry; | 69 entry = other.entry; |
36 current = other.current; | 70 current = other.current; |
37 } else if (current != NULL && other.entry != NULL) { | 71 } else if (current != NULL && other.entry != NULL) { |
38 current->LinkTo(other.entry); | 72 current->LinkTo(other.entry); |
39 current = other.current; | 73 current = other.current; |
40 } | 74 } |
41 return *this; | 75 return *this; |
42 } | 76 } |
(...skipping 600 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
643 if (named->length() == 0) return Array::ZoneHandle(Z); | 677 if (named->length() == 0) return Array::ZoneHandle(Z); |
644 | 678 |
645 const Array& names = | 679 const Array& names = |
646 Array::ZoneHandle(Z, Array::New(named->length(), Heap::kOld)); | 680 Array::ZoneHandle(Z, Array::New(named->length(), Heap::kOld)); |
647 for (intptr_t i = 0; i < named->length(); ++i) { | 681 for (intptr_t i = 0; i < named->length(); ++i) { |
648 names.SetAt(i, DartSymbol((*named)[i]->name())); | 682 names.SetAt(i, DartSymbol((*named)[i]->name())); |
649 } | 683 } |
650 return names; | 684 return names; |
651 } | 685 } |
652 | 686 |
| 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 |
653 | 1259 |
654 FlowGraphBuilder::FlowGraphBuilder( | 1260 FlowGraphBuilder::FlowGraphBuilder( |
655 intptr_t kernel_offset, | 1261 TreeNode* node, |
656 ParsedFunction* parsed_function, | 1262 ParsedFunction* parsed_function, |
657 const ZoneGrowableArray<const ICData*>& ic_data_array, | 1263 const ZoneGrowableArray<const ICData*>& ic_data_array, |
658 ZoneGrowableArray<intptr_t>* context_level_array, | 1264 ZoneGrowableArray<intptr_t>* context_level_array, |
659 InlineExitCollector* exit_collector, | 1265 InlineExitCollector* exit_collector, |
660 intptr_t osr_id, | 1266 intptr_t osr_id, |
661 intptr_t first_block_id) | 1267 intptr_t first_block_id) |
662 : translation_helper_(Thread::Current()), | 1268 : translation_helper_(Thread::Current()), |
663 thread_(translation_helper_.thread()), | 1269 thread_(translation_helper_.thread()), |
664 zone_(translation_helper_.zone()), | 1270 zone_(translation_helper_.zone()), |
665 kernel_offset_(kernel_offset), | 1271 node_(node), |
666 parsed_function_(parsed_function), | 1272 parsed_function_(parsed_function), |
667 osr_id_(osr_id), | 1273 osr_id_(osr_id), |
668 ic_data_array_(ic_data_array), | 1274 ic_data_array_(ic_data_array), |
669 context_level_array_(context_level_array), | 1275 context_level_array_(context_level_array), |
670 exit_collector_(exit_collector), | 1276 exit_collector_(exit_collector), |
671 next_block_id_(first_block_id), | 1277 next_block_id_(first_block_id), |
672 next_function_id_(0), | 1278 next_function_id_(0), |
673 context_depth_(0), | 1279 context_depth_(0), |
674 loop_depth_(0), | 1280 loop_depth_(0), |
675 try_depth_(0), | 1281 try_depth_(0), |
676 catch_depth_(0), | 1282 catch_depth_(0), |
677 for_in_depth_(0), | 1283 for_in_depth_(0), |
678 stack_(NULL), | 1284 stack_(NULL), |
679 pending_argument_count_(0), | 1285 pending_argument_count_(0), |
680 graph_entry_(NULL), | 1286 graph_entry_(NULL), |
681 scopes_(NULL), | 1287 scopes_(NULL), |
682 breakable_block_(NULL), | 1288 breakable_block_(NULL), |
683 switch_block_(NULL), | 1289 switch_block_(NULL), |
684 try_finally_block_(NULL), | 1290 try_finally_block_(NULL), |
685 try_catch_block_(NULL), | 1291 try_catch_block_(NULL), |
686 next_used_try_index_(0), | 1292 next_used_try_index_(0), |
687 catch_block_(NULL), | 1293 catch_block_(NULL), |
688 type_translator_(&translation_helper_, | 1294 type_translator_(&translation_helper_, |
689 &active_class_, | 1295 &active_class_, |
690 /* finalize= */ true), | 1296 /* finalize= */ true), |
| 1297 constant_evaluator_(this, zone_, &translation_helper_, &type_translator_), |
691 streaming_flow_graph_builder_(NULL) { | 1298 streaming_flow_graph_builder_(NULL) { |
692 Script& script = Script::Handle(Z, parsed_function->function().script()); | 1299 Script& script = Script::Handle(Z, parsed_function->function().script()); |
693 H.SetStringOffsets(TypedData::Handle(Z, script.kernel_string_offsets())); | 1300 H.SetStringOffsets(TypedData::Handle(Z, script.kernel_string_offsets())); |
694 H.SetStringData(TypedData::Handle(Z, script.kernel_string_data())); | 1301 H.SetStringData(TypedData::Handle(Z, script.kernel_string_data())); |
695 H.SetCanonicalNames(TypedData::Handle(Z, script.kernel_canonical_names())); | 1302 H.SetCanonicalNames(TypedData::Handle(Z, script.kernel_canonical_names())); |
696 } | 1303 } |
697 | 1304 |
698 | 1305 |
699 FlowGraphBuilder::~FlowGraphBuilder() { | 1306 FlowGraphBuilder::~FlowGraphBuilder() { |
700 if (streaming_flow_graph_builder_ != NULL) { | 1307 if (streaming_flow_graph_builder_ != NULL) { |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
735 JoinEntryInstr* entry = BuildJoinEntry(); | 1342 JoinEntryInstr* entry = BuildJoinEntry(); |
736 instructions += Goto(entry); | 1343 instructions += Goto(entry); |
737 instructions = Fragment(instructions.entry, entry); | 1344 instructions = Fragment(instructions.entry, entry); |
738 } | 1345 } |
739 | 1346 |
740 Statement* finalizer = try_finally_block_->finalizer(); | 1347 Statement* finalizer = try_finally_block_->finalizer(); |
741 intptr_t finalizer_kernel_offset = | 1348 intptr_t finalizer_kernel_offset = |
742 try_finally_block_->finalizer_kernel_offset(); | 1349 try_finally_block_->finalizer_kernel_offset(); |
743 try_finally_block_ = try_finally_block_->outer(); | 1350 try_finally_block_ = try_finally_block_->outer(); |
744 if (finalizer != NULL) { | 1351 if (finalizer != NULL) { |
745 UNREACHABLE(); | 1352 // This will potentially have exceptional cases as described in |
| 1353 // [VisitTryFinally] and will handle them. |
| 1354 instructions += TranslateStatement(finalizer); |
746 } else { | 1355 } else { |
747 instructions += streaming_flow_graph_builder_->BuildStatementAt( | 1356 instructions += streaming_flow_graph_builder_->BuildStatementAt( |
748 finalizer_kernel_offset); | 1357 finalizer_kernel_offset); |
749 } | 1358 } |
750 | 1359 |
751 // We only need to make sure that if the finalizer ended normally, we | 1360 // We only need to make sure that if the finalizer ended normally, we |
752 // continue towards the next outer try-finally. | 1361 // continue towards the next outer try-finally. |
753 if (!instructions.is_open()) break; | 1362 if (!instructions.is_open()) break; |
754 } | 1363 } |
755 | 1364 |
756 if (instructions.is_open() && target_context_depth != -1) { | 1365 if (instructions.is_open() && target_context_depth != -1) { |
757 // A target context depth of -1 indicates that the code after this | 1366 // A target context depth of -1 indicates that the code after this |
758 // will not care about the context chain so we can leave it any way we | 1367 // will not care about the context chain so we can leave it any way we |
759 // want after the last finalizer. That is used when returning. | 1368 // want after the last finalizer. That is used when returning. |
760 instructions += AdjustContextTo(target_context_depth); | 1369 instructions += AdjustContextTo(target_context_depth); |
761 } | 1370 } |
762 | 1371 |
763 try_finally_block_ = saved_block; | 1372 try_finally_block_ = saved_block; |
764 try_catch_block_ = saved_try_catch_block; | 1373 try_catch_block_ = saved_try_catch_block; |
765 context_depth_ = saved_depth; | 1374 context_depth_ = saved_depth; |
766 try_depth_ = saved_try_depth; | 1375 try_depth_ = saved_try_depth; |
767 | 1376 |
768 return instructions; | 1377 return instructions; |
769 } | 1378 } |
770 | 1379 |
771 | 1380 |
| 1381 Fragment FlowGraphBuilder::EnterScope(TreeNode* node, bool* new_context) { |
| 1382 return EnterScope(node->kernel_offset(), new_context); |
| 1383 } |
| 1384 |
| 1385 |
772 Fragment FlowGraphBuilder::EnterScope(intptr_t kernel_offset, | 1386 Fragment FlowGraphBuilder::EnterScope(intptr_t kernel_offset, |
773 bool* new_context) { | 1387 bool* new_context) { |
774 Fragment instructions; | 1388 Fragment instructions; |
775 const intptr_t context_size = | 1389 const intptr_t context_size = |
776 scopes_->scopes.Lookup(kernel_offset)->num_context_variables(); | 1390 scopes_->scopes.Lookup(kernel_offset)->num_context_variables(); |
777 if (context_size > 0) { | 1391 if (context_size > 0) { |
778 instructions += PushContext(context_size); | 1392 instructions += PushContext(context_size); |
779 instructions += Drop(); | 1393 instructions += Drop(); |
780 if (new_context != NULL) { | 1394 if (new_context != NULL) { |
781 *new_context = true; | 1395 *new_context = true; |
782 } | 1396 } |
783 } | 1397 } |
784 return instructions; | 1398 return instructions; |
785 } | 1399 } |
786 | 1400 |
787 | 1401 |
| 1402 Fragment FlowGraphBuilder::ExitScope(TreeNode* node) { |
| 1403 return ExitScope(node->kernel_offset()); |
| 1404 } |
| 1405 |
| 1406 |
788 Fragment FlowGraphBuilder::ExitScope(intptr_t kernel_offset) { | 1407 Fragment FlowGraphBuilder::ExitScope(intptr_t kernel_offset) { |
789 Fragment instructions; | 1408 Fragment instructions; |
790 const intptr_t context_size = | 1409 const intptr_t context_size = |
791 scopes_->scopes.Lookup(kernel_offset)->num_context_variables(); | 1410 scopes_->scopes.Lookup(kernel_offset)->num_context_variables(); |
792 if (context_size > 0) { | 1411 if (context_size > 0) { |
793 instructions += PopContext(); | 1412 instructions += PopContext(); |
794 } | 1413 } |
795 return instructions; | 1414 return instructions; |
796 } | 1415 } |
797 | 1416 |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
848 #ifdef DEBUG | 1467 #ifdef DEBUG |
849 Function& function = | 1468 Function& function = |
850 Function::Handle(Z, parsed_function_->function().raw()); | 1469 Function::Handle(Z, parsed_function_->function().raw()); |
851 while (function.IsClosureFunction()) { | 1470 while (function.IsClosureFunction()) { |
852 function = function.parent_function(); | 1471 function = function.parent_function(); |
853 } | 1472 } |
854 ASSERT(function.IsFactory()); | 1473 ASSERT(function.IsFactory()); |
855 #endif | 1474 #endif |
856 instructions += LoadLocal(scopes_->type_arguments_variable); | 1475 instructions += LoadLocal(scopes_->type_arguments_variable); |
857 } else if (scopes_->this_variable != NULL && | 1476 } else if (scopes_->this_variable != NULL && |
858 active_class_.class_type_parameters > 0) { | 1477 active_class_.kernel_class != NULL && |
| 1478 active_class_.kernel_class->type_parameters().length() > 0) { |
859 ASSERT(!parsed_function_->function().IsFactory()); | 1479 ASSERT(!parsed_function_->function().IsFactory()); |
860 intptr_t type_arguments_field_offset = | 1480 intptr_t type_arguments_field_offset = |
861 active_class_.klass->type_arguments_field_offset(); | 1481 active_class_.klass->type_arguments_field_offset(); |
862 ASSERT(type_arguments_field_offset != dart::Class::kNoTypeArguments); | 1482 ASSERT(type_arguments_field_offset != dart::Class::kNoTypeArguments); |
863 | 1483 |
864 instructions += LoadLocal(scopes_->this_variable); | 1484 instructions += LoadLocal(scopes_->this_variable); |
865 instructions += LoadField(type_arguments_field_offset); | 1485 instructions += LoadField(type_arguments_field_offset); |
866 } else { | 1486 } else { |
867 instructions += NullConstant(); | 1487 instructions += NullConstant(); |
868 } | 1488 } |
(...skipping 914 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1783 parsed_function_->Bailout("kernel::FlowGraphBuilder", reason); | 2403 parsed_function_->Bailout("kernel::FlowGraphBuilder", reason); |
1784 } | 2404 } |
1785 } | 2405 } |
1786 | 2406 |
1787 | 2407 |
1788 FlowGraph* FlowGraphBuilder::BuildGraph() { | 2408 FlowGraph* FlowGraphBuilder::BuildGraph() { |
1789 const Function& function = parsed_function_->function(); | 2409 const Function& function = parsed_function_->function(); |
1790 | 2410 |
1791 if (function.IsConstructorClosureFunction()) return NULL; | 2411 if (function.IsConstructorClosureFunction()) return NULL; |
1792 | 2412 |
| 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 } |
1793 if (streaming_flow_graph_builder_ != NULL) { | 2433 if (streaming_flow_graph_builder_ != NULL) { |
1794 delete streaming_flow_graph_builder_; | 2434 delete streaming_flow_graph_builder_; |
1795 streaming_flow_graph_builder_ = NULL; | 2435 streaming_flow_graph_builder_ = NULL; |
1796 } | 2436 } |
1797 | 2437 if (library_node != NULL && library_node->IsLibrary()) { |
1798 Script& script = Script::Handle(Z, function.script()); | 2438 Library* library = Library::Cast(library_node); |
1799 streaming_flow_graph_builder_ = new StreamingFlowGraphBuilder( | 2439 streaming_flow_graph_builder_ = new StreamingFlowGraphBuilder( |
1800 this, script.kernel_data(), script.kernel_data_size()); | 2440 this, library->kernel_data(), library->kernel_data_size()); |
1801 | 2441 } |
1802 return streaming_flow_graph_builder_->BuildGraph(kernel_offset_); | 2442 |
| 2443 dart::Class& klass = |
| 2444 dart::Class::Handle(zone_, parsed_function_->function().Owner()); |
| 2445 |
| 2446 Function& outermost_function = Function::Handle(Z); |
| 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; |
1803 } | 2513 } |
1804 | 2514 |
1805 | 2515 |
1806 Fragment FlowGraphBuilder::NativeFunctionBody(intptr_t first_positional_offset, | 2516 FlowGraph* FlowGraphBuilder::BuildGraphOfFunction(FunctionNode* function, |
| 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, |
1807 const Function& function) { | 2809 const Function& function) { |
1808 ASSERT(function.is_native()); | 2810 ASSERT(function.is_native()); |
1809 // We explicitly build the graph for native functions in the same way that the | 2811 // We explicitly build the graph for native functions in the same way that the |
1810 // from-source backend does. We should find a way to have a single component | 2812 // from-source backend does. We should find a way to have a single component |
1811 // to build these graphs so that this code is not duplicated. | 2813 // to build these graphs so that this code is not duplicated. |
1812 | 2814 |
1813 Fragment body; | 2815 Fragment body; |
1814 MethodRecognizer::Kind kind = MethodRecognizer::RecognizeKind(function); | 2816 MethodRecognizer::Kind kind = MethodRecognizer::RecognizeKind(function); |
1815 switch (kind) { | 2817 switch (kind) { |
1816 case MethodRecognizer::kObjectEquals: | 2818 case MethodRecognizer::kObjectEquals: |
1817 body += LoadLocal(scopes_->this_variable); | 2819 body += LoadLocal(scopes_->this_variable); |
1818 body += LoadLocal(LookupVariable(first_positional_offset)); | 2820 body += LoadLocal( |
| 2821 LookupVariable(kernel_function->positional_parameters()[0])); |
1819 body += StrictCompare(Token::kEQ_STRICT); | 2822 body += StrictCompare(Token::kEQ_STRICT); |
1820 break; | 2823 break; |
1821 case MethodRecognizer::kStringBaseLength: | 2824 case MethodRecognizer::kStringBaseLength: |
1822 case MethodRecognizer::kStringBaseIsEmpty: | 2825 case MethodRecognizer::kStringBaseIsEmpty: |
1823 // Depending on FLAG_support_externalizable_strings, treat string length | 2826 // Depending on FLAG_support_externalizable_strings, treat string length |
1824 // loads as mutable so that the class check that precedes them will not be | 2827 // loads as mutable so that the class check that precedes them will not be |
1825 // hoisted. This is unsafe because string externalization can change the | 2828 // hoisted. This is unsafe because string externalization can change the |
1826 // class. | 2829 // class. |
1827 body += LoadLocal(scopes_->this_variable); | 2830 body += LoadLocal(scopes_->this_variable); |
1828 body += LoadNativeField(MethodRecognizer::kStringBaseLength, | 2831 body += LoadNativeField(MethodRecognizer::kStringBaseLength, |
(...skipping 17 matching lines...) Expand all Loading... |
1846 LoadNativeField(kind, Array::length_offset(), | 2849 LoadNativeField(kind, Array::length_offset(), |
1847 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid, true); | 2850 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid, true); |
1848 break; | 2851 break; |
1849 case MethodRecognizer::kTypedDataLength: | 2852 case MethodRecognizer::kTypedDataLength: |
1850 body += LoadLocal(scopes_->this_variable); | 2853 body += LoadLocal(scopes_->this_variable); |
1851 body += | 2854 body += |
1852 LoadNativeField(kind, TypedData::length_offset(), | 2855 LoadNativeField(kind, TypedData::length_offset(), |
1853 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid, true); | 2856 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid, true); |
1854 break; | 2857 break; |
1855 case MethodRecognizer::kClassIDgetID: | 2858 case MethodRecognizer::kClassIDgetID: |
1856 body += LoadLocal(LookupVariable(first_positional_offset)); | 2859 body += LoadLocal( |
| 2860 LookupVariable(kernel_function->positional_parameters()[0])); |
1857 body += LoadClassId(); | 2861 body += LoadClassId(); |
1858 break; | 2862 break; |
1859 case MethodRecognizer::kGrowableArrayCapacity: | 2863 case MethodRecognizer::kGrowableArrayCapacity: |
1860 body += LoadLocal(scopes_->this_variable); | 2864 body += LoadLocal(scopes_->this_variable); |
1861 body += LoadField(Array::data_offset(), kArrayCid); | 2865 body += LoadField(Array::data_offset(), kArrayCid); |
1862 body += LoadNativeField(MethodRecognizer::kObjectArrayLength, | 2866 body += LoadNativeField(MethodRecognizer::kObjectArrayLength, |
1863 Array::length_offset(), | 2867 Array::length_offset(), |
1864 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid); | 2868 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid); |
1865 break; | 2869 break; |
1866 case MethodRecognizer::kObjectArrayAllocate: | 2870 case MethodRecognizer::kObjectArrayAllocate: |
1867 body += LoadLocal(scopes_->type_arguments_variable); | 2871 body += LoadLocal(scopes_->type_arguments_variable); |
1868 body += LoadLocal(LookupVariable(first_positional_offset)); | 2872 body += LoadLocal( |
| 2873 LookupVariable(kernel_function->positional_parameters()[0])); |
1869 body += CreateArray(); | 2874 body += CreateArray(); |
1870 break; | 2875 break; |
1871 case MethodRecognizer::kBigint_getDigits: | 2876 case MethodRecognizer::kBigint_getDigits: |
1872 body += LoadLocal(scopes_->this_variable); | 2877 body += LoadLocal(scopes_->this_variable); |
1873 body += LoadNativeField(kind, Bigint::digits_offset(), | 2878 body += LoadNativeField(kind, Bigint::digits_offset(), |
1874 Object::dynamic_type(), kTypedDataUint32ArrayCid); | 2879 Object::dynamic_type(), kTypedDataUint32ArrayCid); |
1875 break; | 2880 break; |
1876 case MethodRecognizer::kBigint_getUsed: | 2881 case MethodRecognizer::kBigint_getUsed: |
1877 body += LoadLocal(scopes_->this_variable); | 2882 body += LoadLocal(scopes_->this_variable); |
1878 body += LoadNativeField(kind, Bigint::used_offset(), | 2883 body += LoadNativeField(kind, Bigint::used_offset(), |
1879 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid); | 2884 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid); |
1880 break; | 2885 break; |
1881 case MethodRecognizer::kLinkedHashMap_getIndex: | 2886 case MethodRecognizer::kLinkedHashMap_getIndex: |
1882 body += LoadLocal(scopes_->this_variable); | 2887 body += LoadLocal(scopes_->this_variable); |
1883 body += LoadNativeField(kind, LinkedHashMap::index_offset(), | 2888 body += LoadNativeField(kind, LinkedHashMap::index_offset(), |
1884 Object::dynamic_type(), kDynamicCid); | 2889 Object::dynamic_type(), kDynamicCid); |
1885 break; | 2890 break; |
1886 case MethodRecognizer::kLinkedHashMap_setIndex: | 2891 case MethodRecognizer::kLinkedHashMap_setIndex: |
1887 body += LoadLocal(scopes_->this_variable); | 2892 body += LoadLocal(scopes_->this_variable); |
1888 body += LoadLocal(LookupVariable(first_positional_offset)); | 2893 body += LoadLocal( |
| 2894 LookupVariable(kernel_function->positional_parameters()[0])); |
1889 body += StoreInstanceField(TokenPosition::kNoSource, | 2895 body += StoreInstanceField(TokenPosition::kNoSource, |
1890 LinkedHashMap::index_offset()); | 2896 LinkedHashMap::index_offset()); |
1891 body += NullConstant(); | 2897 body += NullConstant(); |
1892 break; | 2898 break; |
1893 case MethodRecognizer::kLinkedHashMap_getData: | 2899 case MethodRecognizer::kLinkedHashMap_getData: |
1894 body += LoadLocal(scopes_->this_variable); | 2900 body += LoadLocal(scopes_->this_variable); |
1895 body += LoadNativeField(kind, LinkedHashMap::data_offset(), | 2901 body += LoadNativeField(kind, LinkedHashMap::data_offset(), |
1896 Object::dynamic_type(), kArrayCid); | 2902 Object::dynamic_type(), kArrayCid); |
1897 break; | 2903 break; |
1898 case MethodRecognizer::kLinkedHashMap_setData: | 2904 case MethodRecognizer::kLinkedHashMap_setData: |
1899 body += LoadLocal(scopes_->this_variable); | 2905 body += LoadLocal(scopes_->this_variable); |
1900 body += LoadLocal(LookupVariable(first_positional_offset)); | 2906 body += LoadLocal( |
| 2907 LookupVariable(kernel_function->positional_parameters()[0])); |
1901 body += StoreInstanceField(TokenPosition::kNoSource, | 2908 body += StoreInstanceField(TokenPosition::kNoSource, |
1902 LinkedHashMap::data_offset()); | 2909 LinkedHashMap::data_offset()); |
1903 body += NullConstant(); | 2910 body += NullConstant(); |
1904 break; | 2911 break; |
1905 case MethodRecognizer::kLinkedHashMap_getHashMask: | 2912 case MethodRecognizer::kLinkedHashMap_getHashMask: |
1906 body += LoadLocal(scopes_->this_variable); | 2913 body += LoadLocal(scopes_->this_variable); |
1907 body += LoadNativeField(kind, LinkedHashMap::hash_mask_offset(), | 2914 body += LoadNativeField(kind, LinkedHashMap::hash_mask_offset(), |
1908 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid); | 2915 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid); |
1909 break; | 2916 break; |
1910 case MethodRecognizer::kLinkedHashMap_setHashMask: | 2917 case MethodRecognizer::kLinkedHashMap_setHashMask: |
1911 body += LoadLocal(scopes_->this_variable); | 2918 body += LoadLocal(scopes_->this_variable); |
1912 body += LoadLocal(LookupVariable(first_positional_offset)); | 2919 body += LoadLocal( |
| 2920 LookupVariable(kernel_function->positional_parameters()[0])); |
1913 body += StoreInstanceField(TokenPosition::kNoSource, | 2921 body += StoreInstanceField(TokenPosition::kNoSource, |
1914 LinkedHashMap::hash_mask_offset(), | 2922 LinkedHashMap::hash_mask_offset(), |
1915 kNoStoreBarrier); | 2923 kNoStoreBarrier); |
1916 body += NullConstant(); | 2924 body += NullConstant(); |
1917 break; | 2925 break; |
1918 case MethodRecognizer::kLinkedHashMap_getUsedData: | 2926 case MethodRecognizer::kLinkedHashMap_getUsedData: |
1919 body += LoadLocal(scopes_->this_variable); | 2927 body += LoadLocal(scopes_->this_variable); |
1920 body += LoadNativeField(kind, LinkedHashMap::used_data_offset(), | 2928 body += LoadNativeField(kind, LinkedHashMap::used_data_offset(), |
1921 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid); | 2929 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid); |
1922 break; | 2930 break; |
1923 case MethodRecognizer::kLinkedHashMap_setUsedData: | 2931 case MethodRecognizer::kLinkedHashMap_setUsedData: |
1924 body += LoadLocal(scopes_->this_variable); | 2932 body += LoadLocal(scopes_->this_variable); |
1925 body += LoadLocal(LookupVariable(first_positional_offset)); | 2933 body += LoadLocal( |
| 2934 LookupVariable(kernel_function->positional_parameters()[0])); |
1926 body += StoreInstanceField(TokenPosition::kNoSource, | 2935 body += StoreInstanceField(TokenPosition::kNoSource, |
1927 LinkedHashMap::used_data_offset(), | 2936 LinkedHashMap::used_data_offset(), |
1928 kNoStoreBarrier); | 2937 kNoStoreBarrier); |
1929 body += NullConstant(); | 2938 body += NullConstant(); |
1930 break; | 2939 break; |
1931 case MethodRecognizer::kLinkedHashMap_getDeletedKeys: | 2940 case MethodRecognizer::kLinkedHashMap_getDeletedKeys: |
1932 body += LoadLocal(scopes_->this_variable); | 2941 body += LoadLocal(scopes_->this_variable); |
1933 body += LoadNativeField(kind, LinkedHashMap::deleted_keys_offset(), | 2942 body += LoadNativeField(kind, LinkedHashMap::deleted_keys_offset(), |
1934 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid); | 2943 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid); |
1935 break; | 2944 break; |
1936 case MethodRecognizer::kLinkedHashMap_setDeletedKeys: | 2945 case MethodRecognizer::kLinkedHashMap_setDeletedKeys: |
1937 body += LoadLocal(scopes_->this_variable); | 2946 body += LoadLocal(scopes_->this_variable); |
1938 body += LoadLocal(LookupVariable(first_positional_offset)); | 2947 body += LoadLocal( |
| 2948 LookupVariable(kernel_function->positional_parameters()[0])); |
1939 body += StoreInstanceField(TokenPosition::kNoSource, | 2949 body += StoreInstanceField(TokenPosition::kNoSource, |
1940 LinkedHashMap::deleted_keys_offset(), | 2950 LinkedHashMap::deleted_keys_offset(), |
1941 kNoStoreBarrier); | 2951 kNoStoreBarrier); |
1942 body += NullConstant(); | 2952 body += NullConstant(); |
1943 break; | 2953 break; |
1944 case MethodRecognizer::kBigint_getNeg: | 2954 case MethodRecognizer::kBigint_getNeg: |
1945 body += LoadLocal(scopes_->this_variable); | 2955 body += LoadLocal(scopes_->this_variable); |
1946 body += LoadNativeField(kind, Bigint::neg_offset(), | 2956 body += LoadNativeField(kind, Bigint::neg_offset(), |
1947 Type::ZoneHandle(Z, Type::BoolType()), kBoolCid); | 2957 Type::ZoneHandle(Z, Type::BoolType()), kBoolCid); |
1948 break; | 2958 break; |
1949 default: { | 2959 default: { |
1950 dart::String& name = dart::String::ZoneHandle(Z, function.native_name()); | 2960 dart::String& name = dart::String::ZoneHandle(Z, function.native_name()); |
1951 body += NativeCall(&name, &function); | 2961 body += NativeCall(&name, &function); |
1952 break; | 2962 break; |
1953 } | 2963 } |
1954 } | 2964 } |
1955 return body + Return(TokenPosition::kNoSource); | 2965 return body + Return(TokenPosition::kNoSource); |
1956 } | 2966 } |
1957 | 2967 |
1958 | 2968 |
| 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 |
1959 Fragment FlowGraphBuilder::BuildImplicitClosureCreation( | 3045 Fragment FlowGraphBuilder::BuildImplicitClosureCreation( |
1960 const Function& target) { | 3046 const Function& target) { |
1961 Fragment fragment; | 3047 Fragment fragment; |
1962 const dart::Class& closure_class = | 3048 const dart::Class& closure_class = |
1963 dart::Class::ZoneHandle(Z, I->object_store()->closure_class()); | 3049 dart::Class::ZoneHandle(Z, I->object_store()->closure_class()); |
1964 fragment += AllocateObject(closure_class, target); | 3050 fragment += AllocateObject(closure_class, target); |
1965 LocalVariable* closure = MakeTemporary(); | 3051 LocalVariable* closure = MakeTemporary(); |
1966 | 3052 |
1967 // The function signature can have uninstantiated class type parameters. | 3053 // The function signature can have uninstantiated class type parameters. |
1968 // | 3054 // |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2008 } | 3094 } |
2009 | 3095 |
2010 | 3096 |
2011 Fragment FlowGraphBuilder::GuardFieldClass(const dart::Field& field, | 3097 Fragment FlowGraphBuilder::GuardFieldClass(const dart::Field& field, |
2012 intptr_t deopt_id) { | 3098 intptr_t deopt_id) { |
2013 return Fragment(new (Z) GuardFieldClassInstr(Pop(), field, deopt_id)); | 3099 return Fragment(new (Z) GuardFieldClassInstr(Pop(), field, deopt_id)); |
2014 } | 3100 } |
2015 | 3101 |
2016 | 3102 |
2017 Fragment FlowGraphBuilder::CheckVariableTypeInCheckedMode( | 3103 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( |
2018 const AbstractType& dst_type, | 3117 const AbstractType& dst_type, |
2019 const dart::String& name_symbol) { | 3118 const dart::String& name_symbol) { |
2020 if (I->type_checks()) { | 3119 if (I->type_checks()) { |
2021 if (dst_type.IsMalformed()) { | 3120 if (dst_type.IsMalformed()) { |
2022 return ThrowTypeError(); | 3121 return ThrowTypeError(); |
2023 } | 3122 } |
2024 return CheckAssignableInCheckedMode(dst_type, name_symbol); | 3123 return CheckAssignableInCheckedMode(dst_type, name_symbol); |
2025 } | 3124 } |
2026 return Fragment(); | 3125 return Fragment(); |
2027 } | 3126 } |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2151 GraphEntryInstr(*parsed_function_, normal_entry, Compiler::kNoOSRDeoptId); | 3250 GraphEntryInstr(*parsed_function_, normal_entry, Compiler::kNoOSRDeoptId); |
2152 Fragment body(normal_entry); | 3251 Fragment body(normal_entry); |
2153 body += CheckStackOverflowInPrologue(); | 3252 body += CheckStackOverflowInPrologue(); |
2154 body += BuildImplicitClosureCreation(function); | 3253 body += BuildImplicitClosureCreation(function); |
2155 body += Return(TokenPosition::kNoSource); | 3254 body += Return(TokenPosition::kNoSource); |
2156 | 3255 |
2157 return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1); | 3256 return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1); |
2158 } | 3257 } |
2159 | 3258 |
2160 | 3259 |
| 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 |
2161 FlowGraph* FlowGraphBuilder::BuildGraphOfNoSuchMethodDispatcher( | 3312 FlowGraph* FlowGraphBuilder::BuildGraphOfNoSuchMethodDispatcher( |
2162 const Function& function) { | 3313 const Function& function) { |
2163 // This function is specialized for a receiver class, a method name, and | 3314 // This function is specialized for a receiver class, a method name, and |
2164 // the arguments descriptor at a call site. | 3315 // the arguments descriptor at a call site. |
2165 | 3316 |
2166 TargetEntryInstr* normal_entry = BuildTargetEntry(); | 3317 TargetEntryInstr* normal_entry = BuildTargetEntry(); |
2167 graph_entry_ = new (Z) | 3318 graph_entry_ = new (Z) |
2168 GraphEntryInstr(*parsed_function_, normal_entry, Compiler::kNoOSRDeoptId); | 3319 GraphEntryInstr(*parsed_function_, normal_entry, Compiler::kNoOSRDeoptId); |
2169 | 3320 |
2170 // The backend will expect an array of default values for all the named | 3321 // 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... |
2342 body += InstanceCall(TokenPosition::kMinSource, Symbols::Call(), | 3493 body += InstanceCall(TokenPosition::kMinSource, Symbols::Call(), |
2343 Token::kILLEGAL, descriptor.Count(), argument_names); | 3494 Token::kILLEGAL, descriptor.Count(), argument_names); |
2344 } | 3495 } |
2345 | 3496 |
2346 body += Return(TokenPosition::kNoSource); | 3497 body += Return(TokenPosition::kNoSource); |
2347 | 3498 |
2348 return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1); | 3499 return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1); |
2349 } | 3500 } |
2350 | 3501 |
2351 | 3502 |
| 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 |
2352 TargetEntryInstr* FlowGraphBuilder::BuildTargetEntry() { | 3544 TargetEntryInstr* FlowGraphBuilder::BuildTargetEntry() { |
2353 return new (Z) | 3545 return new (Z) |
2354 TargetEntryInstr(AllocateBlockId(), CurrentTryIndex(), GetNextDeoptId()); | 3546 TargetEntryInstr(AllocateBlockId(), CurrentTryIndex(), GetNextDeoptId()); |
2355 } | 3547 } |
2356 | 3548 |
2357 | 3549 |
2358 JoinEntryInstr* FlowGraphBuilder::BuildJoinEntry(intptr_t try_index) { | 3550 JoinEntryInstr* FlowGraphBuilder::BuildJoinEntry(intptr_t try_index) { |
2359 return new (Z) JoinEntryInstr(AllocateBlockId(), try_index, GetNextDeoptId()); | 3551 return new (Z) JoinEntryInstr(AllocateBlockId(), try_index, GetNextDeoptId()); |
2360 } | 3552 } |
2361 | 3553 |
2362 | 3554 |
2363 JoinEntryInstr* FlowGraphBuilder::BuildJoinEntry() { | 3555 JoinEntryInstr* FlowGraphBuilder::BuildJoinEntry() { |
2364 return new (Z) | 3556 return new (Z) |
2365 JoinEntryInstr(AllocateBlockId(), CurrentTryIndex(), GetNextDeoptId()); | 3557 JoinEntryInstr(AllocateBlockId(), CurrentTryIndex(), GetNextDeoptId()); |
2366 } | 3558 } |
2367 | 3559 |
| 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 |
2368 ArgumentArray FlowGraphBuilder::GetArguments(int count) { | 3725 ArgumentArray FlowGraphBuilder::GetArguments(int count) { |
2369 ArgumentArray arguments = | 3726 ArgumentArray arguments = |
2370 new (Z) ZoneGrowableArray<PushArgumentInstr*>(Z, count); | 3727 new (Z) ZoneGrowableArray<PushArgumentInstr*>(Z, count); |
2371 arguments->SetLength(count); | 3728 arguments->SetLength(count); |
2372 for (intptr_t i = count - 1; i >= 0; --i) { | 3729 for (intptr_t i = count - 1; i >= 0; --i) { |
2373 ASSERT(stack_->definition()->IsPushArgument()); | 3730 ASSERT(stack_->definition()->IsPushArgument()); |
2374 ASSERT(!stack_->definition()->HasSSATemp()); | 3731 ASSERT(!stack_->definition()->HasSSATemp()); |
2375 arguments->data()[i] = stack_->definition()->AsPushArgument(); | 3732 arguments->data()[i] = stack_->definition()->AsPushArgument(); |
2376 Drop(); | 3733 Drop(); |
2377 } | 3734 } |
2378 pending_argument_count_ -= count; | 3735 pending_argument_count_ -= count; |
2379 ASSERT(pending_argument_count_ >= 0); | 3736 ASSERT(pending_argument_count_ >= 0); |
2380 return arguments; | 3737 return arguments; |
2381 } | 3738 } |
2382 | 3739 |
2383 | 3740 |
2384 #define STREAM_EXPRESSION_IF_POSSIBLE(node) \ | 3741 #define STREAM_EXPRESSION_IF_POSSIBLE(node) \ |
2385 if (node->can_stream()) { \ | 3742 if (node->can_stream()) { \ |
2386 fragment_ = streaming_flow_graph_builder_->BuildExpressionAt( \ | 3743 fragment_ = streaming_flow_graph_builder_->BuildExpressionAt( \ |
2387 node->kernel_offset()); \ | 3744 node->kernel_offset()); \ |
2388 return; \ | 3745 return; \ |
2389 } | 3746 } |
2390 | 3747 |
2391 | 3748 |
| 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 |
2392 AbstractType& DartTypeTranslator::TranslateType(DartType* node) { | 3797 AbstractType& DartTypeTranslator::TranslateType(DartType* node) { |
2393 node->AcceptDartTypeVisitor(this); | 3798 node->AcceptDartTypeVisitor(this); |
2394 | 3799 |
2395 // We return a new `ZoneHandle` here on purpose: The intermediate language | 3800 // We return a new `ZoneHandle` here on purpose: The intermediate language |
2396 // instructions do not make a copy of the handle, so we do it. | 3801 // instructions do not make a copy of the handle, so we do it. |
2397 return AbstractType::ZoneHandle(Z, result_.raw()); | 3802 return AbstractType::ZoneHandle(Z, result_.raw()); |
2398 } | 3803 } |
2399 | 3804 |
2400 | 3805 |
2401 AbstractType& DartTypeTranslator::TranslateTypeWithoutFinalization( | 3806 AbstractType& DartTypeTranslator::TranslateTypeWithoutFinalization( |
(...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2681 } | 4086 } |
2682 type = Type::New(klass, TypeArguments::Handle(Z, klass.type_parameters()), | 4087 type = Type::New(klass, TypeArguments::Handle(Z, klass.type_parameters()), |
2683 klass.token_pos()); | 4088 klass.token_pos()); |
2684 if (klass.is_type_finalized()) { | 4089 if (klass.is_type_finalized()) { |
2685 type ^= ClassFinalizer::FinalizeType(klass, type); | 4090 type ^= ClassFinalizer::FinalizeType(klass, type); |
2686 klass.SetCanonicalType(type); | 4091 klass.SetCanonicalType(type); |
2687 } | 4092 } |
2688 return type; | 4093 return type; |
2689 } | 4094 } |
2690 | 4095 |
| 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 |
2691 RawObject* EvaluateMetadata(const dart::Field& metadata_field) { | 5991 RawObject* EvaluateMetadata(const dart::Field& metadata_field) { |
2692 LongJumpScope jump; | 5992 LongJumpScope jump; |
2693 if (setjmp(*jump.Set()) == 0) { | 5993 if (setjmp(*jump.Set()) == 0) { |
2694 Thread* thread = Thread::Current(); | 5994 Thread* thread = Thread::Current(); |
2695 Zone* zone_ = thread->zone(); | 5995 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 |
2696 TranslationHelper helper(thread); | 6013 TranslationHelper helper(thread); |
2697 Script& script = Script::Handle(Z, metadata_field.Script()); | 6014 Script& script = Script::Handle(Z, metadata_field.Script()); |
2698 helper.SetStringOffsets( | 6015 helper.SetStringOffsets( |
2699 TypedData::Handle(Z, script.kernel_string_offsets())); | 6016 TypedData::Handle(Z, script.kernel_string_offsets())); |
2700 helper.SetStringData(TypedData::Handle(Z, script.kernel_string_data())); | 6017 helper.SetStringData(TypedData::Handle(Z, script.kernel_string_data())); |
2701 helper.SetCanonicalNames( | 6018 helper.SetCanonicalNames( |
2702 TypedData::Handle(Z, script.kernel_canonical_names())); | 6019 TypedData::Handle(Z, script.kernel_canonical_names())); |
2703 | 6020 DartTypeTranslator type_translator(&helper, NULL, true); |
2704 StreamingFlowGraphBuilder streaming_flow_graph_builder( | 6021 ConstantEvaluator constant_evaluator(/* flow_graph_builder = */ NULL, Z, |
2705 &helper, zone_, script.kernel_data(), script.kernel_data_size()); | 6022 &helper, &type_translator); |
2706 return streaming_flow_graph_builder.EvaluateMetadata( | 6023 |
2707 metadata_field.kernel_offset()); | 6024 const Array& metadata_values = |
| 6025 Array::Handle(Z, Array::New(metadata_expressions->length())); |
| 6026 |
| 6027 for (intptr_t i = 0; i < metadata_expressions->length(); i++) { |
| 6028 const Instance& value = |
| 6029 constant_evaluator.EvaluateExpression((*metadata_expressions)[i]); |
| 6030 metadata_values.SetAt(i, value); |
| 6031 } |
| 6032 |
| 6033 return metadata_values.raw(); |
2708 } else { | 6034 } else { |
2709 Thread* thread = Thread::Current(); | 6035 Thread* thread = Thread::Current(); |
2710 Error& error = Error::Handle(); | 6036 Error& error = Error::Handle(); |
2711 error = thread->sticky_error(); | 6037 error = thread->sticky_error(); |
2712 thread->clear_sticky_error(); | 6038 thread->clear_sticky_error(); |
2713 return error.raw(); | 6039 return error.raw(); |
2714 } | 6040 } |
2715 } | 6041 } |
2716 | 6042 |
2717 | 6043 |
2718 RawObject* BuildParameterDescriptor(const Function& function) { | 6044 RawObject* BuildParameterDescriptor(const Function& function) { |
2719 LongJumpScope jump; | 6045 LongJumpScope jump; |
2720 if (setjmp(*jump.Set()) == 0) { | 6046 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 |
2721 Thread* thread = Thread::Current(); | 6061 Thread* thread = Thread::Current(); |
2722 Zone* zone_ = thread->zone(); | 6062 Zone* zone_ = thread->zone(); |
2723 TranslationHelper helper(thread); | 6063 TranslationHelper helper(thread); |
2724 Script& script = Script::Handle(Z, function.script()); | 6064 Script& script = Script::Handle(Z, function.script()); |
2725 helper.SetStringOffsets( | 6065 helper.SetStringOffsets( |
2726 TypedData::Handle(Z, script.kernel_string_offsets())); | 6066 TypedData::Handle(Z, script.kernel_string_offsets())); |
2727 helper.SetStringData(TypedData::Handle(Z, script.kernel_string_data())); | 6067 helper.SetStringData(TypedData::Handle(Z, script.kernel_string_data())); |
2728 helper.SetCanonicalNames( | 6068 helper.SetCanonicalNames( |
2729 TypedData::Handle(Z, script.kernel_canonical_names())); | 6069 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); |
2730 | 6073 |
2731 StreamingFlowGraphBuilder streaming_flow_graph_builder( | 6074 const intptr_t positional_count = |
2732 &helper, zone_, script.kernel_data(), script.kernel_data_size()); | 6075 function_node->positional_parameters().length(); |
2733 return streaming_flow_graph_builder.BuildParameterDescriptor( | 6076 const intptr_t param_count = |
2734 function.kernel_offset()); | 6077 positional_count + function_node->named_parameters().length(); |
| 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(); |
2735 } else { | 6109 } else { |
2736 Thread* thread = Thread::Current(); | 6110 Thread* thread = Thread::Current(); |
2737 Error& error = Error::Handle(); | 6111 Error& error = Error::Handle(); |
2738 error = thread->sticky_error(); | 6112 error = thread->sticky_error(); |
2739 thread->clear_sticky_error(); | 6113 thread->clear_sticky_error(); |
2740 return error.raw(); | 6114 return error.raw(); |
2741 } | 6115 } |
2742 } | 6116 } |
2743 | 6117 |
2744 | 6118 |
2745 } // namespace kernel | 6119 } // namespace kernel |
2746 } // namespace dart | 6120 } // namespace dart |
2747 | 6121 |
2748 #endif // !defined(DART_PRECOMPILED_RUNTIME) | 6122 #endif // !defined(DART_PRECOMPILED_RUNTIME) |
OLD | NEW |