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