Commit cb07b8ef authored by adamk's avatar adamk Committed by Commit bot

Add {Map,Set}::FromArray to the API

These are similar to the Map/Set constructors when called with an array,
except that they are guaranteed to be side-effect free if called with
a packed array.

This will be useful in implementing structured clone which, as
specified in HTML, speaks in terms of the internal [[MapData]]
and [[SetData]] slots without going through the exposed iteration
ES semantics.

BUG=v8:3340
LOG=y

Review URL: https://codereview.chromium.org/1155893003

Cr-Commit-Position: refs/heads/master@{#28642}
parent f7b59122
......@@ -2958,10 +2958,18 @@ class V8_EXPORT Map : public Object {
Local<Array> AsArray() const;
/**
* Creates a new Map.
* Creates a new empty Map.
*/
static Local<Map> New(Isolate* isolate);
/**
* Creates a new Map containing the elements of array, which must be comprised
* of [key, value] arrays.
* Guaranteed to be side-effect free if the array contains no holes.
*/
static V8_WARN_UNUSED_RESULT MaybeLocal<Map> FromArray(Local<Context> context,
Local<Array> array);
V8_INLINE static Map* Cast(Value* obj);
private:
......@@ -2983,10 +2991,17 @@ class V8_EXPORT Set : public Object {
Local<Array> AsArray() const;
/**
* Creates a new Set.
* Creates a new empty Set.
*/
static Local<Set> New(Isolate* isolate);
/**
* Creates a new Set containing the items in array.
* Guaranteed to be side-effect free if the array contains no holes.
*/
static V8_WARN_UNUSED_RESULT MaybeLocal<Set> FromArray(Local<Context> context,
Local<Array> array);
V8_INLINE static Set* Cast(Value* obj);
private:
......
......@@ -6156,6 +6156,19 @@ Local<Array> Map::AsArray() const {
}
MaybeLocal<Map> Map::FromArray(Local<Context> context, Local<Array> array) {
PREPARE_FOR_EXECUTION(context, "Map::FromArray", Map);
i::Handle<i::Object> result;
i::Handle<i::Object> argv[] = {Utils::OpenHandle(*array)};
has_pending_exception =
!i::Execution::Call(isolate, isolate->map_from_array(),
isolate->factory()->undefined_value(),
arraysize(argv), argv, false).ToHandle(&result);
RETURN_ON_FAILED_EXECUTION(Map);
RETURN_ESCAPED(Local<Map>::Cast(Utils::ToLocal(result)));
}
Local<v8::Set> v8::Set::New(Isolate* isolate) {
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
LOG_API(i_isolate, "Set::New");
......@@ -6192,6 +6205,19 @@ Local<Array> Set::AsArray() const {
}
MaybeLocal<Set> Set::FromArray(Local<Context> context, Local<Array> array) {
PREPARE_FOR_EXECUTION(context, "Set::FromArray", Set);
i::Handle<i::Object> result;
i::Handle<i::Object> argv[] = {Utils::OpenHandle(*array)};
has_pending_exception =
!i::Execution::Call(isolate, isolate->set_from_array(),
isolate->factory()->undefined_value(),
arraysize(argv), argv, false).ToHandle(&result);
RETURN_ON_FAILED_EXECUTION(Set);
RETURN_ESCAPED(Local<Set>::Cast(Utils::ToLocal(result)));
}
bool Value::IsPromise() const {
auto self = Utils::OpenHandle(this);
return i::Object::IsPromise(self);
......
......@@ -1665,6 +1665,8 @@ void Genesis::InstallNativeFunctions() {
INSTALL_NATIVE(JSFunction, "$observeNativeObjectNotifierPerformChange",
native_object_notifier_perform_change);
INSTALL_NATIVE(JSFunction, "$arrayValues", array_values_iterator);
INSTALL_NATIVE(JSFunction, "$mapFromArray", map_from_array);
INSTALL_NATIVE(JSFunction, "$setFromArray", set_from_array);
}
......
......@@ -4,6 +4,8 @@
var $getHash;
var $getExistingHash;
var $mapFromArray;
var $setFromArray;
(function(global, utils) {
"use strict";
......@@ -480,4 +482,23 @@ utils.InstallFunctions(GlobalMap.prototype, DONT_ENUM, [
$getHash = GetHash;
$getExistingHash = GetExistingHash;
$mapFromArray = function(array) {
var map = new GlobalMap;
var length = array.length;
for (var i = 0; i < length; ++i) {
var entry = array[i];
%_CallFunction(map, entry[0], entry[1], MapSet);
}
return map;
};
$setFromArray = function(array) {
var set = new GlobalSet;
var length = array.length;
for (var i = 0; i < length; ++i) {
%_CallFunction(set, array[i], SetAdd);
}
return set;
};
})
......@@ -189,6 +189,8 @@ enum BindingFlags {
V(ITERATOR_RESULT_MAP_INDEX, Map, iterator_result_map) \
V(JS_MAP_MAP_INDEX, Map, js_map_map) \
V(JS_SET_MAP_INDEX, Map, js_set_map) \
V(MAP_FROM_ARRAY_INDEX, JSFunction, map_from_array) \
V(SET_FROM_ARRAY_INDEX, JSFunction, set_from_array) \
V(MAP_ITERATOR_MAP_INDEX, Map, map_iterator_map) \
V(SET_ITERATOR_MAP_INDEX, Map, set_iterator_map) \
V(ARRAY_VALUES_ITERATOR_INDEX, JSFunction, array_values_iterator) \
......@@ -431,6 +433,8 @@ class Context: public FixedArray {
ITERATOR_RESULT_MAP_INDEX,
JS_MAP_MAP_INDEX,
JS_SET_MAP_INDEX,
MAP_FROM_ARRAY_INDEX,
SET_FROM_ARRAY_INDEX,
MAP_ITERATOR_MAP_INDEX,
SET_ITERATOR_MAP_INDEX,
ARRAY_VALUES_ITERATOR_INDEX,
......
......@@ -21127,6 +21127,9 @@ TEST(Map) {
CHECK_EQ(2, entry->Length());
CHECK_EQ(3, entry->Get(0).As<v8::Int32>()->Value());
CHECK_EQ(4, entry->Get(1).As<v8::Int32>()->Value());
map = v8::Map::FromArray(env.local(), entries).ToLocalChecked();
CHECK_EQ(2, map->Size());
}
......@@ -21149,4 +21152,7 @@ TEST(Set) {
CHECK_EQ(2, keys->Length());
CHECK_EQ(1, keys->Get(0).As<v8::Int32>()->Value());
CHECK_EQ(2, keys->Get(1).As<v8::Int32>()->Value());
set = v8::Set::FromArray(env.local(), keys).ToLocalChecked();
CHECK_EQ(2, set->Size());
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment