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