Chromium Code Reviews| Index: src/profiler/tick-sample.cc |
| diff --git a/src/profiler/tick-sample.cc b/src/profiler/tick-sample.cc |
| index 533f34f85216f2ffaa8241d6b2dd071b4f48e434..3418a325283b9d2c533e46699ce6875d2b4a9789 100644 |
| --- a/src/profiler/tick-sample.cc |
| +++ b/src/profiler/tick-sample.cc |
| @@ -11,7 +11,6 @@ |
| #include "src/vm-state-inl.h" |
| namespace v8 { |
| - |
| namespace { |
| bool IsSamePage(i::byte* ptr1, i::byte* ptr2) { |
| @@ -77,46 +76,120 @@ bool IsNoFrameRegion(i::Address address) { |
| } // namespace |
| +namespace internal { |
| +namespace { |
| + |
| +#if defined(USE_SIMULATOR) |
| +class SimulatorHelper { |
| + public: |
| + // Returns true if register values were successfully retrieved |
| + // from the simulator, otherwise returns false. |
| + static bool FillRegisters(Isolate* isolate, v8::RegisterState* state); |
| +}; |
| + |
| +bool SimulatorHelper::FillRegisters(Isolate* isolate, |
| + v8::RegisterState* state) { |
| + Simulator* simulator = isolate->thread_local_top()->simulator_; |
| + // Check if there is active simulator. |
| + if (simulator == NULL) return false; |
| +#if V8_TARGET_ARCH_ARM |
| + if (!simulator->has_bad_pc()) { |
| + state->pc = reinterpret_cast<Address>(simulator->get_pc()); |
| + } |
| + state->sp = reinterpret_cast<Address>(simulator->get_register(Simulator::sp)); |
| + state->fp = |
| + reinterpret_cast<Address>(simulator->get_register(Simulator::r11)); |
| +#elif V8_TARGET_ARCH_ARM64 |
| + state->pc = reinterpret_cast<Address>(simulator->pc()); |
| + state->sp = reinterpret_cast<Address>(simulator->sp()); |
| + state->fp = reinterpret_cast<Address>(simulator->fp()); |
| +#elif V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 |
| + if (!simulator->has_bad_pc()) { |
| + state->pc = reinterpret_cast<Address>(simulator->get_pc()); |
| + } |
| + state->sp = reinterpret_cast<Address>(simulator->get_register(Simulator::sp)); |
| + state->fp = reinterpret_cast<Address>(simulator->get_register(Simulator::fp)); |
| +#elif V8_TARGET_ARCH_PPC |
| + if (!simulator->has_bad_pc()) { |
| + state->pc = reinterpret_cast<Address>(simulator->get_pc()); |
| + } |
| + state->sp = reinterpret_cast<Address>(simulator->get_register(Simulator::sp)); |
| + state->fp = reinterpret_cast<Address>(simulator->get_register(Simulator::fp)); |
| +#elif V8_TARGET_ARCH_S390 |
| + if (!simulator->has_bad_pc()) { |
| + state->pc = reinterpret_cast<Address>(simulator->get_pc()); |
| + } |
| + state->sp = reinterpret_cast<Address>(simulator->get_register(Simulator::sp)); |
| + state->fp = reinterpret_cast<Address>(simulator->get_register(Simulator::fp)); |
| +#endif |
| + if (state->sp == 0 || state->fp == 0) { |
| + // It possible that the simulator is interrupted while it is updating |
| + // the sp or fp register. ARM64 simulator does this in two steps: |
| + // first setting it to zero and then setting it to the new value. |
| + // Bailout if sp/fp doesn't contain the new value. |
| + // |
| + // FIXME: The above doesn't really solve the issue. |
| + // If a 64-bit target is executed on a 32-bit host even the final |
| + // write is non-atomic, so it might obtain a half of the result. |
| + // Moreover as long as the register set code uses memcpy (as of now), |
| + // it is not guaranteed to be atomic even when both host and target |
| + // are of same bitness. |
| + return false; |
| + } |
| + return true; |
| +} |
| +#endif // USE_SIMULATOR |
| + |
| +} // namespace |
| +} // namespace internal |
| + |
| // |
| // StackTracer implementation |
| // |
| DISABLE_ASAN void TickSample::Init(Isolate* v8_isolate, |
| - const RegisterState& regs, |
| + const RegisterState& reg_state, |
| RecordCEntryFrame record_c_entry_frame, |
| - bool update_stats) { |
| + bool update_stats, bool update_state) { |
| this->update_stats = update_stats; |
| - |
| SampleInfo info; |
| - if (GetStackSample(v8_isolate, const_cast<RegisterState&>(regs), |
| - record_c_entry_frame, reinterpret_cast<void**>(&stack[0]), |
| - kMaxFramesCount, &info)) { |
| - state = info.vm_state; |
| - pc = regs.pc; |
| - frames_count = static_cast<unsigned>(info.frames_count); |
| - has_external_callback = info.external_callback_entry != nullptr; |
| - if (has_external_callback) { |
| - external_callback_entry = info.external_callback_entry; |
| - } else if (frames_count) { |
| - // sp register may point at an arbitrary place in memory, make |
| - // sure MSAN doesn't complain about it. |
| - MSAN_MEMORY_IS_INITIALIZED(regs.sp, sizeof(void*)); |
| - // Sample potential return address value for frameless invocation of |
| - // stubs (we'll figure out later, if this value makes sense). |
| - tos = i::Memory::Address_at(reinterpret_cast<i::Address>(regs.sp)); |
| - } else { |
| - tos = nullptr; |
| - } |
| - } else { |
| + RegisterState tmp_state = reg_state; |
| + if (!GetStackSample(v8_isolate, tmp_state, record_c_entry_frame, stack, |
| + kMaxFramesCount, &info, update_state)) { |
| // It is executing JS but failed to collect a stack trace. |
| // Mark the sample as spoiled. |
| pc = nullptr; |
| + return; |
| + } |
| + |
| +#if defined(USE_SIMULATOR) |
| + RegisterState regs = update_state ? tmp_state : reg_state; |
|
alph
2016/08/08 21:36:57
It should be fine to always use tmp_state. right?
lpy
2016/08/09 18:31:43
Done.
|
| +#else |
| + const RegisterState& regs = reg_state; |
| +#endif |
| + |
| + state = info.vm_state; |
| + pc = regs.pc; |
| + frames_count = static_cast<unsigned>(info.frames_count); |
| + has_external_callback = info.external_callback_entry != nullptr; |
| + if (has_external_callback) { |
| + external_callback_entry = info.external_callback_entry; |
| + } else if (frames_count) { |
| + // sp register may point at an arbitrary place in memory, make |
| + // sure MSAN doesn't complain about it. |
| + MSAN_MEMORY_IS_INITIALIZED(regs.sp, sizeof(void*)); |
| + // Sample potential return address value for frameless invocation of |
| + // stubs (we'll figure out later, if this value makes sense). |
| + tos = i::Memory::Address_at(reinterpret_cast<i::Address>(regs.sp)); |
| + } else { |
| + tos = nullptr; |
| } |
| } |
| -bool TickSample::GetStackSample(Isolate* v8_isolate, const RegisterState& regs, |
| +bool TickSample::GetStackSample(Isolate* v8_isolate, RegisterState& state, |
| RecordCEntryFrame record_c_entry_frame, |
| void** frames, size_t frames_limit, |
| - v8::SampleInfo* sample_info) { |
| + v8::SampleInfo* sample_info, |
| + bool update_state) { |
| i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); |
| sample_info->frames_count = 0; |
| sample_info->vm_state = isolate->current_vm_state(); |
| @@ -125,10 +198,19 @@ bool TickSample::GetStackSample(Isolate* v8_isolate, const RegisterState& regs, |
| i::Address js_entry_sp = isolate->js_entry_sp(); |
| if (js_entry_sp == nullptr) return true; // Not executing JS now. |
| + |
| +#if defined(USE_SIMULATOR) |
| + if (update_state) { |
| + if (!i::SimulatorHelper::FillRegisters(isolate, &state)) { |
|
alph
2016/08/08 21:36:57
nit: you can omit {}
lpy
2016/08/09 18:31:43
Done.
|
| + return false; |
| + } |
| + } |
| +#endif |
| + const v8::RegisterState& regs = state; |
| DCHECK(regs.sp); |
| if (regs.pc && IsNoFrameRegion(static_cast<i::Address>(regs.pc))) { |
| - // Can't collect stack. |
| + // The frame is not setup, so it'd be hard to iterate the stack. Bailout. |
| return false; |
| } |
| @@ -180,67 +262,13 @@ bool TickSample::GetStackSample(Isolate* v8_isolate, const RegisterState& regs, |
| namespace internal { |
| void TickSample::Init(Isolate* isolate, const v8::RegisterState& state, |
| - RecordCEntryFrame record_c_entry_frame, |
| - bool update_stats) { |
| + RecordCEntryFrame record_c_entry_frame, bool update_stats, |
| + bool update_state) { |
| v8::TickSample::Init(reinterpret_cast<v8::Isolate*>(isolate), state, |
| - record_c_entry_frame, update_stats); |
| + record_c_entry_frame, update_stats, update_state); |
| if (pc == nullptr) return; |
| timestamp = base::TimeTicks::HighResolutionNow(); |
| } |
| -#if defined(USE_SIMULATOR) |
| -bool SimulatorHelper::FillRegisters(Isolate* isolate, |
| - v8::RegisterState* state) { |
| - Simulator* simulator = isolate->thread_local_top()->simulator_; |
| - // Check if there is active simulator. |
| - if (simulator == NULL) return false; |
| -#if V8_TARGET_ARCH_ARM |
| - if (!simulator->has_bad_pc()) { |
| - state->pc = reinterpret_cast<Address>(simulator->get_pc()); |
| - } |
| - state->sp = reinterpret_cast<Address>(simulator->get_register(Simulator::sp)); |
| - state->fp = |
| - reinterpret_cast<Address>(simulator->get_register(Simulator::r11)); |
| -#elif V8_TARGET_ARCH_ARM64 |
| - state->pc = reinterpret_cast<Address>(simulator->pc()); |
| - state->sp = reinterpret_cast<Address>(simulator->sp()); |
| - state->fp = reinterpret_cast<Address>(simulator->fp()); |
| -#elif V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 |
| - if (!simulator->has_bad_pc()) { |
| - state->pc = reinterpret_cast<Address>(simulator->get_pc()); |
| - } |
| - state->sp = reinterpret_cast<Address>(simulator->get_register(Simulator::sp)); |
| - state->fp = reinterpret_cast<Address>(simulator->get_register(Simulator::fp)); |
| -#elif V8_TARGET_ARCH_PPC |
| - if (!simulator->has_bad_pc()) { |
| - state->pc = reinterpret_cast<Address>(simulator->get_pc()); |
| - } |
| - state->sp = reinterpret_cast<Address>(simulator->get_register(Simulator::sp)); |
| - state->fp = reinterpret_cast<Address>(simulator->get_register(Simulator::fp)); |
| -#elif V8_TARGET_ARCH_S390 |
| - if (!simulator->has_bad_pc()) { |
| - state->pc = reinterpret_cast<Address>(simulator->get_pc()); |
| - } |
| - state->sp = reinterpret_cast<Address>(simulator->get_register(Simulator::sp)); |
| - state->fp = reinterpret_cast<Address>(simulator->get_register(Simulator::fp)); |
| -#endif |
| - if (state->sp == 0 || state->fp == 0) { |
| - // It possible that the simulator is interrupted while it is updating |
| - // the sp or fp register. ARM64 simulator does this in two steps: |
| - // first setting it to zero and then setting it to the new value. |
| - // Bailout if sp/fp doesn't contain the new value. |
| - // |
| - // FIXME: The above doesn't really solve the issue. |
| - // If a 64-bit target is executed on a 32-bit host even the final |
| - // write is non-atomic, so it might obtain a half of the result. |
| - // Moreover as long as the register set code uses memcpy (as of now), |
| - // it is not guaranteed to be atomic even when both host and target |
| - // are of same bitness. |
| - return false; |
| - } |
| - return true; |
| -} |
| -#endif // USE_SIMULATOR |
| - |
| } // namespace internal |
| } // namespace v8 |