Commit c2febfbf authored by lrn@chromium.org's avatar lrn@chromium.org

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5909 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent b0e4479e
...@@ -66,34 +66,10 @@ function JSONParse(text, reviver) { ...@@ -66,34 +66,10 @@ function JSONParse(text, reviver) {
} }
} }
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) { function QuoteJSONString(str) {
var quotable = /[\\\"\x00-\x1f]/g; var quoted_str = %QuoteJSONString(str);
return '"' + str.replace(quotable, QuoteSingleJSONCharacter) + '"'; if (IS_STRING(quoted_str)) return quoted_str;
return '"' + str + '"';
} }
function StackContains(stack, val) { function StackContains(stack, val) {
......
...@@ -4521,6 +4521,167 @@ static MaybeObject* Runtime_URIUnescape(Arguments args) { ...@@ -4521,6 +4521,167 @@ static MaybeObject* Runtime_URIUnescape(Arguments args) {
} }
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) { static MaybeObject* Runtime_StringParseInt(Arguments args) {
NoHandleAllocation ha; NoHandleAllocation ha;
......
...@@ -100,6 +100,7 @@ namespace internal { ...@@ -100,6 +100,7 @@ namespace internal {
F(CharFromCode, 1, 1) \ F(CharFromCode, 1, 1) \
F(URIEscape, 1, 1) \ F(URIEscape, 1, 1) \
F(URIUnescape, 1, 1) \ F(URIUnescape, 1, 1) \
F(QuoteJSONString, 1, 1) \
\ \
F(NumberToString, 1, 1) \ F(NumberToString, 1, 1) \
F(NumberToStringSkipCache, 1, 1) \ F(NumberToStringSkipCache, 1, 1) \
......
...@@ -224,7 +224,9 @@ namespace internal { ...@@ -224,7 +224,9 @@ namespace internal {
SC(math_sqrt, V8.MathSqrt) \ SC(math_sqrt, V8.MathSqrt) \
SC(math_tan, V8.MathTan) \ SC(math_tan, V8.MathTan) \
SC(transcendental_cache_hit, V8.TranscendentalCacheHit) \ 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. // This file contains all the v8 counters that are in use.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment