Fix for bug 370265 (nsDOMScriptObjectHolder/NS_DropScriptObject tries to get service while shutting down). r/sr=jst.

This commit is contained in:
peterv%propagandism.org 2007-03-02 13:34:14 +00:00
parent e4dac66084
commit 3d6360dc54
7 changed files with 155 additions and 185 deletions

View File

@ -52,6 +52,8 @@
#include "nsDOMClassInfoID.h"
#include "nsIClassInfo.h"
#include "nsIDOM3Node.h"
#include "nsIScriptRuntime.h"
#include "nsIScriptGlobalObject.h"
class nsIDOMScriptObjectFactory;
class nsIXPConnect;
@ -84,7 +86,6 @@ class nsIWordBreaker;
class nsIJSRuntimeService;
class nsIEventListenerManager;
class nsIScriptContext;
class nsIScriptGlobalObject;
template<class E> class nsCOMArray;
class nsIPref;
class nsVoidArray;
@ -955,6 +956,32 @@ public:
*/
static void DestroyAnonymousContent(nsCOMPtr<nsIContent>* aContent);
static nsresult HoldScriptObject(PRUint32 aLangID, void *aObject);
static nsresult DropScriptObject(PRUint32 aLangID, void *aObject);
class ScriptObjectHolder
{
public:
ScriptObjectHolder(PRUint32 aLangID) : mLangID(aLangID),
mObject(nsnull)
{
}
~ScriptObjectHolder()
{
DropScriptObject(mLangID, mObject);
}
nsresult set(void *aObject)
{
nsresult rv = HoldScriptObject(mLangID, aObject);
if (NS_SUCCEEDED(rv)) {
mObject = aObject;
}
return rv;
}
PRUint32 mLangID;
void *mObject;
};
private:
static nsresult doReparentContentWrapper(nsIContent *aChild,
JSContext *cx,
@ -965,6 +992,8 @@ private:
static nsresult EnsureStringBundle(PropertiesFile aFile);
static nsIDOMScriptObjectFactory *GetDOMScriptObjectFactory();
static nsIDOMScriptObjectFactory *sDOMScriptObjectFactory;
static nsIXPConnect *sXPConnect;
@ -1006,8 +1035,11 @@ private:
// For now, we don't want to automatically clean this up in Shutdown(), since
// consumers might unfortunately end up wanting to use it after that
static nsIJSRuntimeService* sJSRuntimeService;
static JSRuntime* sScriptRuntime;
static PRInt32 sScriptRootCount;
static JSRuntime* sJSScriptRuntime;
static PRInt32 sJSScriptRootCount;
static nsIScriptRuntime* sScriptRuntimes[NS_STID_ARRAY_UBOUND];
static PRInt32 sScriptRootCount[NS_STID_ARRAY_UBOUND];
#ifdef IBMBIDI
static nsIBidiKeyboard* sBidiKeyboard;

View File

@ -173,8 +173,10 @@ nsILineBreaker *nsContentUtils::sLineBreaker;
nsIWordBreaker *nsContentUtils::sWordBreaker;
nsVoidArray *nsContentUtils::sPtrsToPtrsToRelease;
nsIJSRuntimeService *nsContentUtils::sJSRuntimeService;
JSRuntime *nsContentUtils::sScriptRuntime;
PRInt32 nsContentUtils::sScriptRootCount = 0;
JSRuntime *nsContentUtils::sJSScriptRuntime;
PRInt32 nsContentUtils::sJSScriptRootCount = 0;
nsIScriptRuntime *nsContentUtils::sScriptRuntimes[NS_STID_ARRAY_UBOUND];
PRInt32 nsContentUtils::sScriptRootCount[NS_STID_ARRAY_UBOUND];
#ifdef IBMBIDI
nsIBidiKeyboard *nsContentUtils::sBidiKeyboard = nsnull;
#endif
@ -223,12 +225,6 @@ EventListenerManagerHashClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
lm->~EventListenerManagerMapEntry();
}
PR_STATIC_CALLBACK(void)
NopClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
{
// Do nothing
}
// static
nsresult
nsContentUtils::Init()
@ -596,18 +592,9 @@ nsContentUtils::Shutdown()
nsISupports *
nsContentUtils::GetClassInfoInstance(nsDOMClassInfoID aID)
{
if (!sDOMScriptObjectFactory) {
static NS_DEFINE_CID(kDOMScriptObjectFactoryCID,
NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
nsIDOMScriptObjectFactory *factory = GetDOMScriptObjectFactory();
CallGetService(kDOMScriptObjectFactoryCID, &sDOMScriptObjectFactory);
if (!sDOMScriptObjectFactory) {
return nsnull;
}
}
return sDOMScriptObjectFactory->GetClassInfoInstance(aID);
return factory ? factory->GetClassInfoInstance(aID) : nsnull;
}
/**
@ -2544,13 +2531,13 @@ nsContentUtils::GetContentPolicy()
nsresult
nsContentUtils::AddJSGCRoot(void* aPtr, const char* aName)
{
if (!sScriptRuntime) {
if (!sJSScriptRuntime) {
nsresult rv = CallGetService("@mozilla.org/js/xpc/RuntimeService;1",
&sJSRuntimeService);
NS_ENSURE_TRUE(sJSRuntimeService, rv);
sJSRuntimeService->GetRuntime(&sScriptRuntime);
if (!sScriptRuntime) {
sJSRuntimeService->GetRuntime(&sJSScriptRuntime);
if (!sJSScriptRuntime) {
NS_RELEASE(sJSRuntimeService);
NS_WARNING("Unable to get JS runtime from JS runtime service");
return NS_ERROR_FAILURE;
@ -2558,20 +2545,20 @@ nsContentUtils::AddJSGCRoot(void* aPtr, const char* aName)
}
PRBool ok;
ok = ::JS_AddNamedRootRT(sScriptRuntime, aPtr, aName);
ok = ::JS_AddNamedRootRT(sJSScriptRuntime, aPtr, aName);
if (!ok) {
if (sScriptRootCount == 0) {
if (sJSScriptRootCount == 0) {
// We just got the runtime... Just null things out, since no
// one's expecting us to have a runtime yet
NS_RELEASE(sJSRuntimeService);
sScriptRuntime = nsnull;
sJSScriptRuntime = nsnull;
}
NS_WARNING("JS_AddNamedRootRT failed");
return NS_ERROR_OUT_OF_MEMORY;
}
// We now have one more root we added to the runtime
++sScriptRootCount;
++sJSScriptRootCount;
return NS_OK;
}
@ -2580,16 +2567,16 @@ nsContentUtils::AddJSGCRoot(void* aPtr, const char* aName)
nsresult
nsContentUtils::RemoveJSGCRoot(void* aPtr)
{
if (!sScriptRuntime) {
if (!sJSScriptRuntime) {
NS_NOTREACHED("Trying to remove a JS GC root when none were added");
return NS_ERROR_UNEXPECTED;
}
::JS_RemoveRootRT(sScriptRuntime, aPtr);
::JS_RemoveRootRT(sJSScriptRuntime, aPtr);
if (--sScriptRootCount == 0) {
if (--sJSScriptRootCount == 0) {
NS_RELEASE(sJSRuntimeService);
sScriptRuntime = nsnull;
sJSScriptRuntime = nsnull;
}
return NS_OK;
@ -3393,3 +3380,56 @@ nsContentUtils::DestroyAnonymousContent(nsCOMPtr<nsIContent>* aContent)
*aContent = nsnull;
}
}
/* static */
nsIDOMScriptObjectFactory*
nsContentUtils::GetDOMScriptObjectFactory()
{
if (!sDOMScriptObjectFactory) {
static NS_DEFINE_CID(kDOMScriptObjectFactoryCID,
NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
CallGetService(kDOMScriptObjectFactoryCID, &sDOMScriptObjectFactory);
}
return sDOMScriptObjectFactory;
}
/* static */
nsresult
nsContentUtils::HoldScriptObject(PRUint32 aLangID, void *aObject)
{
nsresult rv;
PRUint32 langIndex = NS_STID_INDEX(aLangID);
nsIScriptRuntime *runtime = sScriptRuntimes[langIndex];
if (!runtime) {
nsIDOMScriptObjectFactory *factory = GetDOMScriptObjectFactory();
NS_ENSURE_TRUE(factory, NS_ERROR_FAILURE);
rv = factory->GetScriptRuntimeByID(aLangID, &runtime);
NS_ENSURE_SUCCESS(rv, rv);
// This makes sScriptRuntimes hold a strong ref.
sScriptRuntimes[langIndex] = runtime;
}
rv = runtime->HoldScriptObject(aObject);
NS_ENSURE_SUCCESS(rv, rv);
++sScriptRootCount[langIndex];
return NS_OK;
}
/* static */
nsresult
nsContentUtils::DropScriptObject(PRUint32 aLangID, void *aObject)
{
PRUint32 langIndex = NS_STID_INDEX(aLangID);
nsresult rv = sScriptRuntimes[langIndex]->DropScriptObject(aObject);
if (--sScriptRootCount[langIndex] == 0) {
NS_RELEASE(sScriptRuntimes[langIndex]);
}
return rv;
}

View File

@ -817,11 +817,12 @@ nsScriptEventHandlerOwnerTearoff::CompileEventHandler(
if (attr) {
XUL_PROTOTYPE_ATTRIBUTE_METER(gNumCacheFills);
// take a copy of the event handler, and tell the language about it.
attr->mEventHandler = (void *)aHandler;
if (attr->mEventHandler) {
rv = aContext->HoldScriptObject(attr->mEventHandler);
if (aHandler) {
rv = nsContentUtils::HoldScriptObject(aContext->GetScriptTypeID(),
aHandler);
if (NS_FAILED(rv)) return rv;
}
attr->mEventHandler = (void *)aHandler;
}
return NS_OK;
@ -2474,7 +2475,7 @@ void
nsXULPrototypeAttribute::Finalize(PRUint32 aLangID)
{
if (mEventHandler) {
if (NS_FAILED(NS_DropScriptObject(aLangID, mEventHandler)))
if (NS_FAILED(nsContentUtils::DropScriptObject(aLangID, mEventHandler)))
NS_ERROR("Failed to drop script object");
mEventHandler = nsnull;
}
@ -2543,7 +2544,7 @@ nsXULPrototypeElement::Serialize(nsIObjectOutputStream* aStream,
rv |= aStream->Write32(child->mType);
nsXULPrototypeScript* script = NS_STATIC_CAST(nsXULPrototypeScript*, child);
rv |= aStream->Write32(script->mScriptObject.getScriptTypeID());
rv |= aStream->Write32(script->mScriptObject.mLangID);
rv |= aStream->Write8(script->mOutOfLine);
if (! script->mOutOfLine) {
@ -2553,7 +2554,7 @@ nsXULPrototypeElement::Serialize(nsIObjectOutputStream* aStream,
NS_GET_IID(nsIURI),
PR_TRUE);
if (script->mScriptObject) {
if (script->mScriptObject.mObject) {
// This may return NS_OK without muxing script->mSrcURI's
// data into the FastLoad file, in the case where that
// muxed document is already there (written by a prior
@ -2766,7 +2767,7 @@ nsXULPrototypeScript::nsXULPrototypeScript(PRUint32 aLangID, PRUint32 aLineNo, P
mOutOfLine(PR_TRUE),
mSrcLoadWaiters(nsnull),
mLangVersion(aVersion),
mScriptObject(aLangID, nsnull)
mScriptObject(aLangID)
{
NS_LOG_ADDREF(this, 1, ClassName(), ClassSize());
NS_ASSERTION(aLangID != nsIProgrammingLanguage::UNKNOWN,
@ -2784,10 +2785,11 @@ nsXULPrototypeScript::Serialize(nsIObjectOutputStream* aStream,
const nsCOMArray<nsINodeInfo> *aNodeInfos)
{
nsIScriptContext *context = aGlobal->GetScriptContext(
mScriptObject.getScriptTypeID());
NS_ASSERTION(!mSrcLoading || mSrcLoadWaiters != nsnull || !mScriptObject,
mScriptObject.mLangID);
NS_ASSERTION(!mSrcLoading || mSrcLoadWaiters != nsnull ||
!mScriptObject.mObject,
"script source still loading when serializing?!");
if (!mScriptObject)
if (!mScriptObject.mObject)
return NS_ERROR_FAILURE;
// Write basic prototype data
@ -2797,7 +2799,7 @@ nsXULPrototypeScript::Serialize(nsIObjectOutputStream* aStream,
rv = aStream->Write32(mLangVersion);
if (NS_FAILED(rv)) return rv;
// And delegate the writing to the nsIScriptContext
rv = context->Serialize(aStream, mScriptObject);
rv = context->Serialize(aStream, mScriptObject.mObject);
if (NS_FAILED(rv)) return rv;
return NS_OK;
@ -2878,7 +2880,8 @@ nsXULPrototypeScript::Deserialize(nsIObjectInputStream* aStream,
NS_TIMELINE_MARK_FUNCTION("chrome script deserialize");
nsresult rv;
NS_ASSERTION(!mSrcLoading || mSrcLoadWaiters != nsnull || !mScriptObject,
NS_ASSERTION(!mSrcLoading || mSrcLoadWaiters != nsnull ||
!mScriptObject.mObject,
"prototype script not well-initialized when deserializing?!");
// Read basic prototype data
@ -2886,7 +2889,7 @@ nsXULPrototypeScript::Deserialize(nsIObjectInputStream* aStream,
aStream->Read32(&mLangVersion);
nsIScriptContext *context = aGlobal->GetScriptContext(
mScriptObject.getScriptTypeID());
mScriptObject.mLangID);
NS_ASSERTION(context != nsnull, "Have no context for deserialization");
NS_ENSURE_TRUE(context, NS_ERROR_UNEXPECTED);
nsScriptObjectHolder newScriptObject(context);
@ -2895,7 +2898,7 @@ nsXULPrototypeScript::Deserialize(nsIObjectInputStream* aStream,
NS_WARNING("Language deseralization failed");
return rv;
}
mScriptObject = newScriptObject;
mScriptObject.set(newScriptObject);
return NS_OK;
}
@ -2946,7 +2949,7 @@ nsXULPrototypeScript::DeserializeOutOfLine(nsIObjectInputStream* aInput,
// ctor and not setting it until the scriptObject is set -
// code that pre-fetches these globals will then start
// asserting.)
if (mScriptObject.getScriptTypeID() != newLangID) {
if (mScriptObject.mLangID != newLangID) {
NS_ERROR("XUL cache gave different language?");
return NS_ERROR_UNEXPECTED;
}
@ -2955,7 +2958,7 @@ nsXULPrototypeScript::DeserializeOutOfLine(nsIObjectInputStream* aInput,
}
}
if (! mScriptObject) {
if (! mScriptObject.mObject) {
nsCOMPtr<nsIURI> oldURI;
if (mSrcURI) {
@ -3003,8 +3006,8 @@ nsXULPrototypeScript::DeserializeOutOfLine(nsIObjectInputStream* aInput,
mSrcURI->SchemeIs("chrome", &isChrome);
if (isChrome) {
cache->PutScript(mSrcURI,
mScriptObject.getScriptTypeID(),
mScriptObject);
mScriptObject.mLangID,
mScriptObject.mObject);
}
}
} else {
@ -3050,7 +3053,7 @@ nsXULPrototypeScript::Compile(const PRUnichar* aText,
if (! global)
return NS_ERROR_UNEXPECTED;
context = global->GetScriptContext(mScriptObject.getScriptTypeID());
context = global->GetScriptContext(mScriptObject.mLangID);
NS_ASSERTION(context != nsnull, "no context for script global");
if (! context)
return NS_ERROR_UNEXPECTED;
@ -3076,7 +3079,7 @@ nsXULPrototypeScript::Compile(const PRUnichar* aText,
if (NS_FAILED(rv))
return rv;
mScriptObject = newScriptObject;
mScriptObject.set(newScriptObject);
return rv;
}

View File

@ -352,7 +352,7 @@ public:
PRPackedBool mOutOfLine;
nsXULDocument* mSrcLoadWaiters; // [OWNER] but not COMPtr
PRUint32 mLangVersion;
nsScriptObjectHolder mScriptObject;
nsContentUtils::ScriptObjectHolder mScriptObject;
static void ReleaseGlobals()
{

View File

@ -324,7 +324,7 @@ XULContentSinkImpl::ContextStack::GetTopNodeScriptType(PRUint32 *aScriptType)
case nsXULPrototypeNode::eType_Script: {
nsXULPrototypeScript *parent = \
NS_REINTERPRET_CAST(nsXULPrototypeScript*, node);
*aScriptType = parent->mScriptObject.getScriptTypeID();
*aScriptType = parent->mScriptObject.mLangID;
break;
}
default: {
@ -782,7 +782,7 @@ XULContentSinkImpl::HandleEndElement(const PRUnichar *aName)
NS_STATIC_CAST(nsXULPrototypeScript*, node);
// If given a src= attribute, we must ignore script tag content.
if (! script->mSrcURI && ! script->mScriptObject) {
if (! script->mSrcURI && ! script->mScriptObject.mObject) {
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
script->mOutOfLine = PR_FALSE;

View File

@ -2916,7 +2916,7 @@ nsXULDocument::ResumeWalk()
if (NS_SUCCEEDED(rv) && blocked)
return NS_OK;
}
else if (scriptproto->mScriptObject) {
else if (scriptproto->mScriptObject.mObject) {
// An inline script
rv = ExecuteScript(scriptproto);
if (NS_FAILED(rv)) return rv;
@ -3198,7 +3198,7 @@ nsXULDocument::LoadScript(nsXULPrototypeScript* aScriptProto, PRBool* aBlock)
// Load a transcluded script
nsresult rv;
if (aScriptProto->mScriptObject) {
if (aScriptProto->mScriptObject.mObject) {
rv = ExecuteScript(aScriptProto);
// Ignore return value from execution, and don't block
@ -3221,14 +3221,14 @@ nsXULDocument::LoadScript(nsXULPrototypeScript* aScriptProto, PRBool* aBlock)
if (newScriptObject) {
// The script language for a proto must remain constant - we
// can't just change it for this unexpected language.
if (aScriptProto->mScriptObject.getScriptTypeID() != fetchedLang) {
if (aScriptProto->mScriptObject.mLangID != fetchedLang) {
NS_ERROR("XUL cache gave me an incorrect script language");
return NS_ERROR_UNEXPECTED;
}
aScriptProto->mScriptObject.set(newScriptObject);
}
if (aScriptProto->mScriptObject) {
if (aScriptProto->mScriptObject.mObject) {
rv = ExecuteScript(aScriptProto);
// Ignore return value from execution, and don't block
@ -3366,8 +3366,8 @@ nsXULDocument::OnStreamComplete(nsIStreamLoader* aLoader,
if (useXULCache && IsChromeURI(mDocumentURI)) {
gXULCache->PutScript(scriptProto->mSrcURI,
scriptProto->mScriptObject.getScriptTypeID(),
scriptProto->mScriptObject);
scriptProto->mScriptObject.mLangID,
scriptProto->mScriptObject.mObject);
}
if (mIsWritingFastLoad && mCurrentPrototype != mMasterPrototype) {
@ -3387,7 +3387,7 @@ nsXULDocument::OnStreamComplete(nsIStreamLoader* aLoader,
NS_ASSERTION(global != nsnull, "master prototype w/o global?!");
if (global) {
PRUint32 stid = scriptProto->mScriptObject.getScriptTypeID();
PRUint32 stid = scriptProto->mScriptObject.mLangID;
nsIScriptContext *scriptContext = \
global->GetScriptContext(stid);
NS_ASSERTION(scriptContext != nsnull,
@ -3419,7 +3419,7 @@ nsXULDocument::OnStreamComplete(nsIStreamLoader* aLoader,
doc->mNextSrcLoadWaiter = nsnull;
// Execute only if we loaded and compiled successfully, then resume
if (NS_SUCCEEDED(aStatus) && scriptProto->mScriptObject) {
if (NS_SUCCEEDED(aStatus) && scriptProto->mScriptObject.mObject) {
doc->ExecuteScript(scriptProto);
}
doc->ResumeWalk();
@ -3456,7 +3456,7 @@ nsXULDocument::ExecuteScript(nsXULPrototypeScript *aScript)
NS_PRECONDITION(aScript != nsnull, "null ptr");
NS_ENSURE_TRUE(aScript, NS_ERROR_NULL_POINTER);
NS_ENSURE_TRUE(mScriptGlobalObject, NS_ERROR_NOT_INITIALIZED);
PRUint32 stid = aScript->mScriptObject.getScriptTypeID();
PRUint32 stid = aScript->mScriptObject.mLangID;
nsresult rv;
rv = mScriptGlobalObject->EnsureScriptEnvironment(stid);
@ -3467,8 +3467,8 @@ nsXULDocument::ExecuteScript(nsXULPrototypeScript *aScript)
// failure getting a script context is fatal.
NS_ENSURE_TRUE(context != nsnull, NS_ERROR_UNEXPECTED);
if (aScript->mScriptObject)
rv = ExecuteScript(context, aScript->mScriptObject);
if (aScript->mScriptObject.mObject)
rv = ExecuteScript(context, aScript->mScriptObject.mObject);
else
rv = NS_ERROR_UNEXPECTED;
return rv;

View File

@ -39,48 +39,9 @@
#ifndef nsDOMScriptObjectHolder_h__
#define nsDOMScriptObjectHolder_h__
#include "nsIScriptRuntime.h"
#include "nsIScriptContext.h"
#include "nsIDOMScriptObjectFactory.h"
class nsIScriptContext;
// Drop a reference to a script object when all you have is the script
// language ID.
inline nsresult NS_DropScriptObject(PRUint32 aLangID, void *aThing)
{
nsresult rv;
nsCOMPtr<nsIScriptRuntime> scriptRT;
NS_DEFINE_CID(cid, NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
nsCOMPtr<nsIDOMScriptObjectFactory> factory = do_GetService(cid, &rv);
if (NS_SUCCEEDED(rv))
rv = factory->GetScriptRuntimeByID(aLangID, getter_AddRefs(scriptRT));
if (NS_SUCCEEDED(rv))
rv = scriptRT->DropScriptObject(aThing);
if (NS_FAILED(rv))
NS_ERROR("Failed to drop the script object");
return rv;
}
// Hold a reference to a script object when all you have is the script
// language ID, and you need to take a copy of the void script object.
// Must be matched by an NS_DropScriptObject
inline nsresult NS_HoldScriptObject(PRUint32 aLangID, void *aThing)
{
nsresult rv;
nsCOMPtr<nsIScriptRuntime> scriptRT;
NS_DEFINE_CID(cid, NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
nsCOMPtr<nsIDOMScriptObjectFactory> factory = do_GetService(cid, &rv);
if (NS_SUCCEEDED(rv))
rv = factory->GetScriptRuntimeByID(aLangID, getter_AddRefs(scriptRT));
if (NS_SUCCEEDED(rv))
rv = scriptRT->HoldScriptObject(aThing);
if (NS_FAILED(rv))
NS_ERROR("Failed to hold the script object");
return rv;
}
// A thin class used to help with script object memory management. No virtual
// functions and a fully inline implementation should keep the cost down.
// [Note that a fully inline implementation is necessary for use by other
@ -90,59 +51,23 @@ public:
// A constructor that will cause a reference to |ctx| to be stored in
// the object. Only use for short-lived object holders.
nsScriptObjectHolder(nsIScriptContext *ctx, void *aObject = nsnull) :
mObject(aObject), mContextOrLangID(NS_REINTERPRET_CAST(PtrBits, ctx)) {
mObject(aObject), mContext(ctx) {
NS_ASSERTION(ctx, "Must provide a valid context");
NS_ADDREF(ctx);
}
// A constructor that stores only the integer language ID - freeing the
// script object is slower in this case, but is safe for long-lived
// object holders.
nsScriptObjectHolder(PRUint32 aLangID, void *aObject = nsnull) :
mObject(aObject),
mContextOrLangID((aLangID << 1) | SOH_HAS_LANGID_BIT) {
NS_ASSERTION(aLangID != nsIProgrammingLanguage::UNKNOWN,
"Please supply a valid language ID");
}
// copy constructor
nsScriptObjectHolder(const nsScriptObjectHolder& other) :
mObject(other.mObject),
mContextOrLangID(other.mContextOrLangID)
mContext(other.mContext)
{
if (mContextOrLangID & SOH_HAS_LANGID_BIT) {
if (mObject) {
NS_HoldScriptObject(getScriptTypeIDFromBits(), mObject);
}
} else {
// New hold the script object and new reference on the script context.
nsIScriptContext *ctx = NS_REINTERPRET_CAST(nsIScriptContext *,
mContextOrLangID);
NS_ASSERTION(ctx, "Lost context pointer?");
NS_ADDREF(ctx);
if (mObject)
ctx->HoldScriptObject(mObject);
}
// New hold the script object and new reference on the script context.
if (mObject)
mContext->HoldScriptObject(mObject);
}
~nsScriptObjectHolder() {
// If we have a language ID, then we only need to NS_DropScriptObject if
// we are holding a script object.
// If we have a script context, we must always release our reference to it,
// even if we are not holding a script object.
if (mContextOrLangID & SOH_HAS_LANGID_BIT) {
if (mObject) {
NS_DropScriptObject(getScriptTypeIDFromBits(), mObject);
}
} else {
nsIScriptContext *ctx = NS_REINTERPRET_CAST(nsIScriptContext *,
mContextOrLangID);
NS_ASSERTION(ctx, "Lost context pointer?");
if (mObject) {
ctx->DropScriptObject(mObject);
}
NS_IF_RELEASE(ctx);
}
if (mObject)
mContext->DropScriptObject(mObject);
}
// misc operators
@ -157,19 +82,11 @@ public:
return mObject;
}
// Drop the script object - but *not* the nsIScriptContext nor the language
// ID.
// Drop the script object - but *not* the nsIScriptContext.
nsresult drop() {
nsresult rv = NS_OK;
if (mObject) {
if (mContextOrLangID & SOH_HAS_LANGID_BIT) {
rv = NS_DropScriptObject(getScriptTypeIDFromBits(), mObject);
} else {
nsIScriptContext *ctx = NS_REINTERPRET_CAST(nsIScriptContext *,
mContextOrLangID);
NS_ASSERTION(ctx, "Lost ctx pointer!");
rv = ctx->DropScriptObject(mObject);
}
rv = mContext->DropScriptObject(mObject);
mObject = nsnull;
}
return rv;
@ -181,13 +98,7 @@ public:
if (NS_FAILED(rv))
return rv;
if (object) {
if (mContextOrLangID & SOH_HAS_LANGID_BIT) {
rv = NS_HoldScriptObject(getScriptTypeIDFromBits(), object);
} else {
nsIScriptContext *ctx = NS_REINTERPRET_CAST(nsIScriptContext *,
mContextOrLangID);
rv = ctx->HoldScriptObject(object);
}
rv = mContext->HoldScriptObject(object);
// don't store the pointer if we failed to lock it.
if (NS_SUCCEEDED(rv)) {
mObject = object;
@ -205,27 +116,11 @@ public:
}
// Get the language ID.
PRUint32 getScriptTypeID() const {
if (mContextOrLangID & SOH_HAS_LANGID_BIT) {
return getScriptTypeIDFromBits();
}
nsIScriptContext *ctx = NS_REINTERPRET_CAST(nsIScriptContext *,
mContextOrLangID);
NS_ASSERTION(ctx, "How did I lose my pointer?");
return ctx->GetScriptTypeID();
return mContext->GetScriptTypeID();
}
protected:
PRUint32 getScriptTypeIDFromBits() const {
NS_ASSERTION(mContextOrLangID & SOH_HAS_LANGID_BIT, "Not in the bits!");
return (mContextOrLangID & ~SOH_HAS_LANGID_BIT) >> 1;
}
void *mObject;
// We store either an nsIScriptContext* if this bit is clear,
// else the language ID (specifically, ((lang_id << 1) | SOH_HAS_LANGID_BIT)
// when set.
typedef PRWord PtrBits;
enum { SOH_HAS_LANGID_BIT = 0x1 };
PtrBits mContextOrLangID;
nsCOMPtr<nsIScriptContext> mContext;
};
#endif // nsDOMScriptObjectHolder_h__