• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
7 #pragma allow_unsafe_buffers
8 #endif
9 
10 #ifndef BASE_TRACE_EVENT_TRACE_ARGUMENTS_H_
11 #define BASE_TRACE_EVENT_TRACE_ARGUMENTS_H_
12 
13 #include <stdlib.h>
14 #include <string.h>
15 
16 #include <algorithm>
17 #include <memory>
18 #include <string>
19 #include <utility>
20 
21 #include "base/base_export.h"
22 #include "base/memory/raw_ptr_exclusion.h"
23 #include "base/trace_event/common/trace_event_common.h"
24 #include "base/tracing_buildflags.h"
25 #include "third_party/perfetto/include/perfetto/protozero/scattered_heap_buffer.h"
26 #include "third_party/perfetto/include/perfetto/tracing/traced_value.h"
27 #include "third_party/perfetto/protos/perfetto/trace/track_event/debug_annotation.pbzero.h"
28 
29 // Trace macro can have one or two optional arguments, each one of them
30 // identified by a name (a C string literal) and a value, which can be an
31 // integer, enum, floating point, boolean, string pointer or reference, or
32 // std::unique_ptr<ConvertableToTraceFormat> compatible values. Additionally,
33 // custom data types need to be supported, like time values or WTF::CString.
34 //
35 // TraceArguments is a helper class used to store 0 to 2 named arguments
36 // corresponding to an individual trace macro call. As efficiently as possible,
37 // and with the minimal amount of generated machine code (since this affects
38 // any TRACE macro call). Each argument has:
39 //
40 //  - A name (C string literal, e.g "dumps")
41 //  - An 8-bit type value, corresponding to the TRACE_VALUE_TYPE_XXX macros.
42 //  - A value, stored in a TraceValue union
43 //
44 // IMPORTANT: For a TRACE_VALUE_TYPE_CONVERTABLE types, the TraceArguments
45 // instance owns the pointed ConvertableToTraceFormat object, i.e. it will
46 // delete it automatically on destruction.
47 //
48 // TraceArguments instances should be built using one of specialized
49 // constructors declared below. One cannot modify an instance once it has
50 // been built, except for move operations, Reset() and destruction. Examples:
51 //
52 //    TraceArguments args;    // No arguments.
53 //    // args.size() == 0
54 //
55 //    TraceArguments("foo", 100);
56 //    // args.size() == 1
57 //    // args.types()[0] == TRACE_VALUE_TYPE_INT
58 //    // args.names()[0] == "foo"
59 //    // args.values()[0].as_int == 100
60 //
61 //    TraceArguments("bar", 1ULL);
62 //    // args.size() == 1
63 //    // args.types()[0] == TRACE_VALUE_TYPE_UINT
64 //    // args.names()[0] == "bar"
65 //    // args.values()[0].as_uint == 100
66 //
67 //    TraceArguments("foo", "Hello", "bar", "World");
68 //    // args.size() == 2
69 //    // args.types()[0] == TRACE_VALUE_TYPE_STRING
70 //    // args.types()[1] == TRACE_VALUE_TYPE_STRING
71 //    // args.names()[0] == "foo"
72 //    // args.names()[1] == "bar"
73 //    // args.values()[0].as_string == "Hello"
74 //    // args.values()[1].as_string == "World"
75 //
76 //    std::string some_string = ...;
77 //    TraceArguments("str1", some_string);
78 //    // args.size() == 1
79 //    // args.types()[0] == TRACE_VALUE_TYPE_COPY_STRING
80 //    // args.names()[0] == "str1"
81 //    // args.values()[0].as_string == some_string.c_str()
82 //
83 // Note that TRACE_VALUE_TYPE_COPY_STRING corresponds to string pointers
84 // that point to temporary values that may disappear soon. The
85 // TraceArguments::CopyStringTo() method can be used to copy their content
86 // into a StringStorage memory block, and update the |as_string| value pointers
87 // to it to avoid keeping any dangling pointers. This is used by TraceEvent
88 // to keep copies of such strings in the log after their initialization values
89 // have disappeared.
90 //
91 // The TraceStringWithCopy helper class can be used to initialize a value
92 // from a regular string pointer with TRACE_VALUE_TYPE_COPY_STRING too, as in:
93 //
94 //     const char str[] = "....";
95 //     TraceArguments("foo", str, "bar", TraceStringWithCopy(str));
96 //     // args.size() == 2
97 //     // args.types()[0] == TRACE_VALUE_TYPE_STRING
98 //     // args.types()[1] == TRACE_VALUE_TYPE_COPY_STRING
99 //     // args.names()[0] == "foo"
100 //     // args.names()[1] == "bar"
101 //     // args.values()[0].as_string == str
102 //     // args.values()[1].as_string == str
103 //
104 //     StringStorage storage;
105 //     args.CopyStringTo(&storage, false, nullptr, nullptr);
106 //     // args.size() == 2
107 //     // args.types()[0] == TRACE_VALUE_TYPE_STRING
108 //     // args.types()[1] == TRACE_VALUE_TYPE_COPY_STRING
109 //     // args.names()[0] == "foo"
110 //     // args.names()[1] == "bar"
111 //     // args.values()[0].as_string == str
112 //     // args.values()[1].as_string == Address inside |storage|.
113 //
114 // Initialization from a std::unique_ptr<ConvertableToTraceFormat>
115 // is supported but will move ownership of the pointer objects to the
116 // TraceArguments instance:
117 //
118 //     class MyConvertableType :
119 //         public base::trace_event::AsConvertableToTraceFormat {
120 //        ...
121 //     };
122 //
123 //     {
124 //       TraceArguments args("foo" , std::make_unique<MyConvertableType>(...));
125 //       // args.size() == 1
126 //       // args.values()[0].as_convertable == address of MyConvertable object.
127 //     } // Calls |args| destructor, which will delete the object too.
128 //
129 // Finally, it is possible to support initialization from custom values by
130 // specializing the TraceValue::Helper<> template struct as described below.
131 //
132 // This is how values of custom types like WTF::CString can be passed directly
133 // to trace macros.
134 
135 namespace base {
136 
137 class Time;
138 class TimeTicks;
139 class ThreadTicks;
140 
141 namespace trace_event {
142 
143 class TraceEventMemoryOverhead;
144 
145 // For any argument of type TRACE_VALUE_TYPE_CONVERTABLE the provided
146 // class must implement this interface. Note that unlike other values,
147 // these objects will be owned by the TraceArguments instance that points
148 // to them.
149 class BASE_EXPORT ConvertableToTraceFormat
150     : public perfetto::DebugAnnotation
151 {
152  public:
153   ConvertableToTraceFormat() = default;
154   ConvertableToTraceFormat(const ConvertableToTraceFormat&) = delete;
155   ConvertableToTraceFormat& operator=(const ConvertableToTraceFormat&) = delete;
156   ~ConvertableToTraceFormat() override = default;
157 
158   // Append the class info to the provided |out| string. The appended
159   // data must be a valid JSON object. Strings must be properly quoted, and
160   // escaped. There is no processing applied to the content after it is
161   // appended.
162   virtual void AppendAsTraceFormat(std::string* out) const = 0;
163 
164   // Append the class info directly into the Perfetto-defined proto
165   // format; this is attempted first and if this returns true,
166   // AppendAsTraceFormat is not called. The ProtoAppender interface
167   // acts as a bridge to avoid proto/Perfetto dependencies in base.
168   class BASE_EXPORT ProtoAppender {
169    public:
170     virtual ~ProtoAppender() = default;
171 
172     virtual void AddBuffer(uint8_t* begin, uint8_t* end) = 0;
173     // Copy all of the previous buffers registered with AddBuffer
174     // into the proto, with the given |field_id|.
175     virtual size_t Finalize(uint32_t field_id) = 0;
176   };
177   virtual bool AppendToProto(ProtoAppender* appender) const;
178 
179   virtual void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead);
180 
181   // DebugAnnotation implementation.
182   void Add(perfetto::protos::pbzero::DebugAnnotation*) const override;
183 };
184 
185 const int kTraceMaxNumArgs = 2;
186 
187 // A union used to hold the values of individual trace arguments.
188 //
189 // This is a POD union for performance reason. Initialization from an
190 // explicit C++ trace argument should be performed with the Init()
191 // templated method described below.
192 //
193 // Initialization from custom types is possible by implementing a custom
194 // TraceValue::Helper<> instantiation as described below.
195 //
196 // IMPORTANT: Pointer storage inside a TraceUnion follows specific rules:
197 //
198 //   - |as_pointer| is for raw pointers that should be treated as a simple
199 //     address and will never be dereferenced. Associated with the
200 //     TRACE_VALUE_TYPE_POINTER type.
201 //
202 //   - |as_string| is for C-string pointers, associated with both
203 //     TRACE_VALUE_TYPE_STRING and TRACE_VALUE_TYPE_COPY_STRING. The former
204 //     indicates that the string pointer is persistent (e.g. a C string
205 //     literal), while the second indicates that the pointer belongs to a
206 //     temporary variable that may disappear soon. The TraceArguments class
207 //     provides a CopyStringTo() method to copy these strings into a
208 //     StringStorage instance, which is useful if the instance needs to
209 //     survive longer than the temporaries.
210 //
211 //   - |as_convertable| is equivalent to
212 //     std::unique_ptr<ConvertableToTraceFormat>, except that it is a pointer
213 //     to keep this union POD and avoid un-necessary declarations and potential
214 //     code generation. This means that its ownership is passed to the
215 //     TraceValue instance when Init(std::unique_ptr<ConvertableToTraceFormat>)
216 //     is called, and that it will be deleted by the containing TraceArguments
217 //     destructor, or Reset() method.
218 //
219 union BASE_EXPORT TraceValue {
220   bool as_bool;
221   unsigned long long as_uint;
222   long long as_int;
223   double as_double;
224   // This field is not a raw_ptr<> because it was filtered by the rewriter for:
225   // #union
226   RAW_PTR_EXCLUSION const void* as_pointer;
227   const char* as_string;
228   // This field is not a raw_ptr<> because it was filtered by the rewriter for:
229   // #union
230   RAW_PTR_EXCLUSION ConvertableToTraceFormat* as_convertable;
231   // This field is not a raw_ptr<> because it was filtered by the rewriter for:
232   // #union
233   RAW_PTR_EXCLUSION protozero::HeapBuffered<
234       perfetto::protos::pbzero::DebugAnnotation>* as_proto;
235 
236   // Static method to create a new TraceValue instance from a given
237   // initialization value. Note that this deduces the TRACE_VALUE_TYPE_XXX
238   // type but doesn't return it, use ForType<T>::value for this.
239   //
240   // Usage example:
241   //     auto v = TraceValue::Make(100);
242   //     auto v2 = TraceValue::Make("Some text string");
243   //
244   // IMPORTANT: Experience shows that the compiler generates worse code when
245   // using this method rather than calling Init() directly on an existing
246   // TraceValue union :-(
247   //
248   template <typename T>
Make(T && value)249   static TraceValue Make(T&& value) {
250     TraceValue ret;
251     ret.Init(std::forward<T>(value));
252     return ret;
253   }
254 
255   // Output current value as a JSON string. |type| must be a valid
256   // TRACE_VALUE_TYPE_XXX value.
257   void AppendAsJSON(unsigned char type, std::string* out) const;
258 
259   // Output current value as a string. If the output string is to be used
260   // in a JSON format use AppendAsJSON instead. |type| must be valid
261   // TRACE_VALUE_TYPE_XXX value.
262   void AppendAsString(unsigned char type, std::string* out) const;
263 
264  private:
265   void Append(unsigned char type, bool as_json, std::string* out) const;
266 
267  public:
268   // TraceValue::Helper is used to provide information about initialization
269   // value types and an initialization function. It is a struct that should
270   // provide the following for supported initialization value types:
271   //
272   //    - kType: is a static TRACE_VALUE_TYPE_XXX constant.
273   //
274   //    - SetValue(TraceValue*, T): is a static inline method that sets
275   //        TraceValue value from a given T value. Second parameter type
276   //        can also be const T& or T&& to restrict uses.
277   //
278   // IMPORTANT: The type T must be std::decay_t<Q>, where Q is the real C++
279   // argument type. I.e. you should not have to deal with reference types
280   // in your specialization.
281   //
282   // Specializations are defined for integers, enums, floating point, pointers,
283   // constant C string literals and pointers, std::string, time values below.
284   //
285   // Specializations for custom types are possible provided that there exists
286   // a corresponding Helper specialization, for example:
287   //
288   //    template <>
289   //    struct base::trace_event::TraceValue::Helper<Foo> {
290   //      static constexpr unsigned char kTypes = TRACE_VALUE_TYPE_COPY_STRING;
291   //      static inline void SetValue(TraceValue* v, const Foo& value) {
292   //        v->as_string = value.c_str();
293   //      }
294   //    };
295   //
296   // Will allow code like:
297   //
298   //    Foo foo = ...;
299   //    auto v = TraceValue::Make(foo);
300   //
301   // Or even:
302   //    Foo foo = ...;
303   //    TraceArguments args("foo_arg1", foo);
304   //
305   template <typename T, class = void>
306   struct Helper {};
307 
308   template <typename T>
309   static constexpr bool HasHelperSupport =
310       requires { TraceValue::Helper<std::decay_t<T>>::kType; };
311 
312   // TraceValue::TypeFor<T>::value returns the TRACE_VALUE_TYPE_XXX
313   // corresponding to initialization values of type T.
314   template <typename T, class = void>
315   struct TypeFor;
316 
317   template <typename T>
318   struct TypeFor<T, std::enable_if_t<HasHelperSupport<T>>> {
319     using ValueType = std::decay_t<T>;
320     static const unsigned char value = Helper<ValueType>::kType;
321   };
322   template <typename T>
323   struct TypeFor<T,
324                  std::enable_if_t<!HasHelperSupport<T> &&
325                                   perfetto::internal::has_traced_value_support<
326                                       std::decay_t<T>>::value>> {
327     static const unsigned char value = TRACE_VALUE_TYPE_PROTO;
328   };
329 
330   // TraceValue::TypeCheck<T>::value is only defined iff T can be used to
331   // initialize a TraceValue instance. This is useful to restrict template
332   // instantiation to only the appropriate type (see TraceArguments
333   // constructors below).
334   template <
335       typename T,
336       class = std::enable_if_t<
337           HasHelperSupport<T> ||
338           perfetto::internal::has_traced_value_support<std::decay_t<T>>::value>>
339   struct TypeCheck {
340     static const bool value = true;
341   };
342 
343   // There is no constructor to keep this structure POD intentionally.
344   // This avoids un-needed initialization when only 0 or 1 arguments are
345   // used to construct a TraceArguments instance. Use Init() instead to
346   // perform explicit initialization from a given C++ value.
347 
348   // Initialize TraceValue instance from a C++ trace value.
349   // This relies on the proper specialization of TraceValue::Helper<>
350   // described below. Usage is simply:
351   //
352   //  TraceValue v;
353   //  v.Init(<value>);
354   //
355   // NOTE: For ConvertableToTraceFormat values, see the notes above.
356   template <class T>
357   std::enable_if_t<HasHelperSupport<T>> Init(T&& value) {
358     using ValueType = std::decay_t<T>;
359     Helper<ValueType>::SetValue(this, std::forward<T>(value));
360   }
361 
362   template <class T>
363   std::enable_if_t<
364       !HasHelperSupport<T> &&
365       perfetto::internal::has_traced_value_support<std::decay_t<T>>::value>
366   Init(T&& value) {
367     as_proto = new protozero::HeapBuffered<
368         perfetto::protos::pbzero::DebugAnnotation>();
369     perfetto::WriteIntoTracedValue(
370         perfetto::internal::CreateTracedValueFromProto(as_proto->get()),
371         std::forward<T>(value));
372   }
373 };
374 
375 // TraceValue::Helper for integers and enums.
376 template <typename T>
377 struct TraceValue::
378     Helper<T, std::enable_if_t<std::is_integral_v<T> || std::is_enum_v<T>>> {
379   static constexpr unsigned char kType =
380       std::is_signed_v<T> ? TRACE_VALUE_TYPE_INT : TRACE_VALUE_TYPE_UINT;
381   static inline void SetValue(TraceValue* v, T value) {
382     v->as_uint = static_cast<unsigned long long>(value);
383   }
384 };
385 
386 // TraceValue::Helper for floating-point types
387 template <typename T>
388 struct TraceValue::Helper<T, std::enable_if_t<std::is_floating_point_v<T>>> {
389   static constexpr unsigned char kType = TRACE_VALUE_TYPE_DOUBLE;
390   static inline void SetValue(TraceValue* v, T value) { v->as_double = value; }
391 };
392 
393 // TraceValue::Helper for bool.
394 template <>
395 struct TraceValue::Helper<bool> {
396   static constexpr unsigned char kType = TRACE_VALUE_TYPE_BOOL;
397   static inline void SetValue(TraceValue* v, bool value) { v->as_bool = value; }
398 };
399 
400 //  TraceValue::Helper for generic pointer types.
401 template <>
402 struct TraceValue::Helper<const void*> {
403   static constexpr unsigned char kType = TRACE_VALUE_TYPE_POINTER;
404   static inline void SetValue(TraceValue* v, const void* value) {
405     v->as_pointer = value;
406   }
407 };
408 
409 template <>
410 struct TraceValue::Helper<void*> {
411   static constexpr unsigned char kType = TRACE_VALUE_TYPE_POINTER;
412   static inline void SetValue(TraceValue* v, void* value) {
413     v->as_pointer = value;
414   }
415 };
416 
417 // TraceValue::Helper for raw persistent C strings.
418 template <>
419 struct TraceValue::Helper<const char*> {
420   static constexpr unsigned char kType = TRACE_VALUE_TYPE_STRING;
421   static inline void SetValue(TraceValue* v, const char* value) {
422     v->as_string = value;
423   }
424 };
425 
426 // TraceValue::Helper for std::string values.
427 template <>
428 struct TraceValue::Helper<std::string> {
429   static constexpr unsigned char kType = TRACE_VALUE_TYPE_COPY_STRING;
430   static inline void SetValue(TraceValue* v, const std::string& value) {
431     v->as_string = value.c_str();
432   }
433 };
434 
435 // Special case for scoped pointers to convertables to trace format.
436 // |CONVERTABLE_TYPE| must be a type whose pointers can be converted to a
437 // ConvertableToTraceFormat* pointer as well (e.g. a derived class).
438 // IMPORTANT: This takes an std::unique_ptr<CONVERTABLE_TYPE> value, and takes
439 // ownership of the pointed object!
440 template <typename CONVERTABLE_TYPE>
441 struct TraceValue::Helper<
442     std::unique_ptr<CONVERTABLE_TYPE>,
443     std::enable_if_t<
444         std::is_convertible_v<CONVERTABLE_TYPE*, ConvertableToTraceFormat*>>> {
445   static constexpr unsigned char kType = TRACE_VALUE_TYPE_CONVERTABLE;
446   static inline void SetValue(TraceValue* v,
447                               std::unique_ptr<CONVERTABLE_TYPE> value) {
448     v->as_convertable = value.release();
449   }
450 };
451 
452 // Specialization for time-based values like base::Time, which provide a
453 // a ToInternalValue() method.
454 template <typename T>
455 struct TraceValue::Helper<
456     T,
457     std::enable_if_t<std::is_same_v<T, base::Time> ||
458                      std::is_same_v<T, base::TimeTicks> ||
459                      std::is_same_v<T, base::ThreadTicks>>> {
460   static constexpr unsigned char kType = TRACE_VALUE_TYPE_INT;
461   static inline void SetValue(TraceValue* v, const T& value) {
462     v->as_int = value.ToInternalValue();
463   }
464 };
465 
466 // Simple container for const char* that should be copied instead of retained.
467 // The goal is to indicate that the C string is copyable, unlike the default
468 // Init(const char*) implementation. Usage is:
469 //
470 //    const char* str = ...;
471 //    v.Init(TraceStringWithCopy(str));
472 //
473 // Which will mark the string as TRACE_VALUE_TYPE_COPY_STRING, instead of
474 // TRACE_VALUE_TYPE_STRING.
475 //
476 class TraceStringWithCopy {
477  public:
478   explicit TraceStringWithCopy(const char* str) : str_(str) {}
479   const char* str() const { return str_; }
480 
481  private:
482   const char* str_;
483 };
484 
485 template <>
486 struct TraceValue::Helper<TraceStringWithCopy> {
487   static constexpr unsigned char kType = TRACE_VALUE_TYPE_COPY_STRING;
488   static inline void SetValue(TraceValue* v, const TraceStringWithCopy& value) {
489     v->as_string = value.str();
490   }
491 };
492 
493 class TraceArguments;
494 
495 // A small class used to store a copy of all strings from a given
496 // TraceArguments instance (see below). When empty, this should only
497 // take the size of a pointer. Otherwise, this will point to a heap
498 // allocated block containing a size_t value followed by all characters
499 // in the storage area. For most cases, this is more efficient
500 // than using a std::unique_ptr<std::string> or an std::vector<char>.
501 class BASE_EXPORT StringStorage {
502  public:
503   constexpr StringStorage() = default;
504 
505   explicit StringStorage(size_t alloc_size) { Reset(alloc_size); }
506 
507   ~StringStorage() {
508     if (data_)
509       ::free(data_);
510   }
511 
512   StringStorage(StringStorage&& other) noexcept : data_(other.data_) {
513     other.data_ = nullptr;
514   }
515 
516   StringStorage& operator=(StringStorage&& other) noexcept {
517     if (this != &other) {
518       if (data_)
519         ::free(data_);
520       data_ = other.data_;
521       other.data_ = nullptr;
522     }
523     return *this;
524   }
525 
526   // Reset storage area to new allocation size. Existing content might not
527   // be preserved. If |alloc_size| is 0, this will free the storage area
528   // as well.
529   void Reset(size_t alloc_size = 0);
530 
531   // Accessors.
532   constexpr size_t size() const { return data_ ? data_->size : 0u; }
533   constexpr const char* data() const { return data_ ? data_->chars : nullptr; }
534   constexpr char* data() { return data_ ? data_->chars : nullptr; }
535 
536   constexpr const char* begin() const { return data(); }
537   constexpr const char* end() const { return data() + size(); }
538   inline char* begin() { return data(); }
539   inline char* end() { return data() + size(); }
540 
541   // True iff storage is empty.
542   constexpr bool empty() const { return size() == 0; }
543 
544   // Returns true if |ptr| is inside the storage area, false otherwise.
545   // Used during unit-testing.
546   constexpr bool Contains(const void* ptr) const {
547     const char* char_ptr = static_cast<const char*>(ptr);
548     return (char_ptr >= begin() && char_ptr < end());
549   }
550 
551   // Returns true if all string pointers in |args| are contained in this
552   // storage area.
553   bool Contains(const TraceArguments& args) const;
554 
555   // Return an estimate of the memory overhead of this instance. This doesn't
556   // count the size of |data_| itself.
557   constexpr size_t EstimateTraceMemoryOverhead() const {
558     return data_ ? sizeof(size_t) + data_->size : 0u;
559   }
560 
561  private:
562   // Heap allocated data block (variable size), made of:
563   //
564   //   - size: a size_t field, giving the size of the following |chars| array.
565   //   - chars: an array of |size| characters, holding all zero-terminated
566   //     strings referenced from a TraceArguments instance.
567   struct Data {
568     size_t size = 0;
569     char chars[1];  // really |size| character items in storage.
570   };
571 
572   // This is an owning pointer. Normally, using a std::unique_ptr<> would be
573   // enough, but the compiler will then complaing about inlined constructors
574   // and destructors being too complex (!), resulting in larger code for no
575   // good reason.
576   // RAW_PTR_EXCLUSION: As above, inlining bloats code for no good reason.
577   RAW_PTR_EXCLUSION Data* data_ = nullptr;
578 };
579 
580 // TraceArguments models an array of kMaxSize trace-related items,
581 // each one of them having:
582 //   - a name, which is a constant char array literal.
583 //   - a type, as described by TRACE_VALUE_TYPE_XXX macros.
584 //   - a value, stored in a TraceValue union.
585 //
586 // IMPORTANT: For TRACE_VALUE_TYPE_CONVERTABLE, the value holds an owning
587 //            pointer to an AsConvertableToTraceFormat instance, which will
588 //            be destroyed with the array (or moved out of it when passed
589 //            to a TraceEvent instance).
590 //
591 // For TRACE_VALUE_TYPE_COPY_STRING, the value holds a const char* pointer
592 // whose content will be copied when creating a TraceEvent instance.
593 //
594 // IMPORTANT: Most constructors and the destructor are all inlined
595 // intentionally, in order to let the compiler remove un-necessary operations
596 // and reduce machine code.
597 //
598 class BASE_EXPORT TraceArguments {
599  public:
600   // Maximum number of arguments held by this structure.
601   static constexpr size_t kMaxSize = 2;
602 
603   // Default constructor, no arguments.
604   TraceArguments() : size_(0) {}
605 
606   // Constructor for a single argument.
607   template <typename T, class = decltype(TraceValue::TypeCheck<T>::value)>
608   TraceArguments(const char* arg1_name, T&& arg1_value) : size_(1) {
609     types_[0] = TraceValue::TypeFor<T>::value;
610     names_[0] = arg1_name;
611     values_[0].Init(std::forward<T>(arg1_value));
612   }
613 
614   // Constructor for two arguments.
615   template <typename T1,
616             typename T2,
617             class = decltype(TraceValue::TypeCheck<T1>::value &&
618                              TraceValue::TypeCheck<T2>::value)>
619   TraceArguments(const char* arg1_name,
620                  T1&& arg1_value,
621                  const char* arg2_name,
622                  T2&& arg2_value)
623       : size_(2) {
624     types_[0] = TraceValue::TypeFor<T1>::value;
625     types_[1] = TraceValue::TypeFor<T2>::value;
626     names_[0] = arg1_name;
627     names_[1] = arg2_name;
628     values_[0].Init(std::forward<T1>(arg1_value));
629     values_[1].Init(std::forward<T2>(arg2_value));
630   }
631 
632   // Constructor used to convert a legacy set of arguments when there
633   // are no convertable values at all.
634   TraceArguments(int num_args,
635                  const char* const* arg_names,
636                  const unsigned char* arg_types,
637                  const unsigned long long* arg_values);
638 
639   // Constructor used to convert legacy set of arguments, where the
640   // convertable values are also provided by an array of CONVERTABLE_TYPE.
641   template <typename CONVERTABLE_TYPE>
642   TraceArguments(int num_args,
643                  const char* const* arg_names,
644                  const unsigned char* arg_types,
645                  const unsigned long long* arg_values,
646                  CONVERTABLE_TYPE* arg_convertables) {
647     static int max_args = static_cast<int>(kMaxSize);
648     if (num_args > max_args)
649       num_args = max_args;
650     size_ = static_cast<unsigned char>(num_args);
651     for (size_t n = 0; n < size_; ++n) {
652       types_[n] = arg_types[n];
653       names_[n] = arg_names[n];
654       if (arg_types[n] == TRACE_VALUE_TYPE_CONVERTABLE) {
655         values_[n].Init(
656             std::forward<CONVERTABLE_TYPE>(std::move(arg_convertables[n])));
657       } else {
658         values_[n].as_uint = arg_values[n];
659       }
660     }
661   }
662 
663   // Destructor. NOTE: Intentionally inlined (see note above).
664   ~TraceArguments() {
665     for (size_t n = 0; n < size_; ++n) {
666       if (types_[n] == TRACE_VALUE_TYPE_CONVERTABLE)
667         delete values_[n].as_convertable;
668       if (types_[n] == TRACE_VALUE_TYPE_PROTO)
669         delete values_[n].as_proto;
670     }
671   }
672 
673   // Disallow copy operations.
674   TraceArguments(const TraceArguments&) = delete;
675   TraceArguments& operator=(const TraceArguments&) = delete;
676 
677   // Allow move operations.
678   TraceArguments(TraceArguments&& other) noexcept {
679     ::memcpy(this, &other, sizeof(*this));
680     // All owning pointers were copied to |this|. Setting |other.size_| will
681     // mask the pointer values still in |other|.
682     other.size_ = 0;
683   }
684 
685   TraceArguments& operator=(TraceArguments&&) noexcept;
686 
687   // Accessors
688   size_t size() const { return size_; }
689   const unsigned char* types() const { return types_; }
690   const char* const* names() const { return names_; }
691   const TraceValue* values() const { return values_; }
692 
693   // Reset to empty arguments list.
694   void Reset();
695 
696   // Use |storage| to copy all copyable strings.
697   // If |copy_all_strings| is false, then only the TRACE_VALUE_TYPE_COPY_STRING
698   // values will be copied into storage. If it is true, then argument names are
699   // also copied to storage, as well as the strings pointed to by
700   // |*extra_string1| and |*extra_string2|.
701   // NOTE: If there are no strings to copy, |*storage| is left untouched.
702   void CopyStringsTo(StringStorage* storage,
703                      bool copy_all_strings,
704                      const char** extra_string1,
705                      const char** extra_string2);
706 
707   // Append debug string representation to |*out|.
708   void AppendDebugString(std::string* out);
709 
710  private:
711   unsigned char size_;
712   unsigned char types_[kMaxSize];
713   const char* names_[kMaxSize];
714   TraceValue values_[kMaxSize];
715 };
716 
717 }  // namespace trace_event
718 }  // namespace base
719 
720 #endif  // BASE_TRACE_EVENT_TRACE_ARGUMENTS_H_
721