mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-27 23:02:20 +00:00
Bug 1451248. r=jorendorff, r=bz
--HG-- extra : rebase_source : e26439a5954162bdaf332fbd63d623a3810e19e0
This commit is contained in:
parent
e2c8f8433f
commit
04d21ccac0
@ -192,9 +192,9 @@ TErrorResult<CleanupPolicy>::CreateErrorMessageHelper(const dom::ErrNum errorNum
|
||||
AssertInOwningThread();
|
||||
mResult = errorType;
|
||||
|
||||
mMessage = new Message();
|
||||
mMessage->mErrorNumber = errorNumber;
|
||||
return mMessage->mArgs;
|
||||
Message* message = InitMessage(new Message());
|
||||
message->mErrorNumber = errorNumber;
|
||||
return message->mArgs;
|
||||
}
|
||||
|
||||
template<typename CleanupPolicy>
|
||||
@ -204,9 +204,9 @@ TErrorResult<CleanupPolicy>::SerializeMessage(IPC::Message* aMsg) const
|
||||
using namespace IPC;
|
||||
AssertInOwningThread();
|
||||
MOZ_ASSERT(mUnionState == HasMessage);
|
||||
MOZ_ASSERT(mMessage);
|
||||
WriteParam(aMsg, mMessage->mArgs);
|
||||
WriteParam(aMsg, mMessage->mErrorNumber);
|
||||
MOZ_ASSERT(mExtra.mMessage);
|
||||
WriteParam(aMsg, mExtra.mMessage->mArgs);
|
||||
WriteParam(aMsg, mExtra.mMessage->mErrorNumber);
|
||||
}
|
||||
|
||||
template<typename CleanupPolicy>
|
||||
@ -226,7 +226,7 @@ TErrorResult<CleanupPolicy>::DeserializeMessage(const IPC::Message* aMsg,
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mUnionState == HasNothing);
|
||||
mMessage = readMessage.forget();
|
||||
InitMessage(readMessage.forget());
|
||||
#ifdef DEBUG
|
||||
mUnionState = HasMessage;
|
||||
#endif // DEBUG
|
||||
@ -238,10 +238,11 @@ void
|
||||
TErrorResult<CleanupPolicy>::SetPendingExceptionWithMessage(JSContext* aCx)
|
||||
{
|
||||
AssertInOwningThread();
|
||||
MOZ_ASSERT(mMessage, "SetPendingExceptionWithMessage() can be called only once");
|
||||
MOZ_ASSERT(mUnionState == HasMessage);
|
||||
MOZ_ASSERT(mExtra.mMessage,
|
||||
"SetPendingExceptionWithMessage() can be called only once");
|
||||
|
||||
Message* message = mMessage;
|
||||
Message* message = mExtra.mMessage;
|
||||
MOZ_RELEASE_ASSERT(message->HasCorrectNumberOfArguments());
|
||||
const uint32_t argCount = message->mArgs.Length();
|
||||
const char16_t* args[JS::MaxNumErrorArguments + 1];
|
||||
@ -264,8 +265,9 @@ TErrorResult<CleanupPolicy>::ClearMessage()
|
||||
{
|
||||
AssertInOwningThread();
|
||||
MOZ_ASSERT(IsErrorWithMessage());
|
||||
delete mMessage;
|
||||
mMessage = nullptr;
|
||||
MOZ_ASSERT(mUnionState == HasMessage);
|
||||
delete mExtra.mMessage;
|
||||
mExtra.mMessage = nullptr;
|
||||
#ifdef DEBUG
|
||||
mUnionState = HasNothing;
|
||||
#endif // DEBUG
|
||||
@ -281,16 +283,16 @@ TErrorResult<CleanupPolicy>::ThrowJSException(JSContext* cx, JS::Handle<JS::Valu
|
||||
|
||||
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.asValueRef().setUndefined();
|
||||
if (!js::AddRawValueRoot(cx, &mJSException.asValueRef(), "TErrorResult::mJSException")) {
|
||||
// Make sure mExtra.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.
|
||||
JS::Value& exc = InitJSException();
|
||||
if (!js::AddRawValueRoot(cx, &exc, "TErrorResult::mExtra::mJSException")) {
|
||||
// Don't use NS_ERROR_INTERNAL_ERRORRESULT_JS_EXCEPTION, because that
|
||||
// indicates we have in fact rooted mJSException.
|
||||
// indicates we have in fact rooted mExtra.mJSException.
|
||||
mResult = NS_ERROR_OUT_OF_MEMORY;
|
||||
} else {
|
||||
mJSException = exn;
|
||||
exc = exn;
|
||||
mResult = NS_ERROR_INTERNAL_ERRORRESULT_JS_EXCEPTION;
|
||||
#ifdef DEBUG
|
||||
mUnionState = HasJSException;
|
||||
@ -307,14 +309,14 @@ TErrorResult<CleanupPolicy>::SetPendingJSException(JSContext* cx)
|
||||
"Why didn't you tell us you planned to handle JS exceptions?");
|
||||
MOZ_ASSERT(mUnionState == HasJSException);
|
||||
|
||||
JS::Rooted<JS::Value> exception(cx, mJSException);
|
||||
JS::Rooted<JS::Value> exception(cx, mExtra.mJSException);
|
||||
if (JS_WrapValue(cx, &exception)) {
|
||||
JS_SetPendingException(cx, exception);
|
||||
}
|
||||
mJSException = exception;
|
||||
mExtra.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.asValueRef());
|
||||
// what, go ahead and unroot mExtra.mJSException.
|
||||
js::RemoveRawValueRoot(cx, &mExtra.mJSException);
|
||||
|
||||
mResult = NS_OK;
|
||||
#ifdef DEBUG
|
||||
@ -339,10 +341,10 @@ TErrorResult<CleanupPolicy>::SerializeDOMExceptionInfo(IPC::Message* aMsg) const
|
||||
{
|
||||
using namespace IPC;
|
||||
AssertInOwningThread();
|
||||
MOZ_ASSERT(mDOMExceptionInfo);
|
||||
MOZ_ASSERT(mUnionState == HasDOMExceptionInfo);
|
||||
WriteParam(aMsg, mDOMExceptionInfo->mMessage);
|
||||
WriteParam(aMsg, mDOMExceptionInfo->mRv);
|
||||
MOZ_ASSERT(mExtra.mDOMExceptionInfo);
|
||||
WriteParam(aMsg, mExtra.mDOMExceptionInfo->mMessage);
|
||||
WriteParam(aMsg, mExtra.mDOMExceptionInfo->mRv);
|
||||
}
|
||||
|
||||
template<typename CleanupPolicy>
|
||||
@ -361,7 +363,7 @@ TErrorResult<CleanupPolicy>::DeserializeDOMExceptionInfo(const IPC::Message* aMs
|
||||
|
||||
MOZ_ASSERT(mUnionState == HasNothing);
|
||||
MOZ_ASSERT(IsDOMException());
|
||||
mDOMExceptionInfo = new DOMExceptionInfo(rv, message);
|
||||
InitDOMExceptionInfo(new DOMExceptionInfo(rv, message));
|
||||
#ifdef DEBUG
|
||||
mUnionState = HasDOMExceptionInfo;
|
||||
#endif // DEBUG
|
||||
@ -377,7 +379,7 @@ TErrorResult<CleanupPolicy>::ThrowDOMException(nsresult rv,
|
||||
ClearUnionData();
|
||||
|
||||
mResult = NS_ERROR_INTERNAL_ERRORRESULT_DOMEXCEPTION;
|
||||
mDOMExceptionInfo = new DOMExceptionInfo(rv, message);
|
||||
InitDOMExceptionInfo(new DOMExceptionInfo(rv, message));
|
||||
#ifdef DEBUG
|
||||
mUnionState = HasDOMExceptionInfo;
|
||||
#endif
|
||||
@ -388,11 +390,12 @@ void
|
||||
TErrorResult<CleanupPolicy>::SetPendingDOMException(JSContext* cx)
|
||||
{
|
||||
AssertInOwningThread();
|
||||
MOZ_ASSERT(mDOMExceptionInfo,
|
||||
"SetPendingDOMException() can be called only once");
|
||||
MOZ_ASSERT(mUnionState == HasDOMExceptionInfo);
|
||||
MOZ_ASSERT(mExtra.mDOMExceptionInfo,
|
||||
"SetPendingDOMException() can be called only once");
|
||||
|
||||
dom::Throw(cx, mDOMExceptionInfo->mRv, mDOMExceptionInfo->mMessage);
|
||||
dom::Throw(cx, mExtra.mDOMExceptionInfo->mRv,
|
||||
mExtra.mDOMExceptionInfo->mMessage);
|
||||
|
||||
ClearDOMExceptionInfo();
|
||||
mResult = NS_OK;
|
||||
@ -404,9 +407,9 @@ TErrorResult<CleanupPolicy>::ClearDOMExceptionInfo()
|
||||
{
|
||||
AssertInOwningThread();
|
||||
MOZ_ASSERT(IsDOMException());
|
||||
MOZ_ASSERT(mUnionState == HasDOMExceptionInfo || !mDOMExceptionInfo);
|
||||
delete mDOMExceptionInfo;
|
||||
mDOMExceptionInfo = nullptr;
|
||||
MOZ_ASSERT(mUnionState == HasDOMExceptionInfo);
|
||||
delete mExtra.mDOMExceptionInfo;
|
||||
mExtra.mDOMExceptionInfo = nullptr;
|
||||
#ifdef DEBUG
|
||||
mUnionState = HasNothing;
|
||||
#endif // DEBUG
|
||||
@ -420,8 +423,8 @@ TErrorResult<CleanupPolicy>::ClearUnionData()
|
||||
if (IsJSException()) {
|
||||
JSContext* cx = dom::danger::GetJSContext();
|
||||
MOZ_ASSERT(cx);
|
||||
mJSException.asValueRef().setUndefined();
|
||||
js::RemoveRawValueRoot(cx, &mJSException.asValueRef());
|
||||
mExtra.mJSException.setUndefined();
|
||||
js::RemoveRawValueRoot(cx, &mExtra.mJSException);
|
||||
#ifdef DEBUG
|
||||
mUnionState = HasNothing;
|
||||
#endif // DEBUG
|
||||
@ -459,24 +462,26 @@ TErrorResult<CleanupPolicy>::operator=(TErrorResult<CleanupPolicy>&& aRHS)
|
||||
aRHS.mMightHaveUnreportedJSException = false;
|
||||
#endif
|
||||
if (aRHS.IsErrorWithMessage()) {
|
||||
mMessage = aRHS.mMessage;
|
||||
aRHS.mMessage = nullptr;
|
||||
InitMessage(aRHS.mExtra.mMessage);
|
||||
aRHS.mExtra.mMessage = nullptr;
|
||||
} else if (aRHS.IsJSException()) {
|
||||
JSContext* cx = dom::danger::GetJSContext();
|
||||
MOZ_ASSERT(cx);
|
||||
mJSException.asValueRef().setUndefined();
|
||||
if (!js::AddRawValueRoot(cx, &mJSException.asValueRef(), "TErrorResult::mJSException")) {
|
||||
MOZ_CRASH("Could not root mJSException, we're about to OOM");
|
||||
JS::Value& exn = InitJSException();
|
||||
if (!js::AddRawValueRoot(cx, &exn,
|
||||
"TErrorResult::mExtra::mJSException")) {
|
||||
MOZ_CRASH("Could not root mExtra.mJSException, we're about to OOM");
|
||||
}
|
||||
mJSException = aRHS.mJSException;
|
||||
aRHS.mJSException.asValueRef().setUndefined();
|
||||
js::RemoveRawValueRoot(cx, &aRHS.mJSException.asValueRef());
|
||||
mExtra.mJSException = aRHS.mExtra.mJSException;
|
||||
aRHS.mExtra.mJSException.setUndefined();
|
||||
js::RemoveRawValueRoot(cx, &aRHS.mExtra.mJSException);
|
||||
} else if (aRHS.IsDOMException()) {
|
||||
mDOMExceptionInfo = aRHS.mDOMExceptionInfo;
|
||||
aRHS.mDOMExceptionInfo = nullptr;
|
||||
InitDOMExceptionInfo(aRHS.mExtra.mDOMExceptionInfo);
|
||||
aRHS.mExtra.mDOMExceptionInfo = nullptr;
|
||||
} else {
|
||||
// Null out the union on both sides for hygiene purposes.
|
||||
mMessage = aRHS.mMessage = nullptr;
|
||||
// Null out the union on both sides for hygiene purposes. This is purely
|
||||
// precautionary, so InitMessage/placement-new is unnecessary.
|
||||
mExtra.mMessage = aRHS.mExtra.mMessage = nullptr;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
@ -508,21 +513,22 @@ TErrorResult<CleanupPolicy>::CloneTo(TErrorResult& aRv) const
|
||||
#ifdef DEBUG
|
||||
aRv.mUnionState = HasMessage;
|
||||
#endif
|
||||
aRv.mMessage = new Message();
|
||||
aRv.mMessage->mArgs = mMessage->mArgs;
|
||||
aRv.mMessage->mErrorNumber = mMessage->mErrorNumber;
|
||||
Message* message = aRv.InitMessage(new Message());
|
||||
message->mArgs = mExtra.mMessage->mArgs;
|
||||
message->mErrorNumber = mExtra.mMessage->mErrorNumber;
|
||||
} else if (IsDOMException()) {
|
||||
#ifdef DEBUG
|
||||
aRv.mUnionState = HasDOMExceptionInfo;
|
||||
#endif
|
||||
aRv.mDOMExceptionInfo = new DOMExceptionInfo(mDOMExceptionInfo->mRv,
|
||||
mDOMExceptionInfo->mMessage);
|
||||
auto* exnInfo = new DOMExceptionInfo(mExtra.mDOMExceptionInfo->mRv,
|
||||
mExtra.mDOMExceptionInfo->mMessage);
|
||||
aRv.InitDOMExceptionInfo(exnInfo);
|
||||
} else if (IsJSException()) {
|
||||
#ifdef DEBUG
|
||||
aRv.mUnionState = HasJSException;
|
||||
#endif
|
||||
JSContext* cx = dom::danger::GetJSContext();
|
||||
JS::Rooted<JS::Value> exception(cx, mJSException.asValueRef());
|
||||
JS::Rooted<JS::Value> exception(cx, mExtra.mJSException);
|
||||
aRv.ThrowJSException(cx, exception);
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,7 @@
|
||||
#ifndef mozilla_ErrorResult_h
|
||||
#define mozilla_ErrorResult_h
|
||||
|
||||
#include <new>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "js/GCAnnotations.h"
|
||||
@ -463,12 +464,12 @@ private:
|
||||
void ClearMessage();
|
||||
void ClearDOMExceptionInfo();
|
||||
|
||||
// ClearUnionData will try to clear the data in our
|
||||
// mMessage/mJSException/mDOMExceptionInfo union. After this the union may be
|
||||
// in an uninitialized state (e.g. mMessage or mDOMExceptionInfo may be
|
||||
// pointing to deleted memory) and the caller must either reinitialize it or
|
||||
// change mResult to something that will not involve us touching the union
|
||||
// anymore.
|
||||
// ClearUnionData will try to clear the data in our mExtra union. After this
|
||||
// the union may be in an uninitialized state (e.g. mMessage or
|
||||
// mDOMExceptionInfo may point to deleted memory, or mJSException may be a
|
||||
// JS::Value containing an invalid gcthing) and the caller must either
|
||||
// reinitialize it or change mResult to something that will not involve us
|
||||
// touching the union anymore.
|
||||
void ClearUnionData();
|
||||
|
||||
// Implementation of MaybeSetPendingException for the case when we're a
|
||||
@ -500,17 +501,46 @@ private:
|
||||
|
||||
struct Message;
|
||||
struct DOMExceptionInfo;
|
||||
// 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 {
|
||||
union Extra {
|
||||
// mMessage is set by ThrowErrorWithMessage and reported (and deallocated)
|
||||
// by SetPendingExceptionWithMessage.
|
||||
Message* mMessage; // valid when IsErrorWithMessage()
|
||||
JS::UninitializedValue mJSException; // valid when IsJSException()
|
||||
|
||||
// mJSException is set (and rooted) by ThrowJSException and reported (and
|
||||
// unrooted) by SetPendingJSException.
|
||||
JS::Value mJSException; // valid when IsJSException()
|
||||
|
||||
// mDOMExceptionInfo is set by ThrowDOMException and reported (and
|
||||
// deallocated) by SetPendingDOMException.
|
||||
DOMExceptionInfo* mDOMExceptionInfo; // valid when IsDOMException()
|
||||
};
|
||||
|
||||
// |mJSException| has a non-trivial constructor and therefore MUST be
|
||||
// placement-new'd into existence.
|
||||
MOZ_PUSH_DISABLE_NONTRIVIAL_UNION_WARNINGS
|
||||
Extra() {}
|
||||
MOZ_POP_DISABLE_NONTRIVIAL_UNION_WARNINGS
|
||||
} mExtra;
|
||||
|
||||
Message* InitMessage(Message* aMessage) {
|
||||
// The |new| here switches the active arm of |mExtra|, from the compiler's
|
||||
// point of view. Mere assignment *won't* necessarily do the right thing!
|
||||
new (&mExtra.mMessage) Message*(aMessage);
|
||||
return mExtra.mMessage;
|
||||
}
|
||||
|
||||
JS::Value& InitJSException() {
|
||||
// The |new| here switches the active arm of |mExtra|, from the compiler's
|
||||
// point of view. Mere assignment *won't* necessarily do the right thing!
|
||||
new (&mExtra.mJSException) JS::Value(); // sets to undefined
|
||||
return mExtra.mJSException;
|
||||
}
|
||||
|
||||
DOMExceptionInfo* InitDOMExceptionInfo(DOMExceptionInfo* aDOMExceptionInfo) {
|
||||
// The |new| here switches the active arm of |mExtra|, from the compiler's
|
||||
// point of view. Mere assignment *won't* necessarily do the right thing!
|
||||
new (&mExtra.mDOMExceptionInfo) DOMExceptionInfo*(aDOMExceptionInfo);
|
||||
return mExtra.mDOMExceptionInfo;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
// Used to keep track of codepaths that might throw JS exceptions,
|
||||
|
@ -140,16 +140,12 @@ static_assert(sizeof(JSValueShiftedTag) == sizeof(uint64_t),
|
||||
|
||||
#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
|
||||
|
||||
@ -226,8 +222,6 @@ static inline JS::Value PoisonedObjectValue(uintptr_t poison);
|
||||
|
||||
namespace JS {
|
||||
|
||||
static inline constexpr JS::Value UndefinedValue();
|
||||
|
||||
namespace detail {
|
||||
|
||||
constexpr int CanonicalizedNaNSignBit = 0;
|
||||
@ -361,9 +355,7 @@ union MOZ_NON_PARAM alignas(8) Value
|
||||
} s_;
|
||||
|
||||
public:
|
||||
// The default constructor leaves Value uninitialized. Adding a default
|
||||
// constructor prevents Value from being stored in a union.
|
||||
Value() = default;
|
||||
constexpr Value() : asBits_(bitsFromTagAndPayload(JSVAL_TAG_UNDEFINED, 0)) {}
|
||||
Value(const Value& v) = default;
|
||||
|
||||
private:
|
||||
@ -889,55 +881,10 @@ union MOZ_NON_PARAM alignas(8) Value
|
||||
}
|
||||
} 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)
|
||||
{
|
||||
@ -972,7 +919,7 @@ NullValue()
|
||||
static inline constexpr Value
|
||||
UndefinedValue()
|
||||
{
|
||||
return Value::fromTagAndPayload(JSVAL_TAG_UNDEFINED, 0);
|
||||
return Value();
|
||||
}
|
||||
|
||||
static inline constexpr Value
|
||||
|
@ -226,7 +226,6 @@ const WHITELIST_TYPES: &'static [&'static str] = &[
|
||||
"JS::TraceKind",
|
||||
"JS::TransferableOwnership",
|
||||
"JS::Value",
|
||||
"JS::UninitializedValue",
|
||||
"JS::WarningReporter",
|
||||
"JS::shadow::Zone",
|
||||
"JS::Zone",
|
||||
|
@ -7,7 +7,9 @@
|
||||
#ifndef jit_BaselineFrameInfo_h
|
||||
#define jit_BaselineFrameInfo_h
|
||||
|
||||
#include "mozilla/Alignment.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
#include <new>
|
||||
|
||||
#include "jit/BaselineFrame.h"
|
||||
#include "jit/FixedList.h"
|
||||
@ -65,19 +67,17 @@ class StackValue
|
||||
private:
|
||||
Kind kind_;
|
||||
|
||||
union {
|
||||
struct {
|
||||
JS::UninitializedValue v;
|
||||
} constant;
|
||||
struct {
|
||||
mozilla::AlignedStorage2<ValueOperand> reg;
|
||||
} reg;
|
||||
struct {
|
||||
uint32_t slot;
|
||||
} local;
|
||||
struct {
|
||||
uint32_t slot;
|
||||
} arg;
|
||||
union Data {
|
||||
JS::Value constant;
|
||||
ValueOperand reg;
|
||||
uint32_t localSlot;
|
||||
uint32_t argSlot;
|
||||
|
||||
// |constant| has a non-trivial constructor and therefore MUST be
|
||||
// placement-new'd into existence.
|
||||
MOZ_PUSH_DISABLE_NONTRIVIAL_UNION_WARNINGS
|
||||
Data() {}
|
||||
MOZ_POP_DISABLE_NONTRIVIAL_UNION_WARNINGS
|
||||
} data;
|
||||
|
||||
JSValueType knownType_;
|
||||
@ -112,39 +112,39 @@ class StackValue
|
||||
}
|
||||
Value constant() const {
|
||||
MOZ_ASSERT(kind_ == Constant);
|
||||
return data.constant.v.asValueRef();
|
||||
return data.constant;
|
||||
}
|
||||
ValueOperand reg() const {
|
||||
MOZ_ASSERT(kind_ == Register);
|
||||
return *data.reg.reg.addr();
|
||||
return data.reg;
|
||||
}
|
||||
uint32_t localSlot() const {
|
||||
MOZ_ASSERT(kind_ == LocalSlot);
|
||||
return data.local.slot;
|
||||
return data.localSlot;
|
||||
}
|
||||
uint32_t argSlot() const {
|
||||
MOZ_ASSERT(kind_ == ArgSlot);
|
||||
return data.arg.slot;
|
||||
return data.argSlot;
|
||||
}
|
||||
|
||||
void setConstant(const Value& v) {
|
||||
kind_ = Constant;
|
||||
data.constant.v = v;
|
||||
new (&data.constant) Value(v);
|
||||
knownType_ = v.isDouble() ? JSVAL_TYPE_DOUBLE : v.extractNonDoubleType();
|
||||
}
|
||||
void setRegister(const ValueOperand& val, JSValueType knownType = JSVAL_TYPE_UNKNOWN) {
|
||||
kind_ = Register;
|
||||
*data.reg.reg.addr() = val;
|
||||
new (&data.reg) ValueOperand(val);
|
||||
knownType_ = knownType;
|
||||
}
|
||||
void setLocalSlot(uint32_t slot) {
|
||||
kind_ = LocalSlot;
|
||||
data.local.slot = slot;
|
||||
new (&data.localSlot) uint32_t(slot);
|
||||
knownType_ = JSVAL_TYPE_UNKNOWN;
|
||||
}
|
||||
void setArgSlot(uint32_t slot) {
|
||||
kind_ = ArgSlot;
|
||||
data.arg.slot = slot;
|
||||
new (&data.argSlot) uint32_t(slot);
|
||||
knownType_ = JSVAL_TYPE_UNKNOWN;
|
||||
}
|
||||
void setThis() {
|
||||
|
@ -7,8 +7,11 @@
|
||||
#ifndef jit_RegisterSets_h
|
||||
#define jit_RegisterSets_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/MathAlgorithms.h"
|
||||
|
||||
#include <new>
|
||||
|
||||
#include "jit/JitAllocPolicy.h"
|
||||
#include "jit/Registers.h"
|
||||
|
||||
@ -231,26 +234,15 @@ class ConstantOrRegister
|
||||
|
||||
// Space to hold either a Value or a TypedOrValueRegister.
|
||||
union U {
|
||||
JS::UninitializedValue constant;
|
||||
JS::Value constant;
|
||||
TypedOrValueRegister reg;
|
||||
} data;
|
||||
|
||||
Value dataValue() const {
|
||||
MOZ_ASSERT(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;
|
||||
}
|
||||
void setDataReg(const TypedOrValueRegister& reg) {
|
||||
MOZ_ASSERT(!constant());
|
||||
data.reg = reg;
|
||||
}
|
||||
// |constant| has a non-trivial constructor and therefore MUST be
|
||||
// placement-new'd into existence.
|
||||
MOZ_PUSH_DISABLE_NONTRIVIAL_UNION_WARNINGS
|
||||
U() {}
|
||||
MOZ_POP_DISABLE_NONTRIVIAL_UNION_WARNINGS
|
||||
} data;
|
||||
|
||||
public:
|
||||
|
||||
@ -260,13 +252,15 @@ class ConstantOrRegister
|
||||
MOZ_IMPLICIT ConstantOrRegister(const Value& value)
|
||||
: constant_(true)
|
||||
{
|
||||
setDataValue(value);
|
||||
MOZ_ASSERT(constant());
|
||||
new (&data.constant) Value(value);
|
||||
}
|
||||
|
||||
MOZ_IMPLICIT ConstantOrRegister(TypedOrValueRegister reg)
|
||||
: constant_(false)
|
||||
{
|
||||
setDataReg(reg);
|
||||
MOZ_ASSERT(!constant());
|
||||
new (&data.reg) TypedOrValueRegister(reg);
|
||||
}
|
||||
|
||||
bool constant() const {
|
||||
@ -274,11 +268,13 @@ class ConstantOrRegister
|
||||
}
|
||||
|
||||
Value value() const {
|
||||
return dataValue();
|
||||
MOZ_ASSERT(constant());
|
||||
return data.constant;
|
||||
}
|
||||
|
||||
const TypedOrValueRegister& reg() const {
|
||||
return dataReg();
|
||||
MOZ_ASSERT(!constant());
|
||||
return data.reg;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -23,6 +23,8 @@
|
||||
#include "mozilla/MathAlgorithms.h"
|
||||
#include "mozilla/Unused.h"
|
||||
|
||||
#include <new>
|
||||
|
||||
#include "jsmath.h"
|
||||
#include "jsutil.h"
|
||||
|
||||
@ -137,7 +139,6 @@ class AsmJSGlobal
|
||||
union U {
|
||||
ValType importType_;
|
||||
Val val_;
|
||||
U() {}
|
||||
} u;
|
||||
} var;
|
||||
uint32_t ffiIndex_;
|
||||
@ -153,7 +154,6 @@ class AsmJSGlobal
|
||||
ConstantKind kind_;
|
||||
double value_;
|
||||
} constant;
|
||||
V() {}
|
||||
} u;
|
||||
} pod;
|
||||
CacheableChars field_;
|
||||
@ -844,21 +844,27 @@ class NumLit
|
||||
|
||||
private:
|
||||
Which which_;
|
||||
union {
|
||||
JS::UninitializedValue scalar_;
|
||||
union U {
|
||||
JS::Value scalar_;
|
||||
SimdConstant simd_;
|
||||
|
||||
// |scalar_| has a non-trivial constructor and therefore MUST be
|
||||
// placement-new'd into existence.
|
||||
MOZ_PUSH_DISABLE_NONTRIVIAL_UNION_WARNINGS
|
||||
U() {}
|
||||
MOZ_POP_DISABLE_NONTRIVIAL_UNION_WARNINGS
|
||||
} u;
|
||||
|
||||
public:
|
||||
NumLit() = default;
|
||||
|
||||
NumLit(Which w, const Value& v) : which_(w) {
|
||||
u.scalar_ = v;
|
||||
new (&u.scalar_) Value(v);
|
||||
MOZ_ASSERT(!isSimd());
|
||||
}
|
||||
|
||||
NumLit(Which w, SimdConstant c) : which_(w) {
|
||||
u.simd_ = c;
|
||||
new (&u.simd_) SimdConstant(c);
|
||||
MOZ_ASSERT(isSimd());
|
||||
}
|
||||
|
||||
@ -868,7 +874,7 @@ class NumLit
|
||||
|
||||
int32_t toInt32() const {
|
||||
MOZ_ASSERT(which_ == Fixnum || which_ == NegativeInt || which_ == BigUnsigned);
|
||||
return u.scalar_.asValueRef().toInt32();
|
||||
return u.scalar_.toInt32();
|
||||
}
|
||||
|
||||
uint32_t toUint32() const {
|
||||
@ -877,17 +883,17 @@ class NumLit
|
||||
|
||||
double toDouble() const {
|
||||
MOZ_ASSERT(which_ == Double);
|
||||
return u.scalar_.asValueRef().toDouble();
|
||||
return u.scalar_.toDouble();
|
||||
}
|
||||
|
||||
float toFloat() const {
|
||||
MOZ_ASSERT(which_ == Float);
|
||||
return float(u.scalar_.asValueRef().toDouble());
|
||||
return float(u.scalar_.toDouble());
|
||||
}
|
||||
|
||||
Value scalarValue() const {
|
||||
MOZ_ASSERT(which_ != OutOfRangeInt);
|
||||
return u.scalar_.asValueRef();
|
||||
return u.scalar_;
|
||||
}
|
||||
|
||||
bool isSimd() const
|
||||
@ -1471,25 +1477,52 @@ class MOZ_STACK_CLASS ModuleValidator
|
||||
|
||||
private:
|
||||
Which which_;
|
||||
union {
|
||||
struct {
|
||||
union U {
|
||||
struct VarOrConst {
|
||||
Type::Which type_;
|
||||
unsigned index_;
|
||||
NumLit literalValue_;
|
||||
|
||||
VarOrConst(unsigned index, const NumLit& lit)
|
||||
: type_(Type::lit(lit).which()),
|
||||
index_(index),
|
||||
literalValue_(lit) // copies |lit|
|
||||
{}
|
||||
|
||||
VarOrConst(unsigned index, Type::Which which)
|
||||
: type_(which),
|
||||
index_(index)
|
||||
{
|
||||
// The |literalValue_| field remains unused and
|
||||
// uninitialized for non-constant variables.
|
||||
}
|
||||
|
||||
explicit VarOrConst(double constant)
|
||||
: type_(Type::Double),
|
||||
literalValue_(NumLit::Double, DoubleValue(constant))
|
||||
{
|
||||
// The index_ field is unused and uninitialized for
|
||||
// constant doubles.
|
||||
}
|
||||
} varOrConst;
|
||||
uint32_t funcDefIndex_;
|
||||
uint32_t tableIndex_;
|
||||
uint32_t ffiIndex_;
|
||||
struct {
|
||||
Scalar::Type viewType_;
|
||||
} viewInfo;
|
||||
Scalar::Type viewType_;
|
||||
AsmJSMathBuiltinFunction mathBuiltinFunc_;
|
||||
AsmJSAtomicsBuiltinFunction atomicsBuiltinFunc_;
|
||||
SimdType simdCtorType_;
|
||||
struct {
|
||||
struct SimdTypeAndOperation {
|
||||
SimdType type_;
|
||||
SimdOperation which_;
|
||||
} simdOp;
|
||||
|
||||
// |varOrConst|, through |varOrConst.literalValue_|, has a
|
||||
// non-trivial constructor and therefore MUST be placement-new'd
|
||||
// into existence.
|
||||
MOZ_PUSH_DISABLE_NONTRIVIAL_UNION_WARNINGS
|
||||
U() {}
|
||||
MOZ_POP_DISABLE_NONTRIVIAL_UNION_WARNINGS
|
||||
} u;
|
||||
|
||||
friend class ModuleValidator;
|
||||
@ -1533,7 +1566,7 @@ class MOZ_STACK_CLASS ModuleValidator
|
||||
}
|
||||
Scalar::Type viewType() const {
|
||||
MOZ_ASSERT(isAnyArrayView());
|
||||
return u.viewInfo.viewType_;
|
||||
return u.viewType_;
|
||||
}
|
||||
bool isMathFunction() const {
|
||||
return which_ == MathBuiltinFunction;
|
||||
@ -1958,10 +1991,10 @@ class MOZ_STACK_CLASS ModuleValidator
|
||||
Global* global = validationLifo_.new_<Global>(which);
|
||||
if (!global)
|
||||
return false;
|
||||
global->u.varOrConst.index_ = index;
|
||||
global->u.varOrConst.type_ = (isConst ? Type::lit(lit) : type).which();
|
||||
if (isConst)
|
||||
global->u.varOrConst.literalValue_ = lit;
|
||||
new (&global->u.varOrConst) Global::U::VarOrConst(index, lit);
|
||||
else
|
||||
new (&global->u.varOrConst) Global::U::VarOrConst(index, type.which());
|
||||
if (!globalMap_.putNew(var, global))
|
||||
return false;
|
||||
|
||||
@ -1986,8 +2019,7 @@ class MOZ_STACK_CLASS ModuleValidator
|
||||
Global* global = validationLifo_.new_<Global>(which);
|
||||
if (!global)
|
||||
return false;
|
||||
global->u.varOrConst.index_ = index;
|
||||
global->u.varOrConst.type_ = type.which();
|
||||
new (&global->u.varOrConst) Global::U::VarOrConst(index, type.which());
|
||||
if (!globalMap_.putNew(var, global))
|
||||
return false;
|
||||
|
||||
@ -2010,7 +2042,7 @@ class MOZ_STACK_CLASS ModuleValidator
|
||||
Global* global = validationLifo_.new_<Global>(Global::ArrayView);
|
||||
if (!global)
|
||||
return false;
|
||||
global->u.viewInfo.viewType_ = vt;
|
||||
new (&global->u.viewType_) Scalar::Type(vt);
|
||||
if (!globalMap_.putNew(var, global))
|
||||
return false;
|
||||
|
||||
@ -2028,7 +2060,7 @@ class MOZ_STACK_CLASS ModuleValidator
|
||||
Global* global = validationLifo_.new_<Global>(Global::MathBuiltinFunction);
|
||||
if (!global)
|
||||
return false;
|
||||
global->u.mathBuiltinFunc_ = func;
|
||||
new (&global->u.mathBuiltinFunc_) AsmJSMathBuiltinFunction(func);
|
||||
if (!globalMap_.putNew(var, global))
|
||||
return false;
|
||||
|
||||
@ -2041,8 +2073,7 @@ class MOZ_STACK_CLASS ModuleValidator
|
||||
Global* global = validationLifo_.new_<Global>(Global::ConstantLiteral);
|
||||
if (!global)
|
||||
return false;
|
||||
global->u.varOrConst.type_ = Type::Double;
|
||||
global->u.varOrConst.literalValue_ = NumLit(NumLit::Double, DoubleValue(constant));
|
||||
new (&global->u.varOrConst) Global::U::VarOrConst(constant);
|
||||
return globalMap_.putNew(var, global);
|
||||
}
|
||||
public:
|
||||
@ -2087,7 +2118,7 @@ class MOZ_STACK_CLASS ModuleValidator
|
||||
Global* global = validationLifo_.new_<Global>(Global::AtomicsBuiltinFunction);
|
||||
if (!global)
|
||||
return false;
|
||||
global->u.atomicsBuiltinFunc_ = func;
|
||||
new (&global->u.atomicsBuiltinFunc_) AsmJSAtomicsBuiltinFunction(func);
|
||||
if (!globalMap_.putNew(var, global))
|
||||
return false;
|
||||
|
||||
@ -2105,7 +2136,7 @@ class MOZ_STACK_CLASS ModuleValidator
|
||||
Global* global = validationLifo_.new_<Global>(Global::SimdCtor);
|
||||
if (!global)
|
||||
return false;
|
||||
global->u.simdCtorType_ = type;
|
||||
new (&global->u.simdCtorType_) SimdType(type);
|
||||
if (!globalMap_.putNew(var, global))
|
||||
return false;
|
||||
|
||||
@ -2123,8 +2154,7 @@ class MOZ_STACK_CLASS ModuleValidator
|
||||
Global* global = validationLifo_.new_<Global>(Global::SimdOp);
|
||||
if (!global)
|
||||
return false;
|
||||
global->u.simdOp.type_ = type;
|
||||
global->u.simdOp.which_ = op;
|
||||
new (&global->u.simdOp) Global::U::SimdTypeAndOperation{ type, op };
|
||||
if (!globalMap_.putNew(var, global))
|
||||
return false;
|
||||
|
||||
@ -2141,7 +2171,7 @@ class MOZ_STACK_CLASS ModuleValidator
|
||||
Global* global = validationLifo_.new_<Global>(Global::ArrayViewCtor);
|
||||
if (!global)
|
||||
return false;
|
||||
global->u.viewInfo.viewType_ = vt;
|
||||
new (&global->u.viewType_) Scalar::Type(vt);
|
||||
if (!globalMap_.putNew(var, global))
|
||||
return false;
|
||||
|
||||
@ -2161,7 +2191,7 @@ class MOZ_STACK_CLASS ModuleValidator
|
||||
Global* global = validationLifo_.new_<Global>(Global::FFI);
|
||||
if (!global)
|
||||
return false;
|
||||
global->u.ffiIndex_ = ffiIndex;
|
||||
new (&global->u.ffiIndex_) uint32_t(ffiIndex);
|
||||
if (!globalMap_.putNew(var, global))
|
||||
return false;
|
||||
|
||||
@ -2203,7 +2233,7 @@ class MOZ_STACK_CLASS ModuleValidator
|
||||
Global* global = validationLifo_.new_<Global>(Global::Function);
|
||||
if (!global)
|
||||
return false;
|
||||
global->u.funcDefIndex_ = funcDefIndex;
|
||||
new (&global->u.funcDefIndex_) uint32_t(funcDefIndex);
|
||||
if (!globalMap_.putNew(name, global))
|
||||
return false;
|
||||
if (!funcDefs_.emplaceBack(name, sigIndex, firstUse, funcDefIndex))
|
||||
@ -2236,7 +2266,7 @@ class MOZ_STACK_CLASS ModuleValidator
|
||||
if (!global)
|
||||
return false;
|
||||
|
||||
global->u.tableIndex_ = *tableIndex;
|
||||
new (&global->u.tableIndex_) uint32_t(*tableIndex);
|
||||
if (!globalMap_.putNew(name, global))
|
||||
return false;
|
||||
|
||||
|
@ -492,7 +492,6 @@ class Val
|
||||
I16x8 i16x8_;
|
||||
I32x4 i32x4_;
|
||||
F32x4 f32x4_;
|
||||
U() {}
|
||||
} u;
|
||||
|
||||
public:
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCycleCollectionNoteRootCallback.h"
|
||||
|
||||
#include <new>
|
||||
#include <stdint.h>
|
||||
#include "mozilla/DeferredFinalize.h"
|
||||
#include "mozilla/Likely.h"
|
||||
@ -1681,8 +1682,9 @@ CallMethodHelper::ConvertIndependentParam(uint8_t i)
|
||||
// indirectly, regardless of in/out-ness.
|
||||
if (type_tag == nsXPTType::T_JSVAL) {
|
||||
// Root the value.
|
||||
dp->val.j.asValueRef().setUndefined();
|
||||
if (!js::AddRawValueRoot(mCallContext, &dp->val.j.asValueRef(),
|
||||
new (&dp->val.j) JS::Value();
|
||||
MOZ_ASSERT(dp->val.j.isUndefined());
|
||||
if (!js::AddRawValueRoot(mCallContext, &dp->val.j,
|
||||
"XPCWrappedNative::CallMethod param"))
|
||||
{
|
||||
return false;
|
||||
@ -1894,7 +1896,7 @@ CallMethodHelper::CleanupParam(nsXPTCMiniVariant& param, nsXPTType& type)
|
||||
|
||||
switch (type.TagPart()) {
|
||||
case nsXPTType::T_JSVAL:
|
||||
js::RemoveRawValueRoot(mCallContext, (Value*)¶m.val);
|
||||
js::RemoveRawValueRoot(mCallContext, ¶m.val.j);
|
||||
break;
|
||||
case nsXPTType::T_INTERFACE:
|
||||
case nsXPTType::T_INTERFACE_IS:
|
||||
|
@ -96,13 +96,11 @@ hide-types = [
|
||||
"nsString",
|
||||
".*char_traits",
|
||||
".*incompatible_char_type",
|
||||
# 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.
|
||||
# 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.
|
||||
# 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",
|
||||
|
@ -449,6 +449,46 @@
|
||||
# define MOZ_FALLTHROUGH /* FALLTHROUGH */
|
||||
#endif
|
||||
|
||||
/**
|
||||
* C++11 lets unions contain members that have non-trivial special member
|
||||
* functions (default/copy/move constructor, copy/move assignment operator,
|
||||
* destructor) if the user defines the corresponding functions on the union.
|
||||
* (Such user-defined functions must rely on external knowledge about which arm
|
||||
* is active to be safe. Be extra-careful defining these functions!)
|
||||
*
|
||||
* MSVC unfortunately warns/errors for this bog-standard C++11 pattern. Use
|
||||
* these macro-guards around such member functions to disable the warnings:
|
||||
*
|
||||
* union U
|
||||
* {
|
||||
* std::string s;
|
||||
* int x;
|
||||
*
|
||||
* MOZ_PUSH_DISABLE_NONTRIVIAL_UNION_WARNINGS
|
||||
*
|
||||
* // |U| must have a user-defined default constructor because |std::string|
|
||||
* // has a non-trivial default constructor.
|
||||
* U() ... { ... }
|
||||
*
|
||||
* // |U| must have a user-defined destructor because |std::string| has a
|
||||
* // non-trivial destructor.
|
||||
* ~U() { ... }
|
||||
*
|
||||
* MOZ_POP_DISABLE_NONTRIVIAL_UNION_WARNINGS
|
||||
* };
|
||||
*/
|
||||
#if defined(_MSC_VER)
|
||||
# define MOZ_PUSH_DISABLE_NONTRIVIAL_UNION_WARNINGS \
|
||||
__pragma(warning(push)) \
|
||||
__pragma(warning(disable:4582)) \
|
||||
__pragma(warning(disable:4583))
|
||||
# define MOZ_POP_DISABLE_NONTRIVIAL_UNION_WARNINGS \
|
||||
__pragma(warning(pop))
|
||||
#else
|
||||
# define MOZ_PUSH_DISABLE_NONTRIVIAL_UNION_WARNINGS /* nothing */
|
||||
# define MOZ_POP_DISABLE_NONTRIVIAL_UNION_WARNINGS /* nothing */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The following macros are attributes that support the static analysis plugin
|
||||
* included with Mozilla, and will be implemented (when such support is enabled)
|
||||
|
@ -12,13 +12,12 @@
|
||||
#include "nsISupports.h"
|
||||
#include "xptinfo.h"
|
||||
#include "js/Value.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
|
||||
struct nsXPTCMiniVariant
|
||||
{
|
||||
// No ctors or dtors so that we can use arrays of these on the stack
|
||||
// with no penalty.
|
||||
union
|
||||
union U
|
||||
{
|
||||
int8_t i8;
|
||||
int16_t i16;
|
||||
@ -38,7 +37,13 @@ struct nsXPTCMiniVariant
|
||||
// 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::UninitializedValue j;
|
||||
JS::Value j;
|
||||
|
||||
// |j| has a non-trivial constructor and therefore MUST be
|
||||
// placement-new'd into existence.
|
||||
MOZ_PUSH_DISABLE_NONTRIVIAL_UNION_WARNINGS
|
||||
U() {}
|
||||
MOZ_POP_DISABLE_NONTRIVIAL_UNION_WARNINGS
|
||||
} val;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user