mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 14:32:24 +00:00
80c79a3d84
Using the preprocessor string literal operator # on __VA_ARGS__ in a variadic macro does not separately stringize each argument, but instead creates a single string of the expanded arguments. Thus, rename DECLARE_ATTRIBUTES to DECLARE_ATTRIBUTE and have it take a single expression. For multiple attributes, DECLARE_ATTRIBUTES_NAMED must be used instead. Also, use a comma fold expression in AttributesSerializer::WriteTuple to separately call WriteAttribute with each element of the tuple in turn, instead of calling WriteAttribute once with all the tuple contents as arguments. Move the demangling of attribute names that are directly stringized from expressions from the JSON consumer to the JSON producer. To illustrate how to add multiple attributes to an instruction, this CL adds two attributes to the StoreField instruction: slot and is_initialization. When printing an instruction in the IL matcher, if the instruction has any boolean attributes, don't print the attribute if the value is false and only print the name if the attribute is true to reduce clutter. TEST=ci Change-Id: Ie541364374171c3dcbee4b609942d415a1c464e8 Cq-Include-Trybots: luci.dart.try:vm-aot-linux-debug-x64-try,vm-aot-linux-release-x64-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/327864 Reviewed-by: Alexander Markov <alexmarkov@google.com> Commit-Queue: Tess Strickland <sstrickl@google.com>
397 lines
10 KiB
C++
397 lines
10 KiB
C++
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
#include "platform/assert.h"
|
|
|
|
#include "platform/unicode.h"
|
|
#include "vm/double_conversion.h"
|
|
#include "vm/json_writer.h"
|
|
#include "vm/object.h"
|
|
|
|
namespace dart {
|
|
|
|
class MaybeOnStackBuffer {
|
|
public:
|
|
explicit MaybeOnStackBuffer(intptr_t size) {
|
|
if (size > kOnStackBufferCapacity) {
|
|
p_ = reinterpret_cast<char*>(malloc(size));
|
|
} else {
|
|
p_ = &buffer_[0];
|
|
}
|
|
}
|
|
~MaybeOnStackBuffer() {
|
|
if (p_ != &buffer_[0]) free(p_);
|
|
}
|
|
|
|
char* p() { return p_; }
|
|
|
|
private:
|
|
static constexpr intptr_t kOnStackBufferCapacity = 4096;
|
|
char* p_;
|
|
char buffer_[kOnStackBufferCapacity];
|
|
};
|
|
|
|
JSONWriter::JSONWriter(intptr_t buf_size)
|
|
: open_objects_(0), buffer_(buf_size) {}
|
|
|
|
void JSONWriter::AppendBytes(const uint8_t* buffer, intptr_t buffer_length) {
|
|
buffer_.AddRaw(buffer, buffer_length);
|
|
}
|
|
|
|
static const char base64_digits[65] =
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
static const char base64_pad = '=';
|
|
|
|
void JSONWriter::AppendBytesInBase64(const uint8_t* bytes, intptr_t length) {
|
|
ASSERT(bytes != nullptr);
|
|
intptr_t odd_bits = length % 3;
|
|
intptr_t even_bits = length - odd_bits;
|
|
for (intptr_t i = 0; i < even_bits; i += 3) {
|
|
intptr_t triplet = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2];
|
|
buffer_.AddChar(base64_digits[triplet >> 18]);
|
|
buffer_.AddChar(base64_digits[(triplet >> 12) & 63]);
|
|
buffer_.AddChar(base64_digits[(triplet >> 6) & 63]);
|
|
buffer_.AddChar(base64_digits[triplet & 63]);
|
|
}
|
|
if (odd_bits == 1) {
|
|
intptr_t triplet = bytes[even_bits] << 16;
|
|
buffer_.AddChar(base64_digits[triplet >> 18]);
|
|
buffer_.AddChar(base64_digits[(triplet >> 12) & 63]);
|
|
buffer_.AddChar(base64_pad);
|
|
buffer_.AddChar(base64_pad);
|
|
} else if (odd_bits == 2) {
|
|
intptr_t triplet = (bytes[even_bits] << 16) | (bytes[even_bits + 1] << 8);
|
|
buffer_.AddChar(base64_digits[triplet >> 18]);
|
|
buffer_.AddChar(base64_digits[(triplet >> 12) & 63]);
|
|
buffer_.AddChar(base64_digits[(triplet >> 6) & 63]);
|
|
buffer_.AddChar(base64_pad);
|
|
}
|
|
}
|
|
|
|
void JSONWriter::AppendSerializedObject(const char* serialized_object) {
|
|
PrintCommaIfNeeded();
|
|
buffer_.AddString(serialized_object);
|
|
}
|
|
|
|
void JSONWriter::AppendSerializedObject(const char* property_name,
|
|
const char* serialized_object) {
|
|
PrintCommaIfNeeded();
|
|
PrintPropertyName(property_name);
|
|
buffer_.AddString(serialized_object);
|
|
}
|
|
|
|
void JSONWriter::Clear() {
|
|
buffer_.Clear();
|
|
open_objects_ = 0;
|
|
}
|
|
|
|
void JSONWriter::OpenObject(const char* property_name) {
|
|
PrintCommaIfNeeded();
|
|
open_objects_++;
|
|
if (property_name != nullptr) {
|
|
PrintPropertyName(property_name);
|
|
}
|
|
buffer_.AddChar('{');
|
|
}
|
|
|
|
void JSONWriter::UncloseObject() {
|
|
intptr_t len = buffer_.length();
|
|
ASSERT(len > 0);
|
|
ASSERT(buffer_.buffer()[len - 1] == '}');
|
|
open_objects_++;
|
|
buffer_.set_length(len - 1);
|
|
}
|
|
|
|
void JSONWriter::CloseObject() {
|
|
ASSERT(open_objects_ > 0);
|
|
open_objects_--;
|
|
buffer_.AddChar('}');
|
|
}
|
|
|
|
void JSONWriter::OpenArray(const char* property_name) {
|
|
PrintCommaIfNeeded();
|
|
if (property_name != nullptr) {
|
|
PrintPropertyName(property_name);
|
|
}
|
|
open_objects_++;
|
|
buffer_.AddChar('[');
|
|
}
|
|
|
|
void JSONWriter::CloseArray() {
|
|
ASSERT(open_objects_ > 0);
|
|
open_objects_--;
|
|
buffer_.AddChar(']');
|
|
}
|
|
|
|
void JSONWriter::PrintValueNull() {
|
|
PrintCommaIfNeeded();
|
|
buffer_.Printf("null");
|
|
}
|
|
|
|
void JSONWriter::PrintValueBool(bool b) {
|
|
PrintCommaIfNeeded();
|
|
buffer_.Printf("%s", b ? "true" : "false");
|
|
}
|
|
|
|
void JSONWriter::PrintValue(intptr_t i) {
|
|
EnsureIntegerIsRepresentableInJavaScript(static_cast<int64_t>(i));
|
|
PrintCommaIfNeeded();
|
|
buffer_.Printf("%" Pd "", i);
|
|
}
|
|
|
|
void JSONWriter::PrintValue64(int64_t i) {
|
|
EnsureIntegerIsRepresentableInJavaScript(i);
|
|
PrintCommaIfNeeded();
|
|
buffer_.Printf("%" Pd64 "", i);
|
|
}
|
|
|
|
void JSONWriter::PrintValue(double d) {
|
|
// Max length of a double in characters (including \0).
|
|
// See double_conversion.cc.
|
|
const size_t kBufferLen = 25;
|
|
char buffer[kBufferLen];
|
|
DoubleToCString(d, buffer, kBufferLen);
|
|
PrintCommaIfNeeded();
|
|
buffer_.Printf("%s", buffer);
|
|
}
|
|
|
|
void JSONWriter::PrintValueBase64(const uint8_t* bytes, intptr_t length) {
|
|
PrintCommaIfNeeded();
|
|
buffer_.AddChar('"');
|
|
AppendBytesInBase64(bytes, length);
|
|
buffer_.AddChar('"');
|
|
}
|
|
|
|
void JSONWriter::PrintValue(const char* s) {
|
|
PrintCommaIfNeeded();
|
|
buffer_.AddChar('"');
|
|
AddEscapedUTF8String(s);
|
|
buffer_.AddChar('"');
|
|
}
|
|
|
|
void JSONWriter::PrintValue(const char* s, intptr_t i) {
|
|
PrintCommaIfNeeded();
|
|
buffer_.AddChar('"');
|
|
AddEscapedUTF8String(s, i);
|
|
buffer_.AddChar('"');
|
|
}
|
|
|
|
bool JSONWriter::PrintValueStr(const String& s,
|
|
intptr_t offset,
|
|
intptr_t count) {
|
|
PrintCommaIfNeeded();
|
|
buffer_.AddChar('"');
|
|
bool did_truncate = AddDartString(s, offset, count);
|
|
buffer_.AddChar('"');
|
|
return did_truncate;
|
|
}
|
|
|
|
void JSONWriter::PrintValueNoEscape(const char* s) {
|
|
PrintCommaIfNeeded();
|
|
buffer_.Printf("%s", s);
|
|
}
|
|
|
|
void JSONWriter::PrintfValue(const char* format, ...) {
|
|
va_list args;
|
|
va_start(args, format);
|
|
VPrintfValue(format, args);
|
|
va_end(args);
|
|
}
|
|
|
|
void JSONWriter::VPrintfValue(const char* format, va_list args) {
|
|
PrintCommaIfNeeded();
|
|
|
|
va_list measure_args;
|
|
va_copy(measure_args, args);
|
|
intptr_t len = Utils::VSNPrint(nullptr, 0, format, measure_args);
|
|
va_end(measure_args);
|
|
|
|
MaybeOnStackBuffer mosb(len + 1);
|
|
char* p = mosb.p();
|
|
|
|
va_list print_args;
|
|
va_copy(print_args, args);
|
|
intptr_t len2 = Utils::VSNPrint(p, len + 1, format, print_args);
|
|
va_end(print_args);
|
|
ASSERT(len == len2);
|
|
|
|
buffer_.AddChar('"');
|
|
AddEscapedUTF8String(p, len);
|
|
buffer_.AddChar('"');
|
|
}
|
|
|
|
void JSONWriter::PrintPropertyBool(const char* name, bool b) {
|
|
PrintPropertyName(name);
|
|
PrintValueBool(b);
|
|
}
|
|
|
|
void JSONWriter::PrintProperty(const char* name, intptr_t i) {
|
|
PrintPropertyName(name);
|
|
PrintValue(i);
|
|
}
|
|
|
|
void JSONWriter::PrintProperty64(const char* name, int64_t i) {
|
|
PrintPropertyName(name);
|
|
PrintValue64(i);
|
|
}
|
|
|
|
void JSONWriter::PrintProperty(const char* name, double d) {
|
|
PrintPropertyName(name);
|
|
PrintValue(d);
|
|
}
|
|
|
|
void JSONWriter::PrintProperty(const char* name, const char* s) {
|
|
PrintPropertyName(name);
|
|
PrintValue(s);
|
|
}
|
|
|
|
void JSONWriter::PrintPropertyBase64(const char* name,
|
|
const uint8_t* b,
|
|
intptr_t len) {
|
|
PrintPropertyName(name);
|
|
PrintValueBase64(b, len);
|
|
}
|
|
|
|
bool JSONWriter::PrintPropertyStr(const char* name,
|
|
const String& s,
|
|
intptr_t offset,
|
|
intptr_t count) {
|
|
PrintPropertyName(name);
|
|
return PrintValueStr(s, offset, count);
|
|
}
|
|
|
|
void JSONWriter::PrintPropertyNoEscape(const char* name, const char* s) {
|
|
PrintPropertyName(name);
|
|
PrintValueNoEscape(s);
|
|
}
|
|
|
|
void JSONWriter::PrintfProperty(const char* name, const char* format, ...) {
|
|
va_list args;
|
|
va_start(args, format);
|
|
VPrintfProperty(name, format, args);
|
|
va_end(args);
|
|
}
|
|
|
|
void JSONWriter::VPrintfProperty(const char* name,
|
|
const char* format,
|
|
va_list args) {
|
|
PrintPropertyName(name);
|
|
|
|
va_list measure_args;
|
|
va_copy(measure_args, args);
|
|
intptr_t len = Utils::VSNPrint(nullptr, 0, format, measure_args);
|
|
va_end(measure_args);
|
|
|
|
MaybeOnStackBuffer mosb(len + 1);
|
|
char* p = mosb.p();
|
|
|
|
va_list print_args;
|
|
va_copy(print_args, args);
|
|
intptr_t len2 = Utils::VSNPrint(p, len + 1, format, print_args);
|
|
va_end(print_args);
|
|
ASSERT(len == len2);
|
|
|
|
buffer_.AddChar('"');
|
|
AddEscapedUTF8String(p, len);
|
|
buffer_.AddChar('"');
|
|
}
|
|
|
|
void JSONWriter::Steal(char** buffer, intptr_t* buffer_length) {
|
|
ASSERT(buffer != nullptr);
|
|
ASSERT(buffer_length != nullptr);
|
|
*buffer_length = buffer_.length();
|
|
*buffer = buffer_.Steal();
|
|
}
|
|
|
|
void JSONWriter::PrintPropertyName(const char* name) {
|
|
ASSERT(name != nullptr);
|
|
PrintCommaIfNeeded();
|
|
buffer_.AddChar('"');
|
|
AddEscapedUTF8String(name);
|
|
buffer_.AddChar('"');
|
|
buffer_.AddChar(':');
|
|
}
|
|
|
|
void JSONWriter::PrintNewline() {
|
|
buffer_.AddChar('\n');
|
|
}
|
|
|
|
void JSONWriter::PrintCommaIfNeeded() {
|
|
if (NeedComma()) {
|
|
buffer_.AddChar(',');
|
|
}
|
|
}
|
|
|
|
bool JSONWriter::NeedComma() {
|
|
const char* buffer = buffer_.buffer();
|
|
intptr_t length = buffer_.length();
|
|
if (length == 0) {
|
|
return false;
|
|
}
|
|
char ch = buffer[length - 1];
|
|
return (ch != '[') && (ch != '{') && (ch != ':') && (ch != ',');
|
|
}
|
|
|
|
void JSONWriter::EnsureIntegerIsRepresentableInJavaScript(int64_t i) {
|
|
#ifdef DEBUG
|
|
if (!Utils::IsJavaScriptInt(i)) {
|
|
OS::PrintErr(
|
|
"JSONWriter::EnsureIntegerIsRepresentableInJavaScript failed on "
|
|
"%" Pd64 "\n",
|
|
i);
|
|
UNREACHABLE();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void JSONWriter::AddEscapedUTF8String(const char* s) {
|
|
if (s == nullptr) {
|
|
return;
|
|
}
|
|
intptr_t len = strlen(s);
|
|
AddEscapedUTF8String(s, len);
|
|
}
|
|
|
|
void JSONWriter::AddEscapedUTF8String(const char* s, intptr_t len) {
|
|
if (s == nullptr) {
|
|
return;
|
|
}
|
|
buffer_.AddEscapedUTF8(s, len);
|
|
}
|
|
|
|
bool JSONWriter::AddDartString(const String& s,
|
|
intptr_t offset,
|
|
intptr_t count) {
|
|
intptr_t length = s.Length();
|
|
ASSERT(offset >= 0);
|
|
if (offset > length) {
|
|
offset = length;
|
|
}
|
|
if (!Utils::RangeCheck(offset, count, length)) {
|
|
count = length - offset;
|
|
}
|
|
|
|
if (count > 0) { // Avoid asserts about harmless out-of-bounds index.
|
|
NoSafepointScope no_safepoint;
|
|
if (s.IsOneByteString()) {
|
|
buffer_.AddEscapedLatin1(OneByteString::CharAddr(s, offset), count);
|
|
} else if (s.IsExternalOneByteString()) {
|
|
buffer_.AddEscapedLatin1(ExternalOneByteString::CharAddr(s, offset),
|
|
count);
|
|
} else if (s.IsTwoByteString()) {
|
|
buffer_.AddEscapedUTF16(TwoByteString::CharAddr(s, offset), count);
|
|
} else if (s.IsExternalTwoByteString()) {
|
|
buffer_.AddEscapedUTF16(ExternalTwoByteString::CharAddr(s, offset),
|
|
count);
|
|
} else {
|
|
UNREACHABLE();
|
|
}
|
|
}
|
|
|
|
// Return value indicates whether the string is truncated.
|
|
intptr_t limit = offset + count;
|
|
return (offset > 0) || (limit < length);
|
|
}
|
|
|
|
} // namespace dart
|