diff --git a/src/json-stringifier.cc b/src/json-stringifier.cc index a92b5e265c..1d3858f351 100644 --- a/src/json-stringifier.cc +++ b/src/json-stringifier.cc @@ -74,12 +74,13 @@ class JsonStringifier { return SerializeDouble(object->value()); } - Result SerializeJSValue(Handle object); + Result SerializeJSValue(Handle object, Handle key); - V8_INLINE Result SerializeJSArray(Handle object); - V8_INLINE Result SerializeJSObject(Handle object); + V8_INLINE Result SerializeJSArray(Handle object, Handle key); + V8_INLINE Result SerializeJSObject(Handle object, + Handle key); - Result SerializeJSProxy(Handle object); + Result SerializeJSProxy(Handle object, Handle key); Result SerializeJSReceiverSlow(Handle object); Result SerializeArrayLikeSlow(Handle object, uint32_t start, uint32_t length); @@ -105,7 +106,7 @@ class JsonStringifier { Handle CurrentHolder(Handle value, Handle inital_holder); - Result StackPush(Handle object); + Result StackPush(Handle object, Handle key); void StackPop(); Factory* factory() { return isolate_->factory(); } @@ -113,12 +114,14 @@ class JsonStringifier { Isolate* isolate_; IncrementalStringBuilder builder_; Handle tojson_string_; - Handle stack_; Handle property_list_; Handle replacer_function_; uc16* gap_; int indent_; + using KeyObject = std::pair, Handle>; + std::vector stack_; + static const int kJsonEscapeTableEntrySize = 8; static const char* const JsonEscapeTable; }; @@ -198,9 +201,12 @@ const char* const JsonStringifier::JsonEscapeTable = "\xFC\0 \xFD\0 \xFE\0 \xFF\0 "; JsonStringifier::JsonStringifier(Isolate* isolate) - : isolate_(isolate), builder_(isolate), gap_(nullptr), indent_(0) { + : isolate_(isolate), + builder_(isolate), + gap_(nullptr), + indent_(0), + stack_() { tojson_string_ = factory()->toJSON_string(); - stack_ = factory()->NewJSArray(8); } MaybeHandle JsonStringifier::Stringify(Handle object, @@ -345,33 +351,30 @@ MaybeHandle JsonStringifier::ApplyReplacerFunction( Handle JsonStringifier::CurrentHolder( Handle value, Handle initial_holder) { - int length = Smi::ToInt(stack_->length()); - if (length == 0) { + if (stack_.empty()) { Handle holder = factory()->NewJSObject(isolate_->object_function()); JSObject::AddProperty(isolate_, holder, factory()->empty_string(), initial_holder, NONE); return holder; } else { - FixedArray elements = FixedArray::cast(stack_->elements()); - return Handle(JSReceiver::cast(elements->get(length - 1)), + return Handle(JSReceiver::cast(*stack_.back().second), isolate_); } } -JsonStringifier::Result JsonStringifier::StackPush(Handle object) { +JsonStringifier::Result JsonStringifier::StackPush(Handle object, + Handle key) { StackLimitCheck check(isolate_); if (check.HasOverflowed()) { isolate_->StackOverflow(); return EXCEPTION; } - int length = Smi::ToInt(stack_->length()); { DisallowHeapAllocation no_allocation; - FixedArray elements = FixedArray::cast(stack_->elements()); - for (int i = 0; i < length; i++) { - if (elements->get(i) == *object) { + for (const KeyObject& key_object : stack_) { + if (*key_object.second == *object) { AllowHeapAllocation allow_to_return_error; Handle error = factory()->NewTypeError(MessageTemplate::kCircularStructure); @@ -380,15 +383,11 @@ JsonStringifier::Result JsonStringifier::StackPush(Handle object) { } } } - JSArray::SetLength(stack_, length + 1); - FixedArray::cast(stack_->elements())->set(length, *object); + stack_.emplace_back(key, object); return SUCCESS; } -void JsonStringifier::StackPop() { - int length = Smi::ToInt(stack_->length()); - stack_->set_length(Smi::FromInt(length - 1)); -} +void JsonStringifier::StackPop() { stack_.pop_back(); } template JsonStringifier::Result JsonStringifier::Serialize_(Handle object, @@ -443,10 +442,10 @@ JsonStringifier::Result JsonStringifier::Serialize_(Handle object, } case JS_ARRAY_TYPE: if (deferred_string_key) SerializeDeferredKey(comma, key); - return SerializeJSArray(Handle::cast(object)); + return SerializeJSArray(Handle::cast(object), key); case JS_VALUE_TYPE: if (deferred_string_key) SerializeDeferredKey(comma, key); - return SerializeJSValue(Handle::cast(object)); + return SerializeJSValue(Handle::cast(object), key); case SYMBOL_TYPE: return UNCHANGED; default: @@ -460,9 +459,9 @@ JsonStringifier::Result JsonStringifier::Serialize_(Handle object, // Go to slow path for global proxy and objects requiring access checks. if (deferred_string_key) SerializeDeferredKey(comma, key); if (object->IsJSProxy()) { - return SerializeJSProxy(Handle::cast(object)); + return SerializeJSProxy(Handle::cast(object), key); } - return SerializeJSObject(Handle::cast(object)); + return SerializeJSObject(Handle::cast(object), key); } } @@ -470,7 +469,7 @@ JsonStringifier::Result JsonStringifier::Serialize_(Handle object, } JsonStringifier::Result JsonStringifier::SerializeJSValue( - Handle object) { + Handle object, Handle key) { Object raw = object->value(); if (raw->IsString()) { Handle value; @@ -491,7 +490,7 @@ JsonStringifier::Result JsonStringifier::SerializeJSValue( builder_.AppendCString(raw->IsTrue(isolate_) ? "true" : "false"); } else { // ES6 24.3.2.1 step 10.c, serialize as an ordinary JSObject. - return SerializeJSObject(object); + return SerializeJSObject(object, key); } return SUCCESS; } @@ -517,9 +516,9 @@ JsonStringifier::Result JsonStringifier::SerializeDouble(double number) { } JsonStringifier::Result JsonStringifier::SerializeJSArray( - Handle object) { + Handle object, Handle key) { HandleScope handle_scope(isolate_); - Result stack_push = StackPush(object); + Result stack_push = StackPush(object, key); if (stack_push != SUCCESS) return stack_push; uint32_t length = 0; CHECK(object->length()->ToArrayLength(&length)); @@ -632,9 +631,9 @@ JsonStringifier::Result JsonStringifier::SerializeArrayLikeSlow( } JsonStringifier::Result JsonStringifier::SerializeJSObject( - Handle object) { + Handle object, Handle key) { HandleScope handle_scope(isolate_); - Result stack_push = StackPush(object); + Result stack_push = StackPush(object, key); if (stack_push != SUCCESS) return stack_push; if (property_list_.is_null() && @@ -711,9 +710,9 @@ JsonStringifier::Result JsonStringifier::SerializeJSReceiverSlow( } JsonStringifier::Result JsonStringifier::SerializeJSProxy( - Handle object) { + Handle object, Handle key) { HandleScope scope(isolate_); - Result stack_push = StackPush(object); + Result stack_push = StackPush(object, key); if (stack_push != SUCCESS) return stack_push; Maybe is_array = Object::IsArray(object); if (is_array.IsNothing()) return EXCEPTION;