Chromium Code Reviews| Index: runtime/vm/profiler.cc |
| diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc |
| index ff0edc73656e43a62d499cc817030ee4ae801680..dc1dc344e618090216ec61a3b5aaa62557622237 100644 |
| --- a/runtime/vm/profiler.cc |
| +++ b/runtime/vm/profiler.cc |
| @@ -815,40 +815,116 @@ static void CollectSample(Isolate* isolate, |
| } |
| -void Profiler::RecordAllocation(Isolate* isolate, intptr_t cid) { |
| - if ((isolate == NULL) || (Dart::vm_isolate() == NULL)) { |
| - // No isolate. |
| - return; |
| +// Is |isolate| executing Dart code? |
| +static bool ExecutingDart(Isolate* isolate) { |
| + ASSERT(isolate != NULL); |
| + return (isolate->top_exit_frame_info() == 0) && |
| + (isolate->vm_tag() == VMTag::kDartTagId); |
| +} |
| + |
| + |
| +// Has |isolate| exited Dart code? |
| +static bool ExitedDart(Isolate* isolate) { |
| + return (isolate->top_exit_frame_info() != 0) && |
| + (isolate->vm_tag() != VMTag::kDartTagId); |
| +} |
| + |
| + |
| +// Get |isolate|'s stack boundary and verify that |sp| and |fp| are within |
| +// it. Return |false| if anything looks suspicious. |
| +static bool GetAndValidateIsolateStackBounds(Isolate* isolate, |
| + uintptr_t sp, |
| + uintptr_t fp, |
| + uword* stack_lower, |
| + uword* stack_upper) { |
| + ASSERT(isolate != NULL); |
| + ASSERT(stack_lower != NULL); |
| + ASSERT(stack_upper != NULL); |
| +#if defined(USING_SIMULATOR) |
| + Simulator* simulator = NULL; |
| +#endif |
| + |
| +#if defined(USING_SIMULATOR) |
| + const bool in_dart_code = ExecutingDart(isolate); |
| + if (in_dart_code) { |
| + *stack_lower = simulator->StackBase(); |
| + *stack_upper = simulator->StackTop(); |
| + } else if (!isolate->GetProfilerStackBounds(stack_lower, stack_upper)) { |
| + // Could not get stack boundary. |
| + return false; |
| + } |
| + if ((*stack_lower == 0) || (*stack_upper == 0)) { |
| + return false; |
| + } |
| +#else |
| + if (!isolate->GetProfilerStackBounds(stack_lower, stack_upper) || |
| + (*stack_lower == 0) || (*stack_upper == 0)) { |
| + // Could not get stack boundary. |
| + return false; |
| + } |
| +#endif |
| + if (sp > *stack_lower) { |
| + // The stack pointer gives us a tighter lower bound. |
| + *stack_lower = sp; |
| } |
| - ASSERT(isolate != Dart::vm_isolate()); |
| - const bool exited_dart_code = (isolate->top_exit_frame_info() != 0) && |
| - (isolate->vm_tag() != VMTag::kDartTagId); |
| + if (*stack_lower >= *stack_upper) { |
| + // Stack boundary is invalid. |
| + return false; |
| + } |
| - if (!exited_dart_code) { |
| - // No Dart frames on stack. |
| - // TODO(johnmccutchan): Support collecting native stack. |
| - return; |
| + if ((sp < *stack_lower) || (sp >= *stack_upper)) { |
| + // Stack pointer is outside isolate stack boundary. |
| + return false; |
| } |
| + if ((fp < *stack_lower) || (fp >= *stack_upper)) { |
| + // Frame pointer is outside isolate stack boundary. |
| + return false; |
| + } |
| + |
| + return true; |
| +} |
| + |
| + |
| +// Some simple sanity checking of |pc|, |sp|, and |fp|. |
| +static bool InitialRegisterCheck(uintptr_t pc, uintptr_t sp, uintptr_t fp) { |
| + if ((sp == 0) || (fp == 0) || (pc == 0)) { |
| + // None of these registers should be zero. |
| + return false; |
| + } |
| + |
| + if (sp > fp) { |
| + // Assuming the stack grows down, we should never have a stack pointer above |
| + // the frame pointer. |
| + return false; |
| + } |
| + |
| + return true; |
| +} |
| + |
| + |
| +// Return |isolate|'s sample buffer. |
| +static SampleBuffer* GetSampleBuffer(Isolate* isolate) { |
| IsolateProfilerData* profiler_data = isolate->profiler_data(); |
| if (profiler_data == NULL) { |
| // Profiler not initialized. |
| - return; |
| + return NULL; |
| } |
| - |
| SampleBuffer* sample_buffer = profiler_data->sample_buffer(); |
| - if (sample_buffer == NULL) { |
| - // Profiler not initialized. |
| - return; |
| - } |
| + return sample_buffer; |
| +} |
| - const ThreadId thread_id = OSThread::GetCurrentThreadId(); |
| - // Setup sample. |
| + |
| +static Sample* SetupSample(Isolate* isolate, |
| + SampleBuffer* sample_buffer, |
| + ThreadId tid) { |
| + ASSERT(isolate != NULL); |
| + ASSERT(sample_buffer != NULL); |
| Sample* sample = sample_buffer->ReserveSample(); |
| - sample->Init(isolate, OS::GetCurrentTimeMicros(), thread_id); |
| + sample->Init(isolate, OS::GetCurrentTimeMicros(), tid); |
| uword vm_tag = isolate->vm_tag(); |
| - #if defined(USING_SIMULATOR) |
| +#if defined(USING_SIMULATOR) |
| // When running in the simulator, the runtime entry function address |
| // (stored as the vm tag) is the address of a redirect function. |
| // Attempt to find the real runtime entry function address and use that. |
| @@ -856,13 +932,96 @@ void Profiler::RecordAllocation(Isolate* isolate, intptr_t cid) { |
| if (redirect_vm_tag != 0) { |
| vm_tag = redirect_vm_tag; |
| } |
| - #endif |
| +#endif |
| sample->set_vm_tag(vm_tag); |
| sample->set_user_tag(isolate->user_tag()); |
| - sample->SetAllocationCid(cid); |
| + return sample; |
| +} |
| - ProfilerDartExitStackWalker dart_exit_stack_walker(isolate, sample); |
| - dart_exit_stack_walker.walk(); |
| + |
| +static bool CheckIsolate(Isolate* isolate) { |
| + if ((isolate == NULL) || (Dart::vm_isolate() == NULL)) { |
| + // No isolate. |
| + return false; |
| + } |
| + ASSERT(isolate != Dart::vm_isolate()); |
| + return true; |
| +} |
| + |
| + |
| +#if defined(TARGET_OS_WINDOWS) |
| +__declspec(noinline) |
| +static uintptr_t GetProgramCounter() { |
| + return reinterpret_cast<uintptr_t>(_ReturnAddress()); |
| +} |
| +#else |
| +static uintptr_t __attribute__((noinline)) GetProgramCounter() { |
| + return reinterpret_cast<uintptr_t>( |
| + __builtin_extract_return_addr(__builtin_return_address(0))); |
| +} |
| +#endif |
| + |
| +void Profiler::RecordAllocation(Isolate* isolate, intptr_t cid) { |
| + if (!CheckIsolate(isolate)) { |
| + return; |
| + } |
| + |
| + const bool exited_dart_code = ExitedDart(isolate); |
| + |
| + if (!exited_dart_code && !FLAG_profile_vm) { |
| + // No Dart frames on stack and we are not profiling the vm. |
| + return; |
| + } |
| + |
| + SampleBuffer* sample_buffer = GetSampleBuffer(isolate); |
| + if (sample_buffer == NULL) { |
| + // Profiler not initialized. |
| + return; |
| + } |
| + |
| + if (FLAG_profile_vm) { |
| + uintptr_t sp = Isolate::GetCurrentStackPointer(); |
| + uintptr_t fp = 0; |
| + uintptr_t pc = GetProgramCounter(); |
| + |
| + COPY_FP_REGISTER(fp); |
|
regis
2015/08/06 16:55:17
I suppose you tell gcc to always generate frame po
|
| + |
| + uword stack_lower = 0; |
| + uword stack_upper = 0; |
| + |
| + if (!InitialRegisterCheck(pc, sp, fp)) { |
| + return; |
| + } |
| + |
| + if (!GetAndValidateIsolateStackBounds(isolate, |
| + sp, |
| + fp, |
| + &stack_lower, |
| + &stack_upper)) { |
| + // Could not get stack boundary. |
| + return; |
| + } |
| + |
| + Sample* sample = SetupSample(isolate, |
| + sample_buffer, |
| + OSThread::GetCurrentThreadId()); |
| + sample->SetAllocationCid(cid); |
| + ProfilerNativeStackWalker native_stack_walker(sample, |
| + stack_lower, |
| + stack_upper, |
| + pc, |
| + fp, |
| + sp); |
| + native_stack_walker.walk(); |
| + } else { |
| + ASSERT(exited_dart_code); |
| + Sample* sample = SetupSample(isolate, |
| + sample_buffer, |
| + OSThread::GetCurrentThreadId()); |
| + sample->SetAllocationCid(cid); |
| + ProfilerDartExitStackWalker dart_exit_stack_walker(isolate, sample); |
| + dart_exit_stack_walker.walk(); |
| + } |
| } |
| @@ -874,18 +1033,20 @@ void Profiler::RecordSampleInterruptCallback( |
| // No isolate. |
| return; |
| } |
| - |
| ASSERT(isolate != Dart::vm_isolate()); |
| - const bool exited_dart_code = (isolate->top_exit_frame_info() != 0) && |
| - (isolate->vm_tag() != VMTag::kDartTagId); |
| - const bool in_dart_code = (isolate->top_exit_frame_info() == 0) && |
| - (isolate->vm_tag() == VMTag::kDartTagId); |
| + SampleBuffer* sample_buffer = GetSampleBuffer(isolate); |
| + if (sample_buffer == NULL) { |
| + // Profiler not initialized. |
| + return; |
| + } |
| + |
| + const bool exited_dart_code = ExitedDart(isolate); |
| + const bool in_dart_code = ExecutingDart(isolate); |
| uintptr_t sp = 0; |
| uintptr_t fp = state.fp; |
| uintptr_t pc = state.pc; |
| - uintptr_t lr = state.lr; |
| #if defined(USING_SIMULATOR) |
| Simulator* simulator = NULL; |
| #endif |
| @@ -897,7 +1058,6 @@ void Profiler::RecordSampleInterruptCallback( |
| sp = simulator->get_register(SPREG); |
| fp = simulator->get_register(FPREG); |
| pc = simulator->get_pc(); |
| - lr = simulator->get_register(LRREG); |
| #else |
| sp = state.dsp; |
| #endif |
| @@ -906,26 +1066,7 @@ void Profiler::RecordSampleInterruptCallback( |
| sp = state.csp; |
| } |
| - IsolateProfilerData* profiler_data = isolate->profiler_data(); |
| - if (profiler_data == NULL) { |
| - // Profiler not initialized. |
| - return; |
| - } |
| - |
| - SampleBuffer* sample_buffer = profiler_data->sample_buffer(); |
| - if (sample_buffer == NULL) { |
| - // Profiler not initialized. |
| - return; |
| - } |
| - |
| - if ((sp == 0) || (fp == 0) || (pc == 0)) { |
| - // None of these registers should be zero. |
| - return; |
| - } |
| - |
| - if (sp > fp) { |
| - // Assuming the stack grows down, we should never have a stack pointer above |
| - // the frame pointer. |
| + if (!InitialRegisterCheck(pc, sp, fp)) { |
| return; |
| } |
| @@ -938,68 +1079,26 @@ void Profiler::RecordSampleInterruptCallback( |
| uword stack_lower = 0; |
| uword stack_upper = 0; |
| -#if defined(USING_SIMULATOR) |
| - if (in_dart_code) { |
| - stack_lower = simulator->StackBase(); |
| - stack_upper = simulator->StackTop(); |
| - } else if (!isolate->GetProfilerStackBounds(&stack_lower, &stack_upper)) { |
| + if (!GetAndValidateIsolateStackBounds(isolate, |
| + sp, |
| + fp, |
| + &stack_lower, |
| + &stack_upper)) { |
| // Could not get stack boundary. |
| return; |
| } |
| - if ((stack_lower == 0) || (stack_upper == 0)) { |
| - return; |
| - } |
| -#else |
| - if (!isolate->GetProfilerStackBounds(&stack_lower, &stack_upper) || |
| - (stack_lower == 0) || (stack_upper == 0)) { |
| - // Could not get stack boundary. |
| - return; |
| - } |
| -#endif |
| - |
| - if (sp > stack_lower) { |
| - // The stack pointer gives us a tighter lower bound. |
| - stack_lower = sp; |
| - } |
| - |
| - if (stack_lower >= stack_upper) { |
| - // Stack boundary is invalid. |
| - return; |
| - } |
| - |
| - if ((sp < stack_lower) || (sp >= stack_upper)) { |
| - // Stack pointer is outside isolate stack boundary. |
| - return; |
| - } |
| - |
| - if ((fp < stack_lower) || (fp >= stack_upper)) { |
| - // Frame pointer is outside isolate stack boundary. |
| - return; |
| - } |
| // At this point we have a valid stack boundary for this isolate and |
| // know that our initial stack and frame pointers are within the boundary. |
| // Setup sample. |
| - Sample* sample = sample_buffer->ReserveSample(); |
| - sample->Init(isolate, OS::GetCurrentTimeMicros(), state.tid); |
| - uword vm_tag = isolate->vm_tag(); |
| -#if defined(USING_SIMULATOR) |
| - // When running in the simulator, the runtime entry function address |
| - // (stored as the vm tag) is the address of a redirect function. |
| - // Attempt to find the real runtime entry function address and use that. |
| - uword redirect_vm_tag = Simulator::FunctionForRedirect(vm_tag); |
| - if (redirect_vm_tag != 0) { |
| - vm_tag = redirect_vm_tag; |
| - } |
| -#endif |
| + Sample* sample = SetupSample(isolate, |
| + sample_buffer, |
| + OSThread::GetCurrentThreadId()); |
| // Increment counter for vm tag. |
| VMTagCounters* counters = isolate->vm_tag_counters(); |
| ASSERT(counters != NULL); |
| - counters->Increment(vm_tag); |
| - sample->set_vm_tag(vm_tag); |
| - sample->set_user_tag(isolate->user_tag()); |
| - sample->set_lr(lr); |
| + counters->Increment(sample->vm_tag()); |
| ProfilerNativeStackWalker native_stack_walker(sample, |
| stack_lower, |