Bug 1526382 - Part 1: Split nsID& and nsID* in xpconnect, r=mccr8
authorNika Layzell <nika@thelayzells.com>
Wed, 13 Feb 2019 21:42:00 +0000
changeset 459063 9b2bfb8871c9
parent 459062 cd616c3e3eea
child 459064 b4258349e68b
push id111913
push usershindli@mozilla.com
push dateThu, 14 Feb 2019 05:01:59 +0000
treeherdermozilla-inbound@a0752d7e8073 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmccr8
bugs1526382
milestone67.0a1
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 1526382 - Part 1: Split nsID& and nsID* in xpconnect, r=mccr8 Currently the [ref] and [ptr] types share the same underlying implementation. This is unfortunate, and can cause correctness problems with outparam refs (as an example). By using the same tools used to allow other larger objects (such as jsid, nsTArray, and nsString) to be stored directly in the nsXPTCVariant object, this patch directly stores the nsID in the nsXPTCVariant object when calling from JS into C++. Using this new strategy avoids an nsID* allocation every time we pass one over XPConnect, and should also allow us to simplify callers. In addition, some special casing is added to xpidl to make it possible to use the nsid reference type objects directly inside of Array<T>, which will allow us to remove `[array] nsIIDPtr` callers. Differential Revision: https://phabricator.services.mozilla.com/D19175
js/xpconnect/src/XPCConvert.cpp
js/xpconnect/src/XPCVariant.cpp
js/xpconnect/src/XPCWrappedJSClass.cpp
js/xpconnect/src/XPCWrappedNative.cpp
js/xpconnect/src/xpcprivate.h
xpcom/ds/nsIVariant.idl
xpcom/idl-parser/xpidl/jsonxpt.py
xpcom/idl-parser/xpidl/xpidl.py
xpcom/reflect/xptcall/xptcall.h
xpcom/reflect/xptinfo/xptcodegen.py
xpcom/reflect/xptinfo/xptinfo.h
--- a/js/xpconnect/src/XPCConvert.cpp
+++ b/js/xpconnect/src/XPCConvert.cpp
@@ -170,26 +170,29 @@ bool XPCConvert::NativeData2JS(MutableHa
       d.set(*static_cast<const Value*>(s));
       return JS_WrapValue(cx, d);
     }
 
     case nsXPTType::T_VOID:
       XPC_LOG_ERROR(("XPCConvert::NativeData2JS : void* params not supported"));
       return false;
 
