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
This commit is contained in:
parent
b0e4479e70
commit
c2febfbfaf
30
src/json.js
30
src/json.js
@ -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) {
|
||||
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) {
|
||||
|
161
src/runtime.cc
161
src/runtime.cc
@ -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) {
|
||||
NoHandleAllocation ha;
|
||||
|
||||
|
@ -100,6 +100,7 @@ namespace internal {
|
||||
F(CharFromCode, 1, 1) \
|
||||
F(URIEscape, 1, 1) \
|
||||
F(URIUnescape, 1, 1) \
|
||||
F(QuoteJSONString, 1, 1) \
|
||||
\
|
||||
F(NumberToString, 1, 1) \
|
||||
F(NumberToStringSkipCache, 1, 1) \
|
||||
|
@ -224,7 +224,9 @@ namespace internal {
|
||||
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.
|
||||
|
Loading…
Reference in New Issue
Block a user