diff options
Diffstat (limited to 'deps/v8/src/json/json-parser.cc')
-rw-r--r-- | deps/v8/src/json/json-parser.cc | 324 |
1 files changed, 283 insertions, 41 deletions
diff --git a/deps/v8/src/json/json-parser.cc b/deps/v8/src/json/json-parser.cc index c124eedb47..8d5f563fdf 100644 --- a/deps/v8/src/json/json-parser.cc +++ b/deps/v8/src/json/json-parser.cc @@ -122,20 +122,34 @@ static const constexpr uint8_t character_json_scan_flags[256] = { } // namespace MaybeHandle<Object> JsonParseInternalizer::Internalize(Isolate* isolate, - Handle<Object> object, - Handle<Object> reviver) { + Handle<Object> result, + Handle<Object> reviver, + Handle<String> source) { DCHECK(reviver->IsCallable()); - JsonParseInternalizer internalizer(isolate, - Handle<JSReceiver>::cast(reviver)); + JsonParseInternalizer internalizer(isolate, Handle<JSReceiver>::cast(reviver), + source); Handle<JSObject> holder = isolate->factory()->NewJSObject(isolate->object_function()); Handle<String> name = isolate->factory()->empty_string(); - JSObject::AddProperty(isolate, holder, name, object, NONE); - return internalizer.InternalizeJsonProperty(holder, name); + if (v8_flags.harmony_json_parse_with_source) { + DCHECK(result->IsFixedArray()); + Handle<FixedArray> array = Handle<FixedArray>::cast(result); + DCHECK_EQ(2, array->length()); + Handle<Object> object(array->get(0), isolate); + Handle<Object> val_node(array->get(1), isolate); + JSObject::AddProperty(isolate, holder, name, object, NONE); + return internalizer.InternalizeJsonProperty(holder, name, val_node); + } else { + JSObject::AddProperty(isolate, holder, name, result, NONE); + return internalizer.InternalizeJsonProperty(holder, name, Handle<Object>()); + } } +// TODO(v8:12955): Fix the parse node assert bug. See +// https://github.com/tc39/proposal-json-parse-with-source/issues/35. MaybeHandle<Object> JsonParseInternalizer::InternalizeJsonProperty( - Handle<JSReceiver> holder, Handle<String> name) { + Handle<JSReceiver> holder, Handle<String> name, Handle<Object> val_node) { + DCHECK(reviver_->IsCallable()); HandleScope outer_scope(isolate_); Handle<Object> value; ASSIGN_RETURN_ON_EXCEPTION( @@ -151,11 +165,31 @@ MaybeHandle<Object> JsonParseInternalizer::InternalizeJsonProperty( isolate_, length_object, Object::GetLengthFromArrayLike(isolate_, object), Object); double length = length_object->Number(); - for (double i = 0; i < length; i++) { - HandleScope inner_scope(isolate_); - Handle<Object> index = isolate_->factory()->NewNumber(i); - Handle<String> index_name = isolate_->factory()->NumberToString(index); - if (!RecurseAndApply(object, index_name)) return MaybeHandle<Object>(); + + if (v8_flags.harmony_json_parse_with_source) { + DCHECK(val_node->IsFixedArray()); + Handle<FixedArray> val_nodes = Handle<FixedArray>::cast(val_node); + for (double i = 0; i < length; i++) { + HandleScope inner_scope(isolate_); + Handle<Object> index = isolate_->factory()->NewNumber(i); + Handle<String> index_name = + isolate_->factory()->NumberToString(index); + if (!RecurseAndApply(object, index_name, + handle(val_nodes->get(i), isolate_))) { + return MaybeHandle<Object>(); + } + } + } else { + DCHECK(val_node.is_null()); + for (double i = 0; i < length; i++) { + HandleScope inner_scope(isolate_); + Handle<Object> index = isolate_->factory()->NewNumber(i); + Handle<String> index_name = + isolate_->factory()->NumberToString(index); + if (!RecurseAndApply(object, index_name, Handle<Object>())) { + return MaybeHandle<Object>(); + } + } } } else { Handle<FixedArray> contents; @@ -165,28 +199,64 @@ MaybeHandle<Object> JsonParseInternalizer::InternalizeJsonProperty( ENUMERABLE_STRINGS, GetKeysConversion::kConvertToString), Object); - for (int i = 0; i < contents->length(); i++) { - HandleScope inner_scope(isolate_); - Handle<String> key_name(String::cast(contents->get(i)), isolate_); - if (!RecurseAndApply(object, key_name)) return MaybeHandle<Object>(); + if (v8_flags.harmony_json_parse_with_source) { + DCHECK(val_node->IsObjectHashTable()); + Handle<ObjectHashTable> val_nodes = + Handle<ObjectHashTable>::cast(val_node); + for (int i = 0; i < contents->length(); i++) { + HandleScope inner_scope(isolate_); + Handle<String> key_name(String::cast(contents->get(i)), isolate_); + Handle<Object> node = handle(val_nodes->Lookup(key_name), isolate_); + DCHECK(!node->IsTheHole()); + if (!RecurseAndApply(object, key_name, node)) { + return MaybeHandle<Object>(); + } + } + } else { + DCHECK(val_node.is_null()); + for (int i = 0; i < contents->length(); i++) { + HandleScope inner_scope(isolate_); + Handle<String> key_name(String::cast(contents->get(i)), isolate_); + if (!RecurseAndApply(object, key_name, Handle<Object>())) { + return MaybeHandle<Object>(); + } + } } } } - Handle<Object> argv[] = {name, value}; Handle<Object> result; - ASSIGN_RETURN_ON_EXCEPTION( - isolate_, result, Execution::Call(isolate_, reviver_, holder, 2, argv), - Object); + if (v8_flags.harmony_json_parse_with_source) { + DCHECK(!val_node.is_null()); + Handle<JSObject> context = + isolate_->factory()->NewJSObject(isolate_->object_function()); + if (val_node->IsString()) { + JSReceiver::CreateDataProperty(isolate_, context, + isolate_->factory()->source_string(), + val_node, Just(kThrowOnError)) + .Check(); + } + Handle<Object> argv[] = {name, value, context}; + ASSIGN_RETURN_ON_EXCEPTION( + isolate_, result, Execution::Call(isolate_, reviver_, holder, 3, argv), + Object); + } else { + DCHECK(val_node.is_null()); + Handle<Object> argv[] = {name, value}; + ASSIGN_RETURN_ON_EXCEPTION( + isolate_, result, Execution::Call(isolate_, reviver_, holder, 2, argv), + Object); + } return outer_scope.CloseAndEscape(result); } bool JsonParseInternalizer::RecurseAndApply(Handle<JSReceiver> holder, - Handle<String> name) { + Handle<String> name, + Handle<Object> val_node) { STACK_CHECK(isolate_, false); - + DCHECK(reviver_->IsCallable()); Handle<Object> result; ASSIGN_RETURN_ON_EXCEPTION_VALUE( - isolate_, result, InternalizeJsonProperty(holder, name), false); + isolate_, result, InternalizeJsonProperty(holder, name, val_node), false); Maybe<bool> change_result = Nothing<bool>(); if (result->IsUndefined(isolate_)) { change_result = JSReceiver::DeletePropertyOrElement(holder, name, @@ -403,12 +473,28 @@ JsonParser<Char>::~JsonParser() { } template <typename Char> -MaybeHandle<Object> JsonParser<Char>::ParseJson() { - MaybeHandle<Object> result = ParseJsonValue(); - if (!Check(JsonToken::EOS)) +MaybeHandle<Object> JsonParser<Char>::ParseJson(Handle<Object> reviver) { + Handle<Object> result; + // Only record the val node when reviver is callable. + bool reviver_is_callable = reviver->IsCallable(); + bool should_track_json_source = + v8_flags.harmony_json_parse_with_source && reviver_is_callable; + if (should_track_json_source) { + ASSIGN_RETURN_ON_EXCEPTION(isolate(), result, ParseJsonValue<true>(reviver), + Object); + } else { + ASSIGN_RETURN_ON_EXCEPTION(isolate(), result, + ParseJsonValue<false>(reviver), Object); + } + + if (!Check(JsonToken::EOS)) { ReportUnexpectedToken( peek(), MessageTemplate::kJsonParseUnexpectedNonWhiteSpaceCharacter); - if (isolate_->has_pending_exception()) return MaybeHandle<Object>(); + return MaybeHandle<Object>(); + } + if (isolate_->has_pending_exception()) { + return MaybeHandle<Object>(); + } return result; } @@ -662,7 +748,7 @@ Handle<Object> JsonParser<Char>::BuildJsonObject( : reinterpret_cast<Address>( mutable_double_buffer->GetDataStartAddress()); Address filler_address = mutable_double_address; - if (kTaggedSize != kDoubleSize) { + if (!V8_COMPRESS_POINTERS_8GB_BOOL && kTaggedSize != kDoubleSize) { if (IsAligned(mutable_double_address, kDoubleAlignment)) { mutable_double_address += kTaggedSize; } else { @@ -681,7 +767,7 @@ Handle<Object> JsonParser<Char>::BuildJsonObject( if (details.representation().IsDouble()) { if (value.IsSmi()) { - if (kTaggedSize != kDoubleSize) { + if (!V8_COMPRESS_POINTERS_8GB_BOOL && kTaggedSize != kDoubleSize) { // Write alignment filler. HeapObject filler = HeapObject::FromAddress(filler_address); filler.set_map_after_allocation( @@ -698,7 +784,8 @@ Handle<Object> JsonParser<Char>::BuildJsonObject( hn.set_map_after_allocation(*factory()->heap_number_map()); HeapNumber::cast(hn).set_value_as_bits(bits, kRelaxedStore); value = hn; - mutable_double_address += kMutableDoubleSize; + mutable_double_address += + ALIGN_TO_ALLOCATION_ALIGNMENT(kMutableDoubleSize); } else { DCHECK(value.IsHeapNumber()); HeapObject::cast(value).set_map(*factory()->heap_number_map(), @@ -712,7 +799,7 @@ Handle<Object> JsonParser<Char>::BuildJsonObject( #ifdef DEBUG Address end = reinterpret_cast<Address>(mutable_double_buffer->GetDataEndAddress()); - if (kTaggedSize != kDoubleSize) { + if (!V8_COMPRESS_POINTERS_8GB_BOOL && kTaggedSize != kDoubleSize) { DCHECK_EQ(std::min(filler_address, mutable_double_address), end); DCHECK_GE(filler_address, end); DCHECK_GE(mutable_double_address, end); @@ -724,7 +811,8 @@ Handle<Object> JsonParser<Char>::BuildJsonObject( // must ensure that the sweeper is not running or has already swept the // object's page. Otherwise the GC can add the contents of // mutable_double_buffer to the free list. - isolate()->heap()->EnsureSweepingCompleted(*mutable_double_buffer); + isolate()->heap()->EnsureSweepingCompletedForObject( + *mutable_double_buffer); mutable_double_buffer->set_length(0); } } @@ -787,9 +875,56 @@ Handle<Object> JsonParser<Char>::BuildJsonArray( return array; } +// Parse rawJSON value. +template <typename Char> +bool JsonParser<Char>::ParseRawJson() { + if (end_ == cursor_) { + isolate_->Throw(*isolate_->factory()->NewSyntaxError( + MessageTemplate::kInvalidRawJsonValue)); + return false; + } + next_ = V8_LIKELY(*cursor_ <= unibrow::Latin1::kMaxChar) + ? one_char_json_tokens[*cursor_] + : JsonToken::ILLEGAL; + switch (peek()) { + case JsonToken::STRING: + Consume(JsonToken::STRING); + ScanJsonString(false); + break; + + case JsonToken::NUMBER: + ParseJsonNumber(); + break; + + case JsonToken::TRUE_LITERAL: + ScanLiteral("true"); + break; + + case JsonToken::FALSE_LITERAL: + ScanLiteral("false"); + break; + + case JsonToken::NULL_LITERAL: + ScanLiteral("null"); + break; + + default: + ReportUnexpectedCharacter(CurrentCharacter()); + return false; + } + if (isolate_->has_pending_exception()) return false; + if (cursor_ != end_) { + isolate_->Throw(*isolate_->factory()->NewSyntaxError( + MessageTemplate::kInvalidRawJsonValue)); + return false; + } + return true; +} + // Parse any JSON value. template <typename Char> -MaybeHandle<Object> JsonParser<Char>::ParseJsonValue() { +template <bool should_track_json_source> +MaybeHandle<Object> JsonParser<Char>::ParseJsonValue(Handle<Object> reviver) { std::vector<JsonContinuation> cont_stack; SmallVector<JsonProperty> property_stack; SmallVector<Handle<Object>> element_stack; @@ -799,6 +934,34 @@ MaybeHandle<Object> JsonParser<Char>::ParseJsonValue() { JsonContinuation cont(isolate_, JsonContinuation::kReturn, 0); Handle<Object> value; + + // We use val_node to record current json value's parse node. For primitive + // values, the val_node is the source string of the json value. For JSObject + // values, the val_node is an ObjectHashTable in which the key is the property + // name and the value is the property value's parse node. For JSArray values, + // the val_node is a FixedArray containing the parse nodes of the elements. + // And for JSObject values, The order in which properties are defined may be + // different from the order in which properties are enumerated when calling + // InternalizeJSONProperty for the JSObject value. E.g., the json source + // string is '{"a": 1, "1": 2}', and the properties enumerate order is ["1", + // "a"]. Moreover, properties may be defined repeatedly in the json string. + // E.g., the json string is '{"a": 1, "a": 1}', and the properties enumerate + // order is ["a"]. So we cannot use the FixedArray to record the properties's + // parse node by the order in which properties are defined and we use a + // ObjectHashTable here to record the property name and the property's parse + // node. We then look up the property's parse node by the property name when + // calling InternalizeJSONProperty. + Handle<Object> val_node; + // Record the start position and end position for the primitive values. + int start_position; + int end_position; + + // element_val_node_stack is used to track all the elements's parse node. And + // we use this to construct the JSArray's parse node. + SmallVector<Handle<Object>> element_val_node_stack; + // property_val_node_stack is used to track all the property value's parse + // node. And we use this to construct the JSObject's parse node. + SmallVector<Handle<Object>> property_val_node_stack; while (true) { // Produce a json value. // @@ -809,14 +972,28 @@ MaybeHandle<Object> JsonParser<Char>::ParseJsonValue() { SkipWhitespace(); // The switch is immediately followed by 'break' so we can use 'break' to // break out of the loop, and 'continue' to continue the loop. + + if (should_track_json_source) { + start_position = position(); + } switch (peek()) { case JsonToken::STRING: Consume(JsonToken::STRING); value = MakeString(ScanJsonString(false)); + if (should_track_json_source) { + end_position = position(); + val_node = isolate_->factory()->NewSubString( + source_, start_position, end_position); + } break; case JsonToken::NUMBER: value = ParseJsonNumber(); + if (should_track_json_source) { + end_position = position(); + val_node = isolate_->factory()->NewSubString( + source_, start_position, end_position); + } break; case JsonToken::LBRACE: { @@ -824,6 +1001,7 @@ MaybeHandle<Object> JsonParser<Char>::ParseJsonValue() { if (Check(JsonToken::RBRACE)) { // TODO(verwaest): Directly use the map instead. value = factory()->NewJSObject(object_constructor_); + val_node = ObjectHashTable::New(isolate_, 0); break; } @@ -836,6 +1014,9 @@ MaybeHandle<Object> JsonParser<Char>::ParseJsonValue() { ExpectNext(JsonToken::STRING, MessageTemplate::kJsonParseExpectedPropNameOrRBrace); property_stack.emplace_back(ScanJsonPropertyKey(&cont)); + if (should_track_json_source) { + property_val_node_stack.emplace_back(Handle<Object>()); + } ExpectNext(JsonToken::COLON, MessageTemplate::kJsonParseExpectedColonAfterPropertyName); @@ -848,6 +1029,7 @@ MaybeHandle<Object> JsonParser<Char>::ParseJsonValue() { Consume(JsonToken::LBRACK); if (Check(JsonToken::RBRACK)) { value = factory()->NewJSArray(0, PACKED_SMI_ELEMENTS); + val_node = factory()->NewFixedArray(0); break; } @@ -862,16 +1044,25 @@ MaybeHandle<Object> JsonParser<Char>::ParseJsonValue() { case JsonToken::TRUE_LITERAL: ScanLiteral("true"); value = factory()->true_value(); + if (should_track_json_source) { + val_node = isolate_->factory()->true_string(); + } break; case JsonToken::FALSE_LITERAL: ScanLiteral("false"); value = factory()->false_value(); + if (should_track_json_source) { + val_node = isolate_->factory()->false_string(); + } break; case JsonToken::NULL_LITERAL: ScanLiteral("null"); value = factory()->null_value(); + if (should_track_json_source) { + val_node = isolate_->factory()->null_string(); + } break; case JsonToken::COLON: @@ -891,7 +1082,6 @@ MaybeHandle<Object> JsonParser<Char>::ParseJsonValue() { case JsonToken::WHITESPACE: UNREACHABLE(); } - // Done producing a value, consume it. break; } @@ -905,11 +1095,22 @@ MaybeHandle<Object> JsonParser<Char>::ParseJsonValue() { // break out of the loop, and 'continue' to continue the loop. switch (cont.type()) { case JsonContinuation::kReturn: - return cont.scope.CloseAndEscape(value); + if (should_track_json_source) { + DCHECK(!val_node.is_null()); + Handle<FixedArray> result = factory()->NewFixedArray(2); + result->set(0, *value); + result->set(1, *val_node); + return cont.scope.CloseAndEscape(result); + } else { + return cont.scope.CloseAndEscape(value); + } case JsonContinuation::kObjectProperty: { // Store the previous property value into its property info. property_stack.back().value = value; + if (should_track_json_source) { + property_val_node_stack.back() = val_node; + } if (V8_LIKELY(Check(JsonToken::COMMA))) { // Parse the property key. @@ -918,6 +1119,9 @@ MaybeHandle<Object> JsonParser<Char>::ParseJsonValue() { MessageTemplate::kJsonParseExpectedDoubleQuotedPropertyName); property_stack.emplace_back(ScanJsonPropertyKey(&cont)); + if (should_track_json_source) { + property_val_node_stack.emplace_back(Handle<Object>()); + } ExpectNext(JsonToken::COLON); // Break to start producing the subsequent property value. @@ -940,12 +1144,35 @@ MaybeHandle<Object> JsonParser<Char>::ParseJsonValue() { } } value = BuildJsonObject(cont, property_stack, feedback); - property_stack.resize_no_init(cont.index); Expect(JsonToken::RBRACE, MessageTemplate::kJsonParseExpectedCommaOrRBrace); - // Return the object. - value = cont.scope.CloseAndEscape(value); + if (should_track_json_source) { + size_t start = cont.index; + int length = static_cast<int>(property_stack.size() - start); + Handle<ObjectHashTable> table = + ObjectHashTable::New(isolate(), length); + for (int i = 0; i < length; i++) { + const JsonProperty& property = property_stack[start + i]; + if (property.string.is_index()) { + table = ObjectHashTable::Put( + table, factory()->Uint32ToString(property.string.index()), + property_val_node_stack[start + i]); + } else { + table = + ObjectHashTable::Put(table, MakeString(property.string), + property_val_node_stack[start + i]); + } + } + property_val_node_stack.resize_no_init(cont.index); + Object value_obj = *value; + val_node = cont.scope.CloseAndEscape(table); + value = cont.scope.CloseAndEscape(handle(value_obj, isolate_)); + } else { + value = cont.scope.CloseAndEscape(value); + } + property_stack.resize_no_init(cont.index); + // Pop the continuation. cont = std::move(cont_stack.back()); cont_stack.pop_back(); @@ -956,16 +1183,31 @@ MaybeHandle<Object> JsonParser<Char>::ParseJsonValue() { case JsonContinuation::kArrayElement: { // Store the previous element on the stack. element_stack.emplace_back(value); + if (should_track_json_source) { + element_val_node_stack.emplace_back(val_node); + } // Break to start producing the subsequent element value. if (V8_LIKELY(Check(JsonToken::COMMA))) break; value = BuildJsonArray(cont, element_stack); - element_stack.resize_no_init(cont.index); Expect(JsonToken::RBRACK, MessageTemplate::kJsonParseExpectedCommaOrRBrack); - // Return the array. - value = cont.scope.CloseAndEscape(value); + if (should_track_json_source) { + size_t start = cont.index; + int length = static_cast<int>(element_stack.size() - start); + Handle<FixedArray> array = factory()->NewFixedArray(length); + for (int i = 0; i < length; i++) { + array->set(i, *element_val_node_stack[start + i]); + } + element_val_node_stack.resize_no_init(cont.index); + Object value_obj = *value; + val_node = cont.scope.CloseAndEscape(array); + value = cont.scope.CloseAndEscape(handle(value_obj, isolate_)); + } else { + value = cont.scope.CloseAndEscape(value); + } + element_stack.resize_no_init(cont.index); // Pop the continuation. cont = std::move(cont_stack.back()); cont_stack.pop_back(); |