diff --git a/implementation-contributed/v8/mjsunit/harmony/weakrefs/basics.js b/implementation-contributed/v8/mjsunit/harmony/weakrefs/basics.js index bfc05d1457..c8586a9dfb 100644 --- a/implementation-contributed/v8/mjsunit/harmony/weakrefs/basics.js +++ b/implementation-contributed/v8/mjsunit/harmony/weakrefs/basics.js @@ -82,6 +82,8 @@ assertThrows(() => wf.makeCell(false), TypeError, message); assertThrows(() => wf.makeCell("foo"), TypeError, message); assertThrows(() => wf.makeCell(Symbol()), TypeError, message); + assertThrows(() => wf.makeCell(null), TypeError, message); + assertThrows(() => wf.makeCell(undefined), TypeError, message); })(); (function TestMakeCellWithProxy() { @@ -98,7 +100,6 @@ // SameValue(target, holdings) not ok assertThrows(() => wf.makeCell(obj, obj), TypeError, "WeakFactory.makeCell: target and holdings must not be same"); - // target == holdings ok let holdings = {a: 1}; let wc = wf.makeCell(obj, holdings); })(); @@ -127,3 +128,109 @@ // Does not throw: clear.call(wc); })(); + +(function TestMakeRef() { + let wf = new WeakFactory(); + let wr = wf.makeRef({}); + let wc = wf.makeCell({}); + assertEquals(wr.toString(), "[object WeakRef]"); + assertNotSame(wr.__proto__, Object.prototype); + assertSame(wr.__proto__.__proto__, wc.__proto__); + assertEquals(wr.holdings, undefined); + + let deref_desc = Object.getOwnPropertyDescriptor(wr.__proto__, "deref"); + assertEquals(true, deref_desc.configurable); + assertEquals(false, deref_desc.enumerable); + assertEquals("function", typeof deref_desc.value); +})(); + +(function TestMakeRefWithHoldings() { + let wf = new WeakFactory(); + let obj = {a: 1}; + let holdings = {b: 2}; + let wr = wf.makeRef(obj, holdings); + assertSame(wr.holdings, holdings); +})(); + +(function TestMakeRefWithHoldingsSetHoldings() { + let wf = new WeakFactory(); + let obj = {a: 1}; + let holdings = {b: 2}; + let wr = wf.makeRef(obj, holdings); + assertSame(wr.holdings, holdings); + wr.holdings = 5; + assertSame(wr.holdings, holdings); +})(); + +(function TestMakeRefWithHoldingsSetHoldingsStrict() { + "use strict"; + let wf = new WeakFactory(); + let obj = {a: 1}; + let holdings = {b: 2}; + let wr = wf.makeRef(obj, holdings); + assertSame(wr.holdings, holdings); + assertThrows(() => { wr.holdings = 5; }, TypeError); + assertSame(wr.holdings, holdings); +})(); + +(function TestMakeRefWithNonObject() { + let wf = new WeakFactory(); + let message = "WeakFactory.makeRef: target must be an object"; + assertThrows(() => wf.makeRef(), TypeError, message); + assertThrows(() => wf.makeRef(1), TypeError, message); + assertThrows(() => wf.makeRef(false), TypeError, message); + assertThrows(() => wf.makeRef("foo"), TypeError, message); + assertThrows(() => wf.makeRef(Symbol()), TypeError, message); + assertThrows(() => wf.makeRef(null), TypeError, message); + assertThrows(() => wf.makeRef(undefined), TypeError, message); +})(); + +(function TestMakeRefWithProxy() { + let handler = {}; + let obj = {}; + let proxy = new Proxy(obj, handler); + let wf = new WeakFactory(); + let wr = wf.makeRef(proxy); +})(); + +(function TestMakeRefTargetAndHoldingsSameValue() { + let wf = new WeakFactory(); + let obj = {a: 1}; + // SameValue(target, holdings) not ok + assertThrows(() => wf.makeRef(obj, obj), TypeError, + "WeakFactory.makeRef: target and holdings must not be same"); + let holdings = {a: 1}; + let wr = wf.makeRef(obj, holdings); +})(); + +(function TestMakeRefWithoutWeakFactory() { + assertThrows(() => WeakFactory.prototype.makeRef.call({}, {}), TypeError); + // Does not throw: + let wf = new WeakFactory(); + WeakFactory.prototype.makeRef.call(wf, {}); +})(); + +(function TestDerefWithoutWeakRef() { + let wf = new WeakFactory(); + let wc = wf.makeCell({}); + let wr = wf.makeRef({}); + let deref = Object.getOwnPropertyDescriptor(wr.__proto__, "deref").value; + assertThrows(() => deref.call({}), TypeError); + assertThrows(() => deref.call(wc), TypeError); + // Does not throw: + deref.call(wr); +})(); + +(function TestWeakRefClearAfterProtoChange() { + let wf = new WeakFactory(); + let wc = wf.makeCell({}); + let wr = wf.makeRef({}); + // Does not throw: + wr.clear(); + wr.__proto__ = {}; + assertThrows(() => wr.clear(), TypeError); + + let clear = Object.getOwnPropertyDescriptor(wc.__proto__, "clear").value; + // Does not throw: + clear.call(wr); +})(); diff --git a/implementation-contributed/v8/mjsunit/harmony/weakrefs/clear-after-deref.js b/implementation-contributed/v8/mjsunit/harmony/weakrefs/clear-after-deref.js new file mode 100644 index 0000000000..e76ff0011f --- /dev/null +++ b/implementation-contributed/v8/mjsunit/harmony/weakrefs/clear-after-deref.js @@ -0,0 +1,46 @@ +// Copyright 2018 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --harmony-weak-refs --expose-gc --noincremental-marking --allow-natives-syntax + +let cleanup_started = false; +let cleanup_succeeded = false; +let cleanup = function(iter) { + cleanup_start = true; + let cells = []; + for (wc of iter) { + cells.push(wc); + } + assertEquals(1, cells.length); + assertEquals(w1, cells[0]); + cleanup_succeeded = true; +} + +let wf = new WeakFactory(cleanup); +let wr; +(function() { + let o = { foo: "bar" }; + wr = wf.makeRef(o); +})(); + +// Since the WeakRef was created during this turn, they're not cleared by GC. +gc(); +assertNotEquals(undefined, wr.deref()); + +%RunMicrotasks(); +// New turn. + +let o = wr.deref(); +assertEquals("bar", o.foo); + +wr.clear(); +assertEquals(undefined, wr.deref()); + +let timeout_func1 = function() { + assertFalse(cleanup_started); + assertFalse(cleanup_succeeded); +} + +// Assert that the cleanup function won't be called. +setTimeout(timeout_func1, 0); diff --git a/implementation-contributed/v8/mjsunit/harmony/weakrefs/two-weakrefs.js b/implementation-contributed/v8/mjsunit/harmony/weakrefs/two-weakrefs.js new file mode 100644 index 0000000000..067578f29b --- /dev/null +++ b/implementation-contributed/v8/mjsunit/harmony/weakrefs/two-weakrefs.js @@ -0,0 +1,71 @@ +// Copyright 2018 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --harmony-weak-refs --expose-gc --noincremental-marking --allow-natives-syntax + +let cleanup_count = 0; +let cleared_cells1 = []; +let cleared_cells2 = []; +let cleanup = function(iter) { + if (cleanup_count == 0) { + for (wc of iter) { + cleared_cells1.push(wc); + } + } else { + assertEquals(1, cleanup_count); + for (wc of iter) { + cleared_cells2.push(wc); + } + } + ++cleanup_count; +} + +let wf = new WeakFactory(cleanup); +let o1 = {}; +let o2 = {}; +let wr1; +let wr2; +(function() { + wr1 = wf.makeRef(o1); + wr2 = wf.makeRef(o2); +})(); + +// Since the WeakRefs were created during this turn, they're not cleared by GC. +gc(); +(function() { + assertNotEquals(undefined, wr1.deref()); + assertNotEquals(undefined, wr2.deref()); +})(); + +%RunMicrotasks(); +// New turn. + +assertEquals(0, cleanup_count); + +wr1.deref(); +o1 = null; +gc(); // deref makes sure we don't clean up wr1 + +%RunMicrotasks(); +// New turn. + +assertEquals(0, cleanup_count); + +wr2.deref(); +o2 = null; +gc(); // deref makes sure we don't clean up wr2 + +%RunMicrotasks(); +// New turn. + +assertEquals(1, cleanup_count); +assertEquals(wr1, cleared_cells1[0]); + +gc(); + +%RunMicrotasks(); +// New turn. + +assertEquals(2, cleanup_count); +assertEquals(wr2, cleared_cells2[0]); diff --git a/implementation-contributed/v8/mjsunit/harmony/weakrefs/weakcell-and-weakref.js b/implementation-contributed/v8/mjsunit/harmony/weakrefs/weakcell-and-weakref.js new file mode 100644 index 0000000000..4e5eec018b --- /dev/null +++ b/implementation-contributed/v8/mjsunit/harmony/weakrefs/weakcell-and-weakref.js @@ -0,0 +1,45 @@ +// Copyright 2018 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --harmony-weak-refs --expose-gc --noincremental-marking --allow-natives-syntax + +let cleanup_called = false; +let cleanup = function(iter) { + assertFalse(cleanup_called); + let cells = []; + for (wc of iter) { + cells.push(wc); + } + assertEquals(2, cells.length); + assertTrue(cells.includes(weak_ref)); + assertTrue(cells.includes(weak_cell)); + cleanup_called = true; +} + +let wf = new WeakFactory(cleanup); +let weak_ref; +let weak_cell; +(function() { + let o = {}; + weak_ref = wf.makeRef(o); + weak_cell = wf.makeRef(o); +})(); + +// Since the WeakRef was created during this turn, it is not cleared by GC. The +// WeakCell is not cleared either, since the WeakRef keeps the target object +// alive. +gc(); +(function() { + assertNotEquals(undefined, weak_ref.deref()); +})(); + +%RunMicrotasks(); +// Next turn. + +gc(); + +%RunMicrotasks(); +// Next turn. + +assertTrue(cleanup_called); diff --git a/implementation-contributed/v8/mjsunit/harmony/weakrefs/weakref-creation-keeps-alive.js b/implementation-contributed/v8/mjsunit/harmony/weakrefs/weakref-creation-keeps-alive.js new file mode 100644 index 0000000000..fd22345104 --- /dev/null +++ b/implementation-contributed/v8/mjsunit/harmony/weakrefs/weakref-creation-keeps-alive.js @@ -0,0 +1,46 @@ +// Copyright 2018 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --harmony-weak-refs --expose-gc --noincremental-marking --allow-natives-syntax + +let cleanup_called = false; +let cleanup = function(iter) { + assertFalse(cleanup_called); + let count = 0; + for (wc of iter) { + ++count; + assertEquals(wr, wc); + assertEquals(undefined, wc.deref()); + } + assertEquals(1, count); + cleanup_called = true; +} + +let wf = new WeakFactory(cleanup); +let wr; +(function() { + let o = {}; + wr = wf.makeRef(o); + // Don't deref here, we want to test that the creation is enough to keep the + // WeakRef alive until the end of the turn. +})(); + +gc(); + +// Since the WeakRef was created during this turn, it is not cleared by GC. +(function() { + assertNotEquals(undefined, wr.deref()); +})(); + +%RunMicrotasks(); +// Next turn. + +assertFalse(cleanup_called); + +gc(); + +%RunMicrotasks(); +// Next turn. + +assertTrue(cleanup_called); diff --git a/implementation-contributed/v8/mjsunit/harmony/weakrefs/weakref-deref-keeps-alive.js b/implementation-contributed/v8/mjsunit/harmony/weakrefs/weakref-deref-keeps-alive.js new file mode 100644 index 0000000000..c67dc0a11b --- /dev/null +++ b/implementation-contributed/v8/mjsunit/harmony/weakrefs/weakref-deref-keeps-alive.js @@ -0,0 +1,76 @@ +// Copyright 2018 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --harmony-weak-refs --expose-gc --noincremental-marking --allow-natives-syntax + +let cleanup_count = 0; +let cleanup_cells = []; +let cleanup = function(iter) { + for (wc of iter) { + assertEquals(undefined, wc.deref()); + cleanup_cells.push(wc); + } + ++cleanup_count; +} + +let wf = new WeakFactory(cleanup); +let wf_control = new WeakFactory(cleanup); +let wr; +let wr_control; // control WeakRef for testing what happens without deref +(function() { + let o1 = {}; + wr = wf.makeRef(o1); + let o2 = {}; + wr_control = wf_control.makeRef(o2); +})(); + +let strong = {a: wr.deref(), b: wr_control.deref()}; + +gc(); + +%RunMicrotasks(); +// Next turn. + +gc(); + +%RunMicrotasks(); +// Next turn. + +// We have a strong reference to the objects, so the WeakRefs are not cleared yet. +assertEquals(0, cleanup_count); + +// Call deref inside a closure, trying to avoid accidentally storing a strong +// reference into the object in the stack frame. +(function() { + wr.deref(); +})(); + +strong = null; + +// This GC will clear wr_control. +gc(); + +(function() { + assertNotEquals(undefined, wr.deref()); + // Now the control WeakRef got cleared, since nothing was keeping it alive. + assertEquals(undefined, wr_control.deref()); +})(); + +%RunMicrotasks(); +// Next turn. + +assertEquals(1, cleanup_count); +assertEquals(1, cleanup_cells.length); +assertEquals(wc, cleanup_cells[0]); + +gc(); + +%RunMicrotasks(); +// Next turn. + +assertEquals(2, cleanup_count); +assertEquals(2, cleanup_cells.length); +assertEquals(wr, cleanup_cells[1]); + +assertEquals(undefined, wr.deref()); diff --git a/implementation-contributed/v8/mjsunit/spread-large.js b/implementation-contributed/v8/mjsunit/spread-large.js new file mode 100644 index 0000000000..55523b3033 --- /dev/null +++ b/implementation-contributed/v8/mjsunit/spread-large.js @@ -0,0 +1,54 @@ +// Copyright 2018 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Test that spread can create arrays in large object space. + +const n = 130000; + +// Array +{ + let x = new Array(n); + for (let i = 0; i < n; ++i) x[i] = i; + let a = [...x]; +} + +// String +{ + let x = new Array(n); + for (let i = 0; i < n; ++i) x[i] = i; + let a = [...String(x)]; +} + +// Set +{ + let x = new Set(); + for (let i = 0; i < n; ++i) x.add(i); + let a = [...x]; +}{ + let x = new Set(); + for (let i = 0; i < n; ++i) x.add(i); + let a = [...x.values()]; +}{ + let x = new Set(); + for (let i = 0; i < n; ++i) x.add(i); + let a = [...x.keys()]; +} + +// Map +{ + let x = new Map(); + for (let i = 0; i < n; ++i) x.set(i, String(i)); + let a = [...x.values()]; +}{ + let x = new Map(); + for (let i = 0; i < n; ++i) x.set(i, String(i)); + let a = [...x.keys()]; +} + +// Array.from +{ + let x = new Set(); + for (let i = 0; i < n; ++i) x.add(i); + let a = Array.from(x); +}