OLD | NEW |
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, 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/code_generator.h" | 5 #include "vm/code_generator.h" |
6 | 6 |
7 #include "vm/code_index_table.h" | 7 #include "vm/code_index_table.h" |
8 #include "vm/code_patcher.h" | 8 #include "vm/code_patcher.h" |
9 #include "vm/compiler.h" | 9 #include "vm/compiler.h" |
10 #include "vm/dart_api_impl.h" | 10 #include "vm/dart_api_impl.h" |
(...skipping 405 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
416 // This function is called after successful resolving and compilation of | 416 // This function is called after successful resolving and compilation of |
417 // the target method. | 417 // the target method. |
418 ASSERT(arguments.Count() == kPatchStaticCallRuntimeEntry.argument_count()); | 418 ASSERT(arguments.Count() == kPatchStaticCallRuntimeEntry.argument_count()); |
419 DartFrameIterator iterator; | 419 DartFrameIterator iterator; |
420 DartFrame* caller_frame = iterator.NextFrame(); | 420 DartFrame* caller_frame = iterator.NextFrame(); |
421 ASSERT(caller_frame != NULL); | 421 ASSERT(caller_frame != NULL); |
422 uword target = 0; | 422 uword target = 0; |
423 Function& target_function = Function::Handle(); | 423 Function& target_function = Function::Handle(); |
424 CodePatcher::GetStaticCallAt(caller_frame->pc(), &target_function, &target); | 424 CodePatcher::GetStaticCallAt(caller_frame->pc(), &target_function, &target); |
425 ASSERT(target_function.HasCode()); | 425 ASSERT(target_function.HasCode()); |
426 uword new_target = Code::Handle(target_function.code()).EntryPoint(); | 426 uword new_target = Code::Handle(target_function.CurrentCode()).EntryPoint(); |
427 // Verify that we are not patching repeatedly. | 427 // Verify that we are not patching repeatedly. |
428 ASSERT(target != new_target); | 428 ASSERT(target != new_target); |
429 CodePatcher::PatchStaticCallAt(caller_frame->pc(), new_target); | 429 CodePatcher::PatchStaticCallAt(caller_frame->pc(), new_target); |
430 if (FLAG_trace_patching) { | 430 if (FLAG_trace_patching) { |
431 OS::Print("PatchStaticCall: patching from 0x%x to '%s' 0x%x\n", | 431 OS::Print("PatchStaticCall: patching from 0x%x to '%s' 0x%x\n", |
432 caller_frame->pc(), | 432 caller_frame->pc(), |
433 target_function.ToFullyQualifiedCString(), | 433 target_function.ToFullyQualifiedCString(), |
434 new_target); | 434 new_target); |
435 } | 435 } |
436 } | 436 } |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
481 } else { | 481 } else { |
482 if (!function.HasCode()) { | 482 if (!function.HasCode()) { |
483 const Error& error = Error::Handle(Compiler::CompileFunction(function)); | 483 const Error& error = Error::Handle(Compiler::CompileFunction(function)); |
484 if (!error.IsNull()) { | 484 if (!error.IsNull()) { |
485 Exceptions::PropagateError(error); | 485 Exceptions::PropagateError(error); |
486 } | 486 } |
487 } | 487 } |
488 functions_cache.AddCompiledFunction(function, | 488 functions_cache.AddCompiledFunction(function, |
489 num_arguments, | 489 num_arguments, |
490 num_named_arguments); | 490 num_named_arguments); |
491 return function.code(); | 491 return function.CurrentCode(); |
492 } | 492 } |
493 } | 493 } |
494 | 494 |
495 | 495 |
496 // Result of an invoke may be an unhandled exception, in which case we | 496 // Result of an invoke may be an unhandled exception, in which case we |
497 // rethrow it. | 497 // rethrow it. |
498 static void CheckResultError(const Object& result) { | 498 static void CheckResultError(const Object& result) { |
499 if (result.IsError()) { | 499 if (result.IsError()) { |
500 Exceptions::PropagateError(result); | 500 Exceptions::PropagateError(result); |
501 } | 501 } |
(...skipping 300 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
802 const Array& func_arguments = Array::CheckedHandle(arguments.At(2)); | 802 const Array& func_arguments = Array::CheckedHandle(arguments.At(2)); |
803 const Function& function = Function::Handle(closure.function()); | 803 const Function& function = Function::Handle(closure.function()); |
804 ASSERT(!function.IsNull()); | 804 ASSERT(!function.IsNull()); |
805 if (!function.HasCode()) { | 805 if (!function.HasCode()) { |
806 const Error& error = Error::Handle(Compiler::CompileFunction(function)); | 806 const Error& error = Error::Handle(Compiler::CompileFunction(function)); |
807 if (!error.IsNull()) { | 807 if (!error.IsNull()) { |
808 Exceptions::PropagateError(error); | 808 Exceptions::PropagateError(error); |
809 } | 809 } |
810 } | 810 } |
811 const Context& context = Context::Handle(closure.context()); | 811 const Context& context = Context::Handle(closure.context()); |
812 const Code& code = Code::Handle(function.code()); | 812 const Code& code = Code::Handle(function.CurrentCode()); |
813 ASSERT(!code.IsNull()); | 813 ASSERT(!code.IsNull()); |
814 const Instructions& instrs = Instructions::Handle(code.instructions()); | 814 const Instructions& instrs = Instructions::Handle(code.instructions()); |
815 ASSERT(!instrs.IsNull()); | 815 ASSERT(!instrs.IsNull()); |
816 | 816 |
817 // Adjust arguments descriptor array to account for removal of the receiver | 817 // Adjust arguments descriptor array to account for removal of the receiver |
818 // parameter. Since the arguments descriptor array is canonicalized, create a | 818 // parameter. Since the arguments descriptor array is canonicalized, create a |
819 // new one instead of patching the original one. | 819 // new one instead of patching the original one. |
820 const intptr_t len = arg_descriptor.Length(); | 820 const intptr_t len = arg_descriptor.Length(); |
821 const intptr_t num_named_args = (len - 3) / 2; | 821 const intptr_t num_named_args = (len - 3) / 2; |
822 const Array& adjusted_arg_descriptor = Array::Handle(Array::New(len)); | 822 const Array& adjusted_arg_descriptor = Array::Handle(Array::New(len)); |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
969 DEFINE_RUNTIME_ENTRY(OptimizeInvokedFunction, 1) { | 969 DEFINE_RUNTIME_ENTRY(OptimizeInvokedFunction, 1) { |
970 ASSERT(arguments.Count() == | 970 ASSERT(arguments.Count() == |
971 kOptimizeInvokedFunctionRuntimeEntry.argument_count()); | 971 kOptimizeInvokedFunctionRuntimeEntry.argument_count()); |
972 const Function& function = Function::CheckedHandle(arguments.At(0)); | 972 const Function& function = Function::CheckedHandle(arguments.At(0)); |
973 if (function.deoptimization_counter() >= | 973 if (function.deoptimization_counter() >= |
974 FLAG_deoptimization_counter_threshold) { | 974 FLAG_deoptimization_counter_threshold) { |
975 // TODO(srdjan): Investigate excessive deoptimization. | 975 // TODO(srdjan): Investigate excessive deoptimization. |
976 function.set_usage_counter(0); | 976 function.set_usage_counter(0); |
977 return; | 977 return; |
978 } | 978 } |
979 if (Code::Handle(function.code()).is_optimized()) { | 979 if (function.HasOptimizedCode()) { |
980 // The caller has been already optimized. | 980 // The caller has been already optimized. |
981 // TODO(srdjan): This is a significant slowdown, the caller is probably in | 981 // TODO(srdjan): This is a significant slowdown, the caller is probably in |
982 // a loop. Maybe test if the code has been optimized before calling. | 982 // a loop. Maybe test if the code has been optimized before calling. |
983 // If this happens from optimized code, then it means that the optimized | 983 // If this happens from optimized code, then it means that the optimized |
984 // code needs to be reoptimized. | 984 // code needs to be reoptimized. |
985 function.set_usage_counter(0); | 985 function.set_usage_counter(0); |
986 return; | 986 return; |
987 } | 987 } |
988 if (function.is_optimizable()) { | 988 if (function.is_optimizable()) { |
989 ASSERT(!Code::Handle(function.code()).is_optimized()); | 989 ASSERT(!function.HasOptimizedCode()); |
990 const Code& unoptimized_code = Code::Handle(function.code()); | 990 const Code& unoptimized_code = Code::Handle(function.unoptimized_code()); |
991 // Compilation patches the entry of unoptimized code. | 991 // Compilation patches the entry of unoptimized code. |
992 const Error& error = | 992 const Error& error = |
993 Error::Handle(Compiler::CompileOptimizedFunction(function)); | 993 Error::Handle(Compiler::CompileOptimizedFunction(function)); |
994 if (!error.IsNull()) { | 994 if (!error.IsNull()) { |
995 Exceptions::PropagateError(error); | 995 Exceptions::PropagateError(error); |
996 } | 996 } |
997 const Code& optimized_code = Code::Handle(function.code()); | 997 const Code& optimized_code = Code::Handle(function.CurrentCode()); |
998 ASSERT(!optimized_code.IsNull()); | 998 ASSERT(!optimized_code.IsNull()); |
999 ASSERT(!unoptimized_code.IsNull()); | 999 ASSERT(!unoptimized_code.IsNull()); |
1000 } else { | 1000 } else { |
1001 // TODO(5442338): Abort as this should not happen. | 1001 // TODO(5442338): Abort as this should not happen. |
1002 function.set_usage_counter(0); | 1002 function.set_usage_counter(0); |
1003 } | 1003 } |
1004 } | 1004 } |
1005 | 1005 |
1006 | 1006 |
1007 // The caller must be a static call in a Dart frame, or an entry frame. | 1007 // The caller must be a static call in a Dart frame, or an entry frame. |
1008 // Patch static call to point to 'new_entry_point'. | 1008 // Patch static call to point to 'new_entry_point'. |
1009 DEFINE_RUNTIME_ENTRY(FixCallersTarget, 1) { | 1009 DEFINE_RUNTIME_ENTRY(FixCallersTarget, 1) { |
1010 ASSERT(arguments.Count() == kFixCallersTargetRuntimeEntry.argument_count()); | 1010 ASSERT(arguments.Count() == kFixCallersTargetRuntimeEntry.argument_count()); |
1011 const Function& function = Function::CheckedHandle(arguments.At(0)); | 1011 const Function& function = Function::CheckedHandle(arguments.At(0)); |
1012 ASSERT(!function.IsNull()); | 1012 ASSERT(!function.IsNull()); |
1013 ASSERT(function.HasCode()); | 1013 ASSERT(function.HasCode()); |
1014 | 1014 |
1015 StackFrameIterator iterator(StackFrameIterator::kDontValidateFrames); | 1015 StackFrameIterator iterator(StackFrameIterator::kDontValidateFrames); |
1016 StackFrame* frame = iterator.NextFrame(); | 1016 StackFrame* frame = iterator.NextFrame(); |
1017 while (frame != NULL && !frame->IsDartFrame() && !frame->IsEntryFrame()) { | 1017 while (frame != NULL && !frame->IsDartFrame() && !frame->IsEntryFrame()) { |
1018 frame = iterator.NextFrame(); | 1018 frame = iterator.NextFrame(); |
1019 } | 1019 } |
1020 ASSERT(frame != NULL); | 1020 ASSERT(frame != NULL); |
1021 if (frame->IsDartFrame()) { | 1021 if (frame->IsDartFrame()) { |
1022 uword target = 0; | 1022 uword target = 0; |
1023 Function& target_function = Function::Handle(); | 1023 Function& target_function = Function::Handle(); |
1024 CodePatcher::GetStaticCallAt(frame->pc(), &target_function, &target); | 1024 CodePatcher::GetStaticCallAt(frame->pc(), &target_function, &target); |
1025 const uword new_entry_point = Code::Handle(function.code()).EntryPoint(); | 1025 ASSERT(target_function.HasCode()); |
| 1026 const uword new_entry_point = |
| 1027 Code::Handle(function.CurrentCode()).EntryPoint(); |
1026 ASSERT(target != new_entry_point); // Why patch otherwise. | 1028 ASSERT(target != new_entry_point); // Why patch otherwise. |
1027 ASSERT(target_function.HasCode()); | |
1028 CodePatcher::PatchStaticCallAt(frame->pc(), new_entry_point); | 1029 CodePatcher::PatchStaticCallAt(frame->pc(), new_entry_point); |
1029 if (FLAG_trace_patching) { | 1030 if (FLAG_trace_patching) { |
1030 OS::Print("FixCallersTarget: patching from 0x%x to '%s' 0x%x\n", | 1031 OS::Print("FixCallersTarget: patching from 0x%x to '%s' 0x%x\n", |
1031 frame->pc(), | 1032 frame->pc(), |
1032 target_function.ToFullyQualifiedCString(), | 1033 target_function.ToFullyQualifiedCString(), |
1033 new_entry_point); | 1034 new_entry_point); |
1034 } | 1035 } |
1035 } | 1036 } |
1036 } | 1037 } |
1037 | 1038 |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1090 } | 1091 } |
1091 caller_frame->set_pc(continue_at_pc); | 1092 caller_frame->set_pc(continue_at_pc); |
1092 // Clear invocation counter so that the function gets optimized after | 1093 // Clear invocation counter so that the function gets optimized after |
1093 // types/classes have been collected. | 1094 // types/classes have been collected. |
1094 function.set_usage_counter(0); | 1095 function.set_usage_counter(0); |
1095 function.set_deoptimization_counter(function.deoptimization_counter() + 1); | 1096 function.set_deoptimization_counter(function.deoptimization_counter() + 1); |
1096 | 1097 |
1097 // We have to skip the following otherwise the compiler will complain | 1098 // We have to skip the following otherwise the compiler will complain |
1098 // when it attempts to install unoptimized code into a function that | 1099 // when it attempts to install unoptimized code into a function that |
1099 // was already deoptimized. | 1100 // was already deoptimized. |
1100 if (Code::Handle(function.code()).is_optimized()) { | 1101 if (function.HasOptimizedCode()) { |
1101 // Get unoptimized code. Compilation restores (reenables) the entry of | 1102 // Get unoptimized code. Compilation restores (reenables) the entry of |
1102 // unoptimized code. | 1103 // unoptimized code. |
1103 const Error& error = Error::Handle(Compiler::CompileFunction(function)); | 1104 const Error& error = Error::Handle(Compiler::CompileFunction(function)); |
1104 if (!error.IsNull()) { | 1105 if (!error.IsNull()) { |
1105 Exceptions::PropagateError(error); | 1106 Exceptions::PropagateError(error); |
1106 } | 1107 } |
1107 } | 1108 } |
1108 // TODO(srdjan): Handle better complex cases, e.g. when an older optimized | 1109 // TODO(srdjan): Handle better complex cases, e.g. when an older optimized |
1109 // code is alive on frame and gets deoptimized after the function was | 1110 // code is alive on frame and gets deoptimized after the function was |
1110 // optimized a second time. | 1111 // optimized a second time. |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1175 if (function_name.Equals(test_name)) { | 1176 if (function_name.Equals(test_name)) { |
1176 Smi& smi = Smi::Handle(); | 1177 Smi& smi = Smi::Handle(); |
1177 smi ^= cache.At(i + FunctionsCache::kArgCount); | 1178 smi ^= cache.At(i + FunctionsCache::kArgCount); |
1178 if (num_arguments == smi.Value()) { | 1179 if (num_arguments == smi.Value()) { |
1179 smi ^= cache.At(i + FunctionsCache::kNamedArgCount); | 1180 smi ^= cache.At(i + FunctionsCache::kNamedArgCount); |
1180 if (num_named_arguments == smi.Value()) { | 1181 if (num_named_arguments == smi.Value()) { |
1181 Function& result = Function::Handle(); | 1182 Function& result = Function::Handle(); |
1182 result ^= cache.At(i + FunctionsCache::kFunction); | 1183 result ^= cache.At(i + FunctionsCache::kFunction); |
1183 ASSERT(!result.IsNull()); | 1184 ASSERT(!result.IsNull()); |
1184 ASSERT(result.HasCode()); | 1185 ASSERT(result.HasCode()); |
1185 return result.code(); | 1186 return result.CurrentCode(); |
1186 } | 1187 } |
1187 } | 1188 } |
1188 } | 1189 } |
1189 } | 1190 } |
1190 // The cache is null terminated, therefore the loop above should never | 1191 // The cache is null terminated, therefore the loop above should never |
1191 // terminate by itself. | 1192 // terminate by itself. |
1192 UNREACHABLE(); | 1193 UNREACHABLE(); |
1193 return Code::null(); | 1194 return Code::null(); |
1194 } | 1195 } |
1195 | 1196 |
1196 } // namespace dart | 1197 } // namespace dart |
OLD | NEW |