Index: trunk/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/ipcDConnectService.cpp
===================================================================
--- trunk/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/ipcDConnectService.cpp	(revision 6980)
+++ trunk/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/ipcDConnectService.cpp	(revision 6999)
@@ -88,13 +88,15 @@
 
 //
-// +--------------------------------+
-// | opcode : 1 byte                |
-// +--------------------------------+
-// | flags  : 1 byte                |
-// +--------------------------------+
-// .                                .
-// . variable payload               .
-// .                                .
-// +--------------------------------+
+// +--------------------------------------+
+// | major opcode : 1 byte                |
+// +--------------------------------------+
+// | minor opcode : 1 byte                |
+// +--------------------------------------+
+// | flags        : 2 bytes               |
+// +--------------------------------------+
+// .                                      .
+// . variable payload                     .
+// .                                      .
+// +--------------------------------------+
 //
 
@@ -117,4 +119,7 @@
 // dconnect minor opcodes for INVOKE
 
+// DCON_OP_SETUP_REPLY and DCON_OP_INVOKE_REPLY flags
+#define DCON_OP_FLAGS_REPLY_EXCEPTION   0x0001
+
 #pragma pack(1)
 
@@ -123,4 +128,5 @@
   PRUint8  opcode_major;
   PRUint8  opcode_minor;
+  PRUint16 flags;
   PRUint32 request_index; // initialized with NewRequestIndex
 };
@@ -154,6 +160,7 @@
   DConAddr instance;
   nsresult status;
-  // followed by a specially serialized nsIException instance if
-  // NS_FAILED(status) (see ipcDConnectService::SerializeException)
+  // optionally followed by a specially serialized nsIException instance (see
+  // ipcDConnectService::SerializeException) if DCON_OP_FLAGS_REPLY_EXCEPTION is
+  // present in flags
 };
 
@@ -179,7 +186,8 @@
 {
   nsresult result;
-  // followed by an array of out-param blobs if NS_SUCCEEDED(result), or by a
-  // specially serialized nsIException instance if NS_FAILED(result)
-  // (see ipcDConnectService::SerializeException)
+  // followed by an array of out-param blobs if NS_SUCCEEDED(result), and
+  // optionally by a specially serialized nsIException instance (see
+  // ipcDConnectService::SerializeException) if DCON_OP_FLAGS_REPLY_EXCEPTION is
+  // present in flags
 };
 
@@ -1963,6 +1971,5 @@
 
 nsresult
-ipcDConnectService::DeserializeException(const PRUint8 *data,
-                                         PRUint32 dataLen,
+ipcDConnectService::DeserializeException(ipcMessageReader &reader,
                                          PRUint32 peer,
                                          nsIException **xcpt)
@@ -1971,6 +1978,4 @@
   if (!xcpt)
     return NS_ERROR_INVALID_POINTER;
-
-  ipcMessageReader reader(data, dataLen);
 
   nsresult rv;
@@ -2154,4 +2159,5 @@
         msg.opcode_major = DCON_OP_RELEASE;
         msg.opcode_minor = 0;
+        msg.flags = 0;
         msg.request_index = 0; // not used, set to some unused value
         msg.instance = mInstance;
@@ -2367,4 +2373,5 @@
   invoke.opcode_major = DCON_OP_INVOKE;
   invoke.opcode_minor = 0;
+  invoke.flags = 0;
   invoke.request_index = NewRequestIndex();
   invoke.instance = mInstance;
@@ -2466,32 +2473,9 @@
   while (completion.IsPending());
 
+  ipcMessageReader reader(completion.Params(), completion.ParamsLen());
+
   rv = completion.GetResult();
-  if (rv != NS_OK)
-  {
-    NS_ASSERTION(completion.ParamsLen() == 0 ||
-                 completion.ParamsLen() >= sizeof(void*),
-                 "invalid nsIException serialization length");
-    if (completion.ParamsLen() >= sizeof(void*))
-    {
-      LOG(("got nsIException instance (%p), will create a stub\n",
-           *((void **) completion.Params())));
-
-      nsIException *xcpt = nsnull;
-      nsresult rv2; // preserve rv for returning to the caller
-      rv2 = dConnect->DeserializeException (completion.Params(),
-                                            completion.ParamsLen(),
-                                            mPeerID, &xcpt);
-      if (NS_SUCCEEDED(rv2))
-      {
-        rv2 = em->SetCurrentException(xcpt);
-        NS_IF_RELEASE(xcpt);
-      }
-      NS_ASSERTION(NS_SUCCEEDED(rv2), "failed to deserialize/set exception");
-    }
-  }
-  else if (completion.ParamsLen() > 0)
-  {
-    ipcMessageReader reader(completion.Params(), completion.ParamsLen());
-
+  if (NS_SUCCEEDED(rv))
+  {
     PRUint8 i;
 
@@ -2529,8 +2513,8 @@
           if (NS_SUCCEEDED(rv))
           {
-              nsISupports *obj = nsnull;
-              rv = dConnect->DeserializeInterfaceParamBits(bits, mPeerID, iid, obj);
-              if (NS_SUCCEEDED(rv))
-                *pptr = obj;
+            nsISupports *obj = nsnull;
+            rv = dConnect->DeserializeInterfaceParamBits(bits, mPeerID, iid, obj);
+            if (NS_SUCCEEDED(rv))
+              *pptr = obj;
           }
         }
@@ -2548,5 +2532,19 @@
   }
 
-  return rv;
+  if (completion.Reply()->flags & DCON_OP_FLAGS_REPLY_EXCEPTION)
+  {
+    LOG(("got nsIException instance, will create a stub\n"));
+
+    nsIException *xcpt = nsnull;
+    rv = dConnect->DeserializeException (reader, mPeerID, &xcpt);
+    if (NS_SUCCEEDED(rv))
+    {
+      rv = em->SetCurrentException(xcpt);
+      NS_IF_RELEASE(xcpt);
+    }
+    NS_ASSERTION(NS_SUCCEEDED(rv), "failed to deserialize/set exception");
+  }
+
+  return NS_SUCCEEDED(rv) ? completion.GetResult() : rv;
 }
 
