Index: test/cctest/test-api.cc |
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc |
index dcb11be19d1c84a377b2381a7d3929aff4bbe3a1..4b0aa3bfaf397b32aa561cd2f72f77476b5087b5 100644 |
--- a/test/cctest/test-api.cc |
+++ b/test/cctest/test-api.cc |
@@ -3193,6 +3193,124 @@ TEST(PersistentValueMap) { |
} |
+namespace { |
+ |
+void* IntKeyToVoidPointer(int key) { return reinterpret_cast<void*>(key << 1); } |
+ |
+ |
+Local<v8::Object> NewObjectForIntKey( |
+ v8::Isolate* isolate, const v8::Global<v8::ObjectTemplate>& templ, |
+ int key) { |
+ auto local = Local<v8::ObjectTemplate>::New(isolate, templ); |
+ auto obj = local->NewInstance(); |
+ obj->SetAlignedPointerInInternalField(0, IntKeyToVoidPointer(key)); |
+ return obj; |
+} |
+ |
+ |
+template <typename K, typename V> |
+class PhantomStdMapTraits : public v8::StdMapTraits<K, V> { |
+ public: |
+ typedef typename v8::GlobalValueMap<K, V, PhantomStdMapTraits<K, V>> MapType; |
+ static const v8::PersistentContainerCallbackType kCallbackType = |
+ v8::kWeakWithInternalFields; |
+ struct WeakCallbackDataType { |
+ MapType* map; |
+ K key; |
+ }; |
+ static WeakCallbackDataType* WeakCallbackParameter(MapType* map, const K& key, |
+ Local<V> value) { |
+ WeakCallbackDataType* data = new WeakCallbackDataType; |
+ data->map = map; |
+ data->key = key; |
+ return data; |
+ } |
+ static MapType* MapFromWeakCallbackInfo( |
+ const v8::WeakCallbackInfo<WeakCallbackDataType>& data) { |
+ return data.GetParameter()->map; |
+ } |
+ static K KeyFromWeakCallbackInfo( |
+ const v8::WeakCallbackInfo<WeakCallbackDataType>& data) { |
+ return data.GetParameter()->key; |
+ } |
+ static void DisposeCallbackData(WeakCallbackDataType* data) { delete data; } |
+ static void Dispose(v8::Isolate* isolate, v8::Global<V> value, K key) { |
+ CHECK_EQ(IntKeyToVoidPointer(key), |
+ v8::Object::GetAlignedPointerFromInternalField(value, 0)); |
+ } |
+ static void DisposeWeak( |
+ v8::Isolate* isolate, |
+ const v8::WeakCallbackInfo<WeakCallbackDataType>& info, K key) { |
+ CHECK_EQ(IntKeyToVoidPointer(key), info.GetInternalField(0)); |
+ } |
+}; |
+} |
+ |
+ |
+TEST(GlobalValueMap) { |
+ typedef v8::GlobalValueMap<int, v8::Object, |
+ PhantomStdMapTraits<int, v8::Object>> Map; |
+ LocalContext env; |
+ v8::Isolate* isolate = env->GetIsolate(); |
+ v8::Global<ObjectTemplate> templ; |
+ { |
+ HandleScope scope(isolate); |
+ auto t = ObjectTemplate::New(isolate); |
+ t->SetInternalFieldCount(1); |
+ templ.Reset(isolate, t); |
+ } |
+ Map map(isolate); |
+ v8::internal::GlobalHandles* global_handles = |
+ reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles(); |
+ int initial_handle_count = global_handles->global_handles_count(); |
+ CHECK_EQ(0, static_cast<int>(map.Size())); |
+ { |
+ HandleScope scope(isolate); |
+ Local<v8::Object> obj = map.Get(7); |
+ CHECK(obj.IsEmpty()); |
+ Local<v8::Object> expected = v8::Object::New(isolate); |
+ map.Set(7, expected); |
+ CHECK_EQ(1, static_cast<int>(map.Size())); |
+ obj = map.Get(7); |
+ CHECK(expected->Equals(obj)); |
+ { |
+ Map::PersistentValueReference ref = map.GetReference(7); |
+ CHECK(expected->Equals(ref.NewLocal(isolate))); |
+ } |
+ v8::Global<v8::Object> removed = map.Remove(7); |
+ CHECK_EQ(0, static_cast<int>(map.Size())); |
+ CHECK(expected == removed); |
+ removed = map.Remove(7); |
+ CHECK(removed.IsEmpty()); |
+ map.Set(8, expected); |
+ CHECK_EQ(1, static_cast<int>(map.Size())); |
+ map.Set(8, expected); |
+ CHECK_EQ(1, static_cast<int>(map.Size())); |
+ { |
+ Map::PersistentValueReference ref; |
+ Local<v8::Object> expected2 = NewObjectForIntKey(isolate, templ, 8); |
+ removed = map.Set(8, v8::Global<v8::Object>(isolate, expected2), &ref); |
+ CHECK_EQ(1, static_cast<int>(map.Size())); |
+ CHECK(expected == removed); |
+ CHECK(expected2->Equals(ref.NewLocal(isolate))); |
+ } |
+ } |
+ CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count()); |
+ CcTest::i_isolate()->heap()->CollectAllGarbage( |
+ i::Heap::kAbortIncrementalMarkingMask); |
+ CHECK_EQ(0, static_cast<int>(map.Size())); |
+ CHECK_EQ(initial_handle_count, global_handles->global_handles_count()); |
+ { |
+ HandleScope scope(isolate); |
+ Local<v8::Object> value = NewObjectForIntKey(isolate, templ, 9); |
+ map.Set(9, value); |
+ map.Clear(); |
+ } |
+ CHECK_EQ(0, static_cast<int>(map.Size())); |
+ CHECK_EQ(initial_handle_count, global_handles->global_handles_count()); |
+} |
+ |
+ |
TEST(PersistentValueVector) { |
LocalContext env; |
v8::Isolate* isolate = env->GetIsolate(); |