Add basic API support for Map & Set
authoradamk <adamk@chromium.org>
Tue, 26 May 2015 17:36:48 +0000 (10:36 -0700)
committerCommit bot <commit-bot@chromium.org>
Tue, 26 May 2015 17:37:01 +0000 (17:37 +0000)
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}

include/v8.h
src/api.cc
src/api.h
src/bootstrapper.cc
src/contexts.h
src/factory.cc
src/factory.h
src/runtime/runtime-collections.cc
src/runtime/runtime.h
test/cctest/test-api.cc
test/cctest/test-hashmap.cc

index 27e212d468f054878c5e04fd7e3c2d493d2a23a4..16975d5af6b8144633c71d88857798eac3d30ca1 100644 (file)
@@ -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);
index 52f373a8c0a15c2508ebc02bac222c8285e799e1..dbc782c2dbe6802be7892cccf0a84017c923fd7c 100644 (file)
@@ -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);
index 886b903d35820e968b00430fc264ef2c4d110bdc..6d7aaeab4adec09d6404310a530c842be86c82fe 100644 (file)
--- a/src/api.h
+++ b/src/api.h
@@ -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)
index fcca1548443ca809bb8685efcebcf77039497e60..eee9bd3e0722c5520d0561357664c2bbeb5e83e9 100644 (file)
@@ -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);
index 106dd54a417ce900b2d465b84844e70cdbdf2d12..82aa8ca830fbe6de99e0d58e057fb37aae8b043c 100644 (file)
@@ -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,
index fc8919c648dcee78318d29611a7fa6d100daafc2..e5ee73b30f9c667f9f9bb8c7c4cca44698def134 100644 (file)
@@ -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(),
index 01a2474a45cd837e72bfad64f04427885a507034..076f81d8978ded82ef5c48bc995789da15e070c1 100644 (file)
@@ -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();
index 1eef18945e634e2c5d666d85c3a7d68cc9d913f1..94113fd69fb5457441b611e3410d27b156463c37 100644 (file)
@@ -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;
 }
 
index b8d03074c65e2e720185c1bc0c16b4e91b265fce..c0a8af54e283279831421b1290802f7480c6f30d 100644 (file)
@@ -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,
index f2e5d6f87d4b7e4e151d60deed74b0f5181af0a2..af83daaf376651077634a187d41e4c684cc455c9 100644 (file)
@@ -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());
+}
index fb56225fb4432a7f0b17acc78e73290ba395b447..b45d6c7183d0e0111ef22a7c72869c166179f4e0 100644 (file)
@@ -171,7 +171,7 @@ void TestSet(IntKeyHash hash, int size) {
 }
 
 
-TEST(Set) {
+TEST(HashSet) {
   TestSet(Hash, 100);
   TestSet(CollisionHash, 50);
 }