Bug 1411415 - r=bz r=fitzgen
authorKannan Vijayan <kvijayan@mozilla.com>
Mon, 05 Mar 2018 19:27:02 -0500
changeset 461707 61ca8af8e31332158c4307c8277282d27012d46e
parent 461706 f72fd25e822fc7c8f625a0b6f659a7aaee4d4a41
child 461708 7c01c3875cae3d9b8a3fab22c4b07efe20f6d48f
child 461712 5934e66f2c778eace5a8cd80ed734c3596119af4
push id1683
push usersfraser@mozilla.com
push dateThu, 26 Apr 2018 16:43:40 +0000
treeherdermozilla-release@5af6cb21869d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz, fitzgen
bugs1411415
milestone60.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1411415 - r=bz r=fitzgen
dom/bindings/BindingUtils.cpp
dom/bindings/ErrorResult.h
dom/xslt/xpath/txXPCOMExtensionFunction.cpp
js/public/Value.h
js/rust/build.rs
js/src/jit/BaselineFrameInfo.h
js/src/jit/CacheIRCompiler.cpp
js/src/jit/RegisterSets.h
js/src/jit/RematerializedFrame.cpp
js/src/wasm/AsmJS.cpp
js/xpconnect/src/XPCWrappedNative.cpp
layout/style/ServoBindings.toml
xpcom/reflect/xptcall/xptcall.h
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -280,18 +280,18 @@ TErrorResult<CleanupPolicy>::ThrowJSExce
   MOZ_ASSERT(mMightHaveUnreportedJSException,
              "Why didn't you tell us you planned to throw a JS exception?");
 
   ClearUnionData();
 
   // Make sure mJSException is initialized _before_ we try to root it.  But
   // don't set it to exn yet, because we don't want to do that until after we
   // root.
