Bug 463243 - Assert correct type in JSVAL_TO_* (and vice versa) macros to fail fast when type errors happen. r=brendan

This commit is contained in:
Jeff Walden 2009-02-03 13:56:25 -08:00
Родитель d7fd5df073
Коммит f4d1479aaf
15 изменённых файлов: 165 добавлений и 67 удалений

Просмотреть файл

@ -1991,7 +1991,7 @@ nsJSContext::CallEventHandler(nsISupports* aTarget, void *aScope, void *aHandler
AutoFreeJSStack stackGuard(mContext, mark); // ensure always freed.
jsval funval = OBJECT_TO_JSVAL(aHandler);
jsval funval = OBJECT_TO_JSVAL(static_cast<JSObject *>(aHandler));
JSAutoRequest ar(mContext);
PRBool ok = ::JS_CallFunctionValue(mContext, target,
funval, argc, argv, &rval);

Просмотреть файл

@ -743,6 +743,21 @@ JS_NewRuntime(uint32 maxbytes)
#include "js.msg"
#undef MSG_DEF
/*
* If it were possible for pure inline function calls with constant
* arguments to be computed at compile time, these would be static
* assertions, but since it isn't, this is the best we can do.
*/
JS_ASSERT(JSVAL_NULL == OBJECT_TO_JSVAL(NULL));
JS_ASSERT(JSVAL_ZERO == INT_TO_JSVAL(0));
JS_ASSERT(JSVAL_ONE == INT_TO_JSVAL(1));
JS_ASSERT(JSVAL_FALSE == BOOLEAN_TO_JSVAL(JS_FALSE));
JS_ASSERT(JSVAL_TRUE == BOOLEAN_TO_JSVAL(JS_TRUE));
JS_ASSERT(JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID) == 2);
JS_ASSERT(JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_HOLE) == 3);
JS_ASSERT(JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_ARETURN) == 4);
js_NewRuntimeWasCalled = JS_TRUE;
}
#endif /* DEBUG */

Просмотреть файл

