Bug 605296 part 1. Infrastructure for supporting AUTF8String in quickstubs. r=jorendorff
authorBoris Zbarsky <bzbarsky@mit.edu>
Tue, 30 Nov 2010 13:18:15 -0500
changeset 58472 43437276f9f174878ac212b6c03eb4efa831ac20
parent 58471 5f664ece27590bed20d50c8d7cb752b15ecf9567
child 58473 251cd89364a8e08eaa956de02fd279f5eca118bd
push idunknown
push userunknown
push dateunknown
reviewersjorendorff
bugs605296
milestone2.0b8pre
Bug 605296 part 1. Infrastructure for supporting AUTF8String in quickstubs. r=jorendorff
js/src/xpconnect/src/qsgen.py
js/src/xpconnect/src/xpcquickstubs.cpp
js/src/xpconnect/src/xpcquickstubs.h
--- a/js/src/xpconnect/src/qsgen.py
+++ b/js/src/xpconnect/src/qsgen.py
@@ -491,16 +491,21 @@ argumentUnboxingTemplates = {
         "    if (!xpc_qsJsvalToWcharStr(cx, ${argVal}, ${argPtr}, &${name}))\n"
         "        return JS_FALSE;\n",
 
     '[cstring]':
         "    xpc_qsACString ${name}(cx, ${argVal}, ${argPtr});\n"
         "    if (!${name}.IsValid())\n"
         "        return JS_FALSE;\n",
 
+    '[utf8string]':
+        "    xpc_qsAUTF8String ${name}(cx, ${argVal}, ${argPtr});\n"
+        "    if (!${name}.IsValid())\n"
+        "        return JS_FALSE;\n",
+
     '[jsval]':
         "    jsval ${name} = ${argVal};\n"
     }
 
 # From JSData2Native.
 #
 # Omitted optional arguments are treated as though the caller had passed JS
 # `null`; this behavior is from XPCWrappedNative::CallMethod.
@@ -575,17 +580,17 @@ def writeArgumentUnboxing(f, i, name, ty
             elif haveCcx:
                 f.write("        xpc_qsThrowBadArgWithCcx(ccx, rv, %d);\n" % i)
             else:
                 f.write("        xpc_qsThrowBadArg(cx, rv, vp, %d);\n" % i)
             f.write("        return JS_FALSE;\n"
                     "    }\n")
             return True
 
-    warn("Unable to unbox argument of type %s" % type.name)
+    warn("Unable to unbox argument of type %s (native type %s)" % (type.name, typeName))
     if i is None:
         src = '*vp'
     else:
         src = 'argv[%d]' % i
     f.write("    !; // TODO - Unbox argument %s = %s\n" % (name, src))
     return rvdeclared
 
 def writeResultDecl(f, type, varname):
@@ -1126,17 +1131,17 @@ traceableArgumentConversionTemplates = {
     'float':
           "    float ${name} = (float) ${argVal};\n",
     'double':
           "    jsdouble ${name} = ${argVal};\n",
     '[astring]':
           "    XPCReadableJSStringWrapper ${name}(${argVal});\n",
     '[domstring]':
           "    XPCReadableJSStringWrapper ${name}(${argVal});\n",
-    '[cstring]':
+    '[utf8string]':
           "    NS_ConvertUTF16toUTF8 ${name}("
           "(const PRUnichar *)JS_GetStringChars(${argVal}), "
           "JS_GetStringLength(${argVal}));\n",
     'string':
           "    NS_ConvertUTF16toUTF8 ${name}_utf8("
           "(const PRUnichar *)JS_GetStringChars(${argVal}), "
           "JS_GetStringLength(${argVal}));\n"
           "    const char *${name} = ${name}_utf8.get();\n",
--- a/js/src/xpconnect/src/xpcquickstubs.cpp
+++ b/js/src/xpconnect/src/xpcquickstubs.cpp
@@ -689,105 +689,66 @@ xpc_qsGetterOnlyPropertyStub(JSContext *
                                         js_GetErrorMessage, NULL,
                                         JSMSG_GETTER_ONLY);
 }
 
 xpc_qsDOMString::xpc_qsDOMString(JSContext *cx, jsval v, jsval *pval,
                                  StringificationBehavior nullBehavior,
                                  StringificationBehavior undefinedBehavior)
 {
+    typedef implementation_type::char_traits traits;
     // From the T_DOMSTRING case in XPCConvert::JSData2Native.
-    typedef implementation_type::char_traits traits;
-    JSString *s;
-    const PRUnichar *chars;
-    size_t len;
-
-    if(JSVAL_IS_STRING(v))
-    {
-        s = JSVAL_TO_STRING(v);
-    }
-    else
-    {
-        StringificationBehavior behavior = eStringify;
-        if(JSVAL_IS_NULL(v))
-        {
-            behavior = nullBehavior;
-        }
-        else if(JSVAL_IS_VOID(v))
-        {
-            behavior = undefinedBehavior;
-        }
+    JSString *s = InitOrStringify<traits>(cx, v, pval, nullBehavior,
+                                          undefinedBehavior);
+    if (!s)
+        return;
 
-        // If pval is null, that means the argument was optional and
-        // not passed; turn those into void strings if they're
-        // supposed to be stringified.
-        if (behavior != eStringify || !pval)
-        {
-            // Here behavior == eStringify implies !pval, so both eNull and
-            // eStringify should end up with void strings.
-            (new(mBuf) implementation_type(
-                traits::sEmptyBuffer, PRUint32(0)))->SetIsVoid(behavior != eEmpty);
-            mValid = JS_TRUE;
-            return;
-        }
-
-        s = JS_ValueToString(cx, v);
-        if(!s)
-        {
-            mValid = JS_FALSE;
-            return;
-        }
-        *pval = STRING_TO_JSVAL(s);  // Root the new string.
-    }
-
-    len = s->length();
-    chars = (len == 0 ? traits::sEmptyBuffer :
-                        reinterpret_cast<const PRUnichar*>(JS_GetStringChars(s)));
+    size_t len = s->length();
+    const PRUnichar* chars =
+        (len == 0 ? traits::sEmptyBuffer :
+                    reinterpret_cast<const PRUnichar*>(JS_GetStringChars(s)));
     new(mBuf) implementation_type(chars, len);
     mValid = JS_TRUE;
 }
 
 xpc_qsACString::xpc_qsACString(JSContext *cx, jsval v, jsval *pval)
 {
+    typedef implementation_type::char_traits traits;
     // From the T_CSTRING case in XPCConvert::JSData2Native.
-    JSString *s;
-
-    if(JSVAL_IS_STRING(v))
-    {
-        s = JSVAL_TO_STRING(v);
-    }
-    else
-    {
-        if(JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v))
-        {
-            (new(mBuf) implementation_type())->SetIsVoid(PR_TRUE);
-            mValid = JS_TRUE;
-            return;
-        }
-
-        s = JS_ValueToString(cx, v);
-        if(!s)
-        {
-            mValid = JS_FALSE;
-            return;
-        }
-        *pval = STRING_TO_JSVAL(s);  // Root the new string.
-    }
+    JSString *s = InitOrStringify<traits>(cx, v, pval, eNull, eNull);
+    if (!s)
+        return;
 
     JSAutoByteString bytes(cx, s);
     if(!bytes)
     {
         mValid = JS_FALSE;
         return;
     }
 
     new(mBuf) implementation_type(bytes.ptr(), strlen(bytes.ptr()));
     mValid = JS_TRUE;
 }
 
