| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 "platform/address_sanitizer.h" | 5 #include "platform/address_sanitizer.h" |
| 6 #include "platform/memory_sanitizer.h" | 6 #include "platform/memory_sanitizer.h" |
| 7 #include "platform/utils.h" | 7 #include "platform/utils.h" |
| 8 | 8 |
| 9 #include "vm/allocation.h" | 9 #include "vm/allocation.h" |
| 10 #include "vm/atomic.h" | 10 #include "vm/atomic.h" |
| (...skipping 797 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 808 new_protect, | 808 new_protect, |
| 809 &old_protect); | 809 &old_protect); |
| 810 USE(success); | 810 USE(success); |
| 811 ASSERT(success); | 811 ASSERT(success); |
| 812 ASSERT(old_protect == PAGE_READWRITE); | 812 ASSERT(old_protect == PAGE_READWRITE); |
| 813 } | 813 } |
| 814 #endif | 814 #endif |
| 815 } | 815 } |
| 816 | 816 |
| 817 | 817 |
| 818 void Profiler::RecordAllocation(Isolate* isolate, intptr_t cid) { | 818 // Is |isolate| executing Dart code? |
| 819 if ((isolate == NULL) || (Dart::vm_isolate() == NULL)) { | 819 static bool ExecutingDart(Isolate* isolate) { |
| 820 // No isolate. | 820 ASSERT(isolate != NULL); |
| 821 return; | 821 return (isolate->top_exit_frame_info() == 0) && |
| 822 (isolate->vm_tag() == VMTag::kDartTagId); |
| 823 } |
| 824 |
| 825 |
| 826 // Has |isolate| exited Dart code? |
| 827 static bool ExitedDart(Isolate* isolate) { |
| 828 return (isolate->top_exit_frame_info() != 0) && |
| 829 (isolate->vm_tag() != VMTag::kDartTagId); |
| 830 } |
| 831 |
| 832 |
| 833 // Get |isolate|'s stack boundary and verify that |sp| and |fp| are within |
| 834 // it. Return |false| if anything looks suspicious. |
| 835 static bool GetAndValidateIsolateStackBounds(Isolate* isolate, |
| 836 uintptr_t sp, |
| 837 uintptr_t fp, |
| 838 uword* stack_lower, |
| 839 uword* stack_upper) { |
| 840 ASSERT(isolate != NULL); |
| 841 ASSERT(stack_lower != NULL); |
| 842 ASSERT(stack_upper != NULL); |
| 843 #if defined(USING_SIMULATOR) |
| 844 Simulator* simulator = NULL; |
| 845 #endif |
| 846 |
| 847 #if defined(USING_SIMULATOR) |
| 848 const bool in_dart_code = ExecutingDart(isolate); |
| 849 if (in_dart_code) { |
| 850 *stack_lower = simulator->StackBase(); |
| 851 *stack_upper = simulator->StackTop(); |
| 852 } else if (!isolate->GetProfilerStackBounds(stack_lower, stack_upper)) { |
| 853 // Could not get stack boundary. |
| 854 return false; |
| 822 } | 855 } |
| 823 ASSERT(isolate != Dart::vm_isolate()); | 856 if ((*stack_lower == 0) || (*stack_upper == 0)) { |
| 824 | 857 return false; |
| 825 const bool exited_dart_code = (isolate->top_exit_frame_info() != 0) && | 858 } |
| 826 (isolate->vm_tag() != VMTag::kDartTagId); | 859 #else |
| 827 | 860 if (!isolate->GetProfilerStackBounds(stack_lower, stack_upper) || |
| 828 if (!exited_dart_code) { | 861 (*stack_lower == 0) || (*stack_upper == 0)) { |
| 829 // No Dart frames on stack. | 862 // Could not get stack boundary. |
| 830 // TODO(johnmccutchan): Support collecting native stack. | 863 return false; |
| 831 return; | 864 } |
| 865 #endif |
| 866 if (sp > *stack_lower) { |
| 867 // The stack pointer gives us a tighter lower bound. |
| 868 *stack_lower = sp; |
| 832 } | 869 } |
| 833 | 870 |
| 871 if (*stack_lower >= *stack_upper) { |
| 872 // Stack boundary is invalid. |
| 873 return false; |
| 874 } |
| 875 |
| 876 if ((sp < *stack_lower) || (sp >= *stack_upper)) { |
| 877 // Stack pointer is outside isolate stack boundary. |
| 878 return false; |
| 879 } |
| 880 |
| 881 if ((fp < *stack_lower) || (fp >= *stack_upper)) { |
| 882 // Frame pointer is outside isolate stack boundary. |
| 883 return false; |
| 884 } |
| 885 |
| 886 return true; |
| 887 } |
| 888 |
| 889 |
| 890 // Some simple sanity checking of |pc|, |sp|, and |fp|. |
| 891 static bool InitialRegisterCheck(uintptr_t pc, uintptr_t sp, uintptr_t fp) { |
| 892 if ((sp == 0) || (fp == 0) || (pc == 0)) { |
| 893 // None of these registers should be zero. |
| 894 return false; |
| 895 } |
| 896 |
| 897 if (sp > fp) { |
| 898 // Assuming the stack grows down, we should never have a stack pointer above |
| 899 // the frame pointer. |
| 900 return false; |
| 901 } |
| 902 |
| 903 return true; |
| 904 } |
| 905 |
| 906 |
| 907 // Return |isolate|'s sample buffer. |
| 908 static SampleBuffer* GetSampleBuffer(Isolate* isolate) { |
| 834 IsolateProfilerData* profiler_data = isolate->profiler_data(); | 909 IsolateProfilerData* profiler_data = isolate->profiler_data(); |
| 835 if (profiler_data == NULL) { | 910 if (profiler_data == NULL) { |
| 836 // Profiler not initialized. | 911 // Profiler not initialized. |
| 837 return; | 912 return NULL; |
| 838 } | 913 } |
| 914 SampleBuffer* sample_buffer = profiler_data->sample_buffer(); |
| 915 return sample_buffer; |
| 916 } |
| 839 | 917 |
| 840 SampleBuffer* sample_buffer = profiler_data->sample_buffer(); | |
| 841 if (sample_buffer == NULL) { | |
| 842 // Profiler not initialized. | |
| 843 return; | |
| 844 } | |
| 845 | 918 |
| 846 const ThreadId thread_id = OSThread::GetCurrentThreadId(); | 919 static Sample* SetupSample(Isolate* isolate, |
| 847 // Setup sample. | 920 SampleBuffer* sample_buffer, |
| 921 ThreadId tid) { |
| 922 ASSERT(isolate != NULL); |
| 923 ASSERT(sample_buffer != NULL); |
| 848 Sample* sample = sample_buffer->ReserveSample(); | 924 Sample* sample = sample_buffer->ReserveSample(); |
| 849 sample->Init(isolate, OS::GetCurrentTimeMicros(), thread_id); | 925 sample->Init(isolate, OS::GetCurrentTimeMicros(), tid); |
| 850 uword vm_tag = isolate->vm_tag(); | 926 uword vm_tag = isolate->vm_tag(); |
| 851 #if defined(USING_SIMULATOR) | 927 #if defined(USING_SIMULATOR) |
| 852 // When running in the simulator, the runtime entry function address | 928 // When running in the simulator, the runtime entry function address |
| 853 // (stored as the vm tag) is the address of a redirect function. | 929 // (stored as the vm tag) is the address of a redirect function. |
| 854 // Attempt to find the real runtime entry function address and use that. | 930 // Attempt to find the real runtime entry function address and use that. |
| 855 uword redirect_vm_tag = Simulator::FunctionForRedirect(vm_tag); | 931 uword redirect_vm_tag = Simulator::FunctionForRedirect(vm_tag); |
| 856 if (redirect_vm_tag != 0) { | 932 if (redirect_vm_tag != 0) { |
| 857 vm_tag = redirect_vm_tag; | 933 vm_tag = redirect_vm_tag; |
| 858 } | 934 } |
| 859 #endif | 935 #endif |
| 860 sample->set_vm_tag(vm_tag); | 936 sample->set_vm_tag(vm_tag); |
| 861 sample->set_user_tag(isolate->user_tag()); | 937 sample->set_user_tag(isolate->user_tag()); |
| 862 sample->SetAllocationCid(cid); | 938 return sample; |
| 863 | |
| 864 ProfilerDartExitStackWalker dart_exit_stack_walker(isolate, sample); | |
| 865 dart_exit_stack_walker.walk(); | |
| 866 } | 939 } |
| 867 | 940 |
| 868 | 941 |
| 942 static bool CheckIsolate(Isolate* isolate) { |
| 943 if ((isolate == NULL) || (Dart::vm_isolate() == NULL)) { |
| 944 // No isolate. |
| 945 return false; |
| 946 } |
| 947 ASSERT(isolate != Dart::vm_isolate()); |
| 948 return true; |
| 949 } |
| 950 |
| 951 |
| 952 #if defined(TARGET_OS_WINDOWS) |
| 953 __declspec(noinline) |
| 954 static uintptr_t GetProgramCounter() { |
| 955 return reinterpret_cast<uintptr_t>(_ReturnAddress()); |
| 956 } |
| 957 #else |
| 958 static uintptr_t __attribute__((noinline)) GetProgramCounter() { |
| 959 return reinterpret_cast<uintptr_t>( |
| 960 __builtin_extract_return_addr(__builtin_return_address(0))); |
| 961 } |
| 962 #endif |
| 963 |
| 964 void Profiler::RecordAllocation(Isolate* isolate, intptr_t cid) { |
| 965 if (!CheckIsolate(isolate)) { |
| 966 return; |
| 967 } |
| 968 |
| 969 const bool exited_dart_code = ExitedDart(isolate); |
| 970 |
| 971 if (!exited_dart_code && !FLAG_profile_vm) { |
| 972 // No Dart frames on stack and we are not profiling the vm. |
| 973 return; |
| 974 } |
| 975 |
| 976 SampleBuffer* sample_buffer = GetSampleBuffer(isolate); |
| 977 if (sample_buffer == NULL) { |
| 978 // Profiler not initialized. |
| 979 return; |
| 980 } |
| 981 |
| 982 if (FLAG_profile_vm) { |
| 983 uintptr_t sp = 0; |
| 984 uintptr_t fp = 0; |
| 985 uintptr_t pc = GetProgramCounter(); |
| 986 |
| 987 COPY_SP_REGISTER(sp); |
| 988 COPY_FP_REGISTER(fp); |
| 989 |
| 990 uword stack_lower = 0; |
| 991 uword stack_upper = 0; |
| 992 |
| 993 if (!InitialRegisterCheck(pc, sp, fp)) { |
| 994 return; |
| 995 } |
| 996 |
| 997 if (!GetAndValidateIsolateStackBounds(isolate, |
| 998 sp, |
| 999 fp, |
| 1000 &stack_lower, |
| 1001 &stack_upper)) { |
| 1002 // Could not get stack boundary. |
| 1003 return; |
| 1004 } |
| 1005 |
| 1006 Sample* sample = SetupSample(isolate, |
| 1007 sample_buffer, |
| 1008 OSThread::GetCurrentThreadId()); |
| 1009 sample->SetAllocationCid(cid); |
| 1010 ProfilerNativeStackWalker native_stack_walker(sample, |
| 1011 stack_lower, |
| 1012 stack_upper, |
| 1013 pc, |
| 1014 fp, |
| 1015 sp); |
| 1016 native_stack_walker.walk(); |
| 1017 } else { |
| 1018 ASSERT(exited_dart_code); |
| 1019 Sample* sample = SetupSample(isolate, |
| 1020 sample_buffer, |
| 1021 OSThread::GetCurrentThreadId()); |
| 1022 sample->SetAllocationCid(cid); |
| 1023 ProfilerDartExitStackWalker dart_exit_stack_walker(isolate, sample); |
| 1024 dart_exit_stack_walker.walk(); |
| 1025 } |
| 1026 } |
| 1027 |
| 1028 |
| 869 void Profiler::RecordSampleInterruptCallback( | 1029 void Profiler::RecordSampleInterruptCallback( |
| 870 const InterruptedThreadState& state, | 1030 const InterruptedThreadState& state, |
| 871 void* data) { | 1031 void* data) { |
| 872 Isolate* isolate = reinterpret_cast<Isolate*>(data); | 1032 Isolate* isolate = reinterpret_cast<Isolate*>(data); |
| 873 if ((isolate == NULL) || (Dart::vm_isolate() == NULL)) { | 1033 if ((isolate == NULL) || (Dart::vm_isolate() == NULL)) { |
| 874 // No isolate. | 1034 // No isolate. |
| 875 return; | 1035 return; |
| 876 } | 1036 } |
| 877 | |
| 878 ASSERT(isolate != Dart::vm_isolate()); | 1037 ASSERT(isolate != Dart::vm_isolate()); |
| 879 | 1038 |
| 880 const bool exited_dart_code = (isolate->top_exit_frame_info() != 0) && | 1039 SampleBuffer* sample_buffer = GetSampleBuffer(isolate); |
| 881 (isolate->vm_tag() != VMTag::kDartTagId); | 1040 if (sample_buffer == NULL) { |
| 882 const bool in_dart_code = (isolate->top_exit_frame_info() == 0) && | 1041 // Profiler not initialized. |
| 883 (isolate->vm_tag() == VMTag::kDartTagId); | 1042 return; |
| 1043 } |
| 1044 |
| 1045 const bool exited_dart_code = ExitedDart(isolate); |
| 1046 const bool in_dart_code = ExecutingDart(isolate); |
| 884 | 1047 |
| 885 uintptr_t sp = 0; | 1048 uintptr_t sp = 0; |
| 886 uintptr_t fp = state.fp; | 1049 uintptr_t fp = state.fp; |
| 887 uintptr_t pc = state.pc; | 1050 uintptr_t pc = state.pc; |
| 888 uintptr_t lr = state.lr; | |
| 889 #if defined(USING_SIMULATOR) | 1051 #if defined(USING_SIMULATOR) |
| 890 Simulator* simulator = NULL; | 1052 Simulator* simulator = NULL; |
| 891 #endif | 1053 #endif |
| 892 | 1054 |
| 893 if (in_dart_code) { | 1055 if (in_dart_code) { |
| 894 // If we're in Dart code, use the Dart stack pointer. | 1056 // If we're in Dart code, use the Dart stack pointer. |
| 895 #if defined(USING_SIMULATOR) | 1057 #if defined(USING_SIMULATOR) |
| 896 simulator = isolate->simulator(); | 1058 simulator = isolate->simulator(); |
| 897 sp = simulator->get_register(SPREG); | 1059 sp = simulator->get_register(SPREG); |
| 898 fp = simulator->get_register(FPREG); | 1060 fp = simulator->get_register(FPREG); |
| 899 pc = simulator->get_pc(); | 1061 pc = simulator->get_pc(); |
| 900 lr = simulator->get_register(LRREG); | |
| 901 #else | 1062 #else |
| 902 sp = state.dsp; | 1063 sp = state.dsp; |
| 903 #endif | 1064 #endif |
| 904 } else { | 1065 } else { |
| 905 // If we're in runtime code, use the C stack pointer. | 1066 // If we're in runtime code, use the C stack pointer. |
| 906 sp = state.csp; | 1067 sp = state.csp; |
| 907 } | 1068 } |
| 908 | 1069 |
| 909 IsolateProfilerData* profiler_data = isolate->profiler_data(); | 1070 if (!InitialRegisterCheck(pc, sp, fp)) { |
| 910 if (profiler_data == NULL) { | |
| 911 // Profiler not initialized. | |
| 912 return; | 1071 return; |
| 913 } | 1072 } |
| 914 | 1073 |
| 915 SampleBuffer* sample_buffer = profiler_data->sample_buffer(); | |
| 916 if (sample_buffer == NULL) { | |
| 917 // Profiler not initialized. | |
| 918 return; | |
| 919 } | |
| 920 | |
| 921 if ((sp == 0) || (fp == 0) || (pc == 0)) { | |
| 922 // None of these registers should be zero. | |
| 923 return; | |
| 924 } | |
| 925 | |
| 926 if (sp > fp) { | |
| 927 // Assuming the stack grows down, we should never have a stack pointer above | |
| 928 // the frame pointer. | |
| 929 return; | |
| 930 } | |
| 931 | |
| 932 if (StubCode::InJumpToExceptionHandlerStub(pc)) { | 1074 if (StubCode::InJumpToExceptionHandlerStub(pc)) { |
| 933 // The JumpToExceptionHandler stub manually adjusts the stack pointer, | 1075 // The JumpToExceptionHandler stub manually adjusts the stack pointer, |
| 934 // frame pointer, and some isolate state before jumping to a catch entry. | 1076 // frame pointer, and some isolate state before jumping to a catch entry. |
| 935 // It is not safe to walk the stack when executing this stub. | 1077 // It is not safe to walk the stack when executing this stub. |
| 936 return; | 1078 return; |
| 937 } | 1079 } |
| 938 | 1080 |
| 939 uword stack_lower = 0; | 1081 uword stack_lower = 0; |
| 940 uword stack_upper = 0; | 1082 uword stack_upper = 0; |
| 941 #if defined(USING_SIMULATOR) | 1083 if (!GetAndValidateIsolateStackBounds(isolate, |
| 942 if (in_dart_code) { | 1084 sp, |
| 943 stack_lower = simulator->StackBase(); | 1085 fp, |
| 944 stack_upper = simulator->StackTop(); | 1086 &stack_lower, |
| 945 } else if (!isolate->GetProfilerStackBounds(&stack_lower, &stack_upper)) { | 1087 &stack_upper)) { |
| 946 // Could not get stack boundary. | 1088 // Could not get stack boundary. |
| 947 return; | 1089 return; |
| 948 } | 1090 } |
| 949 if ((stack_lower == 0) || (stack_upper == 0)) { | |
| 950 return; | |
| 951 } | |
| 952 #else | |
| 953 if (!isolate->GetProfilerStackBounds(&stack_lower, &stack_upper) || | |
| 954 (stack_lower == 0) || (stack_upper == 0)) { | |
| 955 // Could not get stack boundary. | |
| 956 return; | |
| 957 } | |
| 958 #endif | |
| 959 | |
| 960 if (sp > stack_lower) { | |
| 961 // The stack pointer gives us a tighter lower bound. | |
| 962 stack_lower = sp; | |
| 963 } | |
| 964 | |
| 965 if (stack_lower >= stack_upper) { | |
| 966 // Stack boundary is invalid. | |
| 967 return; | |
| 968 } | |
| 969 | |
| 970 if ((sp < stack_lower) || (sp >= stack_upper)) { | |
| 971 // Stack pointer is outside isolate stack boundary. | |
| 972 return; | |
| 973 } | |
| 974 | |
| 975 if ((fp < stack_lower) || (fp >= stack_upper)) { | |
| 976 // Frame pointer is outside isolate stack boundary. | |
| 977 return; | |
| 978 } | |
| 979 | 1091 |
| 980 // At this point we have a valid stack boundary for this isolate and | 1092 // At this point we have a valid stack boundary for this isolate and |
| 981 // know that our initial stack and frame pointers are within the boundary. | 1093 // know that our initial stack and frame pointers are within the boundary. |
| 982 | 1094 |
| 983 // Setup sample. | 1095 // Setup sample. |
| 984 Sample* sample = sample_buffer->ReserveSample(); | 1096 Sample* sample = SetupSample(isolate, |
| 985 sample->Init(isolate, OS::GetCurrentTimeMicros(), state.tid); | 1097 sample_buffer, |
| 986 uword vm_tag = isolate->vm_tag(); | 1098 OSThread::GetCurrentThreadId()); |
| 987 #if defined(USING_SIMULATOR) | |
| 988 // When running in the simulator, the runtime entry function address | |
| 989 // (stored as the vm tag) is the address of a redirect function. | |
| 990 // Attempt to find the real runtime entry function address and use that. | |
| 991 uword redirect_vm_tag = Simulator::FunctionForRedirect(vm_tag); | |
| 992 if (redirect_vm_tag != 0) { | |
| 993 vm_tag = redirect_vm_tag; | |
| 994 } | |
| 995 #endif | |
| 996 // Increment counter for vm tag. | 1099 // Increment counter for vm tag. |
| 997 VMTagCounters* counters = isolate->vm_tag_counters(); | 1100 VMTagCounters* counters = isolate->vm_tag_counters(); |
| 998 ASSERT(counters != NULL); | 1101 ASSERT(counters != NULL); |
| 999 counters->Increment(vm_tag); | 1102 counters->Increment(sample->vm_tag()); |
| 1000 sample->set_vm_tag(vm_tag); | |
| 1001 sample->set_user_tag(isolate->user_tag()); | |
| 1002 sample->set_lr(lr); | |
| 1003 | 1103 |
| 1004 ProfilerNativeStackWalker native_stack_walker(sample, | 1104 ProfilerNativeStackWalker native_stack_walker(sample, |
| 1005 stack_lower, | 1105 stack_lower, |
| 1006 stack_upper, | 1106 stack_upper, |
| 1007 pc, | 1107 pc, |
| 1008 fp, | 1108 fp, |
| 1009 sp); | 1109 sp); |
| 1010 | 1110 |
| 1011 ProfilerDartExitStackWalker dart_exit_stack_walker(isolate, sample); | 1111 ProfilerDartExitStackWalker dart_exit_stack_walker(isolate, sample); |
| 1012 | 1112 |
| (...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1223 uword pc) { | 1323 uword pc) { |
| 1224 return vm_isolate->heap()->CodeContains(pc) | 1324 return vm_isolate->heap()->CodeContains(pc) |
| 1225 || isolate->heap()->CodeContains(pc); | 1325 || isolate->heap()->CodeContains(pc); |
| 1226 } | 1326 } |
| 1227 | 1327 |
| 1228 | 1328 |
| 1229 ProcessedSampleBuffer::ProcessedSampleBuffer() { | 1329 ProcessedSampleBuffer::ProcessedSampleBuffer() { |
| 1230 } | 1330 } |
| 1231 | 1331 |
| 1232 } // namespace dart | 1332 } // namespace dart |
| OLD | NEW |