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