+xpc_qsAUTF8String::xpc_qsAUTF8String(JSContext *cx, jsval v, jsval *pval)
+{
+    typedef nsCharTraits<PRUnichar> traits;
+    // From the T_UTF8STRING  case in XPCConvert::JSData2Native.
+    JSString *s = InitOrStringify<traits>(cx, v, pval, eNull, eNull);
+    if (!s)
+        return;
+
+    size_t len = s->length();
+    const PRUnichar* chars =
+        reinterpret_cast<const PRUnichar*>(JS_GetStringChars(s));
+
+    new(mBuf) implementation_type(chars, len);
+    mValid = JS_TRUE;
+}
+
 static nsresult
 getNative(nsISupports *idobj,
           QITableEntry* entries,
           JSObject *obj,
           const nsIID &iid,
           void **ppThis,
           nsISupports **pThisRef,
           jsval *vp)
--- a/js/src/xpconnect/src/xpcquickstubs.h
+++ b/js/src/xpconnect/src/xpcquickstubs.h
@@ -1,9 +1,9 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  *
  * ***** BEGIN LICENSE BLOCK *****
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  *
  * The contents of this file are subject to the Mozilla Public License Version
  * 1.1 (the "License"); you may not use this file except in compliance with
  * the License. You may obtain a copy of the License at
  * http://www.mozilla.org/MPL/
@@ -308,43 +308,16 @@ public:
         return reinterpret_cast<implementation_type *>(mBuf);
     }
 
     operator interface_type &()
     {
         return *Ptr();
     }
 
