Unify code for fast and slow path of JSON.stringify.
R=verwaest@chromium.org BUG= Review URL: https://chromiumcodereview.appspot.com/12690017 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@14023 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
53adf3b19c
commit
9e1a7e2e6f
@ -220,6 +220,7 @@ namespace internal {
|
||||
V(undefined_string, "undefined") \
|
||||
V(value_of_string, "valueOf") \
|
||||
V(stack_string, "stack") \
|
||||
V(toJSON_string, "toJSON") \
|
||||
V(InitializeVarGlobal_string, "InitializeVarGlobal") \
|
||||
V(InitializeConstGlobal_string, "InitializeConstGlobal") \
|
||||
V(KeyedLoadElementMonomorphic_string, \
|
||||
|
@ -41,6 +41,9 @@ class BasicJsonStringifier BASE_EMBEDDED {
|
||||
|
||||
MaybeObject* Stringify(Handle<Object> object);
|
||||
|
||||
INLINE(static MaybeObject* StringifyString(Isolate* isolate,
|
||||
Handle<String> object));
|
||||
|
||||
private:
|
||||
static const int kInitialPartLength = 32;
|
||||
static const int kMaxPartLength = 16 * 1024;
|
||||
@ -84,6 +87,11 @@ class BasicJsonStringifier BASE_EMBEDDED {
|
||||
bool deferred_comma,
|
||||
bool deferred_key);
|
||||
|
||||
template <typename StringType>
|
||||
INLINE(static MaybeObject* StringifyString_(Isolate* isolate,
|
||||
Handle<String> string,
|
||||
Handle<String> result));
|
||||
|
||||
// Entry point to serialize the object.
|
||||
INLINE(Result SerializeObject(Handle<Object> obj)) {
|
||||
return Serialize_<false>(obj, false, factory_->empty_string());
|
||||
@ -135,18 +143,18 @@ class BasicJsonStringifier BASE_EMBEDDED {
|
||||
void SerializeString(Handle<String> object);
|
||||
|
||||
template <typename SrcChar, typename DestChar>
|
||||
INLINE(void SerializeStringUnchecked_(const SrcChar* src,
|
||||
DestChar* dest,
|
||||
int length));
|
||||
INLINE(static int SerializeStringUnchecked_(const SrcChar* src,
|
||||
DestChar* dest,
|
||||
int length));
|
||||
|
||||
template <bool is_ascii, typename Char>
|
||||
INLINE(void SerializeString_(Handle<String> string));
|
||||
|
||||
template <typename Char>
|
||||
INLINE(bool DoNotEscape(Char c));
|
||||
INLINE(static bool DoNotEscape(Char c));
|
||||
|
||||
template <typename Char>
|
||||
INLINE(Vector<const Char> GetCharVector(Handle<String> string));
|
||||
INLINE(static Vector<const Char> GetCharVector(Handle<String> string));
|
||||
|
||||
Result StackPush(Handle<Object> object);
|
||||
void StackPop();
|
||||
@ -244,15 +252,15 @@ const char* const BasicJsonStringifier::JsonEscapeTable =
|
||||
"\370\0 \371\0 \372\0 \373\0 "
|
||||
"\374\0 \375\0 \376\0 \377\0 ";
|
||||
|
||||
|
||||
BasicJsonStringifier::BasicJsonStringifier(Isolate* isolate)
|
||||
: isolate_(isolate), current_index_(0), is_ascii_(true) {
|
||||
factory_ = isolate_->factory();
|
||||
accumulator_store_ = Handle<JSValue>::cast(
|
||||
factory_->ToObject(factory_->empty_string()));
|
||||
part_length_ = kInitialPartLength;
|
||||
current_part_ = factory_->NewRawOneByteString(kInitialPartLength);
|
||||
tojson_string_ =
|
||||
factory_->InternalizeOneByteString(STATIC_ASCII_VECTOR("toJSON"));
|
||||
current_part_ = factory_->NewRawOneByteString(part_length_);
|
||||
tojson_string_ = factory_->toJSON_string();
|
||||
stack_ = factory_->NewJSArray(8);
|
||||
}
|
||||
|
||||
@ -275,6 +283,57 @@ MaybeObject* BasicJsonStringifier::Stringify(Handle<Object> object) {
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* BasicJsonStringifier::StringifyString(Isolate* isolate,
|
||||
Handle<String> object) {
|
||||
static const int kJsonQuoteWorstCaseBlowup = 6;
|
||||
static const int kSpaceForQuotes = 2;
|
||||
int worst_case_length =
|
||||
object->length() * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
|
||||
|
||||
if (worst_case_length > 32 * KB) { // Slow path if too large.
|
||||
BasicJsonStringifier stringifier(isolate);
|
||||
return stringifier.Stringify(object);
|
||||
}
|
||||
|
||||
object = FlattenGetString(object);
|
||||
if (object->IsSeqOneByteString()) {
|
||||
return StringifyString_<SeqOneByteString>(
|
||||
isolate,
|
||||
object,
|
||||
isolate->factory()->NewRawOneByteString(worst_case_length));
|
||||
} else {
|
||||
return StringifyString_<SeqTwoByteString>(
|
||||
isolate,
|
||||
object,
|
||||
isolate->factory()->NewRawTwoByteString(worst_case_length));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <typename StringType>
|
||||
MaybeObject* BasicJsonStringifier::StringifyString_(Isolate* isolate,
|
||||
Handle<String> string,
|
||||
Handle<String> result) {
|
||||
AssertNoAllocation no_allocation;
|
||||
int final_size = 0;
|
||||
StringType* dest = StringType::cast(*result);
|
||||
dest->Set(final_size++, '\"');
|
||||
final_size += SerializeStringUnchecked_(StringType::cast(*string)->GetChars(),
|
||||
dest->GetChars() + 1,
|
||||
string->length());
|
||||
dest->Set(final_size++, '\"');
|
||||
if (isolate->heap()->InNewSpace(*result)) {
|
||||
// In new space, simply lower the allocation top to fit the actual size.
|
||||
isolate->heap()->new_space()->ShrinkStringAtAllocationBoundary<StringType>(
|
||||
*result, final_size);
|
||||
return *result;
|
||||
} else {
|
||||
// Not in new space, need to fill the wasted space with filler objects.
|
||||
return SeqString::cast(*result)->Truncate(final_size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <bool is_ascii, typename Char>
|
||||
void BasicJsonStringifier::Append_(Char c) {
|
||||
if (is_ascii) {
|
||||
@ -667,10 +726,9 @@ void BasicJsonStringifier::ChangeEncoding() {
|
||||
|
||||
|
||||
template <typename SrcChar, typename DestChar>
|
||||
void BasicJsonStringifier::SerializeStringUnchecked_(const SrcChar* src,
|
||||
DestChar* dest,
|
||||
int length) {
|
||||
dest += current_index_;
|
||||
int BasicJsonStringifier::SerializeStringUnchecked_(const SrcChar* src,
|
||||
DestChar* dest,
|
||||
int length) {
|
||||
DestChar* dest_start = dest;
|
||||
|
||||
// Assert that uc16 character is not truncated down to 8 bit.
|
||||
@ -688,7 +746,7 @@ void BasicJsonStringifier::SerializeStringUnchecked_(const SrcChar* src,
|
||||
}
|
||||
}
|
||||
|
||||
current_index_ += static_cast<int>(dest - dest_start);
|
||||
return static_cast<int>(dest - dest_start);
|
||||
}
|
||||
|
||||
|
||||
@ -705,14 +763,14 @@ void BasicJsonStringifier::SerializeString_(Handle<String> string) {
|
||||
AssertNoAllocation no_allocation;
|
||||
Vector<const Char> vector = GetCharVector<Char>(string);
|
||||
if (is_ascii) {
|
||||
SerializeStringUnchecked_(
|
||||
current_index_ += SerializeStringUnchecked_(
|
||||
vector.start(),
|
||||
SeqOneByteString::cast(*current_part_)->GetChars(),
|
||||
SeqOneByteString::cast(*current_part_)->GetChars() + current_index_,
|
||||
length);
|
||||
} else {
|
||||
SerializeStringUnchecked_(
|
||||
current_index_ += SerializeStringUnchecked_(
|
||||
vector.start(),
|
||||
SeqTwoByteString::cast(*current_part_)->GetChars(),
|
||||
SeqTwoByteString::cast(*current_part_)->GetChars() + current_index_,
|
||||
length);
|
||||
}
|
||||
} else {
|
||||
|
360
src/runtime.cc
360
src/runtime.cc
@ -5171,365 +5171,11 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
|
||||
}
|
||||
|
||||
|
||||
static const unsigned int kQuoteTableLength = 128u;
|
||||
|
||||
static const int kJsonQuotesCharactersPerEntry = 8;
|
||||
static const char* const JsonQuotes =
|
||||
"\\u0000 \\u0001 \\u0002 \\u0003 "
|
||||
"\\u0004 \\u0005 \\u0006 \\u0007 "
|
||||
"\\b \\t \\n \\u000b "
|
||||
"\\f \\r \\u000e \\u000f "
|
||||
"\\u0010 \\u0011 \\u0012 \\u0013 "
|
||||
"\\u0014 \\u0015 \\u0016 \\u0017 "
|
||||
"\\u0018 \\u0019 \\u001a \\u001b "
|
||||
"\\u001c \\u001d \\u001e \\u001f "
|
||||
" ! \\\" # "
|
||||
"$ % & ' "
|
||||
"( ) * + "
|
||||
", - . / "
|
||||
"0 1 2 3 "
|
||||
"4 5 6 7 "
|
||||
"8 9 : ; "
|
||||
"< = > ? "
|
||||
"@ A B C "
|
||||
"D E F G "
|
||||
"H I J K "
|
||||
"L M N O "
|
||||
"P Q R S "
|
||||
"T U V W "
|
||||
"X Y Z [ "
|
||||
"\\\\ ] ^ _ "
|
||||
"` a b c "
|
||||
"d e f g "
|
||||
"h i j k "
|
||||
"l m n o "
|
||||
"p q r s "
|
||||
"t u v w "
|
||||
"x y z { "
|
||||
"| } ~ \177 ";
|
||||
|
||||
|
||||
// For a string that is less than 32k characters it should always be
|
||||
// possible to allocate it in new space.
|
||||
static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
|
||||
|
||||
|
||||
// Doing JSON quoting cannot make the string more than this many times larger.
|
||||
static const int kJsonQuoteWorstCaseBlowup = 6;
|
||||
|
||||
static const int kSpaceForQuotesAndComma = 3;
|
||||
static const int kSpaceForBrackets = 2;
|
||||
|
||||
// Covers the entire ASCII range (all other characters are unchanged by JSON
|
||||
// quoting).
|
||||
static const byte JsonQuoteLengths[kQuoteTableLength] = {
|
||||
6, 6, 6, 6, 6, 6, 6, 6,
|
||||
2, 2, 2, 6, 2, 2, 6, 6,
|
||||
6, 6, 6, 6, 6, 6, 6, 6,
|
||||
6, 6, 6, 6, 6, 6, 6, 6,
|
||||
1, 1, 2, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 2, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
};
|
||||
|
||||
|
||||
template <typename StringType>
|
||||
MaybeObject* AllocateRawString(Isolate* isolate, int length);
|
||||
|
||||
|
||||
template <>
|
||||
MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
|
||||
return isolate->heap()->AllocateRawTwoByteString(length);
|
||||
}
|
||||
|
||||
|
||||
template <>
|
||||
MaybeObject* AllocateRawString<SeqOneByteString>(Isolate* isolate, int length) {
|
||||
return isolate->heap()->AllocateRawOneByteString(length);
|
||||
}
|
||||
|
||||
|
||||
template <typename Char, typename StringType, bool comma>
|
||||
static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
|
||||
Vector<const Char> characters) {
|
||||
int length = characters.length();
|
||||
const Char* read_cursor = characters.start();
|
||||
const Char* end = read_cursor + length;
|
||||
const int kSpaceForQuotes = 2 + (comma ? 1 :0);
|
||||
int quoted_length = kSpaceForQuotes;
|
||||
while (read_cursor < end) {
|
||||
Char c = *(read_cursor++);
|
||||
if (static_cast<unsigned>(c) >= kQuoteTableLength) {
|
||||
quoted_length++;
|
||||
} else {
|
||||
quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
|
||||
}
|
||||
}
|
||||
MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
|
||||
quoted_length);
|
||||
Object* new_object;
|
||||
if (!new_alloc->ToObject(&new_object)) {
|
||||
return new_alloc;
|
||||
}
|
||||
StringType* new_string = StringType::cast(new_object);
|
||||
|
||||
Char* write_cursor = reinterpret_cast<Char*>(
|
||||
new_string->address() + SeqString::kHeaderSize);
|
||||
if (comma) *(write_cursor++) = ',';
|
||||
*(write_cursor++) = '"';
|
||||
|
||||
read_cursor = characters.start();
|
||||
while (read_cursor < end) {
|
||||
Char c = *(read_cursor++);
|
||||
if (static_cast<unsigned>(c) >= kQuoteTableLength) {
|
||||
*(write_cursor++) = c;
|
||||
} else {
|
||||
int len = JsonQuoteLengths[static_cast<unsigned>(c)];
|
||||
const char* replacement = JsonQuotes +
|
||||
static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
|
||||
for (int i = 0; i < len; i++) {
|
||||
*write_cursor++ = *replacement++;
|
||||
}
|
||||
}
|
||||
}
|
||||
*(write_cursor++) = '"';
|
||||
return new_string;
|
||||
}
|
||||
|
||||
|
||||
template <typename SinkChar, typename SourceChar>
|
||||
static inline SinkChar* WriteQuoteJsonString(
|
||||
Isolate* isolate,
|
||||
SinkChar* write_cursor,
|
||||
Vector<const SourceChar> characters) {
|
||||
// SinkChar is only char if SourceChar is guaranteed to be char.
|
||||
ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
|
||||
const SourceChar* read_cursor = characters.start();
|
||||
const SourceChar* end = read_cursor + characters.length();
|
||||
*(write_cursor++) = '"';
|
||||
while (read_cursor < end) {
|
||||
SourceChar c = *(read_cursor++);
|
||||
if (static_cast<unsigned>(c) >= kQuoteTableLength) {
|
||||
*(write_cursor++) = static_cast<SinkChar>(c);
|
||||
} else {
|
||||
int len = JsonQuoteLengths[static_cast<unsigned>(c)];
|
||||
const char* replacement = JsonQuotes +
|
||||
static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
|
||||
write_cursor[0] = replacement[0];
|
||||
if (len > 1) {
|
||||
write_cursor[1] = replacement[1];
|
||||
if (len > 2) {
|
||||
ASSERT(len == 6);
|
||||
write_cursor[2] = replacement[2];
|
||||
write_cursor[3] = replacement[3];
|
||||
write_cursor[4] = replacement[4];
|
||||
write_cursor[5] = replacement[5];
|
||||
}
|
||||
}
|
||||
write_cursor += len;
|
||||
}
|
||||
}
|
||||
*(write_cursor++) = '"';
|
||||
return write_cursor;
|
||||
}
|
||||
|
||||
|
||||
template <typename Char, typename StringType, bool comma>
|
||||
static MaybeObject* QuoteJsonString(Isolate* isolate,
|
||||
Vector<const Char> characters) {
|
||||
int length = characters.length();
|
||||
isolate->counters()->quote_json_char_count()->Increment(length);
|
||||
int worst_case_length =
|
||||
length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
|
||||
if (worst_case_length > kMaxGuaranteedNewSpaceString) {
|
||||
return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
|
||||
}
|
||||
|
||||
MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
|
||||
worst_case_length);
|
||||
Object* new_object;
|
||||
if (!new_alloc->ToObject(&new_object)) {
|
||||
return new_alloc;
|
||||
}
|
||||
if (!isolate->heap()->new_space()->Contains(new_object)) {
|
||||
// Even if our string is small enough to fit in new space we still have to
|
||||
// handle it being allocated in old space as may happen in the third
|
||||
// attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
|
||||
// CEntryStub::GenerateCore.
|
||||
return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
|
||||
}
|
||||
StringType* new_string = StringType::cast(new_object);
|
||||
ASSERT(isolate->heap()->new_space()->Contains(new_string));
|
||||
|
||||
Char* write_cursor = reinterpret_cast<Char*>(
|
||||
new_string->address() + SeqString::kHeaderSize);
|
||||
if (comma) *(write_cursor++) = ',';
|
||||
write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
|
||||
write_cursor,
|
||||
characters);
|
||||
int final_length = static_cast<int>(
|
||||
write_cursor - reinterpret_cast<Char*>(
|
||||
new_string->address() + SeqString::kHeaderSize));
|
||||
isolate->heap()->new_space()->
|
||||
template ShrinkStringAtAllocationBoundary<StringType>(
|
||||
new_string, final_length);
|
||||
return new_string;
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
|
||||
NoHandleAllocation ha(isolate);
|
||||
CONVERT_ARG_CHECKED(String, str, 0);
|
||||
if (!str->IsFlat()) {
|
||||
MaybeObject* try_flatten = str->TryFlatten();
|
||||
Object* flat;
|
||||
if (!try_flatten->ToObject(&flat)) {
|
||||
return try_flatten;
|
||||
}
|
||||
str = String::cast(flat);
|
||||
ASSERT(str->IsFlat());
|
||||
}
|
||||
String::FlatContent flat = str->GetFlatContent();
|
||||
ASSERT(flat.IsFlat());
|
||||
if (flat.IsTwoByte()) {
|
||||
return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
|
||||
flat.ToUC16Vector());
|
||||
} else {
|
||||
return QuoteJsonString<uint8_t, SeqOneByteString, false>(
|
||||
isolate,
|
||||
flat.ToOneByteVector());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
|
||||
NoHandleAllocation ha(isolate);
|
||||
CONVERT_ARG_CHECKED(String, str, 0);
|
||||
if (!str->IsFlat()) {
|
||||
MaybeObject* try_flatten = str->TryFlatten();
|
||||
Object* flat;
|
||||
if (!try_flatten->ToObject(&flat)) {
|
||||
return try_flatten;
|
||||
}
|
||||
str = String::cast(flat);
|
||||
ASSERT(str->IsFlat());
|
||||
}
|
||||
String::FlatContent flat = str->GetFlatContent();
|
||||
if (flat.IsTwoByte()) {
|
||||
return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
|
||||
flat.ToUC16Vector());
|
||||
} else {
|
||||
return QuoteJsonString<uint8_t, SeqOneByteString, true>(
|
||||
isolate,
|
||||
flat.ToOneByteVector());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <typename Char, typename StringType>
|
||||
static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
|
||||
FixedArray* array,
|
||||
int worst_case_length) {
|
||||
int length = array->length();
|
||||
|
||||
MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
|
||||
worst_case_length);
|
||||
Object* new_object;
|
||||
if (!new_alloc->ToObject(&new_object)) {
|
||||
return new_alloc;
|
||||
}
|
||||
if (!isolate->heap()->new_space()->Contains(new_object)) {
|
||||
// Even if our string is small enough to fit in new space we still have to
|
||||
// handle it being allocated in old space as may happen in the third
|
||||
// attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
|
||||
// CEntryStub::GenerateCore.
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
AssertNoAllocation no_gc;
|
||||
StringType* new_string = StringType::cast(new_object);
|
||||
ASSERT(isolate->heap()->new_space()->Contains(new_string));
|
||||
|
||||
Char* write_cursor = reinterpret_cast<Char*>(
|
||||
new_string->address() + SeqString::kHeaderSize);
|
||||
*(write_cursor++) = '[';
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (i != 0) *(write_cursor++) = ',';
|
||||
String* str = String::cast(array->get(i));
|
||||
String::FlatContent content = str->GetFlatContent();
|
||||
ASSERT(content.IsFlat());
|
||||
if (content.IsTwoByte()) {
|
||||
write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
|
||||
write_cursor,
|
||||
content.ToUC16Vector());
|
||||
} else {
|
||||
write_cursor =
|
||||
WriteQuoteJsonString<Char, uint8_t>(isolate,
|
||||
write_cursor,
|
||||
content.ToOneByteVector());
|
||||
}
|
||||
}
|
||||
*(write_cursor++) = ']';
|
||||
|
||||
int final_length = static_cast<int>(
|
||||
write_cursor - reinterpret_cast<Char*>(
|
||||
new_string->address() + SeqString::kHeaderSize));
|
||||
isolate->heap()->new_space()->
|
||||
template ShrinkStringAtAllocationBoundary<StringType>(
|
||||
new_string, final_length);
|
||||
return new_string;
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
|
||||
NoHandleAllocation ha(isolate);
|
||||
HandleScope scope(isolate);
|
||||
CONVERT_ARG_HANDLE_CHECKED(String, string, 0);
|
||||
ASSERT(args.length() == 1);
|
||||
CONVERT_ARG_CHECKED(JSArray, array, 0);
|
||||
|
||||
if (!array->HasFastObjectElements()) {
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
FixedArray* elements = FixedArray::cast(array->elements());
|
||||
int n = elements->length();
|
||||
bool ascii = true;
|
||||
int total_length = 0;
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
Object* elt = elements->get(i);
|
||||
if (!elt->IsString()) return isolate->heap()->undefined_value();
|
||||
String* element = String::cast(elt);
|
||||
if (!element->IsFlat()) return isolate->heap()->undefined_value();
|
||||
total_length += element->length();
|
||||
if (ascii && element->IsTwoByteRepresentation()) {
|
||||
ascii = false;
|
||||
}
|
||||
}
|
||||
|
||||
int worst_case_length =
|
||||
kSpaceForBrackets + n * kSpaceForQuotesAndComma
|
||||
+ total_length * kJsonQuoteWorstCaseBlowup;
|
||||
|
||||
if (worst_case_length > kMaxGuaranteedNewSpaceString) {
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
|
||||
if (ascii) {
|
||||
return QuoteJsonStringArray<char, SeqOneByteString>(isolate,
|
||||
elements,
|
||||
worst_case_length);
|
||||
} else {
|
||||
return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
|
||||
elements,
|
||||
worst_case_length);
|
||||
}
|
||||
return BasicJsonStringifier::StringifyString(isolate, string);
|
||||
}
|
||||
|
||||
|
||||
|
@ -195,8 +195,6 @@ namespace internal {
|
||||
F(ParseJson, 1, 1) \
|
||||
F(BasicJSONStringify, 1, 1) \
|
||||
F(QuoteJSONString, 1, 1) \
|
||||
F(QuoteJSONStringComma, 1, 1) \
|
||||
F(QuoteJSONStringArray, 1, 1) \
|
||||
\
|
||||
/* Strings */ \
|
||||
F(StringCharCodeAt, 2, 1) \
|
||||
|
Loading…
Reference in New Issue
Block a user