@ -83,13 +83,54 @@ JS_BEGIN_EXTERN_C
/* Objects, strings, and doubles are GC'ed. */
#define JSVAL_IS_GCTHING(v) (!((v) & JSVAL_INT) && \
JSVAL_TAG(v) != JSVAL_BOOLEAN)
#define JSVAL_TO_GCTHING(v) ((void *)JSVAL_CLRTAG(v))
#define JSVAL_TO_OBJECT(v) ((JSObject *)JSVAL_TO_GCTHING(v))
#define JSVAL_TO_DOUBLE(v) ((jsdouble *)JSVAL_TO_GCTHING(v))
#define JSVAL_TO_STRING(v) ((JSString *)JSVAL_TO_GCTHING(v))
#define OBJECT_TO_JSVAL(obj) ((jsval)(obj))
#define DOUBLE_TO_JSVAL(dp) JSVAL_SETTAG((jsval)(dp), JSVAL_DOUBLE)
#define STRING_TO_JSVAL(str) JSVAL_SETTAG((jsval)(str), JSVAL_STRING)
static JS_ALWAYS_INLINE void *
JSVAL_TO_GCTHING(jsval v)
{
JS_ASSERT(JSVAL_IS_GCTHING(v));
return (void *) JSVAL_CLRTAG(v);
}
static JS_ALWAYS_INLINE JSObject *
JSVAL_TO_OBJECT(jsval v)
{
JS_ASSERT(JSVAL_IS_OBJECT(v));
return (JSObject *) JSVAL_TO_GCTHING(v);
}
static JS_ALWAYS_INLINE jsdouble *
JSVAL_TO_DOUBLE(jsval v)
{
JS_ASSERT(JSVAL_IS_DOUBLE(v));
return (jsdouble *) JSVAL_TO_GCTHING(v);
}
static JS_ALWAYS_INLINE JSString *
JSVAL_TO_STRING(jsval v)
{
JS_ASSERT(JSVAL_IS_STRING(v));
return (JSString *) JSVAL_TO_GCTHING(v);
}
static JS_ALWAYS_INLINE jsval
OBJECT_TO_JSVAL(JSObject *obj)
{
JS_STATIC_ASSERT(JSVAL_OBJECT == 0);
JS_ASSERT(((jsval) obj & JSVAL_TAGBITS) == JSVAL_OBJECT);
return (jsval) obj;
}
static JS_ALWAYS_INLINE jsval
DOUBLE_TO_JSVAL(jsdouble *dp)
{
return JSVAL_SETTAG((jsval) dp, JSVAL_DOUBLE);
}
static JS_ALWAYS_INLINE jsval
STRING_TO_JSVAL(JSString *str)
{
return JSVAL_SETTAG((jsval) str, JSVAL_STRING);
}
/* Lock and unlock the GC thing held by a jsval. */
#define JSVAL_LOCK(cx,v) (JSVAL_IS_GCTHING(v) \
@ -109,10 +150,45 @@ JS_BEGIN_EXTERN_C
#define JSVAL_TO_INT(v) ((jsint)(v) >> 1)
#define INT_TO_JSVAL(i) (((jsval)(i) << 1) | JSVAL_INT)
/* Convert between boolean and jsval. */
#define JSVAL_TO_BOOLEAN(v) ((JSBool)((v) >> JSVAL_TAGBITS))
#define BOOLEAN_TO_JSVAL(b) JSVAL_SETTAG((jsval)(b) << JSVAL_TAGBITS, \
JSVAL_BOOLEAN)
/*
* A pseudo-boolean is a 29-bit (for 32-bit jsval) or 61-bit (for 64-bit jsval)
* value other than 0 or 1 encoded as a jsval whose tag is JSVAL_BOOLEAN.
*
* JSVAL_VOID happens to be defined as a jsval encoding a pseudo-boolean, but
* embedders MUST NOT rely on this. All other possible pseudo-boolean values
* are implementation-reserved and MUST NOT be constructed by any embedding of
* SpiderMonkey.
*/
#define JSVAL_TO_PSEUDO_BOOLEAN(v) ((JSBool) ((v) >> JSVAL_TAGBITS))
#define PSEUDO_BOOLEAN_TO_JSVAL(b) \
JSVAL_SETTAG((jsval) (b) << JSVAL_TAGBITS, JSVAL_BOOLEAN)
/*
* Well-known JS values. The extern'd variables are initialized when the
* first JSContext is created by JS_NewContext (see below).
*/
#define JSVAL_NULL ((jsval) 0)
#define JSVAL_ZERO INT_TO_JSVAL(0)
#define JSVAL_ONE INT_TO_JSVAL(1)
#define JSVAL_FALSE PSEUDO_BOOLEAN_TO_JSVAL(JS_FALSE)
#define JSVAL_TRUE PSEUDO_BOOLEAN_TO_JSVAL(JS_TRUE)
#define JSVAL_VOID PSEUDO_BOOLEAN_TO_JSVAL(2)
/* Convert between boolean and jsval, asserting that inputs are valid. */
static JS_ALWAYS_INLINE JSBool
JSVAL_TO_BOOLEAN(jsval v)
{
JS_ASSERT(v == JSVAL_TRUE || v == JSVAL_FALSE);
return JSVAL_TO_PSEUDO_BOOLEAN(v);
}
static JS_ALWAYS_INLINE jsval
BOOLEAN_TO_JSVAL(JSBool b)
{
JS_ASSERT(b == JS_TRUE || b == JS_FALSE);
return PSEUDO_BOOLEAN_TO_JSVAL(b);
}
/* A private data pointer (2-byte-aligned) can be stored as an int jsval. */
#define JSVAL_TO_PRIVATE(v) ((void *)((v) & ~JSVAL_INT))
@ -179,17 +255,6 @@ JS_BEGIN_EXTERN_C
*/
#define JSFUN_GENERIC_NATIVE JSFUN_LAMBDA
/*
* Well-known JS values. The extern'd variables are initialized when the
* first JSContext is created by JS_NewContext (see below).
*/
#define JSVAL_VOID BOOLEAN_TO_JSVAL(2)
#define JSVAL_NULL OBJECT_TO_JSVAL(0)
#define JSVAL_ZERO INT_TO_JSVAL(0)
#define JSVAL_ONE INT_TO_JSVAL(1)
#define JSVAL_FALSE BOOLEAN_TO_JSVAL(JS_FALSE)
#define JSVAL_TRUE BOOLEAN_TO_JSVAL(JS_TRUE)
/*
* Microseconds since the epoch, midnight, January 1, 1970 UTC. See the
* comment in jstypes.h regarding safe int64 usage.

Просмотреть файл

@ -78,7 +78,6 @@ js_AtomToPrintableString(JSContext *cx, JSAtom *atom)
* asserts check these relations.
*/
JS_STATIC_ASSERT(JSTYPE_LIMIT == 8);
JS_STATIC_ASSERT(JSVAL_TO_BOOLEAN(JSVAL_VOID) == 2);
JS_STATIC_ASSERT(JSTYPE_VOID == 0);
const char *const js_common_atom_names[] = {

Просмотреть файл

@ -54,10 +54,10 @@ JS_BEGIN_EXTERN_C
*
* JSVAL_ARETURN is used to throw asynchronous return for generator.close().
*
* NB: BOOLEAN_TO_JSVAL(2) is JSVAL_VOID (see jsapi.h).
* NB: PSEUDO_BOOLEAN_TO_JSVAL(2) is JSVAL_VOID (see jsapi.h).
*/
#define JSVAL_HOLE BOOLEAN_TO_JSVAL(3)
#define JSVAL_ARETURN BOOLEAN_TO_JSVAL(4)
#define JSVAL_HOLE PSEUDO_BOOLEAN_TO_JSVAL(3)
#define JSVAL_ARETURN PSEUDO_BOOLEAN_TO_JSVAL(4)
extern JSClass js_BooleanClass;

Просмотреть файл

@ -383,7 +383,8 @@ js_TypeOfObject(JSContext* cx, JSObject* obj)
JSString* FASTCALL
js_TypeOfBoolean(JSContext* cx, int32 unboxed)
{
jsval boxed = BOOLEAN_TO_JSVAL(unboxed);
/* Watch out for pseudo-booleans. */
jsval boxed = PSEUDO_BOOLEAN_TO_JSVAL(unboxed);
JS_ASSERT(JSVAL_IS_VOID(boxed) || JSVAL_IS_BOOLEAN(boxed));
JSType type = JS_TypeOfValue(cx, boxed);
return ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[type]);
@ -392,8 +393,9 @@ js_TypeOfBoolean(JSContext* cx, int32 unboxed)
jsdouble FASTCALL
js_BooleanOrUndefinedToNumber(JSContext* cx, int32 unboxed)
{
if (unboxed == JSVAL_TO_BOOLEAN(JSVAL_VOID))
if (unboxed == JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID))
return js_NaN;
JS_ASSERT(unboxed == JS_TRUE || unboxed == JS_FALSE);
return unboxed;
}

