Backed out 15 changesets (bug 1475409, bug 1461450, bug 1474369, bug 1471726) for build bustages on xptcstubs_gcc_x86_unix.cpp:55:1. CLOSED TREE
authorBrindusan Cristian <cbrindusan@mozilla.com>
Wed, 25 Jul 2018 22:57:09 +0300
changeset 428375 113e9ca0b5bccaf3eaee398e789f9b7b8c226009
parent 428374 79dbf5b9d8db577bba582a0853eb293d80eed0ba
child 428376 4bf70a81f42f205bd2b0c91da3f511ca39c2f118
push id105680
push usercbrindusan@mozilla.com
push dateWed, 25 Jul 2018 19:57:27 +0000
treeherdermozilla-inbound@113e9ca0b5bc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1475409, 1461450, 1474369, 1471726
milestone63.0a1
backs out79dbf5b9d8db577bba582a0853eb293d80eed0ba
7e2e13953e19169da602f50c51c7edc9b7706200
9d0b9a4c4651f44f9a98bfe2704262105e40aac6
9f14f7b8bc3d6354ebd0baa922fdae6152f4df37
bddd838d19102d55d131a62158d8cb4b5c637284
850f21ca1f451ff48acb72f79c2c316d90fe9c07
320802ab02e3958b7df55dd6d95e10c542d7ee67
db67bf0e7f916eae580b2575a753119bd082420b
f355d9be99123c8c0f71e882213c3895111fd2fe
e1b6a5f74642deb7ac9821a0619774643bce1016
459635cdfc08c898a2337cb742392e22010748aa
44414b1cd32ed889acca0a13507968192c742ccc
a5d04cf5d67fa93256711c781ee5cfc525259eb4
40885fbf99c60efa95765d764d21c92de9846a6d
da79e75b9cb35daeb80fe000a6f0f9ce339aedac
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
Backed out 15 changesets (bug 1475409, bug 1461450, bug 1474369, bug 1471726) for build bustages on xptcstubs_gcc_x86_unix.cpp:55:1. CLOSED TREE Backed out changeset 79dbf5b9d8db (bug 1474369) Backed out changeset 7e2e13953e19 (bug 1474369) Backed out changeset 9d0b9a4c4651 (bug 1474369) Backed out changeset 9f14f7b8bc3d (bug 1475409) Backed out changeset bddd838d1910 (bug 1475409) Backed out changeset 850f21ca1f45 (bug 1475409) Backed out changeset 320802ab02e3 (bug 1474369) Backed out changeset db67bf0e7f91 (bug 1474369) Backed out changeset f355d9be9912 (bug 1474369) Backed out changeset e1b6a5f74642 (bug 1474369) Backed out changeset 459635cdfc08 (bug 1474369) Backed out changeset 44414b1cd32e (bug 1461450) Backed out changeset a5d04cf5d67f (bug 1461450) Backed out changeset 40885fbf99c6 (bug 1471726) Backed out changeset da79e75b9cb3 (bug 1471726)
accessible/xpcom/AccEventGen.py
js/xpconnect/src/XPCConvert.cpp
js/xpconnect/src/XPCInlines.h
js/xpconnect/src/XPCWrappedJSClass.cpp
js/xpconnect/src/XPCWrappedNative.cpp
js/xpconnect/src/xpcprivate.h
js/xpconnect/tests/components/js/xpctest_params.js
js/xpconnect/tests/components/native/xpctest_params.cpp
js/xpconnect/tests/idl/xpctest_params.idl
js/xpconnect/tests/unit/test_params.js
xpcom/ds/nsIVariant.idl
xpcom/ds/nsTArray.h
xpcom/ds/nsVariant.cpp
xpcom/idl-parser/xpidl/jsonxpt.py
xpcom/idl-parser/xpidl/runtests.py
xpcom/idl-parser/xpidl/xpidl.py
xpcom/reflect/xptcall/xptcall.h
xpcom/reflect/xptinfo/xptcodegen.py
xpcom/reflect/xptinfo/xptinfo.h
xpcom/rust/xpcom/src/reexports.rs
xpcom/rust/xpcom/xpcom_macros/src/lib.rs
xpcom/tests/gtest/TestTArray2.cpp
--- a/accessible/xpcom/AccEventGen.py
+++ b/accessible/xpcom/AccEventGen.py
@@ -192,17 +192,17 @@ def writeAttributeGetter(fd, classname, 
     fd.write("  return NS_OK;\n")
     fd.write("}\n\n")
 
 
 def interfaces(iface):
     interfaces = []
     while iface.base:
         interfaces.append(iface)
-        iface = iface.idl.getName(xpidl.TypeId(iface.base), iface.location)
+        iface = iface.idl.getName(iface.base, iface.location)
     interfaces.append(iface)
     interfaces.reverse()
     return interfaces
 
 
 def allAttributes(iface):
     attributes = []
     for i in interfaces(iface):
--- a/js/xpconnect/src/XPCConvert.cpp
+++ b/js/xpconnect/src/XPCConvert.cpp
@@ -53,17 +53,17 @@ XPCConvert::IsMethodReflectable(const ns
         return false;
 
     for (int i = info.GetParamCount() - 1; i >= 0; i--) {
         const nsXPTParamInfo& param = info.GetParam(i);
         const nsXPTType& type = param.GetType();
 
         // Reflected methods can't use native types. All native types end up
         // getting tagged as void*, so this check is easy.
-        if (type.Tag() == nsXPTType::T_VOID)
+        if (type.TagPart() == nsXPTType::T_VOID)
             return false;
     }
     return true;
 }
 
 static JSObject*
 UnwrapNativeCPOW(nsISupports* wrapper)
 {
@@ -103,17 +103,17 @@ XPCConvert::NativeData2JS(MutableHandleV
                           uint32_t arrlen, nsresult* pErr)
 {
     MOZ_ASSERT(s, "bad param");
 
     AutoJSContext cx;
     if (pErr)
         *pErr = NS_ERROR_XPC_BAD_CONVERT_NATIVE;
 
-    switch (type.Tag()) {
+    switch (type.TagPart()) {
     case nsXPTType::T_I8    :
         d.setInt32(*static_cast<const int8_t*>(s));
         return true;
     case nsXPTType::T_I16   :
         d.setInt32(*static_cast<const int16_t*>(s));
         return true;
     case nsXPTType::T_I32   :
         d.setInt32(*static_cast<const int32_t*>(s));
@@ -380,27 +380,20 @@ XPCConvert::NativeData2JS(MutableHandleV
         RootedObject jsobj(cx, promise->PromiseObj());
         if (!JS_WrapObject(cx, &jsobj)) {
             return false;
         }
         d.setObject(*jsobj);
         return true;
     }
 
-    case nsXPTType::T_LEGACY_ARRAY:
-        return NativeArray2JS(d, *static_cast<const void* const*>(s),
+    case nsXPTType::T_ARRAY:
+        return NativeArray2JS(d, static_cast<const void* const*>(s),
                               type.ArrayElementType(), iid, arrlen, pErr);
 
-    case nsXPTType::T_ARRAY:
-    {
-        auto* array = static_cast<const xpt::detail::UntypedTArray*>(s);
-        return NativeArray2JS(d, array->Elements(), type.ArrayElementType(),
-                              iid, array->Length(), pErr);
-    }
-
     default:
         NS_ERROR("bad type");
         return false;
     }
     return true;
 }
 
 /***************************************************************************/
@@ -450,17 +443,17 @@ XPCConvert::JSData2Native(void* d, Handl
 
     AutoJSContext cx;
     if (pErr)
         *pErr = NS_ERROR_XPC_BAD_CONVERT_JS;
 
     bool sizeis = type.Tag() == TD_PSTRING_SIZE_IS ||
         type.Tag() == TD_PWSTRING_SIZE_IS;
 
-    switch (type.Tag()) {
+    switch (type.TagPart()) {
     case nsXPTType::T_I8     :
         return ConvertToPrimitive(cx, s, static_cast<int8_t*>(d));
     case nsXPTType::T_I16    :
         return ConvertToPrimitive(cx, s, static_cast<int16_t*>(d));
     case nsXPTType::T_I32    :
         return ConvertToPrimitive(cx, s, static_cast<int32_t*>(d));
     case nsXPTType::T_I64    :
         return ConvertToPrimitive(cx, s, static_cast<int64_t*>(d));
@@ -836,80 +829,19 @@ XPCConvert::JSData2Native(void* d, Handl
         bool ok = !err.Failed();
         if (pErr) {
             *pErr = err.StealNSResult();
         }
 
         return ok;
     }
 
-    case nsXPTType::T_LEGACY_ARRAY:
-    {
-        void** dest = (void**)d;
-        const nsXPTType& elty = type.ArrayElementType();
-
-        *dest = nullptr;
-
-        // FIXME: XPConnect historically has shortcut the JSArray2Native codepath in
-        // its caller if arrlen is 0, allowing arbitrary values to be passed as
-        // arrays and interpreted as the empty array (bug 1458987).
-        //
-        // NOTE: Once this is fixed, null/undefined should be allowed for arrays if
-        // arrlen is 0.
-        if (arrlen == 0) {
-            return true;
-        }
-
-        bool ok = JSArray2Native(s, elty, iid, pErr, [&] (uint32_t* aLength) -> void* {
-            // Check that we have enough elements in our array.
-            if (*aLength < arrlen) {
-                if (pErr)
-                    *pErr = NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY;
-                return nullptr;
-            }
-            *aLength = arrlen;
-
-            // Allocate the backing buffer & return it.
-            *dest = moz_xmalloc(*aLength * elty.Stride());
-            if (!*dest) {
-                if (pErr)
-                    *pErr = NS_ERROR_OUT_OF_MEMORY;
-                return nullptr;
-            }
-            return *dest;
-        });
-
-        if (!ok && *dest) {
-            // An error occurred, free any allocated backing buffer.
-            free(*dest);
-            *dest = nullptr;
-        }
-        return ok;
-    }
-
     case nsXPTType::T_ARRAY:
-    {
-        auto* dest = (xpt::detail::UntypedTArray*)d;
-        const nsXPTType& elty = type.ArrayElementType();
-
-        bool ok = JSArray2Native(s, elty, iid, pErr, [&] (uint32_t* aLength) -> void* {
-            if (!dest->SetLength(elty, *aLength)) {
-                if (pErr)
-                    *pErr = NS_ERROR_OUT_OF_MEMORY;
-                return nullptr;
-            }
-            return dest->Elements();
-        });
-
-        if (!ok) {
-            // An error occurred, free any allocated backing buffer.
-            dest->Clear();
-        }
-        return ok;
-    }
+        return JSArray2Native((void**)d, s, arrlen,
+                              type.ArrayElementType(), iid, pErr);
 
     default:
         NS_ERROR("bad type");
         return false;
     }
     return true;
 }
 
@@ -1395,178 +1327,304 @@ XPCConvert::JSValToXPCException(MutableH
     }
     return NS_ERROR_FAILURE;
 }
 
 /***************************************************************************/
 
 // array fun...
 
+static bool
+ValidArrayType(const nsXPTType& type)
+{
+    switch (type.Tag()) {
+        // These types aren't allowed to be in arrays.
+        case nsXPTType::T_VOID:
+        case nsXPTType::T_DOMSTRING:
+        case nsXPTType::T_UTF8STRING:
+        case nsXPTType::T_CSTRING:
+        case nsXPTType::T_ASTRING:
+        case nsXPTType::T_PSTRING_SIZE_IS:
+        case nsXPTType::T_PWSTRING_SIZE_IS:
+        case nsXPTType::T_ARRAY:
+            return false;
+        default:
+            return true;
+    }
+}
+
 // static
 bool
-XPCConvert::NativeArray2JS(MutableHandleValue d, const void* buf,
+XPCConvert::NativeArray2JS(MutableHandleValue d, const void* const* s,
                            const nsXPTType& type, const nsID* iid,
                            uint32_t count, nsresult* pErr)
 {
-    MOZ_ASSERT(buf, "bad param");
+    MOZ_ASSERT(s, "bad param");
 
     AutoJSContext cx;
 
+    // XXX add support for putting chars in a string rather than an array
+
+    // XXX add support to indicate *which* array element was not convertable
+
     RootedObject array(cx, JS_NewArrayObject(cx, count));
     if (!array)
         return false;
 
     if (pErr)
         *pErr = NS_ERROR_XPC_BAD_CONVERT_NATIVE;
 
+    if (!ValidArrayType(type))
+        return false;
+
     RootedValue current(cx, JS::NullValue());
     for (uint32_t i = 0; i < count; ++i) {
-        if (!NativeData2JS(&current, type.ElementPtr(buf, i), type, iid, 0, pErr) ||
+        if (!NativeData2JS(&current, type.ElementPtr(*s, i), type, iid, 0, pErr) ||
             !JS_DefineElement(cx, array, i, current, JSPROP_ENUMERATE))
             return false;
     }
 
     if (pErr)
         *pErr = NS_OK;
     d.setObject(*array);
     return true;
 }
 
+
+// Fast conversion of typed arrays to native using memcpy.
+// No float or double canonicalization is done. Called by
+// JSarray2Native whenever a TypedArray is met. ArrayBuffers
+// are not accepted; create a properly typed array view on them
+// first. The element type of array must match the XPCOM
+// type in size, type and signedness exactly. As an exception,
+// Uint8ClampedArray is allowed for arrays of uint8_t. DataViews
+// are not supported.
+
 // static
 bool
-XPCConvert::JSArray2Native(JS::HandleValue aJSVal,
-                           const nsXPTType& aEltType,
-                           const nsIID* aIID,
-                           nsresult* pErr,
-                           ArrayAllocFixupLen aAllocFixupLen)
+XPCConvert::JSTypedArray2Native(void** d,
+                                JSObject* jsArray,
+                                uint32_t count,
+                                const nsXPTType& type,
+                                nsresult* pErr)
 {
-    // Wrap aAllocFixupLen to check length is within bounds & initialize the
-    // allocated memory if needed.
-    auto allocFixupLen = [&] (uint32_t* aLength) -> void* {
-        if (*aLength > (UINT32_MAX / aEltType.Stride())) {
-            return nullptr; // Byte length doesn't fit in uint32_t
-        }
+    MOZ_ASSERT(jsArray, "bad param");
+    MOZ_ASSERT(d, "bad param");
+    MOZ_ASSERT(JS_IsTypedArrayObject(jsArray), "not a typed array");
+
+    // Check the actual length of the input array against the
+    // given size_is.
+    uint32_t len = JS_GetTypedArrayLength(jsArray);
+    if (len < count) {
+        if (pErr)
+            *pErr = NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY;
+
+        return false;
+    }
+
+    uint8_t expected;
+    switch (JS_GetArrayBufferViewType(jsArray)) {
+    case js::Scalar::Int8:
+        expected = nsXPTType::T_I8;
+        break;
 
-        void* buf = aAllocFixupLen(aLength);
+    case js::Scalar::Uint8:
+    case js::Scalar::Uint8Clamped:
+        expected = nsXPTType::T_U8;
+        break;
+
+    case js::Scalar::Int16:
+        expected = nsXPTType::T_I16;
+        break;
+
+    case js::Scalar::Uint16:
+        expected = nsXPTType::T_U16;
+        break;
+
+    case js::Scalar::Int32:
+        expected = nsXPTType::T_I32;
+        break;
+
+    case js::Scalar::Uint32:
+        expected = nsXPTType::T_U32;
+        break;
+
+    case js::Scalar::Float32:
+        expected = nsXPTType::T_FLOAT;
+        break;
+
+    case js::Scalar::Float64:
+        expected = nsXPTType::T_DOUBLE;
+        break;
 
-        // Ensure the buffer has valid values for each element. We can skip this
-        // for arithmetic types, as they do not require initialization.
-        if (buf && !aEltType.IsArithmetic()) {
-            for (uint32_t i = 0; i < *aLength; ++i) {
-                InitializeValue(aEltType, aEltType.ElementPtr(buf, i));
-            }
-        }
-        return buf;
-    };
+    // Yet another array type was defined? It is not supported yet...
+    default:
+        if (pErr)
+            *pErr = NS_ERROR_XPC_BAD_CONVERT_JS;
+        return false;
+    }
+
+    // Check that the type we got is the type we expected.
+    if (expected != type.Tag()) {
+        if (pErr)
+            *pErr = NS_ERROR_XPC_BAD_CONVERT_JS;
+        return false;
+    }
+
+    // Check if the size would overflow uint32_t.
+    if (count > (UINT32_MAX / type.Stride())) {
+        if (pErr)
+            *pErr = NS_ERROR_OUT_OF_MEMORY;
+        return false;
+    }
+
+    // Get the backing memory buffer to copy out of.
+    JS::AutoCheckCannotGC nogc;
+    bool isShared;
+    void* buf = JS_GetArrayBufferViewData(jsArray, &isShared, nogc);
+
+    // Require opting in to shared memory - a future project.
+    if (isShared) {
+        if (pErr)
+            *pErr = NS_ERROR_XPC_BAD_CONVERT_JS;
+        return false;
+    }
+
+    // Allocate the buffer, and copy.
+    *d = moz_xmalloc(count * type.Stride());
+    if (!*d) {
+        if (pErr)
+            *pErr = NS_ERROR_OUT_OF_MEMORY;
+        return false;
+    }
+
+    memcpy(*d, buf, count * type.Stride());
+
+    if (pErr)
+        *pErr = NS_OK;
+
+    return true;
+}
+
+// static
+bool
+XPCConvert::JSArray2Native(void** d, HandleValue s,
+                           uint32_t count, const nsXPTType& type,
+                           const nsID* iid, nsresult* pErr)
+{
+    MOZ_ASSERT(d, "bad param");
 
     AutoJSContext cx;
 
-    // JSArray2Native only accepts objects (Array and TypedArray).
-    if (!aJSVal.isObject()) {
-        if (pErr)
-            *pErr = NS_ERROR_XPC_CANT_CONVERT_PRIMITIVE_TO_ARRAY;
-        return false;
+    // FIXME: XPConnect historically has shortcut the JSArray2Native codepath in
+    // its caller if count is 0, allowing arbitrary values to be passed as
+    // arrays and interpreted as the empty array (bug 1458987).
+    //
+    // NOTE: Once this is fixed, null/undefined should be allowed for arrays if
+    // count is 0.
+    if (count == 0) {
+        *d = nullptr;
+        return true;
     }
-    RootedObject jsarray(cx, &aJSVal.toObject());
+
+    // XXX add support for getting chars from strings
+
+    // XXX add support to indicate *which* array element was not convertable
 
     if (pErr)
         *pErr = NS_ERROR_XPC_BAD_CONVERT_JS;
 
-    if (JS_IsTypedArrayObject(jsarray)) {
-        // Fast conversion of typed arrays to native using memcpy. No float or
-        // double canonicalization is done. ArrayBuffers are not accepted;
-        // create a properly typed array view on them first. The element type of
-        // array must match the XPCOM type in size, type and signedness exactly.
-        // As an exception, Uint8ClampedArray is allowed for arrays of uint8_t.
-        // DataViews are not supported.
+    if (!ValidArrayType(type))
+        return false;
 
-        nsXPTTypeTag tag;
-        switch (JS_GetArrayBufferViewType(jsarray)) {
-            case js::Scalar::Int8:         tag = TD_INT8;   break;
-            case js::Scalar::Uint8:        tag = TD_UINT8;  break;
-            case js::Scalar::Uint8Clamped: tag = TD_UINT8;  break;
-            case js::Scalar::Int16:        tag = TD_INT16;  break;
-            case js::Scalar::Uint16:       tag = TD_UINT16; break;
-            case js::Scalar::Int32:        tag = TD_INT32;  break;
-            case js::Scalar::Uint32:       tag = TD_UINT32; break;
-            case js::Scalar::Float32:      tag = TD_FLOAT;  break;
-            case js::Scalar::Float64:      tag = TD_DOUBLE; break;
-            default:                       return false;
-        }
-        if (aEltType.Tag() != tag) {
-            return false;
-        }
-
-        // Get the backing memory buffer to copy out of.
-        JS::AutoCheckCannotGC nogc;
-        bool isShared = false;
-        const void* data = JS_GetArrayBufferViewData(jsarray, &isShared, nogc);
-
-        // Require opting in to shared memory - a future project.
-        if (isShared) {
-            return false;
-        }
-
-        uint32_t length = JS_GetTypedArrayLength(jsarray);
-        void* buf = allocFixupLen(&length);
-        if (!buf) {
-            return false;
-        }
-
-        // Directly copy data into the allocated target buffer.
-        memcpy(buf, data, length * aEltType.Stride());
-        return true;
+    if (s.isNullOrUndefined()) {
+        if (pErr)
+            *pErr = NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY;
+        return false;
     }
 
-    // If jsarray is not a TypedArrayObject, check for an Array object.
-    uint32_t length = 0;
-    bool isArray = false;
-    if (!JS_IsArrayObject(cx, jsarray, &isArray) || !isArray ||
-        !JS_GetArrayLength(cx, jsarray, &length)) {
+    if (!s.isObject()) {
+        if (pErr)
+            *pErr = NS_ERROR_XPC_CANT_CONVERT_PRIMITIVE_TO_ARRAY;
+        return false;
+    }
+
+    RootedObject jsarray(cx, &s.toObject());
+
+    // If this is a typed array, then try a fast conversion with memcpy.
+    if (JS_IsTypedArrayObject(jsarray)) {
+        return JSTypedArray2Native(d, jsarray, count, type, pErr);
+    }
+
+    bool isArray;
+    if (!JS_IsArrayObject(cx, jsarray, &isArray) || !isArray) {
         if (pErr)
             *pErr = NS_ERROR_XPC_CANT_CONVERT_OBJECT_TO_ARRAY;
         return false;
     }
 
-    void* buf = allocFixupLen(&length);
-    if (!buf) {
+    uint32_t len;
+    if (!JS_GetArrayLength(cx, jsarray, &len) || len < count) {
+        if (pErr)
+            *pErr = NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY;
+        return false;
+    }
+
+    if (count > (UINT32_MAX / type.Stride())) {
+        if (pErr)
+            *pErr = NS_ERROR_OUT_OF_MEMORY;
+        return false;
+    }
+
+    // Allocate the destination array, and begin converting elements.
+    *d = moz_xmalloc(count * type.Stride());
+    if (!*d) {
+        if (pErr)
+            *pErr = NS_ERROR_OUT_OF_MEMORY;
         return false;
     }
 
-    // Translate each array element separately.
     RootedValue current(cx);
-    for (uint32_t i = 0; i < length; ++i) {
-        if (!JS_GetElement(cx, jsarray, i, &current) ||
-            !JSData2Native(aEltType.ElementPtr(buf, i), current,
-                           aEltType, aIID, 0, pErr)) {
-            // Array element conversion failed. Clean up all elements converted
-            // before the error. Caller handles freeing 'buf'.
-            for (uint32_t j = 0; j < i; ++j) {
-                CleanupValue(aEltType, aEltType.ElementPtr(buf, j));
-            }
-            return false;
-        }
+    uint32_t initedCount;
+    for (initedCount = 0; initedCount < count; ++initedCount) {
+        if (!JS_GetElement(cx, jsarray, initedCount, &current) ||
+            !JSData2Native(type.ElementPtr(*d, initedCount),
+                           current, type, iid, 0, pErr))
+            break;
     }
 
-    return true;
+    // Check if we handled every array element.
+    if (initedCount == count) {
+        if (pErr)
+            *pErr = NS_OK;
+        return true;
+    }
+
+    // Something failed! Clean up after ourselves.
+    for (uint32_t i = 0; i < initedCount; ++i) {
+        CleanupValue(type, type.ElementPtr(*d, i));
+    }
+    free(*d);
+    *d = nullptr;
+    return false;
 }
 
 /***************************************************************************/
 
 // Internal implementation details for xpc::CleanupValue.
 
 void
 xpc::InnerCleanupValue(const nsXPTType& aType, void* aValue, uint32_t aArrayLen)
 {
     MOZ_ASSERT(!aType.IsArithmetic(),
                "Arithmetic types should not get to InnerCleanupValue!");
     MOZ_ASSERT(aArrayLen == 0 ||
                aType.Tag() == nsXPTType::T_PSTRING_SIZE_IS ||
                aType.Tag() == nsXPTType::T_PWSTRING_SIZE_IS ||
-               aType.Tag() == nsXPTType::T_LEGACY_ARRAY,
+               aType.Tag() == nsXPTType::T_ARRAY,
                "Array lengths may only appear for certain types!");
 
     switch (aType.Tag()) {
         // Pointer types
         case nsXPTType::T_DOMOBJECT:
             aType.GetDOMObjectInfo().Cleanup(*(void**)aValue);
             break;
 
@@ -1593,86 +1651,27 @@ xpc::InnerCleanupValue(const nsXPTType& 
         case nsXPTType::T_IID:
         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
-        case nsXPTType::T_LEGACY_ARRAY:
+        // Array Types
+        case nsXPTType::T_ARRAY:
         {
             const nsXPTType& elty = aType.ArrayElementType();
             void* elements = *(void**)aValue;
 
             for (uint32_t i = 0; i < aArrayLen; ++i) {
                 CleanupValue(elty, elty.ElementPtr(elements, i));
             }
             free(elements);
             break;
         }
-
-        // Array Type
-        case nsXPTType::T_ARRAY:
-        {
-            const nsXPTType& elty = aType.ArrayElementType();
-            auto* array = (xpt::detail::UntypedTArray*)aValue;
-
-            for (uint32_t i = 0; i < array->Length(); ++i) {
-                CleanupValue(elty, elty.ElementPtr(array->Elements(), i));
-            }
-            array->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;
-
-        default:
-            MOZ_CRASH("Unknown Type!");
     }
 
-    // Clear any non-complex values to the valid '0' state.
-    if (!aType.IsComplex()) {
-        aType.ZeroValue(aValue);
+    // Null out the pointer if we have it.
+    if (aType.HasPointerRepr()) {
+        *(void**)aValue = nullptr;
     }
 }
-
-/***************************************************************************/
-
-// Implementation of xpc::InitializeValue.
-
-void
-xpc::InitializeValue(const nsXPTType& aType, void* aValue)
-{
-    switch (aType.Tag()) {
-        // Types which require custom, specific initialization.
-        case nsXPTType::T_JSVAL:
-            new (aValue) JS::Value();
-            MOZ_ASSERT(reinterpret_cast<JS::Value*>(aValue)->isUndefined());
-            break;
-
-        case nsXPTType::T_ASTRING:
-        case nsXPTType::T_DOMSTRING:
-            new (aValue) nsString();
-            break;
-        case nsXPTType::T_CSTRING:
-        case nsXPTType::T_UTF8STRING:
-            new (aValue) nsCString();
-            break;
-
-        case nsXPTType::T_ARRAY:
-            new (aValue) xpt::detail::UntypedTArray();
-            break;
-
-        // The remaining types all have valid states where all bytes are '0'.
-        default:
-            aType.ZeroValue(aValue);
-            break;
-    }
-}
--- a/js/xpconnect/src/XPCInlines.h
+++ b/js/xpconnect/src/XPCInlines.h
@@ -525,20 +525,17 @@ void ThrowBadResult(nsresult result, XPC
 inline void
 xpc::CleanupValue(const nsXPTType& aType,
                   void* aValue,
                   uint32_t aArrayLen)
 {
     // Check if we can do a cheap early return, and only perform the inner call
     // if we can't. We never have to clean up null pointer types or arithmetic
     // types.
-    //
-    // NOTE: We can skip zeroing arithmetic types in CleanupValue, as they are
-    // already in a valid state.
-    if (aType.IsArithmetic() || (aType.IsPointer() && !*(void**)aValue)) {
+    if (aType.IsArithmetic() || (aType.HasPointerRepr() && !*(void**)aValue)) {
         return;
     }
     xpc::InnerCleanupValue(aType, aValue, aArrayLen);
 }
 
 /***************************************************************************/
 
 #endif /* xpcinlines_h___ */
--- a/js/xpconnect/src/XPCWrappedJSClass.cpp
+++ b/js/xpconnect/src/XPCWrappedJSClass.cpp
@@ -663,17 +663,17 @@ nsXPCWrappedJSClass::GetRootJSObject(JSC
 }
 
 bool
 nsXPCWrappedJSClass::GetArraySizeFromParam(const nsXPTMethodInfo* method,
                                            const nsXPTType& type,
                                            nsXPTCMiniVariant* nativeParams,
                                            uint32_t* result) const
 {
-    if (type.Tag() != nsXPTType::T_LEGACY_ARRAY &&
+    if (type.Tag() != nsXPTType::T_ARRAY &&
         type.Tag() != nsXPTType::T_PSTRING_SIZE_IS &&
         type.Tag() != nsXPTType::T_PWSTRING_SIZE_IS) {
         *result = 0;
         return true;
     }
 
     uint8_t argnum = type.ArgNum();
     const nsXPTParamInfo& param = method->Param(argnum);
@@ -740,37 +740,35 @@ nsXPCWrappedJSClass::CleanupOutparams(co
                                       bool inOutOnly, uint8_t count) const
 {
     // clean up any 'out' params handed in
     for (uint8_t i = 0; i < count; i++) {
         const nsXPTParamInfo& param = info->GetParam(i);
         if (!param.IsOut())
             continue;
 
+        // Extract the array length so we can use it in CleanupValue.
+        uint32_t arrayLen = 0;
+        if (!GetArraySizeFromParam(info, param.Type(), nativeParams, &arrayLen))
+            continue;
+
         MOZ_ASSERT(param.IsIndirect(), "Outparams are always indirect");
 
-        // Call 'CleanupValue' on parameters which we know to be initialized:
-        //  1. Complex parameters (initialized by caller)
-        //  2. 'inout' parameters (initialized by caller)
-        //  3. 'out' parameters when 'inOutOnly' is 'false' (initialized by us)
-        //
-        // We skip non-complex 'out' parameters before the call, as they may
-        // contain random junk.
-        if (param.Type().IsComplex() || param.IsIn() || !inOutOnly) {
-            uint32_t arrayLen = 0;
-            if (!GetArraySizeFromParam(info, param.Type(), nativeParams, &arrayLen))
-                continue;
-
+        // The inOutOnly flag is necessary because full outparams may contain
+        // uninitialized junk before the call is made, and we don't want to try
+        // to clean up uninitialized junk.
+        if (!inOutOnly || param.IsIn()) {
             xpc::CleanupValue(param.Type(), nativeParams[i].val.p, arrayLen);
         }
 
-        // Ensure our parameters are in a clean state. Complex values are always
-        // handled by CleanupValue, and others have a valid null representation.
-        if (!param.Type().IsComplex()) {
-            param.Type().ZeroValue(nativeParams[i].val.p);
+        // Even if we didn't call CleanupValue, null out any pointers. This is
+        // just to protect C++ callers which may read garbage if they forget to
+        // check the error value.
+        if (param.Type().HasPointerRepr()) {
+            *(void**)nativeParams[i].val.p = nullptr;
         }
     }
 }
 
 nsresult
 nsXPCWrappedJSClass::CheckForException(XPCCallContext & ccx,
                                        AutoEntryScript& aes,
                                        const char * aPropertyName,
--- a/js/xpconnect/src/XPCWrappedNative.cpp
+++ b/js/xpconnect/src/XPCWrappedNative.cpp
@@ -1240,30 +1240,34 @@ CallMethodHelper::Call()
     }
 
     return GatherAndConvertResults();
 }
 
 CallMethodHelper::~CallMethodHelper()
 {
     for (nsXPTCVariant& param : mDispatchParams) {
+        // Only clean up values which need cleanup.
+        if (!param.DoesValNeedCleanup())
+            continue;
+
         uint32_t arraylen = 0;
         if (!GetArraySizeFromParam(param.type, UndefinedHandleValue, &arraylen))
             continue;
 
         xpc::CleanupValue(param.type, &param.val, arraylen);
     }
 }
 
 bool
 CallMethodHelper::GetArraySizeFromParam(const nsXPTType& type,
                                         HandleValue maybeArray,
                                         uint32_t* result)
 {
-    if (type.Tag() != nsXPTType::T_LEGACY_ARRAY &&
+    if (type.Tag() != nsXPTType::T_ARRAY &&
         type.Tag() != nsXPTType::T_PSTRING_SIZE_IS &&
         type.Tag() != nsXPTType::T_PWSTRING_SIZE_IS) {
         *result = 0;
         return true;
     }
 
     uint8_t argnum = type.ArgNum();
     uint32_t* lengthp = &GetDispatchParam(argnum)->val.u32;
@@ -1468,49 +1472,35 @@ CallMethodHelper::InitializeDispatchPara
         if (mArgc < requiredArgs) {
             Throw(NS_ERROR_XPC_NOT_ENOUGH_ARGS, mCallContext);
             return false;
         }
     }
 
     mJSContextIndex = mMethodInfo->IndexOfJSContext();
 
-    // Allocate enough space in mDispatchParams up-front.
-    if (!mDispatchParams.AppendElements(paramCount + wantsJSContext + wantsOptArgc)) {
-        Throw(NS_ERROR_OUT_OF_MEMORY, mCallContext);
-        return false;
+    // iterate through the params to clear flags (for safe cleanup later)
+    for (uint8_t i = 0; i < paramCount + wantsJSContext + wantsOptArgc; i++) {
+        nsXPTCVariant* dp = mDispatchParams.AppendElement();
+        dp->ClearFlags();
+        dp->val.p = nullptr;
     }
 
-    // Initialize each parameter to a valid state (for safe cleanup later).
-    for (uint8_t i = 0, paramIdx = 0; i < mDispatchParams.Length(); i++) {
-        nsXPTCVariant& dp = mDispatchParams[i];
+    // Fill in the JSContext argument
+    if (wantsJSContext) {
+        nsXPTCVariant* dp = &mDispatchParams[mJSContextIndex];
+        dp->type = nsXPTType::T_VOID;
+        dp->val.p = mCallContext;
+    }
 
-        if (i == mJSContextIndex) {
-            // Fill in the JSContext argument
-            dp.type = nsXPTType::T_VOID;
-            dp.val.p = mCallContext;
-        } else if (i == mOptArgcIndex) {
-            // Fill in the optional_argc argument
-            dp.type = nsXPTType::T_U8;
-            dp.val.u8 = std::min<uint32_t>(mArgc, paramCount) - requiredArgs;
-        } else {
-            // Initialize normal arguments.
-            const nsXPTParamInfo& param = mMethodInfo->Param(paramIdx);
-            dp.type = param.Type();
-            xpc::InitializeValue(dp.type, &dp.val);
-
-            // Specify the correct storage/calling semantics. This will also set
-            // the `ptr` field to be self-referential.
-            if (param.IsIndirect()) {
-                dp.SetIndirect();
-            }
-
-            // Advance to the next normal parameter.
-            paramIdx++;
-        }
+    // Fill in the optional_argc argument
+    if (wantsOptArgc) {
+        nsXPTCVariant* dp = &mDispatchParams[mOptArgcIndex];
+        dp->type = nsXPTType::T_U8;
+        dp->val.u8 = std::min<uint32_t>(mArgc, paramCount) - requiredArgs;
     }
 
     return true;
 }
 
 bool
 CallMethodHelper::ConvertIndependentParams(bool* foundDependentParam)
 {
@@ -1527,18 +1517,50 @@ CallMethodHelper::ConvertIndependentPara
 
     return true;
 }
 
 bool
 CallMethodHelper::ConvertIndependentParam(uint8_t i)
 {
     const nsXPTParamInfo& paramInfo = mMethodInfo->GetParam(i);
-    const nsXPTType& type = paramInfo.Type();
+    const nsXPTType& type = paramInfo.GetType();
     nsXPTCVariant* dp = GetDispatchParam(i);
+    dp->type = type;
+    MOZ_ASSERT(!paramInfo.IsShared(), "[shared] implies [noscript]!");
+
+    // Specify the correct storage/calling semantics.
+    if (paramInfo.IsIndirect())
+        dp->SetIndirect();
+
+    // Some types are always stored within the nsXPTCVariant, and passed
+    // indirectly, regardless of in/out-ness. These types are stored in the
+    // nsXPTCVariant's extended value.
+    switch (type.Tag()) {
+        // Ensure that the jsval has a valid value.
+        case nsXPTType::T_JSVAL:
+            new (&dp->ext.jsval) JS::Value();
+            MOZ_ASSERT(dp->ext.jsval.isUndefined());
+            break;
+
+        // Initialize our temporary string class values so they can be assigned
+        // to by the XPCConvert logic.
+        case nsXPTType::T_ASTRING:
+        case nsXPTType::T_DOMSTRING:
+            new (&dp->ext.nsstr) nsString();
+            break;
+        case nsXPTType::T_CSTRING:
+        case nsXPTType::T_UTF8STRING:
+            new (&dp->ext.nscstr) nsCString();
+            break;
+    }
+
+    // Flag cleanup for anything that isn't self-contained.
+    if (!type.IsArithmetic())
+        dp->SetValNeedsCleanup();
 
     // Even if there's nothing to convert, we still need to examine the
     // JSObject container for out-params. If it's null or otherwise invalid,
     // we want to know before the call, rather than after.
     //
     // This is a no-op for 'in' params.
     RootedValue src(mCallContext);
     if (!GetOutParamSource(i, &src))
@@ -1614,18 +1636,28 @@ CallMethodHelper::ConvertDependentParams
 
     return true;
 }
 
 bool
 CallMethodHelper::ConvertDependentParam(uint8_t i)
 {
     const nsXPTParamInfo& paramInfo = mMethodInfo->GetParam(i);
-    const nsXPTType& type = paramInfo.Type();
+    const nsXPTType& type = paramInfo.GetType();
+
     nsXPTCVariant* dp = GetDispatchParam(i);
+    dp->type = type;
+
+    // Specify the correct storage/calling semantics.
+    if (paramInfo.IsIndirect())
+        dp->SetIndirect();
+
+    // Make sure we clean up all of our dependent types. All of them require
+    // allocations of some kind.
+    dp->SetValNeedsCleanup();
 
     // Even if there's nothing to convert, we still need to examine the
     // JSObject container for out-params. If it's null or otherwise invalid,
     // we want to know before the call, rather than after.
     //
     // This is a no-op for 'in' params.
     RootedValue src(mCallContext);
     if (!GetOutParamSource(i, &src))
@@ -1675,40 +1707,37 @@ CallMethodHelper::Invoke()
 
 static void
 TraceParam(JSTracer* aTrc, void* aVal, const nsXPTType& aType,
            uint32_t aArrayLen = 0)
 {
     if (aType.Tag() == nsXPTType::T_JSVAL) {
         JS::UnsafeTraceRoot(aTrc, (JS::Value*)aVal,
                             "XPCWrappedNative::CallMethod param");
-    } else if (aType.Tag() == nsXPTType::T_ARRAY) {
-        auto* array = (xpt::detail::UntypedTArray*)aVal;
+    } else if (aType.Tag() == nsXPTType::T_ARRAY && *(void**)aVal) {
         const nsXPTType& elty = aType.ArrayElementType();
-
-        for (uint32_t i = 0; i < array->Length(); ++i) {
-            TraceParam(aTrc, elty.ElementPtr(array->Elements(), i), elty);
+        if (elty.Tag() != nsXPTType::T_JSVAL) {
+            return;
         }
-    } else if (aType.Tag() == nsXPTType::T_LEGACY_ARRAY && *(void**)aVal) {
-        const nsXPTType& elty = aType.ArrayElementType();
 
         for (uint32_t i = 0; i < aArrayLen; ++i) {
-            TraceParam(aTrc, elty.ElementPtr(*(void**)aVal, i), elty);
+            TraceParam(aTrc, elty.ElementPtr(aVal, i), elty);
         }
     }
 }
 
 void
 CallMethodHelper::trace(JSTracer* aTrc)
 {
     // We need to note each of our initialized parameters which contain jsvals.
     for (nsXPTCVariant& param : mDispatchParams) {
-        // We only need to trace parameters which have an innermost JSVAL.
-        if (param.type.InnermostType().Tag() != nsXPTType::T_JSVAL) {
-            return;
+        if (!param.DoesValNeedCleanup()) {
+            MOZ_ASSERT(param.type.Tag() != nsXPTType::T_JSVAL,
+                       "JSVals are marked as needing cleanup (even though they don't)");
+            continue;
         }
 
         uint32_t arrayLen = 0;
         if (!GetArraySizeFromParam(param.type, UndefinedHandleValue, &arrayLen))
             continue;
 
         TraceParam(aTrc, &param.val, param.type, arrayLen);
     }
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -1958,64 +1958,55 @@ public:
                                          const nsID* iid,
                                          nsISupports* aOuter,
                                          nsresult* pErr);
 
     // Note - This return the XPCWrappedNative, rather than the native itself,
     // for the WN case. You probably want UnwrapReflectorToISupports.
     static bool GetISupportsFromJSObject(JSObject* obj, nsISupports** iface);
 
+    /**
+     * Convert a native array into a JS::Value.
+     *
+     * @param d [out] the resulting JS::Value
+     * @param s the native array we're working with
+     * @param type the type of objects in the array
+     * @param iid the interface of each object in the array that we want
+     * @param count the number of items in the array
+     * @param scope the default scope to put on the new JSObjects' parent chain
+     * @param pErr [out] relevant error code, if any.
+     */
+    static bool NativeArray2JS(JS::MutableHandleValue d, const void* const* s,
+                               const nsXPTType& type, const nsID* iid,
+                               uint32_t count, nsresult* pErr);
+
+    static bool JSArray2Native(void** d, JS::HandleValue s,
+                               uint32_t count, const nsXPTType& type,
+                               const nsID* iid, nsresult* pErr);
+
+    static bool JSTypedArray2Native(void** d,
+                                    JSObject* jsarray,
+                                    uint32_t count,
+                                    const nsXPTType& type,
+                                    nsresult* pErr);
+
     static nsresult JSValToXPCException(JS::MutableHandleValue s,
                                         const char* ifaceName,
                                         const char* methodName,
                                         mozilla::dom::Exception** exception);
 
     static nsresult ConstructException(nsresult rv, const char* message,
                                        const char* ifaceName,
                                        const char* methodName,
                                        nsISupports* data,
                                        mozilla::dom::Exception** exception,
                                        JSContext* cx,
                                        JS::Value* jsExceptionPtr);
 
 private:
-    /**
-     * Convert a native array into a JS::Value.
-     *
-     * @param d [out] the resulting JS::Value
-     * @param buf the native buffer containing input values
-     * @param type the type of objects in the array
-     * @param iid the interface of each object in the array that we want
-     * @param count the number of items in the array
-     * @param scope the default scope to put on the new JSObjects' parent chain
-     * @param pErr [out] relevant error code, if any.
-     */
-    static bool NativeArray2JS(JS::MutableHandleValue d, const void* buf,
-                               const nsXPTType& type, const nsID* iid,
-                               uint32_t count, nsresult* pErr);
-
-    typedef std::function<void* (uint32_t*)> ArrayAllocFixupLen;
-
-    /**
-     * Convert a JS::Value into a native array.
-     *
-     * @param aJSVal the JS::Value to convert
-     * @param aEltType the type of objects in the array
-     * @param aIID the interface of each object in the array
-     * @param pErr [out] relevant error code, if any
-     * @param aAllocFixupLen function called with the JS Array's length to
-     *                       allocate the backing buffer. This function may
-     *                       modify the length of array to be converted.
-     */
-    static bool JSArray2Native(JS::HandleValue aJSVal,
-                               const nsXPTType& aEltType,
-                               const nsIID* aIID,
-                               nsresult* pErr,
-                               ArrayAllocFixupLen aAllocFixupLen);
-
     XPCConvert() = delete;
 
 };
 
 /***************************************************************************/
 // code for throwing exceptions into JS
 
 class nsXPCException;
@@ -3045,17 +3036,17 @@ nsIPrincipal* GetObjectPrincipal(JSObjec
 //   TD_PNSIID
 //     value : nsID* (free)
 //   TD_DOMSTRING, 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)
+//   TD_ARRAY (NOTE: aArrayLen should be passed)
 //     value : void** (cleanup elements & free)
 //   TD_DOMOBJECT
 //     value : T** (cleanup)
 //   TD_PROMISE
 //     value : dom::Promise** (release)
 //
 // Other types are ignored.
 //
@@ -3066,27 +3057,16 @@ inline void CleanupValue(const nsXPTType
                          void* aValue,
                          uint32_t aArrayLen = 0);
 
 // Out-of-line internals for xpc::CleanupValue. Defined in XPCConvert.cpp.
 void InnerCleanupValue(const nsXPTType& aType,
                        void* aValue,
                        uint32_t aArrayLen);
 
-// In order to be able to safely call CleanupValue on a generated value, the
-// data behind it needs to be initialized to a safe value. This method handles
-// initializing the backing data to a safe value to use as an argument to
-// XPCConvert methods, or xpc::CleanupValue.
-//
-// The pointer `aValue` must point to a block of memory at least aType.Stride()
-// bytes large, and correctly aligned.
-//
-// This method accepts the same types as xpc::CleanupValue.
-void InitializeValue(const nsXPTType& aType, void* aValue);
-
 } // namespace xpc
 
 namespace mozilla {
 namespace dom {
 extern bool
 DefineStaticJSVals(JSContext* cx);
 } // namespace dom
 } // namespace mozilla
--- a/js/xpconnect/tests/components/js/xpctest_params.js
+++ b/js/xpconnect/tests/components/js/xpctest_params.js
@@ -59,29 +59,21 @@ TestParams.prototype = {
   testString: f,
   testWchar: f,
   testWstring: f,
   testDOMString: f,
   testAString: f,
   testAUTF8String: f,
   testACString: f,
   testJsval: f,
-  testShortSequence: f,
-  testDoubleSequence: f,
-  testAStringSequence: f,
-  testACStringSequence: f,
-  testInterfaceSequence: f,
-  testJsvalSequence: f,
-  testInterfaceIsSequence: f_is,
   testShortArray: f_is,
   testDoubleArray: f_is,
   testStringArray: f_is,
   testWstringArray: f_is,
   testInterfaceArray: f_is,
-  testJsvalArray: f_is,
   testSizedString: f_is,
   testSizedWstring: f_is,
   testInterfaceIs: f_is,
   testInterfaceIsArray: f_size_and_iid,
   testOutAString: function(o) { o.value = "out"; },
   testStringArrayOptionalSize: function(arr, size) {
     if (arr.length != size) { throw "bad size passed to test method"; }
     var rv = "";
--- a/js/xpconnect/tests/components/native/xpctest_params.cpp
+++ b/js/xpconnect/tests/components/native/xpctest_params.cpp
@@ -23,24 +23,16 @@ nsXPCTestParams::~nsXPCTestParams()
 }
 
 #define STRING_METHOD_IMPL {                                                  \
     _retval.Assign(b);                                                        \
     b.Assign(a);                                                              \
     return NS_OK;                                                             \
 }
 
-#define SEQUENCE_METHOD_IMPL(TAKE_OWNERSHIP) {                                \
-    _retval.SwapElements(b);                                                  \
-    b = a;                                                                    \
-    for (uint32_t i = 0; i < b.Length(); ++i)                                 \
-        TAKE_OWNERSHIP(b[i]);                                                 \
-    return NS_OK;                                                             \
-}
-
 #define TAKE_OWNERSHIP_NOOP(val) {}
 #define TAKE_OWNERSHIP_INTERFACE(val) {static_cast<nsISupports*>(val)->AddRef();}
 #define TAKE_OWNERSHIP_STRING(val) {                                          \
     nsDependentCString vprime(val);                                           \
     val = ToNewCString(vprime);                                               \
 }
 #define TAKE_OWNERSHIP_WSTRING(val) {                                         \
     nsDependentString vprime(val);                                            \
@@ -226,23 +218,16 @@ NS_IMETHODIMP nsXPCTestParams::TestWstri
 
 NS_IMETHODIMP nsXPCTestParams::TestInterfaceArray(uint32_t aLength, nsIXPCTestInterfaceA** a,
                                                   uint32_t* bLength, nsIXPCTestInterfaceA * **b,
                                                   uint32_t* rvLength, nsIXPCTestInterfaceA * **rv)
 {
     BUFFER_METHOD_IMPL(nsIXPCTestInterfaceA*, 0, TAKE_OWNERSHIP_INTERFACE);
 }
 
-NS_IMETHODIMP nsXPCTestParams::TestJsvalArray(uint32_t aLength, JS::Value *a,
-                                              uint32_t* bLength, JS::Value **b,
-                                              uint32_t* rvLength, JS::Value **rv)
-{
-    BUFFER_METHOD_IMPL(JS::Value, 0, TAKE_OWNERSHIP_NOOP);
-}
-
 NS_IMETHODIMP nsXPCTestParams::TestSizedString(uint32_t aLength, const char * a,
                                                uint32_t* bLength, char * *b,
                                                uint32_t* rvLength, char * *rv)
 {
     BUFFER_METHOD_IMPL(char, 1, TAKE_OWNERSHIP_NOOP);
 }
 
 NS_IMETHODIMP nsXPCTestParams::TestSizedWstring(uint32_t aLength, const char16_t * a,
@@ -316,73 +301,8 @@ NS_IMETHODIMP nsXPCTestParams::TestStrin
 {
   out.Truncate();
   for (uint32_t i = 0; i < length; ++i) {
     out.Append(a[i]);
   }
 
   return NS_OK;
 }
-
-NS_IMETHODIMP
-nsXPCTestParams::TestShortSequence(const nsTArray<short>& a, nsTArray<short>& b, nsTArray<short>& _retval)
-{
-    SEQUENCE_METHOD_IMPL(TAKE_OWNERSHIP_NOOP);
-}
-
-NS_IMETHODIMP
-nsXPCTestParams::TestDoubleSequence(const nsTArray<double>& a, nsTArray<double>& b, nsTArray<double>& _retval)
-{
-    SEQUENCE_METHOD_IMPL(TAKE_OWNERSHIP_NOOP);
-}
-
-NS_IMETHODIMP
-nsXPCTestParams::TestInterfaceSequence(const nsTArray<RefPtr<nsIXPCTestInterfaceA>>& a,
-                                       nsTArray<RefPtr<nsIXPCTestInterfaceA>>& b,
-                                       nsTArray<RefPtr<nsIXPCTestInterfaceA>>& _retval)
-{
-    SEQUENCE_METHOD_IMPL(TAKE_OWNERSHIP_NOOP);
-}
-
-NS_IMETHODIMP
-nsXPCTestParams::TestAStringSequence(const nsTArray<nsString>& a,
-                                     nsTArray<nsString>& b,
-                                     nsTArray<nsString>& _retval)
-{
-    SEQUENCE_METHOD_IMPL(TAKE_OWNERSHIP_NOOP);
-}
-
-NS_IMETHODIMP
-nsXPCTestParams::TestACStringSequence(const nsTArray<nsCString>& a,
-                                      nsTArray<nsCString>& b,
-                                      nsTArray<nsCString>& _retval)
-{
-    SEQUENCE_METHOD_IMPL(TAKE_OWNERSHIP_NOOP);
-}
-
-NS_IMETHODIMP
-nsXPCTestParams::TestJsvalSequence(const nsTArray<JS::Value>& a,
-                                   nsTArray<JS::Value>& b,
-                                   nsTArray<JS::Value>& _retval)
-{
-    SEQUENCE_METHOD_IMPL(TAKE_OWNERSHIP_NOOP);
-}
-
-NS_IMETHODIMP
-nsXPCTestParams::TestSequenceSequence(const nsTArray<nsTArray<short>>& a,
-                                      nsTArray<nsTArray<short>>& b,
-                                      nsTArray<nsTArray<short>>& _retval)
-{
-    SEQUENCE_METHOD_IMPL(TAKE_OWNERSHIP_NOOP);
-}
-
-NS_IMETHODIMP
-nsXPCTestParams::TestInterfaceIsSequence(const nsIID* aIID, const nsTArray<void*>& a,
-                                         nsIID** bIID, nsTArray<void*>& b,
-                                         nsIID** rvIID, nsTArray<void*>& _retval)
-{
-    // Shuffle around our nsIIDs
-    *rvIID = (*bIID)->Clone();
-    *bIID = aIID->Clone();
-
-    // Perform the generic sequence shuffle.
-    SEQUENCE_METHOD_IMPL(TAKE_OWNERSHIP_INTERFACE);
-}
--- a/js/xpconnect/tests/idl/xpctest_params.idl
+++ b/js/xpconnect/tests/idl/xpctest_params.idl
@@ -34,29 +34,16 @@ interface nsIXPCTestParams : nsISupports
   wchar                 testWchar(in wchar a, inout wchar b);
   wstring               testWstring(in wstring a, inout wstring b);
   DOMString             testDOMString(in DOMString a, inout DOMString b);
   AString               testAString(in AString a, inout AString b);
   AUTF8String           testAUTF8String(in AUTF8String a, inout AUTF8String b);
   ACString              testACString(in ACString a, inout ACString b);
   jsval                 testJsval(in jsval a, inout jsval b);
 
-  // Test various forms of the Array<T> type.
-  Array<short>          testShortSequence(in Array<short> a, inout Array<short> b);
-  Array<double>         testDoubleSequence(in Array<double> a, inout Array<double> b);
-  Array<nsIXPCTestInterfaceA> testInterfaceSequence(in Array<nsIXPCTestInterfaceA> a, inout Array<nsIXPCTestInterfaceA> b);
-  Array<AString>        testAStringSequence(in Array<AString> a, inout Array<AString> b);
-  Array<ACString>       testACStringSequence(in Array<ACString> a, inout Array<ACString> b);
-  Array<jsval>          testJsvalSequence(in Array<jsval> a, inout Array<jsval> b);
-  Array<Array<short> >  testSequenceSequence(in Array<Array<short> > a, inout Array<Array<short> > b);
-
-  void                  testInterfaceIsSequence(in nsIIDPtr aIID, [iid_is(aIID)] in Array<nsQIResult> a,
-                                                inout nsIIDPtr bIID, [iid_is(bIID)] inout Array<nsQIResult> b,
-                                                out nsIIDPtr rvIID, [retval, iid_is(rvIID)] out Array<nsQIResult> rv);
-
   //
   // Dependent parameters use the same types as above, but are handled much differently.
   //
 
   // Test arrays.
   void                  testShortArray(in unsigned long aLength, [array, size_is(aLength)] in short a,
                                        inout unsigned long bLength, [array, size_is(bLength)] inout short b,
                                        out unsigned long rvLength, [retval, array, size_is(rvLength)] out short rv);
@@ -90,20 +77,14 @@ interface nsIXPCTestParams : nsISupports
   // in mozilla-central, but calendar stuff depends on it.
   void                  testInterfaceIsArray(in unsigned long aLength, in nsIIDPtr aIID,
                                              [array, size_is(aLength), iid_is(aIID)] in nsQIResult a,
                                              inout unsigned long bLength, inout nsIIDPtr bIID,
                                              [array, size_is(bLength), iid_is(bIID)] inout nsQIResult b,
                                              out unsigned long rvLength, out nsIIDPtr rvIID,
                                              [retval, array, size_is(rvLength), iid_is(rvIID)] out nsQIResult rv);
 
-  // Test arrays of jsvals
-  void                  testJsvalArray(in unsigned long aLength, [array, size_is(aLength)] in jsval a,
-                                       inout unsigned long bLength, [array, size_is(bLength)] inout jsval b,
-                                       out unsigned long rvLength, [retval, array, size_is(rvLength)] out jsval rv);
-
-
   // Test for out dipper parameters
   void                 testOutAString(out AString o);
 
   // Test for optional array size_is.
   ACString             testStringArrayOptionalSize([array, size_is(aLength)] in string a, [optional] in unsigned long aLength);
 };
--- a/js/xpconnect/tests/unit/test_params.js
+++ b/js/xpconnect/tests/unit/test_params.js
@@ -158,18 +158,16 @@ function test_component(contractid) {
   doIsTest("testDoubleArray", [-10, -0.5], 2, [1, 3, 1e11, -8e-5 ], 4, arrayComparator(fuzzComparator));
 
   doIsTest("testStringArray", ["mary", "hat", "hey", "lid", "tell", "lam"], 6,
                               ["ids", "fleas", "woes", "wide", "has", "know", "!"], 7, arrayComparator(standardComparator));
   doIsTest("testWstringArray", ["沒有語言", "的偉大嗎?]"], 2,
                                ["we", "are", "being", "sooo", "international", "right", "now"], 7, arrayComparator(standardComparator));
   doIsTest("testInterfaceArray", [makeA(), makeA()], 2,
                                  [makeA(), makeA(), makeA(), makeA(), makeA(), makeA()], 6, arrayComparator(interfaceComparator));
-  doIsTest("testJsvalArray", [{ cheese: 'whiz', apple: 8 }, [1, 5, '3'], /regex/], 3,
-                             ['apple', 2.2e10, 3.3e30, { only: "wheedle", except: {} }], 4, arrayComparator(standardComparator));
 
   // Test typed arrays and ArrayBuffer aliasing.
   var arrayBuffer = new ArrayBuffer(16);
   var int16Array = new Int16Array(arrayBuffer, 2, 3);
   int16Array.set([-32768, 0, 32767]);
   doIsTest("testShortArray", int16Array, 3, new Int16Array([1773, -32768, 32767, 7]), 4, arrayComparator(standardComparator));
   doIsTest("testDoubleArray", new Float64Array([-10, -0.5]), 2, new Float64Array([0, 3.2, 1.0e10, -8.33 ]), 4, arrayComparator(fuzzComparator));
 
@@ -192,29 +190,9 @@ function test_component(contractid) {
 
   // Test incorrect (too big) array size parameter; this should throw NOT_ENOUGH_ELEMENTS.
   doTypedArrayMismatchTest("testShortArray", new Int16Array([-3, 7, 4]), 4,
                                              new Int16Array([1, -32, 6]), 3);
 
   // Test type mismatch (int16 <-> uint16); this should throw BAD_CONVERT_JS.
   doTypedArrayMismatchTest("testShortArray", new Uint16Array([0, 7, 4, 3]), 4,
                                              new Uint16Array([1, 5, 6]), 3);
-
-  // Test Sequence<T> types.
-  doTest("testShortSequence", [2, 4, 6], [1, 3, 5, 7], arrayComparator(standardComparator));
-  doTest("testDoubleSequence", [-10, -0.5], [1, 3, 1e11, -8e-5 ], arrayComparator(fuzzComparator));
-  doTest("testACStringSequence", ["mary", "hat", "hey", "lid", "tell", "lam"],
-                                 ["ids", "fleas", "woes", "wide", "has", "know", "!"],
-                                 arrayComparator(standardComparator));
-  doTest("testAStringSequence", ["沒有語言", "的偉大嗎?]"],
-                                ["we", "are", "being", "sooo", "international", "right", "now"],
-                                arrayComparator(standardComparator));
-
-  doTest("testInterfaceSequence", [makeA(), makeA()],
-                                  [makeA(), makeA(), makeA(), makeA(), makeA(), makeA()], arrayComparator(interfaceComparator));
-
-  doTest("testJsvalSequence", [{ cheese: 'whiz', apple: 8 }, [1, 5, '3'], /regex/],
-                              ['apple', 2.2e10, 3.3e30, { only: "wheedle", except: {} }], arrayComparator(standardComparator));
-
-  doIsTest("testInterfaceIsSequence", [makeA(), makeA(), makeA(), makeA(), makeA()], Ci['nsIXPCTestInterfaceA'],
-                                      [makeB(), makeB(), makeB()], Ci['nsIXPCTestInterfaceB'],
-                                      arrayComparator(interfaceComparator), dotEqualsComparator);
 }
--- a/xpcom/ds/nsIVariant.idl
+++ b/xpcom/ds/nsIVariant.idl
@@ -29,17 +29,17 @@ interface nsIDataType : nsISupports
     const uint16_t VTYPE_WCHAR               = 12; // TD_WCHAR             = 12,
     const uint16_t VTYPE_VOID                = 13; // TD_VOID              = 13,
     const uint16_t VTYPE_ID                  = 14; // TD_PNSIID            = 14,
     const uint16_t VTYPE_DOMSTRING           = 15; // TD_DOMSTRING         = 15,
     const uint16_t VTYPE_CHAR_STR            = 16; // TD_PSTRING           = 16,
     const uint16_t VTYPE_WCHAR_STR           = 17; // TD_PWSTRING          = 17,
     const uint16_t VTYPE_INTERFACE           = 18; // TD_INTERFACE_TYPE    = 18,
     const uint16_t VTYPE_INTERFACE_IS        = 19; // TD_INTERFACE_IS_TYPE = 19,
-    const uint16_t VTYPE_ARRAY               = 20; // TD_LEGACY_ARRAY      = 20,
+    const uint16_t VTYPE_ARRAY               = 20; // TD_ARRAY             = 20,
     const uint16_t VTYPE_STRING_SIZE_IS      = 21; // TD_PSTRING_SIZE_IS   = 21,
     const uint16_t VTYPE_WSTRING_SIZE_IS     = 22; // TD_PWSTRING_SIZE_IS  = 22,
     const uint16_t VTYPE_UTF8STRING          = 23; // TD_UTF8STRING        = 23,
     const uint16_t VTYPE_CSTRING             = 24; // TD_CSTRING           = 24,
     const uint16_t VTYPE_ASTRING             = 25; // TD_ASTRING           = 25,
     const uint16_t VTYPE_EMPTY_ARRAY         = 254;
     const uint16_t VTYPE_EMPTY               = 255;
 };
--- a/xpcom/ds/nsTArray.h
+++ b/xpcom/ds/nsTArray.h
@@ -2530,23 +2530,16 @@ public:
 
   AutoTArray(const self_type& aOther)
     : nsTArray<E>()
   {
     Init();
     this->AppendElements(aOther);
   }
 
-  AutoTArray(self_type&& aOther)
-    : nsTArray<E>()
-  {
-    Init();
-    this->SwapElements(aOther);
-  }
-
   explicit AutoTArray(const base_type& aOther)
     : mAlign()
   {
     Init();
     this->AppendElements(aOther);
   }
 
   explicit AutoTArray(base_type&& aOther)
@@ -2571,22 +2564,16 @@ public:
   }
 
   self_type& operator=(const self_type& aOther)
   {
     base_type::operator=(aOther);
     return *this;
   }
 
-  self_type& operator=(self_type&& aOther)
-  {
-    base_type::operator=(std::move(aOther));
-    return *this;
-  }
-
   template<typename Allocator>
   self_type& operator=(const nsTArray_Impl<elem_type, Allocator>& aOther)
   {
     base_type::operator=(aOther);
     return *this;
   }
 
 private:
--- a/xpcom/ds/nsVariant.cpp
+++ b/xpcom/ds/nsVariant.cpp
@@ -1667,17 +1667,17 @@ nsVariantBase::nsVariantBase()
       {nsIDataType::VTYPE_WCHAR             , TD_WCHAR            },
       {nsIDataType::VTYPE_VOID              , TD_VOID             },
       {nsIDataType::VTYPE_ID                , TD_PNSIID           },
       {nsIDataType::VTYPE_DOMSTRING         , TD_DOMSTRING        },
       {nsIDataType::VTYPE_CHAR_STR          , TD_PSTRING          },
       {nsIDataType::VTYPE_WCHAR_STR         , TD_PWSTRING         },
       {nsIDataType::VTYPE_INTERFACE         , TD_INTERFACE_TYPE   },
       {nsIDataType::VTYPE_INTERFACE_IS      , TD_INTERFACE_IS_TYPE},
-      {nsIDataType::VTYPE_ARRAY             , TD_LEGACY_ARRAY     },
+      {nsIDataType::VTYPE_ARRAY             , TD_ARRAY            },
       {nsIDataType::VTYPE_STRING_SIZE_IS    , TD_PSTRING_SIZE_IS  },
       {nsIDataType::VTYPE_WSTRING_SIZE_IS   , TD_PWSTRING_SIZE_IS },
       {nsIDataType::VTYPE_UTF8STRING        , TD_UTF8STRING       },
       {nsIDataType::VTYPE_CSTRING           , TD_CSTRING          },
       {nsIDataType::VTYPE_ASTRING           , TD_ASTRING          }
     };
     static const int length = sizeof(array) / sizeof(array[0]);
     static bool inited = false;
--- a/xpcom/idl-parser/xpidl/jsonxpt.py
+++ b/xpcom/idl-parser/xpidl/jsonxpt.py
@@ -58,28 +58,20 @@ def get_type(type, calltype, iid_is=None
     if isinstance(type, xpidl.Builtin):
         ret = {'tag': TypeMap[type.name]}
         if type.name in ['string', 'wstring'] and size_is is not None:
             ret['tag'] += '_SIZE_IS'
             ret['size_is'] = size_is
         return ret
 
     if isinstance(type, xpidl.Array):
-        # NB: For a Array<T> we pass down the iid_is to get the type of T.
+        # NB: For an Array<T> we pass down the iid_is to get the type of T.
         #     This allows Arrays of InterfaceIs types to work.
         return {
             'tag': 'TD_ARRAY',
-            'element': get_type(type.type, calltype, iid_is),
-        }
-
-    if isinstance(type, xpidl.LegacyArray):
-        # NB: For a Legacy [array] T we pass down iid_is to get the type of T.
-        #     This allows [array] of InterfaceIs types to work.
-        return {
-            'tag': 'TD_LEGACY_ARRAY',
             'size_is': size_is,
             'element': get_type(type.type, calltype, iid_is),
         }
 
     if isinstance(type, xpidl.Interface) or isinstance(type, xpidl.Forward):
         return {
             'tag': 'TD_INTERFACE_TYPE',
             'name': type.name,
--- a/xpcom/idl-parser/xpidl/runtests.py
+++ b/xpcom/idl-parser/xpidl/runtests.py
@@ -76,17 +76,17 @@ long bar(in long a, in float b, [array] 
         self.assertEqual("long", m.type)
         self.assertEqual(3, len(m.params))
         self.assertEqual("long", m.params[0].type)
         self.assertEqual("in", m.params[0].paramtype)
         self.assertEqual("float", m.params[1].type)
         self.assertEqual("in", m.params[1].paramtype)
         self.assertEqual("long", m.params[2].type)
         self.assertEqual("in", m.params[2].paramtype)
-        self.assertTrue(isinstance(m.params[2].realtype, xpidl.LegacyArray))
+        self.assertTrue(isinstance(m.params[2].realtype, xpidl.Array))
         self.assertEqual("long", m.params[2].realtype.type.name)
 
     def testAttribute(self):
         i = self.p.parse("""[uuid(abc)] interface foo {
 attribute long bar;
 };""", filename='f')
         self.assertTrue(isinstance(i, xpidl.IDL))
         self.assertTrue(isinstance(i.productions[0], xpidl.Interface))
--- a/xpcom/idl-parser/xpidl/xpidl.py
+++ b/xpcom/idl-parser/xpidl/xpidl.py
@@ -7,26 +7,25 @@
 
 """A parser for cross-platform IDL (XPIDL) files."""
 
 import sys
 import os.path
 import re
 from ply import lex
 from ply import yacc
-from collections import namedtuple
 
 """A type conforms to the following pattern:
 
     def isScriptable(self):
         'returns True or False'
 
     def nativeType(self, calltype):
         'returns a string representation of the native type
-        calltype must be 'in', 'out', 'inout', or 'element'
+        calltype must be 'in', 'out', or 'inout'
 
 Interface members const/method/attribute conform to the following pattern:
 
     name = 'string'
 
     def toIDL(self):
         'returns the member signature as IDL'
 """
@@ -127,33 +126,30 @@ class Builtin(object):
     def isScriptable(self):
         return True
 
     def isPointer(self):
         """Check if this type is a pointer type - this will control how pointers act"""
         return self.nativename.endswith('*')
 
     def nativeType(self, calltype, shared=False, const=False):
-        if self.name in ["string", "wstring"] and calltype == 'element':
-            raise IDLError("Use string class types for string Array elements", self.location)
-
         if const:
             print >>sys.stderr, IDLError(
                 "[const] doesn't make sense on builtin types.", self.location, warning=True)
             const = 'const '
         elif calltype == 'in' and self.isPointer():
             const = 'const '
         elif shared:
             if not self.isPointer():
                 raise IDLError("[shared] not applicable to non-pointer types.", self.location)
             const = 'const '
         else:
             const = ''
         return "%s%s %s" % (const, self.nativename,
-                            '*' if 'out' in calltype else '')
+                            calltype != 'in' and '*' or '')
 
     def rustType(self, calltype, shared=False, const=False):
         # We want to rewrite any *mut pointers to *const pointers if constness
         # was requested.
         const = const or (calltype == 'in' and self.isPointer()) or shared
         rustname = self.rustname
         if const and self.isPointer():
             rustname = self.rustname.replace("*mut", "*const")
@@ -320,37 +316,27 @@ class Include(object):
             parent.deps.extend(self.IDL.deps)
             return
 
         raise IDLError("File '%s' not found" % self.filename, self.location)
 
 
 class IDL(object):
     def __init__(self, productions):
-        self.hasSequence = False
         self.productions = productions
         self.deps = []
 
     def setName(self, object):
         self.namemap.set(object)
 
     def getName(self, id, location):
-        if id.name == 'Array':
-            if id.params is None or len(id.params) != 1:
-                raise IDLError("Array takes exactly 1 parameter", location)
-            self.hasSequence = True
-            return Array(self.getName(id.params[0], location), location)
-
-        if id.params is not None:
-            raise IDLError("Generic type '%s' unrecognized" % id.name, location)
-
         try:
-            return self.namemap[id.name]
+            return self.namemap[id]
         except KeyError:
-            raise IDLError("type '%s' not found" % id.name, location)
+            raise IDLError("type '%s' not found" % id, location)
 
     def hasName(self, id):
         return id in self.namemap
 
     def getNames(self):
         return iter(self.namemap)
 
     def __str__(self):
@@ -363,18 +349,16 @@ class IDL(object):
         self.webidlconfig = webidlconfig
         for p in self.productions:
             p.resolve(self)
 
     def includes(self):
         for p in self.productions:
             if p.kind == 'include':
                 yield p
-        if self.hasSequence:
-            yield Include("nsTArray.h", BuiltinLocation)
 
     def needsJSTypes(self):
         for p in self.productions:
             if p.kind == 'interface' and p.needsJSTypes():
                 return True
         return False
 
 
@@ -407,24 +391,22 @@ class Typedef(object):
 
     def __eq__(self, other):
         return self.name == other.name and self.type == other.type
 
     def resolve(self, parent):
         parent.setName(self)
         self.realtype = parent.getName(self.type, self.location)
 
-        if not isinstance(self.realtype, (Builtin, Native, Typedef)):
-            raise IDLError("Unsupported typedef target type", self.location)
-
     def isScriptable(self):
         return self.realtype.isScriptable()
 
     def nativeType(self, calltype):
-        return "%s %s" % (self.name, '*' if 'out' in calltype else '')
+        return "%s %s" % (self.name,
+                          calltype != 'in' and '*' or '')
 
     def rustType(self, calltype):
         return "%s%s" % (calltype != 'in' and '*mut ' or '',
                          self.name)
 
     def __str__(self):
         return "typedef %s %s\n" % (self.type, self.name)
 
@@ -453,19 +435,18 @@ class Forward(object):
                     break
 
         parent.setName(self)
 
     def isScriptable(self):
         return True
 
     def nativeType(self, calltype):
-        if calltype == 'element':
-            return 'RefPtr<%s>' % self.name
-        return "%s *%s" % (self.name, '*' if 'out' in calltype else '')
+        return "%s %s" % (self.name,
+                          calltype != 'in' and '* *' or '*')
 
     def rustType(self, calltype):
         if rustBlacklistedForward(self.name):
             raise RustNoncompat("forward declaration %s is unsupported" % self.name)
         return "%s*const %s" % (calltype != 'in' and '*mut ' or '',
                                 self.name)
 
     def __str__(self):
@@ -473,29 +454,39 @@ class Forward(object):
 
 
 class Native(object):
     kind = 'native'
 
     modifier = None
     specialtype = None
 
-    # A tuple type here means that a custom value is used for each calltype:
-    #   (in, out/inout, array element) respectively.
-    # A `None` here means that the written type should be used as-is.
     specialtypes = {
         'nsid': None,
-        'domstring': ('const nsAString&', 'nsAString&', 'nsString'),
-        'utf8string': ('const nsACString&', 'nsACString&', 'nsCString'),
-        'cstring': ('const nsACString&', 'nsACString&', 'nsCString'),
-        'astring': ('const nsAString&', 'nsAString&', 'nsString'),
-        'jsval': ('JS::HandleValue', 'JS::MutableHandleValue', 'JS::Value'),
+        'domstring': 'nsAString',
+        'utf8string': 'nsACString',
+        'cstring': 'nsACString',
+        'astring': 'nsAString',
+        'jsval': 'JS::Value',
         'promise': '::mozilla::dom::Promise',
     }
 
+    # Mappings from C++ native name types to rust native names. Types which
+    # aren't listed here are incompatible with rust code.
+    rust_nativenames = {
+        'void': "libc::c_void",
+        'char': "u8",
+        'char16_t': "u16",
+        'nsID': "nsID",
+        'nsIID': "nsIID",
+        'nsCID': "nsCID",
+        'nsAString': "::nsstring::nsAString",
+        'nsACString': "::nsstring::nsACString",
+    }
+
     def __init__(self, name, nativename, attlist, location):
         self.name = name
         self.nativename = nativename
         self.location = location
 
         for name, value, aloc in attlist:
             if value is not None:
                 raise IDLError("Unexpected attribute value", aloc)
@@ -537,85 +528,57 @@ class Native(object):
         return self.modifier == 'ptr'
 
     def isRef(self, calltype):
         return self.modifier == 'ref'
 
     def nativeType(self, calltype, const=False, shared=False):
         if shared:
             if calltype != 'out':
-                raise IDLError("[shared] only applies to out parameters.", self.location)
+                raise IDLError("[shared] only applies to out parameters.")
             const = True
 
-        if isinstance(self.nativename, tuple):
-            if calltype == 'in':
-                return self.nativename[0] + ' '
-            elif 'out' in calltype:
-                return self.nativename[1] + ' '
-            else:
-                return self.nativename[2] + ' '
-
-        # 'in' nsid parameters should be made 'const'
-        if self.specialtype == 'nsid' and calltype == 'in':
+        if self.specialtype not in [None, 'promise'] and calltype == 'in':
             const = True
 
-        if calltype == 'element':
-            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.specialtype == 'jsval':
+            if calltype == 'out' or calltype == 'inout':
+                return "JS::MutableHandleValue "
+            return "JS::HandleValue "
 
         if self.isRef(calltype):
-            m = '& '  # [ref] is always passed with a single indirection
+            m = '& '
+        elif self.isPtr(calltype):
+            m = '*' + ((self.modifier == 'ptr' and calltype != 'in') and '*' or '')
         else:
-            m = '* ' if 'out' in calltype else ''
-            if self.isPtr(calltype):
-                m += '* '
+            m = calltype != 'in' and '*' or ''
         return "%s%s %s" % (const and 'const ' or '', self.nativename, m)
 
     def rustType(self, calltype, const=False, shared=False):
-        # For the most part, 'native' types don't make sense in rust, as they
-        # are native C++ types. However, we can support a few types here, as
-        # they're important.
-        #
-        # NOTE: This code doesn't try to perfectly match C++ constness, as
-        # constness doesn't affect ABI, and raw pointers are already unsafe.
+        if shared:
+            if calltype != 'out':
+                raise IDLError("[shared] only applies to out parameters.")
+            const = True
 
-        if self.modifier not in ['ptr', 'ref']:
-            raise RustNoncompat('Rust only supports [ref] / [ptr] native types')
-
-        prefix = '*mut ' if 'out' in calltype else '*const '
-        if 'out' in calltype and self.modifier == 'ptr':
-            prefix += '*mut '
+        if self.specialtype is not None and calltype == 'in':
+            const = True
 
-        if self.specialtype == 'nsid':
-            return prefix + self.nativename
-        if self.specialtype in ['cstring', 'utf8string']:
-            if 'element' in calltype:
-                return '::nsstring::nsCString'
-            return prefix + '::nsstring::nsACString'
-        if self.specialtype in ['astring', 'domstring']:
-            if 'element' in calltype:
-                return '::nsstring::nsString'
-            return prefix + '::nsstring::nsAString'
-        if self.nativename == 'void':
-            return prefix + 'libc::c_void'
+        if self.nativename not in self.rust_nativenames:
+            raise RustNoncompat("native type %s is unsupported" % self.nativename)
+        name = self.rust_nativenames[self.nativename]
 
-        if self.specialtype:
-            raise RustNoncompat("specialtype %s unsupported" % self.specialtype)
-        raise RustNoncompat("native type %s unsupported" % self.nativename)
+        if self.isRef(calltype):
+            m = const and '&' or '&mut '
+        elif self.isPtr(calltype):
+            m = (const and '*const ' or '*mut ')
+            if self.modifier == 'ptr' and calltype != 'in':
+                m += '*mut '
+        else:
+            m = calltype != 'in' and '*mut ' or ''
+        return "%s%s" % (m, name)
 
     def __str__(self):
         return "native %s(%s)\n" % (self.name, self.nativename)
 
 
 class WebIDL(object):
     kind = 'webidl'
 
@@ -645,23 +608,21 @@ class WebIDL(object):
             self.headerFile = self.native.replace('::', '/') + '.h'
 
         parent.setName(self)
 
     def isScriptable(self):
         return True  # All DOM objects are script exposed.
 
     def nativeType(self, calltype):
-        if calltype == 'element':
-            return 'RefPtr<%s>' % self.native
-        return "%s *%s" % (self.native, '*' if 'out' in calltype else '')
+        return "%s %s" % (self.native, calltype != 'in' and '* *' or '*')
 
     def rustType(self, calltype):
         # Just expose the type as a void* - we can't do any better.
-        return "%s*const libc::c_void" % ('*mut ' if 'out' in calltype else '')
+        return "%s*const libc::c_void" % (calltype != 'in' and '*mut ' or '')
 
     def __str__(self):
         return "webidl %s\n" % self.name
 
 
 class Interface(object):
     kind = 'interface'
 
@@ -696,32 +657,32 @@ class Interface(object):
 
         # Hack alert: if an identifier is already present, libIDL assigns
         # doc comments incorrectly. This is quirks-mode extraordinaire!
         if parent.hasName(self.name):
             for member in self.members:
                 if hasattr(member, 'doccomments'):
                     member.doccomments[0:0] = self.doccomments
                     break
-            self.doccomments = parent.getName(TypeId(self.name), None).doccomments
+            self.doccomments = parent.getName(self.name, None).doccomments
 
         if self.attributes.function:
             has_method = False
             for member in self.members:
                 if member.kind is 'method':
                     if has_method:
                         raise IDLError(
                             "interface '%s' has multiple methods, but marked 'function'" %
                             self.name, self.location)
                     else:
                         has_method = True
 
         parent.setName(self)
         if self.base is not None:
-            realbase = parent.getName(TypeId(self.base), self.location)
+            realbase = parent.getName(self.base, self.location)
             if realbase.kind != 'interface':
                 raise IDLError("interface '%s' inherits from non-interface type '%s'" %
                                (self.name, self.base), self.location)
 
             if self.attributes.scriptable and not realbase.attributes.scriptable:
                 raise IDLError("interface '%s' is scriptable but derives from "
                                "non-scriptable '%s'" %
                                (self.name, self.base), self.location, warning=True)
@@ -747,23 +708,22 @@ class Interface(object):
 
     def isScriptable(self):
         # NOTE: this is not whether *this* interface is scriptable... it's
         # whether, when used as a type, it's scriptable, which is true of all
         # interfaces.
         return True
 
     def nativeType(self, calltype, const=False):
-        if calltype == 'element':
-            return 'RefPtr<%s>' % self.name
-        return "%s%s *%s" % ('const ' if const else '', self.name,
-                             '*' if 'out' in calltype else '')
+        return "%s%s %s" % (const and 'const ' or '',
+                            self.name,
+                            calltype != 'in' and '* *' or '*')
 
-    def rustType(self, calltype, const=False):
-        return "%s*const %s" % ('*mut ' if 'out' in calltype else '',
+    def rustType(self, calltype):
+        return "%s*const %s" % (calltype != 'in' and '*mut ' or '',
                                 self.name)
 
     def __str__(self):
         l = ["interface %s\n" % self.name]
         if self.base is not None:
             l.append("\tbase %s\n" % self.base)
         l.append(str(self.attributes))
         if self.members is None:
@@ -772,38 +732,38 @@ class Interface(object):
             for m in self.members:
                 l.append(str(m))
         return "".join(l)
 
     def getConst(self, name, location):
         # The constant may be in a base class
         iface = self
         while name not in iface.namemap and iface is not None:
-            iface = self.idl.getName(TypeId(self.base), self.location)
+            iface = self.idl.getName(self.base, self.location)
         if iface is None:
-            raise IDLError("cannot find symbol '%s'" % name, self.location)
+            raise IDLError("cannot find symbol '%s'" % name)
         c = iface.namemap.get(name, location)
         if c.kind != 'const':
             raise IDLError("symbol '%s' is not a constant", c.location)
 
         return c.getValue()
 
     def needsJSTypes(self):
         for m in self.members:
-            if m.kind == "attribute" and m.type == TypeId("jsval"):
+            if m.kind == "attribute" and m.type == "jsval":
                 return True
             if m.kind == "method" and m.needsJSTypes():
                 return True
         return False
 
     def countEntries(self):
         ''' Returns the number of entries in the vtable for this interface. '''
         total = sum(member.count() for member in self.members)
         if self.base is not None:
-            realbase = self.idl.getName(TypeId(self.base), self.location)
+            realbase = self.idl.getName(self.base, self.location)
             total += realbase.countEntries()
         return total
 
 
 class InterfaceAttributes(object):
     uuid = None
     scriptable = False
     builtinclass = False
@@ -1119,17 +1079,17 @@ class Method(object):
                                     self.name,
                                     ", ".join([p.toIDL()
                                                for p in self.params]),
                                     raises)
 
     def needsJSTypes(self):
         if self.implicit_jscontext:
             return True
-        if self.type == TypeId("jsval"):
+        if self.type == "jsval":
             return True
         for p in self.params:
             t = p.realtype
             if isinstance(t, Native) and t.specialtype == "jsval":
                 return True
         return False
 
     def count(self):
@@ -1201,17 +1161,17 @@ class Param(object):
                 elif name == 'optional':
                     self.optional = True
                 else:
                     raise IDLError("Unexpected attribute '%s'" % name, aloc)
 
     def resolve(self, method):
         self.realtype = method.iface.idl.getName(self.type, self.location)
         if self.array:
-            self.realtype = LegacyArray(self.realtype)
+            self.realtype = Array(self.realtype)
         if (self.null is not None and
                 getBuiltinOrNativeTypeName(self.realtype) != '[domstring]'):
             raise IDLError("'Null' attribute can only be used on DOMString",
                            self.location)
         if (self.undefined is not None and
                 getBuiltinOrNativeTypeName(self.realtype) != '[domstring]'):
             raise IDLError("'Undefined' attribute can only be used on DOMString",
                            self.location)
@@ -1246,90 +1206,30 @@ class Param(object):
 
     def toIDL(self):
         return "%s%s %s %s" % (paramAttlistToIDL(self.attlist),
                                self.paramtype,
                                self.type,
                                self.name)
 
 
-class LegacyArray(object):
+class Array(object):
     def __init__(self, basetype):
         self.type = basetype
-        self.location = self.type.location
 
     def isScriptable(self):
         return self.type.isScriptable()
 
     def nativeType(self, calltype, const=False):
-        if 'element' in calltype:
-            raise IDLError("nested [array] unsupported", self.location)
-
-        # For legacy reasons, we have to add a 'const ' to builtin pointer array
-        # types. (`[array] in string` and `[array] in wstring` parameters)
-        if calltype == 'in' and isinstance(self.type, Builtin) and self.type.isPointer():
-            const = True
-
-        return "%s%s*%s" % ('const ' if const else '',
-                            self.type.nativeType('legacyelement'),
-                            '*' if 'out' in calltype else '')
+        return "%s%s*" % (const and 'const ' or '',
+                          self.type.nativeType(calltype))
 
     def rustType(self, calltype, const=False):
-        return "%s%s%s" % ('*mut ' if 'out' in calltype else '',
-                           '*const ' if const else '*mut ',
-                           self.type.rustType('legacyelement'))
-
-
-class Array(object):
-    kind = 'array'
-
-    def __init__(self, type, location):
-        self.type = type
-        self.location = location
-
-    @property
-    def name(self):
-        return "Array<%s>" % self.type.name
-
-    def resolve(self, idl):
-        idl.getName(self.type, self.location)
-
-    def isScriptable(self):
-        return self.type.isScriptable()
-
-    def nativeType(self, calltype):
-        if calltype == 'legacyelement':
-            raise IDLError("[array] Array<T> is unsupported", self.location)
-
-        base = 'nsTArray<%s>' % self.type.nativeType('element')
-        if 'out' in calltype:
-            return '%s& ' % base
-        elif 'in' == calltype:
-            return 'const %s& ' % base
-        else:
-            return base
-
-    def rustType(self, calltype):
-        # NOTE: To add Rust support, ensure 'element' is handled correctly in
-        # all rustType callees.
-        raise RustNoncompat("Array<...> types")
-
-
-TypeId = namedtuple('TypeId', 'name params')
-
-
-# Make str(TypeId) produce a nicer value
-TypeId.__str__ = lambda self: \
-    "%s<%s>" % (self.name, ', '.join(str(p) for p in self.params)) \
-    if self.params is not None \
-    else self.name
-
-
-# Allow skipping 'params' in TypeId(..)
-TypeId.__new__.__defaults__ = (None,)
+        return "%s %s" % (const and '*const' or '*mut',
+                          self.type.rustType(calltype))
 
 
 class IDLParser(object):
     keywords = {
         'const': 'CONST',
         'interface': 'INTERFACE',
         'in': 'IN',
         'inout': 'INOUT',
@@ -1362,17 +1262,17 @@ class IDLParser(object):
 
     hexchar = r'[a-fA-F0-9]'
 
     t_NUMBER = r'-?\d+'
     t_HEXNUM = r'0x%s+' % hexchar
     t_LSHIFT = r'<<'
     t_RSHIFT = r'>>'
 
-    literals = '"(){}[]<>,;:=|+-*'
+    literals = '"(){}[],;:=|+-*'
 
     t_ignore = ' \t'
 
     def t_multilinecomment(self, t):
         r'/\*(?s).*?\*/'
         t.lexer.lineno += t.value.count('\n')
         if t.value.startswith("/**"):
             self._doccomments.append(t.value)
@@ -1455,17 +1355,17 @@ class IDLParser(object):
         """productions : interface productions
                        | typedef productions
                        | native productions
                        | webidl productions"""
         p[0] = list(p[2])
         p[0].insert(0, p[1])
 
     def p_typedef(self, p):
-        """typedef : TYPEDEF type IDENTIFIER ';'"""
+        """typedef : TYPEDEF IDENTIFIER IDENTIFIER ';'"""
         p[0] = Typedef(type=p[2],
                        name=p[3],
                        location=self.getLocation(p, 1),
                        doccomments=p.slice[1].doccomments)
 
     def p_native(self, p):
         """native : attributes NATIVE IDENTIFIER afternativeid '(' NATIVEID ')' ';'"""
         p[0] = Native(name=p[3],
@@ -1568,17 +1468,17 @@ class IDLParser(object):
         p[0] = list(p[2])
         p[0].insert(0, p[1])
 
     def p_member_cdata(self, p):
         """member : CDATA"""
         p[0] = CDATA(p[1], self.getLocation(p, 1))
 
     def p_member_const(self, p):
-        """member : CONST type IDENTIFIER '=' number ';' """
+        """member : CONST IDENTIFIER IDENTIFIER '=' number ';' """
         p[0] = ConstMember(type=p[2], name=p[3],
                            value=p[5], location=self.getLocation(p, 1),
                            doccomments=p.slice[1].doccomments)
 
 # All "number" products return a function(interface)
 
     def p_number_decimal(self, p):
         """number : NUMBER"""
@@ -1630,33 +1530,33 @@ class IDLParser(object):
 
     def p_number_bitor(self, p):
         """number : number '|' number"""
         n1 = p[1]
         n2 = p[3]
         p[0] = lambda i: n1(i) | n2(i)
 
     def p_member_att(self, p):
-        """member : attributes optreadonly ATTRIBUTE type IDENTIFIER ';'"""
+        """member : attributes optreadonly ATTRIBUTE IDENTIFIER IDENTIFIER ';'"""
         if 'doccomments' in p[1]:
             doccomments = p[1]['doccomments']
         elif p[2] is not None:
             doccomments = p[2]
         else:
             doccomments = p.slice[3].doccomments
 
         p[0] = Attribute(type=p[4],
                          name=p[5],
                          attlist=p[1]['attlist'],
                          readonly=p[2] is not None,
                          location=self.getLocation(p, 3),
                          doccomments=doccomments)
 
     def p_member_method(self, p):
-        """member : attributes type IDENTIFIER '(' paramlist ')' raises ';'"""
+        """member : attributes IDENTIFIER IDENTIFIER '(' paramlist ')' raises ';'"""
         if 'doccomments' in p[1]:
             doccomments = p[1]['doccomments']
         else:
             doccomments = p.slice[2].doccomments
 
         p[0] = Method(type=p[2],
                       name=p[3],
                       attlist=p[1]['attlist'],
@@ -1679,17 +1579,17 @@ class IDLParser(object):
         p[0] = []
 
     def p_moreparams_continue(self, p):
         """moreparams : ',' param moreparams"""
         p[0] = list(p[3])
         p[0].insert(0, p[2])
 
     def p_param(self, p):
-        """param : attributes paramtype type IDENTIFIER"""
+        """param : attributes paramtype IDENTIFIER IDENTIFIER"""
         p[0] = Param(paramtype=p[2],
                      type=p[3],
                      name=p[4],
                      attlist=p[1]['attlist'],
                      location=self.getLocation(p, 3))
 
     def p_paramtype(self, p):
         """paramtype : IN
@@ -1717,35 +1617,16 @@ class IDLParser(object):
         """idlist : IDENTIFIER"""
         p[0] = [p[1]]
 
     def p_idlist_continue(self, p):
         """idlist : IDENTIFIER ',' idlist"""
         p[0] = list(p[3])
         p[0].insert(0, p[1])
 
-    def p_type_id(self, p):
-        """type : IDENTIFIER"""
-        p[0] = TypeId(name=p[1])
-        p.slice[0].doccomments = p.slice[1].doccomments
-
-    def p_type_generic(self, p):
-        """type : IDENTIFIER '<' typelist '>'"""
-        p[0] = TypeId(name=p[1], params=p[3])
-        p.slice[0].doccomments = p.slice[1].doccomments
-
-    def p_typelist(self, p):
-        """typelist : type"""
-        p[0] = [p[1]]
-
-    def p_typelist_continue(self, p):
-        """typelist : type ',' typelist"""
-        p[0] = list(p[3])
-        p[0].insert(0, p[1])
-
     def p_error(self, t):
         if not t:
             raise IDLError(
                 "Syntax Error at end of file. Possibly due to missing semicolon(;), braces(}) "
                 "or both", None)
         else:
             location = Location(self.lexer, t.lineno, t.lexpos)
             raise IDLError("invalid syntax", location)
--- a/xpcom/reflect/xptcall/xptcall.h
+++ b/xpcom/reflect/xptcall/xptcall.h
@@ -40,30 +40,31 @@ struct nsXPTCMiniVariant
     Union val;
 };
 
 static_assert(offsetof(nsXPTCMiniVariant, val) == 0,
               "nsXPTCMiniVariant must be a thin wrapper");
 
 struct nsXPTCVariant
 {
+// No ctors or dtors so that we can use arrays of these on the stack with no
+// penalty.
     union ExtendedVal
     {
     // 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;
 
         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;
         ~ExtendedVal() = delete;
     };
 
     union
@@ -73,48 +74,53 @@ struct nsXPTCVariant
 
         // Storage for any extended variants.
         ExtendedVal ext;
     };
 
     nsXPTType type;
     uint8_t   flags;
 
-    // Clear to a valid, null state.
-    nsXPTCVariant() {
-        memset(this, 0, sizeof(nsXPTCVariant));
-        type = nsXPTType::T_VOID;
-    }
-
     enum
     {
         //
         // Bitflag definitions
         //
 
         // Indicates that we &val.p should be passed n the stack, i.e. that
         // val should be passed by reference.
         IS_INDIRECT    = 0x1,
+
+        // Indicates that the value we hold requires some sort of cleanup (memory
+        // deallocation, interface release, JS::Value unrooting, etc). The precise
+        // cleanup that is performed depends on the 'type' field above.
+        // If the value is an array, this flag specifies whether the elements
+        // within the array require cleanup (we always clean up the array itself,
+        // so this flag would be redundant for that purpose).
+        VAL_NEEDS_CLEANUP = 0x2
     };
 
     void ClearFlags()         {flags = 0;}
     void SetIndirect()        {flags |= IS_INDIRECT;}
+    void SetValNeedsCleanup() {flags |= VAL_NEEDS_CLEANUP;}
 
     bool IsIndirect()         const  {return 0 != (flags & IS_INDIRECT);}
+    bool DoesValNeedCleanup() const  {return 0 != (flags & VAL_NEEDS_CLEANUP);}
 
     // Implicitly convert to nsXPTCMiniVariant.
     operator nsXPTCMiniVariant&() {
         return *(nsXPTCMiniVariant*) &val;
     }
     operator const nsXPTCMiniVariant&() const {
         return *(const nsXPTCMiniVariant*) &val;
     }
 
-    // As this type contains an anonymous union, we need to provide an explicit
-    // destructor.
+    // As this type contains an anonymous union, we need to provide explicit
+    // constructors & destructors.
+    nsXPTCVariant() { }
     ~nsXPTCVariant() { }
 };
 
 static_assert(offsetof(nsXPTCVariant, val) == offsetof(nsXPTCVariant, ext),
               "nsXPTCVariant::{ext,val} must have matching offsets");
 
 class nsIXPTCProxy : public nsISupports
 {
--- a/xpcom/reflect/xptinfo/xptcodegen.py
+++ b/xpcom/reflect/xptinfo/xptcodegen.py
@@ -260,40 +260,35 @@ def link_to_cpp(interfaces, fd):
         idx = type_cache.get(key)
         if idx is None:
             idx = type_cache[key] = len(types)
             types.append(lower_type(type))
         return idx
 
     def describe_type(type):  # Create the type's documentation comment.
         tag = type['tag'][3:].lower()
-        if tag == 'legacy_array':
+        if tag == 'array':
             return '%s[size_is=%d]' % (
                 describe_type(type['element']), type['size_is'])
         elif tag == 'interface_type' or tag == 'domobject':
             return type['name']
         elif tag == 'interface_is_type':
             return 'iid_is(%d)' % type['iid_is']
         elif tag.endswith('_size_is'):
             return '%s(size_is=%d)' % (tag, type['size_is'])
         return tag
 
     def lower_type(type, in_=False, out=False, optional=False):
         tag = type['tag']
         d1 = d2 = 0
 
-        if tag == 'TD_LEGACY_ARRAY':
+        if tag == 'TD_ARRAY':
             d1 = type['size_is']
             d2 = lower_extra_type(type['element'])
 
-        elif tag == 'TD_ARRAY':
-            # NOTE: TD_ARRAY can hold 16 bits of type index, while
-            # TD_LEGACY_ARRAY can only hold 8.
-            d1, d2 = splitint(lower_extra_type(type['element']))
-
         elif tag == 'TD_INTERFACE_TYPE':
             d1, d2 = splitint(interface_idx(type['name']))
 
         elif tag == 'TD_INTERFACE_IS_TYPE':
             d1 = type['iid_is']
 
         elif tag == 'TD_DOMOBJECT':
             d1, d2 = splitint(lower_domobject(type))
--- a/xpcom/reflect/xptinfo/xptinfo.h
+++ b/xpcom/reflect/xptinfo/xptinfo.h
@@ -13,17 +13,16 @@
 #ifndef xptinfo_h
 #define xptinfo_h
 
 #include <stdint.h>
 #include "nsID.h"
 #include "mozilla/Assertions.h"
 #include "js/Value.h"
 #include "nsString.h"
-#include "nsTArray.h"
 
 // Forward Declarations
 namespace mozilla {
 namespace dom {
 struct NativePropertyHooks;
 } // namespace dom
 } // namespace mozilla
 
@@ -148,162 +147,128 @@ static_assert(sizeof(nsXPTInterfaceInfo)
 /*
  * The following enum represents contains the different tag types which
  * can be found in nsXPTTypeInfo::mTag.
  *
  * WARNING: mTag is 5 bits wide, supporting at most 32 tags.
  */
 enum nsXPTTypeTag : uint8_t
 {
-  // Arithmetic (POD) Types
-  //  - Do not require cleanup,
-  //  - All bit patterns are valid,
-  //  - Outparams may be uninitialized by caller,
-  //  - Directly supported in xptcall.
-  //
-  // NOTE: The name 'Arithmetic' comes from Harbison/Steele. Despite being a tad
-  // unclear, it is used frequently in xptcall, so is unlikely to be changed.
   TD_INT8              = 0,
   TD_INT16             = 1,
   TD_INT32             = 2,
   TD_INT64             = 3,
   TD_UINT8             = 4,
   TD_UINT16            = 5,
   TD_UINT32            = 6,
   TD_UINT64            = 7,
   TD_FLOAT             = 8,
   TD_DOUBLE            = 9,
   TD_BOOL              = 10,
   TD_CHAR              = 11,
   TD_WCHAR             = 12,
-  _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_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,
-  TD_PROMISE           = 23,
-  _TD_LAST_POINTER     = TD_PROMISE,
-
-  // Complex Types
-  //  - Require cleanup,
-  //  - Always passed indirectly,
-  //  - Outparams must be initialized by caller,
-  //  - Supported in xptcall due to indirection.
-  TD_DOMSTRING         = 24,
-  TD_UTF8STRING        = 25,
-  TD_CSTRING           = 26,
-  TD_ASTRING           = 27,
-  TD_JSVAL             = 28,
-  TD_ARRAY             = 29,
-  _TD_LAST_COMPLEX     = TD_ARRAY
+  TD_DOMSTRING         = 15,
+  TD_PSTRING           = 16,
+  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_JSVAL             = 26,
+  TD_DOMOBJECT         = 27,
+  TD_PROMISE           = 28
 };
 
-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
  * integers, to keep alignment requirements low.
  *
  * nsXPTType contains 3 extra bits, reserved for use by nsXPTParamInfo.
  */
 struct nsXPTType
 {
-  nsXPTTypeTag Tag() const { return static_cast<nsXPTTypeTag>(mTag); }
+  // NOTE: This is uint8_t instead of nsXPTTypeTag so that it can be compared
+  // with the nsXPTType::* re-exports.
+  uint8_t Tag() const { return mTag; }
 
-  // The index in the function argument list which should be used when
-  // determining the iid_is or size_is properties of this dependent type.
   uint8_t ArgNum() const {
     MOZ_ASSERT(Tag() == TD_INTERFACE_IS_TYPE ||
                Tag() == TD_PSTRING_SIZE_IS ||
                Tag() == TD_PWSTRING_SIZE_IS ||
-               Tag() == TD_LEGACY_ARRAY);
+               Tag() == TD_ARRAY);
     return mData1;
   }
 
+  const nsXPTType& ArrayElementType() const {
+    MOZ_ASSERT(Tag() == TD_ARRAY);
+    return xpt::detail::GetType(mData2);
+  }
+
 private:
-  // Helper for reading 16-bit data values split between mData1 and mData2.
   uint16_t Data16() const { return ((uint16_t)mData1 << 8) | mData2; }
 
 public:
-  // Get the type of the element in the current array or sequence. Arrays only
-  // fit 8 bits of type data, while sequences support up to 16 bits of type data
-  // due to not needing to store an ArgNum.
-  const nsXPTType& ArrayElementType() const {
-    if (Tag() == TD_LEGACY_ARRAY) {
-      return xpt::detail::GetType(mData2);
-    }
-    MOZ_ASSERT(Tag() == TD_ARRAY);
-    return xpt::detail::GetType(Data16());
-  }
-
   // We store the 16-bit iface value as two 8-bit values in order to
   // avoid 16-bit alignment requirements for XPTTypeDescriptor, which
   // reduces its size and also the size of XPTParamDescriptor.
   const nsXPTInterfaceInfo* GetInterface() const {
     MOZ_ASSERT(Tag() == TD_INTERFACE_TYPE);
     return xpt::detail::GetInterface(Data16());
   }
 
   const nsXPTDOMObjectInfo& GetDOMObjectInfo() const {
     MOZ_ASSERT(Tag() == TD_DOMOBJECT);
     return xpt::detail::GetDOMObjectInfo(Data16());
   }
 
-  // See the comments in nsXPTTypeTag for an explanation as to what each of
-  // these categories mean.
-  bool IsArithmetic() const { return Tag() <= _TD_LAST_ARITHMETIC; }
-  bool IsPointer() const { return !IsArithmetic() && Tag() <= _TD_LAST_POINTER; }
-  bool IsComplex() const { return Tag() > _TD_LAST_POINTER; }
+  // 'Arithmetic' here roughly means that the value is self-contained and
+  // doesn't depend on anything else in memory (ie: not a pointer, not an
+  // XPCOM object, not a jsval, etc).
+  //
+  // Supposedly this terminology comes from Harbison/Steele, but it's still
+  // a rather crappy name. We'd change it if it wasn't used all over the
+  // place in xptcall. :-(
+  bool IsArithmetic() const { return Tag() <= TD_WCHAR; }
 
   bool IsInterfacePointer() const {
     return Tag() == TD_INTERFACE_TYPE || Tag() == TD_INTERFACE_IS_TYPE;
   }
 
+  bool IsArray() const { return Tag() == TD_ARRAY; }
+
   bool IsDependent() const {
-    return (Tag() == TD_ARRAY && InnermostType().IsDependent()) ||
-           Tag() == TD_INTERFACE_IS_TYPE || Tag() == TD_LEGACY_ARRAY ||
+    return Tag() == TD_INTERFACE_IS_TYPE || Tag() == TD_ARRAY ||
            Tag() == TD_PSTRING_SIZE_IS || Tag() == TD_PWSTRING_SIZE_IS;
   }
 
   // Unwrap a nested type to its innermost value (e.g. through arrays).
   const nsXPTType& InnermostType() const {
-    if (Tag() == TD_LEGACY_ARRAY || Tag() == TD_ARRAY) {
+    if (Tag() == TD_ARRAY) {
       return ArrayElementType().InnermostType();
     }
     return *this;
   }
 
-  // In-memory size of native type in bytes.
+  // Helper methods for working with the type's native representation.
   inline size_t Stride() const;
+  inline bool HasPointerRepr() const;
 
   // Offset the given base pointer to reference the element at the given index.
   void* ElementPtr(const void* aBase, uint32_t aIndex) const {
     return (char*)aBase + (aIndex * Stride());
   }
 
-  // Zero out a native value of the given type. The type must not be 'complex'.
-  void ZeroValue(void* aValue) const {
-    MOZ_RELEASE_ASSERT(!IsComplex(), "Cannot zero a complex value");
-    memset(aValue, 0, Stride());
-  }
-
   // Indexes into the extra types array of a small set of known types.
   enum class Idx : uint8_t
   {
     INT8 = 0,
     UINT8,
     INT16,
     UINT16,
     INT32,
@@ -319,62 +284,63 @@ public:
     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);
-    return { TD_LEGACY_ARRAY, false, false, false, 0, (uint8_t)aInner };
+    return { TD_ARRAY, false, false, false, 0, (uint8_t)aInner };
   }
   static const nsXPTType& Get(Idx aInner) {
     MOZ_ASSERT(aInner <= Idx::INTERFACE_IS_TYPE);
     return xpt::detail::GetType((uint8_t)aInner);
   }
 
   ///////////////////////////////////////
   // nsXPTType backwards compatibility //
   ///////////////////////////////////////
 
-  nsXPTType& operator=(nsXPTTypeTag aPrefix) { mTag = aPrefix; return *this; }
-  operator nsXPTTypeTag() const { return Tag(); }
+  nsXPTType& operator=(uint8_t aPrefix) { mTag = aPrefix; return *this; }
+  operator uint8_t() const { return TagPart(); };
+  uint8_t TagPart() const { return mTag; };
 
-#define TD_ALIAS_(name_, value_) static constexpr nsXPTTypeTag name_ = value_
-  TD_ALIAS_(T_I8                , TD_INT8             );
-  TD_ALIAS_(T_I16               , TD_INT16            );
-  TD_ALIAS_(T_I32               , TD_INT32            );
-  TD_ALIAS_(T_I64               , TD_INT64            );
-  TD_ALIAS_(T_U8                , TD_UINT8            );
-  TD_ALIAS_(T_U16               , TD_UINT16           );
-  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_DOMSTRING         , TD_DOMSTRING        );
-  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_JSVAL             , TD_JSVAL            );
-  TD_ALIAS_(T_DOMOBJECT         , TD_DOMOBJECT        );
-  TD_ALIAS_(T_PROMISE           , TD_PROMISE          );
-  TD_ALIAS_(T_ARRAY             , TD_ARRAY            );
-#undef TD_ALIAS_
+  enum // Re-export TD_ interfaces from nsXPTType
+  {
+    T_I8                = TD_INT8             ,
+    T_I16               = TD_INT16            ,
+    T_I32               = TD_INT32            ,
+    T_I64               = TD_INT64            ,
+    T_U8                = TD_UINT8            ,
+    T_U16               = TD_UINT16           ,
+    T_U32               = TD_UINT32           ,
+    T_U64               = TD_UINT64           ,
+    T_FLOAT             = TD_FLOAT            ,
+    T_DOUBLE            = TD_DOUBLE           ,
+    T_BOOL              = TD_BOOL             ,
+    T_CHAR              = TD_CHAR             ,
+    T_WCHAR             = TD_WCHAR            ,
+    T_VOID              = TD_VOID             ,
+    T_IID               = TD_PNSIID           ,
+    T_DOMSTRING         = TD_DOMSTRING        ,
+    T_CHAR_STR          = TD_PSTRING          ,
+    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_JSVAL             = TD_JSVAL            ,
+    T_DOMOBJECT         = TD_DOMOBJECT        ,
+    T_PROMISE           = TD_PROMISE
+  };
 
   ////////////////////////////////////////////////////////////////
   // Ensure these fields are in the same order as xptcodegen.py //
   ////////////////////////////////////////////////////////////////
 
   uint8_t mTag : 5;
 
   // Parameter bitflags are packed into the XPTTypeDescriptor to save space.
@@ -405,20 +371,25 @@ struct nsXPTParamInfo
   bool IsOptional() const { return mType.mOptionalParam; }
   bool IsShared() const { return false; } // XXX remove (backcompat)
 
   // Get the type of this parameter.
   const nsXPTType& Type() const { return mType; }
   const nsXPTType& GetType() const { return Type(); } // XXX remove (backcompat)
 
   // Whether this parameter is passed indirectly on the stack. All out/inout
-  // params are passed indirectly, and complex types are always passed
-  // indirectly.
+  // params are passed indirectly, although some types are passed indirectly
+  // unconditionally.
   bool IsIndirect() const {
-    return IsOut() || Type().IsComplex();
+    return IsOut() ||
+      mType.Tag() == TD_JSVAL ||
+      mType.Tag() == TD_ASTRING ||
+      mType.Tag() == TD_DOMSTRING ||
+      mType.Tag() == TD_CSTRING ||
+      mType.Tag() == TD_UTF8STRING;
   }
 
   ////////////////////////////////////////////////////////////////
   // Ensure these fields are in the same order as xptcodegen.py //
   ////////////////////////////////////////////////////////////////
 
   nsXPTType mType;
 };
@@ -526,44 +497,16 @@ struct nsXPTDOMObjectInfo
   bool (*mWrap) (JSContext* aCx, void* aObj, JS::MutableHandleValue aHandle);
   void (*mCleanup) (void* aObj);
 };
 
 
 namespace xpt {
 namespace detail {
 
-// The UntypedTArray type allows low-level access from XPConnect to nsTArray
-// internals without static knowledge of the array element type in question.
-class UntypedTArray
-  : public nsTArray_base<nsTArrayFallibleAllocator, nsTArray_CopyWithMemutils>
-{
-public:
-  void* Elements() const {
-    return static_cast<void*>(Hdr() + 1);
-  }
-
-  // Changes the length and capacity to be at least large enough for aTo elements.
-  bool SetLength(const nsXPTType& aEltTy, uint32_t aTo) {
-    if (!EnsureCapacity<nsTArrayFallibleAllocator>(aTo, aEltTy.Stride())) {
-      return false;
-    }
-    mHdr->mLength = aTo;
-    return true;
-  }
-
-  // Free backing memory for the nsTArray object.
-  void Clear() {
-    if (mHdr != EmptyHdr() && !UsesAutoArrayBuffer()) {
-      nsTArrayFallibleAllocator::Free(mHdr);
-    }
-    mHdr = EmptyHdr();
-  }
-};
-
 /**
  * The compressed representation of constants from XPT. Not part of the public
  * interface, as we also need to support Shim interfaces.
  */
 struct ConstInfo
 {
   ////////////////////////////////////////////////////////////////
   // Ensure these fields are in the same order as xptcodegen.py //
@@ -645,51 +588,76 @@ inline const char*
 GetString(uint32_t aIndex)
 {
   return &sStrings[aIndex];
 }
 
 } // namespace detail
 } // namespace xpt
 
+inline bool
+nsXPTType::HasPointerRepr() const
+{
+  // This method should return `true` if the given type would be represented as
+  // a pointer when not passed indirectly.
+  switch (Tag()) {
+    case TD_VOID:
+    case TD_PNSIID:
+    case TD_PSTRING:
+    case TD_PWSTRING:
+    case TD_INTERFACE_TYPE:
+    case TD_INTERFACE_IS_TYPE:
+    case TD_ARRAY:
+    case TD_PSTRING_SIZE_IS:
+    case TD_PWSTRING_SIZE_IS:
+    case TD_DOMOBJECT:
+    case TD_PROMISE:
+        return true;
+    default:
+        return false;
+  }
+}
+
 inline size_t
 nsXPTType::Stride() const
 {
   // Compute the stride to use when walking an array of the given type.
-  switch (Tag()) {
+  //
+  // NOTE: We cast to nsXPTTypeTag here so we get a warning if a type is missed
+  // in this switch statement. It's important that this method returns a value
+  // for every possible type.
+
+  switch (static_cast<nsXPTTypeTag>(Tag())) {
     case TD_INT8:              return sizeof(int8_t);
     case TD_INT16:             return sizeof(int16_t);
     case TD_INT32:             return sizeof(int32_t);
     case TD_INT64:             return sizeof(int64_t);
     case TD_UINT8:             return sizeof(uint8_t);
     case TD_UINT16:            return sizeof(uint16_t);
     case TD_UINT32:            return sizeof(uint32_t);
     case TD_UINT64:            return sizeof(uint64_t);
     case TD_FLOAT:             return sizeof(float);
     case TD_DOUBLE:            return sizeof(double);
     case TD_BOOL:              return sizeof(bool);
     case TD_CHAR:              return sizeof(char);
     case TD_WCHAR:             return sizeof(char16_t);
-
     case TD_VOID:              return sizeof(void*);
     case TD_PNSIID:            return sizeof(nsIID*);
     case TD_DOMSTRING:         return sizeof(nsString);
     case TD_PSTRING:           return sizeof(char*);
     case TD_PWSTRING:          return sizeof(char16_t*);
     case TD_INTERFACE_TYPE:    return sizeof(nsISupports*);
     case TD_INTERFACE_IS_TYPE: return sizeof(nsISupports*);
-    case TD_LEGACY_ARRAY:      return sizeof(void*);
+    case TD_ARRAY:             return sizeof(void*);
     case TD_PSTRING_SIZE_IS:   return sizeof(char*);
     case TD_PWSTRING_SIZE_IS:  return sizeof(char16_t*);
-    case TD_DOMOBJECT:         return sizeof(void*);
-    case TD_PROMISE:           return sizeof(void*);
-
     case TD_UTF8STRING:        return sizeof(nsCString);
     case TD_CSTRING:           return sizeof(nsCString);
     case TD_ASTRING:           return sizeof(nsString);
     case TD_JSVAL:             return sizeof(JS::Value);
-    case TD_ARRAY:             return sizeof(xpt::detail::UntypedTArray);
+    case TD_DOMOBJECT:         return sizeof(void*);
+    case TD_PROMISE:           return sizeof(void*);
   }
 
   MOZ_CRASH("Unknown type");
 }
 
 #endif /* xptinfo_h */
--- a/xpcom/rust/xpcom/src/reexports.rs
+++ b/xpcom/rust/xpcom/src/reexports.rs
@@ -6,13 +6,13 @@
 /// which are defined in other libraries which `xpcom` depends on, but which may
 /// not be `extern crate`-ed into the crate the macros are expanded into. This
 /// module re-exports those types from `xpcom` so that they can be used from the
 /// macro.
 
 // re-export libc so it can be used by the procedural macro.
 pub extern crate libc;
 
-pub use nsstring::{nsACString, nsAString, nsCString, nsString};
+pub use nsstring::{nsACString, nsAString};
 
 pub use nserror::{nsresult, NsresultExt, NS_ERROR_NO_INTERFACE, NS_OK};
 
 pub use std::ops::Deref;
--- a/xpcom/rust/xpcom/xpcom_macros/src/lib.rs
+++ b/xpcom/rust/xpcom/xpcom_macros/src/lib.rs
@@ -558,19 +558,17 @@ fn xpcom(init: DeriveInput) -> Result<To
         impl #name {
             /// This method is used for
             fn allocate(__init: #name_init) -> ::xpcom::RefPtr<Self> {
                 #[allow(unused_imports)]
                 use ::xpcom::*;
                 #[allow(unused_imports)]
                 use ::xpcom::interfaces::*;
                 #[allow(unused_imports)]
-                use ::xpcom::reexports::{
-                    libc, nsACString, nsAString, nsCString, nsString, nsresult
-                };
+                use ::xpcom::reexports::{libc, nsACString, nsAString, nsresult};
 
                 unsafe {
                     // NOTE: This is split into multiple lines to make the
                     // output more readable.
                     let value = #name {
                         #(#vtables)*
                         __refcnt: #refcnt_ty::new(),
                         #(#inits)*
--- a/xpcom/tests/gtest/TestTArray2.cpp
+++ b/xpcom/tests/gtest/TestTArray2.cpp
@@ -377,35 +377,16 @@ TEST(TArray, test_move_array) {
   // operator=
   copyMoveableArray2 = std::move(autoMoveableArray);
   // Mix with FallibleTArray
   FallibleTArray<Moveable> differentAllocatorMoveableArray2(std::move(copyMoveableArray2));
   AutoTArray<Moveable, 4> autoMoveableArray2(std::move(differentAllocatorMoveableArray2));
   differentAllocatorMoveableArray2 = std::move(autoMoveableArray2);
 
   ASSERT_EQ(Moveable::Count(), 8);
-
-  AutoTArray<Moveable, 8> moveableAutoArray;
-  for (uint32_t i = 0; i < 4; ++i) {
-    ASSERT_TRUE(moveableAutoArray.AppendElement(Moveable()));
-  }
-
-  ASSERT_EQ(Moveable::Count(), 12);
-
-  const AutoTArray<Moveable, 8>& constRefMoveableAutoArray = moveableAutoArray;
-
-  ASSERT_EQ(Moveable::Count(), 12);
-
-  AutoTArray<Moveable, 8> copyMoveableAutoArray(constRefMoveableAutoArray);
-
-  ASSERT_EQ(Moveable::Count(), 16);
-
-  AutoTArray<Moveable, 8> movedMoveableAutoArray(std::move(moveableAutoArray));
-
-  ASSERT_EQ(Moveable::Count(), 16);
 }
 
 //----
 
 TEST(TArray, test_string_array) {
   nsTArray<nsCString> strArray;
   const char kdata[] = "hello world";
   size_t i;