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