mirror of
https://github.com/roytam1/UXP.git
synced 2026-05-26 14:54:25 +00:00
121 lines
3.8 KiB
C++
121 lines
3.8 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
*/
|
|
/* 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 "gc/Barrier.h"
|
|
#include "js/RootingAPI.h"
|
|
|
|
#include "jsapi-tests/tests.h"
|
|
|
|
struct MyHeap
|
|
{
|
|
explicit MyHeap(JSObject* obj) : weak(obj) {}
|
|
js::WeakRef<JSObject*> weak;
|
|
|
|
void trace(JSTracer* trc) {
|
|
js::TraceWeakEdge(trc, &weak, "weak");
|
|
}
|
|
};
|
|
|
|
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));
|
|
CHECK(obj);
|
|
CHECK(JS_DefineProperty(cx, obj, "x", 42, 0));
|
|
|
|
// Store the object behind a weak pointer and remove other references.
|
|
JS::Rooted<MyHeap> heap(cx, MyHeap(obj));
|
|
obj = nullptr;
|
|
|
|
cx->gc.minorGC(JS::gcreason::API);
|
|
|
|
// The minor collection should have treated the weak ref as a strong ref,
|
|
// so the object should still be live, despite not having any other live
|
|
// references.
|
|
CHECK(heap.get().weak.unbarrieredGet() != nullptr);
|
|
obj = heap.get().weak;
|
|
CHECK(JS_GetProperty(cx, obj, "x", &v));
|
|
CHECK(v.isInt32());
|
|
CHECK(v.toInt32() == 42);
|
|
|
|
// A full collection with a second ref should keep the object as well.
|
|
CHECK(obj == heap.get().weak);
|
|
JS_GC(cx);
|
|
CHECK(obj == heap.get().weak);
|
|
v = JS::UndefinedValue();
|
|
CHECK(JS_GetProperty(cx, obj, "x", &v));
|
|
CHECK(v.isInt32());
|
|
CHECK(v.toInt32() == 42);
|
|
|
|
// A full collection after nulling the root should collect the object, or
|
|
// at least null out the weak reference before returning to the mutator.
|
|
obj = nullptr;
|
|
JS_GC(cx);
|
|
CHECK(heap.get().weak == nullptr);
|
|
|
|
return true;
|
|
}
|
|
END_TEST(testGCWeakRef)
|