[json] implement InternalizeJSONProperty in C++.
R=cbruni@chromium.org Review-Url: https://codereview.chromium.org/2026563002 Cr-Commit-Position: refs/heads/master@{#36604}
This commit is contained in:
parent
9c20666d65
commit
c32a4f53b1
10
src/api.cc
10
src/api.cc
@ -2742,9 +2742,10 @@ MaybeLocal<Value> JSON::Parse(Isolate* v8_isolate, Local<String> json_string) {
|
|||||||
PREPARE_FOR_EXECUTION_WITH_ISOLATE(isolate, JSON, Parse, Value);
|
PREPARE_FOR_EXECUTION_WITH_ISOLATE(isolate, JSON, Parse, Value);
|
||||||
i::Handle<i::String> string = Utils::OpenHandle(*json_string);
|
i::Handle<i::String> string = Utils::OpenHandle(*json_string);
|
||||||
i::Handle<i::String> source = i::String::Flatten(string);
|
i::Handle<i::String> source = i::String::Flatten(string);
|
||||||
|
i::Handle<i::Object> undefined = isolate->factory()->undefined_value();
|
||||||
auto maybe = source->IsSeqOneByteString()
|
auto maybe = source->IsSeqOneByteString()
|
||||||
? i::JsonParser<true>::Parse(source)
|
? i::JsonParser<true>::Parse(isolate, source, undefined)
|
||||||
: i::JsonParser<false>::Parse(source);
|
: i::JsonParser<false>::Parse(isolate, source, undefined);
|
||||||
Local<Value> result;
|
Local<Value> result;
|
||||||
has_pending_exception = !ToLocal<Value>(maybe, &result);
|
has_pending_exception = !ToLocal<Value>(maybe, &result);
|
||||||
RETURN_ON_FAILED_EXECUTION(Value);
|
RETURN_ON_FAILED_EXECUTION(Value);
|
||||||
@ -2756,9 +2757,10 @@ MaybeLocal<Value> JSON::Parse(Local<Context> context,
|
|||||||
PREPARE_FOR_EXECUTION(context, JSON, Parse, Value);
|
PREPARE_FOR_EXECUTION(context, JSON, Parse, Value);
|
||||||
i::Handle<i::String> string = Utils::OpenHandle(*json_string);
|
i::Handle<i::String> string = Utils::OpenHandle(*json_string);
|
||||||
i::Handle<i::String> source = i::String::Flatten(string);
|
i::Handle<i::String> source = i::String::Flatten(string);
|
||||||
|
i::Handle<i::Object> undefined = isolate->factory()->undefined_value();
|
||||||
auto maybe = source->IsSeqOneByteString()
|
auto maybe = source->IsSeqOneByteString()
|
||||||
? i::JsonParser<true>::Parse(source)
|
? i::JsonParser<true>::Parse(isolate, source, undefined)
|
||||||
: i::JsonParser<false>::Parse(source);
|
: i::JsonParser<false>::Parse(isolate, source, undefined);
|
||||||
Local<Value> result;
|
Local<Value> result;
|
||||||
has_pending_exception = !ToLocal<Value>(maybe, &result);
|
has_pending_exception = !ToLocal<Value>(maybe, &result);
|
||||||
RETURN_ON_FAILED_EXECUTION(Value);
|
RETURN_ON_FAILED_EXECUTION(Value);
|
||||||
|
@ -19,50 +19,8 @@ var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol");
|
|||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
function CreateDataProperty(o, p, v) {
|
|
||||||
var desc = {value: v, enumerable: true, writable: true, configurable: true};
|
|
||||||
return %reflect_define_property(o, p, desc);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function InternalizeJSONProperty(holder, name, reviver) {
|
|
||||||
var val = holder[name];
|
|
||||||
if (IS_RECEIVER(val)) {
|
|
||||||
if (%is_arraylike(val)) {
|
|
||||||
var length = TO_LENGTH(val.length);
|
|
||||||
for (var i = 0; i < length; i++) {
|
|
||||||
var newElement =
|
|
||||||
InternalizeJSONProperty(val, %_NumberToString(i), reviver);
|
|
||||||
if (IS_UNDEFINED(newElement)) {
|
|
||||||
%reflect_delete_property(val, i);
|
|
||||||
} else {
|
|
||||||
CreateDataProperty(val, i, newElement);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
var keys = %object_keys(val);
|
|
||||||
for (var i = 0; i < keys.length; i++) {
|
|
||||||
var p = keys[i];
|
|
||||||
var newElement = InternalizeJSONProperty(val, p, reviver);
|
|
||||||
if (IS_UNDEFINED(newElement)) {
|
|
||||||
%reflect_delete_property(val, p);
|
|
||||||
} else {
|
|
||||||
CreateDataProperty(val, p, newElement);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return %_Call(reviver, holder, name, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function JSONParse(text, reviver) {
|
function JSONParse(text, reviver) {
|
||||||
var unfiltered = %ParseJson(text);
|
return %ParseJson(text, reviver);
|
||||||
if (IS_CALLABLE(reviver)) {
|
|
||||||
return InternalizeJSONProperty({'': unfiltered}, '', reviver);
|
|
||||||
} else {
|
|
||||||
return unfiltered;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
|
@ -13,16 +13,96 @@
|
|||||||
#include "src/objects-inl.h"
|
#include "src/objects-inl.h"
|
||||||
#include "src/parsing/scanner.h"
|
#include "src/parsing/scanner.h"
|
||||||
#include "src/parsing/token.h"
|
#include "src/parsing/token.h"
|
||||||
|
#include "src/property-descriptor.h"
|
||||||
#include "src/transitions.h"
|
#include "src/transitions.h"
|
||||||
|
|
||||||
namespace v8 {
|
namespace v8 {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
|
MaybeHandle<Object> JsonParseInternalizer::Internalize(Isolate* isolate,
|
||||||
|
Handle<Object> object,
|
||||||
|
Handle<Object> reviver) {
|
||||||
|
DCHECK(reviver->IsCallable());
|
||||||
|
JsonParseInternalizer internalizer(isolate,
|
||||||
|
Handle<JSReceiver>::cast(reviver));
|
||||||
|
Handle<JSObject> holder =
|
||||||
|
isolate->factory()->NewJSObject(isolate->object_function());
|
||||||
|
Handle<String> name = isolate->factory()->empty_string();
|
||||||
|
JSObject::AddProperty(holder, name, object, NONE);
|
||||||
|
return internalizer.InternalizeJsonProperty(holder, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
MaybeHandle<Object> JsonParseInternalizer::InternalizeJsonProperty(
|
||||||
|
Handle<JSReceiver> holder, Handle<String> name) {
|
||||||
|
HandleScope outer_scope(isolate_);
|
||||||
|
Handle<Object> value;
|
||||||
|
ASSIGN_RETURN_ON_EXCEPTION(
|
||||||
|
isolate_, value, Object::GetPropertyOrElement(holder, name), Object);
|
||||||
|
if (value->IsJSReceiver()) {
|
||||||
|
Handle<JSReceiver> object = Handle<JSReceiver>::cast(value);
|
||||||
|
Maybe<bool> is_array = Object::IsArray(object);
|
||||||
|
if (is_array.IsNothing()) return MaybeHandle<Object>();
|
||||||
|
if (is_array.FromJust()) {
|
||||||
|
Handle<Object> length_object;
|
||||||
|
ASSIGN_RETURN_ON_EXCEPTION(
|
||||||
|
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> name = isolate_->factory()->NumberToString(index);
|
||||||
|
if (!RecurseAndApply(object, name)) return MaybeHandle<Object>();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Handle<FixedArray> contents;
|
||||||
|
ASSIGN_RETURN_ON_EXCEPTION(
|
||||||
|
isolate_, contents,
|
||||||
|
KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly,
|
||||||
|
ENUMERABLE_STRINGS,
|
||||||
|
GetKeysConversion::kConvertToString),
|
||||||
|
Object);
|
||||||
|
for (int i = 0; i < contents->length(); i++) {
|
||||||
|
HandleScope inner_scope(isolate_);
|
||||||
|
Handle<String> name(String::cast(contents->get(i)), isolate_);
|
||||||
|
if (!RecurseAndApply(object, name)) 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);
|
||||||
|
return outer_scope.CloseAndEscape(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool JsonParseInternalizer::RecurseAndApply(Handle<JSReceiver> holder,
|
||||||
|
Handle<String> name) {
|
||||||
|
Handle<Object> result;
|
||||||
|
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
|
||||||
|
isolate_, result, InternalizeJsonProperty(holder, name), false);
|
||||||
|
Maybe<bool> change_result = Nothing<bool>();
|
||||||
|
if (result->IsUndefined()) {
|
||||||
|
change_result = JSReceiver::DeletePropertyOrElement(holder, name, SLOPPY);
|
||||||
|
} else {
|
||||||
|
PropertyDescriptor desc;
|
||||||
|
desc.set_value(result);
|
||||||
|
desc.set_configurable(true);
|
||||||
|
desc.set_enumerable(true);
|
||||||
|
desc.set_writable(true);
|
||||||
|
change_result = JSReceiver::DefineOwnProperty(isolate_, holder, name, &desc,
|
||||||
|
Object::DONT_THROW);
|
||||||
|
}
|
||||||
|
MAYBE_RETURN(change_result, false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
template <bool seq_one_byte>
|
template <bool seq_one_byte>
|
||||||
JsonParser<seq_one_byte>::JsonParser(Handle<String> source)
|
JsonParser<seq_one_byte>::JsonParser(Isolate* isolate, Handle<String> source)
|
||||||
: source_(source),
|
: source_(source),
|
||||||
source_length_(source->length()),
|
source_length_(source->length()),
|
||||||
isolate_(source->map()->GetHeap()->isolate()),
|
isolate_(isolate),
|
||||||
factory_(isolate_->factory()),
|
factory_(isolate_->factory()),
|
||||||
zone_(isolate_->allocator()),
|
zone_(isolate_->allocator()),
|
||||||
object_constructor_(isolate_->native_context()->object_function(),
|
object_constructor_(isolate_->native_context()->object_function(),
|
||||||
@ -90,6 +170,9 @@ MaybeHandle<Object> JsonParser<seq_one_byte>::ParseJson() {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MaybeHandle<Object> InternalizeJsonProperty(Handle<JSObject> holder,
|
||||||
|
Handle<String> key);
|
||||||
|
|
||||||
template <bool seq_one_byte>
|
template <bool seq_one_byte>
|
||||||
void JsonParser<seq_one_byte>::Advance() {
|
void JsonParser<seq_one_byte>::Advance() {
|
||||||
position_++;
|
position_++;
|
||||||
|
@ -13,19 +13,45 @@ namespace internal {
|
|||||||
|
|
||||||
enum ParseElementResult { kElementFound, kElementNotFound, kNullHandle };
|
enum ParseElementResult { kElementFound, kElementNotFound, kNullHandle };
|
||||||
|
|
||||||
|
class JsonParseInternalizer BASE_EMBEDDED {
|
||||||
|
public:
|
||||||
|
static MaybeHandle<Object> Internalize(Isolate* isolate,
|
||||||
|
Handle<Object> object,
|
||||||
|
Handle<Object> reviver);
|
||||||
|
|
||||||
|
private:
|
||||||
|
JsonParseInternalizer(Isolate* isolate, Handle<JSReceiver> reviver)
|
||||||
|
: isolate_(isolate), reviver_(reviver) {}
|
||||||
|
|
||||||
|
MaybeHandle<Object> InternalizeJsonProperty(Handle<JSReceiver> holder,
|
||||||
|
Handle<String> key);
|
||||||
|
|
||||||
|
bool RecurseAndApply(Handle<JSReceiver> holder, Handle<String> name);
|
||||||
|
|
||||||
|
Isolate* isolate_;
|
||||||
|
Handle<JSReceiver> reviver_;
|
||||||
|
};
|
||||||
|
|
||||||
// A simple json parser.
|
// A simple json parser.
|
||||||
template <bool seq_one_byte>
|
template <bool seq_one_byte>
|
||||||
class JsonParser BASE_EMBEDDED {
|
class JsonParser BASE_EMBEDDED {
|
||||||
public:
|
public:
|
||||||
MUST_USE_RESULT static MaybeHandle<Object> Parse(Handle<String> source) {
|
MUST_USE_RESULT static MaybeHandle<Object> Parse(Isolate* isolate,
|
||||||
return JsonParser(source).ParseJson();
|
Handle<String> source,
|
||||||
|
Handle<Object> reviver) {
|
||||||
|
Handle<Object> result;
|
||||||
|
ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
|
||||||
|
JsonParser(isolate, source).ParseJson(), Object);
|
||||||
|
if (reviver->IsCallable()) {
|
||||||
|
return JsonParseInternalizer::Internalize(isolate, result, reviver);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const int kEndOfString = -1;
|
static const int kEndOfString = -1;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit JsonParser(Handle<String> source);
|
JsonParser(Isolate* isolate, Handle<String> source);
|
||||||
|
|
||||||
// Parse a string containing a single JSON value.
|
// Parse a string containing a single JSON value.
|
||||||
MaybeHandle<Object> ParseJson();
|
MaybeHandle<Object> ParseJson();
|
||||||
|
@ -534,33 +534,20 @@ JsonStringifier::Result JsonStringifier::SerializeJSReceiverSlow(
|
|||||||
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
|
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
|
||||||
isolate_, contents,
|
isolate_, contents,
|
||||||
KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly,
|
KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly,
|
||||||
ENUMERABLE_STRINGS),
|
ENUMERABLE_STRINGS,
|
||||||
|
GetKeysConversion::kConvertToString),
|
||||||
EXCEPTION);
|
EXCEPTION);
|
||||||
}
|
}
|
||||||
builder_.AppendCharacter('{');
|
builder_.AppendCharacter('{');
|
||||||
Indent();
|
Indent();
|
||||||
bool comma = false;
|
bool comma = false;
|
||||||
for (int i = 0; i < contents->length(); i++) {
|
for (int i = 0; i < contents->length(); i++) {
|
||||||
Object* key = contents->get(i);
|
Handle<String> key(String::cast(contents->get(i)), isolate_);
|
||||||
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 {
|
|
||||||
maybe_property = Object::GetPropertyOrElement(object, key_handle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Handle<Object> property;
|
Handle<Object> property;
|
||||||
ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, property, maybe_property,
|
ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, property,
|
||||||
|
Object::GetPropertyOrElement(object, key),
|
||||||
EXCEPTION);
|
EXCEPTION);
|
||||||
Result result = SerializeProperty(property, comma, key_handle);
|
Result result = SerializeProperty(property, comma, key);
|
||||||
if (!comma && result == SUCCESS) comma = true;
|
if (!comma && result == SUCCESS) comma = true;
|
||||||
if (result == EXCEPTION) return result;
|
if (result == EXCEPTION) return result;
|
||||||
}
|
}
|
||||||
@ -572,6 +559,7 @@ JsonStringifier::Result JsonStringifier::SerializeJSReceiverSlow(
|
|||||||
|
|
||||||
JsonStringifier::Result JsonStringifier::SerializeJSProxy(
|
JsonStringifier::Result JsonStringifier::SerializeJSProxy(
|
||||||
Handle<JSProxy> object) {
|
Handle<JSProxy> object) {
|
||||||
|
HandleScope scope(isolate_);
|
||||||
Result stack_push = StackPush(object);
|
Result stack_push = StackPush(object);
|
||||||
if (stack_push != SUCCESS) return stack_push;
|
if (stack_push != SUCCESS) return stack_push;
|
||||||
Maybe<bool> is_array = Object::IsArray(object);
|
Maybe<bool> is_array = Object::IsArray(object);
|
||||||
|
@ -16,16 +16,18 @@ namespace internal {
|
|||||||
|
|
||||||
RUNTIME_FUNCTION(Runtime_ParseJson) {
|
RUNTIME_FUNCTION(Runtime_ParseJson) {
|
||||||
HandleScope scope(isolate);
|
HandleScope scope(isolate);
|
||||||
DCHECK_EQ(1, args.length());
|
DCHECK_EQ(2, args.length());
|
||||||
CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
|
CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
|
||||||
|
CONVERT_ARG_HANDLE_CHECKED(Object, reviver, 1);
|
||||||
Handle<String> source;
|
Handle<String> source;
|
||||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, source,
|
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, source,
|
||||||
Object::ToString(isolate, object));
|
Object::ToString(isolate, object));
|
||||||
source = String::Flatten(source);
|
source = String::Flatten(source);
|
||||||
// Optimized fast case where we only have Latin1 characters.
|
// Optimized fast case where we only have Latin1 characters.
|
||||||
RETURN_RESULT_OR_FAILURE(isolate, source->IsSeqOneByteString()
|
RETURN_RESULT_OR_FAILURE(
|
||||||
? JsonParser<true>::Parse(source)
|
isolate, source->IsSeqOneByteString()
|
||||||
: JsonParser<false>::Parse(source));
|
? JsonParser<true>::Parse(isolate, source, reviver)
|
||||||
|
: JsonParser<false>::Parse(isolate, source, reviver));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
@ -327,8 +327,7 @@ namespace internal {
|
|||||||
F(OrdinaryHasInstance, 2, 1) \
|
F(OrdinaryHasInstance, 2, 1) \
|
||||||
F(IsWasmObject, 1, 1)
|
F(IsWasmObject, 1, 1)
|
||||||
|
|
||||||
#define FOR_EACH_INTRINSIC_JSON(F) \
|
#define FOR_EACH_INTRINSIC_JSON(F) F(ParseJson, 2, 1)
|
||||||
F(ParseJson, 1, 1)
|
|
||||||
|
|
||||||
#define FOR_EACH_INTRINSIC_LITERALS(F) \
|
#define FOR_EACH_INTRINSIC_LITERALS(F) \
|
||||||
F(CreateRegExpLiteral, 4, 1) \
|
F(CreateRegExpLiteral, 4, 1) \
|
||||||
|
Loading…
Reference in New Issue
Block a user