Revision: 5909
Author: [email protected]
Date: Wed Dec  1 02:04:34 2010
Log: Move quoting of a JSON string to a specialized runtime function.

Previously used string replace regexp with function replacement.

Review URL: http://codereview.chromium.org/5443001
http://code.google.com/p/v8/source/detail?r=5909

Modified:
 /branches/bleeding_edge/src/json.js
 /branches/bleeding_edge/src/runtime.cc
 /branches/bleeding_edge/src/runtime.h
 /branches/bleeding_edge/src/v8-counters.h

=======================================
--- /branches/bleeding_edge/src/json.js Wed Oct 27 02:19:43 2010
+++ /branches/bleeding_edge/src/json.js Wed Dec  1 02:04:34 2010
@@ -65,35 +65,11 @@
     return unfiltered;
   }
 }
-
-var characterQuoteCache = {
-  '\b': '\\b',  // ASCII 8, Backspace
-  '\t': '\\t',  // ASCII 9, Tab
-  '\n': '\\n',  // ASCII 10, Newline
-  '\f': '\\f',  // ASCII 12, Formfeed
-  '\r': '\\r',  // ASCII 13, Carriage Return
-  '\"': '\\"',
-  '\\': '\\\\'
-};
-
-function QuoteSingleJSONCharacter(c) {
-  if (c in characterQuoteCache) {
-    return characterQuoteCache[c];
-  }
-  var charCode = c.charCodeAt(0);
-  var result;
-  if (charCode < 16) result = '\\u000';
-  else if (charCode < 256) result = '\\u00';
-  else if (charCode < 4096) result = '\\u0';
-  else result = '\\u';
-  result += charCode.toString(16);
-  characterQuoteCache[c] = result;
-  return result;
-}

 function QuoteJSONString(str) {
-  var quotable = /[\\\"\x00-\x1f]/g;
-  return '"' + str.replace(quotable, QuoteSingleJSONCharacter) + '"';
+  var quoted_str = %QuoteJSONString(str);
+  if (IS_STRING(quoted_str)) return quoted_str;
+  return '"' + str + '"';
 }

 function StackContains(stack, val) {
=======================================
--- /branches/bleeding_edge/src/runtime.cc      Tue Nov 30 05:16:36 2010
+++ /branches/bleeding_edge/src/runtime.cc      Wed Dec  1 02:04:34 2010
@@ -4519,6 +4519,167 @@
   }
   return destination;
 }
+
+
+static const char* const JsonQuotes[128] = {
+    "\\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",
+    NULL, NULL, "\\\"", NULL,
+    NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL,
+    "\\\\", NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL,
+};
+
+
+static const byte JsonQuoteLengths[128] = {
+    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 Char>
+Char* WriteString(Char* dst, const char* src_string) {
+  char c;
+  for (c = *src_string; c; c = *src_string) {
+    *dst = c;
+    dst++;
+    src_string++;
+  }
+  return dst;
+}
+
+
+template <typename StringType>
+MaybeObject* AllocateRawString(int length);
+
+
+template <>
+MaybeObject* AllocateRawString<SeqTwoByteString>(int length) {
+  return Heap::AllocateRawTwoByteString(length);
+}
+
+
+template <>
+MaybeObject* AllocateRawString<SeqAsciiString>(int length) {
+  return Heap::AllocateRawAsciiString(length);
+}
+
+
+template <typename Char, typename StringType>
+static MaybeObject* QuoteJsonString(String* original,
+                                    Vector<const Char> characters) {
+  int length = characters.length();
+  int quoted_length = 0;
+  for (int i = 0; i < length; i++) {
+    unsigned int c = characters[i];
+    if (sizeof(Char) > 1u) {
+      quoted_length +=
+          (c >= sizeof(JsonQuoteLengths)) ? 1 : JsonQuoteLengths[c];
+    } else {
+      quoted_length += JsonQuoteLengths[c];
+    }
+  }
+  if (quoted_length == length) {
+    return Heap::undefined_value();
+  }
+  Counters::quote_json_char_count.Increment(length);
+
+  // Add space for quotes.
+  quoted_length += 2;
+
+  MaybeObject* new_alloc = AllocateRawString<StringType>(quoted_length);
+  Object* new_object;
+  if (!new_alloc->ToObject(&new_object)) {
+    Counters::quote_json_char_recount.Increment(length);
+    return new_alloc;
+  }
+  StringType* new_string = StringType::cast(new_object);
+
+
+ STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
+  Char* write_cursor = reinterpret_cast<Char*>(
+      new_string->address() + SeqAsciiString::kHeaderSize);
+  *(write_cursor++) = '"';
+  const Char* read_cursor = characters.start();
+  const Char* end = read_cursor + length;
+  while (read_cursor < end) {
+    Char c = *(read_cursor++);
+ if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= sizeof(JsonQuotes)) {
+      *(write_cursor++) = c;
+    } else {
+      const char* replacement = JsonQuotes[static_cast<unsigned>(c)];
+      if (!replacement) {
+        *(write_cursor++) = c;
+      } else {
+        write_cursor = WriteString(write_cursor, replacement);
+      }
+    }
+  }
+  *(write_cursor++) = '"';
+  ASSERT_EQ(SeqAsciiString::kHeaderSize + quoted_length * sizeof(Char),
+ reinterpret_cast<Address>(write_cursor) - new_string->address());
+  return new_string;
+}
+
+
+static MaybeObject* Runtime_QuoteJSONString(Arguments args) {
+  NoHandleAllocation ha;
+  CONVERT_CHECKED(String, str, args[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());
+  }
+  if (str->IsTwoByteRepresentation()) {
+ return QuoteJsonString<uc16, SeqTwoByteString>(str, str->ToUC16Vector());
+  } else {
+ return QuoteJsonString<char, SeqAsciiString>(str, str->ToAsciiVector());
+  }
+}


 static MaybeObject* Runtime_StringParseInt(Arguments args) {
=======================================
--- /branches/bleeding_edge/src/runtime.h       Mon Nov 22 01:57:21 2010
+++ /branches/bleeding_edge/src/runtime.h       Wed Dec  1 02:04:34 2010
@@ -100,6 +100,7 @@
   F(CharFromCode, 1, 1) \
   F(URIEscape, 1, 1) \
   F(URIUnescape, 1, 1) \
+  F(QuoteJSONString, 1, 1) \
   \
   F(NumberToString, 1, 1) \
   F(NumberToStringSkipCache, 1, 1) \
=======================================
--- /branches/bleeding_edge/src/v8-counters.h   Mon Oct  4 07:30:43 2010
+++ /branches/bleeding_edge/src/v8-counters.h   Wed Dec  1 02:04:34 2010
@@ -224,7 +224,9 @@
   SC(math_sqrt, V8.MathSqrt)                                          \
   SC(math_tan, V8.MathTan)                                            \
   SC(transcendental_cache_hit, V8.TranscendentalCacheHit)             \
-  SC(transcendental_cache_miss, V8.TranscendentalCacheMiss)
+  SC(transcendental_cache_miss, V8.TranscendentalCacheMiss)           \
+  SC(quote_json_char_count, V8.QuoteJsonCharacterCount)               \
+  SC(quote_json_char_recount, V8.QuoteJsonCharacterReCount)           \


 // This file contains all the v8 counters that are in use.

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to