Index: src/runtime.cc |
diff --git a/src/runtime.cc b/src/runtime.cc |
index 934c82eb10566973cd6fead748b1144f10b20989..8e251575cbef13d73e96f278dec8a72ebff08364 100644 |
--- a/src/runtime.cc |
+++ b/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); |
} |