Chromium Code Reviews| 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 2790 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2801 void EffectGraphVisitor::VisitStaticSetterNode(StaticSetterNode* node) { | 2801 void EffectGraphVisitor::VisitStaticSetterNode(StaticSetterNode* node) { |
| 2802 BuildStaticSetter(node, false); // Result not needed. | 2802 BuildStaticSetter(node, false); // Result not needed. |
| 2803 } | 2803 } |
| 2804 | 2804 |
| 2805 | 2805 |
| 2806 void ValueGraphVisitor::VisitStaticSetterNode(StaticSetterNode* node) { | 2806 void ValueGraphVisitor::VisitStaticSetterNode(StaticSetterNode* node) { |
| 2807 BuildStaticSetter(node, true); // Result needed. | 2807 BuildStaticSetter(node, true); // Result needed. |
| 2808 } | 2808 } |
| 2809 | 2809 |
| 2810 | 2810 |
| 2811 static intptr_t OffsetForLengthGetter(MethodRecognizer::Kind kind) { | |
|
srdjan
2013/08/12 21:49:47
Can we share this with the one in FlowGraphOptimiz
Florian Schneider
2013/08/14 12:30:24
The one in the FlowGraphOptimizer is gone with thi
| |
| 2812 switch (kind) { | |
| 2813 case MethodRecognizer::kObjectArrayLength: | |
| 2814 case MethodRecognizer::kImmutableArrayLength: | |
| 2815 return Array::length_offset(); | |
| 2816 case MethodRecognizer::kTypedDataLength: | |
| 2817 // .length is defined in _TypedList which is the base class for internal | |
| 2818 // and external typed data. | |
| 2819 ASSERT(TypedData::length_offset() == ExternalTypedData::length_offset()); | |
| 2820 return TypedData::length_offset(); | |
| 2821 case MethodRecognizer::kGrowableArrayLength: | |
| 2822 return GrowableObjectArray::length_offset(); | |
| 2823 default: | |
| 2824 UNREACHABLE(); | |
| 2825 return 0; | |
| 2826 } | |
| 2827 } | |
| 2828 | |
| 2829 | |
| 2811 void EffectGraphVisitor::VisitNativeBodyNode(NativeBodyNode* node) { | 2830 void EffectGraphVisitor::VisitNativeBodyNode(NativeBodyNode* node) { |
| 2831 const Function& function = owner()->parsed_function()->function(); | |
| 2832 if (!function.IsClosureFunction()) { | |
| 2833 MethodRecognizer::Kind kind = | |
| 2834 MethodRecognizer::RecognizeKind(function); | |
|
Kevin Millikin (Google)
2013/08/13 11:47:40
Fits on the previous line.
Florian Schneider
2013/08/14 12:30:24
Done.
| |
| 2835 switch (kind) { | |
| 2836 case MethodRecognizer::kStringBaseLength: { | |
| 2837 LocalVariable* receiver_var = | |
| 2838 node->scope()->LookupVariable(Symbols::This(), | |
| 2839 true); // Test only. | |
| 2840 Value* receiver = Bind(new LoadLocalInstr(*receiver_var)); | |
| 2841 // Treat length loads as mutable (i.e. affected by side effects) to | |
| 2842 // avoid hoisting them since we can't hoist the preceding class-check. | |
| 2843 // This is because of externalization of strings that affects their | |
| 2844 // class-id. | |
| 2845 const bool is_immutable = false; | |
| 2846 LoadFieldInstr* load = new LoadFieldInstr( | |
| 2847 receiver, | |
| 2848 String::length_offset(), | |
| 2849 Type::ZoneHandle(Type::SmiType()), | |
| 2850 is_immutable); | |
| 2851 load->set_result_cid(kSmiCid); | |
| 2852 load->set_recognized_kind(MethodRecognizer::kStringBaseLength); | |
| 2853 return ReturnDefinition(load); | |
| 2854 } | |
| 2855 case MethodRecognizer::kGrowableArrayLength: | |
| 2856 case MethodRecognizer::kObjectArrayLength: | |
| 2857 case MethodRecognizer::kImmutableArrayLength: | |
| 2858 case MethodRecognizer::kTypedDataLength: { | |
| 2859 LocalVariable* receiver_var = | |
| 2860 node->scope()->LookupVariable(Symbols::This(), | |
| 2861 true); // Test only. | |
| 2862 Value* receiver = Bind(new LoadLocalInstr(*receiver_var)); | |
| 2863 const bool is_immutable = | |
| 2864 (kind != MethodRecognizer::kGrowableArrayLength); | |
| 2865 LoadFieldInstr* load = new LoadFieldInstr( | |
| 2866 receiver, | |
| 2867 OffsetForLengthGetter(kind), | |
| 2868 Type::ZoneHandle(Type::SmiType()), | |
| 2869 is_immutable); | |
| 2870 load->set_result_cid(kSmiCid); | |
| 2871 load->set_recognized_kind(kind); | |
| 2872 return ReturnDefinition(load); | |
| 2873 } | |
| 2874 default: | |
| 2875 break; | |
| 2876 } | |
| 2877 } | |
| 2812 InlineBailout("EffectGraphVisitor::VisitNativeBodyNode"); | 2878 InlineBailout("EffectGraphVisitor::VisitNativeBodyNode"); |
| 2879 function.set_is_optimizable(false); | |
| 2813 NativeCallInstr* native_call = new NativeCallInstr(node); | 2880 NativeCallInstr* native_call = new NativeCallInstr(node); |
| 2814 ReturnDefinition(native_call); | 2881 ReturnDefinition(native_call); |
| 2815 } | 2882 } |
| 2816 | 2883 |
| 2817 | 2884 |
| 2818 void EffectGraphVisitor::VisitPrimaryNode(PrimaryNode* node) { | 2885 void EffectGraphVisitor::VisitPrimaryNode(PrimaryNode* node) { |
| 2819 // PrimaryNodes are temporary during parsing. | 2886 // PrimaryNodes are temporary during parsing. |
| 2820 UNREACHABLE(); | 2887 UNREACHABLE(); |
| 2821 } | 2888 } |
| 2822 | 2889 |
| (...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3161 Bind(new AllocateContextInstr(node->token_pos(), | 3228 Bind(new AllocateContextInstr(node->token_pos(), |
| 3162 num_context_variables)); | 3229 num_context_variables)); |
| 3163 { LocalVariable* tmp_var = EnterTempLocalScope(allocated_context); | 3230 { LocalVariable* tmp_var = EnterTempLocalScope(allocated_context); |
| 3164 // If this node_sequence is the body of the function being compiled, and | 3231 // If this node_sequence is the body of the function being compiled, and |
| 3165 // if this function allocates context variables, but none of its enclosing | 3232 // if this function allocates context variables, but none of its enclosing |
| 3166 // functions do, the context on entry is not linked as parent of the | 3233 // functions do, the context on entry is not linked as parent of the |
| 3167 // allocated context but saved on entry and restored on exit as to prevent | 3234 // allocated context but saved on entry and restored on exit as to prevent |
| 3168 // memory leaks. | 3235 // memory leaks. |
| 3169 // In this case, the parser pre-allocates a variable to save the context. | 3236 // In this case, the parser pre-allocates a variable to save the context. |
| 3170 if (MustSaveRestoreContext(node)) { | 3237 if (MustSaveRestoreContext(node)) { |
| 3171 Value* current_context = Bind(new CurrentContextInstr()); | 3238 BuildSaveContext( |
|
Florian Schneider
2013/08/12 15:48:14
Unrelated refactoring.
| |
| 3172 Do(BuildStoreTemp( | 3239 *owner()->parsed_function()->saved_entry_context_var()); |
| 3173 *owner()->parsed_function()->saved_entry_context_var(), | |
| 3174 current_context)); | |
| 3175 Value* null_context = Bind(new ConstantInstr(Object::ZoneHandle())); | 3240 Value* null_context = Bind(new ConstantInstr(Object::ZoneHandle())); |
| 3176 AddInstruction(new StoreContextInstr(null_context)); | 3241 AddInstruction(new StoreContextInstr(null_context)); |
| 3177 } | 3242 } |
| 3178 Value* current_context = Bind(new CurrentContextInstr()); | 3243 Value* current_context = Bind(new CurrentContextInstr()); |
| 3179 Value* tmp_val = Bind(new LoadLocalInstr(*tmp_var)); | 3244 Value* tmp_val = Bind(new LoadLocalInstr(*tmp_var)); |
| 3180 Do(new StoreVMFieldInstr(tmp_val, | 3245 Do(new StoreVMFieldInstr(tmp_val, |
| 3181 Context::parent_offset(), | 3246 Context::parent_offset(), |
| 3182 current_context, | 3247 current_context, |
| 3183 Type::ZoneHandle())); | 3248 Type::ZoneHandle())); |
| 3184 AddInstruction( | 3249 AddInstruction( |
| (...skipping 394 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3579 // Print the function ast before IL generation. | 3644 // Print the function ast before IL generation. |
| 3580 AstPrinter::PrintFunctionNodes(*parsed_function()); | 3645 AstPrinter::PrintFunctionNodes(*parsed_function()); |
| 3581 } | 3646 } |
| 3582 const Function& function = parsed_function()->function(); | 3647 const Function& function = parsed_function()->function(); |
| 3583 TargetEntryInstr* normal_entry = | 3648 TargetEntryInstr* normal_entry = |
| 3584 new TargetEntryInstr(AllocateBlockId(), | 3649 new TargetEntryInstr(AllocateBlockId(), |
| 3585 CatchClauseNode::kInvalidTryIndex); | 3650 CatchClauseNode::kInvalidTryIndex); |
| 3586 graph_entry_ = new GraphEntryInstr(*parsed_function(), normal_entry, osr_id_); | 3651 graph_entry_ = new GraphEntryInstr(*parsed_function(), normal_entry, osr_id_); |
| 3587 EffectGraphVisitor for_effect(this, 0); | 3652 EffectGraphVisitor for_effect(this, 0); |
| 3588 // This check may be deleted if the generated code is leaf. | 3653 // This check may be deleted if the generated code is leaf. |
| 3589 CheckStackOverflowInstr* check = | 3654 // Native functions don't need a stack check at entry. |
| 3590 new CheckStackOverflowInstr(function.token_pos(), 0); | 3655 if (!function.is_native()) { |
| 3591 // If we are inlining don't actually attach the stack check. We must still | 3656 CheckStackOverflowInstr* check = |
| 3592 // create the stack check in order to allocate a deopt id. | 3657 new CheckStackOverflowInstr(function.token_pos(), 0); |
| 3593 if (!IsInlining()) for_effect.AddInstruction(check); | 3658 // If we are inlining don't actually attach the stack check. We must still |
| 3659 // create the stack check in order to allocate a deopt id. | |
| 3660 if (!IsInlining()) for_effect.AddInstruction(check); | |
| 3661 } | |
| 3594 parsed_function()->node_sequence()->Visit(&for_effect); | 3662 parsed_function()->node_sequence()->Visit(&for_effect); |
| 3595 AppendFragment(normal_entry, for_effect); | 3663 AppendFragment(normal_entry, for_effect); |
| 3596 // Check that the graph is properly terminated. | 3664 // Check that the graph is properly terminated. |
| 3597 ASSERT(!for_effect.is_open()); | 3665 ASSERT(!for_effect.is_open()); |
| 3598 | 3666 |
| 3599 // When compiling for OSR, use a depth first search to prune instructions | 3667 // When compiling for OSR, use a depth first search to prune instructions |
| 3600 // unreachable from the OSR entry. Catch entries are not (yet) properly | 3668 // unreachable from the OSR entry. Catch entries are not (yet) properly |
| 3601 // recognized as reachable. | 3669 // recognized as reachable. |
| 3602 if (osr_id_ != Isolate::kNoDeoptId) { | 3670 if (osr_id_ != Isolate::kNoDeoptId) { |
| 3603 if (graph_entry_->SuccessorCount() > 1) { | 3671 if (graph_entry_->SuccessorCount() > 1) { |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 3626 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1; | 3694 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1; |
| 3627 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len); | 3695 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len); |
| 3628 OS::SNPrint(chars, len, kFormat, function_name, reason); | 3696 OS::SNPrint(chars, len, kFormat, function_name, reason); |
| 3629 const Error& error = Error::Handle( | 3697 const Error& error = Error::Handle( |
| 3630 LanguageError::New(String::Handle(String::New(chars)))); | 3698 LanguageError::New(String::Handle(String::New(chars)))); |
| 3631 Isolate::Current()->long_jump_base()->Jump(1, error); | 3699 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 3632 } | 3700 } |
| 3633 | 3701 |
| 3634 | 3702 |
| 3635 } // namespace dart | 3703 } // namespace dart |
| OLD | NEW |