/**
 * Finalizer for instances of FinalizationWitness.
 *
 * Unless method Forget() has been called, the finalizer displays an error
 * message.
 */
void Finalize(JSFreeOp *fop, JSObject *objSelf)
{
  nsRefPtr<FinalizationEvent> event = ExtractFinalizationEvent(objSelf);
  if (event == nullptr) {
    // Forget() has been called
    return;
  }

  // Notify observers. Since we are executed during garbage-collection,
  // we need to dispatch the notification to the main thread.
  (void)NS_DispatchToMainThread(event);
  // We may fail at dispatching to the main thread if we arrive too late
  // during shutdown. In that case, there is not much we can do.
}
/**
 * JS method |forget()|
 *
 * === JS documentation
 *
 *  Neutralize the witness. Once this method is called, the witness will
 *  never report any error.
 */
bool ForgetImpl(JSContext* cx, const JS::CallArgs& args)
{
  if (args.length() != 0) {
    JS_ReportErrorASCII(cx, "forget() takes no arguments");
    return false;
  }
  JS::Rooted<JS::Value> valSelf(cx, args.thisv());
  JS::Rooted<JSObject*> objSelf(cx, &valSelf.toObject());

  RefPtr<FinalizationEvent> event = ExtractFinalizationEvent(objSelf);
  if (event == nullptr) {
    JS_ReportErrorASCII(cx, "forget() called twice");
    return false;
  }

  args.rval().setUndefined();
  return true;
}