Bug 560643 - Part 3, add support for jsval XPIDL type. r=jst, sr=jst.
authorJason Orendorff <jorendorff@mozilla.com>
Fri, 18 Jun 2010 15:29:21 -0500
changeset 46230 699c59338e5c9e17de8d4be48116dd76ebe28e50
parent 46229 70f2ce61987656e914d7a154bbbf19c6371a16d3
child 46231 8ffaff868ccfb4d12bfcbfb3e086e7072114f30b
push idunknown
push userunknown
push dateunknown
reviewersjst, jst
bugs560643
milestone1.9.3a6pre
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 560643 - Part 3, add support for jsval XPIDL type. r=jst, sr=jst.
js/src/xpconnect/src/qsgen.py
js/src/xpconnect/src/xpcconvert.cpp
js/src/xpconnect/src/xpcwrappednative.cpp
xpcom/base/nsrootidl.idl
xpcom/idl-parser/xpidl.py
xpcom/reflect/xptcall/public/xptcall.h
xpcom/reflect/xptinfo/public/xptinfo.h
xpcom/typelib/xpidl/xpidl_typelib.c
xpcom/typelib/xpidl/xpidl_util.c
xpcom/typelib/xpt/public/xpt_struct.h
--- a/js/src/xpconnect/src/qsgen.py
+++ b/js/src/xpconnect/src/qsgen.py
@@ -477,17 +477,20 @@ argumentUnboxingTemplates = {
     'wstring':
         "    PRUnichar *${name};\n"
         "    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"
+        "        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.
 #
 def writeArgumentUnboxing(f, i, name, type, haveCcx, optional, rvdeclared,
@@ -571,44 +574,48 @@ def writeArgumentUnboxing(f, i, name, ty
     else:
         src = 'argv[%d]' % i
     f.write("    !; // TODO - Unbox argument %s = %s\n" % (name, src))
     return rvdeclared
 
 def writeResultDecl(f, type, varname):
     if isVoidType(type):
         return  # nothing to declare
-    
+
     t = unaliasType(type)
     if t.kind == 'builtin':
         if not t.nativename.endswith('*'):
             if type.kind == 'typedef':
                 typeName = type.name  # use it
             else:
                 typeName = t.nativename
             f.write("    %s %s;\n" % (typeName, varname))
             return
     elif t.kind == 'native':
         name = getBuiltinOrNativeTypeName(t)
         if name in ('[domstring]', '[astring]'):
             f.write("    nsString %s;\n" % varname)
             return
+        elif name == '[jsval]':
+            return  # nothing to declare; see special case in outParamForm
     elif t.kind in ('interface', 'forward'):
         f.write("    nsCOMPtr<%s> %s;\n" % (type.name, varname))
         return
 
     warn("Unable to declare result of type %s" % type.name)
     f.write("    !; // TODO - Declare out parameter `%s`.\n" % varname)
 
 def outParamForm(name, type):
     type = unaliasType(type)
     if type.kind == 'builtin':
         return '&' + name
     elif type.kind == 'native':
-        if type.modifier == 'ref':
+        if getBuiltinOrNativeTypeName(type) == '[jsval]':
+            return 'vp'
+        elif type.modifier == 'ref':
             return name
         else:
             return '&' + name
     else:
         return 'getter_AddRefs(%s)' % name
 
 # From NativeData2JS.
 resultConvTemplates = {
@@ -649,17 +656,22 @@ resultConvTemplates = {
     'boolean':
         "    ${jsvalRef} = (result ? JSVAL_TRUE : JSVAL_FALSE);\n"
         "    return JS_TRUE;\n",
 
     '[astring]':
         "    return xpc_qsStringToJsval(cx, result, ${jsvalPtr});\n",
 
     '[domstring]':
-        "    return xpc_qsStringToJsval(cx, result, ${jsvalPtr});\n"
+        "    return xpc_qsStringToJsval(cx, result, ${jsvalPtr});\n",
+
+    '[jsval]':
+        # Here there's nothing to convert, because the result has already been
+        # written directly to *rv. See the special case in outParamForm.
+        "    return JS_TRUE;\n"
     }
 
 def isVariantType(t):
     return isSpecificInterfaceType(t, 'nsIVariant')
 
 def writeResultConv(f, type, jsvalPtr, jsvalRef):
     """ Emit code to convert the C++ variable `result` to a jsval.
 
@@ -982,86 +994,62 @@ def writeQuickStub(f, customMethodCalls,
     # Epilog.
     f.write("}\n\n")
 
     # Now write out the call to the template function.
     if customMethodCall is not None:
         f.write(callTemplate)
 
 # Only these types can be returned (note: no strings);
-# if the type isn't one of these, then traceTypeMap['_default'] is used
+# if the type isn't one of these, then defaultTraceType is used
 traceReturnTypeMap = {
-    'void':
-        ["jsval ", "JSVAL", "JSVAL_VOID"],
-    'boolean':
-        ["JSBool ", "BOOL", "JS_FALSE"],
-    'short':
-        ["int32 ", "INT32", "0"],
-    'unsigned short':
-        ["uint32 ", "UINT32", "0"],
-    'long':
-        ["int32 ", "INT32", "0"],
-    'unsigned long':
-        ["uint32 ", "UINT32", "0"],
-    'float':
-        ["jsdouble ", "DOUBLE", "0"],
-    'double':
-        ["jsdouble ", "DOUBLE", "0"],
-    'octet':
-        ["uint32 ", "UINT32", "0"]
+    'void':             ("jsval ", "JSVAL", "JSVAL_VOID"),
+    'boolean':          ("JSBool ", "BOOL", "JS_FALSE"),
+    'short':            ("int32 ", "INT32", "0"),
+    'unsigned short':   ("uint32 ", "UINT32", "0"),
+    'long':             ("int32 ", "INT32", "0"),
+    'unsigned long':    ("uint32 ", "UINT32", "0"),
+    'float':            ("jsdouble ", "DOUBLE", "0"),
+    'double':           ("jsdouble ", "DOUBLE", "0"),
+    'octet':            ("uint32 ", "UINT32", "0"),
+    'jsval':            ("jsval ", "JSVAL", "JSVAL_VOID")
     }
 
 # This list extends the above list, but includes types that
-# are valid for arguments only, namely strings.  It also
-# includes the default jsval type.
-traceTypeMap = {
-    '[astring]':
-        ["JSString *", "STRING", "nsnull"],
-    '[domstring]':
-        ["JSString *", "STRING", "nsnull"],
-    '[cstring]':
-        ["JSString *", "STRING", "nsnull"],
-    'string':
-        ["JSString *", "STRING", "nsnull"],
-    'wstring':
-        ["JSString *", "STRING", "nsnull"],
+# are valid for arguments only, namely strings.
+traceTypeMap = traceReturnTypeMap.copy()
+traceTypeMap.update({
+    '[astring]':        ("JSString *", "STRING", "nsnull"),
+    '[domstring]':      ("JSString *", "STRING", "nsnull"),
+    '[cstring]':        ("JSString *", "STRING", "nsnull"),
+    'string':           ("JSString *", "STRING", "nsnull"),
+    'wstring':          ("JSString *", "STRING", "nsnull"),
+    })
 
-    '_default':
-        ["jsval ", "JSVAL", "JSVAL_VOID"]
-    }
+defaultTraceType = ("jsval ", "JSVAL", "JSVAL_VOID")
 
 def getTraceType(type):
     type = getBuiltinOrNativeTypeName(type)
-    traceType = traceReturnTypeMap.get(type) or traceTypeMap.get(type) or traceTypeMap.get("_default")
-    assert traceType
-    return traceType[0]
+    return traceTypeMap.get(type, defaultTraceType)[0]
 
 def getTraceReturnType(type):
     type = getBuiltinOrNativeTypeName(type)
-    traceType = traceReturnTypeMap.get(type) or traceTypeMap.get("_default")
-    assert traceType
-    return traceType[0]
+    return traceReturnTypeMap.get(type, defaultTraceType)[0]
 
 def getTraceInfoType(type):
     type = getBuiltinOrNativeTypeName(type)
-    traceType = traceReturnTypeMap.get(type) or traceTypeMap.get(type) or traceTypeMap.get("_default")
-    assert traceType
-    return traceType[1]
+    return traceTypeMap.get(type, defaultTraceType)[1]
 
 def getTraceInfoReturnType(type):
     type = getBuiltinOrNativeTypeName(type)
-    traceType = traceReturnTypeMap.get(type) or traceTypeMap.get("_default")
-    assert traceType
-    return traceType[1]
+    return traceReturnTypeMap.get(type, defaultTraceType)[1]
 
 def getTraceInfoDefaultReturn(type):
     type = getBuiltinOrNativeTypeName(type)
-    traceType = traceTypeMap.get(type) or traceTypeMap.get("_default")
-    assert traceType
-    return traceType[2]
+    return traceTypeMap.get(type, defaultTraceType)[2]
 
 def getFailureString(retval, indent):
     assert indent > 0
     ret = " " * (4 * indent)
     ret += "js_SetTraceableNativeFailed(cx);\n"
     ret += " " * (4 * indent)
     ret += "return %s;\n" % retval
     ret += " " * (4 * (indent - 1))
@@ -1137,17 +1125,17 @@ def writeTraceableArgumentConversion(f, 
             pass
         else:
             if not rvdeclared:
                 f.write("    nsresult rv;\n");
             f.write("    %s *%s;\n" % (type.name, name))
             f.write("    xpc_qsSelfRef %sref;\n" % name)
             f.write("    rv = xpc_qsUnwrapArg<%s>("
                     "cx, %s, &%s, &%sref.ptr, &vp.array[%d]);\n"
-                    % (type.name, argVal, name, name, 1 + i))
+                    % (type.name, argVal, name, name, 2 + i))
             f.write("    if (NS_FAILED(rv)) {\n")
             if haveCcx:
                 f.write("        xpc_qsThrowBadArgWithCcx(ccx, rv, %d);\n" % i)
             else:
                 # XXX Fix this to return a real error!
                 f.write("        xpc_qsThrowBadArgWithDetails(cx, rv, %d, "
                         "\"%s\", \"%s\");\n"
                         % (i, member.iface.name, member.name))
@@ -1183,16 +1171,18 @@ traceableResultConvTemplates = {
         "    if (!xpc_qsStringToJsval(cx, result, &rval)) {\n"
         "        JS_ReportOutOfMemory(cx);\n${errorStr}"
         "    return rval;\n",
     '[astring]':
         "    jsval rval;\n"
         "    if (!xpc_qsStringToJsval(cx, result, &rval)) {\n"
         "        JS_ReportOutOfMemory(cx);\n${errorStr}"
         "    return rval;\n",
+    '[jsval]':
+        "    return vp.array[0];\n"
     }
 
 def writeTraceableResultConv(f, type):
     typeName = getBuiltinOrNativeTypeName(type)
     if typeName is not None:
         template = traceableResultConvTemplates.get(typeName)
         if template is not None:
             values = { 'errorStr': getFailureString(
@@ -1259,27 +1249,27 @@ def writeTraceableQuickStub(f, customMet
             f.write("    XPCLazyCallContext lccx(ccx);\n")
 
     # Get the 'self' pointer.
     if customMethodCall is None or not 'thisType' in customMethodCall:
         f.write("    %s *self;\n" % member.iface.name)
     else:
         f.write("    %s *self;\n" % customMethodCall['thisType'])
     f.write("    xpc_qsSelfRef selfref;\n")
-    f.write("    xpc_qsArgValArray<%d> vp(cx);\n" % (1 + len(member.params)))
+    f.write("    xpc_qsArgValArray<%d> vp(cx);\n" % (2 + len(member.params)))
     if haveCcx:
         f.write("    if (!xpc_qsUnwrapThisFromCcx(ccx, &self, &selfref.ptr, "
-                "&vp.array[0])) {\n")
+                "&vp.array[1])) {\n")
     elif (member.kind == 'method') and isInterfaceType(member.realtype):
         f.write("    XPCLazyCallContext lccx(JS_CALLER, cx, obj);\n")
         f.write("    if (!xpc_qsUnwrapThis(cx, obj, callee, &self, &selfref.ptr, "
-                "&vp.array[0], &lccx)) {\n")
+                "&vp.array[1], &lccx)) {\n")
     else:
         f.write("    if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, "
-                "&vp.array[0], nsnull)) {\n")
+                "&vp.array[1], nsnull)) {\n")
     writeFailure(f, getTraceInfoDefaultReturn(member.realtype), 2)
 
     argNames = []
 
     # Convert in-parameters.
     rvdeclared = False
     for i, param in enumerate(member.params):
         argName = "arg%d" % i
@@ -1309,17 +1299,19 @@ def writeTraceableQuickStub(f, customMet
         selfname = prefix + 'self'
         nsresultname = prefix + 'rv'
 
         # Prepare out-parameter.
         writeResultDecl(f, member.realtype, resultname)
 
         # Call the method.
         comName = header.methodNativeName(member)
-        if not isVoidType(member.realtype):
+        if getBuiltinOrNativeTypeName(member.realtype) == '[jsval]':
+            argNames.append("&vp.array[0]")
+        elif not isVoidType(member.realtype):
             argNames.append(outParamForm(resultname, member.realtype))
         args = ', '.join(argNames)
 
         f.write("    ")
         if canFail:
             f.write("%s = " % nsresultname)
         f.write("%s->%s(%s);\n" % (selfname, comName, args))
 
--- a/js/src/xpconnect/src/xpcconvert.cpp
+++ b/js/src/xpconnect/src/xpcconvert.cpp
@@ -108,17 +108,17 @@ static uint8 xpc_reflectable_flags[XPC_F
     XPC_MK_FLAG(  0  ,  1  ,   0 ,  1 ), /* T_INTERFACE         */
     XPC_MK_FLAG(  0  ,  1  ,   0 ,  1 ), /* T_INTERFACE_IS      */
     XPC_MK_FLAG(  0  ,  1  ,   0 ,  1 ), /* T_ARRAY             */
     XPC_MK_FLAG(  0  ,  1  ,   0 ,  1 ), /* T_PSTRING_SIZE_IS   */
     XPC_MK_FLAG(  0  ,  1  ,   0 ,  1 ), /* T_PWSTRING_SIZE_IS  */
     XPC_MK_FLAG(  0  ,  1  ,   0 ,  0 ), /* T_UTF8STRING        */
     XPC_MK_FLAG(  0  ,  1  ,   0 ,  0 ), /* T_CSTRING           */
     XPC_MK_FLAG(  0  ,  1  ,   0 ,  0 ), /* T_ASTRING           */
-    XPC_MK_FLAG(  0  ,  0  ,   0 ,  0 ), /* 26 - reserved       */
+    XPC_MK_FLAG(  1  ,  0  ,   1 ,  0 ), /* T_JSVAL             */
     XPC_MK_FLAG(  0  ,  0  ,   0 ,  0 ), /* 27 - reserved       */
     XPC_MK_FLAG(  0  ,  0  ,   0 ,  0 ), /* 28 - reserved       */
     XPC_MK_FLAG(  0  ,  0  ,   0 ,  0 ), /* 29 - reserved       */
     XPC_MK_FLAG(  0  ,  0  ,   0 ,  0 ), /* 30 - reserved       */
     XPC_MK_FLAG(  0  ,  0  ,   0 ,  0 )  /* 31 - reserved       */
     };
 
 static intN sXPCOMUCStringFinalizerIndex = -1;
@@ -287,16 +287,21 @@ XPCConvert::NativeData2JS(XPCLazyCallCon
             if(!p)
                 return JS_FALSE;
             JSString* str;
             if(!(str = JS_NewUCStringCopyN(cx, p, 1)))
                 return JS_FALSE;
             *d = STRING_TO_JSVAL(str);
             break;
         }
+
+    case nsXPTType::T_JSVAL :
+        *d = *((jsval*)s);
+        break;
+
     default:
         if(!type.IsPointer())
         {
             XPC_LOG_ERROR(("XPCConvert::NativeData2JS : unsupported type"));
             return JS_FALSE;
         }
 
         // set the default result
@@ -475,16 +480,17 @@ XPCConvert::NativeData2JS(XPCLazyCallCon
                     JSObject* jsobj = JSVAL_TO_OBJECT(*d);
                     if(jsobj && !jsobj->getParent())
                         NS_ASSERTION(jsobj->getClass()->flags & JSCLASS_IS_GLOBAL,
                                      "Why did we recreate this wrapper?");
 #endif
                 }
                 break;
             }
+
         default:
             NS_ERROR("bad type");
             return JS_FALSE;
         }
     }
     return JS_TRUE;
 }
 
@@ -612,16 +618,19 @@ XPCConvert::JSData2Native(XPCCallContext
             if(!(str = JS_ValueToString(cx, s))||
                !(chars = JS_GetStringChars(str)))
             {
                 return JS_FALSE;
             }
             *((uint16*)d)  = (uint16) chars[0];
             break;
         }
+    case nsXPTType::T_JSVAL :
+        *((jsval*)d) = s;
+        break;
     default:
         if(!type.IsPointer())
         {
             NS_ERROR("unsupported type");
             return JS_FALSE;
         }
 
         switch(type.TagPart())
--- a/js/src/xpconnect/src/xpcwrappednative.cpp
+++ b/js/src/xpconnect/src/xpcwrappednative.cpp
@@ -2375,18 +2375,21 @@ CallMethodHelper::~CallMethodHelper()
             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;
-        }
+            else if(dp->IsValJSRoot())
+                JS_RemoveRoot(mCallContext, (jsval*)dp->ptr);
+        }   
     }
+
 }
 
 JSBool
 CallMethodHelper::GetArrayInfoFromParam(uint8 paramIndex, SizeMode mode,
                                         JSUint32* result) const
 {
     nsresult rv;
     const nsXPTParamInfo& paramInfo = mMethodInfo->GetParam(paramIndex);
@@ -2560,17 +2563,17 @@ CallMethodHelper::GatherAndConvertResult
             {
                 ThrowBadParam(err, i, mCallContext);
                 return JS_FALSE;
             }
         }
 
         if(paramInfo.IsRetval())
         {
-            if(!mCallContext.GetReturnValueWasSet())
+            if(!mCallContext.GetReturnValueWasSet() && type.TagPart() != nsXPTType::T_JSVAL)
                 mCallContext.SetRetVal(v);
         }
         else if(i < mArgc)
         {
             // we actually assured this before doing the invoke
             NS_ASSERTION(JSVAL_IS_OBJECT(mArgv[i]), "out var is not object");
             if(!JS_SetPropertyById(mCallContext,
                                    JSVAL_TO_OBJECT(mArgv[i]),
@@ -2724,16 +2727,32 @@ CallMethodHelper::ConvertIndependentPara
         if (!GetOutParamSource(i, &src))
             return JS_FALSE;
 
         if(paramInfo.IsOut())
         {
             dp->SetPtrIsData();
             dp->ptr = &dp->val;
 
+            if (type_tag == nsXPTType::T_JSVAL)
+            {
+                if (paramInfo.IsRetval())
+                {
+                    dp->ptr = mCallContext.GetRetVal();
+                }
+                else
+                {
+                    jsval *rootp = (jsval *)&dp->val.p;
+                    dp->ptr = rootp;
+                    *rootp = JSVAL_VOID;
+                    if (!JS_AddRoot(mCallContext, rootp))
+                        return JS_FALSE;
+                }
+            }
+
             if(type.IsPointer() &&
                type_tag != nsXPTType::T_INTERFACE &&
                !paramInfo.IsShared())
             {
                 useAllocator = JS_TRUE;
                 dp->SetValIsAllocated();
             }
 
--- a/xpcom/base/nsrootidl.idl
+++ b/xpcom/base/nsrootidl.idl
@@ -115,16 +115,16 @@ typedef unsigned long       size_t;
 [ref, cstring] native ACString(ignored);
 [ref, cstring] native ACStringRef(ignored);
 [ptr, cstring] native ACStringPtr(ignored);
 
 [ref, astring] native AString(ignored);
 [ref, astring] native AStringRef(ignored);
 [ptr, astring] native AStringPtr(ignored);
 
-native jsval(jsval);
+[jsval]       native jsval(jsval);
 
 %{C++
 /* 
  * End commenting out the C++ versions of the above in the output header
  */
 #endif
 %}
--- a/xpcom/idl-parser/xpidl.py
+++ b/xpcom/idl-parser/xpidl.py
@@ -400,17 +400,18 @@ class Native(object):
     modifier = None
     specialtype = None
 
     specialtypes = {
         'nsid': None,
         'domstring': 'nsAString',
         'utf8string': 'nsACString',
         'cstring': 'nsACString',
-        'astring': 'nsAString'
+        'astring': 'nsAString',
+        'jsval': 'jsval'
         }
 
     def __init__(self, name, nativename, attlist, location):
         self.name = name
         self.nativename = nativename
         self.location = location
 
         for name, value, aloc in attlist:
--- a/xpcom/reflect/xptcall/public/xptcall.h
+++ b/xpcom/reflect/xptcall/public/xptcall.h
@@ -90,35 +90,38 @@ struct nsXPTCVariant : public nsXPTCMini
     {
         // these are bitflags!
         PTR_IS_DATA    = 0x1,  // ptr points to 'real' data in val
         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_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
     };
 
     void ClearFlags()         {flags = 0;}
     void SetPtrIsData()       {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 SetValIsCString()    {flags |= VAL_IS_CSTR;}
+    void SetValIsJSRoot()     {flags |= VAL_IS_JSROOT;}
 
     PRBool IsPtrData()       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);}
 
     void Init(const nsXPTCMiniVariant& mv, const nsXPTType& t, PRUint8 f)
     {
         type = t;
         flags = f;
 
         if(f & PTR_IS_DATA)
         {
--- a/xpcom/reflect/xptinfo/public/xptinfo.h
+++ b/xpcom/reflect/xptinfo/public/xptinfo.h
@@ -136,17 +136,18 @@ public:
         T_WCHAR_STR         = TD_PWSTRING         ,
         T_INTERFACE         = TD_INTERFACE_TYPE   ,
         T_INTERFACE_IS      = TD_INTERFACE_IS_TYPE,
         T_ARRAY             = TD_ARRAY            ,
         T_PSTRING_SIZE_IS   = TD_PSTRING_SIZE_IS  ,
         T_PWSTRING_SIZE_IS  = TD_PWSTRING_SIZE_IS ,
         T_UTF8STRING        = TD_UTF8STRING       ,
         T_CSTRING           = TD_CSTRING          ,
-        T_ASTRING           = TD_ASTRING
+        T_ASTRING           = TD_ASTRING          ,
+        T_JSVAL             = TD_JSVAL
     };
 // NO DATA - this a flyweight wrapper
 };
 
 class nsXPTParamInfo : public XPTParamDescriptor
 {
 // NO DATA - this a flyweight wrapper
 public:
--- a/xpcom/typelib/xpidl/xpidl_typelib.c
+++ b/xpcom/typelib/xpidl/xpidl_typelib.c
@@ -869,16 +869,20 @@ handle_iid_is:
                   } else if (IDL_tree_property_get(type, "utf8string")) {
                       td->prefix.flags = TD_UTF8STRING | XPT_TDP_POINTER;
                       if (IDL_tree_property_get(type, "ref"))
                           td->prefix.flags |= XPT_TDP_REFERENCE;
                   } else if (IDL_tree_property_get(type, "cstring")) {
                       td->prefix.flags = TD_CSTRING | XPT_TDP_POINTER;
                       if (IDL_tree_property_get(type, "ref"))
                           td->prefix.flags |= XPT_TDP_REFERENCE;
+                  } else if (IDL_tree_property_get(type, "jsval")) {
+                      td->prefix.flags = TD_JSVAL;
+                      if (IDL_tree_property_get(type, "ptr"))
+                          td->prefix.flags |= XPT_TDP_POINTER;
                   } else {
                       td->prefix.flags = TD_VOID | XPT_TDP_POINTER;
                   }
                   break;
                 }
               default:
                 if (IDL_NODE_TYPE(IDL_NODE_UP(up)) == IDLN_TYPE_DCL) {
                     /* restart with the underlying type */
--- a/xpcom/typelib/xpidl/xpidl_util.c
+++ b/xpcom/typelib/xpidl/xpidl_util.c
@@ -368,17 +368,18 @@ verify_attribute_declaration(IDL_tree at
 
     if (attr_type != NULL)
     {
         if (UP_IS_NATIVE(attr_type) &&
             IDL_tree_property_get(attr_type, "nsid") == NULL &&
             IDL_tree_property_get(attr_type, "domstring") == NULL &&
             IDL_tree_property_get(attr_type, "utf8string") == NULL &&
             IDL_tree_property_get(attr_type, "cstring") == NULL &&
-            IDL_tree_property_get(attr_type, "astring") == NULL)
+            IDL_tree_property_get(attr_type, "astring") == NULL &&
+            IDL_tree_property_get(attr_type, "jsval") == NULL)
         {
             IDL_tree_error(attr_tree,
                            "attributes in [scriptable] interfaces that are "
                            "non-scriptable because they refer to native "
                            "types must be marked [noscript]\n");
             return FALSE;
         }
         /*
@@ -618,17 +619,18 @@ verify_method_declaration(IDL_tree metho
          */
         if (scriptable_method &&
             UP_IS_NATIVE(param_type) &&
             IDL_tree_property_get(param_type, "nsid") == NULL &&
             IDL_tree_property_get(simple_decl, "iid_is") == NULL &&
             IDL_tree_property_get(param_type, "domstring") == NULL &&
             IDL_tree_property_get(param_type, "utf8string") == NULL &&
             IDL_tree_property_get(param_type, "cstring") == NULL &&
-            IDL_tree_property_get(param_type, "astring") == NULL)
+            IDL_tree_property_get(param_type, "astring") == NULL &&
+            IDL_tree_property_get(param_type, "jsval") == NULL)
         {
             IDL_tree_error(method_tree,
                            "methods in [scriptable] interfaces that are "
                            "non-scriptable because they refer to native "
                            "types (parameter \"%s\") must be marked "
                            "[noscript]", param_name);
             return FALSE;
         }
@@ -695,17 +697,18 @@ verify_method_declaration(IDL_tree metho
 
             if (!(IDL_NODE_TYPE(real_type) == IDLN_TYPE_STRING ||
                   IDL_NODE_TYPE(real_type) == IDLN_TYPE_WIDE_STRING ||
                   (UP_IS_NATIVE(real_type) &&
                    !IDL_tree_property_get(real_type, "nsid") &&
                    !IDL_tree_property_get(real_type, "domstring")  &&
                    !IDL_tree_property_get(real_type, "utf8string") &&
                    !IDL_tree_property_get(real_type, "cstring")    &&
-                   !IDL_tree_property_get(real_type, "astring"))))
+                   !IDL_tree_property_get(real_type, "astring")    &&
+                   !IDL_tree_property_get(real_type, "jsval"))))
             {
                 IDL_tree_error(method_tree,
                                "[shared] parameter \"%s\" must be of type "
                                "string, wstring or native", param_name);
                 return FALSE;
             }
         }
 
@@ -780,17 +783,18 @@ verify_method_declaration(IDL_tree metho
     /* XXX q: can return type be nsid? */
     /* Native return type? */
     if (scriptable_method &&
         op->op_type_spec != NULL && UP_IS_NATIVE(op->op_type_spec) &&
         IDL_tree_property_get(op->op_type_spec, "nsid") == NULL &&
         IDL_tree_property_get(op->op_type_spec, "domstring") == NULL &&
         IDL_tree_property_get(op->op_type_spec, "utf8string") == NULL &&
         IDL_tree_property_get(op->op_type_spec, "cstring") == NULL &&
-        IDL_tree_property_get(op->op_type_spec, "astring") == NULL)
+        IDL_tree_property_get(op->op_type_spec, "astring") == NULL &&
+        IDL_tree_property_get(op->op_type_spec, "jsval") == NULL)
     {
         IDL_tree_error(method_tree,
                        "methods in [scriptable] interfaces that are "
                        "non-scriptable because they return native "
                        "types must be marked [noscript]");
         return FALSE;
     }
 
--- a/xpcom/typelib/xpt/public/xpt_struct.h
+++ b/xpcom/typelib/xpt/public/xpt_struct.h
@@ -370,17 +370,18 @@ enum XPTTypeDescriptorTags {
     TD_PWSTRING          = 17,
     TD_INTERFACE_TYPE    = 18,
     TD_INTERFACE_IS_TYPE = 19,
     TD_ARRAY             = 20,
     TD_PSTRING_SIZE_IS   = 21,
     TD_PWSTRING_SIZE_IS  = 22,
     TD_UTF8STRING        = 23,
     TD_CSTRING           = 24,
-    TD_ASTRING           = 25
+    TD_ASTRING           = 25,
+    TD_JSVAL             = 26
 };
 
 struct XPTTypeDescriptor {
     XPTTypeDescriptorPrefix prefix;
     PRUint8 argnum;                 /* used for iid_is and size_is */
     PRUint8 argnum2;                /* used for length_is */
     union {                         
         PRUint16 iface;             /* used for TD_INTERFACE_TYPE */