[json] implement JSON.stringify gap pre-processing in C++.

This is in preparation of fully porting JSON.stringify to C++.

R=cbruni@chromium.org

Review-Url: https://codereview.chromium.org/2006663002
Cr-Commit-Position: refs/heads/master@{#36449}
This commit is contained in:
yangguo 2016-05-23 11:21:37 -07:00 committed by Commit bot
parent f43aa0bc6c
commit c1f1e1ab98
5 changed files with 59 additions and 32 deletions

View File

@ -2778,8 +2778,8 @@ MaybeLocal<String> JSON::Stringify(Local<Context> context,
? isolate->factory()->empty_string()
: Utils::OpenHandle(*gap);
i::Handle<i::Object> maybe;
has_pending_exception = !i::BasicJsonStringifier(isolate, gap_string)
.Stringify(object)
has_pending_exception = !i::BasicJsonStringifier(isolate)
.Stringify(object, gap_string)
.ToHandle(&maybe);
RETURN_ON_FAILED_EXECUTION(String);
Local<String> result;

View File

@ -233,6 +233,9 @@ function JSONStringify(value, replacer, space) {
space = TO_STRING(space);
}
}
if (!IS_CALLABLE(replacer) && !property_list) {
return %BasicJSONStringify(value, space);
}
var gap;
if (IS_NUMBER(space)) {
space = MaxSimple(0, MinSimple(TO_INTEGER(space), 10));
@ -246,9 +249,6 @@ function JSONStringify(value, replacer, space) {
} else {
gap = "";
}
if (!IS_CALLABLE(replacer) && !property_list) {
return %BasicJSONStringify(value, gap);
}
return JSONSerialize('', {'': value}, replacer, new Stack(), "", gap);
}

View File

@ -81,29 +81,15 @@ const char* const BasicJsonStringifier::JsonEscapeTable =
"\370\0 \371\0 \372\0 \373\0 "
"\374\0 \375\0 \376\0 \377\0 ";
BasicJsonStringifier::BasicJsonStringifier(Isolate* isolate, Handle<String> gap)
: isolate_(isolate), builder_(isolate), gap_string_(gap), indent_(0) {
BasicJsonStringifier::BasicJsonStringifier(Isolate* isolate)
: isolate_(isolate), builder_(isolate), gap_(nullptr), indent_(0) {
tojson_string_ = factory()->toJSON_string();
stack_ = factory()->NewJSArray(8);
int gap_length = gap->length();
if (gap_length != 0) {
gap = String::Flatten(gap);
if (gap->IsTwoByteRepresentation()) builder_.ChangeEncoding();
DisallowHeapAllocation no_gc;
String::FlatContent flat = gap->GetFlatContent();
gap_ = NewArray<uc16>(gap_length + 1);
if (flat.IsOneByte()) {
CopyChars(gap_, flat.ToOneByteVector().start(), gap_length);
} else {
CopyChars(gap_, flat.ToUC16Vector().start(), gap_length);
}
gap_[gap_length] = '\0';
} else {
gap_ = nullptr;
}
}
MaybeHandle<Object> BasicJsonStringifier::Stringify(Handle<Object> object) {
MaybeHandle<Object> BasicJsonStringifier::Stringify(Handle<Object> object,
Handle<Object> gap) {
if (!gap->IsUndefined() && !InitializeGap(gap)) return MaybeHandle<Object>();
Result result = SerializeObject(object);
if (result == UNCHANGED) return factory()->undefined_value();
if (result == SUCCESS) return builder_.Finish();
@ -111,6 +97,46 @@ MaybeHandle<Object> BasicJsonStringifier::Stringify(Handle<Object> object) {
return MaybeHandle<Object>();
}
bool BasicJsonStringifier::InitializeGap(Handle<Object> gap) {
DCHECK_NULL(gap_);
HandleScope scope(isolate_);
if (gap->IsJSReceiver()) {
Handle<String> class_name(Handle<JSReceiver>::cast(gap)->class_name());
if (class_name.is_identical_to(factory()->String_string())) {
ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, gap,
Object::ToString(isolate_, gap), false);
} else if (class_name.is_identical_to(factory()->number_string())) {
ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, gap, Object::ToNumber(gap),
false);
}
}
if (gap->IsString()) {
Handle<String> gap_string = Handle<String>::cast(gap);
if (gap_string->length() > 0) {
int gap_length = std::min(gap_string->length(), 10);
gap_ = NewArray<uc16>(gap_length + 1);
String::WriteToFlat(*gap_string, gap_, 0, gap_length);
for (int i = 0; i < gap_length; i++) {
if (gap_[i] > String::kMaxOneByteCharCode) {
builder_.ChangeEncoding();
break;
}
}
gap_[gap_length] = '\0';
}
} else if (gap->IsNumber()) {
int num_value = DoubleToInt32(gap->Number());
if (num_value > 0) {
int gap_length = std::min(num_value, 10);
gap_ = NewArray<uc16>(gap_length + 1);
for (int i = 0; i < gap_length; i++) gap_[i] = ' ';
gap_[gap_length] = '\0';
}
}
return true;
}
MaybeHandle<Object> BasicJsonStringifier::StringifyString(
Isolate* isolate, Handle<String> object) {
static const int kJsonQuoteWorstCaseBlowup = 6;
@ -119,9 +145,8 @@ MaybeHandle<Object> BasicJsonStringifier::StringifyString(
object->length() * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
if (worst_case_length > 32 * KB) { // Slow path if too large.
BasicJsonStringifier stringifier(isolate,
isolate->factory()->empty_string());
return stringifier.Stringify(object);
BasicJsonStringifier stringifier(isolate);
return stringifier.Stringify(object, isolate->factory()->undefined_value());
}
object = String::Flatten(object);

View File

@ -13,11 +13,12 @@ namespace internal {
class BasicJsonStringifier BASE_EMBEDDED {
public:
BasicJsonStringifier(Isolate* isolate, Handle<String> gap);
explicit BasicJsonStringifier(Isolate* isolate);
~BasicJsonStringifier() { DeleteArray(gap_); }
MUST_USE_RESULT MaybeHandle<Object> Stringify(Handle<Object> object);
MUST_USE_RESULT MaybeHandle<Object> Stringify(Handle<Object> object,
Handle<Object> gap);
MUST_USE_RESULT static MaybeHandle<Object> StringifyString(
Isolate* isolate, Handle<String> object);
@ -25,6 +26,8 @@ class BasicJsonStringifier BASE_EMBEDDED {
private:
enum Result { UNCHANGED, SUCCESS, EXCEPTION };
bool InitializeGap(Handle<Object> gap);
MUST_USE_RESULT MaybeHandle<Object> ApplyToJsonFunction(
Handle<Object> object,
Handle<Object> key);
@ -104,7 +107,6 @@ class BasicJsonStringifier BASE_EMBEDDED {
IncrementalStringBuilder builder_;
Handle<String> tojson_string_;
Handle<JSArray> stack_;
Handle<String> gap_string_;
uc16* gap_;
int indent_;

View File

@ -28,10 +28,10 @@ RUNTIME_FUNCTION(Runtime_BasicJSONStringify) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
CONVERT_ARG_HANDLE_CHECKED(String, gap, 1);
CONVERT_ARG_HANDLE_CHECKED(Object, gap, 1);
Handle<Object> result;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, result, BasicJsonStringifier(isolate, gap).Stringify(object));
isolate, result, BasicJsonStringifier(isolate).Stringify(object, gap));
return *result;
}