9#include "absl/container/flat_hash_map.h"
10#include "protos/perfetto/common/builtin_clock.pbzero.h"
11#include "protos/perfetto/trace/chrome/v8.pbzero.h"
12#include "protos/perfetto/trace/trace_packet.pbzero.h"
13#include "protos/perfetto/trace/trace_packet_defaults.pbzero.h"
35#if V8_ENABLE_WEBASSEMBLY
43using ::perfetto::protos::pbzero::BuiltinClock;
44using ::perfetto::protos::pbzero::TracePacket;
45using ::perfetto::protos::pbzero::V8InternalCode;
46using ::perfetto::protos::pbzero::V8JsCode;
48CodeDataSource::TraceContext::TracePacketHandle NewTracePacket(
49 CodeDataSource::TraceContext& context) {
50 CodeDataSourceIncrementalState* inc_state = context.GetIncrementalState();
51 auto packet = context.NewTracePacket();
54 if (inc_state->is_initialized()) {
55 packet->set_sequence_flags(TracePacket::SEQ_NEEDS_INCREMENTAL_STATE);
59 inc_state->Init(context);
61 packet->set_sequence_flags(TracePacket::SEQ_INCREMENTAL_STATE_CLEARED);
63 auto* defaults = packet->set_trace_packet_defaults();
64 defaults->set_timestamp_clock_id(BuiltinClock::BUILTIN_CLOCK_MONOTONIC);
66 auto* v8_defaults = defaults->set_v8_code_defaults();
72CodeTraceContext NewCodeTraceContext(CodeDataSource::TraceContext& ctx) {
73 return CodeTraceContext(NewTracePacket(ctx), ctx.GetIncrementalState());
76class IsolateRegistry {
78 static IsolateRegistry& GetInstance() {
79 static IsolateRegistry* g_instance =
new IsolateRegistry();
84 auto logger = std::make_unique<PerfettoLogger>(isolate);
86 if (num_active_data_sources_ != 0) {
87 isolate->logger()->AddListener(logger.get());
96 if (num_active_data_sources_ != 0) {
97 isolate->logger()->RemoveListener(it->second.get());
102 void OnCodeDataSourceStart() {
105 if (num_active_data_sources_ == 1) {
108 LogExistingCodeForAllIsolates(lock);
111 void OnCodeDataSourceStop() {
115 if (num_active_data_sources_ == 0) {
122 for (
const auto& [isolate, logger] : isolates_) {
123 isolate->logger()->AddListener(logger.get());
128 for (
const auto& [isolate, logger] : isolates_) {
129 isolate->logger()->RemoveListener(logger.get());
134 for (
const auto& [isolate, listener] : isolates_) {
135 isolate->RequestInterrupt(
137 PerfettoLogger* logger =
reinterpret_cast<PerfettoLogger*
>(
data);
138 logger->LogExistingCode();
146 absl::flat_hash_map<Isolate*, std::unique_ptr<PerfettoLogger>>
isolates_;
149void WriteJsCode(Isolate* isolate,
const CodeTraceContext& ctx,
151 if (IsBytecodeArray(abstract_code)) {
153 code_proto.set_tier(V8JsCode::TIER_IGNITION);
154 code_proto.set_instruction_start(bytecode->GetFirstBytecodeAddress());
155 code_proto.set_instruction_size_bytes(bytecode->length());
156 if (ctx.log_instructions()) {
157 code_proto.set_bytecode(
158 reinterpret_cast<const uint8_t*
>(bytecode->GetFirstBytecodeAddress()),
164 DCHECK(IsCode(abstract_code));
167 V8JsCode::Tier tier = V8JsCode::TIER_UNKNOWN;
168 switch (code->kind()) {
169 case CodeKind::BUILTIN:
170 if (code->builtin_id() == Builtin::kInterpreterEntryTrampoline) {
171 DCHECK(isolate->interpreted_frames_native_stack());
172 DCHECK(code->has_instruction_stream());
173 tier = V8JsCode::TIER_IGNITION;
178 DCHECK_EQ(code->builtin_id(), Builtin::kEmptyFunction);
179 DCHECK(!code->has_instruction_stream());
182 case CodeKind::INTERPRETED_FUNCTION:
186 case CodeKind::BASELINE:
187 tier = V8JsCode::TIER_SPARKPLUG;
189 case CodeKind::MAGLEV:
190 tier = V8JsCode::TIER_MAGLEV;
192 case CodeKind::TURBOFAN_JS:
193 tier = V8JsCode::TIER_TURBOFAN;
196 case CodeKind::BYTECODE_HANDLER:
197 case CodeKind::FOR_TESTING:
198 case CodeKind::REGEXP:
199 case CodeKind::WASM_FUNCTION:
200 case CodeKind::WASM_TO_CAPI_FUNCTION:
201 case CodeKind::WASM_TO_JS_FUNCTION:
202 case CodeKind::JS_TO_WASM_FUNCTION:
203 case CodeKind::C_WASM_ENTRY:
207 code_proto.set_tier(tier);
208 code_proto.set_instruction_start(code->instruction_start());
209 code_proto.set_instruction_size_bytes(code->instruction_size());
210 if (ctx.log_instructions()) {
211 code_proto.set_machine_code(
212 reinterpret_cast<const uint8_t*
>(code->instruction_start()),
213 code->instruction_size());
221 IsolateRegistry::GetInstance().Register(isolate);
226 CodeDataSource::CallIfEnabled(
232 IsolateRegistry::GetInstance().Unregister(isolate);
237 IsolateRegistry::GetInstance().OnCodeDataSourceStart();
242 IsolateRegistry::GetInstance().OnCodeDataSourceStop();
260 if (!IsCode(*abstract_code))
return;
263 V8InternalCode::Type type = V8InternalCode::TYPE_UNKNOWN;
264 switch (code->kind()) {
265 case CodeKind::REGEXP:
268 case CodeKind::BYTECODE_HANDLER:
269 type = V8InternalCode::TYPE_BYTECODE_HANDLER;
271 case CodeKind::FOR_TESTING:
272 type = V8InternalCode::TYPE_FOR_TESTING;
274 case CodeKind::BUILTIN:
275 type = V8InternalCode::TYPE_BUILTIN;
277 case CodeKind::WASM_FUNCTION:
278 type = V8InternalCode::TYPE_WASM_FUNCTION;
280 case CodeKind::WASM_TO_CAPI_FUNCTION:
281 type = V8InternalCode::TYPE_WASM_TO_CAPI_FUNCTION;
283 case CodeKind::WASM_TO_JS_FUNCTION:
284 type = V8InternalCode::TYPE_WASM_TO_JS_FUNCTION;
286 case CodeKind::JS_TO_WASM_FUNCTION:
287 type = V8InternalCode::TYPE_JS_TO_WASM_FUNCTION;
289 case CodeKind::C_WASM_ENTRY:
290 type = V8InternalCode::TYPE_C_WASM_ENTRY;
293 case CodeKind::INTERPRETED_FUNCTION:
294 case CodeKind::BASELINE:
295 case CodeKind::MAGLEV:
296 case CodeKind::TURBOFAN_JS:
300 CodeDataSource::Trace(
301 [&](v8::internal::CodeDataSource::TraceContext trace_context) {
306 code_proto->set_name(name);
307 code_proto->set_type(type);
308 if (code->is_builtin()) {
309 code_proto->set_builtin_id(
static_cast<int32_t
>(code->builtin_id()));
311 code_proto->set_instruction_start(code->instruction_start());
312 code_proto->set_instruction_size_bytes(code->instruction_size());
314 code_proto->set_machine_code(
315 reinterpret_cast<const uint8_t*
>(code->instruction_start()),
316 code->instruction_size());
325 if (!IsString(*name))
return;
342 DCHECK(IsScript(info->script()));
344 CodeDataSource::Trace(
345 [&](v8::internal::CodeDataSource::TraceContext trace_context) {
354 WriteJsCode(&
isolate_, ctx, *abstract_code, *code_proto);
357#if V8_ENABLE_WEBASSEMBLY
360 const char* source_url,
int code_offset,
364 CodeDataSource::Trace(
365 [&](v8::internal::CodeDataSource::TraceContext trace_context) {
369 code_proto->set_v8_wasm_script_iid(ctx.InternWasmScript(
370 isolate_, script_id, source_url, code->native_module()));
371 code_proto->set_function_name(name.begin(), name.size());
373 code_proto->set_instruction_start(code->instruction_start());
374 code_proto->set_instruction_size_bytes(code->instructions_size());
376 code_proto->set_machine_code(
377 reinterpret_cast<const uint8_t*
>(code->instruction_start()),
378 code->instructions_size());
394 DCHECK(IsCode(*abstract_code));
396 DCHECK(code->kind() == CodeKind::REGEXP);
398 CodeDataSource::Trace(
399 [&](v8::internal::CodeDataSource::TraceContext trace_context) {
408 code_proto->set_instruction_start(code->instruction_start());
409 code_proto->set_instruction_size_bytes(code->instruction_size());
411 code_proto->set_machine_code(
412 reinterpret_cast<const uint8_t*
>(code->instruction_start()),
413 code->instruction_size());
420 CodeDataSource::Trace(
421 [&](v8::internal::CodeDataSource::TraceContext trace_context) {
425 code_move->set_from_instruction_start_address(
426 from->instruction_start());
427 code_move->set_to_instruction_start_address(to->instruction_start());
429 code_move->set_instruction_size_bytes(code->instruction_size());
431 code_move->set_to_machine_code(
432 reinterpret_cast<const uint8_t*
>(code->instruction_start()),
433 code->instruction_size());
439 CodeDataSource::Trace(
440 [&](v8::internal::CodeDataSource::TraceContext trace_context) {
444 code_move->set_from_instruction_start_address(
445 from->GetFirstBytecodeAddress());
446 code_move->set_to_instruction_start_address(
447 to->GetFirstBytecodeAddress());
448 code_move->set_instruction_size_bytes(to->length());
450 code_move->set_to_bytecode(
451 reinterpret_cast<const uint8_t*
>(to->GetFirstBytecodeAddress()),
464 int fp_to_sp_delta) {}
467 const char* reason) {}
union v8::internal::@341::BuiltinMetadata::KindSpecificData data
static int GetCurrentThreadId()
static void EmitCodeCreateEvents(Isolate *isolate)
perfetto::protos::pbzero::V8JsCode * set_v8_js_code()
uint64_t InternJsScript(Isolate &isolate, Tagged< Script > script)
perfetto::protos::pbzero::V8CodeMove * set_code_move()
perfetto::protos::pbzero::V8WasmCode * set_v8_wasm_code()
perfetto::protos::pbzero::V8RegExpCode * set_v8_reg_exp_code()
uint64_t InternIsolate(Isolate &isolate)
perfetto::protos::pbzero::V8InternalCode * set_v8_internal_code()
uint64_t InternJsFunction(Isolate &isolate, DirectHandle< SharedFunctionInfo > info, uint64_t v8_js_script_iid, int line_num, int column_num)
bool log_instructions() const
void LogCompiledFunctions(bool ensure_source_positions_available=true)
void CodeDeoptEvent(DirectHandle< Code > code, DeoptimizeKind kind, Address pc, int fp_to_sp_delta) override
static void OnCodeDataSourceStop()
void BytecodeMoveEvent(Tagged< BytecodeArray > from, Tagged< BytecodeArray > to) override
void SharedFunctionInfoMoveEvent(Address from, Address to) override
static void OnCodeDataSourceStart()
PerfettoLogger(Isolate *isolate)
void GetterCallbackEvent(DirectHandle< Name > name, Address entry_point) override
void CodeMoveEvent(Tagged< InstructionStream > from, Tagged< InstructionStream > to) override
void RegExpCodeCreateEvent(DirectHandle< AbstractCode > code, DirectHandle< String > source, RegExpFlags flags) override
bool is_listening_to_code_events() override
void CodeDisableOptEvent(DirectHandle< AbstractCode > code, DirectHandle< SharedFunctionInfo > shared) override
void WeakCodeClearEvent() override
static void UnregisterIsolate(Isolate *isolate)
static void RegisterIsolate(Isolate *isolate)
void CodeMovingGCEvent() override
void CodeDependencyChangeEvent(DirectHandle< Code > code, DirectHandle< SharedFunctionInfo > shared, const char *reason) override
void SetterCallbackEvent(DirectHandle< Name > name, Address entry_point) override
~PerfettoLogger() override
void NativeContextMoveEvent(Address from, Address to) override
void CodeCreateEvent(CodeTag tag, DirectHandle< AbstractCode > code, const char *name) override
void CallbackEvent(DirectHandle< Name > name, Address entry_point) override
void WriteToProto(Proto &proto) const
LockGuard< Mutex > MutexGuard
Tagged(T object) -> Tagged< T >
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
absl::flat_hash_map< Isolate *, std::unique_ptr< PerfettoLogger > > isolates_
int num_active_data_sources_
#define DCHECK(condition)
#define DCHECK_LT(v1, v2)
#define DCHECK_EQ(v1, v2)