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