mirror of
https://github.com/roytam1/basilisk55.git
synced 2026-05-26 05:02:25 +00:00
ported from UXP: Make WeakRef support always enabled (6861bedf)
This commit is contained in:
@@ -303,7 +303,6 @@ LoadContextOptions(const char* aPrefName, void* /* aClosure */)
|
||||
.setAsyncStack(GetWorkerPref<bool>(NS_LITERAL_CSTRING("asyncstack")))
|
||||
.setWerror(GetWorkerPref<bool>(NS_LITERAL_CSTRING("werror")))
|
||||
.setStreams(GetWorkerPref<bool>(NS_LITERAL_CSTRING("streams")))
|
||||
.setWeakRefs(GetWorkerPref<bool>(NS_LITERAL_CSTRING("weakrefs")))
|
||||
.setExtraWarnings(GetWorkerPref<bool>(NS_LITERAL_CSTRING("strict")))
|
||||
.setArrayProtoValues(GetWorkerPref<bool>(
|
||||
NS_LITERAL_CSTRING("array_prototype_values")));
|
||||
|
||||
@@ -36,7 +36,6 @@ WORKER_SIMPLE_PREF("dom.serviceWorkers.openWindow.enabled", OpenWindowEnabled, O
|
||||
WORKER_SIMPLE_PREF("dom.storageManager.enabled", StorageManagerEnabled, STORAGEMANAGER_ENABLED)
|
||||
WORKER_SIMPLE_PREF("dom.push.enabled", PushEnabled, PUSH_ENABLED)
|
||||
WORKER_SIMPLE_PREF("dom.streams.enabled", StreamsEnabled, STREAMS_ENABLED)
|
||||
WORKER_SIMPLE_PREF("javascript.options.weakrefs", WeakRefsEnabled, WEAKREFS_ENABLED)
|
||||
WORKER_SIMPLE_PREF("dom.requestcontext.enabled", RequestContextEnabled, REQUESTCONTEXT_ENABLED)
|
||||
WORKER_SIMPLE_PREF("gfx.offscreencanvas.enabled", OffscreenCanvasEnabled, OFFSCREENCANVAS_ENABLED)
|
||||
WORKER_SIMPLE_PREF("dom.webkitBlink.dirPicker.enabled", WebkitBlinkDirectoryPickerEnabled, DOM_WEBKITBLINK_DIRPICKER_WEBKITBLINK)
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "gc/Nursery.h"
|
||||
#include "gc/Tracer.h"
|
||||
#include "vm/GlobalObject.h"
|
||||
#include "vm/Symbol.h"
|
||||
|
||||
#include "jsobjinlines.h"
|
||||
|
||||
@@ -37,11 +38,34 @@ WeakRef_deref_impl(JSContext* cx, const CallArgs& args)
|
||||
MOZ_ASSERT(IsWeakRef(args.thisv()));
|
||||
|
||||
WeakRefObject::Referent* data = GetReferent(&args.thisv().toObject());
|
||||
JSObject* target = data ? data->target.get() : nullptr;
|
||||
if (target)
|
||||
args.rval().setObject(*target);
|
||||
else
|
||||
if (!data) {
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (data->isObject()) {
|
||||
JSObject* target = data->objectTarget.get();
|
||||
if (target) {
|
||||
RootedValue kept(cx, ObjectValue(*target));
|
||||
if (!cx->runtime()->addWeakRefKeptObject(cx, kept))
|
||||
return false;
|
||||
args.rval().set(kept);
|
||||
} else {
|
||||
args.rval().setUndefined();
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(data->isSymbol());
|
||||
JS::Symbol* target = data->symbolTarget.get();
|
||||
if (target) {
|
||||
RootedValue kept(cx, SymbolValue(target));
|
||||
if (!cx->runtime()->addWeakRefKeptObject(cx, kept))
|
||||
return false;
|
||||
args.rval().set(kept);
|
||||
} else {
|
||||
args.rval().setUndefined();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -83,13 +107,18 @@ InitWeakRefClass(JSContext* cx, HandleObject obj, bool defineMembers)
|
||||
}
|
||||
|
||||
/* static */ WeakRefObject*
|
||||
WeakRefObject::create(JSContext* cx, HandleObject target, HandleObject proto /* = nullptr */)
|
||||
WeakRefObject::create(JSContext* cx, HandleValue target, HandleObject proto /* = nullptr */)
|
||||
{
|
||||
Rooted<WeakRefObject*> obj(cx, NewObjectWithClassProto<WeakRefObject>(cx, proto));
|
||||
if (!obj)
|
||||
return nullptr;
|
||||
|
||||
Referent* data = cx->new_<Referent>(target, cx->options().weakRefs());
|
||||
Referent* data;
|
||||
if (target.isObject())
|
||||
data = cx->new_<Referent>(&target.toObject());
|
||||
else
|
||||
data = cx->new_<Referent>(target.toSymbol());
|
||||
|
||||
if (!data)
|
||||
return nullptr;
|
||||
|
||||
@@ -97,6 +126,18 @@ WeakRefObject::create(JSContext* cx, HandleObject target, HandleObject proto /*
|
||||
return obj;
|
||||
}
|
||||
|
||||
static bool
|
||||
CanBeHeldWeakly(HandleValue target)
|
||||
{
|
||||
if (target.isObject())
|
||||
return true;
|
||||
|
||||
if (target.isSymbol())
|
||||
return target.toSymbol()->code() != JS::SymbolCode::InSymbolRegistry;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
WeakRefObject::construct(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
@@ -105,18 +146,12 @@ WeakRefObject::construct(JSContext* cx, unsigned argc, Value* vp)
|
||||
if (!ThrowIfNotConstructing(cx, args, "WeakRef"))
|
||||
return false;
|
||||
|
||||
if (!args.get(0).isObject()) {
|
||||
UniqueChars bytes =
|
||||
DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, args.get(0), nullptr);
|
||||
if (!bytes)
|
||||
return false;
|
||||
|
||||
JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT,
|
||||
bytes.get());
|
||||
if (!CanBeHeldWeakly(args.get(0))) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_WEAKREF_TARGET);
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedObject target(cx, &args[0].toObject());
|
||||
RootedValue target(cx, args[0]);
|
||||
|
||||
RootedObject proto(cx);
|
||||
RootedObject newTarget(cx, &args.newTarget().toObject());
|
||||
@@ -127,6 +162,9 @@ WeakRefObject::construct(JSContext* cx, unsigned argc, Value* vp)
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
if (!cx->runtime()->addWeakRefKeptObject(cx, target))
|
||||
return false;
|
||||
|
||||
args.rval().setObject(*obj);
|
||||
return true;
|
||||
}
|
||||
@@ -142,19 +180,23 @@ WeakRefObject::deref(JSContext* cx, unsigned argc, Value* vp)
|
||||
WeakRefObject::trace(JSTracer* trc, JSObject* obj)
|
||||
{
|
||||
if (Referent* data = GetReferent(obj)) {
|
||||
JSObject* target = data->target.unbarrieredGet();
|
||||
if (!target)
|
||||
return;
|
||||
if (data->isObject()) {
|
||||
JSObject* target = data->objectTarget.unbarrieredGet();
|
||||
if (!target)
|
||||
return;
|
||||
|
||||
// When pref-disabled, keep referent alive via strong trace so deref()
|
||||
// stays usable as a stub without touching GC internals.
|
||||
if (!data->enabled) {
|
||||
TraceManuallyBarrieredEdge(trc, data->target.unsafeGet(), "WeakRef stub referent");
|
||||
} else if (IsInsideNursery(target)) {
|
||||
// Weak edges must be tenured; trace strongly while referent is in the nursery.
|
||||
TraceManuallyBarrieredEdge(trc, data->target.unsafeGet(), "WeakRef nursery referent");
|
||||
if (IsInsideNursery(target)) {
|
||||
// Weak edges must be tenured; trace strongly while referent is in the nursery.
|
||||
TraceManuallyBarrieredEdge(trc, data->objectTarget.unsafeGet(),
|
||||
"WeakRef nursery referent");
|
||||
} else {
|
||||
TraceWeakEdge(trc, &data->objectTarget, "WeakRef referent");
|
||||
}
|
||||
} else {
|
||||
TraceWeakEdge(trc, &data->target, "WeakRef referent");
|
||||
MOZ_ASSERT(data->isSymbol());
|
||||
JS::Symbol* target = data->symbolTarget.unbarrieredGet();
|
||||
if (target)
|
||||
TraceWeakEdge(trc, &data->symbolTarget, "WeakRef symbol referent");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -162,7 +204,6 @@ WeakRefObject::trace(JSTracer* trc, JSObject* obj)
|
||||
/* static */ void
|
||||
WeakRefObject::finalize(FreeOp* fop, JSObject* obj)
|
||||
{
|
||||
MOZ_ASSERT(!fop->maybeOffMainThread());
|
||||
if (Referent* data = GetReferent(obj))
|
||||
fop->delete_(data);
|
||||
}
|
||||
|
||||
@@ -15,16 +15,28 @@ class WeakRefObject : public NativeObject
|
||||
{
|
||||
public:
|
||||
struct Referent {
|
||||
explicit Referent(JSObject* obj, bool enabled)
|
||||
: target(obj), enabled(enabled) {}
|
||||
WeakRef<JSObject*> target;
|
||||
bool enabled;
|
||||
enum class Kind {
|
||||
Object,
|
||||
Symbol
|
||||
};
|
||||
|
||||
explicit Referent(JSObject* obj)
|
||||
: kind(Kind::Object), objectTarget(obj), symbolTarget(nullptr) {}
|
||||
explicit Referent(JS::Symbol* sym)
|
||||
: kind(Kind::Symbol), objectTarget(nullptr), symbolTarget(sym) {}
|
||||
|
||||
bool isObject() const { return kind == Kind::Object; }
|
||||
bool isSymbol() const { return kind == Kind::Symbol; }
|
||||
|
||||
Kind kind;
|
||||
WeakRef<JSObject*> objectTarget;
|
||||
WeakRef<JS::Symbol*> symbolTarget;
|
||||
};
|
||||
|
||||
static const Class class_;
|
||||
|
||||
static JSObject* initClass(JSContext* cx, HandleObject obj);
|
||||
static WeakRefObject* create(JSContext* cx, HandleObject target, HandleObject proto = nullptr);
|
||||
static WeakRefObject* create(JSContext* cx, HandleValue target, HandleObject proto = nullptr);
|
||||
|
||||
static void trace(JSTracer* trc, JSObject* obj);
|
||||
static void finalize(FreeOp* fop, JSObject* obj);
|
||||
@@ -37,7 +49,8 @@ class WeakRefObject : public NativeObject
|
||||
|
||||
WeakRef<JSObject*>& target() {
|
||||
MOZ_ASSERT(getData());
|
||||
return getData()->target;
|
||||
MOZ_ASSERT(getData()->isObject());
|
||||
return getData()->objectTarget;
|
||||
}
|
||||
|
||||
static const JSPropertySpec properties[];
|
||||
|
||||
@@ -80,6 +80,7 @@ MSG_DEF(JSMSG_EMPTY_ARRAY_REDUCE, 0, JSEXN_TYPEERR, "reduce of empty array
|
||||
MSG_DEF(JSMSG_UNEXPECTED_TYPE, 2, JSEXN_TYPEERR, "{0} is {1}")
|
||||
MSG_DEF(JSMSG_MISSING_FUN_ARG, 2, JSEXN_TYPEERR, "missing argument {0} when calling function {1}")
|
||||
MSG_DEF(JSMSG_NOT_NONNULL_OBJECT, 1, JSEXN_TYPEERR, "{0} is not a non-null object")
|
||||
MSG_DEF(JSMSG_NOT_WEAKREF_TARGET, 0, JSEXN_TYPEERR, "WeakRef target must be an object or a non-registered symbol")
|
||||
MSG_DEF(JSMSG_SET_NON_OBJECT_RECEIVER, 1, JSEXN_TYPEERR, "can't assign to properties of {0}: not an object")
|
||||
MSG_DEF(JSMSG_INVALID_DESCRIPTOR, 0, JSEXN_TYPEERR, "property descriptors must not specify a value or be writable when a getter or setter has been specified")
|
||||
MSG_DEF(JSMSG_OBJECT_NOT_EXTENSIBLE, 1, JSEXN_TYPEERR, "{0}: Object is not extensible")
|
||||
|
||||
@@ -22,6 +22,64 @@ struct MyHeap
|
||||
|
||||
BEGIN_TEST(testGCWeakRef)
|
||||
{
|
||||
CHECK(cx->options().weakRefs());
|
||||
cx->options().setWeakRefs(false);
|
||||
CHECK(cx->options().weakRefs());
|
||||
|
||||
JS::RootedValue v(cx);
|
||||
EXEC("var weakRefTarget = { x: 42 };\n"
|
||||
"var weakRef = new WeakRef(weakRefTarget);\n"
|
||||
"weakRefTarget = null;\n");
|
||||
|
||||
// The constructor keeps the target alive until the host clears kept
|
||||
// objects. This must remain true even after callers try the old disabled
|
||||
// option path above.
|
||||
JS_GC(cx);
|
||||
JS_GC(cx);
|
||||
EVAL("weakRef.deref()", &v);
|
||||
CHECK(v.isObject());
|
||||
|
||||
JS::ClearWeakRefKeptObjects(cx);
|
||||
v = JS::UndefinedValue();
|
||||
JS_GC(cx);
|
||||
JS_GC(cx);
|
||||
EVAL("weakRef.deref()", &v);
|
||||
CHECK(v.isUndefined());
|
||||
|
||||
EXEC("var weakRefSymbol = Symbol('weak-ref-symbol');\n"
|
||||
"var symbolRef = new WeakRef(weakRefSymbol);\n"
|
||||
"if (symbolRef.deref() !== weakRefSymbol)\n"
|
||||
" throw new Error('WeakRef must accept unique symbols');\n"
|
||||
"var registeredSymbolRejected = false;\n"
|
||||
"try {\n"
|
||||
" new WeakRef(Symbol.for('weak-ref-symbol'));\n"
|
||||
"} catch (e) {\n"
|
||||
" registeredSymbolRejected = e instanceof TypeError;\n"
|
||||
"}\n"
|
||||
"if (!registeredSymbolRejected)\n"
|
||||
" throw new Error('WeakRef must reject registered symbols');\n");
|
||||
|
||||
EXEC("var keptTarget = { y: 7 };\n"
|
||||
"var keptRef = new WeakRef(keptTarget);\n");
|
||||
JS::ClearWeakRefKeptObjects(cx);
|
||||
EXEC("var keptResult = keptRef.deref();\n"
|
||||
"if (keptResult !== keptTarget)\n"
|
||||
" throw new Error('WeakRef deref must return the target');\n"
|
||||
"keptTarget = null;\n"
|
||||
"keptResult = null;\n");
|
||||
|
||||
JS_GC(cx);
|
||||
JS_GC(cx);
|
||||
EVAL("keptRef.deref()", &v);
|
||||
CHECK(v.isObject());
|
||||
|
||||
JS::ClearWeakRefKeptObjects(cx);
|
||||
v = JS::UndefinedValue();
|
||||
JS_GC(cx);
|
||||
JS_GC(cx);
|
||||
EVAL("keptRef.deref()", &v);
|
||||
CHECK(v.isUndefined());
|
||||
|
||||
// Create an object and add a property to it so that we can read the
|
||||
// property back later to verify that object internals are not garbage.
|
||||
JS::RootedObject obj(cx, JS_NewPlainObject(cx));
|
||||
@@ -39,7 +97,6 @@ BEGIN_TEST(testGCWeakRef)
|
||||
// references.
|
||||
CHECK(heap.get().weak.unbarrieredGet() != nullptr);
|
||||
obj = heap.get().weak;
|
||||
JS::RootedValue v(cx);
|
||||
CHECK(JS_GetProperty(cx, obj, "x", &v));
|
||||
CHECK(v.isInt32());
|
||||
CHECK(v.toInt32() == 42);
|
||||
@@ -62,4 +119,3 @@ BEGIN_TEST(testGCWeakRef)
|
||||
return true;
|
||||
}
|
||||
END_TEST(testGCWeakRef)
|
||||
|
||||
|
||||
@@ -629,6 +629,15 @@ JS::InitSelfHostedCode(JSContext* cx)
|
||||
return true;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS::ClearWeakRefKeptObjects(JSContext* cx)
|
||||
{
|
||||
MOZ_ASSERT(cx);
|
||||
MOZ_ASSERT(!cx->runtime()->isHeapBusy());
|
||||
|
||||
cx->runtime()->clearWeakRefKeptObjects();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(const char*)
|
||||
JS_GetImplementationVersion(void)
|
||||
{
|
||||
|
||||
+10
-5
@@ -1012,7 +1012,7 @@ class JS_PUBLIC_API(ContextOptions) {
|
||||
strictMode_(false),
|
||||
extraWarnings_(false),
|
||||
arrayProtoValues_(true),
|
||||
weakRefs_(false),
|
||||
streams_(false),
|
||||
#ifdef NIGHTLY_BUILD
|
||||
forEachStatement_(false)
|
||||
#else
|
||||
@@ -1168,13 +1168,12 @@ class JS_PUBLIC_API(ContextOptions) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool weakRefs() const { return weakRefs_; }
|
||||
bool weakRefs() const { return true; }
|
||||
ContextOptions& setWeakRefs(bool flag) {
|
||||
weakRefs_ = flag;
|
||||
(void) flag;
|
||||
return *this;
|
||||
}
|
||||
ContextOptions& toggleWeakRefs() {
|
||||
weakRefs_ = !weakRefs_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -1196,7 +1195,6 @@ class JS_PUBLIC_API(ContextOptions) {
|
||||
bool extraWarnings_ : 1;
|
||||
bool arrayProtoValues_ : 1;
|
||||
bool streams_ : 1;
|
||||
bool weakRefs_ : 1;
|
||||
bool forEachStatement_: 1;
|
||||
};
|
||||
|
||||
@@ -1218,6 +1216,13 @@ InitSelfHostedCode(JSContext* cx);
|
||||
JS_PUBLIC_API(void)
|
||||
AssertObjectBelongsToCurrentThread(JSObject* obj);
|
||||
|
||||
/**
|
||||
* Clear objects and symbols that WeakRef.prototype.deref kept alive for the
|
||||
* current synchronous JavaScript execution.
|
||||
*/
|
||||
JS_PUBLIC_API(void)
|
||||
ClearWeakRefKeptObjects(JSContext* cx);
|
||||
|
||||
} /* namespace JS */
|
||||
|
||||
extern JS_PUBLIC_API(const char*)
|
||||
|
||||
+4
-1
@@ -677,7 +677,9 @@ RunFile(JSContext* cx, const char* filename, FILE* file, bool compileOnly)
|
||||
AnalyzeEntrainedVariables(cx, script);
|
||||
#endif
|
||||
if (!compileOnly) {
|
||||
if (!JS_ExecuteScript(cx, script))
|
||||
bool ok = JS_ExecuteScript(cx, script);
|
||||
JS::ClearWeakRefKeptObjects(cx);
|
||||
if (!ok)
|
||||
return false;
|
||||
int64_t t2 = PRMJ_Now() - t1;
|
||||
if (printTiming)
|
||||
@@ -860,6 +862,7 @@ DrainJobQueue(JSContext* cx)
|
||||
}
|
||||
sc->jobQueue.clear();
|
||||
sc->drainingJobQueue = false;
|
||||
JS::ClearWeakRefKeptObjects(cx);
|
||||
|
||||
// It's possible a job added an async task, and it's also possible
|
||||
// that task has already finished.
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
// Manual WeakRef smoke tests for browser console use.
|
||||
//
|
||||
// Usage:
|
||||
// 1) Optionally flip `javascript.options.weakrefs` in about:config and reload.
|
||||
// 2) Paste this file into the browser console (or load via file://) and run:
|
||||
// 1) Paste this file into the browser console (or load via file://) and run:
|
||||
// runWeakRefManual();
|
||||
// 3) Inspect the returned array of results; no throws or crashes are expected.
|
||||
// 2) Inspect the returned array of results; no throws or crashes are expected.
|
||||
//
|
||||
// Notes:
|
||||
// - When the pref is ON, deref() should return the target.
|
||||
// - When the pref is OFF, the stub traces strongly so deref() should also
|
||||
// return the target.
|
||||
// - WeakRef is always enabled. Once all strong references are gone, a full GC
|
||||
// may clear the referent and make deref() return undefined.
|
||||
|
||||
function runWeakRefManual() {
|
||||
const results = [];
|
||||
@@ -21,7 +19,7 @@ function runWeakRefManual() {
|
||||
log("initial deref tag", ref.deref()?.tag);
|
||||
log("repeat deref identity", ref.deref() === target);
|
||||
|
||||
// Clear the strong reference; the WeakRef should still be able to return it.
|
||||
// Clear the strong reference. A future full GC may clear the WeakRef.
|
||||
target = null;
|
||||
|
||||
const afterClear = ref.deref();
|
||||
|
||||
@@ -196,6 +196,7 @@ JSRuntime::JSRuntime(JSRuntime* parentRuntime)
|
||||
simulator_(nullptr),
|
||||
#endif
|
||||
scriptAndCountsVector(nullptr),
|
||||
weakRefKeptObjects(nullptr),
|
||||
lcovOutput(),
|
||||
NaNValue(DoubleNaNValue()),
|
||||
negativeInfinityValue(DoubleValue(NegativeInfinity<double>())),
|
||||
@@ -375,6 +376,8 @@ JSRuntime::destroyRuntime()
|
||||
MOZ_ASSERT(!isHeapBusy());
|
||||
MOZ_ASSERT(childRuntimeCount == 0);
|
||||
|
||||
clearWeakRefKeptObjects();
|
||||
|
||||
fx.destroyInstance();
|
||||
|
||||
sharedIntlData.destroyInstance();
|
||||
@@ -476,6 +479,61 @@ JSRuntime::setTelemetryCallback(JSRuntime* rt, JSAccumulateTelemetryDataCallback
|
||||
rt->telemetryCallback = callback;
|
||||
}
|
||||
|
||||
static bool
|
||||
SameWeakRefKeptObject(const JS::Value& kept, JS::HandleValue target)
|
||||
{
|
||||
MOZ_ASSERT(kept.isObject() || kept.isSymbol());
|
||||
MOZ_ASSERT(target.isObject() || target.isSymbol());
|
||||
|
||||
if (kept.isObject())
|
||||
return target.isObject() && &kept.toObject() == &target.toObject();
|
||||
|
||||
return target.isSymbol() && kept.toSymbol() == target.toSymbol();
|
||||
}
|
||||
|
||||
bool
|
||||
JSRuntime::addWeakRefKeptObject(JSContext* cx, JS::HandleValue target)
|
||||
{
|
||||
MOZ_ASSERT(cx->runtime() == this);
|
||||
MOZ_ASSERT(target.isObject() || target.isSymbol());
|
||||
MOZ_ASSERT(!isHeapBusy());
|
||||
|
||||
if (!weakRefKeptObjects) {
|
||||
auto* keptObjects =
|
||||
cx->new_<JS::PersistentRooted<js::WeakRefKeptObjectVector>>(
|
||||
cx, js::WeakRefKeptObjectVector(js::SystemAllocPolicy()));
|
||||
if (!keptObjects)
|
||||
return false;
|
||||
|
||||
weakRefKeptObjects = keptObjects;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < weakRefKeptObjects->length(); i++) {
|
||||
const JS::Value& kept = (*weakRefKeptObjects)[i];
|
||||
if (SameWeakRefKeptObject(kept, target))
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!weakRefKeptObjects->append(target.get())) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
JSRuntime::clearWeakRefKeptObjects()
|
||||
{
|
||||
MOZ_ASSERT(!isHeapBusy());
|
||||
|
||||
if (!weakRefKeptObjects)
|
||||
return;
|
||||
|
||||
defaultFreeOp()->delete_(weakRefKeptObjects);
|
||||
weakRefKeptObjects = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
JSRuntime::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::RuntimeSizes* rtSizes)
|
||||
{
|
||||
|
||||
@@ -361,6 +361,7 @@ class PerThreadData
|
||||
};
|
||||
|
||||
using ScriptAndCountsVector = GCVector<ScriptAndCounts, 0, SystemAllocPolicy>;
|
||||
using WeakRefKeptObjectVector = JS::GCVector<JS::Value, 0, SystemAllocPolicy>;
|
||||
|
||||
class AutoLockForExclusiveAccess;
|
||||
} // namespace js
|
||||
@@ -901,6 +902,12 @@ struct JSRuntime : public JS::shadow::Runtime,
|
||||
/* Strong references on scripts held for PCCount profiling API. */
|
||||
JS::PersistentRooted<js::ScriptAndCountsVector>* scriptAndCountsVector;
|
||||
|
||||
/* Strong references to live WeakRef targets kept until the next job boundary. */
|
||||
JS::PersistentRooted<js::WeakRefKeptObjectVector>* weakRefKeptObjects;
|
||||
|
||||
[[nodiscard]] bool addWeakRefKeptObject(JSContext* cx, JS::HandleValue target);
|
||||
void clearWeakRefKeptObjects();
|
||||
|
||||
/* Code coverage output. */
|
||||
js::coverage::LCovRuntime lcovOutput;
|
||||
|
||||
|
||||
@@ -1510,7 +1510,6 @@ ReloadPrefsCallback(const char* pref, void* data)
|
||||
bool extraWarnings = Preferences::GetBool(JS_OPTIONS_DOT_STR "strict");
|
||||
|
||||
bool streams = Preferences::GetBool(JS_OPTIONS_DOT_STR "streams");
|
||||
bool weakRefs = Preferences::GetBool(JS_OPTIONS_DOT_STR "weakrefs");
|
||||
|
||||
bool inlining = Preferences::GetBool(JS_OPTIONS_DOT_STR "ion.inlining");
|
||||
|
||||
@@ -1535,8 +1534,7 @@ ReloadPrefsCallback(const char* pref, void* data)
|
||||
.setWerror(werror)
|
||||
.setExtraWarnings(extraWarnings)
|
||||
.setArrayProtoValues(arrayProtoValues)
|
||||
.setStreams(streams)
|
||||
.setWeakRefs(weakRefs);
|
||||
.setStreams(streams);
|
||||
|
||||
JS_SetParallelParsingEnabled(cx, parallelParsing);
|
||||
JS_SetOffthreadIonCompilationEnabled(cx, offthreadIonCompilation);
|
||||
|
||||
@@ -1411,9 +1411,6 @@ pref("javascript.options.dynamicImport", true);
|
||||
// Streams API
|
||||
pref("javascript.options.streams", true);
|
||||
|
||||
// Enable garbage collection of weakrefed objects
|
||||
pref("javascript.options.weakrefs", false);
|
||||
|
||||
// advanced prefs
|
||||
pref("advanced.mailftp", false);
|
||||
pref("image.animation_mode", "normal");
|
||||
|
||||
@@ -1506,6 +1506,8 @@ CycleCollectedJSContext::AfterProcessTask(uint32_t aRecursionDepth)
|
||||
|
||||
// Step 4.2 Execute any events that were waiting for a stable state.
|
||||
ProcessStableStateQueue();
|
||||
|
||||
JS::ClearWeakRefKeptObjects(mJSContext);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1544,6 +1546,8 @@ CycleCollectedJSContext::AfterProcessMicrotasks()
|
||||
});
|
||||
RunInStableState(cleanupRunnable.forget());
|
||||
};
|
||||
|
||||
JS::ClearWeakRefKeptObjects(mJSContext);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
|
||||
Reference in New Issue
Block a user