LCOV - code coverage report
Current view: top level - src/profiler - tick-sample.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 56 58 96.6 %
Date: 2017-04-26 Functions: 4 4 100.0 %

          Line data    Source code
       1             : // Copyright 2013 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/profiler/tick-sample.h"
       6             : 
       7             : #include "include/v8-profiler.h"
       8             : #include "src/counters.h"
       9             : #include "src/frames-inl.h"
      10             : #include "src/msan.h"
      11             : #include "src/simulator.h"
      12             : #include "src/vm-state-inl.h"
      13             : 
      14             : namespace v8 {
      15             : namespace {
      16             : 
      17             : bool IsSamePage(i::byte* ptr1, i::byte* ptr2) {
      18             :   const uint32_t kPageSize = 4096;
      19             :   uintptr_t mask = ~static_cast<uintptr_t>(kPageSize - 1);
      20      706203 :   return (reinterpret_cast<uintptr_t>(ptr1) & mask) ==
      21             :          (reinterpret_cast<uintptr_t>(ptr2) & mask);
      22             : }
      23             : 
      24             : // Check if the code at specified address could potentially be a
      25             : // frame setup code.
      26      236129 : bool IsNoFrameRegion(i::Address address) {
      27             :   struct Pattern {
      28             :     int bytes_count;
      29             :     i::byte bytes[8];
      30             :     int offsets[4];
      31             :   };
      32             :   i::byte* pc = reinterpret_cast<i::byte*>(address);
      33             :   static Pattern patterns[] = {
      34             : #if V8_HOST_ARCH_IA32
      35             :     // push %ebp
      36             :     // mov %esp,%ebp
      37             :     {3, {0x55, 0x89, 0xe5}, {0, 1, -1}},
      38             :     // pop %ebp
      39             :     // ret N
      40             :     {2, {0x5d, 0xc2}, {0, 1, -1}},
      41             :     // pop %ebp
      42             :     // ret
      43             :     {2, {0x5d, 0xc3}, {0, 1, -1}},
      44             : #elif V8_HOST_ARCH_X64
      45             :     // pushq %rbp
      46             :     // movq %rsp,%rbp
      47             :     {4, {0x55, 0x48, 0x89, 0xe5}, {0, 1, -1}},
      48             :     // popq %rbp
      49             :     // ret N
      50             :     {2, {0x5d, 0xc2}, {0, 1, -1}},
      51             :     // popq %rbp
      52             :     // ret
      53             :     {2, {0x5d, 0xc3}, {0, 1, -1}},
      54             : #endif
      55             :     {0, {}, {}}
      56             :   };
      57      941602 :   for (Pattern* pattern = patterns; pattern->bytes_count; ++pattern) {
      58     2118260 :     for (int* offset_ptr = pattern->offsets; *offset_ptr != -1; ++offset_ptr) {
      59             :       int offset = *offset_ptr;
      60     2118990 :       if (!offset || IsSamePage(pc, pc - offset)) {
      61             :         MSAN_MEMORY_IS_INITIALIZED(pc - offset, pattern->bytes_count);
      62     1412712 :         if (!memcmp(pc - offset, pattern->bytes, pattern->bytes_count))
      63             :           return true;
      64             :       } else {
      65             :         // It is not safe to examine bytes on another page as it might not be
      66             :         // allocated thus causing a SEGFAULT.
      67             :         // Check the pattern part that's on the same page and
      68             :         // pessimistically assume it could be the entire pattern match.
      69             :         MSAN_MEMORY_IS_INITIALIZED(pc, pattern->bytes_count - offset);
      70          75 :         if (!memcmp(pc, pattern->bytes + offset, pattern->bytes_count - offset))
      71             :           return true;
      72             :       }
      73             :     }
      74             :   }
      75             :   return false;
      76             : }
      77             : 
      78             : }  // namespace
      79             : 
      80             : namespace internal {
      81             : namespace {
      82             : 
      83             : #if defined(USE_SIMULATOR)
      84             : class SimulatorHelper {
      85             :  public:
      86             :   // Returns true if register values were successfully retrieved
      87             :   // from the simulator, otherwise returns false.
      88             :   static bool FillRegisters(Isolate* isolate, v8::RegisterState* state);
      89             : };
      90             : 
      91             : bool SimulatorHelper::FillRegisters(Isolate* isolate,
      92             :                                     v8::RegisterState* state) {
      93             :   Simulator* simulator = isolate->thread_local_top()->simulator_;
      94             :   // Check if there is active simulator.
      95             :   if (simulator == NULL) return false;
      96             : #if V8_TARGET_ARCH_ARM
      97             :   if (!simulator->has_bad_pc()) {
      98             :     state->pc = reinterpret_cast<Address>(simulator->get_pc());
      99             :   }
     100             :   state->sp = reinterpret_cast<Address>(simulator->get_register(Simulator::sp));
     101             :   state->fp =
     102             :       reinterpret_cast<Address>(simulator->get_register(Simulator::r11));
     103             : #elif V8_TARGET_ARCH_ARM64
     104             :   state->pc = reinterpret_cast<Address>(simulator->pc());
     105             :   state->sp = reinterpret_cast<Address>(simulator->sp());
     106             :   state->fp = reinterpret_cast<Address>(simulator->fp());
     107             : #elif V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64
     108             :   if (!simulator->has_bad_pc()) {
     109             :     state->pc = reinterpret_cast<Address>(simulator->get_pc());
     110             :   }
     111             :   state->sp = reinterpret_cast<Address>(simulator->get_register(Simulator::sp));
     112             :   state->fp = reinterpret_cast<Address>(simulator->get_register(Simulator::fp));
     113             : #elif V8_TARGET_ARCH_PPC
     114             :   if (!simulator->has_bad_pc()) {
     115             :     state->pc = reinterpret_cast<Address>(simulator->get_pc());
     116             :   }
     117             :   state->sp = reinterpret_cast<Address>(simulator->get_register(Simulator::sp));
     118             :   state->fp = reinterpret_cast<Address>(simulator->get_register(Simulator::fp));
     119             : #elif V8_TARGET_ARCH_S390
     120             :   if (!simulator->has_bad_pc()) {
     121             :     state->pc = reinterpret_cast<Address>(simulator->get_pc());
     122             :   }
     123             :   state->sp = reinterpret_cast<Address>(simulator->get_register(Simulator::sp));
     124             :   state->fp = reinterpret_cast<Address>(simulator->get_register(Simulator::fp));
     125             : #endif
     126             :   if (state->sp == 0 || state->fp == 0) {
     127             :     // It possible that the simulator is interrupted while it is updating
     128             :     // the sp or fp register. ARM64 simulator does this in two steps:
     129             :     // first setting it to zero and then setting it to the new value.
     130             :     // Bailout if sp/fp doesn't contain the new value.
     131             :     //
     132             :     // FIXME: The above doesn't really solve the issue.
     133             :     // If a 64-bit target is executed on a 32-bit host even the final
     134             :     // write is non-atomic, so it might obtain a half of the result.
     135             :     // Moreover as long as the register set code uses memcpy (as of now),
     136             :     // it is not guaranteed to be atomic even when both host and target
     137             :     // are of same bitness.
     138             :     return false;
     139             :   }
     140             :   return true;
     141             : }
     142             : #endif  // USE_SIMULATOR
     143             : 
     144             : }  // namespace
     145             : }  // namespace internal
     146             : 
     147             : //
     148             : // StackTracer implementation
     149             : //
     150      232638 : DISABLE_ASAN void TickSample::Init(Isolate* v8_isolate,
     151             :                                    const RegisterState& reg_state,
     152             :                                    RecordCEntryFrame record_c_entry_frame,
     153             :                                    bool update_stats,
     154             :                                    bool use_simulator_reg_state) {
     155      232638 :   this->update_stats = update_stats;
     156             :   SampleInfo info;
     157      232638 :   RegisterState regs = reg_state;
     158      232638 :   if (!GetStackSample(v8_isolate, &regs, record_c_entry_frame, stack,
     159      232638 :                       kMaxFramesCount, &info, use_simulator_reg_state)) {
     160             :     // It is executing JS but failed to collect a stack trace.
     161             :     // Mark the sample as spoiled.
     162         991 :     pc = nullptr;
     163      233629 :     return;
     164             :   }
     165             : 
     166      231647 :   state = info.vm_state;
     167      231647 :   pc = regs.pc;
     168      231647 :   frames_count = static_cast<unsigned>(info.frames_count);
     169      231647 :   has_external_callback = info.external_callback_entry != nullptr;
     170      231647 :   if (has_external_callback) {
     171       27615 :     external_callback_entry = info.external_callback_entry;
     172      204032 :   } else if (frames_count) {
     173             :     // sp register may point at an arbitrary place in memory, make
     174             :     // sure MSAN doesn't complain about it.
     175             :     MSAN_MEMORY_IS_INITIALIZED(regs.sp, sizeof(void*));
     176             :     // Sample potential return address value for frameless invocation of
     177             :     // stubs (we'll figure out later, if this value makes sense).
     178      197771 :     tos = i::Memory::Address_at(reinterpret_cast<i::Address>(regs.sp));
     179             :   } else {
     180        6261 :     tos = nullptr;
     181             :   }
     182             : }
     183             : 
     184      239575 : bool TickSample::GetStackSample(Isolate* v8_isolate, RegisterState* regs,
     185             :                                 RecordCEntryFrame record_c_entry_frame,
     186             :                                 void** frames, size_t frames_limit,
     187             :                                 v8::SampleInfo* sample_info,
     188             :                                 bool use_simulator_reg_state) {
     189     1146204 :   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
     190      239575 :   sample_info->frames_count = 0;
     191      239575 :   sample_info->vm_state = isolate->current_vm_state();
     192      239575 :   sample_info->external_callback_entry = nullptr;
     193      239575 :   if (sample_info->vm_state == GC) return true;
     194             : 
     195             :   i::Address js_entry_sp = isolate->js_entry_sp();
     196      237041 :   if (js_entry_sp == nullptr) return true;  // Not executing JS now.
     197             : 
     198             : #if defined(USE_SIMULATOR)
     199             :   if (use_simulator_reg_state) {
     200             :     if (!i::SimulatorHelper::FillRegisters(isolate, regs)) return false;
     201             :   }
     202             : #else
     203             :   USE(use_simulator_reg_state);
     204             : #endif
     205             :   DCHECK(regs->sp);
     206             : 
     207      236164 :   if (regs->pc && IsNoFrameRegion(static_cast<i::Address>(regs->pc))) {
     208             :     // The frame is not setup, so it'd be hard to iterate the stack. Bailout.
     209             :     return false;
     210             :   }
     211             : 
     212             :   i::ExternalCallbackScope* scope = isolate->external_callback_scope();
     213      235053 :   i::Address handler = i::Isolate::handler(isolate->thread_local_top());
     214             :   // If there is a handler on top of the external callback scope then
     215             :   // we have already entrered JavaScript again and the external callback
     216             :   // is not the top function.
     217      235053 :   if (scope && scope->scope_address() < handler) {
     218             :     i::Address* external_callback_entry_ptr =
     219             :         scope->callback_entrypoint_address();
     220             :     sample_info->external_callback_entry =
     221             :         external_callback_entry_ptr == nullptr ? nullptr
     222       27926 :                                                : *external_callback_entry_ptr;
     223             :   }
     224             : 
     225             :   i::SafeStackFrameIterator it(isolate, reinterpret_cast<i::Address>(regs->fp),
     226             :                                reinterpret_cast<i::Address>(regs->sp),
     227      235053 :                                js_entry_sp);
     228      235053 :   if (it.done()) return true;
     229             : 
     230             :   size_t i = 0;
     231      685848 :   if (record_c_entry_frame == kIncludeCEntryFrame &&
     232      419154 :       (it.top_frame_type() == internal::StackFrame::EXIT ||
     233             :        it.top_frame_type() == internal::StackFrame::BUILTIN_EXIT)) {
     234      204146 :     frames[i++] = isolate->c_function();
     235             :   }
     236           0 :   i::RuntimeCallTimer* timer =
     237             :       isolate->counters()->runtime_call_stats()->current_timer();
     238      501820 :   for (; !it.done() && i < frames_limit; it.Advance()) {
     239      271431 :     while (timer && reinterpret_cast<i::Address>(timer) < it.frame()->fp() &&
     240             :            i < frames_limit) {
     241           0 :       frames[i++] = reinterpret_cast<i::Address>(timer->counter());
     242             :       timer = timer->parent();
     243             :     }
     244      271431 :     if (i == frames_limit) break;
     245      542862 :     if (!it.frame()->is_interpreted()) {
     246      181068 :       frames[i++] = it.frame()->pc();
     247       90534 :       continue;
     248             :     }
     249             :     // For interpreted frames use the bytecode array pointer as the pc.
     250      180897 :     i::InterpretedFrame* frame = static_cast<i::InterpretedFrame*>(it.frame());
     251             :     // Since the sampler can interrupt execution at any point the
     252             :     // bytecode_array might be garbage, so don't dereference it.
     253             :     i::Address bytecode_array =
     254      180897 :         reinterpret_cast<i::Address>(frame->GetBytecodeArray()) -
     255      180897 :         i::kHeapObjectTag;
     256      361794 :     frames[i++] = bytecode_array + i::BytecodeArray::kHeaderSize +
     257      361794 :                   frame->GetBytecodeOffset();
     258             :   }
     259      230389 :   sample_info->frames_count = i;
     260      230389 :   return true;
     261             : }
     262             : 
     263             : namespace internal {
     264             : 
     265      232617 : void TickSample::Init(Isolate* isolate, const v8::RegisterState& state,
     266             :                       RecordCEntryFrame record_c_entry_frame, bool update_stats,
     267             :                       bool use_simulator_reg_state) {
     268             :   v8::TickSample::Init(reinterpret_cast<v8::Isolate*>(isolate), state,
     269             :                        record_c_entry_frame, update_stats,
     270      232617 :                        use_simulator_reg_state);
     271      465234 :   if (pc == nullptr) return;
     272      231343 :   timestamp = base::TimeTicks::HighResolutionNow();
     273             : }
     274             : 
     275             : }  // namespace internal
     276             : }  // namespace v8

Generated by: LCOV version 1.10