Commit a5531459 authored by yangguo@chromium.org's avatar yangguo@chromium.org

Abstract string building in JSON-stringifier into IncrementalStringBuilder.

R=ishell@chromium.org

Review URL: https://codereview.chromium.org/713223002

Cr-Commit-Position: refs/heads/master@{#25276}
git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@25276 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 19b98d7b
...@@ -877,7 +877,6 @@ source_set("v8_base") { ...@@ -877,7 +877,6 @@ source_set("v8_base") {
"src/runtime/runtime-utils.h", "src/runtime/runtime-utils.h",
"src/runtime/runtime.cc", "src/runtime/runtime.cc",
"src/runtime/runtime.h", "src/runtime/runtime.h",
"src/runtime/string-builder.h",
"src/safepoint-table.cc", "src/safepoint-table.cc",
"src/safepoint-table.h", "src/safepoint-table.h",
"src/sampler.cc", "src/sampler.cc",
...@@ -897,6 +896,8 @@ source_set("v8_base") { ...@@ -897,6 +896,8 @@ source_set("v8_base") {
"src/snapshot-source-sink.cc", "src/snapshot-source-sink.cc",
"src/snapshot-source-sink.h", "src/snapshot-source-sink.h",
"src/snapshot.h", "src/snapshot.h",
"src/string-builder.h",
"src/string-builder.c",
"src/string-search.cc", "src/string-search.cc",
"src/string-search.h", "src/string-search.h",
"src/string-stream.cc", "src/string-stream.cc",
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "src/v8.h" #include "src/v8.h"
#include "src/conversions.h" #include "src/conversions.h"
#include "src/string-builder.h"
#include "src/utils.h" #include "src/utils.h"
namespace v8 { namespace v8 {
...@@ -24,42 +25,8 @@ class BasicJsonStringifier BASE_EMBEDDED { ...@@ -24,42 +25,8 @@ class BasicJsonStringifier BASE_EMBEDDED {
Handle<String> object)); Handle<String> object));
private: private:
static const int kInitialPartLength = 32;
static const int kMaxPartLength = 16 * 1024;
static const int kPartLengthGrowthFactor = 2;
enum Result { UNCHANGED, SUCCESS, EXCEPTION }; enum Result { UNCHANGED, SUCCESS, EXCEPTION };
void Accumulate();
void Extend();
void ChangeEncoding();
INLINE(void ShrinkCurrentPart());
template <bool is_one_byte, typename Char>
INLINE(void Append_(Char c));
template <bool is_one_byte, typename Char>
INLINE(void Append_(const Char* chars));
INLINE(void Append(uint8_t c)) {
if (is_one_byte_) {
Append_<true>(c);
} else {
Append_<false>(c);
}
}
INLINE(void AppendOneByte(const char* chars)) {
if (is_one_byte_) {
Append_<true>(reinterpret_cast<const uint8_t*>(chars));
} else {
Append_<false>(reinterpret_cast<const uint8_t*>(chars));
}
}
MUST_USE_RESULT MaybeHandle<Object> ApplyToJsonFunction( MUST_USE_RESULT MaybeHandle<Object> ApplyToJsonFunction(
Handle<Object> object, Handle<Object> object,
Handle<Object> key); Handle<Object> key);
...@@ -69,14 +36,9 @@ class BasicJsonStringifier BASE_EMBEDDED { ...@@ -69,14 +36,9 @@ class BasicJsonStringifier BASE_EMBEDDED {
bool deferred_comma, bool deferred_comma,
bool deferred_key); bool deferred_key);
template <typename ResultType, typename Char>
INLINE(static Handle<String> StringifyString_(Isolate* isolate,
Vector<Char> vector,
Handle<String> result));
// Entry point to serialize the object. // Entry point to serialize the object.
INLINE(Result SerializeObject(Handle<Object> obj)) { INLINE(Result SerializeObject(Handle<Object> obj)) {
return Serialize_<false>(obj, false, factory_->empty_string()); return Serialize_<false>(obj, false, factory()->empty_string());
} }
// Serialize an array element. // Serialize an array element.
...@@ -103,9 +65,9 @@ class BasicJsonStringifier BASE_EMBEDDED { ...@@ -103,9 +65,9 @@ class BasicJsonStringifier BASE_EMBEDDED {
Result Serialize_(Handle<Object> object, bool comma, Handle<Object> key); Result Serialize_(Handle<Object> object, bool comma, Handle<Object> key);
void SerializeDeferredKey(bool deferred_comma, Handle<Object> deferred_key) { void SerializeDeferredKey(bool deferred_comma, Handle<Object> deferred_key) {
if (deferred_comma) Append(','); if (deferred_comma) builder_.AppendCharacter(',');
SerializeString(Handle<String>::cast(deferred_key)); SerializeString(Handle<String>::cast(deferred_key));
Append(':'); builder_.AppendCharacter(':');
} }
Result SerializeSmi(Smi* object); Result SerializeSmi(Smi* object);
...@@ -125,11 +87,11 @@ class BasicJsonStringifier BASE_EMBEDDED { ...@@ -125,11 +87,11 @@ class BasicJsonStringifier BASE_EMBEDDED {
void SerializeString(Handle<String> object); void SerializeString(Handle<String> object);
template <typename SrcChar, typename DestChar> template <typename SrcChar, typename DestChar>
INLINE(static int SerializeStringUnchecked_(const SrcChar* src, INLINE(static void SerializeStringUnchecked_(
DestChar* dest, Vector<const SrcChar> src,
int length)); IncrementalStringBuilder::NoExtend<DestChar>* dest));
template <bool is_one_byte, typename Char> template <typename SrcChar, typename DestChar>
INLINE(void SerializeString_(Handle<String> string)); INLINE(void SerializeString_(Handle<String> string));
template <typename Char> template <typename Char>
...@@ -141,26 +103,12 @@ class BasicJsonStringifier BASE_EMBEDDED { ...@@ -141,26 +103,12 @@ class BasicJsonStringifier BASE_EMBEDDED {
Result StackPush(Handle<Object> object); Result StackPush(Handle<Object> object);
void StackPop(); void StackPop();
INLINE(Handle<String> accumulator()) { Factory* factory() { return isolate_->factory(); }
return Handle<String>(String::cast(accumulator_store_->value()), isolate_);
}
INLINE(void set_accumulator(Handle<String> string)) {
return accumulator_store_->set_value(*string);
}
Isolate* isolate_; Isolate* isolate_;
Factory* factory_; IncrementalStringBuilder builder_;
// 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_string_; Handle<String> tojson_string_;
Handle<JSArray> stack_; Handle<JSArray> stack_;
int current_index_;
int part_length_;
bool is_one_byte_;
bool overflowed_;
static const int kJsonEscapeTableEntrySize = 8; static const int kJsonEscapeTableEntrySize = 8;
static const char* const JsonEscapeTable; static const char* const JsonEscapeTable;
...@@ -237,31 +185,16 @@ const char* const BasicJsonStringifier::JsonEscapeTable = ...@@ -237,31 +185,16 @@ const char* const BasicJsonStringifier::JsonEscapeTable =
BasicJsonStringifier::BasicJsonStringifier(Isolate* isolate) BasicJsonStringifier::BasicJsonStringifier(Isolate* isolate)
: isolate_(isolate), : isolate_(isolate), builder_(isolate) {
current_index_(0), tojson_string_ = factory()->toJSON_string();
is_one_byte_(true), stack_ = factory()->NewJSArray(8);
overflowed_(false) {
factory_ = isolate_->factory();
accumulator_store_ = Handle<JSValue>::cast(
Object::ToObject(isolate, factory_->empty_string()).ToHandleChecked());
part_length_ = kInitialPartLength;
current_part_ = factory_->NewRawOneByteString(part_length_).ToHandleChecked();
tojson_string_ = factory_->toJSON_string();
stack_ = factory_->NewJSArray(8);
} }
MaybeHandle<Object> BasicJsonStringifier::Stringify(Handle<Object> object) { MaybeHandle<Object> BasicJsonStringifier::Stringify(Handle<Object> object) {
Result result = SerializeObject(object); Result result = SerializeObject(object);
if (result == UNCHANGED) return isolate_->factory()->undefined_value(); if (result == UNCHANGED) return factory()->undefined_value();
if (result == SUCCESS) { if (result == SUCCESS) return builder_.Finish();
ShrinkCurrentPart();
Accumulate();
if (overflowed_) {
THROW_NEW_ERROR(isolate_, NewInvalidStringLengthError(), Object);
}
return accumulator();
}
DCHECK(result == EXCEPTION); DCHECK(result == EXCEPTION);
return MaybeHandle<Object>(); return MaybeHandle<Object>();
} }
...@@ -281,58 +214,29 @@ MaybeHandle<Object> BasicJsonStringifier::StringifyString( ...@@ -281,58 +214,29 @@ MaybeHandle<Object> BasicJsonStringifier::StringifyString(
object = String::Flatten(object); object = String::Flatten(object);
DCHECK(object->IsFlat()); DCHECK(object->IsFlat());
Handle<SeqString> result;
if (object->IsOneByteRepresentationUnderneath()) { if (object->IsOneByteRepresentationUnderneath()) {
Handle<String> result = isolate->factory()->NewRawOneByteString( result = isolate->factory()
worst_case_length).ToHandleChecked(); ->NewRawOneByteString(worst_case_length)
DisallowHeapAllocation no_gc; .ToHandleChecked();
return StringifyString_<SeqOneByteString>( IncrementalStringBuilder::NoExtendString<uint8_t> no_extend(
isolate, result, worst_case_length);
object->GetFlatContent().ToOneByteVector(), no_extend.Append('\"');
result); SerializeStringUnchecked_(object->GetFlatContent().ToOneByteVector(),
&no_extend);
no_extend.Append('\"');
} else { } else {
Handle<String> result = isolate->factory()->NewRawTwoByteString( result = isolate->factory()
worst_case_length).ToHandleChecked(); ->NewRawTwoByteString(worst_case_length)
DisallowHeapAllocation no_gc; .ToHandleChecked();
return StringifyString_<SeqTwoByteString>( IncrementalStringBuilder::NoExtendString<uc16> no_extend(result,
isolate, worst_case_length);
object->GetFlatContent().ToUC16Vector(), no_extend.Append('\"');
result); SerializeStringUnchecked_(object->GetFlatContent().ToUC16Vector(),
&no_extend);
no_extend.Append('\"');
} }
} return result;
template <typename ResultType, typename Char>
Handle<String> BasicJsonStringifier::StringifyString_(Isolate* isolate,
Vector<Char> vector,
Handle<String> result) {
DisallowHeapAllocation no_gc;
int final_size = 0;
ResultType* dest = ResultType::cast(*result);
dest->Set(final_size++, '\"');
final_size += SerializeStringUnchecked_(vector.start(),
dest->GetChars() + 1,
vector.length());
dest->Set(final_size++, '\"');
return SeqString::Truncate(Handle<SeqString>::cast(result), final_size);
}
template <bool is_one_byte, typename Char>
void BasicJsonStringifier::Append_(Char c) {
if (is_one_byte) {
SeqOneByteString::cast(*current_part_)->SeqOneByteStringSet(
current_index_++, c);
} else {
SeqTwoByteString::cast(*current_part_)->SeqTwoByteStringSet(
current_index_++, c);
}
if (current_index_ == part_length_) Extend();
}
template <bool is_one_byte, typename Char>
void BasicJsonStringifier::Append_(const Char* chars) {
for (; *chars != '\0'; chars++) Append_<is_one_byte, Char>(*chars);
} }
...@@ -345,7 +249,7 @@ MaybeHandle<Object> BasicJsonStringifier::ApplyToJsonFunction( ...@@ -345,7 +249,7 @@ MaybeHandle<Object> BasicJsonStringifier::ApplyToJsonFunction(
if (!fun->IsJSFunction()) return object; if (!fun->IsJSFunction()) return object;
// Call toJSON function. // Call toJSON function.
if (key->IsSmi()) key = factory_->NumberToString(key); if (key->IsSmi()) key = factory()->NumberToString(key);
Handle<Object> argv[] = { key }; Handle<Object> argv[] = { key };
HandleScope scope(isolate_); HandleScope scope(isolate_);
ASSIGN_RETURN_ON_EXCEPTION( ASSIGN_RETURN_ON_EXCEPTION(
...@@ -372,7 +276,7 @@ BasicJsonStringifier::Result BasicJsonStringifier::StackPush( ...@@ -372,7 +276,7 @@ BasicJsonStringifier::Result BasicJsonStringifier::StackPush(
if (elements->get(i) == *object) { if (elements->get(i) == *object) {
AllowHeapAllocation allow_to_return_error; AllowHeapAllocation allow_to_return_error;
Handle<Object> error; Handle<Object> error;
MaybeHandle<Object> maybe_error = factory_->NewTypeError( MaybeHandle<Object> maybe_error = factory()->NewTypeError(
"circular_structure", HandleVector<Object>(NULL, 0)); "circular_structure", HandleVector<Object>(NULL, 0));
if (maybe_error.ToHandle(&error)) isolate_->Throw(*error); if (maybe_error.ToHandle(&error)) isolate_->Throw(*error);
return EXCEPTION; return EXCEPTION;
...@@ -416,15 +320,15 @@ BasicJsonStringifier::Result BasicJsonStringifier::Serialize_( ...@@ -416,15 +320,15 @@ BasicJsonStringifier::Result BasicJsonStringifier::Serialize_(
switch (Oddball::cast(*object)->kind()) { switch (Oddball::cast(*object)->kind()) {
case Oddball::kFalse: case Oddball::kFalse:
if (deferred_string_key) SerializeDeferredKey(comma, key); if (deferred_string_key) SerializeDeferredKey(comma, key);
AppendOneByte("false"); builder_.AppendCString("false");
return SUCCESS; return SUCCESS;
case Oddball::kTrue: case Oddball::kTrue:
if (deferred_string_key) SerializeDeferredKey(comma, key); if (deferred_string_key) SerializeDeferredKey(comma, key);
AppendOneByte("true"); builder_.AppendCString("true");
return SUCCESS; return SUCCESS;
case Oddball::kNull: case Oddball::kNull:
if (deferred_string_key) SerializeDeferredKey(comma, key); if (deferred_string_key) SerializeDeferredKey(comma, key);
AppendOneByte("null"); builder_.AppendCString("null");
return SUCCESS; return SUCCESS;
default: default:
return UNCHANGED; return UNCHANGED;
...@@ -472,23 +376,11 @@ BasicJsonStringifier::Result BasicJsonStringifier::SerializeGeneric( ...@@ -472,23 +376,11 @@ BasicJsonStringifier::Result BasicJsonStringifier::SerializeGeneric(
EXCEPTION); EXCEPTION);
if (result->IsUndefined()) return UNCHANGED; if (result->IsUndefined()) return UNCHANGED;
if (deferred_key) { if (deferred_key) {
if (key->IsSmi()) key = factory_->NumberToString(key); if (key->IsSmi()) key = factory()->NumberToString(key);
SerializeDeferredKey(deferred_comma, key); SerializeDeferredKey(deferred_comma, key);
} }
Handle<String> result_string = Handle<String>::cast(result); builder_.AppendString(Handle<String>::cast(result));
// Shrink current part, attach it to the accumulator, also attach the result
// string to the accumulator, and allocate a new part.
ShrinkCurrentPart(); // Shrink.
part_length_ = kInitialPartLength; // Allocate conservatively.
Extend(); // Attach current part and allocate new part.
// Attach result string to the accumulator.
Handle<String> cons;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate_, cons,
factory_->NewConsString(accumulator(), result_string),
EXCEPTION);
set_accumulator(cons);
return SUCCESS; return SUCCESS;
} }
...@@ -511,7 +403,7 @@ BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSValue( ...@@ -511,7 +403,7 @@ BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSValue(
DCHECK(class_name == isolate_->heap()->Boolean_string()); DCHECK(class_name == isolate_->heap()->Boolean_string());
Object* value = JSValue::cast(*object)->value(); Object* value = JSValue::cast(*object)->value();
DCHECK(value->IsBoolean()); DCHECK(value->IsBoolean());
AppendOneByte(value->IsTrue() ? "true" : "false"); builder_.AppendCString(value->IsTrue() ? "true" : "false");
} }
return SUCCESS; return SUCCESS;
} }
...@@ -521,7 +413,7 @@ BasicJsonStringifier::Result BasicJsonStringifier::SerializeSmi(Smi* object) { ...@@ -521,7 +413,7 @@ BasicJsonStringifier::Result BasicJsonStringifier::SerializeSmi(Smi* object) {
static const int kBufferSize = 100; static const int kBufferSize = 100;
char chars[kBufferSize]; char chars[kBufferSize];
Vector<char> buffer(chars, kBufferSize); Vector<char> buffer(chars, kBufferSize);
AppendOneByte(IntToCString(object->value(), buffer)); builder_.AppendCString(IntToCString(object->value(), buffer));
return SUCCESS; return SUCCESS;
} }
...@@ -529,13 +421,13 @@ BasicJsonStringifier::Result BasicJsonStringifier::SerializeSmi(Smi* object) { ...@@ -529,13 +421,13 @@ BasicJsonStringifier::Result BasicJsonStringifier::SerializeSmi(Smi* object) {
BasicJsonStringifier::Result BasicJsonStringifier::SerializeDouble( BasicJsonStringifier::Result BasicJsonStringifier::SerializeDouble(
double number) { double number) {
if (std::isinf(number) || std::isnan(number)) { if (std::isinf(number) || std::isnan(number)) {
AppendOneByte("null"); builder_.AppendCString("null");
return SUCCESS; return SUCCESS;
} }
static const int kBufferSize = 100; static const int kBufferSize = 100;
char chars[kBufferSize]; char chars[kBufferSize];
Vector<char> buffer(chars, kBufferSize); Vector<char> buffer(chars, kBufferSize);
AppendOneByte(DoubleToCString(number, buffer)); builder_.AppendCString(DoubleToCString(number, buffer));
return SUCCESS; return SUCCESS;
} }
...@@ -547,13 +439,13 @@ BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSArray( ...@@ -547,13 +439,13 @@ BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSArray(
if (stack_push != SUCCESS) return stack_push; if (stack_push != SUCCESS) return stack_push;
uint32_t length = 0; uint32_t length = 0;
CHECK(object->length()->ToArrayIndex(&length)); CHECK(object->length()->ToArrayIndex(&length));
Append('['); builder_.AppendCharacter('[');
switch (object->GetElementsKind()) { switch (object->GetElementsKind()) {
case FAST_SMI_ELEMENTS: { case FAST_SMI_ELEMENTS: {
Handle<FixedArray> elements( Handle<FixedArray> elements(
FixedArray::cast(object->elements()), isolate_); FixedArray::cast(object->elements()), isolate_);
for (uint32_t i = 0; i < length; i++) { for (uint32_t i = 0; i < length; i++) {
if (i > 0) Append(','); if (i > 0) builder_.AppendCharacter(',');
SerializeSmi(Smi::cast(elements->get(i))); SerializeSmi(Smi::cast(elements->get(i)));
} }
break; break;
...@@ -564,7 +456,7 @@ BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSArray( ...@@ -564,7 +456,7 @@ BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSArray(
Handle<FixedDoubleArray> elements( Handle<FixedDoubleArray> elements(
FixedDoubleArray::cast(object->elements()), isolate_); FixedDoubleArray::cast(object->elements()), isolate_);
for (uint32_t i = 0; i < length; i++) { for (uint32_t i = 0; i < length; i++) {
if (i > 0) Append(','); if (i > 0) builder_.AppendCharacter(',');
SerializeDouble(elements->get_scalar(i)); SerializeDouble(elements->get_scalar(i));
} }
break; break;
...@@ -573,14 +465,14 @@ BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSArray( ...@@ -573,14 +465,14 @@ BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSArray(
Handle<FixedArray> elements( Handle<FixedArray> elements(
FixedArray::cast(object->elements()), isolate_); FixedArray::cast(object->elements()), isolate_);
for (uint32_t i = 0; i < length; i++) { for (uint32_t i = 0; i < length; i++) {
if (i > 0) Append(','); if (i > 0) builder_.AppendCharacter(',');
Result result = Result result =
SerializeElement(isolate_, SerializeElement(isolate_,
Handle<Object>(elements->get(i), isolate_), Handle<Object>(elements->get(i), isolate_),
i); i);
if (result == SUCCESS) continue; if (result == SUCCESS) continue;
if (result == UNCHANGED) { if (result == UNCHANGED) {
AppendOneByte("null"); builder_.AppendCString("null");
} else { } else {
return result; return result;
} }
...@@ -596,9 +488,8 @@ BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSArray( ...@@ -596,9 +488,8 @@ BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSArray(
break; break;
} }
} }
Append(']'); builder_.AppendCharacter(']');
StackPop(); StackPop();
current_part_ = handle_scope.CloseAndEscape(current_part_);
return SUCCESS; return SUCCESS;
} }
...@@ -606,19 +497,19 @@ BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSArray( ...@@ -606,19 +497,19 @@ BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSArray(
BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSArraySlow( BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSArraySlow(
Handle<JSArray> object, uint32_t length) { Handle<JSArray> object, uint32_t length) {
for (uint32_t i = 0; i < length; i++) { for (uint32_t i = 0; i < length; i++) {
if (i > 0) Append(','); if (i > 0) builder_.AppendCharacter(',');
Handle<Object> element; Handle<Object> element;
ASSIGN_RETURN_ON_EXCEPTION_VALUE( ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate_, element, isolate_, element,
Object::GetElement(isolate_, object, i), Object::GetElement(isolate_, object, i),
EXCEPTION); EXCEPTION);
if (element->IsUndefined()) { if (element->IsUndefined()) {
AppendOneByte("null"); builder_.AppendCString("null");
} else { } else {
Result result = SerializeElement(isolate_, element, i); Result result = SerializeElement(isolate_, element, i);
if (result == SUCCESS) continue; if (result == SUCCESS) continue;
if (result == UNCHANGED) { if (result == UNCHANGED) {
AppendOneByte("null"); builder_.AppendCString("null");
} else { } else {
return result; return result;
} }
...@@ -635,7 +526,7 @@ BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSObject( ...@@ -635,7 +526,7 @@ BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSObject(
if (stack_push != SUCCESS) return stack_push; if (stack_push != SUCCESS) return stack_push;
DCHECK(!object->IsJSGlobalProxy() && !object->IsGlobalObject()); DCHECK(!object->IsJSGlobalProxy() && !object->IsGlobalObject());
Append('{'); builder_.AppendCharacter('{');
bool comma = false; bool comma = false;
if (object->HasFastProperties() && if (object->HasFastProperties() &&
...@@ -687,7 +578,7 @@ BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSObject( ...@@ -687,7 +578,7 @@ BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSObject(
maybe_property = Object::GetPropertyOrElement(object, key_handle); maybe_property = Object::GetPropertyOrElement(object, key_handle);
} else { } else {
DCHECK(key->IsNumber()); DCHECK(key->IsNumber());
key_handle = factory_->NumberToString(Handle<Object>(key, isolate_)); key_handle = factory()->NumberToString(Handle<Object>(key, isolate_));
uint32_t index; uint32_t index;
if (key->IsSmi()) { if (key->IsSmi()) {
maybe_property = Object::GetElement( maybe_property = Object::GetElement(
...@@ -707,130 +598,67 @@ BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSObject( ...@@ -707,130 +598,67 @@ BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSObject(
} }
} }
Append('}'); builder_.AppendCharacter('}');
StackPop(); StackPop();
current_part_ = handle_scope.CloseAndEscape(current_part_);
return SUCCESS; return SUCCESS;
} }
void BasicJsonStringifier::ShrinkCurrentPart() {
DCHECK(current_index_ < part_length_);
current_part_ = SeqString::Truncate(Handle<SeqString>::cast(current_part_),
current_index_);
}
void BasicJsonStringifier::Accumulate() {
if (accumulator()->length() + current_part_->length() > String::kMaxLength) {
// Screw it. Simply set the flag and carry on. Throw exception at the end.
set_accumulator(factory_->empty_string());
overflowed_ = true;
} else {
set_accumulator(factory_->NewConsString(accumulator(),
current_part_).ToHandleChecked());
}
}
void BasicJsonStringifier::Extend() {
Accumulate();
if (part_length_ <= kMaxPartLength / kPartLengthGrowthFactor) {
part_length_ *= kPartLengthGrowthFactor;
}
if (is_one_byte_) {
current_part_ =
factory_->NewRawOneByteString(part_length_).ToHandleChecked();
} else {
current_part_ =
factory_->NewRawTwoByteString(part_length_).ToHandleChecked();
}
DCHECK(!current_part_.is_null());
current_index_ = 0;
}
void BasicJsonStringifier::ChangeEncoding() {
ShrinkCurrentPart();
Accumulate();
current_part_ =
factory_->NewRawTwoByteString(part_length_).ToHandleChecked();
DCHECK(!current_part_.is_null());
current_index_ = 0;
is_one_byte_ = false;
}
template <typename SrcChar, typename DestChar> template <typename SrcChar, typename DestChar>
int BasicJsonStringifier::SerializeStringUnchecked_(const SrcChar* src, void BasicJsonStringifier::SerializeStringUnchecked_(
DestChar* dest, Vector<const SrcChar> src,
int length) { IncrementalStringBuilder::NoExtend<DestChar>* dest) {
DestChar* dest_start = dest;
// Assert that uc16 character is not truncated down to 8 bit. // Assert that uc16 character is not truncated down to 8 bit.
// The <uc16, char> version of this method must not be called. // The <uc16, char> version of this method must not be called.
DCHECK(sizeof(*dest) >= sizeof(*src)); DCHECK(sizeof(DestChar) >= sizeof(SrcChar));
for (int i = 0; i < length; i++) { for (int i = 0; i < src.length(); i++) {
SrcChar c = src[i]; SrcChar c = src[i];
if (DoNotEscape(c)) { if (DoNotEscape(c)) {
*(dest++) = static_cast<DestChar>(c); dest->Append(c);
} else { } else {
const uint8_t* chars = reinterpret_cast<const uint8_t*>( dest->AppendCString(&JsonEscapeTable[c * kJsonEscapeTableEntrySize]);
&JsonEscapeTable[c * kJsonEscapeTableEntrySize]);
while (*chars != '\0') *(dest++) = *(chars++);
} }
} }
return static_cast<int>(dest - dest_start);
} }
template <bool is_one_byte, typename Char> template <typename SrcChar, typename DestChar>
void BasicJsonStringifier::SerializeString_(Handle<String> string) { void BasicJsonStringifier::SerializeString_(Handle<String> string) {
int length = string->length(); int length = string->length();
Append_<is_one_byte, char>('"'); builder_.Append<uint8_t, DestChar>('"');
// We make a rough estimate to find out if the current string can be // We make a rough estimate to find out if the current string can be
// serialized without allocating a new string part. The worst case length of // serialized without allocating a new string part. The worst case length of
// an escaped character is 6. Shifting the remainin string length right by 3 // an escaped character is 6. Shifting the remainin string length right by 3
// is a more pessimistic estimate, but faster to calculate. // is a more pessimistic estimate, but faster to calculate.
int worst_case_length = length << 3;
if (((part_length_ - current_index_) >> 3) > length) { if (builder_.CurrentPartCanFit(worst_case_length)) {
DisallowHeapAllocation no_gc; DisallowHeapAllocation no_gc;
Vector<const Char> vector = GetCharVector<Char>(string); Vector<const SrcChar> vector = GetCharVector<SrcChar>(string);
if (is_one_byte) { IncrementalStringBuilder::NoExtendBuilder<DestChar> no_extend(
current_index_ += SerializeStringUnchecked_( &builder_, worst_case_length);
vector.start(), SerializeStringUnchecked_(vector, &no_extend);
SeqOneByteString::cast(*current_part_)->GetChars() + current_index_,
length);
} else {
current_index_ += SerializeStringUnchecked_(
vector.start(),
SeqTwoByteString::cast(*current_part_)->GetChars() + current_index_,
length);
}
} else { } else {
String* string_location = NULL; String* string_location = NULL;
Vector<const Char> vector(NULL, 0); Vector<const SrcChar> vector(NULL, 0);
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
// 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) {
DisallowHeapAllocation no_gc; DisallowHeapAllocation no_gc;
// This does not actually prevent the string from being relocated later. // This does not actually prevent the string from being relocated later.
vector = GetCharVector<Char>(string); vector = GetCharVector<SrcChar>(string);
string_location = *string; string_location = *string;
} }
Char c = vector[i]; SrcChar c = vector[i];
if (DoNotEscape(c)) { if (DoNotEscape(c)) {
Append_<is_one_byte, Char>(c); builder_.Append<SrcChar, DestChar>(c);
} else { } else {
Append_<is_one_byte, uint8_t>(reinterpret_cast<const uint8_t*>( builder_.AppendCString(&JsonEscapeTable[c * kJsonEscapeTableEntrySize]);
&JsonEscapeTable[c * kJsonEscapeTableEntrySize]));
} }
} }
} }
Append_<is_one_byte, uint8_t>('"'); builder_.Append<uint8_t, DestChar>('"');
} }
...@@ -865,18 +693,18 @@ Vector<const uc16> BasicJsonStringifier::GetCharVector(Handle<String> string) { ...@@ -865,18 +693,18 @@ Vector<const uc16> BasicJsonStringifier::GetCharVector(Handle<String> string) {
void BasicJsonStringifier::SerializeString(Handle<String> object) { void BasicJsonStringifier::SerializeString(Handle<String> object) {
object = String::Flatten(object); object = String::Flatten(object);
if (is_one_byte_) { if (builder_.CurrentEncoding() == String::ONE_BYTE_ENCODING) {
if (object->IsOneByteRepresentationUnderneath()) { if (object->IsOneByteRepresentationUnderneath()) {
SerializeString_<true, uint8_t>(object); SerializeString_<uint8_t, uint8_t>(object);
} else { } else {
ChangeEncoding(); builder_.ChangeEncoding();
SerializeString(object); SerializeString(object);
} }
} else { } else {
if (object->IsOneByteRepresentationUnderneath()) { if (object->IsOneByteRepresentationUnderneath()) {
SerializeString_<false, uint8_t>(object); SerializeString_<uint8_t, uc16>(object);
} else { } else {
SerializeString_<false, uc16>(object); SerializeString_<uc16, uc16>(object);
} }
} }
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
#include "src/jsregexp-inl.h" #include "src/jsregexp-inl.h"
#include "src/jsregexp.h" #include "src/jsregexp.h"
#include "src/runtime/runtime-utils.h" #include "src/runtime/runtime-utils.h"
#include "src/runtime/string-builder.h" #include "src/string-builder.h"
#include "src/string-search.h" #include "src/string-search.h"
namespace v8 { namespace v8 {
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
#include "src/jsregexp-inl.h" #include "src/jsregexp-inl.h"
#include "src/jsregexp.h" #include "src/jsregexp.h"
#include "src/runtime/runtime-utils.h" #include "src/runtime/runtime-utils.h"
#include "src/runtime/string-builder.h" #include "src/string-builder.h"
#include "src/string-search.h" #include "src/string-search.h"
namespace v8 { namespace v8 {
......
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/string-builder.h"
namespace v8 {
namespace internal {
MaybeHandle<String> ReplacementStringBuilder::ToString() {
Isolate* isolate = heap_->isolate();
if (array_builder_.length() == 0) {
return isolate->factory()->empty_string();
}
Handle<String> joined_string;
if (is_one_byte_) {
Handle<SeqOneByteString> seq;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, seq, isolate->factory()->NewRawOneByteString(character_count_),
String);
DisallowHeapAllocation no_gc;
uint8_t* char_buffer = seq->GetChars();
StringBuilderConcatHelper(*subject_, char_buffer, *array_builder_.array(),
array_builder_.length());
joined_string = Handle<String>::cast(seq);
} else {
// Two-byte.
Handle<SeqTwoByteString> seq;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, seq, isolate->factory()->NewRawTwoByteString(character_count_),
String);
DisallowHeapAllocation no_gc;
uc16* char_buffer = seq->GetChars();
StringBuilderConcatHelper(*subject_, char_buffer, *array_builder_.array(),
array_builder_.length());
joined_string = Handle<String>::cast(seq);
}
return joined_string;
}
IncrementalStringBuilder::IncrementalStringBuilder(Isolate* isolate)
: isolate_(isolate),
encoding_(String::ONE_BYTE_ENCODING),
overflowed_(false),
part_length_(kInitialPartLength),
current_index_(0) {
// Create an accumulator handle starting with the empty string.
accumulator_ = Handle<String>(isolate->heap()->empty_string(), isolate);
current_part_ =
factory()->NewRawOneByteString(part_length_).ToHandleChecked();
}
void IncrementalStringBuilder::Accumulate() {
// Only accumulate fully written strings. Shrink first if necessary.
DCHECK_EQ(current_index_, current_part()->length());
Handle<String> new_accumulator;
if (accumulator()->length() + current_part()->length() > String::kMaxLength) {
// Set the flag and carry on. Delay throwing the exception till the end.
new_accumulator = factory()->empty_string();
overflowed_ = true;
} else {
new_accumulator = factory()
->NewConsString(accumulator(), current_part())
.ToHandleChecked();
}
set_accumulator(new_accumulator);
}
void IncrementalStringBuilder::Extend() {
Accumulate();
if (part_length_ <= kMaxPartLength / kPartLengthGrowthFactor) {
part_length_ *= kPartLengthGrowthFactor;
}
Handle<String> new_part;
if (encoding_ == String::ONE_BYTE_ENCODING) {
new_part = factory()->NewRawOneByteString(part_length_).ToHandleChecked();
} else {
new_part = factory()->NewRawTwoByteString(part_length_).ToHandleChecked();
}
// Reuse the same handle to avoid being invalidated when exiting handle scope.
set_current_part(new_part);
current_index_ = 0;
}
MaybeHandle<String> IncrementalStringBuilder::Finish() {
ShrinkCurrentPart();
Accumulate();
if (overflowed_) {
THROW_NEW_ERROR(isolate_, NewInvalidStringLengthError(), String);
}
return accumulator();
}
void IncrementalStringBuilder::AppendString(Handle<String> string) {
ShrinkCurrentPart();
part_length_ = kInitialPartLength; // Allocate conservatively.
Extend(); // Attach current part and allocate new part.
Handle<String> concat =
factory()->NewConsString(accumulator(), string).ToHandleChecked();
set_accumulator(concat);
}
}
} // namespace v8::internal
...@@ -2,8 +2,10 @@ ...@@ -2,8 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#ifndef V8_RUNTIME_STRING_BUILDER_H_ #ifndef V8_STRING_BUILDER_H_
#define V8_RUNTIME_STRING_BUILDER_H_ #define V8_STRING_BUILDER_H_
#include "src/v8.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
...@@ -233,39 +235,7 @@ class ReplacementStringBuilder { ...@@ -233,39 +235,7 @@ class ReplacementStringBuilder {
} }
MaybeHandle<String> ToString() { MaybeHandle<String> ToString();
Isolate* isolate = heap_->isolate();
if (array_builder_.length() == 0) {
return isolate->factory()->empty_string();
}
Handle<String> joined_string;
if (is_one_byte_) {
Handle<SeqOneByteString> seq;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, seq,
isolate->factory()->NewRawOneByteString(character_count_), String);
DisallowHeapAllocation no_gc;
uint8_t* char_buffer = seq->GetChars();
StringBuilderConcatHelper(*subject_, char_buffer, *array_builder_.array(),
array_builder_.length());
joined_string = Handle<String>::cast(seq);
} else {
// Two-byte.
Handle<SeqTwoByteString> seq;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, seq,
isolate->factory()->NewRawTwoByteString(character_count_), String);
DisallowHeapAllocation no_gc;
uc16* char_buffer = seq->GetChars();
StringBuilderConcatHelper(*subject_, char_buffer, *array_builder_.array(),
array_builder_.length());
joined_string = Handle<String>::cast(seq);
}
return joined_string;
}
void IncrementCharacterCount(int by) { void IncrementCharacterCount(int by) {
...@@ -290,7 +260,171 @@ class ReplacementStringBuilder { ...@@ -290,7 +260,171 @@ class ReplacementStringBuilder {
int character_count_; int character_count_;
bool is_one_byte_; bool is_one_byte_;
}; };
class IncrementalStringBuilder {
public:
explicit IncrementalStringBuilder(Isolate* isolate);
INLINE(String::Encoding CurrentEncoding()) { return encoding_; }
template <typename SrcChar, typename DestChar>
INLINE(void Append(SrcChar c));
INLINE(void AppendCharacter(uint8_t c)) {
if (encoding_ == String::ONE_BYTE_ENCODING) {
Append<uint8_t, uint8_t>(c);
} else {
Append<uint8_t, uc16>(c);
}
}
INLINE(void AppendCString(const char* s)) {
const uint8_t* u = reinterpret_cast<const uint8_t*>(s);
if (encoding_ == String::ONE_BYTE_ENCODING) {
while (*u != '\0') Append<uint8_t, uint8_t>(*(u++));
} else {
while (*u != '\0') Append<uint8_t, uc16>(*(u++));
}
}
INLINE(bool CurrentPartCanFit(int length)) {
return part_length_ - current_index_ > length;
}
void AppendString(Handle<String> string);
MaybeHandle<String> Finish();
// Change encoding to two-byte.
void ChangeEncoding() {
DCHECK_EQ(String::ONE_BYTE_ENCODING, encoding_);
ShrinkCurrentPart();
encoding_ = String::TWO_BYTE_ENCODING;
Extend();
}
template <typename DestChar>
class NoExtend {
public:
explicit NoExtend(Handle<String> string, int offset) {
DCHECK(string->IsSeqOneByteString() || string->IsSeqTwoByteString());
if (sizeof(DestChar) == 1) {
start_ = reinterpret_cast<DestChar*>(
Handle<SeqOneByteString>::cast(string)->GetChars() + offset);
} else {
start_ = reinterpret_cast<DestChar*>(
Handle<SeqTwoByteString>::cast(string)->GetChars() + offset);
}
cursor_ = start_;
}
INLINE(void Append(DestChar c)) { *(cursor_++) = c; }
INLINE(void AppendCString(const char* s)) {
const uint8_t* u = reinterpret_cast<const uint8_t*>(s);
while (*u != '\0') Append(*(u++));
}
int written() { return cursor_ - start_; }
private:
DestChar* start_;
DestChar* cursor_;
DisallowHeapAllocation no_gc_;
};
template <typename DestChar>
class NoExtendString : public NoExtend<DestChar> {
public:
NoExtendString(Handle<String> string, int required_length)
: NoExtend<DestChar>(string, 0), string_(string) {
DCHECK(string->length() >= required_length);
}
~NoExtendString() {
Handle<SeqString> string = Handle<SeqString>::cast(string_);
int length = NoExtend<DestChar>::written();
*string_.location() = *SeqString::Truncate(string, length);
}
private:
Handle<String> string_;
};
template <typename DestChar>
class NoExtendBuilder : public NoExtend<DestChar> {
public:
NoExtendBuilder(IncrementalStringBuilder* builder, int required_length)
: NoExtend<DestChar>(builder->current_part(), builder->current_index_),
builder_(builder) {
DCHECK(builder->CurrentPartCanFit(required_length));
}
~NoExtendBuilder() {
builder_->current_index_ += NoExtend<DestChar>::written();
}
private:
IncrementalStringBuilder* builder_;
};
private:
Factory* factory() { return isolate_->factory(); }
INLINE(Handle<String> accumulator()) { return accumulator_; }
INLINE(void set_accumulator(Handle<String> string)) {
*accumulator_.location() = *string;
}
INLINE(Handle<String> current_part()) { return current_part_; }
INLINE(void set_current_part(Handle<String> string)) {
*current_part_.location() = *string;
}
// Add the current part to the accumulator.
void Accumulate();
// Finish the current part and allocate a new part.
void Extend();
// Shrink current part to the right size.
void ShrinkCurrentPart() {
DCHECK(current_index_ < part_length_);
set_current_part(SeqString::Truncate(
Handle<SeqString>::cast(current_part()), current_index_));
}
static const int kInitialPartLength = 32;
static const int kMaxPartLength = 16 * 1024;
static const int kPartLengthGrowthFactor = 2;
Isolate* isolate_;
String::Encoding encoding_;
bool overflowed_;
int part_length_;
int current_index_;
Handle<String> accumulator_;
Handle<String> current_part_;
};
template <typename SrcChar, typename DestChar>
void IncrementalStringBuilder::Append(SrcChar c) {
DCHECK_EQ(encoding_ == String::ONE_BYTE_ENCODING, sizeof(DestChar) == 1);
if (sizeof(DestChar) == 1) {
DCHECK_EQ(String::ONE_BYTE_ENCODING, encoding_);
SeqOneByteString::cast(*current_part_)
->SeqOneByteStringSet(current_index_++, c);
} else {
DCHECK_EQ(String::TWO_BYTE_ENCODING, encoding_);
SeqTwoByteString::cast(*current_part_)
->SeqTwoByteStringSet(current_index_++, c);
}
if (current_index_ == part_length_) Extend();
}
} }
} // namespace v8::internal } // namespace v8::internal
#endif // V8_RUNTIME_STRING_BUILDER_H_ #endif // V8_STRING_BUILDER_H_
...@@ -790,7 +790,6 @@ ...@@ -790,7 +790,6 @@
'../../src/runtime/runtime-utils.h', '../../src/runtime/runtime-utils.h',
'../../src/runtime/runtime.cc', '../../src/runtime/runtime.cc',
'../../src/runtime/runtime.h', '../../src/runtime/runtime.h',
'../../src/runtime/string-builder.h',
'../../src/safepoint-table.cc', '../../src/safepoint-table.cc',
'../../src/safepoint-table.h', '../../src/safepoint-table.h',
'../../src/sampler.cc', '../../src/sampler.cc',
...@@ -810,6 +809,8 @@ ...@@ -810,6 +809,8 @@
'../../src/snapshot.h', '../../src/snapshot.h',
'../../src/snapshot-source-sink.cc', '../../src/snapshot-source-sink.cc',
'../../src/snapshot-source-sink.h', '../../src/snapshot-source-sink.h',
'../../src/string-builder.h',
'../../src/string-builder.cc',
'../../src/string-search.cc', '../../src/string-search.cc',
'../../src/string-search.h', '../../src/string-search.h',
'../../src/string-stream.cc', '../../src/string-stream.cc',
......
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