• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 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 SRC_TRACING_TRACE_EVENT_H_
6 #define SRC_TRACING_TRACE_EVENT_H_
7 
8 #include <stddef.h>
9 #include <memory>
10 
11 #include "base/trace_event/common/trace_event_common.h"
12 #include "include/v8-platform.h"
13 #include "src/base/atomicops.h"
14 #include "src/base/macros.h"
15 
16 // This header file defines implementation details of how the trace macros in
17 // trace_event_common.h collect and store trace events. Anything not
18 // implementation-specific should go in trace_macros_common.h instead of here.
19 
20 
21 // The pointer returned from GetCategoryGroupEnabled() points to a
22 // value with zero or more of the following bits. Used in this class only.
23 // The TRACE_EVENT macros should only use the value as a bool.
24 // These values must be in sync with macro values in trace_log.h in
25 // chromium.
26 enum CategoryGroupEnabledFlags {
27   // Category group enabled for the recording mode.
28   kEnabledForRecording_CategoryGroupEnabledFlags = 1 << 0,
29   // Category group enabled by SetEventCallbackEnabled().
30   kEnabledForEventCallback_CategoryGroupEnabledFlags = 1 << 2,
31   // Category group enabled to export events to ETW.
32   kEnabledForETWExport_CategoryGroupEnabledFlags = 1 << 3,
33 };
34 
35 // By default, const char* asrgument values are assumed to have long-lived scope
36 // and will not be copied. Use this macro to force a const char* to be copied.
37 #define TRACE_STR_COPY(str) v8::internal::tracing::TraceStringWithCopy(str)
38 
39 // By default, uint64 ID argument values are not mangled with the Process ID in
40 // TRACE_EVENT_ASYNC macros. Use this macro to force Process ID mangling.
41 #define TRACE_ID_MANGLE(id) v8::internal::tracing::TraceID::ForceMangle(id)
42 
43 // By default, pointers are mangled with the Process ID in TRACE_EVENT_ASYNC
44 // macros. Use this macro to prevent Process ID mangling.
45 #define TRACE_ID_DONT_MANGLE(id) v8::internal::tracing::TraceID::DontMangle(id)
46 
47 // By default, trace IDs are eventually converted to a single 64-bit number. Use
48 // this macro to add a scope string.
49 #define TRACE_ID_WITH_SCOPE(scope, id) \
50   trace_event_internal::TraceID::WithScope(scope, id)
51 
52 #define INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE() \
53   *INTERNAL_TRACE_EVENT_UID(category_group_enabled) &                    \
54       (kEnabledForRecording_CategoryGroupEnabledFlags |                  \
55        kEnabledForEventCallback_CategoryGroupEnabledFlags)
56 
57 // The following macro has no implementation, but it needs to exist since
58 // it gets called from scoped trace events. It cannot call UNIMPLEMENTED()
59 // since an empty implementation is a valid one.
60 #define INTERNAL_TRACE_MEMORY(category, name)
61 
62 ////////////////////////////////////////////////////////////////////////////////
63 // Implementation specific tracing API definitions.
64 
65 // Get a pointer to the enabled state of the given trace category. Only
66 // long-lived literal strings should be given as the category group. The
67 // returned pointer can be held permanently in a local static for example. If
68 // the unsigned char is non-zero, tracing is enabled. If tracing is enabled,
69 // TRACE_EVENT_API_ADD_TRACE_EVENT can be called. It's OK if tracing is disabled
70 // between the load of the tracing state and the call to
71 // TRACE_EVENT_API_ADD_TRACE_EVENT, because this flag only provides an early out
72 // for best performance when tracing is disabled.
73 // const uint8_t*
74 //     TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(const char* category_group)
75 #define TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED              \
76   v8::internal::tracing::TraceEventHelper::GetCurrentPlatform() \
77       ->GetCategoryGroupEnabled
78 
79 // Get the number of times traces have been recorded. This is used to implement
80 // the TRACE_EVENT_IS_NEW_TRACE facility.
81 // unsigned int TRACE_EVENT_API_GET_NUM_TRACES_RECORDED()
82 #define TRACE_EVENT_API_GET_NUM_TRACES_RECORDED UNIMPLEMENTED()
83 
84 // Add a trace event to the platform tracing system.
85 // uint64_t TRACE_EVENT_API_ADD_TRACE_EVENT(
86 //                    char phase,
87 //                    const uint8_t* category_group_enabled,
88 //                    const char* name,
89 //                    const char* scope,
90 //                    uint64_t id,
91 //                    uint64_t bind_id,
92 //                    int num_args,
93 //                    const char** arg_names,
94 //                    const uint8_t* arg_types,
95 //                    const uint64_t* arg_values,
96 //                    unsigned int flags)
97 #define TRACE_EVENT_API_ADD_TRACE_EVENT v8::internal::tracing::AddTraceEventImpl
98 
99 // Set the duration field of a COMPLETE trace event.
100 // void TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(
101 //     const uint8_t* category_group_enabled,
102 //     const char* name,
103 //     uint64_t id)
104 #define TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION             \
105   v8::internal::tracing::TraceEventHelper::GetCurrentPlatform() \
106       ->UpdateTraceEventDuration
107 
108 // Defines atomic operations used internally by the tracing system.
109 #define TRACE_EVENT_API_ATOMIC_WORD v8::base::AtomicWord
110 #define TRACE_EVENT_API_ATOMIC_LOAD(var) v8::base::NoBarrier_Load(&(var))
111 #define TRACE_EVENT_API_ATOMIC_STORE(var, value) \
112   v8::base::NoBarrier_Store(&(var), (value))
113 
114 ////////////////////////////////////////////////////////////////////////////////
115 
116 // Implementation detail: trace event macros create temporary variables
117 // to keep instrumentation overhead low. These macros give each temporary
118 // variable a unique name based on the line number to prevent name collisions.
119 #define INTERNAL_TRACE_EVENT_UID3(a, b) trace_event_unique_##a##b
120 #define INTERNAL_TRACE_EVENT_UID2(a, b) INTERNAL_TRACE_EVENT_UID3(a, b)
121 #define INTERNAL_TRACE_EVENT_UID(name_prefix) \
122   INTERNAL_TRACE_EVENT_UID2(name_prefix, __LINE__)
123 
124 // Implementation detail: internal macro to create static category.
125 // No barriers are needed, because this code is designed to operate safely
126 // even when the unsigned char* points to garbage data (which may be the case
127 // on processors without cache coherency).
128 // TODO(fmeawad): This implementation contradicts that we can have a different
129 // configuration for each isolate,
130 // https://code.google.com/p/v8/issues/detail?id=4563
131 #define INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO_CUSTOM_VARIABLES(             \
132     category_group, atomic, category_group_enabled)                          \
133   category_group_enabled =                                                   \
134       reinterpret_cast<const uint8_t*>(TRACE_EVENT_API_ATOMIC_LOAD(atomic)); \
135   if (!category_group_enabled) {                                             \
136     category_group_enabled =                                                 \
137         TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(category_group);          \
138     TRACE_EVENT_API_ATOMIC_STORE(                                            \
139         atomic, reinterpret_cast<TRACE_EVENT_API_ATOMIC_WORD>(               \
140                     category_group_enabled));                                \
141   }
142 
143 #define INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group)             \
144   static TRACE_EVENT_API_ATOMIC_WORD INTERNAL_TRACE_EVENT_UID(atomic) = 0; \
145   const uint8_t* INTERNAL_TRACE_EVENT_UID(category_group_enabled);         \
146   INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO_CUSTOM_VARIABLES(                 \
147       category_group, INTERNAL_TRACE_EVENT_UID(atomic),                    \
148       INTERNAL_TRACE_EVENT_UID(category_group_enabled));
149 
150 // Implementation detail: internal macro to create static category and add
151 // event if the category is enabled.
152 #define INTERNAL_TRACE_EVENT_ADD(phase, category_group, name, flags, ...)    \
153   do {                                                                       \
154     INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group);                  \
155     if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) {  \
156       v8::internal::tracing::AddTraceEvent(                                  \
157           phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), name,     \
158           v8::internal::tracing::kGlobalScope, v8::internal::tracing::kNoId, \
159           v8::internal::tracing::kNoId, flags, ##__VA_ARGS__);               \
160     }                                                                        \
161   } while (0)
162 
163 // Implementation detail: internal macro to create static category and add begin
164 // event if the category is enabled. Also adds the end event when the scope
165 // ends.
166 #define INTERNAL_TRACE_EVENT_ADD_SCOPED(category_group, name, ...)           \
167   INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group);                    \
168   v8::internal::tracing::ScopedTracer INTERNAL_TRACE_EVENT_UID(tracer);      \
169   if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) {    \
170     uint64_t h = v8::internal::tracing::AddTraceEvent(                       \
171         TRACE_EVENT_PHASE_COMPLETE,                                          \
172         INTERNAL_TRACE_EVENT_UID(category_group_enabled), name,              \
173         v8::internal::tracing::kGlobalScope, v8::internal::tracing::kNoId,   \
174         v8::internal::tracing::kNoId, TRACE_EVENT_FLAG_NONE, ##__VA_ARGS__); \
175     INTERNAL_TRACE_EVENT_UID(tracer)                                         \
176         .Initialize(INTERNAL_TRACE_EVENT_UID(category_group_enabled), name,  \
177                     h);                                                      \
178   }
179 
180 #define INTERNAL_TRACE_EVENT_ADD_SCOPED_WITH_FLOW(category_group, name,     \
181                                                   bind_id, flow_flags, ...) \
182   INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group);                   \
183   v8::internal::tracing::ScopedTracer INTERNAL_TRACE_EVENT_UID(tracer);     \
184   if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) {   \
185     unsigned int trace_event_flags = flow_flags;                            \
186     v8::internal::tracing::TraceID trace_event_bind_id(bind_id,             \
187                                                        &trace_event_flags); \
188     uint64_t h = v8::internal::tracing::AddTraceEvent(                      \
189         TRACE_EVENT_PHASE_COMPLETE,                                         \
190         INTERNAL_TRACE_EVENT_UID(category_group_enabled), name,             \
191         v8::internal::tracing::kGlobalScope, v8::internal::tracing::kNoId,  \
192         trace_event_bind_id.raw_id(), trace_event_flags, ##__VA_ARGS__);    \
193     INTERNAL_TRACE_EVENT_UID(tracer)                                        \
194         .Initialize(INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, \
195                     h);                                                     \
196   }
197 
198 // Implementation detail: internal macro to create static category and add
199 // event if the category is enabled.
200 #define INTERNAL_TRACE_EVENT_ADD_WITH_ID(phase, category_group, name, id,      \
201                                          flags, ...)                           \
202   do {                                                                         \
203     INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group);                    \
204     if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) {    \
205       unsigned int trace_event_flags = flags | TRACE_EVENT_FLAG_HAS_ID;        \
206       v8::internal::tracing::TraceID trace_event_trace_id(id,                  \
207                                                           &trace_event_flags); \
208       v8::internal::tracing::AddTraceEvent(                                    \
209           phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), name,       \
210           trace_event_trace_id.scope(), trace_event_trace_id.raw_id(),         \
211           v8::internal::tracing::kNoId, trace_event_flags, ##__VA_ARGS__);     \
212     }                                                                          \
213   } while (0)
214 
215 // Adds a trace event with a given timestamp. Not Implemented.
216 #define INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP(phase, category_group, name, \
217                                                 timestamp, flags, ...)       \
218   UNIMPLEMENTED()
219 
220 // Adds a trace event with a given id and timestamp. Not Implemented.
221 #define INTERNAL_TRACE_EVENT_ADD_WITH_ID_AND_TIMESTAMP(     \
222     phase, category_group, name, id, timestamp, flags, ...) \
223   UNIMPLEMENTED()
224 
225 // Adds a trace event with a given id, thread_id, and timestamp. Not
226 // Implemented.
227 #define INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(            \
228     phase, category_group, name, id, thread_id, timestamp, flags, ...) \
229   UNIMPLEMENTED()
230 
231 // Enter and leave a context based on the current scope.
232 #define INTERNAL_TRACE_EVENT_SCOPED_CONTEXT(category_group, name, context) \
233   struct INTERNAL_TRACE_EVENT_UID(ScopedContext) {                         \
234    public:                                                                 \
235     INTERNAL_TRACE_EVENT_UID(ScopedContext)(uint64_t cid) : cid_(cid) {    \
236       TRACE_EVENT_ENTER_CONTEXT(category_group, name, cid_);               \
237     }                                                                      \
238     ~INTERNAL_TRACE_EVENT_UID(ScopedContext)() {                           \
239       TRACE_EVENT_LEAVE_CONTEXT(category_group, name, cid_);               \
240     }                                                                      \
241                                                                            \
242    private:                                                                \
243     /* Local class friendly DISALLOW_COPY_AND_ASSIGN */                    \
244     INTERNAL_TRACE_EVENT_UID(ScopedContext)                                \
245     (const INTERNAL_TRACE_EVENT_UID(ScopedContext)&) {}                    \
246     void operator=(const INTERNAL_TRACE_EVENT_UID(ScopedContext)&) {}      \
247     uint64_t cid_;                                                         \
248   };                                                                       \
249   INTERNAL_TRACE_EVENT_UID(ScopedContext)                                  \
250   INTERNAL_TRACE_EVENT_UID(scoped_context)(context);
251 
252 #define TRACE_EVENT_CALL_STATS_SCOPED(isolate, category_group, name) \
253   INTERNAL_TRACE_EVENT_CALL_STATS_SCOPED(isolate, category_group, name)
254 
255 #define INTERNAL_TRACE_EVENT_CALL_STATS_SCOPED(isolate, category_group, name)  \
256   INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group);                      \
257   v8::internal::tracing::CallStatsScopedTracer INTERNAL_TRACE_EVENT_UID(       \
258       tracer);                                                                 \
259   if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) {      \
260     INTERNAL_TRACE_EVENT_UID(tracer)                                           \
261         .Initialize(isolate, INTERNAL_TRACE_EVENT_UID(category_group_enabled), \
262                     name);                                                     \
263   }
264 
265 namespace v8 {
266 namespace internal {
267 
268 class Isolate;
269 
270 namespace tracing {
271 
272 // Specify these values when the corresponding argument of AddTraceEvent is not
273 // used.
274 const int kZeroNumArgs = 0;
275 const decltype(nullptr) kGlobalScope = nullptr;
276 const uint64_t kNoId = 0;
277 
278 extern base::Atomic32 kRuntimeCallStatsTracingEnabled;
279 
280 class TraceEventHelper {
281  public:
282   static v8::Platform* GetCurrentPlatform();
283 };
284 
285 // TraceID encapsulates an ID that can either be an integer or pointer. Pointers
286 // are by default mangled with the Process ID so that they are unlikely to
287 // collide when the same pointer is used on different processes.
288 class TraceID {
289  public:
290   class WithScope {
291    public:
WithScope(const char * scope,uint64_t raw_id)292     WithScope(const char* scope, uint64_t raw_id)
293         : scope_(scope), raw_id_(raw_id) {}
raw_id()294     uint64_t raw_id() const { return raw_id_; }
scope()295     const char* scope() const { return scope_; }
296 
297    private:
298     const char* scope_ = nullptr;
299     uint64_t raw_id_;
300   };
301 
302   class DontMangle {
303    public:
DontMangle(const void * raw_id)304     explicit DontMangle(const void* raw_id)
305         : raw_id_(static_cast<uint64_t>(reinterpret_cast<uintptr_t>(raw_id))) {}
DontMangle(uint64_t raw_id)306     explicit DontMangle(uint64_t raw_id) : raw_id_(raw_id) {}
DontMangle(unsigned int raw_id)307     explicit DontMangle(unsigned int raw_id) : raw_id_(raw_id) {}
DontMangle(uint16_t raw_id)308     explicit DontMangle(uint16_t raw_id) : raw_id_(raw_id) {}
DontMangle(unsigned char raw_id)309     explicit DontMangle(unsigned char raw_id) : raw_id_(raw_id) {}
DontMangle(int64_t raw_id)310     explicit DontMangle(int64_t raw_id)
311         : raw_id_(static_cast<uint64_t>(raw_id)) {}
DontMangle(int raw_id)312     explicit DontMangle(int raw_id) : raw_id_(static_cast<uint64_t>(raw_id)) {}
DontMangle(int16_t raw_id)313     explicit DontMangle(int16_t raw_id)
314         : raw_id_(static_cast<uint64_t>(raw_id)) {}
DontMangle(signed char raw_id)315     explicit DontMangle(signed char raw_id)
316         : raw_id_(static_cast<uint64_t>(raw_id)) {}
DontMangle(WithScope scoped_id)317     explicit DontMangle(WithScope scoped_id)
318         : scope_(scoped_id.scope()), raw_id_(scoped_id.raw_id()) {}
scope()319     const char* scope() const { return scope_; }
raw_id()320     uint64_t raw_id() const { return raw_id_; }
321 
322    private:
323     const char* scope_ = nullptr;
324     uint64_t raw_id_;
325   };
326 
327   class ForceMangle {
328    public:
ForceMangle(uint64_t raw_id)329     explicit ForceMangle(uint64_t raw_id) : raw_id_(raw_id) {}
ForceMangle(unsigned int raw_id)330     explicit ForceMangle(unsigned int raw_id) : raw_id_(raw_id) {}
ForceMangle(uint16_t raw_id)331     explicit ForceMangle(uint16_t raw_id) : raw_id_(raw_id) {}
ForceMangle(unsigned char raw_id)332     explicit ForceMangle(unsigned char raw_id) : raw_id_(raw_id) {}
ForceMangle(int64_t raw_id)333     explicit ForceMangle(int64_t raw_id)
334         : raw_id_(static_cast<uint64_t>(raw_id)) {}
ForceMangle(int raw_id)335     explicit ForceMangle(int raw_id) : raw_id_(static_cast<uint64_t>(raw_id)) {}
ForceMangle(int16_t raw_id)336     explicit ForceMangle(int16_t raw_id)
337         : raw_id_(static_cast<uint64_t>(raw_id)) {}
ForceMangle(signed char raw_id)338     explicit ForceMangle(signed char raw_id)
339         : raw_id_(static_cast<uint64_t>(raw_id)) {}
raw_id()340     uint64_t raw_id() const { return raw_id_; }
341 
342    private:
343     uint64_t raw_id_;
344   };
345 
TraceID(const void * raw_id,unsigned int * flags)346   TraceID(const void* raw_id, unsigned int* flags)
347       : raw_id_(static_cast<uint64_t>(reinterpret_cast<uintptr_t>(raw_id))) {
348     *flags |= TRACE_EVENT_FLAG_MANGLE_ID;
349   }
TraceID(ForceMangle raw_id,unsigned int * flags)350   TraceID(ForceMangle raw_id, unsigned int* flags) : raw_id_(raw_id.raw_id()) {
351     *flags |= TRACE_EVENT_FLAG_MANGLE_ID;
352   }
TraceID(DontMangle maybe_scoped_id,unsigned int * flags)353   TraceID(DontMangle maybe_scoped_id, unsigned int* flags)
354       : scope_(maybe_scoped_id.scope()), raw_id_(maybe_scoped_id.raw_id()) {}
TraceID(uint64_t raw_id,unsigned int * flags)355   TraceID(uint64_t raw_id, unsigned int* flags) : raw_id_(raw_id) {
356     (void)flags;
357   }
TraceID(unsigned int raw_id,unsigned int * flags)358   TraceID(unsigned int raw_id, unsigned int* flags) : raw_id_(raw_id) {
359     (void)flags;
360   }
TraceID(uint16_t raw_id,unsigned int * flags)361   TraceID(uint16_t raw_id, unsigned int* flags) : raw_id_(raw_id) {
362     (void)flags;
363   }
TraceID(unsigned char raw_id,unsigned int * flags)364   TraceID(unsigned char raw_id, unsigned int* flags) : raw_id_(raw_id) {
365     (void)flags;
366   }
TraceID(int64_t raw_id,unsigned int * flags)367   TraceID(int64_t raw_id, unsigned int* flags)
368       : raw_id_(static_cast<uint64_t>(raw_id)) {
369     (void)flags;
370   }
TraceID(int raw_id,unsigned int * flags)371   TraceID(int raw_id, unsigned int* flags)
372       : raw_id_(static_cast<uint64_t>(raw_id)) {
373     (void)flags;
374   }
TraceID(int16_t raw_id,unsigned int * flags)375   TraceID(int16_t raw_id, unsigned int* flags)
376       : raw_id_(static_cast<uint64_t>(raw_id)) {
377     (void)flags;
378   }
TraceID(signed char raw_id,unsigned int * flags)379   TraceID(signed char raw_id, unsigned int* flags)
380       : raw_id_(static_cast<uint64_t>(raw_id)) {
381     (void)flags;
382   }
TraceID(WithScope scoped_id,unsigned int * flags)383   TraceID(WithScope scoped_id, unsigned int* flags)
384       : scope_(scoped_id.scope()), raw_id_(scoped_id.raw_id()) {}
385 
raw_id()386   uint64_t raw_id() const { return raw_id_; }
scope()387   const char* scope() const { return scope_; }
388 
389  private:
390   const char* scope_ = nullptr;
391   uint64_t raw_id_;
392 };
393 
394 // Simple union to store various types as uint64_t.
395 union TraceValueUnion {
396   bool as_bool;
397   uint64_t as_uint;
398   int64_t as_int;
399   double as_double;
400   const void* as_pointer;
401   const char* as_string;
402 };
403 
404 // Simple container for const char* that should be copied instead of retained.
405 class TraceStringWithCopy {
406  public:
TraceStringWithCopy(const char * str)407   explicit TraceStringWithCopy(const char* str) : str_(str) {}
408   operator const char*() const { return str_; }
409 
410  private:
411   const char* str_;
412 };
413 
AddTraceEventImpl(char phase,const uint8_t * category_group_enabled,const char * name,const char * scope,uint64_t id,uint64_t bind_id,int32_t num_args,const char ** arg_names,const uint8_t * arg_types,const uint64_t * arg_values,unsigned int flags)414 static V8_INLINE uint64_t AddTraceEventImpl(
415     char phase, const uint8_t* category_group_enabled, const char* name,
416     const char* scope, uint64_t id, uint64_t bind_id, int32_t num_args,
417     const char** arg_names, const uint8_t* arg_types,
418     const uint64_t* arg_values, unsigned int flags) {
419   std::unique_ptr<ConvertableToTraceFormat> arg_convertables[2];
420   if (num_args > 0 && arg_types[0] == TRACE_VALUE_TYPE_CONVERTABLE) {
421     arg_convertables[0].reset(reinterpret_cast<ConvertableToTraceFormat*>(
422         static_cast<intptr_t>(arg_values[0])));
423   }
424   if (num_args > 1 && arg_types[1] == TRACE_VALUE_TYPE_CONVERTABLE) {
425     arg_convertables[1].reset(reinterpret_cast<ConvertableToTraceFormat*>(
426         static_cast<intptr_t>(arg_values[1])));
427   }
428   DCHECK(num_args <= 2);
429   v8::Platform* platform =
430       v8::internal::tracing::TraceEventHelper::GetCurrentPlatform();
431   return platform->AddTraceEvent(phase, category_group_enabled, name, scope, id,
432                                  bind_id, num_args, arg_names, arg_types,
433                                  arg_values, arg_convertables, flags);
434 }
435 
436 // Define SetTraceValue for each allowed type. It stores the type and
437 // value in the return arguments. This allows this API to avoid declaring any
438 // structures so that it is portable to third_party libraries.
439 #define INTERNAL_DECLARE_SET_TRACE_VALUE(actual_type, union_member,         \
440                                          value_type_id)                     \
441   static V8_INLINE void SetTraceValue(actual_type arg, unsigned char* type, \
442                                       uint64_t* value) {                    \
443     TraceValueUnion type_value;                                             \
444     type_value.union_member = arg;                                          \
445     *type = value_type_id;                                                  \
446     *value = type_value.as_uint;                                            \
447   }
448 // Simpler form for int types that can be safely casted.
449 #define INTERNAL_DECLARE_SET_TRACE_VALUE_INT(actual_type, value_type_id)    \
450   static V8_INLINE void SetTraceValue(actual_type arg, unsigned char* type, \
451                                       uint64_t* value) {                    \
452     *type = value_type_id;                                                  \
453     *value = static_cast<uint64_t>(arg);                                    \
454   }
455 
INTERNAL_DECLARE_SET_TRACE_VALUE_INT(uint64_t,TRACE_VALUE_TYPE_UINT)456 INTERNAL_DECLARE_SET_TRACE_VALUE_INT(uint64_t, TRACE_VALUE_TYPE_UINT)
457 INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned int, TRACE_VALUE_TYPE_UINT)
458 INTERNAL_DECLARE_SET_TRACE_VALUE_INT(uint16_t, TRACE_VALUE_TYPE_UINT)
459 INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned char, TRACE_VALUE_TYPE_UINT)
460 INTERNAL_DECLARE_SET_TRACE_VALUE_INT(int64_t, TRACE_VALUE_TYPE_INT)
461 INTERNAL_DECLARE_SET_TRACE_VALUE_INT(int, TRACE_VALUE_TYPE_INT)
462 INTERNAL_DECLARE_SET_TRACE_VALUE_INT(int16_t, TRACE_VALUE_TYPE_INT)
463 INTERNAL_DECLARE_SET_TRACE_VALUE_INT(signed char, TRACE_VALUE_TYPE_INT)
464 INTERNAL_DECLARE_SET_TRACE_VALUE(bool, as_bool, TRACE_VALUE_TYPE_BOOL)
465 INTERNAL_DECLARE_SET_TRACE_VALUE(double, as_double, TRACE_VALUE_TYPE_DOUBLE)
466 INTERNAL_DECLARE_SET_TRACE_VALUE(const void*, as_pointer,
467                                  TRACE_VALUE_TYPE_POINTER)
468 INTERNAL_DECLARE_SET_TRACE_VALUE(const char*, as_string,
469                                  TRACE_VALUE_TYPE_STRING)
470 INTERNAL_DECLARE_SET_TRACE_VALUE(const TraceStringWithCopy&, as_string,
471                                  TRACE_VALUE_TYPE_COPY_STRING)
472 
473 #undef INTERNAL_DECLARE_SET_TRACE_VALUE
474 #undef INTERNAL_DECLARE_SET_TRACE_VALUE_INT
475 
476 static V8_INLINE void SetTraceValue(ConvertableToTraceFormat* convertable_value,
477                                     unsigned char* type, uint64_t* value) {
478   *type = TRACE_VALUE_TYPE_CONVERTABLE;
479   *value = static_cast<uint64_t>(reinterpret_cast<intptr_t>(convertable_value));
480 }
481 
482 template <typename T>
483 static V8_INLINE typename std::enable_if<
484     std::is_convertible<T*, ConvertableToTraceFormat*>::value>::type
SetTraceValue(std::unique_ptr<T> ptr,unsigned char * type,uint64_t * value)485 SetTraceValue(std::unique_ptr<T> ptr, unsigned char* type, uint64_t* value) {
486   SetTraceValue(ptr.release(), type, value);
487 }
488 
489 // These AddTraceEvent template
490 // function is defined here instead of in the macro, because the arg_values
491 // could be temporary objects, such as std::string. In order to store
492 // pointers to the internal c_str and pass through to the tracing API,
493 // the arg_values must live throughout these procedures.
494 
AddTraceEvent(char phase,const uint8_t * category_group_enabled,const char * name,const char * scope,uint64_t id,uint64_t bind_id,unsigned int flags)495 static V8_INLINE uint64_t AddTraceEvent(char phase,
496                                         const uint8_t* category_group_enabled,
497                                         const char* name, const char* scope,
498                                         uint64_t id, uint64_t bind_id,
499                                         unsigned int flags) {
500   return TRACE_EVENT_API_ADD_TRACE_EVENT(phase, category_group_enabled, name,
501                                          scope, id, bind_id, kZeroNumArgs,
502                                          nullptr, nullptr, nullptr, flags);
503 }
504 
505 template <class ARG1_TYPE>
AddTraceEvent(char phase,const uint8_t * category_group_enabled,const char * name,const char * scope,uint64_t id,uint64_t bind_id,unsigned int flags,const char * arg1_name,ARG1_TYPE && arg1_val)506 static V8_INLINE uint64_t AddTraceEvent(
507     char phase, const uint8_t* category_group_enabled, const char* name,
508     const char* scope, uint64_t id, uint64_t bind_id, unsigned int flags,
509     const char* arg1_name, ARG1_TYPE&& arg1_val) {
510   const int num_args = 1;
511   uint8_t arg_type;
512   uint64_t arg_value;
513   SetTraceValue(std::forward<ARG1_TYPE>(arg1_val), &arg_type, &arg_value);
514   return TRACE_EVENT_API_ADD_TRACE_EVENT(
515       phase, category_group_enabled, name, scope, id, bind_id, num_args,
516       &arg1_name, &arg_type, &arg_value, flags);
517 }
518 
519 template <class ARG1_TYPE, class ARG2_TYPE>
AddTraceEvent(char phase,const uint8_t * category_group_enabled,const char * name,const char * scope,uint64_t id,uint64_t bind_id,unsigned int flags,const char * arg1_name,ARG1_TYPE && arg1_val,const char * arg2_name,ARG2_TYPE && arg2_val)520 static V8_INLINE uint64_t AddTraceEvent(
521     char phase, const uint8_t* category_group_enabled, const char* name,
522     const char* scope, uint64_t id, uint64_t bind_id, unsigned int flags,
523     const char* arg1_name, ARG1_TYPE&& arg1_val, const char* arg2_name,
524     ARG2_TYPE&& arg2_val) {
525   const int num_args = 2;
526   const char* arg_names[2] = {arg1_name, arg2_name};
527   unsigned char arg_types[2];
528   uint64_t arg_values[2];
529   SetTraceValue(std::forward<ARG1_TYPE>(arg1_val), &arg_types[0],
530                 &arg_values[0]);
531   SetTraceValue(std::forward<ARG2_TYPE>(arg2_val), &arg_types[1],
532                 &arg_values[1]);
533   return TRACE_EVENT_API_ADD_TRACE_EVENT(
534       phase, category_group_enabled, name, scope, id, bind_id, num_args,
535       arg_names, arg_types, arg_values, flags);
536 }
537 
538 // Used by TRACE_EVENTx macros. Do not use directly.
539 class ScopedTracer {
540  public:
541   // Note: members of data_ intentionally left uninitialized. See Initialize.
ScopedTracer()542   ScopedTracer() : p_data_(NULL) {}
543 
~ScopedTracer()544   ~ScopedTracer() {
545     if (p_data_ && *data_.category_group_enabled)
546       TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(
547           data_.category_group_enabled, data_.name, data_.event_handle);
548   }
549 
Initialize(const uint8_t * category_group_enabled,const char * name,uint64_t event_handle)550   void Initialize(const uint8_t* category_group_enabled, const char* name,
551                   uint64_t event_handle) {
552     data_.category_group_enabled = category_group_enabled;
553     data_.name = name;
554     data_.event_handle = event_handle;
555     p_data_ = &data_;
556   }
557 
558  private:
559   // This Data struct workaround is to avoid initializing all the members
560   // in Data during construction of this object, since this object is always
561   // constructed, even when tracing is disabled. If the members of Data were
562   // members of this class instead, compiler warnings occur about potential
563   // uninitialized accesses.
564   struct Data {
565     const uint8_t* category_group_enabled;
566     const char* name;
567     uint64_t event_handle;
568   };
569   Data* p_data_;
570   Data data_;
571 };
572 
573 // Do not use directly.
574 class CallStatsScopedTracer {
575  public:
CallStatsScopedTracer()576   CallStatsScopedTracer() : p_data_(nullptr) {}
~CallStatsScopedTracer()577   ~CallStatsScopedTracer() {
578     if (V8_UNLIKELY(p_data_ && *data_.category_group_enabled)) {
579       AddEndTraceEvent();
580     }
581   }
582 
583   void Initialize(v8::internal::Isolate* isolate,
584                   const uint8_t* category_group_enabled, const char* name);
585 
586  private:
587   void AddEndTraceEvent();
588   struct Data {
589     const uint8_t* category_group_enabled;
590     const char* name;
591     v8::internal::Isolate* isolate;
592   };
593   bool has_parent_scope_;
594   Data* p_data_;
595   Data data_;
596 };
597 
598 }  // namespace tracing
599 }  // namespace internal
600 }  // namespace v8
601 
602 #endif  // SRC_TRACING_TRACE_EVENT_H_
603