summaryrefslogtreecommitdiff
path: root/deps/v8/src/json/json-parser.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/json/json-parser.cc')
-rw-r--r--deps/v8/src/json/json-parser.cc324
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();