1 // Copyright (c) 2014 The Chromium Authors. All rights reserved.
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 <stdint.h>
8 
9 #include <atomic>
10 #include <utility>
11 
12 #include "base/bits.h"
13 #include "base/containers/circular_deque.h"
14 #include "base/json/json_writer.h"
15 #include "base/json/string_escape.h"
16 #include "base/memory/ptr_util.h"
17 #include "base/trace_event/trace_event.h"
18 #include "base/trace_event/trace_event_impl.h"
19 #include "base/trace_event/trace_event_memory_overhead.h"
20 #include "base/trace_event/trace_log.h"
21 #include "base/values.h"
22 
23 namespace base {
24 namespace trace_event {
25 
26 namespace {
27 const char kTypeStartDict = '{';
28 const char kTypeEndDict = '}';
29 const char kTypeStartArray = '[';
30 const char kTypeEndArray = ']';
31 const char kTypeBool = 'b';
32 const char kTypeInt = 'i';
33 const char kTypeDouble = 'd';
34 const char kTypeString = 's';
35 const char kTypeCStr = '*';  // only used for key names
36 
37 std::atomic<TracedValue::WriterFactoryCallback> g_writer_factory_callback;
38 
39 #ifndef NDEBUG
40 const bool kStackTypeDict = false;
41 const bool kStackTypeArray = true;
42 #define DCHECK_CURRENT_CONTAINER_IS(x) DCHECK_EQ(x, nesting_stack_.back())
43 #define DCHECK_CONTAINER_STACK_DEPTH_EQ(x) DCHECK_EQ(x, nesting_stack_.size())
44 #define DEBUG_PUSH_CONTAINER(x) nesting_stack_.push_back(x)
45 #define DEBUG_POP_CONTAINER() nesting_stack_.pop_back()
46 #else
47 #define DCHECK_CURRENT_CONTAINER_IS(x) \
48   do {                                 \
49   } while (0)
50 #define DCHECK_CONTAINER_STACK_DEPTH_EQ(x) \
51   do {                                     \
52   } while (0)
53 #define DEBUG_PUSH_CONTAINER(x) \
54   do {                          \
55   } while (0)
56 #define DEBUG_POP_CONTAINER() \
57   do {                        \
58   } while (0)
59 #endif
60 
WriteKeyNameAsRawPtr(Pickle & pickle,const char * ptr)61 inline void WriteKeyNameAsRawPtr(Pickle& pickle, const char* ptr) {
62   pickle.WriteBytes(&kTypeCStr, 1);
63   pickle.WriteUInt64(static_cast<uint64_t>(reinterpret_cast<uintptr_t>(ptr)));
64 }
65 
WriteKeyNameWithCopy(Pickle & pickle,base::StringPiece str)66 inline void WriteKeyNameWithCopy(Pickle& pickle, base::StringPiece str) {
67   pickle.WriteBytes(&kTypeString, 1);
68   pickle.WriteString(str);
69 }
70 
ReadKeyName(PickleIterator & pickle_iterator)71 std::string ReadKeyName(PickleIterator& pickle_iterator) {
72   const char* type = nullptr;
73   bool res = pickle_iterator.ReadBytes(&type, 1);
74   std::string key_name;
75   if (res && *type == kTypeCStr) {
76     uint64_t ptr_value = 0;
77     res = pickle_iterator.ReadUInt64(&ptr_value);
78     key_name = reinterpret_cast<const char*>(static_cast<uintptr_t>(ptr_value));
79   } else if (res && *type == kTypeString) {
80     res = pickle_iterator.ReadString(&key_name);
81   }
82   DCHECK(res);
83   return key_name;
84 }
85 
86 class PickleWriter final : public TracedValue::Writer {
87  public:
PickleWriter(size_t capacity)88   explicit PickleWriter(size_t capacity) {
89     if (capacity) {
90       pickle_.Reserve(capacity);
91     }
92   }
93 
IsPickleWriter() const94   bool IsPickleWriter() const override { return true; }
IsProtoWriter() const95   bool IsProtoWriter() const override { return false; }
96 
SetInteger(const char * name,int value)97   void SetInteger(const char* name, int value) override {
98     pickle_.WriteBytes(&kTypeInt, 1);
99     pickle_.WriteInt(value);
100     WriteKeyNameAsRawPtr(pickle_, name);
101   }
102 
SetIntegerWithCopiedName(base::StringPiece name,int value)103   void SetIntegerWithCopiedName(base::StringPiece name, int value) override {
104     pickle_.WriteBytes(&kTypeInt, 1);
105     pickle_.WriteInt(value);
106     WriteKeyNameWithCopy(pickle_, name);
107   }
108 
SetDouble(const char * name,double value)109   void SetDouble(const char* name, double value) override {
110     pickle_.WriteBytes(&kTypeDouble, 1);
111     pickle_.WriteDouble(value);
112     WriteKeyNameAsRawPtr(pickle_, name);
113   }
114 
SetDoubleWithCopiedName(base::StringPiece name,double value)115   void SetDoubleWithCopiedName(base::StringPiece name, double value) override {
116     pickle_.WriteBytes(&kTypeDouble, 1);
117     pickle_.WriteDouble(value);
118     WriteKeyNameWithCopy(pickle_, name);
119   }
120 
SetBoolean(const char * name,bool value)121   void SetBoolean(const char* name, bool value) override {
122     pickle_.WriteBytes(&kTypeBool, 1);
123     pickle_.WriteBool(value);
124     WriteKeyNameAsRawPtr(pickle_, name);
125   }
126 
SetBooleanWithCopiedName(base::StringPiece name,bool value)127   void SetBooleanWithCopiedName(base::StringPiece name, bool value) override {
128     pickle_.WriteBytes(&kTypeBool, 1);
129     pickle_.WriteBool(value);
130     WriteKeyNameWithCopy(pickle_, name);
131   }
132 
SetString(const char * name,base::StringPiece value)133   void SetString(const char* name, base::StringPiece value) override {
134     pickle_.WriteBytes(&kTypeString, 1);
135     pickle_.WriteString(value);
136     WriteKeyNameAsRawPtr(pickle_, name);
137   }
138 
SetStringWithCopiedName(base::StringPiece name,base::StringPiece value)139   void SetStringWithCopiedName(base::StringPiece name,
140                                base::StringPiece value) override {
141     pickle_.WriteBytes(&kTypeString, 1);
142     pickle_.WriteString(value);
143     WriteKeyNameWithCopy(pickle_, name);
144   }
145 
SetValue(const char * name,Writer * value)146   void SetValue(const char* name, Writer* value) override {
147     DCHECK(value->IsPickleWriter());
148     const PickleWriter* pickle_writer = static_cast<const PickleWriter*>(value);
149 
150     BeginDictionary(name);
151     pickle_.WriteBytes(pickle_writer->pickle_.payload(),
152                        static_cast<int>(pickle_writer->pickle_.payload_size()));
153     EndDictionary();
154   }
155 
SetValueWithCopiedName(base::StringPiece name,Writer * value)156   void SetValueWithCopiedName(base::StringPiece name, Writer* value) override {
157     DCHECK(value->IsPickleWriter());
158     const PickleWriter* pickle_writer = static_cast<const PickleWriter*>(value);
159 
160     BeginDictionaryWithCopiedName(name);
161     pickle_.WriteBytes(pickle_writer->pickle_.payload(),
162                        static_cast<int>(pickle_writer->pickle_.payload_size()));
163     EndDictionary();
164   }
165 
BeginArray()166   void BeginArray() override { pickle_.WriteBytes(&kTypeStartArray, 1); }
167 
BeginDictionary()168   void BeginDictionary() override { pickle_.WriteBytes(&kTypeStartDict, 1); }
169 
BeginDictionary(const char * name)170   void BeginDictionary(const char* name) override {
171     pickle_.WriteBytes(&kTypeStartDict, 1);
172     WriteKeyNameAsRawPtr(pickle_, name);
173   }
174 
BeginDictionaryWithCopiedName(base::StringPiece name)175   void BeginDictionaryWithCopiedName(base::StringPiece name) override {
176     pickle_.WriteBytes(&kTypeStartDict, 1);
177     WriteKeyNameWithCopy(pickle_, name);
178   }
179 
BeginArray(const char * name)180   void BeginArray(const char* name) override {
181     pickle_.WriteBytes(&kTypeStartArray, 1);
182     WriteKeyNameAsRawPtr(pickle_, name);
183   }
184 
BeginArrayWithCopiedName(base::StringPiece name)185   void BeginArrayWithCopiedName(base::StringPiece name) override {
186     pickle_.WriteBytes(&kTypeStartArray, 1);
187     WriteKeyNameWithCopy(pickle_, name);
188   }
189 
EndDictionary()190   void EndDictionary() override { pickle_.WriteBytes(&kTypeEndDict, 1); }
EndArray()191   void EndArray() override { pickle_.WriteBytes(&kTypeEndArray, 1); }
192 
AppendInteger(int value)193   void AppendInteger(int value) override {
194     pickle_.WriteBytes(&kTypeInt, 1);
195     pickle_.WriteInt(value);
196   }
197 
AppendDouble(double value)198   void AppendDouble(double value) override {
199     pickle_.WriteBytes(&kTypeDouble, 1);
200     pickle_.WriteDouble(value);
201   }
202 
AppendBoolean(bool value)203   void AppendBoolean(bool value) override {
204     pickle_.WriteBytes(&kTypeBool, 1);
205     pickle_.WriteBool(value);
206   }
207 
AppendString(base::StringPiece value)208   void AppendString(base::StringPiece value) override {
209     pickle_.WriteBytes(&kTypeString, 1);
210     pickle_.WriteString(value);
211   }
212 
AppendAsTraceFormat(std::string * out) const213   void AppendAsTraceFormat(std::string* out) const override {
214     struct State {
215       enum Type { kTypeDict, kTypeArray };
216       Type type;
217       bool needs_comma;
218     };
219 
220     auto maybe_append_key_name = [](State current_state, PickleIterator* it,
221                                     std::string* out) {
222       if (current_state.type == State::kTypeDict) {
223         EscapeJSONString(ReadKeyName(*it), true, out);
224         out->append(":");
225       }
226     };
227 
228     base::circular_deque<State> state_stack;
229 
230     out->append("{");
231     state_stack.push_back({State::kTypeDict});
232 
233     PickleIterator it(pickle_);
234     for (const char* type; it.ReadBytes(&type, 1);) {
235       switch (*type) {
236         case kTypeEndDict:
237           out->append("}");
238           state_stack.pop_back();
239           continue;
240 
241         case kTypeEndArray:
242           out->append("]");
243           state_stack.pop_back();
244           continue;
245       }
246 
247       // Use an index so it will stay valid across resizes.
248       size_t current_state_index = state_stack.size() - 1;
249       if (state_stack[current_state_index].needs_comma) {
250         out->append(",");
251       }
252 
253       switch (*type) {
254         case kTypeStartDict: {
255           maybe_append_key_name(state_stack[current_state_index], &it, out);
256           out->append("{");
257           state_stack.push_back({State::kTypeDict});
258           break;
259         }
260 
261         case kTypeStartArray: {
262           maybe_append_key_name(state_stack[current_state_index], &it, out);
263           out->append("[");
264           state_stack.push_back({State::kTypeArray});
265           break;
266         }
267 
268         case kTypeBool: {
269           TraceEvent::TraceValue json_value;
270           CHECK(it.ReadBool(&json_value.as_bool));
271           maybe_append_key_name(state_stack[current_state_index], &it, out);
272           json_value.AppendAsJSON(TRACE_VALUE_TYPE_BOOL, out);
273           break;
274         }
275 
276         case kTypeInt: {
277           int value;
278           CHECK(it.ReadInt(&value));
279           maybe_append_key_name(state_stack[current_state_index], &it, out);
280           TraceEvent::TraceValue json_value;
281           json_value.as_int = value;
282           json_value.AppendAsJSON(TRACE_VALUE_TYPE_INT, out);
283           break;
284         }
285 
286         case kTypeDouble: {
287           TraceEvent::TraceValue json_value;
288           CHECK(it.ReadDouble(&json_value.as_double));
289           maybe_append_key_name(state_stack[current_state_index], &it, out);
290           json_value.AppendAsJSON(TRACE_VALUE_TYPE_DOUBLE, out);
291           break;
292         }
293 
294         case kTypeString: {
295           std::string value;
296           CHECK(it.ReadString(&value));
297           maybe_append_key_name(state_stack[current_state_index], &it, out);
298           TraceEvent::TraceValue json_value;
299           json_value.as_string = value.c_str();
300           json_value.AppendAsJSON(TRACE_VALUE_TYPE_STRING, out);
301           break;
302         }
303 
304         default:
305           NOTREACHED();
306       }
307 
308       state_stack[current_state_index].needs_comma = true;
309     }
310 
311     out->append("}");
312     state_stack.pop_back();
313 
314     DCHECK(state_stack.empty());
315   }
316 
EstimateTraceMemoryOverhead(TraceEventMemoryOverhead * overhead)317   void EstimateTraceMemoryOverhead(
318       TraceEventMemoryOverhead* overhead) override {
319     overhead->Add(TraceEventMemoryOverhead::kTracedValue,
320                   /* allocated size */
321                   pickle_.GetTotalAllocatedSize(),
322                   /* resident size */
323                   pickle_.size());
324   }
325 
ToBaseValue() const326   std::unique_ptr<base::Value> ToBaseValue() const {
327     base::Value root(base::Value::Type::DICTIONARY);
328     Value* cur_dict = &root;
329     Value* cur_list = nullptr;
330     std::vector<Value*> stack;
331     PickleIterator it(pickle_);
332     const char* type;
333 
334     while (it.ReadBytes(&type, 1)) {
335       DCHECK((cur_dict && !cur_list) || (cur_list && !cur_dict));
336       switch (*type) {
337         case kTypeStartDict: {
338           base::Value new_dict(base::Value::Type::DICTIONARY);
339           if (cur_dict) {
340             stack.push_back(cur_dict);
341             cur_dict = cur_dict->SetKey(ReadKeyName(it), std::move(new_dict));
342           } else {
343             cur_list->Append(std::move(new_dict));
344             // |new_dict| is invalidated at this point, so |cur_dict| needs to
345             // be reset.
346             cur_dict = &cur_list->GetList().back();
347             stack.push_back(cur_list);
348             cur_list = nullptr;
349           }
350         } break;
351 
352         case kTypeEndArray:
353         case kTypeEndDict: {
354           if (stack.back()->is_dict()) {
355             cur_dict = stack.back();
356             cur_list = nullptr;
357           } else if (stack.back()->is_list()) {
358             cur_list = stack.back();
359             cur_dict = nullptr;
360           }
361           stack.pop_back();
362         } break;
363 
364         case kTypeStartArray: {
365           base::Value new_list(base::Value::Type::LIST);
366           if (cur_dict) {
367             stack.push_back(cur_dict);
368             cur_list = cur_dict->SetKey(ReadKeyName(it), std::move(new_list));
369             cur_dict = nullptr;
370           } else {
371             cur_list->Append(std::move(new_list));
372             stack.push_back(cur_list);
373             // |cur_list| is invalidated at this point by the Append, so it
374             // needs to be reset.
375             cur_list = &cur_list->GetList().back();
376           }
377         } break;
378 
379         case kTypeBool: {
380           bool value;
381           CHECK(it.ReadBool(&value));
382           if (cur_dict) {
383             cur_dict->SetBoolKey(ReadKeyName(it), value);
384           } else {
385             cur_list->Append(value);
386           }
387         } break;
388 
389         case kTypeInt: {
390           int value;
391           CHECK(it.ReadInt(&value));
392           if (cur_dict) {
393             cur_dict->SetIntKey(ReadKeyName(it), value);
394           } else {
395             cur_list->Append(value);
396           }
397         } break;
398 
399         case kTypeDouble: {
400           TraceEvent::TraceValue trace_value;
401           CHECK(it.ReadDouble(&trace_value.as_double));
402           Value base_value;
403           if (!std::isfinite(trace_value.as_double)) {
404             // base::Value doesn't support nan and infinity values. Use strings
405             // for them instead. This follows the same convention in
406             // AppendAsTraceFormat(), supported by TraceValue::Append*().
407             std::string value_string;
408             trace_value.AppendAsString(TRACE_VALUE_TYPE_DOUBLE, &value_string);
409             base_value = Value(value_string);
410           } else {
411             base_value = Value(trace_value.as_double);
412           }
413           if (cur_dict) {
414             cur_dict->SetKey(ReadKeyName(it), std::move(base_value));
415           } else {
416             cur_list->Append(std::move(base_value));
417           }
418         } break;
419 
420         case kTypeString: {
421           std::string value;
422           CHECK(it.ReadString(&value));
423           if (cur_dict) {
424             cur_dict->SetStringKey(ReadKeyName(it), std::move(value));
425           } else {
426             cur_list->Append(std::move(value));
427           }
428         } break;
429 
430         default:
431           NOTREACHED();
432       }
433     }
434     DCHECK(stack.empty());
435     return base::Value::ToUniquePtrValue(std::move(root));
436   }
437 
438  private:
439   Pickle pickle_;
440 };
441 
CreateWriter(size_t capacity)442 std::unique_ptr<TracedValue::Writer> CreateWriter(size_t capacity) {
443   TracedValue::WriterFactoryCallback callback =
444       g_writer_factory_callback.load(std::memory_order_relaxed);
445   if (callback) {
446     return callback(capacity);
447   }
448 
449   return std::make_unique<PickleWriter>(capacity);
450 }
451 
452 }  // namespace
453 
AppendToProto(ProtoAppender * appender)454 bool TracedValue::Writer::AppendToProto(ProtoAppender* appender) {
455   return false;
456 }
457 
458 // static
SetWriterFactoryCallback(WriterFactoryCallback callback)459 void TracedValue::SetWriterFactoryCallback(WriterFactoryCallback callback) {
460   g_writer_factory_callback.store(callback);
461 }
462 
TracedValue(size_t capacity)463 TracedValue::TracedValue(size_t capacity)
464     : TracedValue(capacity, /*forced_json*/ false) {}
465 
TracedValue(size_t capacity,bool forced_json)466 TracedValue::TracedValue(size_t capacity, bool forced_json) {
467   DEBUG_PUSH_CONTAINER(kStackTypeDict);
468 
469   writer_ = forced_json ? std::make_unique<PickleWriter>(capacity)
470                         : CreateWriter(capacity);
471 }
472 
~TracedValue()473 TracedValue::~TracedValue() {
474   DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
475   DEBUG_POP_CONTAINER();
476   DCHECK_CONTAINER_STACK_DEPTH_EQ(0u);
477 }
478 
SetInteger(const char * name,int value)479 void TracedValue::SetInteger(const char* name, int value) {
480   DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
481   writer_->SetInteger(name, value);
482 }
483 
SetIntegerWithCopiedName(base::StringPiece name,int value)484 void TracedValue::SetIntegerWithCopiedName(base::StringPiece name, int value) {
485   DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
486   writer_->SetIntegerWithCopiedName(name, value);
487 }
488 
SetDouble(const char * name,double value)489 void TracedValue::SetDouble(const char* name, double value) {
490   DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
491   writer_->SetDouble(name, value);
492 }
493 
SetDoubleWithCopiedName(base::StringPiece name,double value)494 void TracedValue::SetDoubleWithCopiedName(base::StringPiece name,
495                                           double value) {
496   DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
497   writer_->SetDoubleWithCopiedName(name, value);
498 }
499 
SetBoolean(const char * name,bool value)500 void TracedValue::SetBoolean(const char* name, bool value) {
501   DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
502   writer_->SetBoolean(name, value);
503 }
504 
SetBooleanWithCopiedName(base::StringPiece name,bool value)505 void TracedValue::SetBooleanWithCopiedName(base::StringPiece name, bool value) {
506   DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
507   writer_->SetBooleanWithCopiedName(name, value);
508 }
509 
SetString(const char * name,base::StringPiece value)510 void TracedValue::SetString(const char* name, base::StringPiece value) {
511   DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
512   writer_->SetString(name, value);
513 }
514 
SetStringWithCopiedName(base::StringPiece name,base::StringPiece value)515 void TracedValue::SetStringWithCopiedName(base::StringPiece name,
516                                           base::StringPiece value) {
517   DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
518   writer_->SetStringWithCopiedName(name, value);
519 }
520 
SetValue(const char * name,TracedValue * value)521 void TracedValue::SetValue(const char* name, TracedValue* value) {
522   DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
523   writer_->SetValue(name, value->writer_.get());
524 }
525 
SetValueWithCopiedName(base::StringPiece name,TracedValue * value)526 void TracedValue::SetValueWithCopiedName(base::StringPiece name,
527                                          TracedValue* value) {
528   DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
529   writer_->SetValueWithCopiedName(name, value->writer_.get());
530 }
531 
BeginDictionary(const char * name)532 void TracedValue::BeginDictionary(const char* name) {
533   DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
534   DEBUG_PUSH_CONTAINER(kStackTypeDict);
535   writer_->BeginDictionary(name);
536 }
537 
BeginDictionaryWithCopiedName(base::StringPiece name)538 void TracedValue::BeginDictionaryWithCopiedName(base::StringPiece name) {
539   DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
540   DEBUG_PUSH_CONTAINER(kStackTypeDict);
541   writer_->BeginDictionaryWithCopiedName(name);
542 }
543 
BeginArray(const char * name)544 void TracedValue::BeginArray(const char* name) {
545   DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
546   DEBUG_PUSH_CONTAINER(kStackTypeArray);
547   writer_->BeginArray(name);
548 }
549 
BeginArrayWithCopiedName(base::StringPiece name)550 void TracedValue::BeginArrayWithCopiedName(base::StringPiece name) {
551   DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
552   DEBUG_PUSH_CONTAINER(kStackTypeArray);
553   writer_->BeginArrayWithCopiedName(name);
554 }
555 
AppendInteger(int value)556 void TracedValue::AppendInteger(int value) {
557   DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
558   writer_->AppendInteger(value);
559 }
560 
AppendDouble(double value)561 void TracedValue::AppendDouble(double value) {
562   DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
563   writer_->AppendDouble(value);
564 }
565 
AppendBoolean(bool value)566 void TracedValue::AppendBoolean(bool value) {
567   DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
568   writer_->AppendBoolean(value);
569 }
570 
AppendString(base::StringPiece value)571 void TracedValue::AppendString(base::StringPiece value) {
572   DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
573   writer_->AppendString(value);
574 }
575 
BeginArray()576 void TracedValue::BeginArray() {
577   DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
578   DEBUG_PUSH_CONTAINER(kStackTypeArray);
579   writer_->BeginArray();
580 }
581 
BeginDictionary()582 void TracedValue::BeginDictionary() {
583   DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
584   DEBUG_PUSH_CONTAINER(kStackTypeDict);
585   writer_->BeginDictionary();
586 }
587 
EndArray()588 void TracedValue::EndArray() {
589   DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
590   DEBUG_POP_CONTAINER();
591   writer_->EndArray();
592 }
593 
EndDictionary()594 void TracedValue::EndDictionary() {
595   DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
596   DEBUG_POP_CONTAINER();
597   writer_->EndDictionary();
598 }
599 
ToBaseValue() const600 std::unique_ptr<base::Value> TracedValue::ToBaseValue() const {
601   DCHECK(writer_->IsPickleWriter());
602   return static_cast<const PickleWriter*>(writer_.get())->ToBaseValue();
603 }
604 
AppendAsTraceFormat(std::string * out) const605 void TracedValue::AppendAsTraceFormat(std::string* out) const {
606   DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
607   DCHECK_CONTAINER_STACK_DEPTH_EQ(1u);
608 
609   writer_->AppendAsTraceFormat(out);
610 }
611 
AppendToProto(ProtoAppender * appender)612 bool TracedValue::AppendToProto(ProtoAppender* appender) {
613   return writer_->AppendToProto(appender);
614 }
615 
EstimateTraceMemoryOverhead(TraceEventMemoryOverhead * overhead)616 void TracedValue::EstimateTraceMemoryOverhead(
617     TraceEventMemoryOverhead* overhead) {
618   writer_->EstimateTraceMemoryOverhead(overhead);
619 }
620 
ToJSON() const621 std::string TracedValueJSON::ToJSON() const {
622   std::string result;
623   AppendAsTraceFormat(&result);
624   return result;
625 }
626 
ToFormattedJSON() const627 std::string TracedValueJSON::ToFormattedJSON() const {
628   std::string str;
629   base::JSONWriter::WriteWithOptions(
630       *ToBaseValue(),
631       base::JSONWriter::OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION |
632           base::JSONWriter::OPTIONS_PRETTY_PRINT,
633       &str);
634   return str;
635 }
636 
637 }  // namespace trace_event
638 }  // namespace base
639