Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(94)

Unified Diff: src/runtime.cc

Issue 12993003: Revert r14023 (Unify code for fast and slow path of JSON.stringify) from trunk. (Closed) Base URL: https://v8.googlecode.com/svn/trunk
Patch Set: Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/runtime.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/runtime.cc
diff --git a/src/runtime.cc b/src/runtime.cc
index 38f77d07137eb06acec574d67d409cdfca073cd1..58f2a5153071eea0bd76ad383b77eae481e41778 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -5171,11 +5171,365 @@ 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) {
- HandleScope scope(isolate);
- CONVERT_ARG_HANDLE_CHECKED(String, string, 0);
+ 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);
ASSERT(args.length() == 1);
- return BasicJsonStringifier::StringifyString(isolate, string);
+ 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);
+ }
}
« no previous file with comments | « src/runtime.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698