Commit 87567584 authored by Camillo Bruni's avatar Camillo Bruni Committed by V8 LUCI CQ

[runtime][json] Add IncrementalStringBuilder::AppendCStringLiteral

Directly memcpy char* literals if they fit in the current pending
part. This avoids incremental checks for the current part size.

This will improve JSON.stringify for objects with lots of
true, false, null values by roughly 10%;

Drive-by-fix:
- Improve JSON.stringify for empty [] and {}
- Add IncrementalStringBuilder::NoExtend DECHECKs

Bug: v8:12195
Change-Id: I81ebc9e088cf983adbcfb2d768137e4a3cef9a7a
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3260524Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Commit-Queue: Camillo Bruni <cbruni@chromium.org>
Cr-Commit-Position: refs/heads/main@{#77817}
parent 5e16d853
...@@ -47,7 +47,7 @@ MaybeHandle<Object> CreateDynamicFunction(Isolate* isolate, ...@@ -47,7 +47,7 @@ MaybeHandle<Object> CreateDynamicFunction(Isolate* isolate,
IncrementalStringBuilder builder(isolate); IncrementalStringBuilder builder(isolate);
builder.AppendCharacter('('); builder.AppendCharacter('(');
builder.AppendCString(token); builder.AppendCString(token);
builder.AppendCString(" anonymous("); builder.AppendCStringLiteral(" anonymous(");
if (argc > 1) { if (argc > 1) {
for (int i = 1; i < argc; ++i) { for (int i = 1; i < argc; ++i) {
if (i > 1) builder.AppendCharacter(','); if (i > 1) builder.AppendCharacter(',');
...@@ -60,14 +60,14 @@ MaybeHandle<Object> CreateDynamicFunction(Isolate* isolate, ...@@ -60,14 +60,14 @@ MaybeHandle<Object> CreateDynamicFunction(Isolate* isolate,
} }
builder.AppendCharacter('\n'); builder.AppendCharacter('\n');
parameters_end_pos = builder.Length(); parameters_end_pos = builder.Length();
builder.AppendCString(") {\n"); builder.AppendCStringLiteral(") {\n");
if (argc > 0) { if (argc > 0) {
Handle<String> body; Handle<String> body;
ASSIGN_RETURN_ON_EXCEPTION( ASSIGN_RETURN_ON_EXCEPTION(
isolate, body, Object::ToString(isolate, args.at(argc)), Object); isolate, body, Object::ToString(isolate, args.at(argc)), Object);
builder.AppendString(body); builder.AppendString(body);
} }
builder.AppendCString("\n})"); builder.AppendCStringLiteral("\n})");
ASSIGN_RETURN_ON_EXCEPTION(isolate, source, builder.Finish(), Object); ASSIGN_RETURN_ON_EXCEPTION(isolate, source, builder.Finish(), Object);
} }
......
...@@ -85,9 +85,9 @@ Local<String> GetFunctionDescription(Local<Function> function) { ...@@ -85,9 +85,9 @@ Local<String> GetFunctionDescription(Local<Function> function) {
auto debug_name = auto debug_name =
i::GetWasmFunctionDebugName(isolate, instance, func_index); i::GetWasmFunctionDebugName(isolate, instance, func_index);
i::IncrementalStringBuilder builder(isolate); i::IncrementalStringBuilder builder(isolate);
builder.AppendCString("function "); builder.AppendCStringLiteral("function ");
builder.AppendString(debug_name); builder.AppendString(debug_name);
builder.AppendCString("() { [native code] }"); builder.AppendCStringLiteral("() { [native code] }");
return Utils::ToLocal(builder.Finish().ToHandleChecked()); return Utils::ToLocal(builder.Finish().ToHandleChecked());
} }
} }
......
...@@ -261,10 +261,10 @@ MaybeHandle<Object> AppendErrorString(Isolate* isolate, Handle<Object> error, ...@@ -261,10 +261,10 @@ MaybeHandle<Object> AppendErrorString(Isolate* isolate, Handle<Object> error,
DCHECK(isolate->has_pending_exception()); DCHECK(isolate->has_pending_exception());
isolate->clear_pending_exception(); isolate->clear_pending_exception();
isolate->set_external_caught_exception(false); isolate->set_external_caught_exception(false);
builder->AppendCString("<error>"); builder->AppendCStringLiteral("<error>");
} else { } else {
// Formatted thrown exception successfully, append it. // Formatted thrown exception successfully, append it.
builder->AppendCString("<error: "); builder->AppendCStringLiteral("<error: ");
builder->AppendString(err_str.ToHandleChecked()); builder->AppendString(err_str.ToHandleChecked());
builder->AppendCharacter('>'); builder->AppendCharacter('>');
} }
...@@ -369,7 +369,7 @@ MaybeHandle<Object> ErrorUtils::FormatStackTrace(Isolate* isolate, ...@@ -369,7 +369,7 @@ MaybeHandle<Object> ErrorUtils::FormatStackTrace(Isolate* isolate,
Object); Object);
for (int i = 0; i < elems->length(); ++i) { for (int i = 0; i < elems->length(); ++i) {
builder.AppendCString("\n at "); builder.AppendCStringLiteral("\n at ");
Handle<StackFrameInfo> frame(StackFrameInfo::cast(elems->get(i)), isolate); Handle<StackFrameInfo> frame(StackFrameInfo::cast(elems->get(i)), isolate);
SerializeStackFrameInfo(isolate, frame, &builder); SerializeStackFrameInfo(isolate, frame, &builder);
...@@ -389,12 +389,12 @@ MaybeHandle<Object> ErrorUtils::FormatStackTrace(Isolate* isolate, ...@@ -389,12 +389,12 @@ MaybeHandle<Object> ErrorUtils::FormatStackTrace(Isolate* isolate,
if (exception_string.is_null()) { if (exception_string.is_null()) {
// Formatting the thrown exception threw again, give up. // Formatting the thrown exception threw again, give up.
builder.AppendCString("<error>"); builder.AppendCStringLiteral("<error>");
} else { } else {
// Formatted thrown exception successfully, append it. // Formatted thrown exception successfully, append it.
builder.AppendCString("<error: "); builder.AppendCStringLiteral("<error: ");
builder.AppendString(exception_string.ToHandleChecked()); builder.AppendString(exception_string.ToHandleChecked());
builder.AppendCString("<error>"); builder.AppendCStringLiteral("<error>");
} }
} }
} }
...@@ -658,7 +658,7 @@ MaybeHandle<String> ErrorUtils::ToString(Isolate* isolate, ...@@ -658,7 +658,7 @@ MaybeHandle<String> ErrorUtils::ToString(Isolate* isolate,
// the code unit 0x0020 (SPACE), and msg. // the code unit 0x0020 (SPACE), and msg.
IncrementalStringBuilder builder(isolate); IncrementalStringBuilder builder(isolate);
builder.AppendString(name); builder.AppendString(name);
builder.AppendCString(": "); builder.AppendCStringLiteral(": ");
builder.AppendString(msg); builder.AppendString(msg);
Handle<String> result; Handle<String> result;
...@@ -745,7 +745,7 @@ Handle<String> BuildDefaultCallSite(Isolate* isolate, Handle<Object> object) { ...@@ -745,7 +745,7 @@ Handle<String> BuildDefaultCallSite(Isolate* isolate, Handle<Object> object) {
builder.AppendString(Object::TypeOf(isolate, object)); builder.AppendString(Object::TypeOf(isolate, object));
if (object->IsString()) { if (object->IsString()) {
builder.AppendCString(" \""); builder.AppendCStringLiteral(" \"");
Handle<String> string = Handle<String>::cast(object); Handle<String> string = Handle<String>::cast(object);
// This threshold must be sufficiently far below String::kMaxLength that // This threshold must be sufficiently far below String::kMaxLength that
// the {builder}'s result can never exceed that limit. // the {builder}'s result can never exceed that limit.
...@@ -756,20 +756,17 @@ Handle<String> BuildDefaultCallSite(Isolate* isolate, Handle<Object> object) { ...@@ -756,20 +756,17 @@ Handle<String> BuildDefaultCallSite(Isolate* isolate, Handle<Object> object) {
string = isolate->factory()->NewProperSubString(string, 0, string = isolate->factory()->NewProperSubString(string, 0,
kMaxPrintedStringLength); kMaxPrintedStringLength);
builder.AppendString(string); builder.AppendString(string);
builder.AppendCString("<...>"); builder.AppendCStringLiteral("<...>");
} }
builder.AppendCString("\""); builder.AppendCStringLiteral("\"");
} else if (object->IsNull(isolate)) { } else if (object->IsNull(isolate)) {
builder.AppendCString(" "); builder.AppendCStringLiteral(" null");
builder.AppendString(isolate->factory()->null_string());
} else if (object->IsTrue(isolate)) { } else if (object->IsTrue(isolate)) {
builder.AppendCString(" "); builder.AppendCStringLiteral(" true");
builder.AppendString(isolate->factory()->true_string());
} else if (object->IsFalse(isolate)) { } else if (object->IsFalse(isolate)) {
builder.AppendCString(" "); builder.AppendCStringLiteral(" false");
builder.AppendString(isolate->factory()->false_string());
} else if (object->IsNumber()) { } else if (object->IsNumber()) {
builder.AppendCString(" "); builder.AppendCharacter(' ');
builder.AppendString(isolate->factory()->NumberToString(object)); builder.AppendString(isolate->factory()->NumberToString(object));
} }
......
...@@ -411,26 +411,26 @@ class CircularStructureMessageBuilder { ...@@ -411,26 +411,26 @@ class CircularStructureMessageBuilder {
void AppendStartLine(Handle<Object> start_object) { void AppendStartLine(Handle<Object> start_object) {
builder_.AppendCString(kStartPrefix); builder_.AppendCString(kStartPrefix);
builder_.AppendCString("starting at object with constructor "); builder_.AppendCStringLiteral("starting at object with constructor ");
AppendConstructorName(start_object); AppendConstructorName(start_object);
} }
void AppendNormalLine(Handle<Object> key, Handle<Object> object) { void AppendNormalLine(Handle<Object> key, Handle<Object> object) {
builder_.AppendCString(kLinePrefix); builder_.AppendCString(kLinePrefix);
AppendKey(key); AppendKey(key);
builder_.AppendCString(" -> object with constructor "); builder_.AppendCStringLiteral(" -> object with constructor ");
AppendConstructorName(object); AppendConstructorName(object);
} }
void AppendClosingLine(Handle<Object> closing_key) { void AppendClosingLine(Handle<Object> closing_key) {
builder_.AppendCString(kEndPrefix); builder_.AppendCString(kEndPrefix);
AppendKey(closing_key); AppendKey(closing_key);
builder_.AppendCString(" closes the circle"); builder_.AppendCStringLiteral(" closes the circle");
} }
void AppendEllipsis() { void AppendEllipsis() {
builder_.AppendCString(kLinePrefix); builder_.AppendCString(kLinePrefix);
builder_.AppendCString("..."); builder_.AppendCStringLiteral("...");
} }
MaybeHandle<String> Finish() { return builder_.Finish(); } MaybeHandle<String> Finish() { return builder_.Finish(); }
...@@ -447,7 +447,7 @@ class CircularStructureMessageBuilder { ...@@ -447,7 +447,7 @@ class CircularStructureMessageBuilder {
// A key can either be a string, the empty string or a Smi. // A key can either be a string, the empty string or a Smi.
void AppendKey(Handle<Object> key) { void AppendKey(Handle<Object> key) {
if (key->IsSmi()) { if (key->IsSmi()) {
builder_.AppendCString("index "); builder_.AppendCStringLiteral("index ");
AppendSmi(Smi::cast(*key)); AppendSmi(Smi::cast(*key));
return; return;
} }
...@@ -455,9 +455,9 @@ class CircularStructureMessageBuilder { ...@@ -455,9 +455,9 @@ class CircularStructureMessageBuilder {
CHECK(key->IsString()); CHECK(key->IsString());
Handle<String> key_as_string = Handle<String>::cast(key); Handle<String> key_as_string = Handle<String>::cast(key);
if (key_as_string->length() == 0) { if (key_as_string->length() == 0) {
builder_.AppendCString("<anonymous>"); builder_.AppendCStringLiteral("<anonymous>");
} else { } else {
builder_.AppendCString("property '"); builder_.AppendCStringLiteral("property '");
builder_.AppendString(key_as_string); builder_.AppendString(key_as_string);
builder_.AppendCharacter('\''); builder_.AppendCharacter('\'');
} }
...@@ -520,12 +520,13 @@ JsonStringifier::Result JsonStringifier::Serialize_(Handle<Object> object, ...@@ -520,12 +520,13 @@ JsonStringifier::Result JsonStringifier::Serialize_(Handle<Object> object,
bool comma, bool comma,
Handle<Object> key) { Handle<Object> key) {
StackLimitCheck interrupt_check(isolate_); StackLimitCheck interrupt_check(isolate_);
Handle<Object> initial_value = object;
PtrComprCageBase cage_base(isolate_);
if (interrupt_check.InterruptRequested() && if (interrupt_check.InterruptRequested() &&
isolate_->stack_guard()->HandleInterrupts().IsException(isolate_)) { isolate_->stack_guard()->HandleInterrupts().IsException(isolate_)) {
return EXCEPTION; return EXCEPTION;
} }
Handle<Object> initial_value = object;
PtrComprCageBase cage_base(isolate_);
if (!object->IsSmi()) { if (!object->IsSmi()) {
InstanceType instance_type = InstanceType instance_type =
HeapObject::cast(*object).map(cage_base).instance_type(); HeapObject::cast(*object).map(cage_base).instance_type();
...@@ -560,15 +561,15 @@ JsonStringifier::Result JsonStringifier::Serialize_(Handle<Object> object, ...@@ -560,15 +561,15 @@ JsonStringifier::Result JsonStringifier::Serialize_(Handle<Object> object,
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);
builder_.AppendCString("false"); builder_.AppendCStringLiteral("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);
builder_.AppendCString("true"); builder_.AppendCStringLiteral("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);
builder_.AppendCString("null"); builder_.AppendCStringLiteral("null");
return SUCCESS; return SUCCESS;
default: default:
return UNCHANGED; return UNCHANGED;
...@@ -621,7 +622,11 @@ JsonStringifier::Result JsonStringifier::SerializeJSPrimitiveWrapper( ...@@ -621,7 +622,11 @@ JsonStringifier::Result JsonStringifier::SerializeJSPrimitiveWrapper(
*factory()->NewTypeError(MessageTemplate::kBigIntSerializeJSON)); *factory()->NewTypeError(MessageTemplate::kBigIntSerializeJSON));
return EXCEPTION; return EXCEPTION;
} else if (raw.IsBoolean()) { } else if (raw.IsBoolean()) {
builder_.AppendCString(raw.IsTrue(isolate_) ? "true" : "false"); if (raw.IsTrue(isolate_)) {
builder_.AppendCStringLiteral("true");
} else {
builder_.AppendCStringLiteral("false");
}
} else { } else {
// ES6 24.3.2.1 step 10.c, serialize as an ordinary JSObject. // ES6 24.3.2.1 step 10.c, serialize as an ordinary JSObject.
return SerializeJSObject(object, key); return SerializeJSObject(object, key);
...@@ -639,7 +644,7 @@ JsonStringifier::Result JsonStringifier::SerializeSmi(Smi object) { ...@@ -639,7 +644,7 @@ JsonStringifier::Result JsonStringifier::SerializeSmi(Smi object) {
JsonStringifier::Result JsonStringifier::SerializeDouble(double number) { JsonStringifier::Result JsonStringifier::SerializeDouble(double number) {
if (std::isinf(number) || std::isnan(number)) { if (std::isinf(number) || std::isnan(number)) {
builder_.AppendCString("null"); builder_.AppendCStringLiteral("null");
return SUCCESS; return SUCCESS;
} }
static const int kBufferSize = 100; static const int kBufferSize = 100;
...@@ -651,16 +656,22 @@ JsonStringifier::Result JsonStringifier::SerializeDouble(double number) { ...@@ -651,16 +656,22 @@ JsonStringifier::Result JsonStringifier::SerializeDouble(double number) {
JsonStringifier::Result JsonStringifier::SerializeJSArray( JsonStringifier::Result JsonStringifier::SerializeJSArray(
Handle<JSArray> object, Handle<Object> key) { Handle<JSArray> object, Handle<Object> key) {
PtrComprCageBase cage_base(isolate_);
Result stack_push = StackPush(object, key);
if (stack_push != SUCCESS) return stack_push;
uint32_t length = 0; uint32_t length = 0;
CHECK(object->length().ToArrayLength(&length)); CHECK(object->length().ToArrayLength(&length));
DCHECK(!object->IsAccessCheckNeeded()); DCHECK(!object->IsAccessCheckNeeded());
if (length == 0) {
builder_.AppendCStringLiteral("[]");
return SUCCESS;
}
PtrComprCageBase cage_base(isolate_);
Result stack_push = StackPush(object, key);
if (stack_push != SUCCESS) return stack_push;
builder_.AppendCharacter('['); builder_.AppendCharacter('[');
Indent(); Indent();
uint32_t i = 0; uint32_t i = 0;
if (replacer_function_.is_null() && length > 0) { if (replacer_function_.is_null()) {
StackLimitCheck interrupt_check(isolate_); StackLimitCheck interrupt_check(isolate_);
const uint32_t kInterruptLength = 4000; const uint32_t kInterruptLength = 4000;
uint32_t limit = std::min(length, kInterruptLength); uint32_t limit = std::min(length, kInterruptLength);
...@@ -722,7 +733,7 @@ JsonStringifier::Result JsonStringifier::SerializeJSArray( ...@@ -722,7 +733,7 @@ JsonStringifier::Result JsonStringifier::SerializeJSArray(
isolate_), isolate_),
i); i);
if (result == UNCHANGED) { if (result == UNCHANGED) {
builder_.AppendCString("null"); builder_.AppendCStringLiteral("null");
} else if (result != SUCCESS) { } else if (result != SUCCESS) {
return result; return result;
} }
...@@ -739,7 +750,7 @@ JsonStringifier::Result JsonStringifier::SerializeJSArray( ...@@ -739,7 +750,7 @@ JsonStringifier::Result JsonStringifier::SerializeJSArray(
if (result != SUCCESS) return result; if (result != SUCCESS) return result;
} }
Unindent(); Unindent();
if (length > 0) NewLine(); NewLine();
builder_.AppendCharacter(']'); builder_.AppendCharacter(']');
StackPop(); StackPop();
return SUCCESS; return SUCCESS;
...@@ -765,7 +776,7 @@ JsonStringifier::Result JsonStringifier::SerializeArrayLikeSlow( ...@@ -765,7 +776,7 @@ JsonStringifier::Result JsonStringifier::SerializeArrayLikeSlow(
if (result == UNCHANGED) { if (result == UNCHANGED) {
// Detect overflow sooner for large sparse arrays. // Detect overflow sooner for large sparse arrays.
if (builder_.HasOverflowed()) return EXCEPTION; if (builder_.HasOverflowed()) return EXCEPTION;
builder_.AppendCString("null"); builder_.AppendCStringLiteral("null");
} else { } else {
return result; return result;
} }
...@@ -788,19 +799,34 @@ V8_INLINE bool CanFastSerializeJSObject(PtrComprCageBase cage_base, ...@@ -788,19 +799,34 @@ V8_INLINE bool CanFastSerializeJSObject(PtrComprCageBase cage_base,
JsonStringifier::Result JsonStringifier::SerializeJSObject( JsonStringifier::Result JsonStringifier::SerializeJSObject(
Handle<JSObject> object, Handle<Object> key) { Handle<JSObject> object, Handle<Object> key) {
Result stack_push = StackPush(object, key);
if (stack_push != SUCCESS) return stack_push;
PtrComprCageBase cage_base(isolate_); PtrComprCageBase cage_base(isolate_);
HandleScope handle_scope(isolate_); HandleScope handle_scope(isolate_);
if (property_list_.is_null() &&
CanFastSerializeJSObject(cage_base, *object, isolate_)) { if (!property_list_.is_null() ||
!CanFastSerializeJSObject(cage_base, *object, isolate_)) {
Result stack_push = StackPush(object, key);
if (stack_push != SUCCESS) return stack_push;
Result result = SerializeJSReceiverSlow(object);
if (result != SUCCESS) return result;
StackPop();
return SUCCESS;
}
DCHECK(!object->IsJSGlobalProxy()); DCHECK(!object->IsJSGlobalProxy());
DCHECK(!object->HasIndexedInterceptor()); DCHECK(!object->HasIndexedInterceptor());
DCHECK(!object->HasNamedInterceptor()); DCHECK(!object->HasNamedInterceptor());
Handle<Map> map(object->map(cage_base), isolate_);
if (map->NumberOfOwnDescriptors() == 0) {
builder_.AppendCStringLiteral("{}");
return SUCCESS;
}
Result stack_push = StackPush(object, key);
if (stack_push != SUCCESS) return stack_push;
builder_.AppendCharacter('{'); builder_.AppendCharacter('{');
Indent(); Indent();
bool comma = false; bool comma = false;
Handle<Map> map(object->map(cage_base), isolate_);
for (InternalIndex i : map->IterateOwnDescriptors()) { for (InternalIndex i : map->IterateOwnDescriptors()) {
Handle<String> key_name; Handle<String> key_name;
PropertyDetails details = PropertyDetails::Empty(); PropertyDetails details = PropertyDetails::Empty();
...@@ -824,8 +850,7 @@ JsonStringifier::Result JsonStringifier::SerializeJSObject( ...@@ -824,8 +850,7 @@ JsonStringifier::Result JsonStringifier::SerializeJSObject(
} else { } else {
ASSIGN_RETURN_ON_EXCEPTION_VALUE( ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate_, property, isolate_, property,
Object::GetPropertyOrElement(isolate_, object, key_name), Object::GetPropertyOrElement(isolate_, object, key_name), EXCEPTION);
EXCEPTION);
} }
Result result = SerializeProperty(property, comma, key_name); Result result = SerializeProperty(property, comma, key_name);
if (!comma && result == SUCCESS) comma = true; if (!comma && result == SUCCESS) comma = true;
...@@ -834,10 +859,6 @@ JsonStringifier::Result JsonStringifier::SerializeJSObject( ...@@ -834,10 +859,6 @@ JsonStringifier::Result JsonStringifier::SerializeJSObject(
Unindent(); Unindent();
if (comma) NewLine(); if (comma) NewLine();
builder_.AppendCharacter('}'); builder_.AppendCharacter('}');
} else {
Result result = SerializeJSReceiverSlow(object);
if (result != SUCCESS) return result;
}
StackPop(); StackPop();
return SUCCESS; return SUCCESS;
} }
...@@ -1005,7 +1026,7 @@ void JsonStringifier::SerializeString_(Handle<String> string) { ...@@ -1005,7 +1026,7 @@ void JsonStringifier::SerializeString_(Handle<String> string) {
} else { } else {
// The next character is not a trailing surrogate. Thus, the // The next character is not a trailing surrogate. Thus, the
// current character is a lone leading surrogate. // current character is a lone leading surrogate.
builder_.AppendCString("\\u"); builder_.AppendCStringLiteral("\\u");
char* const hex = DoubleToRadixCString(c, 16); char* const hex = DoubleToRadixCString(c, 16);
builder_.AppendCString(hex); builder_.AppendCString(hex);
DeleteArray(hex); DeleteArray(hex);
...@@ -1013,7 +1034,7 @@ void JsonStringifier::SerializeString_(Handle<String> string) { ...@@ -1013,7 +1034,7 @@ void JsonStringifier::SerializeString_(Handle<String> string) {
} else { } else {
// There is no next character. Thus, the current character is a // There is no next character. Thus, the current character is a
// lone leading surrogate. // lone leading surrogate.
builder_.AppendCString("\\u"); builder_.AppendCStringLiteral("\\u");
char* const hex = DoubleToRadixCString(c, 16); char* const hex = DoubleToRadixCString(c, 16);
builder_.AppendCString(hex); builder_.AppendCString(hex);
DeleteArray(hex); DeleteArray(hex);
...@@ -1023,7 +1044,7 @@ void JsonStringifier::SerializeString_(Handle<String> string) { ...@@ -1023,7 +1044,7 @@ void JsonStringifier::SerializeString_(Handle<String> string) {
// been preceded by a leading surrogate, we would've ended up in the // been preceded by a leading surrogate, we would've ended up in the
// other branch earlier on, and the current character would've been // other branch earlier on, and the current character would've been
// handled as part of the surrogate pair already.) // handled as part of the surrogate pair already.)
builder_.AppendCString("\\u"); builder_.AppendCStringLiteral("\\u");
char* const hex = DoubleToRadixCString(c, 16); char* const hex = DoubleToRadixCString(c, 16);
builder_.AppendCString(hex); builder_.AppendCString(hex);
DeleteArray(hex); DeleteArray(hex);
......
...@@ -937,9 +937,9 @@ Handle<String> NativeCodeFunctionSourceString( ...@@ -937,9 +937,9 @@ Handle<String> NativeCodeFunctionSourceString(
Handle<SharedFunctionInfo> shared_info) { Handle<SharedFunctionInfo> shared_info) {
Isolate* const isolate = shared_info->GetIsolate(); Isolate* const isolate = shared_info->GetIsolate();
IncrementalStringBuilder builder(isolate); IncrementalStringBuilder builder(isolate);
builder.AppendCString("function "); builder.AppendCStringLiteral("function ");
builder.AppendString(handle(shared_info->Name(), isolate)); builder.AppendString(handle(shared_info->Name(), isolate));
builder.AppendCString("() { [native code] }"); builder.AppendCStringLiteral("() { [native code] }");
return builder.Finish().ToHandleChecked(); return builder.Finish().ToHandleChecked();
} }
......
...@@ -452,12 +452,12 @@ Handle<String> NoSideEffectsErrorToString(Isolate* isolate, ...@@ -452,12 +452,12 @@ Handle<String> NoSideEffectsErrorToString(Isolate* isolate,
IncrementalStringBuilder builder(isolate); IncrementalStringBuilder builder(isolate);
builder.AppendString(name_str); builder.AppendString(name_str);
builder.AppendCString(": "); builder.AppendCStringLiteral(": ");
if (builder.Length() + msg_str->length() <= String::kMaxLength) { if (builder.Length() + msg_str->length() <= String::kMaxLength) {
builder.AppendString(msg_str); builder.AppendString(msg_str);
} else { } else {
builder.AppendCString("<a very large string>"); builder.AppendCStringLiteral("<a very large string>");
} }
return builder.Finish().ToHandleChecked(); return builder.Finish().ToHandleChecked();
...@@ -501,7 +501,7 @@ MaybeHandle<String> Object::NoSideEffectsToMaybeString(Isolate* isolate, ...@@ -501,7 +501,7 @@ MaybeHandle<String> Object::NoSideEffectsToMaybeString(Isolate* isolate,
if (fun_str->length() > 128) { if (fun_str->length() > 128) {
IncrementalStringBuilder builder(isolate); IncrementalStringBuilder builder(isolate);
builder.AppendString(isolate->factory()->NewSubString(fun_str, 0, 111)); builder.AppendString(isolate->factory()->NewSubString(fun_str, 0, 111));
builder.AppendCString("...<omitted>..."); builder.AppendCStringLiteral("...<omitted>...");
builder.AppendString(isolate->factory()->NewSubString( builder.AppendString(isolate->factory()->NewSubString(
fun_str, fun_str->length() - 2, fun_str->length())); fun_str, fun_str->length() - 2, fun_str->length()));
...@@ -517,7 +517,7 @@ MaybeHandle<String> Object::NoSideEffectsToMaybeString(Isolate* isolate, ...@@ -517,7 +517,7 @@ MaybeHandle<String> Object::NoSideEffectsToMaybeString(Isolate* isolate,
} }
IncrementalStringBuilder builder(isolate); IncrementalStringBuilder builder(isolate);
builder.AppendCString("Symbol("); builder.AppendCStringLiteral("Symbol(");
if (symbol->description().IsString()) { if (symbol->description().IsString()) {
builder.AppendString( builder.AppendString(
handle(String::cast(symbol->description()), isolate)); handle(String::cast(symbol->description()), isolate));
...@@ -555,9 +555,9 @@ MaybeHandle<String> Object::NoSideEffectsToMaybeString(Isolate* isolate, ...@@ -555,9 +555,9 @@ MaybeHandle<String> Object::NoSideEffectsToMaybeString(Isolate* isolate,
if (ctor_name->length() != 0) { if (ctor_name->length() != 0) {
IncrementalStringBuilder builder(isolate); IncrementalStringBuilder builder(isolate);
builder.AppendCString("#<"); builder.AppendCStringLiteral("#<");
builder.AppendString(ctor_name); builder.AppendString(ctor_name);
builder.AppendCString(">"); builder.AppendCharacter('>');
return builder.Finish().ToHandleChecked(); return builder.Finish().ToHandleChecked();
} }
...@@ -603,9 +603,9 @@ Handle<String> Object::NoSideEffectsToString(Isolate* isolate, ...@@ -603,9 +603,9 @@ Handle<String> Object::NoSideEffectsToString(Isolate* isolate,
tag_obj->IsString() ? Handle<String>::cast(tag_obj) : builtin_tag; tag_obj->IsString() ? Handle<String>::cast(tag_obj) : builtin_tag;
IncrementalStringBuilder builder(isolate); IncrementalStringBuilder builder(isolate);
builder.AppendCString("[object "); builder.AppendCStringLiteral("[object ");
builder.AppendString(tag); builder.AppendString(tag);
builder.AppendCString("]"); builder.AppendCharacter(']');
return builder.Finish().ToHandleChecked(); return builder.Finish().ToHandleChecked();
} }
......
...@@ -419,19 +419,19 @@ Handle<Object> SharedFunctionInfo::GetSourceCodeHarmony( ...@@ -419,19 +419,19 @@ Handle<Object> SharedFunctionInfo::GetSourceCodeHarmony(
DCHECK(!shared->name_should_print_as_anonymous()); DCHECK(!shared->name_should_print_as_anonymous());
IncrementalStringBuilder builder(isolate); IncrementalStringBuilder builder(isolate);
builder.AppendCString("function "); builder.AppendCStringLiteral("function ");
builder.AppendString(Handle<String>(shared->Name(), isolate)); builder.AppendString(Handle<String>(shared->Name(), isolate));
builder.AppendCString("("); builder.AppendCharacter('(');
Handle<FixedArray> args(Script::cast(shared->script()).wrapped_arguments(), Handle<FixedArray> args(Script::cast(shared->script()).wrapped_arguments(),
isolate); isolate);
int argc = args->length(); int argc = args->length();
for (int i = 0; i < argc; i++) { for (int i = 0; i < argc; i++) {
if (i > 0) builder.AppendCString(", "); if (i > 0) builder.AppendCStringLiteral(", ");
builder.AppendString(Handle<String>(String::cast(args->get(i)), isolate)); builder.AppendString(Handle<String>(String::cast(args->get(i)), isolate));
} }
builder.AppendCString(") {\n"); builder.AppendCStringLiteral(") {\n");
builder.AppendString(source); builder.AppendString(source);
builder.AppendCString("\n}"); builder.AppendCStringLiteral("\n}");
return builder.Finish().ToHandleChecked(); return builder.Finish().ToHandleChecked();
} }
......
...@@ -195,18 +195,18 @@ MaybeHandle<String> FormatEvalOrigin(Isolate* isolate, Handle<Script> script) { ...@@ -195,18 +195,18 @@ MaybeHandle<String> FormatEvalOrigin(Isolate* isolate, Handle<Script> script) {
if (sourceURL->IsString()) return Handle<String>::cast(sourceURL); if (sourceURL->IsString()) return Handle<String>::cast(sourceURL);
IncrementalStringBuilder builder(isolate); IncrementalStringBuilder builder(isolate);
builder.AppendCString("eval at "); builder.AppendCStringLiteral("eval at ");
if (script->has_eval_from_shared()) { if (script->has_eval_from_shared()) {
Handle<SharedFunctionInfo> eval_shared(script->eval_from_shared(), isolate); Handle<SharedFunctionInfo> eval_shared(script->eval_from_shared(), isolate);
auto eval_name = SharedFunctionInfo::DebugName(eval_shared); auto eval_name = SharedFunctionInfo::DebugName(eval_shared);
if (eval_name->length() != 0) { if (eval_name->length() != 0) {
builder.AppendString(eval_name); builder.AppendString(eval_name);
} else { } else {
builder.AppendCString("<anonymous>"); builder.AppendCStringLiteral("<anonymous>");
} }
if (eval_shared->script().IsScript()) { if (eval_shared->script().IsScript()) {
Handle<Script> eval_script(Script::cast(eval_shared->script()), isolate); Handle<Script> eval_script(Script::cast(eval_shared->script()), isolate);
builder.AppendCString(" ("); builder.AppendCStringLiteral(" (");
if (eval_script->compilation_type() == Script::COMPILATION_TYPE_EVAL) { if (eval_script->compilation_type() == Script::COMPILATION_TYPE_EVAL) {
// Eval script originated from another eval. // Eval script originated from another eval.
Handle<String> str; Handle<String> str;
...@@ -222,19 +222,19 @@ MaybeHandle<String> FormatEvalOrigin(Isolate* isolate, Handle<Script> script) { ...@@ -222,19 +222,19 @@ MaybeHandle<String> FormatEvalOrigin(Isolate* isolate, Handle<Script> script) {
if (Script::GetPositionInfo(eval_script, if (Script::GetPositionInfo(eval_script,
Script::GetEvalPosition(isolate, script), Script::GetEvalPosition(isolate, script),
&info, Script::NO_OFFSET)) { &info, Script::NO_OFFSET)) {
builder.AppendCString(":"); builder.AppendCharacter(':');
builder.AppendInt(info.line + 1); builder.AppendInt(info.line + 1);
builder.AppendCString(":"); builder.AppendCharacter(':');
builder.AppendInt(info.column + 1); builder.AppendInt(info.column + 1);
} }
} else { } else {
builder.AppendCString("unknown source"); builder.AppendCStringLiteral("unknown source");
} }
} }
builder.AppendCString(")"); builder.AppendCharacter(')');
} }
} else { } else {
builder.AppendCString("<anonymous>"); builder.AppendCStringLiteral("<anonymous>");
} }
return builder.Finish().ToHandleChecked(); return builder.Finish().ToHandleChecked();
} }
...@@ -581,7 +581,8 @@ void AppendFileLocation(Isolate* isolate, Handle<StackFrameInfo> frame, ...@@ -581,7 +581,8 @@ void AppendFileLocation(Isolate* isolate, Handle<StackFrameInfo> frame,
if (!script_name_or_source_url->IsString() && frame->IsEval()) { if (!script_name_or_source_url->IsString() && frame->IsEval()) {
builder->AppendString( builder->AppendString(
Handle<String>::cast(StackFrameInfo::GetEvalOrigin(frame))); Handle<String>::cast(StackFrameInfo::GetEvalOrigin(frame)));
builder->AppendCString(", "); // Expecting source position to follow. // Expecting source position to follow.
builder->AppendCStringLiteral(", ");
} }
if (IsNonEmptyString(script_name_or_source_url)) { if (IsNonEmptyString(script_name_or_source_url)) {
...@@ -590,7 +591,7 @@ void AppendFileLocation(Isolate* isolate, Handle<StackFrameInfo> frame, ...@@ -590,7 +591,7 @@ void AppendFileLocation(Isolate* isolate, Handle<StackFrameInfo> frame,
// Source code does not originate from a file and is not native, but we // Source code does not originate from a file and is not native, but we
// can still get the source position inside the source string, e.g. in // can still get the source position inside the source string, e.g. in
// an eval string. // an eval string.
builder->AppendCString("<anonymous>"); builder->AppendCStringLiteral("<anonymous>");
} }
int line_number = StackFrameInfo::GetLineNumber(frame); int line_number = StackFrameInfo::GetLineNumber(frame);
...@@ -665,7 +666,7 @@ void AppendMethodCall(Isolate* isolate, Handle<StackFrameInfo> frame, ...@@ -665,7 +666,7 @@ void AppendMethodCall(Isolate* isolate, Handle<StackFrameInfo> frame,
if (IsNonEmptyString(method_name)) { if (IsNonEmptyString(method_name)) {
Handle<String> method_string = Handle<String>::cast(method_name); Handle<String> method_string = Handle<String>::cast(method_name);
if (!StringEndsWithMethodName(isolate, function_string, method_string)) { if (!StringEndsWithMethodName(isolate, function_string, method_string)) {
builder->AppendCString(" [as "); builder->AppendCStringLiteral(" [as ");
builder->AppendString(method_string); builder->AppendString(method_string);
builder->AppendCharacter(']'); builder->AppendCharacter(']');
} }
...@@ -678,7 +679,7 @@ void AppendMethodCall(Isolate* isolate, Handle<StackFrameInfo> frame, ...@@ -678,7 +679,7 @@ void AppendMethodCall(Isolate* isolate, Handle<StackFrameInfo> frame,
if (IsNonEmptyString(method_name)) { if (IsNonEmptyString(method_name)) {
builder->AppendString(Handle<String>::cast(method_name)); builder->AppendString(Handle<String>::cast(method_name));
} else { } else {
builder->AppendCString("<anonymous>"); builder->AppendCStringLiteral("<anonymous>");
} }
} }
} }
...@@ -687,24 +688,24 @@ void SerializeJSStackFrame(Isolate* isolate, Handle<StackFrameInfo> frame, ...@@ -687,24 +688,24 @@ void SerializeJSStackFrame(Isolate* isolate, Handle<StackFrameInfo> frame,
IncrementalStringBuilder* builder) { IncrementalStringBuilder* builder) {
Handle<Object> function_name = StackFrameInfo::GetFunctionName(frame); Handle<Object> function_name = StackFrameInfo::GetFunctionName(frame);
if (frame->IsAsync()) { if (frame->IsAsync()) {
builder->AppendCString("async "); builder->AppendCStringLiteral("async ");
if (frame->IsPromiseAll() || frame->IsPromiseAny()) { if (frame->IsPromiseAll() || frame->IsPromiseAny()) {
builder->AppendCString("Promise."); builder->AppendCStringLiteral("Promise.");
builder->AppendString(Handle<String>::cast(function_name)); builder->AppendString(Handle<String>::cast(function_name));
builder->AppendCString(" (index "); builder->AppendCStringLiteral(" (index ");
builder->AppendInt(StackFrameInfo::GetSourcePosition(frame)); builder->AppendInt(StackFrameInfo::GetSourcePosition(frame));
builder->AppendCString(")"); builder->AppendCharacter(')');
return; return;
} }
} }
if (frame->IsMethodCall()) { if (frame->IsMethodCall()) {
AppendMethodCall(isolate, frame, builder); AppendMethodCall(isolate, frame, builder);
} else if (frame->IsConstructor()) { } else if (frame->IsConstructor()) {
builder->AppendCString("new "); builder->AppendCStringLiteral("new ");
if (IsNonEmptyString(function_name)) { if (IsNonEmptyString(function_name)) {
builder->AppendString(Handle<String>::cast(function_name)); builder->AppendString(Handle<String>::cast(function_name));
} else { } else {
builder->AppendCString("<anonymous>"); builder->AppendCStringLiteral("<anonymous>");
} }
} else if (IsNonEmptyString(function_name)) { } else if (IsNonEmptyString(function_name)) {
builder->AppendString(Handle<String>::cast(function_name)); builder->AppendString(Handle<String>::cast(function_name));
...@@ -712,9 +713,9 @@ void SerializeJSStackFrame(Isolate* isolate, Handle<StackFrameInfo> frame, ...@@ -712,9 +713,9 @@ void SerializeJSStackFrame(Isolate* isolate, Handle<StackFrameInfo> frame,
AppendFileLocation(isolate, frame, builder); AppendFileLocation(isolate, frame, builder);
return; return;
} }
builder->AppendCString(" ("); builder->AppendCStringLiteral(" (");
AppendFileLocation(isolate, frame, builder); AppendFileLocation(isolate, frame, builder);
builder->AppendCString(")"); builder->AppendCharacter(')');
} }
#if V8_ENABLE_WEBASSEMBLY #if V8_ENABLE_WEBASSEMBLY
...@@ -729,32 +730,32 @@ void SerializeWasmStackFrame(Isolate* isolate, Handle<StackFrameInfo> frame, ...@@ -729,32 +730,32 @@ void SerializeWasmStackFrame(Isolate* isolate, Handle<StackFrameInfo> frame,
} else { } else {
builder->AppendString(Handle<String>::cast(module_name)); builder->AppendString(Handle<String>::cast(module_name));
if (!function_name->IsNull()) { if (!function_name->IsNull()) {
builder->AppendCString("."); builder->AppendCharacter('.');
builder->AppendString(Handle<String>::cast(function_name)); builder->AppendString(Handle<String>::cast(function_name));
} }
} }
builder->AppendCString(" ("); builder->AppendCStringLiteral(" (");
} }
Handle<Object> url(frame->GetScriptNameOrSourceURL(), isolate); Handle<Object> url(frame->GetScriptNameOrSourceURL(), isolate);
if (IsNonEmptyString(url)) { if (IsNonEmptyString(url)) {
builder->AppendString(Handle<String>::cast(url)); builder->AppendString(Handle<String>::cast(url));
} else { } else {
builder->AppendCString("<anonymous>"); builder->AppendCStringLiteral("<anonymous>");
} }
builder->AppendCString(":"); builder->AppendCharacter(':');
const int wasm_func_index = frame->GetWasmFunctionIndex(); const int wasm_func_index = frame->GetWasmFunctionIndex();
builder->AppendCString("wasm-function["); builder->AppendCStringLiteral("wasm-function[");
builder->AppendInt(wasm_func_index); builder->AppendInt(wasm_func_index);
builder->AppendCString("]:"); builder->AppendCStringLiteral("]:");
char buffer[16]; char buffer[16];
SNPrintF(base::ArrayVector(buffer), "0x%x", SNPrintF(base::ArrayVector(buffer), "0x%x",
StackFrameInfo::GetColumnNumber(frame) - 1); StackFrameInfo::GetColumnNumber(frame) - 1);
builder->AppendCString(buffer); builder->AppendCString(buffer);
if (has_name) builder->AppendCString(")"); if (has_name) builder->AppendCharacter(')');
} }
#endif // V8_ENABLE_WEBASSEMBLY #endif // V8_ENABLE_WEBASSEMBLY
......
...@@ -876,10 +876,22 @@ uint8_t SeqOneByteString::Get( ...@@ -876,10 +876,22 @@ uint8_t SeqOneByteString::Get(
} }
void SeqOneByteString::SeqOneByteStringSet(int index, uint16_t value) { void SeqOneByteString::SeqOneByteStringSet(int index, uint16_t value) {
DCHECK(index >= 0 && index < length() && value <= kMaxOneByteCharCode); DCHECK_GE(index, 0);
DCHECK_LT(index, length());
DCHECK_LE(value, kMaxOneByteCharCode);
WriteField<byte>(kHeaderSize + index * kCharSize, static_cast<byte>(value)); WriteField<byte>(kHeaderSize + index * kCharSize, static_cast<byte>(value));
} }
void SeqOneByteString::SeqOneByteStringSetChars(int index,
const uint8_t* string,
int string_length) {
DCHECK_LE(0, index);
DCHECK_LT(index + string_length, length());
void* address =
reinterpret_cast<void*>(field_address(kHeaderSize + index * kCharSize));
memcpy(address, string, string_length);
}
Address SeqOneByteString::GetCharsAddress() const { Address SeqOneByteString::GetCharsAddress() const {
return field_address(kHeaderSize); return field_address(kHeaderSize);
} }
......
...@@ -689,6 +689,8 @@ class SeqOneByteString ...@@ -689,6 +689,8 @@ class SeqOneByteString
inline uint8_t Get(int index, PtrComprCageBase cage_base, inline uint8_t Get(int index, PtrComprCageBase cage_base,
const SharedStringAccessGuardIfNeeded& access_guard) const; const SharedStringAccessGuardIfNeeded& access_guard) const;
inline void SeqOneByteStringSet(int index, uint16_t value); inline void SeqOneByteStringSet(int index, uint16_t value);
inline void SeqOneByteStringSetChars(int index, const uint8_t* string,
int length);
// Get the address of the characters in this string. // Get the address of the characters in this string.
inline Address GetCharsAddress() const; inline Address GetCharsAddress() const;
......
...@@ -48,7 +48,7 @@ RUNTIME_FUNCTION(Runtime_SymbolDescriptiveString) { ...@@ -48,7 +48,7 @@ RUNTIME_FUNCTION(Runtime_SymbolDescriptiveString) {
DCHECK_EQ(1, args.length()); DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(Symbol, symbol, 0); CONVERT_ARG_HANDLE_CHECKED(Symbol, symbol, 0);
IncrementalStringBuilder builder(isolate); IncrementalStringBuilder builder(isolate);
builder.AppendCString("Symbol("); builder.AppendCStringLiteral("Symbol(");
if (symbol->description().IsString()) { if (symbol->description().IsString()) {
builder.AppendString(handle(String::cast(symbol->description()), isolate)); builder.AppendString(handle(String::cast(symbol->description()), isolate));
} }
......
...@@ -130,6 +130,24 @@ class IncrementalStringBuilder { ...@@ -130,6 +130,24 @@ class IncrementalStringBuilder {
} }
} }
template <int N>
V8_INLINE void AppendCStringLiteral(const char (&literal)[N]) {
// Note that the literal contains the zero char.
const int length = N - 1;
STATIC_ASSERT(length > 0);
if (length == 1) return AppendCharacter(literal[0]);
if (encoding_ == String::ONE_BYTE_ENCODING && CurrentPartCanFit(N)) {
const uint8_t* chars = reinterpret_cast<const uint8_t*>(literal);
SeqOneByteString::cast(*current_part_)
.SeqOneByteStringSetChars(current_index_, chars, length);
current_index_ += length;
if (current_index_ == part_length_) Extend();
DCHECK(HasValidCurrentIndex());
return;
}
return AppendCString(literal);
}
V8_INLINE void AppendCString(const char* s) { V8_INLINE void AppendCString(const char* s) {
const uint8_t* u = reinterpret_cast<const uint8_t*>(s); const uint8_t* u = reinterpret_cast<const uint8_t*>(s);
if (encoding_ == String::ONE_BYTE_ENCODING) { if (encoding_ == String::ONE_BYTE_ENCODING) {
...@@ -190,19 +208,38 @@ class IncrementalStringBuilder { ...@@ -190,19 +208,38 @@ class IncrementalStringBuilder {
template <typename DestChar> template <typename DestChar>
class NoExtend { class NoExtend {
public: public:
NoExtend(Handle<String> string, int offset, NoExtend(String string, int offset,
const DisallowGarbageCollection& no_gc) { const DisallowGarbageCollection& no_gc) {
DCHECK(string->IsSeqOneByteString() || string->IsSeqTwoByteString()); DCHECK(string.IsSeqOneByteString() || string.IsSeqTwoByteString());
if (sizeof(DestChar) == 1) { if (sizeof(DestChar) == 1) {
start_ = reinterpret_cast<DestChar*>( start_ = reinterpret_cast<DestChar*>(
Handle<SeqOneByteString>::cast(string)->GetChars(no_gc) + offset); SeqOneByteString::cast(string).GetChars(no_gc) + offset);
} else { } else {
start_ = reinterpret_cast<DestChar*>( start_ = reinterpret_cast<DestChar*>(
Handle<SeqTwoByteString>::cast(string)->GetChars(no_gc) + offset); SeqTwoByteString::cast(string).GetChars(no_gc) + offset);
} }
cursor_ = start_; cursor_ = start_;
#ifdef DEBUG
string_ = string;
#endif
} }
#ifdef DEBUG
~NoExtend() {
DestChar* end;
if (sizeof(DestChar) == 1) {
auto one_byte_string = SeqOneByteString::cast(string_);
end = reinterpret_cast<DestChar*>(one_byte_string.GetChars(no_gc_) +
one_byte_string.length());
} else {
auto two_byte_string = SeqTwoByteString::cast(string_);
end = reinterpret_cast<DestChar*>(two_byte_string.GetChars(no_gc_) +
two_byte_string.length());
}
DCHECK_LE(cursor_, end + 1);
}
#endif
V8_INLINE void Append(DestChar c) { *(cursor_++) = c; } V8_INLINE void Append(DestChar c) { *(cursor_++) = c; }
V8_INLINE void AppendCString(const char* s) { V8_INLINE void AppendCString(const char* s) {
const uint8_t* u = reinterpret_cast<const uint8_t*>(s); const uint8_t* u = reinterpret_cast<const uint8_t*>(s);
...@@ -214,6 +251,9 @@ class IncrementalStringBuilder { ...@@ -214,6 +251,9 @@ class IncrementalStringBuilder {
private: private:
DestChar* start_; DestChar* start_;
DestChar* cursor_; DestChar* cursor_;
#ifdef DEBUG
String string_;
#endif
DISALLOW_GARBAGE_COLLECTION(no_gc_) DISALLOW_GARBAGE_COLLECTION(no_gc_)
}; };
...@@ -242,14 +282,15 @@ class IncrementalStringBuilder { ...@@ -242,14 +282,15 @@ class IncrementalStringBuilder {
public: public:
NoExtendBuilder(IncrementalStringBuilder* builder, int required_length, NoExtendBuilder(IncrementalStringBuilder* builder, int required_length,
const DisallowGarbageCollection& no_gc) const DisallowGarbageCollection& no_gc)
: NoExtend<DestChar>(builder->current_part(), builder->current_index_, : NoExtend<DestChar>(*(builder->current_part()),
no_gc), builder->current_index_, no_gc),
builder_(builder) { builder_(builder) {
DCHECK(builder->CurrentPartCanFit(required_length)); DCHECK(builder->CurrentPartCanFit(required_length));
} }
~NoExtendBuilder() { ~NoExtendBuilder() {
builder_->current_index_ += NoExtend<DestChar>::written(); builder_->current_index_ += NoExtend<DestChar>::written();
DCHECK(builder_->HasValidCurrentIndex());
} }
private: private:
...@@ -277,6 +318,8 @@ class IncrementalStringBuilder { ...@@ -277,6 +318,8 @@ class IncrementalStringBuilder {
// Finish the current part and allocate a new part. // Finish the current part and allocate a new part.
void Extend(); void Extend();
bool HasValidCurrentIndex() const;
// Shrink current part to the right size. // Shrink current part to the right size.
void ShrinkCurrentPart() { void ShrinkCurrentPart() {
DCHECK(current_index_ < part_length_); DCHECK(current_index_ < part_length_);
...@@ -314,6 +357,7 @@ void IncrementalStringBuilder::Append(SrcChar c) { ...@@ -314,6 +357,7 @@ void IncrementalStringBuilder::Append(SrcChar c) {
.SeqTwoByteStringSet(current_index_++, c); .SeqTwoByteStringSet(current_index_++, c);
} }
if (current_index_ == part_length_) Extend(); if (current_index_ == part_length_) Extend();
DCHECK(HasValidCurrentIndex());
} }
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
...@@ -246,6 +246,10 @@ int IncrementalStringBuilder::Length() const { ...@@ -246,6 +246,10 @@ int IncrementalStringBuilder::Length() const {
return accumulator_->length() + current_index_; return accumulator_->length() + current_index_;
} }
bool IncrementalStringBuilder::HasValidCurrentIndex() const {
return current_index_ < part_length_;
}
void IncrementalStringBuilder::Accumulate(Handle<String> new_part) { void IncrementalStringBuilder::Accumulate(Handle<String> new_part) {
Handle<String> new_accumulator; Handle<String> new_accumulator;
if (accumulator()->length() + new_part->length() > String::kMaxLength) { if (accumulator()->length() + new_part->length() > String::kMaxLength) {
......
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