-protected:
-    /*
-     * Neither field is initialized; that is left to the derived class
-     * constructor. However, the destructor destroys the string object
-     * stored in mBuf, if mValid is true.
-     */
-    void *mBuf[JS_HOWMANY(sizeof(implementation_type), sizeof(void *))];
-    JSBool mValid;
-};
-
-/**
- * Class for converting a jsval to DOMString.
- *
- *     xpc_qsDOMString arg0(cx, &argv[0]);
- *     if (!arg0.IsValid())
- *         return JS_FALSE;
- *
- * The second argument to the constructor is an in-out parameter. It must
- * point to a rooted jsval, such as a JSNative argument or return value slot.
- * The value in the jsval on entry is converted to a string. The constructor
- * may overwrite that jsval with a string value, to protect the characters of
- * the string from garbage collection. The caller must leave the jsval alone
- * for the lifetime of the xpc_qsDOMString.
- */
-class xpc_qsDOMString : public xpc_qsBasicString<nsAString, nsDependentString>
-{
-public:
     /* Enum that defines how JS |null| and |undefined| should be treated.  See
      * the WebIDL specification.  eStringify means convert to the string "null"
      * or "undefined" respectively, via the standard JS ToString() operation;
      * eEmpty means convert to the string ""; eNull means convert to an empty
      * string with the void bit set.
      *
      * Per webidl the default behavior of an unannotated interface is
      * eStringify, but our de-facto behavior has been eNull for |null| and
@@ -355,16 +328,98 @@ public:
     enum StringificationBehavior {
         eStringify,
         eEmpty,
         eNull,
         eDefaultNullBehavior = eNull,
         eDefaultUndefinedBehavior = eStringify
     };
 
+protected:
+    /*
+     * Neither field is initialized; that is left to the derived class
+     * constructor. However, the destructor destroys the string object
+     * stored in mBuf, if mValid is true.
+     */
+    void *mBuf[JS_HOWMANY(sizeof(implementation_type), sizeof(void *))];
+    JSBool mValid;
+
+    /*
+     * If null is returned, then we either failed or fully initialized
+     * |this|; in either case the caller should return immediately
+     * without doing anything else. Otherwise, the JSString* created
+     * from |v| will be returned.  It'll be rooted, as needed, in
+     * *pval.  nullBehavior and undefinedBehavior control what happens
+     * when |v| is JSVAL_IS_NULL and JSVAL_IS_VOID respectively.
+     */
+    template<class traits>
+    JSString* InitOrStringify(JSContext* cx, jsval v, jsval* pval,
+                              StringificationBehavior nullBehavior,
+                              StringificationBehavior undefinedBehavior) {
+        JSString *s;
+        if(JSVAL_IS_STRING(v))
+        {
+            s = JSVAL_TO_STRING(v);
+        }
+        else
+        {
+            StringificationBehavior behavior = eStringify;
+            if(JSVAL_IS_NULL(v))
+            {
+                behavior = nullBehavior;
+            }
+            else if(JSVAL_IS_VOID(v))
+            {
+                behavior = undefinedBehavior;
+            }
+
+            // If pval is null, that means the argument was optional and
+            // not passed; turn those into void strings if they're
+            // supposed to be stringified.
+            if (behavior != eStringify || !pval)
+            {
+                // Here behavior == eStringify implies !pval, so both eNull and
+                // eStringify should end up with void strings.
+                (new(mBuf) implementation_type(
+                    traits::sEmptyBuffer, PRUint32(0)))->
+                    SetIsVoid(behavior != eEmpty);
+                mValid = JS_TRUE;
+                return nsnull;
+            }
+
+            s = JS_ValueToString(cx, v);
+            if(!s)
+            {
+                mValid = JS_FALSE;
+                return nsnull;
+            }
+            *pval = STRING_TO_JSVAL(s);  // Root the new string.
+        }
+
+        return s;
+    }
+};
+
+/**
+ * Class for converting a jsval to DOMString.
+ *
+ *     xpc_qsDOMString arg0(cx, &argv[0]);
+ *     if (!arg0.IsValid())
+ *         return JS_FALSE;
+ *
+ * The second argument to the constructor is an in-out parameter. It must
+ * point to a rooted jsval, such as a JSNative argument or return value slot.
+ * The value in the jsval on entry is converted to a string. The constructor
+ * may overwrite that jsval with a string value, to protect the characters of
+ * the string from garbage collection. The caller must leave the jsval alone
+ * for the lifetime of the xpc_qsDOMString.
+ */
+class xpc_qsDOMString : public xpc_qsBasicString<nsAString, nsDependentString>
+{
+public:
     xpc_qsDOMString(JSContext *cx, jsval v, jsval *pval,
                     StringificationBehavior nullBehavior,
                     StringificationBehavior undefinedBehavior);
 };
 
 /**
  * The same as xpc_qsDOMString, but with slightly different conversion behavior,
  * corresponding to the [astring] magic XPIDL annotation rather than [domstring].
@@ -382,16 +437,26 @@ public:
  * with [cstring] rather than [domstring] or [astring].
  */
 class xpc_qsACString : public xpc_qsBasicString<nsACString, nsCString>
 {
 public:
     xpc_qsACString(JSContext *cx, jsval v, jsval *pval);
 };
 
+/**
+ * And similar for AUTF8String.
+ */
+class xpc_qsAUTF8String :
+  public xpc_qsBasicString<nsACString, NS_ConvertUTF16toUTF8>
+{
+public:
+  xpc_qsAUTF8String(JSContext* cx, jsval v, jsval *pval);
+};
+
 struct xpc_qsSelfRef
 {
     xpc_qsSelfRef() : ptr(nsnull) {}
     explicit xpc_qsSelfRef(nsISupports *p) : ptr(p) {}
     ~xpc_qsSelfRef() { NS_IF_RELEASE(ptr); }
 
     nsISupports* ptr;
 };