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