Просмотреть файл

@ -94,7 +94,7 @@ struct JSTraceableNative {
* in use. If it is, a performance regression occurs, not an actual runtime
* error.
*/
#define JSVAL_ERROR_COOKIE OBJECT_TO_JSVAL((void*)0x10)
#define JSVAL_ERROR_COOKIE OBJECT_TO_JSVAL((JSObject*)0x10)
/* Macros used by JS_DEFINE_CALLINFOn. */
#ifdef DEBUG

Просмотреть файл

@ -651,7 +651,8 @@ js_watch_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
#endif
ok = !wp->setter ||
((sprop->attrs & JSPROP_SETTER)
? js_InternalCall(cx, obj, OBJECT_TO_JSVAL(wp->setter),
? js_InternalCall(cx, obj,
OBJECT_TO_JSVAL((JSObject *)wp->setter),
1, vp, vp)
: wp->setter(cx, OBJ_THIS_OBJECT(cx, obj), userid, vp));
if (injectFrame) {

Просмотреть файл

@ -3590,7 +3590,7 @@ js_Interpret(JSContext *cx)
JSXMLObjectOps *ops; \
\
ops = (JSXMLObjectOps *) obj2->map->ops; \
if (obj2 == JSVAL_TO_OBJECT(rval)) \
if (JSVAL_IS_OBJECT(rval) && obj2 == JSVAL_TO_OBJECT(rval)) \
rval = lval; \
if (!ops->equality(cx, obj2, rval, &cond)) \
goto error; \

Просмотреть файл

@ -1879,7 +1879,7 @@ obj_lookupGetter(JSContext *cx, uintN argc, jsval *vp)
if (OBJ_IS_NATIVE(pobj)) {
sprop = (JSScopeProperty *) prop;
if (sprop->attrs & JSPROP_GETTER)
*vp = OBJECT_TO_JSVAL(sprop->getter);
*vp = OBJECT_TO_JSVAL((JSObject *) sprop->getter);
}
OBJ_DROP_PROPERTY(cx, pobj, prop);
}
@ -1904,7 +1904,7 @@ obj_lookupSetter(JSContext *cx, uintN argc, jsval *vp)
if (OBJ_IS_NATIVE(pobj)) {
sprop = (JSScopeProperty *) prop;
if (sprop->attrs & JSPROP_SETTER)
*vp = OBJECT_TO_JSVAL(sprop->setter);
*vp = OBJECT_TO_JSVAL((JSObject *) sprop->setter);
}
OBJ_DROP_PROPERTY(cx, pobj, prop);
}

Просмотреть файл

@ -334,8 +334,8 @@ struct JSScopeProperty {
#define SPROP_GET(cx,sprop,obj,obj2,vp) \
(((sprop)->attrs & JSPROP_GETTER) \
? js_InternalGetOrSet(cx, obj, (sprop)->id, \
OBJECT_TO_JSVAL((sprop)->getter), JSACC_READ, \
0, 0, vp) \
OBJECT_TO_JSVAL((JSObject *) (sprop)->getter), \
JSACC_READ, 0, 0, vp) \
: (sprop)->getter(cx, OBJ_THIS_OBJECT(cx,obj), SPROP_USERID(sprop), vp))
/*
@ -345,8 +345,8 @@ struct JSScopeProperty {
#define SPROP_SET(cx,sprop,obj,obj2,vp) \
(((sprop)->attrs & JSPROP_SETTER) \
? js_InternalGetOrSet(cx, obj, (sprop)->id, \
OBJECT_TO_JSVAL((sprop)->setter), JSACC_WRITE, \
1, vp, vp) \
OBJECT_TO_JSVAL((JSObject *) (sprop)->setter), \
JSACC_WRITE, 1, vp, vp) \
: ((sprop)->attrs & JSPROP_GETTER) \
? (JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, \
JSMSG_GETTER_ONLY, NULL), JS_FALSE) \

Просмотреть файл

@ -1456,8 +1456,9 @@ ValueToNative(JSContext* cx, jsval v, uint8 type, double* slot)
debug_only_v(printf("double<%g> ", d);)
return;
case JSVAL_BOOLEAN:
/* Watch out for pseudo-booleans. */
JS_ASSERT(tag == JSVAL_BOOLEAN);
*(JSBool*)slot = JSVAL_TO_BOOLEAN(v);
*(JSBool*)slot = JSVAL_TO_PSEUDO_BOOLEAN(v);
debug_only_v(printf("boolean<%d> ", *(JSBool*)slot);)
return;
case JSVAL_STRING:
@ -1540,7 +1541,8 @@ NativeToValue(JSContext* cx, jsval& v, uint8 type, double* slot)
jsdouble d;
switch (type) {
case JSVAL_BOOLEAN:
v = BOOLEAN_TO_JSVAL(*(JSBool*)slot);
/* Watch out for pseudo-booleans. */
v = PSEUDO_BOOLEAN_TO_JSVAL(*(JSBool*)slot);
debug_only_v(printf("boolean<%d> ", *(JSBool*)slot);)
break;
case JSVAL_INT:
@ -4909,7 +4911,7 @@ TraceRecorder::ifop()
if (JSVAL_TAG(v) == JSVAL_BOOLEAN) {
/* Test for boolean is true, negate later if we are testing for false. */
cond = JSVAL_TO_BOOLEAN(v) == 1;
cond = JSVAL_TO_PSEUDO_BOOLEAN(v) == JS_TRUE;
x = lir->ins2i(LIR_eq, v_ins, 1);
} else if (isNumber(v)) {
jsdouble d = asNumber(v);
@ -5178,10 +5180,10 @@ TraceRecorder::equalityHelper(jsval l, jsval r, LIns* l_ins, LIns* r_ins,
fp = true;
}
} else if (JSVAL_IS_NULL(l) && JSVAL_TAG(r) == JSVAL_BOOLEAN) {
l_ins = lir->insImm(JSVAL_TO_BOOLEAN(JSVAL_VOID));
l_ins = lir->insImm(JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID));
cond = (r == JSVAL_VOID);
} else if (JSVAL_TAG(l) == JSVAL_BOOLEAN && JSVAL_IS_NULL(r)) {
r_ins = lir->insImm(JSVAL_TO_BOOLEAN(JSVAL_VOID));
r_ins = lir->insImm(JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID));
cond = (l == JSVAL_VOID);
} else if (isNumber(l) && JSVAL_IS_STRING(r)) {
args[0] = r_ins, args[1] = cx_ins;
@ -5432,13 +5434,13 @@ TraceRecorder::binary(LOpcode op)
if (JSVAL_TAG(l) == JSVAL_BOOLEAN) {
LIns* args[] = { a, cx_ins };
a = lir->insCall(&js_BooleanOrUndefinedToNumber_ci, args);
lnum = js_BooleanOrUndefinedToNumber(cx, JSVAL_TO_BOOLEAN(l));
lnum = js_BooleanOrUndefinedToNumber(cx, JSVAL_TO_PSEUDO_BOOLEAN(l));
leftIsNumber = true;
}
if (JSVAL_TAG(r) == JSVAL_BOOLEAN) {
LIns* args[] = { b, cx_ins };
b = lir->insCall(&js_BooleanOrUndefinedToNumber_ci, args);
rnum = js_BooleanOrUndefinedToNumber(cx, JSVAL_TO_BOOLEAN(r));
rnum = js_BooleanOrUndefinedToNumber(cx, JSVAL_TO_PSEUDO_BOOLEAN(r));
rightIsNumber = true;
}
if (leftIsNumber && rightIsNumber) {
@ -5735,13 +5737,10 @@ TraceRecorder::native_get(LIns* obj_ins, LIns* pobj_ins, JSScopeProperty* sprop,
if (sprop->slot != SPROP_INVALID_SLOT)
v_ins = stobj_get_slot(pobj_ins, sprop->slot, dslots_ins);
else
v_ins = INS_CONST(JSVAL_TO_BOOLEAN(JSVAL_VOID));
v_ins = INS_CONST(JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID));
return true;
}
// So box_jsval can emit no LIR_or at all to tag an object jsval.
JS_STATIC_ASSERT(JSVAL_OBJECT == 0);
JS_REQUIRES_STACK void
TraceRecorder::box_jsval(jsval v, LIns*& v_ins)
{
@ -6000,7 +5999,7 @@ TraceRecorder::record_EnterFrame()
debug_only_v(
js_Disassemble(cx, cx->fp->script, JS_TRUE, stdout);
printf("----\n");)
LIns* void_ins = INS_CONST(JSVAL_TO_BOOLEAN(JSVAL_VOID));
LIns* void_ins = INS_CONST(JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID));
jsval* vp = &fp->argv[fp->argc];
jsval* vpstop = vp + ptrdiff_t(fp->fun->nargs) - ptrdiff_t(fp->argc);
@ -6039,7 +6038,7 @@ TraceRecorder::record_LeaveFrame()
JS_REQUIRES_STACK bool
TraceRecorder::record_JSOP_PUSH()
{
stack(0, INS_CONST(JSVAL_TO_BOOLEAN(JSVAL_VOID)));
stack(0, INS_CONST(JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID)));
return true;
}
@ -6703,7 +6702,7 @@ success:
break;
}
case FAIL_VOID:
guard(false, lir->ins2i(LIR_eq, res_ins, JSVAL_TO_BOOLEAN(JSVAL_VOID)), OOM_EXIT);
guard(false, lir->ins2i(LIR_eq, res_ins, JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID)), OOM_EXIT);
break;
case FAIL_COOKIE:
guard(false, lir->ins2(LIR_eq, res_ins, INS_CONST(JSVAL_ERROR_COOKIE)), OOM_EXIT);
@ -6762,7 +6761,7 @@ TraceRecorder::record_JSOP_TYPEOF()
if (JSVAL_TAG(r) == JSVAL_BOOLEAN) {
// We specialize identically for boolean and undefined. We must not have a hole here.
// Pass the unboxed type here, since TypeOfBoolean knows how to handle it.
JS_ASSERT(JSVAL_TO_BOOLEAN(r) <= 2);
JS_ASSERT(r == JSVAL_TRUE || r == JSVAL_FALSE || r == JSVAL_VOID);
type = lir->insCall(&js_TypeOfBoolean_ci, args);
} else {
JS_ASSERT(JSVAL_TAG(r) == JSVAL_OBJECT);
@ -6776,7 +6775,7 @@ TraceRecorder::record_JSOP_TYPEOF()
JS_REQUIRES_STACK bool
TraceRecorder::record_JSOP_VOID()
{
stack(-1, INS_CONST(JSVAL_TO_BOOLEAN(JSVAL_VOID)));
stack(-1, INS_CONST(JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID)));
return true;
}
@ -7137,7 +7136,7 @@ SetProperty_tn(JSContext* cx, JSObject* obj, JSString* idstr, jsval v)
!OBJ_SET_PROPERTY(cx, obj, id, &v)) {
cx->builtinStatus |= JSBUILTIN_ERROR;
}
return JSVAL_TO_BOOLEAN(JSVAL_VOID);
return JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID);
}
static JSBool
@ -7165,7 +7164,7 @@ SetElement_tn(JSContext* cx, JSObject* obj, int32 index, jsval v)
if (!js_Int32ToId(cx, index, &id) || !OBJ_SET_PROPERTY(cx, obj, id, &v))
cx->builtinStatus |= JSBUILTIN_ERROR;
return JSVAL_TO_BOOLEAN(JSVAL_VOID);
return JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID);
}
JS_DEFINE_TRCINFO_1(SetProperty,
@ -7562,7 +7561,7 @@ TraceRecorder::prop(JSObject* obj, LIns* obj_ins, uint32& slot, LIns*& v_ins)
/* Check for non-existent property reference, which results in undefined. */
const JSCodeSpec& cs = js_CodeSpec[*cx->fp->regs->pc];
if (PCVAL_IS_NULL(pcval)) {
v_ins = INS_CONST(JSVAL_TO_BOOLEAN(JSVAL_VOID));
v_ins = INS_CONST(JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID));
JS_ASSERT(cs.ndefs == 1);
stack(-cs.nuses, v_ins);
slot = SPROP_INVALID_SLOT;
@ -7653,7 +7652,7 @@ TraceRecorder::elem(jsval& oval, jsval& idx, jsval*& vp, LIns*& v_ins, LIns*& ad
offsetof(JSRuntime, anyArrayProtoHasElement))),
MISMATCH_EXIT);
// Return undefined and indicate that we didn't actually read this (addr_ins).
v_ins = lir->insImm(JSVAL_TO_BOOLEAN(JSVAL_VOID));
v_ins = lir->insImm(JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID));
addr_ins = NULL;
return true;
}
@ -7674,7 +7673,7 @@ TraceRecorder::elem(jsval& oval, jsval& idx, jsval*& vp, LIns*& v_ins, LIns*& ad
if (JSVAL_TAG(*vp) == JSVAL_BOOLEAN) {
// Optimize to guard for a hole only after untagging, so we know that
// we have a boolean, to avoid an extra guard for non-boolean values.
guard(false, lir->ins2(LIR_eq, v_ins, INS_CONST(JSVAL_TO_BOOLEAN(JSVAL_HOLE))),
guard(false, lir->ins2(LIR_eq, v_ins, INS_CONST(JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_HOLE))),
MISMATCH_EXIT);
}
return true;
@ -8152,7 +8151,7 @@ TraceRecorder::record_JSOP_IN()
ABORT_TRACE("string or integer expected");
}
guard(false, lir->ins2i(LIR_eq, x, JSVAL_TO_BOOLEAN(JSVAL_VOID)), OOM_EXIT);
guard(false, lir->ins2i(LIR_eq, x, JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID)), OOM_EXIT);
x = lir->ins2i(LIR_eq, x, 1);
JSObject* obj2;
@ -8762,7 +8761,7 @@ TraceRecorder::record_JSOP_CALLPROP()
} else if (JSVAL_TAG(l) == JSVAL_BOOLEAN) {
if (l == JSVAL_VOID)
ABORT_TRACE("callprop on void");
guard(false, lir->ins2i(LIR_eq, get(&l), JSVAL_TO_BOOLEAN(JSVAL_VOID)), MISMATCH_EXIT);
guard(false, lir->ins2i(LIR_eq, get(&l), JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID)), MISMATCH_EXIT);
i = JSProto_Boolean;
debug_only(protoname = "Boolean.prototype";)
} else {
@ -8865,7 +8864,7 @@ TraceRecorder::record_JSOP_STOP()
JS_ASSERT(OBJECT_TO_JSVAL(fp->thisp) == fp->argv[-1]);
rval_ins = get(&fp->argv[-1]);
} else {
rval_ins = INS_CONST(JSVAL_TO_BOOLEAN(JSVAL_VOID));
rval_ins = INS_CONST(JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID));
}
clearFrameSlotsFromCache();
return true;
@ -8909,7 +8908,7 @@ TraceRecorder::record_JSOP_ENTERBLOCK()
JSObject* obj;
JS_GET_SCRIPT_OBJECT(script, GET_FULL_INDEX(0), obj);
LIns* void_ins = INS_CONST(JSVAL_TO_BOOLEAN(JSVAL_VOID));
LIns* void_ins = INS_CONST(JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID));
for (int i = 0, n = OBJ_BLOCK_COUNT(cx, obj); i < n; i++)
stack(i, void_ins);
return true;
@ -9272,7 +9271,7 @@ TraceRecorder::record_JSOP_NEWARRAY()
JS_REQUIRES_STACK bool
TraceRecorder::record_JSOP_HOLE()
{
stack(0, INS_CONST(JSVAL_TO_BOOLEAN(JSVAL_HOLE)));
stack(0, INS_CONST(JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_HOLE)));
return true;
}

