From: adamk Date: Tue, 23 Jun 2015 15:14:06 +0000 (-0700) Subject: Expose Map/Set methods through the API X-Git-Tag: upstream/4.7.83~1803 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=df472240285a93f25edac20100db2240fae5c7c6;p=platform%2Fupstream%2Fv8.git Expose Map/Set methods through the API Map: get, set, has, delete, clear Set: add, has, delete, clear All except clear are implemented as calls into collection.js. Note that some of these shadow methods of v8::Object. It's unclear how confusing that's going to be: on the one hand, it seems likely that most operations you would want to do on a Map or Set are these. On the other, generic code could get confused if it somehow gets ahold of a variable that happens to be C++-typed as a v8::Map or v8::Set. BUG=v8:3340 LOG=y Review URL: https://codereview.chromium.org/1204623002 Cr-Commit-Position: refs/heads/master@{#29237} --- diff --git a/include/v8.h b/include/v8.h index 0caec4317..e16c2b372 100644 --- a/include/v8.h +++ b/include/v8.h @@ -2982,6 +2982,16 @@ class V8_EXPORT Array : public Object { class V8_EXPORT Map : public Object { public: size_t Size() const; + void Clear(); + V8_WARN_UNUSED_RESULT MaybeLocal Get(Local context, + Local key); + V8_WARN_UNUSED_RESULT MaybeLocal Set(Local context, + Local key, + Local value); + V8_WARN_UNUSED_RESULT Maybe Has(Local context, + Local key); + V8_WARN_UNUSED_RESULT Maybe Delete(Local context, + Local key); /** * Returns an array of length Size() * 2, where index N is the Nth key and @@ -3016,6 +3026,13 @@ class V8_EXPORT Map : public Object { class V8_EXPORT Set : public Object { public: size_t Size() const; + void Clear(); + V8_WARN_UNUSED_RESULT MaybeLocal Add(Local context, + Local key); + V8_WARN_UNUSED_RESULT Maybe Has(Local context, + Local key); + V8_WARN_UNUSED_RESULT Maybe Delete(Local context, + Local key); /** * Returns an array of the keys in this Set. diff --git a/src/api.cc b/src/api.cc index ea1da6958..3b2c9909b 100644 --- a/src/api.cc +++ b/src/api.cc @@ -6264,6 +6264,70 @@ size_t v8::Map::Size() const { } +void Map::Clear() { + auto self = Utils::OpenHandle(this); + i::Isolate* isolate = self->GetIsolate(); + LOG_API(isolate, "Map::Clear"); + ENTER_V8(isolate); + i::Runtime::JSMapClear(isolate, self); +} + + +MaybeLocal Map::Get(Local context, Local key) { + PREPARE_FOR_EXECUTION(context, "Map::Get", Value); + auto self = Utils::OpenHandle(this); + Local result; + i::Handle argv[] = {Utils::OpenHandle(*key)}; + has_pending_exception = + !ToLocal(i::Execution::Call(isolate, isolate->map_get(), self, + arraysize(argv), argv, false), + &result); + RETURN_ON_FAILED_EXECUTION(Value); + RETURN_ESCAPED(result); +} + + +MaybeLocal Map::Set(Local context, Local key, + Local value) { + PREPARE_FOR_EXECUTION(context, "Map::Set", Map); + auto self = Utils::OpenHandle(this); + i::Handle result; + i::Handle argv[] = {Utils::OpenHandle(*key), + Utils::OpenHandle(*value)}; + has_pending_exception = + !i::Execution::Call(isolate, isolate->map_set(), self, arraysize(argv), + argv, false).ToHandle(&result); + RETURN_ON_FAILED_EXECUTION(Map); + RETURN_ESCAPED(Local::Cast(Utils::ToLocal(result))); +} + + +Maybe Map::Has(Local context, Local key) { + PREPARE_FOR_EXECUTION_PRIMITIVE(context, "Map::Has", bool); + auto self = Utils::OpenHandle(this); + i::Handle result; + i::Handle argv[] = {Utils::OpenHandle(*key)}; + has_pending_exception = + !i::Execution::Call(isolate, isolate->map_has(), self, arraysize(argv), + argv, false).ToHandle(&result); + RETURN_ON_FAILED_EXECUTION_PRIMITIVE(bool); + return Just(result->IsTrue()); +} + + +Maybe Map::Delete(Local context, Local key) { + PREPARE_FOR_EXECUTION_PRIMITIVE(context, "Map::Delete", bool); + auto self = Utils::OpenHandle(this); + i::Handle result; + i::Handle argv[] = {Utils::OpenHandle(*key)}; + has_pending_exception = + !i::Execution::Call(isolate, isolate->map_delete(), self, arraysize(argv), + argv, false).ToHandle(&result); + RETURN_ON_FAILED_EXECUTION_PRIMITIVE(bool); + return Just(result->IsTrue()); +} + + Local Map::AsArray() const { i::Handle obj = Utils::OpenHandle(this); i::Isolate* isolate = obj->GetIsolate(); @@ -6316,6 +6380,54 @@ size_t v8::Set::Size() const { } +void Set::Clear() { + auto self = Utils::OpenHandle(this); + i::Isolate* isolate = self->GetIsolate(); + LOG_API(isolate, "Set::Clear"); + ENTER_V8(isolate); + i::Runtime::JSSetClear(isolate, self); +} + + +MaybeLocal Set::Add(Local context, Local key) { + PREPARE_FOR_EXECUTION(context, "Set::Add", Set); + auto self = Utils::OpenHandle(this); + i::Handle result; + i::Handle argv[] = {Utils::OpenHandle(*key)}; + has_pending_exception = + !i::Execution::Call(isolate, isolate->set_add(), self, arraysize(argv), + argv, false).ToHandle(&result); + RETURN_ON_FAILED_EXECUTION(Set); + RETURN_ESCAPED(Local::Cast(Utils::ToLocal(result))); +} + + +Maybe Set::Has(Local context, Local key) { + PREPARE_FOR_EXECUTION_PRIMITIVE(context, "Set::Has", bool); + auto self = Utils::OpenHandle(this); + i::Handle result; + i::Handle argv[] = {Utils::OpenHandle(*key)}; + has_pending_exception = + !i::Execution::Call(isolate, isolate->set_has(), self, arraysize(argv), + argv, false).ToHandle(&result); + RETURN_ON_FAILED_EXECUTION_PRIMITIVE(bool); + return Just(result->IsTrue()); +} + + +Maybe Set::Delete(Local context, Local key) { + PREPARE_FOR_EXECUTION_PRIMITIVE(context, "Set::Delete", bool); + auto self = Utils::OpenHandle(this); + i::Handle result; + i::Handle argv[] = {Utils::OpenHandle(*key)}; + has_pending_exception = + !i::Execution::Call(isolate, isolate->set_delete(), self, arraysize(argv), + argv, false).ToHandle(&result); + RETURN_ON_FAILED_EXECUTION_PRIMITIVE(bool); + return Just(result->IsTrue()); +} + + Local Set::AsArray() const { i::Handle obj = Utils::OpenHandle(this); i::Isolate* isolate = obj->GetIsolate(); diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc index c38e9da4f..b0a625775 100644 --- a/src/bootstrapper.cc +++ b/src/bootstrapper.cc @@ -1711,6 +1711,13 @@ void Genesis::InstallNativeFunctions() { INSTALL_NATIVE(JSFunction, "$observeNativeObjectNotifierPerformChange", native_object_notifier_perform_change); INSTALL_NATIVE(JSFunction, "$arrayValues", array_values_iterator); + INSTALL_NATIVE(JSFunction, "$mapGet", map_get); + INSTALL_NATIVE(JSFunction, "$mapSet", map_set); + INSTALL_NATIVE(JSFunction, "$mapHas", map_has); + INSTALL_NATIVE(JSFunction, "$mapDelete", map_delete); + INSTALL_NATIVE(JSFunction, "$setAdd", set_add); + INSTALL_NATIVE(JSFunction, "$setHas", set_has); + INSTALL_NATIVE(JSFunction, "$setDelete", set_delete); INSTALL_NATIVE(JSFunction, "$mapFromArray", map_from_array); INSTALL_NATIVE(JSFunction, "$setFromArray", set_from_array); } diff --git a/src/collection.js b/src/collection.js index 86898529c..ceab1642c 100644 --- a/src/collection.js +++ b/src/collection.js @@ -4,6 +4,12 @@ var $getHash; var $getExistingHash; +var $mapSet; +var $mapHas; +var $mapDelete; +var $setAdd; +var $setHas; +var $setDelete; var $mapFromArray; var $setFromArray; @@ -481,6 +487,13 @@ utils.InstallFunctions(GlobalMap.prototype, DONT_ENUM, [ // Expose to the global scope. $getHash = GetHash; $getExistingHash = GetExistingHash; +$mapGet = MapGet; +$mapSet = MapSet; +$mapHas = MapHas; +$mapDelete = MapDelete; +$setAdd = SetAdd; +$setHas = SetHas; +$setDelete = SetDelete; $mapFromArray = function(array) { var map = new GlobalMap; diff --git a/src/contexts.h b/src/contexts.h index 670f5a7c0..78d4bc425 100644 --- a/src/contexts.h +++ b/src/contexts.h @@ -191,6 +191,13 @@ enum BindingFlags { V(JS_MAP_MAP_INDEX, Map, js_map_map) \ V(JS_SET_FUN_INDEX, JSFunction, js_set_fun) \ V(JS_SET_MAP_INDEX, Map, js_set_map) \ + V(MAP_GET_METHOD_INDEX, JSFunction, map_get) \ + V(MAP_SET_METHOD_INDEX, JSFunction, map_set) \ + V(MAP_HAS_METHOD_INDEX, JSFunction, map_has) \ + V(MAP_DELETE_METHOD_INDEX, JSFunction, map_delete) \ + V(SET_ADD_METHOD_INDEX, JSFunction, set_add) \ + V(SET_HAS_METHOD_INDEX, JSFunction, set_has) \ + V(SET_DELETE_METHOD_INDEX, JSFunction, set_delete) \ 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) \ @@ -437,6 +444,13 @@ class Context: public FixedArray { JS_MAP_MAP_INDEX, JS_SET_FUN_INDEX, JS_SET_MAP_INDEX, + MAP_GET_METHOD_INDEX, + MAP_SET_METHOD_INDEX, + MAP_HAS_METHOD_INDEX, + MAP_DELETE_METHOD_INDEX, + SET_ADD_METHOD_INDEX, + SET_HAS_METHOD_INDEX, + SET_DELETE_METHOD_INDEX, MAP_FROM_ARRAY_INDEX, SET_FROM_ARRAY_INDEX, MAP_ITERATOR_MAP_INDEX, diff --git a/src/runtime/runtime-collections.cc b/src/runtime/runtime-collections.cc index 94113fd69..1ba1e3435 100644 --- a/src/runtime/runtime-collections.cc +++ b/src/runtime/runtime-collections.cc @@ -82,13 +82,18 @@ RUNTIME_FUNCTION(Runtime_SetShrink) { } +void Runtime::JSSetClear(Isolate* isolate, Handle set) { + Handle table(OrderedHashSet::cast(set->table())); + table = OrderedHashSet::Clear(table); + set->set_table(*table); +} + + RUNTIME_FUNCTION(Runtime_SetClear) { HandleScope scope(isolate); DCHECK(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0); - Handle table(OrderedHashSet::cast(holder->table())); - table = OrderedHashSet::Clear(table); - holder->set_table(*table); + Runtime::JSSetClear(isolate, holder); return isolate->heap()->undefined_value(); } @@ -174,13 +179,18 @@ RUNTIME_FUNCTION(Runtime_MapShrink) { } +void Runtime::JSMapClear(Isolate* isolate, Handle map) { + Handle table(OrderedHashMap::cast(map->table())); + table = OrderedHashMap::Clear(table); + map->set_table(*table); +} + + RUNTIME_FUNCTION(Runtime_MapClear) { HandleScope scope(isolate); DCHECK(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0); - Handle table(OrderedHashMap::cast(holder->table())); - table = OrderedHashMap::Clear(table); - holder->set_table(*table); + Runtime::JSMapClear(isolate, holder); return isolate->heap()->undefined_value(); } diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index 96d8a741e..c9db4e74c 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -872,7 +872,9 @@ class Runtime : public AllStatic { static void JSMapInitialize(Isolate* isolate, Handle map); + static void JSMapClear(Isolate* isolate, Handle map); static void JSSetInitialize(Isolate* isolate, Handle set); + static void JSSetClear(Isolate* isolate, Handle set); static void WeakCollectionInitialize( Isolate* isolate, Handle weak_collection); diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc index 3d8af9f3f..d0e7a87ea 100644 --- a/test/cctest/test-api.cc +++ b/test/cctest/test-api.cc @@ -21584,8 +21584,43 @@ TEST(Map) { map = v8::Map::FromArray(env.local(), contents).ToLocalChecked(); CHECK_EQ(2U, map->Size()); + CHECK(map->Has(env.local(), v8::Integer::New(isolate, 1)).FromJust()); + CHECK(map->Has(env.local(), v8::Integer::New(isolate, 3)).FromJust()); + + CHECK(!map->Has(env.local(), v8::Integer::New(isolate, 2)).FromJust()); + CHECK(!map->Has(env.local(), map).FromJust()); + + CHECK_EQ(2, map->Get(env.local(), v8::Integer::New(isolate, 1)) + .ToLocalChecked() + ->Int32Value()); + CHECK_EQ(4, map->Get(env.local(), v8::Integer::New(isolate, 3)) + .ToLocalChecked() + ->Int32Value()); + + CHECK(map->Get(env.local(), v8::Integer::New(isolate, 42)) + .ToLocalChecked() + ->IsUndefined()); + + CHECK(!map->Set(env.local(), map, map).IsEmpty()); + CHECK_EQ(3U, map->Size()); + CHECK(map->Has(env.local(), map).FromJust()); + + CHECK(map->Delete(env.local(), map).FromJust()); + CHECK_EQ(2U, map->Size()); + CHECK(!map->Has(env.local(), map).FromJust()); + CHECK(!map->Delete(env.local(), map).FromJust()); + + map->Clear(); + CHECK_EQ(0U, map->Size()); +} + + +TEST(MapFromArrayOddLength) { + v8::Isolate* isolate = CcTest::isolate(); + v8::HandleScope handle_scope(isolate); + LocalContext env; // Odd lengths result in a null MaybeLocal. - contents = v8::Array::New(isolate, 41); + Local contents = v8::Array::New(isolate, 41); CHECK(v8::Map::FromArray(env.local(), contents).IsEmpty()); } @@ -21613,4 +21648,22 @@ TEST(Set) { set = v8::Set::FromArray(env.local(), keys).ToLocalChecked(); CHECK_EQ(2U, set->Size()); + + CHECK(set->Has(env.local(), v8::Integer::New(isolate, 1)).FromJust()); + CHECK(set->Has(env.local(), v8::Integer::New(isolate, 2)).FromJust()); + + CHECK(!set->Has(env.local(), v8::Integer::New(isolate, 3)).FromJust()); + CHECK(!set->Has(env.local(), set).FromJust()); + + CHECK(!set->Add(env.local(), set).IsEmpty()); + CHECK_EQ(3U, set->Size()); + CHECK(set->Has(env.local(), set).FromJust()); + + CHECK(set->Delete(env.local(), set).FromJust()); + CHECK_EQ(2U, set->Size()); + CHECK(!set->Has(env.local(), set).FromJust()); + CHECK(!set->Delete(env.local(), set).FromJust()); + + set->Clear(); + CHECK_EQ(0U, set->Size()); }