Bug 1451248. r=jorendorff, r=bz

--HG--
extra : rebase_source : e26439a5954162bdaf332fbd63d623a3810e19e0
This commit is contained in:
Jeff Walden 2018-04-25 19:40:09 -07:00
parent e2c8f8433f
commit 04d21ccac0
12 changed files with 266 additions and 214 deletions

View File

@ -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);
}
}

View File

@ -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,

View File

@ -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

View File

@ -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",

View File

@ -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() {

View File

@ -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;
}
};

View File

@ -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;

View File

@ -492,7 +492,6 @@ class Val
I16x8 i16x8_;
I32x4 i32x4_;
F32x4 f32x4_;
U() {}
} u;
public:

View File

@ -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*)&param.val);
js::RemoveRawValueRoot(mCallContext, &param.val.j);
break;
case nsXPTType::T_INTERFACE:
case nsXPTType::T_INTERFACE_IS:

View File

@ -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",

View File

@ -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)

View File

@ -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;
};