Просмотреть файл

@ -183,7 +183,7 @@
# elif defined _MSC_VER
# define JS_ALWAYS_INLINE __forceinline
# elif defined __GNUC__
# define JS_ALWAYS_INLINE __attribute__((always_inline))
# define JS_ALWAYS_INLINE __attribute__((always_inline)) JS_INLINE
# else
# define JS_ALWAYS_INLINE JS_INLINE
# endif

Просмотреть файл

@ -4257,6 +4257,21 @@ function testInterpreterReentery8() {
}
test(testInterpreterReentery8);
function testHolePushing() {
var a = ["foobar", "baz"];
for (var i = 0; i < 5; i++)
a = [, "overwritten", "new"];
var s = "[";
for (i = 0; i < a.length; i++) {
s += (i in a) ? a[i] : "<hole>";
if (i != a.length - 1)
s += ",";
}
return s + "], " + (0 in a);
}
testHolePushing.expected = "[<hole>,overwritten,new], false";
test(testHolePushing);
/*****************************************************************************
* *
* _____ _ _ _____ ______ _____ _______ *

Просмотреть файл

@ -255,7 +255,8 @@ LookupGetterOrSetter(JSContext *cx, JSBool wantGetter, jsval *vp)
{
if(attrs & JSPROP_GETTER)
{
JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(getter));
JS_SET_RVAL(cx, vp,
OBJECT_TO_JSVAL(reinterpret_cast<JSObject *>(getter)));
return JS_TRUE;
}
}
@ -263,7 +264,8 @@ LookupGetterOrSetter(JSContext *cx, JSBool wantGetter, jsval *vp)
{
if(attrs & JSPROP_SETTER)
{
JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(setter));
JS_SET_RVAL(cx, vp,
OBJECT_TO_JSVAL(reinterpret_cast<JSObject *>(setter)));
return JS_TRUE;
}
}