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