Record JSOP_IN (452563, r=gal).

This commit is contained in:
Brendan Eich 2008-08-28 00:18:05 -07:00
parent 044f0f4026
commit bea371d215
5 changed files with 144 additions and 22 deletions

View File

@ -76,6 +76,7 @@ BUILTIN2(CloseIterator, LO, LO, LO, bool, JSContext*, jsval, 0,
BUILTIN2(CallTree, LO, LO, P, nanojit::GuardRecord*, avmplus::InterpState*, nanojit::Fragment*, 0, 0)
BUILTIN2(FastNewObject, LO, LO, P, JSObject*, JSContext*, JSObject*, 0, 0)
BUILTIN3(AddProperty, LO, LO, LO, LO, bool, JSContext*, JSObject*, JSScopeProperty*, 0, 0)
BUILTIN3(HasNamedProperty, LO, LO, LO, LO, bool, JSContext*, JSObject*, JSString*, 0, 0)
BUILTIN3(CallGetter, LO, LO, LO, P, jsval, JSContext*, JSObject*, JSScopeProperty*, 0, 0)
BUILTIN2(TypeOfObject, LO, LO, P, JSString*, JSContext*, JSObject*, 1, 1)
BUILTIN2(TypeOfBoolean, LO, LO, P, JSString*, JSContext*, jsint, 1, 1)

View File

@ -530,6 +530,22 @@ js_AddProperty(JSContext* cx, JSObject* obj, JSScopeProperty* sprop)
return false;
}
bool FASTCALL
js_HasNamedProperty(JSContext* cx, JSObject* obj, JSString* idstr)
{
jsid id;
if (!js_ValueToStringId(cx, STRING_TO_JSVAL(idstr), &id))
return JSVAL_ERROR_COOKIE;
JSObject* obj2;
JSProperty* prop;
if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop))
return JSVAL_TO_BOOLEAN(JSVAL_VOID);
if (prop)
OBJ_DROP_PROPERTY(cx, obj2, prop);
return prop != NULL;
}
jsval FASTCALL
js_CallGetter(JSContext* cx, JSObject* obj, JSScopeProperty* sprop)
{

View File

@ -3127,6 +3127,23 @@ js_Interpret(JSContext *cx)
} \
JS_END_MACRO
#define TRY_BRANCH_AFTER_COND(cond,spdec) \
JS_BEGIN_MACRO \
uintN diff_; \
JS_ASSERT(js_CodeSpec[op].length == 1); \
diff_ = (uintN) regs.pc[1] - (uintN) JSOP_IFEQ; \
if (diff_ <= 1) { \
regs.sp -= spdec; \
if (cond == (diff_ != 0)) { \
++regs.pc; \
len = GET_JUMP_OFFSET(regs.pc); \
BRANCH(len); \
} \
len = 1 + JSOP_IFEQ_LENGTH; \
DO_NEXT_OP(len); \
} \
JS_END_MACRO
BEGIN_CASE(JSOP_IN)
rval = FETCH_OPND(-1);
if (JSVAL_IS_PRIMITIVE(rval)) {
@ -3137,10 +3154,12 @@ js_Interpret(JSContext *cx)
FETCH_ELEMENT_ID(obj, -2, id);
if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop))
goto error;
regs.sp--;
STORE_OPND(-1, BOOLEAN_TO_JSVAL(prop != NULL));
cond = prop != NULL;
if (prop)
OBJ_DROP_PROPERTY(cx, obj2, prop);
TRY_BRANCH_AFTER_COND(cond, 2);
regs.sp--;
STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond));
END_CASE(JSOP_IN)
BEGIN_CASE(JSOP_ITER)
@ -3484,23 +3503,6 @@ js_Interpret(JSContext *cx)
BITWISE_OP(&);
END_CASE(JSOP_BITAND)
#define TRY_BRANCH_AFTER_COND(cond,spdec) \
JS_BEGIN_MACRO \
uintN diff_; \
JS_ASSERT(js_CodeSpec[op].length == 1); \
diff_ = (uintN) regs.pc[1] - (uintN) JSOP_IFEQ; \
if (diff_ <= 1) { \
regs.sp -= spdec; \
if (cond == (diff_ != 0)) { \
++regs.pc; \
len = GET_JUMP_OFFSET(regs.pc); \
BRANCH(len); \
} \
len = 1 + JSOP_IFEQ_LENGTH; \
DO_NEXT_OP(len); \
} \
JS_END_MACRO
#define RELATIONAL_OP(OP) \
JS_BEGIN_MACRO \
rval = FETCH_OPND(-1); \

View File

