mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 650353 - Implement Compartment-Per-Global in XPConnect. r=mrbkap
This commit is contained in:
parent
8cef559f81
commit
b1d0aeeace
@ -47,22 +47,6 @@
|
||||
#include "jsfriendapi.h"
|
||||
|
||||
/***************************************************************************/
|
||||
bool
|
||||
xpc::PtrAndPrincipalHashKey::KeyEquals(const PtrAndPrincipalHashKey* aKey) const
|
||||
{
|
||||
if (aKey->mPtr != mPtr)
|
||||
return false;
|
||||
if (aKey->mPrincipal == mPrincipal)
|
||||
return true;
|
||||
|
||||
bool equals;
|
||||
if (NS_FAILED(mPrincipal->EqualsIgnoringDomain(aKey->mPrincipal, &equals))) {
|
||||
NS_ERROR("we failed, guessing!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return equals;
|
||||
}
|
||||
|
||||
inline void
|
||||
XPCJSRuntime::AddVariantRoot(XPCTraceableVariant* variant)
|
||||
|
@ -256,22 +256,27 @@ CompartmentDestroyedCallback(JSFreeOp *fop, JSCompartment *compartment)
|
||||
XPCJSRuntime* self = nsXPConnect::GetRuntimeInstance();
|
||||
if (!self)
|
||||
return;
|
||||
XPCCompartmentSet &set = self->GetCompartmentSet();
|
||||
|
||||
// Get the current compartment private into an AutoPtr (which will do the
|
||||
// cleanup for us), and null out the private (which may already be null).
|
||||
nsAutoPtr<xpc::CompartmentPrivate>
|
||||
priv(static_cast<xpc::CompartmentPrivate*>(JS_GetCompartmentPrivate(compartment)));
|
||||
if (!priv)
|
||||
return;
|
||||
|
||||
JS_SetCompartmentPrivate(compartment, nsnull);
|
||||
|
||||
xpc::PtrAndPrincipalHashKey *key = priv->key;
|
||||
XPCCompartmentMap &map = self->GetCompartmentMap();
|
||||
#ifdef DEBUG
|
||||
JSCompartment *current = NULL;
|
||||
NS_ASSERTION(map.Get(key, ¤t), "no compartment?");
|
||||
NS_ASSERTION(current == compartment, "compartment mismatch");
|
||||
#endif
|
||||
map.Remove(key);
|
||||
// JSD creates compartments in our runtime without going through our creation
|
||||
// code. This means that those compartments aren't in our set, and don't have
|
||||
// compartment privates. JSD is on the way out, so let's just handle that
|
||||
// case for now.
|
||||
if (!priv) {
|
||||
MOZ_ASSERT(!set.has(compartment));
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove the compartment from the set.
|
||||
MOZ_ASSERT(set.has(compartment));
|
||||
set.remove(compartment);
|
||||
return;
|
||||
}
|
||||
|
||||
struct ObjectHolder : public JSDHashEntryHdr
|
||||
@ -395,18 +400,6 @@ TraceDOMExpandos(nsPtrHashKey<JSObject> *expando, void *aClosure)
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
TraceCompartment(xpc::PtrAndPrincipalHashKey *aKey, JSCompartment *compartment, void *aClosure)
|
||||
{
|
||||
xpc::CompartmentPrivate *priv =
|
||||
static_cast<xpc::CompartmentPrivate *>(JS_GetCompartmentPrivate(compartment));
|
||||
if (priv->expandoMap)
|
||||
priv->expandoMap->Enumerate(TraceExpandos, aClosure);
|
||||
if (priv->domExpandoMap)
|
||||
priv->domExpandoMap->EnumerateEntries(TraceDOMExpandos, aClosure);
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
void XPCJSRuntime::TraceXPConnectRoots(JSTracer *trc)
|
||||
{
|
||||
JSContext *iter = nsnull;
|
||||
@ -430,7 +423,15 @@ void XPCJSRuntime::TraceXPConnectRoots(JSTracer *trc)
|
||||
JS_DHashTableEnumerate(&mJSHolders, TraceJSHolder, trc);
|
||||
|
||||
// Trace compartments.
|
||||
GetCompartmentMap().EnumerateRead(TraceCompartment, trc);
|
||||
XPCCompartmentSet &set = GetCompartmentSet();
|
||||
for (XPCCompartmentRange r = set.all(); !r.empty(); r.popFront()) {
|
||||
xpc::CompartmentPrivate *priv = (xpc::CompartmentPrivate *)
|
||||
JS_GetCompartmentPrivate(r.front());
|
||||
if (priv->expandoMap)
|
||||
priv->expandoMap->Enumerate(TraceExpandos, trc);
|
||||
if (priv->domExpandoMap)
|
||||
priv->domExpandoMap->EnumerateEntries(TraceDOMExpandos, trc);
|
||||
}
|
||||
}
|
||||
|
||||
struct Closure
|
||||
@ -523,18 +524,6 @@ SuspectDOMExpandos(nsPtrHashKey<JSObject> *key, void *arg)
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
SuspectCompartment(xpc::PtrAndPrincipalHashKey *key, JSCompartment *compartment, void *arg)
|
||||
{
|
||||
xpc::CompartmentPrivate *priv =
|
||||
static_cast<xpc::CompartmentPrivate *>(JS_GetCompartmentPrivate(compartment));
|
||||
if (priv->expandoMap)
|
||||
priv->expandoMap->EnumerateRead(SuspectExpandos, arg);
|
||||
if (priv->domExpandoMap)
|
||||
priv->domExpandoMap->EnumerateEntries(SuspectDOMExpandos, arg);
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
void
|
||||
XPCJSRuntime::AddXPConnectRoots(nsCycleCollectionTraversalCallback &cb)
|
||||
{
|
||||
@ -590,7 +579,15 @@ XPCJSRuntime::AddXPConnectRoots(nsCycleCollectionTraversalCallback &cb)
|
||||
}
|
||||
|
||||
// Suspect wrapped natives with expando objects.
|
||||
GetCompartmentMap().EnumerateRead(SuspectCompartment, &closure);
|
||||
XPCCompartmentSet &set = GetCompartmentSet();
|
||||
for (XPCCompartmentRange r = set.all(); !r.empty(); r.popFront()) {
|
||||
xpc::CompartmentPrivate *priv = (xpc::CompartmentPrivate *)
|
||||
JS_GetCompartmentPrivate(r.front());
|
||||
if (priv->expandoMap)
|
||||
priv->expandoMap->EnumerateRead(SuspectExpandos, &closure);
|
||||
if (priv->domExpandoMap)
|
||||
priv->domExpandoMap->EnumerateEntries(SuspectDOMExpandos, &closure);
|
||||
}
|
||||
}
|
||||
|
||||
static JSDHashOperator
|
||||
@ -643,19 +640,6 @@ SweepExpandos(XPCWrappedNative *wn, JSObject *&expando, void *arg)
|
||||
: PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
SweepCompartment(nsCStringHashKey& aKey, JSCompartment *compartment, void *aClosure)
|
||||
{
|
||||
MOZ_ASSERT(!aClosure);
|
||||
xpc::CompartmentPrivate *priv =
|
||||
static_cast<xpc::CompartmentPrivate *>(JS_GetCompartmentPrivate(compartment));
|
||||
if (priv->waiverWrapperMap)
|
||||
priv->waiverWrapperMap->Sweep();
|
||||
if (priv->expandoMap)
|
||||
priv->expandoMap->Enumerate(SweepExpandos, nsnull);
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
XPCJSRuntime::GCCallback(JSRuntime *rt, JSGCStatus status)
|
||||
{
|
||||
@ -732,8 +716,15 @@ XPCJSRuntime::FinalizeCallback(JSFreeOp *fop, JSFinalizeStatus status)
|
||||
XPCWrappedNativeScope::StartFinalizationPhaseOfGC(fop, self);
|
||||
|
||||
// Sweep compartments.
|
||||
self->GetCompartmentMap().EnumerateRead((XPCCompartmentMap::EnumReadFunction)
|
||||
SweepCompartment, nsnull);
|
||||
XPCCompartmentSet &set = self->GetCompartmentSet();
|
||||
for (XPCCompartmentRange r = set.all(); !r.empty(); r.popFront()) {
|
||||
xpc::CompartmentPrivate *priv = (xpc::CompartmentPrivate *)
|
||||
JS_GetCompartmentPrivate(r.front());
|
||||
if (priv->waiverWrapperMap)
|
||||
priv->waiverWrapperMap->Sweep();
|
||||
if (priv->expandoMap)
|
||||
priv->expandoMap->Enumerate(SweepExpandos, NULL);
|
||||
}
|
||||
|
||||
self->mDoingFinalization = true;
|
||||
break;
|
||||
@ -2038,7 +2029,7 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
|
||||
sizeof(ObjectHolder), 512))
|
||||
mJSHolders.ops = nsnull;
|
||||
|
||||
mCompartmentMap.Init();
|
||||
mCompartmentSet.init();
|
||||
|
||||
// Install a JavaScript 'debugger' keyword handler in debug builds only
|
||||
#ifdef DEBUG
|
||||
@ -2083,6 +2074,7 @@ XPCJSRuntime::newXPCJSRuntime(nsXPConnect* aXPConnect)
|
||||
self->GetNativeScriptableSharedMap() &&
|
||||
self->GetDyingWrappedNativeProtoMap() &&
|
||||
self->GetMapLock() &&
|
||||
self->GetCompartmentSet().initialized() &&
|
||||
self->mWatchdogThread) {
|
||||
return self;
|
||||
}
|
||||
|
@ -82,26 +82,6 @@ NS_CYCLE_COLLECTION_CLASSNAME(XPCWrappedNative)::Unlink(void *p)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
struct TraverseExpandoObjectClosure
|
||||
{
|
||||
XPCWrappedNative *wn;
|
||||
nsCycleCollectionTraversalCallback &cb;
|
||||
};
|
||||
|
||||
static PLDHashOperator
|
||||
TraverseExpandoObjects(xpc::PtrAndPrincipalHashKey *aKey, JSCompartment *compartment, void *aClosure)
|
||||
{
|
||||
TraverseExpandoObjectClosure *closure = static_cast<TraverseExpandoObjectClosure*>(aClosure);
|
||||
xpc::CompartmentPrivate *priv =
|
||||
static_cast<xpc::CompartmentPrivate *>(JS_GetCompartmentPrivate(compartment));
|
||||
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(closure->cb, "XPCWrappedNative expando object");
|
||||
closure->cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT,
|
||||
priv->LookupExpandoObjectPreserveColor(closure->wn));
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
NS_CYCLE_COLLECTION_CLASSNAME(XPCWrappedNative)::Traverse(void *p,
|
||||
nsCycleCollectionTraversalCallback &cb)
|
||||
@ -144,8 +124,14 @@ NS_CYCLE_COLLECTION_CLASSNAME(XPCWrappedNative)::Traverse(void *p,
|
||||
|
||||
if (tmp->MightHaveExpandoObject()) {
|
||||
XPCJSRuntime *rt = tmp->GetRuntime();
|
||||
TraverseExpandoObjectClosure closure = { tmp, cb };
|
||||
rt->GetCompartmentMap().EnumerateRead(TraverseExpandoObjects, &closure);
|
||||
XPCCompartmentSet &set = rt->GetCompartmentSet();
|
||||
for (XPCCompartmentRange r = set.all(); !r.empty(); r.popFront()) {
|
||||
xpc::CompartmentPrivate *priv = (xpc::CompartmentPrivate *)
|
||||
JS_GetCompartmentPrivate(r.front());
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "XPCWrappedNative expando object");
|
||||
cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT,
|
||||
priv->LookupExpandoObjectPreserveColor(tmp));
|
||||
}
|
||||
}
|
||||
|
||||
// XPCWrappedNative keeps its native object alive.
|
||||
|
@ -1135,28 +1135,14 @@ xpc_CreateGlobalObject(JSContext *cx, JSClass *clasp,
|
||||
CheckTypeInference(cx, clasp, principal);
|
||||
|
||||
NS_ABORT_IF_FALSE(NS_IsMainThread(), "using a principal off the main thread?");
|
||||
NS_ABORT_IF_FALSE(principal, "bad key");
|
||||
|
||||
XPCCompartmentMap& map = nsXPConnect::GetRuntimeInstance()->GetCompartmentMap();
|
||||
xpc::PtrAndPrincipalHashKey key(ptr, principal);
|
||||
if (!map.Get(&key, compartment)) {
|
||||
xpc::PtrAndPrincipalHashKey *priv_key =
|
||||
new xpc::PtrAndPrincipalHashKey(ptr, principal);
|
||||
xpc::CompartmentPrivate *priv = new xpc::CompartmentPrivate(priv_key, wantXrays);
|
||||
if (!CreateNewCompartment(cx, clasp, principal, priv,
|
||||
global, compartment)) {
|
||||
xpc::CompartmentPrivate *priv = new xpc::CompartmentPrivate(wantXrays);
|
||||
if (!CreateNewCompartment(cx, clasp, principal, priv, global, compartment))
|
||||
return UnexpectedFailure(NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
map.Put(&key, *compartment);
|
||||
} else {
|
||||
js::AutoSwitchCompartment sc(cx, *compartment);
|
||||
|
||||
JSObject *tempGlobal = JS_NewGlobalObject(cx, clasp);
|
||||
if (!tempGlobal)
|
||||
XPCCompartmentSet& set = nsXPConnect::GetRuntimeInstance()->GetCompartmentSet();
|
||||
if (!set.put(*compartment))
|
||||
return UnexpectedFailure(NS_ERROR_FAILURE);
|
||||
*global = tempGlobal;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
// Verify that the right trace hook is called. Note that this doesn't
|
||||
|
@ -100,15 +100,15 @@
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsXPIDLString.h"
|
||||
#include "nsAutoJSValHolder.h"
|
||||
|
||||
#include "js/HashTable.h"
|
||||
#include "mozilla/GuardObjects.h"
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "nsDataHashtable.h"
|
||||
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsIJSContextStack.h"
|
||||
#include "nsIJSEngineTelemetryStats.h"
|
||||
#include "nsDeque.h"
|
||||
|
||||
#include "nsIConsoleService.h"
|
||||
#include "nsIScriptError.h"
|
||||
@ -123,6 +123,8 @@
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsStringBuffer.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsDeque.h"
|
||||
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsNetUtil.h"
|
||||
@ -235,75 +237,11 @@ extern const char XPC_SCRIPT_ERROR_CONTRACTID[];
|
||||
extern const char XPC_ID_CONTRACTID[];
|
||||
extern const char XPC_XPCONNECT_CONTRACTID[];
|
||||
|
||||
namespace xpc {
|
||||
typedef js::HashSet<JSCompartment *,
|
||||
js::DefaultHasher<JSCompartment *>,
|
||||
js::SystemAllocPolicy> XPCCompartmentSet;
|
||||
|
||||
class PtrAndPrincipalHashKey : public PLDHashEntryHdr
|
||||
{
|
||||
public:
|
||||
typedef PtrAndPrincipalHashKey *KeyType;
|
||||
typedef const PtrAndPrincipalHashKey *KeyTypePointer;
|
||||
|
||||
PtrAndPrincipalHashKey(const PtrAndPrincipalHashKey *aKey)
|
||||
: mPtr(aKey->mPtr), mPrincipal(aKey->mPrincipal),
|
||||
mSavedHash(aKey->mSavedHash)
|
||||
{
|
||||
MOZ_COUNT_CTOR(PtrAndPrincipalHashKey);
|
||||
}
|
||||
|
||||
PtrAndPrincipalHashKey(nsISupports *aPtr, nsIPrincipal *aPrincipal)
|
||||
: mPtr(aPtr), mPrincipal(aPrincipal)
|
||||
{
|
||||
MOZ_COUNT_CTOR(PtrAndPrincipalHashKey);
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
aPrincipal->GetURI(getter_AddRefs(uri));
|
||||
mSavedHash = uri
|
||||
? NS_SecurityHashURI(uri)
|
||||
: (NS_PTR_TO_UINT32(mPtr.get()) >> 2);
|
||||
}
|
||||
|
||||
~PtrAndPrincipalHashKey()
|
||||
{
|
||||
MOZ_COUNT_DTOR(PtrAndPrincipalHashKey);
|
||||
}
|
||||
|
||||
PtrAndPrincipalHashKey* GetKey() const
|
||||
{
|
||||
return const_cast<PtrAndPrincipalHashKey*>(this);
|
||||
}
|
||||
const PtrAndPrincipalHashKey* GetKeyPointer() const { return this; }
|
||||
|
||||
inline bool KeyEquals(const PtrAndPrincipalHashKey* aKey) const;
|
||||
|
||||
static const PtrAndPrincipalHashKey*
|
||||
KeyToPointer(PtrAndPrincipalHashKey* aKey) { return aKey; }
|
||||
static PLDHashNumber HashKey(const PtrAndPrincipalHashKey* aKey)
|
||||
{
|
||||
return aKey->mSavedHash;
|
||||
}
|
||||
|
||||
nsISupports* GetPtr()
|
||||
{
|
||||
return mPtr;
|
||||
}
|
||||
|
||||
enum { ALLOW_MEMMOVE = true };
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsISupports> mPtr;
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
|
||||
// During shutdown, when we GC, we need to remove these keys from the hash
|
||||
// table. However, computing the saved hash, NS_SecurityHashURI calls back
|
||||
// into XPCOM (which is illegal during shutdown). In order to avoid this,
|
||||
// we compute the hash up front, so when we're in GC during shutdown, we
|
||||
// don't have to call into XPCOM.
|
||||
PLDHashNumber mSavedHash;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// This map is only used on the main thread.
|
||||
typedef nsDataHashtable<xpc::PtrAndPrincipalHashKey, JSCompartment *> XPCCompartmentMap;
|
||||
typedef XPCCompartmentSet::Range XPCCompartmentRange;
|
||||
|
||||
/***************************************************************************/
|
||||
// Useful macros...
|
||||
@ -677,8 +615,8 @@ public:
|
||||
XPCWrappedNativeProtoMap* GetDetachedWrappedNativeProtoMap() const
|
||||
{return mDetachedWrappedNativeProtoMap;}
|
||||
|
||||
XPCCompartmentMap& GetCompartmentMap()
|
||||
{return mCompartmentMap;}
|
||||
XPCCompartmentSet& GetCompartmentSet()
|
||||
{return mCompartmentSet;}
|
||||
|
||||
XPCLock* GetMapLock() const {return mMapLock;}
|
||||
|
||||
@ -822,7 +760,7 @@ private:
|
||||
XPCNativeScriptableSharedMap* mNativeScriptableSharedMap;
|
||||
XPCWrappedNativeProtoMap* mDyingWrappedNativeProtoMap;
|
||||
XPCWrappedNativeProtoMap* mDetachedWrappedNativeProtoMap;
|
||||
XPCCompartmentMap mCompartmentMap;
|
||||
XPCCompartmentSet mCompartmentSet;
|
||||
XPCLock* mMapLock;
|
||||
PRThread* mThreadRunningGC;
|
||||
nsTArray<nsXPCWrappedJS*> mWrappedJSToReleaseArray;
|
||||
@ -4434,16 +4372,14 @@ namespace xpc {
|
||||
|
||||
struct CompartmentPrivate
|
||||
{
|
||||
CompartmentPrivate(PtrAndPrincipalHashKey *key, bool wantXrays)
|
||||
: key(key),
|
||||
wantXrays(wantXrays)
|
||||
CompartmentPrivate(bool wantXrays)
|
||||
: wantXrays(wantXrays)
|
||||
{
|
||||
MOZ_COUNT_CTOR(xpc::CompartmentPrivate);
|
||||
}
|
||||
|
||||
~CompartmentPrivate();
|
||||
|
||||
nsAutoPtr<PtrAndPrincipalHashKey> key;
|
||||
bool wantXrays;
|
||||
nsAutoPtr<JSObject2JSObjectMap> waiverWrapperMap;
|
||||
// NB: we don't want this map to hold a strong reference to the wrapper.
|
||||
|
@ -90,6 +90,8 @@ struct DebugOnly
|
||||
value--;
|
||||
}
|
||||
|
||||
T *operator&() { return &value; }
|
||||
|
||||
operator T&() { return value; }
|
||||
operator const T&() const { return value; }
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user