зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1342012 - Support script and module private values which contain pointers to cycle-collected C++ objects r=jandem
This commit is contained in:
Родитель
41dd1b00f4
Коммит
20a91427ef
|
@ -620,6 +620,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.")
|
||||
|
|
|
@ -3740,7 +3740,7 @@ JS_PUBLIC_API void JS::SetModulePrivate(JSObject* module,
|
|||
}
|
||||
|
||||
JS_PUBLIC_API JS::Value JS::GetModulePrivate(JSObject* module) {
|
||||
return module->as<ModuleObject>().scriptSourceObject()->unwrappedPrivate();
|
||||
return module->as<ModuleObject>().scriptSourceObject()->canonicalPrivate();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API void JS::SetScriptPrivate(JSScript* script,
|
||||
|
@ -3749,7 +3749,19 @@ JS_PUBLIC_API void JS::SetScriptPrivate(JSScript* script,
|
|||
}
|
||||
|
||||
JS_PUBLIC_API JS::Value JS::GetScriptPrivate(JSScript* script) {
|
||||
return script->sourceObject()->unwrappedPrivate();
|
||||
return script->sourceObject()->canonicalPrivate();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API JS::ScriptPrivateFinalizeHook JS::GetScriptPrivateFinalizeHook(
|
||||
JSRuntime* rt) {
|
||||
AssertHeapIsIdle();
|
||||
return rt->scriptPrivateFinalizeHook;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API void JS::SetScriptPrivateFinalizeHook(
|
||||
JSRuntime* rt, JS::ScriptPrivateFinalizeHook func) {
|
||||
AssertHeapIsIdle();
|
||||
rt->scriptPrivateFinalizeHook = func;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API bool JS::ModuleInstantiate(JSContext* cx,
|
||||
|
|
|
@ -3104,13 +3104,17 @@ using ModuleDynamicImportHook = bool (*)(JSContext* cx,
|
|||
HandleObject promise);
|
||||
|
||||
/**
|
||||
* Get the HostResolveImportedModule hook for the runtime.
|
||||
* Get the HostImportModuleDynamically hook for the runtime.
|
||||
*/
|
||||
extern JS_PUBLIC_API ModuleDynamicImportHook
|
||||
GetModuleDynamicImportHook(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 SetModuleDynamicImportHook(
|
||||
JSRuntime* rt, ModuleDynamicImportHook func);
|
||||
|
@ -3152,6 +3156,26 @@ extern JS_PUBLIC_API void SetScriptPrivate(JSScript* script,
|
|||
*/
|
||||
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(JSRuntime* rt);
|
||||
|
||||
/**
|
||||
* Set the script private finalize hook for the runtime to the given function.
|
||||
*/
|
||||
extern JS_PUBLIC_API void SetScriptPrivateFinalizeHook(
|
||||
JSRuntime* rt, ScriptPrivateFinalizeHook func);
|
||||
|
||||
/*
|
||||
* Perform the ModuleInstantiate operation on the given source text module
|
||||
* record.
|
||||
|
|
|
@ -1404,6 +1404,14 @@ JS_FRIEND_API void js::LogDtor(void* self, const char* type, uint32_t sz) {
|
|||
}
|
||||
}
|
||||
|
||||
JS_FRIEND_API JS::Value js::MaybeGetScriptPrivate(JSObject* object) {
|
||||
if (!object->is<ScriptSourceObject>()) {
|
||||
return UndefinedValue();
|
||||
}
|
||||
|
||||
return object->as<ScriptSourceObject>().canonicalPrivate();
|
||||
}
|
||||
|
||||
JS_FRIEND_API uint64_t js::GetGCHeapUsageForObjectZone(JSObject* obj) {
|
||||
return obj->zone()->usage.gcBytes();
|
||||
}
|
||||
|
|
|
@ -106,6 +106,22 @@ extern JS_FRIEND_API bool JS_IsDeadWrapper(JSObject* obj);
|
|||
extern JS_FRIEND_API JSObject* JS_NewDeadWrapper(
|
||||
JSContext* cx, JSObject* origObject = nullptr);
|
||||
|
||||
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.
|
||||
|
|
|
@ -3367,7 +3367,7 @@ ModuleObject* js::GetModuleObjectForScript(JSScript* script) {
|
|||
Value js::FindScriptOrModulePrivateForScript(JSScript* script) {
|
||||
while (script) {
|
||||
ScriptSourceObject* sso = script->sourceObject();
|
||||
Value value = sso->unwrappedPrivate();
|
||||
Value value = sso->canonicalPrivate();
|
||||
if (!value.isUndefined()) {
|
||||
return value;
|
||||
}
|
||||
|
|
|
@ -1317,6 +1317,16 @@ void ScriptSourceObject::finalize(FreeOp* fop, JSObject* obj) {
|
|||
MOZ_ASSERT(fop->onMainThread());
|
||||
ScriptSourceObject* sso = &obj->as<ScriptSourceObject>();
|
||||
sso->source()->decref();
|
||||
|
||||
Value value = sso->canonicalPrivate();
|
||||
if (!value.isUndefined()) {
|
||||
// The embedding may need to dispose of its private data.
|
||||
JS::AutoSuppressGCAnalysis suppressGC;
|
||||
if (JS::ScriptPrivateFinalizeHook hook =
|
||||
fop->runtime()->scriptPrivateFinalizeHook) {
|
||||
hook(fop, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptSourceObject::trace(JSTracer* trc, JSObject* obj) {
|
||||
|
|
|
@ -1176,8 +1176,10 @@ class ScriptSourceObject : public NativeObject {
|
|||
setReservedSlot(PRIVATE_SLOT, value);
|
||||
}
|
||||
|
||||
Value unwrappedPrivate() const {
|
||||
return unwrappedCanonical()->getReservedSlot(PRIVATE_SLOT);
|
||||
Value canonicalPrivate() const {
|
||||
Value value = getReservedSlot(PRIVATE_SLOT);
|
||||
MOZ_ASSERT_IF(!isCanonical(), value.isUndefined());
|
||||
return value;
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -163,7 +163,8 @@ JSRuntime::JSRuntime(JSRuntime* parentRuntime)
|
|||
wasmInstances(mutexid::WasmRuntimeInstances),
|
||||
moduleResolveHook(),
|
||||
moduleMetadataHook(),
|
||||
moduleDynamicImportHook() {
|
||||
moduleDynamicImportHook(),
|
||||
scriptPrivateFinalizeHook() {
|
||||
JS_COUNT_CTOR(JSRuntime);
|
||||
liveRuntimesCount++;
|
||||
|
||||
|
|
|
@ -979,6 +979,9 @@ struct JSRuntime : public js::MallocProvider<JSRuntime> {
|
|||
// module import and can accessed by off-thread parsing.
|
||||
mozilla::Atomic<JS::ModuleDynamicImportHook> moduleDynamicImportHook;
|
||||
|
||||
// A hook called on script finalization.
|
||||
js::MainThreadData<JS::ScriptPrivateFinalizeHook> scriptPrivateFinalizeHook;
|
||||
|
||||
public:
|
||||
#if defined(JS_BUILD_BINAST)
|
||||
js::BinaryASTSupport& binast() { return binast_; }
|
||||
|
|
|
@ -75,6 +75,7 @@
|
|||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "js/Debug.h"
|
||||
#include "js/GCAPI.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCycleCollectionNoteRootCallback.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
|
@ -627,28 +628,36 @@ void CycleCollectedJSRuntime::NoteGCThingXPCOMChildren(
|
|||
// Nothing else to do!
|
||||
return;
|
||||
}
|
||||
|
||||
// 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()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче