mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
[mq]: Refactor value logic for better reuse
This commit is contained in:
parent
a2c395a9dc
commit
f7242c4d3f
230
js/src/jsapi.h
230
js/src/jsapi.h
@ -52,12 +52,12 @@
|
||||
JS_BEGIN_EXTERN_C
|
||||
|
||||
/* Well-known JS values, initialized on startup. */
|
||||
#define JSVAL_NULL JSVAL_CONSTANT(JSVAL_MASK32_NULL, 0)
|
||||
#define JSVAL_ZERO JSVAL_CONSTANT(JSVAL_MASK32_INT32, 0)
|
||||
#define JSVAL_ONE JSVAL_CONSTANT(JSVAL_MASK32_INT32, 1)
|
||||
#define JSVAL_FALSE JSVAL_CONSTANT(JSVAL_MASK32_BOOLEAN, JS_FALSE)
|
||||
#define JSVAL_TRUE JSVAL_CONSTANT(JSVAL_MASK32_BOOLEAN, JS_TRUE)
|
||||
#define JSVAL_VOID JSVAL_CONSTANT(JSVAL_MASK32_UNDEFINED, 0)
|
||||
#define JSVAL_NULL BUILD_JSVAL(JSVAL_MASK32_NULL, 0)
|
||||
#define JSVAL_ZERO BUILD_JSVAL(JSVAL_MASK32_INT32, 0)
|
||||
#define JSVAL_ONE BUILD_JSVAL(JSVAL_MASK32_INT32, 1)
|
||||
#define JSVAL_FALSE BUILD_JSVAL(JSVAL_MASK32_BOOLEAN, JS_FALSE)
|
||||
#define JSVAL_TRUE BUILD_JSVAL(JSVAL_MASK32_BOOLEAN, JS_TRUE)
|
||||
#define JSVAL_VOID BUILD_JSVAL(JSVAL_MASK32_UNDEFINED, 0)
|
||||
|
||||
/* Predicates for type testing. */
|
||||
|
||||
@ -65,14 +65,14 @@ static JS_ALWAYS_INLINE JSBool
|
||||
JSVAL_IS_NULL(jsval v)
|
||||
{
|
||||
jsval_layout l = { v };
|
||||
return l.s.mask32 == JSVAL_MASK32_NULL;
|
||||
return JSVAL_IS_NULL_IMPL(l);
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE JSBool
|
||||
JSVAL_IS_VOID(jsval v)
|
||||
{
|
||||
jsval_layout l = { v };
|
||||
return l.s.mask32 == JSVAL_MASK32_UNDEFINED;
|
||||
return JSVAL_IS_UNDEFINED_IMPL(l);
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE JSBool
|
||||
@ -103,17 +103,14 @@ INT_FITS_IN_JSVAL(jsint i)
|
||||
static JS_ALWAYS_INLINE jsval
|
||||
INT_TO_JSVAL(int32 i)
|
||||
{
|
||||
jsval_layout l;
|
||||
l.s.mask32 = JSVAL_MASK32_INT32;
|
||||
l.s.payload.i32 = i;
|
||||
return l.asBits;
|
||||
return INT32_TO_JSVAL_IMPL(i).asBits;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE JSBool
|
||||
JSVAL_IS_DOUBLE(jsval v)
|
||||
{
|
||||
jsval_layout l = { v };
|
||||
return l.s.mask32 < JSVAL_MASK32_CLEAR;
|
||||
return JSVAL_IS_DOUBLE_IMPL(l);
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE jsdouble
|
||||
@ -127,16 +124,14 @@ JSVAL_TO_DOUBLE(jsval v)
|
||||
static JS_ALWAYS_INLINE jsval
|
||||
DOUBLE_TO_JSVAL(jsdouble d)
|
||||
{
|
||||
jsval_layout l;
|
||||
l.asDouble = d;
|
||||
JS_ASSERT(l.s.tag.nanBits != JSVAL_NANBOX_PATTERN);
|
||||
return l.asBits;
|
||||
return DOUBLE_TO_JSVAL_IMPL(d).asBits;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE JSBool
|
||||
JSVAL_IS_NUMBER(jsval v)
|
||||
{
|
||||
return JSVAL_IS_INT(v) | JSVAL_IS_DOUBLE(v);
|
||||
jsval_layout l = { v };
|
||||
return JSVAL_IS_NUMBER_IMPL(l);
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE JSBool
|
||||
@ -151,30 +146,20 @@ JSVAL_TO_STRING(jsval v)
|
||||
{
|
||||
JS_ASSERT(JSVAL_IS_STRING(v));
|
||||
jsval_layout l = { v };
|
||||
return l.s.payload.str;
|
||||
return JSVAL_TO_STRING_IMPL(l);
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE jsval
|
||||
STRING_TO_JSVAL(JSString *str)
|
||||
{
|
||||
jsval_layout l;
|
||||
l.s.mask32 = JSVAL_MASK32_STRING;
|
||||
l.s.payload.str = str;
|
||||
return l.asBits;
|
||||
return STRING_TO_JSVAL_IMPL(str).asBits;
|
||||
}
|
||||
|
||||
/*
|
||||
* N.B. These functions use the older meaning of "object" as "object or null".
|
||||
* This is not a problem if code only works with jsvals or only works with
|
||||
* js::Value, but if both uses are mixed, it is important not to get confused
|
||||
* by the two meanings. For example, JSVAL_IS_OBJECT(v) does not imply
|
||||
* v.isObject().
|
||||
*/
|
||||
static JS_ALWAYS_INLINE JSBool
|
||||
JSVAL_IS_OBJECT(jsval v)
|
||||
{
|
||||
jsval_layout l = { v };
|
||||
return (l.s.mask32 & JSVAL_MASK32_OBJORNULL) > JSVAL_MASK32_CLEAR;
|
||||
return JSVAL_IS_OBJECT_OR_NULL_IMPL(l);
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE JSObject *
|
||||
@ -182,9 +167,10 @@ JSVAL_TO_OBJECT(jsval v)
|
||||
{
|
||||
JS_ASSERT(JSVAL_IS_OBJECT(v));
|
||||
jsval_layout l = { v };
|
||||
return l.s.payload.obj;
|
||||
return JSVAL_TO_OBJECT_IMPL(l);
|
||||
}
|
||||
|
||||
/* N.B. Not cheap; uses public API instead of obj->isFunction()! */
|
||||
static JS_ALWAYS_INLINE jsval
|
||||
OBJECT_TO_JSVAL(JSObject *obj)
|
||||
{
|
||||
@ -193,12 +179,10 @@ OBJECT_TO_JSVAL(JSObject *obj)
|
||||
|
||||
if (!obj)
|
||||
return JSVAL_NULL;
|
||||
uint32 mask = JS_ObjectIsFunction(NULL, obj) ? JSVAL_MASK32_FUNOBJ
|
||||
: JSVAL_MASK32_NONFUNOBJ;
|
||||
jsval_layout l;
|
||||
l.s.mask32 = mask;
|
||||
l.s.payload.obj = obj;
|
||||
return l.asBits;
|
||||
|
||||
JSValueMask32 mask = JS_ObjectIsFunction(NULL, obj) ? JSVAL_MASK32_FUNOBJ
|
||||
: JSVAL_MASK32_NONFUNOBJ;
|
||||
return OBJECT_TO_JSVAL_IMPL(mask, obj).asBits;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE JSBool
|
||||
@ -219,24 +203,21 @@ JSVAL_TO_BOOLEAN(jsval v)
|
||||
static JS_ALWAYS_INLINE jsval
|
||||
BOOLEAN_TO_JSVAL(JSBool b)
|
||||
{
|
||||
jsval_layout l;
|
||||
l.s.mask32 = JSVAL_MASK32_BOOLEAN;
|
||||
l.s.payload.boo = b;
|
||||
return l.asBits;
|
||||
return BOOLEAN_TO_JSVAL_IMPL(b).asBits;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE JSBool
|
||||
JSVAL_IS_PRIMITIVE(jsval v)
|
||||
{
|
||||
jsval_layout l = { v };
|
||||
return (l.s.mask32 & JSVAL_MASK32_OBJECT) <= JSVAL_MASK32_CLEAR;
|
||||
return JSVAL_IS_PRIMITIVE_IMPL(l);
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE JSBool
|
||||
JSVAL_IS_GCTHING(jsval v)
|
||||
{
|
||||
jsval_layout l = { v };
|
||||
return (l.s.mask32 & JSVAL_MASK32_GCTHING) > JSVAL_MASK32_CLEAR;
|
||||
return JSVAL_IS_GCTHING_IMPL(l);
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE void *
|
||||
@ -244,24 +225,23 @@ JSVAL_TO_GCTHING(jsval v)
|
||||
{
|
||||
JS_ASSERT(JSVAL_IS_GCTHING(v));
|
||||
jsval_layout l = { v };
|
||||
return l.s.payload.ptr;
|
||||
return JSVAL_TO_GCTHING_IMPL(l);
|
||||
}
|
||||
|
||||
/* To be GC-safe, privates are tagged as doubles. */
|
||||
|
||||
static JS_ALWAYS_INLINE jsval
|
||||
PRIVATE_TO_JSVAL(void *ptr)
|
||||
{
|
||||
jsval_layout l;
|
||||
l.s.mask32 = JSVAL_MASK32_INT32;
|
||||
l.s.payload.ptr = ptr;
|
||||
return l.asBits;
|
||||
return PRIVATE_TO_JSVAL_IMPL(ptr).asBits;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE void *
|
||||
JSVAL_TO_PRIVATE(jsval v)
|
||||
{
|
||||
JS_ASSERT(JSVAL_IS_INT(v));
|
||||
JS_ASSERT(JSVAL_IS_DOUBLE(v));
|
||||
jsval_layout l = { v };
|
||||
return l.s.payload.ptr;
|
||||
return JSVAL_TO_PRIVATE_IMPL(l);
|
||||
}
|
||||
|
||||
/* Lock and unlock the GC thing held by a jsval. */
|
||||
@ -1187,7 +1167,7 @@ JSVAL_TRACE_KIND(jsval v)
|
||||
{
|
||||
JS_ASSERT(JSVAL_IS_GCTHING(v));
|
||||
jsval_layout l = { v };
|
||||
return (uint32)(l.s.mask32 == JSVAL_MASK32_STRING);
|
||||
return JSVAL_TRACE_KIND_IMPL(l);
|
||||
}
|
||||
|
||||
struct JSTracer {
|
||||
@ -3007,44 +2987,26 @@ class Value
|
||||
* break this encapsulation should be listed as friends below. Also see
|
||||
* uses of public jsval members in jsapi.h/jspubtd.h.
|
||||
*/
|
||||
friend bool StrictlyEqual(JSContext *, const Value &, const Value &);
|
||||
friend bool Interpret(JSContext *); /* grep "value representation" */
|
||||
friend class PrimitiveValue;
|
||||
|
||||
protected:
|
||||
/* Type masks */
|
||||
|
||||
template <int I> class T {};
|
||||
|
||||
void staticAssertions() {
|
||||
JS_STATIC_ASSERT(sizeof(void *) == 4);
|
||||
JS_STATIC_ASSERT(sizeof(jsval) == 8);
|
||||
JS_STATIC_ASSERT(sizeof(JSBool) == 4);
|
||||
JS_STATIC_ASSERT(sizeof(JSValueMask16) == 2);
|
||||
JS_STATIC_ASSERT(sizeof(jsval_payload) == 4);
|
||||
JS_STATIC_ASSERT(JSVAL_NANBOX_PATTERN == 0xFFFF);
|
||||
JS_STATIC_ASSERT(sizeof(JSValueMask32) == 4);
|
||||
JS_STATIC_ASSERT(JSVAL_MASK32_CLEAR == 0xFFFF0000);
|
||||
JS_STATIC_ASSERT(sizeof(JSBool) == 4);
|
||||
JS_STATIC_ASSERT(sizeof(JSWhyMagic) <= 4);
|
||||
JS_STATIC_ASSERT(sizeof(((jsval_layout *)0)->s.payload) == 4);
|
||||
JS_STATIC_ASSERT(sizeof(jsval) == 8);
|
||||
}
|
||||
|
||||
jsval_layout data;
|
||||
|
||||
static bool isNullOrUndefinedMask(uint32 mask) {
|
||||
return (mask & JSVAL_MASK32_SINGLETON) > JSVAL_MASK32_CLEAR;
|
||||
}
|
||||
|
||||
static bool isDoubleMask(uint32 mask) {
|
||||
return mask < JSVAL_MASK32_CLEAR;
|
||||
}
|
||||
|
||||
static bool isNumberMask(uint32 mask) {
|
||||
return (mask < JSVAL_MASK32_CLEAR) | (mask == JSVAL_MASK32_INT32);
|
||||
}
|
||||
|
||||
static bool isObjectMask(uint32 mask) {
|
||||
return (mask & JSVAL_MASK32_OBJECT) > JSVAL_MASK32_CLEAR;
|
||||
}
|
||||
|
||||
static bool isObjectOrNullMask(uint32 mask) {
|
||||
return (mask & JSVAL_MASK32_OBJORNULL) > JSVAL_MASK32_CLEAR;
|
||||
}
|
||||
|
||||
public:
|
||||
/* Constructors */
|
||||
|
||||
@ -3075,18 +3037,15 @@ class Value
|
||||
/* Change to a Value of a single type */
|
||||
|
||||
void setNull() {
|
||||
data.s.mask32 = JSVAL_MASK32_NULL;
|
||||
data.s.payload.obj = NULL;
|
||||
data.asBits = JSVAL_NULL;
|
||||
}
|
||||
|
||||
void setUndefined() {
|
||||
data.s.mask32 = JSVAL_MASK32_UNDEFINED;
|
||||
data.s.payload.obj = NULL;
|
||||
data.asBits = JSVAL_VOID;
|
||||
}
|
||||
|
||||
void setInt32(int32 i) {
|
||||
data.s.mask32 = JSVAL_MASK32_INT32;
|
||||
data.s.payload.i32 = i;
|
||||
data = INT32_TO_JSVAL_IMPL(i);
|
||||
}
|
||||
|
||||
int32 &asInt32Ref() {
|
||||
@ -3096,8 +3055,7 @@ class Value
|
||||
|
||||
void setDouble(double d) {
|
||||
ASSERT_DOUBLE_ALIGN();
|
||||
data.asDouble = d;
|
||||
JS_ASSERT(data.s.tag.nanBits != JSVAL_NANBOX_PATTERN);
|
||||
data = DOUBLE_TO_JSVAL_IMPL(d);
|
||||
}
|
||||
|
||||
double &asDoubleRef() {
|
||||
@ -3107,62 +3065,54 @@ class Value
|
||||
}
|
||||
|
||||
void setString(JSString *str) {
|
||||
data.s.mask32 = JSVAL_MASK32_STRING;
|
||||
data.s.payload.str = str;
|
||||
data = STRING_TO_JSVAL_IMPL(str);
|
||||
}
|
||||
|
||||
void setFunObj(JSObject &arg) {
|
||||
JS_ASSERT(JS_ObjectIsFunction(NULL, &arg));
|
||||
data.s.mask32 = JSVAL_MASK32_FUNOBJ;
|
||||
data.s.payload.obj = &arg;
|
||||
data = OBJECT_TO_JSVAL_IMPL(JSVAL_MASK32_FUNOBJ, &arg);
|
||||
}
|
||||
|
||||
void setNonFunObj(JSObject &arg) {
|
||||
JS_ASSERT(!JS_ObjectIsFunction(NULL, &arg));
|
||||
data.s.mask32 = JSVAL_MASK32_NONFUNOBJ;
|
||||
data.s.payload.obj = &arg;
|
||||
data = OBJECT_TO_JSVAL_IMPL(JSVAL_MASK32_NONFUNOBJ, &arg);
|
||||
}
|
||||
|
||||
void setBoolean(bool b) {
|
||||
data.s.mask32 = JSVAL_MASK32_BOOLEAN;
|
||||
data.s.payload.boo = b;
|
||||
data = BOOLEAN_TO_JSVAL_IMPL(b);
|
||||
}
|
||||
|
||||
void setMagic(JSWhyMagic why) {
|
||||
data.s.mask32 = JSVAL_MASK32_MAGIC;
|
||||
data.s.payload.why = why;
|
||||
data = MAGIC_TO_JSVAL_IMPL(why);
|
||||
}
|
||||
|
||||
/* Change to a Value of a type dynamically chosen from a set of types */
|
||||
|
||||
void setNumber(uint32 ui) {
|
||||
if (ui > JSVAL_INT_MAX) {
|
||||
data.asDouble = ui;
|
||||
JS_ASSERT(data.s.tag.nanBits != JSVAL_NANBOX_PATTERN);
|
||||
} else {
|
||||
data.s.mask32 = JSVAL_MASK32_INT32;
|
||||
data.s.payload.i32 = (int32)ui;
|
||||
}
|
||||
if (ui > JSVAL_INT_MAX)
|
||||
data = DOUBLE_TO_JSVAL_IMPL(ui);
|
||||
else
|
||||
data = INT32_TO_JSVAL_IMPL((int32)ui);
|
||||
}
|
||||
|
||||
inline void setNumber(double d);
|
||||
|
||||
void setFunObjOrNull(JSObject *arg) {
|
||||
JS_ASSERT_IF(arg, JS_ObjectIsFunction(NULL, arg));
|
||||
data.s.mask32 = arg ? JSVAL_MASK32_FUNOBJ : JSVAL_MASK32_NULL;
|
||||
data.s.payload.obj = arg;
|
||||
JSValueMask32 mask = arg ? JSVAL_MASK32_FUNOBJ : JSVAL_MASK32_NULL;
|
||||
data = OBJECT_TO_JSVAL_IMPL(mask, arg);
|
||||
}
|
||||
|
||||
void setFunObjOrUndefined(JSObject *arg) {
|
||||
JS_ASSERT_IF(arg, JS_ObjectIsFunction(NULL, arg));
|
||||
data.s.mask32 = arg ? JSVAL_MASK32_FUNOBJ : JSVAL_MASK32_UNDEFINED;
|
||||
data.s.payload.obj = arg;
|
||||
JSValueMask32 mask = arg ? JSVAL_MASK32_FUNOBJ : JSVAL_MASK32_UNDEFINED;
|
||||
data = OBJECT_TO_JSVAL_IMPL(mask, arg);
|
||||
}
|
||||
|
||||
void setNonFunObjOrNull(JSObject *arg) {
|
||||
JS_ASSERT_IF(arg, !JS_ObjectIsFunction(NULL, arg));
|
||||
data.s.mask32 = arg ? JSVAL_MASK32_NONFUNOBJ : JSVAL_MASK32_NULL;
|
||||
data.s.payload.obj = arg;
|
||||
JSValueMask32 mask = arg ? JSVAL_MASK32_NONFUNOBJ : JSVAL_MASK32_NULL;
|
||||
data = OBJECT_TO_JSVAL_IMPL(mask, arg);
|
||||
}
|
||||
|
||||
inline void setObject(JSObject &arg);
|
||||
@ -3171,15 +3121,15 @@ class Value
|
||||
/* Query a Value's type */
|
||||
|
||||
bool isUndefined() const {
|
||||
return data.s.mask32 == JSVAL_MASK32_UNDEFINED;
|
||||
return JSVAL_IS_UNDEFINED_IMPL(data);
|
||||
}
|
||||
|
||||
bool isNull() const {
|
||||
return data.s.mask32 == JSVAL_MASK32_NULL;
|
||||
return JSVAL_IS_NULL_IMPL(data);
|
||||
}
|
||||
|
||||
bool isNullOrUndefined() const {
|
||||
return isNullOrUndefinedMask(data.s.mask32);
|
||||
return JSVAL_IS_SINGLETON_IMPL(data);
|
||||
}
|
||||
|
||||
bool isInt32() const {
|
||||
@ -3187,16 +3137,15 @@ class Value
|
||||
}
|
||||
|
||||
bool isInt32(int32 i32) const {
|
||||
return (data.s.mask32 == JSVAL_MASK32_INT32) &
|
||||
(data.s.payload.i32 == i32);
|
||||
return JSVAL_IS_SPECIFIC_INT32_IMPL(data, i32);
|
||||
}
|
||||
|
||||
bool isDouble() const {
|
||||
return isDoubleMask(data.s.mask32);
|
||||
return JSVAL_IS_DOUBLE_IMPL(data);
|
||||
}
|
||||
|
||||
bool isNumber() const {
|
||||
return isNumberMask(data.s.mask32);
|
||||
return JSVAL_IS_NUMBER_IMPL(data);
|
||||
}
|
||||
|
||||
bool isString() const {
|
||||
@ -3212,19 +3161,19 @@ class Value
|
||||
}
|
||||
|
||||
bool isObject() const {
|
||||
return isObjectMask(data.s.mask32);
|
||||
return JSVAL_IS_OBJECT_IMPL(data);
|
||||
}
|
||||
|
||||
bool isPrimitive() const {
|
||||
return !isObject();
|
||||
return JSVAL_IS_PRIMITIVE_IMPL(data);
|
||||
}
|
||||
|
||||
bool isObjectOrNull() const {
|
||||
return isObjectOrNullMask(data.s.mask32);
|
||||
return JSVAL_IS_OBJECT_OR_NULL_IMPL(data);
|
||||
}
|
||||
|
||||
bool isGCThing() const {
|
||||
return (data.s.mask32 & JSVAL_MASK32_GCTHING) > JSVAL_MASK32_CLEAR;
|
||||
return JSVAL_IS_GCTHING_IMPL(data);
|
||||
}
|
||||
|
||||
bool isBoolean() const {
|
||||
@ -3232,13 +3181,11 @@ class Value
|
||||
}
|
||||
|
||||
bool isTrue() const {
|
||||
return data.s.mask32 == JSVAL_MASK32_BOOLEAN &&
|
||||
data.s.payload.boo == JS_TRUE;
|
||||
return JSVAL_IS_SPECIFIC_BOOLEAN(data, true);
|
||||
}
|
||||
|
||||
bool isFalse() const {
|
||||
return data.s.mask32 == JSVAL_MASK32_BOOLEAN &&
|
||||
data.s.payload.boo == JS_FALSE;
|
||||
return JSVAL_IS_SPECIFIC_BOOLEAN(data, false);
|
||||
}
|
||||
|
||||
bool isMagic() const {
|
||||
@ -3252,13 +3199,17 @@ class Value
|
||||
|
||||
int32 traceKind() const {
|
||||
JS_ASSERT(isGCThing());
|
||||
return (int32)(data.s.mask32 == JSVAL_MASK32_STRING);
|
||||
return JSVAL_TRACE_KIND_IMPL(data);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
JSWhyMagic whyMagic() const {
|
||||
JS_ASSERT(isMagic());
|
||||
return data.s.payload.why;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Comparison */
|
||||
|
||||
bool operator==(const Value &rhs) const {
|
||||
return data.asBits == rhs.data.asBits;
|
||||
@ -3268,6 +3219,18 @@ class Value
|
||||
return data.asBits != rhs.data.asBits;
|
||||
}
|
||||
|
||||
friend bool SamePrimitiveTypeOrBothObjects(const Value &lhs, const Value &rhs) {
|
||||
return JSVAL_SAME_PRIMITIVE_TYPE_OR_BOTH_OBJECTS_IMPL(lhs.data, rhs.data);
|
||||
}
|
||||
|
||||
friend bool BothInt32(const Value &lhs, const Value &rhs) {
|
||||
return JSVAL_BOTH_INT32_IMPL(lhs.data, rhs.data);
|
||||
}
|
||||
|
||||
friend bool BothString(const Value &lhs, const Value &rhs) {
|
||||
return JSVAL_BOTH_STRING_IMPL(lhs.data, rhs.data);
|
||||
}
|
||||
|
||||
/* Extract a Value's payload */
|
||||
|
||||
int32 asInt32() const {
|
||||
@ -3288,32 +3251,32 @@ class Value
|
||||
|
||||
JSString *asString() const {
|
||||
JS_ASSERT(isString());
|
||||
return data.s.payload.str;
|
||||
return JSVAL_TO_STRING_IMPL(data);
|
||||
}
|
||||
|
||||
JSObject &asNonFunObj() const {
|
||||
JS_ASSERT(isNonFunObj());
|
||||
return *data.s.payload.obj;
|
||||
return *JSVAL_TO_OBJECT_IMPL(data);
|
||||
}
|
||||
|
||||
JSObject &asFunObj() const {
|
||||
JS_ASSERT(isFunObj());
|
||||
return *data.s.payload.obj;
|
||||
return *JSVAL_TO_OBJECT_IMPL(data);
|
||||
}
|
||||
|
||||
JSObject &asObject() const {
|
||||
JS_ASSERT(isObject());
|
||||
return *data.s.payload.obj;
|
||||
return *JSVAL_TO_OBJECT_IMPL(data);
|
||||
}
|
||||
|
||||
JSObject *asObjectOrNull() const {
|
||||
JS_ASSERT(isObjectOrNull());
|
||||
return data.s.payload.obj;
|
||||
return JSVAL_TO_OBJECT_IMPL(data);
|
||||
}
|
||||
|
||||
void *asGCThing() const {
|
||||
JS_ASSERT(isGCThing());
|
||||
return data.s.payload.ptr;
|
||||
return JSVAL_TO_GCTHING_IMPL(data);
|
||||
}
|
||||
|
||||
bool asBoolean() const {
|
||||
@ -3321,6 +3284,11 @@ class Value
|
||||
return data.s.payload.boo;
|
||||
}
|
||||
|
||||
uint32 asRawUint32() const {
|
||||
JS_ASSERT(!isDouble());
|
||||
return data.s.payload.u32;
|
||||
}
|
||||
|
||||
/* Swap two Values */
|
||||
|
||||
void swap(Value &rhs) {
|
||||
|
@ -385,8 +385,7 @@ NoSuchMethod(JSContext *cx, uintN argc, Value *vp, uint32 flags)
|
||||
|
||||
namespace js {
|
||||
|
||||
static const uint32 FAKE_NUMBER_MASK = JSVAL_MASK32_INT32 |
|
||||
PrimitiveValue::DOUBLE_MASK;
|
||||
static const uint32 FAKE_NUMBER_MASK = JSVAL_MASK32_INT32 | PrimitiveValue::DOUBLE_MASK;
|
||||
|
||||
const uint32 PrimitiveValue::Masks[PrimitiveValue::THISP_ARRAY_SIZE] = {
|
||||
0, /* 000 */
|
||||
@ -952,36 +951,29 @@ EqualObjects(JSContext *cx, JSObject *lobj, JSObject *robj)
|
||||
}
|
||||
|
||||
bool
|
||||
StrictlyEqual(JSContext *cx, const Value &lval, const Value &rval)
|
||||
StrictlyEqual(JSContext *cx, const Value &lref, const Value &rref)
|
||||
{
|
||||
uint32 lmask = lval.data.s.mask32;
|
||||
uint32 rmask = rval.data.s.mask32;
|
||||
if (lmask == rmask) {
|
||||
if (lmask == JSVAL_MASK32_STRING)
|
||||
return js_EqualStrings(lval.data.s.payload.str, rval.data.s.payload.str);
|
||||
if (Value::isObjectMask(lmask))
|
||||
return EqualObjects(cx, lval.data.s.payload.obj, rval.data.s.payload.obj);
|
||||
if (Value::isDoubleMask(lmask))
|
||||
return JSDOUBLE_COMPARE(lval.data.asDouble, ==, rval.data.asDouble, JS_FALSE);
|
||||
JS_ASSERT(lmask == JSVAL_MASK32_NULL ||
|
||||
lmask == JSVAL_MASK32_UNDEFINED ||
|
||||
lmask == JSVAL_MASK32_INT32 ||
|
||||
lmask == JSVAL_MASK32_FUNOBJ ||
|
||||
lmask == JSVAL_MASK32_NONFUNOBJ ||
|
||||
lmask == JSVAL_MASK32_BOOLEAN);
|
||||
return lval.data.s.payload.u32 == rval.data.s.payload.u32;
|
||||
Value lval = lref, rval = rref;
|
||||
if (SamePrimitiveTypeOrBothObjects(lval, rval)) {
|
||||
if (lval.isString())
|
||||
return js_EqualStrings(lval.asString(), rval.asString());
|
||||
if (lval.isDouble())
|
||||
return JSDOUBLE_COMPARE(lval.asDouble(), ==, rval.asDouble(), JS_FALSE);
|
||||
if (lval.isObject())
|
||||
return EqualObjects(cx, &lval.asObject(), &rval.asObject());
|
||||
return lval.asRawUint32() == rval.asRawUint32();
|
||||
}
|
||||
|
||||
if (Value::isNumberMask(lmask) && Value::isNumberMask(rmask)) {
|
||||
double ld = lmask == JSVAL_MASK32_INT32 ? lval.data.s.payload.i32
|
||||
: lval.data.asDouble;
|
||||
double rd = rmask == JSVAL_MASK32_INT32 ? rval.data.s.payload.i32
|
||||
: rval.data.asDouble;
|
||||
if (lval.isDouble() && rval.isInt32()) {
|
||||
double ld = lval.asDouble();
|
||||
double rd = rval.asInt32();
|
||||
return JSDOUBLE_COMPARE(ld, ==, rd, JS_FALSE);
|
||||
}
|
||||
if (lval.isInt32() && rval.isDouble()) {
|
||||
double ld = lval.asInt32();
|
||||
double rd = rval.asDouble();
|
||||
return JSDOUBLE_COMPARE(ld, ==, rd, JS_FALSE);
|
||||
}
|
||||
|
||||
if (Value::isObjectMask(lmask) && Value::isObjectMask(rmask))
|
||||
return EqualObjects(cx, lval.data.s.payload.obj, rval.data.s.payload.obj);
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -1787,6 +1779,15 @@ namespace reprmeter {
|
||||
VALUE_TO_OBJECT(cx, vp_, obj); \
|
||||
JS_END_MACRO
|
||||
|
||||
#define DEFAULT_VALUE(cx, n, hint, v) \
|
||||
JS_BEGIN_MACRO \
|
||||
JS_ASSERT(v.isObject()); \
|
||||
JS_ASSERT(v == regs.sp[n]); \
|
||||
if (!v.asObject().defaultValue(cx, hint, ®s.sp[n])) \
|
||||
goto error; \
|
||||
v = regs.sp[n]; \
|
||||
JS_END_MACRO
|
||||
|
||||
/* Test whether v is an int in the range [-2^31 + 1, 2^31 - 2] */
|
||||
static JS_ALWAYS_INLINE bool
|
||||
CanIncDecWithoutOverflow(int32_t i)
|
||||
|
@ -283,7 +283,7 @@ class PrimitiveValue
|
||||
static const uint32 Masks[THISP_ARRAY_SIZE];
|
||||
|
||||
public:
|
||||
static const uint32 DOUBLE_MASK = 0x8000;
|
||||
static const uint32 DOUBLE_MASK = 0xFFFF8000;
|
||||
|
||||
static bool test(JSFunction *fun, const Value &v) {
|
||||
uint32 mask = Masks[(fun->flags >> THISP_SHIFT) & THISP_MASK];
|
||||
|
178
js/src/jsops.cpp
178
js/src/jsops.cpp
@ -816,9 +816,9 @@ END_CASE(JSOP_BITAND)
|
||||
*/
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
#define XML_EQUALITY_OP(OP) \
|
||||
if ((lmask == JSVAL_MASK32_NONFUNOBJ && lref.asObject().isXML()) || \
|
||||
(rmask == JSVAL_MASK32_NONFUNOBJ && rref.asObject().isXML())) { \
|
||||
if (!js_TestXMLEquality(cx, lref, rref, &cond)) \
|
||||
if ((lval.isNonFunObj() && lval.asObject().isXML()) || \
|
||||
(rval.isNonFunObj() && rval.asObject().isXML())) { \
|
||||
if (!js_TestXMLEquality(cx, lval, rval, &cond)) \
|
||||
goto error; \
|
||||
cond = cond OP JS_TRUE; \
|
||||
} else
|
||||
@ -826,7 +826,7 @@ END_CASE(JSOP_BITAND)
|
||||
#define EXTENDED_EQUALITY_OP(OP) \
|
||||
if (((clasp = l->getClass())->flags & JSCLASS_IS_EXTENDED) && \
|
||||
((ExtendedClass *)clasp)->equality) { \
|
||||
if (!((ExtendedClass *)clasp)->equality(cx, l, &rref, &cond)) \
|
||||
if (!((ExtendedClass *)clasp)->equality(cx, l, &lval, &cond)) \
|
||||
goto error; \
|
||||
cond = cond OP JS_TRUE; \
|
||||
} else
|
||||
@ -837,57 +837,42 @@ END_CASE(JSOP_BITAND)
|
||||
|
||||
#define EQUALITY_OP(OP, IFNAN) \
|
||||
JS_BEGIN_MACRO \
|
||||
/* Depends on the value representation. */ \
|
||||
Class *clasp; \
|
||||
JSBool cond; \
|
||||
Value &rref = regs.sp[-1]; \
|
||||
Value &lref = regs.sp[-2]; \
|
||||
uint32 rmask = rref.data.s.mask32; \
|
||||
uint32 lmask = lref.data.s.mask32; \
|
||||
Value rval = regs.sp[-1]; \
|
||||
Value lval = regs.sp[-2]; \
|
||||
XML_EQUALITY_OP(OP) \
|
||||
if (lmask == rmask || \
|
||||
(Value::isObjectMask(lmask) && Value::isObjectMask(rmask))) { \
|
||||
if (lmask == JSVAL_MASK32_STRING) { \
|
||||
JSString *l = lref.asString(), *r = rref.asString(); \
|
||||
if (SamePrimitiveTypeOrBothObjects(lval, rval)) { \
|
||||
if (lval.isString()) { \
|
||||
JSString *l = lval.asString(), *r = rval.asString(); \
|
||||
cond = js_EqualStrings(l, r) OP JS_TRUE; \
|
||||
} else if (Value::isObjectMask(lmask)) { \
|
||||
JSObject *l = &lref.asObject(), *r = &rref.asObject(); \
|
||||
} else if (lval.isDouble()) { \
|
||||
double l = lval.asDouble(), r = rval.asDouble(); \
|
||||
cond = JSDOUBLE_COMPARE(l, OP, r, IFNAN); \
|
||||
} else if (lval.isObject()) { \
|
||||
JSObject *l = &lval.asObject(), *r = &rval.asObject(); \
|
||||
EXTENDED_EQUALITY_OP(OP) \
|
||||
cond = l OP r; \
|
||||
} else if (JS_UNLIKELY(Value::isDoubleMask(lmask))) { \
|
||||
double l = lref.asDouble(), r = rref.asDouble(); \
|
||||
cond = JSDOUBLE_COMPARE(l, OP, r, IFNAN); \
|
||||
} else { \
|
||||
cond = lref.data.s.payload.u32 OP rref.data.s.payload.u32; \
|
||||
cond = lval.asRawUint32() OP rval.asRawUint32(); \
|
||||
} \
|
||||
} else if (Value::isDoubleMask(lmask) && Value::isDoubleMask(rmask)) { \
|
||||
double l = lref.asDouble(), r = rref.asDouble(); \
|
||||
cond = JSDOUBLE_COMPARE(l, OP, r, IFNAN); \
|
||||
} else { \
|
||||
if (Value::isNullOrUndefinedMask(lmask)) { \
|
||||
cond = Value::isNullOrUndefinedMask(rmask) OP true; \
|
||||
} else if (Value::isNullOrUndefinedMask(rmask)) { \
|
||||
if (lval.isNullOrUndefined()) { \
|
||||
cond = rval.isNullOrUndefined() OP true; \
|
||||
} else if (rval.isNullOrUndefined()) { \
|
||||
cond = true OP false; \
|
||||
} else { \
|
||||
if (Value::isObjectMask(lmask)) { \
|
||||
JSObject &obj = lref.asObject(); \
|
||||
if (!obj.defaultValue(cx, JSTYPE_VOID, &lref)) \
|
||||
goto error; \
|
||||
lmask = lref.data.s.mask32; \
|
||||
} \
|
||||
if (Value::isObjectMask(rmask)) { \
|
||||
JSObject &obj = rref.asObject(); \
|
||||
if (!obj.defaultValue(cx, JSTYPE_VOID, &rref)) \
|
||||
goto error; \
|
||||
rmask = rref.data.s.mask32; \
|
||||
} \
|
||||
if (lmask == JSVAL_MASK32_STRING && rmask == JSVAL_MASK32_STRING) { \
|
||||
JSString *l = lref.asString(), *r = rref.asString(); \
|
||||
if (lval.isObject()) \
|
||||
DEFAULT_VALUE(cx, -2, JSTYPE_VOID, lval); \
|
||||
if (rval.isObject()) \
|
||||
DEFAULT_VALUE(cx, -1, JSTYPE_VOID, rval); \
|
||||
if (BothString(lval, rval)) { \
|
||||
JSString *l = lval.asString(), *r = rval.asString(); \
|
||||
cond = js_EqualStrings(l, r) OP JS_TRUE; \
|
||||
} else { \
|
||||
double l, r; \
|
||||
if (!ValueToNumber(cx, lref, &l) || \
|
||||
!ValueToNumber(cx, rref, &r)) { \
|
||||
if (!ValueToNumber(cx, lval, &l) || \
|
||||
!ValueToNumber(cx, rval, &r)) { \
|
||||
goto error; \
|
||||
} \
|
||||
cond = JSDOUBLE_COMPARE(l, OP, r, IFNAN); \
|
||||
@ -963,39 +948,24 @@ END_CASE(JSOP_CASEX)
|
||||
|
||||
#define RELATIONAL_OP(OP) \
|
||||
JS_BEGIN_MACRO \
|
||||
/* Depends on the value representation */ \
|
||||
Value &rref = regs.sp[-1]; \
|
||||
Value &lref = regs.sp[-2]; \
|
||||
uint32 rmask = rref.data.s.mask32; \
|
||||
uint32 lmask = lref.data.s.mask32; \
|
||||
uint32 maskand = lmask & rmask; \
|
||||
Value rval = regs.sp[-1]; \
|
||||
Value lval = regs.sp[-2]; \
|
||||
bool cond; \
|
||||
/* Optimize for two int-tagged operands (typical loop control). */ \
|
||||
if (maskand == JSVAL_MASK32_INT32) { \
|
||||
cond = lref.asInt32() OP rref.asInt32(); \
|
||||
if (BothInt32(lval, rval)) { \
|
||||
cond = lval.asInt32() OP rval.asInt32(); \
|
||||
} else { \
|
||||
if (Value::isObjectMask(lmask | rmask)) { \
|
||||
if (Value::isObjectMask(lmask)) { \
|
||||
JSObject &obj = lref.asObject(); \
|
||||
if (!obj.defaultValue(cx, JSTYPE_NUMBER, &lref)) \
|
||||
goto error; \
|
||||
lmask = lref.data.s.mask32; \
|
||||
} \
|
||||
if (Value::isObjectMask(rmask)) { \
|
||||
JSObject &obj = rref.asObject(); \
|
||||
if (!obj.defaultValue(cx, JSTYPE_NUMBER, &rref)) \
|
||||
goto error; \
|
||||
rmask = rref.data.s.mask32; \
|
||||
} \
|
||||
maskand = lmask & rmask; \
|
||||
} \
|
||||
if (maskand == JSVAL_MASK32_STRING) { \
|
||||
JSString *l = lref.asString(), *r = rref.asString(); \
|
||||
if (lval.isObject()) \
|
||||
DEFAULT_VALUE(cx, -2, JSTYPE_NUMBER, lval); \
|
||||
if (rval.isObject()) \
|
||||
DEFAULT_VALUE(cx, -1, JSTYPE_NUMBER, rval); \
|
||||
if (BothString(lval, rval)) { \
|
||||
JSString *l = lval.asString(), *r = rval.asString(); \
|
||||
cond = js_CompareStrings(l, r) OP 0; \
|
||||
} else { \
|
||||
double l, r; \
|
||||
if (!ValueToNumber(cx, lref, &l) || \
|
||||
!ValueToNumber(cx, rref, &r)) { \
|
||||
if (!ValueToNumber(cx, lval, &l) || \
|
||||
!ValueToNumber(cx, rval, &r)) { \
|
||||
goto error; \
|
||||
} \
|
||||
cond = JSDOUBLE_COMPARE(l, OP, r, false); \
|
||||
@ -1064,14 +1034,11 @@ END_CASE(JSOP_URSH)
|
||||
|
||||
BEGIN_CASE(JSOP_ADD)
|
||||
{
|
||||
/* Depends on the value representation */
|
||||
Value &rref = regs.sp[-1];
|
||||
Value &lref = regs.sp[-2];
|
||||
uint32 rmask = rref.data.s.mask32;
|
||||
uint32 lmask = lref.data.s.mask32;
|
||||
Value rval = regs.sp[-1];
|
||||
Value lval = regs.sp[-2];
|
||||
|
||||
if ((lmask & rmask) == JSVAL_MASK32_INT32) {
|
||||
int32_t l = lref.asInt32(), r = rref.asInt32();
|
||||
if (BothInt32(lval, rval)) {
|
||||
int32_t l = lval.asInt32(), r = rval.asInt32();
|
||||
int32_t sum = l + r;
|
||||
regs.sp--;
|
||||
if (JS_UNLIKELY(bool((l ^ sum) & (r ^ sum) & 0x80000000)))
|
||||
@ -1080,50 +1047,47 @@ BEGIN_CASE(JSOP_ADD)
|
||||
regs.sp[-1].setInt32(sum);
|
||||
} else
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
if (lmask == JSVAL_MASK32_NONFUNOBJ && lref.asObject().isXML() &&
|
||||
rmask == JSVAL_MASK32_NONFUNOBJ && rref.asObject().isXML()) {
|
||||
if (lval.isNonFunObj() && lval.asObject().isXML() &&
|
||||
rval.isNonFunObj() && rval.asObject().isXML()) {
|
||||
Value rval;
|
||||
if (!js_ConcatenateXML(cx, &lref.asObject(), &rref.asObject(), &rval))
|
||||
if (!js_ConcatenateXML(cx, &lval.asObject(), &rval.asObject(), &rval))
|
||||
goto error;
|
||||
regs.sp--;
|
||||
regs.sp[-1] = rval;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if (Value::isObjectMask(lmask)) {
|
||||
if (!lref.asObject().defaultValue(cx, JSTYPE_VOID, &lref))
|
||||
goto error;
|
||||
lmask = lref.data.s.mask32;
|
||||
}
|
||||
if (Value::isObjectMask(rmask)) {
|
||||
if (!rref.asObject().defaultValue(cx, JSTYPE_VOID, &rref))
|
||||
goto error;
|
||||
rmask = rref.data.s.mask32;
|
||||
}
|
||||
if (lmask == JSVAL_MASK32_STRING || rmask == JSVAL_MASK32_STRING) {
|
||||
JSString *str1, *str2;
|
||||
if (lmask == rmask) {
|
||||
str1 = lref.asString();
|
||||
str2 = rref.asString();
|
||||
} else if (lmask == JSVAL_MASK32_STRING) {
|
||||
str1 = lref.asString();
|
||||
str2 = js_ValueToString(cx, rref);
|
||||
if (!str2)
|
||||
goto error;
|
||||
if (lval.isObject())
|
||||
DEFAULT_VALUE(cx, -2, JSTYPE_VOID, lval);
|
||||
if (rval.isObject())
|
||||
DEFAULT_VALUE(cx, -1, JSTYPE_VOID, rval);
|
||||
bool lIsString, rIsString;
|
||||
if ((lIsString = lval.isString()) | (rIsString = rval.isString())) {
|
||||
JSString *lstr, *rstr;
|
||||
if (lIsString) {
|
||||
lstr = lval.asString();
|
||||
} else {
|
||||
str2 = rref.asString();
|
||||
str1 = js_ValueToString(cx, lref);
|
||||
if (!str1)
|
||||
lstr = js_ValueToString(cx, lval);
|
||||
if (!lstr)
|
||||
goto error;
|
||||
regs.sp[-2].setString(lstr);
|
||||
}
|
||||
JSString *str = js_ConcatStrings(cx, str1, str2);
|
||||
if (rIsString) {
|
||||
rstr = rval.asString();
|
||||
} else {
|
||||
rstr = js_ValueToString(cx, rval);
|
||||
if (!rstr)
|
||||
goto error;
|
||||
regs.sp[-1].setString(rstr);
|
||||
}
|
||||
JSString *str = js_ConcatStrings(cx, lstr, rstr);
|
||||
if (!str)
|
||||
goto error;
|
||||
regs.sp--;
|
||||
regs.sp[-1].setString(str);
|
||||
} else {
|
||||
double l, r;
|
||||
if (!ValueToNumber(cx, lref, &l) || !ValueToNumber(cx, rref, &r))
|
||||
if (!ValueToNumber(cx, lval, &l) || !ValueToNumber(cx, rval, &r))
|
||||
goto error;
|
||||
l += r;
|
||||
regs.sp--;
|
||||
@ -2135,15 +2099,10 @@ END_CASE(JSOP_GETELEM)
|
||||
|
||||
BEGIN_CASE(JSOP_CALLELEM)
|
||||
{
|
||||
/* Depends on the value representation. */
|
||||
|
||||
/* Fetch the left part and resolve it to a non-null object. */
|
||||
JSObject *obj;
|
||||
FETCH_OBJECT(cx, -2, obj);
|
||||
|
||||
/* Save the mask so that we don't need to query it later. */
|
||||
uint32 objmask = regs.sp[-2].data.s.mask32;
|
||||
|
||||
/* Fetch index and convert it to id suitable for use with obj. */
|
||||
jsid id;
|
||||
FETCH_ELEMENT_ID(obj, -1, id);
|
||||
@ -2161,8 +2120,7 @@ BEGIN_CASE(JSOP_CALLELEM)
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
regs.sp[-1].data.s.mask32 = objmask;
|
||||
regs.sp[-1].data.s.payload.obj = obj;
|
||||
regs.sp[-1].setObject(*obj);
|
||||
}
|
||||
}
|
||||
END_CASE(JSOP_CALLELEM)
|
||||
|
461
js/src/jspubtd.h
461
js/src/jspubtd.h
@ -158,35 +158,12 @@ typedef struct JSONParser JSONParser;
|
||||
*/
|
||||
|
||||
/*
|
||||
* TODO: wrong, fix, explain more
|
||||
* Engine-internal value details:
|
||||
*
|
||||
* A jsval has an abstract type which is represented by a mask which assigns a
|
||||
* bit to each type. This allows fast set-membership queries. However, we give
|
||||
* one type (null) a mask of 0 for two reasons:
|
||||
*
|
||||
* 1. memset'ing values to 0 produces a valid value. This was true of the old,
|
||||
* boxed jsvals (and now jsboxedwords) and eases the transition.
|
||||
*
|
||||
* 2. Testing for null can often be compiled to slightly shorter/faster code.
|
||||
*
|
||||
* The down-side is that set-membership queries need to be done more carefully.
|
||||
* E.g., to test whether a value v is undefined or null, the correct test is:
|
||||
*
|
||||
* (v.mask & ~UndefinedMask) == 0
|
||||
*
|
||||
* instead of the intuitive (but incorrect) test:
|
||||
*
|
||||
* (v.mask & (NullMask | UndefinedMask)) != 0
|
||||
*
|
||||
* Since the value representation is kept a private detail of js::Value and
|
||||
* only exposed to a few functions through friendship, this type of error
|
||||
* should be hidden behind simple inline methods like v.isNullOrUndefined().
|
||||
* TODO: explain boxing strategy
|
||||
*/
|
||||
|
||||
typedef enum JSValueMask16
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1400
|
||||
: unsigned short
|
||||
#if defined(_MSC_VER)
|
||||
: uint16
|
||||
#endif
|
||||
{
|
||||
JSVAL_MASK16_NULL = (uint16)0x0001,
|
||||
@ -203,6 +180,11 @@ typedef enum JSValueMask16
|
||||
JSVAL_MASK16_OBJORNULL = JSVAL_MASK16_OBJECT | JSVAL_MASK16_NULL,
|
||||
JSVAL_MASK16_GCTHING = JSVAL_MASK16_OBJECT | JSVAL_MASK16_STRING,
|
||||
|
||||
/*
|
||||
* This enumerator value plus __attribute__((packed)) plus the static
|
||||
* assert that sizeof(JSValueMask16) == 2 should guarantee that enumerators
|
||||
* are uint16 in GCC.
|
||||
*/
|
||||
JSVAL_NANBOX_PATTERN = ((uint16)0xFFFF)
|
||||
}
|
||||
#if defined(__GNUC__)
|
||||
@ -210,45 +192,36 @@ __attribute__((packed))
|
||||
#endif
|
||||
JSValueMask16;
|
||||
|
||||
#define JSVAL_MASK32_CLEAR ((uint32)0xFFFF0000)
|
||||
|
||||
#define JSVAL_MASK32_NULL ((uint32)(JSVAL_MASK32_CLEAR | JSVAL_MASK16_NULL))
|
||||
#define JSVAL_MASK32_UNDEFINED ((uint32)(JSVAL_MASK32_CLEAR | JSVAL_MASK16_UNDEFINED))
|
||||
#define JSVAL_MASK32_INT32 ((uint32)(JSVAL_MASK32_CLEAR | JSVAL_MASK16_INT32))
|
||||
#define JSVAL_MASK32_STRING ((uint32)(JSVAL_MASK32_CLEAR | JSVAL_MASK16_STRING))
|
||||
#define JSVAL_MASK32_NONFUNOBJ ((uint32)(JSVAL_MASK32_CLEAR | JSVAL_MASK16_NONFUNOBJ))
|
||||
#define JSVAL_MASK32_FUNOBJ ((uint32)(JSVAL_MASK32_CLEAR | JSVAL_MASK16_FUNOBJ))
|
||||
#define JSVAL_MASK32_BOOLEAN ((uint32)(JSVAL_MASK32_CLEAR | JSVAL_MASK16_BOOLEAN))
|
||||
#define JSVAL_MASK32_MAGIC ((uint32)(JSVAL_MASK32_CLEAR | JSVAL_MASK16_MAGIC))
|
||||
|
||||
#define JSVAL_MASK32_SINGLETON ((uint32)(JSVAL_MASK32_CLEAR | JSVAL_MASK16_SINGLETON))
|
||||
#define JSVAL_MASK32_OBJECT ((uint32)(JSVAL_MASK32_CLEAR | JSVAL_MASK16_OBJECT))
|
||||
#define JSVAL_MASK32_OBJORNULL ((uint32)(JSVAL_MASK32_CLEAR | JSVAL_MASK16_OBJORNULL))
|
||||
#define JSVAL_MASK32_GCTHING ((uint32)(JSVAL_MASK32_CLEAR | JSVAL_MASK16_GCTHING))
|
||||
|
||||
typedef enum JSWhyMagic
|
||||
{
|
||||
JS_ARRAY_HOLE, /* a hole in a dense array */
|
||||
JS_ARGS_HOLE, /* a hole in the args object's array */
|
||||
JS_NATIVE_ENUMERATE, /* indicates that a custom enumerate hook forwarded
|
||||
* to js_Enumerate, which really means the object can be
|
||||
* enumerated like a native object. */
|
||||
JS_NO_ITER_VALUE, /* there is not a pending iterator value */
|
||||
JS_GENERATOR_CLOSING /* exception value thrown when closing a generator */
|
||||
} JSWhyMagic;
|
||||
|
||||
typedef union jsval_payload
|
||||
{
|
||||
int32 i32;
|
||||
uint32 u32;
|
||||
JSBool boo;
|
||||
#if JS_BITS_PER_WORD == 32
|
||||
JSString *str;
|
||||
JSObject *obj;
|
||||
void *ptr;
|
||||
typedef enum JSValueMask32
|
||||
#if defined(_MSC_VER)
|
||||
: uint32
|
||||
#endif
|
||||
JSWhyMagic why;
|
||||
} jsval_data;
|
||||
{
|
||||
/*
|
||||
* This enumerator value plus __attribute__((packed)) plus the static
|
||||
* assert that sizeof(JSValueMask32) == 4 should guarantee that enumerators
|
||||
* are uint32 in GCC.
|
||||
*/
|
||||
JSVAL_MASK32_CLEAR = ((uint32)0xFFFF0000),
|
||||
|
||||
JSVAL_MASK32_NULL = ((uint32)(JSVAL_MASK32_CLEAR | JSVAL_MASK16_NULL)),
|
||||
JSVAL_MASK32_UNDEFINED = ((uint32)(JSVAL_MASK32_CLEAR | JSVAL_MASK16_UNDEFINED)),
|
||||
JSVAL_MASK32_INT32 = ((uint32)(JSVAL_MASK32_CLEAR | JSVAL_MASK16_INT32)),
|
||||
JSVAL_MASK32_STRING = ((uint32)(JSVAL_MASK32_CLEAR | JSVAL_MASK16_STRING)),
|
||||
JSVAL_MASK32_NONFUNOBJ = ((uint32)(JSVAL_MASK32_CLEAR | JSVAL_MASK16_NONFUNOBJ)),
|
||||
JSVAL_MASK32_FUNOBJ = ((uint32)(JSVAL_MASK32_CLEAR | JSVAL_MASK16_FUNOBJ)),
|
||||
JSVAL_MASK32_BOOLEAN = ((uint32)(JSVAL_MASK32_CLEAR | JSVAL_MASK16_BOOLEAN)),
|
||||
JSVAL_MASK32_MAGIC = ((uint32)(JSVAL_MASK32_CLEAR | JSVAL_MASK16_MAGIC)),
|
||||
|
||||
JSVAL_MASK32_SINGLETON = ((uint32)(JSVAL_MASK32_CLEAR | JSVAL_MASK16_SINGLETON)),
|
||||
JSVAL_MASK32_OBJECT = ((uint32)(JSVAL_MASK32_CLEAR | JSVAL_MASK16_OBJECT)),
|
||||
JSVAL_MASK32_OBJORNULL = ((uint32)(JSVAL_MASK32_CLEAR | JSVAL_MASK16_OBJORNULL)),
|
||||
JSVAL_MASK32_GCTHING = ((uint32)(JSVAL_MASK32_CLEAR | JSVAL_MASK16_GCTHING))
|
||||
}
|
||||
#if defined(__GNUC__)
|
||||
__attribute__((packed))
|
||||
#endif
|
||||
JSValueMask32;
|
||||
|
||||
#ifdef __GNUC__
|
||||
# define VALUE_ALIGNMENT __attribute__((aligned (8)))
|
||||
@ -264,32 +237,376 @@ typedef union jsval_payload
|
||||
# error "TODO: do something for compiler"
|
||||
#endif
|
||||
|
||||
typedef VALUE_ALIGNMENT uint64 jsval;
|
||||
|
||||
#define BUILD_JSVAL(mask32, payload) ((jsval)((((uint64)(uint32)(mask32)) << 32) | (uint32)(payload)))
|
||||
|
||||
typedef enum JSWhyMagic
|
||||
{
|
||||
JS_ARRAY_HOLE, /* a hole in a dense array */
|
||||
JS_ARGS_HOLE, /* a hole in the args object's array */
|
||||
JS_NATIVE_ENUMERATE, /* indicates that a custom enumerate hook forwarded
|
||||
* to js_Enumerate, which really means the object can be
|
||||
* enumerated like a native object. */
|
||||
JS_NO_ITER_VALUE, /* there is not a pending iterator value */
|
||||
JS_GENERATOR_CLOSING /* exception value thrown when closing a generator */
|
||||
} JSWhyMagic;
|
||||
|
||||
#if !defined(IS_LITTLE_ENDIAN)
|
||||
# error "Need to fix up jsval_layout"
|
||||
# error "Unsupported configuration"
|
||||
#endif
|
||||
|
||||
// TODO: explain
|
||||
typedef union jsval_layout
|
||||
{
|
||||
uint64 asBits;
|
||||
struct {
|
||||
jsval_payload payload;
|
||||
union {
|
||||
int32 i32;
|
||||
uint32 u32;
|
||||
JSBool boo;
|
||||
#if JS_BITS_PER_WORD == 32
|
||||
JSString *str;
|
||||
JSObject *obj;
|
||||
void *ptr;
|
||||
#elif JS_BITS_PER_WORD == 64
|
||||
uint32 ptr;
|
||||
#else
|
||||
# error "Unsupported configuration"
|
||||
#endif
|
||||
JSWhyMagic why;
|
||||
} payload;
|
||||
union {
|
||||
struct {
|
||||
JSValueMask16 mask16;
|
||||
uint16 nanBits;
|
||||
} tag;
|
||||
uint32 mask32;
|
||||
JSValueMask32 mask32;
|
||||
};
|
||||
} s;
|
||||
double asDouble;
|
||||
} jsval_layout;
|
||||
|
||||
typedef uint64 jsval;
|
||||
#if JS_BITS_PER_WORD == 32
|
||||
|
||||
/* These are engine-internal details, not part of the public API */
|
||||
#define DOUBLE_AS_JSVAL(d) (*(jsval *)&(d))
|
||||
#define JSVAL_CONSTANT(mask32, payload) ((jsval)((((uint64)(mask32)) << 32) | (payload)))
|
||||
static JS_ALWAYS_INLINE JSBool
|
||||
JSVAL_IS_NULL_IMPL(jsval_layout l)
|
||||
{
|
||||
return l.s.mask32 == JSVAL_MASK32_NULL;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE JSBool
|
||||
JSVAL_IS_UNDEFINED_IMPL(jsval_layout l)
|
||||
{
|
||||
return l.s.mask32 == JSVAL_MASK32_UNDEFINED;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE JSBool
|
||||
JSVAL_IS_SPECIFIC_INT32_IMPL(jsval_layout l, int32 i32)
|
||||
{
|
||||
return l.s.mask32 == JSVAL_MASK32_INT32 && l.s.payload.i32 == i32;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE jsval_layout
|
||||
INT32_TO_JSVAL_IMPL(int32 i)
|
||||
{
|
||||
jsval_layout l;
|
||||
l.s.mask32 = JSVAL_MASK32_INT32;
|
||||
l.s.payload.i32 = i;
|
||||
return l;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE JSBool
|
||||
JSVAL_IS_DOUBLE_IMPL(jsval_layout l)
|
||||
{
|
||||
return l.s.mask32 < JSVAL_MASK32_CLEAR;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE jsval_layout
|
||||
DOUBLE_TO_JSVAL_IMPL(jsdouble d)
|
||||
{
|
||||
jsval_layout l;
|
||||
l.asDouble = d;
|
||||
JS_ASSERT(l.s.tag.nanBits != JSVAL_NANBOX_PATTERN);
|
||||
return l;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE jsval_layout
|
||||
STRING_TO_JSVAL_IMPL(JSString *str)
|
||||
{
|
||||
jsval_layout l;
|
||||
l.s.mask32 = JSVAL_MASK32_STRING;
|
||||
l.s.payload.str = str;
|
||||
return l;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE JSString *
|
||||
JSVAL_TO_STRING_IMPL(jsval_layout l)
|
||||
{
|
||||
return l.s.payload.str;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE JSObject *
|
||||
JSVAL_TO_OBJECT_IMPL(jsval_layout l)
|
||||
{
|
||||
return l.s.payload.obj;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE jsval_layout
|
||||
OBJECT_TO_JSVAL_IMPL(JSValueMask32 mask, JSObject *obj)
|
||||
{
|
||||
jsval_layout l;
|
||||
l.s.mask32 = mask;
|
||||
l.s.payload.obj = obj;
|
||||
return l;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE jsval_layout
|
||||
BOOLEAN_TO_JSVAL_IMPL(JSBool b)
|
||||
{
|
||||
jsval_layout l;
|
||||
l.s.mask32 = JSVAL_MASK32_BOOLEAN;
|
||||
l.s.payload.boo = b;
|
||||
return l;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE void *
|
||||
JSVAL_TO_GCTHING_IMPL(jsval_layout l)
|
||||
{
|
||||
return l.s.payload.ptr;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE JSBool
|
||||
JSVAL_IS_SPECIFIC_BOOLEAN(jsval_layout l, JSBool b)
|
||||
{
|
||||
return (l.s.mask32 == JSVAL_MASK32_BOOLEAN) && (l.s.payload.boo == b);
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE jsval_layout
|
||||
PRIVATE_TO_JSVAL_IMPL(void *ptr)
|
||||
{
|
||||
JS_ASSERT(((uint32)ptr | 1) == 0);
|
||||
jsval_layout l;
|
||||
l.s.tag.nanBits = 0;
|
||||
l.s.payload.ptr = ptr;
|
||||
return l;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE void *
|
||||
JSVAL_TO_PRIVATE_IMPL(jsval_layout l)
|
||||
{
|
||||
return l.s.payload.ptr;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE jsval_layout
|
||||
MAGIC_TO_JSVAL_IMPL(JSWhyMagic why)
|
||||
{
|
||||
jsval_layout l;
|
||||
l.s.mask32 = JSVAL_MASK32_MAGIC;
|
||||
l.s.payload.why = why;
|
||||
return l;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE JSBool
|
||||
JSVAL_SAME_PRIMITIVE_TYPE_OR_BOTH_OBJECTS_IMPL(jsval_layout lhs, jsval_layout rhs)
|
||||
{
|
||||
return ((lhs.s.mask32 ^ rhs.s.mask32) & ~(uint32)JSVAL_MASK16_OBJECT) == 0 ||
|
||||
(lhs.s.mask32 < JSVAL_MASK32_CLEAR && rhs.s.mask32 < JSVAL_MASK32_CLEAR);
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE JSBool
|
||||
JSVAL_BOTH_STRING_IMPL(jsval_layout lhs, jsval_layout rhs)
|
||||
{
|
||||
return (lhs.s.mask32 & rhs.s.mask32) == JSVAL_MASK32_STRING;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE JSBool
|
||||
JSVAL_BOTH_INT32_IMPL(jsval_layout lhs, jsval_layout rhs)
|
||||
{
|
||||
return (lhs.s.mask32 & rhs.s.mask32) == JSVAL_MASK32_INT32;
|
||||
}
|
||||
|
||||
#elif JS_BITS_PER_WORD == 64
|
||||
|
||||
static JS_ALWAYS_INLINE JSBool
|
||||
JSVAL_IS_NULL_IMPL(jsval_layout l)
|
||||
{
|
||||
return l.asBits == BUILD_JSVAL(JSVAL_MASK32_NULL, 0);
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE JSBool
|
||||
JSVAL_IS_UNDEFINED_IMPL(jsval_layout l)
|
||||
{
|
||||
return l.asBits == BUILD_JSVAL(JSVAL_MASK32_UNDEFINED, 0);
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE JSBool
|
||||
JSVAL_IS_SPECIFIC_INT32_IMPL(jsval_layout l, int32 i32)
|
||||
{
|
||||
return l.asBits == BUILD_JSVAL(JSVAL_MASK32_INT32, i32);
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE jsval_layout
|
||||
INT32_TO_JSVAL_IMPL(int32 i)
|
||||
{
|
||||
jsval_layout l;
|
||||
l.asBits = BUILD_JSVAL(JSVAL_MASK32_INT32, i);
|
||||
return l;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE JSBool
|
||||
JSVAL_IS_DOUBLE_IMPL(jsval_layout l)
|
||||
{
|
||||
return l.asBits < BUILD_JSVAL(JSVAL_MASK32_CLEAR, 0);
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE jsval_layout
|
||||
DOUBLE_TO_JSVAL_IMPL(jsdouble d)
|
||||
{
|
||||
jsval_layout l;
|
||||
l.asDouble = d;
|
||||
JS_ASSERT(l.s.tag.nanBits != JSVAL_NANBOX_PATTERN);
|
||||
return l;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE jsval_layout
|
||||
STRING_TO_JSVAL_IMPL(JSString *str)
|
||||
{
|
||||
JS_ASSERT((size_t)str < (size_t)0xFFFFFFFF);
|
||||
jsval_layout l;
|
||||
l.asBits = BUILD_JSVAL(JSVAL_MASK32_STRING, (uint32)str);
|
||||
return l;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE JSString *
|
||||
JSVAL_TO_STRING_IMPL(jsval_layout v)
|
||||
{
|
||||
return (JSString *)(uint64)l.s.payload.ptr;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE JSObject *
|
||||
JSVAL_TO_OBJECT_IMPL(jsval_layout l)
|
||||
{
|
||||
return (JSObject *)(uint64)l.s.payload.ptr;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE jsval_layout
|
||||
OBJECT_TO_JSVAL_IMPL(JSValueMask32 mask32, JSObject *obj)
|
||||
{
|
||||
JS_ASSERT((size_t)obj < (size_t)0xFFFFFFFF);
|
||||
jsval_layout l;
|
||||
l.asBits = BUILD_JSVAL(mask32, (uint32)obj);
|
||||
return l;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE jsval_layout
|
||||
BOOLEAN_TO_JSVAL_IMPL(JSBool b)
|
||||
{
|
||||
jsval_layout l;
|
||||
l.asBits = BUILD_JSVAL(JSVAL_MASK32_BOOLEAN, b);
|
||||
return l;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE void *
|
||||
JSVAL_TO_GCTHING_IMPL(jsval_layout l)
|
||||
{
|
||||
return (void *)(uint64)l.s.payload.ptr;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE JSBool
|
||||
JSVAL_IS_SPECIFIC_BOOLEAN(jsval_layout l, JSBool b)
|
||||
{
|
||||
return l.asBits == BUILD_JSVAL(JSVAL_MASK32_BOOLEAN, b);
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE jsval_layout
|
||||
PRIVATE_TO_JSVAL_IMPL(void *ptr)
|
||||
{
|
||||
JS_ASSERT(((uint32)ptr | 1) == 0);
|
||||
jsval_layout l;
|
||||
l.asBits = 0x8000000000000000LL | (ptr >> 1);
|
||||
return l;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE void *
|
||||
JSVAL_TO_PRIVATE_IMPL(jsval_layout l)
|
||||
{
|
||||
return (void *)(l.s.payload.asBits << 1);
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE jsval_layout
|
||||
MAGIC_TO_JSVAL_IMPL(JSWhyMagic why)
|
||||
{
|
||||
jsval_layout l;
|
||||
l.asBits = BUILD_JSVAL(JSVAL_MASK32_MAGIC, why);
|
||||
return l;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE JSBool
|
||||
JSVAL_SAME_PRIMITIVE_TYPE_OR_BOTH_OBJECTS_IMPL(jsval_layout lhs, jsval_layout rhs)
|
||||
{
|
||||
uint32 xor32 = (uint32)((lhs.asBits ^ rhs.asBits) >> 32);
|
||||
return (xor32 & ~(uint32)JSVAL_MASK16_OBJECT) == 0 ||
|
||||
(JSVAL_IS_DOUBLE_IMPL(lhs) && JSVAL_IS_DOUBLE_IMPL(rhs));
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE JSBool
|
||||
JSVAL_BOTH_STRING_IMPL(jsval_layout lhs, jsval_layout rhs)
|
||||
{
|
||||
return (uint32)((lhs.asBits & rhs.asBits) >> 32) == JSVAL_MASK32_STRING;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE JSBool
|
||||
JSVAL_BOTH_INT32_IMPL(jsval_layout lhs, jsval_layout rhs)
|
||||
{
|
||||
return (uint32)((lhs.asBits & rhs.asBits) >> 32) == JSVAL_MASK32_INT32;
|
||||
}
|
||||
|
||||
#else
|
||||
# error "Unsupported configuration"
|
||||
#endif
|
||||
|
||||
static JS_ALWAYS_INLINE JSBool
|
||||
JSVAL_IS_SINGLETON_IMPL(jsval_layout l)
|
||||
{
|
||||
return (l.s.mask32 & JSVAL_MASK32_SINGLETON) > JSVAL_MASK32_CLEAR;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE JSBool
|
||||
JSVAL_IS_NUMBER_IMPL(jsval_layout l)
|
||||
{
|
||||
JSValueMask32 mask = l.s.mask32;
|
||||
return mask < JSVAL_MASK32_CLEAR || mask == JSVAL_MASK32_INT32;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE JSBool
|
||||
JSVAL_IS_OBJECT_IMPL(jsval_layout l)
|
||||
{
|
||||
return (l.s.mask32 & JSVAL_MASK32_OBJECT) > JSVAL_MASK32_CLEAR;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE JSBool
|
||||
JSVAL_IS_OBJECT_OR_NULL_IMPL(jsval_layout l)
|
||||
{
|
||||
return (l.s.mask32 & JSVAL_MASK32_OBJORNULL) > JSVAL_MASK32_CLEAR;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE JSBool
|
||||
JSVAL_IS_PRIMITIVE_IMPL(jsval_layout l)
|
||||
{
|
||||
return (l.s.mask32 & JSVAL_MASK32_OBJECT) <= JSVAL_MASK32_CLEAR;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE JSBool
|
||||
JSVAL_IS_GCTHING_IMPL(jsval_layout l)
|
||||
{
|
||||
return (l.s.mask32 & JSVAL_MASK32_GCTHING) > JSVAL_MASK32_CLEAR;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE uint32
|
||||
JSVAL_TRACE_KIND_IMPL(jsval_layout l)
|
||||
{
|
||||
return (uint32)(l.s.mask32 == JSVAL_MASK32_STRING);
|
||||
}
|
||||
|
||||
/*
|
||||
* Boxed word macros (private engine detail)
|
||||
|
Loading…
Reference in New Issue
Block a user