OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 "vm/flow_graph_builder.h" | 5 #include "vm/flow_graph_builder.h" |
6 | 6 |
7 #include "lib/invocation_mirror.h" | 7 #include "lib/invocation_mirror.h" |
8 #include "vm/ast_printer.h" | 8 #include "vm/ast_printer.h" |
9 #include "vm/bit_vector.h" | 9 #include "vm/bit_vector.h" |
10 #include "vm/class_finalizer.h" | 10 #include "vm/class_finalizer.h" |
(...skipping 1080 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1091 1, | 1091 1, |
1092 owner()->ic_data_array()); | 1092 owner()->ic_data_array()); |
1093 Do(call); | 1093 Do(call); |
1094 | 1094 |
1095 // Rebind the return value for the actual return call to be null. | 1095 // Rebind the return value for the actual return call to be null. |
1096 return_value = BuildNullValue(); | 1096 return_value = BuildNullValue(); |
1097 } | 1097 } |
1098 | 1098 |
1099 intptr_t current_context_level = owner()->context_level(); | 1099 intptr_t current_context_level = owner()->context_level(); |
1100 ASSERT(current_context_level >= 0); | 1100 ASSERT(current_context_level >= 0); |
1101 if (owner()->parsed_function()->saved_entry_context_var() != NULL) { | 1101 if (HasContextScope()) { |
1102 // CTX on entry was saved, but not linked as context parent. | |
1103 BuildRestoreContext(*owner()->parsed_function()->saved_entry_context_var()); | |
1104 } else { | |
1105 UnchainContexts(current_context_level); | 1102 UnchainContexts(current_context_level); |
1106 } | 1103 } |
1107 | 1104 |
1108 | 1105 |
1109 AddReturnExit(node->token_pos(), return_value); | 1106 AddReturnExit(node->token_pos(), return_value); |
1110 | 1107 |
1111 if (function.is_async_closure() && | 1108 if (function.is_async_closure() && |
1112 (node->return_type() == ReturnNode::kContinuationTarget)) { | 1109 (node->return_type() == ReturnNode::kContinuationTarget)) { |
1113 JoinEntryInstr* const join = new(I) JoinEntryInstr( | 1110 JoinEntryInstr* const join = new(I) JoinEntryInstr( |
1114 owner()->AllocateBlockId(), owner()->try_index()); | 1111 owner()->AllocateBlockId(), owner()->try_index()); |
(...skipping 2531 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3646 void EffectGraphVisitor::VisitStoreIndexedNode(StoreIndexedNode* node) { | 3643 void EffectGraphVisitor::VisitStoreIndexedNode(StoreIndexedNode* node) { |
3647 ReturnDefinition(BuildStoreIndexedValues(node, kResultNotNeeded)); | 3644 ReturnDefinition(BuildStoreIndexedValues(node, kResultNotNeeded)); |
3648 } | 3645 } |
3649 | 3646 |
3650 | 3647 |
3651 void ValueGraphVisitor::VisitStoreIndexedNode(StoreIndexedNode* node) { | 3648 void ValueGraphVisitor::VisitStoreIndexedNode(StoreIndexedNode* node) { |
3652 ReturnDefinition(BuildStoreIndexedValues(node, kResultNeeded)); | 3649 ReturnDefinition(BuildStoreIndexedValues(node, kResultNeeded)); |
3653 } | 3650 } |
3654 | 3651 |
3655 | 3652 |
3656 bool EffectGraphVisitor::MustSaveRestoreContext(SequenceNode* node) const { | 3653 bool EffectGraphVisitor::HasContextScope() const { |
3657 return (node == owner()->parsed_function()->node_sequence()) && | 3654 const ContextScope& context_scope = ContextScope::Handle( |
3658 (owner()->parsed_function()->saved_entry_context_var() != NULL); | 3655 owner()->parsed_function()->function().context_scope()); |
| 3656 return !context_scope.IsNull() && (context_scope.num_variables() > 0); |
3659 } | 3657 } |
3660 | 3658 |
3661 | 3659 |
3662 void EffectGraphVisitor::UnchainContexts(intptr_t n) { | 3660 void EffectGraphVisitor::UnchainContexts(intptr_t n) { |
3663 if (n > 0) { | 3661 if (n > 0) { |
3664 Value* context = Bind(BuildCurrentContext()); | 3662 Value* context = Bind(BuildCurrentContext()); |
3665 while (n-- > 0) { | 3663 while (n-- > 0) { |
3666 context = Bind( | 3664 context = Bind( |
3667 new(I) LoadFieldInstr(context, | 3665 new(I) LoadFieldInstr(context, |
3668 Context::parent_offset(), | 3666 Context::parent_offset(), |
3669 // Not an instance, no type. | 3667 // Not an instance, no type. |
3670 Type::ZoneHandle(I, Type::null()), | 3668 Type::ZoneHandle(I, Type::null()), |
3671 Scanner::kNoSourcePos)); | 3669 Scanner::kNoSourcePos)); |
3672 } | 3670 } |
3673 Do(BuildStoreContext(context)); | 3671 Do(BuildStoreContext(context)); |
3674 } | 3672 } |
3675 } | 3673 } |
3676 | 3674 |
3677 | 3675 |
3678 // <Statement> ::= Sequence { scope: LocalScope | 3676 // <Statement> ::= Sequence { scope: LocalScope |
3679 // nodes: <Statement>* | 3677 // nodes: <Statement>* |
3680 // label: SourceLabel } | 3678 // label: SourceLabel } |
3681 void EffectGraphVisitor::VisitSequenceNode(SequenceNode* node) { | 3679 void EffectGraphVisitor::VisitSequenceNode(SequenceNode* node) { |
3682 LocalScope* scope = node->scope(); | 3680 LocalScope* scope = node->scope(); |
3683 const intptr_t num_context_variables = | 3681 const intptr_t num_context_variables = |
3684 (scope != NULL) ? scope->num_context_variables() : 0; | 3682 (scope != NULL) ? scope->num_context_variables() : 0; |
| 3683 const bool is_top_level_sequence = |
| 3684 node == owner()->parsed_function()->node_sequence(); |
3685 // The outermost function sequence cannot contain a label. | 3685 // The outermost function sequence cannot contain a label. |
3686 ASSERT((node->label() == NULL) || | 3686 ASSERT((node->label() == NULL) || !is_top_level_sequence); |
3687 (node != owner()->parsed_function()->node_sequence())); | |
3688 NestedBlock nested_block(owner(), node); | 3687 NestedBlock nested_block(owner(), node); |
3689 | 3688 |
3690 if (num_context_variables > 0) { | 3689 if (num_context_variables > 0) { |
3691 // The loop local scope declares variables that are captured. | 3690 // The local scope declares variables that are captured. |
3692 // Allocate and chain a new context. | 3691 // Allocate and chain a new context (Except don't chain when at the function |
3693 // Allocate context computation (uses current context) | 3692 // entry if the function does not capture any variables from outer scopes). |
3694 Value* allocated_context = | 3693 Value* allocated_context = |
3695 Bind(new(I) AllocateContextInstr(node->token_pos(), | 3694 Bind(new(I) AllocateContextInstr(node->token_pos(), |
3696 num_context_variables)); | 3695 num_context_variables)); |
3697 { LocalVariable* tmp_var = EnterTempLocalScope(allocated_context); | 3696 { LocalVariable* tmp_var = EnterTempLocalScope(allocated_context); |
3698 // If this node_sequence is the body of the function being compiled, and | 3697 if (HasContextScope() || !is_top_level_sequence) { |
3699 // if this function allocates context variables, but none of its enclosing | 3698 Value* tmp_val = Bind(new(I) LoadLocalInstr(*tmp_var)); |
3700 // functions do, the context on entry is not linked as parent of the | 3699 Value* parent_context = Bind(BuildCurrentContext()); |
3701 // allocated context but saved on entry and restored on exit as to prevent | 3700 Do(new(I) StoreInstanceFieldInstr(Context::parent_offset(), |
3702 // memory leaks. | 3701 tmp_val, |
3703 // In this case, the parser pre-allocates a variable to save the context. | 3702 parent_context, |
3704 Value* tmp_val = Bind(new(I) LoadLocalInstr(*tmp_var)); | 3703 kEmitStoreBarrier, |
3705 Value* parent_context = NULL; | 3704 Scanner::kNoSourcePos)); |
3706 if (MustSaveRestoreContext(node)) { | |
3707 BuildSaveContext( | |
3708 *owner()->parsed_function()->saved_entry_context_var()); | |
3709 parent_context = Bind( | |
3710 new(I) ConstantInstr(Object::ZoneHandle(I, Object::null()))); | |
3711 } else { | |
3712 parent_context = Bind(BuildCurrentContext()); | |
3713 } | 3705 } |
3714 Do(new(I) StoreInstanceFieldInstr(Context::parent_offset(), | |
3715 tmp_val, | |
3716 parent_context, | |
3717 kEmitStoreBarrier, | |
3718 Scanner::kNoSourcePos)); | |
3719 Do(BuildStoreContext(Bind(ExitTempLocalScope(tmp_var)))); | 3706 Do(BuildStoreContext(Bind(ExitTempLocalScope(tmp_var)))); |
3720 } | 3707 } |
3721 | 3708 |
3722 // If this node_sequence is the body of the function being compiled, copy | 3709 // If this node_sequence is the body of the function being compiled, copy |
3723 // the captured parameters from the frame into the context. | 3710 // the captured parameters from the frame into the context. |
3724 if (node == owner()->parsed_function()->node_sequence()) { | 3711 if (is_top_level_sequence) { |
3725 ASSERT(scope->context_level() == 1); | 3712 ASSERT(scope->context_level() == 1); |
3726 const Function& function = owner()->parsed_function()->function(); | 3713 const Function& function = owner()->parsed_function()->function(); |
3727 const int num_params = function.NumParameters(); | 3714 const int num_params = function.NumParameters(); |
3728 int param_frame_index = (num_params == function.num_fixed_parameters()) ? | 3715 int param_frame_index = (num_params == function.num_fixed_parameters()) ? |
3729 (kParamEndSlotFromFp + num_params) : kFirstLocalSlotFromFp; | 3716 (kParamEndSlotFromFp + num_params) : kFirstLocalSlotFromFp; |
3730 for (int pos = 0; pos < num_params; param_frame_index--, pos++) { | 3717 for (int pos = 0; pos < num_params; param_frame_index--, pos++) { |
3731 const LocalVariable& parameter = *scope->VariableAt(pos); | 3718 const LocalVariable& parameter = *scope->VariableAt(pos); |
3732 ASSERT(parameter.owner() == scope); | 3719 ASSERT(parameter.owner() == scope); |
3733 if (parameter.is_captured()) { | 3720 if (parameter.is_captured()) { |
3734 // Create a temporary local describing the original position. | 3721 // Create a temporary local describing the original position. |
(...skipping 15 matching lines...) Expand all Loading... |
3750 Do(BuildStoreLocal(parameter, load)); | 3737 Do(BuildStoreLocal(parameter, load)); |
3751 // Write NULL to the source location to detect buggy accesses and | 3738 // Write NULL to the source location to detect buggy accesses and |
3752 // allow GC of passed value if it gets overwritten by a new value in | 3739 // allow GC of passed value if it gets overwritten by a new value in |
3753 // the function. | 3740 // the function. |
3754 Value* null_constant = Bind(new(I) ConstantInstr( | 3741 Value* null_constant = Bind(new(I) ConstantInstr( |
3755 Object::ZoneHandle(I, Object::null()))); | 3742 Object::ZoneHandle(I, Object::null()))); |
3756 Do(BuildStoreLocal(*temp_local, null_constant)); | 3743 Do(BuildStoreLocal(*temp_local, null_constant)); |
3757 } | 3744 } |
3758 } | 3745 } |
3759 } | 3746 } |
3760 } else if (MustSaveRestoreContext(node)) { | |
3761 // Even when the current scope has no context variables, we may | |
3762 // still need to save the current context if, for example, there | |
3763 // are loop scopes below this which will allocate a context | |
3764 // object. | |
3765 BuildSaveContext( | |
3766 *owner()->parsed_function()->saved_entry_context_var()); | |
3767 Do(BuildStoreContext(Bind(new(I) ConstantInstr(Object::ZoneHandle( | |
3768 I, I->object_store()->empty_context()))))); | |
3769 } | 3747 } |
3770 | 3748 |
3771 // This check may be deleted if the generated code is leaf. | 3749 // This check may be deleted if the generated code is leaf. |
3772 // Native functions don't need a stack check at entry. | 3750 // Native functions don't need a stack check at entry. |
3773 const Function& function = owner()->parsed_function()->function(); | 3751 const Function& function = owner()->parsed_function()->function(); |
3774 if ((node == owner()->parsed_function()->node_sequence()) && | 3752 if (is_top_level_sequence && !function.is_native()) { |
3775 !function.is_native()) { | |
3776 // Always allocate CheckOverflowInstr so that deopt-ids match regardless | 3753 // Always allocate CheckOverflowInstr so that deopt-ids match regardless |
3777 // if we inline or not. | 3754 // if we inline or not. |
3778 if (!function.IsImplicitGetterFunction() && | 3755 if (!function.IsImplicitGetterFunction() && |
3779 !function.IsImplicitSetterFunction()) { | 3756 !function.IsImplicitSetterFunction()) { |
3780 CheckStackOverflowInstr* check = | 3757 CheckStackOverflowInstr* check = |
3781 new(I) CheckStackOverflowInstr(function.token_pos(), 0); | 3758 new(I) CheckStackOverflowInstr(function.token_pos(), 0); |
3782 // If we are inlining don't actually attach the stack check. We must still | 3759 // If we are inlining don't actually attach the stack check. We must still |
3783 // create the stack check in order to allocate a deopt id. | 3760 // create the stack check in order to allocate a deopt id. |
3784 if (!owner()->IsInlining()) { | 3761 if (!owner()->IsInlining()) { |
3785 AddInstruction(check); | 3762 AddInstruction(check); |
3786 } | 3763 } |
3787 } | 3764 } |
3788 } | 3765 } |
3789 | 3766 |
3790 if (FLAG_enable_type_checks && | 3767 if (FLAG_enable_type_checks && is_top_level_sequence) { |
3791 (node == owner()->parsed_function()->node_sequence())) { | |
3792 const Function& function = owner()->parsed_function()->function(); | 3768 const Function& function = owner()->parsed_function()->function(); |
3793 const int num_params = function.NumParameters(); | 3769 const int num_params = function.NumParameters(); |
3794 int pos = 0; | 3770 int pos = 0; |
3795 if (function.IsConstructor()) { | 3771 if (function.IsConstructor()) { |
3796 // Skip type checking of receiver and phase for constructor functions. | 3772 // Skip type checking of receiver and phase for constructor functions. |
3797 pos = 2; | 3773 pos = 2; |
3798 } else if (function.IsFactory() || function.IsDynamicFunction()) { | 3774 } else if (function.IsFactory() || function.IsDynamicFunction()) { |
3799 // Skip type checking of type arguments for factory functions. | 3775 // Skip type checking of type arguments for factory functions. |
3800 // Skip type checking of receiver for instance functions. | 3776 // Skip type checking of receiver for instance functions. |
3801 pos = 1; | 3777 pos = 1; |
(...skipping 18 matching lines...) Expand all Loading... |
3820 Do(BuildStoreLocal(parameter, parameter_value)); | 3796 Do(BuildStoreLocal(parameter, parameter_value)); |
3821 } | 3797 } |
3822 pos++; | 3798 pos++; |
3823 } | 3799 } |
3824 } | 3800 } |
3825 | 3801 |
3826 // Continuation part: | 3802 // Continuation part: |
3827 // If this node sequence is the body of an async closure leave room for a | 3803 // If this node sequence is the body of an async closure leave room for a |
3828 // preamble. The preamble is generated after visiting the body. | 3804 // preamble. The preamble is generated after visiting the body. |
3829 GotoInstr* preamble_start = NULL; | 3805 GotoInstr* preamble_start = NULL; |
3830 if ((node == owner()->parsed_function()->node_sequence()) && | 3806 if (is_top_level_sequence && |
3831 (owner()->parsed_function()->function().is_async_closure())) { | 3807 (owner()->parsed_function()->function().is_async_closure())) { |
3832 JoinEntryInstr* preamble_end = new(I) JoinEntryInstr( | 3808 JoinEntryInstr* preamble_end = new(I) JoinEntryInstr( |
3833 owner()->AllocateBlockId(), owner()->try_index()); | 3809 owner()->AllocateBlockId(), owner()->try_index()); |
3834 ASSERT(exit() != NULL); | 3810 ASSERT(exit() != NULL); |
3835 exit()->Goto(preamble_end); | 3811 exit()->Goto(preamble_end); |
3836 ASSERT(exit()->next()->IsGoto()); | 3812 ASSERT(exit()->next()->IsGoto()); |
3837 preamble_start = exit()->next()->AsGoto(); | 3813 preamble_start = exit()->next()->AsGoto(); |
3838 ASSERT(preamble_start->IsGoto()); | 3814 ASSERT(preamble_start->IsGoto()); |
3839 exit_ = preamble_end; | 3815 exit_ = preamble_end; |
3840 } | 3816 } |
3841 | 3817 |
3842 intptr_t i = 0; | 3818 intptr_t i = 0; |
3843 while (is_open() && (i < node->length())) { | 3819 while (is_open() && (i < node->length())) { |
3844 EffectGraphVisitor for_effect(owner()); | 3820 EffectGraphVisitor for_effect(owner()); |
3845 node->NodeAt(i++)->Visit(&for_effect); | 3821 node->NodeAt(i++)->Visit(&for_effect); |
3846 Append(for_effect); | 3822 Append(for_effect); |
3847 if (!is_open()) { | 3823 if (!is_open()) { |
3848 // E.g., because of a JumpNode. | 3824 // E.g., because of a JumpNode. |
3849 break; | 3825 break; |
3850 } | 3826 } |
3851 } | 3827 } |
3852 | 3828 |
3853 // Continuation part: | 3829 // Continuation part: |
3854 // After generating the CFG for the body we can create the preamble because we | 3830 // After generating the CFG for the body we can create the preamble because we |
3855 // know exactly how many continuation states we need. | 3831 // know exactly how many continuation states we need. |
3856 if ((node == owner()->parsed_function()->node_sequence()) && | 3832 if (is_top_level_sequence && |
3857 (owner()->parsed_function()->function().is_async_closure())) { | 3833 (owner()->parsed_function()->function().is_async_closure())) { |
3858 ASSERT(preamble_start != NULL); | 3834 ASSERT(preamble_start != NULL); |
3859 // We are at the top level. Fetch the corresponding scope. | 3835 // We are at the top level. Fetch the corresponding scope. |
3860 LocalScope* top_scope = node->scope(); | 3836 LocalScope* top_scope = node->scope(); |
3861 LocalVariable* jump_var = top_scope->LookupVariable( | 3837 LocalVariable* jump_var = top_scope->LookupVariable( |
3862 Symbols::AwaitJumpVar(), false); | 3838 Symbols::AwaitJumpVar(), false); |
3863 ASSERT(jump_var != NULL && jump_var->is_captured()); | 3839 ASSERT(jump_var != NULL && jump_var->is_captured()); |
3864 | 3840 |
3865 Instruction* saved_entry = entry_; | 3841 Instruction* saved_entry = entry_; |
3866 Instruction* saved_exit = exit_; | 3842 Instruction* saved_exit = exit_; |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3907 exit_ = preamble_start; | 3883 exit_ = preamble_start; |
3908 } else { | 3884 } else { |
3909 exit_->LinkTo(preamble_start); | 3885 exit_->LinkTo(preamble_start); |
3910 } | 3886 } |
3911 } | 3887 } |
3912 } | 3888 } |
3913 entry_ = saved_entry; | 3889 entry_ = saved_entry; |
3914 exit_ = saved_exit; | 3890 exit_ = saved_exit; |
3915 } | 3891 } |
3916 | 3892 |
3917 if (is_open()) { | 3893 if (is_open() && |
3918 if (MustSaveRestoreContext(node)) { | 3894 (num_context_variables > 0) && |
3919 BuildRestoreContext( | 3895 (HasContextScope() || !is_top_level_sequence)) { |
3920 *owner()->parsed_function()->saved_entry_context_var()); | 3896 UnchainContexts(1); |
3921 } else if (num_context_variables > 0) { | |
3922 UnchainContexts(1); | |
3923 } | |
3924 } | 3897 } |
3925 | 3898 |
3926 // If this node sequence is labeled, a break out of the sequence will have | 3899 // If this node sequence is labeled, a break out of the sequence will have |
3927 // taken care of unchaining the context. | 3900 // taken care of unchaining the context. |
3928 if (nested_block.break_target() != NULL) { | 3901 if (nested_block.break_target() != NULL) { |
3929 if (is_open()) Goto(nested_block.break_target()); | 3902 if (is_open()) Goto(nested_block.break_target()); |
3930 exit_ = nested_block.break_target(); | 3903 exit_ = nested_block.break_target(); |
3931 } | 3904 } |
3932 } | 3905 } |
3933 | 3906 |
(...skipping 348 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4282 Report::MessageF(Report::kBailout, | 4255 Report::MessageF(Report::kBailout, |
4283 Script::Handle(function.script()), | 4256 Script::Handle(function.script()), |
4284 function.token_pos(), | 4257 function.token_pos(), |
4285 "FlowGraphBuilder Bailout: %s %s", | 4258 "FlowGraphBuilder Bailout: %s %s", |
4286 String::Handle(function.name()).ToCString(), | 4259 String::Handle(function.name()).ToCString(), |
4287 reason); | 4260 reason); |
4288 UNREACHABLE(); | 4261 UNREACHABLE(); |
4289 } | 4262 } |
4290 | 4263 |
4291 } // namespace dart | 4264 } // namespace dart |
OLD | NEW |