Bug 780108 - Get rid of the double switch in XPCConvert::JSData2Native; r=bholley
authorMs2ger <ms2ger@gmail.com>
Sat, 04 Aug 2012 09:28:45 +0200
changeset 103320 cb1eac927462acb6e9be402bf87199f27a2f44d8
parent 103319 7abce15d1cb3b6f07ff8689008285f732b7bc9a8
child 103321 a184e7de6ba978ed73631af3d54be2dc2200ca1c
push id18
push usershu@rfrn.org
push dateMon, 06 Aug 2012 22:42:45 +0000
reviewersbholley
bugs780108
milestone17.0a1
Bug 780108 - Get rid of the double switch in XPCConvert::JSData2Native; r=bholley
js/xpconnect/src/XPCConvert.cpp
--- a/js/xpconnect/src/XPCConvert.cpp
+++ b/js/xpconnect/src/XPCConvert.cpp
@@ -1,9 +1,9 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sw=4 et tw=78:
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* Data conversion between native and JavaScript types. */
 
@@ -425,375 +425,371 @@ XPCConvert::JSData2Native(XPCCallContext
         if (!JS_ValueToNumber(cx, s, (double*)d))
             return false;
         break;
     case nsXPTType::T_BOOL   :
         JS_ValueToBoolean(cx, s, &tb);
         *((bool*)d) = tb;
         break;
     case nsXPTType::T_CHAR   :
-        {
-            JSString* str = JS_ValueToString(cx, s);
-            if (!str) {
-                return false;
-            }
-            size_t length;
-            const jschar* chars = JS_GetStringCharsAndLength(cx, str, &length);
-            if (!chars) {
-                return false;
-            }
-            jschar ch = length ? chars[0] : 0;
+    {
+        JSString* str = JS_ValueToString(cx, s);
+        if (!str) {
+            return false;
+        }
+        size_t length;
+        const jschar* chars = JS_GetStringCharsAndLength(cx, str, &length);
+        if (!chars) {
+            return false;
+        }
+        jschar ch = length ? chars[0] : 0;
 #ifdef DEBUG
-            CheckJSCharInCharRange(ch);
+        CheckJSCharInCharRange(ch);
 #endif
-            *((char*)d) = char(ch);
+        *((char*)d) = char(ch);
+        break;
+    }
+    case nsXPTType::T_WCHAR  :
+    {
+        JSString* str;
+        if (!(str = JS_ValueToString(cx, s))) {
+            return false;
+        }
+        size_t length;
+        const jschar* chars = JS_GetStringCharsAndLength(cx, str, &length);
+        if (!chars) {
+            return false;
+        }
+        if (length == 0) {
+            *((uint16_t*)d) = 0;
             break;
         }
-    case nsXPTType::T_WCHAR  :
-        {
-            JSString* str;
-            if (!(str = JS_ValueToString(cx, s))) {
-                return false;
-            }
-            size_t length;
-            const jschar* chars = JS_GetStringCharsAndLength(cx, str, &length);
-            if (!chars) {
-                return false;
-            }
-            if (length == 0) {
-                *((uint16_t*)d) = 0;
-                break;
-            }
-            *((uint16_t*)d) = uint16_t(chars[0]);
-            break;
-        }
+        *((uint16_t*)d) = uint16_t(chars[0]);
+        break;
+    }
     case nsXPTType::T_JSVAL :
         *((jsval*)d) = s;
         break;
-    default:
+    case nsXPTType::T_VOID:
+        XPC_LOG_ERROR(("XPCConvert::JSData2Native : void* params not supported"));
+        NS_ERROR("void* params not supported");
+        return false;
+    case nsXPTType::T_IID:
+    {
+        const nsID* pid = nullptr;
+
+        // There's no good reason to pass a null IID.
+        if (s.isNullOrUndefined()) {
+            if (pErr)
+                *pErr = NS_ERROR_XPC_BAD_CONVERT_JS;
+            return false;
+        }
+
+        if (!s.isObject() ||
+            (!(pid = xpc_JSObjectToID(cx, &s.toObject()))) ||
+            (!(pid = (const nsID*) nsMemory::Clone(pid, sizeof(nsID))))) {
+            return false;
+        }
+        *((const nsID**)d) = pid;
+        return true;
+    }
 
-        switch (type.TagPart()) {
-        case nsXPTType::T_VOID:
-            XPC_LOG_ERROR(("XPCConvert::JSData2Native : void* params not supported"));
-            NS_ERROR("void* params not supported");
-            return false;
-        case nsXPTType::T_IID:
-        {
-            const nsID* pid = nullptr;
+    case nsXPTType::T_ASTRING:
+    {
+        isDOMString = false;
+        // Fall through to T_DOMSTRING case.
+    }
+    case nsXPTType::T_DOMSTRING:
+    {
+        static const PRUnichar EMPTY_STRING[] = { '\0' };
+        static const PRUnichar VOID_STRING[] = { 'u', 'n', 'd', 'e', 'f', 'i', 'n', 'e', 'd', '\0' };
+
+        const PRUnichar* chars = nullptr;
+        JSString* str = nullptr;
+        JSBool isNewString = false;
+        PRUint32 length = 0;
+
+        if (JSVAL_IS_VOID(s)) {
+            if (isDOMString) {
+                chars  = VOID_STRING;
+                length = ArrayLength(VOID_STRING) - 1;
+            } else {
+                chars = EMPTY_STRING;
+                length = 0;
+            }
+        } else if (!JSVAL_IS_NULL(s)) {
+            str = JS_ValueToString(cx, s);
+            if (!str)
+                return false;
 
-            // There's no good reason to pass a null IID.
-            if (s.isNullOrUndefined()) {
-                if (pErr)
-                    *pErr = NS_ERROR_XPC_BAD_CONVERT_JS;
-                return false;
+            length = (PRUint32) JS_GetStringLength(str);
+            if (length) {
+                chars = JS_GetStringCharsZ(cx, str);
+                if (!chars)
+                    return false;
+                if (STRING_TO_JSVAL(str) != s)
+                    isNewString = true;
+            } else {
+                str = nullptr;
+                chars = EMPTY_STRING;
             }
+        }
+
+        if (useAllocator) {
+            // XXX extra string copy when isNewString
+            if (str && !isNewString) {
+                size_t strLength;
+                const jschar *strChars = JS_GetStringCharsZAndLength(cx, str, &strLength);
+                if (!strChars)
+                    return false;
+
+                XPCReadableJSStringWrapper *wrapper =
+                    ccx.NewStringWrapper(strChars, strLength);
+                if (!wrapper)
+                    return false;
 
-            if (!s.isObject() ||
-                (!(pid = xpc_JSObjectToID(cx, &s.toObject()))) ||
-                (!(pid = (const nsID*) nsMemory::Clone(pid, sizeof(nsID))))) {
-                return false;
+                *((const nsAString**)d) = wrapper;
+            } else if (JSVAL_IS_NULL(s)) {
+                XPCReadableJSStringWrapper *wrapper =
+                    new XPCReadableJSStringWrapper();
+                if (!wrapper)
+                    return false;
+
+                *((const nsAString**)d) = wrapper;
+            } else {
+                // use nsString to encourage sharing
+                const nsAString *rs = new nsString(chars, length);
+                if (!rs)
+                    return false;
+                *((const nsAString**)d) = rs;
             }
-            *((const nsID**)d) = pid;
+        } else {
+            nsAString* ws = *((nsAString**)d);
+
+            if (JSVAL_IS_NULL(s) || (!isDOMString && JSVAL_IS_VOID(s))) {
+                ws->Truncate();
+                ws->SetIsVoid(true);
+            } else
+                ws->Assign(chars, length);
+        }
+        return true;
+    }
+
+    case nsXPTType::T_CHAR_STR:
+    {
+        if (JSVAL_IS_VOID(s) || JSVAL_IS_NULL(s)) {
+            *((char**)d) = nullptr;
             return true;
         }
 
-        case nsXPTType::T_ASTRING:
-        {
-            isDOMString = false;
-            // Fall through to T_DOMSTRING case.
+        JSString* str = JS_ValueToString(cx, s);
+        if (!str) {
+            return false;
         }
-        case nsXPTType::T_DOMSTRING:
-        {
-            static const PRUnichar EMPTY_STRING[] = { '\0' };
-            static const PRUnichar VOID_STRING[] = { 'u', 'n', 'd', 'e', 'f', 'i', 'n', 'e', 'd', '\0' };
+#ifdef DEBUG
+        const jschar* chars=nullptr;
+        if (nullptr != (chars = JS_GetStringCharsZ(cx, str))) {
+            bool legalRange = true;
+            int len = JS_GetStringLength(str);
+            const jschar* t;
+            PRInt32 i=0;
+            for (t=chars; (i< len) && legalRange ; i++,t++) {
+                if (!CheckJSCharInCharRange(*t))
+                    break;
+            }
+        }
+#endif // DEBUG
+        size_t length = JS_GetStringEncodingLength(cx, str);
+        if (length == size_t(-1)) {
+            return false;
+        }
+        char *buffer = static_cast<char *>(nsMemory::Alloc(length + 1));
+        if (!buffer) {
+            return false;
+        }
+        JS_EncodeStringToBuffer(str, buffer, length);
+        buffer[length] = '\0';
+        *((void**)d) = buffer;
+        return true;
+    }
 
-            const PRUnichar* chars = nullptr;
-            JSString* str = nullptr;
-            JSBool isNewString = false;
-            PRUint32 length = 0;
+    case nsXPTType::T_WCHAR_STR:
+    {
+        const jschar* chars=nullptr;
+        JSString* str;
+
+        if (JSVAL_IS_VOID(s) || JSVAL_IS_NULL(s)) {
+            *((jschar**)d) = nullptr;
+            return true;
+        }
 
-            if (JSVAL_IS_VOID(s)) {
-                if (isDOMString) {
-                    chars  = VOID_STRING;
-                    length = ArrayLength(VOID_STRING) - 1;
-                } else {
-                    chars = EMPTY_STRING;
-                    length = 0;
-                }
-            } else if (!JSVAL_IS_NULL(s)) {
-                str = JS_ValueToString(cx, s);
-                if (!str)
+        if (!(str = JS_ValueToString(cx, s))) {
+            return false;
+        }
+        if (!(chars = JS_GetStringCharsZ(cx, str))) {
+            return false;
+        }
+        int len = JS_GetStringLength(str);
+        int byte_len = (len+1)*sizeof(jschar);
+        if (!(*((void**)d) = nsMemory::Alloc(byte_len))) {
+            // XXX should report error
+            return false;
+        }
+        jschar* destchars = *((jschar**)d);
+        memcpy(destchars, chars, byte_len);
+        destchars[len] = 0;
+
+        return true;
+    }
+
+    case nsXPTType::T_UTF8STRING:
+    {
+        const jschar* chars;
+        PRUint32 length;
+        JSString* str;
+
+        if (JSVAL_IS_NULL(s) || JSVAL_IS_VOID(s)) {
+            if (useAllocator) {
+                nsACString *rs = new nsCString();
+                if (!rs)
                     return false;
 
-                length = (PRUint32) JS_GetStringLength(str);
-                if (length) {
-                    chars = JS_GetStringCharsZ(cx, str);
-                    if (!chars)
-                        return false;
-                    if (STRING_TO_JSVAL(str) != s)
-                        isNewString = true;
-                } else {
-                    str = nullptr;
-                    chars = EMPTY_STRING;
-                }
-            }
-
-            if (useAllocator) {
-                // XXX extra string copy when isNewString
-                if (str && !isNewString) {
-                    size_t strLength;
-                    const jschar *strChars = JS_GetStringCharsZAndLength(cx, str, &strLength);
-                    if (!strChars)
-                        return false;
-
-                    XPCReadableJSStringWrapper *wrapper =
-                        ccx.NewStringWrapper(strChars, strLength);
-                    if (!wrapper)
-                        return false;
-
-                    *((const nsAString**)d) = wrapper;
-                } else if (JSVAL_IS_NULL(s)) {
-                    XPCReadableJSStringWrapper *wrapper =
-                        new XPCReadableJSStringWrapper();
-                    if (!wrapper)
-                        return false;
-
-                    *((const nsAString**)d) = wrapper;
-                } else {
-                    // use nsString to encourage sharing
-                    const nsAString *rs = new nsString(chars, length);
-                    if (!rs)
-                        return false;
-                    *((const nsAString**)d) = rs;
-                }
+                rs->SetIsVoid(true);
+                *((nsACString**)d) = rs;
             } else {
-                nsAString* ws = *((nsAString**)d);
-
-                if (JSVAL_IS_NULL(s) || (!isDOMString && JSVAL_IS_VOID(s))) {
-                    ws->Truncate();
-                    ws->SetIsVoid(true);
-                } else
-                    ws->Assign(chars, length);
+                nsCString* rs = *((nsCString**)d);
+                rs->Truncate();
+                rs->SetIsVoid(true);
             }
             return true;
         }
 
-        case nsXPTType::T_CHAR_STR:
-        {
-            if (JSVAL_IS_VOID(s) || JSVAL_IS_NULL(s)) {
-                *((char**)d) = nullptr;
-                return true;
-            }
+        // The JS val is neither null nor void...
 
-            JSString* str = JS_ValueToString(cx, s);
-            if (!str) {
-                return false;
-            }
-#ifdef DEBUG
-            const jschar* chars=nullptr;
-            if (nullptr != (chars = JS_GetStringCharsZ(cx, str))) {
-                bool legalRange = true;
-                int len = JS_GetStringLength(str);
-                const jschar* t;
-                PRInt32 i=0;
-                for (t=chars; (i< len) && legalRange ; i++,t++) {
-                    if (!CheckJSCharInCharRange(*t))
-                        break;
-                }
-            }
-#endif // DEBUG
-            size_t length = JS_GetStringEncodingLength(cx, str);
-            if (length == size_t(-1)) {
-                return false;
-            }
-            char *buffer = static_cast<char *>(nsMemory::Alloc(length + 1));
-            if (!buffer) {
-                return false;
-            }
-            JS_EncodeStringToBuffer(str, buffer, length);
-            buffer[length] = '\0';
-            *((void**)d) = buffer;
-            return true;
+        if (!(str = JS_ValueToString(cx, s))||
+            !(chars = JS_GetStringCharsZ(cx, str))) {
+            return false;
         }
 
-        case nsXPTType::T_WCHAR_STR:
-        {
-            const jschar* chars=nullptr;
-            JSString* str;
+        length = JS_GetStringLength(str);
 
-            if (JSVAL_IS_VOID(s) || JSVAL_IS_NULL(s)) {
-                *((jschar**)d) = nullptr;
-                return true;
-            }
-
-            if (!(str = JS_ValueToString(cx, s))) {
+        nsCString *rs;
+        if (useAllocator) {
+            // Use nsCString to enable sharing
+            rs = new nsCString();
+            if (!rs)
                 return false;
-            }
-            if (!(chars = JS_GetStringCharsZ(cx, str))) {
-                return false;
-            }
-            int len = JS_GetStringLength(str);
-            int byte_len = (len+1)*sizeof(jschar);
-            if (!(*((void**)d) = nsMemory::Alloc(byte_len))) {
-                // XXX should report error
-                return false;
-            }
-            jschar* destchars = *((jschar**)d);
-            memcpy(destchars, chars, byte_len);
-            destchars[len] = 0;
-
-            return true;
-        }
 
-        case nsXPTType::T_UTF8STRING:
-        {
-            const jschar* chars;
-            PRUint32 length;
-            JSString* str;
-
-            if (JSVAL_IS_NULL(s) || JSVAL_IS_VOID(s)) {
-                if (useAllocator) {
-                    nsACString *rs = new nsCString();
-                    if (!rs)
-                        return false;
+            *((const nsCString**)d) = rs;
+        } else {
+            rs = *((nsCString**)d);
+        }
+        const PRUnichar* start = (const PRUnichar*)chars;
+        const PRUnichar* end = start + length;
+        CopyUTF16toUTF8(nsDependentSubstring(start, end), *rs);
+        return true;
+    }
 
-                    rs->SetIsVoid(true);
-                    *((nsACString**)d) = rs;
-                } else {
-                    nsCString* rs = *((nsCString**)d);
-                    rs->Truncate();
-                    rs->SetIsVoid(true);
-                }
-                return true;
-            }
-
-            // The JS val is neither null nor void...
-
-            if (!(str = JS_ValueToString(cx, s))||
-                !(chars = JS_GetStringCharsZ(cx, str))) {
-                return false;
-            }
-
-            length = JS_GetStringLength(str);
-
-            nsCString *rs;
+    case nsXPTType::T_CSTRING:
+    {
+        if (JSVAL_IS_NULL(s) || JSVAL_IS_VOID(s)) {
             if (useAllocator) {
-                // Use nsCString to enable sharing
-                rs = new nsCString();
+                nsACString *rs = new nsCString();
                 if (!rs)
                     return false;
 
-                *((const nsCString**)d) = rs;
+                rs->SetIsVoid(true);
+                *((nsACString**)d) = rs;
             } else {
-                rs = *((nsCString**)d);
+                nsACString* rs = *((nsACString**)d);
+                rs->Truncate();
+                rs->SetIsVoid(true);
             }
-            const PRUnichar* start = (const PRUnichar*)chars;
-            const PRUnichar* end = start + length;
-            CopyUTF16toUTF8(nsDependentSubstring(start, end), *rs);
             return true;
         }
 
-        case nsXPTType::T_CSTRING:
-        {
-            if (JSVAL_IS_NULL(s) || JSVAL_IS_VOID(s)) {
-                if (useAllocator) {
-                    nsACString *rs = new nsCString();
-                    if (!rs)
-                        return false;
+        // The JS val is neither null nor void...
+        JSString* str = JS_ValueToString(cx, s);
+        if (!str) {
+            return false;
+        }
+
+        size_t length = JS_GetStringEncodingLength(cx, str);
+        if (length == size_t(-1)) {
+            return false;
+        }
+
+        nsACString *rs;
+        if (useAllocator) {
+            rs = new nsCString();
+            if (!rs)
+                return false;
+            *((const nsACString**)d) = rs;
+        } else {
+            rs = *((nsACString**)d);
+        }
 
-                    rs->SetIsVoid(true);
-                    *((nsACString**)d) = rs;
-                } else {
-                    nsACString* rs = *((nsACString**)d);
-                    rs->Truncate();
-                    rs->SetIsVoid(true);
-                }
-                return true;
-            }
+        rs->SetLength(PRUint32(length));
+        if (rs->Length() != PRUint32(length)) {
+            return false;
+        }
+        JS_EncodeStringToBuffer(str, rs->BeginWriting(), length);
+
+        return true;
+    }
+
+    case nsXPTType::T_INTERFACE:
+    case nsXPTType::T_INTERFACE_IS:
+    {
+        NS_ASSERTION(iid,"can't do interface conversions without iid");
 
-            // The JS val is neither null nor void...
-            JSString* str = JS_ValueToString(cx, s);
-            if (!str) {
+        if (iid->Equals(NS_GET_IID(nsIVariant))) {
+            XPCVariant* variant = XPCVariant::newVariant(ccx, s);
+            if (!variant)
+                return false;
+            *((nsISupports**)d) = static_cast<nsIVariant*>(variant);
+            return true;
+        } else if (iid->Equals(NS_GET_IID(nsIAtom)) &&
+                   JSVAL_IS_STRING(s)) {
+            // We're trying to pass a string as an nsIAtom.  Let's atomize!
+            JSString* str = JSVAL_TO_STRING(s);
+            const PRUnichar* chars = JS_GetStringCharsZ(cx, str);
+            if (!chars) {
+                if (pErr)
+                    *pErr = NS_ERROR_XPC_BAD_CONVERT_JS_NULL_REF;
                 return false;
             }
-
-            size_t length = JS_GetStringEncodingLength(cx, str);
-            if (length == size_t(-1)) {
-                return false;
-            }
+            PRUint32 length = JS_GetStringLength(str);
+            nsIAtom* atom = NS_NewAtom(nsDependentSubstring(chars,
+                                                            chars + length));
+            if (!atom && pErr)
+                *pErr = NS_ERROR_OUT_OF_MEMORY;
+            *((nsISupports**)d) = atom;
+            return atom != nullptr;
+        }
+        //else ...
 
-            nsACString *rs;
-            if (useAllocator) {
-                rs = new nsCString();
-                if (!rs)
-                    return false;
-                *((const nsACString**)d) = rs;
-            } else {
-                rs = *((nsACString**)d);
-            }
-
-            rs->SetLength(PRUint32(length));
-            if (rs->Length() != PRUint32(length)) {
-                return false;
-            }
-            JS_EncodeStringToBuffer(str, rs->BeginWriting(), length);
-
+        if (s.isNullOrUndefined()) {
+            *((nsISupports**)d) = nullptr;
             return true;
         }
 
-        case nsXPTType::T_INTERFACE:
-        case nsXPTType::T_INTERFACE_IS:
-        {
-            NS_ASSERTION(iid,"can't do interface conversions without iid");
-
-            if (iid->Equals(NS_GET_IID(nsIVariant))) {
-                XPCVariant* variant = XPCVariant::newVariant(ccx, s);
-                if (!variant)
-                    return false;
-                *((nsISupports**)d) = static_cast<nsIVariant*>(variant);
-                return true;
-            } else if (iid->Equals(NS_GET_IID(nsIAtom)) &&
-                       JSVAL_IS_STRING(s)) {
-                // We're trying to pass a string as an nsIAtom.  Let's atomize!
-                JSString* str = JSVAL_TO_STRING(s);
-                const PRUnichar* chars = JS_GetStringCharsZ(cx, str);
-                if (!chars) {
-                    if (pErr)
-                        *pErr = NS_ERROR_XPC_BAD_CONVERT_JS_NULL_REF;
-                    return false;
-                }
-                PRUint32 length = JS_GetStringLength(str);
-                nsIAtom* atom = NS_NewAtom(nsDependentSubstring(chars,
-                                                                chars + length));
-                if (!atom && pErr)
-                    *pErr = NS_ERROR_OUT_OF_MEMORY;
-                *((nsISupports**)d) = atom;
-                return atom != nullptr;
-            }
-            //else ...
-
-            if (s.isNullOrUndefined()) {
-                *((nsISupports**)d) = nullptr;
-                return true;
-            }
-
-            // only wrap JSObjects
-            if (!s.isObject()) {
-                if (pErr && s.isInt32() && 0 == s.toInt32())
-                    *pErr = NS_ERROR_XPC_BAD_CONVERT_JS_ZERO_ISNOT_NULL;
-                return false;
-            }
-
-            return JSObject2NativeInterface(ccx, (void**)d, &s.toObject(), iid,
-                                            nullptr, pErr);
-        }
-        default:
-            NS_ERROR("bad type");
+        // only wrap JSObjects
+        if (!s.isObject()) {
+            if (pErr && s.isInt32() && 0 == s.toInt32())
+                *pErr = NS_ERROR_XPC_BAD_CONVERT_JS_ZERO_ISNOT_NULL;
             return false;
         }
+
+        return JSObject2NativeInterface(ccx, (void**)d, &s.toObject(), iid,
+                                        nullptr, pErr);
+    }
+    default:
+        NS_ERROR("bad type");
+        return false;
     }
     return true;
 }
 
 inline JSBool
 CreateHolderIfNeeded(XPCCallContext& ccx, JSObject* obj, jsval* d,
                      nsIXPConnectJSObjectHolder** dest)
 {