Index: src/json-stringifier.h |
diff --git a/src/json-stringifier.h b/src/json-stringifier.h |
index 0b084e070d0aa43eeef090c92c4ff517ee1f3dbc..8172b7080c2559fcceae010dc02c319706884c9b 100644 |
--- a/src/json-stringifier.h |
+++ b/src/json-stringifier.h |
@@ -85,8 +85,10 @@ class BasicJsonStringifier BASE_EMBEDDED { |
INLINE(Result SerializeJSArray(Handle<JSArray> object)); |
INLINE(Result SerializeJSObject(Handle<JSObject> object)); |
- Result SerializeJSArraySlow(Handle<JSArray> object, uint32_t start, |
- uint32_t length); |
+ Result SerializeJSProxy(Handle<JSProxy> object); |
+ Result SerializeJSReceiverSlow(Handle<JSReceiver> object); |
+ Result SerializeArrayLikeSlow(Handle<JSReceiver> object, uint32_t start, |
+ uint32_t length); |
void SerializeString(Handle<String> object); |
@@ -326,7 +328,7 @@ void BasicJsonStringifier::StackPop() { |
template <bool deferred_string_key> |
BasicJsonStringifier::Result BasicJsonStringifier::Serialize_( |
Handle<Object> object, bool comma, Handle<Object> key) { |
- if (object->IsJSObject()) { |
+ if (object->IsJSReceiver()) { |
ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
isolate_, object, |
ApplyToJsonFunction(object, key), |
@@ -372,11 +374,14 @@ BasicJsonStringifier::Result BasicJsonStringifier::Serialize_( |
if (deferred_string_key) SerializeDeferredKey(comma, key); |
SerializeString(Handle<String>::cast(object)); |
return SUCCESS; |
- } else if (object->IsJSObject()) { |
+ } else if (object->IsJSReceiver()) { |
if (object->IsCallable()) return UNCHANGED; |
// Go to slow path for global proxy and objects requiring access checks. |
if (object->IsAccessCheckNeeded() || object->IsJSGlobalProxy()) break; |
if (deferred_string_key) SerializeDeferredKey(comma, key); |
+ if (object->IsJSProxy()) { |
+ return SerializeJSProxy(Handle<JSProxy>::cast(object)); |
+ } |
return SerializeJSObject(Handle<JSObject>::cast(object)); |
} |
} |
@@ -494,7 +499,7 @@ BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSArray( |
for (uint32_t i = 0; i < length; i++) { |
if (object->length() != *old_length || |
object->GetElementsKind() != FAST_ELEMENTS) { |
- Result result = SerializeJSArraySlow(object, i, length); |
+ Result result = SerializeArrayLikeSlow(object, i, length); |
if (result != SUCCESS) return result; |
break; |
} |
@@ -516,7 +521,7 @@ BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSArray( |
// The FAST_HOLEY_* cases could be handled in a faster way. They resemble |
// the non-holey cases except that a lookup is necessary for holes. |
default: { |
- Result result = SerializeJSArraySlow(object, 0, length); |
+ Result result = SerializeArrayLikeSlow(object, 0, length); |
if (result != SUCCESS) return result; |
break; |
} |
@@ -528,9 +533,8 @@ BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSArray( |
return SUCCESS; |
} |
- |
-BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSArraySlow( |
- Handle<JSArray> object, uint32_t start, uint32_t length) { |
+BasicJsonStringifier::Result BasicJsonStringifier::SerializeArrayLikeSlow( |
+ Handle<JSReceiver> object, uint32_t start, uint32_t length) { |
for (uint32_t i = start; i < length; i++) { |
Separator(i == 0); |
Handle<Object> element; |
@@ -552,7 +556,6 @@ BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSArraySlow( |
return SUCCESS; |
} |
- |
BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSObject( |
Handle<JSObject> object) { |
HandleScope handle_scope(isolate_); |
@@ -560,15 +563,17 @@ BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSObject( |
if (stack_push != SUCCESS) return stack_push; |
DCHECK(!object->IsJSGlobalProxy() && !object->IsJSGlobalObject()); |
- builder_.AppendCharacter('{'); |
- Indent(); |
- bool comma = false; |
- |
- if (object->HasFastProperties() && |
- !object->HasIndexedInterceptor() && |
- !object->HasNamedInterceptor() && |
- object->elements()->length() == 0) { |
- Handle<Map> map(object->map()); |
+ if (object->map()->instance_type() > LAST_CUSTOM_ELEMENTS_RECEIVER && |
+ object->HasFastProperties() && |
+ Handle<JSObject>::cast(object)->elements()->length() == 0) { |
+ DCHECK(object->IsJSObject()); |
+ Handle<JSObject> js_obj = Handle<JSObject>::cast(object); |
+ DCHECK(!js_obj->HasIndexedInterceptor()); |
+ DCHECK(!js_obj->HasNamedInterceptor()); |
+ Handle<Map> map(js_obj->map()); |
+ builder_.AppendCharacter('{'); |
+ Indent(); |
+ bool comma = false; |
for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) { |
Handle<Name> name(map->instance_descriptors()->GetKey(i), isolate_); |
// TODO(rossberg): Should this throw? |
@@ -577,60 +582,104 @@ BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSObject( |
PropertyDetails details = map->instance_descriptors()->GetDetails(i); |
if (details.IsDontEnum()) continue; |
Handle<Object> property; |
- if (details.type() == DATA && *map == object->map()) { |
+ if (details.type() == DATA && *map == js_obj->map()) { |
FieldIndex field_index = FieldIndex::ForDescriptor(*map, i); |
- Isolate* isolate = object->GetIsolate(); |
- if (object->IsUnboxedDoubleField(field_index)) { |
- double value = object->RawFastDoublePropertyAt(field_index); |
- property = isolate->factory()->NewHeapNumber(value); |
- |
+ if (js_obj->IsUnboxedDoubleField(field_index)) { |
+ double value = js_obj->RawFastDoublePropertyAt(field_index); |
+ property = isolate_->factory()->NewHeapNumber(value); |
} else { |
- property = handle(object->RawFastPropertyAt(field_index), isolate); |
+ property = handle(js_obj->RawFastPropertyAt(field_index), isolate_); |
} |
} else { |
ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
- isolate_, property, |
- Object::GetPropertyOrElement(object, key), |
+ isolate_, property, Object::GetPropertyOrElement(js_obj, key), |
EXCEPTION); |
} |
Result result = SerializeProperty(property, comma, key); |
if (!comma && result == SUCCESS) comma = true; |
if (result == EXCEPTION) return result; |
} |
+ Unindent(); |
+ if (comma) NewLine(); |
+ builder_.AppendCharacter('}'); |
} else { |
- Handle<FixedArray> contents; |
- ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
- isolate_, contents, |
- JSReceiver::GetKeys(object, OWN_ONLY, ENUMERABLE_STRINGS), EXCEPTION); |
- |
- for (int i = 0; i < contents->length(); i++) { |
- Object* key = contents->get(i); |
- Handle<String> key_handle; |
- MaybeHandle<Object> maybe_property; |
- if (key->IsString()) { |
- key_handle = Handle<String>(String::cast(key), isolate_); |
- maybe_property = Object::GetPropertyOrElement(object, key_handle); |
+ Result result = SerializeJSReceiverSlow(object); |
+ if (result != SUCCESS) return result; |
+ } |
+ StackPop(); |
+ return SUCCESS; |
+} |
+ |
+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); |
+ |
+ builder_.AppendCharacter('{'); |
+ Indent(); |
+ bool comma = false; |
+ for (int i = 0; i < contents->length(); i++) { |
+ Object* key = contents->get(i); |
+ Handle<String> key_handle; |
+ MaybeHandle<Object> maybe_property; |
+ if (key->IsString()) { |
+ key_handle = Handle<String>(String::cast(key), isolate_); |
+ maybe_property = Object::GetPropertyOrElement(object, key_handle); |
+ } else { |
+ DCHECK(key->IsNumber()); |
+ key_handle = factory()->NumberToString(Handle<Object>(key, isolate_)); |
+ if (key->IsSmi()) { |
+ maybe_property = |
+ JSReceiver::GetElement(isolate_, object, Smi::cast(key)->value()); |
} else { |
- DCHECK(key->IsNumber()); |
- key_handle = factory()->NumberToString(Handle<Object>(key, isolate_)); |
- if (key->IsSmi()) { |
- maybe_property = |
- JSReceiver::GetElement(isolate_, object, Smi::cast(key)->value()); |
- } else { |
- maybe_property = Object::GetPropertyOrElement(object, key_handle); |
- } |
+ maybe_property = Object::GetPropertyOrElement(object, key_handle); |
} |
- Handle<Object> property; |
- ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
- isolate_, property, maybe_property, EXCEPTION); |
- Result result = SerializeProperty(property, comma, key_handle); |
- if (!comma && result == SUCCESS) comma = true; |
- if (result == EXCEPTION) return result; |
} |
+ Handle<Object> property; |
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, property, maybe_property, |
+ EXCEPTION); |
+ Result result = SerializeProperty(property, comma, key_handle); |
+ if (!comma && result == SUCCESS) comma = true; |
+ if (result == EXCEPTION) return result; |
} |
Unindent(); |
if (comma) NewLine(); |
builder_.AppendCharacter('}'); |
+ return SUCCESS; |
+} |
+ |
+BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSProxy( |
+ Handle<JSProxy> object) { |
+ Result stack_push = StackPush(object); |
+ if (stack_push != SUCCESS) return stack_push; |
+ Maybe<bool> is_array = Object::IsArray(object); |
+ if (is_array.IsNothing()) return EXCEPTION; |
+ if (is_array.FromJust()) { |
+ Handle<Object> length_object; |
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
+ isolate_, length_object, |
+ Object::GetLengthFromArrayLike(isolate_, object), EXCEPTION); |
+ uint32_t length; |
+ if (!length_object->ToUint32(&length)) { |
+ // Technically, we need to be able to handle lengths outside the |
+ // uint32_t range. However, we would run into string size overflow |
+ // if we tried to stringify such an array. |
+ isolate_->Throw(*isolate_->factory()->NewInvalidStringLengthError()); |
+ return EXCEPTION; |
+ } |
+ builder_.AppendCharacter('['); |
+ Indent(); |
+ Result result = SerializeArrayLikeSlow(object, 0, length); |
+ if (result != SUCCESS) return result; |
+ Unindent(); |
+ if (length > 0) NewLine(); |
+ builder_.AppendCharacter(']'); |
+ } else { |
+ Result result = SerializeJSReceiverSlow(object); |
+ if (result != SUCCESS) return result; |
+ } |
StackPop(); |
return SUCCESS; |
} |