Commit dd242e3f authored by sandholm@chromium.org's avatar sandholm@chromium.org

Optimize JSON stringify by allowing QuoteJSONString to prefix with a comma.

Review URL: http://codereview.chromium.org/6335004

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6337 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 762f9cf7
...@@ -193,14 +193,14 @@ function BasicSerializeArray(value, stack, builder) { ...@@ -193,14 +193,14 @@ function BasicSerializeArray(value, stack, builder) {
// First entry is a string. Remaining entries are likely to be strings too. // First entry is a string. Remaining entries are likely to be strings too.
builder.push(%QuoteJSONString(val)); builder.push(%QuoteJSONString(val));
for (var i = 1; i < len; i++) { for (var i = 1; i < len; i++) {
builder.push(",");
val = value[i]; val = value[i];
if (IS_STRING(val)) { if (IS_STRING(val)) {
builder.push(%QuoteJSONString(val)); builder.push(%QuoteJSONStringComma(val));
} else { } else {
builder.push(",");
var before = builder.length; var before = builder.length;
BasicJSONSerialize(i, value[i], stack, builder); BasicJSONSerialize(i, value[i], stack, builder);
if (before == builder.length) builder.push("null"); if (before == builder.length) builder[before - 1] = ",null";
} }
} }
} else if (IS_NUMBER(val)) { } else if (IS_NUMBER(val)) {
...@@ -216,7 +216,7 @@ function BasicSerializeArray(value, stack, builder) { ...@@ -216,7 +216,7 @@ function BasicSerializeArray(value, stack, builder) {
} else { } else {
var before = builder.length; var before = builder.length;
BasicJSONSerialize(i, value[i], stack, builder); BasicJSONSerialize(i, value[i], stack, builder);
if (before == builder.length) builder.push("null"); if (before == builder.length) builder[before - 1] = ",null";
} }
} }
} else { } else {
...@@ -228,7 +228,7 @@ function BasicSerializeArray(value, stack, builder) { ...@@ -228,7 +228,7 @@ function BasicSerializeArray(value, stack, builder) {
before = builder.length; before = builder.length;
val = value[i]; val = value[i];
BasicJSONSerialize(i, val, stack, builder); BasicJSONSerialize(i, val, stack, builder);
if (before == builder.length) builder.push("null"); if (before == builder.length) builder[before - 1] = ",null";
} }
} }
stack.pop(); stack.pop();
...@@ -241,9 +241,14 @@ function BasicSerializeObject(value, stack, builder) { ...@@ -241,9 +241,14 @@ function BasicSerializeObject(value, stack, builder) {
throw MakeTypeError('circular_structure', []); throw MakeTypeError('circular_structure', []);
} }
builder.push("{"); builder.push("{");
var first = true;
for (var p in value) { for (var p in value) {
if (%HasLocalProperty(value, p)) { if (%HasLocalProperty(value, p)) {
builder.push(%QuoteJSONString(p)); if (!first) {
builder.push(%QuoteJSONStringComma(p));
} else {
builder.push(%QuoteJSONString(p));
}
builder.push(":"); builder.push(":");
var before = builder.length; var before = builder.length;
BasicJSONSerialize(p, value[p], stack, builder); BasicJSONSerialize(p, value[p], stack, builder);
...@@ -251,16 +256,12 @@ function BasicSerializeObject(value, stack, builder) { ...@@ -251,16 +256,12 @@ function BasicSerializeObject(value, stack, builder) {
builder.pop(); builder.pop();
builder.pop(); builder.pop();
} else { } else {
builder.push(","); first = false;
} }
} }
} }
stack.pop(); stack.pop();
if (builder.pop() != ",") { builder.push("}");
builder.push("{}"); // Object has no own properties. Push "{" back on.
} else {
builder.push("}");
}
} }
......
...@@ -4621,12 +4621,12 @@ MaybeObject* AllocateRawString<SeqAsciiString>(int length) { ...@@ -4621,12 +4621,12 @@ MaybeObject* AllocateRawString<SeqAsciiString>(int length) {
} }
template <typename Char, typename StringType> template <typename Char, typename StringType, bool comma>
static MaybeObject* SlowQuoteJsonString(Vector<const Char> characters) { static MaybeObject* SlowQuoteJsonString(Vector<const Char> characters) {
int length = characters.length(); int length = characters.length();
const Char* read_cursor = characters.start(); const Char* read_cursor = characters.start();
const Char* end = read_cursor + length; const Char* end = read_cursor + length;
const int kSpaceForQuotes = 2; const int kSpaceForQuotes = 2 + (comma ? 1 :0);
int quoted_length = kSpaceForQuotes; int quoted_length = kSpaceForQuotes;
while (read_cursor < end) { while (read_cursor < end) {
Char c = *(read_cursor++); Char c = *(read_cursor++);
...@@ -4645,6 +4645,7 @@ static MaybeObject* SlowQuoteJsonString(Vector<const Char> characters) { ...@@ -4645,6 +4645,7 @@ static MaybeObject* SlowQuoteJsonString(Vector<const Char> characters) {
Char* write_cursor = reinterpret_cast<Char*>( Char* write_cursor = reinterpret_cast<Char*>(
new_string->address() + SeqAsciiString::kHeaderSize); new_string->address() + SeqAsciiString::kHeaderSize);
if (comma) *(write_cursor++) = ',';
*(write_cursor++) = '"'; *(write_cursor++) = '"';
read_cursor = characters.start(); read_cursor = characters.start();
...@@ -4666,14 +4667,14 @@ static MaybeObject* SlowQuoteJsonString(Vector<const Char> characters) { ...@@ -4666,14 +4667,14 @@ static MaybeObject* SlowQuoteJsonString(Vector<const Char> characters) {
} }
template <typename Char, typename StringType> template <typename Char, typename StringType, bool comma>
static MaybeObject* QuoteJsonString(Vector<const Char> characters) { static MaybeObject* QuoteJsonString(Vector<const Char> characters) {
int length = characters.length(); int length = characters.length();
Counters::quote_json_char_count.Increment(length); Counters::quote_json_char_count.Increment(length);
const int kSpaceForQuotes = 2; const int kSpaceForQuotes = 2 + (comma ? 1 :0);
int worst_case_length = length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes; int worst_case_length = length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
if (worst_case_length > kMaxGuaranteedNewSpaceString) { if (worst_case_length > kMaxGuaranteedNewSpaceString) {
return SlowQuoteJsonString<Char, StringType>(characters); return SlowQuoteJsonString<Char, StringType, comma>(characters);
} }
MaybeObject* new_alloc = AllocateRawString<StringType>(worst_case_length); MaybeObject* new_alloc = AllocateRawString<StringType>(worst_case_length);
...@@ -4686,7 +4687,7 @@ static MaybeObject* QuoteJsonString(Vector<const Char> characters) { ...@@ -4686,7 +4687,7 @@ static MaybeObject* QuoteJsonString(Vector<const Char> characters) {
// handle it being allocated in old space as may happen in the third // handle it being allocated in old space as may happen in the third
// attempt. See CALL_AND_RETRY in heap-inl.h and similar code in // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
// CEntryStub::GenerateCore. // CEntryStub::GenerateCore.
return SlowQuoteJsonString<Char, StringType>(characters); return SlowQuoteJsonString<Char, StringType, comma>(characters);
} }
StringType* new_string = StringType::cast(new_object); StringType* new_string = StringType::cast(new_object);
ASSERT(Heap::new_space()->Contains(new_string)); ASSERT(Heap::new_space()->Contains(new_string));
...@@ -4694,6 +4695,7 @@ static MaybeObject* QuoteJsonString(Vector<const Char> characters) { ...@@ -4694,6 +4695,7 @@ static MaybeObject* QuoteJsonString(Vector<const Char> characters) {
STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize); STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
Char* write_cursor = reinterpret_cast<Char*>( Char* write_cursor = reinterpret_cast<Char*>(
new_string->address() + SeqAsciiString::kHeaderSize); new_string->address() + SeqAsciiString::kHeaderSize);
if (comma) *(write_cursor++) = ',';
*(write_cursor++) = '"'; *(write_cursor++) = '"';
const Char* read_cursor = characters.start(); const Char* read_cursor = characters.start();
...@@ -4744,13 +4746,32 @@ static MaybeObject* Runtime_QuoteJSONString(Arguments args) { ...@@ -4744,13 +4746,32 @@ static MaybeObject* Runtime_QuoteJSONString(Arguments args) {
ASSERT(str->IsFlat()); ASSERT(str->IsFlat());
} }
if (str->IsTwoByteRepresentation()) { if (str->IsTwoByteRepresentation()) {
return QuoteJsonString<uc16, SeqTwoByteString>(str->ToUC16Vector()); return QuoteJsonString<uc16, SeqTwoByteString, false>(str->ToUC16Vector());
} else { } else {
return QuoteJsonString<char, SeqAsciiString>(str->ToAsciiVector()); return QuoteJsonString<char, SeqAsciiString, false>(str->ToAsciiVector());
} }
} }
static MaybeObject* Runtime_QuoteJSONStringComma(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, true>(str->ToUC16Vector());
} else {
return QuoteJsonString<char, SeqAsciiString, true>(str->ToAsciiVector());
}
}
static MaybeObject* Runtime_StringParseInt(Arguments args) { static MaybeObject* Runtime_StringParseInt(Arguments args) {
NoHandleAllocation ha; NoHandleAllocation ha;
......
...@@ -106,6 +106,7 @@ namespace internal { ...@@ -106,6 +106,7 @@ namespace internal {
F(URIEscape, 1, 1) \ F(URIEscape, 1, 1) \
F(URIUnescape, 1, 1) \ F(URIUnescape, 1, 1) \
F(QuoteJSONString, 1, 1) \ F(QuoteJSONString, 1, 1) \
F(QuoteJSONStringComma, 1, 1) \
\ \
F(NumberToString, 1, 1) \ F(NumberToString, 1, 1) \
F(NumberToStringSkipCache, 1, 1) \ F(NumberToStringSkipCache, 1, 1) \
......
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