mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-05 15:28:39 +09:00
Issue #1691 - Part 6a: Support private values which contain pointers to cycle-collected C++ objects https://bugzilla.mozilla.org/show_bug.cgi?id=1342012
(cherry picked from commit 1286cca73d58332ba0becd0011f747713b8acfac)
This commit is contained in:
parent
5c09a3b3cc
commit
1b811bd711
10 changed files with 107 additions and 23 deletions
|
|
@ -593,6 +593,7 @@ MSG_DEF(JSMSG_MISSING_EXPORT, 1, JSEXN_SYNTAXERR, "local binding for
|
|||
MSG_DEF(JSMSG_BAD_MODULE_STATUS, 0, JSEXN_INTERNALERR, "module record has unexpected status")
|
||||
MSG_DEF(JSMSG_NO_DYNAMIC_IMPORT, 0, JSEXN_SYNTAXERR, "dynamic module import is not implemented")
|
||||
MSG_DEF(JSMSG_IMPORT_SCRIPT_NOT_FOUND, 0, JSEXN_TYPEERR, "can't find referencing script for dynamic module import")
|
||||
MSG_DEF(JSMSG_BAD_MODULE_SPECIFIER, 1, JSEXN_TYPEERR, "error resolving module specifier '{0}'")
|
||||
|
||||
// Promise
|
||||
MSG_DEF(JSMSG_CANNOT_RESOLVE_PROMISE_WITH_ITSELF, 0, JSEXN_TYPEERR, "A promise cannot be resolved with itself.")
|
||||
|
|
|
|||
|
|
@ -4756,7 +4756,7 @@ JS::SetModulePrivate(JSObject* module, const JS::Value& value)
|
|||
JS_PUBLIC_API(JS::Value)
|
||||
JS::GetModulePrivate(JSObject* module)
|
||||
{
|
||||
return module->as<ModuleObject>().scriptSourceObject()->getPrivate();
|
||||
return module->as<ModuleObject>().scriptSourceObject()->canonicalPrivate();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
|
|
@ -4768,7 +4768,21 @@ JS::SetScriptPrivate(JSScript* script, const JS::Value& value)
|
|||
JS_PUBLIC_API(JS::Value)
|
||||
JS::GetScriptPrivate(JSScript* script)
|
||||
{
|
||||
return script->scriptSourceUnwrap().getPrivate();
|
||||
return script->scriptSourceUnwrap().canonicalPrivate();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JS::ScriptPrivateFinalizeHook)
|
||||
JS::GetScriptPrivateFinalizeHook(JSContext* cx)
|
||||
{
|
||||
AssertHeapIsIdle(cx);
|
||||
return cx->runtime()->scriptPrivateFinalizeHook;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS::SetScriptPrivateFinalizeHook(JSContext* cx, JS::ScriptPrivateFinalizeHook func)
|
||||
{
|
||||
AssertHeapIsIdle(cx);
|
||||
cx->runtime()->scriptPrivateFinalizeHook = func;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
|
|
|
|||
|
|
@ -4327,13 +4327,17 @@ Evaluate(JSContext* cx, const ReadOnlyCompileOptions& options,
|
|||
using ModuleResolveHook = JSObject* (*)(JSContext*, HandleValue, HandleString);
|
||||
|
||||
/**
|
||||
* Get the HostResolveImportedModule hook for the runtime.
|
||||
* Get the HostImportModuleDynamically hook for the runtime.
|
||||
*/
|
||||
extern JS_PUBLIC_API(ModuleResolveHook)
|
||||
GetModuleResolveHook(JSRuntime* rt);
|
||||
|
||||
/**
|
||||
* Set the HostResolveImportedModule hook for the runtime to the given function.
|
||||
* Set the HostImportModuleDynamically hook for the runtime to the given
|
||||
* function.
|
||||
*
|
||||
* If this hook is not set (or set to nullptr) then the JS engine will throw an
|
||||
* exception if dynamic module import is attempted.
|
||||
*/
|
||||
extern JS_PUBLIC_API(void)
|
||||
SetModuleResolveHook(JSRuntime* rt, ModuleResolveHook func);
|
||||
|
|
@ -4406,6 +4410,26 @@ SetScriptPrivate(JSScript* script, const JS::Value& value);
|
|||
extern JS_PUBLIC_API(JS::Value)
|
||||
GetScriptPrivate(JSScript* script);
|
||||
|
||||
/**
|
||||
* A hook that's called whenever a script or module which has a private value
|
||||
* set with SetScriptPrivate() or SetModulePrivate() is finalized. This can be
|
||||
* used to clean up the private state. The private value is passed as an
|
||||
* argument.
|
||||
*/
|
||||
using ScriptPrivateFinalizeHook = void (*)(JSFreeOp*, const JS::Value&);
|
||||
|
||||
/**
|
||||
* Get the script private finalize hook for the runtime.
|
||||
*/
|
||||
extern JS_PUBLIC_API(ScriptPrivateFinalizeHook)
|
||||
GetScriptPrivateFinalizeHook(JSContext* cx);
|
||||
|
||||
/**
|
||||
* Set the script private finalize hook for the runtime to the given function.
|
||||
*/
|
||||
extern JS_PUBLIC_API(void)
|
||||
SetScriptPrivateFinalizeHook(JSContext* cx, ScriptPrivateFinalizeHook func);
|
||||
|
||||
/*
|
||||
* Perform the ModuleInstantiate operation on the given source text module
|
||||
* record.
|
||||
|
|
|
|||
|
|
@ -1321,6 +1321,15 @@ js::GetAllocationMetadata(JSObject* obj)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(JS::Value)
|
||||
js::MaybeGetScriptPrivate(JSObject* object) {
|
||||
if (!object->is<ScriptSourceObject>()) {
|
||||
return UndefinedValue();
|
||||
}
|
||||
|
||||
return object->as<ScriptSourceObject>().canonicalPrivate();
|
||||
}
|
||||
|
||||
JS_FRIEND_API(bool)
|
||||
js::ReportIsNotFunction(JSContext* cx, HandleValue v)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -95,6 +95,22 @@ JS_PCToLineNumber(JSScript* script, jsbytecode* pc, unsigned* columnp = nullptr)
|
|||
extern JS_FRIEND_API(bool)
|
||||
JS_IsDeadWrapper(JSObject* obj);
|
||||
|
||||
namespace js {
|
||||
|
||||
/**
|
||||
* Get the script private value associated with an object, if any.
|
||||
*
|
||||
* The private value is set with SetScriptPrivate() or SetModulePrivate() and is
|
||||
* internally stored on the relevant ScriptSourceObject.
|
||||
*
|
||||
* This is used by the cycle collector to trace through
|
||||
* ScriptSourceObjects. This allows private values to contain an nsISupports
|
||||
* pointer and hence support references to cycle collected C++ objects.
|
||||
*/
|
||||
JS_FRIEND_API(JS::Value) MaybeGetScriptPrivate(JSObject* object);
|
||||
|
||||
} // namespace js
|
||||
|
||||
/*
|
||||
* Used by the cycle collector to trace through a shape or object group and
|
||||
* all cycle-participating data it reaches, using bounded stack space.
|
||||
|
|
|
|||
|
|
@ -641,10 +641,17 @@ class ScriptSourceObject : public NativeObject
|
|||
void setPrivate(const Value& value) {
|
||||
setReservedSlot(PRIVATE_SLOT, value);
|
||||
}
|
||||
|
||||
Value getPrivate() const {
|
||||
return getReservedSlot(PRIVATE_SLOT);
|
||||
}
|
||||
|
||||
Value canonicalPrivate() const {
|
||||
Value value = getReservedSlot(PRIVATE_SLOT);
|
||||
MOZ_ASSERT_IF(!isCanonical(), value.isUndefined());
|
||||
return value;
|
||||
}
|
||||
|
||||
private:
|
||||
enum {
|
||||
SOURCE_SLOT = 0,
|
||||
|
|
|
|||
|
|
@ -3088,7 +3088,7 @@ js::FindScriptOrModulePrivateForScript(JSScript* script)
|
|||
{
|
||||
while (script) {
|
||||
ScriptSourceObject* sso = &script->scriptSourceUnwrap();
|
||||
Value value = sso->getPrivate();
|
||||
Value value = sso->canonicalPrivate();
|
||||
if (!value.isUndefined()) {
|
||||
return value;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -245,7 +245,8 @@ JSRuntime::JSRuntime(JSRuntime* parentRuntime)
|
|||
js::StackFormat::SpiderMonkey),
|
||||
moduleResolveHook(),
|
||||
moduleMetadataHook(),
|
||||
moduleDynamicImportHook()
|
||||
moduleDynamicImportHook(),
|
||||
scriptPrivateFinalizeHook()
|
||||
{
|
||||
setGCStoreBufferPtr(&gc.storeBuffer);
|
||||
|
||||
|
|
|
|||
|
|
@ -1304,6 +1304,9 @@ struct JSRuntime : public JS::shadow::Runtime,
|
|||
// A hook that implements the abstract operation
|
||||
// HostImportModuleDynamically.
|
||||
JS::ModuleDynamicImportHook moduleDynamicImportHook;
|
||||
|
||||
// A hook called on script finalization.
|
||||
JS::ScriptPrivateFinalizeHook scriptPrivateFinalizeHook;
|
||||
};
|
||||
|
||||
namespace js {
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@
|
|||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "jsprf.h"
|
||||
#include "js/Debug.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCycleCollectionNoteRootCallback.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
|
|
@ -642,25 +643,33 @@ CycleCollectedJSContext::NoteGCThingXPCOMChildren(const js::Class* aClasp,
|
|||
}
|
||||
// XXX This test does seem fragile, we should probably whitelist classes
|
||||
// that do hold a strong reference, but that might not be possible.
|
||||
else if (aClasp->flags & JSCLASS_HAS_PRIVATE &&
|
||||
aClasp->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS) {
|
||||
if (aClasp->flags & JSCLASS_HAS_PRIVATE &&
|
||||
aClasp->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS) {
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "js::GetObjectPrivate(obj)");
|
||||
aCb.NoteXPCOMChild(static_cast<nsISupports*>(js::GetObjectPrivate(aObj)));
|
||||
} else {
|
||||
const DOMJSClass* domClass = GetDOMClass(aObj);
|
||||
if (domClass) {
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "UnwrapDOMObject(obj)");
|
||||
// It's possible that our object is an unforgeable holder object, in
|
||||
// which case it doesn't actually have a C++ DOM object associated with
|
||||
// it. Use UnwrapPossiblyNotInitializedDOMObject, which produces null in
|
||||
// that case, since NoteXPCOMChild/NoteNativeChild are null-safe.
|
||||
if (domClass->mDOMObjectIsISupports) {
|
||||
aCb.NoteXPCOMChild(UnwrapPossiblyNotInitializedDOMObject<nsISupports>(aObj));
|
||||
} else if (domClass->mParticipant) {
|
||||
aCb.NoteNativeChild(UnwrapPossiblyNotInitializedDOMObject<void>(aObj),
|
||||
domClass->mParticipant);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const DOMJSClass* domClass = GetDOMClass(aObj);
|
||||
if (domClass) {
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "UnwrapDOMObject(obj)");
|
||||
// It's possible that our object is an unforgeable holder object, in
|
||||
// which case it doesn't actually have a C++ DOM object associated with
|
||||
// it. Use UnwrapPossiblyNotInitializedDOMObject, which produces null in
|
||||
// that case, since NoteXPCOMChild/NoteNativeChild are null-safe.
|
||||
if (domClass->mDOMObjectIsISupports) {
|
||||
aCb.NoteXPCOMChild(
|
||||
UnwrapPossiblyNotInitializedDOMObject<nsISupports>(aObj));
|
||||
} else if (domClass->mParticipant) {
|
||||
aCb.NoteNativeChild(UnwrapPossiblyNotInitializedDOMObject<void>(aObj),
|
||||
domClass->mParticipant);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
JS::Value value = js::MaybeGetScriptPrivate(aObj);
|
||||
if (!value.isUndefined()) {
|
||||
aCb.NoteXPCOMChild(static_cast<nsISupports*>(value.toPrivate()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue