Commit 3990953b authored by alph's avatar alph Committed by Commit bot

[tracing] Add support for TracedValue JSON serializer.

BUG=chromium:406277

Review-Url: https://codereview.chromium.org/2399463004
Cr-Commit-Position: refs/heads/master@{#40049}
parent fc840361
......@@ -1642,6 +1642,8 @@ v8_source_set("v8_base") {
"src/strtod.h",
"src/tracing/trace-event.cc",
"src/tracing/trace-event.h",
"src/tracing/traced-value.cc",
"src/tracing/traced-value.h",
"src/transitions-inl.h",
"src/transitions.cc",
"src/transitions.h",
......
// 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"
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
std::string EscapeString(const std::string& value) {
std::string result;
result.reserve(value.length() + 2);
result += '"';
size_t length = value.length();
char number_buffer[10];
for (size_t src = 0; src < length; ++src) {
char c = value[src];
switch (c) {
case '\t':
result += "\\t";
break;
case '\n':
result += "\\n";
break;
case '\"':
result += "\\\"";
break;
case '\\':
result += "\\\\";
break;
default:
if (c < '\040') {
base::OS::SNPrintF(
number_buffer, arraysize(number_buffer), "\\u%04X",
static_cast<unsigned>(static_cast<unsigned char>(c)));
result += number_buffer;
} else {
result += c;
}
}
}
result += '"';
return result;
}
} // namespace
std::unique_ptr<TracedValue> TracedValue::Create() {
return std::unique_ptr<TracedValue>(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);
data_ += std::to_string(value);
}
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 std::string& value) {
DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
WriteName(name);
data_ += EscapeString(value);
}
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();
data_ += std::to_string(value);
}
void TracedValue::AppendBoolean(bool value) {
DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
WriteComma();
data_ += value ? "true" : "false";
}
void TracedValue::AppendString(const std::string& value) {
DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
WriteComma();
data_ += EscapeString(value);
}
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
// 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.
#ifndef V8_TRACING_TRACED_VALUE_H_
#define V8_TRACING_TRACED_VALUE_H_
#include <stddef.h>
#include <memory>
#include <string>
#include <vector>
#include "include/v8-platform.h"
#include "src/base/macros.h"
namespace v8 {
namespace tracing {
class TracedValue : public ConvertableToTraceFormat {
public:
~TracedValue() override;
static std::unique_ptr<TracedValue> Create();
void EndDictionary();
void EndArray();
// These methods assume that |name| is a long lived "quoted" string.
void SetInteger(const char* name, int value);
void SetDouble(const char* name, double value);
void SetBoolean(const char* name, bool value);
void SetString(const char* name, const std::string& value);
void BeginDictionary(const char* name);
void BeginArray(const char* name);
void AppendInteger(int);
void AppendDouble(double);
void AppendBoolean(bool);
void AppendString(const std::string&);
void BeginArray();
void BeginDictionary();
// ConvertableToTraceFormat implementation.
void AppendAsTraceFormat(std::string* out) const override;
private:
TracedValue();
void WriteComma();
void WriteName(const char* name);
#ifdef DEBUG
// In debug builds checks the pairings of {Begin,End}{Dictionary,Array}
std::vector<bool> nesting_stack_;
#endif
std::string data_;
bool first_item_;
DISALLOW_COPY_AND_ASSIGN(TracedValue);
};
} // namespace tracing
} // namespace v8
#endif // V8_TRACING_TRACED_VALUE_H_
......@@ -1212,6 +1212,8 @@
'ic/stub-cache.h',
'tracing/trace-event.cc',
'tracing/trace-event.h',
'tracing/traced-value.cc',
'tracing/traced-value.h',
'transitions-inl.h',
'transitions.cc',
'transitions.h',
......
......@@ -166,6 +166,7 @@ v8_executable("cctest") {
"test-thread-termination.cc",
"test-threads.cc",
"test-trace-event.cc",
"test-traced-value.cc",
"test-transitions.cc",
"test-typedarrays.cc",
"test-types.cc",
......
......@@ -186,6 +186,7 @@
'test-thread-termination.cc',
'test-threads.cc',
'test-trace-event.cc',
'test-traced-value.cc',
'test-transitions.cc',
'test-typedarrays.cc',
'test-ast-types.cc',
......
// 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 "test/cctest/cctest.h"
using v8::tracing::TracedValue;
TEST(FlatDictionary) {
auto value = TracedValue::Create();
value->SetInteger("int", 2014);
value->SetDouble("double", 0.0);
value->SetBoolean("bool", true);
value->SetString("string", "string");
std::string json = "PREFIX";
value->AppendAsTraceFormat(&json);
CHECK_EQ(
"PREFIX{\"int\":2014,\"double\":0.000000,\"bool\":true,\"string\":"
"\"string\"}",
json);
}
TEST(NoDotPathExpansion) {
auto value = TracedValue::Create();
value->SetInteger("in.t", 2014);
value->SetDouble("doub.le", 0.0);
value->SetBoolean("bo.ol", true);
value->SetString("str.ing", "str.ing");
std::string json;
value->AppendAsTraceFormat(&json);
CHECK_EQ(
"{\"in.t\":2014,\"doub.le\":0.000000,\"bo.ol\":true,\"str.ing\":\"str."
"ing\"}",
json);
}
TEST(Hierarchy) {
auto value = TracedValue::Create();
value->SetInteger("i0", 2014);
value->BeginDictionary("dict1");
value->SetInteger("i1", 2014);
value->BeginDictionary("dict2");
value->SetBoolean("b2", false);
value->EndDictionary();
value->SetString("s1", "foo");
value->EndDictionary();
value->SetDouble("d0", 0.0);
value->SetBoolean("b0", true);
value->BeginArray("a1");
value->AppendInteger(1);
value->AppendBoolean(true);
value->BeginDictionary();
value->SetInteger("i2", 3);
value->EndDictionary();
value->EndArray();
value->SetString("s0", "foo");
value->BeginArray("arr1");
value->BeginDictionary();
value->EndDictionary();
value->BeginArray();
value->EndArray();
value->BeginDictionary();
value->EndDictionary();
value->EndArray();
std::string json;
value->AppendAsTraceFormat(&json);
CHECK_EQ(
"{\"i0\":2014,\"dict1\":{\"i1\":2014,\"dict2\":{\"b2\":false},"
"\"s1\":\"foo\"},\"d0\":0.000000,\"b0\":true,\"a1\":[1,true,{\"i2\":3}],"
"\"s0\":\"foo\",\"arr1\":[{},[],{}]}",
json);
}
TEST(LongStrings) {
std::string long_string = "supercalifragilisticexpialidocious";
std::string long_string2 = "0123456789012345678901234567890123456789";
char long_string3[4096];
for (size_t i = 0; i < sizeof(long_string3); ++i)
long_string3[i] = static_cast<char>('a' + (i % 26));
long_string3[sizeof(long_string3) - 1] = '\0';
auto value = TracedValue::Create();
value->SetString("a", "short");
value->SetString("b", long_string);
value->BeginArray("c");
value->AppendString(long_string2);
value->AppendString("");
value->BeginDictionary();
value->SetString("a", long_string3);
value->EndDictionary();
value->EndArray();
std::string json;
value->AppendAsTraceFormat(&json);
CHECK_EQ("{\"a\":\"short\",\"b\":\"" + long_string + "\",\"c\":[\"" +
long_string2 + "\",\"\",{\"a\":\"" + long_string3 + "\"}]}",
json);
}
TEST(Escaping) {
const char* string1 = "abc\"\'\\\\x\"y\'z\n\x09\x17";
std::string chars127;
for (int i = 1; i <= 127; ++i) {
chars127 += static_cast<char>(i);
}
auto value = TracedValue::Create();
value->SetString("a", string1);
value->SetString("b", chars127);
std::string json;
value->AppendAsTraceFormat(&json);
// Cannot use the expected value literal directly in CHECK_EQ
// as it fails to process # character on Windows.
const char* expected =
"{\"a\":\"abc\\\"\'\\\\\\\\x\\\"y\'z\\n\\t\\u0017\",\"b\":"
"\"\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\u0008\\t\\n\\u000B"
"\\u000C\\u000D\\u000E\\u000F\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\"
"u0016\\u0017\\u0018\\u0019\\u001A\\u001B\\u001C\\u001D\\u001E\\u001F "
"!\\\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`"
"abcdefghijklmnopqrstuvwxyz{|}~\177\"}";
CHECK_EQ(expected, json);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment