Commit 395fa8ba authored by adamk's avatar adamk Committed by Commit bot

Add basic API support for Map & Set

Only supports constructing new objects and returning size.
Followup patch will need to add ability to retrieve and
set contents in order to support structured clone.

Also removes a bunch of outdated "experimental" markers from v8.h.

BUG=v8:3340
LOG=y

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

Cr-Commit-Position: refs/heads/master@{#28637}
parent a6676cfe
......@@ -1823,37 +1823,31 @@ class V8_EXPORT Value : public Data {
/**
* Returns true if this value is a Map.
* This is an experimental feature.
*/
bool IsMap() const;
/**
* Returns true if this value is a Set.
* This is an experimental feature.
*/
bool IsSet() const;
/**
* Returns true if this value is a Map Iterator.
* This is an experimental feature.
*/
bool IsMapIterator() const;
/**
* Returns true if this value is a Set Iterator.
* This is an experimental feature.
*/
bool IsSetIterator() const;
/**
* Returns true if this value is a WeakMap.
* This is an experimental feature.
*/
bool IsWeakMap() const;
/**
* Returns true if this value is a WeakSet.
* This is an experimental feature.
*/
bool IsWeakSet() const;
......@@ -2950,6 +2944,46 @@ class V8_EXPORT Array : public Object {
};
/**
* An instance of the built-in Map constructor (ECMA-262, 6th Edition, 23.1.1).
*/
class V8_EXPORT Map : public Object {
public:
size_t Size() const;
/**
* Creates a new Map.
*/
static Local<Map> New(Isolate* isolate);
V8_INLINE static Map* Cast(Value* obj);
private:
Map();
static void CheckCast(Value* obj);
};
/**
* An instance of the built-in Set constructor (ECMA-262, 6th Edition, 23.2.1).
*/
class V8_EXPORT Set : public Object {
public:
size_t Size() const;
/**
* Creates a new Set.
*/
static Local<Set> New(Isolate* isolate);
V8_INLINE static Set* Cast(Value* obj);
private:
Set();
static void CheckCast(Value* obj);
};
template<typename T>
class ReturnValue {
public:
......@@ -7782,6 +7816,22 @@ Array* Array::Cast(v8::Value* value) {
}
Map* Map::Cast(v8::Value* value) {
#ifdef V8_ENABLE_CHECKS
CheckCast(value);
#endif
return static_cast<Map*>(value);
}
Set* Set::Cast(v8::Value* value) {
#ifdef V8_ENABLE_CHECKS
CheckCast(value);
#endif
return static_cast<Set*>(value);
}
Promise* Promise::Cast(v8::Value* value) {
#ifdef V8_ENABLE_CHECKS
CheckCast(value);
......
......@@ -3085,6 +3085,20 @@ void v8::Array::CheckCast(Value* that) {
}
void v8::Map::CheckCast(Value* that) {
i::Handle<i::Object> obj = Utils::OpenHandle(that);
Utils::ApiCheck(obj->IsJSMap(), "v8::Map::Cast()",
"Could not convert to Map");
}
void v8::Set::CheckCast(Value* that) {
i::Handle<i::Object> obj = Utils::OpenHandle(that);
Utils::ApiCheck(obj->IsJSSet(), "v8::Set::Cast()",
"Could not convert to Set");
}
void v8::Promise::CheckCast(Value* that) {
Utils::ApiCheck(that->IsPromise(),
"v8::Promise::Cast()",
......@@ -6102,6 +6116,36 @@ Local<Object> Array::CloneElementAt(uint32_t index) {
}
Local<v8::Map> v8::Map::New(Isolate* isolate) {
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
LOG_API(i_isolate, "Map::New");
ENTER_V8(i_isolate);
i::Handle<i::JSMap> obj = i_isolate->factory()->NewJSMap();
return Utils::ToLocal(obj);
}
size_t v8::Map::Size() const {
i::Handle<i::JSMap> obj = Utils::OpenHandle(this);
return i::OrderedHashMap::cast(obj->table())->NumberOfElements();
}
Local<v8::Set> v8::Set::New(Isolate* isolate) {
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
LOG_API(i_isolate, "Set::New");
ENTER_V8(i_isolate);
i::Handle<i::JSSet> obj = i_isolate->factory()->NewJSSet();
return Utils::ToLocal(obj);
}
size_t v8::Set::Size() const {
i::Handle<i::JSSet> obj = Utils::OpenHandle(this);
return i::OrderedHashSet::cast(obj->table())->NumberOfElements();
}
bool Value::IsPromise() const {
auto self = Utils::OpenHandle(this);
return i::Object::IsPromise(self);
......
......@@ -146,6 +146,8 @@ class RegisteredExtension {
V(RegExp, JSRegExp) \
V(Object, JSObject) \
V(Array, JSArray) \
V(Map, JSMap) \
V(Set, JSSet) \
V(ArrayBuffer, JSArrayBuffer) \
V(ArrayBufferView, JSArrayBufferView) \
V(TypedArray, JSTypedArray) \
......@@ -203,6 +205,10 @@ class Utils {
v8::internal::Handle<v8::internal::JSObject> obj);
static inline Local<Array> ToLocal(
v8::internal::Handle<v8::internal::JSArray> obj);
static inline Local<Map> ToLocal(
v8::internal::Handle<v8::internal::JSMap> obj);
static inline Local<Set> ToLocal(
v8::internal::Handle<v8::internal::JSSet> obj);
static inline Local<ArrayBuffer> ToLocal(
v8::internal::Handle<v8::internal::JSArrayBuffer> obj);
static inline Local<ArrayBufferView> ToLocal(
......@@ -360,6 +366,8 @@ MAKE_TO_LOCAL(ToLocal, Symbol, Symbol)
MAKE_TO_LOCAL(ToLocal, JSRegExp, RegExp)
MAKE_TO_LOCAL(ToLocal, JSObject, Object)
MAKE_TO_LOCAL(ToLocal, JSArray, Array)
MAKE_TO_LOCAL(ToLocal, JSMap, Map)
MAKE_TO_LOCAL(ToLocal, JSSet, Set)
MAKE_TO_LOCAL(ToLocal, JSArrayBuffer, ArrayBuffer)
MAKE_TO_LOCAL(ToLocal, JSArrayBufferView, ArrayBufferView)
MAKE_TO_LOCAL(ToLocal, JSDataView, DataView)
......
......@@ -1221,13 +1221,19 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> global_object,
native_context()->set_data_view_fun(*data_view_fun);
}
// -- M a p
InstallFunction(global, "Map", JS_MAP_TYPE, JSMap::kSize,
isolate->initial_object_prototype(), Builtins::kIllegal);
{ // -- M a p
Handle<JSFunction> js_map_fun = InstallFunction(
global, "Map", JS_MAP_TYPE, JSMap::kSize,
isolate->initial_object_prototype(), Builtins::kIllegal);
native_context()->set_js_map_map(js_map_fun->initial_map());
}
// -- S e t
InstallFunction(global, "Set", JS_SET_TYPE, JSSet::kSize,
isolate->initial_object_prototype(), Builtins::kIllegal);
{ // -- S e t
Handle<JSFunction> js_set_fun = InstallFunction(
global, "Set", JS_SET_TYPE, JSSet::kSize,
isolate->initial_object_prototype(), Builtins::kIllegal);
native_context()->set_js_set_map(js_set_fun->initial_map());
}
{ // Set up the iterator result object
STATIC_ASSERT(JSGeneratorObject::kResultPropertyCount == 2);
......
......@@ -187,6 +187,8 @@ enum BindingFlags {
V(STRONG_GENERATOR_FUNCTION_MAP_INDEX, Map, strong_generator_function_map) \
V(GENERATOR_OBJECT_PROTOTYPE_MAP_INDEX, Map, generator_object_prototype_map) \
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_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) \
......@@ -427,6 +429,8 @@ class Context: public FixedArray {
STRONG_GENERATOR_FUNCTION_MAP_INDEX,
GENERATOR_OBJECT_PROTOTYPE_MAP_INDEX,
ITERATOR_RESULT_MAP_INDEX,
JS_MAP_MAP_INDEX,
JS_SET_MAP_INDEX,
MAP_ITERATOR_MAP_INDEX,
SET_ITERATOR_MAP_INDEX,
ARRAY_VALUES_ITERATOR_INDEX,
......
......@@ -1744,6 +1744,22 @@ Handle<JSDataView> Factory::NewJSDataView() {
}
Handle<JSMap> Factory::NewJSMap() {
Handle<Map> map(isolate()->native_context()->js_map_map());
Handle<JSMap> js_map = Handle<JSMap>::cast(NewJSObjectFromMap(map));
Runtime::JSMapInitialize(isolate(), js_map);
return js_map;
}
Handle<JSSet> Factory::NewJSSet() {
Handle<Map> map(isolate()->native_context()->js_set_map());
Handle<JSSet> js_set = Handle<JSSet>::cast(NewJSObjectFromMap(map));
Runtime::JSSetInitialize(isolate(), js_set);
return js_set;
}
Handle<JSMapIterator> Factory::NewJSMapIterator() {
Handle<Map> map(isolate()->native_context()->map_iterator_map());
CALL_HEAP_FUNCTION(isolate(),
......
......@@ -464,6 +464,9 @@ class Factory final {
Handle<JSDataView> NewJSDataView(Handle<JSArrayBuffer> buffer,
size_t byte_offset, size_t byte_length);
Handle<JSMap> NewJSMap();
Handle<JSSet> NewJSSet();
// TODO(aandrey): Maybe these should take table, index and kind arguments.
Handle<JSMapIterator> NewJSMapIterator();
Handle<JSSetIterator> NewJSSetIterator();
......
......@@ -45,12 +45,17 @@ RUNTIME_FUNCTION(Runtime_GenericHash) {
}
void Runtime::JSSetInitialize(Isolate* isolate, Handle<JSSet> set) {
Handle<OrderedHashSet> table = isolate->factory()->NewOrderedHashSet();
set->set_table(*table);
}
RUNTIME_FUNCTION(Runtime_SetInitialize) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
Handle<OrderedHashSet> table = isolate->factory()->NewOrderedHashSet();
holder->set_table(*table);
Runtime::JSSetInitialize(isolate, holder);
return *holder;
}
......@@ -143,12 +148,17 @@ RUNTIME_FUNCTION(Runtime_SetIteratorDetails) {
}
void Runtime::JSMapInitialize(Isolate* isolate, Handle<JSMap> map) {
Handle<OrderedHashMap> table = isolate->factory()->NewOrderedHashMap();
map->set_table(*table);
}
RUNTIME_FUNCTION(Runtime_MapInitialize) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
Handle<OrderedHashMap> table = isolate->factory()->NewOrderedHashMap();
holder->set_table(*table);
Runtime::JSMapInitialize(isolate, holder);
return *holder;
}
......
......@@ -852,6 +852,10 @@ class Runtime : public AllStatic {
Isolate* isolate, Handle<FixedArray> literals,
Handle<FixedArray> elements, bool is_strong);
static void JSMapInitialize(Isolate* isolate, Handle<JSMap> map);
static void JSSetInitialize(Isolate* isolate, Handle<JSSet> set);
static void WeakCollectionInitialize(
Isolate* isolate, Handle<JSWeakCollection> weak_collection);
static void WeakCollectionSet(Handle<JSWeakCollection> weak_collection,
......
......@@ -21100,3 +21100,37 @@ TEST(ExtrasExportsObject) {
CHECK(result->Value() == 5.0);
}
TEST(Map) {
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope handle_scope(isolate);
LocalContext env;
v8::Local<v8::Map> map = v8::Map::New(isolate);
CHECK(map->IsObject());
CHECK(map->IsMap());
CHECK_EQ(0, map->Size());
v8::Local<v8::Value> val = CompileRun("new Map([[1, 2], [3, 4]])");
CHECK(val->IsMap());
map = v8::Local<v8::Map>::Cast(val);
CHECK_EQ(2, map->Size());
}
TEST(Set) {
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope handle_scope(isolate);
LocalContext env;
v8::Local<v8::Set> set = v8::Set::New(isolate);
CHECK(set->IsObject());
CHECK(set->IsSet());
CHECK_EQ(0, set->Size());
v8::Local<v8::Value> val = CompileRun("new Set([1, 2])");
CHECK(val->IsSet());
set = v8::Local<v8::Set>::Cast(val);
CHECK_EQ(2, set->Size());
}
......@@ -171,7 +171,7 @@ void TestSet(IntKeyHash hash, int size) {
}
TEST(Set) {
TEST(HashSet) {
TestSet(Hash, 100);
TestSet(CollisionHash, 50);
}
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