-    case nsXPTType::T_IID: {
+    case nsXPTType::T_NSIDPTR: {
       nsID* iid2 = *static_cast<nsID* const*>(s);
       if (!iid2) {
         d.setNull();
         return true;
       }
 
       return xpc::ID2JSValue(cx, *iid2, d);
     }
 
+    case nsXPTType::T_NSID:
+      return xpc::ID2JSValue(cx, *static_cast<const nsID*>(s), d);
+
     case nsXPTType::T_ASTRING: {
       const nsAString* p = static_cast<const nsAString*>(s);
       if (!p || p->IsVoid()) {
         d.setNull();
         return true;
       }
 
       nsStringBuffer* buf;
@@ -537,23 +540,30 @@ bool XPCConvert::JSData2Native(JSContext
     case nsXPTType::T_JSVAL:
       *((Value*)d) = s;
       break;
     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:
+    case nsXPTType::T_NSIDPTR:
       if (Maybe<nsID> id = xpc::JSValue2ID(cx, s)) {
         *((const nsID**)d) = id.ref().Clone();
         return true;
       }
       return false;
 
+    case nsXPTType::T_NSID:
+      if (Maybe<nsID> id = xpc::JSValue2ID(cx, s)) {
+        *((nsID*)d) = id.ref();
+        return true;
+      }
+      return false;
+
     case nsXPTType::T_ASTRING: {
       nsAString* ws = (nsAString*)d;
       if (s.isUndefined() || s.isNull()) {
         ws->SetIsVoid(true);
         return true;
       }
       size_t length = 0;
       JSString* str = ToString(cx, s);
@@ -1610,17 +1620,17 @@ void xpc::InnerCleanupValue(const nsXPTT
       ((nsAString*)aValue)->Truncate();
       break;
     case nsXPTType::T_UTF8STRING:
     case nsXPTType::T_CSTRING:
       ((nsACString*)aValue)->Truncate();
       break;
 
     // Pointer Types
-    case nsXPTType::T_IID:
+    case nsXPTType::T_NSIDPTR:
     case nsXPTType::T_CHAR_STR:
     case nsXPTType::T_WCHAR_STR:
     case nsXPTType::T_PSTRING_SIZE_IS:
     case nsXPTType::T_PWSTRING_SIZE_IS:
       free(*(void**)aValue);
       break;
 
     // Legacy Array Type
@@ -1642,16 +1652,21 @@ void xpc::InnerCleanupValue(const nsXPTT
 
       for (uint32_t i = 0; i < array->Length(); ++i) {
         DestructValue(elty, elty.ElementPtr(array->Elements(), i));
       }
       array->Clear();
       break;
     }
 
+    // Clear nsID& parameters to `0`
+    case nsXPTType::T_NSID:
+      ((nsID*)aValue)->Clear();
+      break;
+
     // Clear the JS::Value to `undefined`
     case nsXPTType::T_JSVAL:
       ((JS::Value*)aValue)->setUndefined();
       break;
 
     // Non-arithmetic types requiring no cleanup
     case nsXPTType::T_VOID:
       break;
--- a/js/xpconnect/src/XPCVariant.cpp
+++ b/js/xpconnect/src/XPCVariant.cpp
@@ -226,17 +226,17 @@ bool XPCArrayHomogenizer::GetTypeForArra
       break;
     case tBool:
       *resultType = nsXPTType::MkArrayType(nsXPTType::Idx::BOOL);
       break;
     case tStr:
       *resultType = nsXPTType::MkArrayType(nsXPTType::Idx::PWSTRING);
       break;
     case tID:
-      *resultType = nsXPTType::MkArrayType(nsXPTType::Idx::PNSIID);
+      *resultType = nsXPTType::MkArrayType(nsXPTType::Idx::NSIDPTR);
       break;
     case tISup:
       *resultType = nsXPTType::MkArrayType(nsXPTType::Idx::INTERFACE_IS_TYPE);
       *resultID = NS_GET_IID(nsISupports);
       break;
     case tNull:
       // FALL THROUGH
     case tVar:
@@ -461,17 +461,17 @@ bool XPCVariant::VariantDataToJS(nsIVari
       return XPCConvert::NativeData2JS(pJSVal, (const void*)&wc, {TD_WCHAR},
                                        &iid, 0, pErr);
     }
     case nsIDataType::VTYPE_ID: {
       if (NS_FAILED(variant->GetAsID(&iid))) {
         return false;
       }
       nsID* v = &iid;
-      return XPCConvert::NativeData2JS(pJSVal, (const void*)&v, {TD_PNSIID},
+      return XPCConvert::NativeData2JS(pJSVal, (const void*)&v, {TD_NSIDPTR},
                                        &iid, 0, pErr);
     }
     case nsIDataType::VTYPE_ASTRING: {
       nsAutoString astring;
       if (NS_FAILED(variant->GetAsAString(astring))) {
         return false;
       }
       return XPCConvert::NativeData2JS(pJSVal, &astring, {TD_ASTRING}, &iid, 0,
@@ -607,17 +607,17 @@ bool XPCVariant::VariantDataToJS(nsIVari
           break;
         case nsIDataType::VTYPE_CHAR:
           xptIndex = nsXPTType::Idx::CHAR;
           break;
         case nsIDataType::VTYPE_WCHAR:
           xptIndex = nsXPTType::Idx::WCHAR;
           break;
         case nsIDataType::VTYPE_ID:
-          xptIndex = nsXPTType::Idx::PNSIID;
+          xptIndex = nsXPTType::Idx::NSIDPTR;
           break;
         case nsIDataType::VTYPE_CHAR_STR:
           xptIndex = nsXPTType::Idx::PSTRING;
           break;
         case nsIDataType::VTYPE_WCHAR_STR:
           xptIndex = nsXPTType::Idx::PWSTRING;
           break;
         case nsIDataType::VTYPE_INTERFACE:
--- a/js/xpconnect/src/XPCWrappedJSClass.cpp
+++ b/js/xpconnect/src/XPCWrappedJSClass.cpp
@@ -554,25 +554,27 @@ bool nsXPCWrappedJSClass::GetInterfaceTy
     if (!inner.GetInterface()) {
       return false;
     }
 
     *result = inner.GetInterface()->IID();
   } else if (inner.Tag() == nsXPTType::T_INTERFACE_IS) {
     // Get IID from a passed parameter.
     const nsXPTParamInfo& param = method->Param(inner.ArgNum());
-    if (param.Type().Tag() != nsXPTType::T_IID) {
+    if (param.Type().Tag() != nsXPTType::T_NSID &&
+        param.Type().Tag() != nsXPTType::T_NSIDPTR) {
       return false;
     }
 
     void* ptr = nativeParams[inner.ArgNum()].val.p;
 
-    // If the IID is passed indirectly (as an outparam), dereference by an
-    // extra level.
-    if (ptr && param.IsIndirect()) {
+    // If our IID is passed as a pointer outparameter, an extra level of
+    // dereferencing is required.
+    if (ptr && param.Type().Tag() == nsXPTType::T_NSIDPTR &&
+        param.IsIndirect()) {
       ptr = *(nsID**)ptr;
     }
 
     if (!ptr) {
       return false;
     }
 
     *result = *(nsID*)ptr;
--- a/js/xpconnect/src/XPCWrappedNative.cpp
+++ b/js/xpconnect/src/XPCWrappedNative.cpp
@@ -1257,23 +1257,33 @@ bool CallMethodHelper::GetInterfaceTypeF
   const nsXPTType& inner = type.InnermostType();
   if (inner.Tag() == nsXPTType::T_INTERFACE) {
     if (!inner.GetInterface()) {
       return Throw(NS_ERROR_XPC_CANT_GET_PARAM_IFACE_INFO, mCallContext);
     }
 
     *result = inner.GetInterface()->IID();
   } else if (inner.Tag() == nsXPTType::T_INTERFACE_IS) {
-    nsID* id = (nsID*)GetDispatchParam(inner.ArgNum())->val.p;
-    if (!id) {
+    const nsXPTCVariant* param = GetDispatchParam(inner.ArgNum());
+    if (param->type.Tag() != nsXPTType::T_NSID &&
+        param->type.Tag() != nsXPTType::T_NSIDPTR) {
+      return Throw(NS_ERROR_UNEXPECTED, mCallContext);
+    }
+
+    const void* ptr = &param->val;
+    if (param->type.Tag() == nsXPTType::T_NSIDPTR) {
+      ptr = *static_cast<nsID* const*>(ptr);
+    }
+
+    if (!ptr) {
       return ThrowBadParam(NS_ERROR_XPC_CANT_GET_PARAM_IFACE_INFO,
                            inner.ArgNum(), mCallContext);
     }
 
-    *result = *id;
+    *result = *static_cast<const nsID*>(ptr);
   }
   return true;
 }
 
 bool CallMethodHelper::GetOutParamSource(uint8_t paramIndex,
                                          MutableHandleValue srcp) const {
   const nsXPTParamInfo& paramInfo = mMethodInfo->GetParam(paramIndex);
   bool isRetval = &paramInfo == mMethodInfo->GetRetval();
@@ -1494,19 +1504,19 @@ bool CallMethodHelper::ConvertIndependen
   if (!paramInfo.IsIn()) {
     return true;
   }
 
   // Some types usually don't support default values, but we want to handle
   // the default value if IsOptional is true.
   if (i >= mArgc) {
     MOZ_ASSERT(paramInfo.IsOptional(), "missing non-optional argument!");
-    if (type.Tag() == nsXPTType::T_IID) {
-      // NOTE: 'const nsIID&' is supported, so it must be allocated.
-      dp->val.p = new nsIID();
+    if (type.Tag() == nsXPTType::T_NSID) {
+      // Use a default value of the null ID for optional NSID objects.
+      dp->ext.nsid.Clear();
       return true;
     }
   }
 
   // We're definitely some variety of 'in' now, so there's something to
   // convert. The source value for conversion depends on whether we're
   // dealing with an 'in' or an 'inout' parameter. 'inout' was handled above,
   // so all that's left is 'in'.
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -2891,17 +2891,17 @@ nsresult HasInstance(JSContext* cx, JS::
 // Returns the principal associated with |obj|'s realm. The object must not be a
 // cross-compartment wrapper.
 nsIPrincipal* GetObjectPrincipal(JSObject* obj);
 
 // Attempt to clean up the passed in value pointer. The pointer `value` must be
 // a pointer to a value described by the type `nsXPTType`.
 //
 // This method expects a value of the following types:
-//   TD_PNSIID
+//   TD_NSIDPTR
 //     value : nsID* (free)
 //   TD_ASTRING, TD_CSTRING, TD_UTF8STRING
 //     value : ns[C]String* (truncate)
 //   TD_PSTRING, TD_PWSTRING, TD_PSTRING_SIZE_IS, TD_PWSTRING_SIZE_IS
 //     value : char[16_t]** (free)
 //   TD_INTERFACE_TYPE, TD_INTERFACE_IS_TYPE
 //     value : nsISupports** (release)
 //   TD_LEGACY_ARRAY (NOTE: aArrayLen should be passed)
--- a/xpcom/ds/nsIVariant.idl
+++ b/xpcom/ds/nsIVariant.idl
@@ -28,17 +28,17 @@ struct nsIDataType
         VTYPE_UINT32            = TD_UINT32           ,
         VTYPE_UINT64            = TD_UINT64           ,
         VTYPE_FLOAT             = TD_FLOAT            ,
         VTYPE_DOUBLE            = TD_DOUBLE           ,
         VTYPE_BOOL              = TD_BOOL             ,
         VTYPE_CHAR              = TD_CHAR             ,
         VTYPE_WCHAR             = TD_WCHAR            ,
         VTYPE_VOID              = TD_VOID             ,
-        VTYPE_ID                = TD_PNSIID           ,
+        VTYPE_ID                = TD_NSIDPTR          ,
         VTYPE_CHAR_STR          = TD_PSTRING          ,
         VTYPE_WCHAR_STR         = TD_PWSTRING         ,
         VTYPE_INTERFACE         = TD_INTERFACE_TYPE   ,
         VTYPE_INTERFACE_IS      = TD_INTERFACE_IS_TYPE,
         VTYPE_ARRAY             = TD_LEGACY_ARRAY     ,
         VTYPE_STRING_SIZE_IS    = TD_PSTRING_SIZE_IS  ,
         VTYPE_WSTRING_SIZE_IS   = TD_PWSTRING_SIZE_IS ,
         VTYPE_UTF8STRING        = TD_UTF8STRING       ,
--- a/xpcom/idl-parser/xpidl/jsonxpt.py
+++ b/xpcom/idl-parser/xpidl/jsonxpt.py
@@ -32,17 +32,17 @@ TypeMap = {
     'unsigned long long': 'TD_UINT64',
     'float':              'TD_FLOAT',
     'double':             'TD_DOUBLE',
     'char':               'TD_CHAR',
     'string':             'TD_PSTRING',
     'wchar':              'TD_WCHAR',
     'wstring':            'TD_PWSTRING',
     # special types
-    'nsid':               'TD_PNSIID',
+    'nsid':               'TD_NSID',
     'astring':            'TD_ASTRING',
     'utf8string':         'TD_UTF8STRING',
     'cstring':            'TD_CSTRING',
     'jsval':              'TD_JSVAL',
     'promise':            'TD_PROMISE',
 }
 
 
@@ -88,17 +88,19 @@ def get_type(type, calltype, iid_is=None
         return {
             'tag': 'TD_DOMOBJECT',
             'name': type.name,
             'native': type.native,
             'headerFile': type.headerFile,
         }
 
     if isinstance(type, xpidl.Native):
-        if type.specialtype:
+        if type.specialtype == 'nsid' and type.isPtr(calltype):
+            return {'tag': 'TD_NSIDPTR'}
+        elif type.specialtype:
             return {
                 'tag': TypeMap[type.specialtype]
             }
         elif iid_is is not None:
             return {
                 'tag': 'TD_INTERFACE_IS_TYPE',
                 'iid_is': iid_is,
             }
--- a/xpcom/idl-parser/xpidl/xpidl.py
+++ b/xpcom/idl-parser/xpidl/xpidl.py
@@ -555,30 +555,31 @@ class Native(object):
             else:
                 return self.nativename[2] + ' '
 
         # 'in' nsid parameters should be made 'const'
         if self.specialtype == 'nsid' and calltype == 'in':
             const = True
 
         if calltype == 'element':
+            if self.specialtype == 'nsid':
+                if self.isPtr(calltype):
+                    raise IDLError("Array<nsIDPtr> not yet supported. "
+                                   "File an XPConnect bug if you need it.", self.location)
+
+                # ns[CI]?IDs should be held directly in Array<T>s
+                return self.nativename
+
             if self.isRef(calltype):
                 raise IDLError("[ref] qualified type unsupported in Array<T>", self.location)
 
             # Promises should be held in RefPtr<T> in Array<T>s
             if self.specialtype == 'promise':
                 return 'RefPtr<mozilla::dom::Promise>'
 
-            # We don't support nsIDPtr, in Array<T> currently, although
-            # this or support for Array<nsID> will be needed to replace
-            # [array] completely.
-            if self.specialtype == 'nsid':
-                raise IDLError("Array<nsIDPtr> not yet supported. "
-                               "File an XPConnect bug if you need it.", self.location)
-
         if self.isRef(calltype):
             m = '& '  # [ref] is always passed with a single indirection
         else:
             m = '* ' if 'out' in calltype else ''
             if self.isPtr(calltype):
                 m += '* '
         return "%s%s %s" % (const and 'const ' or '', self.nativename, m)
 
--- a/xpcom/reflect/xptcall/xptcall.h
+++ b/xpcom/reflect/xptcall/xptcall.h
@@ -46,16 +46,17 @@ struct nsXPTCVariant {
     // ExtendedVal is an extension on nsXPTCMiniVariant. It contains types
     // unknown to the assembly implementations which must be passed by indirect
     // semantics.
     //
     // nsXPTCVariant contains enough space to store ExtendedVal inline, which
     // can be used to store these types when IsIndirect() is true.
     nsXPTCMiniVariant mini;
 
+    nsID nsid;
     nsCString nscstr;
     nsString nsstr;
     JS::Value jsval;
     xpt::detail::UntypedTArray array;
 
     // This type contains non-standard-layout types, so needs an explicit
     // Ctor/Dtor - we'll just delete them.
     ExtendedVal() = delete;
--- a/xpcom/reflect/xptinfo/xptcodegen.py
+++ b/xpcom/reflect/xptinfo/xptcodegen.py
@@ -166,17 +166,17 @@ utility_types = [
     {'tag': 'TD_UINT32'},
     {'tag': 'TD_INT64'},
     {'tag': 'TD_UINT64'},
     {'tag': 'TD_FLOAT'},
     {'tag': 'TD_DOUBLE'},
     {'tag': 'TD_BOOL'},
     {'tag': 'TD_CHAR'},
     {'tag': 'TD_WCHAR'},
-    {'tag': 'TD_PNSIID'},
+    {'tag': 'TD_NSIDPTR'},
     {'tag': 'TD_PSTRING'},
     {'tag': 'TD_PWSTRING'},
     {'tag': 'TD_INTERFACE_IS_TYPE', 'iid_is': 0},
 ]
 
 
 # Core of the code generator. Takes a list of raw JSON XPT interfaces, and
 # writes out a file containing the necessary static declarations into fd.
--- a/xpcom/reflect/xptinfo/xptinfo.h
+++ b/xpcom/reflect/xptinfo/xptinfo.h
@@ -160,17 +160,17 @@ enum nsXPTTypeTag : uint8_t {
   _TD_LAST_ARITHMETIC = TD_WCHAR,
 
   // Pointer Types
   //  - Require cleanup unless NULL,
   //  - All-zeros (NULL) bit pattern is valid,
   //  - Outparams may be uninitialized by caller,
   //  - Supported in xptcall as raw pointer.
   TD_VOID = 13,
-  TD_PNSIID = 14,
+  TD_NSIDPTR = 14,
   TD_PSTRING = 15,
   TD_PWSTRING = 16,
   TD_INTERFACE_TYPE = 17,
   TD_INTERFACE_IS_TYPE = 18,
   TD_LEGACY_ARRAY = 19,
   TD_PSTRING_SIZE_IS = 20,
   TD_PWSTRING_SIZE_IS = 21,
   TD_DOMOBJECT = 22,
@@ -180,18 +180,19 @@ enum nsXPTTypeTag : uint8_t {
   // Complex Types
   //  - Require cleanup,
   //  - Always passed indirectly,
   //  - Outparams must be initialized by caller,
   //  - Supported in xptcall due to indirection.
   TD_UTF8STRING = 24,
   TD_CSTRING = 25,
   TD_ASTRING = 26,
-  TD_JSVAL = 27,
-  TD_ARRAY = 28,
+  TD_NSID = 27,
+  TD_JSVAL = 28,
+  TD_ARRAY = 29,
   _TD_LAST_COMPLEX = TD_ARRAY
 };
 
 static_assert(_TD_LAST_COMPLEX < 32, "nsXPTTypeTag must fit in 5 bits");
 
 /*
  * A nsXPTType is a union used to identify the type of a method argument or
  * return value. The internal data is stored as an 5-bit tag, and two 8-bit
@@ -289,17 +290,17 @@ struct nsXPTType {
     UINT32,
     INT64,
     UINT64,
     FLOAT,
     DOUBLE,
     BOOL,
     CHAR,
     WCHAR,
-    PNSIID,
+    NSIDPTR,
     PSTRING,
     PWSTRING,
     INTERFACE_IS_TYPE
   };
 
   // Helper methods for fabricating nsXPTType values used by xpconnect.
   static nsXPTType MkArrayType(Idx aInner) {
     MOZ_ASSERT(aInner <= Idx::INTERFACE_IS_TYPE);
@@ -330,27 +331,28 @@ struct nsXPTType {
   TD_ALIAS_(T_U32, TD_UINT32);
   TD_ALIAS_(T_U64, TD_UINT64);
   TD_ALIAS_(T_FLOAT, TD_FLOAT);
   TD_ALIAS_(T_DOUBLE, TD_DOUBLE);
   TD_ALIAS_(T_BOOL, TD_BOOL);
   TD_ALIAS_(T_CHAR, TD_CHAR);
   TD_ALIAS_(T_WCHAR, TD_WCHAR);
   TD_ALIAS_(T_VOID, TD_VOID);
-  TD_ALIAS_(T_IID, TD_PNSIID);
+  TD_ALIAS_(T_NSIDPTR, TD_NSIDPTR);
   TD_ALIAS_(T_CHAR_STR, TD_PSTRING);
   TD_ALIAS_(T_WCHAR_STR, TD_PWSTRING);
   TD_ALIAS_(T_INTERFACE, TD_INTERFACE_TYPE);
   TD_ALIAS_(T_INTERFACE_IS, TD_INTERFACE_IS_TYPE);
   TD_ALIAS_(T_LEGACY_ARRAY, TD_LEGACY_ARRAY);
   TD_ALIAS_(T_PSTRING_SIZE_IS, TD_PSTRING_SIZE_IS);
   TD_ALIAS_(T_PWSTRING_SIZE_IS, TD_PWSTRING_SIZE_IS);
   TD_ALIAS_(T_UTF8STRING, TD_UTF8STRING);
   TD_ALIAS_(T_CSTRING, TD_CSTRING);
   TD_ALIAS_(T_ASTRING, TD_ASTRING);
+  TD_ALIAS_(T_NSID, TD_NSID);
   TD_ALIAS_(T_JSVAL, TD_JSVAL);
   TD_ALIAS_(T_DOMOBJECT, TD_DOMOBJECT);
   TD_ALIAS_(T_PROMISE, TD_PROMISE);
   TD_ALIAS_(T_ARRAY, TD_ARRAY);
 #undef TD_ALIAS_
 
   ////////////////////////////////////////////////////////////////
   // Ensure these fields are in the same order as xptcodegen.py //
@@ -630,31 +632,32 @@ inline const char* GetString(uint32_t aI
   MACRO(TD_FLOAT, float)                    \
   MACRO(TD_DOUBLE, double)                  \
   MACRO(TD_BOOL, bool)                      \
   MACRO(TD_CHAR, char)                      \
   MACRO(TD_WCHAR, char16_t)
 
 #define XPT_FOR_EACH_POINTER_TYPE(MACRO)    \
   MACRO(TD_VOID, void*)                     \
-  MACRO(TD_PNSIID, nsID*)                   \
+  MACRO(TD_NSIDPTR, nsID*)                  \
   MACRO(TD_PSTRING, char*)                  \
   MACRO(TD_PWSTRING, wchar_t*)              \
   MACRO(TD_INTERFACE_TYPE, nsISupports*)    \
   MACRO(TD_INTERFACE_IS_TYPE, nsISupports*) \
   MACRO(TD_LEGACY_ARRAY, void*)             \
   MACRO(TD_PSTRING_SIZE_IS, char*)          \
   MACRO(TD_PWSTRING_SIZE_IS, wchar_t*)      \
   MACRO(TD_DOMOBJECT, void*)                \
   MACRO(TD_PROMISE, mozilla::dom::Promise*)
 
 #define XPT_FOR_EACH_COMPLEX_TYPE(MACRO) \
   MACRO(TD_UTF8STRING, nsCString)        \
   MACRO(TD_CSTRING, nsCString)           \
   MACRO(TD_ASTRING, nsString)            \
+  MACRO(TD_NSID, nsID)                   \
   MACRO(TD_JSVAL, JS::Value)             \
   MACRO(TD_ARRAY, xpt::detail::UntypedTArray)
 
 #define XPT_FOR_EACH_TYPE(MACRO)      \
   XPT_FOR_EACH_ARITHMETIC_TYPE(MACRO) \
   XPT_FOR_EACH_POINTER_TYPE(MACRO)    \
   XPT_FOR_EACH_COMPLEX_TYPE(MACRO)