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