[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:
yangguo 2016-05-30 22:43:39 -07:00 committed by Commit bot
parent 9c20666d65
commit c32a4f53b1
7 changed files with 135 additions and 77 deletions

View File

@ -2742,9 +2742,10 @@ MaybeLocal<Value> JSON::Parse(Isolate* v8_isolate, Local<String> json_string) {
PREPARE_FOR_EXECUTION_WITH_ISOLATE(isolate, JSON, Parse, Value);
i::Handle<i::String> string = Utils::OpenHandle(*json_string);
i::Handle<i::String> source = i::String::Flatten(string);
i::Handle<i::Object> undefined = isolate->factory()->undefined_value();
auto maybe = source->IsSeqOneByteString()
? i::JsonParser<true>::Parse(source)
: i::JsonParser<false>::Parse(source);
? i::JsonParser<true>::Parse(isolate, source, undefined)
: i::JsonParser<false>::Parse(isolate, source, undefined);
Local<Value> result;
has_pending_exception = !ToLocal<Value>(maybe, &result);
RETURN_ON_FAILED_EXECUTION(Value);
@ -2756,9 +2757,10 @@ MaybeLocal<Value> JSON::Parse(Local<Context> context,
PREPARE_FOR_EXECUTION(context, JSON, Parse, Value);
i::Handle<i::String> string = Utils::OpenHandle(*json_string);
i::Handle<i::String> source = i::String::Flatten(string);
i::Handle<i::Object> undefined = isolate->factory()->undefined_value();
auto maybe = source->IsSeqOneByteString()
? i::JsonParser<true>::Parse(source)
: i::JsonParser<false>::Parse(source);
? i::JsonParser<true>::Parse(isolate, source, undefined)
: i::JsonParser<false>::Parse(isolate, source, undefined);
Local<Value> result;
has_pending_exception = !ToLocal<Value>(maybe, &result);
RETURN_ON_FAILED_EXECUTION(Value);

View File

@ -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) {
var unfiltered = %ParseJson(text);
if (IS_CALLABLE(reviver)) {
return InternalizeJSONProperty({'': unfiltered}, '', reviver);
} else {
return unfiltered;
}
return %ParseJson(text, reviver);
}
// -------------------------------------------------------------------

View File

@ -13,16 +13,96 @@
#include "src/objects-inl.h"
#include "src/parsing/scanner.h"
#include "src/parsing/token.h"
#include "src/property-descriptor.h"
#include "src/transitions.h"
namespace v8 {
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>
JsonParser<seq_one_byte>::JsonParser(Handle<String> source)
JsonParser<seq_one_byte>::JsonParser(Isolate* isolate, Handle<String> source)
: source_(source),
source_length_(source->length()),
isolate_(source->map()->GetHeap()->isolate()),
isolate_(isolate),
factory_(isolate_->factory()),
zone_(isolate_->allocator()),
object_constructor_(isolate_->native_context()->object_function(),
@ -90,6 +170,9 @@ MaybeHandle<Object> JsonParser<seq_one_byte>::ParseJson() {
return result;
}
MaybeHandle<Object> InternalizeJsonProperty(Handle<JSObject> holder,
Handle<String> key);
template <bool seq_one_byte>
void JsonParser<seq_one_byte>::Advance() {
position_++;

View File

@ -13,19 +13,45 @@ namespace internal {
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.
template <bool seq_one_byte>
class JsonParser BASE_EMBEDDED {
public:
MUST_USE_RESULT static MaybeHandle<Object> Parse(Handle<String> source) {
return JsonParser(source).ParseJson();
MUST_USE_RESULT static MaybeHandle<Object> Parse(Isolate* isolate,
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;
private:
explicit JsonParser(Handle<String> source);
JsonParser(Isolate* isolate, Handle<String> source);
// Parse a string containing a single JSON value.
MaybeHandle<Object> ParseJson();

View File

@ -534,33 +534,20 @@ JsonStringifier::Result JsonStringifier::SerializeJSReceiverSlow(
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate_, contents,
KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly,
ENUMERABLE_STRINGS),
ENUMERABLE_STRINGS,
GetKeysConversion::kConvertToString),
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 {
maybe_property = Object::GetPropertyOrElement(object, key_handle);
}
}
Handle<String> key(String::cast(contents->get(i)), isolate_);
Handle<Object> property;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, property, maybe_property,
ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, property,
Object::GetPropertyOrElement(object, key),
EXCEPTION);
Result result = SerializeProperty(property, comma, key_handle);
Result result = SerializeProperty(property, comma, key);
if (!comma && result == SUCCESS) comma = true;
if (result == EXCEPTION) return result;
}
@ -572,6 +559,7 @@ JsonStringifier::Result JsonStringifier::SerializeJSReceiverSlow(
JsonStringifier::Result JsonStringifier::SerializeJSProxy(
Handle<JSProxy> object) {
HandleScope scope(isolate_);
Result stack_push = StackPush(object);
if (stack_push != SUCCESS) return stack_push;
Maybe<bool> is_array = Object::IsArray(object);

View File

@ -16,16 +16,18 @@ namespace internal {
RUNTIME_FUNCTION(Runtime_ParseJson) {
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, reviver, 1);
Handle<String> source;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, source,
Object::ToString(isolate, object));
source = String::Flatten(source);
// Optimized fast case where we only have Latin1 characters.
RETURN_RESULT_OR_FAILURE(isolate, source->IsSeqOneByteString()
? JsonParser<true>::Parse(source)
: JsonParser<false>::Parse(source));
RETURN_RESULT_OR_FAILURE(
isolate, source->IsSeqOneByteString()
? JsonParser<true>::Parse(isolate, source, reviver)
: JsonParser<false>::Parse(isolate, source, reviver));
}
} // namespace internal

View File

@ -327,8 +327,7 @@ namespace internal {
F(OrdinaryHasInstance, 2, 1) \
F(IsWasmObject, 1, 1)
#define FOR_EACH_INTRINSIC_JSON(F) \
F(ParseJson, 1, 1)
#define FOR_EACH_INTRINSIC_JSON(F) F(ParseJson, 2, 1)
#define FOR_EACH_INTRINSIC_LITERALS(F) \
F(CreateRegExpLiteral, 4, 1) \