Skip to content

Commit 395fa8b

Browse files
ajkleinCommit bot
authored andcommitted
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}
1 parent a6676cf commit 395fa8b

File tree

11 files changed

+196
-17
lines changed

11 files changed

+196
-17
lines changed

include/v8.h

Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1823,37 +1823,31 @@ class V8_EXPORT Value : public Data {
18231823

18241824
/**
18251825
* Returns true if this value is a Map.
1826-
* This is an experimental feature.
18271826
*/
18281827
bool IsMap() const;
18291828

18301829
/**
18311830
* Returns true if this value is a Set.
1832-
* This is an experimental feature.
18331831
*/
18341832
bool IsSet() const;
18351833

18361834
/**
18371835
* Returns true if this value is a Map Iterator.
1838-
* This is an experimental feature.
18391836
*/
18401837
bool IsMapIterator() const;
18411838

18421839
/**
18431840
* Returns true if this value is a Set Iterator.
1844-
* This is an experimental feature.
18451841
*/
18461842
bool IsSetIterator() const;
18471843

18481844
/**
18491845
* Returns true if this value is a WeakMap.
1850-
* This is an experimental feature.
18511846
*/
18521847
bool IsWeakMap() const;
18531848

18541849
/**
18551850
* Returns true if this value is a WeakSet.
1856-
* This is an experimental feature.
18571851
*/
18581852
bool IsWeakSet() const;
18591853

@@ -2950,6 +2944,46 @@ class V8_EXPORT Array : public Object {
29502944
};
29512945

29522946

2947+
/**
2948+
* An instance of the built-in Map constructor (ECMA-262, 6th Edition, 23.1.1).
2949+
*/
2950+
class V8_EXPORT Map : public Object {
2951+
public:
2952+
size_t Size() const;
2953+
2954+
/**
2955+
* Creates a new Map.
2956+
*/
2957+
static Local<Map> New(Isolate* isolate);
2958+
2959+
V8_INLINE static Map* Cast(Value* obj);
2960+
2961+
private:
2962+
Map();
2963+
static void CheckCast(Value* obj);
2964+
};
2965+
2966+
2967+
/**
2968+
* An instance of the built-in Set constructor (ECMA-262, 6th Edition, 23.2.1).
2969+
*/
2970+
class V8_EXPORT Set : public Object {
2971+
public:
2972+
size_t Size() const;
2973+
2974+
/**
2975+
* Creates a new Set.
2976+
*/
2977+
static Local<Set> New(Isolate* isolate);
2978+
2979+
V8_INLINE static Set* Cast(Value* obj);
2980+
2981+
private:
2982+
Set();
2983+
static void CheckCast(Value* obj);
2984+
};
2985+
2986+
29532987
template<typename T>
29542988
class ReturnValue {
29552989
public:
@@ -7782,6 +7816,22 @@ Array* Array::Cast(v8::Value* value) {
77827816
}
77837817

77847818

7819+
Map* Map::Cast(v8::Value* value) {
7820+
#ifdef V8_ENABLE_CHECKS
7821+
CheckCast(value);
7822+
#endif
7823+
return static_cast<Map*>(value);
7824+
}
7825+
7826+
7827+
Set* Set::Cast(v8::Value* value) {
7828+
#ifdef V8_ENABLE_CHECKS
7829+
CheckCast(value);
7830+
#endif
7831+
return static_cast<Set*>(value);
7832+
}
7833+
7834+
77857835
Promise* Promise::Cast(v8::Value* value) {
77867836
#ifdef V8_ENABLE_CHECKS
77877837
CheckCast(value);

src/api.cc

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3085,6 +3085,20 @@ void v8::Array::CheckCast(Value* that) {
30853085
}
30863086

30873087

3088+
void v8::Map::CheckCast(Value* that) {
3089+
i::Handle<i::Object> obj = Utils::OpenHandle(that);
3090+
Utils::ApiCheck(obj->IsJSMap(), "v8::Map::Cast()",
3091+
"Could not convert to Map");
3092+
}
3093+
3094+
3095+
void v8::Set::CheckCast(Value* that) {
3096+
i::Handle<i::Object> obj = Utils::OpenHandle(that);
3097+
Utils::ApiCheck(obj->IsJSSet(), "v8::Set::Cast()",
3098+
"Could not convert to Set");
3099+
}
3100+
3101+
30883102
void v8::Promise::CheckCast(Value* that) {
30893103
Utils::ApiCheck(that->IsPromise(),
30903104
"v8::Promise::Cast()",
@@ -6102,6 +6116,36 @@ Local<Object> Array::CloneElementAt(uint32_t index) {
61026116
}
61036117

61046118

6119+
Local<v8::Map> v8::Map::New(Isolate* isolate) {
6120+
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
6121+
LOG_API(i_isolate, "Map::New");
6122+
ENTER_V8(i_isolate);
6123+
i::Handle<i::JSMap> obj = i_isolate->factory()->NewJSMap();
6124+
return Utils::ToLocal(obj);
6125+
}
6126+
6127+
6128+
size_t v8::Map::Size() const {
6129+
i::Handle<i::JSMap> obj = Utils::OpenHandle(this);
6130+
return i::OrderedHashMap::cast(obj->table())->NumberOfElements();
6131+
}
6132+
6133+
6134+
Local<v8::Set> v8::Set::New(Isolate* isolate) {
6135+
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
6136+
LOG_API(i_isolate, "Set::New");
6137+
ENTER_V8(i_isolate);
6138+
i::Handle<i::JSSet> obj = i_isolate->factory()->NewJSSet();
6139+
return Utils::ToLocal(obj);
6140+
}
6141+
6142+
6143+
size_t v8::Set::Size() const {
6144+
i::Handle<i::JSSet> obj = Utils::OpenHandle(this);
6145+
return i::OrderedHashSet::cast(obj->table())->NumberOfElements();
6146+
}
6147+
6148+
61056149
bool Value::IsPromise() const {
61066150
auto self = Utils::OpenHandle(this);
61076151
return i::Object::IsPromise(self);

src/api.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,8 @@ class RegisteredExtension {
146146
V(RegExp, JSRegExp) \
147147
V(Object, JSObject) \
148148
V(Array, JSArray) \
149+
V(Map, JSMap) \
150+
V(Set, JSSet) \
149151
V(ArrayBuffer, JSArrayBuffer) \
150152
V(ArrayBufferView, JSArrayBufferView) \
151153
V(TypedArray, JSTypedArray) \
@@ -203,6 +205,10 @@ class Utils {
203205
v8::internal::Handle<v8::internal::JSObject> obj);
204206
static inline Local<Array> ToLocal(
205207
v8::internal::Handle<v8::internal::JSArray> obj);
208+
static inline Local<Map> ToLocal(
209+
v8::internal::Handle<v8::internal::JSMap> obj);
210+
static inline Local<Set> ToLocal(
211+
v8::internal::Handle<v8::internal::JSSet> obj);
206212
static inline Local<ArrayBuffer> ToLocal(
207213
v8::internal::Handle<v8::internal::JSArrayBuffer> obj);
208214
static inline Local<ArrayBufferView> ToLocal(
@@ -360,6 +366,8 @@ MAKE_TO_LOCAL(ToLocal, Symbol, Symbol)
360366
MAKE_TO_LOCAL(ToLocal, JSRegExp, RegExp)
361367
MAKE_TO_LOCAL(ToLocal, JSObject, Object)
362368
MAKE_TO_LOCAL(ToLocal, JSArray, Array)
369+
MAKE_TO_LOCAL(ToLocal, JSMap, Map)
370+
MAKE_TO_LOCAL(ToLocal, JSSet, Set)
363371
MAKE_TO_LOCAL(ToLocal, JSArrayBuffer, ArrayBuffer)
364372
MAKE_TO_LOCAL(ToLocal, JSArrayBufferView, ArrayBufferView)
365373
MAKE_TO_LOCAL(ToLocal, JSDataView, DataView)

src/bootstrapper.cc

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1221,13 +1221,19 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> global_object,
12211221
native_context()->set_data_view_fun(*data_view_fun);
12221222
}
12231223

1224-
// -- M a p
1225-
InstallFunction(global, "Map", JS_MAP_TYPE, JSMap::kSize,
1226-
isolate->initial_object_prototype(), Builtins::kIllegal);
1224+
{ // -- M a p
1225+
Handle<JSFunction> js_map_fun = InstallFunction(
1226+
global, "Map", JS_MAP_TYPE, JSMap::kSize,
1227+
isolate->initial_object_prototype(), Builtins::kIllegal);
1228+
native_context()->set_js_map_map(js_map_fun->initial_map());
1229+
}
12271230

1228-
// -- S e t
1229-
InstallFunction(global, "Set", JS_SET_TYPE, JSSet::kSize,
1230-
isolate->initial_object_prototype(), Builtins::kIllegal);
1231+
{ // -- S e t
1232+
Handle<JSFunction> js_set_fun = InstallFunction(
1233+
global, "Set", JS_SET_TYPE, JSSet::kSize,
1234+
isolate->initial_object_prototype(), Builtins::kIllegal);
1235+
native_context()->set_js_set_map(js_set_fun->initial_map());
1236+
}
12311237

12321238
{ // Set up the iterator result object
12331239
STATIC_ASSERT(JSGeneratorObject::kResultPropertyCount == 2);

src/contexts.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,8 @@ enum BindingFlags {
187187
V(STRONG_GENERATOR_FUNCTION_MAP_INDEX, Map, strong_generator_function_map) \
188188
V(GENERATOR_OBJECT_PROTOTYPE_MAP_INDEX, Map, generator_object_prototype_map) \
189189
V(ITERATOR_RESULT_MAP_INDEX, Map, iterator_result_map) \
190+
V(JS_MAP_MAP_INDEX, Map, js_map_map) \
191+
V(JS_SET_MAP_INDEX, Map, js_set_map) \
190192
V(MAP_ITERATOR_MAP_INDEX, Map, map_iterator_map) \
191193
V(SET_ITERATOR_MAP_INDEX, Map, set_iterator_map) \
192194
V(ARRAY_VALUES_ITERATOR_INDEX, JSFunction, array_values_iterator) \
@@ -427,6 +429,8 @@ class Context: public FixedArray {
427429
STRONG_GENERATOR_FUNCTION_MAP_INDEX,
428430
GENERATOR_OBJECT_PROTOTYPE_MAP_INDEX,
429431
ITERATOR_RESULT_MAP_INDEX,
432+
JS_MAP_MAP_INDEX,
433+
JS_SET_MAP_INDEX,
430434
MAP_ITERATOR_MAP_INDEX,
431435
SET_ITERATOR_MAP_INDEX,
432436
ARRAY_VALUES_ITERATOR_INDEX,

src/factory.cc

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1744,6 +1744,22 @@ Handle<JSDataView> Factory::NewJSDataView() {
17441744
}
17451745

17461746

1747+
Handle<JSMap> Factory::NewJSMap() {
1748+
Handle<Map> map(isolate()->native_context()->js_map_map());
1749+
Handle<JSMap> js_map = Handle<JSMap>::cast(NewJSObjectFromMap(map));
1750+
Runtime::JSMapInitialize(isolate(), js_map);
1751+
return js_map;
1752+
}
1753+
1754+
1755+
Handle<JSSet> Factory::NewJSSet() {
1756+
Handle<Map> map(isolate()->native_context()->js_set_map());
1757+
Handle<JSSet> js_set = Handle<JSSet>::cast(NewJSObjectFromMap(map));
1758+
Runtime::JSSetInitialize(isolate(), js_set);
1759+
return js_set;
1760+
}
1761+
1762+
17471763
Handle<JSMapIterator> Factory::NewJSMapIterator() {
17481764
Handle<Map> map(isolate()->native_context()->map_iterator_map());
17491765
CALL_HEAP_FUNCTION(isolate(),

src/factory.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,9 @@ class Factory final {
464464
Handle<JSDataView> NewJSDataView(Handle<JSArrayBuffer> buffer,
465465
size_t byte_offset, size_t byte_length);
466466

467+
Handle<JSMap> NewJSMap();
468+
Handle<JSSet> NewJSSet();
469+
467470
// TODO(aandrey): Maybe these should take table, index and kind arguments.
468471
Handle<JSMapIterator> NewJSMapIterator();
469472
Handle<JSSetIterator> NewJSSetIterator();

src/runtime/runtime-collections.cc

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,17 @@ RUNTIME_FUNCTION(Runtime_GenericHash) {
4545
}
4646

4747

48+
void Runtime::JSSetInitialize(Isolate* isolate, Handle<JSSet> set) {
49+
Handle<OrderedHashSet> table = isolate->factory()->NewOrderedHashSet();
50+
set->set_table(*table);
51+
}
52+
53+
4854
RUNTIME_FUNCTION(Runtime_SetInitialize) {
4955
HandleScope scope(isolate);
5056
DCHECK(args.length() == 1);
5157
CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
52-
Handle<OrderedHashSet> table = isolate->factory()->NewOrderedHashSet();
53-
holder->set_table(*table);
58+
Runtime::JSSetInitialize(isolate, holder);
5459
return *holder;
5560
}
5661

@@ -143,12 +148,17 @@ RUNTIME_FUNCTION(Runtime_SetIteratorDetails) {
143148
}
144149

145150

151+
void Runtime::JSMapInitialize(Isolate* isolate, Handle<JSMap> map) {
152+
Handle<OrderedHashMap> table = isolate->factory()->NewOrderedHashMap();
153+
map->set_table(*table);
154+
}
155+
156+
146157
RUNTIME_FUNCTION(Runtime_MapInitialize) {
147158
HandleScope scope(isolate);
148159
DCHECK(args.length() == 1);
149160
CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
150-
Handle<OrderedHashMap> table = isolate->factory()->NewOrderedHashMap();
151-
holder->set_table(*table);
161+
Runtime::JSMapInitialize(isolate, holder);
152162
return *holder;
153163
}
154164

src/runtime/runtime.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -852,6 +852,10 @@ class Runtime : public AllStatic {
852852
Isolate* isolate, Handle<FixedArray> literals,
853853
Handle<FixedArray> elements, bool is_strong);
854854

855+
856+
static void JSMapInitialize(Isolate* isolate, Handle<JSMap> map);
857+
static void JSSetInitialize(Isolate* isolate, Handle<JSSet> set);
858+
855859
static void WeakCollectionInitialize(
856860
Isolate* isolate, Handle<JSWeakCollection> weak_collection);
857861
static void WeakCollectionSet(Handle<JSWeakCollection> weak_collection,

test/cctest/test-api.cc

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21100,3 +21100,37 @@ TEST(ExtrasExportsObject) {
2110021100

2110121101
CHECK(result->Value() == 5.0);
2110221102
}
21103+
21104+
21105+
TEST(Map) {
21106+
v8::Isolate* isolate = CcTest::isolate();
21107+
v8::HandleScope handle_scope(isolate);
21108+
LocalContext env;
21109+
21110+
v8::Local<v8::Map> map = v8::Map::New(isolate);
21111+
CHECK(map->IsObject());
21112+
CHECK(map->IsMap());
21113+
CHECK_EQ(0, map->Size());
21114+
21115+
v8::Local<v8::Value> val = CompileRun("new Map([[1, 2], [3, 4]])");
21116+
CHECK(val->IsMap());
21117+
map = v8::Local<v8::Map>::Cast(val);
21118+
CHECK_EQ(2, map->Size());
21119+
}
21120+
21121+
21122+
TEST(Set) {
21123+
v8::Isolate* isolate = CcTest::isolate();
21124+
v8::HandleScope handle_scope(isolate);
21125+
LocalContext env;
21126+
21127+
v8::Local<v8::Set> set = v8::Set::New(isolate);
21128+
CHECK(set->IsObject());
21129+
CHECK(set->IsSet());
21130+
CHECK_EQ(0, set->Size());
21131+
21132+
v8::Local<v8::Value> val = CompileRun("new Set([1, 2])");
21133+
CHECK(val->IsSet());
21134+
set = v8::Local<v8::Set>::Cast(val);
21135+
CHECK_EQ(2, set->Size());
21136+
}

0 commit comments

Comments
 (0)