@ -2420,7 +2420,9 @@ TraceRecorder::ifop()
jsdouble d = asNumber(v);
jsdpun u;
u.d = 0;
guard((d == 0 || JSDOUBLE_IS_NaN(d)), lir->ins2(LIR_feq, get(&v), lir->insImmq(u.u64)), BRANCH_EXIT);
guard(d == 0 || JSDOUBLE_IS_NaN(d),
lir->ins2(LIR_feq, get(&v), lir->insImmq(u.u64)),
BRANCH_EXIT);
} else if (JSVAL_IS_STRING(v)) {
guard(JSSTRING_LENGTH(JSVAL_TO_STRING(v)) == 0,
lir->ins_eq0(lir->ins2(LIR_piand,
@ -3782,7 +3784,7 @@ TraceRecorder::record_JSOP_SETPROP()
JSObject* obj = JSVAL_TO_OBJECT(l);
if (obj->map->ops->setProperty != js_SetProperty)
ABORT_TRACE("non-native setProperty");
ABORT_TRACE("non-native JSObjectOps::setProperty");
LIns* obj_ins = get(&l);
@ -4881,7 +4883,82 @@ TraceRecorder::record_JSOP_THROW()
bool
TraceRecorder::record_JSOP_IN()
{
return false;
jsval& rval = stackval(-1);
if (JSVAL_IS_PRIMITIVE(rval))
ABORT_TRACE("JSOP_IN on non-object right operand");
jsval& lval = stackval(-2);
if (!JSVAL_IS_PRIMITIVE(lval))
ABORT_TRACE("JSOP_IN on E4X QName left operand");
jsid id;
if (JSVAL_IS_INT(lval)) {
id = INT_JSVAL_TO_JSID(lval);
} else {
if (!js_ValueToStringId(cx, lval, &id))
ABORT_TRACE("OOM under js_ValueToStringId in JSOP_IN");
lval = ID_TO_VALUE(id);
}
// Expect what we see at trace recording time (hit or miss) to be the same
// when executing the trace. Use a builtin helper for named properties, as
// forInLoop does. First, handle indexes in dense arrays as a special case.
JSObject* obj = JSVAL_TO_OBJECT(rval);
LIns* obj_ins = get(&rval);
bool cond;
LIns* x;
do {
if (guardDenseArray(obj, obj_ins)) {
if (JSVAL_IS_INT(lval)) {
jsint idx = JSVAL_TO_INT(lval);
LIns* idx_ins = f2i(get(&lval));
LIns* dslots_ins = lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, dslots));
if (!guardDenseArrayIndex(obj, idx, obj_ins, dslots_ins, idx_ins))
ABORT_TRACE("dense array index out of bounds");
cond = obj->dslots[idx] != JSVAL_HOLE;
x = lir->ins_eq0(lir->ins2(LIR_eq,
lir->insLoad(LIR_ldp, dslots_ins, idx * sizeof(jsval)),
INS_CONST(JSVAL_HOLE)));
break;
}
// Not an index id, but a dense array -- go up to the proto. */
obj = STOBJ_GET_PROTO(obj);
obj_ins = stobj_get_fslot(obj_ins, JSSLOT_PROTO);
} else {
if (JSVAL_IS_INT(id))
ABORT_TRACE("INT in OBJ where OBJ is not a dense array");
}
JSObject* obj2;
JSProperty* prop;
if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop))
ABORT_TRACE("OBJ_LOOKUP_PROPERTY failed in JSOP_IN");
cond = prop != NULL;
if (prop)
OBJ_DROP_PROPERTY(cx, obj2, prop);
LIns* args[] = { get(&lval), obj_ins, cx_ins };
x = lir->insCall(F_HasNamedProperty, args);
guard(false, lir->ins2i(LIR_eq, x, 2), OOM_EXIT);
x = lir->ins2i(LIR_eq, x, 1);
} while (0);
/* The interpreter fuses comparisons and the following branch,
so we have to do that here as well. */
if (cx->fp->regs->pc[1] == JSOP_IFEQ || cx->fp->regs->pc[1] == JSOP_IFNE)
guard(cond, x, BRANCH_EXIT);
/* We update the stack after the guard. This is safe since
the guard bails out at the comparison and the interpreter
will this re-execute the comparison. This way the
value of the condition doesn't have to be calculated and
saved on the stack in most cases. */
set(&lval, x);
return true;
}
bool

View File

@ -849,6 +849,32 @@ function forVarInWith() {
forVarInWith.expected = "pqrst";
test(forVarInWith);
function inObjectTest() {
var o = {p: 1, q: 2, r: 3, s: 4, t: 5};
var r = 0;
for (var i in o) {
if (!(i in o))
break;
if ((i + i) in o)
break;
++r;
}
return r;
}
inObjectTest.expected = 5;
test(inObjectTest);
function inArrayTest() {
var a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
for (var i = 0; i < a.length; i++) {
if (!(i in a))
break;
}
return i;
}
inArrayTest.expected = 10;
test(inArrayTest);
/* Keep these at the end so that we can see the summary after the trace-debug spew. */
print("\npassed:", passes.length && passes.join(","));
print("\nFAILED:", fails.length && fails.join(","));