Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  WeakRefObject.cpp

  Sprache: C
 

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "builtin/WeakRefObject.h"

#include "jsapi.h"

#include "gc/FinalizationObservers.h"
#include "js/friend/ErrorMessages.h"  // js::GetErrorMessage, JSMSG_*
#include "vm/GlobalObject.h"
#include "vm/JSContext.h"

#include "gc/PrivateIterators-inl.h"
#include "gc/WeakMap-inl.h"
#include "vm/JSObject-inl.h"
#include "vm/NativeObject-inl.h"

using namespace js::gc;

namespace js {

/* static */
bool WeakRefObject::construct(JSContext* cx, unsigned argc, Value* vp) {
  CallArgs args = CallArgsFromVp(argc, vp);

  // https://tc39.es/proposal-weakrefs/#sec-weak-ref-constructor
  // The WeakRef constructor is not intended to be called as a function and will
  // throw an exception when called in that manner.
  if (!ThrowIfNotConstructing(cx, args, "WeakRef")) {
    return false;
  }

  // https://tc39.es/proposal-weakrefs/#sec-weak-ref-target
  // 1. If NewTarget is undefined, throw a TypeError exception.
  // 2. If Type(target) is not Object, throw a TypeError exception.
  if (!CanBeHeldWeakly(args.get(0))) {
    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                              JSMSG_BAD_WEAKREF_TARGET);
    return false;
  }

  // 3. Let weakRef be ? OrdinaryCreateFromConstructor(NewTarget,
  //    "%WeakRefPrototype%", « [[Target]] »).
  RootedObject proto(cx);
  if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_WeakRef, &proto)) {
    return false;
  }

  Rooted<WeakRefObject*> weakRef(
      cx, NewObjectWithClassProto<WeakRefObject>(cx, proto));
  if (!weakRef) {
    return false;
  }

  RootedValue target(cx, args[0]);
  bool isPermanent = false;
  if (target.isObject()) {
    // Fully unwrap the target to register it with the GC.
    RootedObject object(cx, CheckedUnwrapDynamic(&target.toObject(), cx));
    if (!object) {
      ReportAccessDenied(cx);
      return false;
    }

    target = ObjectValue(*object);

    // If the target is a DOM wrapper, preserve it.
    if (!preserveDOMWrapper(cx, object)) {
      return false;
    }
  } else {
    JS::Symbol* symbol = target.toSymbol();
    isPermanent = symbol->isPermanentAndMayBeShared();
  }

  // Skip the following steps for permanent targets.
  // (See the note following https://tc39.es/ecma262/#sec-canbeheldweakly)
  if (!isPermanent) {
    // 4. Perform AddToKeptObjects(target).
    if (!target.toGCThing()->zone()->addToKeptObjects(target)) {
      ReportOutOfMemory(cx);
      return false;
    };

    // Add an entry to the per-zone maps from target JS object to a list of weak
    // ref objects.
    gc::GCRuntime* gc = &cx->runtime()->gc;
    if (!gc->registerWeakRef(cx, target, weakRef)) {
      ReportOutOfMemory(cx);
      return false;
    }
  }

  // 5. Set weakRef.[[Target]] to target.
  weakRef->setReservedSlotGCThingAsPrivate(TargetSlot, target.toGCThing());

  // 6. Return weakRef.
  args.rval().setObject(*weakRef);

  return true;
}

/* static */
bool WeakRefObject::preserveDOMWrapper(JSContext* cx, HandleObject obj) {
  if (!MaybePreserveDOMWrapper(cx, obj)) {
    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                              JSMSG_BAD_WEAKREF_TARGET);
    return false;
  }

  return true;
}

/* static */
void WeakRefObject::trace(JSTracer* trc, JSObject* obj) {
  WeakRefObject* weakRef = &obj->as<WeakRefObject>();

  // The next and prev slots added by the ObserverListObject base class are
  // internal weak pointers and are not traced, even if requested by the tracer.

  if (trc->traceWeakEdges()) {
    Value target = weakRef->target();
    Value prior = target;
    TraceManuallyBarrieredEdge(trc, &target, "WeakRefObject::target");
    if (target != prior) {
      weakRef->setTargetUnbarriered(target);
    }
  }
}

/* static */
void WeakRefObject::finalize(JS::GCContext* gcx, JSObject* obj) {
  auto* weakRef = &obj->as<WeakRefObject>();
  weakRef->clearTargetAndUnlink();
}

const JSClassOps WeakRefObject::classOps_ = {
    .finalize = finalize,
    .trace = trace,
};

const ClassSpec WeakRefObject::classSpec_ = {
    GenericCreateConstructor<WeakRefObject::construct, 1,
                             gc::AllocKind::FUNCTION>,
    GenericCreatePrototype<WeakRefObject>,
    nullptr,
    nullptr,
    WeakRefObject::methods,
    WeakRefObject::properties,
};