@@ -2582,48 +2580,7 @@
     LOG(("got SETUP_REPLY: status=%x instance=%p\n", reply->status, reply->instance));
 
-    if (reply->status != NS_OK)
-    {
-      mStatus = reply->status;
-
-      const PRUint8 *params = ((const PRUint8 *) op) + sizeof (DConnectSetupReply);
-      const PRUint32 paramsLen = opLen - sizeof (DConnectSetupReply);
-
-      NS_ASSERTION(paramsLen == 0 || paramsLen >= sizeof(void*),
-                   "invalid nsIException serialization length");
-      if (paramsLen >= sizeof(void*))
-      {
-        LOG(("got nsIException instance (%p), will create a stub\n",
-             *((void **) params)));
-
-        nsresult rv;
-        nsCOMPtr <nsIExceptionService> es;
-        es = do_GetService (NS_EXCEPTIONSERVICE_CONTRACTID, &rv);
-        if (NS_SUCCEEDED(rv))
-        {
-          nsCOMPtr <nsIExceptionManager> em;
-          rv = es->GetCurrentExceptionManager (getter_AddRefs(em));
-          if (NS_SUCCEEDED(rv))
-          {
-            // ensure ipcDConnectService is not deleted before we finish
-            nsRefPtr <ipcDConnectService> dConnect (ipcDConnectService::GetInstance());
-            if (dConnect)
-            {
-              nsIException *xcpt = nsnull;
-              rv = dConnect->DeserializeException (params, paramsLen,
-                                                   sender, &xcpt);
-              if (NS_SUCCEEDED(rv))
-              {
-                rv = em->SetCurrentException(xcpt);
-                NS_IF_RELEASE(xcpt);
-              }
-            }
-            else
-              rv = NS_ERROR_UNEXPECTED;
-          }
-        }
-        NS_ASSERTION(NS_SUCCEEDED(rv), "failed to deserialize/set exception");
-      }
-    }
-    else
+    mStatus = reply->status;
+
+    if (NS_SUCCEEDED(reply->status))
     {
       // ensure ipcDConnectService is not deleted before we finish
@@ -2638,4 +2595,43 @@
         mStatus = rv;
     }
