• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 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 #include "base/trace_event/traced_value.h"
6 
7 #include <inttypes.h>
8 #include <stdint.h>
9 
10 #include <atomic>
11 #include <string_view>
12 #include <utility>
13 
14 #include "base/bits.h"
15 #include "base/containers/circular_deque.h"
16 #include "base/containers/span.h"
17 #include "base/json/json_writer.h"
18 #include "base/json/string_escape.h"
19 #include "base/memory/ptr_util.h"
20 #include "base/notreached.h"
21 #include "base/pickle.h"
22 #include "base/strings/stringprintf.h"
23 #include "base/trace_event/trace_event.h"
24 #include "base/trace_event/trace_event_impl.h"
25 #include "base/trace_event/trace_event_memory_overhead.h"
26 #include "base/trace_event/trace_log.h"
27 #include "base/values.h"
28 
29 namespace base::trace_event {
30 
31 namespace {
32 constexpr char kTypeStartDict = '{';
33 constexpr char kTypeEndDict = '}';
34 constexpr char kTypeStartArray = '[';
35 constexpr char kTypeEndArray = ']';
36 constexpr char kTypeBool = 'b';
37 constexpr char kTypeInt = 'i';
38 constexpr char kTypeDouble = 'd';
39 constexpr char kTypeString = 's';
40 constexpr char kTypeCStr = '*';  // only used for key names
41 
42 std::atomic<TracedValue::WriterFactoryCallback> g_writer_factory_callback;
43 
44 #ifndef NDEBUG
45 constexpr bool kStackTypeDict = false;
46 constexpr bool kStackTypeArray = true;
47 #define DCHECK_CURRENT_CONTAINER_IS(x) DCHECK_EQ(x, nesting_stack_.back())
48 #define DCHECK_CONTAINER_STACK_DEPTH_EQ(x) DCHECK_EQ(x, nesting_stack_.size())
49 #define DEBUG_PUSH_CONTAINER(x) nesting_stack_.push_back(x)
50 #define DEBUG_POP_CONTAINER() nesting_stack_.pop_back()
51 #else
52 #define DCHECK_CURRENT_CONTAINER_IS(x) \
53   do {                                 \
54   } while (0)
55 #define DCHECK_CONTAINER_STACK_DEPTH_EQ(x) \
56   do {                                     \
57   } while (0)
58 #define DEBUG_PUSH_CONTAINER(x) \
59   do {                          \
60   } while (0)
61 #define DEBUG_POP_CONTAINER() \
62   do {                        \
63   } while (0)
64 #endif
65 
WriteKeyNameAsRawPtr(Pickle & pickle,const char * ptr)66 inline void WriteKeyNameAsRawPtr(Pickle& pickle, const char* ptr) {
67   pickle.WriteBytes(byte_span_from_ref(kTypeCStr));
68   pickle.WriteUInt64(static_cast<uint64_t>(reinterpret_cast<uintptr_t>(ptr)));
69 }
70 
WriteKeyNameWithCopy(Pickle & pickle,std::string_view str)71 inline void WriteKeyNameWithCopy(Pickle& pickle, std::string_view str) {
72   pickle.WriteBytes(byte_span_from_ref(kTypeString));
73   pickle.WriteString(str);
74 }
75 
ReadKeyName(PickleIterator & pickle_iterator)76 std::string ReadKeyName(PickleIterator& pickle_iterator) {
77   const char* type = nullptr;
78   bool res = pickle_iterator.ReadBytes(&type, 1);
79   std::string key_name;
80   if (res && *type == kTypeCStr) {
81     uint64_t ptr_value = 0;
82     res = pickle_iterator.ReadUInt64(&ptr_value);
83     key_name = reinterpret_cast<const char*>(static_cast<uintptr_t>(ptr_value));
84   } else if (res && *type == kTypeString) {
85     res = pickle_iterator.ReadString(&key_name);
86   }
87   DCHECK(res);
88   return key_name;
89 }
90 
91 class PickleWriter final : public TracedValue::Writer {
92  public:
PickleWriter(size_t capacity)93   explicit PickleWriter(size_t capacity) {
94     if (capacity) {
95       pickle_.Reserve(capacity);
96     }
97   }
98 
IsPickleWriter() const99   bool IsPickleWriter() const override { return true; }
IsProtoWriter() const100   bool IsProtoWriter() const override { return false; }
101 
SetInteger(const char * name,int value)102   void SetInteger(const char* name, int value) override {
103     pickle_.WriteBytes(byte_span_from_ref(kTypeInt));
104     pickle_.WriteInt(value);
105     WriteKeyNameAsRawPtr(pickle_, name);
106   }
107 
SetIntegerWithCopiedName(std::string_view name,int value)108   void SetIntegerWithCopiedName(std::string_view name, int value) override {
109     pickle_.WriteBytes(byte_span_from_ref(kTypeInt));
110     pickle_.WriteInt(value);
111     WriteKeyNameWithCopy(pickle_, name);
112   }
113 
SetDouble(const char * name,double value)114   void SetDouble(const char* name, double value) override {
115     pickle_.WriteBytes(byte_span_from_ref(kTypeDouble));
116     pickle_.WriteDouble(value);
117     WriteKeyNameAsRawPtr(pickle_, name);
118   }
119 
SetDoubleWithCopiedName(std::string_view name,double value)120   void SetDoubleWithCopiedName(std::string_view name, double value) override {
121     pickle_.WriteBytes(byte_span_from_ref(kTypeDouble));
122     pickle_.WriteDouble(value);
123     WriteKeyNameWithCopy(pickle_, name);
124   }
125 
SetBoolean(const char * name,bool value)126   void SetBoolean(const char* name, bool value) override {
127     pickle_.WriteBytes(byte_span_from_ref(kTypeBool));
128     pickle_.WriteBool(value);
129     WriteKeyNameAsRawPtr(pickle_, name);
130   }
131 
SetBooleanWithCopiedName(std::string_view name,bool value)132   void SetBooleanWithCopiedName(std::string_view name, bool value) override {
133     pickle_.WriteBytes(byte_span_from_ref(kTypeBool));
134     pickle_.WriteBool(value);
135     WriteKeyNameWithCopy(pickle_, name);
136   }
137 
SetString(const char * name,std::string_view value)138   void SetString(const char* name, std::string_view value) override {
139     pickle_.WriteBytes(byte_span_from_ref(kTypeString));
140     pickle_.WriteString(value);
141     WriteKeyNameAsRawPtr(pickle_, name);
142   }
143 
SetStringWithCopiedName(std::string_view name,std::string_view value)144   void SetStringWithCopiedName(std::string_view name,
145                                std::string_view value) override {
146     pickle_.WriteBytes(byte_span_from_ref(kTypeString));
147     pickle_.WriteString(value);
148     WriteKeyNameWithCopy(pickle_, name);
149   }
150 
SetValue(const char * name,Writer * value)151   void SetValue(const char* name, Writer* value) override {
152     CHECK(value->IsPickleWriter());
153     const PickleWriter* pickle_writer = static_cast<const PickleWriter*>(value);
154 
155     BeginDictionary(name);
156     pickle_.WriteBytes(pickle_writer->pickle_.payload_bytes());
157     EndDictionary();
158   }
159 
SetValueWithCopiedName(std::string_view name,Writer * value)160   void SetValueWithCopiedName(std::string_view name, Writer* value) override {
161     CHECK(value->IsPickleWriter());
162     const PickleWriter* pickle_writer = static_cast<const PickleWriter*>(value);
163 
164     BeginDictionaryWithCopiedName(name);
165     pickle_.WriteBytes(pickle_writer->pickle_.payload_bytes());
166     EndDictionary();
167   }
168 
BeginArray()169   void BeginArray() override {
170     pickle_.WriteBytes(byte_span_from_ref(kTypeStartArray));
171   }
172 
BeginDictionary()173   void BeginDictionary() override {
174     pickle_.WriteBytes(byte_span_from_ref(kTypeStartDict));
175   }
176 
BeginDictionary(const char * name)177   void BeginDictionary(const char* name) override {
178     pickle_.WriteBytes(byte_span_from_ref(kTypeStartDict));
179     WriteKeyNameAsRawPtr(pickle_, name);
180   }
181 
BeginDictionaryWithCopiedName(std::string_view name)182   void BeginDictionaryWithCopiedName(std::string_view name) override {
183     pickle_.WriteBytes(byte_span_from_ref(kTypeStartDict));
184     WriteKeyNameWithCopy(pickle_, name);
185   }
186 
BeginArray(const char * name)187   void BeginArray(const char* name) override {
188     pickle_.WriteBytes(byte_span_from_ref(kTypeStartArray));
189     WriteKeyNameAsRawPtr(pickle_, name);
190   }
191 
BeginArrayWithCopiedName(std::string_view name)192   void BeginArrayWithCopiedName(std::string_view name) override {
193     pickle_.WriteBytes(byte_span_from_ref(kTypeStartArray));
194     WriteKeyNameWithCopy(pickle_, name);
195   }
196 
EndDictionary()197   void EndDictionary() override {
198     pickle_.WriteBytes(byte_span_from_ref(kTypeEndDict));
199   }
EndArray()200   void EndArray() override {
201     pickle_.WriteBytes(byte_span_from_ref(kTypeEndArray));
202   }
203 
AppendInteger(int value)204   void AppendInteger(int value) override {
205     pickle_.WriteBytes(byte_span_from_ref(kTypeInt));
206     pickle_.WriteInt(value);
207   }
208 
AppendDouble(double value)209   void AppendDouble(double value) override {
210     pickle_.WriteBytes(byte_span_from_ref(kTypeDouble));
211     pickle_.WriteDouble(value);
212   }
213 
AppendBoolean(bool value)214   void AppendBoolean(bool value) override {
215     pickle_.WriteBytes(byte_span_from_ref(kTypeBool));
216     pickle_.WriteBool(value);
217   }
218 
AppendString(std::string_view value)219   void AppendString(std::string_view value) override {
220     pickle_.WriteBytes(byte_span_from_ref(kTypeString));
221     pickle_.WriteString(value);
222   }
223 
AppendAsTraceFormat(std::string * out) const224   void AppendAsTraceFormat(std::string* out) const override {
225     struct State {
226       enum Type { kTypeDict, kTypeArray };
227       Type type;
228       bool needs_comma;
229     };
230 
231     auto maybe_append_key_name = [](State current_state, PickleIterator* it,
232                                     std::string* out) {
233       if (current_state.type == State::kTypeDict) {
234         EscapeJSONString(ReadKeyName(*it), true, out);
235         out->append(":");
236       }
237     };
238 
239     base::circular_deque<State> state_stack;
240 
241     out->append("{");
242     state_stack.push_back({State::kTypeDict});
243 
244     PickleIterator it(pickle_);
245     for (const char* type; it.ReadBytes(&type, 1);) {
246       switch (*type) {
247         case kTypeEndDict:
248           out->append("}");
249           state_stack.pop_back();
250           continue;
251 
252         case kTypeEndArray:
253           out->append("]");
254           state_stack.pop_back();
255           continue;
256       }
257 
258       // Use an index so it will stay valid across resizes.
259       size_t current_state_index = state_stack.size() - 1;
260       if (state_stack[current_state_index].needs_comma) {
261         out->append(",");
262       }
263 
264       switch (*type) {
265         case kTypeStartDict: {
266           maybe_append_key_name(state_stack[current_state_index], &it, out);
267           out->append("{");
268           state_stack.push_back({State::kTypeDict});
269           break;
270         }
271 
272         case kTypeStartArray: {
273           maybe_append_key_name(state_stack[current_state_index], &it, out);
274           out->append("[");
275           state_stack.push_back({State::kTypeArray});
276           break;
277         }
278 
279         case kTypeBool: {
280           TraceEvent::TraceValue json_value;
281           CHECK(it.ReadBool(&json_value.as_bool));
282           maybe_append_key_name(state_stack[current_state_index], &it, out);
283           json_value.AppendAsJSON(TRACE_VALUE_TYPE_BOOL, out);
284           break;
285         }
286 
287         case kTypeInt: {
288           int value;
289           CHECK(it.ReadInt(&value));
290           maybe_append_key_name(state_stack[current_state_index], &it, out);
291           TraceEvent::TraceValue json_value;
292           json_value.as_int = value;
293           json_value.AppendAsJSON(TRACE_VALUE_TYPE_INT, out);
294           break;
295         }
296 
297         case kTypeDouble: {
298           TraceEvent::TraceValue json_value;
299           CHECK(it.ReadDouble(&json_value.as_double));
300           maybe_append_key_name(state_stack[current_state_index], &it, out);
301           json_value.AppendAsJSON(TRACE_VALUE_TYPE_DOUBLE, out);
302           break;
303         }
304 
305         case kTypeString: {
306           std::string value;
307           CHECK(it.ReadString(&value));
308           maybe_append_key_name(state_stack[current_state_index], &it, out);
309           TraceEvent::TraceValue json_value;
310           json_value.as_string = value.c_str();
311           json_value.AppendAsJSON(TRACE_VALUE_TYPE_STRING, out);
312           break;
313         }
314 
315         default:
316           NOTREACHED();
317       }
318 
319       state_stack[current_state_index].needs_comma = true;
320     }
321 
322     out->append("}");
323     state_stack.pop_back();
324 
325     DCHECK(state_stack.empty());
326   }
327 
EstimateTraceMemoryOverhead(TraceEventMemoryOverhead * overhead)328   void EstimateTraceMemoryOverhead(
329       TraceEventMemoryOverhead* overhead) override {
330     overhead->Add(TraceEventMemoryOverhead::kTracedValue,
331                   /* allocated size */
332                   pickle_.GetTotalAllocatedSize(),
333                   /* resident size */
334                   pickle_.size());
335   }
336 
ToBaseValue() const337   std::unique_ptr<base::Value> ToBaseValue() const {
338     base::Value root(base::Value::Type::DICT);
339     Value* cur_dict = &root;
340     Value* cur_list = nullptr;
341     std::vector<Value*> stack;
342     PickleIterator it(pickle_);
343     const char* type;
344 
345     while (it.ReadBytes(&type, 1)) {
346       DCHECK((cur_dict && !cur_list) || (cur_list && !cur_dict));
347       switch (*type) {
348         case kTypeStartDict: {
349           if (cur_dict) {
350             stack.push_back(cur_dict);
351             cur_dict = cur_dict->GetDict().Set(ReadKeyName(it),
352                                                Value(Value::Type::DICT));
353           } else {
354             cur_list->GetList().Append(Value(Value::Type::DICT));
355             // Update |cur_dict| to point to the newly added dictionary.
356             cur_dict = &cur_list->GetList().back();
357             stack.push_back(cur_list);
358             cur_list = nullptr;
359           }
360         } break;
361 
362         case kTypeEndArray:
363         case kTypeEndDict: {
364           if (stack.back()->is_dict()) {
365             cur_dict = stack.back();
366             cur_list = nullptr;
367           } else if (stack.back()->is_list()) {
368             cur_list = stack.back();
369             cur_dict = nullptr;
370           }
371           stack.pop_back();
372         } break;
373 
374         case kTypeStartArray: {
375           Value::List new_list;
376           if (cur_dict) {
377             stack.push_back(cur_dict);
378             cur_list =
379                 cur_dict->GetDict().Set(ReadKeyName(it), std::move(new_list));
380             cur_dict = nullptr;
381           } else {
382             cur_list->GetList().Append(std::move(new_list));
383             stack.push_back(cur_list);
384             // |cur_list| is invalidated at this point by the Append, so it
385             // needs to be reset.
386             cur_list = &cur_list->GetList().back();
387           }
388         } break;
389 
390         case kTypeBool: {
391           bool value;
392           CHECK(it.ReadBool(&value));
393           if (cur_dict) {
394             cur_dict->GetDict().Set(ReadKeyName(it), value);
395           } else {
396             cur_list->GetList().Append(value);
397           }
398         } break;
399 
400         case kTypeInt: {
401           int value;
402           CHECK(it.ReadInt(&value));
403           if (cur_dict) {
404             cur_dict->GetDict().Set(ReadKeyName(it), value);
405           } else {
406             cur_list->GetList().Append(value);
407           }
408         } break;
409 
410         case kTypeDouble: {
411           TraceEvent::TraceValue trace_value;
412           CHECK(it.ReadDouble(&trace_value.as_double));
413           Value base_value;
414           if (!std::isfinite(trace_value.as_double)) {
415             // base::Value doesn't support nan and infinity values. Use strings
416             // for them instead. This follows the same convention in
417             // AppendAsTraceFormat(), supported by TraceValue::Append*().
418             std::string value_string;
419             trace_value.AppendAsString(TRACE_VALUE_TYPE_DOUBLE, &value_string);
420             base_value = Value(value_string);
421           } else {
422             base_value = Value(trace_value.as_double);
423           }
424           if (cur_dict) {
425             cur_dict->GetDict().Set(ReadKeyName(it), std::move(base_value));
426           } else {
427             cur_list->GetList().Append(std::move(base_value));
428           }
429         } break;
430 
431         case kTypeString: {
432           std::string value;
433           CHECK(it.ReadString(&value));
434           if (cur_dict) {
435             cur_dict->GetDict().Set(ReadKeyName(it), std::move(value));
436           } else {
437             cur_list->GetList().Append(std::move(value));
438           }
439         } break;
440 
441         default:
442           NOTREACHED();
443       }
444     }
445     DCHECK(stack.empty());
446     return base::Value::ToUniquePtrValue(std::move(root));
447   }
448 
449  private:
450   Pickle pickle_;
451 };
452 
CreateWriter(size_t capacity)453 std::unique_ptr<TracedValue::Writer> CreateWriter(size_t capacity) {
454   TracedValue::WriterFactoryCallback callback =
455       g_writer_factory_callback.load(std::memory_order_relaxed);
456   if (callback) {
457     return callback(capacity);
458   }
459 
460   return std::make_unique<PickleWriter>(capacity);
461 }
462 
463 }  // namespace
464 
AppendToProto(ProtoAppender * appender)465 bool TracedValue::Writer::AppendToProto(ProtoAppender* appender) {
466   return false;
467 }
468 
469 // static
SetWriterFactoryCallback(WriterFactoryCallback callback)470 void TracedValue::SetWriterFactoryCallback(WriterFactoryCallback callback) {
471   g_writer_factory_callback.store(callback);
472 }
473 
TracedValue(size_t capacity)474 TracedValue::TracedValue(size_t capacity)
475     : TracedValue(capacity, /*forced_json*/ false) {}
476 
TracedValue(size_t capacity,bool forced_json)477 TracedValue::TracedValue(size_t capacity, bool forced_json) {
478   DEBUG_PUSH_CONTAINER(kStackTypeDict);
479 
480   writer_ = forced_json ? std::make_unique<PickleWriter>(capacity)
481                         : CreateWriter(capacity);
482 }
483 
~TracedValue()484 TracedValue::~TracedValue() {
485   DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
486   DEBUG_POP_CONTAINER();
487   DCHECK_CONTAINER_STACK_DEPTH_EQ(0u);
488 }
489 
SetInteger(const char * name,int value)490 void TracedValue::SetInteger(const char* name, int value) {
491   DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
492   writer_->SetInteger(name, value);
493 }
494 
SetIntegerWithCopiedName(std::string_view name,int value)495 void TracedValue::SetIntegerWithCopiedName(std::string_view name, int value) {
496   DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
497   writer_->SetIntegerWithCopiedName(name, value);
498 }
499 
SetDouble(const char * name,double value)500 void TracedValue::SetDouble(const char* name, double value) {
501   DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
502   writer_->SetDouble(name, value);
503 }
504 
SetDoubleWithCopiedName(std::string_view name,double value)505 void TracedValue::SetDoubleWithCopiedName(std::string_view name, double value) {
506   DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
507   writer_->SetDoubleWithCopiedName(name, value);
508 }
509 
SetBoolean(const char * name,bool value)510 void TracedValue::SetBoolean(const char* name, bool value) {
511   DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
512   writer_->SetBoolean(name, value);
513 }
514 
SetBooleanWithCopiedName(std::string_view name,bool value)515 void TracedValue::SetBooleanWithCopiedName(std::string_view name, bool value) {
516   DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
517   writer_->SetBooleanWithCopiedName(name, value);
518 }
519 
SetString(const char * name,std::string_view value)520 void TracedValue::SetString(const char* name, std::string_view value) {
521   DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
522   writer_->SetString(name, value);
523 }
524 
SetStringWithCopiedName(std::string_view name,std::string_view value)525 void TracedValue::SetStringWithCopiedName(std::string_view name,
526                                           std::string_view value) {
527   DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
528   writer_->SetStringWithCopiedName(name, value);
529 }
530 
SetValue(const char * name,TracedValue * value)531 void TracedValue::SetValue(const char* name, TracedValue* value) {
532   DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
533   writer_->SetValue(name, value->writer_.get());
534 }
535 
SetValueWithCopiedName(std::string_view name,TracedValue * value)536 void TracedValue::SetValueWithCopiedName(std::string_view name,
537                                          TracedValue* value) {
538   DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
539   writer_->SetValueWithCopiedName(name, value->writer_.get());
540 }
541 
542 namespace {
543 
544 // TODO(altimin): Add native support for pointers for nested values in
545 // DebugAnnotation proto.
PointerToString(const void * value)546 std::string PointerToString(const void* value) {
547   return base::StringPrintf(
548       "0x%" PRIx64, static_cast<uint64_t>(reinterpret_cast<uintptr_t>(value)));
549 }
550 
551 }  // namespace
552 
SetPointer(const char * name,const void * value)553 void TracedValue::SetPointer(const char* name, const void* value) {
554   DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
555   writer_->SetString(name, PointerToString(value));
556 }
557 
SetPointerWithCopiedName(std::string_view name,const void * value)558 void TracedValue::SetPointerWithCopiedName(std::string_view name,
559                                            const void* value) {
560   DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
561   writer_->SetStringWithCopiedName(name, PointerToString(value));
562 }
563 
BeginDictionary(const char * name)564 void TracedValue::BeginDictionary(const char* name) {
565   DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
566   DEBUG_PUSH_CONTAINER(kStackTypeDict);
567   writer_->BeginDictionary(name);
568 }
569 
BeginDictionaryWithCopiedName(std::string_view name)570 void TracedValue::BeginDictionaryWithCopiedName(std::string_view name) {
571   DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
572   DEBUG_PUSH_CONTAINER(kStackTypeDict);
573   writer_->BeginDictionaryWithCopiedName(name);
574 }
575 
BeginArray(const char * name)576 void TracedValue::BeginArray(const char* name) {
577   DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
578   DEBUG_PUSH_CONTAINER(kStackTypeArray);
579   writer_->BeginArray(name);
580 }
581 
BeginArrayWithCopiedName(std::string_view name)582 void TracedValue::BeginArrayWithCopiedName(std::string_view name) {
583   DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
584   DEBUG_PUSH_CONTAINER(kStackTypeArray);
585   writer_->BeginArrayWithCopiedName(name);
586 }
587 
AppendInteger(int value)588 void TracedValue::AppendInteger(int value) {
589   DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
590   writer_->AppendInteger(value);
591 }
592 
AppendDouble(double value)593 void TracedValue::AppendDouble(double value) {
594   DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
595   writer_->AppendDouble(value);
596 }
597 
AppendBoolean(bool value)598 void TracedValue::AppendBoolean(bool value) {
599   DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
600   writer_->AppendBoolean(value);
601 }
602 
AppendString(std::string_view value)603 void TracedValue::AppendString(std::string_view value) {
604   DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
605   writer_->AppendString(value);
606 }
607 
AppendPointer(const void * value)608 void TracedValue::AppendPointer(const void* value) {
609   DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
610   writer_->AppendString(PointerToString(value));
611 }
612 
BeginArray()613 void TracedValue::BeginArray() {
614   DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
615   DEBUG_PUSH_CONTAINER(kStackTypeArray);
616   writer_->BeginArray();
617 }
618 
BeginDictionary()619 void TracedValue::BeginDictionary() {
620   DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
621   DEBUG_PUSH_CONTAINER(kStackTypeDict);
622   writer_->BeginDictionary();
623 }
624 
EndArray()625 void TracedValue::EndArray() {
626   DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
627   DEBUG_POP_CONTAINER();
628   writer_->EndArray();
629 }
630 
EndDictionary()631 void TracedValue::EndDictionary() {
632   DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
633   DEBUG_POP_CONTAINER();
634   writer_->EndDictionary();
635 }
636 
ToBaseValue() const637 std::unique_ptr<base::Value> TracedValue::ToBaseValue() const {
638   DCHECK(writer_->IsPickleWriter());
639   return static_cast<const PickleWriter*>(writer_.get())->ToBaseValue();
640 }
641 
AppendAsTraceFormat(std::string * out) const642 void TracedValue::AppendAsTraceFormat(std::string* out) const {
643   DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
644   DCHECK_CONTAINER_STACK_DEPTH_EQ(1u);
645 
646   writer_->AppendAsTraceFormat(out);
647 }
648 
AppendToProto(ProtoAppender * appender) const649 bool TracedValue::AppendToProto(ProtoAppender* appender) const {
650   return writer_->AppendToProto(appender);
651 }
652 
EstimateTraceMemoryOverhead(TraceEventMemoryOverhead * overhead)653 void TracedValue::EstimateTraceMemoryOverhead(
654     TraceEventMemoryOverhead* overhead) {
655   writer_->EstimateTraceMemoryOverhead(overhead);
656 }
657 
Array(const std::initializer_list<ArrayItem> items)658 TracedValue::Array::Array(const std::initializer_list<ArrayItem> items) {
659   items_ = std::move(items);
660 }
661 
Array(TracedValue::Array && other)662 TracedValue::Array::Array(TracedValue::Array&& other) {
663   items_ = std::move(other.items_);
664 }
665 
WriteToValue(TracedValue * value) const666 void TracedValue::Array::WriteToValue(TracedValue* value) const {
667   for (const auto& item : items_) {
668     item.WriteToValue(value);
669   }
670 }
671 
Dictionary(const std::initializer_list<DictionaryItem> items)672 TracedValue::Dictionary::Dictionary(
673     const std::initializer_list<DictionaryItem> items) {
674   items_ = items;
675 }
676 
Dictionary(TracedValue::Dictionary && other)677 TracedValue::Dictionary::Dictionary(TracedValue::Dictionary&& other) {
678   items_ = std::move(other.items_);
679 }
680 
WriteToValue(TracedValue * value) const681 void TracedValue::Dictionary::WriteToValue(TracedValue* value) const {
682   for (const auto& item : items_) {
683     item.WriteToValue(value);
684   }
685 }
686 
ValueHolder(int value)687 TracedValue::ValueHolder::ValueHolder(int value) {
688   kept_value_.int_value = value;
689   kept_value_type_ = KeptValueType::kIntType;
690 }
691 
ValueHolder(double value)692 TracedValue::ValueHolder::ValueHolder(double value) {
693   kept_value_.double_value = value;
694   kept_value_type_ = KeptValueType::kDoubleType;
695 }
696 
ValueHolder(bool value)697 TracedValue::ValueHolder::ValueHolder(bool value) {
698   kept_value_.bool_value = value;
699   kept_value_type_ = KeptValueType::kBoolType;
700 }
701 
ValueHolder(std::string_view value)702 TracedValue::ValueHolder::ValueHolder(std::string_view value) {
703   kept_value_.string_piece_value = value;
704   kept_value_type_ = KeptValueType::kStringPieceType;
705 }
706 
ValueHolder(std::string value)707 TracedValue::ValueHolder::ValueHolder(std::string value) {
708   new (&kept_value_.std_string_value) std::string(std::move(value));
709   kept_value_type_ = KeptValueType::kStdStringType;
710 }
711 
ValueHolder(void * value)712 TracedValue::ValueHolder::ValueHolder(void* value) {
713   kept_value_.void_ptr_value = value;
714   kept_value_type_ = KeptValueType::kVoidPtrType;
715 }
716 
ValueHolder(const char * value)717 TracedValue::ValueHolder::ValueHolder(const char* value) {
718   kept_value_.string_piece_value = value;
719   kept_value_type_ = KeptValueType::kStringPieceType;
720 }
721 
ValueHolder(TracedValue::Dictionary & value)722 TracedValue::ValueHolder::ValueHolder(TracedValue::Dictionary& value) {
723   new (&kept_value_.dictionary_value) TracedValue::Dictionary(std::move(value));
724   kept_value_type_ = KeptValueType::kDictionaryType;
725 }
726 
ValueHolder(TracedValue::Array & value)727 TracedValue::ValueHolder::ValueHolder(TracedValue::Array& value) {
728   new (&kept_value_.array_value) TracedValue::Array(std::move(value));
729   kept_value_type_ = KeptValueType::kArrayType;
730 }
731 
ValueHolder(TracedValue::ValueHolder && other)732 TracedValue::ValueHolder::ValueHolder(TracedValue::ValueHolder&& other) {
733   // Remember to call a destructor if necessary.
734   if (kept_value_type_ == KeptValueType::kStdStringType) {
735     delete (&kept_value_.std_string_value);
736   }
737   switch (other.kept_value_type_) {
738     case KeptValueType::kIntType: {
739       kept_value_.int_value = other.kept_value_.int_value;
740       break;
741     }
742     case KeptValueType::kDoubleType: {
743       kept_value_.double_value = other.kept_value_.double_value;
744       break;
745     }
746     case KeptValueType::kBoolType: {
747       kept_value_.bool_value = other.kept_value_.bool_value;
748       break;
749     }
750     case KeptValueType::kStringPieceType: {
751       kept_value_.string_piece_value = other.kept_value_.string_piece_value;
752       break;
753     }
754     case KeptValueType::kStdStringType: {
755       new (&kept_value_.std_string_value)
756           std::string(std::move(other.kept_value_.std_string_value));
757       break;
758     }
759     case KeptValueType::kVoidPtrType: {
760       kept_value_.void_ptr_value = other.kept_value_.void_ptr_value;
761       break;
762     }
763     case KeptValueType::kArrayType: {
764       new (&kept_value_.array_value)
765           TracedValue::Array(std::move(other.kept_value_.array_value));
766       break;
767     }
768     case KeptValueType::kDictionaryType: {
769       new (&kept_value_.dictionary_value) TracedValue::Dictionary(
770           std::move(other.kept_value_.dictionary_value));
771       break;
772     }
773   }
774   kept_value_type_ = other.kept_value_type_;
775 }
776 
WriteToValue(TracedValue * value) const777 void TracedValue::ValueHolder::WriteToValue(TracedValue* value) const {
778   switch (kept_value_type_) {
779     case KeptValueType::kIntType: {
780       value->AppendInteger(kept_value_.int_value);
781       break;
782     }
783     case KeptValueType::kDoubleType: {
784       value->AppendDouble(kept_value_.double_value);
785       break;
786     }
787     case KeptValueType::kBoolType: {
788       value->AppendBoolean(kept_value_.bool_value);
789       break;
790     }
791     case KeptValueType::kStringPieceType: {
792       value->AppendString(kept_value_.string_piece_value);
793       break;
794     }
795     case KeptValueType::kStdStringType: {
796       value->AppendString(kept_value_.std_string_value);
797       break;
798     }
799     case KeptValueType::kVoidPtrType: {
800       value->AppendPointer(kept_value_.void_ptr_value);
801       break;
802     }
803     case KeptValueType::kArrayType: {
804       value->BeginArray();
805       kept_value_.array_value.WriteToValue(value);
806       value->EndArray();
807       break;
808     }
809     case KeptValueType::kDictionaryType: {
810       value->BeginDictionary();
811       kept_value_.dictionary_value.WriteToValue(value);
812       value->EndDictionary();
813       break;
814     }
815   }
816 }
817 
WriteToValue(const char * name,TracedValue * value) const818 void TracedValue::ValueHolder::WriteToValue(const char* name,
819                                             TracedValue* value) const {
820   switch (kept_value_type_) {
821     case KeptValueType::kIntType: {
822       value->SetInteger(name, kept_value_.int_value);
823       break;
824     }
825     case KeptValueType::kDoubleType: {
826       value->SetDouble(name, kept_value_.double_value);
827       break;
828     }
829     case KeptValueType::kBoolType: {
830       value->SetBoolean(name, kept_value_.bool_value);
831       break;
832     }
833     case KeptValueType::kStringPieceType: {
834       value->SetString(name, kept_value_.string_piece_value);
835       break;
836     }
837     case KeptValueType::kStdStringType: {
838       value->SetString(name, kept_value_.std_string_value);
839       break;
840     }
841     case KeptValueType::kVoidPtrType: {
842       value->SetPointer(name, kept_value_.void_ptr_value);
843       break;
844     }
845     case KeptValueType::kArrayType: {
846       value->BeginArray(name);
847       kept_value_.array_value.WriteToValue(value);
848       value->EndArray();
849       break;
850     }
851     case KeptValueType::kDictionaryType: {
852       value->BeginDictionary(name);
853       kept_value_.dictionary_value.WriteToValue(value);
854       value->EndDictionary();
855       break;
856     }
857   }
858 }
859 
WriteToValue(TracedValue * value) const860 void TracedValue::ArrayItem::WriteToValue(TracedValue* value) const {
861   ValueHolder::WriteToValue(value);
862 }
863 
WriteToValue(TracedValue * value) const864 void TracedValue::DictionaryItem::WriteToValue(TracedValue* value) const {
865   ValueHolder::WriteToValue(name_, value);
866 }
867 
Build(const std::initializer_list<DictionaryItem> items)868 std::unique_ptr<TracedValue> TracedValue::Build(
869     const std::initializer_list<DictionaryItem> items) {
870   std::unique_ptr<TracedValue> value(new TracedValue());
871   for (const auto& item : items) {
872     item.WriteToValue(value.get());
873   }
874   return value;
875 }
876 
ToJSON() const877 std::string TracedValueJSON::ToJSON() const {
878   std::string result;
879   AppendAsTraceFormat(&result);
880   return result;
881 }
882 
ToFormattedJSON() const883 std::string TracedValueJSON::ToFormattedJSON() const {
884   std::string str;
885   base::JSONWriter::WriteWithOptions(
886       *ToBaseValue(),
887       base::JSONWriter::OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION |
888           base::JSONWriter::OPTIONS_PRETTY_PRINT,
889       &str);
890   return str;
891 }
892 
ArrayScope(TracedValue * value)893 TracedValue::ArrayScope::ArrayScope(TracedValue* value) : value_(value) {}
894 
~ArrayScope()895 TracedValue::ArrayScope::~ArrayScope() {
896   value_->EndArray();
897 }
898 
AppendArrayScoped()899 TracedValue::ArrayScope TracedValue::AppendArrayScoped() {
900   BeginArray();
901   return TracedValue::ArrayScope(this);
902 }
903 
BeginArrayScoped(const char * name)904 TracedValue::ArrayScope TracedValue::BeginArrayScoped(const char* name) {
905   BeginArray(name);
906   return TracedValue::ArrayScope(this);
907 }
908 
BeginArrayScopedWithCopiedName(std::string_view name)909 TracedValue::ArrayScope TracedValue::BeginArrayScopedWithCopiedName(
910     std::string_view name) {
911   BeginArrayWithCopiedName(name);
912   return TracedValue::ArrayScope(this);
913 }
914 
DictionaryScope(TracedValue * value)915 TracedValue::DictionaryScope::DictionaryScope(TracedValue* value)
916     : value_(value) {}
917 
~DictionaryScope()918 TracedValue::DictionaryScope::~DictionaryScope() {
919   value_->EndDictionary();
920 }
921 
AppendDictionaryScoped()922 TracedValue::DictionaryScope TracedValue::AppendDictionaryScoped() {
923   BeginDictionary();
924   return TracedValue::DictionaryScope(this);
925 }
926 
BeginDictionaryScoped(const char * name)927 TracedValue::DictionaryScope TracedValue::BeginDictionaryScoped(
928     const char* name) {
929   BeginDictionary(name);
930   return TracedValue::DictionaryScope(this);
931 }
932 
BeginDictionaryScopedWithCopiedName(std::string_view name)933 TracedValue::DictionaryScope TracedValue::BeginDictionaryScopedWithCopiedName(
934     std::string_view name) {
935   BeginDictionaryWithCopiedName(name);
936   return TracedValue::DictionaryScope(this);
937 }
938 
939 }  // namespace base::trace_event
940