1// Copyright 2012 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#ifndef V8_LOGGING_LOG_H_ 6#define V8_LOGGING_LOG_H_ 7 8#include <atomic> 9#include <memory> 10#include <set> 11#include <string> 12 13#include "include/v8-callbacks.h" 14#include "include/v8-profiler.h" 15#include "src/base/platform/elapsed-timer.h" 16#include "src/execution/isolate.h" 17#include "src/logging/code-events.h" 18#include "src/objects/objects.h" 19 20namespace v8 { 21 22namespace sampler { 23class Sampler; 24} // namespace sampler 25 26namespace internal { 27 28struct TickSample; 29 30// Logger is used for collecting logging information from V8 during 31// execution. The result is dumped to a file. 32// 33// Available command line flags: 34// 35// --log 36// Minimal logging (no API, code, or GC sample events), default is off. 37// 38// --log-all 39// Log all events to the file, default is off. This is the same as combining 40// --log-api and --log-code. 41// 42// --log-api 43// Log API events to the logfile, default is off. --log-api implies --log. 44// 45// --log-code 46// Log code (create, move, and delete) events to the logfile, default is off. 47// --log-code implies --log. 48// 49// --logfile <filename> 50// Specify the name of the logfile, default is "v8.log". 51// 52// --prof 53// Collect statistical profiling information (ticks), default is off. The 54// tick profiler requires code events, so --prof implies --log-code. 55// 56// --prof-sampling-interval <microseconds> 57// The interval between --prof samples, default is 1000 microseconds (5000 on 58// Android). 59 60// Forward declarations. 61class CodeEventListener; 62class Isolate; 63class JitLogger; 64class Log; 65class LowLevelLogger; 66class PerfBasicLogger; 67class PerfJitLogger; 68class Profiler; 69class SourcePosition; 70class Ticker; 71 72#undef LOG 73#define LOG(isolate, Call) \ 74 do { \ 75 if (v8::internal::FLAG_log) (isolate)->logger()->Call; \ 76 } while (false) 77 78#define LOG_CODE_EVENT(isolate, Call) \ 79 do { \ 80 auto&& logger = (isolate)->logger(); \ 81 if (logger->is_listening_to_code_events()) logger->Call; \ 82 } while (false) 83 84class ExistingCodeLogger { 85 public: 86 explicit ExistingCodeLogger(Isolate* isolate, 87 CodeEventListener* listener = nullptr) 88 : isolate_(isolate), listener_(listener) {} 89 90 void LogCodeObjects(); 91 void LogBuiltins(); 92 93 void LogCompiledFunctions(); 94 void LogExistingFunction(Handle<SharedFunctionInfo> shared, 95 Handle<AbstractCode> code, 96 CodeEventListener::LogEventsAndTags tag = 97 CodeEventListener::FUNCTION_TAG); 98 void LogCodeObject(Object object); 99 100 private: 101 Isolate* isolate_; 102 CodeEventListener* listener_; 103}; 104 105enum class LogSeparator; 106 107class Logger : public CodeEventListener { 108 public: 109 enum class ScriptEventType { 110 kReserveId, 111 kCreate, 112 kDeserialize, 113 kBackgroundCompile, 114 kStreamingCompile 115 }; 116 117 explicit Logger(Isolate* isolate); 118 ~Logger() override; 119 120 // The separator is used to write an unescaped "," into the log. 121 static const LogSeparator kNext; 122 123 // Acquires resources for logging if the right flags are set. 124 bool SetUp(Isolate* isolate); 125 126 // Additional steps taken after the logger has been set up. 127 void LateSetup(Isolate* isolate); 128 129 // Frees resources acquired in SetUp. 130 // When a temporary file is used for the log, returns its stream descriptor, 131 // leaving the file open. 132 V8_EXPORT_PRIVATE FILE* TearDownAndGetLogFile(); 133 134 // Sets the current code event handler. 135 void SetCodeEventHandler(uint32_t options, JitCodeEventHandler event_handler); 136 137 sampler::Sampler* sampler(); 138 V8_EXPORT_PRIVATE std::string file_name() const; 139 140 V8_EXPORT_PRIVATE void StopProfilerThread(); 141 142 // Emits an event with a string value -> (name, value). 143 V8_EXPORT_PRIVATE void StringEvent(const char* name, const char* value); 144 145 // Emits an event with an int value -> (name, value). 146 void IntPtrTEvent(const char* name, intptr_t value); 147 148 // Emits memory management events for C allocated structures. 149 void NewEvent(const char* name, void* object, size_t size); 150 void DeleteEvent(const char* name, void* object); 151 152 // ==== Events logged by --log-function-events ==== 153 void FunctionEvent(const char* reason, int script_id, double time_delta_ms, 154 int start_position, int end_position, 155 String function_name); 156 void FunctionEvent(const char* reason, int script_id, double time_delta_ms, 157 int start_position, int end_position, 158 const char* function_name = nullptr, 159 size_t function_name_length = 0, bool is_one_byte = true); 160 161 void CompilationCacheEvent(const char* action, const char* cache_type, 162 SharedFunctionInfo sfi); 163 void ScriptEvent(ScriptEventType type, int script_id); 164 void ScriptDetails(Script script); 165 166 // ==== Events logged by --log-code. ==== 167 V8_EXPORT_PRIVATE void AddCodeEventListener(CodeEventListener* listener); 168 V8_EXPORT_PRIVATE void RemoveCodeEventListener(CodeEventListener* listener); 169 170 // CodeEventListener implementation. 171 void CodeCreateEvent(LogEventsAndTags tag, Handle<AbstractCode> code, 172 const char* name) override; 173 void CodeCreateEvent(LogEventsAndTags tag, Handle<AbstractCode> code, 174 Handle<Name> name) override; 175 void CodeCreateEvent(LogEventsAndTags tag, Handle<AbstractCode> code, 176 Handle<SharedFunctionInfo> shared, 177 Handle<Name> script_name) override; 178 void CodeCreateEvent(LogEventsAndTags tag, Handle<AbstractCode> code, 179 Handle<SharedFunctionInfo> shared, 180 Handle<Name> script_name, int line, int column) override; 181#if V8_ENABLE_WEBASSEMBLY 182 void CodeCreateEvent(LogEventsAndTags tag, const wasm::WasmCode* code, 183 wasm::WasmName name, const char* source_url, 184 int code_offset, int script_id) override; 185#endif // V8_ENABLE_WEBASSEMBLY 186 187 void CallbackEvent(Handle<Name> name, Address entry_point) override; 188 void GetterCallbackEvent(Handle<Name> name, Address entry_point) override; 189 void SetterCallbackEvent(Handle<Name> name, Address entry_point) override; 190 void RegExpCodeCreateEvent(Handle<AbstractCode> code, 191 Handle<String> source) override; 192 void CodeMoveEvent(AbstractCode from, AbstractCode to) override; 193 void SharedFunctionInfoMoveEvent(Address from, Address to) override; 194 void NativeContextMoveEvent(Address from, Address to) override {} 195 void CodeMovingGCEvent() override; 196 void CodeDisableOptEvent(Handle<AbstractCode> code, 197 Handle<SharedFunctionInfo> shared) override; 198 void CodeDeoptEvent(Handle<Code> code, DeoptimizeKind kind, Address pc, 199 int fp_to_sp_delta) override; 200 void CodeDependencyChangeEvent(Handle<Code> code, 201 Handle<SharedFunctionInfo> sfi, 202 const char* reason) override; 203 void FeedbackVectorEvent(FeedbackVector vector, AbstractCode code); 204 void WeakCodeClearEvent() override {} 205 206 void ProcessDeoptEvent(Handle<Code> code, SourcePosition position, 207 const char* kind, const char* reason); 208 209 // Emits a code line info record event. 210 void CodeLinePosInfoRecordEvent(Address code_start, 211 ByteArray source_position_table, 212 JitCodeEvent::CodeType code_type); 213#if V8_ENABLE_WEBASSEMBLY 214 void WasmCodeLinePosInfoRecordEvent( 215 Address code_start, base::Vector<const byte> source_position_table); 216#endif // V8_ENABLE_WEBASSEMBLY 217 218 void CodeNameEvent(Address addr, int pos, const char* code_name); 219 220 void ICEvent(const char* type, bool keyed, Handle<Map> map, 221 Handle<Object> key, char old_state, char new_state, 222 const char* modifier, const char* slow_stub_reason); 223 224 void MapEvent(const char* type, Handle<Map> from, Handle<Map> to, 225 const char* reason = nullptr, 226 Handle<HeapObject> name_or_sfi = Handle<HeapObject>()); 227 void MapCreate(Map map); 228 void MapDetails(Map map); 229 230 void SharedLibraryEvent(const std::string& library_path, uintptr_t start, 231 uintptr_t end, intptr_t aslr_slide); 232 void SharedLibraryEnd(); 233 234 void CurrentTimeEvent(); 235 236 V8_EXPORT_PRIVATE void TimerEvent(v8::LogEventStatus se, const char* name); 237 238 void BasicBlockCounterEvent(const char* name, int block_id, uint32_t count); 239 240 void BuiltinHashEvent(const char* name, int hash); 241 242 static void EnterExternal(Isolate* isolate); 243 static void LeaveExternal(Isolate* isolate); 244 245 static void DefaultEventLoggerSentinel(const char* name, int event) {} 246 247 V8_INLINE static void CallEventLoggerInternal(Isolate* isolate, 248 const char* name, 249 v8::LogEventStatus se, 250 bool expose_to_api) { 251 if (isolate->event_logger() == DefaultEventLoggerSentinel) { 252 LOG(isolate, TimerEvent(se, name)); 253 } else if (expose_to_api) { 254 isolate->event_logger()(name, static_cast<v8::LogEventStatus>(se)); 255 } 256 } 257 258 V8_INLINE static void CallEventLogger(Isolate* isolate, const char* name, 259 v8::LogEventStatus se, 260 bool expose_to_api) { 261 if (!isolate->event_logger()) return; 262 CallEventLoggerInternal(isolate, name, se, expose_to_api); 263 } 264 265 V8_EXPORT_PRIVATE bool is_logging(); 266 267 bool is_listening_to_code_events() override { 268 return is_logging() || jit_logger_ != nullptr; 269 } 270 271 void LogExistingFunction(Handle<SharedFunctionInfo> shared, 272 Handle<AbstractCode> code); 273 // Logs all compiled functions found in the heap. 274 V8_EXPORT_PRIVATE void LogCompiledFunctions(); 275 // Logs all accessor callbacks found in the heap. 276 V8_EXPORT_PRIVATE void LogAccessorCallbacks(); 277 // Used for logging stubs found in the snapshot. 278 V8_EXPORT_PRIVATE void LogCodeObjects(); 279 V8_EXPORT_PRIVATE void LogBuiltins(); 280 // Logs all Maps found on the heap. 281 void LogAllMaps(); 282 283 // Converts tag to a corresponding NATIVE_... if the script is native. 284 V8_INLINE static CodeEventListener::LogEventsAndTags ToNativeByScript( 285 CodeEventListener::LogEventsAndTags, Script); 286 287 private: 288 void UpdateIsLogging(bool value); 289 290 // Emits the profiler's first message. 291 void ProfilerBeginEvent(); 292 293 // Emits callback event messages. 294 void CallbackEventInternal(const char* prefix, Handle<Name> name, 295 Address entry_point); 296 297 // Internal configurable move event. 298 void MoveEventInternal(CodeEventListener::LogEventsAndTags event, 299 Address from, Address to); 300 301 // Helper method. It resets name_buffer_ and add tag name into it. 302 void InitNameBuffer(CodeEventListener::LogEventsAndTags tag); 303 304 // Emits a profiler tick event. Used by the profiler thread. 305 void TickEvent(TickSample* sample, bool overflow); 306 void RuntimeCallTimerEvent(); 307 308 // Logs a StringEvent regardless of whether FLAG_log is true. 309 void UncheckedStringEvent(const char* name, const char* value); 310 311 // Logs a scripts sources. Keeps track of all logged scripts to ensure that 312 // each script is logged only once. 313 bool EnsureLogScriptSource(Script script); 314 315 void LogSourceCodeInformation(Handle<AbstractCode> code, 316 Handle<SharedFunctionInfo> shared); 317 void LogCodeDisassemble(Handle<AbstractCode> code); 318 319 void WriteApiSecurityCheck(); 320 void WriteApiNamedPropertyAccess(const char* tag, JSObject holder, 321 Object name); 322 void WriteApiIndexedPropertyAccess(const char* tag, JSObject holder, 323 uint32_t index); 324 void WriteApiObjectAccess(const char* tag, JSReceiver obj); 325 void WriteApiEntryCall(const char* name); 326 327 int64_t Time(); 328 329 Isolate* isolate_; 330 331 // The sampler used by the profiler and the sliding state window. 332 std::unique_ptr<Ticker> ticker_; 333 334 // When the statistical profile is active, profiler_ 335 // points to a Profiler, that handles collection 336 // of samples. 337 std::unique_ptr<Profiler> profiler_; 338 339 // Internal implementation classes with access to private members. 340 friend class Profiler; 341 342 std::atomic<bool> is_logging_; 343 std::unique_ptr<Log> log_; 344#if V8_OS_LINUX 345 std::unique_ptr<PerfBasicLogger> perf_basic_logger_; 346 std::unique_ptr<PerfJitLogger> perf_jit_logger_; 347#endif 348 std::unique_ptr<LowLevelLogger> ll_logger_; 349 std::unique_ptr<JitLogger> jit_logger_; 350#ifdef ENABLE_GDB_JIT_INTERFACE 351 std::unique_ptr<JitLogger> gdb_jit_logger_; 352#endif 353#if defined(V8_OS_WIN) && defined(V8_ENABLE_SYSTEM_INSTRUMENTATION) 354 std::unique_ptr<JitLogger> etw_jit_logger_; 355#endif 356 std::set<int> logged_source_code_; 357 uint32_t next_source_info_id_ = 0; 358 359 // Guards against multiple calls to TearDown() that can happen in some tests. 360 // 'true' between SetUp() and TearDown(). 361 bool is_initialized_; 362 363 ExistingCodeLogger existing_code_logger_; 364 365 base::ElapsedTimer timer_; 366}; 367 368#define TIMER_EVENTS_LIST(V) \ 369 V(RecompileSynchronous, true) \ 370 V(RecompileConcurrent, true) \ 371 V(CompileIgnition, true) \ 372 V(CompileFullCode, true) \ 373 V(OptimizeCode, true) \ 374 V(CompileCode, true) \ 375 V(CompileCodeBackground, true) \ 376 V(DeoptimizeCode, true) \ 377 V(Execute, true) 378 379#define V(TimerName, expose) \ 380 class TimerEvent##TimerName : public AllStatic { \ 381 public: \ 382 static const char* name(void* unused = nullptr) { \ 383 return "V8." #TimerName; \ 384 } \ 385 static bool expose_to_api() { return expose; } \ 386 }; 387TIMER_EVENTS_LIST(V) 388#undef V 389 390template <class TimerEvent> 391class V8_NODISCARD TimerEventScope { 392 public: 393 explicit TimerEventScope(Isolate* isolate) : isolate_(isolate) { 394 LogTimerEvent(v8::LogEventStatus::kStart); 395 } 396 397 ~TimerEventScope() { LogTimerEvent(v8::LogEventStatus::kEnd); } 398 399 private: 400 void LogTimerEvent(v8::LogEventStatus se); 401 Isolate* isolate_; 402}; 403 404// Abstract 405class V8_EXPORT_PRIVATE CodeEventLogger : public CodeEventListener { 406 public: 407 explicit CodeEventLogger(Isolate* isolate); 408 ~CodeEventLogger() override; 409 410 void CodeCreateEvent(LogEventsAndTags tag, Handle<AbstractCode> code, 411 const char* name) override; 412 void CodeCreateEvent(LogEventsAndTags tag, Handle<AbstractCode> code, 413 Handle<Name> name) override; 414 void CodeCreateEvent(LogEventsAndTags tag, Handle<AbstractCode> code, 415 Handle<SharedFunctionInfo> shared, 416 Handle<Name> script_name) override; 417 void CodeCreateEvent(LogEventsAndTags tag, Handle<AbstractCode> code, 418 Handle<SharedFunctionInfo> shared, 419 Handle<Name> script_name, int line, int column) override; 420#if V8_ENABLE_WEBASSEMBLY 421 void CodeCreateEvent(LogEventsAndTags tag, const wasm::WasmCode* code, 422 wasm::WasmName name, const char* source_url, 423 int code_offset, int script_id) override; 424#endif // V8_ENABLE_WEBASSEMBLY 425 426 void RegExpCodeCreateEvent(Handle<AbstractCode> code, 427 Handle<String> source) override; 428 void CallbackEvent(Handle<Name> name, Address entry_point) override {} 429 void GetterCallbackEvent(Handle<Name> name, Address entry_point) override {} 430 void SetterCallbackEvent(Handle<Name> name, Address entry_point) override {} 431 void SharedFunctionInfoMoveEvent(Address from, Address to) override {} 432 void NativeContextMoveEvent(Address from, Address to) override {} 433 void CodeMovingGCEvent() override {} 434 void CodeDeoptEvent(Handle<Code> code, DeoptimizeKind kind, Address pc, 435 int fp_to_sp_delta) override {} 436 void CodeDependencyChangeEvent(Handle<Code> code, 437 Handle<SharedFunctionInfo> sfi, 438 const char* reason) override {} 439 void WeakCodeClearEvent() override {} 440 441 bool is_listening_to_code_events() override { return true; } 442 443 protected: 444 Isolate* isolate_; 445 446 private: 447 class NameBuffer; 448 449 virtual void LogRecordedBuffer(Handle<AbstractCode> code, 450 MaybeHandle<SharedFunctionInfo> maybe_shared, 451 const char* name, int length) = 0; 452#if V8_ENABLE_WEBASSEMBLY 453 virtual void LogRecordedBuffer(const wasm::WasmCode* code, const char* name, 454 int length) = 0; 455#endif // V8_ENABLE_WEBASSEMBLY 456 457 std::unique_ptr<NameBuffer> name_buffer_; 458}; 459 460struct CodeEvent { 461 Isolate* isolate_; 462 uintptr_t code_start_address; 463 size_t code_size; 464 Handle<String> function_name; 465 Handle<String> script_name; 466 int script_line; 467 int script_column; 468 CodeEventType code_type; 469 const char* comment; 470 uintptr_t previous_code_start_address; 471}; 472 473class ExternalCodeEventListener : public CodeEventListener { 474 public: 475 explicit ExternalCodeEventListener(Isolate* isolate); 476 ~ExternalCodeEventListener() override; 477 478 void CodeCreateEvent(LogEventsAndTags tag, Handle<AbstractCode> code, 479 const char* comment) override; 480 void CodeCreateEvent(LogEventsAndTags tag, Handle<AbstractCode> code, 481 Handle<Name> name) override; 482 void CodeCreateEvent(LogEventsAndTags tag, Handle<AbstractCode> code, 483 Handle<SharedFunctionInfo> shared, 484 Handle<Name> name) override; 485 void CodeCreateEvent(LogEventsAndTags tag, Handle<AbstractCode> code, 486 Handle<SharedFunctionInfo> shared, Handle<Name> source, 487 int line, int column) override; 488#if V8_ENABLE_WEBASSEMBLY 489 void CodeCreateEvent(LogEventsAndTags tag, const wasm::WasmCode* code, 490 wasm::WasmName name, const char* source_url, 491 int code_offset, int script_id) override; 492#endif // V8_ENABLE_WEBASSEMBLY 493 494 void RegExpCodeCreateEvent(Handle<AbstractCode> code, 495 Handle<String> source) override; 496 void CallbackEvent(Handle<Name> name, Address entry_point) override {} 497 void GetterCallbackEvent(Handle<Name> name, Address entry_point) override {} 498 void SetterCallbackEvent(Handle<Name> name, Address entry_point) override {} 499 void SharedFunctionInfoMoveEvent(Address from, Address to) override {} 500 void NativeContextMoveEvent(Address from, Address to) override {} 501 void CodeMoveEvent(AbstractCode from, AbstractCode to) override; 502 void CodeDisableOptEvent(Handle<AbstractCode> code, 503 Handle<SharedFunctionInfo> shared) override {} 504 void CodeMovingGCEvent() override {} 505 void CodeDeoptEvent(Handle<Code> code, DeoptimizeKind kind, Address pc, 506 int fp_to_sp_delta) override {} 507 void CodeDependencyChangeEvent(Handle<Code> code, 508 Handle<SharedFunctionInfo> sfi, 509 const char* reason) override {} 510 void WeakCodeClearEvent() override {} 511 512 void StartListening(v8::CodeEventHandler* code_event_handler); 513 void StopListening(); 514 515 bool is_listening_to_code_events() override { return true; } 516 517 private: 518 void LogExistingCode(); 519 520 bool is_listening_; 521 Isolate* isolate_; 522 v8::CodeEventHandler* code_event_handler_; 523}; 524 525} // namespace internal 526} // namespace v8 527 528#endif // V8_LOGGING_LOG_H_ 529