+
+    if (reply->flags & DCON_OP_FLAGS_REPLY_EXCEPTION)
+    {
+      const PRUint8 *params = ((const PRUint8 *) op) + sizeof (DConnectSetupReply);
+      const PRUint32 paramsLen = opLen - sizeof (DConnectSetupReply);
+
+      ipcMessageReader reader(params, paramsLen);
+
+      LOG(("got nsIException instance, will create a stub\n"));
+
+      nsresult rv;
+      nsCOMPtr <nsIExceptionService> es;
+      es = do_GetService (NS_EXCEPTIONSERVICE_CONTRACTID, &rv);
+      if (NS_SUCCEEDED(rv))
+      {
+        nsCOMPtr <nsIExceptionManager> em;
+        rv = es->GetCurrentExceptionManager (getter_AddRefs(em));
+        if (NS_SUCCEEDED(rv))
+        {
+          // ensure ipcDConnectService is not deleted before we finish
+          nsRefPtr <ipcDConnectService> dConnect (ipcDConnectService::GetInstance());
+          if (dConnect)
+          {
+            nsIException *xcpt = nsnull;
+            rv = dConnect->DeserializeException (reader, sender, &xcpt);
+            if (NS_SUCCEEDED(rv))
+            {
+              rv = em->SetCurrentException(xcpt);
+              NS_IF_RELEASE(xcpt);
+            }
+          }
+          else
+            rv = NS_ERROR_UNEXPECTED;
+        }
+      }
+      NS_ASSERTION(NS_SUCCEEDED(rv), "failed to deserialize/set exception");
+      if (NS_FAILED(rv))
+        mStatus = rv;
+    }
   }
 
@@ -2665,4 +2661,5 @@
 
   aMsg->opcode_major = DCON_OP_SETUP;
+  aMsg->flags = 0;
   aMsg->request_index = NewRequestIndex();
 
