// |jit-test| --enable-weak-refs
//
// https://tc39.es/proposal-weakrefs/#sec-keepduringjob
// When the abstract operation KeepDuringJob is called with a target object
// reference, it adds the target to an identity Set that will point strongly at
// the target until the end of the current Job.
//
// https://tc39.es/proposal-weakrefs/#sec-weakref-invariants
// When WeakRef.prototype.deref is called, the referent (if it's not already
// dead) is kept alive so that subsequent, synchronous accesses also return the
// object.

let wr;
{
  let obj = {};
  wr = new WeakRef(obj);
  obj = null;
}
// obj is out of block scope now, should be GCed.

gc();

assertEq(undefined == wr.deref(), false);

// test for target is in another zone.
var g = newGlobal({newCompartment: true});
var wr2 = new g.WeakRef({});
assertEq(undefined == wr2.deref(), false);

let wr3 = g.eval("new WeakRef({})");
let wr4 = new WeakRef(evalcx('({})', newGlobal({newCompartment: true})));
let wr5 = new g.WeakRef(evalcx('({})', newGlobal({newCompartment: true})));

var that = this;
(function(){
  let wr6 = new g.WeakRef(newGlobal({newCompartment: true}));
  let wr7 = new WeakRef(wr6);
  let wr8 = new WeakRef(that);
  wr6 = null;
  wr7 = null;
  wr8 = null;
})();

gc();

let wr1;
// Allocate the object in the function to prevent marked as a singleton so the
// object won't be kept alive by IC stub.
function allocObj() { return {}; }

(function () {
  let obj = allocObj();
  wr1 = new WeakRef(obj);
  obj = null;
})();

assertEq(undefined === wr1.deref(), false);

gc();

// See https://tc39.es/proposal-weakrefs/#sec-weakref-invariants
// This list is reset when synchronous work is done using the
// ClearKeptObjects abstract operation.
//
// TODO:
// Bug 1603070: The shell has no way to start a new task.
//
// In shell, there's no window object hence there isn't a setTimeout nor event
// handler, so we use this function to simulate that.
// The timeout function in shell doesn't launch a new job, and it will cause
// this test file timeout so I didn't use it here.
function simulateEndOfJob(fn) {
  clearKeptObjects();
  gc();
  fn();
}

simulateEndOfJob(() => {
  assertEq(undefined, wr1.deref());
});

