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