1 // Copyright 2016 the V8 project 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.
4
5 #include "src/tracing/traced-value.h"
6
7 #include "src/base/platform/platform.h"
8 #include "src/conversions.h"
9
10 namespace v8 {
11 namespace tracing {
12
13 namespace {
14
15 #define DCHECK_CURRENT_CONTAINER_IS(x) DCHECK_EQ(x, nesting_stack_.back())
16 #define DCHECK_CONTAINER_STACK_DEPTH_EQ(x) DCHECK_EQ(x, nesting_stack_.size())
17 #ifdef DEBUG
18 const bool kStackTypeDict = false;
19 const bool kStackTypeArray = true;
20 #define DEBUG_PUSH_CONTAINER(x) nesting_stack_.push_back(x)
21 #define DEBUG_POP_CONTAINER() nesting_stack_.pop_back()
22 #else
23 #define DEBUG_PUSH_CONTAINER(x) ((void)0)
24 #define DEBUG_POP_CONTAINER() ((void)0)
25 #endif
26
EscapeAndAppendString(const char * value,std::string * result)27 void EscapeAndAppendString(const char* value, std::string* result) {
28 *result += '"';
29 char number_buffer[10];
30 while (*value) {
31 char c = *value++;
32 switch (c) {
33 case '\t':
34 *result += "\\t";
35 break;
36 case '\n':
37 *result += "\\n";
38 break;
39 case '\"':
40 *result += "\\\"";
41 break;
42 case '\\':
43 *result += "\\\\";
44 break;
45 default:
46 if (c < '\x20') {
47 base::OS::SNPrintF(
48 number_buffer, arraysize(number_buffer), "\\u%04X",
49 static_cast<unsigned>(static_cast<unsigned char>(c)));
50 *result += number_buffer;
51 } else {
52 *result += c;
53 }
54 }
55 }
56 *result += '"';
57 }
58
59 } // namespace
60
Create()61 std::unique_ptr<TracedValue> TracedValue::Create() {
62 return std::unique_ptr<TracedValue>(new TracedValue());
63 }
64
TracedValue()65 TracedValue::TracedValue() : first_item_(true) {
66 DEBUG_PUSH_CONTAINER(kStackTypeDict);
67 }
68
~TracedValue()69 TracedValue::~TracedValue() {
70 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
71 DEBUG_POP_CONTAINER();
72 DCHECK_CONTAINER_STACK_DEPTH_EQ(0u);
73 }
74
SetInteger(const char * name,int value)75 void TracedValue::SetInteger(const char* name, int value) {
76 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
77 WriteName(name);
78 data_ += std::to_string(value);
79 }
80
SetDouble(const char * name,double value)81 void TracedValue::SetDouble(const char* name, double value) {
82 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
83 WriteName(name);
84 i::EmbeddedVector<char, 100> buffer;
85 data_ += DoubleToCString(value, buffer);
86 }
87
SetBoolean(const char * name,bool value)88 void TracedValue::SetBoolean(const char* name, bool value) {
89 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
90 WriteName(name);
91 data_ += value ? "true" : "false";
92 }
93
SetString(const char * name,const char * value)94 void TracedValue::SetString(const char* name, const char* value) {
95 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
96 WriteName(name);
97 EscapeAndAppendString(value, &data_);
98 }
99
BeginDictionary(const char * name)100 void TracedValue::BeginDictionary(const char* name) {
101 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
102 DEBUG_PUSH_CONTAINER(kStackTypeDict);
103 WriteName(name);
104 data_ += '{';
105 first_item_ = true;
106 }
107
BeginArray(const char * name)108 void TracedValue::BeginArray(const char* name) {
109 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
110 DEBUG_PUSH_CONTAINER(kStackTypeArray);
111 WriteName(name);
112 data_ += '[';
113 first_item_ = true;
114 }
115
AppendInteger(int value)116 void TracedValue::AppendInteger(int value) {
117 DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
118 WriteComma();
119 data_ += std::to_string(value);
120 }
121
AppendDouble(double value)122 void TracedValue::AppendDouble(double value) {
123 DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
124 WriteComma();
125 i::EmbeddedVector<char, 100> buffer;
126 data_ += DoubleToCString(value, buffer);
127 }
128
AppendBoolean(bool value)129 void TracedValue::AppendBoolean(bool value) {
130 DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
131 WriteComma();
132 data_ += value ? "true" : "false";
133 }
134
AppendString(const char * value)135 void TracedValue::AppendString(const char* value) {
136 DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
137 WriteComma();
138 EscapeAndAppendString(value, &data_);
139 }
140
BeginDictionary()141 void TracedValue::BeginDictionary() {
142 DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
143 DEBUG_PUSH_CONTAINER(kStackTypeDict);
144 WriteComma();
145 data_ += '{';
146 first_item_ = true;
147 }
148
BeginArray()149 void TracedValue::BeginArray() {
150 DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
151 DEBUG_PUSH_CONTAINER(kStackTypeArray);
152 WriteComma();
153 data_ += '[';
154 first_item_ = true;
155 }
156
EndDictionary()157 void TracedValue::EndDictionary() {
158 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
159 DEBUG_POP_CONTAINER();
160 data_ += '}';
161 first_item_ = false;
162 }
163
EndArray()164 void TracedValue::EndArray() {
165 DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
166 DEBUG_POP_CONTAINER();
167 data_ += ']';
168 first_item_ = false;
169 }
170
WriteComma()171 void TracedValue::WriteComma() {
172 if (first_item_) {
173 first_item_ = false;
174 } else {
175 data_ += ',';
176 }
177 }
178
WriteName(const char * name)179 void TracedValue::WriteName(const char* name) {
180 WriteComma();
181 data_ += '"';
182 data_ += name;
183 data_ += "\":";
184 }
185
AppendAsTraceFormat(std::string * out) const186 void TracedValue::AppendAsTraceFormat(std::string* out) const {
187 *out += '{';
188 *out += data_;
189 *out += '}';
190 }
191
192 } // namespace tracing
193 } // namespace v8
194