const JSClass WeakRefObject::class_ = {
    "WeakRef",
    JSCLASS_HAS_RESERVED_SLOTS(SlotCount) |
        JSCLASS_HAS_CACHED_PROTO(JSProto_WeakRef) | JSCLASS_FOREGROUND_FINALIZE,
    &classOps_, &classSpec_, &classExtension_};

const JSClass WeakRefObject::protoClass_ = {
    // https://tc39.es/proposal-weakrefs/#sec-weak-ref.prototype
    // https://tc39.es/proposal-weakrefs/#sec-properties-of-the-weak-ref-prototype-object
    "WeakRef.prototype",
    JSCLASS_HAS_CACHED_PROTO(JSProto_WeakRef),
    JS_NULL_CLASS_OPS,
    &classSpec_,
};

const JSPropertySpec WeakRefObject::properties[] = {
    JS_STRING_SYM_PS(toStringTag, "WeakRef", JSPROP_READONLY),
    JS_PS_END,
};

const JSFunctionSpec WeakRefObject::methods[] = {
    JS_FN("deref", deref, 00),
    JS_FS_END,
};

Value WeakRefObject::target() {
  Value value = getReservedSlot(TargetSlot);
  if (value.isUndefined()) {
    return UndefinedValue();
  }

  auto* cell = static_cast<Cell*>(value.toPrivate());
  if (cell->is<JSObject>()) {
    return ObjectValue(*cell->as<JSObject>());
  }

  return SymbolValue(cell->as<JS::Symbol>());
}

/* static */
bool WeakRefObject::deref(JSContext* cx, unsigned argc, Value* vp) {
  CallArgs args = CallArgsFromVp(argc, vp);

  // https://tc39.es/proposal-weakrefs/#sec-weak-ref.prototype.deref
  // 1. Let weakRef be the this value.
  // 2. If Type(weakRef) is not Object, throw a TypeError exception.
  // 3. If weakRef does not have a [[Target]] internal slot, throw a TypeError
  //    exception.
  if (!args.thisv().isObject() ||
      !args.thisv().toObject().is<WeakRefObject>()) {
    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                              JSMSG_NOT_A_WEAK_REF,
                              "Receiver of WeakRef.deref call");
    return false;
  }

  Rooted<WeakRefObject*> weakRef(cx,
                                 &args.thisv().toObject().as<WeakRefObject>());

  // We need to perform a read barrier, which may clear the target.
  readBarrier(cx, weakRef);

  // 4. Let target be the value of weakRef.[[Target]].
  // 5. If target is not empty,
  //    a. Perform AddToKeptObjects(target).
  //    b. Return target.
  // 6. Return undefined.
  RootedValue target(cx, weakRef->target());
  if (target.isUndefined()) {
    args.rval().setUndefined();
    return true;
  }

  bool isPermanent =
      target.isSymbol() && target.toSymbol()->isPermanentAndMayBeShared();
  if (!isPermanent && !target.toGCThing()->zone()->addToKeptObjects(target)) {
    ReportOutOfMemory(cx);
    return false;
  }

  // Target should be wrapped into the current realm before returning it.
  if (!JS_WrapValue(cx, &target)) {
    return false;
  }

  args.rval().set(target);
  return true;
}

void WeakRefObject::setTarget(Value target) {
  setReservedSlotGCThingAsPrivate(TargetSlot, target.toGCThing());
}
void WeakRefObject::setTargetUnbarriered(Value target) {
  setReservedSlotGCThingAsPrivateUnbarriered(TargetSlot, target.toGCThing());
}

void WeakRefObject::clearTargetAndUnlink() {
  unlink();
  clearReservedSlotGCThingAsPrivate(TargetSlot);
}

/* static */
void WeakRefObject::readBarrier(JSContext* cx, Handle<WeakRefObject*> self) {
  RootedValue target(cx, self->target());
  if (target.isUndefined()) {
    return;
  }

  if (target.isObject() && target.toObject().getClass()->isDOMClass()) {
    // We preserved the target when the WeakRef was created. If it has since
    // been released then the DOM object it wraps has been collected, so clear
    // the target.
    RootedObject obj(cx, &target.toObject());

    // Ensure buffered wrapper preservations are committed because the DOM's
    // hasReleasedWrapperCallback checks the preserving-wrapper flag.
    cx->runtime()->commitPendingWrapperPreservations(obj->zone());

    MOZ_ASSERT(cx->runtime()->hasReleasedWrapperCallback);
    bool wasReleased = cx->runtime()->hasReleasedWrapperCallback(obj);
    if (wasReleased) {
      obj->zone()->finalizationObservers()->removeWeakRefTarget(target, self);
      return;
    }
  }

  gc::ValueReadBarrier(target);
}

namespace gc {

void GCRuntime::traceKeptObjects(JSTracer* trc) {
  for (GCZonesIter zone(this); !zone.done(); zone.next()) {
    zone->traceKeptObjects(trc);
  }
}

}  // namespace gc

}  // namespace js

Messung V0.5 in Prozent
C=95 H=97 G=95

¤ Dauer der Verarbeitung: 0.4 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=277311
#Domains=752002