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
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 */