summaryrefslogtreecommitdiff
path: root/js/public
diff options
context:
space:
mode:
Diffstat (limited to 'js/public')
-rw-r--r--js/public/CallArgs.h2
-rw-r--r--js/public/Date.h8
-rw-r--r--js/public/Proxy.h4
-rw-r--r--js/public/TraceKind.h8
-rw-r--r--js/public/Value.h109
5 files changed, 85 insertions, 46 deletions
diff --git a/js/public/CallArgs.h b/js/public/CallArgs.h
index 6e6164e55a..a7774309aa 100644
--- a/js/public/CallArgs.h
+++ b/js/public/CallArgs.h
@@ -290,7 +290,7 @@ class MOZ_STACK_CLASS CallArgs : public detail::CallArgsBase<detail::IncludeUsed
args.constructing_ = constructing;
#ifdef DEBUG
for (unsigned i = 0; i < argc; ++i)
- MOZ_ASSERT_IF(argv[i].isMarkable(), !GCThingIsMarkedGray(GCCellPtr(argv[i])));
+ MOZ_ASSERT_IF(argv[i].isGCThing(), !GCThingIsMarkedGray(GCCellPtr(argv[i])));
#endif
return args;
}
diff --git a/js/public/Date.h b/js/public/Date.h
index cba0ea875d..cab36a3de9 100644
--- a/js/public/Date.h
+++ b/js/public/Date.h
@@ -134,6 +134,14 @@ NewDateObject(JSContext* cx, ClippedTime time);
JS_PUBLIC_API(double)
MakeDate(double year, unsigned month, unsigned day);
+// Year is a year, month is 0-11, day is 1-based, and time is in milliseconds.
+// The return value is a number of milliseconds since the epoch.
+//
+// Consistent with the MakeDate algorithm defined in ECMAScript, this value is
+// *not* clipped! Use JS::TimeClip if you need a clipped date.
+JS_PUBLIC_API(double)
+MakeDate(double year, unsigned month, unsigned day, double time);
+
// Takes an integer number of milliseconds since the epoch and returns the
// year. Can return NaN, and will do so if NaN is passed in.
JS_PUBLIC_API(double)
diff --git a/js/public/Proxy.h b/js/public/Proxy.h
index 3e95538db6..5acb91b26e 100644
--- a/js/public/Proxy.h
+++ b/js/public/Proxy.h
@@ -456,7 +456,7 @@ SetProxyExtra(JSObject* obj, size_t n, const Value& extra)
Value* vp = &detail::GetProxyDataLayout(obj)->values->extraSlots[n];
// Trigger a barrier before writing the slot.
- if (vp->isMarkable() || extra.isMarkable())
+ if (vp->isGCThing() || extra.isGCThing())
SetValueInProxy(vp, extra);
else
*vp = extra;
@@ -482,7 +482,7 @@ SetReservedOrProxyPrivateSlot(JSObject* obj, size_t slot, const Value& value)
MOZ_ASSERT(slot == 0);
MOZ_ASSERT(slot < JSCLASS_RESERVED_SLOTS(GetObjectClass(obj)) || IsProxy(obj));
shadow::Object* sobj = reinterpret_cast<shadow::Object*>(obj);
- if (sobj->slotRef(slot).isMarkable() || value.isMarkable())
+ if (sobj->slotRef(slot).isGCThing() || value.isGCThing())
SetReservedOrProxyPrivateSlotWithBarrier(obj, slot, value);
else
sobj->slotRef(slot) = value;
diff --git a/js/public/TraceKind.h b/js/public/TraceKind.h
index 2eda9cb2c1..3270966fc2 100644
--- a/js/public/TraceKind.h
+++ b/js/public/TraceKind.h
@@ -40,9 +40,11 @@ enum class TraceKind
// Note: The order here is determined by our Value packing. Other users
// should sort alphabetically, for consistency.
Object = 0x00,
- String = 0x01,
- Symbol = 0x02,
- Script = 0x03,
+ String = 0x02,
+ Symbol = 0x03,
+
+ // 0x1 is not used for any GCThing Value tag, so we use it for Script.
+ Script = 0x01,
// Shape details are exposed through JS_TraceShapeCycleCollectorChildren.
Shape = 0x04,
diff --git a/js/public/Value.h b/js/public/Value.h
index 00fdad5861..01666ed4e1 100644
--- a/js/public/Value.h
+++ b/js/public/Value.h
@@ -51,12 +51,12 @@ JS_ENUM_HEADER(JSValueType, uint8_t)
JSVAL_TYPE_DOUBLE = 0x00,
JSVAL_TYPE_INT32 = 0x01,
JSVAL_TYPE_UNDEFINED = 0x02,
- JSVAL_TYPE_BOOLEAN = 0x03,
- JSVAL_TYPE_MAGIC = 0x04,
- JSVAL_TYPE_STRING = 0x05,
- JSVAL_TYPE_SYMBOL = 0x06,
- JSVAL_TYPE_PRIVATE_GCTHING = 0x07,
- JSVAL_TYPE_NULL = 0x08,
+ JSVAL_TYPE_NULL = 0x03,
+ JSVAL_TYPE_BOOLEAN = 0x04,
+ JSVAL_TYPE_MAGIC = 0x05,
+ JSVAL_TYPE_STRING = 0x06,
+ JSVAL_TYPE_SYMBOL = 0x07,
+ JSVAL_TYPE_PRIVATE_GCTHING = 0x08,
JSVAL_TYPE_OBJECT = 0x0c,
/* These never appear in a jsval; they are only provided as an out-of-band value. */
@@ -75,11 +75,11 @@ JS_ENUM_HEADER(JSValueTag, uint32_t)
JSVAL_TAG_CLEAR = 0xFFFFFF80,
JSVAL_TAG_INT32 = JSVAL_TAG_CLEAR | JSVAL_TYPE_INT32,
JSVAL_TAG_UNDEFINED = JSVAL_TAG_CLEAR | JSVAL_TYPE_UNDEFINED,
+ JSVAL_TAG_NULL = JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL,
JSVAL_TAG_STRING = JSVAL_TAG_CLEAR | JSVAL_TYPE_STRING,
JSVAL_TAG_SYMBOL = JSVAL_TAG_CLEAR | JSVAL_TYPE_SYMBOL,
JSVAL_TAG_BOOLEAN = JSVAL_TAG_CLEAR | JSVAL_TYPE_BOOLEAN,
JSVAL_TAG_MAGIC = JSVAL_TAG_CLEAR | JSVAL_TYPE_MAGIC,
- JSVAL_TAG_NULL = JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL,
JSVAL_TAG_OBJECT = JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT,
JSVAL_TAG_PRIVATE_GCTHING = JSVAL_TAG_CLEAR | JSVAL_TYPE_PRIVATE_GCTHING
} JS_ENUM_FOOTER(JSValueTag);
@@ -95,11 +95,11 @@ JS_ENUM_HEADER(JSValueTag, uint32_t)
JSVAL_TAG_MAX_DOUBLE = 0x1FFF0,
JSVAL_TAG_INT32 = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_INT32,
JSVAL_TAG_UNDEFINED = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_UNDEFINED,
+ JSVAL_TAG_NULL = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL,
JSVAL_TAG_STRING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_STRING,
JSVAL_TAG_SYMBOL = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_SYMBOL,
JSVAL_TAG_BOOLEAN = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN,
JSVAL_TAG_MAGIC = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_MAGIC,
- JSVAL_TAG_NULL = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL,
JSVAL_TAG_OBJECT = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT,
JSVAL_TAG_PRIVATE_GCTHING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_PRIVATE_GCTHING
} JS_ENUM_FOOTER(JSValueTag);
@@ -112,11 +112,11 @@ JS_ENUM_HEADER(JSValueShiftedTag, uint64_t)
JSVAL_SHIFTED_TAG_MAX_DOUBLE = ((((uint64_t)JSVAL_TAG_MAX_DOUBLE) << JSVAL_TAG_SHIFT) | 0xFFFFFFFF),
JSVAL_SHIFTED_TAG_INT32 = (((uint64_t)JSVAL_TAG_INT32) << JSVAL_TAG_SHIFT),
JSVAL_SHIFTED_TAG_UNDEFINED = (((uint64_t)JSVAL_TAG_UNDEFINED) << JSVAL_TAG_SHIFT),
+ JSVAL_SHIFTED_TAG_NULL = (((uint64_t)JSVAL_TAG_NULL) << JSVAL_TAG_SHIFT),
JSVAL_SHIFTED_TAG_STRING = (((uint64_t)JSVAL_TAG_STRING) << JSVAL_TAG_SHIFT),
JSVAL_SHIFTED_TAG_SYMBOL = (((uint64_t)JSVAL_TAG_SYMBOL) << JSVAL_TAG_SHIFT),
JSVAL_SHIFTED_TAG_BOOLEAN = (((uint64_t)JSVAL_TAG_BOOLEAN) << JSVAL_TAG_SHIFT),
JSVAL_SHIFTED_TAG_MAGIC = (((uint64_t)JSVAL_TAG_MAGIC) << JSVAL_TAG_SHIFT),
- JSVAL_SHIFTED_TAG_NULL = (((uint64_t)JSVAL_TAG_NULL) << JSVAL_TAG_SHIFT),
JSVAL_SHIFTED_TAG_OBJECT = (((uint64_t)JSVAL_TAG_OBJECT) << JSVAL_TAG_SHIFT),
JSVAL_SHIFTED_TAG_PRIVATE_GCTHING = (((uint64_t)JSVAL_TAG_PRIVATE_GCTHING) << JSVAL_TAG_SHIFT)
} JS_ENUM_FOOTER(JSValueShiftedTag);
@@ -140,24 +140,25 @@ static_assert(sizeof(JSValueShiftedTag) == sizeof(uint64_t),
#define JSVAL_TYPE_TO_TAG(type) ((JSValueTag)(JSVAL_TAG_CLEAR | (type)))
-#define JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET JSVAL_TAG_NULL
+#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)))
#define JSVAL_TYPE_TO_SHIFTED_TAG(type) (((uint64_t)JSVAL_TYPE_TO_TAG(type)) << JSVAL_TAG_SHIFT)
-#define JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET JSVAL_TAG_NULL
#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
-#define JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET JSVAL_SHIFTED_TAG_NULL
#define JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET JSVAL_SHIFTED_TAG_OBJECT
#define JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET JSVAL_SHIFTED_TAG_UNDEFINED
#define JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET JSVAL_SHIFTED_TAG_STRING
@@ -537,12 +538,7 @@ class MOZ_NON_PARAM alignas(8) Value
}
bool isObjectOrNull() const {
- MOZ_ASSERT(uint32_t(toTag()) <= uint32_t(JSVAL_TAG_OBJECT));
-#if defined(JS_NUNBOX32)
- return uint32_t(toTag()) >= uint32_t(JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET);
-#elif defined(JS_PUNBOX64)
- return data.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET;
-#endif
+ return isObject() || isNull();
}
bool isGCThing() const {
@@ -575,12 +571,8 @@ class MOZ_NON_PARAM alignas(8) Value
return isMagic();
}
- bool isMarkable() const {
- return isGCThing() && !isNull();
- }
-
JS::TraceKind traceKind() const {
- MOZ_ASSERT(isMarkable());
+ MOZ_ASSERT(isGCThing());
static_assert((JSVAL_TAG_STRING & 0x03) == size_t(JS::TraceKind::String),
"Value type tags must correspond with JS::TraceKinds.");
static_assert((JSVAL_TAG_SYMBOL & 0x03) == size_t(JS::TraceKind::Symbol),
@@ -684,11 +676,6 @@ class MOZ_NON_PARAM alignas(8) Value
#endif
}
- js::gc::Cell* toMarkablePointer() const {
- MOZ_ASSERT(isMarkable());
- return toGCThing();
- }
-
GCCellPtr toGCCellPtr() const {
return GCCellPtr(toGCThing(), traceKind());
}
@@ -760,9 +747,9 @@ class MOZ_NON_PARAM alignas(8) Value
* Private GC Thing API
*
* Non-JSObject, JSString, and JS::Symbol cells may be put into the 64-bit
- * payload as private GC things. Such Values are considered isMarkable()
- * and isGCThing(), and as such, automatically marked. Their traceKind()
- * is gotten via their cells.
+ * payload as private GC things. Such Values are considered isGCThing(), and
+ * as such, automatically marked. Their traceKind() is gotten via their
+ * cells.
*/
void setPrivateGCThing(js::gc::Cell* cell) {
@@ -834,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;
@@ -860,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;
@@ -888,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;
@@ -912,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;
@@ -965,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)
{
@@ -980,7 +1010,7 @@ IsOptimizedPlaceholderMagicValue(const Value& v)
static MOZ_ALWAYS_INLINE void
ExposeValueToActiveJS(const Value& v)
{
- if (v.isMarkable())
+ if (v.isGCThing())
js::gc::ExposeGCThingToActiveJS(GCCellPtr(v));
}
@@ -1298,7 +1328,7 @@ template <>
struct BarrierMethods<JS::Value>
{
static gc::Cell* asGCThingOrNull(const JS::Value& v) {
- return v.isMarkable() ? v.toGCThing() : nullptr;
+ return v.isGCThing() ? v.toGCThing() : nullptr;
}
static void postBarrier(JS::Value* v, const JS::Value& prev, const JS::Value& next) {
JS::HeapValuePostBarrier(v, prev, next);
@@ -1338,9 +1368,8 @@ class ValueOperations
bool isObject() const { return value().isObject(); }
bool isMagic() const { return value().isMagic(); }
bool isMagic(JSWhyMagic why) const { return value().isMagic(why); }
- bool isMarkable() const { return value().isMarkable(); }
- bool isPrimitive() const { return value().isPrimitive(); }
bool isGCThing() const { return value().isGCThing(); }
+ bool isPrimitive() const { return value().isPrimitive(); }
bool isNullOrUndefined() const { return value().isNullOrUndefined(); }
bool isObjectOrNull() const { return value().isObjectOrNull(); }
@@ -1485,7 +1514,7 @@ DispatchTyped(F f, const JS::Value& val, Args&&... args)
return f(val.toSymbol(), mozilla::Forward<Args>(args)...);
if (MOZ_UNLIKELY(val.isPrivateGCThing()))
return DispatchTyped(f, val.toGCCellPtr(), mozilla::Forward<Args>(args)...);
- MOZ_ASSERT(!val.isMarkable());
+ MOZ_ASSERT(!val.isGCThing());
return F::defaultValue(val);
}