-  mJSException.setUndefined();
-  if (!js::AddRawValueRoot(cx, &mJSException, "TErrorResult::mJSException")) {
+  mJSException.asValueRef().setUndefined();
+  if (!js::AddRawValueRoot(cx, &mJSException.asValueRef(), "TErrorResult::mJSException")) {
     // Don't use NS_ERROR_INTERNAL_ERRORRESULT_JS_EXCEPTION, because that
     // indicates we have in fact rooted mJSException.
     mResult = NS_ERROR_OUT_OF_MEMORY;
   } else {
     mJSException = exn;
     mResult = NS_ERROR_INTERNAL_ERRORRESULT_JS_EXCEPTION;
 #ifdef DEBUG
     mUnionState = HasJSException;
@@ -310,17 +310,17 @@ TErrorResult<CleanupPolicy>::SetPendingJ
 
   JS::Rooted<JS::Value> exception(cx, mJSException);
   if (JS_WrapValue(cx, &exception)) {
     JS_SetPendingException(cx, exception);
   }
   mJSException = exception;
   // If JS_WrapValue failed, not much we can do about it...  No matter
   // what, go ahead and unroot mJSException.
-  js::RemoveRawValueRoot(cx, &mJSException);
+  js::RemoveRawValueRoot(cx, &mJSException.asValueRef());
 
   mResult = NS_OK;
 #ifdef DEBUG
   mUnionState = HasNothing;
 #endif // DEBUG
 }
 
 template<typename CleanupPolicy>
@@ -416,18 +416,18 @@ TErrorResult<CleanupPolicy>::ClearDOMExc
 template<typename CleanupPolicy>
 void
 TErrorResult<CleanupPolicy>::ClearUnionData()
 {
   AssertInOwningThread();
   if (IsJSException()) {
     JSContext* cx = dom::danger::GetJSContext();
     MOZ_ASSERT(cx);
-    mJSException.setUndefined();
-    js::RemoveRawValueRoot(cx, &mJSException);
+    mJSException.asValueRef().setUndefined();
+    js::RemoveRawValueRoot(cx, &mJSException.asValueRef());
 #ifdef DEBUG
     mUnionState = HasNothing;
 #endif // DEBUG
   } else if (IsErrorWithMessage()) {
     ClearMessage();
   } else if (IsDOMException()) {
     ClearDOMExceptionInfo();
   }
@@ -460,23 +460,23 @@ TErrorResult<CleanupPolicy>::operator=(T
   aRHS.mMightHaveUnreportedJSException = false;
 #endif
   if (aRHS.IsErrorWithMessage()) {
     mMessage = aRHS.mMessage;
     aRHS.mMessage = nullptr;
   } else if (aRHS.IsJSException()) {
     JSContext* cx = dom::danger::GetJSContext();
     MOZ_ASSERT(cx);
-    mJSException.setUndefined();
-    if (!js::AddRawValueRoot(cx, &mJSException, "TErrorResult::mJSException")) {
+    mJSException.asValueRef().setUndefined();
+    if (!js::AddRawValueRoot(cx, &mJSException.asValueRef(), "TErrorResult::mJSException")) {
       MOZ_CRASH("Could not root mJSException, we're about to OOM");
     }
     mJSException = aRHS.mJSException;
-    aRHS.mJSException.setUndefined();
-    js::RemoveRawValueRoot(cx, &aRHS.mJSException);
+    aRHS.mJSException.asValueRef().setUndefined();
+    js::RemoveRawValueRoot(cx, &aRHS.mJSException.asValueRef());
   } else if (aRHS.IsDOMException()) {
     mDOMExceptionInfo = aRHS.mDOMExceptionInfo;
     aRHS.mDOMExceptionInfo = nullptr;
   } else {
     // Null out the union on both sides for hygiene purposes.
     mMessage = aRHS.mMessage = nullptr;
   }
 
@@ -518,17 +518,17 @@ TErrorResult<CleanupPolicy>::CloneTo(TEr
 #endif
     aRv.mDOMExceptionInfo = new DOMExceptionInfo(mDOMExceptionInfo->mRv,
                                                  mDOMExceptionInfo->mMessage);
   } else if (IsJSException()) {
 #ifdef DEBUG
     aRv.mUnionState = HasJSException;
 #endif
     JSContext* cx = dom::danger::GetJSContext();
-    JS::Rooted<JS::Value> exception(cx, mJSException);
+    JS::Rooted<JS::Value> exception(cx, mJSException.asValueRef());
     aRv.ThrowJSException(cx, exception);
   }
 }
 
 template<typename CleanupPolicy>
 void
 TErrorResult<CleanupPolicy>::SuppressException()
 {
--- a/dom/bindings/ErrorResult.h
+++ b/dom/bindings/ErrorResult.h
@@ -503,17 +503,17 @@ private:
   // mMessage is set by ThrowErrorWithMessage and reported (and deallocated) by
   // SetPendingExceptionWithMessage.
   // mJSException is set (and rooted) by ThrowJSException and reported
   // (and unrooted) by SetPendingJSException.
   // mDOMExceptionInfo is set by ThrowDOMException and reported
   // (and deallocated) by SetPendingDOMException.
   union {
     Message* mMessage; // valid when IsErrorWithMessage()
-    JS::Value mJSException; // valid when IsJSException()
+    JS::UninitializedValue mJSException; // valid when IsJSException()
     DOMExceptionInfo* mDOMExceptionInfo; // valid when IsDOMException()
   };
 
 #ifdef DEBUG
   // Used to keep track of codepaths that might throw JS exceptions,
   // for assertion purposes.
   bool mMightHaveUnreportedJSException;
 
--- a/dom/xslt/xpath/txXPCOMExtensionFunction.cpp
+++ b/dom/xslt/xpath/txXPCOMExtensionFunction.cpp
@@ -318,17 +318,17 @@ public:
     operator nsXPTCVariant*() const
     {
       return mArray.get();
     }
 
     void trace(JSTracer* trc) {
         for (uint8_t i = 0; i < mCount; ++i) {
             if (mArray[i].type == nsXPTType::T_JSVAL) {
-                JS::UnsafeTraceRoot(trc, &mArray[i].val.j, "txParam value");
+                JS::UnsafeTraceRoot(trc, &mArray[i].val.j.asValueRef(), "txParam value");
             }
         }
     }
 
 private:
     mozilla::UniquePtr<nsXPTCVariant[]> mArray;
     uint8_t mCount;
 };
--- a/js/public/Value.h
+++ b/js/public/Value.h
@@ -133,22 +133,26 @@ static_assert(sizeof(JSValueShiftedTag) 
  */
 #undef JS_ENUM_HEADER
 #undef JS_ENUM_FOOTER
 
 #if defined(JS_NUNBOX32)
 
 #define JSVAL_TYPE_TO_TAG(type)      ((JSValueTag)(JSVAL_TAG_CLEAR | (type)))
 
+#define JSVAL_RAW64_UNDEFINED        (uint64_t(JSVAL_TAG_UNDEFINED) << 32)
+
 #define JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET           JSVAL_TAG_OBJECT
 #define JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET              JSVAL_TAG_INT32
 #define JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET             JSVAL_TAG_STRING
 
 #elif defined(JS_PUNBOX64)
 
+#define JSVAL_RAW64_UNDEFINED        (uint64_t(JSVAL_TAG_UNDEFINED) << JSVAL_TAG_SHIFT)
+
 // This should only be used in toGCThing, see the 'Spectre mitigations' comment.
 #define JSVAL_PAYLOAD_MASK_GCTHING   0x00007FFFFFFFFFFFLL
 
 #define JSVAL_TAG_MASK               0xFFFF800000000000LL
 #define JSVAL_TYPE_TO_TAG(type)      ((JSValueTag)(JSVAL_TAG_MAX_DOUBLE | (type)))
 #define JSVAL_TYPE_TO_SHIFTED_TAG(type) (((uint64_t)JSVAL_TYPE_TO_TAG(type)) << JSVAL_TAG_SHIFT)
 
 #define JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET           JSVAL_TAG_OBJECT
@@ -854,17 +858,17 @@ class MOZ_NON_PARAM alignas(8) Value
                 size_t         word;
                 uintptr_t      uintptr;
             } payload;
             JSValueTag tag;
         } s;
         double asDouble;
         void* asPtr;
 
-        layout() = default;
+        layout() : asBits(JSVAL_RAW64_UNDEFINED) {}
         explicit constexpr layout(uint64_t bits) : asBits(bits) {}
         explicit constexpr layout(double d) : asDouble(d) {}
     } data;
 # elif defined(JS_PUNBOX64)
     union layout {
         uint64_t asBits;
 #if !defined(_WIN64)
         /* MSVC does not pack these correctly :-( */
@@ -880,17 +884,17 @@ class MOZ_NON_PARAM alignas(8) Value
                 JSWhyMagic     why;
             } payload;
         } s;
         double asDouble;
         void* asPtr;
         size_t asWord;
         uintptr_t asUIntPtr;
 
