From 58d623f228b90213a530afc74dc317553f842673 Mon Sep 17 00:00:00 2001 From: "rossberg@chromium.org" Date: Tue, 18 Mar 2014 09:57:14 +0000 Subject: [PATCH] Stage ES6 promises and weak collections Split collections flag into weak and non-weak. R=mstarzinger@chromium.org BUG= Review URL: https://codereview.chromium.org/201593004 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@20019 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/bootstrapper.cc | 12 +- src/collection.js | 173 ----------- src/flag-definitions.h | 10 +- src/weak_collection.js | 206 +++++++++++++ test/mjsunit/{harmony => es6}/promises.js | 0 .../{harmony => es6}/regress/regress-2034.js | 2 +- .../{harmony => es6}/regress/regress-2156.js | 2 +- .../{harmony => es6}/regress/regress-2829.js | 2 +- test/mjsunit/es6/weak_collections.js | 333 +++++++++++++++++++++ test/mjsunit/es7/object-observe.js | 3 +- test/mjsunit/harmony/collections.js | 7 +- test/mjsunit/harmony/private.js | 2 +- test/mjsunit/harmony/proxies-hash.js | 2 +- test/mjsunit/harmony/symbols.js | 2 +- test/mjsunit/regress/regress-crbug-350864.js | 2 +- tools/gyp/v8.gyp | 1 + 16 files changed, 568 insertions(+), 191 deletions(-) create mode 100644 src/weak_collection.js rename test/mjsunit/{harmony => es6}/promises.js (100%) rename test/mjsunit/{harmony => es6}/regress/regress-2034.js (98%) rename test/mjsunit/{harmony => es6}/regress/regress-2156.js (96%) rename test/mjsunit/{harmony => es6}/regress/regress-2829.js (98%) create mode 100644 test/mjsunit/es6/weak_collections.js diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc index 8ac594c..879f103 100644 --- a/src/bootstrapper.cc +++ b/src/bootstrapper.cc @@ -1350,16 +1350,19 @@ void Genesis::InitializeExperimentalGlobal() { } if (FLAG_harmony_collections) { - { // -- S e t - InstallFunction(global, "Set", JS_SET_TYPE, JSSet::kSize, + { // -- M a p + InstallFunction(global, "Map", JS_MAP_TYPE, JSMap::kSize, isolate()->initial_object_prototype(), Builtins::kIllegal, true, true); } - { // -- M a p - InstallFunction(global, "Map", JS_MAP_TYPE, JSMap::kSize, + { // -- S e t + InstallFunction(global, "Set", JS_SET_TYPE, JSSet::kSize, isolate()->initial_object_prototype(), Builtins::kIllegal, true, true); } + } + + if (FLAG_harmony_weak_collections) { { // -- W e a k M a p InstallFunction(global, "WeakMap", JS_WEAK_MAP_TYPE, JSWeakMap::kSize, isolate()->initial_object_prototype(), @@ -2050,6 +2053,7 @@ bool Genesis::InstallExperimentalNatives() { INSTALL_EXPERIMENTAL_NATIVE(i, symbols, "symbol.js") INSTALL_EXPERIMENTAL_NATIVE(i, proxies, "proxy.js") INSTALL_EXPERIMENTAL_NATIVE(i, collections, "collection.js") + INSTALL_EXPERIMENTAL_NATIVE(i, weak_collections, "weak_collection.js") INSTALL_EXPERIMENTAL_NATIVE(i, promises, "promise.js") INSTALL_EXPERIMENTAL_NATIVE(i, generators, "generator.js") INSTALL_EXPERIMENTAL_NATIVE(i, iteration, "array-iterator.js") diff --git a/src/collection.js b/src/collection.js index 1f7aef4..9054187 100644 --- a/src/collection.js +++ b/src/collection.js @@ -33,8 +33,6 @@ var $Set = global.Set; var $Map = global.Map; -var $WeakMap = global.WeakMap; -var $WeakSet = global.WeakSet; // Global sentinel to be used instead of undefined keys, which are not // supported internally but required for Harmony sets and maps. @@ -230,174 +228,3 @@ function SetUpMap() { } SetUpMap(); - - -// ------------------------------------------------------------------- -// Harmony WeakMap - -function WeakMapConstructor() { - if (%_IsConstructCall()) { - %WeakCollectionInitialize(this); - } else { - throw MakeTypeError('constructor_not_function', ['WeakMap']); - } -} - - -function WeakMapGet(key) { - if (!IS_WEAKMAP(this)) { - throw MakeTypeError('incompatible_method_receiver', - ['WeakMap.prototype.get', this]); - } - if (!(IS_SPEC_OBJECT(key) || IS_SYMBOL(key))) { - throw %MakeTypeError('invalid_weakmap_key', [this, key]); - } - return %WeakCollectionGet(this, key); -} - - -function WeakMapSet(key, value) { - if (!IS_WEAKMAP(this)) { - throw MakeTypeError('incompatible_method_receiver', - ['WeakMap.prototype.set', this]); - } - if (!(IS_SPEC_OBJECT(key) || IS_SYMBOL(key))) { - throw %MakeTypeError('invalid_weakmap_key', [this, key]); - } - return %WeakCollectionSet(this, key, value); -} - - -function WeakMapHas(key) { - if (!IS_WEAKMAP(this)) { - throw MakeTypeError('incompatible_method_receiver', - ['WeakMap.prototype.has', this]); - } - if (!(IS_SPEC_OBJECT(key) || IS_SYMBOL(key))) { - throw %MakeTypeError('invalid_weakmap_key', [this, key]); - } - return %WeakCollectionHas(this, key); -} - - -function WeakMapDelete(key) { - if (!IS_WEAKMAP(this)) { - throw MakeTypeError('incompatible_method_receiver', - ['WeakMap.prototype.delete', this]); - } - if (!(IS_SPEC_OBJECT(key) || IS_SYMBOL(key))) { - throw %MakeTypeError('invalid_weakmap_key', [this, key]); - } - return %WeakCollectionDelete(this, key); -} - - -function WeakMapClear() { - if (!IS_WEAKMAP(this)) { - throw MakeTypeError('incompatible_method_receiver', - ['WeakMap.prototype.clear', this]); - } - // Replace the internal table with a new empty table. - %WeakCollectionInitialize(this); -} - - -// ------------------------------------------------------------------- - -function SetUpWeakMap() { - %CheckIsBootstrapping(); - - %SetCode($WeakMap, WeakMapConstructor); - %FunctionSetPrototype($WeakMap, new $Object()); - %SetProperty($WeakMap.prototype, "constructor", $WeakMap, DONT_ENUM); - - // Set up the non-enumerable functions on the WeakMap prototype object. - InstallFunctions($WeakMap.prototype, DONT_ENUM, $Array( - "get", WeakMapGet, - "set", WeakMapSet, - "has", WeakMapHas, - "delete", WeakMapDelete, - "clear", WeakMapClear - )); -} - -SetUpWeakMap(); - - -// ------------------------------------------------------------------- -// Harmony WeakSet - -function WeakSetConstructor() { - if (%_IsConstructCall()) { - %WeakCollectionInitialize(this); - } else { - throw MakeTypeError('constructor_not_function', ['WeakSet']); - } -} - - -function WeakSetAdd(value) { - if (!IS_WEAKSET(this)) { - throw MakeTypeError('incompatible_method_receiver', - ['WeakSet.prototype.add', this]); - } - if (!(IS_SPEC_OBJECT(value) || IS_SYMBOL(value))) { - throw %MakeTypeError('invalid_weakset_value', [this, value]); - } - return %WeakCollectionSet(this, value, true); -} - - -function WeakSetHas(value) { - if (!IS_WEAKSET(this)) { - throw MakeTypeError('incompatible_method_receiver', - ['WeakSet.prototype.has', this]); - } - if (!(IS_SPEC_OBJECT(value) || IS_SYMBOL(value))) { - throw %MakeTypeError('invalid_weakset_value', [this, value]); - } - return %WeakCollectionHas(this, value); -} - - -function WeakSetDelete(value) { - if (!IS_WEAKSET(this)) { - throw MakeTypeError('incompatible_method_receiver', - ['WeakSet.prototype.delete', this]); - } - if (!(IS_SPEC_OBJECT(value) || IS_SYMBOL(value))) { - throw %MakeTypeError('invalid_weakset_value', [this, value]); - } - return %WeakCollectionDelete(this, value); -} - - -function WeakSetClear() { - if (!IS_WEAKSET(this)) { - throw MakeTypeError('incompatible_method_receiver', - ['WeakSet.prototype.clear', this]); - } - // Replace the internal table with a new empty table. - %WeakCollectionInitialize(this); -} - - -// ------------------------------------------------------------------- - -function SetUpWeakSet() { - %CheckIsBootstrapping(); - - %SetCode($WeakSet, WeakSetConstructor); - %FunctionSetPrototype($WeakSet, new $Object()); - %SetProperty($WeakSet.prototype, "constructor", $WeakSet, DONT_ENUM); - - // Set up the non-enumerable functions on the WeakSet prototype object. - InstallFunctions($WeakSet.prototype, DONT_ENUM, $Array( - "add", WeakSetAdd, - "has", WeakSetHas, - "delete", WeakSetDelete, - "clear", WeakSetClear - )); -} - -SetUpWeakSet(); diff --git a/src/flag-definitions.h b/src/flag-definitions.h index 3bc8444..d69ab89 100644 --- a/src/flag-definitions.h +++ b/src/flag-definitions.h @@ -178,7 +178,9 @@ DEFINE_bool(harmony_symbols, false, DEFINE_bool(harmony_promises, false, "enable harmony promises") DEFINE_bool(harmony_proxies, false, "enable harmony proxies") DEFINE_bool(harmony_collections, false, - "enable harmony collections (sets, maps, and weak maps)") + "enable harmony collections (sets, maps, weak sets, weak maps)") +DEFINE_bool(harmony_weak_collections, false, + "enable only harmony weak collections (weak sets and maps)") DEFINE_bool(harmony_generators, false, "enable harmony generators") DEFINE_bool(harmony_iteration, false, "enable harmony iteration (for-of)") DEFINE_bool(harmony_numeric_literals, false, @@ -191,7 +193,6 @@ DEFINE_bool(harmony, false, "enable all harmony features (except typeof)") DEFINE_implication(harmony, harmony_scoping) DEFINE_implication(harmony, harmony_modules) DEFINE_implication(harmony, harmony_symbols) -DEFINE_implication(harmony, harmony_promises) DEFINE_implication(harmony, harmony_proxies) DEFINE_implication(harmony, harmony_collections) DEFINE_implication(harmony, harmony_generators) @@ -199,11 +200,14 @@ DEFINE_implication(harmony, harmony_iteration) DEFINE_implication(harmony, harmony_numeric_literals) DEFINE_implication(harmony, harmony_strings) DEFINE_implication(harmony, harmony_arrays) -DEFINE_implication(harmony_promises, harmony_collections) +DEFINE_implication(harmony_collections, harmony_weak_collections) +DEFINE_implication(harmony_promises, harmony_weak_collections) DEFINE_implication(harmony_modules, harmony_scoping) DEFINE_implication(harmony, es_staging) DEFINE_implication(es_staging, harmony_maths) +DEFINE_implication(es_staging, harmony_promises) +DEFINE_implication(es_staging, harmony_weak_collections) // Flags for experimental implementation features. DEFINE_bool(packed_arrays, true, "optimizes arrays that have no holes") diff --git a/src/weak_collection.js b/src/weak_collection.js new file mode 100644 index 0000000..81d4ab5 --- /dev/null +++ b/src/weak_collection.js @@ -0,0 +1,206 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"use strict"; + +// This file relies on the fact that the following declaration has been made +// in runtime.js: +// var $Array = global.Array; + +var $WeakMap = global.WeakMap; +var $WeakSet = global.WeakSet; + + +// ------------------------------------------------------------------- +// Harmony WeakMap + +function WeakMapConstructor() { + if (%_IsConstructCall()) { + %WeakCollectionInitialize(this); + } else { + throw MakeTypeError('constructor_not_function', ['WeakMap']); + } +} + + +function WeakMapGet(key) { + if (!IS_WEAKMAP(this)) { + throw MakeTypeError('incompatible_method_receiver', + ['WeakMap.prototype.get', this]); + } + if (!(IS_SPEC_OBJECT(key) || IS_SYMBOL(key))) { + throw %MakeTypeError('invalid_weakmap_key', [this, key]); + } + return %WeakCollectionGet(this, key); +} + + +function WeakMapSet(key, value) { + if (!IS_WEAKMAP(this)) { + throw MakeTypeError('incompatible_method_receiver', + ['WeakMap.prototype.set', this]); + } + if (!(IS_SPEC_OBJECT(key) || IS_SYMBOL(key))) { + throw %MakeTypeError('invalid_weakmap_key', [this, key]); + } + return %WeakCollectionSet(this, key, value); +} + + +function WeakMapHas(key) { + if (!IS_WEAKMAP(this)) { + throw MakeTypeError('incompatible_method_receiver', + ['WeakMap.prototype.has', this]); + } + if (!(IS_SPEC_OBJECT(key) || IS_SYMBOL(key))) { + throw %MakeTypeError('invalid_weakmap_key', [this, key]); + } + return %WeakCollectionHas(this, key); +} + + +function WeakMapDelete(key) { + if (!IS_WEAKMAP(this)) { + throw MakeTypeError('incompatible_method_receiver', + ['WeakMap.prototype.delete', this]); + } + if (!(IS_SPEC_OBJECT(key) || IS_SYMBOL(key))) { + throw %MakeTypeError('invalid_weakmap_key', [this, key]); + } + return %WeakCollectionDelete(this, key); +} + + +function WeakMapClear() { + if (!IS_WEAKMAP(this)) { + throw MakeTypeError('incompatible_method_receiver', + ['WeakMap.prototype.clear', this]); + } + // Replace the internal table with a new empty table. + %WeakCollectionInitialize(this); +} + + +// ------------------------------------------------------------------- + +function SetUpWeakMap() { + %CheckIsBootstrapping(); + + %SetCode($WeakMap, WeakMapConstructor); + %FunctionSetPrototype($WeakMap, new $Object()); + %SetProperty($WeakMap.prototype, "constructor", $WeakMap, DONT_ENUM); + + // Set up the non-enumerable functions on the WeakMap prototype object. + InstallFunctions($WeakMap.prototype, DONT_ENUM, $Array( + "get", WeakMapGet, + "set", WeakMapSet, + "has", WeakMapHas, + "delete", WeakMapDelete, + "clear", WeakMapClear + )); +} + +SetUpWeakMap(); + + +// ------------------------------------------------------------------- +// Harmony WeakSet + +function WeakSetConstructor() { + if (%_IsConstructCall()) { + %WeakCollectionInitialize(this); + } else { + throw MakeTypeError('constructor_not_function', ['WeakSet']); + } +} + + +function WeakSetAdd(value) { + if (!IS_WEAKSET(this)) { + throw MakeTypeError('incompatible_method_receiver', + ['WeakSet.prototype.add', this]); + } + if (!(IS_SPEC_OBJECT(value) || IS_SYMBOL(value))) { + throw %MakeTypeError('invalid_weakset_value', [this, value]); + } + return %WeakCollectionSet(this, value, true); +} + + +function WeakSetHas(value) { + if (!IS_WEAKSET(this)) { + throw MakeTypeError('incompatible_method_receiver', + ['WeakSet.prototype.has', this]); + } + if (!(IS_SPEC_OBJECT(value) || IS_SYMBOL(value))) { + throw %MakeTypeError('invalid_weakset_value', [this, value]); + } + return %WeakCollectionHas(this, value); +} + + +function WeakSetDelete(value) { + if (!IS_WEAKSET(this)) { + throw MakeTypeError('incompatible_method_receiver', + ['WeakSet.prototype.delete', this]); + } + if (!(IS_SPEC_OBJECT(value) || IS_SYMBOL(value))) { + throw %MakeTypeError('invalid_weakset_value', [this, value]); + } + return %WeakCollectionDelete(this, value); +} + + +function WeakSetClear() { + if (!IS_WEAKSET(this)) { + throw MakeTypeError('incompatible_method_receiver', + ['WeakSet.prototype.clear', this]); + } + // Replace the internal table with a new empty table. + %WeakCollectionInitialize(this); +} + + +// ------------------------------------------------------------------- + +function SetUpWeakSet() { + %CheckIsBootstrapping(); + + %SetCode($WeakSet, WeakSetConstructor); + %FunctionSetPrototype($WeakSet, new $Object()); + %SetProperty($WeakSet.prototype, "constructor", $WeakSet, DONT_ENUM); + + // Set up the non-enumerable functions on the WeakSet prototype object. + InstallFunctions($WeakSet.prototype, DONT_ENUM, $Array( + "add", WeakSetAdd, + "has", WeakSetHas, + "delete", WeakSetDelete, + "clear", WeakSetClear + )); +} + +SetUpWeakSet(); diff --git a/test/mjsunit/harmony/promises.js b/test/mjsunit/es6/promises.js similarity index 100% rename from test/mjsunit/harmony/promises.js rename to test/mjsunit/es6/promises.js diff --git a/test/mjsunit/harmony/regress/regress-2034.js b/test/mjsunit/es6/regress/regress-2034.js similarity index 98% rename from test/mjsunit/harmony/regress/regress-2034.js rename to test/mjsunit/es6/regress/regress-2034.js index c510f97..1b7dac0 100644 --- a/test/mjsunit/harmony/regress/regress-2034.js +++ b/test/mjsunit/es6/regress/regress-2034.js @@ -25,7 +25,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --harmony-collections +// Flags: --harmony-weak-collections var key = {}; var map = new WeakMap; diff --git a/test/mjsunit/harmony/regress/regress-2156.js b/test/mjsunit/es6/regress/regress-2156.js similarity index 96% rename from test/mjsunit/harmony/regress/regress-2156.js rename to test/mjsunit/es6/regress/regress-2156.js index 3482571..a34e381 100644 --- a/test/mjsunit/harmony/regress/regress-2156.js +++ b/test/mjsunit/es6/regress/regress-2156.js @@ -25,7 +25,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --allow-natives-syntax --harmony-collections +// Flags: --allow-natives-syntax --harmony-weak-collections var key1 = {}; var key2 = {}; diff --git a/test/mjsunit/harmony/regress/regress-2829.js b/test/mjsunit/es6/regress/regress-2829.js similarity index 98% rename from test/mjsunit/harmony/regress/regress-2829.js rename to test/mjsunit/es6/regress/regress-2829.js index a046ae0..8d8f3f8 100644 --- a/test/mjsunit/harmony/regress/regress-2829.js +++ b/test/mjsunit/es6/regress/regress-2829.js @@ -25,7 +25,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --harmony-collections +// Flags: --harmony-weak-collections (function test1() { var wm1 = new WeakMap(); diff --git a/test/mjsunit/es6/weak_collections.js b/test/mjsunit/es6/weak_collections.js new file mode 100644 index 0000000..af23903 --- /dev/null +++ b/test/mjsunit/es6/weak_collections.js @@ -0,0 +1,333 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Flags: --harmony-weak-collections --expose-gc --allow-natives-syntax + + +// Note: this test is superseded by harmony/collections.js. +// IF YOU CHANGE THIS FILE, apply the same changes to harmony/collections.js! +// TODO(rossberg): Remove once non-weak collections have caught up. + +// Test valid getter and setter calls on WeakSets. +function TestValidSetCalls(m) { + assertDoesNotThrow(function () { m.add(new Object) }); + assertDoesNotThrow(function () { m.has(new Object) }); + assertDoesNotThrow(function () { m.delete(new Object) }); +} +TestValidSetCalls(new WeakSet); + + +// Test valid getter and setter calls on WeakMaps +function TestValidMapCalls(m) { + assertDoesNotThrow(function () { m.get(new Object) }); + assertDoesNotThrow(function () { m.set(new Object) }); + assertDoesNotThrow(function () { m.has(new Object) }); + assertDoesNotThrow(function () { m.delete(new Object) }); +} +TestValidMapCalls(new WeakMap); + + +// Test invalid getter and setter calls for WeakMap +function TestInvalidCalls(m) { + assertThrows(function () { m.get(undefined) }, TypeError); + assertThrows(function () { m.set(undefined, 0) }, TypeError); + assertThrows(function () { m.get(null) }, TypeError); + assertThrows(function () { m.set(null, 0) }, TypeError); + assertThrows(function () { m.get(0) }, TypeError); + assertThrows(function () { m.set(0, 0) }, TypeError); + assertThrows(function () { m.get('a-key') }, TypeError); + assertThrows(function () { m.set('a-key', 0) }, TypeError); +} +TestInvalidCalls(new WeakMap); + + +// Test expected behavior for WeakSets +function TestSet(set, key) { + assertFalse(set.has(key)); + assertSame(undefined, set.add(key)); + assertTrue(set.has(key)); + assertTrue(set.delete(key)); + assertFalse(set.has(key)); + assertFalse(set.delete(key)); + assertFalse(set.has(key)); +} +function TestSetBehavior(set) { + for (var i = 0; i < 20; i++) { + TestSet(set, new Object); + TestSet(set, i); + TestSet(set, i / 100); + TestSet(set, 'key-' + i); + } + var keys = [ +0, -0, +Infinity, -Infinity, true, false, null, undefined ]; + for (var i = 0; i < keys.length; i++) { + TestSet(set, keys[i]); + } +} +TestSet(new WeakSet, new Object); + + +// Test expected mapping behavior for WeakMaps +function TestMapping(map, key, value) { + assertSame(undefined, map.set(key, value)); + assertSame(value, map.get(key)); +} +function TestMapBehavior1(m) { + TestMapping(m, new Object, 23); + TestMapping(m, new Object, 'the-value'); + TestMapping(m, new Object, new Object); +} +TestMapBehavior1(new WeakMap); + + +// Test expected querying behavior of WeakMaps +function TestQuery(m) { + var key = new Object; + var values = [ 'x', 0, +Infinity, -Infinity, true, false, null, undefined ]; + for (var i = 0; i < values.length; i++) { + TestMapping(m, key, values[i]); + assertTrue(m.has(key)); + assertFalse(m.has(new Object)); + } +} +TestQuery(new WeakMap); + + +// Test expected deletion behavior of WeakMaps +function TestDelete(m) { + var key = new Object; + TestMapping(m, key, 'to-be-deleted'); + assertTrue(m.delete(key)); + assertFalse(m.delete(key)); + assertFalse(m.delete(new Object)); + assertSame(m.get(key), undefined); +} +TestDelete(new WeakMap); + + +// Test GC of WeakMaps with entry +function TestGC1(m) { + var key = new Object; + m.set(key, 'not-collected'); + gc(); + assertSame('not-collected', m.get(key)); +} +TestGC1(new WeakMap); + + +// Test GC of WeakMaps with chained entries +function TestGC2(m) { + var head = new Object; + for (key = head, i = 0; i < 10; i++, key = m.get(key)) { + m.set(key, new Object); + } + gc(); + var count = 0; + for (key = head; key != undefined; key = m.get(key)) { + count++; + } + assertEquals(11, count); +} +TestGC2(new WeakMap); + + +// Test property attribute [[Enumerable]] +function TestEnumerable(func) { + function props(x) { + var array = []; + for (var p in x) array.push(p); + return array.sort(); + } + assertArrayEquals([], props(func)); + assertArrayEquals([], props(func.prototype)); + assertArrayEquals([], props(new func())); +} +TestEnumerable(WeakMap); +TestEnumerable(WeakSet); + + +// Test arbitrary properties on WeakMaps +function TestArbitrary(m) { + function TestProperty(map, property, value) { + map[property] = value; + assertEquals(value, map[property]); + } + for (var i = 0; i < 20; i++) { + TestProperty(m, i, 'val' + i); + TestProperty(m, 'foo' + i, 'bar' + i); + } + TestMapping(m, new Object, 'foobar'); +} +TestArbitrary(new WeakMap); + + +// Test direct constructor call +assertThrows(function() { WeakMap(); }, TypeError); +assertThrows(function() { WeakSet(); }, TypeError); + + +// Test some common JavaScript idioms for WeakMaps +var m = new WeakMap; +assertTrue(m instanceof WeakMap); +assertTrue(WeakMap.prototype.set instanceof Function) +assertTrue(WeakMap.prototype.get instanceof Function) +assertTrue(WeakMap.prototype.has instanceof Function) +assertTrue(WeakMap.prototype.delete instanceof Function) +assertTrue(WeakMap.prototype.clear instanceof Function) + + +// Test some common JavaScript idioms for WeakSets +var s = new WeakSet; +assertTrue(s instanceof WeakSet); +assertTrue(WeakSet.prototype.add instanceof Function) +assertTrue(WeakSet.prototype.has instanceof Function) +assertTrue(WeakSet.prototype.delete instanceof Function) +assertTrue(WeakSet.prototype.clear instanceof Function) + + +// Test class of instance and prototype. +assertEquals("WeakMap", %_ClassOf(new WeakMap)) +assertEquals("Object", %_ClassOf(WeakMap.prototype)) +assertEquals("WeakSet", %_ClassOf(new WeakSet)) +assertEquals("Object", %_ClassOf(WeakMap.prototype)) + + +// Test name of constructor. +assertEquals("WeakMap", WeakMap.name); +assertEquals("WeakSet", WeakSet.name); + + +// Test prototype property of WeakMap and WeakSet. +function TestPrototype(C) { + assertTrue(C.prototype instanceof Object); + assertEquals({ + value: {}, + writable: true, // TODO(2793): This should be non-writable. + enumerable: false, + configurable: false + }, Object.getOwnPropertyDescriptor(C, "prototype")); +} +TestPrototype(WeakMap); +TestPrototype(WeakSet); + + +// Test constructor property of the WeakMap and WeakSet prototype. +function TestConstructor(C) { + assertFalse(C === Object.prototype.constructor); + assertSame(C, C.prototype.constructor); + assertSame(C, (new C).__proto__.constructor); +} +TestConstructor(WeakMap); +TestConstructor(WeakSet); + + +// Test the WeakMap and WeakSet global properties themselves. +function TestDescriptor(global, C) { + assertEquals({ + value: C, + writable: true, + enumerable: false, + configurable: true + }, Object.getOwnPropertyDescriptor(global, C.name)); +} +TestDescriptor(this, WeakMap); +TestDescriptor(this, WeakSet); + + +// Regression test for WeakMap prototype. +assertTrue(WeakMap.prototype.constructor === WeakMap) +assertTrue(Object.getPrototypeOf(WeakMap.prototype) === Object.prototype) + + +// Regression test for issue 1617: The prototype of the WeakMap constructor +// needs to be unique (i.e. different from the one of the Object constructor). +assertFalse(WeakMap.prototype === Object.prototype); +var o = Object.create({}); +assertFalse("get" in o); +assertFalse("set" in o); +assertEquals(undefined, o.get); +assertEquals(undefined, o.set); +var o = Object.create({}, { myValue: { + value: 10, + enumerable: false, + configurable: true, + writable: true +}}); +assertEquals(10, o.myValue); + + +// Regression test for issue 1884: Invoking any of the methods for Harmony +// maps, sets, or weak maps, with a wrong type of receiver should be throwing +// a proper TypeError. +var alwaysBogus = [ undefined, null, true, "x", 23, {} ]; +var bogusReceiversTestSet = [ + { proto: WeakMap.prototype, + funcs: [ 'get', 'set', 'has', 'delete' ], + receivers: alwaysBogus.concat([ new WeakSet ]), + }, + { proto: WeakSet.prototype, + funcs: [ 'add', 'has', 'delete' ], + receivers: alwaysBogus.concat([ new WeakMap ]), + }, +]; +function TestBogusReceivers(testSet) { + for (var i = 0; i < testSet.length; i++) { + var proto = testSet[i].proto; + var funcs = testSet[i].funcs; + var receivers = testSet[i].receivers; + for (var j = 0; j < funcs.length; j++) { + var func = proto[funcs[j]]; + for (var k = 0; k < receivers.length; k++) { + assertThrows(function () { func.call(receivers[k], {}) }, TypeError); + } + } + } +} +TestBogusReceivers(bogusReceiversTestSet); + + +// Test WeakMap clear +(function() { + var k = new Object(); + var w = new WeakMap(); + w.set(k, 23); + assertTrue(w.has(k)); + assertEquals(23, w.get(k)); + w.clear(); + assertFalse(w.has(k)); + assertEquals(undefined, w.get(k)); +})(); + + +// Test WeakSet clear +(function() { + var k = new Object(); + var w = new WeakSet(); + w.add(k); + assertTrue(w.has(k)); + w.clear(); + assertFalse(w.has(k)); +})(); diff --git a/test/mjsunit/es7/object-observe.js b/test/mjsunit/es7/object-observe.js index fb15a1f..0aa3601 100644 --- a/test/mjsunit/es7/object-observe.js +++ b/test/mjsunit/es7/object-observe.js @@ -25,7 +25,8 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --harmony-observation --harmony-proxies --harmony-collections +// Flags: --harmony-observation --harmony-proxies +// Flags: --harmony-collections --harmony-weak-collections // Flags: --harmony-symbols --allow-natives-syntax var allObservers = []; diff --git a/test/mjsunit/harmony/collections.js b/test/mjsunit/harmony/collections.js index 7e95b9e..b33d080 100644 --- a/test/mjsunit/harmony/collections.js +++ b/test/mjsunit/harmony/collections.js @@ -25,10 +25,11 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --harmony-collections --expose-gc --allow-natives-syntax +// Flags: --harmony-collections --harmony-weak-collections +// Flags: --expose-gc --allow-natives-syntax -// Test valid getter and setter calls on Sets. +// Test valid getter and setter calls on Sets and WeakSets function TestValidSetCalls(m) { assertDoesNotThrow(function () { m.add(new Object) }); assertDoesNotThrow(function () { m.has(new Object) }); @@ -63,7 +64,7 @@ function TestInvalidCalls(m) { TestInvalidCalls(new WeakMap); -// Test expected behavior for Sets +// Test expected behavior for Sets and WeakSets function TestSet(set, key) { assertFalse(set.has(key)); assertSame(undefined, set.add(key)); diff --git a/test/mjsunit/harmony/private.js b/test/mjsunit/harmony/private.js index c906632..9c9bf2c 100644 --- a/test/mjsunit/harmony/private.js +++ b/test/mjsunit/harmony/private.js @@ -25,7 +25,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --harmony-symbols --harmony-collections +// Flags: --harmony-symbols --harmony-collections --harmony-weak-collections // Flags: --expose-gc --allow-natives-syntax var symbols = [] diff --git a/test/mjsunit/harmony/proxies-hash.js b/test/mjsunit/harmony/proxies-hash.js index 789de35..6f0b19f 100644 --- a/test/mjsunit/harmony/proxies-hash.js +++ b/test/mjsunit/harmony/proxies-hash.js @@ -25,7 +25,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --harmony-proxies --harmony-collections +// Flags: --harmony-proxies --harmony-collections --harmony-weak-collections // Helper. diff --git a/test/mjsunit/harmony/symbols.js b/test/mjsunit/harmony/symbols.js index 154eca0..26adb74 100644 --- a/test/mjsunit/harmony/symbols.js +++ b/test/mjsunit/harmony/symbols.js @@ -25,7 +25,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --harmony-symbols --harmony-collections +// Flags: --harmony-symbols --harmony-collections --harmony-weak-collections // Flags: --expose-gc --allow-natives-syntax var symbols = [] diff --git a/test/mjsunit/regress/regress-crbug-350864.js b/test/mjsunit/regress/regress-crbug-350864.js index eef3dba..15b3242 100644 --- a/test/mjsunit/regress/regress-crbug-350864.js +++ b/test/mjsunit/regress/regress-crbug-350864.js @@ -25,7 +25,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --harmony_symbols --harmony-collections +// Flags: --harmony_symbols --harmony-weak-collections var v0 = new WeakMap; var v1 = {}; diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp index a8c0f3f..6039ce1 100644 --- a/tools/gyp/v8.gyp +++ b/tools/gyp/v8.gyp @@ -1066,6 +1066,7 @@ '../../src/symbol.js', '../../src/proxy.js', '../../src/collection.js', + '../../src/weak_collection.js', '../../src/promise.js', '../../src/generator.js', '../../src/array-iterator.js', -- 2.7.4