17d6ba15b6
This change removes support for external strings from the VM along with Dart_NewExternalLatin1String, Dart_NewExternalUTF16String and Dart_IsExternalString Dart C API functions. External strings are not used by the VM nor any known embedder, but Dart VM was paying the maintenance and performance price for the external string implementation classes. TEST=ci Change-Id: I094cd2d2b7ec0840e9f09e1ca9e5a7acd4e78c28 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/358760 Reviewed-by: Ryan Macnak <rmacnak@google.com> Reviewed-by: Siva Annamalai <asiva@google.com> Commit-Queue: Alexander Markov <alexmarkov@google.com>
392 lines
10 KiB
C++
392 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.IsTwoByteString()) {
|
|
buffer_.AddEscapedUTF16(TwoByteString::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
|