Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(52)

Side by Side Diff: runtime/vm/flow_graph_builder.cc

Issue 695483003: Remove saving/restoring of the context at function entry. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/flow_graph_builder.h ('k') | runtime/vm/object.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_builder.h ('k') | runtime/vm/object.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698