Index: src/json-stringifier.cc |
diff --git a/src/json-stringifier.cc b/src/json-stringifier.cc |
index ac206822e9abc5b704c3aad1d8f09e18603c984a..79463f1d983b68016dfbb89e051720fc2b328b70 100644 |
--- a/src/json-stringifier.cc |
+++ b/src/json-stringifier.cc |
@@ -88,7 +88,9 @@ BasicJsonStringifier::BasicJsonStringifier(Isolate* isolate) |
} |
MaybeHandle<Object> BasicJsonStringifier::Stringify(Handle<Object> object, |
+ Handle<Object> replacer, |
Handle<Object> gap) { |
+ if (!InitializeReplacer(replacer)) return MaybeHandle<Object>(); |
if (!gap->IsUndefined() && !InitializeGap(gap)) return MaybeHandle<Object>(); |
Result result = SerializeObject(object); |
if (result == UNCHANGED) return factory()->undefined_value(); |
@@ -97,15 +99,64 @@ MaybeHandle<Object> BasicJsonStringifier::Stringify(Handle<Object> object, |
return MaybeHandle<Object>(); |
} |
+bool IsInList(Handle<String> key, List<Handle<String> >* list) { |
+ // TODO(yangguo): This is O(n^2) for n properties in the list. Deal with this |
+ // if this becomes an issue. |
+ for (const Handle<String>& existing : *list) { |
+ if (String::Equals(existing, key)) return true; |
+ } |
+ return false; |
+} |
+ |
+bool BasicJsonStringifier::InitializeReplacer(Handle<Object> replacer) { |
+ DCHECK(property_list_.is_null()); |
+ Maybe<bool> is_array = Object::IsArray(replacer); |
+ if (is_array.IsNothing()) return false; |
+ if (is_array.FromJust()) { |
+ HandleScope handle_scope(isolate_); |
+ List<Handle<String> > list; |
+ Handle<Object> length_obj; |
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
+ isolate_, length_obj, |
+ Object::GetLengthFromArrayLike(isolate_, replacer), false); |
+ uint32_t length; |
+ if (!length_obj->ToUint32(&length)) length = kMaxUInt32; |
+ for (uint32_t i = 0; i < length; i++) { |
+ Handle<Object> element; |
+ Handle<String> key; |
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
+ isolate_, element, Object::GetElement(isolate_, replacer, i), false); |
+ if (element->IsNumber() || element->IsString()) { |
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
+ isolate_, key, Object::ToString(isolate_, element), false); |
+ } else if (element->IsJSValue()) { |
+ Handle<Object> value(Handle<JSValue>::cast(element)->value(), isolate_); |
+ if (value->IsNumber() || value->IsString()) { |
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
+ isolate_, key, Object::ToString(isolate_, element), false); |
+ } |
+ } |
+ if (key.is_null()) continue; |
+ if (!IsInList(key, &list)) list.Add(key); |
+ } |
+ property_list_ = factory()->NewUninitializedFixedArray(list.length()); |
+ for (int i = 0; i < list.length(); i++) { |
+ property_list_->set(i, *list[i]); |
+ } |
+ property_list_ = handle_scope.CloseAndEscape(property_list_); |
+ } |
+ return true; |
+} |
+ |
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())) { |
+ if (gap->IsJSValue()) { |
+ Handle<Object> value(Handle<JSValue>::cast(gap)->value(), isolate_); |
+ if (value->IsString()) { |
ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, gap, |
Object::ToString(isolate_, gap), false); |
- } else if (class_name.is_identical_to(factory()->number_string())) { |
+ } else if (value->IsNumber()) { |
ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, gap, Object::ToNumber(gap), |
false); |
} |
@@ -146,7 +197,8 @@ MaybeHandle<Object> BasicJsonStringifier::StringifyString( |
if (worst_case_length > 32 * KB) { // Slow path if too large. |
BasicJsonStringifier stringifier(isolate); |
- return stringifier.Stringify(object, isolate->factory()->undefined_value()); |
+ Handle<Object> undefined = isolate->factory()->undefined_value(); |
+ return stringifier.Stringify(object, undefined, undefined); |
} |
object = String::Flatten(object); |
@@ -437,7 +489,8 @@ BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSObject( |
Result stack_push = StackPush(object); |
if (stack_push != SUCCESS) return stack_push; |
- if (object->map()->instance_type() > LAST_CUSTOM_ELEMENTS_RECEIVER && |
+ if (property_list_.is_null() && |
+ object->map()->instance_type() > LAST_CUSTOM_ELEMENTS_RECEIVER && |
object->HasFastProperties() && |
Handle<JSObject>::cast(object)->elements()->length() == 0) { |
DCHECK(object->IsJSObject()); |
@@ -487,10 +540,12 @@ BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSObject( |
BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSReceiverSlow( |
Handle<JSReceiver> object) { |
- Handle<FixedArray> contents; |
- ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
- isolate_, contents, |
- JSReceiver::GetKeys(object, OWN_ONLY, ENUMERABLE_STRINGS), EXCEPTION); |
+ Handle<FixedArray> contents = property_list_; |
+ if (contents.is_null()) { |
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
+ isolate_, contents, |
+ JSReceiver::GetKeys(object, OWN_ONLY, ENUMERABLE_STRINGS), EXCEPTION); |
+ } |
builder_.AppendCharacter('{'); |
Indent(); |