5 #include "src/profiler/profiler-listener.h" 7 #include "src/deoptimizer.h" 8 #include "src/objects-inl.h" 9 #include "src/profiler/cpu-profiler.h" 10 #include "src/profiler/profile-generator-inl.h" 11 #include "src/snapshot/embedded-data.h" 12 #include "src/source-position-table.h" 13 #include "src/wasm/wasm-code-manager.h" 18 ProfilerListener::ProfilerListener(Isolate* isolate,
19 CodeEventObserver* observer)
20 : isolate_(isolate), observer_(observer) {}
22 ProfilerListener::~ProfilerListener() =
default;
24 void ProfilerListener::CallbackEvent(Name name, Address entry_point) {
25 CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
26 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
27 rec->instruction_start = entry_point;
28 rec->entry = NewCodeEntry(CodeEventListener::CALLBACK_TAG, GetName(name));
29 rec->instruction_size = 1;
30 DispatchCodeEvent(evt_rec);
33 void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
34 AbstractCode code,
const char* name) {
35 CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
36 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
37 rec->instruction_start = code->InstructionStart();
38 rec->entry = NewCodeEntry(tag, GetName(name), CodeEntry::kEmptyResourceName,
39 CpuProfileNode::kNoLineNumberInfo,
40 CpuProfileNode::kNoColumnNumberInfo,
nullptr,
41 code->InstructionStart());
42 RecordInliningInfo(rec->entry, code);
43 rec->instruction_size = code->InstructionSize();
44 DispatchCodeEvent(evt_rec);
47 void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
48 AbstractCode code, Name name) {
49 CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
50 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
51 rec->instruction_start = code->InstructionStart();
52 rec->entry = NewCodeEntry(tag, GetName(name), CodeEntry::kEmptyResourceName,
53 CpuProfileNode::kNoLineNumberInfo,
54 CpuProfileNode::kNoColumnNumberInfo,
nullptr,
55 code->InstructionStart());
56 RecordInliningInfo(rec->entry, code);
57 rec->instruction_size = code->InstructionSize();
58 DispatchCodeEvent(evt_rec);
61 void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
63 SharedFunctionInfo* shared,
65 CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
66 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
67 rec->instruction_start = code->InstructionStart();
68 rec->entry = NewCodeEntry(tag, GetName(shared->DebugName()),
69 GetName(InferScriptName(script_name, shared)),
70 CpuProfileNode::kNoLineNumberInfo,
71 CpuProfileNode::kNoColumnNumberInfo,
nullptr,
72 code->InstructionStart());
73 RecordInliningInfo(rec->entry, code);
74 rec->entry->FillFunctionInfo(shared);
75 rec->instruction_size = code->InstructionSize();
76 DispatchCodeEvent(evt_rec);
79 void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
80 AbstractCode abstract_code,
81 SharedFunctionInfo* shared,
82 Name script_name,
int line,
int column) {
83 CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
84 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
85 rec->instruction_start = abstract_code->InstructionStart();
86 std::unique_ptr<SourcePositionTable> line_table;
87 if (shared->script()->IsScript()) {
88 Script* script = Script::cast(shared->script());
89 line_table.reset(
new SourcePositionTable());
90 for (SourcePositionTableIterator it(abstract_code->source_position_table());
91 !it.done(); it.Advance()) {
94 if (it.source_position().InliningId() != SourcePosition::kNotInlined)
96 int position = it.source_position().ScriptOffset();
97 int line_number = script->GetLineNumber(position) + 1;
98 line_table->SetPosition(it.code_offset(), line_number);
102 NewCodeEntry(tag, GetName(shared->DebugName()),
103 GetName(InferScriptName(script_name, shared)), line, column,
104 std::move(line_table), abstract_code->InstructionStart());
105 RecordInliningInfo(rec->entry, abstract_code);
106 rec->entry->FillFunctionInfo(shared);
107 rec->instruction_size = abstract_code->InstructionSize();
108 DispatchCodeEvent(evt_rec);
111 void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
112 const wasm::WasmCode* code,
113 wasm::WasmName name) {
114 CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
115 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
116 rec->instruction_start = code->instruction_start();
117 rec->entry = NewCodeEntry(
118 tag, GetName(name.start()), CodeEntry::kWasmResourceNamePrefix,
119 CpuProfileNode::kNoLineNumberInfo, CpuProfileNode::kNoColumnNumberInfo,
120 nullptr, code->instruction_start());
121 rec->instruction_size = code->instructions().length();
122 DispatchCodeEvent(evt_rec);
125 void ProfilerListener::CodeMoveEvent(AbstractCode from, AbstractCode to) {
126 CodeEventsContainer evt_rec(CodeEventRecord::CODE_MOVE);
127 CodeMoveEventRecord* rec = &evt_rec.CodeMoveEventRecord_;
128 rec->from_instruction_start = from->InstructionStart();
129 rec->to_instruction_start = to->InstructionStart();
130 DispatchCodeEvent(evt_rec);
133 void ProfilerListener::CodeDisableOptEvent(AbstractCode code,
134 SharedFunctionInfo* shared) {
135 CodeEventsContainer evt_rec(CodeEventRecord::CODE_DISABLE_OPT);
136 CodeDisableOptEventRecord* rec = &evt_rec.CodeDisableOptEventRecord_;
137 rec->instruction_start = code->InstructionStart();
138 rec->bailout_reason = GetBailoutReason(shared->disable_optimization_reason());
139 DispatchCodeEvent(evt_rec);
142 void ProfilerListener::CodeDeoptEvent(Code code, DeoptimizeKind kind,
143 Address pc,
int fp_to_sp_delta) {
144 CodeEventsContainer evt_rec(CodeEventRecord::CODE_DEOPT);
145 CodeDeoptEventRecord* rec = &evt_rec.CodeDeoptEventRecord_;
146 Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(code, pc);
147 rec->instruction_start = code->InstructionStart();
148 rec->deopt_reason = DeoptimizeReasonToString(info.deopt_reason);
149 rec->deopt_id = info.deopt_id;
151 rec->fp_to_sp_delta = fp_to_sp_delta;
155 AttachDeoptInlinedFrames(code, rec);
156 DispatchCodeEvent(evt_rec);
159 void ProfilerListener::GetterCallbackEvent(Name name, Address entry_point) {
160 CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
161 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
162 rec->instruction_start = entry_point;
164 NewCodeEntry(CodeEventListener::CALLBACK_TAG, GetConsName(
"get ", name));
165 rec->instruction_size = 1;
166 DispatchCodeEvent(evt_rec);
169 void ProfilerListener::RegExpCodeCreateEvent(AbstractCode code, String source) {
170 CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
171 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
172 rec->instruction_start = code->InstructionStart();
173 rec->entry = NewCodeEntry(
174 CodeEventListener::REG_EXP_TAG, GetConsName(
"RegExp: ", source),
175 CodeEntry::kEmptyResourceName, CpuProfileNode::kNoLineNumberInfo,
176 CpuProfileNode::kNoColumnNumberInfo,
nullptr, code->InstructionStart());
177 rec->instruction_size = code->InstructionSize();
178 DispatchCodeEvent(evt_rec);
181 void ProfilerListener::SetterCallbackEvent(Name name, Address entry_point) {
182 CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
183 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
184 rec->instruction_start = entry_point;
186 NewCodeEntry(CodeEventListener::CALLBACK_TAG, GetConsName(
"set ", name));
187 rec->instruction_size = 1;
188 DispatchCodeEvent(evt_rec);
191 Name ProfilerListener::InferScriptName(Name name, SharedFunctionInfo* info) {
192 if (name->IsString() && String::cast(name)->length())
return name;
193 if (!info->script()->IsScript())
return name;
194 Object* source_url = Script::cast(info->script())->source_url();
195 return source_url->IsName() ? Name::cast(source_url) : name;
198 void ProfilerListener::RecordInliningInfo(CodeEntry* entry,
199 AbstractCode abstract_code) {
200 if (!abstract_code->IsCode())
return;
201 Code code = abstract_code->GetCode();
202 if (code->kind() != Code::OPTIMIZED_FUNCTION)
return;
203 DeoptimizationData deopt_input_data =
204 DeoptimizationData::cast(code->deoptimization_data());
205 int deopt_count = deopt_input_data->DeoptCount();
206 for (
int i = 0;
i < deopt_count;
i++) {
207 int pc_offset = deopt_input_data->Pc(
i)->value();
208 if (pc_offset == -1)
continue;
209 int translation_index = deopt_input_data->TranslationIndex(
i)->value();
210 TranslationIterator it(deopt_input_data->TranslationByteArray(),
212 Translation::Opcode opcode =
static_cast<Translation::Opcode
>(it.Next());
213 DCHECK_EQ(Translation::BEGIN, opcode);
214 it.Skip(Translation::NumberOfOperandsFor(opcode));
216 std::vector<std::unique_ptr<CodeEntry>> inline_stack;
217 while (it.HasNext() &&
218 Translation::BEGIN !=
219 (opcode =
static_cast<Translation::Opcode
>(it.Next()))) {
220 if (opcode != Translation::INTERPRETED_FRAME) {
221 it.Skip(Translation::NumberOfOperandsFor(opcode));
225 int shared_info_id = it.Next();
229 SharedFunctionInfo* shared_info = SharedFunctionInfo::cast(
230 deopt_input_data->LiteralArray()->get(shared_info_id));
231 if (!depth++)
continue;
233 const char* resource_name =
234 (shared_info->script()->IsScript() &&
235 Script::cast(shared_info->script())->name()->IsName())
236 ? GetName(Name::cast(Script::cast(shared_info->script())->name()))
237 : CodeEntry::kEmptyResourceName;
239 CodeEntry* inline_entry =
240 new CodeEntry(entry->tag(), GetName(shared_info->DebugName()),
241 resource_name, CpuProfileNode::kNoLineNumberInfo,
242 CpuProfileNode::kNoColumnNumberInfo,
nullptr,
243 code->InstructionStart());
244 inline_entry->FillFunctionInfo(shared_info);
245 inline_stack.emplace_back(inline_entry);
247 if (!inline_stack.empty()) {
248 entry->AddInlineStack(pc_offset, std::move(inline_stack));
253 void ProfilerListener::AttachDeoptInlinedFrames(Code code,
254 CodeDeoptEventRecord* rec) {
255 int deopt_id = rec->deopt_id;
256 SourcePosition last_position = SourcePosition::Unknown();
257 int mask = RelocInfo::ModeMask(RelocInfo::DEOPT_ID) |
258 RelocInfo::ModeMask(RelocInfo::DEOPT_SCRIPT_OFFSET) |
259 RelocInfo::ModeMask(RelocInfo::DEOPT_INLINING_ID);
261 rec->deopt_frames =
nullptr;
262 rec->deopt_frame_count = 0;
264 for (RelocIterator it(code, mask); !it.done(); it.next()) {
265 RelocInfo* info = it.rinfo();
266 if (info->rmode() == RelocInfo::DEOPT_SCRIPT_OFFSET) {
267 int script_offset =
static_cast<int>(info->data());
269 DCHECK(it.rinfo()->rmode() == RelocInfo::DEOPT_INLINING_ID);
270 int inlining_id =
static_cast<int>(it.rinfo()->data());
271 last_position = SourcePosition(script_offset, inlining_id);
274 if (info->rmode() == RelocInfo::DEOPT_ID) {
275 if (deopt_id != static_cast<int>(info->data()))
continue;
276 DCHECK(last_position.IsKnown());
281 HandleScope scope(isolate_);
282 std::vector<SourcePositionInfo> stack =
283 last_position.InliningStack(handle(code, isolate_));
284 CpuProfileDeoptFrame* deopt_frames =
285 new CpuProfileDeoptFrame[stack.size()];
287 int deopt_frame_count = 0;
288 for (SourcePositionInfo& pos_info : stack) {
289 if (pos_info.position.ScriptOffset() == kNoSourcePosition)
continue;
290 if (pos_info.script.is_null())
continue;
291 int script_id = pos_info.script->id();
292 size_t offset =
static_cast<size_t>(pos_info.position.ScriptOffset());
293 deopt_frames[deopt_frame_count++] = {script_id, offset};
295 rec->deopt_frames = deopt_frames;
296 rec->deopt_frame_count = deopt_frame_count;
302 CodeEntry* ProfilerListener::NewCodeEntry(
303 CodeEventListener::LogEventsAndTags tag,
const char* name,
304 const char* resource_name,
int line_number,
int column_number,
305 std::unique_ptr<SourcePositionTable> line_info, Address instruction_start) {
306 return new CodeEntry(tag, name, resource_name, line_number, column_number,
307 std::move(line_info), instruction_start);