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 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 < '\040') { 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 61 std::unique_ptr<TracedValue> TracedValue::Create() { 62 return std::unique_ptr<TracedValue>(new TracedValue()); 63 } 64 65 TracedValue::TracedValue() : first_item_(true) { 66 DEBUG_PUSH_CONTAINER(kStackTypeDict); 67 } 68 69 TracedValue::~TracedValue() { 70 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict); 71 DEBUG_POP_CONTAINER(); 72 DCHECK_CONTAINER_STACK_DEPTH_EQ(0u); 73 } 74 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 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 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 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 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 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 116 void TracedValue::AppendInteger(int value) { 117 DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray); 118 WriteComma(); 119 data_ += std::to_string(value); 120 } 121 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 129 void TracedValue::AppendBoolean(bool value) { 130 DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray); 131 WriteComma(); 132 data_ += value ? "true" : "false"; 133 } 134 135 void TracedValue::AppendString(const char* value) { 136 DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray); 137 WriteComma(); 138 EscapeAndAppendString(value, &data_); 139 } 140 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 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 157 void TracedValue::EndDictionary() { 158 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict); 159 DEBUG_POP_CONTAINER(); 160 data_ += '}'; 161 first_item_ = false; 162 } 163 164 void TracedValue::EndArray() { 165 DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray); 166 DEBUG_POP_CONTAINER(); 167 data_ += ']'; 168 first_item_ = false; 169 } 170 171 void TracedValue::WriteComma() { 172 if (first_item_) { 173 first_item_ = false; 174 } else { 175 data_ += ','; 176 } 177 } 178 179 void TracedValue::WriteName(const char* name) { 180 WriteComma(); 181 data_ += '"'; 182 data_ += name; 183 data_ += "\":"; 184 } 185 186 void TracedValue::AppendAsTraceFormat(std::string* out) const { 187 *out += '{'; 188 *out += data_; 189 *out += '}'; 190 } 191 192 } // namespace tracing 193 } // namespace v8 194