-        layout() = default;
+        layout() : asBits(JSVAL_RAW64_UNDEFINED) {}
         explicit constexpr layout(uint64_t bits) : asBits(bits) {}
         explicit constexpr layout(double d) : asDouble(d) {}
     } data;
 # endif  /* JS_PUNBOX64 */
 #else   /* MOZ_LITTLE_ENDIAN */
 # if defined(JS_NUNBOX32)
     union layout {
         uint64_t asBits;
@@ -908,17 +912,17 @@ class MOZ_NON_PARAM alignas(8) Value
                 JSWhyMagic     why;
                 size_t         word;
                 uintptr_t      uintptr;
             } payload;
         } s;
         double asDouble;
         void* asPtr;
 
-        layout() = default;
+        layout() : asBits(JSVAL_RAW64_UNDEFINED) {}
         explicit constexpr layout(uint64_t bits) : asBits(bits) {}
         explicit constexpr layout(double d) : asDouble(d) {}
     } data;
 # elif defined(JS_PUNBOX64)
     union layout {
         uint64_t asBits;
         struct {
             JSValueTag         tag : 17;
@@ -932,17 +936,17 @@ class MOZ_NON_PARAM alignas(8) Value
                 JSWhyMagic     why;
             } payload;
         } s;
         double asDouble;
         void* asPtr;
         size_t asWord;
         uintptr_t asUIntPtr;
 
-        layout() = default;
+        layout() : asBits(JSVAL_RAW64_UNDEFINED) {}
         explicit constexpr layout(uint64_t bits) : asBits(bits) {}
         explicit constexpr layout(double d) : asDouble(d) {}
     } data;
 # endif /* JS_PUNBOX64 */
 #endif  /* MOZ_LITTLE_ENDIAN */
 
   private:
     explicit constexpr Value(uint64_t asBits) : data(asBits) {}
