| 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 |