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_LOG_H_
6#define V8_LOG_H_
7
8#include <set>
9#include <string>
10
11#include "include/v8-profiler.h"
12#include "src/base/platform/elapsed-timer.h"
13#include "src/code-events.h"
14#include "src/objects.h"
15
16namespace v8 {
17
18struct TickSample;
19
20namespace sampler {
21class Sampler;
22}
23
24namespace internal {
25
26// Logger is used for collecting logging information from V8 during
27// execution. The result is dumped to a file.
28//
29// Available command line flags:
30//
31// --log
32// Minimal logging (no API, code, or GC sample events), default is off.
33//
34// --log-all
35// Log all events to the file, default is off. This is the same as combining
36// --log-api, --log-code, and --log-regexp.
37//
38// --log-api
39// Log API events to the logfile, default is off. --log-api implies --log.
40//
41// --log-code
42// Log code (create, move, and delete) events to the logfile, default is off.
43// --log-code implies --log.
44//
45// --log-regexp
46// Log creation and use of regular expressions, Default is off.
47// --log-regexp 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 Ticker;
70
71#undef LOG
72#define LOG(isolate, Call) \
73 do { \
74 v8::internal::Logger* logger = (isolate)->logger(); \
75 if (logger->is_logging()) logger->Call; \
76 } while (false)
77
78#define LOG_CODE_EVENT(isolate, Call) \
79 do { \
80 v8::internal::Logger* 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
92 void LogCompiledFunctions();
93 void LogExistingFunction(Handle<SharedFunctionInfo> shared,
94 Handle<AbstractCode> code,
95 CodeEventListener::LogEventsAndTags tag =
96 CodeEventListener::LAZY_COMPILE_TAG);
97 void LogCodeObject(Object object);
98
99 private:
100 Isolate* isolate_;
101 CodeEventListener* listener_;
102};
103
104enum class LogSeparator;
105
106class Logger : public CodeEventListener {
107 public:
108 enum StartEnd { START = 0, END = 1, STAMP = 2 };
109
110 enum class ScriptEventType {
111 kReserveId,
112 kCreate,
113 kDeserialize,
114 kBackgroundCompile,
115 kStreamingCompile
116 };
117
118 // The separator is used to write an unescaped "," into the log.
119 static const LogSeparator kNext;
120
121 // Acquires resources for logging if the right flags are set.
122 bool SetUp(Isolate* isolate);
123
124 // Sets the current code event handler.
125 void SetCodeEventHandler(uint32_t options,
126 JitCodeEventHandler event_handler);
127
128 sampler::Sampler* sampler();
129
130 V8_EXPORT_PRIVATE void StopProfilerThread();
131
132 // Frees resources acquired in SetUp.
133 // When a temporary file is used for the log, returns its stream descriptor,
134 // leaving the file open.
135 V8_EXPORT_PRIVATE FILE* TearDown();
136
137 // Emits an event with a string value -> (name, value).
138 V8_EXPORT_PRIVATE void StringEvent(const char* name, const char* value);
139
140 // Emits an event with an int value -> (name, value).
141 void IntPtrTEvent(const char* name, intptr_t value);
142
143 // Emits an event with an handle value -> (name, location).
144 void HandleEvent(const char* name, Address* location);
145
146 // Emits memory management events for C allocated structures.
147 void NewEvent(const char* name, void* object, size_t size);
148 void DeleteEvent(const char* name, void* object);
149
150 // Emits an event with a tag, and some resource usage information.
151 // -> (name, tag, <rusage information>).
152 // Currently, the resource usage information is a process time stamp
153 // and a real time timestamp.
154 void ResourceEvent(const char* name, const char* tag);
155
156 // Emits an event that an undefined property was read from an
157 // object.
158 void SuspectReadEvent(Name name, Object obj);
159
160 // ==== Events logged by --log-function-events ====
161 void FunctionEvent(const char* reason, int script_id, double time_delta_ms,
162 int start_position, int end_position,
163 String function_name);
164 void FunctionEvent(const char* reason, int script_id, double time_delta_ms,
165 int start_position, int end_position,
166 const char* function_name = nullptr,
167 size_t function_name_length = 0);
168
169 void CompilationCacheEvent(const char* action, const char* cache_type,
170 SharedFunctionInfo sfi);
171 void ScriptEvent(ScriptEventType type, int script_id);
172 void ScriptDetails(Script script);
173
174 // ==== Events logged by --log-api. ====
175 void ApiSecurityCheck();
176 void ApiNamedPropertyAccess(const char* tag, JSObject holder, Object name);
177 void ApiIndexedPropertyAccess(const char* tag, JSObject holder,
178 uint32_t index);
179 void ApiObjectAccess(const char* tag, JSObject obj);
180 void ApiEntryCall(const char* name);
181
182 // ==== Events logged by --log-code. ====
183 V8_EXPORT_PRIVATE void AddCodeEventListener(CodeEventListener* listener);
184 V8_EXPORT_PRIVATE void RemoveCodeEventListener(CodeEventListener* listener);
185
186 // Emits a code event for a callback function.
187 void CallbackEvent(Name name, Address entry_point) override;
188 void GetterCallbackEvent(Name name, Address entry_point) override;
189 void SetterCallbackEvent(Name name, Address entry_point) override;
190 // Emits a code create event.
191 void CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
192 AbstractCode code, const char* source) override;
193 void CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
194 AbstractCode code, Name name) override;
195 void CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
196 AbstractCode code, SharedFunctionInfo shared,
197 Name name) override;
198 void CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
199 AbstractCode code, SharedFunctionInfo shared,
200 Name source, int line, int column) override;
201 void CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
202 const wasm::WasmCode* code,
203 wasm::WasmName name) override;
204 // Emits a code deoptimization event.
205 void CodeDisableOptEvent(AbstractCode code,
206 SharedFunctionInfo shared) override;
207 void CodeMovingGCEvent() override;
208 // Emits a code create event for a RegExp.
209 void RegExpCodeCreateEvent(AbstractCode code, String source) override;
210 // Emits a code move event.
211 void CodeMoveEvent(AbstractCode from, AbstractCode to) override;
212 // Emits a code line info record event.
213 void CodeLinePosInfoRecordEvent(Address code_start,
214 ByteArray source_position_table);
215 void CodeLinePosInfoRecordEvent(Address code_start,
216 Vector<const byte> source_position_table);
217
218 void SharedFunctionInfoMoveEvent(Address from, Address to) override;
219
220 void CodeNameEvent(Address addr, int pos, const char* code_name);
221
222 void CodeDeoptEvent(Code code, DeoptimizeKind kind, Address pc,
223 int fp_to_sp_delta) override;
224
225 void ICEvent(const char* type, bool keyed, Map map, Object key,
226 char old_state, char new_state, const char* modifier,
227 const char* slow_stub_reason);
228
229 void MapEvent(const char* type, Map from, Map to,
230 const char* reason = nullptr,
231 HeapObject name_or_sfi = HeapObject());
232 void MapCreate(Map map);
233 void MapDetails(Map map);
234
235 void SharedLibraryEvent(const std::string& library_path, uintptr_t start,
236 uintptr_t end, intptr_t aslr_slide);
237
238 void CurrentTimeEvent();
239
240 V8_EXPORT_PRIVATE void TimerEvent(StartEnd se, const char* name);
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 CallEventLogger(Isolate* isolate, const char* name,
248 StartEnd se, bool expose_to_api);
249
250 bool is_logging() {
251 return is_logging_;
252 }
253
254 // Used by CpuProfiler. TODO(petermarshall): Untangle
255 void set_is_logging(bool new_value) { is_logging_ = new_value; }
256
257 bool is_listening_to_code_events() override {
258 return is_logging() || jit_logger_ != nullptr;
259 }
260
261 void LogExistingFunction(Handle<SharedFunctionInfo> shared,
262 Handle<AbstractCode> code);
263 // Logs all compiled functions found in the heap.
264 V8_EXPORT_PRIVATE void LogCompiledFunctions();
265 // Logs all accessor callbacks found in the heap.
266 V8_EXPORT_PRIVATE void LogAccessorCallbacks();
267 // Used for logging stubs found in the snapshot.
268 V8_EXPORT_PRIVATE void LogCodeObjects();
269 // Logs all Maps found on the heap.
270 void LogAllMaps();
271
272 // Converts tag to a corresponding NATIVE_... if the script is native.
273 V8_INLINE static CodeEventListener::LogEventsAndTags ToNativeByScript(
274 CodeEventListener::LogEventsAndTags, Script);
275
276 // Used for logging stubs found in the snapshot.
277 void LogCodeObject(Object code_object);
278
279 private:
280 explicit Logger(Isolate* isolate);
281 ~Logger() override;
282
283 // Emits the profiler's first message.
284 void ProfilerBeginEvent();
285
286 // Emits callback event messages.
287 void CallbackEventInternal(const char* prefix, Name name,
288 Address entry_point);
289
290 // Internal configurable move event.
291 void MoveEventInternal(CodeEventListener::LogEventsAndTags event,
292 Address from, Address to);
293
294 // Helper method. It resets name_buffer_ and add tag name into it.
295 void InitNameBuffer(CodeEventListener::LogEventsAndTags tag);
296
297 // Emits a profiler tick event. Used by the profiler thread.
298 void TickEvent(TickSample* sample, bool overflow);
299 void RuntimeCallTimerEvent();
300
301 // Logs a StringEvent regardless of whether FLAG_log is true.
302 void UncheckedStringEvent(const char* name, const char* value);
303
304 // Logs an IntPtrTEvent regardless of whether FLAG_log is true.
305 void UncheckedIntPtrTEvent(const char* name, intptr_t value);
306
307 // Logs a scripts sources. Keeps track of all logged scripts to ensure that
308 // each script is logged only once.
309 bool EnsureLogScriptSource(Script script);
310
311 Isolate* isolate_;
312
313 // The sampler used by the profiler and the sliding state window.
314 std::unique_ptr<Ticker> ticker_;
315
316 // When the statistical profile is active, profiler_
317 // points to a Profiler, that handles collection
318 // of samples.
319 std::unique_ptr<Profiler> profiler_;
320
321 // An array of log events names.
322 const char* const* log_events_;
323
324 // Internal implementation classes with access to
325 // private members.
326 friend class EventLog;
327 friend class Isolate;
328 friend class TimeLog;
329 friend class Profiler;
330 template <StateTag Tag> friend class VMState;
331 friend class LoggerTestHelper;
332
333 bool is_logging_;
334 Log* log_;
335 std::unique_ptr<PerfBasicLogger> perf_basic_logger_;
336 std::unique_ptr<PerfJitLogger> perf_jit_logger_;
337 std::unique_ptr<LowLevelLogger> ll_logger_;
338 std::unique_ptr<JitLogger> jit_logger_;
339 std::set<int> logged_source_code_;
340 uint32_t next_source_info_id_ = 0;
341
342 // Guards against multiple calls to TearDown() that can happen in some tests.
343 // 'true' between SetUp() and TearDown().
344 bool is_initialized_;
345
346 ExistingCodeLogger existing_code_logger_;
347
348 base::ElapsedTimer timer_;
349};
350
351#define TIMER_EVENTS_LIST(V) \
352 V(RecompileSynchronous, true) \
353 V(RecompileConcurrent, true) \
354 V(CompileIgnition, true) \
355 V(CompileFullCode, true) \
356 V(OptimizeCode, true) \
357 V(CompileCode, true) \
358 V(CompileCodeBackground, true) \
359 V(DeoptimizeCode, true) \
360 V(Execute, true) \
361 V(External, true)
362
363#define V(TimerName, expose) \
364 class TimerEvent##TimerName : public AllStatic { \
365 public: \
366 static const char* name(void* unused = nullptr) { \
367 return "V8." #TimerName; \
368 } \
369 static bool expose_to_api() { return expose; } \
370 };
371TIMER_EVENTS_LIST(V)
372#undef V
373
374
375template <class TimerEvent>
376class TimerEventScope {
377 public:
378 explicit TimerEventScope(Isolate* isolate) : isolate_(isolate) {
379 LogTimerEvent(Logger::START);
380 }
381
382 ~TimerEventScope() { LogTimerEvent(Logger::END); }
383
384 private:
385 void LogTimerEvent(Logger::StartEnd se);
386 Isolate* isolate_;
387};
388
389class V8_EXPORT_PRIVATE CodeEventLogger : public CodeEventListener {
390 public:
391 explicit CodeEventLogger(Isolate* isolate);
392 ~CodeEventLogger() override;
393
394 void CodeCreateEvent(LogEventsAndTags tag, AbstractCode code,
395 const char* comment) override;
396 void CodeCreateEvent(LogEventsAndTags tag, AbstractCode code,
397 Name name) override;
398 void CodeCreateEvent(LogEventsAndTags tag, AbstractCode code,
399 SharedFunctionInfo shared, Name name) override;
400 void CodeCreateEvent(LogEventsAndTags tag, AbstractCode code,
401 SharedFunctionInfo shared, Name source, int line,
402 int column) override;
403 void CodeCreateEvent(LogEventsAndTags tag, const wasm::WasmCode* code,
404 wasm::WasmName name) override;
405
406 void RegExpCodeCreateEvent(AbstractCode code, String source) override;
407 void CallbackEvent(Name name, Address entry_point) override {}
408 void GetterCallbackEvent(Name name, Address entry_point) override {}
409 void SetterCallbackEvent(Name name, Address entry_point) override {}
410 void SharedFunctionInfoMoveEvent(Address from, Address to) override {}
411 void CodeMovingGCEvent() override {}
412 void CodeDeoptEvent(Code code, DeoptimizeKind kind, Address pc,
413 int fp_to_sp_delta) override {}
414
415 protected:
416 Isolate* isolate_;
417
418 private:
419 class NameBuffer;
420
421 virtual void LogRecordedBuffer(AbstractCode code, SharedFunctionInfo shared,
422 const char* name, int length) = 0;
423 virtual void LogRecordedBuffer(const wasm::WasmCode* code, const char* name,
424 int length) = 0;
425
426 NameBuffer* name_buffer_;
427};
428
429struct CodeEvent {
430 Isolate* isolate_;
431 uintptr_t code_start_address;
432 size_t code_size;
433 Handle<String> function_name;
434 Handle<String> script_name;
435 int script_line;
436 int script_column;
437 CodeEventType code_type;
438 const char* comment;
439};
440
441class ExternalCodeEventListener : public CodeEventListener {
442 public:
443 explicit ExternalCodeEventListener(Isolate* isolate);
444 ~ExternalCodeEventListener() override;
445
446 void CodeCreateEvent(LogEventsAndTags tag, AbstractCode code,
447 const char* comment) override;
448 void CodeCreateEvent(LogEventsAndTags tag, AbstractCode code,
449 Name name) override;
450 void CodeCreateEvent(LogEventsAndTags tag, AbstractCode code,
451 SharedFunctionInfo shared, Name name) override;
452 void CodeCreateEvent(LogEventsAndTags tag, AbstractCode code,
453 SharedFunctionInfo shared, Name source, int line,
454 int column) override;
455 void CodeCreateEvent(LogEventsAndTags tag, const wasm::WasmCode* code,
456 wasm::WasmName name) override;
457
458 void RegExpCodeCreateEvent(AbstractCode code, String source) override;
459 void CallbackEvent(Name name, Address entry_point) override {}
460 void GetterCallbackEvent(Name name, Address entry_point) override {}
461 void SetterCallbackEvent(Name name, Address entry_point) override {}
462 void SharedFunctionInfoMoveEvent(Address from, Address to) override {}
463 void CodeMoveEvent(AbstractCode from, AbstractCode to) override {}
464 void CodeDisableOptEvent(AbstractCode code,
465 SharedFunctionInfo shared) override {}
466 void CodeMovingGCEvent() override {}
467 void CodeDeoptEvent(Code code, DeoptimizeKind kind, Address pc,
468 int fp_to_sp_delta) override {}
469
470 void StartListening(v8::CodeEventHandler* code_event_handler);
471 void StopListening();
472
473 bool is_listening_to_code_events() override { return true; }
474
475 private:
476 void LogExistingCode();
477
478 bool is_listening_;
479 Isolate* isolate_;
480 v8::CodeEventHandler* code_event_handler_;
481};
482
483} // namespace internal
484} // namespace v8
485
486
487#endif // V8_LOG_H_
488