@@ -985,18 +989,61 @@ class MOZ_NON_PARAM alignas(8) Value
     }
 
     static constexpr Value
     fromDouble(double d) {
         return Value(d);
     }
 } JS_HAZ_GC_POINTER;
 
+/**
+ * This is a null-constructible structure that can convert to and from
+ * a Value, allowing UninitializedValue to be stored in unions.
+ */
+struct MOZ_NON_PARAM alignas(8) UninitializedValue
+{
+  private:
+    uint64_t bits;
+
+  public:
+    UninitializedValue() = default;
+    UninitializedValue(const UninitializedValue&) = default;
+    MOZ_IMPLICIT UninitializedValue(const Value& val) : bits(val.asRawBits()) {}
+
+    inline uint64_t asRawBits() const {
+        return bits;
+    }
+
+    inline Value& asValueRef() {
+        return *reinterpret_cast<Value*>(this);
+    }
+    inline const Value& asValueRef() const {
+        return *reinterpret_cast<const Value*>(this);
+    }
+
+    inline operator Value&() {
+        return asValueRef();
+    }
+    inline operator Value const&() const {
+        return asValueRef();
+    }
+    inline operator Value() const {
+        return asValueRef();
+    }
+
+    inline void operator=(Value const& other) {
+        asValueRef() = other;
+    }
+};
+
 static_assert(sizeof(Value) == 8, "Value size must leave three tag bits, be a binary power, and is ubiquitously depended upon everywhere");
 
