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 <string>
9
10#include "src/allocation.h"
11#include "src/base/compiler-specific.h"
12#include "src/base/platform/elapsed-timer.h"
13#include "src/base/platform/platform.h"
14#include "src/code-events.h"
15#include "src/isolate.h"
16#include "src/objects.h"
17
18namespace v8 {
19
20struct TickSample;
21
22namespace sampler {
23class Sampler;
24}
25
26namespace internal {
27
28// Logger is used for collecting logging information from V8 during
29// execution. The result is dumped to a file.
30//
31// Available command line flags:
32//
33//  --log
34// Minimal logging (no API, code, or GC sample events), default is off.
35//
36// --log-all
37// Log all events to the file, default is off.  This is the same as combining
38// --log-api, --log-code, --log-gc, and --log-regexp.
39//
40// --log-api
41// Log API events to the logfile, default is off.  --log-api implies --log.
42//
43// --log-code
44// Log code (create, move, and delete) events to the logfile, default is off.
45// --log-code implies --log.
46//
47// --log-gc
48// Log GC heap samples after each GC that can be processed by hp2ps, default
49// is off.  --log-gc implies --log.
50//
51// --log-regexp
52// Log creation and use of regular expressions, Default is off.
53// --log-regexp implies --log.
54//
55// --logfile <filename>
56// Specify the name of the logfile, default is "v8.log".
57//
58// --prof
59// Collect statistical profiling information (ticks), default is off.  The
60// tick profiler requires code events, so --prof implies --log-code.
61
62// Forward declarations.
63class CodeEventListener;
64class CpuProfiler;
65class Isolate;
66class JitLogger;
67class Log;
68class LowLevelLogger;
69class PerfBasicLogger;
70class PerfJitLogger;
71class Profiler;
72class ProfilerListener;
73class RuntimeCallTimer;
74class Ticker;
75
76#undef LOG
77#define LOG(isolate, Call)                              \
78  do {                                                  \
79    v8::internal::Logger* logger = (isolate)->logger(); \
80    if (logger->is_logging()) logger->Call;             \
81  } while (false)
82
83#define LOG_CODE_EVENT(isolate, Call)                   \
84  do {                                                  \
85    v8::internal::Logger* logger = (isolate)->logger(); \
86    if (logger->is_logging_code_events()) logger->Call; \
87  } while (false)
88
89class Logger : public CodeEventListener {
90 public:
91  enum StartEnd { START = 0, END = 1 };
92
93  // Acquires resources for logging if the right flags are set.
94  bool SetUp(Isolate* isolate);
95
96  // Sets the current code event handler.
97  void SetCodeEventHandler(uint32_t options,
98                           JitCodeEventHandler event_handler);
99
100  // Sets up ProfilerListener.
101  void SetUpProfilerListener();
102
103  // Tear down ProfilerListener if it has no observers.
104  void TearDownProfilerListener();
105
106  sampler::Sampler* sampler();
107
108  ProfilerListener* profiler_listener() { return profiler_listener_.get(); }
109
110  // Frees resources acquired in SetUp.
111  // When a temporary file is used for the log, returns its stream descriptor,
112  // leaving the file open.
113  FILE* TearDown();
114
115  // Emits an event with a string value -> (name, value).
116  void StringEvent(const char* name, const char* value);
117
118  // Emits an event with an int value -> (name, value).
119  void IntEvent(const char* name, int value);
120  void IntPtrTEvent(const char* name, intptr_t value);
121
122  // Emits an event with an handle value -> (name, location).
123  void HandleEvent(const char* name, Object** location);
124
125  // Emits memory management events for C allocated structures.
126  void NewEvent(const char* name, void* object, size_t size);
127  void DeleteEvent(const char* name, void* object);
128
129  // Emits an event with a tag, and some resource usage information.
130  // -> (name, tag, <rusage information>).
131  // Currently, the resource usage information is a process time stamp
132  // and a real time timestamp.
133  void ResourceEvent(const char* name, const char* tag);
134
135  // Emits an event that an undefined property was read from an
136  // object.
137  void SuspectReadEvent(Name* name, Object* obj);
138
139  // ==== Events logged by --log-api. ====
140  void ApiSecurityCheck();
141  void ApiNamedPropertyAccess(const char* tag, JSObject* holder, Object* name);
142  void ApiIndexedPropertyAccess(const char* tag,
143                                JSObject* holder,
144                                uint32_t index);
145  void ApiObjectAccess(const char* tag, JSObject* obj);
146  void ApiEntryCall(const char* name);
147
148  // ==== Events logged by --log-code. ====
149  void addCodeEventListener(CodeEventListener* listener);
150  void removeCodeEventListener(CodeEventListener* listener);
151
152  // Emits a code event for a callback function.
153  void CallbackEvent(Name* name, Address entry_point);
154  void GetterCallbackEvent(Name* name, Address entry_point);
155  void SetterCallbackEvent(Name* name, Address entry_point);
156  // Emits a code create event.
157  void CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
158                       AbstractCode* code, const char* source);
159  void CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
160                       AbstractCode* code, Name* name);
161  void CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
162                       AbstractCode* code, SharedFunctionInfo* shared,
163                       Name* name);
164  void CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
165                       AbstractCode* code, SharedFunctionInfo* shared,
166                       Name* source, int line, int column);
167  void CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
168                       AbstractCode* code, int args_count);
169  // Emits a code deoptimization event.
170  void CodeDisableOptEvent(AbstractCode* code, SharedFunctionInfo* shared);
171  void CodeMovingGCEvent();
172  // Emits a code create event for a RegExp.
173  void RegExpCodeCreateEvent(AbstractCode* code, String* source);
174  // Emits a code move event.
175  void CodeMoveEvent(AbstractCode* from, Address to);
176  // Emits a code line info record event.
177  void CodeLinePosInfoRecordEvent(AbstractCode* code,
178                                  ByteArray* source_position_table);
179
180  void SharedFunctionInfoMoveEvent(Address from, Address to);
181
182  void CodeNameEvent(Address addr, int pos, const char* code_name);
183
184  void CodeDeoptEvent(Code* code, Address pc, int fp_to_sp_delta);
185
186  void ICEvent(const char* type, bool keyed, const Address pc, int line,
187               int column, Map* map, Object* key, char old_state,
188               char new_state, const char* modifier,
189               const char* slow_stub_reason);
190  void CompareIC(const Address pc, int line, int column, Code* stub,
191                 const char* op, const char* old_left, const char* old_right,
192                 const char* old_state, const char* new_left,
193                 const char* new_right, const char* new_state);
194  void BinaryOpIC(const Address pc, int line, int column, Code* stub,
195                  const char* old_state, const char* new_state,
196                  AllocationSite* allocation_site);
197  void ToBooleanIC(const Address pc, int line, int column, Code* stub,
198                   const char* old_state, const char* new_state);
199  void PatchIC(const Address pc, const Address test, int delta);
200
201  // ==== Events logged by --log-gc. ====
202  // Heap sampling events: start, end, and individual types.
203  void HeapSampleBeginEvent(const char* space, const char* kind);
204  void HeapSampleEndEvent(const char* space, const char* kind);
205  void HeapSampleItemEvent(const char* type, int number, int bytes);
206  void HeapSampleJSConstructorEvent(const char* constructor,
207                                    int number, int bytes);
208  void HeapSampleJSRetainersEvent(const char* constructor,
209                                         const char* event);
210  void HeapSampleJSProducerEvent(const char* constructor,
211                                 Address* stack);
212  void HeapSampleStats(const char* space, const char* kind,
213                       intptr_t capacity, intptr_t used);
214
215  void SharedLibraryEvent(const std::string& library_path, uintptr_t start,
216                          uintptr_t end, intptr_t aslr_slide);
217
218  void CurrentTimeEvent();
219
220  void TimerEvent(StartEnd se, const char* name);
221
222  static void EnterExternal(Isolate* isolate);
223  static void LeaveExternal(Isolate* isolate);
224
225  static void DefaultEventLoggerSentinel(const char* name, int event) {}
226
227  INLINE(static void CallEventLogger(Isolate* isolate, const char* name,
228                                     StartEnd se, bool expose_to_api));
229
230  bool is_logging() {
231    return is_logging_;
232  }
233
234  bool is_logging_code_events() {
235    return is_logging() || jit_logger_ != NULL;
236  }
237
238  // Stop collection of profiling data.
239  // When data collection is paused, CPU Tick events are discarded.
240  void StopProfiler();
241
242  void LogExistingFunction(Handle<SharedFunctionInfo> shared,
243                           Handle<AbstractCode> code);
244  // Logs all compiled functions found in the heap.
245  void LogCompiledFunctions();
246  // Logs all accessor callbacks found in the heap.
247  void LogAccessorCallbacks();
248  // Used for logging stubs found in the snapshot.
249  void LogCodeObjects();
250  // Used for logging bytecode handlers found in the snapshot.
251  void LogBytecodeHandlers();
252
253  // Converts tag to a corresponding NATIVE_... if the script is native.
254  INLINE(static CodeEventListener::LogEventsAndTags ToNativeByScript(
255      CodeEventListener::LogEventsAndTags, Script*));
256
257  // Profiler's sampling interval (in milliseconds).
258#if defined(ANDROID)
259  // Phones and tablets have processors that are much slower than desktop
260  // and laptop computers for which current heuristics are tuned.
261  static const int kSamplingIntervalMs = 5;
262#else
263  static const int kSamplingIntervalMs = 1;
264#endif
265
266  // Callback from Log, stops profiling in case of insufficient resources.
267  void LogFailure();
268
269 private:
270  explicit Logger(Isolate* isolate);
271  ~Logger();
272
273  // Emits the profiler's first message.
274  void ProfilerBeginEvent();
275
276  // Emits callback event messages.
277  void CallbackEventInternal(const char* prefix,
278                             Name* name,
279                             Address entry_point);
280
281  // Internal configurable move event.
282  void MoveEventInternal(CodeEventListener::LogEventsAndTags event,
283                         Address from, Address to);
284
285  // Used for logging stubs found in the snapshot.
286  void LogCodeObject(Object* code_object);
287
288  // Helper method. It resets name_buffer_ and add tag name into it.
289  void InitNameBuffer(CodeEventListener::LogEventsAndTags tag);
290
291  // Emits a profiler tick event. Used by the profiler thread.
292  void TickEvent(TickSample* sample, bool overflow);
293  void RuntimeCallTimerEvent();
294
295  PRINTF_FORMAT(2, 3) void ApiEvent(const char* format, ...);
296
297  // Logs a StringEvent regardless of whether FLAG_log is true.
298  void UncheckedStringEvent(const char* name, const char* value);
299
300  // Logs an IntEvent regardless of whether FLAG_log is true.
301  void UncheckedIntEvent(const char* name, int value);
302  void UncheckedIntPtrTEvent(const char* name, intptr_t value);
303
304  Isolate* isolate_;
305
306  // The sampler used by the profiler and the sliding state window.
307  Ticker* ticker_;
308
309  // When the statistical profile is active, profiler_
310  // points to a Profiler, that handles collection
311  // of samples.
312  Profiler* profiler_;
313
314  // An array of log events names.
315  const char* const* log_events_;
316
317  // Internal implementation classes with access to
318  // private members.
319  friend class EventLog;
320  friend class Isolate;
321  friend class TimeLog;
322  friend class Profiler;
323  template <StateTag Tag> friend class VMState;
324  friend class LoggerTestHelper;
325
326  bool is_logging_;
327  Log* log_;
328  PerfBasicLogger* perf_basic_logger_;
329  PerfJitLogger* perf_jit_logger_;
330  LowLevelLogger* ll_logger_;
331  JitLogger* jit_logger_;
332  std::unique_ptr<ProfilerListener> profiler_listener_;
333  List<CodeEventListener*> listeners_;
334
335  // Guards against multiple calls to TearDown() that can happen in some tests.
336  // 'true' between SetUp() and TearDown().
337  bool is_initialized_;
338
339  base::ElapsedTimer timer_;
340
341  friend class CpuProfiler;
342};
343
344#define TIMER_EVENTS_LIST(V)    \
345  V(RecompileSynchronous, true) \
346  V(RecompileConcurrent, true)  \
347  V(CompileIgnition, true)      \
348  V(CompileFullCode, true)      \
349  V(OptimizeCode, true)         \
350  V(CompileCode, true)          \
351  V(DeoptimizeCode, true)       \
352  V(Execute, true)              \
353  V(External, true)
354
355#define V(TimerName, expose)                                                  \
356  class TimerEvent##TimerName : public AllStatic {                            \
357   public:                                                                    \
358    static const char* name(void* unused = NULL) { return "V8." #TimerName; } \
359    static bool expose_to_api() { return expose; }                            \
360  };
361TIMER_EVENTS_LIST(V)
362#undef V
363
364
365template <class TimerEvent>
366class TimerEventScope {
367 public:
368  explicit TimerEventScope(Isolate* isolate) : isolate_(isolate) {
369    LogTimerEvent(Logger::START);
370  }
371
372  ~TimerEventScope() { LogTimerEvent(Logger::END); }
373
374 private:
375  void LogTimerEvent(Logger::StartEnd se);
376  Isolate* isolate_;
377};
378
379class CodeEventLogger : public CodeEventListener {
380 public:
381  CodeEventLogger();
382  ~CodeEventLogger() override;
383
384  void CodeCreateEvent(LogEventsAndTags tag, AbstractCode* code,
385                       const char* comment) override;
386  void CodeCreateEvent(LogEventsAndTags tag, AbstractCode* code,
387                       Name* name) override;
388  void CodeCreateEvent(LogEventsAndTags tag, AbstractCode* code,
389                       int args_count) override;
390  void CodeCreateEvent(LogEventsAndTags tag, AbstractCode* code,
391                       SharedFunctionInfo* shared, Name* name) override;
392  void CodeCreateEvent(LogEventsAndTags tag, AbstractCode* code,
393                       SharedFunctionInfo* shared, Name* source, int line,
394                       int column) override;
395  void RegExpCodeCreateEvent(AbstractCode* code, String* source) override;
396
397  void CallbackEvent(Name* name, Address entry_point) override {}
398  void GetterCallbackEvent(Name* name, Address entry_point) override {}
399  void SetterCallbackEvent(Name* name, Address entry_point) override {}
400  void SharedFunctionInfoMoveEvent(Address from, Address to) override {}
401  void CodeMovingGCEvent() override {}
402  void CodeDeoptEvent(Code* code, Address pc, int fp_to_sp_delta) override {}
403
404 private:
405  class NameBuffer;
406
407  virtual void LogRecordedBuffer(AbstractCode* code, SharedFunctionInfo* shared,
408                                 const char* name, int length) = 0;
409
410  NameBuffer* name_buffer_;
411};
412
413
414}  // namespace internal
415}  // namespace v8
416
417
418#endif  // V8_LOG_H_
419