Commit 748f8bf7 authored by yangguo@chromium.org's avatar yangguo@chromium.org

Optimize inner-loop in JSON.stringify.

R=verwaest@chromium.org
BUG=

Review URL: https://chromiumcodereview.appspot.com/11234031

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12798 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 5677ee65
...@@ -58,15 +58,9 @@ class BasicJsonStringifier BASE_EMBEDDED { ...@@ -58,15 +58,9 @@ class BasicJsonStringifier BASE_EMBEDDED {
template <bool is_ascii, typename Char> template <bool is_ascii, typename Char>
INLINE(void Append_(Char c)); INLINE(void Append_(Char c));
template <bool is_ascii, typename Char>
INLINE(void AppendUnchecked_(Char c));
template <bool is_ascii, typename Char> template <bool is_ascii, typename Char>
INLINE(void Append_(const Char* chars)); INLINE(void Append_(const Char* chars));
template <bool is_ascii, typename Char>
INLINE(void AppendUnchecked_(const Char* chars));
INLINE(void Append(char c)) { INLINE(void Append(char c)) {
if (is_ascii_) { if (is_ascii_) {
Append_<true>(c); Append_<true>(c);
...@@ -123,10 +117,18 @@ class BasicJsonStringifier BASE_EMBEDDED { ...@@ -123,10 +117,18 @@ class BasicJsonStringifier BASE_EMBEDDED {
void SerializeString(Handle<String> object); void SerializeString(Handle<String> object);
template <typename SrcChar, typename DestChar>
INLINE(void SerializeStringUnchecked_(const SrcChar* src,
DestChar* dest,
int length));
template <bool is_ascii, typename Char> template <bool is_ascii, typename Char>
INLINE(void SerializeString_(Vector<const Char> vector, INLINE(void SerializeString_(Vector<const Char> vector,
Handle<String> string)); Handle<String> string));
template <typename Char>
INLINE(bool DoNotEscape(Char c));
template <typename Char> template <typename Char>
INLINE(Vector<const Char> GetCharVector(Handle<String> string)); INLINE(Vector<const Char> GetCharVector(Handle<String> string));
...@@ -152,12 +154,14 @@ class BasicJsonStringifier BASE_EMBEDDED { ...@@ -152,12 +154,14 @@ class BasicJsonStringifier BASE_EMBEDDED {
int part_length_; int part_length_;
bool is_ascii_; bool is_ascii_;
static const int kJsonQuotesCharactersPerEntry = 8; static const int kJsonEscapeTableEntrySize = 8;
static const char* const JsonQuotes; static const char* const JsonEscapeTable;
}; };
const char* const BasicJsonStringifier::JsonQuotes = // Translation table to escape ASCII characters.
// Table entries start at a multiple of 8 and are null-terminated.
const char* const BasicJsonStringifier::JsonEscapeTable =
"\\u0000\0 \\u0001\0 \\u0002\0 \\u0003\0 " "\\u0000\0 \\u0001\0 \\u0002\0 \\u0003\0 "
"\\u0004\0 \\u0005\0 \\u0006\0 \\u0007\0 " "\\u0004\0 \\u0005\0 \\u0006\0 \\u0007\0 "
"\\b\0 \\t\0 \\n\0 \\u000b\0 " "\\b\0 \\t\0 \\n\0 \\u000b\0 "
...@@ -235,31 +239,12 @@ void BasicJsonStringifier::Append_(Char c) { ...@@ -235,31 +239,12 @@ void BasicJsonStringifier::Append_(Char c) {
} }
template <bool is_ascii, typename Char>
void BasicJsonStringifier::AppendUnchecked_(Char c) {
if (is_ascii) {
SeqAsciiString::cast(*current_part_)->SeqAsciiStringSet(
current_index_++, c);
} else {
SeqTwoByteString::cast(*current_part_)->SeqTwoByteStringSet(
current_index_++, c);
}
ASSERT(current_index_ < part_length_);
}
template <bool is_ascii, typename Char> template <bool is_ascii, typename Char>
void BasicJsonStringifier::Append_(const Char* chars) { void BasicJsonStringifier::Append_(const Char* chars) {
for ( ; *chars != '\0'; chars++) Append_<is_ascii, Char>(*chars); for ( ; *chars != '\0'; chars++) Append_<is_ascii, Char>(*chars);
} }
template <bool is_ascii, typename Char>
void BasicJsonStringifier::AppendUnchecked_(const Char* chars) {
for ( ; *chars != '\0'; chars++) AppendUnchecked_<is_ascii, Char>(*chars);
}
Handle<Object> BasicJsonStringifier::GetProperty(Handle<JSObject> object, Handle<Object> BasicJsonStringifier::GetProperty(Handle<JSObject> object,
Handle<String> key) { Handle<String> key) {
LookupResult lookup(isolate_); LookupResult lookup(isolate_);
...@@ -579,34 +564,60 @@ void BasicJsonStringifier::ChangeEncoding() { ...@@ -579,34 +564,60 @@ void BasicJsonStringifier::ChangeEncoding() {
} }
template <typename SrcChar, typename DestChar>
void BasicJsonStringifier::SerializeStringUnchecked_(const SrcChar* src,
DestChar* dest,
int length) {
dest += current_index_;
DestChar* dest_start = dest;
*(dest++) = '"';
for (int i = 0; i < length; i++) {
SrcChar c = src[i];
if (DoNotEscape(c)) {
*(dest++) = c;
} else {
const char* chars = &JsonEscapeTable[c * kJsonEscapeTableEntrySize];
while (*chars != '\0') *(dest++) = *(chars++);
}
}
*(dest++) = '"';
current_index_ += dest - dest_start;
}
template <bool is_ascii, typename Char> template <bool is_ascii, typename Char>
void BasicJsonStringifier::SerializeString_(Vector<const Char> vector, void BasicJsonStringifier::SerializeString_(Vector<const Char> vector,
Handle<String> string) { Handle<String> string) {
int length = vector.length(); int length = vector.length();
if (current_index_ + (length << 3) < (part_length_ - 2)) { // We make a rough estimate to find out if the current string can be
AssertNoAllocation no_allocation_scope; // serialized without allocating a new string part. The worst case length of
AppendUnchecked_<is_ascii, char>('"'); // an escaped character is 6. Shifting left by 3 is a more pessimistic
for (int i = 0; i < length; i++) { // estimate than multiplying by 6, but faster to calculate.
Char c = vector[i]; static const int kEnclosingQuotesLength = 2;
if ((c >= '#' && c <= '~' && c != '\\') || if (current_index_ + (length << 3) + kEnclosingQuotesLength < part_length_) {
(!is_ascii && ((c & 0xFF80) != 0))) { if (is_ascii) {
AppendUnchecked_<is_ascii, Char>(c); SerializeStringUnchecked_(
vector.start(),
SeqAsciiString::cast(*current_part_)->GetChars(),
length);
} else { } else {
AppendUnchecked_<is_ascii, char>( SerializeStringUnchecked_(
&JsonQuotes[c * kJsonQuotesCharactersPerEntry]); vector.start(),
} SeqTwoByteString::cast(*current_part_)->GetChars(),
length);
} }
AppendUnchecked_<is_ascii, char>('"');
} else { } else {
Append_<is_ascii, char>('"'); Append_<is_ascii, char>('"');
String* string_location = *string; String* string_location = *string;
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
Char c = vector[i]; Char c = vector[i];
if ((c >= '#' && c <= '~' && c != '\\') || if (DoNotEscape(c)) {
(!is_ascii && ((c & 0xFF80) != 0))) {
Append_<is_ascii, Char>(c); Append_<is_ascii, Char>(c);
} else { } else {
Append_<is_ascii, char>(&JsonQuotes[c * kJsonQuotesCharactersPerEntry]); Append_<is_ascii, char>(
&JsonEscapeTable[c * kJsonEscapeTableEntrySize]);
} }
// If GC moved the string, we need to refresh the vector. // If GC moved the string, we need to refresh the vector.
if (*string != string_location) { if (*string != string_location) {
...@@ -619,6 +630,18 @@ void BasicJsonStringifier::SerializeString_(Vector<const Char> vector, ...@@ -619,6 +630,18 @@ void BasicJsonStringifier::SerializeString_(Vector<const Char> vector,
} }
template <>
bool BasicJsonStringifier::DoNotEscape(char c) {
return c >= '#' && c <= '~' && c != '\\';
}
template <>
bool BasicJsonStringifier::DoNotEscape(uc16 c) {
return (c >= 0x80) || (c >= '#' && c <= '~' && c != '\\');
}
template <> template <>
Vector<const char> BasicJsonStringifier::GetCharVector(Handle<String> string) { Vector<const char> BasicJsonStringifier::GetCharVector(Handle<String> string) {
String::FlatContent flat = string->GetFlatContent(); String::FlatContent flat = string->GetFlatContent();
......
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