This commit is contained in:
Andreas Gal 2008-07-30 16:37:35 -07:00
commit e91eb4bc47
9 changed files with 227 additions and 107 deletions

View File

@ -69,9 +69,6 @@
#include "jsxml.h"
#endif
#define JSSLOT_ITER_STATE (JSSLOT_PRIVATE)
#define JSSLOT_ITER_FLAGS (JSSLOT_PRIVATE + 1)
#if JSSLOT_ITER_FLAGS >= JS_INITIAL_NSLOTS
#error JS_INITIAL_NSLOTS must be greater than JSSLOT_ITER_FLAGS.
#endif
@ -225,11 +222,11 @@ IteratorNextImpl(JSContext *cx, JSObject *obj, jsval *rval)
iterable = OBJ_GET_PARENT(cx, obj);
JS_ASSERT(iterable);
state = OBJ_GET_SLOT(cx, obj, JSSLOT_ITER_STATE);
state = STOBJ_GET_SLOT(obj, JSSLOT_ITER_STATE);
if (JSVAL_IS_NULL(state))
goto stop;
flags = JSVAL_TO_INT(OBJ_GET_SLOT(cx, obj, JSSLOT_ITER_FLAGS));
flags = JSVAL_TO_INT(STOBJ_GET_SLOT(obj, JSSLOT_ITER_FLAGS));
JS_ASSERT(!(flags & JSITER_ENUMERATE));
foreach = (flags & JSITER_FOREACH) != 0;
ok =
@ -263,7 +260,7 @@ IteratorNextImpl(JSContext *cx, JSObject *obj, jsval *rval)
return JS_TRUE;
stop:
JS_ASSERT(OBJ_GET_SLOT(cx, obj, JSSLOT_ITER_STATE) == JSVAL_NULL);
JS_ASSERT(STOBJ_GET_SLOT(obj, JSSLOT_ITER_STATE) == JSVAL_NULL);
*rval = JSVAL_HOLE;
return JS_TRUE;
}
@ -319,7 +316,7 @@ js_GetNativeIteratorFlags(JSContext *cx, JSObject *iterobj)
{
if (OBJ_GET_CLASS(cx, iterobj) != &js_IteratorClass)
return 0;
return JSVAL_TO_INT(OBJ_GET_SLOT(cx, iterobj, JSSLOT_ITER_FLAGS));
return JSVAL_TO_INT(STOBJ_GET_SLOT(iterobj, JSSLOT_ITER_FLAGS));
}
/*
@ -598,7 +595,7 @@ js_CallIteratorNext(JSContext *cx, JSObject *iterobj, jsval *rval)
/* Fast path for native iterators */
if (OBJ_GET_CLASS(cx, iterobj) == &js_IteratorClass) {
flags = JSVAL_TO_INT(OBJ_GET_SLOT(cx, iterobj, JSSLOT_ITER_FLAGS));
flags = JSVAL_TO_INT(STOBJ_GET_SLOT(iterobj, JSSLOT_ITER_FLAGS));
if (flags & JSITER_ENUMERATE)
return CallEnumeratorNext(cx, iterobj, flags, rval);

View File

@ -57,6 +57,12 @@ JS_BEGIN_EXTERN_C
#define JSITER_FOREACH 0x2 /* return [key, value] pair rather than key */
#define JSITER_KEYVALUE 0x4 /* destructuring for-in wants [key, value] */
/*
* Native iterator object slots, shared between jsiter.cpp and jstracer.cpp.
*/
#define JSSLOT_ITER_STATE (JSSLOT_PRIVATE)
#define JSSLOT_ITER_FLAGS (JSSLOT_PRIVATE + 1)
/*
* Convert the value stored in *vp to its iteration object. The flags should
* contain JSITER_ENUMERATE if js_ValueToIterator is called when enumerating

View File

@ -4129,20 +4129,6 @@ out:
return JS_TRUE;
}
/*
* Private type used to enumerate properties of a native JS object. It is not
* allocated when there are no enumerable properties in the object. Instead
* for empty enumerators the code uses JSVAL_ZERO as the enumeration state.
*/
struct JSNativeEnumerator {
uint32 cursor; /* index into ids array, runs from
length down to 0 */
uint32 length; /* length of ids array */
JSNativeEnumerator *next; /* double-linked list support */
JSNativeEnumerator **prevp;
jsid ids[1]; /* enumeration id array */
};
/*
* This function is used to enumerate the properties of native JSObjects
* and those host objects that do not define a JSNewEnumerateOp-style iterator

View File

@ -609,6 +609,22 @@ js_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *rval);
extern JSBool
js_DefaultValue(JSContext *cx, JSObject *obj, JSType hint, jsval *vp);
/*
* Private type used to enumerate properties of a native JS object. It is not
* allocated when there are no enumerable properties in the object. Instead for
* empty enumerators js_Enumerate uses JSVAL_ZERO as the enumeration state.
*
* Shared between jsobj.cpp and jstracer.cpp.
*/
struct JSNativeEnumerator {
uint32 cursor; /* index into ids array, runs from
length down to 0 */
uint32 length; /* length of ids array */
JSNativeEnumerator *next; /* double-linked list support */
JSNativeEnumerator **prevp;
jsid ids[1]; /* enumeration id array */
};
extern JSBool
js_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
jsval *statep, jsid *idp);

