// Copyright 2016 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "src/tracing/traced-value.h" #include "src/base/platform/platform.h" #include "src/numbers/conversions.h" #include "src/utils/vector.h" namespace v8 { namespace tracing { namespace { #define DCHECK_CURRENT_CONTAINER_IS(x) DCHECK_EQ(x, nesting_stack_.back()) #define DCHECK_CONTAINER_STACK_DEPTH_EQ(x) DCHECK_EQ(x, nesting_stack_.size()) #ifdef DEBUG const bool kStackTypeDict = false; const bool kStackTypeArray = true; #define DEBUG_PUSH_CONTAINER(x) nesting_stack_.push_back(x) #define DEBUG_POP_CONTAINER() nesting_stack_.pop_back() #else #define DEBUG_PUSH_CONTAINER(x) ((void)0) #define DEBUG_POP_CONTAINER() ((void)0) #endif void EscapeAndAppendString(const char* value, std::string* result) { *result += '"'; while (*value) { unsigned char c = *value++; switch (c) { case '\b': *result += "\\b"; break; case '\f': *result += "\\f"; break; case '\n': *result += "\\n"; break; case '\r': *result += "\\r"; break; case '\t': *result += "\\t"; break; case '\"': *result += "\\\""; break; case '\\': *result += "\\\\"; break; default: if (c < '\x20' || c == '\x7F') { char number_buffer[8]; base::OS::SNPrintF(number_buffer, arraysize(number_buffer), "\\u%04X", static_cast(c)); *result += number_buffer; } else { *result += c; } } } *result += '"'; } } // namespace // static std::unique_ptr TracedValue::Create() { return std::unique_ptr(new TracedValue()); } TracedValue::TracedValue() : first_item_(true) { DEBUG_PUSH_CONTAINER(kStackTypeDict); } TracedValue::~TracedValue() { DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict); DEBUG_POP_CONTAINER(); DCHECK_CONTAINER_STACK_DEPTH_EQ(0u); } void TracedValue::SetInteger(const char* name, int value) { DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict); WriteName(name); data_ += std::to_string(value); } void TracedValue::SetDouble(const char* name, double value) { DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict); WriteName(name); i::EmbeddedVector buffer; data_ += DoubleToCString(value, buffer); } void TracedValue::SetBoolean(const char* name, bool value) { DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict); WriteName(name); data_ += value ? "true" : "false"; } void TracedValue::SetString(const char* name, const char* value) { DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict); WriteName(name); EscapeAndAppendString(value, &data_); } void TracedValue::SetValue(const char* name, TracedValue* value) { DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict); WriteName(name); std::string tmp; value->AppendAsTraceFormat(&tmp); data_ += tmp; } void TracedValue::BeginDictionary(const char* name) { DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict); DEBUG_PUSH_CONTAINER(kStackTypeDict); WriteName(name); data_ += '{'; first_item_ = true; } void TracedValue::BeginArray(const char* name) { DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict); DEBUG_PUSH_CONTAINER(kStackTypeArray); WriteName(name); data_ += '['; first_item_ = true; } void TracedValue::AppendInteger(int value) { DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray); WriteComma(); data_ += std::to_string(value); } void TracedValue::AppendDouble(double value) { DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray); WriteComma(); i::EmbeddedVector buffer; data_ += DoubleToCString(value, buffer); } void TracedValue::AppendBoolean(bool value) { DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray); WriteComma(); data_ += value ? "true" : "false"; } void TracedValue::AppendString(const char* value) { DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray); WriteComma(); EscapeAndAppendString(value, &data_); } void TracedValue::BeginDictionary() { DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray); DEBUG_PUSH_CONTAINER(kStackTypeDict); WriteComma(); data_ += '{'; first_item_ = true; } void TracedValue::BeginArray() { DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray); DEBUG_PUSH_CONTAINER(kStackTypeArray); WriteComma(); data_ += '['; first_item_ = true; } void TracedValue::EndDictionary() { DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict); DEBUG_POP_CONTAINER(); data_ += '}'; first_item_ = false; } void TracedValue::EndArray() { DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray); DEBUG_POP_CONTAINER(); data_ += ']'; first_item_ = false; } void TracedValue::WriteComma() { if (first_item_) { first_item_ = false; } else { data_ += ','; } } void TracedValue::WriteName(const char* name) { WriteComma(); data_ += '"'; data_ += name; data_ += "\":"; } void TracedValue::AppendAsTraceFormat(std::string* out) const { *out += '{'; *out += data_; *out += '}'; } } // namespace tracing } // namespace v8