+static_assert(sizeof(UninitializedValue) == sizeof(Value), "Value and UninitializedValue must be the same size");
+static_assert(alignof(UninitializedValue) == alignof(Value), "Value and UninitializedValue must have same alignment");
+
 inline bool
 IsOptimizedPlaceholderMagicValue(const Value& v)
 {
     if (v.isMagic()) {
         MOZ_ASSERT(v.whyMagic() == JS_OPTIMIZED_ARGUMENTS || v.whyMagic() == JS_OPTIMIZED_OUT);
         return true;
     }
     return false;
--- a/js/rust/build.rs
+++ b/js/rust/build.rs
@@ -229,16 +229,17 @@ const WHITELIST_TYPES: &'static [&'stati
     "JS::SourceBufferHolder",
     "js::StackFormat",
     "JSStructuredCloneCallbacks",
     "JS::Symbol",
     "JS::SymbolCode",
     "JS::TraceKind",
     "JS::TransferableOwnership",
     "JS::Value",
+    "JS::UninitializedValue",
     "JS::WarningReporter",
     "JS::shadow::Zone",
     "JS::Zone",
 ];
 
 /// Global variables we want to generate bindings to.
 const WHITELIST_VARS: &'static [&'static str] = &[
     "JS_STRUCTURED_CLONE_VERSION",
--- a/js/src/jit/BaselineFrameInfo.h
+++ b/js/src/jit/BaselineFrameInfo.h
@@ -62,17 +62,17 @@ class StackValue
 #endif
     };
 
   private:
     Kind kind_;
 
     union {
         struct {
-            Value v;
+            JS::UninitializedValue v;
         } constant;
         struct {
             mozilla::AlignedStorage2<ValueOperand> reg;
         } reg;
         struct {
             uint32_t slot;
         } local;
         struct {
@@ -107,17 +107,17 @@ class StackValue
     void reset() {
 #ifdef DEBUG
         kind_ = Uninitialized;
         knownType_ = JSVAL_TYPE_UNKNOWN;
 #endif
     }
     Value constant() const {
         MOZ_ASSERT(kind_ == Constant);
-        return data.constant.v;
+        return data.constant.v.asValueRef();
     }
     ValueOperand reg() const {
         MOZ_ASSERT(kind_ == Register);
         return *data.reg.reg.addr();
     }
     uint32_t localSlot() const {
         MOZ_ASSERT(kind_ == LocalSlot);
         return data.local.slot;
--- a/js/src/jit/CacheIRCompiler.cpp
+++ b/js/src/jit/CacheIRCompiler.cpp
@@ -924,17 +924,17 @@ CacheIRWriter::copyStubData(uint8_t* des
           case StubField::Type::Id:
             InitGCPtr<jsid>(destWords, field.asWord());
             break;
           case StubField::Type::RawInt64:
           case StubField::Type::DOMExpandoGeneration:
             *reinterpret_cast<uint64_t*>(destWords) = field.asInt64();
             break;
           case StubField::Type::Value:
-            InitGCPtr<JS::Value>(destWords, field.asInt64());
+            AsGCPtr<Value>(destWords)->init(Value::fromRawBits(uint64_t(field.asInt64())));
             break;
           case StubField::Type::Limit:
             MOZ_CRASH("Invalid type");
         }
         destWords += StubField::sizeInBytes(field.type()) / sizeof(uintptr_t);
     }
 }
 
--- a/js/src/jit/RegisterSets.h
+++ b/js/src/jit/RegisterSets.h
@@ -231,23 +231,23 @@ class TypedOrValueRegister
 // A constant value, or registers to hold a typed/untyped value.
 class ConstantOrRegister
 {
     // Whether a constant value is being stored.
     bool constant_;
 
     // Space to hold either a Value or a TypedOrValueRegister.
     union U {
-        Value constant;
+        JS::UninitializedValue constant;
         TypedOrValueRegister reg;
     } data;
 
-    const Value& dataValue() const {
+    Value dataValue() const {
         MOZ_ASSERT(constant());
-        return data.constant;
+        return data.constant.asValueRef();
     }
     void setDataValue(const Value& value) {
         MOZ_ASSERT(constant());
         data.constant = value;
     }
     const TypedOrValueRegister& dataReg() const {
         MOZ_ASSERT(!constant());
         return data.reg;
@@ -273,17 +273,17 @@ class ConstantOrRegister
     {
         setDataReg(reg);
     }
 
     bool constant() const {
         return constant_;
     }
 
-    const Value& value() const {
+    Value value() const {
         return dataValue();
     }
 
     const TypedOrValueRegister& reg() const {
         return dataReg();
     }
 };
 
--- a/js/src/jit/RematerializedFrame.cpp
+++ b/js/src/jit/RematerializedFrame.cpp
@@ -54,19 +54,27 @@ RematerializedFrame::RematerializedFrame
 }
 
 /* static */ RematerializedFrame*
 RematerializedFrame::New(JSContext* cx, uint8_t* top, InlineFrameIterator& iter,
                          MaybeReadFallback& fallback)
 {
     unsigned numFormals = iter.isFunctionFrame() ? iter.calleeTemplate()->nargs() : 0;
     unsigned argSlots = Max(numFormals, iter.numActualArgs());
-    size_t numBytes = sizeof(RematerializedFrame) +
-        (argSlots + iter.script()->nfixed()) * sizeof(Value) -
-        sizeof(Value); // 1 Value included in sizeof(RematerializedFrame)
+    unsigned extraSlots = argSlots + iter.script()->nfixed();
+
+    // One Value slot is included in sizeof(RematerializedFrame), so we can
+    // reduce the extra slot count by one.  However, if there are zero slot
+    // allocations total, then reducing the slots by one will lead to
+    // the memory allocation being smaller  than sizeof(RematerializedFrame).
+    if (extraSlots > 0)
+        extraSlots -= 1;
+
+    size_t numBytes = sizeof(RematerializedFrame) + (extraSlots * sizeof(Value));
+    MOZ_ASSERT(numBytes >= sizeof(RematerializedFrame));
 
     void* buf = cx->pod_calloc<uint8_t>(numBytes);
     if (!buf)
         return nullptr;
 
     return new (buf) RematerializedFrame(cx, top, iter.numActualArgs(), iter, fallback);
 }
 
--- a/js/src/wasm/AsmJS.cpp
+++ b/js/src/wasm/AsmJS.cpp
@@ -839,17 +839,17 @@ class NumLit
         Bool16x8,
         Bool32x4,
         OutOfRangeInt = -1
     };
 
   private:
     Which which_;
     union {
-        Value scalar_;
+        JS::UninitializedValue scalar_;
         SimdConstant simd_;
     } u;
 
   public:
     NumLit() = default;
 
     NumLit(Which w, const Value& v) : which_(w) {
         u.scalar_ = v;
@@ -862,36 +862,36 @@ class NumLit
     }
 
     Which which() const {
         return which_;
     }
 
     int32_t toInt32() const {
         MOZ_ASSERT(which_ == Fixnum || which_ == NegativeInt || which_ == BigUnsigned);
-        return u.scalar_.toInt32();
+        return u.scalar_.asValueRef().toInt32();
     }
 
     uint32_t toUint32() const {
         return (uint32_t)toInt32();
     }
 
     double toDouble() const {
         MOZ_ASSERT(which_ == Double);
-        return u.scalar_.toDouble();
+        return u.scalar_.asValueRef().toDouble();
     }
 
     float toFloat() const {
         MOZ_ASSERT(which_ == Float);
-        return float(u.scalar_.toDouble());
+        return float(u.scalar_.asValueRef().toDouble());
     }
 
     Value scalarValue() const {
         MOZ_ASSERT(which_ != OutOfRangeInt);
-        return u.scalar_;
+        return u.scalar_.asValueRef();
     }
 
     bool isSimd() const
     {
         return which_ == Int8x16 || which_ == Uint8x16 || which_ == Int16x8 ||
                which_ == Uint16x8 || which_ == Int32x4 || which_ == Uint32x4 ||
                which_ == Float32x4 || which_ == Bool8x16 || which_ == Bool16x8 ||
                which_ == Bool32x4;
--- a/js/xpconnect/src/XPCWrappedNative.cpp
+++ b/js/xpconnect/src/XPCWrappedNative.cpp
@@ -1670,19 +1670,22 @@ CallMethodHelper::ConvertIndependentPara
     // Specify the correct storage/calling semantics.
     if (paramInfo.IsIndirect())
         dp->SetIndirect();
 
     // The JSVal proper is always stored within the 'val' union and passed
     // indirectly, regardless of in/out-ness.
     if (type_tag == nsXPTType::T_JSVAL) {
         // Root the value.
-        dp->val.j.setUndefined();
-        if (!js::AddRawValueRoot(mCallContext, &dp->val.j, "XPCWrappedNative::CallMethod param"))
+        dp->val.j.asValueRef().setUndefined();
+        if (!js::AddRawValueRoot(mCallContext, &dp->val.j.asValueRef(),
+                                 "XPCWrappedNative::CallMethod param"))
+        {
             return false;
+        }
     }
 
     // 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,
--- a/layout/style/ServoBindings.toml
+++ b/layout/style/ServoBindings.toml
@@ -93,21 +93,23 @@ raw-lines = [
     "pub use self::root::mozilla::dom::*;",
     "use atomic_refcell::AtomicRefCell;",
     "use data::ElementData;",
 ]
 hide-types = [
     "nsString",
     ".*char_traits",
     ".*incompatible_char_type",
-    # JS::Value uses alignas(8) which bindgen can't represent correctly on Linux
-    # 32-bit.  See https://github.com/rust-lang-nursery/rust-bindgen/issues/917.
+    # JS::Value and JS::UninitializedValue use alignas(8) which bindgen
+    # can't represent correctly on Linux 32-bit.  See
+    # https://github.com/rust-lang-nursery/rust-bindgen/issues/917.
     # It's also not used by Stylo.  The following types are also hidden for
     # making use of it and being similarly unused by Stylo.
     "JS::Value",
+    "JS::UninitializedValue",
     "mozilla::binding_danger::TErrorResult.*",
     "mozilla::ErrorResult.*", # Causes JSWhyMagic to be included & handled incorrectly.
     "mozilla::dom::CallbackFunction",
     "mozilla::dom::CallbackObject.*",
     "nsINode_ErrorResult",
     "nsDOMAttributeMap_ErrorResult",
     # End of JS::Value related types
 ]
--- a/xpcom/reflect/xptcall/xptcall.h
+++ b/xpcom/reflect/xptcall/xptcall.h
@@ -34,17 +34,17 @@ struct nsXPTCMiniVariant
         bool      b;
         char      c;
         char16_t wc;
         void*     p;
 
         // Types below here are unknown to the assembly implementations, and
         // therefore _must_ be passed with indirect semantics. We put them in
         // the union here for type safety, so that we can avoid void* tricks.
-        JS::Value j;
+        JS::UninitializedValue j;
     } val;
 };
 
 struct nsXPTCVariant : public nsXPTCMiniVariant
 {
 // No ctors or dtors so that we can use arrays of these on the stack
 // with no penalty.