@@ -2688,5 +2685,5 @@
   {
     rv = IPC_WaitMessage(IPC_SENDER_ANY, kDConnectTargetID,
-			 &completion.GetSelector(), &completion,
+                         &completion.GetSelector(), &completion,
                          DCON_WAIT_TIMEOUT);
     if (NS_FAILED(rv))
@@ -3521,4 +3518,33 @@
   NS_IF_RELEASE(instance);
 
+  nsCOMPtr <nsIException> exception;
+  PRBool got_exception = PR_FALSE;
+
+  if (rv != NS_OK)
+  {
+    // try to fetch an nsIException possibly set by one of the setup methods
+    nsresult rv2;
+    nsCOMPtr <nsIExceptionService> es;
+    es = do_GetService(NS_EXCEPTIONSERVICE_CONTRACTID, &rv2);
+    if (NS_SUCCEEDED(rv2))
+    {
+      nsCOMPtr <nsIExceptionManager> em;
+      rv2 = es->GetCurrentExceptionManager (getter_AddRefs (em));
+      if (NS_SUCCEEDED(rv2))
+      {
+        nsCOMPtr <nsIException> exception;
+        rv2 = em->GetCurrentException (getter_AddRefs (exception));
+        if (NS_SUCCEEDED(rv2))
+        {
+          LOG(("got nsIException instance, will serialize\n"));
+          got_exception = PR_TRUE;
+        }
+      }
+    }
+    NS_ASSERTION(NS_SUCCEEDED(rv2), "failed to get/serialize exception");
+    if (NS_FAILED(rv2))
+      rv = rv2;
+  }
+
   ipcMessageWriter writer(64);
 
@@ -3526,34 +3552,18 @@
   msg.opcode_major = DCON_OP_SETUP_REPLY;
   msg.opcode_minor = 0;
+  msg.flags = 0;
   msg.request_index = setup->request_index;
   msg.instance = wrapper;
   msg.status = rv;
 
+  if (got_exception)
+    msg.flags |= DCON_OP_FLAGS_REPLY_EXCEPTION;
+
   writer.PutBytes(&msg, sizeof(msg));
 
-  if (rv != NS_OK)
-  {
-    // try to fetch an nsIException possibly set by one of the setup methods
-    // and send it instead of the failed instance (even if it is null)
-    nsCOMPtr <nsIExceptionService> es;
-    es = do_GetService(NS_EXCEPTIONSERVICE_CONTRACTID, &rv);
-    if (NS_SUCCEEDED(rv))
-    {
-      nsCOMPtr <nsIExceptionManager> em;
-      rv = es->GetCurrentExceptionManager (getter_AddRefs (em));
-      if (NS_SUCCEEDED(rv))
-      {
-        nsCOMPtr <nsIException> exception;
-        rv = em->GetCurrentException (getter_AddRefs (exception));
-        if (NS_SUCCEEDED(rv))
-        {
-          LOG(("got nsIException instance (%p), will serialize\n",
-               (nsIException *)exception));
-
-          rv = SerializeException(writer, peer, exception, wrappers);
-        }
-      }
-    }
-    NS_ASSERTION(NS_SUCCEEDED(rv), "failed to get/serialze exception");
+  if (got_exception)
+  {
+    rv = SerializeException(writer, peer, exception, wrappers);
+    NS_ASSERTION(NS_SUCCEEDED(rv), "failed to get/serialize exception");
   }
 
@@ -3731,24 +3741,24 @@
   {
     // try to fetch an nsIException possibly set by the method
-    nsresult invoke_rv = rv;
+    nsresult rv2;
     nsCOMPtr <nsIExceptionService> es;
-    es = do_GetService(NS_EXCEPTIONSERVICE_CONTRACTID, &rv);
-    if (NS_SUCCEEDED(rv))
+    es = do_GetService(NS_EXCEPTIONSERVICE_CONTRACTID, &rv2);
+    if (NS_SUCCEEDED(rv2))
     {
       nsCOMPtr <nsIExceptionManager> em;
-      rv = es->GetCurrentExceptionManager (getter_AddRefs (em));
-      if (NS_SUCCEEDED(rv))
-      {
-        rv = em->GetCurrentException (getter_AddRefs (exception));
-        if (NS_SUCCEEDED(rv))
+      rv2 = es->GetCurrentExceptionManager (getter_AddRefs (em));
+      if (NS_SUCCEEDED(rv2))
+      {
+        rv2 = em->GetCurrentException (getter_AddRefs (exception));
+        if (NS_SUCCEEDED(rv2))
         {
-          LOG(("got nsIException instance (%p), will serialize\n",
-               (nsIException *)exception));
+          LOG(("got nsIException instance, will serialize\n"));
           got_exception = PR_TRUE;
-          // restore the method's result
-          rv = invoke_rv;
         }
       }
     }
+    NS_ASSERTION(NS_SUCCEEDED(rv2), "failed to get/serialize exception");
+    if (NS_FAILED(rv2))
+      rv = rv2;
   }
 
@@ -3765,17 +3775,16 @@
   reply.opcode_major = DCON_OP_INVOKE_REPLY;
   reply.opcode_minor = 0;
+  reply.flags = 0;
   reply.request_index = invoke->request_index;
   reply.result = rv;
 
+  if (got_exception)
+    reply.flags |= DCON_OP_FLAGS_REPLY_EXCEPTION;
+
   writer.PutBytes(&reply, sizeof(reply));
 
   nsVoidArray wrappers;
 
-  if (got_exception)
-  {
-    rv = SerializeException(writer, peer, exception, wrappers);
-    NS_ASSERTION(NS_SUCCEEDED(rv), "failed to get/serialze exception");
-  }
-  else if (NS_SUCCEEDED(rv) && params)
+  if (NS_SUCCEEDED(rv) && params)
   {
     // serialize out-params and retvals
@@ -3833,4 +3842,10 @@
   }
 
+  if (got_exception)
+  {
+    rv = SerializeException(writer, peer, exception, wrappers);
+    NS_ASSERTION(NS_SUCCEEDED(rv), "failed to get/serialize exception");
+  }
+
   if (NS_FAILED(rv))
     rv = IPC_SendMessage(peer, kDConnectTargetID, (const PRUint8 *) &reply, sizeof(reply));
Index: trunk/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/ipcDConnectService.h
===================================================================
--- trunk/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/ipcDConnectService.h	(revision 6980)
+++ trunk/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/ipcDConnectService.h	(revision 6999)
@@ -83,4 +83,5 @@
 
 class nsIException;
+class ipcMessageReader;
 class ipcMessageWriter;
 
@@ -231,5 +232,5 @@
                                           PRUint32 peer, nsIException *xcpt,
                                           nsVoidArray &wrappers);
-  NS_HIDDEN_(nsresult) DeserializeException(const PRUint8 *data, PRUint32 dataLen,
+  NS_HIDDEN_(nsresult) DeserializeException(ipcMessageReader &reader,
                                             PRUint32 peer, nsIException **xcpt);
 
