Bug 683802 - Factor dipper handling out into a helper method. r=mrbkap
authorBobby Holley <bobbyholley@gmail.com>
Sun, 25 Sep 2011 15:38:00 +0100
changeset 78840 0ce5751acd70f120dc4300b95c9e4a5842e912c0
parent 78839 fc259b0fa088434e9b924e5d40c48ab018c0649f
child 78841 e4248ea9a71455d8b210e91eda0c44cb289f863f
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 - Factor dipper handling out into a helper method. r=mrbkap
js/src/xpconnect/src/xpcwrappednative.cpp
--- a/js/src/xpconnect/src/xpcwrappednative.cpp
+++ b/js/src/xpconnect/src/xpcwrappednative.cpp
@@ -2235,16 +2235,19 @@ 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 JSBool HandleDipperParam(nsXPTCVariant* dp,
+                                              const nsXPTParamInfo& paramInfo);
+
     JS_ALWAYS_INLINE nsresult Invoke();
 
 public:
 
     CallMethodHelper(XPCCallContext& ccx)
         : mCallContext(ccx)
         , mIFaceInfo(ccx.GetInterface()->GetInterfaceInfo())
         , mMethodInfo(nsnull)
@@ -2818,16 +2821,20 @@ CallMethodHelper::ConvertIndependentPara
 {
     JSBool useAllocator = JS_FALSE;
     const nsXPTParamInfo& paramInfo = mMethodInfo->GetParam(i);
     const nsXPTType& type = paramInfo.GetType();
     uint8 type_tag = type.TagPart();
     nsXPTCVariant* dp = GetDispatchParam(i);
     dp->type = type;
 
+    // Handle dipper types separately.
+    if(paramInfo.IsDipper())
+        return HandleDipperParam(dp, paramInfo);
+
     if(type_tag == nsXPTType::T_INTERFACE)
     {
         dp->SetValIsInterface();
     }
 
     jsval src;
 
     if (!GetOutParamSource(i, &src))
@@ -2873,55 +2880,28 @@ CallMethodHelper::ConvertIndependentPara
             case nsXPTType::T_CHAR_STR:
                 dp->SetValIsAllocated();
                 useAllocator = JS_TRUE;
                 break;
             case nsXPTType::T_ASTRING:
                 // Fall through to the T_DOMSTRING case
 
             case nsXPTType::T_DOMSTRING:
-                if(paramInfo.IsDipper())
-                {
-                    // Is an 'out' DOMString. Make a new nsAString
-                    // now and then continue in order to skip the call to
-                    // JSData2Native
-
-                    dp->SetValIsDOMString();
-                    if(!(dp->val.p = new nsAutoString()))
-                    {
-                        JS_ReportOutOfMemory(mCallContext);
-                        return JS_FALSE;
-                    }
-                    return JS_TRUE;
-                }
-                // else...
 
                 // Is an 'in' DOMString. Set 'useAllocator' to indicate
                 // that JSData2Native should allocate a new
                 // nsAString.
                 dp->SetValIsDOMString();
                 useAllocator = JS_TRUE;
                 break;
 
             case nsXPTType::T_UTF8STRING:
                 // Fall through to the C string case for now...
             case nsXPTType::T_CSTRING:
                 dp->SetValIsCString();
-                if(paramInfo.IsDipper())
-                {
-                    // Is an 'out' CString.
-                    if(!(dp->val.p = new nsCString()))
-                    {
-                        JS_ReportOutOfMemory(mCallContext);
-                        return JS_FALSE;
-                    }
-                    return JS_TRUE;
-                }
-                // else ...
-                // Is an 'in' CString.
                 useAllocator = JS_TRUE;
                 break;
             }
         }
         else {
             if(type_tag == nsXPTType::T_JSVAL) {
                 dp->SetValIsAllocated();
                 useAllocator = JS_TRUE;
@@ -3094,16 +3074,78 @@ CallMethodHelper::ConvertDependentParams
                 return JS_FALSE;
             }
         }
     }
 
     return JS_TRUE;
 }
 
+// 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.
+//
+// XPIDL decides which types to make dippers. The list of these types
+// is given in the isDipperType() function in typelib.py, and is currently
+// limited to 4 string types.
+//
+// When a dipper type is declared as an 'out' parameter, xpidl internally
+// converts it to an 'in', and sets the XPT_PD_DIPPER flag on it. For this
+// reason, dipper types are sometimes referred to as 'out parameters
+// masquerading as in'. The burden of maintaining this illusion falls mostly
+// on XPConnect - we create the empty containers, and harvest the results
+// after the call.
+//
+// This method creates these empty containers.
+JSBool
+CallMethodHelper::HandleDipperParam(nsXPTCVariant* dp,
+                                    const nsXPTParamInfo& paramInfo)
+{
+    // Get something we can make comparisons with.
+    uint8 type_tag = paramInfo.GetType().TagPart();
+
+    // Dippers always have the 'in' and 'dipper' flags set. Never 'out'.
+    NS_ABORT_IF_FALSE(!paramInfo.IsOut(), "Dipper has unexpected flags.");
+
+    // xpidl.h specifies that dipper types will be used in exactly four
+    // cases, all strings. Verify that here.
+    NS_ABORT_IF_FALSE(type_tag == nsXPTType::T_ASTRING ||
+                      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;
+    }
+
+    return JS_TRUE;
+}
+
 nsresult
 CallMethodHelper::Invoke()
 {
     PRUint32 argc = mDispatchParams.Length();
     nsXPTCVariant* argv = mDispatchParams.Elements();
 
     if(XPCPerThreadData::IsMainThread(mCallContext))
         return NS_InvokeByIndex(mCallee, mVTableIndex, argc, argv);