summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwolfbeast <mcwerewolf@gmail.com>2018-04-29 13:39:11 +0200
committerwolfbeast <mcwerewolf@gmail.com>2018-04-29 13:39:11 +0200
commit66aa6b595c47231958a855e4b166f5d55df1184d (patch)
tree6be9ba956bd1651cf23d35eff2ae51058d65d813
parent927868e8b93f508fe89ee82f618f4a1761366f70 (diff)
downloadUXP-66aa6b595c47231958a855e4b166f5d55df1184d.tar
UXP-66aa6b595c47231958a855e4b166f5d55df1184d.tar.gz
UXP-66aa6b595c47231958a855e4b166f5d55df1184d.tar.lz
UXP-66aa6b595c47231958a855e4b166f5d55df1184d.tar.xz
UXP-66aa6b595c47231958a855e4b166f5d55df1184d.zip
Bug 1411415.
-rw-r--r--dom/bindings/BindingUtils.cpp20
-rw-r--r--dom/bindings/ErrorResult.h2
-rw-r--r--dom/xslt/xpath/txXPCOMExtensionFunction.cpp2
-rw-r--r--js/public/Value.h55
-rw-r--r--js/src/jit/BaselineFrameInfo.h4
-rw-r--r--js/src/jit/RegisterSets.h8
-rw-r--r--js/src/jit/RematerializedFrame.cpp14
-rw-r--r--js/src/wasm/AsmJS.cpp10
-rw-r--r--js/xpconnect/src/XPCWrappedNative.cpp7
-rw-r--r--xpcom/reflect/xptcall/xptcall.h2
10 files changed, 91 insertions, 33 deletions
diff --git a/dom/bindings/BindingUtils.cpp b/dom/bindings/BindingUtils.cpp
index 33f5f7a44..7056658a7 100644
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -259,8 +259,8 @@ TErrorResult<CleanupPolicy>::ThrowJSException(JSContext* cx, JS::Handle<JS::Valu
// 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_DOM_JS_EXCEPTION, because that indicates we have
// in fact rooted mJSException.
mResult = NS_ERROR_OUT_OF_MEMORY;
@@ -289,7 +289,7 @@ TErrorResult<CleanupPolicy>::SetPendingJSException(JSContext* cx)
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
@@ -395,8 +395,8 @@ TErrorResult<CleanupPolicy>::ClearUnionData()
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
@@ -439,13 +439,13 @@ TErrorResult<CleanupPolicy>::operator=(TErrorResult<CleanupPolicy>&& aRHS)
} 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;
@@ -497,7 +497,7 @@ TErrorResult<CleanupPolicy>::CloneTo(TErrorResult& aRv) const
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);
}
}
diff --git a/dom/bindings/ErrorResult.h b/dom/bindings/ErrorResult.h
index c45e7ea3b..7c3fc9e2f 100644
--- a/dom/bindings/ErrorResult.h
+++ b/dom/bindings/ErrorResult.h
@@ -461,7 +461,7 @@ private:
// (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()
};
diff --git a/dom/xslt/xpath/txXPCOMExtensionFunction.cpp b/dom/xslt/xpath/txXPCOMExtensionFunction.cpp
index 4913702aa..032161722 100644
--- a/dom/xslt/xpath/txXPCOMExtensionFunction.cpp
+++ b/dom/xslt/xpath/txXPCOMExtensionFunction.cpp
@@ -322,7 +322,7 @@ public:
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");
}
}
}
diff --git a/js/public/Value.h b/js/public/Value.h
index a40e65c83..01666ed4e 100644
--- a/js/public/Value.h
+++ b/js/public/Value.h
@@ -140,12 +140,16 @@ 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)
+
#define JSVAL_PAYLOAD_MASK 0x00007FFFFFFFFFFFLL
#define JSVAL_TAG_MASK 0xFFFF800000000000LL
#define JSVAL_TYPE_TO_TAG(type) ((JSValueTag)(JSVAL_TAG_MAX_DOUBLE | (type)))
@@ -817,7 +821,7 @@ class MOZ_NON_PARAM alignas(8) Value
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;
@@ -843,7 +847,7 @@ class MOZ_NON_PARAM alignas(8) Value
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;
@@ -871,7 +875,7 @@ class MOZ_NON_PARAM alignas(8) Value
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;
@@ -895,7 +899,7 @@ class MOZ_NON_PARAM alignas(8) Value
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;
@@ -948,8 +952,51 @@ class 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)
{
diff --git a/js/src/jit/BaselineFrameInfo.h b/js/src/jit/BaselineFrameInfo.h
index 13bf0358d..1691270ac 100644
--- a/js/src/jit/BaselineFrameInfo.h
+++ b/js/src/jit/BaselineFrameInfo.h
@@ -67,7 +67,7 @@ class StackValue
union {
struct {
- Value v;
+ JS::UninitializedValue v;
} constant;
struct {
mozilla::AlignedStorage2<ValueOperand> reg;
@@ -112,7 +112,7 @@ class StackValue
}
Value constant() const {
MOZ_ASSERT(kind_ == Constant);
- return data.constant.v;
+ return data.constant.v.asValueRef();
}
ValueOperand reg() const {
MOZ_ASSERT(kind_ == Register);
diff --git a/js/src/jit/RegisterSets.h b/js/src/jit/RegisterSets.h
index 0a4045dd7..08ae53f16 100644
--- a/js/src/jit/RegisterSets.h
+++ b/js/src/jit/RegisterSets.h
@@ -226,13 +226,13 @@ class ConstantOrRegister
// 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());
@@ -268,7 +268,7 @@ class ConstantOrRegister
return constant_;
}
- const Value& value() const {
+ Value value() const {
return dataValue();
}
diff --git a/js/src/jit/RematerializedFrame.cpp b/js/src/jit/RematerializedFrame.cpp
index cb324220c..32fad1267 100644
--- a/js/src/jit/RematerializedFrame.cpp
+++ b/js/src/jit/RematerializedFrame.cpp
@@ -61,9 +61,17 @@ RematerializedFrame::New(JSContext* cx, uint8_t* top, InlineFrameIterator& iter,
{
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)
diff --git a/js/src/wasm/AsmJS.cpp b/js/src/wasm/AsmJS.cpp
index b4f41c3d5..7fade24fb 100644
--- a/js/src/wasm/AsmJS.cpp
+++ b/js/src/wasm/AsmJS.cpp
@@ -857,7 +857,7 @@ class NumLit
private:
Which which_;
union {
- Value scalar_;
+ JS::UninitializedValue scalar_;
SimdConstant simd_;
} u;
@@ -880,7 +880,7 @@ class NumLit
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 {
@@ -889,17 +889,17 @@ class NumLit
RawF64 toDouble() const {
MOZ_ASSERT(which_ == Double);
- return RawF64(u.scalar_.toDouble());
+ return RawF64(u.scalar_.asValueRef().toDouble());
}
RawF32 toFloat() const {
MOZ_ASSERT(which_ == Float);
- return RawF32(float(u.scalar_.toDouble()));
+ return RawF32(float(u.scalar_.asValueRef().toDouble()));
}
Value scalarValue() const {
MOZ_ASSERT(which_ != OutOfRangeInt);
- return u.scalar_;
+ return u.scalar_.asValueRef();
}
bool isSimd() const
diff --git a/js/xpconnect/src/XPCWrappedNative.cpp b/js/xpconnect/src/XPCWrappedNative.cpp
index acf92f3c3..a12e36baa 100644
--- a/js/xpconnect/src/XPCWrappedNative.cpp
+++ b/js/xpconnect/src/XPCWrappedNative.cpp
@@ -1785,9 +1785,12 @@ CallMethodHelper::ConvertIndependentParam(uint8_t i)
// 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.
diff --git a/xpcom/reflect/xptcall/xptcall.h b/xpcom/reflect/xptcall/xptcall.h
index 1f2367b5d..304787635 100644
--- a/xpcom/reflect/xptcall/xptcall.h
+++ b/xpcom/reflect/xptcall/xptcall.h
@@ -39,7 +39,7 @@ 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::Value j;
+ JS::UninitializedValue j;
} val;
};