v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
log.cc
Go to the documentation of this file.
1// Copyright 2011 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/logging/log.h"
6
7#include <atomic>
8#include <cstdarg>
9#include <memory>
10#include <sstream>
11
12#include "include/v8-locker.h"
13#include "src/api/api-inl.h"
14#include "src/base/hashing.h"
32#include "src/heap/heap-inl.h"
41#include "src/logging/log-inl.h"
44#include "src/objects/code.h"
50#include "src/utils/memcopy.h"
51#include "src/utils/version.h"
52
53#ifdef ENABLE_GDB_JIT_INTERFACE
55#endif // ENABLE_GDB_JIT_INTERFACE
56
57#if V8_ENABLE_WEBASSEMBLY
62#endif // V8_ENABLE_WEBASSEMBLY
63
64#if defined(V8_ENABLE_ETW_STACK_WALKING)
66#endif // V8_ENABLE_ETW_STACK_WALKING
67
68namespace v8 {
69namespace internal {
70
71static const char* kLogEventsNames[] = {
72#define DECLARE_EVENT(ignore1, name) name,
74#undef DECLARE_EVENT
75};
76static const char* kCodeTagNames[] = {
77#define DECLARE_EVENT(ignore1, name) #name,
79#undef DECLARE_EVENT
80};
81
82std::ostream& operator<<(std::ostream& os, LogEventListener::CodeTag tag) {
83 os << kCodeTagNames[static_cast<int>(tag)];
84 return os;
85}
86std::ostream& operator<<(std::ostream& os, LogEventListener::Event event) {
87 os << kLogEventsNames[static_cast<int>(event)];
88 return os;
89}
90
91namespace {
92
93v8::CodeEventType GetCodeEventTypeForTag(LogEventListener::CodeTag tag) {
94 switch (tag) {
95 case LogEventListener::CodeTag::kLength:
96 // Manually create this switch, since v8::CodeEventType is API expose and
97 // cannot be easily modified.
98 case LogEventListener::CodeTag::kBuiltin:
99 return v8::CodeEventType::kBuiltinType;
100 case LogEventListener::CodeTag::kCallback:
101 return v8::CodeEventType::kCallbackType;
102 case LogEventListener::CodeTag::kEval:
103 return v8::CodeEventType::kEvalType;
104 case LogEventListener::CodeTag::kNativeFunction:
105 case LogEventListener::CodeTag::kFunction:
106 return v8::CodeEventType::kFunctionType;
107 case LogEventListener::CodeTag::kHandler:
108 return v8::CodeEventType::kHandlerType;
109 case LogEventListener::CodeTag::kBytecodeHandler:
110 return v8::CodeEventType::kBytecodeHandlerType;
111 case LogEventListener::CodeTag::kRegExp:
112 return v8::CodeEventType::kRegExpType;
113 case LogEventListener::CodeTag::kNativeScript:
114 case LogEventListener::CodeTag::kScript:
115 return v8::CodeEventType::kScriptType;
116 case LogEventListener::CodeTag::kStub:
117 return v8::CodeEventType::kStubType;
118 }
119 UNREACHABLE();
120}
121
122#define CALL_CODE_EVENT_HANDLER(Call) \
123 if (listener_) { \
124 listener_->Call; \
125 } else { \
126 PROFILE(isolate_, Call); \
127 }
128
129const char* ComputeMarker(Tagged<SharedFunctionInfo> shared,
131 PtrComprCageBase cage_base = GetPtrComprCageBase(shared);
132 CodeKind kind = code->kind(cage_base);
133 // We record interpreter trampoline builtin copies as having the
134 // "interpreted" marker.
135 if (v8_flags.interpreted_frames_native_stack && kind == CodeKind::BUILTIN &&
136 code->has_instruction_stream(cage_base) &&
137 code->builtin_id(cage_base) == Builtin::kInterpreterEntryTrampoline) {
138 kind = CodeKind::INTERPRETED_FUNCTION;
139 }
140 if (shared->optimization_disabled() &&
141 kind == CodeKind::INTERPRETED_FUNCTION) {
142 return "";
143 }
144 return CodeKindToMarker(
145 kind, IsCode(code) && code->GetCode()->is_context_specialized());
146}
147
148#if V8_ENABLE_WEBASSEMBLY
149const char* ComputeMarker(const wasm::WasmCode* code) {
150 switch (code->kind()) {
152 return code->is_liftoff() ? "" : "*";
153 default:
154 return "";
155 }
156}
157#endif // V8_ENABLE_WEBASSEMBLY
158
159} // namespace
160
162 public:
164
165 void Reset() { utf8_pos_ = 0; }
166
167 void Init(CodeTag tag) {
168 Reset();
169 AppendBytes(kCodeTagNames[static_cast<int>(tag)]);
170 AppendByte(':');
171 }
172
174 if (IsString(name)) {
176 } else {
177 Tagged<Symbol> symbol = Cast<Symbol>(name);
178 AppendBytes("symbol(");
179 if (!IsUndefined(symbol->description())) {
180 AppendBytes("\"");
181 AppendString(Cast<String>(symbol->description()));
182 AppendBytes("\" ");
183 }
184 AppendBytes("hash ");
185 AppendHex(symbol->hash());
186 AppendByte(')');
187 }
188 }
189
191 if (str.is_null()) return;
192 size_t length = 0;
193 std::unique_ptr<char[]> c_str = str->ToCString(&length);
194 AppendBytes(c_str.get(), length);
195 }
196
197 void AppendBytes(const char* bytes, size_t size) {
198 size = std::min(size, kUtf8BufferSize - utf8_pos_);
199 MemCopy(utf8_buffer_ + utf8_pos_, bytes, size);
200 utf8_pos_ += size;
201 }
202
203 void AppendBytes(const char* bytes) {
204 size_t len = strlen(bytes);
205 DCHECK_GE(kMaxInt, len);
206 AppendBytes(bytes, static_cast<int>(len));
207 }
208
209 void AppendByte(char c) {
210 if (utf8_pos_ >= kUtf8BufferSize) return;
211 utf8_buffer_[utf8_pos_++] = c;
212 }
213
214 void AppendInt(int n) {
215 if (utf8_pos_ >= kUtf8BufferSize) return;
216 size_t space = kUtf8BufferSize - utf8_pos_;
218 int size = SNPrintF(buffer, "%d", n);
219 if (size > 0 && utf8_pos_ + size <= kUtf8BufferSize) {
220 utf8_pos_ += size;
221 }
222 }
223
224 void AppendHex(uint32_t n) {
225 if (utf8_pos_ >= kUtf8BufferSize) return;
226 size_t space = kUtf8BufferSize - utf8_pos_;
228 int size = SNPrintF(buffer, "%x", n);
229 if (size > 0 && utf8_pos_ + size <= kUtf8BufferSize) {
230 utf8_pos_ += size;
231 }
232 }
233
234 const char* get() { return utf8_buffer_; }
235 size_t size() const { return utf8_pos_; }
236
237 private:
238 static const size_t kUtf8BufferSize = 4096;
239 static const size_t kUtf16BufferSize = kUtf8BufferSize;
240
241 size_t utf8_pos_;
243};
244
246 : isolate_(isolate), name_buffer_(std::make_unique<NameBuffer>()) {}
247
249
252 const char* comment) {
254 name_buffer_->Init(tag);
255 name_buffer_->AppendBytes(comment);
258 name_buffer_->get(), name_buffer_->size());
259}
260
271
275 DirectHandle<Name> script_name) {
277 name_buffer_->Init(tag);
278 name_buffer_->AppendBytes(ComputeMarker(*shared, *code));
279 name_buffer_->AppendByte(' ');
280 name_buffer_->AppendName(*script_name);
282 LogRecordedBuffer(*code, shared, name_buffer_->get(), name_buffer_->size());
283}
284
288 DirectHandle<Name> script_name, int line,
289 int column) {
291 name_buffer_->Init(tag);
292 name_buffer_->AppendBytes(ComputeMarker(*shared, *code));
293 name_buffer_->AppendBytes(shared->DebugNameCStr().get());
294 name_buffer_->AppendByte(' ');
295 if (IsString(*script_name)) {
296 name_buffer_->AppendString(Cast<String>(*script_name));
297 } else {
298 name_buffer_->AppendBytes("symbol(hash ");
299 name_buffer_->AppendHex(Cast<Name>(*script_name)->hash());
300 name_buffer_->AppendByte(')');
301 }
302 name_buffer_->AppendByte(':');
303 name_buffer_->AppendInt(line);
304 name_buffer_->AppendByte(':');
305 name_buffer_->AppendInt(column);
307 LogRecordedBuffer(*code, shared, name_buffer_->get(), name_buffer_->size());
308}
309
310#if V8_ENABLE_WEBASSEMBLY
311void CodeEventLogger::CodeCreateEvent(CodeTag tag, const wasm::WasmCode* code,
312 wasm::WasmName name,
313 const char* source_url,
314 int /*code_offset*/, int /*script_id*/) {
316 name_buffer_->Init(tag);
317 DCHECK(!name.empty());
318 name_buffer_->AppendBytes(name.begin(), name.length());
319 name_buffer_->AppendByte('-');
320 if (code->IsAnonymous()) {
321 name_buffer_->AppendBytes("<anonymous>");
322 } else {
323 name_buffer_->AppendInt(code->index());
324 }
325 name_buffer_->AppendByte('-');
326 name_buffer_->AppendBytes(ExecutionTierToString(code->tier()));
328 LogRecordedBuffer(code, name_buffer_->get(), name_buffer_->size());
329}
330#endif // V8_ENABLE_WEBASSEMBLY
331
334 RegExpFlags flags) {
336 // Note we don't call Init due to the required pprof demangling hack for
337 // regexp patterns.
338 name_buffer_->Reset();
339 // https://github.com/google/pprof/blob/4cf4322d492d108a9d6526d10844e04792982cbb/internal/symbolizer/symbolizer.go#L312.
340 name_buffer_->AppendBytes("RegExp.>");
341 name_buffer_->AppendBytes(" src: '");
342 name_buffer_->AppendString(*source);
343 name_buffer_->AppendBytes("' flags: '");
344 DirectHandle<String> flags_str =
346 name_buffer_->AppendString(*flags_str);
347 name_buffer_->AppendBytes("'");
350 name_buffer_->get(), name_buffer_->size());
351}
352
353// Linux perf tool logging support.
354#if V8_OS_LINUX
355class LinuxPerfBasicLogger : public CodeEventLogger {
356 public:
357 explicit LinuxPerfBasicLogger(Isolate* isolate);
358 ~LinuxPerfBasicLogger() override;
359
360 void CodeMoveEvent(Tagged<InstructionStream> from,
361 Tagged<InstructionStream> to) override {}
362 void BytecodeMoveEvent(Tagged<BytecodeArray> from,
363 Tagged<BytecodeArray> to) override {}
364 void CodeDisableOptEvent(DirectHandle<AbstractCode> code,
365 DirectHandle<SharedFunctionInfo> shared) override {}
366
367 private:
368 void LogRecordedBuffer(Tagged<AbstractCode> code,
369 MaybeDirectHandle<SharedFunctionInfo> maybe_shared,
370 const char* name, size_t length) override;
371#if V8_ENABLE_WEBASSEMBLY
372 void LogRecordedBuffer(const wasm::WasmCode* code, const char* name,
373 size_t length) override;
374#endif // V8_ENABLE_WEBASSEMBLY
375 void WriteLogRecordedBuffer(uintptr_t address, size_t size, const char* name,
376 size_t name_length);
377
378 static base::LazyRecursiveMutex& GetFileMutex();
379
380 // Extension added to V8 log file name to get the low-level log name.
381 static const char kFilenameFormatString[];
382 static const int kFilenameBufferPadding;
383
384 // Per-process singleton file. We assume that there is one main isolate
385 // to determine when it goes away, we keep the reference count.
386 static FILE* perf_output_handle_;
387 static uint64_t reference_count_;
388};
389
390// Extra space for the "perf-%d.map" filename, including the PID.
391const int LinuxPerfBasicLogger::kFilenameBufferPadding = 32;
392
393// static
394base::LazyRecursiveMutex& LinuxPerfBasicLogger::GetFileMutex() {
396 return file_mutex;
397}
398
399// The following static variables are protected by
400// LinuxPerfBasicLogger::GetFileMutex().
401uint64_t LinuxPerfBasicLogger::reference_count_ = 0;
402FILE* LinuxPerfBasicLogger::perf_output_handle_ = nullptr;
403
404LinuxPerfBasicLogger::LinuxPerfBasicLogger(Isolate* isolate)
405 : CodeEventLogger(isolate) {
406 base::LockGuard<base::RecursiveMutex> guard_file(GetFileMutex().Pointer());
407 int process_id_ = base::OS::GetCurrentProcessId();
408 reference_count_++;
409 // If this is the first logger, open the file.
410 if (reference_count_ == 1) {
411 CHECK_NULL(perf_output_handle_);
412 CHECK_NOT_NULL(v8_flags.perf_basic_prof_path);
413 const char* base_dir = v8_flags.perf_basic_prof_path;
414 // Open the perf JIT dump file.
415 base::ScopedVector<char> perf_dump_name(strlen(base_dir) +
416 kFilenameBufferPadding);
417 int size =
418 SNPrintF(perf_dump_name, "%s/perf-%d.map", base_dir, process_id_);
419 CHECK_NE(size, -1);
420 perf_output_handle_ =
421 base::OS::FOpen(perf_dump_name.begin(), base::OS::LogFileOpenMode);
422 CHECK_NOT_NULL(perf_output_handle_);
423 setvbuf(perf_output_handle_, nullptr, _IOLBF, 0);
424 }
425}
426
427LinuxPerfBasicLogger::~LinuxPerfBasicLogger() {
428 base::LockGuard<base::RecursiveMutex> guard_file(GetFileMutex().Pointer());
429 reference_count_--;
430
431 // If this was the last logger, close the file.
432 if (reference_count_ == 0) {
433 CHECK_NOT_NULL(perf_output_handle_);
434 base::Fclose(perf_output_handle_);
435 perf_output_handle_ = nullptr;
436 }
437}
438
439void LinuxPerfBasicLogger::WriteLogRecordedBuffer(uintptr_t address,
440 size_t size, const char* name,
441 size_t name_length) {
442 // Linux perf expects hex literals without a leading 0x, while some
443 // implementations of printf might prepend one when using the %p format
444 // for pointers, leading to wrongly formatted JIT symbols maps. On the other
445 // hand, Android's simpleperf does expect a leading 0x.
446 //
447 // Instead, we use V8PRIxPTR format string and cast pointer to uintpr_t,
448 // so that we have control over the exact output format.
449 int int_name_length = static_cast<int>(name_length);
450#ifdef V8_OS_ANDROID
451 base::OS::FPrint(perf_output_handle_, "0x%" V8PRIxPTR " 0x%zx %.*s\n",
452 address, size, int_name_length, name);
453#else
454 base::OS::FPrint(perf_output_handle_, "%" V8PRIxPTR " %zx %.*s\n", address,
455 size, int_name_length, name);
456#endif
457}
458
459void LinuxPerfBasicLogger::LogRecordedBuffer(
460 Tagged<AbstractCode> code, MaybeDirectHandle<SharedFunctionInfo>,
461 const char* name, size_t length) {
463 PtrComprCageBase cage_base(isolate_);
464 if (v8_flags.perf_basic_prof_only_functions &&
465 !CodeKindIsBuiltinOrJSFunction(code->kind(cage_base))) {
466 return;
467 }
468
469 WriteLogRecordedBuffer(
470 static_cast<uintptr_t>(code->InstructionStart(cage_base)),
471 code->InstructionSize(cage_base), name, length);
472}
473
474#if V8_ENABLE_WEBASSEMBLY
475void LinuxPerfBasicLogger::LogRecordedBuffer(const wasm::WasmCode* code,
476 const char* name, size_t length) {
477 WriteLogRecordedBuffer(static_cast<uintptr_t>(code->instruction_start()),
478 code->instructions().length(), name, length);
479}
480#endif // V8_ENABLE_WEBASSEMBLY
481#endif // V8_OS_LINUX
482
483// External LogEventListener
485 : is_listening_(false), isolate_(isolate), code_event_handler_(nullptr) {}
486
492
494 HandleScope scope(isolate_);
495 ExistingCodeLogger logger(isolate_, this);
496 logger.LogBuiltins();
497 logger.LogCodeObjects();
498 logger.LogCompiledFunctions();
499}
500
502 CodeEventHandler* code_event_handler) {
503 if (is_listening_ || code_event_handler == nullptr) {
504 return;
505 }
506 code_event_handler_ = code_event_handler;
508 if (is_listening_) {
510 }
511}
512
514 if (!is_listening_) {
515 return;
516 }
517
519 is_listening_ = false;
520}
521
524 const char* comment) {
525 PtrComprCageBase cage_base(isolate_);
526 CodeEvent code_event;
527 code_event.code_start_address =
528 static_cast<uintptr_t>(code->InstructionStart(cage_base));
529 code_event.code_size = static_cast<size_t>(code->InstructionSize(cage_base));
530 code_event.function_name = isolate_->factory()->empty_string();
531 code_event.script_name = isolate_->factory()->empty_string();
532 code_event.script_line = 0;
533 code_event.script_column = 0;
534 code_event.code_type = GetCodeEventTypeForTag(tag);
535 code_event.comment = comment;
536
537 code_event_handler_->Handle(reinterpret_cast<v8::CodeEvent*>(&code_event));
538}
539
542 DirectHandle<Name> name) {
543 DirectHandle<String> name_string =
544 Name::ToFunctionName(isolate_, name).ToHandleChecked();
545
546 PtrComprCageBase cage_base(isolate_);
547 CodeEvent code_event;
548 code_event.code_start_address =
549 static_cast<uintptr_t>(code->InstructionStart(cage_base));
550 code_event.code_size = static_cast<size_t>(code->InstructionSize(cage_base));
551 code_event.function_name = name_string;
552 code_event.script_name = isolate_->factory()->empty_string();
553 code_event.script_line = 0;
554 code_event.script_column = 0;
555 code_event.code_type = GetCodeEventTypeForTag(tag);
556 code_event.comment = "";
557
558 code_event_handler_->Handle(reinterpret_cast<v8::CodeEvent*>(&code_event));
559}
560
564 DirectHandle<String> name_string =
565 Name::ToFunctionName(isolate_, name).ToHandleChecked();
566
567 PtrComprCageBase cage_base(isolate_);
568 CodeEvent code_event;
569 code_event.code_start_address =
570 static_cast<uintptr_t>(code->InstructionStart(cage_base));
571 code_event.code_size = static_cast<size_t>(code->InstructionSize(cage_base));
572 code_event.function_name = name_string;
573 code_event.script_name = isolate_->factory()->empty_string();
574 code_event.script_line = 0;
575 code_event.script_column = 0;
576 code_event.code_type = GetCodeEventTypeForTag(tag);
577 code_event.comment = "";
578
579 code_event_handler_->Handle(reinterpret_cast<v8::CodeEvent*>(&code_event));
580}
581
585 int line, int column) {
586 DirectHandle<String> name_string =
588 .ToHandleChecked();
589 DirectHandle<String> source_string =
590 Name::ToFunctionName(isolate_, source).ToHandleChecked();
591
592 PtrComprCageBase cage_base(isolate_);
593 CodeEvent code_event;
594 code_event.code_start_address =
595 static_cast<uintptr_t>(code->InstructionStart(cage_base));
596 code_event.code_size = static_cast<size_t>(code->InstructionSize(cage_base));
597 code_event.function_name = name_string;
598 code_event.script_name = source_string;
599 code_event.script_line = line;
600 code_event.script_column = column;
601 code_event.code_type = GetCodeEventTypeForTag(tag);
602 code_event.comment = "";
603
604 code_event_handler_->Handle(reinterpret_cast<v8::CodeEvent*>(&code_event));
605}
606
607#if V8_ENABLE_WEBASSEMBLY
609 const wasm::WasmCode* code,
610 wasm::WasmName name,
611 const char* source_url,
612 int code_offset, int script_id) {
613 // TODO(mmarchini): handle later
614}
615#endif // V8_ENABLE_WEBASSEMBLY
616
619 RegExpFlags flags) {
620 PtrComprCageBase cage_base(isolate_);
621 CodeEvent code_event;
622 code_event.code_start_address =
623 static_cast<uintptr_t>(code->InstructionStart(cage_base));
624 code_event.code_size = static_cast<size_t>(code->InstructionSize(cage_base));
625 code_event.function_name = source;
626 code_event.script_name = isolate_->factory()->empty_string();
627 code_event.script_line = 0;
628 code_event.script_column = 0;
629 code_event.code_type =
630 GetCodeEventTypeForTag(LogEventListener::CodeTag::kRegExp);
631 code_event.comment = "";
632
633 code_event_handler_->Handle(reinterpret_cast<v8::CodeEvent*>(&code_event));
634}
635
636namespace {
637
638void InitializeCodeEvent(Isolate* isolate, CodeEvent* event,
639 Address previous_code_start_address,
640 Address code_start_address, int code_size) {
641 event->previous_code_start_address =
642 static_cast<uintptr_t>(previous_code_start_address);
643 event->code_start_address = static_cast<uintptr_t>(code_start_address);
644 event->code_size = static_cast<size_t>(code_size);
645 event->function_name = isolate->factory()->empty_string();
646 event->script_name = isolate->factory()->empty_string();
647 event->script_line = 0;
648 event->script_column = 0;
649 event->code_type = v8::CodeEventType::kRelocationType;
650 event->comment = "";
651}
652
653} // namespace
654
657 CodeEvent code_event;
658 InitializeCodeEvent(isolate_, &code_event, from->instruction_start(),
659 to->instruction_start(),
660 to->code(kAcquireLoad)->instruction_size());
661 code_event_handler_->Handle(reinterpret_cast<v8::CodeEvent*>(&code_event));
662}
663
666 CodeEvent code_event;
667 InitializeCodeEvent(isolate_, &code_event, from->GetFirstBytecodeAddress(),
668 to->GetFirstBytecodeAddress(), to->length());
669 code_event_handler_->Handle(reinterpret_cast<v8::CodeEvent*>(&code_event));
670}
671
672// Low-level logging support.
674 public:
675 LowLevelLogger(Isolate* isolate, const char* file_name);
676 ~LowLevelLogger() override;
677
679 Tagged<InstructionStream> to) override;
681 Tagged<BytecodeArray> to) override;
685 void CodeMovingGCEvent() override;
686
687 private:
690 const char* name, size_t length) override;
691#if V8_ENABLE_WEBASSEMBLY
692 void LogRecordedBuffer(const wasm::WasmCode* code, const char* name,
693 size_t length) override;
694#endif // V8_ENABLE_WEBASSEMBLY
695
696 // Low-level profiling event structures.
698 static const char kTag = 'C';
699
700 int32_t name_size;
702 int32_t code_size;
703 };
704
706 static const char kTag = 'M';
707
710 };
711
712 static const char kCodeMovingGCTag = 'G';
713
714 // Extension added to V8 log file name to get the low-level log name.
715 static const char kLogExt[];
716
717 void LogCodeInfo();
718 void LogWriteBytes(const char* bytes, size_t size);
719
720 template <typename T>
721 void LogWriteStruct(const T& s) {
722 char tag = T::kTag;
723 LogWriteBytes(reinterpret_cast<const char*>(&tag), sizeof(tag));
724 LogWriteBytes(reinterpret_cast<const char*>(&s), sizeof(s));
725 }
726
728};
729
730const char LowLevelLogger::kLogExt[] = ".ll";
731
732LowLevelLogger::LowLevelLogger(Isolate* isolate, const char* name)
733 : CodeEventLogger(isolate), ll_output_handle_(nullptr) {
734 // Open the low-level log file.
735 size_t len = strlen(name);
736 base::ScopedVector<char> ll_name(static_cast<int>(len + sizeof(kLogExt)));
737 MemCopy(ll_name.begin(), name, len);
738 MemCopy(ll_name.begin() + len, kLogExt, sizeof(kLogExt));
741 setvbuf(ll_output_handle_, nullptr, _IOLBF, 0);
742
743 LogCodeInfo();
744}
745
750
752#if V8_TARGET_ARCH_IA32
753 const char arch[] = "ia32";
754#elif V8_TARGET_ARCH_X64 && V8_TARGET_ARCH_64_BIT
755 const char arch[] = "x64";
756#elif V8_TARGET_ARCH_ARM
757 const char arch[] = "arm";
758#elif V8_TARGET_ARCH_PPC64
759 const char arch[] = "ppc64";
760#elif V8_TARGET_ARCH_LOONG64
761 const char arch[] = "loong64";
762#elif V8_TARGET_ARCH_ARM64
763 const char arch[] = "arm64";
764#elif V8_TARGET_ARCH_S390X
765 const char arch[] = "s390x";
766#elif V8_TARGET_ARCH_RISCV64
767 const char arch[] = "riscv64";
768#elif V8_TARGET_ARCH_RISCV32
769 const char arch[] = "riscv32";
770#else
771 const char arch[] = "unknown";
772#endif
773 LogWriteBytes(arch, sizeof(arch));
774}
775
778 const char* name, size_t length) {
780 PtrComprCageBase cage_base(isolate_);
781 CodeCreateStruct event;
782 event.name_size = static_cast<uint32_t>(length);
783 event.code_address = code->InstructionStart(cage_base);
784 event.code_size = code->InstructionSize(cage_base);
785 LogWriteStruct(event);
786 LogWriteBytes(name, length);
788 reinterpret_cast<const char*>(code->InstructionStart(cage_base)),
789 code->InstructionSize(cage_base));
790}
791
792#if V8_ENABLE_WEBASSEMBLY
794 const char* name, size_t length) {
795 CodeCreateStruct event;
796 event.name_size = static_cast<uint32_t>(length);
797 event.code_address = code->instruction_start();
798 event.code_size = code->instructions().length();
799 LogWriteStruct(event);
800 LogWriteBytes(name, length);
801 LogWriteBytes(reinterpret_cast<const char*>(code->instruction_start()),
802 code->instructions().length());
803}
804#endif // V8_ENABLE_WEBASSEMBLY
805
808 CodeMoveStruct event;
809 event.from_address = from->instruction_start();
810 event.to_address = to->instruction_start();
811 LogWriteStruct(event);
812}
813
816 CodeMoveStruct event;
817 event.from_address = from->GetFirstBytecodeAddress();
818 event.to_address = to->GetFirstBytecodeAddress();
819 LogWriteStruct(event);
820}
821
822void LowLevelLogger::LogWriteBytes(const char* bytes, size_t size) {
823 size_t rv = fwrite(bytes, 1, size, ll_output_handle_);
824 DCHECK_EQ(size, rv);
825 USE(rv);
826}
827
829 const char tag = kCodeMovingGCTag;
830
831 LogWriteBytes(&tag, sizeof(tag));
832}
833
835 public:
836 JitLogger(Isolate* isolate, JitCodeEventHandler code_event_handler);
837
839 Tagged<InstructionStream> to) override;
841 Tagged<BytecodeArray> to) override;
844 void AddCodeLinePosInfoEvent(void* jit_handler_data, int pc_offset,
845 int position,
846 JitCodeEvent::PositionType position_type,
847 JitCodeEvent::CodeType code_type);
848
850 void EndCodePosInfoEvent(Address start_address, void* jit_handler_data,
851 JitCodeEvent::CodeType code_type);
852
853 private:
856 const char* name, size_t length) override;
857#if V8_ENABLE_WEBASSEMBLY
858 void LogRecordedBuffer(const wasm::WasmCode* code, const char* name,
859 size_t length) override;
860#endif // V8_ENABLE_WEBASSEMBLY
861
864};
865
867 : CodeEventLogger(isolate), code_event_handler_(code_event_handler) {
868 DCHECK_NOT_NULL(code_event_handler);
869}
870
873 MaybeDirectHandle<SharedFunctionInfo> maybe_shared, const char* name,
874 size_t length) {
876 PtrComprCageBase cage_base(isolate_);
877 JitCodeEvent event;
879 event.code_start = reinterpret_cast<void*>(code->InstructionStart(cage_base));
880 event.code_type = IsCode(code, cage_base) ? JitCodeEvent::JIT_CODE
882 event.code_len = code->InstructionSize(cage_base);
884 if (maybe_shared.ToHandle(&shared) &&
885 IsScript(shared->script(cage_base), cage_base)) {
886 event.script = ToApiHandle<v8::UnboundScript>(shared);
887 } else {
888 event.script = Local<v8::UnboundScript>();
889 }
890 event.name.str = name;
891 event.name.len = length;
892 event.isolate = reinterpret_cast<v8::Isolate*>(isolate_);
893 code_event_handler_(&event);
894}
895
896#if V8_ENABLE_WEBASSEMBLY
897void JitLogger::LogRecordedBuffer(const wasm::WasmCode* code, const char* name,
898 size_t length) {
899 JitCodeEvent event;
901 event.code_type = JitCodeEvent::WASM_CODE;
902 event.code_start = code->instructions().begin();
903 event.code_len = code->instructions().length();
904 event.name.str = name;
905 event.name.len = length;
906 event.isolate = reinterpret_cast<v8::Isolate*>(isolate_);
907
908 if (!code->IsAnonymous()) { // Skip for WasmCode::Kind::kWasmToJsWrapper.
909 wasm::WasmModuleSourceMap* source_map =
910 code->native_module()->GetWasmSourceMap();
911 wasm::WireBytesRef code_ref =
912 code->native_module()->module()->functions[code->index()].code;
913 uint32_t code_offset = code_ref.offset();
914 uint32_t code_end_offset = code_ref.end_offset();
915
916 std::vector<v8::JitCodeEvent::line_info_t> mapping_info;
917 std::string filename;
918 std::unique_ptr<JitCodeEvent::wasm_source_info_t> wasm_source_info;
919
920 if (source_map && source_map->IsValid() &&
921 source_map->HasSource(code_offset, code_end_offset)) {
922 size_t last_line_number = 0;
923
924 for (SourcePositionTableIterator iterator(code->source_positions());
925 !iterator.done(); iterator.Advance()) {
926 uint32_t offset =
927 iterator.source_position().ScriptOffset() + code_offset;
928 if (!source_map->HasValidEntry(code_offset, offset)) continue;
929 if (filename.empty()) {
930 filename = source_map->GetFilename(offset);
931 }
932 mapping_info.push_back({static_cast<size_t>(iterator.code_offset()),
933 last_line_number, JitCodeEvent::POSITION});
934 last_line_number = source_map->GetSourceLine(offset) + 1;
935 }
936
937 wasm_source_info = std::make_unique<JitCodeEvent::wasm_source_info_t>();
938 wasm_source_info->filename = filename.c_str();
939 wasm_source_info->filename_size = filename.size();
940 wasm_source_info->line_number_table_size = mapping_info.size();
941 wasm_source_info->line_number_table = mapping_info.data();
942
943 event.wasm_source_info = wasm_source_info.get();
944 }
945 }
946 code_event_handler_(&event);
947}
948#endif // V8_ENABLE_WEBASSEMBLY
949
953
955 if (!from->TryGetCodeUnchecked(&code, kAcquireLoad)) {
956 // Not yet fully initialized and no CodeCreateEvent has been emitted yet.
957 return;
958 }
959
960 JitCodeEvent event;
962 event.code_type = JitCodeEvent::JIT_CODE;
963 event.code_start = reinterpret_cast<void*>(from->instruction_start());
964 event.code_len = code->instruction_size();
965 event.new_code_start = reinterpret_cast<void*>(to->instruction_start());
966 event.isolate = reinterpret_cast<v8::Isolate*>(isolate_);
967
968 code_event_handler_(&event);
969}
970
974
975 JitCodeEvent event;
977 event.code_type = JitCodeEvent::BYTE_CODE;
978 event.code_start = reinterpret_cast<void*>(from->GetFirstBytecodeAddress());
979 event.code_len = from->length();
980 event.new_code_start = reinterpret_cast<void*>(to->GetFirstBytecodeAddress());
981 event.isolate = reinterpret_cast<v8::Isolate*>(isolate_);
982
983 code_event_handler_(&event);
984}
985
987 void* jit_handler_data, int pc_offset, int position,
988 JitCodeEvent::PositionType position_type,
989 JitCodeEvent::CodeType code_type) {
990 JitCodeEvent event;
992 event.code_type = code_type;
993 event.user_data = jit_handler_data;
994 event.line_info.offset = pc_offset;
995 event.line_info.pos = position;
996 event.line_info.position_type = position_type;
997 event.isolate = reinterpret_cast<v8::Isolate*>(isolate_);
998
999 code_event_handler_(&event);
1000}
1001
1003 JitCodeEvent event;
1005 event.code_type = code_type;
1006 event.isolate = reinterpret_cast<v8::Isolate*>(isolate_);
1007
1008 code_event_handler_(&event);
1009 return event.user_data;
1010}
1011
1013 void* jit_handler_data,
1014 JitCodeEvent::CodeType code_type) {
1015 JitCodeEvent event;
1017 event.code_type = code_type;
1018 event.code_start = reinterpret_cast<void*>(start_address);
1019 event.user_data = jit_handler_data;
1020 event.isolate = reinterpret_cast<v8::Isolate*>(isolate_);
1021
1022 code_event_handler_(&event);
1023}
1024
1025// TODO(lpy): Keeping sampling thread inside V8 is a workaround currently,
1026// the reason is to reduce code duplication during migration to sampler library,
1027// sampling thread, as well as the sampler, will be moved to D8 eventually.
1029 public:
1030 static const int kSamplingThreadStackSize = 64 * KB;
1031
1032 SamplingThread(sampler::Sampler* sampler, int interval_microseconds)
1033 : base::Thread(
1034 base::Thread::Options("SamplingThread", kSamplingThreadStackSize)),
1035 sampler_(sampler),
1036 interval_microseconds_(interval_microseconds) {}
1037
1038 void Run() override {
1039 while (sampler_->IsActive()) {
1040 sampler_->DoSample();
1043 }
1044 }
1045
1046 private:
1049};
1050
1051#if defined(V8_ENABLE_ETW_STACK_WALKING)
1052class ETWJitLogger : public JitLogger {
1053 public:
1054 explicit ETWJitLogger(Isolate* isolate)
1055 : JitLogger(isolate, i::ETWJITInterface::EventHandler) {}
1056};
1057#endif // V8_ENABLE_ETW_STACK_WALKING
1058
1059// The Profiler samples pc and sp values for the main thread.
1060// Each sample is appended to a circular buffer.
1061// An independent thread removes data and writes it to the log.
1062// This design minimizes the time spent in the sampler.
1063//
1064class Profiler : public base::Thread {
1065 public:
1066 explicit Profiler(Isolate* isolate);
1067 void Engage();
1068 void Disengage();
1069
1070 // Inserts collected profiling data into buffer.
1071 void Insert(TickSample* sample) {
1072 if (Succ(head_) == static_cast<int>(base::Acquire_Load(&tail_))) {
1074 } else {
1075 buffer_[head_] = *sample;
1076 head_ = Succ(head_);
1077 buffer_semaphore_.Signal(); // Tell we have an element.
1078 }
1079 }
1080
1081 void Run() override;
1082
1083 private:
1084 // Waits for a signal and removes profiling data.
1085 bool Remove(TickSample* sample) {
1086 buffer_semaphore_.Wait(); // Wait for an element.
1087 *sample = buffer_[base::Relaxed_Load(&tail_)];
1090 &tail_, static_cast<base::Atomic32>(Succ(base::Relaxed_Load(&tail_))));
1092 return result;
1093 }
1094
1095 // Returns the next index in the cyclic buffer.
1096 int Succ(int index) { return (index + 1) % kBufferSize; }
1097
1099 // Cyclic buffer for communicating profiling samples
1100 // between the signal handler and the worker thread.
1101 static const int kBufferSize = 128;
1102 TickSample buffer_[kBufferSize]; // Buffer storage.
1103 int head_; // Index to the buffer head.
1104 base::Atomic32 tail_; // Index to the buffer tail.
1105 base::Atomic32 overflow_; // Tell whether a buffer overflow has occurred.
1106 // Semaphore used for buffer synchronization.
1108
1109 // Tells whether worker thread should continue running.
1111};
1112
1113//
1114// Ticker used to provide ticks to the profiler and the sliding state
1115// window.
1116//
1117class Ticker : public sampler::Sampler {
1118 public:
1119 Ticker(Isolate* isolate, int interval_microseconds)
1120 : sampler::Sampler(reinterpret_cast<v8::Isolate*>(isolate)),
1122 std::make_unique<SamplingThread>(this, interval_microseconds)),
1123 perThreadData_(isolate->FindPerThreadDataForThisThread()) {}
1124
1125 ~Ticker() override {
1126 if (IsActive()) Stop();
1127 }
1128
1129 void SetProfiler(Profiler* profiler) {
1131 profiler_ = profiler;
1132 if (!IsActive()) Start();
1133 sampling_thread_->StartSynchronously();
1134 }
1135
1137 profiler_ = nullptr;
1138 if (IsActive()) Stop();
1139 sampling_thread_->Join();
1140 }
1141
1142 void SampleStack(const v8::RegisterState& state) override {
1143 if (!profiler_) return;
1144 Isolate* isolate = reinterpret_cast<Isolate*>(this->isolate());
1145 if (isolate->was_locker_ever_used() &&
1146 (!isolate->thread_manager()->IsLockedByThread(
1148 perThreadData_->thread_state() != nullptr))
1149 return;
1150#if V8_HEAP_USE_PKU_JIT_WRITE_PROTECT
1151 i::RwxMemoryWriteScope::SetDefaultPermissionsForSignalHandler();
1152#endif
1153 TickSample sample;
1154 sample.Init(isolate, state, TickSample::kIncludeCEntryFrame, true);
1155 profiler_->Insert(&sample);
1156 }
1157
1158 private:
1160 std::unique_ptr<SamplingThread> sampling_thread_;
1162};
1163
1164//
1165// Profiler implementation when invoking with --prof.
1166//
1168 : base::Thread(Options("v8:Profiler")),
1169 isolate_(isolate),
1170 head_(0),
1171 buffer_semaphore_(0) {
1175}
1176
1178 std::vector<base::OS::SharedLibraryAddress> addresses =
1180 for (const auto& address : addresses) {
1181 LOG(isolate_, SharedLibraryEvent(address.library_path, address.start,
1182 address.end, address.aslr_slide));
1183 }
1184 LOG(isolate_, SharedLibraryEnd());
1185
1186 // Start thread processing the profiler buffer.
1188 CHECK(Start());
1189
1190 // Register to get ticks.
1192 logger->ticker_->SetProfiler(this);
1193
1194 LOG(isolate_, ProfilerBeginEvent());
1195}
1196
1198 // Stop receiving ticks.
1199 isolate_->v8_file_logger()->ticker_->ClearProfiler();
1200
1201 // Terminate the worker thread by setting running_ to false,
1202 // inserting a fake element in the queue and then wait for
1203 // the thread to terminate.
1205 TickSample sample;
1206 Insert(&sample);
1207 Join();
1208
1209 LOG(isolate_, UncheckedStringEvent("profiler", "end"));
1210}
1211
1213 TickSample sample;
1214 bool overflow = Remove(&sample);
1215 while (base::Relaxed_Load(&running_)) {
1216 LOG(isolate_, TickEvent(&sample, overflow));
1217 overflow = Remove(&sample);
1218 }
1219}
1220
1221//
1222// V8FileLogger class implementation.
1223//
1224#define MSG_BUILDER() \
1225 std::unique_ptr<LogFile::MessageBuilder> msg_ptr = \
1226 log_file_->NewMessageBuilder(); \
1227 if (!msg_ptr) return; \
1228 LogFile::MessageBuilder& msg = *msg_ptr.get();
1229
1231 : isolate_(isolate),
1232 is_logging_(false),
1233 is_initialized_(false),
1234 existing_code_logger_(isolate) {}
1235
1236V8FileLogger::~V8FileLogger() = default;
1237
1239
1241 if (v8_flags.verify_predictable) {
1242 return isolate_->heap()->MonotonicallyIncreasingTimeInMs() * 1000;
1243 }
1244 return timer_.Elapsed().InMicroseconds();
1245}
1246
1247// These logger can be called concurrently, so only update the VMState if
1248// the call is from the main thread.
1249template <StateTag tag>
1251 public:
1252 explicit VMStateIfMainThread(Isolate* isolate) {
1253 if (ThreadId::Current() == isolate->thread_id()) {
1254 vm_state_.emplace(isolate);
1255 }
1256 }
1257
1258 private:
1259 std::optional<VMState<tag>> vm_state_;
1260};
1261
1264 MSG_BUILDER();
1265 msg << "profiler" << kNext << "begin" << kNext
1266 << v8_flags.prof_sampling_interval;
1267 msg.WriteToLogFile();
1268}
1269
1270void V8FileLogger::StringEvent(const char* name, const char* value) {
1271 if (v8_flags.log) UncheckedStringEvent(name, value);
1272}
1273
1274void V8FileLogger::UncheckedStringEvent(const char* name, const char* value) {
1276 MSG_BUILDER();
1277 msg << name << kNext << value;
1278 msg.WriteToLogFile();
1279}
1280
1281void V8FileLogger::IntPtrTEvent(const char* name, intptr_t value) {
1282 if (!v8_flags.log) return;
1284 MSG_BUILDER();
1285 msg << name << kNext;
1286 msg.AppendFormatString("%" V8PRIdPTR, value);
1287 msg.WriteToLogFile();
1288}
1289
1290void V8FileLogger::SharedLibraryEvent(const std::string& library_path,
1291 uintptr_t start, uintptr_t end,
1292 intptr_t aslr_slide) {
1293 if (!v8_flags.prof_cpp) return;
1295 MSG_BUILDER();
1296 msg << "shared-library" << kNext << library_path.c_str() << kNext
1297 << reinterpret_cast<void*>(start) << kNext << reinterpret_cast<void*>(end)
1298 << kNext << aslr_slide;
1299 msg.WriteToLogFile();
1300}
1301
1303 if (!v8_flags.prof_cpp) return;
1305 MSG_BUILDER();
1306 msg << "shared-library-end";
1307 msg.WriteToLogFile();
1308}
1309
1312 DCHECK(v8_flags.log_timer_events);
1313 MSG_BUILDER();
1314 msg << "current-time" << kNext << Time();
1315 msg.WriteToLogFile();
1316}
1317
1320 DCHECK(v8_flags.log_timer_events);
1321 MSG_BUILDER();
1322 switch (se) {
1323 case kStart:
1324 msg << "timer-event-start";
1325 break;
1326 case kEnd:
1327 msg << "timer-event-end";
1328 break;
1329 case kLog:
1330 msg << "timer-event";
1331 }
1332 msg << kNext << name << kNext << Time();
1333 msg.WriteToLogFile();
1334}
1335
1337 // Disable logging while the CPU profiler is running.
1338 if (isolate_->is_profiling()) return false;
1339 return is_logging_.load(std::memory_order_relaxed);
1340}
1341
1342// Instantiate template methods.
1343#define V(TimerName, expose) \
1344 template void TimerEventScope<TimerEvent##TimerName>::LogTimerEvent( \
1345 v8::LogEventStatus se);
1347#undef V
1348
1349void V8FileLogger::NewEvent(const char* name, void* object, size_t size) {
1350 if (!v8_flags.log) return;
1352 MSG_BUILDER();
1353 msg << "new" << kNext << name << kNext << object << kNext
1354 << static_cast<unsigned int>(size);
1355 msg.WriteToLogFile();
1356}
1357
1358void V8FileLogger::DeleteEvent(const char* name, void* object) {
1359 if (!v8_flags.log) return;
1361 MSG_BUILDER();
1362 msg << "delete" << kNext << name << kNext << object;
1363 msg.WriteToLogFile();
1364}
1365
1366namespace {
1367
1368void AppendCodeCreateHeader(LogFile::MessageBuilder& msg,
1370 uint8_t* address, int size, uint64_t time) {
1371 msg << LogEventListener::Event::kCodeCreation << V8FileLogger::kNext << tag
1375}
1376
1377void AppendCodeCreateHeader(Isolate* isolate, LogFile::MessageBuilder& msg,
1379 Tagged<AbstractCode> code, uint64_t time) {
1380 PtrComprCageBase cage_base(isolate);
1381 AppendCodeCreateHeader(
1382 msg, tag, code->kind(cage_base),
1383 reinterpret_cast<uint8_t*>(code->InstructionStart(cage_base)),
1384 code->InstructionSize(cage_base), time);
1385}
1386
1387} // namespace
1388// We log source code information in the form:
1389//
1390// code-source-info <addr>,<script>,<start>,<end>,<pos>,<inline-pos>,<fns>
1391//
1392// where
1393// <addr> is code object address
1394// <script> is script id
1395// <start> is the starting position inside the script
1396// <end> is the end position inside the script
1397// <pos> is source position table encoded in the string,
1398// it is a sequence of C<code-offset>O<script-offset>[I<inlining-id>]
1399// where
1400// <code-offset> is the offset within the code object
1401// <script-offset> is the position within the script
1402// <inlining-id> is the offset in the <inlining> table
1403// <inlining> table is a sequence of strings of the form
1404// F<function-id>O<script-offset>[I<inlining-id>]
1405// where
1406// <function-id> is an index into the <fns> function table
1407// <fns> is the function table encoded as a sequence of strings
1408// S<shared-function-info-address>
1409
1412 PtrComprCageBase cage_base(isolate_);
1413 Tagged<Object> script_object = shared->script(cage_base);
1414 if (!IsScript(script_object, cage_base)) return;
1415 Tagged<Script> script = Cast<Script>(script_object);
1416 EnsureLogScriptSource(script);
1417
1418 if (!v8_flags.log_source_position) return;
1420 MSG_BUILDER();
1421 msg << "code-source-info" << V8FileLogger::kNext
1422 << reinterpret_cast<void*>(code->InstructionStart(cage_base))
1423 << V8FileLogger::kNext << script->id() << V8FileLogger::kNext
1424 << shared->StartPosition() << V8FileLogger::kNext << shared->EndPosition()
1426 // TODO(v8:11429): Clean-up baseline-replated code in source position
1427 // iteration.
1428 bool hasInlined = false;
1429 if (code->kind(cage_base) != CodeKind::BASELINE) {
1431 code->SourcePositionTable(isolate_, *shared));
1432 for (; !iterator.done(); iterator.Advance()) {
1433 SourcePosition pos = iterator.source_position();
1434 msg << "C" << iterator.code_offset() << "O" << pos.ScriptOffset();
1435 if (pos.isInlined()) {
1436 msg << "I" << pos.InliningId();
1437 hasInlined = true;
1438 }
1439 }
1440 }
1441 msg << V8FileLogger::kNext;
1442 int maxInlinedId = -1;
1443 if (hasInlined) {
1444 Tagged<TrustedPodArray<InliningPosition>> inlining_positions =
1445 Cast<DeoptimizationData>(Cast<Code>(code)->deoptimization_data())
1446 ->InliningPositions();
1447 for (int i = 0; i < inlining_positions->length(); i++) {
1448 InliningPosition inlining_pos = inlining_positions->get(i);
1449 msg << "F";
1450 if (inlining_pos.inlined_function_id != -1) {
1451 msg << inlining_pos.inlined_function_id;
1452 if (inlining_pos.inlined_function_id > maxInlinedId) {
1453 maxInlinedId = inlining_pos.inlined_function_id;
1454 }
1455 }
1456 SourcePosition pos = inlining_pos.position;
1457 msg << "O" << pos.ScriptOffset();
1458 if (pos.isInlined()) {
1459 msg << "I" << pos.InliningId();
1460 }
1461 }
1462 }
1463 msg << V8FileLogger::kNext;
1464 if (hasInlined) {
1465 Tagged<DeoptimizationData> deopt_data =
1466 Cast<DeoptimizationData>(Cast<Code>(code)->deoptimization_data());
1467 msg << std::hex;
1468 for (int i = 0; i <= maxInlinedId; i++) {
1469 msg << "S"
1470 << reinterpret_cast<void*>(
1471 deopt_data->GetInlinedFunction(i).address());
1472 }
1473 msg << std::dec;
1474 }
1475 msg.WriteToLogFile();
1476}
1477
1479 if (!v8_flags.log_code_disassemble) return;
1481 PtrComprCageBase cage_base(isolate_);
1482 MSG_BUILDER();
1483 msg << "code-disassemble" << V8FileLogger::kNext
1484 << reinterpret_cast<void*>(code->InstructionStart(cage_base))
1485 << V8FileLogger::kNext << CodeKindToString(code->kind(cage_base))
1487 {
1488 std::ostringstream stream;
1489 if (IsCode(*code, cage_base)) {
1490#ifdef ENABLE_DISASSEMBLER
1491 Cast<Code>(*code)->Disassemble(nullptr, stream, isolate_);
1492#endif
1493 } else {
1494 Cast<BytecodeArray>(*code)->Disassemble(stream);
1495 }
1496 std::string string = stream.str();
1497 msg.AppendString(string.c_str(), string.length());
1498 }
1499 msg.WriteToLogFile();
1500}
1501
1502// Builtins and Bytecode handlers
1504 const char* name) {
1505 if (!is_listening_to_code_events()) return;
1506 if (!v8_flags.log_code) return;
1508 {
1509 MSG_BUILDER();
1510 AppendCodeCreateHeader(isolate_, msg, tag, *code, Time());
1511 msg << name;
1512 msg.WriteToLogFile();
1513 }
1514 LogCodeDisassemble(code);
1515}
1516
1518 DirectHandle<Name> name) {
1519 if (!is_listening_to_code_events()) return;
1520 if (!v8_flags.log_code) return;
1522 {
1523 MSG_BUILDER();
1524 AppendCodeCreateHeader(isolate_, msg, tag, *code, Time());
1525 msg << *name;
1526 msg.WriteToLogFile();
1527 }
1528 LogCodeDisassemble(code);
1529}
1530
1531// Scripts
1534 DirectHandle<Name> script_name) {
1535 if (!is_listening_to_code_events()) return;
1536 if (!v8_flags.log_code) return;
1538 if (*code ==
1539 Cast<AbstractCode>(isolate_->builtins()->code(Builtin::kCompileLazy))) {
1540 return;
1541 }
1542 {
1543 MSG_BUILDER();
1544 AppendCodeCreateHeader(isolate_, msg, tag, *code, Time());
1545 msg << *script_name << kNext << reinterpret_cast<void*>(shared->address())
1546 << kNext << ComputeMarker(*shared, *code);
1547 msg.WriteToLogFile();
1548 }
1549 LogSourceCodeInformation(code, shared);
1550 LogCodeDisassemble(code);
1551}
1552
1554 Tagged<AbstractCode> code) {
1556 if (!v8_flags.log_feedback_vector) return;
1558 PtrComprCageBase cage_base(isolate_);
1559 MSG_BUILDER();
1560 msg << "feedback-vector" << kNext << Time();
1561 msg << kNext << reinterpret_cast<void*>(vector.address()) << kNext
1562 << vector->length();
1563 msg << kNext << reinterpret_cast<void*>(code->InstructionStart(cage_base));
1564#ifndef V8_ENABLE_LEAPTIERING
1565 msg << kNext << vector->tiering_state();
1566 msg << kNext << vector->maybe_has_maglev_code();
1567 msg << kNext << vector->maybe_has_turbofan_code();
1568#endif // !V8_ENABLE_LEAPTIERING
1569 msg << kNext << vector->invocation_count();
1570
1571#ifdef OBJECT_PRINT
1572 std::ostringstream buffer;
1573 vector->FeedbackVectorPrint(buffer);
1574 std::string contents = buffer.str();
1575 msg.AppendString(contents.c_str(), contents.length());
1576#else
1577 msg << "object-printing-disabled";
1578#endif
1579 msg.WriteToLogFile();
1580}
1581
1582// Functions
1583// Although, it is possible to extract source and line from
1584// the SharedFunctionInfo object, we left it to caller
1585// to leave logging functions free from heap allocations.
1588 DirectHandle<Name> script_name, int line,
1589 int column) {
1590 if (!is_listening_to_code_events()) return;
1591 if (!v8_flags.log_code) return;
1593 {
1594 MSG_BUILDER();
1595 AppendCodeCreateHeader(isolate_, msg, tag, *code, Time());
1596 msg << shared->DebugNameCStr().get() << " " << *script_name << ":" << line
1597 << ":" << column << kNext << reinterpret_cast<void*>(shared->address())
1598 << kNext << ComputeMarker(*shared, *code);
1599
1600 msg.WriteToLogFile();
1601 }
1602 LogSourceCodeInformation(code, shared);
1603 LogCodeDisassemble(code);
1604}
1605
1606#if V8_ENABLE_WEBASSEMBLY
1607void V8FileLogger::CodeCreateEvent(CodeTag tag, const wasm::WasmCode* code,
1608 wasm::WasmName name,
1609 const char* /*source_url*/,
1610 int /*code_offset*/, int /*script_id*/) {
1611 if (!is_listening_to_code_events()) return;
1612 if (!v8_flags.log_code) return;
1614 MSG_BUILDER();
1615 AppendCodeCreateHeader(msg, tag, CodeKind::WASM_FUNCTION,
1616 code->instructions().begin(),
1617 code->instructions().length(), Time());
1618 DCHECK(!name.empty());
1619 msg.AppendString(name);
1620
1621 // We have to add two extra fields that allow the tick processor to group
1622 // events for the same wasm function, even if it gets compiled again. For
1623 // normal JS functions, we use the shared function info. For wasm, the pointer
1624 // to the native module + function index works well enough. For Wasm wrappers,
1625 // just use the address of the WasmCode.
1626 // TODO(herhut) Clean up the tick processor code instead.
1627 const void* tag_ptr =
1628 code->native_module() != nullptr
1629 ? reinterpret_cast<uint8_t*>(code->native_module()) + code->index()
1630 : reinterpret_cast<const uint8_t*>(code);
1631
1632 msg << kNext << tag_ptr << kNext << ComputeMarker(code);
1633 msg.WriteToLogFile();
1634}
1635#endif // V8_ENABLE_WEBASSEMBLY
1636
1638 DirectHandle<Name> name,
1639 Address entry_point) {
1640 if (!v8_flags.log_code) return;
1642 MSG_BUILDER();
1643 msg << Event::kCodeCreation << kNext << CodeTag::kCallback << kNext << -2
1645 << kNext << 1 << kNext << prefix << *name;
1646 msg.WriteToLogFile();
1647}
1648
1650 CallbackEventInternal("", name, entry_point);
1651}
1652
1654 Address entry_point) {
1655 CallbackEventInternal("get ", name, entry_point);
1656}
1657
1659 Address entry_point) {
1660 CallbackEventInternal("set ", name, entry_point);
1661}
1662
1664 DirectHandle<String> source,
1665 RegExpFlags flags) {
1666 if (!is_listening_to_code_events()) return;
1667 if (!v8_flags.log_code) return;
1669 MSG_BUILDER();
1670 AppendCodeCreateHeader(isolate_, msg, LogEventListener::CodeTag::kRegExp,
1671 *code, Time());
1672 msg << *source;
1673 msg.WriteToLogFile();
1674}
1675
1678 if (!is_listening_to_code_events()) return;
1679 MoveEventInternal(Event::kCodeMove, from->instruction_start(),
1680 to->instruction_start());
1681}
1682
1685 if (!is_listening_to_code_events()) return;
1686 MoveEventInternal(Event::kCodeMove, from->GetFirstBytecodeAddress(),
1687 to->GetFirstBytecodeAddress());
1688}
1689
1691 if (!is_listening_to_code_events()) return;
1692 MoveEventInternal(Event::kSharedFuncMove, from, to);
1693}
1694
1696 if (!is_listening_to_code_events()) return;
1697 if (!v8_flags.ll_prof) return;
1699}
1700
1703 if (!is_listening_to_code_events()) return;
1704 if (!v8_flags.log_code) return;
1706 MSG_BUILDER();
1707 msg << Event::kCodeDisableOpt << kNext << shared->DebugNameCStr().get()
1708 << kNext << GetBailoutReason(shared->disabled_optimization_reason());
1709 msg.WriteToLogFile();
1710}
1711
1713 SourcePosition position, const char* kind,
1714 const char* reason) {
1716 MSG_BUILDER();
1717 msg << Event::kCodeDeopt << kNext << Time() << kNext
1718 << code->InstructionStreamObjectSize() << kNext
1719 << reinterpret_cast<void*>(code->instruction_start());
1720
1721 std::ostringstream deopt_location;
1722 int inlining_id = -1;
1723 int script_offset = -1;
1724 if (position.IsKnown()) {
1725 position.Print(deopt_location, *code);
1726 inlining_id = position.InliningId();
1727 script_offset = position.ScriptOffset();
1728 } else {
1729 deopt_location << "<unknown>";
1730 }
1731 msg << kNext << inlining_id << kNext << script_offset << kNext;
1732 msg << kind << kNext;
1733 msg << deopt_location.str().c_str() << kNext << reason;
1734 msg.WriteToLogFile();
1735}
1736
1738 Address pc, int fp_to_sp_delta) {
1739 if (!is_logging() || !v8_flags.log_deopt) return;
1742 ProcessDeoptEvent(code, info.position, Deoptimizer::MessageFor(kind),
1743 DeoptimizeReasonToString(info.deopt_reason));
1744}
1745
1748 const char* reason) {
1749 if (!is_logging() || !v8_flags.log_deopt) return;
1751 SourcePosition position(sfi->StartPosition(), -1);
1752 ProcessDeoptEvent(code, position, "dependency-change", reason);
1753}
1754
1755namespace {
1756
1757void CodeLinePosEvent(JitLogger& jit_logger, Address code_start,
1759 JitCodeEvent::CodeType code_type) {
1760 void* jit_handler_data = jit_logger.StartCodePosInfoEvent(code_type);
1761 for (; !iter.done(); iter.Advance()) {
1762 if (iter.is_statement()) {
1763 jit_logger.AddCodeLinePosInfoEvent(jit_handler_data, iter.code_offset(),
1766 code_type);
1767 }
1768 jit_logger.AddCodeLinePosInfoEvent(jit_handler_data, iter.code_offset(),
1770 JitCodeEvent::POSITION, code_type);
1771 }
1772 jit_logger.EndCodePosInfoEvent(code_start, jit_handler_data, code_type);
1773}
1774
1775} // namespace
1776
1778 Address code_start, Tagged<TrustedByteArray> source_position_table,
1779 JitCodeEvent::CodeType code_type) {
1780 if (!jit_logger_) return;
1782 SourcePositionTableIterator iter(source_position_table);
1783 CodeLinePosEvent(*jit_logger_, code_start, iter, code_type);
1784}
1785
1786#if V8_ENABLE_WEBASSEMBLY
1787void V8FileLogger::WasmCodeLinePosInfoRecordEvent(
1788 Address code_start, base::Vector<const uint8_t> source_position_table) {
1789 if (!jit_logger_) return;
1791 SourcePositionTableIterator iter(source_position_table);
1792 CodeLinePosEvent(*jit_logger_, code_start, iter, JitCodeEvent::WASM_CODE);
1793}
1794#endif // V8_ENABLE_WEBASSEMBLY
1795
1796void V8FileLogger::CodeNameEvent(Address addr, int pos, const char* code_name) {
1797 if (code_name == nullptr) return; // Not a code object.
1798 if (!is_listening_to_code_events()) return;
1800 MSG_BUILDER();
1801 msg << Event::kSnapshotCodeName << kNext << pos << kNext << code_name;
1802 msg.WriteToLogFile();
1803}
1804
1806 if (!v8_flags.log_code) return;
1808 MSG_BUILDER();
1809 msg << event << kNext << reinterpret_cast<void*>(from) << kNext
1810 << reinterpret_cast<void*>(to);
1811 msg.WriteToLogFile();
1812}
1813
1814namespace {
1815void AppendFunctionMessage(LogFile::MessageBuilder& msg, const char* reason,
1816 int script_id, double time_delta, int start_position,
1817 int end_position, uint64_t time) {
1818 msg << "function" << V8FileLogger::kNext << reason << V8FileLogger::kNext
1819 << script_id << V8FileLogger::kNext << start_position
1820 << V8FileLogger::kNext << end_position << V8FileLogger::kNext;
1821 if (V8_UNLIKELY(v8_flags.predictable)) {
1822 msg << 0.1;
1823 } else {
1824 msg << time_delta;
1825 }
1826 msg << V8FileLogger::kNext << time << V8FileLogger::kNext;
1827}
1828} // namespace
1829
1830void V8FileLogger::FunctionEvent(const char* reason, int script_id,
1831 double time_delta, int start_position,
1832 int end_position,
1833 Tagged<String> function_name) {
1834 if (!v8_flags.log_function_events) return;
1836 MSG_BUILDER();
1837 AppendFunctionMessage(msg, reason, script_id, time_delta, start_position,
1838 end_position, Time());
1839 if (!function_name.is_null()) msg << function_name;
1840 msg.WriteToLogFile();
1841}
1842
1843void V8FileLogger::FunctionEvent(const char* reason, int script_id,
1844 double time_delta, int start_position,
1845 int end_position, const char* function_name,
1846 size_t function_name_length,
1847 bool is_one_byte) {
1848 if (!v8_flags.log_function_events) return;
1850 MSG_BUILDER();
1851 AppendFunctionMessage(msg, reason, script_id, time_delta, start_position,
1852 end_position, Time());
1853 if (function_name_length > 0) {
1854 msg.AppendString(function_name, function_name_length, is_one_byte);
1855 }
1856 msg.WriteToLogFile();
1857}
1858
1860 const char* cache_type,
1862 if (!v8_flags.log_function_events) return;
1864 MSG_BUILDER();
1865 int script_id = -1;
1866 if (IsScript(sfi->script())) {
1867 script_id = Cast<Script>(sfi->script())->id();
1868 }
1869 msg << "compilation-cache" << V8FileLogger::kNext << action
1870 << V8FileLogger::kNext << cache_type << V8FileLogger::kNext << script_id
1871 << V8FileLogger::kNext << sfi->StartPosition() << V8FileLogger::kNext
1872 << sfi->EndPosition() << V8FileLogger::kNext << Time();
1873 msg.WriteToLogFile();
1874}
1875
1877 if (!v8_flags.log_function_events) return;
1879 MSG_BUILDER();
1880 msg << "script" << V8FileLogger::kNext;
1881 switch (type) {
1883 msg << "reserve-id";
1884 break;
1886 msg << "create";
1887 break;
1889 msg << "deserialize";
1890 break;
1892 msg << "background-compile";
1893 break;
1895 msg << "streaming-compile";
1896 break;
1898 msg << "streaming-compile-foreground";
1899 break;
1900 }
1901 msg << V8FileLogger::kNext << script_id << V8FileLogger::kNext << Time();
1902 msg.WriteToLogFile();
1903}
1904
1906 if (!v8_flags.log_function_events) return;
1908 {
1909 MSG_BUILDER();
1910 msg << "script-details" << V8FileLogger::kNext << script->id()
1912 if (IsString(script->name())) {
1913 msg << Cast<String>(script->name());
1914 }
1915 msg << V8FileLogger::kNext << script->line_offset() << V8FileLogger::kNext
1916 << script->column_offset() << V8FileLogger::kNext;
1917 if (IsString(script->source_mapping_url())) {
1918 msg << Cast<String>(script->source_mapping_url());
1919 }
1920 msg.WriteToLogFile();
1921 }
1922 EnsureLogScriptSource(script);
1923}
1924
1926 if (!v8_flags.log_source_code) return true;
1928 // Make sure the script is written to the log file.
1929 int script_id = script->id();
1930 if (logged_source_code_.find(script_id) != logged_source_code_.end()) {
1931 return true;
1932 }
1933 // This script has not been logged yet.
1934 logged_source_code_.insert(script_id);
1935 Tagged<Object> source_object = script->source();
1936 if (!IsString(source_object)) return false;
1937
1938 std::unique_ptr<LogFile::MessageBuilder> msg_ptr =
1939 log_file_->NewMessageBuilder();
1940 if (!msg_ptr) return false;
1941 LogFile::MessageBuilder& msg = *msg_ptr.get();
1942
1943 Tagged<String> source_code = Cast<String>(source_object);
1944 msg << "script-source" << kNext << script_id << kNext;
1945
1946 // Log the script name.
1947 if (IsString(script->name())) {
1948 msg << Cast<String>(script->name()) << kNext;
1949 } else {
1950 msg << "<unknown>" << kNext;
1951 }
1952
1953 // Log the source code.
1954 msg << source_code;
1955 msg.WriteToLogFile();
1956 return true;
1957}
1958
1960#ifdef V8_RUNTIME_CALL_STATS
1963 RuntimeCallCounter* counter = stats->current_counter();
1964 if (counter == nullptr) return;
1965 MSG_BUILDER();
1966 msg << "active-runtime-timer" << kNext << counter->name();
1967 msg.WriteToLogFile();
1968#endif // V8_RUNTIME_CALL_STATS
1969}
1970
1971void V8FileLogger::TickEvent(TickSample* sample, bool overflow) {
1972 if (!v8_flags.prof_cpp) return;
1974 if (V8_UNLIKELY(TracingFlags::runtime_stats.load(std::memory_order_relaxed) ==
1977 }
1978 MSG_BUILDER();
1979 msg << Event::kTick << kNext << reinterpret_cast<void*>(sample->pc) << kNext
1980 << Time();
1981 if (sample->has_external_callback) {
1982 msg << kNext << 1 << kNext
1983 << reinterpret_cast<void*>(sample->external_callback_entry);
1984 } else {
1985 msg << kNext << 0 << kNext << reinterpret_cast<void*>(sample->tos);
1986 }
1987 msg << kNext << static_cast<int>(sample->state);
1988 if (overflow) msg << kNext << "overflow";
1989 for (unsigned i = 0; i < sample->frames_count; ++i) {
1990 msg << kNext << reinterpret_cast<void*>(sample->stack[i]);
1991 }
1992 msg.WriteToLogFile();
1993}
1994
1995void V8FileLogger::ICEvent(const char* type, bool keyed, DirectHandle<Map> map,
1996 DirectHandle<Object> key, char old_state,
1997 char new_state, const char* modifier,
1998 const char* slow_stub_reason) {
1999 if (!v8_flags.log_ic) return;
2001 int line;
2002 int column;
2003 // GetAbstractPC must come before MSG_BUILDER(), as it can GC, which might
2004 // attempt to get the log lock again and result in a deadlock.
2005 Address pc = isolate_->GetAbstractPC(&line, &column);
2006 MSG_BUILDER();
2007 if (keyed) msg << "Keyed";
2008 msg << type << kNext << reinterpret_cast<void*>(pc) << kNext << Time()
2009 << kNext << line << kNext << column << kNext << old_state << kNext
2010 << new_state << kNext
2011 << AsHex::Address(map.is_null() ? kNullAddress : map->ptr()) << kNext;
2012 if (IsSmi(*key)) {
2013 msg << Smi::ToInt(*key);
2014 } else if (IsNumber(*key)) {
2015 msg << Object::NumberValue(*key);
2016 } else if (IsName(*key)) {
2017 msg << Cast<Name>(*key);
2018 }
2019 msg << kNext << modifier << kNext;
2020 if (slow_stub_reason != nullptr) {
2021 msg << slow_stub_reason;
2022 }
2023 msg.WriteToLogFile();
2024}
2025
2026void V8FileLogger::MapEvent(const char* type, DirectHandle<Map> from,
2027 DirectHandle<Map> to, const char* reason,
2028 DirectHandle<HeapObject> name_or_sfi) {
2029 if (!v8_flags.log_maps) return;
2031 if (!to.is_null()) MapDetails(*to);
2032 int line = -1;
2033 int column = -1;
2034 Address pc = 0;
2035
2036 if (!isolate_->bootstrapper()->IsActive()) {
2037 pc = isolate_->GetAbstractPC(&line, &column);
2038 }
2039 MSG_BUILDER();
2040 msg << "map" << kNext << type << kNext << Time() << kNext
2041 << AsHex::Address(from.is_null() ? kNullAddress : from->ptr()) << kNext
2042 << AsHex::Address(to.is_null() ? kNullAddress : to->ptr()) << kNext
2043 << AsHex::Address(pc) << kNext << line << kNext << column << kNext
2044 << reason << kNext;
2045
2046 if (!name_or_sfi.is_null()) {
2047 if (IsName(*name_or_sfi)) {
2048 msg << Cast<Name>(*name_or_sfi);
2049 } else if (IsSharedFunctionInfo(*name_or_sfi)) {
2051 msg << sfi->DebugNameCStr().get();
2052 msg << " " << sfi->unique_id();
2053 }
2054 }
2055 msg.WriteToLogFile();
2056}
2057
2059 if (!v8_flags.log_maps) return;
2062 MSG_BUILDER();
2063 msg << "map-create" << kNext << Time() << kNext << AsHex::Address(map.ptr());
2064 msg.WriteToLogFile();
2065}
2066
2068 if (!v8_flags.log_maps) return;
2071 MSG_BUILDER();
2072 msg << "map-details" << kNext << Time() << kNext << AsHex::Address(map.ptr())
2073 << kNext;
2074 if (v8_flags.log_maps_details) {
2075 std::ostringstream buffer;
2076 map->PrintMapDetails(buffer);
2077 msg << buffer.str().c_str();
2078 }
2079 msg.WriteToLogFile();
2080}
2081
2083 if (!v8_flags.log_maps) return;
2086 MSG_BUILDER();
2087 msg << "map-move" << kNext << Time() << kNext << AsHex::Address(from.ptr())
2088 << kNext << AsHex::Address(to.ptr());
2089 msg.WriteToLogFile();
2090}
2091
2092static std::vector<std::pair<Handle<SharedFunctionInfo>, Handle<AbstractCode>>>
2094 HeapObjectIterator iterator(heap);
2096 std::vector<std::pair<Handle<SharedFunctionInfo>, Handle<AbstractCode>>>
2097 compiled_funcs;
2098 Isolate* isolate = heap->isolate();
2099 auto hash =
2100 [](const std::pair<Tagged<SharedFunctionInfo>, Tagged<AbstractCode>>& p) {
2101 return base::hash_combine(p.first.address(), p.second.address());
2102 };
2103 std::unordered_set<
2104 std::pair<Tagged<SharedFunctionInfo>, Tagged<AbstractCode>>,
2105 decltype(hash)>
2106 seen(8, hash);
2107
2109 if (auto [iter, inserted] = seen.emplace(sfi, c); inserted)
2110 compiled_funcs.emplace_back(handle(sfi, isolate), handle(c, isolate));
2111 };
2112
2113 // Iterate the heap to find JSFunctions and record their optimized code.
2114 for (Tagged<HeapObject> obj = iterator.Next(); !obj.is_null();
2115 obj = iterator.Next()) {
2116 if (IsSharedFunctionInfo(obj)) {
2118 if (sfi->is_compiled() && !sfi->HasBytecodeArray()) {
2119 record(sfi, Cast<AbstractCode>(sfi->abstract_code(isolate)));
2120 }
2121 } else if (IsJSFunction(obj)) {
2122 // Given that we no longer iterate over all optimized JSFunctions, we need
2123 // to take care of this here.
2124 Tagged<JSFunction> function = Cast<JSFunction>(obj);
2125 // TODO(jarin) This leaves out deoptimized code that might still be on the
2126 // stack. Also note that we will not log optimized code objects that are
2127 // only on a type feedback vector. We should make this more precise.
2128 if (function->HasAttachedOptimizedCode(isolate) &&
2129 Cast<Script>(function->shared()->script())->HasValidSource()) {
2130 record(function->shared(), Cast<AbstractCode>(function->code(isolate)));
2131 }
2132 }
2133 }
2134
2135 Script::Iterator script_iterator(heap->isolate());
2136 for (Tagged<Script> script = script_iterator.Next(); !script.is_null();
2137 script = script_iterator.Next()) {
2138 if (!script->HasValidSource()) continue;
2139
2140 SharedFunctionInfo::ScriptIterator sfi_iterator(heap->isolate(), script);
2141 for (Tagged<SharedFunctionInfo> sfi = sfi_iterator.Next(); !sfi.is_null();
2142 sfi = sfi_iterator.Next()) {
2143 if (sfi->is_compiled()) {
2144 record(sfi, Cast<AbstractCode>(sfi->abstract_code(isolate)));
2145 }
2146 }
2147 }
2148
2149 return compiled_funcs;
2150}
2151
2152#if defined(V8_ENABLE_ETW_STACK_WALKING)
2153static std::vector<Handle<SharedFunctionInfo>> EnumerateInterpretedFunctions(
2154 Heap* heap) {
2155 HeapObjectIterator iterator(heap);
2157 std::vector<Handle<SharedFunctionInfo>> interpreted_funcs;
2158 Isolate* isolate = heap->isolate();
2159
2160 for (Tagged<HeapObject> obj = iterator.Next(); !obj.is_null();
2161 obj = iterator.Next()) {
2162 if (IsSharedFunctionInfo(obj)) {
2164 if (sfi->HasBytecodeArray()) {
2165 interpreted_funcs.push_back(handle(sfi, isolate));
2166 }
2167 }
2168 }
2169
2170 return interpreted_funcs;
2171}
2172
2173void V8FileLogger::LogInterpretedFunctions() {
2174 existing_code_logger_.LogInterpretedFunctions();
2175}
2176
2177void ExistingCodeLogger::LogInterpretedFunctions() {
2179 Heap* heap = isolate_->heap();
2180 HandleScope scope(isolate_);
2181 std::vector<Handle<SharedFunctionInfo>> interpreted_funcs =
2182 EnumerateInterpretedFunctions(heap);
2183 for (Handle<SharedFunctionInfo> sfi : interpreted_funcs) {
2184 if (sfi->HasInterpreterData(isolate_) || !sfi->HasSourceCode() ||
2185 !sfi->HasBytecodeArray()) {
2186 continue;
2187 }
2189 sfi->is_toplevel() ? LogEventListener::CodeTag::kScript
2190 : LogEventListener::CodeTag::kFunction;
2192 }
2193}
2194#endif // V8_ENABLE_ETW_STACK_WALKING
2195
2197
2202
2204 bool ensure_source_positions_available) {
2205 existing_code_logger_.LogCompiledFunctions(ensure_source_positions_available);
2206}
2207
2209
2211 Heap* heap = isolate_->heap();
2212 HeapObjectIterator iterator(heap);
2214 for (Tagged<HeapObject> obj = iterator.Next(); !obj.is_null();
2215 obj = iterator.Next()) {
2216 if (!IsAccessorInfo(obj)) continue;
2218 if (!IsName(ai->name())) continue;
2219 Address getter_entry = ai->getter(isolate_);
2220 HandleScope scope(isolate_);
2222 if (getter_entry != kNullAddress) {
2223#if USES_FUNCTION_DESCRIPTORS
2224 getter_entry = *FUNCTION_ENTRYPOINT_ADDRESS(getter_entry);
2225#endif
2226 PROFILE(isolate_, GetterCallbackEvent(name, getter_entry));
2227 }
2228 Address setter_entry = ai->setter(isolate_);
2229 if (setter_entry != kNullAddress) {
2230#if USES_FUNCTION_DESCRIPTORS
2231 setter_entry = *FUNCTION_ENTRYPOINT_ADDRESS(setter_entry);
2232#endif
2233 PROFILE(isolate_, SetterCallbackEvent(name, setter_entry));
2234 }
2235 }
2236}
2237
2239 Heap* heap = isolate_->heap();
2241 for (Tagged<HeapObject> obj = iterator.Next(); !obj.is_null();
2242 obj = iterator.Next()) {
2243 if (!IsMap(obj)) continue;
2244 Tagged<Map> map = Cast<Map>(obj);
2245 MapCreate(map);
2246 MapDetails(map);
2247 }
2248}
2249
2250static void AddIsolateIdIfNeeded(std::ostream& os, Isolate* isolate) {
2251 if (!v8_flags.logfile_per_isolate) return;
2252 os << "isolate-" << isolate << "-" << base::OS::GetCurrentProcessId() << "-";
2253}
2254
2255static void PrepareLogFileName(std::ostream& os, Isolate* isolate,
2256 const char* file_name) {
2257 int dir_separator_count = 0;
2258 for (const char* p = file_name; *p; p++) {
2259 if (base::OS::isDirectorySeparator(*p)) dir_separator_count++;
2260 }
2261
2262 for (const char* p = file_name; *p; p++) {
2263 if (dir_separator_count == 0) {
2264 AddIsolateIdIfNeeded(os, isolate);
2265 dir_separator_count--;
2266 }
2267 if (*p == '%') {
2268 p++;
2269 switch (*p) {
2270 case '\0':
2271 // If there's a % at the end of the string we back up
2272 // one character so we can escape the loop properly.
2273 p--;
2274 break;
2275 case 'p':
2277 break;
2278 case 't':
2279 // %t expands to the current time in milliseconds.
2281 break;
2282 case '%':
2283 // %% expands (contracts really) to %.
2284 os << '%';
2285 break;
2286 default:
2287 // All other %'s expand to themselves.
2288 os << '%' << *p;
2289 break;
2290 }
2291 } else {
2292 if (base::OS::isDirectorySeparator(*p)) dir_separator_count--;
2293 os << *p;
2294 }
2295 }
2296}
2297
2299 // Tests and EnsureInitialize() can call this twice in a row. It's harmless.
2300 if (is_initialized_) return true;
2301 is_initialized_ = true;
2302
2303 std::ostringstream log_file_name;
2304 PrepareLogFileName(log_file_name, isolate, v8_flags.logfile);
2305 log_file_ = std::make_unique<LogFile>(this, log_file_name.str());
2306
2307#if V8_OS_LINUX
2308 if (v8_flags.perf_basic_prof) {
2309 perf_basic_logger_ = std::make_unique<LinuxPerfBasicLogger>(isolate);
2310 CHECK(logger()->AddListener(perf_basic_logger_.get()));
2311 }
2312
2313 if (v8_flags.perf_prof) {
2314 perf_jit_logger_ = std::make_unique<LinuxPerfJitLogger>(isolate);
2315 CHECK(logger()->AddListener(perf_jit_logger_.get()));
2316 }
2317#else
2318 static_assert(
2319 !v8_flags.perf_prof.value(),
2320 "--perf-prof should be statically disabled on non-Linux platforms");
2321 static_assert(
2322 !v8_flags.perf_basic_prof.value(),
2323 "--perf-basic-prof should be statically disabled on non-Linux platforms");
2324#endif
2325
2326#ifdef ENABLE_GDB_JIT_INTERFACE
2327 if (v8_flags.gdbjit) {
2328 gdb_jit_logger_ =
2329 std::make_unique<JitLogger>(isolate, i::GDBJITInterface::EventHandler);
2330 CHECK(logger()->AddListener(gdb_jit_logger_.get()));
2331 CHECK(isolate->logger()->is_listening_to_code_events());
2332 }
2333#endif // ENABLE_GDB_JIT_INTERFACE
2334
2335 if (v8_flags.ll_prof) {
2336 ll_logger_ =
2337 std::make_unique<LowLevelLogger>(isolate, log_file_name.str().c_str());
2338 CHECK(logger()->AddListener(ll_logger_.get()));
2339 }
2340 ticker_ = std::make_unique<Ticker>(isolate, v8_flags.prof_sampling_interval);
2341 if (v8_flags.log) UpdateIsLogging(true);
2342 timer_.Start();
2343 if (v8_flags.prof_cpp) {
2344 CHECK(v8_flags.log);
2345 CHECK(is_logging());
2346 profiler_ = std::make_unique<Profiler>(isolate);
2347 profiler_->Engage();
2348 }
2349 if (is_logging_) {
2350 CHECK(logger()->AddListener(this));
2351 }
2352 return true;
2353}
2354
2356 if (!isolate->logger()->is_listening_to_code_events()) return;
2358#if V8_ENABLE_WEBASSEMBLY
2360#endif
2361}
2362
2363#if defined(V8_ENABLE_ETW_STACK_WALKING)
2364void V8FileLogger::SetEtwCodeEventHandler(uint32_t options) {
2365 DCHECK(v8_flags.enable_etw_stack_walking ||
2366 v8_flags.enable_etw_by_custom_filter_only);
2368#if V8_ENABLE_WEBASSEMBLY
2370#endif // V8_ENABLE_WEBASSEMBLY
2371
2372 if (!etw_jit_logger_) {
2373 etw_jit_logger_ = std::make_unique<ETWJitLogger>(isolate_);
2374 CHECK(logger()->AddListener(etw_jit_logger_.get()));
2376 // Generate builtins for new isolates always. Otherwise it will not
2377 // traverse the builtins.
2378 options |= kJitCodeEventEnumExisting;
2379 }
2380
2381 if (options & kJitCodeEventEnumExisting) {
2382 // TODO(v8:11043) Here we log the existing code to all the listeners
2383 // registered to this Isolate logger, while we should only log to the newly
2384 // created ETWJitLogger. This should not generally be a problem because it
2385 // is quite unlikely to have both file logger and ETW tracing both enabled
2386 // by default.
2387 HandleScope scope(isolate_);
2388
2389 bool rundown = (options & ETWJITInterface::kEtwRundown);
2390 if (rundown) isolate_->SetETWIsInRundown(true);
2391
2392 LogBuiltins();
2394 LogCompiledFunctions(false);
2396 LogInterpretedFunctions();
2397 }
2398
2399 if (rundown) isolate_->SetETWIsInRundown(false);
2400 }
2401}
2402
2403void V8FileLogger::ResetEtwCodeEventHandler() {
2404 DCHECK(v8_flags.enable_etw_stack_walking ||
2405 v8_flags.enable_etw_by_custom_filter_only);
2406 if (etw_jit_logger_) {
2407 CHECK(logger()->RemoveListener(etw_jit_logger_.get()));
2408 etw_jit_logger_.reset();
2409 }
2410}
2411#endif // V8_ENABLE_ETW_STACK_WALKING
2412
2414 JitCodeEventHandler event_handler) {
2415 if (jit_logger_) {
2416 CHECK(logger()->RemoveListener(jit_logger_.get()));
2417 jit_logger_.reset();
2419 }
2420
2421 if (event_handler) {
2422#if V8_ENABLE_WEBASSEMBLY
2424#endif // V8_ENABLE_WEBASSEMBLY
2425 jit_logger_ = std::make_unique<JitLogger>(isolate_, event_handler);
2427 CHECK(logger()->AddListener(jit_logger_.get()));
2428 if (options & kJitCodeEventEnumExisting) {
2429 HandleScope scope(isolate_);
2430 LogBuiltins();
2433 }
2434 }
2435}
2436
2438std::string V8FileLogger::file_name() const {
2439 return log_file_.get()->file_name();
2440}
2441
2443 if (profiler_ != nullptr) {
2444 profiler_->Disengage();
2445 profiler_.reset();
2446 }
2447}
2448
2450 if (!is_initialized_) return nullptr;
2451 is_initialized_ = false;
2452 UpdateIsLogging(false);
2453
2454 // Stop the profiler thread before closing the file.
2456
2457 ticker_.reset();
2458 timer_.Stop();
2459
2460#if V8_OS_LINUX
2461 if (perf_basic_logger_) {
2462 CHECK(logger()->RemoveListener(perf_basic_logger_.get()));
2463 perf_basic_logger_.reset();
2464 }
2465
2466 if (perf_jit_logger_) {
2467 CHECK(logger()->RemoveListener(perf_jit_logger_.get()));
2468 perf_jit_logger_.reset();
2469 }
2470#endif
2471
2472 if (ll_logger_) {
2473 CHECK(logger()->RemoveListener(ll_logger_.get()));
2474 ll_logger_.reset();
2475 }
2476
2477 if (jit_logger_) {
2478 CHECK(logger()->RemoveListener(jit_logger_.get()));
2479 jit_logger_.reset();
2481 }
2482
2483 return log_file_->Close();
2484}
2485
2487
2489 if (value) {
2491 }
2492 {
2493 base::MutexGuard guard(log_file_->mutex());
2494 // Relaxed atomic to avoid locking the mutex for the most common case: when
2495 // logging is disabled.
2496 is_logging_.store(value, std::memory_order_relaxed);
2497 }
2499}
2500
2502 HandleScope scope(isolate_);
2503 DirectHandle<AbstractCode> abstract_code(object, isolate_);
2504 CodeTag tag = CodeTag::kStub;
2505 const char* description = "Unknown code from before profiling";
2506 PtrComprCageBase cage_base(isolate_);
2507 switch (abstract_code->kind(cage_base)) {
2508 case CodeKind::INTERPRETED_FUNCTION:
2509 case CodeKind::TURBOFAN_JS:
2510 case CodeKind::BASELINE:
2511 case CodeKind::MAGLEV:
2512 return; // We log this later using LogCompiledFunctions.
2513 case CodeKind::FOR_TESTING:
2514 description = "STUB code";
2515 tag = CodeTag::kStub;
2516 break;
2517 case CodeKind::REGEXP:
2518 description = "Regular expression code";
2519 tag = CodeTag::kRegExp;
2520 break;
2521 case CodeKind::BYTECODE_HANDLER:
2522 description =
2523 isolate_->builtins()->name(abstract_code->builtin_id(cage_base));
2524 tag = CodeTag::kBytecodeHandler;
2525 break;
2526 case CodeKind::BUILTIN:
2527 if (abstract_code->has_instruction_stream(cage_base)) {
2528 DCHECK_EQ(abstract_code->builtin_id(cage_base),
2529 Builtin::kInterpreterEntryTrampoline);
2530 // We treat interpreter trampoline builtin copies as
2531 // INTERPRETED_FUNCTION, which are logged using LogCompiledFunctions.
2532 return;
2533 }
2534 description = Builtins::name(abstract_code->builtin_id(cage_base));
2535 tag = CodeTag::kBuiltin;
2536 break;
2537 case CodeKind::WASM_FUNCTION:
2538 description = "A Wasm function";
2539 tag = CodeTag::kFunction;
2540 break;
2541 case CodeKind::JS_TO_WASM_FUNCTION:
2542 description = "A JavaScript to Wasm adapter";
2543 tag = CodeTag::kStub;
2544 break;
2545 case CodeKind::WASM_TO_CAPI_FUNCTION:
2546 description = "A Wasm to C-API adapter";
2547 tag = CodeTag::kStub;
2548 break;
2549 case CodeKind::WASM_TO_JS_FUNCTION:
2550 description = "A Wasm to JavaScript adapter";
2551 tag = CodeTag::kStub;
2552 break;
2553 case CodeKind::C_WASM_ENTRY:
2554 description = "A C to Wasm entry stub";
2555 tag = CodeTag::kStub;
2556 break;
2557 }
2558 CALL_CODE_EVENT_HANDLER(CodeCreateEvent(tag, abstract_code, description))
2559}
2560
2562 Heap* heap = isolate_->heap();
2565 PtrComprCageBase cage_base(isolate_);
2566 for (Tagged<HeapObject> obj = iterator.Next(); !obj.is_null();
2567 obj = iterator.Next()) {
2568 InstanceType instance_type = obj->map(cage_base)->instance_type();
2569 if (InstanceTypeChecker::IsCode(instance_type) ||
2570 InstanceTypeChecker::IsBytecodeArray(instance_type)) {
2572 }
2573 }
2574}
2575
2578 // The main "copy" of used builtins are logged by LogCodeObjects() while
2579 // iterating Code objects.
2580 // TODO(v8:11880): Log other copies of remapped builtins once we
2581 // decide to remap them multiple times into the code range (for example
2582 // for arm64).
2583}
2584
2586 bool ensure_source_positions_available) {
2587 Heap* heap = isolate_->heap();
2588 HandleScope scope(isolate_);
2589 std::vector<std::pair<Handle<SharedFunctionInfo>, Handle<AbstractCode>>>
2590 compiled_funcs = EnumerateCompiledFunctions(heap);
2591
2592 // During iteration, there can be heap allocation due to
2593 // GetScriptLineNumber call.
2594 for (auto& pair : compiled_funcs) {
2595 DirectHandle<SharedFunctionInfo> shared = pair.first;
2596
2597 // If the script is a Smi, then the SharedFunctionInfo is in
2598 // the process of being deserialized.
2599 Tagged<Object> script = shared->raw_script(kAcquireLoad);
2600 if (IsSmi(script)) {
2602 continue;
2603 }
2604
2605 if (ensure_source_positions_available) {
2607 }
2608 if (shared->HasInterpreterData(isolate_)) {
2611 shared->InterpreterTrampoline(isolate_)),
2612 isolate_));
2613 }
2614 if (shared->HasBaselineCode()) {
2616 shared,
2617 direct_handle(Cast<AbstractCode>(shared->baseline_code(kAcquireLoad)),
2618 isolate_));
2619 }
2620 // TODO(saelo): remove the "!IsTrustedSpaceObject" once builtin Code
2621 // objects are also in trusted space. Currently this breaks because we must
2622 // not compare objects in trusted space with ones inside the sandbox.
2623 static_assert(!kAllCodeObjectsLiveInTrustedSpace);
2624 if (!HeapLayout::InTrustedSpace(*pair.second) &&
2625 pair.second.is_identical_to(BUILTIN_CODE(isolate_, CompileLazy))) {
2626 continue;
2627 }
2628 LogExistingFunction(pair.first, pair.second);
2629 }
2630
2631#if V8_ENABLE_WEBASSEMBLY
2632 HeapObjectIterator iterator(heap);
2634
2635 for (Tagged<HeapObject> obj = iterator.Next(); !obj.is_null();
2636 obj = iterator.Next()) {
2637 if (!IsWasmModuleObject(obj)) continue;
2638 auto module_object = Cast<WasmModuleObject>(obj);
2639 module_object->native_module()->LogWasmCodes(isolate_,
2640 module_object->script());
2641 }
2643#endif // V8_ENABLE_WEBASSEMBLY
2644}
2645
2648 CodeTag tag) {
2649 if (IsScript(shared->script())) {
2652 Script::GetPositionInfo(script, shared->StartPosition(), &info);
2653 int line_num = info.line + 1;
2654 int column_num = info.column + 1;
2655 if (IsString(script->name())) {
2656 DirectHandle<String> script_name(Cast<String>(script->name()), isolate_);
2657 if (!shared->is_toplevel()) {
2659 CodeCreateEvent(V8FileLogger::ToNativeByScript(tag, *script), code,
2660 shared, script_name, line_num, column_num))
2661 } else {
2662 // Can't distinguish eval and script here, so always use Script.
2663 CALL_CODE_EVENT_HANDLER(CodeCreateEvent(
2664 V8FileLogger::ToNativeByScript(CodeTag::kScript, *script), code,
2665 shared, script_name))
2666 }
2667 } else {
2668 CALL_CODE_EVENT_HANDLER(CodeCreateEvent(
2669 V8FileLogger::ToNativeByScript(tag, *script), code, shared,
2670 isolate_->factory()->empty_string(), line_num, column_num))
2671 }
2672 } else if (shared->IsApiFunction()) {
2673 // API function.
2674 DirectHandle<FunctionTemplateInfo> fun_data(shared->api_func_data(),
2675 isolate_);
2676 if (fun_data->has_callback(isolate_)) {
2677 Address entry_point = fun_data->callback(isolate_);
2678#if USES_FUNCTION_DESCRIPTORS
2679 entry_point = *FUNCTION_ENTRYPOINT_ADDRESS(entry_point);
2680#endif
2681 DirectHandle<String> fun_name =
2683 CALL_CODE_EVENT_HANDLER(CallbackEvent(fun_name, entry_point))
2684
2685 // Fast API function.
2686 int c_functions_count = fun_data->GetCFunctionsCount();
2687 for (int i = 0; i < c_functions_count; i++) {
2689 CallbackEvent(fun_name, fun_data->GetCFunction(isolate_, i)))
2690 }
2691 }
2692#if V8_ENABLE_WEBASSEMBLY
2693 } else if (shared->HasWasmJSFunctionData()) {
2695 CodeCreateEvent(CodeTag::kFunction, code, "wasm-to-js"));
2696#endif // V8_ENABLE_WEBASSEMBLY
2697 }
2698}
2699
2700#undef CALL_CODE_EVENT_HANDLER
2701#undef MSG_BUILDER
2702
2703} // namespace internal
2704} // namespace v8
Isolate * isolate_
Builtins::Kind kind
Definition builtins.cc:40
#define BUILTIN_CODE(isolate, name)
Definition builtins.h:45
SourcePosition pos
virtual void Handle(CodeEvent *code_event)=0
virtual int64_t CurrentClockTimeMilliseconds()
TimeDelta Elapsed() const
static void Sleep(TimeDelta interval)
static void SignalCodeMovingGC()
static const char *const LogFileOpenMode
Definition platform.h:194
static FILE * FOpen(const char *path, const char *mode)
static int GetCurrentProcessId()
static std::vector< SharedLibraryAddress > GetSharedLibraryAddresses()
static bool isDirectorySeparator(const char ch)
Thread(const Options &options)
V8_WARN_UNUSED_RESULT bool Start()
static constexpr TimeDelta FromMicroseconds(int64_t microseconds)
Definition time.h:87
int64_t InMicroseconds() const
Definition time.cc:251
constexpr T * begin() const
Definition vector.h:96
V8_EXPORT_PRIVATE Tagged< Code > code(Builtin builtin)
Definition builtins.cc:149
bool is_initialized() const
Definition builtins.h:279
static void EmitCodeCreateEvents(Isolate *isolate)
Definition builtins.cc:401
static V8_EXPORT_PRIVATE const char * name(Builtin builtin)
Definition builtins.cc:226
void AppendName(Tagged< Name > name)
Definition log.cc:173
void AppendBytes(const char *bytes)
Definition log.cc:203
static const size_t kUtf16BufferSize
Definition log.cc:239
char utf8_buffer_[kUtf8BufferSize]
Definition log.cc:242
void AppendString(Tagged< String > str)
Definition log.cc:190
static const size_t kUtf8BufferSize
Definition log.cc:238
void AppendBytes(const char *bytes, size_t size)
Definition log.cc:197
void RegExpCodeCreateEvent(DirectHandle< AbstractCode > code, DirectHandle< String > source, RegExpFlags flags) override
Definition log.cc:332
std::unique_ptr< NameBuffer > name_buffer_
Definition log.h:484
bool is_listening_to_code_events() override
Definition log.h:467
void CodeCreateEvent(CodeTag tag, DirectHandle< AbstractCode > code, const char *name) override
Definition log.cc:250
CodeEventLogger(Isolate *isolate)
Definition log.cc:245
virtual void LogRecordedBuffer(Tagged< AbstractCode > code, MaybeDirectHandle< SharedFunctionInfo > maybe_shared, const char *name, size_t length)=0
static void InstallInterpreterTrampolineCopy(Isolate *isolate, DirectHandle< SharedFunctionInfo > shared_info, LogEventListener::CodeTag log_tag)
Definition compiler.cc:681
RuntimeCallStats * runtime_call_stats()
Definition counters.h:633
DeoptInfo GetDeoptInfo() const
Definition deoptimizer.h:64
static const char * MessageFor(DeoptimizeKind kind)
V8_INLINE bool is_null() const
Definition handles.h:693
void LogCompiledFunctions(bool ensure_source_positions_available=true)
Definition log.cc:2585
void LogExistingFunction(DirectHandle< SharedFunctionInfo > shared, DirectHandle< AbstractCode > code, LogEventListener::CodeTag tag=LogEventListener::CodeTag::kFunction)
Definition log.cc:2646
void LogCodeObject(Tagged< AbstractCode > object)
Definition log.cc:2501
void StartListening(v8::CodeEventHandler *code_event_handler)
Definition log.cc:501
void CodeMoveEvent(Tagged< InstructionStream > from, Tagged< InstructionStream > to) override
Definition log.cc:655
void RegExpCodeCreateEvent(DirectHandle< AbstractCode > code, DirectHandle< String > source, RegExpFlags flags) override
Definition log.cc:617
void BytecodeMoveEvent(Tagged< BytecodeArray > from, Tagged< BytecodeArray > to) override
Definition log.cc:664
void CodeCreateEvent(CodeTag tag, DirectHandle< AbstractCode > code, const char *comment) override
Definition log.cc:522
ExternalLogEventListener(Isolate *isolate)
Definition log.cc:484
v8::CodeEventHandler * code_event_handler_
Definition log.h:556
static V8_INLINE bool InTrustedSpace(Tagged< HeapObject > object)
Tagged< HeapObject > Next()
Definition heap.cc:6658
V8_EXPORT_PRIVATE double MonotonicallyIncreasingTimeInMs() const
Definition heap.cc:4098
void UpdateLogObjectRelocation()
Definition isolate.cc:4383
void CollectSourcePositionsForAllBytecodeArrays()
Definition isolate.cc:7184
Counters * counters()
Definition isolate.h:1180
Logger * logger() const
Definition isolate.h:1508
bool was_locker_ever_used() const
Definition isolate.h:1729
Bootstrapper * bootstrapper()
Definition isolate.h:1178
bool is_profiling() const
Definition isolate.h:1476
Address GetAbstractPC(int *line, int *column)
Definition isolate.cc:1539
bool interpreted_frames_native_stack() const
Definition isolate.h:2066
Builtins * builtins()
Definition isolate.h:1443
V8FileLogger * v8_file_logger() const
Definition isolate.h:1192
v8::internal::Factory * factory()
Definition isolate.h:1527
static V8_EXPORT_PRIVATE DirectHandle< String > StringFromFlags(Isolate *isolate, Flags flags)
Definition js-regexp.cc:144
static constexpr Flags AsJSRegExpFlags(RegExpFlags f)
Definition js-regexp.h:54
JitCodeEventHandler code_event_handler_
Definition log.cc:862
void CodeMoveEvent(Tagged< InstructionStream > from, Tagged< InstructionStream > to) override
Definition log.cc:950
void AddCodeLinePosInfoEvent(void *jit_handler_data, int pc_offset, int position, JitCodeEvent::PositionType position_type, JitCodeEvent::CodeType code_type)
Definition log.cc:986
void CodeDisableOptEvent(DirectHandle< AbstractCode > code, DirectHandle< SharedFunctionInfo > shared) override
Definition log.cc:842
JitLogger(Isolate *isolate, JitCodeEventHandler code_event_handler)
Definition log.cc:866
base::Mutex logger_mutex_
Definition log.cc:863
void BytecodeMoveEvent(Tagged< BytecodeArray > from, Tagged< BytecodeArray > to) override
Definition log.cc:971
void * StartCodePosInfoEvent(JitCodeEvent::CodeType code_type)
Definition log.cc:1002
void LogRecordedBuffer(Tagged< AbstractCode > code, MaybeDirectHandle< SharedFunctionInfo > maybe_shared, const char *name, size_t length) override
Definition log.cc:871
void EndCodePosInfoEvent(Address start_address, void *jit_handler_data, JitCodeEvent::CodeType code_type)
Definition log.cc:1012
void AppendString(Tagged< String > str, std::optional< int > length_limit=std::nullopt)
Definition log-file.cc:112
bool is_listening_to_code_events()
bool AddListener(LogEventListener *listener)
bool RemoveListener(LogEventListener *listener)
static const char kLogExt[]
Definition log.cc:715
void LogWriteBytes(const char *bytes, size_t size)
Definition log.cc:822
LowLevelLogger(Isolate *isolate, const char *file_name)
Definition log.cc:732
static const char kCodeMovingGCTag
Definition log.cc:712
void CodeMovingGCEvent() override
Definition log.cc:828
void BytecodeMoveEvent(Tagged< BytecodeArray > from, Tagged< BytecodeArray > to) override
Definition log.cc:814
void SnapshotPositionEvent(Tagged< HeapObject > obj, int pos)
~LowLevelLogger() override
Definition log.cc:746
void LogRecordedBuffer(Tagged< AbstractCode > code, MaybeDirectHandle< SharedFunctionInfo > maybe_shared, const char *name, size_t length) override
Definition log.cc:776
void CodeMoveEvent(Tagged< InstructionStream > from, Tagged< InstructionStream > to) override
Definition log.cc:806
void LogWriteStruct(const T &s)
Definition log.cc:721
void CodeDisableOptEvent(DirectHandle< AbstractCode > code, DirectHandle< SharedFunctionInfo > shared) override
Definition log.cc:682
V8_WARN_UNUSED_RESULT V8_INLINE bool ToHandle(DirectHandle< S > *out) const
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< String > ToFunctionName(Isolate *isolate, DirectHandle< Name > name)
Definition objects.cc:4049
static double NumberValue(Tagged< Number > obj)
base::Atomic32 running_
Definition log.cc:1110
static const int kBufferSize
Definition log.cc:1101
base::Atomic32 tail_
Definition log.cc:1104
Profiler(Isolate *isolate)
Definition log.cc:1167
void Run() override
Definition log.cc:1212
base::Semaphore buffer_semaphore_
Definition log.cc:1107
Isolate * isolate_
Definition log.cc:1098
base::Atomic32 overflow_
Definition log.cc:1105
TickSample buffer_[kBufferSize]
Definition log.cc:1102
int Succ(int index)
Definition log.cc:1096
void Insert(TickSample *sample)
Definition log.cc:1071
bool Remove(TickSample *sample)
Definition log.cc:1085
static const int kSamplingThreadStackSize
Definition log.cc:1030
sampler::Sampler * sampler_
Definition log.cc:1047
void Run() override
Definition log.cc:1038
SamplingThread(sampler::Sampler *sampler, int interval_microseconds)
Definition log.cc:1032
const int interval_microseconds_
Definition log.cc:1048
Tagged< Script > Next()
Definition objects.cc:4795
static bool GetPositionInfo(DirectHandle< Script > script, int position, PositionInfo *info, OffsetFlag offset_flag=OffsetFlag::kWithOffset)
Definition objects.cc:4367
V8_EXPORT_PRIVATE Tagged< SharedFunctionInfo > Next()
static void EnsureSourcePositionsAvailable(Isolate *isolate, DirectHandle< SharedFunctionInfo > shared_info)
static Handle< String > DebugName(Isolate *isolate, DirectHandle< SharedFunctionInfo > shared)
static constexpr int ToInt(const Tagged< Object > object)
Definition smi.h:33
static constexpr Tagged< Smi > uninitialized_deserialization_value()
Definition smi.h:114
V8_INLINE constexpr bool is_null() const
Definition tagged.h:502
static ThreadId Current()
Definition thread-id.h:32
Isolate::PerIsolateThreadData * perThreadData_
Definition log.cc:1161
Profiler * profiler_
Definition log.cc:1159
std::unique_ptr< SamplingThread > sampling_thread_
Definition log.cc:1160
void SampleStack(const v8::RegisterState &state) override
Definition log.cc:1142
void SetProfiler(Profiler *profiler)
Definition log.cc:1129
~Ticker() override
Definition log.cc:1125
Ticker(Isolate *isolate, int interval_microseconds)
Definition log.cc:1119
void ClearProfiler()
Definition log.cc:1136
V8_EXPORT_PRIVATE std::string file_name() const
Definition log.cc:2438
std::set< int > logged_source_code_
Definition log.h:378
void SetterCallbackEvent(DirectHandle< Name > name, Address entry_point) override
Definition log.cc:1658
void MapCreate(Tagged< Map > map)
Definition log.cc:2058
void MapMoveEvent(Tagged< Map > from, Tagged< Map > to)
Definition log.cc:2082
Logger * logger() const
Definition log.cc:2486
void IntPtrTEvent(const char *name, intptr_t value)
Definition log.cc:1281
V8_EXPORT_PRIVATE bool is_logging()
Definition log.cc:1336
std::unique_ptr< Ticker > ticker_
Definition log.h:354
void LogCodeDisassemble(DirectHandle< AbstractCode > code)
Definition log.cc:1478
void CodeDependencyChangeEvent(DirectHandle< Code > code, DirectHandle< SharedFunctionInfo > sfi, const char *reason) override
Definition log.cc:1746
void CodeDisableOptEvent(DirectHandle< AbstractCode > code, DirectHandle< SharedFunctionInfo > shared) override
Definition log.cc:1701
void FeedbackVectorEvent(Tagged< FeedbackVector > vector, Tagged< AbstractCode > code)
Definition log.cc:1553
void DeleteEvent(const char *name, void *object)
Definition log.cc:1358
std::unique_ptr< JitLogger > jit_logger_
Definition log.h:371
V8_EXPORT_PRIVATE void StopProfilerThread()
Definition log.cc:2442
void MapDetails(Tagged< Map > map)
Definition log.cc:2067
std::unique_ptr< Profiler > profiler_
Definition log.h:359
void BytecodeMoveEvent(Tagged< BytecodeArray > from, Tagged< BytecodeArray > to) override
Definition log.cc:1683
void MoveEventInternal(Event event, Address from, Address to)
Definition log.cc:1805
void CompilationCacheEvent(const char *action, const char *cache_type, Tagged< SharedFunctionInfo > sfi)
Definition log.cc:1859
std::atomic< bool > is_logging_
Definition log.h:364
V8_EXPORT_PRIVATE FILE * TearDownAndGetLogFile()
Definition log.cc:2449
void RegExpCodeCreateEvent(DirectHandle< AbstractCode > code, DirectHandle< String > source, RegExpFlags flags) override
Definition log.cc:1663
bool is_listening_to_code_events() override
Definition log.h:272
void LogExistingFunction(DirectHandle< SharedFunctionInfo > shared, DirectHandle< AbstractCode > code)
Definition log.cc:2198
void ScriptEvent(ScriptEventType type, int script_id)
Definition log.cc:1876
V8_EXPORT_PRIVATE void LogAccessorCallbacks()
Definition log.cc:2210
bool EnsureLogScriptSource(Tagged< Script > script)
Definition log.cc:1925
void UncheckedStringEvent(const char *name, const char *value)
Definition log.cc:1274
V8_EXPORT_PRIVATE void LogCompiledFunctions(bool ensure_source_positions_available=true)
Definition log.cc:2203
void CodeMoveEvent(Tagged< InstructionStream > from, Tagged< InstructionStream > to) override
Definition log.cc:1676
void CodeDeoptEvent(DirectHandle< Code > code, DeoptimizeKind kind, Address pc, int fp_to_sp_delta) override
Definition log.cc:1737
void CallbackEvent(DirectHandle< Name > name, Address entry_point) override
Definition log.cc:1649
void SharedFunctionInfoMoveEvent(Address from, Address to) override
Definition log.cc:1690
void LateSetup(Isolate *isolate)
Definition log.cc:2355
void CodeNameEvent(Address addr, int pos, const char *code_name)
Definition log.cc:1796
V8_EXPORT_PRIVATE void LogBuiltins()
Definition log.cc:2208
sampler::Sampler * sampler()
Definition log.cc:2437
void ProcessDeoptEvent(DirectHandle< Code > code, SourcePosition position, const char *kind, const char *reason)
Definition log.cc:1712
void UpdateIsLogging(bool value)
Definition log.cc:2488
void SetCodeEventHandler(uint32_t options, JitCodeEventHandler event_handler)
Definition log.cc:2413
void SharedLibraryEvent(const std::string &library_path, uintptr_t start, uintptr_t end, intptr_t aslr_slide)
Definition log.cc:1290
V8_EXPORT_PRIVATE void TimerEvent(v8::LogEventStatus se, const char *name)
Definition log.cc:1318
void MapEvent(const char *type, DirectHandle< Map > from, DirectHandle< Map > to, const char *reason=nullptr, DirectHandle< HeapObject > name_or_sfi=DirectHandle< HeapObject >())
Definition log.cc:2026
bool SetUp(Isolate *isolate)
Definition log.cc:2298
void TickEvent(TickSample *sample, bool overflow)
Definition log.cc:1971
std::unique_ptr< LogFile > log_file_
Definition log.h:365
void FunctionEvent(const char *reason, int script_id, double time_delta_ms, int start_position, int end_position, Tagged< String > function_name)
Definition log.cc:1830
void CodeLinePosInfoRecordEvent(Address code_start, Tagged< TrustedByteArray > source_position_table, JitCodeEvent::CodeType code_type)
Definition log.cc:1777
void ScriptDetails(Tagged< Script > script)
Definition log.cc:1905
void CodeCreateEvent(CodeTag tag, DirectHandle< AbstractCode > code, const char *name) override
Definition log.cc:1503
void ICEvent(const char *type, bool keyed, DirectHandle< Map > map, DirectHandle< Object > key, char old_state, char new_state, const char *modifier, const char *slow_stub_reason)
Definition log.cc:1995
V8_EXPORT_PRIVATE void StringEvent(const char *name, const char *value)
Definition log.cc:1270
void NewEvent(const char *name, void *object, size_t size)
Definition log.cc:1349
V8_EXPORT_PRIVATE void LogCodeObjects()
Definition log.cc:2196
static const LogSeparator kNext
Definition log.h:122
void GetterCallbackEvent(DirectHandle< Name > name, Address entry_point) override
Definition log.cc:1653
void LogSourceCodeInformation(DirectHandle< AbstractCode > code, DirectHandle< SharedFunctionInfo > shared)
Definition log.cc:1410
V8FileLogger(Isolate *isolate)
Definition log.cc:1230
std::unique_ptr< LowLevelLogger > ll_logger_
Definition log.h:370
void CodeMovingGCEvent() override
Definition log.cc:1695
void CallbackEventInternal(const char *prefix, DirectHandle< Name > name, Address entry_point)
Definition log.cc:1637
base::ElapsedTimer timer_
Definition log.h:387
ExistingCodeLogger existing_code_logger_
Definition log.h:385
static V8_INLINE CodeTag ToNativeByScript(CodeTag tag, Tagged< Script > script)
Definition log-inl.h:18
static V8_EXPORT_PRIVATE v8::Platform * GetCurrentPlatform()
Definition v8.cc:282
VMStateIfMainThread(Isolate *isolate)
Definition log.cc:1252
std::optional< VMState< tag > > vm_state_
Definition log.cc:1259
size_t GetSourceLine(size_t wasm_offset) const
bool HasValidEntry(size_t start, size_t addr) const
bool HasSource(size_t start, size_t end) const
std::string GetFilename(size_t wasm_offset) const
bool IsActive() const
Definition sampler.h:55
Isolate * isolate() const
Definition sampler.h:43
Sampler(Isolate *isolate)
Definition sampler.cc:568
#define CODE_TYPE_LIST(V)
Definition code-events.h:44
#define PROFILE(the_isolate, Call)
Definition code-events.h:59
#define LOG_EVENT_LIST(V)
Definition code-events.h:33
Handle< Code > code
int start
Handle< SharedFunctionInfo > info
int end
std::string filename
int32_t offset
SharedFunctionInfoRef shared
TimeRecord time
DurationRecord record
ZoneVector< RpoNumber > & result
LiftoffAssembler::CacheState state
int pc_offset
Point to
int position
Definition liveedit.cc:290
#define MSG_BUILDER()
Definition log.cc:1224
#define DECLARE_EVENT(ignore1, name)
#define CALL_CODE_EVENT_HANDLER(Call)
Definition log.cc:122
#define LOG(isolate, Call)
Definition log.h:78
#define TIMER_EVENTS_LIST(V)
Definition log.h:390
InstructionOperand source
#define LAZY_RECURSIVE_MUTEX_INITIALIZER
Definition mutex.h:180
STL namespace.
void Relaxed_Store(volatile Atomic8 *ptr, Atomic8 value)
Definition atomicops.h:189
LazyStaticInstance< RecursiveMutex, DefaultConstructTrait< RecursiveMutex >, ThreadSafeInitOnceTrait >::type LazyRecursiveMutex
Definition mutex.h:176
V8_INLINE size_t hash_combine(size_t seed, size_t hash)
Definition hashing.h:77
Atomic8 Relaxed_Load(volatile const Atomic8 *ptr)
Definition atomicops.h:234
int SNPrintF(Vector< char > str, const char *format,...)
Definition strings.cc:20
int Fclose(FILE *stream)
Definition wrappers.h:22
Atomic8 Acquire_Load(volatile const Atomic8 *ptr)
Definition atomicops.h:249
void Release_Store(volatile Atomic8 *ptr, Atomic8 value)
Definition atomicops.h:204
int32_t Atomic32
Definition atomicops.h:59
constexpr uint32_t kEtwRundown
Definition etw-jit-win.h:27
WasmImportWrapperCache * GetWasmImportWrapperCache()
WasmEngine * GetWasmEngine()
V8_INLINE IndirectHandle< T > handle(Tagged< T > object, Isolate *isolate)
Definition handles-inl.h:72
PerThreadAssertScopeDebugOnly< false, SAFEPOINTS_ASSERT, HEAP_ALLOCATION_ASSERT > DisallowGarbageCollection
const char * CodeKindToMarker(CodeKind kind, bool context_specialized)
Definition code-kind.cc:21
bool IsNumber(Tagged< Object > obj)
const char * CodeKindToString(CodeKind kind)
Definition code-kind.cc:10
static void PrepareLogFileName(std::ostream &os, Isolate *isolate, const char *file_name)
Definition log.cc:2255
Tagged(T object) -> Tagged< T >
char const * DeoptimizeReasonToString(DeoptimizeReason reason)
V8_INLINE constexpr bool IsSmi(TaggedImpl< kRefType, StorageType > obj)
Definition objects.h:665
kInterpreterTrampolineOffset Tagged< HeapObject >
V8_INLINE DirectHandle< T > direct_handle(Tagged< T > object, Isolate *isolate)
too high values may cause the compiler to set high thresholds for inlining to as much as possible avoid inlined allocation of objects that cannot escape trace load stores from virtual maglev objects use TurboFan fast string builder analyze liveness of environment slots and zap dead values trace TurboFan load elimination emit data about basic block usage in builtins to this enable builtin reordering when run mksnapshot flag for emit warnings when applying builtin profile data verify register allocation in TurboFan randomly schedule instructions to stress dependency tracking enable store store elimination in TurboFan rewrite far to near simulate GC compiler thread race related to allow float parameters to be passed in simulator mode JS Wasm Run additional turbo_optimize_inlined_js_wasm_wrappers enable experimental feedback collection in generic lowering enable Turboshaft s WasmLoadElimination enable Turboshaft s low level load elimination for JS enable Turboshaft s escape analysis for string concatenation use enable Turbolev features that we want to ship in the not too far future trace individual Turboshaft reduction steps trace intermediate Turboshaft reduction steps invocation count threshold for early optimization Enables optimizations which favor memory size over execution speed Enables sampling allocation profiler with X as a sample interval min size of a semi the new space consists of two semi spaces max size of the Collect garbage after Collect garbage after keeps maps alive for< n > old space garbage collections print one detailed trace line in name
Definition flags.cc:2086
std::ostream & operator<<(std::ostream &os, AtomicMemoryOrder order)
static void AddIsolateIdIfNeeded(std::ostream &os, Isolate *isolate)
Definition log.cc:2250
static const char * kLogEventsNames[]
Definition log.cc:71
V8_INLINE PtrComprCageBase GetPtrComprCageBase()
const char * GetBailoutReason(BailoutReason reason)
constexpr bool CodeKindIsBuiltinOrJSFunction(CodeKind kind)
Definition code-kind.h:79
refactor address components for immediate indexing make OptimizeMaglevOnNextCall optimize to turbofan instead of maglev filter for tracing turbofan compilation trace turbo cfg trace TurboFan s graph trimmer trace TurboFan s control equivalence trace TurboFan s register allocator trace stack load store counters for optimized code in run fuzzing &&concurrent_recompilation trace_turbo trace_turbo_scheduled trace_turbo_stack_accesses verify TurboFan machine graph of code stubs enable FixedArray bounds checks print TurboFan statistics of wasm compilations maximum cumulative size of bytecode considered for inlining scale factor of bytecode size used to calculate the inlining budget * KB
Definition flags.cc:1366
V8_EXPORT_PRIVATE FlagValues v8_flags
static std::vector< std::pair< Handle< SharedFunctionInfo >, Handle< AbstractCode > > > EnumerateCompiledFunctions(Heap *heap)
Definition log.cc:2093
static const char * kCodeTagNames[]
Definition log.cc:76
return value
Definition map-inl.h:893
constexpr bool kAllCodeObjectsLiveInTrustedSpace
static constexpr Address kNullAddress
Definition v8-internal.h:53
constexpr int kMaxInt
Definition globals.h:374
void MemCopy(void *dest, const void *src, size_t size)
Definition memcopy.h:124
kInterpreterTrampolineOffset script
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
@ kJitCodeEventEnumExisting
void(*)(const JitCodeEvent *event) JitCodeEventHandler
LogEventStatus
@ kStart
Local< T > Handle
v8::Local< T > ToApiHandle(v8::internal::DirectHandle< v8::internal::Object > obj)
Definition api.h:297
static constexpr AcquireLoadTag kAcquireLoad
Definition globals.h:2908
CodeEventType
base::Vector< const char > contents
#define DCHECK_NULL(val)
Definition logging.h:491
#define CHECK(condition)
Definition logging.h:124
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define CHECK_NULL(val)
#define CHECK_NOT_NULL(val)
#define CHECK_NE(lhs, rhs)
#define DCHECK_GE(v1, v2)
Definition logging.h:488
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define USE(...)
Definition macros.h:293
#define V8PRIdPTR
Definition macros.h:332
#define V8PRIxPTR
Definition macros.h:331
static AsHex Address(Address a)
Definition ostreams.h:142
DirectHandle< String > script_name
Definition log.h:492
CodeEventType code_type
Definition log.h:495
uintptr_t code_start_address
Definition log.h:489
DirectHandle< String > function_name
Definition log.h:491
const char * comment
Definition log.h:496
void Init(Isolate *isolate, const v8::RegisterState &state, RecordCEntryFrame record_c_entry_frame, bool update_stats, bool use_simulator_reg_state=true, base::TimeDelta sampling_interval=base::TimeDelta(), const std::optional< uint64_t > trace_id=std::nullopt)
static V8_EXPORT_PRIVATE std::atomic_uint runtime_stats
#define V8_UNLIKELY(condition)
Definition v8config.h:660