mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 21:31:04 +00:00
Bug 731845 - XPCWrappedNative::ReparentWrapperIfFound should handle preserved wrappers. r=mrbkap
This commit is contained in:
parent
c56541c485
commit
23e960e8cf
@ -597,29 +597,10 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNode, bool aClone, bool aDeep,
|
||||
if (aCx && wrapper) {
|
||||
nsIXPConnect *xpc = nsContentUtils::XPConnect();
|
||||
if (xpc) {
|
||||
JSObject *preservedWrapper = nsnull;
|
||||
|
||||
// If reparenting moves us to a new compartment, preserving causes
|
||||
// problems. In that case, we release ourselves and re-preserve after
|
||||
// reparenting so we're sure to have the right JS object preserved.
|
||||
// We use a JSObject stack copy of the wrapper to protect it from GC
|
||||
// under ReparentWrappedNativeIfFound.
|
||||
if (aNode->PreservingWrapper()) {
|
||||
preservedWrapper = wrapper;
|
||||
nsContentUtils::ReleaseWrapper(aNode, aNode);
|
||||
NS_ASSERTION(aNode->GetWrapper(),
|
||||
"ReleaseWrapper cleared our wrapper, this code needs to "
|
||||
"be changed to deal with that!");
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIXPConnectJSObjectHolder> oldWrapper;
|
||||
rv = xpc->ReparentWrappedNativeIfFound(aCx, wrapper, aNewScope, aNode,
|
||||
getter_AddRefs(oldWrapper));
|
||||
|
||||
if (preservedWrapper) {
|
||||
nsContentUtils::PreserveWrapper(aNode, aNode);
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
aNode->mNodeInfo.swap(nodeInfo);
|
||||
|
||||
|
@ -53,6 +53,8 @@
|
||||
#include "WrapperFactory.h"
|
||||
#include "dombindings.h"
|
||||
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
#include "mozilla/Util.h"
|
||||
|
||||
bool
|
||||
@ -1479,6 +1481,43 @@ XPCWrappedNative::SystemIsBeingShutDown()
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
// If we have to transplant an object across compartments, we need to be
|
||||
// careful if the underlying object implements nsWrapperCache and is preserving
|
||||
// the wrapper.
|
||||
//
|
||||
// The class brackets a pair of Unpreserve/Preserve calls in the given scope.
|
||||
//
|
||||
// This class _must_ live on the stack, in part so that mPreservedWrapper is
|
||||
// visible to the stack scanner. The caller wants the wrapper to be preserved,
|
||||
// so we don't want it to get accidentally GCed.
|
||||
class AutoWrapperChanger NS_STACK_CLASS {
|
||||
public:
|
||||
AutoWrapperChanger() : mCache(nsnull)
|
||||
, mCOMObj(nsnull)
|
||||
, mPreservedWrapper(nsnull)
|
||||
{}
|
||||
|
||||
void init(nsISupports* aCOMObj, nsWrapperCache* aWrapperCache) {
|
||||
mCOMObj = aCOMObj;
|
||||
mCache = aWrapperCache;
|
||||
if (mCache->PreservingWrapper()) {
|
||||
mPreservedWrapper = mCache->GetWrapper();
|
||||
MOZ_ASSERT(mPreservedWrapper);
|
||||
nsContentUtils::ReleaseWrapper(mCOMObj, mCache);
|
||||
}
|
||||
}
|
||||
|
||||
~AutoWrapperChanger() {
|
||||
if (mPreservedWrapper)
|
||||
nsContentUtils::PreserveWrapper(mCOMObj, mCache);
|
||||
}
|
||||
|
||||
private:
|
||||
nsWrapperCache* mCache;
|
||||
nsISupports* mCOMObj;
|
||||
JSObject* mPreservedWrapper;
|
||||
};
|
||||
|
||||
// static
|
||||
nsresult
|
||||
XPCWrappedNative::ReparentWrapperIfFound(XPCCallContext& ccx,
|
||||
@ -1497,10 +1536,16 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCCallContext& ccx,
|
||||
nsresult rv;
|
||||
|
||||
nsRefPtr<XPCWrappedNative> wrapper;
|
||||
AutoWrapperChanger wrapperChanger;
|
||||
JSObject *flat;
|
||||
nsWrapperCache* cache = nsnull;
|
||||
CallQueryInterface(aCOMObj, &cache);
|
||||
if (cache) {
|
||||
|
||||
// There's a wrapper cache. Make sure we keep it sane no matter what
|
||||
// happens.
|
||||
wrapperChanger.init(aCOMObj, cache);
|
||||
|
||||
flat = cache->GetWrapper();
|
||||
if (flat && !IS_SLIM_WRAPPER_OBJECT(flat)) {
|
||||
wrapper = static_cast<XPCWrappedNative*>(xpc_GetJSPrivate(flat));
|
||||
|
Loading…
Reference in New Issue
Block a user