Bug 683802 - Coalesce type-specific cleanup indicators. r=mrbkap
authorBobby Holley <bobbyholley@gmail.com>
Sun, 25 Sep 2011 15:38:01 +0100
changeset 78845 b254267d7599d204186505821b16fa565bad159c
parent 78844 8b2c81d7bd77495382c8e18ca0be321c259dc97e
child 78846 04dc934f61d5b15d53af6f95a9f2430f21de0ed7
push id78
push userclegnitto@mozilla.com
push dateFri, 16 Dec 2011 17:32:24 +0000
treeherdermozilla-release@79d24e644fdd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmrbkap
bugs683802
milestone9.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 683802 - Coalesce type-specific cleanup indicators. r=mrbkap
content/xslt/src/xpath/txXPCOMExtensionFunction.cpp
js/src/xpconnect/src/xpcvariant.cpp
js/src/xpconnect/src/xpcwrappednative.cpp
xpcom/reflect/xptcall/public/xptcall.h
--- a/content/xslt/src/xpath/txXPCOMExtensionFunction.cpp
+++ b/content/xslt/src/xpath/txXPCOMExtensionFunction.cpp
@@ -345,21 +345,26 @@ private:
     PRUint8 mCount;
 };
 
 txParamArrayHolder::~txParamArrayHolder()
 {
     PRUint8 i;
     for (i = 0; i < mCount; ++i) {
         nsXPTCVariant &variant = mArray[i];
-        if (variant.IsValInterface()) {
-            static_cast<nsISupports*>(variant.val.p)->Release();
-        }
-        else if (variant.IsValDOMString()) {
-            delete (nsAString*)variant.val.p;
+        if (variant.DoesValNeedCleanup()) {
+            if (variant.type.TagPart() == nsXPTType::T_DOMSTRING)
+                delete (nsAString*)variant.val.p;
+            else {
+                NS_ABORT_IF_FALSE(variant.type.TagPart() == nsXPTType::T_INTERFACE ||
+                                  variant.type.TagPart() == nsXPTType::T_INTERFACE_IS,
+                                  "We only support cleanup of strings and interfaces "
+                                  "here, and this looks like neither!");
+                static_cast<nsISupports*>(variant.val.p)->Release();
+            }
         }
     }
 }
 
 PRBool
 txParamArrayHolder::Init(PRUint8 aCount)
 {
     mCount = aCount;
@@ -414,17 +419,17 @@ txXPCOMExtensionFunctionCall::evaluate(t
         // Create context wrapper.
         context = new txFunctionEvaluationContext(aContext, mState);
         if (!context) {
             return NS_ERROR_OUT_OF_MEMORY;
         }
 
         nsXPTCVariant &invokeParam = invokeParams[0];
         invokeParam.type = paramInfo.GetType();
-        invokeParam.SetValIsInterface();
+        invokeParam.SetValNeedsCleanup();
         NS_ADDREF((txIFunctionEvaluationContext*&)invokeParam.val.p = context);
 
         // Skip first argument, since it's the context.
         paramStart = 1;
     }
     else {
         context = nsnull;
     }
@@ -462,17 +467,17 @@ txXPCOMExtensionFunctionCall::evaluate(t
                 if (!adaptor) {
                     return NS_ERROR_OUT_OF_MEMORY;
                 }
 
                 nsCOMPtr<txINodeSet> nodeSet = adaptor;
                 rv = adaptor->Init();
                 NS_ENSURE_SUCCESS(rv, rv);
 
-                invokeParam.SetValIsInterface();
+                invokeParam.SetValNeedsCleanup();
                 nodeSet.swap((txINodeSet*&)invokeParam.val.p);
                 break;
             }
             case eBOOLEAN:
             {
                 rv = expr->evaluateToBool(aContext, invokeParam.val.b);
                 NS_ENSURE_SUCCESS(rv, rv);
 
@@ -492,33 +497,33 @@ txXPCOMExtensionFunctionCall::evaluate(t
                 nsString *value = new nsString();
                 if (!value) {
                     return NS_ERROR_OUT_OF_MEMORY;
                 }
 
                 rv = expr->evaluateToString(aContext, *value);
                 NS_ENSURE_SUCCESS(rv, rv);
 
-                invokeParam.SetValIsDOMString();
+                invokeParam.SetValNeedsCleanup();
                 invokeParam.val.p = value;
                 break;
             }
             case eOBJECT:
             {
               nsRefPtr<txAExprResult> exprRes;
               rv = expr->evaluate(aContext, getter_AddRefs(exprRes));
               NS_ENSURE_SUCCESS(rv, rv);
 
               nsCOMPtr<txIXPathObject> adaptor =
                 new txXPathObjectAdaptor(exprRes);
               if (!adaptor) {
                   return NS_ERROR_OUT_OF_MEMORY;
               }
 
-              invokeParam.SetValIsInterface();
+              invokeParam.SetValNeedsCleanup();
               adaptor.swap((txIXPathObject*&)invokeParam.val.p);
               break;
             }
             case eCONTEXT:
             case eUNKNOWN:
             {
                 // We only support passing the context as the *first* argument.
                 return NS_ERROR_FAILURE;
@@ -535,23 +540,23 @@ txXPCOMExtensionFunctionCall::evaluate(t
     nsXPTCVariant &returnParam = invokeParams[inArgs];
     returnParam.type = returnInfo.GetType();
     if (returnType == eSTRING) {
         nsString *value = new nsString();
         if (!value) {
             return NS_ERROR_FAILURE;
         }
 
-        returnParam.SetValIsDOMString();
+        returnParam.SetValNeedsCleanup();
         returnParam.val.p = value;
     }
     else {
         returnParam.SetIndirect();
         if (returnType == eNODESET || returnType == eOBJECT) {
-            returnParam.SetValIsInterface();
+            returnParam.SetValNeedsCleanup();
         }
     }
 
     rv = NS_InvokeByIndex(mHelper, mMethodIndex, paramCount, invokeParams);
 
     // In case someone is holding on to the txFunctionEvaluationContext which
     // could thus stay alive longer than this function.
     if (context) {
--- a/js/src/xpconnect/src/xpcvariant.cpp
+++ b/js/src/xpconnect/src/xpcvariant.cpp
@@ -550,51 +550,51 @@ XPCVariant::VariantDataToJS(XPCLazyCallC
                 return JS_FALSE;
             xpctvar.type = (uint8)(TD_UTF8STRING | XPT_TDP_POINTER);
             xpctvar.val.p = &utf8String;
             break;       
         case nsIDataType::VTYPE_CHAR_STR:       
             if(NS_FAILED(variant->GetAsString((char**)&xpctvar.val.p)))
                 return JS_FALSE;
             xpctvar.type = (uint8)(TD_PSTRING | XPT_TDP_POINTER);
-            xpctvar.SetValIsAllocated();
+            xpctvar.SetValNeedsCleanup();
             break;
         case nsIDataType::VTYPE_STRING_SIZE_IS:
             if(NS_FAILED(variant->GetAsStringWithSize(&size, 
                                                       (char**)&xpctvar.val.p)))
                 return JS_FALSE;
             xpctvar.type = (uint8)(TD_PSTRING_SIZE_IS | XPT_TDP_POINTER);
-            xpctvar.SetValIsAllocated();
+            xpctvar.SetValNeedsCleanup();
             break;
         case nsIDataType::VTYPE_WCHAR_STR:        
             if(NS_FAILED(variant->GetAsWString((PRUnichar**)&xpctvar.val.p)))
                 return JS_FALSE;
             xpctvar.type = (uint8)(TD_PWSTRING | XPT_TDP_POINTER);
-            xpctvar.SetValIsAllocated();
+            xpctvar.SetValNeedsCleanup();
             break;
         case nsIDataType::VTYPE_WSTRING_SIZE_IS:        
             if(NS_FAILED(variant->GetAsWStringWithSize(&size, 
                                                       (PRUnichar**)&xpctvar.val.p)))
                 return JS_FALSE;
             xpctvar.type = (uint8)(TD_PWSTRING_SIZE_IS | XPT_TDP_POINTER);
-            xpctvar.SetValIsAllocated();
+            xpctvar.SetValNeedsCleanup();
             break;
         case nsIDataType::VTYPE_INTERFACE:        
         case nsIDataType::VTYPE_INTERFACE_IS:        
         {
             nsID* piid;
             if(NS_FAILED(variant->GetAsInterface(&piid, &xpctvar.val.p)))
                 return JS_FALSE;
 
             iid = *piid;
             nsMemory::Free((char*)piid);
 
             xpctvar.type = (uint8)(TD_INTERFACE_IS_TYPE | XPT_TDP_POINTER);
             if(xpctvar.val.p)
-                xpctvar.SetValIsInterface();
+                xpctvar.SetValNeedsCleanup();
             break;
         }
         case nsIDataType::VTYPE_ARRAY:
         {
             nsDiscriminatedUnion du;
             nsVariant::Initialize(&du);
             nsresult rv;
 
@@ -705,20 +705,25 @@ VARIANT_DONE:
     else
     {
         success = XPCConvert::NativeData2JS(lccx, pJSVal,
                                             (const void*)&xpctvar.val,
                                             xpctvar.type,
                                             &iid, pErr);
     }
 
-    if(xpctvar.IsValAllocated())
-        nsMemory::Free((char*)xpctvar.val.p);
-    else if(xpctvar.IsValInterface())
-        ((nsISupports*)xpctvar.val.p)->Release();
+    // We may have done something in the above code that requires cleanup.
+    if (xpctvar.DoesValNeedCleanup())
+    {
+        if (type == nsIDataType::VTYPE_INTERFACE ||
+            type == nsIDataType::VTYPE_INTERFACE_IS)
+            ((nsISupports*)xpctvar.val.p)->Release();
+        else
+            nsMemory::Free((char*)xpctvar.val.p);
+    }
 
     return success;
 }
 
 /***************************************************************************/
 /***************************************************************************/
 // XXX These default implementations need to be improved to allow for
 // some more interesting conversions.
--- a/js/src/xpconnect/src/xpcwrappednative.cpp
+++ b/js/src/xpconnect/src/xpcwrappednative.cpp
@@ -2235,16 +2235,18 @@ class CallMethodHelper
     }
 
     JS_ALWAYS_INLINE JSBool InitializeDispatchParams();
 
     JS_ALWAYS_INLINE JSBool ConvertIndependentParams(JSBool* foundDependentParam);
     JS_ALWAYS_INLINE JSBool ConvertIndependentParam(uint8 i);
     JS_ALWAYS_INLINE JSBool ConvertDependentParams();
 
+    JS_ALWAYS_INLINE void CleanupParam(nsXPTCMiniVariant& param, nsXPTType& type);
+
     JS_ALWAYS_INLINE JSBool HandleDipperParam(nsXPTCVariant* dp,
                                               const nsXPTParamInfo& paramInfo);
 
     JS_ALWAYS_INLINE nsresult Invoke();
 
 public:
 
     CallMethodHelper(XPCCallContext& ccx)
@@ -2386,79 +2388,59 @@ CallMethodHelper::Call()
 CallMethodHelper::~CallMethodHelper()
 {
     uint8 paramCount = mMethodInfo->GetParamCount();
     if (mDispatchParams.Length())
     {
         for(uint8 i = 0; i < paramCount; i++)
         {
             nsXPTCVariant* dp = GetDispatchParam(i);
-
-            if(dp->IsValArray())
+            const nsXPTParamInfo& paramInfo = mMethodInfo->GetParam(i);
+
+            if(paramInfo.GetType().IsArray())
             {
                 void* p = dp->val.p;
                 if(!p)
                     continue;
 
-                // going to have to cleanup the array and perhaps its contents
-                if(dp->IsValAllocated() || dp->IsValInterface())
+                // Clean up the array contents if necessary.
+                if(dp->DoesValNeedCleanup())
                 {
-                    // we need to figure out how many elements are present.
+                    // We need some basic information to properly destroy the array.
                     JSUint32 array_count;
-
-                    if(!GetArraySizeFromParam(i, &array_count))
+                    nsXPTType datum_type;
+                    if(!GetArraySizeFromParam(i, &array_count) ||
+                       !NS_SUCCEEDED(mIFaceInfo->GetTypeForParam(mVTableIndex,
+                                                                 &paramInfo,
+                                                                 1, &datum_type)))
                     {
-                        NS_ERROR("failed to get array length, we'll leak here");
+                        // XXXbholley - I'm not convinced that the above calls will
+                        // ever fail.
+                        NS_ERROR("failed to get array information, we'll leak here");
                         continue;
                     }
-                    if(dp->IsValAllocated())
+
+                    // Loop over the array contents. For each one, we create a
+                    // dummy 'val' and pass it to the cleanup helper.
+                    for(JSUint32 k = 0; k < array_count; k++)
                     {
-                        void** a = (void**)p;
-                        for(JSUint32 k = 0; k < array_count; k++)
-                        {
-                            void* o = a[k];
-                            if(o) nsMemory::Free(o);
-                        }
-                    }
-                    else // if(dp->IsValInterface())
-                    {
-                        nsISupports** a = (nsISupports**)p;
-                        for(JSUint32 k = 0; k < array_count; k++)
-                        {
-                            nsISupports* o = a[k];
-                            NS_IF_RELEASE(o);
-                        }
+                        nsXPTCMiniVariant v;
+                        v.val.p = static_cast<void**>(p)[k];
+                        CleanupParam(v, datum_type);
                     }
                 }
+
                 // always free the array itself
                 nsMemory::Free(p);
             }
             else
             {
-                if(dp->IsValJSRoot())
-                {
-                    NS_ASSERTION(!dp->IsValAllocated() && !dp->IsValInterface(),
-                                 "jsvals are their own class of values");
-                    JS_RemoveValueRoot(mCallContext, (jsval*)dp->ptr);
-                    continue;
-                }
-
-                void* p = dp->val.p;
-                if(!p)
-                    continue;
-                if(dp->IsValAllocated())
-                    nsMemory::Free(p);
-                else if(dp->IsValInterface())
-                    ((nsISupports*)p)->Release();
-                else if(dp->IsValDOMString())
-                    mCallContext.DeleteString((nsAString*)p);
-                else if(dp->IsValUTF8String())
-                    delete (nsCString*) p;
-                else if(dp->IsValCString())
-                    delete (nsCString*) p;
+                // Clean up single parameters (if requested).
+                if (dp->DoesValNeedCleanup())
+                    CleanupParam(*dp, dp->type);
             }
         }
     }
 
 }
 
 JSBool
 CallMethodHelper::GetArrayInfoFromParam(uint8 paramIndex, SizeMode mode,
@@ -2831,78 +2813,78 @@ CallMethodHelper::ConvertIndependentPara
         return HandleDipperParam(dp, paramInfo);
 
     // Specify the correct storage/calling semantics.
     if(paramInfo.IsIndirect())
         dp->SetIndirect();
 
     if(type_tag == nsXPTType::T_INTERFACE)
     {
-        dp->SetValIsInterface();
+        dp->SetValNeedsCleanup();
     }
 
     jsval src;
 
     if (!GetOutParamSource(i, &src))
         return JS_FALSE;
 
     // The JSVal proper is always stored within the 'val' union and passed
     // indirectly, regardless of in/out-ness.
     if(type_tag == nsXPTType::T_JSVAL)
     {
         // Root the value.
         dp->val.j = JSVAL_VOID;
         if (!JS_AddValueRoot(mCallContext, &dp->val.j))
             return JS_FALSE;
-        dp->SetValIsJSRoot();
+        dp->SetValNeedsCleanup();
     }
 
     if(paramInfo.IsOut())
     {
         if(type.IsPointer() &&
            type_tag != nsXPTType::T_INTERFACE &&
            !paramInfo.IsShared())
         {
             useAllocator = JS_TRUE;
-            dp->SetValIsAllocated();
+            dp->SetValNeedsCleanup();
         }
 
         if(!paramInfo.IsIn())
             return JS_TRUE;
     }
     else
     {
         if(type.IsPointer())
         {
             switch(type_tag)
             {
             case nsXPTType::T_IID:
-                dp->SetValIsAllocated();
+                dp->SetValNeedsCleanup();
                 useAllocator = JS_TRUE;
                 break;
             case nsXPTType::T_CHAR_STR:
-                dp->SetValIsAllocated();
+                dp->SetValNeedsCleanup();
                 useAllocator = JS_TRUE;
                 break;
             case nsXPTType::T_ASTRING:
                 // Fall through to the T_DOMSTRING case
 
             case nsXPTType::T_DOMSTRING:
 
                 // Is an 'in' DOMString. Set 'useAllocator' to indicate
                 // that JSData2Native should allocate a new
                 // nsAString.
-                dp->SetValIsDOMString();
+                dp->SetValNeedsCleanup();
                 useAllocator = JS_TRUE;
                 break;
 
             case nsXPTType::T_UTF8STRING:
                 // Fall through to the C string case for now...
             case nsXPTType::T_CSTRING:
-                dp->SetValIsCString();
+                dp->SetValNeedsCleanup();
                 useAllocator = JS_TRUE;
                 break;
             }
         }
 
         // Do this *after* the above because in the case where we have a
         // "T_DOMSTRING && IsDipper()" then arg might be null since this
         // is really an 'out' param masquerading as an 'in' param.
@@ -2963,46 +2945,44 @@ CallMethodHelper::ConvertDependentParams
         dp->type = type;
 
         // Specify the correct storage/calling semantics.
         if(paramInfo.IsIndirect())
             dp->SetIndirect();
 
         if(isArray)
         {
-            dp->SetValIsArray();
-
             if(NS_FAILED(mIFaceInfo->GetTypeForParam(mVTableIndex, &paramInfo, 1,
                                                      &datum_type)))
             {
                 Throw(NS_ERROR_XPC_CANT_GET_ARRAY_INFO, mCallContext);
                 return JS_FALSE;
             }
         }
         else
             datum_type = type;
 
         if(datum_type.IsInterfacePointer())
         {
-            dp->SetValIsInterface();
+            dp->SetValNeedsCleanup();
         }
 
         jsval src;
 
         if (!GetOutParamSource(i, &src))
             return JS_FALSE;
 
         if(paramInfo.IsOut())
         {
             if(datum_type.IsPointer() &&
                !datum_type.IsInterfacePointer() &&
                (isArray || !paramInfo.IsShared()))
             {
                 useAllocator = JS_TRUE;
-                dp->SetValIsAllocated();
+                dp->SetValNeedsCleanup();
             }
 
             if(!paramInfo.IsIn())
                 continue;
         }
         else
         {
             NS_ASSERTION(i < mArgc || paramInfo.IsOptional(),
@@ -3010,17 +2990,17 @@ CallMethodHelper::ConvertDependentParams
             src = i < mArgc ? mArgv[i] : JSVAL_NULL;
 
             if((datum_type.IsPointer() &&
                 (datum_type.TagPart() == nsXPTType::T_IID ||
                  datum_type.TagPart() == nsXPTType::T_PSTRING_SIZE_IS)) ||
                (isArray && datum_type.TagPart() == nsXPTType::T_CHAR_STR))
             {
                 useAllocator = JS_TRUE;
-                dp->SetValIsAllocated();
+                dp->SetValNeedsCleanup();
             }
         }
 
         nsID param_iid;
         if(datum_type.IsInterfacePointer() &&
            !GetInterfaceTypeFromParam(i, datum_type, &param_iid))
             return JS_FALSE;
 
@@ -3070,16 +3050,55 @@ CallMethodHelper::ConvertDependentParams
                 return JS_FALSE;
             }
         }
     }
 
     return JS_TRUE;
 }
 
+// Performs all necessary teardown on a parameter after method invocation.
+//
+// This method should only be called if the value in question was flagged
+// for cleanup (ie, if dp->DoesValNeedCleanup()).
+void
+CallMethodHelper::CleanupParam(nsXPTCMiniVariant& param, nsXPTType& type)
+{
+    // We handle array elements, but not the arrays themselves.
+    NS_ABORT_IF_FALSE(type.TagPart() != nsXPTType::T_ARRAY, "Can't handle arrays.");
+
+    // Pointers may sometimes be null even if cleanup was requested. Combine
+    // the null checking for all the different types into one check here.
+    if (type.TagPart() != nsXPTType::T_JSVAL && param.val.p == nsnull)
+        return;
+
+    switch(type.TagPart())
+    {
+        case nsXPTType::T_JSVAL:
+            JS_RemoveValueRoot(mCallContext, (jsval*)&param.val);
+            break;
+        case nsXPTType::T_INTERFACE:
+        case nsXPTType::T_INTERFACE_IS:
+            ((nsISupports*)param.val.p)->Release();
+            break;
+        case nsXPTType::T_ASTRING:
+        case nsXPTType::T_DOMSTRING:
+            mCallContext.DeleteString((nsAString*)param.val.p);
+            break;
+        case nsXPTType::T_UTF8STRING:
+        case nsXPTType::T_CSTRING:
+            delete (nsCString*) param.val.p;
+            break;
+        default:
+            NS_ABORT_IF_FALSE(type.IsPointer(), "Cleanup requested on unexpected type.");
+            nsMemory::Free(param.val.p);
+            break;
+    }
+}
+
 // Handle parameters with dipper types.
 //
 // Dipper types are one of the more inscrutable aspects of xpidl. In a
 // nutshell, dippers are empty container objects, created and passed by
 // the caller, and filled by the callee. The callee receives a
 // fully-formed object, and thus does not have to construct anything. But
 // the object is functionally empty, and the callee is responsible for
 // putting something useful inside of it.
@@ -3112,33 +3131,30 @@ CallMethodHelper::HandleDipperParam(nsXP
                       type_tag == nsXPTType::T_DOMSTRING ||
                       type_tag == nsXPTType::T_UTF8STRING ||
                       type_tag == nsXPTType::T_CSTRING,
                       "Unexpected dipper type!");
 
     // ASTRING and DOMSTRING are very similar, and both use nsAutoString.
     // UTF8_STRING and CSTRING are also quite similar, and both use nsCString.
     if(type_tag == nsXPTType::T_ASTRING || type_tag == nsXPTType::T_DOMSTRING)
-    {
-        dp->SetValIsDOMString();
         dp->val.p = new nsAutoString();
-    }
     else
-    {
-        dp->SetValIsCString();
         dp->val.p = new nsCString();
-    }
 
     // Check for OOM, in either case.
     if(!dp->val.p)
     {
         JS_ReportOutOfMemory(mCallContext);
         return JS_FALSE;
     }
 
+    // We allocated, so we need to deallocate after the method call completes.
+    dp->SetValNeedsCleanup();
+
     return JS_TRUE;
 }
 
 nsresult
 CallMethodHelper::Invoke()
 {
     PRUint32 argc = mDispatchParams.Length();
     nsXPTCVariant* argv = mDispatchParams.Elements();
--- a/xpcom/reflect/xptcall/public/xptcall.h
+++ b/xpcom/reflect/xptcall/public/xptcall.h
@@ -109,43 +109,31 @@ struct nsXPTCVariant : public nsXPTCMini
         // explicitly with SetIndirect() and IsIndirect().
         //
         // Since ptr always points to &val, the semantics of this flag are kind of
         // dumb, since the ptr field is unnecessary. But changing them would
         // require changing dozens of assembly files, so they're likely to stay
         // the way they are.
         PTR_IS_DATA    = 0x1,
 
-        VAL_IS_ALLOCD  = 0x2,  // val.p holds alloc'd ptr that must be freed
-        VAL_IS_IFACE   = 0x4,  // val.p holds interface ptr that must be released
-        VAL_IS_ARRAY   = 0x8,  // val.p holds a pointer to an array needing cleanup
-        VAL_IS_DOMSTR  = 0x10, // val.p holds a pointer to domstring needing cleanup
-        VAL_IS_UTF8STR = 0x20, // val.p holds a pointer to utf8string needing cleanup
-        VAL_IS_CSTR    = 0x40, // val.p holds a pointer to cstring needing cleanup
-        VAL_IS_JSROOT  = 0x80  // val.p holds a pointer to a jsval that must be unrooted
+        // Indicates that the value we hold requires some sort of cleanup (memory
+        // deallocation, interface release, jsval unrooting, etc). The precise
+        // cleanup that is performed depends on the 'type' field above.
+        // If the value is an array, this flag specifies whether the elements
+        // within the array require cleanup (we always clean up the array itself,
+        // so this flag would be redundant for that purpose).
+        VAL_NEEDS_CLEANUP = 0x2
     };
 
     void ClearFlags()         {flags = 0;}
     void SetIndirect()        {ptr = &val; flags |= PTR_IS_DATA;}
-    void SetValIsAllocated()  {flags |= VAL_IS_ALLOCD;}
-    void SetValIsInterface()  {flags |= VAL_IS_IFACE;}
-    void SetValIsArray()      {flags |= VAL_IS_ARRAY;}
-    void SetValIsDOMString()  {flags |= VAL_IS_DOMSTR;}
-    void SetValIsUTF8String() {flags |= VAL_IS_UTF8STR;}
-    void SetValIsCString()    {flags |= VAL_IS_CSTR;}
-    void SetValIsJSRoot()     {flags |= VAL_IS_JSROOT;}
+    void SetValNeedsCleanup() {flags |= VAL_NEEDS_CLEANUP;}
 
-    PRBool IsIndirect()      const  {return 0 != (flags & PTR_IS_DATA);}
-    PRBool IsValAllocated()  const  {return 0 != (flags & VAL_IS_ALLOCD);}
-    PRBool IsValInterface()  const  {return 0 != (flags & VAL_IS_IFACE);}
-    PRBool IsValArray()      const  {return 0 != (flags & VAL_IS_ARRAY);}
-    PRBool IsValDOMString()  const  {return 0 != (flags & VAL_IS_DOMSTR);}
-    PRBool IsValUTF8String() const  {return 0 != (flags & VAL_IS_UTF8STR);}
-    PRBool IsValCString()    const  {return 0 != (flags & VAL_IS_CSTR);}    
-    PRBool IsValJSRoot()     const  {return 0 != (flags & VAL_IS_JSROOT);}
+    PRBool IsIndirect()         const  {return 0 != (flags & PTR_IS_DATA);}
+    PRBool DoesValNeedCleanup() const  {return 0 != (flags & VAL_NEEDS_CLEANUP);}
 
     // Internal use only. Use IsIndirect() instead.
     PRBool IsPtrData()       const  {return 0 != (flags & PTR_IS_DATA);}
 
     void Init(const nsXPTCMiniVariant& mv, const nsXPTType& t, PRUint8 f)
     {
         type = t;
         flags = f;