Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(617)

Unified Diff: src/json-stringifier.h

Issue 11232002: Stress GC less by allocating exponentially growing string chunks in JSON.stringify. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 8 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | test/mjsunit/json.js » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/json-stringifier.h
diff --git a/src/json-stringifier.h b/src/json-stringifier.h
index f95e8c4f68eb0c935e0ba1477da15d83d62d0421..43edfd136022cdf1a42fc4905adcce9f7d6ff806 100644
--- a/src/json-stringifier.h
+++ b/src/json-stringifier.h
@@ -42,7 +42,9 @@ class BasicJsonStringifier BASE_EMBEDDED {
MaybeObject* Stringify(Handle<Object> object);
private:
- static const int kPartLength = 8 * 1024;
+ static const int kInitialPartLength = 32;
+ static const int kMaxPartLength = 16 * 1024;
+ static const int kPartLengthGrowthFactor = 2;
static const int kStackLimit = 8 * 1024;
enum Result { UNCHANGED, SUCCESS, BAILOUT, CIRCULAR, STACK_OVERFLOW };
@@ -130,12 +132,23 @@ class BasicJsonStringifier BASE_EMBEDDED {
INLINE(Result StackPush(Handle<Object> object));
INLINE(void StackPop());
+ INLINE(Handle<String> accumulator()) {
+ return Handle<String>(String::cast(accumulator_store_->value()));
+ }
+
+ INLINE(void set_accumulator(Handle<String> string)) {
+ return accumulator_store_->set_value(*string);
+ }
+
Isolate* isolate_;
- Handle<String> accumulator_;
+ // We use a value wrapper for the string accumulator to keep the
+ // (indirect) handle to it in the outermost handle scope.
+ Handle<JSValue> accumulator_store_;
Handle<String> current_part_;
Handle<String> tojson_symbol_;
Handle<JSArray> stack_;
int current_index_;
+ int part_length_;
bool is_ascii_;
static const int kJsonQuotesCharactersPerEntry = 8;
@@ -180,9 +193,11 @@ const char* const BasicJsonStringifier::JsonQuotes =
BasicJsonStringifier::BasicJsonStringifier(Isolate* isolate)
: isolate_(isolate), current_index_(0), is_ascii_(true) {
- accumulator_ = isolate_->factory()->empty_string();
+ accumulator_store_ = Handle<JSValue>::cast(
+ isolate_->factory()->ToObject(isolate_->factory()->empty_string()));
+ part_length_ = kInitialPartLength;
current_part_ =
- isolate_->factory()->NewRawAsciiString(kPartLength);
+ isolate_->factory()->NewRawAsciiString(kInitialPartLength);
tojson_symbol_ = isolate_->factory()->LookupAsciiSymbol("toJSON");
stack_ = isolate_->factory()->NewJSArray(8);
}
@@ -192,7 +207,7 @@ MaybeObject* BasicJsonStringifier::Stringify(Handle<Object> object) {
switch (Serialize(object)) {
case SUCCESS:
ShrinkCurrentPart();
- return *isolate_->factory()->NewConsString(accumulator_, current_part_);
+ return *isolate_->factory()->NewConsString(accumulator(), current_part_);
case UNCHANGED:
return isolate_->heap()->undefined_value();
case CIRCULAR:
@@ -215,7 +230,7 @@ void BasicJsonStringifier::Append_(Char c) {
SeqTwoByteString::cast(*current_part_)->SeqTwoByteStringSet(
current_index_++, c);
}
- if (current_index_ == kPartLength) Extend<is_ascii>();
+ if (current_index_ == part_length_) Extend<is_ascii>();
}
@@ -228,7 +243,7 @@ void BasicJsonStringifier::AppendUnchecked_(Char c) {
SeqTwoByteString::cast(*current_part_)->SeqTwoByteStringSet(
current_index_++, c);
}
- ASSERT(current_index_ < kPartLength);
+ ASSERT(current_index_ < part_length_);
}
@@ -403,6 +418,7 @@ BasicJsonStringifier::Result BasicJsonStringifier::SerializeDouble(
BasicJsonStringifier::Result BasicJsonStringifier::SerializeArray(
Handle<JSArray> object) {
+ HandleScope handle_scope(isolate_);
if (StackPush(object) == CIRCULAR) return CIRCULAR;
int length = Smi::cast(object->length())->value();
Append('[');
@@ -460,12 +476,14 @@ BasicJsonStringifier::Result BasicJsonStringifier::SerializeArray(
}
Append(']');
StackPop();
+ current_part_ = handle_scope.CloseAndEscape(current_part_);
return SUCCESS;
}
BasicJsonStringifier::Result BasicJsonStringifier::SerializeObject(
Handle<JSObject> object) {
+ HandleScope handle_scope(isolate_);
Result stack_push = StackPush(object);
if (stack_push != SUCCESS) return stack_push;
if (object->IsJSGlobalProxy()) return BAILOUT;
@@ -502,12 +520,13 @@ BasicJsonStringifier::Result BasicJsonStringifier::SerializeObject(
}
Append('}');
StackPop();
+ current_part_ = handle_scope.CloseAndEscape(current_part_);
return SUCCESS;
}
void BasicJsonStringifier::ShrinkCurrentPart() {
- ASSERT(current_index_ < kPartLength);
+ ASSERT(current_index_ < part_length_);
if (current_index_ == 0) {
current_part_ = isolate_->factory()->empty_string();
return;
@@ -515,10 +534,10 @@ void BasicJsonStringifier::ShrinkCurrentPart() {
int string_size, allocated_string_size;
if (is_ascii_) {
- allocated_string_size = SeqAsciiString::SizeFor(kPartLength);
+ allocated_string_size = SeqAsciiString::SizeFor(part_length_);
string_size = SeqAsciiString::SizeFor(current_index_);
} else {
- allocated_string_size = SeqTwoByteString::SizeFor(kPartLength);
+ allocated_string_size = SeqTwoByteString::SizeFor(part_length_);
string_size = SeqTwoByteString::SizeFor(current_index_);
}
@@ -538,14 +557,17 @@ void BasicJsonStringifier::ShrinkCurrentPart() {
template <bool is_ascii>
void BasicJsonStringifier::Extend() {
- accumulator_ =
- isolate_->factory()->NewConsString(accumulator_, current_part_);
+ set_accumulator(
+ isolate_->factory()->NewConsString(accumulator(), current_part_));
+ if (part_length_ <= kMaxPartLength / kPartLengthGrowthFactor) {
+ part_length_ *= kPartLengthGrowthFactor;
+ }
if (is_ascii) {
current_part_ =
- isolate_->factory()->NewRawAsciiString(kPartLength);
+ isolate_->factory()->NewRawAsciiString(part_length_);
} else {
current_part_ =
- isolate_->factory()->NewRawTwoByteString(kPartLength);
+ isolate_->factory()->NewRawTwoByteString(part_length_);
}
current_index_ = 0;
}
@@ -553,10 +575,10 @@ void BasicJsonStringifier::Extend() {
void BasicJsonStringifier::ChangeEncoding() {
ShrinkCurrentPart();
- accumulator_ = isolate_->factory()->NewConsString(accumulator_,
- current_part_);
+ set_accumulator(
+ isolate_->factory()->NewConsString(accumulator(), current_part_));
current_part_ =
- isolate_->factory()->NewRawTwoByteString(kPartLength);
+ isolate_->factory()->NewRawTwoByteString(part_length_);
current_index_ = 0;
is_ascii_ = false;
}
@@ -565,7 +587,7 @@ void BasicJsonStringifier::ChangeEncoding() {
template <bool is_ascii, typename Char>
void BasicJsonStringifier::SerializeString_(Vector<const Char> vector) {
int length = vector.length();
- if (current_index_ + (length << 3) < (kPartLength - 2)) {
+ if (current_index_ + (length << 3) < (part_length_ - 2)) {
AppendUnchecked_<is_ascii, char>('"');
for (int i = 0; i < length; i++) {
Char c = vector[i];
« no previous file with comments | « no previous file | test/mjsunit/json.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698