| 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/code_descriptors.h" | 10 #include "vm/code_descriptors.h" |
| (...skipping 2832 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2843 void EffectGraphVisitor::VisitStaticSetterNode(StaticSetterNode* node) { | 2843 void EffectGraphVisitor::VisitStaticSetterNode(StaticSetterNode* node) { |
| 2844 BuildStaticSetter(node, false); // Result not needed. | 2844 BuildStaticSetter(node, false); // Result not needed. |
| 2845 } | 2845 } |
| 2846 | 2846 |
| 2847 | 2847 |
| 2848 void ValueGraphVisitor::VisitStaticSetterNode(StaticSetterNode* node) { | 2848 void ValueGraphVisitor::VisitStaticSetterNode(StaticSetterNode* node) { |
| 2849 BuildStaticSetter(node, true); // Result needed. | 2849 BuildStaticSetter(node, true); // Result needed. |
| 2850 } | 2850 } |
| 2851 | 2851 |
| 2852 | 2852 |
| 2853 static intptr_t OffsetForLengthGetter(MethodRecognizer::Kind kind) { |
| 2854 switch (kind) { |
| 2855 case MethodRecognizer::kObjectArrayLength: |
| 2856 case MethodRecognizer::kImmutableArrayLength: |
| 2857 return Array::length_offset(); |
| 2858 case MethodRecognizer::kTypedDataLength: |
| 2859 // .length is defined in _TypedList which is the base class for internal |
| 2860 // and external typed data. |
| 2861 ASSERT(TypedData::length_offset() == ExternalTypedData::length_offset()); |
| 2862 return TypedData::length_offset(); |
| 2863 case MethodRecognizer::kGrowableArrayLength: |
| 2864 return GrowableObjectArray::length_offset(); |
| 2865 default: |
| 2866 UNREACHABLE(); |
| 2867 return 0; |
| 2868 } |
| 2869 } |
| 2870 |
| 2871 |
| 2853 void EffectGraphVisitor::VisitNativeBodyNode(NativeBodyNode* node) { | 2872 void EffectGraphVisitor::VisitNativeBodyNode(NativeBodyNode* node) { |
| 2873 const Function& function = owner()->parsed_function()->function(); |
| 2874 if (!function.IsClosureFunction()) { |
| 2875 MethodRecognizer::Kind kind = MethodRecognizer::RecognizeKind(function); |
| 2876 switch (kind) { |
| 2877 case MethodRecognizer::kStringBaseLength: { |
| 2878 LocalVariable* receiver_var = |
| 2879 node->scope()->LookupVariable(Symbols::This(), |
| 2880 true); // Test only. |
| 2881 Value* receiver = Bind(new LoadLocalInstr(*receiver_var)); |
| 2882 // Treat length loads as mutable (i.e. affected by side effects) to |
| 2883 // avoid hoisting them since we can't hoist the preceding class-check. |
| 2884 // This is because of externalization of strings that affects their |
| 2885 // class-id. |
| 2886 const bool is_immutable = false; |
| 2887 LoadFieldInstr* load = new LoadFieldInstr( |
| 2888 receiver, |
| 2889 String::length_offset(), |
| 2890 Type::ZoneHandle(Type::SmiType()), |
| 2891 is_immutable); |
| 2892 load->set_result_cid(kSmiCid); |
| 2893 load->set_recognized_kind(MethodRecognizer::kStringBaseLength); |
| 2894 return ReturnDefinition(load); |
| 2895 } |
| 2896 case MethodRecognizer::kGrowableArrayLength: |
| 2897 case MethodRecognizer::kObjectArrayLength: |
| 2898 case MethodRecognizer::kImmutableArrayLength: |
| 2899 case MethodRecognizer::kTypedDataLength: { |
| 2900 LocalVariable* receiver_var = |
| 2901 node->scope()->LookupVariable(Symbols::This(), |
| 2902 true); // Test only. |
| 2903 Value* receiver = Bind(new LoadLocalInstr(*receiver_var)); |
| 2904 const bool is_immutable = |
| 2905 (kind != MethodRecognizer::kGrowableArrayLength); |
| 2906 LoadFieldInstr* load = new LoadFieldInstr( |
| 2907 receiver, |
| 2908 OffsetForLengthGetter(kind), |
| 2909 Type::ZoneHandle(Type::SmiType()), |
| 2910 is_immutable); |
| 2911 load->set_result_cid(kSmiCid); |
| 2912 load->set_recognized_kind(kind); |
| 2913 return ReturnDefinition(load); |
| 2914 } |
| 2915 default: |
| 2916 break; |
| 2917 } |
| 2918 } |
| 2854 InlineBailout("EffectGraphVisitor::VisitNativeBodyNode"); | 2919 InlineBailout("EffectGraphVisitor::VisitNativeBodyNode"); |
| 2920 function.set_is_optimizable(false); |
| 2855 NativeCallInstr* native_call = new NativeCallInstr(node); | 2921 NativeCallInstr* native_call = new NativeCallInstr(node); |
| 2856 ReturnDefinition(native_call); | 2922 ReturnDefinition(native_call); |
| 2857 } | 2923 } |
| 2858 | 2924 |
| 2859 | 2925 |
| 2860 void EffectGraphVisitor::VisitPrimaryNode(PrimaryNode* node) { | 2926 void EffectGraphVisitor::VisitPrimaryNode(PrimaryNode* node) { |
| 2861 // PrimaryNodes are temporary during parsing. | 2927 // PrimaryNodes are temporary during parsing. |
| 2862 UNREACHABLE(); | 2928 UNREACHABLE(); |
| 2863 } | 2929 } |
| 2864 | 2930 |
| (...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3203 Bind(new AllocateContextInstr(node->token_pos(), | 3269 Bind(new AllocateContextInstr(node->token_pos(), |
| 3204 num_context_variables)); | 3270 num_context_variables)); |
| 3205 { LocalVariable* tmp_var = EnterTempLocalScope(allocated_context); | 3271 { LocalVariable* tmp_var = EnterTempLocalScope(allocated_context); |
| 3206 // If this node_sequence is the body of the function being compiled, and | 3272 // If this node_sequence is the body of the function being compiled, and |
| 3207 // if this function allocates context variables, but none of its enclosing | 3273 // if this function allocates context variables, but none of its enclosing |
| 3208 // functions do, the context on entry is not linked as parent of the | 3274 // functions do, the context on entry is not linked as parent of the |
| 3209 // allocated context but saved on entry and restored on exit as to prevent | 3275 // allocated context but saved on entry and restored on exit as to prevent |
| 3210 // memory leaks. | 3276 // memory leaks. |
| 3211 // In this case, the parser pre-allocates a variable to save the context. | 3277 // In this case, the parser pre-allocates a variable to save the context. |
| 3212 if (MustSaveRestoreContext(node)) { | 3278 if (MustSaveRestoreContext(node)) { |
| 3213 Value* current_context = Bind(new CurrentContextInstr()); | 3279 BuildSaveContext( |
| 3214 Do(BuildStoreTemp( | 3280 *owner()->parsed_function()->saved_entry_context_var()); |
| 3215 *owner()->parsed_function()->saved_entry_context_var(), | |
| 3216 current_context)); | |
| 3217 Value* null_context = Bind(new ConstantInstr(Object::ZoneHandle())); | 3281 Value* null_context = Bind(new ConstantInstr(Object::ZoneHandle())); |
| 3218 AddInstruction(new StoreContextInstr(null_context)); | 3282 AddInstruction(new StoreContextInstr(null_context)); |
| 3219 } | 3283 } |
| 3220 Value* current_context = Bind(new CurrentContextInstr()); | 3284 Value* current_context = Bind(new CurrentContextInstr()); |
| 3221 Value* tmp_val = Bind(new LoadLocalInstr(*tmp_var)); | 3285 Value* tmp_val = Bind(new LoadLocalInstr(*tmp_var)); |
| 3222 Do(new StoreVMFieldInstr(tmp_val, | 3286 Do(new StoreVMFieldInstr(tmp_val, |
| 3223 Context::parent_offset(), | 3287 Context::parent_offset(), |
| 3224 current_context, | 3288 current_context, |
| 3225 Type::ZoneHandle())); | 3289 Type::ZoneHandle())); |
| 3226 AddInstruction( | 3290 AddInstruction( |
| (...skipping 396 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3623 // Print the function ast before IL generation. | 3687 // Print the function ast before IL generation. |
| 3624 AstPrinter::PrintFunctionNodes(*parsed_function()); | 3688 AstPrinter::PrintFunctionNodes(*parsed_function()); |
| 3625 } | 3689 } |
| 3626 const Function& function = parsed_function()->function(); | 3690 const Function& function = parsed_function()->function(); |
| 3627 TargetEntryInstr* normal_entry = | 3691 TargetEntryInstr* normal_entry = |
| 3628 new TargetEntryInstr(AllocateBlockId(), | 3692 new TargetEntryInstr(AllocateBlockId(), |
| 3629 CatchClauseNode::kInvalidTryIndex); | 3693 CatchClauseNode::kInvalidTryIndex); |
| 3630 graph_entry_ = new GraphEntryInstr(*parsed_function(), normal_entry, osr_id_); | 3694 graph_entry_ = new GraphEntryInstr(*parsed_function(), normal_entry, osr_id_); |
| 3631 EffectGraphVisitor for_effect(this, 0); | 3695 EffectGraphVisitor for_effect(this, 0); |
| 3632 // This check may be deleted if the generated code is leaf. | 3696 // This check may be deleted if the generated code is leaf. |
| 3633 CheckStackOverflowInstr* check = | 3697 // Native functions don't need a stack check at entry. |
| 3634 new CheckStackOverflowInstr(function.token_pos(), 0); | 3698 if (!function.is_native()) { |
| 3635 // If we are inlining don't actually attach the stack check. We must still | 3699 CheckStackOverflowInstr* check = |
| 3636 // create the stack check in order to allocate a deopt id. | 3700 new CheckStackOverflowInstr(function.token_pos(), 0); |
| 3637 if (!IsInlining()) for_effect.AddInstruction(check); | 3701 // If we are inlining don't actually attach the stack check. We must still |
| 3702 // create the stack check in order to allocate a deopt id. |
| 3703 if (!IsInlining()) for_effect.AddInstruction(check); |
| 3704 } |
| 3638 parsed_function()->node_sequence()->Visit(&for_effect); | 3705 parsed_function()->node_sequence()->Visit(&for_effect); |
| 3639 AppendFragment(normal_entry, for_effect); | 3706 AppendFragment(normal_entry, for_effect); |
| 3640 // Check that the graph is properly terminated. | 3707 // Check that the graph is properly terminated. |
| 3641 ASSERT(!for_effect.is_open()); | 3708 ASSERT(!for_effect.is_open()); |
| 3642 | 3709 |
| 3643 // When compiling for OSR, use a depth first search to prune instructions | 3710 // When compiling for OSR, use a depth first search to prune instructions |
| 3644 // unreachable from the OSR entry. Catch entries are not (yet) properly | 3711 // unreachable from the OSR entry. Catch entries are not (yet) properly |
| 3645 // recognized as reachable. | 3712 // recognized as reachable. |
| 3646 if (osr_id_ != Isolate::kNoDeoptId) { | 3713 if (osr_id_ != Isolate::kNoDeoptId) { |
| 3647 if (graph_entry_->SuccessorCount() > 1) { | 3714 if (graph_entry_->SuccessorCount() > 1) { |
| (...skipping 22 matching lines...) Expand all Loading... |
| 3670 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1; | 3737 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1; |
| 3671 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len); | 3738 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len); |
| 3672 OS::SNPrint(chars, len, kFormat, function_name, reason); | 3739 OS::SNPrint(chars, len, kFormat, function_name, reason); |
| 3673 const Error& error = Error::Handle( | 3740 const Error& error = Error::Handle( |
| 3674 LanguageError::New(String::Handle(String::New(chars)))); | 3741 LanguageError::New(String::Handle(String::New(chars)))); |
| 3675 Isolate::Current()->long_jump_base()->Jump(1, error); | 3742 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 3676 } | 3743 } |
| 3677 | 3744 |
| 3678 | 3745 |
| 3679 } // namespace dart | 3746 } // namespace dart |
| OLD | NEW |