Line data Source code
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 :
16 : namespace v8 {
17 :
18 : struct TickSample;
19 :
20 : namespace sampler {
21 : class Sampler;
22 : }
23 :
24 : namespace 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.
61 : class CodeEventListener;
62 : class Isolate;
63 : class JitLogger;
64 : class Log;
65 : class LowLevelLogger;
66 : class PerfBasicLogger;
67 : class PerfJitLogger;
68 : class Profiler;
69 : class 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 :
84 : class ExistingCodeLogger {
85 : public:
86 : explicit ExistingCodeLogger(Isolate* isolate,
87 : CodeEventListener* listener = nullptr)
88 61551 : : 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 :
104 : enum class LogSeparator;
105 :
106 : class 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 : 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 : FILE* TearDown();
136 :
137 : // Emits an event with a string value -> (name, value).
138 : 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 : void AddCodeEventListener(CodeEventListener* listener);
184 : 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 0 : 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 1552 : void set_is_logging(bool new_value) { is_logging_ = new_value; }
256 :
257 7471969 : bool is_listening_to_code_events() override {
258 14938191 : 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 : void LogCompiledFunctions();
265 : // Logs all accessor callbacks found in the heap.
266 : void LogAccessorCallbacks();
267 : // Used for logging stubs found in the snapshot.
268 : 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 : };
371 : TIMER_EVENTS_LIST(V)
372 : #undef V
373 :
374 :
375 : template <class TimerEvent>
376 : class TimerEventScope {
377 : public:
378 3868312 : explicit TimerEventScope(Isolate* isolate) : isolate_(isolate) {
379 3868312 : LogTimerEvent(Logger::START);
380 : }
381 :
382 3868324 : ~TimerEventScope() { LogTimerEvent(Logger::END); }
383 :
384 : private:
385 : void LogTimerEvent(Logger::StartEnd se);
386 : Isolate* isolate_;
387 : };
388 :
389 : class 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 168 : void CallbackEvent(Name name, Address entry_point) override {}
408 0 : void GetterCallbackEvent(Name name, Address entry_point) override {}
409 0 : void SetterCallbackEvent(Name name, Address entry_point) override {}
410 0 : void SharedFunctionInfoMoveEvent(Address from, Address to) override {}
411 10 : void CodeMovingGCEvent() override {}
412 0 : void CodeDeoptEvent(Code code, DeoptimizeKind kind, Address pc,
413 0 : 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 :
429 : struct 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 :
441 : class 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 336 : void CallbackEvent(Name name, Address entry_point) override {}
460 0 : void GetterCallbackEvent(Name name, Address entry_point) override {}
461 0 : void SetterCallbackEvent(Name name, Address entry_point) override {}
462 0 : void SharedFunctionInfoMoveEvent(Address from, Address to) override {}
463 0 : void CodeMoveEvent(AbstractCode from, AbstractCode to) override {}
464 0 : void CodeDisableOptEvent(AbstractCode code,
465 0 : SharedFunctionInfo shared) override {}
466 0 : void CodeMovingGCEvent() override {}
467 0 : void CodeDeoptEvent(Code code, DeoptimizeKind kind, Address pc,
468 0 : int fp_to_sp_delta) override {}
469 :
470 : void StartListening(v8::CodeEventHandler* code_event_handler);
471 : void StopListening();
472 :
473 42 : 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_
|