v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
symbolizer.cc
Go to the documentation of this file.
1// Copyright 2020 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
6
11
12namespace v8 {
13namespace internal {
14
16 : code_map_(instruction_stream_map) {}
17
19 Address* out_instruction_start) {
20 return code_map_->FindEntry(address, out_instruction_start);
21}
22
23namespace {
24
25CodeEntry* EntryForVMState(StateTag tag) {
26 switch (tag) {
27 case GC:
28 return CodeEntry::gc_entry();
29 case JS:
30 case PARSER:
31 case COMPILER:
33 case ATOMICS_WAIT:
34 // DOM events handlers are reported as OTHER / EXTERNAL entries.
35 // To avoid confusing people, let's put all these entries into
36 // one bucket.
37 case OTHER:
38 case EXTERNAL:
39 case LOGGING:
41 case IDLE:
42 return CodeEntry::idle_entry();
43 }
44}
45
46} // namespace
47
49 const TickSample& sample) {
50 ProfileStackTrace stack_trace;
51 // Conservatively reserve space for stack frames + pc + function + vm-state.
52 // There could in fact be more of them because of inlined entries.
53 stack_trace.reserve(sample.frames_count + 3);
54
55 // The ProfileNode knows nothing about all versions of generated code for
56 // the same JS function. The line number information associated with
57 // the latest version of generated code is used to find a source line number
58 // for a JS function. Then, the detected source line is passed to
59 // ProfileNode to increase the tick count for this source line.
60 const int no_line_info = v8::CpuProfileNode::kNoLineNumberInfo;
61 int src_line = no_line_info;
62 bool src_line_not_found = true;
63
64 if (sample.pc != nullptr) {
65 if (sample.has_external_callback && sample.state == EXTERNAL) {
66 // Don't use PC when in external callback code, as it can point
67 // inside a callback's code, and we will erroneously report
68 // that a callback calls itself.
69 stack_trace.push_back(
70 {FindEntry(reinterpret_cast<Address>(sample.external_callback_entry)),
71 no_line_info});
72 } else {
73 Address attributed_pc = reinterpret_cast<Address>(sample.pc);
74 Address pc_entry_instruction_start = kNullAddress;
75 CodeEntry* pc_entry =
76 FindEntry(attributed_pc, &pc_entry_instruction_start);
77 // If there is no pc_entry, we're likely in native code. Find out if the
78 // top of the stack (the return address) was pointing inside a JS
79 // function, meaning that we have encountered a frameless invocation.
80 if (!pc_entry && !sample.has_external_callback) {
81 attributed_pc = reinterpret_cast<Address>(sample.tos);
82 pc_entry = FindEntry(attributed_pc, &pc_entry_instruction_start);
83 }
84 // If pc is in the function code before it set up stack frame or after the
85 // frame was destroyed, StackFrameIteratorForProfiler incorrectly thinks
86 // that ebp contains the return address of the current function and skips
87 // the caller's frame. Check for this case and just skip such samples.
88 if (pc_entry) {
89 int pc_offset =
90 static_cast<int>(attributed_pc - pc_entry_instruction_start);
91 // TODO(petermarshall): pc_offset can still be negative in some cases.
92 src_line = pc_entry->GetSourceLine(pc_offset);
94 src_line = pc_entry->line_number();
95 }
96 src_line_not_found = false;
97 stack_trace.push_back({pc_entry, src_line});
98
99 if (pc_entry->builtin() == Builtin::kFunctionPrototypeApply ||
100 pc_entry->builtin() == Builtin::kFunctionPrototypeCall) {
101 // When current function is either the Function.prototype.apply or the
102 // Function.prototype.call builtin the top frame is either frame of
103 // the calling JS function or internal frame.
104 // In the latter case we know the caller for sure but in the
105 // former case we don't so we simply replace the frame with
106 // 'unresolved' entry.
107 if (!sample.has_external_callback) {
110 stack_trace.push_back(
111 {CodeEntry::unresolved_entry(), no_line_info});
112 }
113 }
114 }
115 }
116
117 for (unsigned i = 0; i < sample.frames_count; ++i) {
118 Address stack_pos = reinterpret_cast<Address>(sample.stack[i]);
119 Address instruction_start = kNullAddress;
120 CodeEntry* entry = FindEntry(stack_pos, &instruction_start);
121 int line_number = no_line_info;
122 if (entry) {
123 // Find out if the entry has an inlining stack associated.
124 int pc_offset = static_cast<int>(stack_pos - instruction_start);
125 // TODO(petermarshall): pc_offset can still be negative in some cases.
126 const std::vector<CodeEntryAndLineNumber>* inline_stack =
128 if (inline_stack) {
129 int most_inlined_frame_line_number = entry->GetSourceLine(pc_offset);
130 for (auto inline_stack_entry : *inline_stack) {
131 stack_trace.push_back(inline_stack_entry);
132 }
133
134 // This is a bit of a messy hack. The line number for the most-inlined
135 // frame (the function at the end of the chain of function calls) has
136 // the wrong line number in inline_stack. The actual line number in
137 // this function is stored in the SourcePositionTable in entry. We fix
138 // up the line number for the most-inlined frame here.
139 // TODO(petermarshall): Remove this and use a tree with a node per
140 // inlining_id.
141 DCHECK(!inline_stack->empty());
142 size_t index = stack_trace.size() - inline_stack->size();
143 stack_trace[index].line_number = most_inlined_frame_line_number;
144 }
145 // Skip unresolved frames (e.g. internal frame) and get source line of
146 // the first JS caller.
147 if (src_line_not_found) {
148 src_line = entry->GetSourceLine(pc_offset);
150 src_line = entry->line_number();
151 }
152 src_line_not_found = false;
153 }
154 line_number = entry->GetSourceLine(pc_offset);
155
156 // The inline stack contains the top-level function i.e. the same
157 // function as entry. We don't want to add it twice. The one from the
158 // inline stack has the correct line number for this particular inlining
159 // so we use it instead of pushing entry to stack_trace.
160 if (inline_stack) continue;
161 }
162 stack_trace.push_back({entry, line_number});
163 }
164 }
165
166 if (v8_flags.prof_browser_mode) {
167 bool no_symbolized_entries = true;
168 for (auto e : stack_trace) {
169 if (e.code_entry != nullptr) {
170 no_symbolized_entries = false;
171 break;
172 }
173 }
174 // If no frames were symbolized, put the VM state entry in.
175 if (no_symbolized_entries) {
176 if (sample.pc == nullptr) {
178 } else {
181 }
182 stack_trace.push_back({EntryForVMState(sample.state), no_line_info});
183 }
184 }
185
186 return SymbolizedSample{stack_trace, src_line};
187}
188
189} // namespace internal
190} // namespace v8
static const int kNoLineNumberInfo
static V8_EXPORT_PRIVATE CodeEntry * gc_entry()
const std::vector< CodeEntryAndLineNumber > * GetInlineStack(int pc_offset) const
static V8_EXPORT_PRIVATE CodeEntry * program_entry()
static V8_EXPORT_PRIVATE CodeEntry * idle_entry()
int GetSourceLine(int pc_offset) const
static V8_EXPORT_PRIVATE CodeEntry * unresolved_entry()
CodeEntry * FindEntry(Address addr, Address *out_instruction_start=nullptr)
static ProfilerStats * Instance()
void AddReason(Reason reason)
CodeEntry * FindEntry(Address address, Address *out_instruction_start=nullptr)
Definition symbolizer.cc:18
InstructionStreamMap *const code_map_
Definition symbolizer.h:38
Symbolizer(InstructionStreamMap *instruction_stream_map)
Definition symbolizer.cc:15
SymbolizedSample SymbolizeTickSample(const TickSample &sample)
Definition symbolizer.cc:48
int pc_offset
V8_EXPORT_PRIVATE FlagValues v8_flags
static constexpr Address kNullAddress
Definition v8-internal.h:53
std::vector< CodeEntryAndLineNumber > ProfileStackTrace
StateTag
Definition v8-unwinder.h:36
@ COMPILER
Definition v8-unwinder.h:41
@ BYTECODE_COMPILER
Definition v8-unwinder.h:40
@ EXTERNAL
Definition v8-unwinder.h:43
@ GC
Definition v8-unwinder.h:38
@ ATOMICS_WAIT
Definition v8-unwinder.h:44
@ PARSER
Definition v8-unwinder.h:39
@ LOGGING
Definition v8-unwinder.h:46
@ IDLE
Definition v8-unwinder.h:45
@ JS
Definition v8-unwinder.h:37
@ OTHER
Definition v8-unwinder.h:42
#define DCHECK(condition)
Definition logging.h:482