1 // Copyright (c) 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/trace_event/trace_event_argument.h"
7 #include "base/json/json_writer.h"
8 #include "base/trace_event/trace_event_memory_overhead.h"
9 #include "base/values.h"
12 namespace trace_event
{
15 const char kTypeStartDict
= '{';
16 const char kTypeEndDict
= '}';
17 const char kTypeStartArray
= '[';
18 const char kTypeEndArray
= ']';
19 const char kTypeBool
= 'b';
20 const char kTypeInt
= 'i';
21 const char kTypeDouble
= 'd';
22 const char kTypeString
= 's';
23 const char kTypeCStr
= '*';
26 const bool kStackTypeDict
= false;
27 const bool kStackTypeArray
= true;
28 #define DCHECK_CURRENT_CONTAINER_IS(x) DCHECK_EQ(x, nesting_stack_.back())
29 #define DCHECK_CONTAINER_STACK_DEPTH_EQ(x) DCHECK_EQ(x, nesting_stack_.size())
30 #define DEBUG_PUSH_CONTAINER(x) nesting_stack_.push_back(x)
31 #define DEBUG_POP_CONTAINER() nesting_stack_.pop_back()
33 #define DCHECK_CURRENT_CONTAINER_IS(x) do {} while (0)
34 #define DCHECK_CONTAINER_STACK_DEPTH_EQ(x) do {} while (0)
35 #define DEBUG_PUSH_CONTAINER(x) do {} while (0)
36 #define DEBUG_POP_CONTAINER() do {} while (0)
39 inline void WriteKeyNameAsRawPtr(Pickle
& pickle
, const char* ptr
) {
40 pickle
.WriteBytes(&kTypeCStr
, 1);
41 pickle
.WriteUInt64(static_cast<uint64
>(reinterpret_cast<uintptr_t>(ptr
)));
44 inline void WriteKeyNameAsStdString(Pickle
& pickle
, const std::string
& str
) {
45 pickle
.WriteBytes(&kTypeString
, 1);
46 pickle
.WriteString(str
);
49 std::string
ReadKeyName(PickleIterator
& pickle_iterator
) {
50 const char* type
= nullptr;
51 bool res
= pickle_iterator
.ReadBytes(&type
, 1);
53 if (res
&& *type
== kTypeCStr
) {
55 res
= pickle_iterator
.ReadUInt64(&ptr_value
);
56 key_name
= reinterpret_cast<const char*>(static_cast<uintptr_t>(ptr_value
));
57 } else if (res
&& *type
== kTypeString
) {
58 res
= pickle_iterator
.ReadString(&key_name
);
65 TracedValue::TracedValue() : TracedValue(0) {
68 TracedValue::TracedValue(size_t capacity
) {
69 DEBUG_PUSH_CONTAINER(kStackTypeDict
);
71 pickle_
.Reserve(capacity
);
74 TracedValue::~TracedValue() {
75 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict
);
76 DEBUG_POP_CONTAINER();
77 DCHECK_CONTAINER_STACK_DEPTH_EQ(0u);
80 void TracedValue::SetInteger(const char* name
, int value
) {
81 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict
);
82 pickle_
.WriteBytes(&kTypeInt
, 1);
83 pickle_
.WriteInt(value
);
84 WriteKeyNameAsRawPtr(pickle_
, name
);
87 void TracedValue::SetIntegerWithCopiedName(const std::string
& name
, int value
) {
88 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict
);
89 pickle_
.WriteBytes(&kTypeInt
, 1);
90 pickle_
.WriteInt(value
);
91 WriteKeyNameAsStdString(pickle_
, name
);
94 void TracedValue::SetDouble(const char* name
, double value
) {
95 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict
);
96 pickle_
.WriteBytes(&kTypeDouble
, 1);
97 pickle_
.WriteDouble(value
);
98 WriteKeyNameAsRawPtr(pickle_
, name
);
101 void TracedValue::SetDoubleWithCopiedName(const std::string
& name
,
103 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict
);
104 pickle_
.WriteBytes(&kTypeDouble
, 1);
105 pickle_
.WriteDouble(value
);
106 WriteKeyNameAsStdString(pickle_
, name
);
109 void TracedValue::SetBoolean(const char* name
, bool value
) {
110 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict
);
111 pickle_
.WriteBytes(&kTypeBool
, 1);
112 pickle_
.WriteBool(value
);
113 WriteKeyNameAsRawPtr(pickle_
, name
);
116 void TracedValue::SetBooleanWithCopiedName(const std::string
& name
,
118 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict
);
119 pickle_
.WriteBytes(&kTypeBool
, 1);
120 pickle_
.WriteBool(value
);
121 WriteKeyNameAsStdString(pickle_
, name
);
124 void TracedValue::SetString(const char* name
, const std::string
& value
) {
125 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict
);
126 pickle_
.WriteBytes(&kTypeString
, 1);
127 pickle_
.WriteString(value
);
128 WriteKeyNameAsRawPtr(pickle_
, name
);
131 void TracedValue::SetStringWithCopiedName(const std::string
& name
,
132 const std::string
& value
) {
133 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict
);
134 pickle_
.WriteBytes(&kTypeString
, 1);
135 pickle_
.WriteString(value
);
136 WriteKeyNameAsStdString(pickle_
, name
);
139 void TracedValue::SetValue(const char* name
, const TracedValue
& value
) {
140 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict
);
141 BeginDictionary(name
);
142 pickle_
.WriteBytes(value
.pickle_
.payload(),
143 static_cast<int>(value
.pickle_
.payload_size()));
147 void TracedValue::SetValueWithCopiedName(const std::string
& name
,
148 const TracedValue
& value
) {
149 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict
);
150 BeginDictionaryWithCopiedName(name
);
151 pickle_
.WriteBytes(value
.pickle_
.payload(),
152 static_cast<int>(value
.pickle_
.payload_size()));
156 void TracedValue::BeginDictionary(const char* name
) {
157 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict
);
158 DEBUG_PUSH_CONTAINER(kStackTypeDict
);
159 pickle_
.WriteBytes(&kTypeStartDict
, 1);
160 WriteKeyNameAsRawPtr(pickle_
, name
);
163 void TracedValue::BeginDictionaryWithCopiedName(const std::string
& name
) {
164 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict
);
165 DEBUG_PUSH_CONTAINER(kStackTypeDict
);
166 pickle_
.WriteBytes(&kTypeStartDict
, 1);
167 WriteKeyNameAsStdString(pickle_
, name
);
170 void TracedValue::BeginArray(const char* name
) {
171 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict
);
172 DEBUG_PUSH_CONTAINER(kStackTypeArray
);
173 pickle_
.WriteBytes(&kTypeStartArray
, 1);
174 WriteKeyNameAsRawPtr(pickle_
, name
);
177 void TracedValue::BeginArrayWithCopiedName(const std::string
& name
) {
178 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict
);
179 DEBUG_PUSH_CONTAINER(kStackTypeArray
);
180 pickle_
.WriteBytes(&kTypeStartArray
, 1);
181 WriteKeyNameAsStdString(pickle_
, name
);
184 void TracedValue::EndDictionary() {
185 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict
);
186 DEBUG_POP_CONTAINER();
187 pickle_
.WriteBytes(&kTypeEndDict
, 1);
190 void TracedValue::AppendInteger(int value
) {
191 DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray
);
192 pickle_
.WriteBytes(&kTypeInt
, 1);
193 pickle_
.WriteInt(value
);
196 void TracedValue::AppendDouble(double value
) {
197 DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray
);
198 pickle_
.WriteBytes(&kTypeDouble
, 1);
199 pickle_
.WriteDouble(value
);
202 void TracedValue::AppendBoolean(bool value
) {
203 DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray
);
204 pickle_
.WriteBytes(&kTypeBool
, 1);
205 pickle_
.WriteBool(value
);
208 void TracedValue::AppendString(const std::string
& value
) {
209 DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray
);
210 pickle_
.WriteBytes(&kTypeString
, 1);
211 pickle_
.WriteString(value
);
214 void TracedValue::BeginArray() {
215 DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray
);
216 DEBUG_PUSH_CONTAINER(kStackTypeArray
);
217 pickle_
.WriteBytes(&kTypeStartArray
, 1);
220 void TracedValue::BeginDictionary() {
221 DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray
);
222 DEBUG_PUSH_CONTAINER(kStackTypeDict
);
223 pickle_
.WriteBytes(&kTypeStartDict
, 1);
226 void TracedValue::EndArray() {
227 DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray
);
228 DEBUG_POP_CONTAINER();
229 pickle_
.WriteBytes(&kTypeEndArray
, 1);
232 void TracedValue::SetValue(const char* name
, scoped_ptr
<base::Value
> value
) {
233 SetBaseValueWithCopiedName(name
, *value
);
236 void TracedValue::SetBaseValueWithCopiedName(const std::string
& name
,
237 const base::Value
& value
) {
238 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict
);
239 switch (value
.GetType()) {
240 case base::Value::TYPE_NULL
:
241 case base::Value::TYPE_BINARY
:
245 case base::Value::TYPE_BOOLEAN
: {
247 value
.GetAsBoolean(&bool_value
);
248 SetBooleanWithCopiedName(name
, bool_value
);
251 case base::Value::TYPE_INTEGER
: {
253 value
.GetAsInteger(&int_value
);
254 SetIntegerWithCopiedName(name
, int_value
);
257 case base::Value::TYPE_DOUBLE
: {
259 value
.GetAsDouble(&double_value
);
260 SetDoubleWithCopiedName(name
, double_value
);
263 case base::Value::TYPE_STRING
: {
264 const StringValue
* string_value
;
265 value
.GetAsString(&string_value
);
266 SetStringWithCopiedName(name
, string_value
->GetString());
269 case base::Value::TYPE_DICTIONARY
: {
270 const DictionaryValue
* dict_value
;
271 value
.GetAsDictionary(&dict_value
);
272 BeginDictionaryWithCopiedName(name
);
273 for (DictionaryValue::Iterator
it(*dict_value
); !it
.IsAtEnd();
275 SetBaseValueWithCopiedName(it
.key(), it
.value());
280 case base::Value::TYPE_LIST
: {
281 const ListValue
* list_value
;
282 value
.GetAsList(&list_value
);
283 BeginArrayWithCopiedName(name
);
284 for (base::Value
* base_value
: *list_value
)
285 AppendBaseValue(*base_value
);
291 void TracedValue::AppendBaseValue(const base::Value
& value
) {
292 DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray
);
293 switch (value
.GetType()) {
294 case base::Value::TYPE_NULL
:
295 case base::Value::TYPE_BINARY
:
299 case base::Value::TYPE_BOOLEAN
: {
301 value
.GetAsBoolean(&bool_value
);
302 AppendBoolean(bool_value
);
305 case base::Value::TYPE_INTEGER
: {
307 value
.GetAsInteger(&int_value
);
308 AppendInteger(int_value
);
311 case base::Value::TYPE_DOUBLE
: {
313 value
.GetAsDouble(&double_value
);
314 AppendDouble(double_value
);
317 case base::Value::TYPE_STRING
: {
318 const StringValue
* string_value
;
319 value
.GetAsString(&string_value
);
320 AppendString(string_value
->GetString());
323 case base::Value::TYPE_DICTIONARY
: {
324 const DictionaryValue
* dict_value
;
325 value
.GetAsDictionary(&dict_value
);
327 for (DictionaryValue::Iterator
it(*dict_value
); !it
.IsAtEnd();
329 SetBaseValueWithCopiedName(it
.key(), it
.value());
334 case base::Value::TYPE_LIST
: {
335 const ListValue
* list_value
;
336 value
.GetAsList(&list_value
);
338 for (base::Value
* base_value
: *list_value
)
339 AppendBaseValue(*base_value
);
345 scoped_ptr
<base::Value
> TracedValue::ToBaseValue() const {
346 scoped_ptr
<DictionaryValue
> root(new DictionaryValue
);
347 DictionaryValue
* cur_dict
= root
.get();
348 ListValue
* cur_list
= nullptr;
349 std::vector
<Value
*> stack
;
350 PickleIterator
it(pickle_
);
353 while (it
.ReadBytes(&type
, 1)) {
354 DCHECK((cur_dict
&& !cur_list
) || (cur_list
&& !cur_dict
));
356 case kTypeStartDict
: {
357 auto new_dict
= new DictionaryValue();
359 cur_dict
->Set(ReadKeyName(it
), make_scoped_ptr(new_dict
));
360 stack
.push_back(cur_dict
);
363 cur_list
->Append(make_scoped_ptr(new_dict
));
364 stack
.push_back(cur_list
);
372 if (stack
.back()->GetAsDictionary(&cur_dict
)) {
374 } else if (stack
.back()->GetAsList(&cur_list
)) {
380 case kTypeStartArray
: {
381 auto new_list
= new ListValue();
383 cur_dict
->Set(ReadKeyName(it
), make_scoped_ptr(new_list
));
384 stack
.push_back(cur_dict
);
388 cur_list
->Append(make_scoped_ptr(new_list
));
389 stack
.push_back(cur_list
);
396 CHECK(it
.ReadBool(&value
));
398 cur_dict
->SetBoolean(ReadKeyName(it
), value
);
400 cur_list
->AppendBoolean(value
);
406 CHECK(it
.ReadInt(&value
));
408 cur_dict
->SetInteger(ReadKeyName(it
), value
);
410 cur_list
->AppendInteger(value
);
416 CHECK(it
.ReadDouble(&value
));
418 cur_dict
->SetDouble(ReadKeyName(it
), value
);
420 cur_list
->AppendDouble(value
);
426 CHECK(it
.ReadString(&value
));
428 cur_dict
->SetString(ReadKeyName(it
), value
);
430 cur_list
->AppendString(value
);
438 DCHECK(stack
.empty());
442 void TracedValue::AppendAsTraceFormat(std::string
* out
) const {
443 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict
);
444 DCHECK_CONTAINER_STACK_DEPTH_EQ(1u);
446 // TODO(primiano): this could be smarter, skip the ToBaseValue encoding and
447 // produce the JSON on its own. This will require refactoring JSONWriter
448 // to decouple the base::Value traversal from the JSON writing bits
450 JSONWriter::Write(*ToBaseValue(), &tmp
);
454 void TracedValue::EstimateTraceMemoryOverhead(
455 TraceEventMemoryOverhead
* overhead
) {
456 overhead
->Add("TracedValue", pickle_
.size());
459 } // namespace trace_event