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