View File

@ -410,6 +410,10 @@ js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc,
i = (jsint)GET_UINT24(pc);
goto print_int;
case JOF_UINT8:
i = pc[1];
goto print_int;
case JOF_INT8:
i = GET_INT8(pc);
goto print_int;

View File

@ -76,7 +76,7 @@ typedef enum JSOp {
#define JOF_TABLESWITCHX 10 /* extended (32-bit offset) table switch */
#define JOF_LOOKUPSWITCHX 11 /* extended (32-bit offset) lookup switch */
#define JOF_UINT24 12 /* extended unsigned 24-bit literal (index) */
#define JOF_2BYTE 13 /* 2-byte opcode, e.g., upper 8 bits of 24-bit
#define JOF_UINT8 13 /* uint8 immediate, e.g. top 8 bits of 24-bit
atom index */
#define JOF_LOCAL 14 /* block-local operand stack variable */
#define JOF_OBJECT 15 /* unsigned 16-bit object pool index */

View File

@ -237,7 +237,7 @@ OPDEF(JSOP_VARDEC, 102,"vardec", NULL, 3, 0, 1, 15, JOF_QVAR |
* Initialize for-in iterator using the JSITER_* flag bits in this op's uint8
* immediate operand. See also JSOP_ENDITER.
*/
OPDEF(JSOP_ITER, 103,"iter", NULL, 2, 1, 1, 0, JOF_2BYTE)
OPDEF(JSOP_ITER, 103,"iter", NULL, 2, 1, 1, 0, JOF_UINT8)
/* ECMA-compliant for/in ops. */
OPDEF(JSOP_FORNAME, 104,"forname", NULL, 3, 0, 1, 19, JOF_ATOM|JOF_NAME|JOF_FOR)
@ -425,7 +425,7 @@ OPDEF(JSOP_UINT24, 188,"uint24", NULL, 4, 0, 1, 16, JOF_UINT24
* JSOP_INDEXBASE and JSOP_RESETBASE to provide the upper bits of the index.
* See jsemit.c, EmitIndexOp.
*/
OPDEF(JSOP_INDEXBASE, 189,"atombase", NULL, 2, 0, 0, 0, JOF_2BYTE|JOF_INDEXBASE)
OPDEF(JSOP_INDEXBASE, 189,"atombase", NULL, 2, 0, 0, 0, JOF_UINT8|JOF_INDEXBASE)
OPDEF(JSOP_RESETBASE, 190,"resetbase", NULL, 1, 0, 0, 0, JOF_BYTE)
OPDEF(JSOP_RESETBASE0, 191,"resetbase0", NULL, 1, 0, 0, 0, JOF_BYTE)

View File

@ -54,6 +54,7 @@
#include "jscntxt.h"
#include "jsfun.h"
#include "jsinterp.h"
#include "jsiter.h"
#include "jsobj.h"
#include "jsopcode.h"
#include "jsscript.h"
@ -1079,13 +1080,13 @@ TraceRecorder::verifyTypeStability()
uint16* gslots = treeInfo->globalSlots.data();
uint8* m = treeInfo->globalTypeMap.data();
JS_ASSERT(treeInfo->globalTypeMap.length() == ngslots);
FORALL_GLOBAL_SLOTS(cx, ngslots, gslots,
FORALL_GLOBAL_SLOTS(cx, ngslots, gslots,
if (!checkType(*vp, *m))
return false;
++m
);
m = treeInfo->stackTypeMap.data();
FORALL_SLOTS_IN_PENDING_FRAMES(cx, callDepth,
FORALL_SLOTS_IN_PENDING_FRAMES(cx, callDepth,
if (!checkType(*vp, *m))
return false;
++m
@ -1192,11 +1193,11 @@ js_DeleteRecorder(JSContext* cx)
}
static bool
js_StartRecorder(JSContext* cx, GuardRecord* anchor, Fragment* f,
js_StartRecorder(JSContext* cx, GuardRecord* anchor, Fragment* f,
unsigned ngslots, uint8* globalTypeMap, uint8* stackTypeMap)
{
/* start recording if no exception during construction */
JS_TRACE_MONITOR(cx).recorder = new (&gc) TraceRecorder(cx, anchor, f,
JS_TRACE_MONITOR(cx).recorder = new (&gc) TraceRecorder(cx, anchor, f,
ngslots, globalTypeMap, stackTypeMap);
if (cx->throwing) {
js_AbortRecording(cx, NULL, "setting up recorder failed");
@ -1394,7 +1395,7 @@ js_LoopEdge(JSContext* cx, jsbytecode* oldpc)
JS_ASSERT(ti->entryStackDepth == unsigned(cx->fp->regs->sp - StackBase(cx->fp)));
/* recording primary trace */
return js_StartRecorder(cx, NULL, f, ti->globalSlots.length(),
return js_StartRecorder(cx, NULL, f, ti->globalSlots.length(),
ti->globalTypeMap.data(), ti->stackTypeMap.data());
}
return false;
@ -1414,7 +1415,7 @@ js_LoopEdge(JSContext* cx, jsbytecode* oldpc)
return false;
default:
JS_ASSERT(lr->exit->exitType == DONT_GROW);
/* We ran out of heap, or an unsupported instruction. Exit for now and re-enter once the
/* We ran out of heap, or an unsupported instruction. Exit for now and re-enter once the
GC ran. */
return false;
}
@ -1714,15 +1715,15 @@ TraceRecorder::binary(LOpcode op)
}
bool
TraceRecorder::map_is_native(JSObjectMap* map, LIns* map_ins)
TraceRecorder::map_is_native(JSObjectMap* map, LIns* map_ins, LIns*& ops_ins)
{
LIns* ops = addName(lir->insLoadi(map_ins, offsetof(JSObjectMap, ops)), "ops");
ops_ins = addName(lir->insLoadi(map_ins, offsetof(JSObjectMap, ops)), "ops");
if (map->ops == &js_ObjectOps) {
guard(true, addName(lir->ins2(LIR_eq, ops, lir->insImmPtr(&js_ObjectOps)),
guard(true, addName(lir->ins2(LIR_eq, ops_ins, lir->insImmPtr(&js_ObjectOps)),
"guard(native-ops)"));
return true;
}
LIns* n = lir->insLoadi(ops, offsetof(JSObjectOps, newObjectMap));
LIns* n = lir->insLoadi(ops_ins, offsetof(JSObjectOps, newObjectMap));
if (map->ops->newObjectMap == js_ObjectOps.newObjectMap) {
guard(true, addName(lir->ins2(LIR_eq, n, lir->insImmPtr((void*)js_ObjectOps.newObjectMap)),
"guard(native-map)"));
@ -1735,7 +1736,8 @@ bool
TraceRecorder::test_property_cache(JSObject* obj, LIns* obj_ins, JSObject*& obj2, jsuword& pcval)
{
LIns* map_ins = lir->insLoadi(obj_ins, offsetof(JSObject, map));
if (!map_is_native(obj->map, map_ins))
LIns* ops_ins;
if (!map_is_native(obj->map, map_ins, ops_ins))
return false;
JSAtom* atom;
@ -1775,9 +1777,10 @@ TraceRecorder::test_property_cache(JSObject* obj, LIns* obj_ins, JSObject*& obj2
if (PCVCAP_TAG(entry->vcap) == 1) {
JS_ASSERT(OBJ_SCOPE(obj2)->shape == PCVCAP_SHAPE(entry->vcap));
LIns* obj2_ins = get(&STOBJ_GET_SLOT(obj, JSSLOT_PROTO));
LIns* obj2_ins = stobj_get_fslot(obj_ins, JSSLOT_PROTO);
map_ins = lir->insLoadi(obj2_ins, offsetof(JSObject, map));
if (!map_is_native(obj2->map, map_ins))
LIns* ops_ins;
if (!map_is_native(obj2->map, map_ins, ops_ins))
return false;
shape_ins = addName(lir->insLoadi(map_ins, offsetof(JSScope, shape)), "shape");
@ -1869,13 +1872,18 @@ TraceRecorder::stobj_set_slot(LIns* obj_ins, unsigned slot, LIns*& dslots_ins, L
}
}
LIns*
TraceRecorder::stobj_get_fslot(LIns* obj_ins, unsigned slot)
{
JS_ASSERT(slot < JS_INITIAL_NSLOTS);
return lir->insLoadi(obj_ins, offsetof(JSObject, fslots) + slot * sizeof(jsval));
}
LIns*
TraceRecorder::stobj_get_slot(LIns* obj_ins, unsigned slot, LIns*& dslots_ins)
{
if (slot < JS_INITIAL_NSLOTS) {
return lir->insLoadi(obj_ins,
offsetof(JSObject, fslots) + slot * sizeof(jsval));
}
if (slot < JS_INITIAL_NSLOTS)
return stobj_get_fslot(obj_ins, slot);
if (!dslots_ins)
dslots_ins = lir->insLoadi(obj_ins, offsetof(JSObject, dslots));
@ -1984,35 +1992,40 @@ TraceRecorder::getThis(LIns*& this_ins)
}
bool
TraceRecorder::guardThatObjectHasClass(JSObject* obj, LIns* obj_ins,
JSClass* cls, LIns*& dslots_ins)
TraceRecorder::guardClass(JSObject* obj, LIns* obj_ins, JSClass* clasp)
{
if (STOBJ_GET_CLASS(obj) != cls)
if (STOBJ_GET_CLASS(obj) != clasp)
return false;
LIns* class_ins = stobj_get_slot(obj_ins, JSSLOT_CLASS, dslots_ins);
LIns* class_ins = stobj_get_fslot(obj_ins, JSSLOT_CLASS);
class_ins = lir->ins2(LIR_and, class_ins, lir->insImmPtr((void*)~3));
guard(true, lir->ins2(LIR_eq, class_ins, lir->insImmPtr(cls)));
char namebuf[32];
JS_snprintf(namebuf, sizeof namebuf, "guard(class is %s)", clasp->name);
guard(true, addName(lir->ins2(LIR_eq, class_ins, lir->insImmPtr(clasp)), namebuf));
return true;
}
bool TraceRecorder::guardThatObjectIsDenseArray(JSObject* obj, LIns* obj_ins, LIns*& dslots_ins)
bool TraceRecorder::guardDenseArray(JSObject* obj, LIns* obj_ins)
{
return guardThatObjectHasClass(obj, obj_ins, &js_ArrayClass, dslots_ins);
return guardClass(obj, obj_ins, &js_ArrayClass);
}
bool TraceRecorder::guardDenseArrayIndexWithinBounds(JSObject* obj, jsint idx,
LIns* obj_ins, LIns*& dslots_ins, LIns* idx_ins)
bool TraceRecorder::guardDenseArrayIndex(JSObject* obj, jsint idx, LIns* obj_ins,
LIns* dslots_ins, LIns* idx_ins)
{
jsuint length = ARRAY_DENSE_LENGTH(obj);
if (!((jsuint)idx < length && idx < obj->fslots[JSSLOT_ARRAY_LENGTH]))
return false;
if (!dslots_ins)
dslots_ins = lir->insLoadi(obj_ins, offsetof(JSObject, dslots));
LIns* length_ins = stobj_get_slot(obj_ins, JSSLOT_ARRAY_LENGTH, dslots_ins);
LIns* length_ins = stobj_get_fslot(obj_ins, JSSLOT_ARRAY_LENGTH);
// guard(index >= 0)
guard(true, lir->ins2i(LIR_ge, idx_ins, 0));
// guard(index < length)
guard(true, lir->ins2(LIR_lt, idx_ins, length_ins));
// guard(index < capacity)
guard(false, lir->ins_eq0(dslots_ins));
guard(true, lir->ins2(LIR_lt, idx_ins,
@ -2103,14 +2116,7 @@ bool TraceRecorder::record_JSOP_ARGUMENTS()
{
return false;
}
bool TraceRecorder::record_JSOP_FORARG()
{
return false;
}
bool TraceRecorder::record_JSOP_FORVAR()
{
return false;
}
bool TraceRecorder::record_JSOP_DUP()
{
stack(0, get(&stackval(-1)));
@ -2342,7 +2348,8 @@ bool TraceRecorder::record_JSOP_SETPROP()
ABORT_TRACE("cache miss");
LIns* map_ins = lir->insLoadi(obj_ins, offsetof(JSObject, map));
if (!map_is_native(obj->map, map_ins))
LIns* ops_ins;
if (!map_is_native(obj->map, map_ins, ops_ins))
return false;
if (obj != globalObj) { // global object's shape is guarded at trace entry
@ -2404,8 +2411,7 @@ bool TraceRecorder::record_JSOP_SETELEM()
LIns* obj_ins = get(&l);
/* make sure the object is actually a dense array */
LIns* dslots_ins = lir->insLoadi(obj_ins, offsetof(JSObject, dslots));
if (!guardThatObjectIsDenseArray(obj, obj_ins, dslots_ins))
if (!guardDenseArray(obj, obj_ins))
ABORT_TRACE("not a dense array");
/* check that the index is within bounds */
@ -2448,7 +2454,7 @@ bool TraceRecorder::record_JSOP_CALLNAME()
}
JSInlineFrame*
TraceRecorder::synthesizeFrame(JSObject* callee, JSObject *thisp, jsbytecode* pc)
TraceRecorder::synthesizeFrame(JSObject* callee, JSObject* thisp, jsbytecode* pc)
{
JS_ASSERT(HAS_FUNCTION_CLASS(callee));
@ -2549,7 +2555,7 @@ bool TraceRecorder::record_JSOP_CALL()
ABORT_TRACE("can't trace function calls with arity mismatch");
unsigned callDepth = getCallDepth();
lir->insStorei(lir->insImmPtr(JSVAL_TO_OBJECT(fval)),
lirbuf->rp, callDepth * sizeof(JSObject*));
lirbuf->rp, callDepth * sizeof(JSObject*));
if (callDepth+1 > treeInfo->maxCallDepth)
treeInfo->maxCallDepth = callDepth+1;
atoms = fun->u.i.script->atomMap.vector;
@ -2711,8 +2717,7 @@ TraceRecorder::elem(jsval& l, jsval& r, jsval*& vp, LIns*& v_ins, LIns*& addr_in
guard(false, lir->ins2(LIR_eq, obj_ins, lir->insImmPtr((void*)globalObj)));
/* make sure the object is actually a dense array */
LIns* dslots_ins = lir->insLoadi(obj_ins, offsetof(JSObject, dslots));
if (!guardThatObjectIsDenseArray(obj, obj_ins, dslots_ins))
if (!guardDenseArray(obj, obj_ins))
return false;
/* check that the index is within bounds */
@ -2722,12 +2727,15 @@ TraceRecorder::elem(jsval& l, jsval& r, jsval*& vp, LIns*& v_ins, LIns*& addr_in
/* we have to check that its really an integer, but this check will to go away
once we peel the loop type down to integer for this slot */
guard(true, lir->ins2(LIR_feq, get(&r), lir->ins1(LIR_i2f, idx_ins)));
if (!guardDenseArrayIndexWithinBounds(obj, idx, obj_ins, dslots_ins, idx_ins))
LIns* dslots_ins = lir->insLoadi(obj_ins, offsetof(JSObject, dslots));
if (!guardDenseArrayIndex(obj, idx, obj_ins, dslots_ins, idx_ins))
return false;
vp = &obj->dslots[idx];
addr_ins = lir->ins2(LIR_add, dslots_ins,
lir->ins2i(LIR_lsh, idx_ins, sizeof(jsval) == 4 ? 2 : 3));
lir->ins2i(LIR_lsh, idx_ins, (sizeof(jsval) == 4) ? 2 : 3));
/* load the value, check the type (need to check JSVAL_HOLE only for booleans) */
v_ins = lir->insLoad(LIR_ld, addr_ins, 0);
return unbox_jsval(*vp, v_ins);
@ -2878,38 +2886,47 @@ bool TraceRecorder::record_JSOP_OBJECT()
{
return false;
}
bool TraceRecorder::record_JSOP_POP()
{
return true;
}
bool TraceRecorder::record_JSOP_POS()
{
return false;
jsval& r = stackval(-1);
return isNumber(r);
}
bool TraceRecorder::record_JSOP_TRAP()
{
return false;
}
bool TraceRecorder::record_JSOP_GETARG()
{
stack(0, arg(GET_ARGNO(cx->fp->regs->pc)));
return true;
}
bool TraceRecorder::record_JSOP_SETARG()
{
arg(GET_ARGNO(cx->fp->regs->pc), stack(-1));
return true;
}
bool TraceRecorder::record_JSOP_GETVAR()
{
stack(0, var(GET_SLOTNO(cx->fp->regs->pc)));
return true;
}
bool TraceRecorder::record_JSOP_SETVAR()
{
var(GET_SLOTNO(cx->fp->regs->pc), stack(-1));
return true;
}
bool TraceRecorder::record_JSOP_UINT16()
{
jsdpun u;
@ -2917,82 +2934,190 @@ bool TraceRecorder::record_JSOP_UINT16()
stack(0, lir->insImmq(u.u64));
return true;
}
bool TraceRecorder::record_JSOP_NEWINIT()
{
return false;
}
bool TraceRecorder::record_JSOP_ENDINIT()
{
return false;
}
bool TraceRecorder::record_JSOP_INITPROP()
{
return false;
}
bool TraceRecorder::record_JSOP_INITELEM()
{
return false;
}
bool TraceRecorder::record_JSOP_DEFSHARP()
{
return false;
}
bool TraceRecorder::record_JSOP_USESHARP()
{
return false;
}
bool TraceRecorder::record_JSOP_INCARG()
{
return inc(argval(GET_ARGNO(cx->fp->regs->pc)), 1);
}
bool TraceRecorder::record_JSOP_INCVAR()
{
return inc(varval(GET_SLOTNO(cx->fp->regs->pc)), 1);
}
bool TraceRecorder::record_JSOP_DECARG()
{
return inc(argval(GET_ARGNO(cx->fp->regs->pc)), -1);
}
bool TraceRecorder::record_JSOP_DECVAR()
{
return inc(varval(GET_SLOTNO(cx->fp->regs->pc)), -1);
}
bool TraceRecorder::record_JSOP_ARGINC()
{
return inc(argval(GET_ARGNO(cx->fp->regs->pc)), 1, false);
}
bool TraceRecorder::record_JSOP_VARINC()
{
return inc(varval(GET_SLOTNO(cx->fp->regs->pc)), 1, false);
}
bool TraceRecorder::record_JSOP_ARGDEC()
{
return inc(argval(GET_ARGNO(cx->fp->regs->pc)), -1, false);
}
bool TraceRecorder::record_JSOP_VARDEC()
{
return inc(varval(GET_SLOTNO(cx->fp->regs->pc)), -1, false);
}
bool TraceRecorder::record_JSOP_ITER()
{
return true;
}
bool TraceRecorder::forInProlog(LIns*& iterobj_ins)
{
jsval& iterval = stackval(-1);
JS_ASSERT(!JSVAL_IS_PRIMITIVE(iterval));
JSObject* iterobj = JSVAL_TO_OBJECT(iterval);
iterobj_ins = get(&iterval);
if (guardClass(iterobj, iterobj_ins, &js_IteratorClass)) {
uintN flags = JSVAL_TO_INT(iterobj->fslots[JSSLOT_ITER_FLAGS]);
if (flags & ~JSITER_ENUMERATE)
ABORT_TRACE("for-each-in or destructuring JSOP_ITER not traced");
guard(true,
addName(lir->ins_eq0(lir->ins2(LIR_and,
lir->insLoadi(iterobj_ins,
offsetof(JSObject, fslots) +
JSSLOT_ITER_FLAGS * sizeof(jsval)),
lir->insImm(~JSITER_ENUMERATE))),
"guard(iter flags is JSITER_ENUMERATE)"));
JSObject* obj = STOBJ_GET_PARENT(iterobj);
LIns* obj_ins = stobj_get_fslot(iterobj_ins, JSSLOT_PARENT);
LIns* map_ins = lir->insLoadi(obj_ins, offsetof(JSObject, map));
LIns* ops_ins;
if (!map_is_native(obj->map, map_ins, ops_ins))
return false;
LIns* n = lir->insLoadi(ops_ins, offsetof(JSObjectOps, enumerate));
if (obj->map->ops->enumerate == js_ObjectOps.enumerate) {
guard(true, addName(lir->ins2(LIR_eq, n, lir->insImmPtr((void*)js_ObjectOps.enumerate)),
"guard(native-enumerate)"));
return true;
}
}
return false;
}
bool TraceRecorder::record_JSOP_ENDITER()
{
return true;
}
bool TraceRecorder::record_JSOP_FORNAME()
{
return false;
}
bool TraceRecorder::record_JSOP_FORPROP()
{
return false;
}
bool TraceRecorder::record_JSOP_FORELEM()
{
return false;
}
bool TraceRecorder::record_JSOP_FORARG()
{
return false;
}
bool TraceRecorder::record_JSOP_FORVAR()
{
LIns* iterobj_ins;
if (!forInProlog(iterobj_ins))
return false;
LIns* stateval_ins = stobj_get_fslot(iterobj_ins, JSSLOT_ITER_STATE);
guard(false,
addName(lir->ins2(LIR_eq, stateval_ins, lir->insImmPtr((void*) JSVAL_ZERO)),
"guard(non-empty iter state)"));
LIns* state_ins = lir->ins2(LIR_and, stateval_ins, lir->insImmPtr((void*) ~3));
LIns* cursor_ins = lir->insLoadi(state_ins, offsetof(JSNativeEnumerator, cursor));
guard(false, addName(lir->ins_eq0(cursor_ins), "guard(ne->cursor != 0)"));
cursor_ins = lir->ins2i(LIR_sub, cursor_ins, 1);
lir->insStorei(cursor_ins, state_ins, offsetof(JSNativeEnumerator, cursor));
LIns* ids_ins = lir->ins2i(LIR_add, state_ins, offsetof(JSNativeEnumerator, ids));
LIns* id_addr_ins = lir->ins2(LIR_add, ids_ins,
lir->ins2i(LIR_lsh, cursor_ins, (sizeof(jsid) == 4) ? 2 : 3));
LIns* id_ins = lir->insLoadi(id_addr_ins, 0);
var(GET_SLOTNO(cx->fp->regs->pc), id_ins);
// Stack an unboxed true to make JSOP_IFEQ loop.
stack(0, lir->insImm(1));
return true;
}
bool TraceRecorder::record_JSOP_FORLOCAL()
{
return false;
}
bool TraceRecorder::record_JSOP_FORCONST()
{
return false;
}
bool TraceRecorder::record_JSOP_POPN()
{
return true;
}
bool TraceRecorder::record_JSOP_BINDNAME()
{
JSObject* obj = cx->fp->scopeChain;
@ -3241,6 +3366,7 @@ bool TraceRecorder::record_JSOP_RETRVAL()
{
return false;
}
bool TraceRecorder::record_JSOP_GETGVAR()
{
jsval slotval = cx->fp->slots[GET_SLOTNO(cx->fp->regs->pc)];
@ -3251,7 +3377,7 @@ bool TraceRecorder::record_JSOP_GETGVAR()
if (!lazilyImportGlobalSlot(slot))
ABORT_TRACE("lazy import of global slot failed");
stack(0, get(&STOBJ_GET_SLOT(cx->fp->scopeChain, slot)));
return true;
}
@ -3266,7 +3392,7 @@ bool TraceRecorder::record_JSOP_SETGVAR()
if (!lazilyImportGlobalSlot(slot))
ABORT_TRACE("lazy import of global slot failed");
set(&STOBJ_GET_SLOT(cx->fp->scopeChain, slot), stack(-1));
return true;
}
@ -3278,10 +3404,10 @@ bool TraceRecorder::record_JSOP_INCGVAR()
return true; // We will see JSOP_INCNAME from the interpreter's jump, so no-op here.
uint32 slot = JSVAL_TO_INT(slotval);
if (!lazilyImportGlobalSlot(slot))
ABORT_TRACE("lazy import of global slot failed");
return inc(STOBJ_GET_SLOT(cx->fp->scopeChain, slot), 1);
}
@ -3292,10 +3418,10 @@ bool TraceRecorder::record_JSOP_DECGVAR()
return true; // We will see JSOP_INCNAME from the interpreter's jump, so no-op here.
uint32 slot = JSVAL_TO_INT(slotval);
if (!lazilyImportGlobalSlot(slot))
ABORT_TRACE("lazy import of global slot failed");
return inc(STOBJ_GET_SLOT(cx->fp->scopeChain, slot), -1);
}
@ -3309,7 +3435,7 @@ bool TraceRecorder::record_JSOP_GVARINC()
if (!lazilyImportGlobalSlot(slot))
ABORT_TRACE("lazy import of global slot failed");
return inc(STOBJ_GET_SLOT(cx->fp->scopeChain, slot), 1, false);
}
@ -3323,7 +3449,7 @@ bool TraceRecorder::record_JSOP_GVARDEC()
if (!lazilyImportGlobalSlot(slot))
ABORT_TRACE("lazy import of global slot failed");
return inc(STOBJ_GET_SLOT(cx->fp->scopeChain, slot), -1, false);
}
@ -3614,21 +3740,6 @@ bool TraceRecorder::record_JSOP_LOCALDEC()
return false;
}
bool TraceRecorder::record_JSOP_FORLOCAL()
{
return false;
}
bool TraceRecorder::record_JSOP_FORCONST()
{
return false;
}
bool TraceRecorder::record_JSOP_ENDITER()
{
return false;
}
bool TraceRecorder::record_JSOP_GENERATOR()
{
return false;
@ -3757,13 +3868,12 @@ bool TraceRecorder::record_JSOP_LENGTH()
return true;
}
JSObject *obj = JSVAL_TO_OBJECT(l);
JSObject* obj = JSVAL_TO_OBJECT(l);
if (!OBJ_IS_DENSE_ARRAY(cx, obj))
ABORT_TRACE("only dense arrays supported");
LIns* dslots_ins;
if (!guardThatObjectIsDenseArray(obj, get(&l), dslots_ins))
if (!guardDenseArray(obj, get(&l)))
ABORT_TRACE("OBJ_IS_DENSE_ARRAY but not?!?");
LIns* v_ins = lir->ins1(LIR_i2f, stobj_get_slot(get(&l), JSSLOT_ARRAY_LENGTH, dslots_ins));
LIns* v_ins = lir->ins1(LIR_i2f, stobj_get_fslot(get(&l), JSSLOT_ARRAY_LENGTH));
set(&l, v_ins);
return true;
}

View File

@ -226,11 +226,13 @@ class TraceRecorder {
bool bbinary(nanojit::LOpcode op);
void demote(jsval& v, jsdouble result);
bool map_is_native(JSObjectMap* map, nanojit::LIns* map_ins);
bool test_property_cache(JSObject* obj, nanojit::LIns* obj_ins, JSObject*& obj2, jsuword& pcval);
bool map_is_native(JSObjectMap* map, nanojit::LIns* map_ins, nanojit::LIns*& ops_ins);
bool test_property_cache(JSObject* obj, nanojit::LIns* obj_ins, JSObject*& obj2,
jsuword& pcval);
bool test_property_cache_direct_slot(JSObject* obj, nanojit::LIns* obj_ins, uint32& slot);
void stobj_set_slot(nanojit::LIns* obj_ins, unsigned slot,
nanojit::LIns*& dslots_ins, nanojit::LIns* v_ins);
nanojit::LIns* stobj_get_fslot(nanojit::LIns* obj_ins, unsigned slot);
nanojit::LIns* stobj_get_slot(nanojit::LIns* obj_ins, unsigned slot,
nanojit::LIns*& dslots_ins);
bool native_set(nanojit::LIns* obj_ins, JSScopeProperty* sprop,
@ -247,13 +249,12 @@ class TraceRecorder {
bool box_jsval(jsval v, nanojit::LIns*& v_ins);
bool unbox_jsval(jsval v, nanojit::LIns*& v_ins);
bool guardThatObjectHasClass(JSObject* obj, nanojit::LIns* obj_ins,
JSClass* cls, nanojit::LIns*& dslots_ins);
bool guardThatObjectIsDenseArray(JSObject* obj, nanojit::LIns* obj_ins,
nanojit::LIns*& dslots_ins);
bool guardDenseArrayIndexWithinBounds(JSObject* obj, jsint idx, nanojit::LIns* obj_ins,
nanojit::LIns*& dslots_ins, nanojit::LIns* idx_ins);
bool guardClass(JSObject* obj, nanojit::LIns* obj_ins, JSClass* clasp);
bool guardDenseArray(JSObject* obj, nanojit::LIns* obj_ins);
bool guardDenseArrayIndex(JSObject* obj, jsint idx, nanojit::LIns* obj_ins,
nanojit::LIns* dslots_ins, nanojit::LIns* idx_ins);
void clearFrameSlotsFromCache();
bool forInProlog(nanojit::LIns*& iterobj_ins);
public:
int backEdgeCount;