mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge.
This commit is contained in:
commit
57a8fae3d1
@ -1267,7 +1267,9 @@ JS_EvaluateUCInStackFrame(JSContext *cx, JSStackFrame *fp,
|
||||
flags = fp->flags;
|
||||
fp->flags |= JSFRAME_DEBUGGER | JSFRAME_EVAL;
|
||||
script = js_CompileScript(cx, scobj, JS_StackFramePrincipals(cx, fp),
|
||||
TCF_COMPILE_N_GO, chars, length, NULL,
|
||||
TCF_COMPILE_N_GO |
|
||||
TCF_PUT_STATIC_DEPTH(fp->script->staticDepth + 1),
|
||||
chars, length, NULL,
|
||||
filename, lineno);
|
||||
fp->flags = flags;
|
||||
if (!script)
|
||||
|
@ -1878,6 +1878,9 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
|
||||
if (!(tc->flags & TCF_IN_FUNCTION)) {
|
||||
if ((cx->fp->flags & JSFRAME_SPECIAL) && cx->fp->fun) {
|
||||
if (cg->staticDepth > JS_DISPLAY_SIZE)
|
||||
goto out;
|
||||
|
||||
localKind = js_LookupLocal(cx, cx->fp->fun, atom, &index);
|
||||
if (localKind != JSLOCAL_NONE) {
|
||||
if (PN_OP(pn) == JSOP_NAME) {
|
||||
|
@ -209,6 +209,14 @@ struct JSTreeContext { /* tree context for semantic checks */
|
||||
TCF_FUN_USES_NONLOCALS | \
|
||||
TCF_FUN_CLOSURE_VS_VAR)
|
||||
|
||||
/*
|
||||
* Flags field, not stored in JSTreeContext.flags, for passing staticDepth
|
||||
* into js_CompileScript.
|
||||
*/
|
||||
#define TCF_STATIC_DEPTH_MASK 0xffff0000
|
||||
#define TCF_GET_STATIC_DEPTH(f) ((uint32)(f) >> 16)
|
||||
#define TCF_PUT_STATIC_DEPTH(d) ((uint16)(d) << 16)
|
||||
|
||||
#ifdef JS_SCOPE_DEPTH_METER
|
||||
# define JS_SCOPE_DEPTH_METERING(code) ((void) (code))
|
||||
#else
|
||||
|
@ -1318,14 +1318,15 @@ js_obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
fp->flags |= JSFRAME_EVAL;
|
||||
} while ((fp = fp->down) != caller);
|
||||
|
||||
script = js_CompileScript(cx, scopeobj, principals, TCF_COMPILE_N_GO,
|
||||
script = js_CompileScript(cx, scopeobj, principals,
|
||||
TCF_COMPILE_N_GO |
|
||||
TCF_PUT_STATIC_DEPTH(caller->script->staticDepth + 1),
|
||||
JSSTRING_CHARS(str), JSSTRING_LENGTH(str),
|
||||
NULL, file, line);
|
||||
if (!script) {
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
}
|
||||
script->staticDepth = caller->script->staticDepth + 1;
|
||||
|
||||
if (argc < 2) {
|
||||
/* Execute using caller's new scope object (might be a Call object). */
|
||||
|
@ -566,7 +566,7 @@ js_CompileScript(JSContext *cx, JSObject *obj, JSPrincipals *principals,
|
||||
void *sbrk(ptrdiff_t), *before = sbrk(0);
|
||||
#endif
|
||||
|
||||
JS_ASSERT(!(tcflags & ~(TCF_COMPILE_N_GO | TCF_NO_SCRIPT_RVAL)));
|
||||
JS_ASSERT(!(tcflags & ~(TCF_COMPILE_N_GO | TCF_NO_SCRIPT_RVAL | TCF_STATIC_DEPTH_MASK)));
|
||||
|
||||
if (!js_InitParseContext(cx, &pc, principals, chars, length, file,
|
||||
filename, lineno)) {
|
||||
@ -591,7 +591,8 @@ js_CompileScript(JSContext *cx, JSObject *obj, JSPrincipals *principals,
|
||||
pc.tokenStream.lineno);
|
||||
|
||||
/* From this point the control must flow via the label out. */
|
||||
cg.treeContext.flags |= tcflags;
|
||||
cg.treeContext.flags |= (uint16) tcflags;
|
||||
cg.staticDepth = TCF_GET_STATIC_DEPTH(tcflags);
|
||||
|
||||
/*
|
||||
* Inline Statements() to emit as we go to save space.
|
||||
|
@ -263,7 +263,7 @@ script_compile_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
||||
* and compile-time scope.
|
||||
*/
|
||||
fp->flags |= JSFRAME_SCRIPT_OBJECT;
|
||||
tcflags = 0;
|
||||
tcflags = caller ? TCF_PUT_STATIC_DEPTH(caller->staticDepth + 1) : 0;
|
||||
script = js_CompileScript(cx, scopeobj, principals, tcflags,
|
||||
JSSTRING_CHARS(str), JSSTRING_LENGTH(str),
|
||||
NULL, file, line);
|
||||
|
@ -2591,6 +2591,35 @@ TraceRecorder::ifop()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TraceRecorder::switchop()
|
||||
{
|
||||
jsval& v = stackval(-1);
|
||||
if (isNumber(v)) {
|
||||
jsdouble d = asNumber(v);
|
||||
jsdpun u;
|
||||
u.d = d;
|
||||
guard(true,
|
||||
addName(lir->ins2(LIR_feq, get(&v), lir->insImmq(u.u64)),
|
||||
"guard(switch on numeric)"),
|
||||
BRANCH_EXIT);
|
||||
} else if (JSVAL_IS_STRING(v)) {
|
||||
LIns* args[] = { get(&v), INS_CONSTPTR(JSVAL_TO_STRING(v)) };
|
||||
guard(true,
|
||||
addName(lir->ins_eq0(lir->ins_eq0(lir->insCall(F_EqualStrings, args))),
|
||||
"guard(switch on string)"),
|
||||
BRANCH_EXIT);
|
||||
} else if (JSVAL_IS_BOOLEAN(v)) {
|
||||
guard(true,
|
||||
addName(lir->ins2(LIR_eq, get(&v), lir->insImm(JSVAL_TO_BOOLEAN(v))),
|
||||
"guard(switch on boolean)"),
|
||||
BRANCH_EXIT);
|
||||
} else {
|
||||
ABORT_TRACE("switch on object, null, or undefined");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TraceRecorder::inc(jsval& v, jsint incr, bool pre)
|
||||
{
|
||||
@ -2672,13 +2701,15 @@ TraceRecorder::incElem(jsint incr, bool pre)
|
||||
}
|
||||
|
||||
bool
|
||||
TraceRecorder::cmp(LOpcode op, bool negate)
|
||||
TraceRecorder::cmp(LOpcode op, int flags)
|
||||
{
|
||||
jsval& r = stackval(-1);
|
||||
jsval& l = stackval(-2);
|
||||
LIns* x;
|
||||
bool negate = !!(flags & CMP_NEGATE);
|
||||
bool cond;
|
||||
if (JSVAL_IS_STRING(l) && JSVAL_IS_STRING(r)) {
|
||||
JS_ASSERT(!negate);
|
||||
LIns* args[] = { get(&r), get(&l) };
|
||||
x = lir->ins1(LIR_i2f, lir->insCall(F_CompareStrings, args));
|
||||
x = lir->ins2i(op, x, 0);
|
||||
@ -2727,6 +2758,7 @@ TraceRecorder::cmp(LOpcode op, bool negate)
|
||||
lnum = js_ValueToNumber(cx, &tmp[0]);
|
||||
|
||||
args[0] = get(&r);
|
||||
args[1] = cx_ins;
|
||||
if (JSVAL_IS_STRING(r)) {
|
||||
r_ins = lir->insCall(F_StringToNumber, args);
|
||||
} else if (JSVAL_TAG(r) == JSVAL_BOOLEAN) {
|
||||
@ -2759,7 +2791,7 @@ TraceRecorder::cmp(LOpcode op, bool negate)
|
||||
cond = (lnum == rnum) ^ negate;
|
||||
break;
|
||||
}
|
||||
} else if (JSVAL_IS_BOOLEAN(l) && JSVAL_IS_BOOLEAN(r)) {
|
||||
} else if (JSVAL_IS_BOOLEAN(l) && JSVAL_IS_BOOLEAN(r)) {
|
||||
x = lir->ins2(op, lir->ins1(LIR_i2f, get(&l)), lir->ins1(LIR_i2f, get(&r)));
|
||||
if (negate)
|
||||
x = lir->ins_eq0(x);
|
||||
@ -2791,7 +2823,8 @@ TraceRecorder::cmp(LOpcode op, bool negate)
|
||||
|
||||
/* The interpreter fuses comparisons and the following branch,
|
||||
so we have to do that here as well. */
|
||||
fuseIf(cx->fp->regs->pc + 1, cond, x);
|
||||
if (flags & CMP_TRY_BRANCH_AFTER_COND)
|
||||
fuseIf(cx->fp->regs->pc + 1, cond, x);
|
||||
|
||||
/* We update the stack after the guard. This is safe since
|
||||
the guard bails out at the comparison and the interpreter
|
||||
@ -2802,6 +2835,61 @@ TraceRecorder::cmp(LOpcode op, bool negate)
|
||||
return true;
|
||||
}
|
||||
|
||||
// FIXME: we currently compare only like operand types; if for JSOP_EQ and
|
||||
// JSOP_NE we ever evolve to handle conversions then we must insist on like
|
||||
// "types" here (care required for 0 == -1, e.g.).
|
||||
bool
|
||||
TraceRecorder::equal(int flags)
|
||||
{
|
||||
jsval& r = stackval(-1);
|
||||
jsval& l = stackval(-2);
|
||||
bool negate = !!(flags & CMP_NEGATE);
|
||||
if (JSVAL_IS_STRING(l) && JSVAL_IS_STRING(r)) {
|
||||
LIns* args[] = { get(&r), get(&l) };
|
||||
bool cond = js_EqualStrings(JSVAL_TO_STRING(l), JSVAL_TO_STRING(r)) ^ negate;
|
||||
LIns* x = lir->ins_eq0(lir->insCall(F_EqualStrings, args));
|
||||
if (!negate)
|
||||
x = lir->ins_eq0(x);
|
||||
|
||||
/* The interpreter fuses comparisons and the following branch,
|
||||
so we have to do that here as well. */
|
||||
if (CMP_TRY_BRANCH_AFTER_COND) {
|
||||
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 therefore 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(&l, x);
|
||||
return true;
|
||||
}
|
||||
if (JSVAL_IS_OBJECT(l) && JSVAL_IS_OBJECT(r)) {
|
||||
bool cond = (l == r) ^ negate;
|
||||
LIns* x = lir->ins2(LIR_eq, get(&l), get(&r));
|
||||
if (negate)
|
||||
x = lir->ins_eq0(x);
|
||||
|
||||
/* The interpreter fuses comparisons and the following branch,
|
||||
so we have to do that here as well. */
|
||||
if (CMP_TRY_BRANCH_AFTER_COND) {
|
||||
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 therefore 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(&l, x);
|
||||
return true;
|
||||
}
|
||||
return cmp(LIR_feq, flags);
|
||||
}
|
||||
|
||||
bool
|
||||
TraceRecorder::unary(LOpcode op)
|
||||
{
|
||||
@ -2831,21 +2919,24 @@ TraceRecorder::binary(LOpcode op)
|
||||
bool leftNumber = isNumber(l), rightNumber = isNumber(r);
|
||||
if ((op >= LIR_sub && op <= LIR_ush) || // sub, mul, (callh), or, xor, (not,) lsh, rsh, ush
|
||||
(op >= LIR_fsub && op <= LIR_fdiv)) { // fsub, fmul, fdiv
|
||||
LIns* args[] = { NULL, cx_ins };
|
||||
LIns* args[2];
|
||||
if (JSVAL_IS_STRING(l)) {
|
||||
args[0] = a;
|
||||
args[1] = cx_ins;
|
||||
a = lir->insCall(F_StringToNumber, args);
|
||||
leftNumber = true;
|
||||
}
|
||||
if (JSVAL_IS_STRING(r)) {
|
||||
args[0] = b;
|
||||
args[1] = cx_ins;
|
||||
b = lir->insCall(F_StringToNumber, args);
|
||||
rightNumber = true;
|
||||
}
|
||||
}
|
||||
if (leftNumber && rightNumber) {
|
||||
if (intop) {
|
||||
a = lir->insCall(op == LIR_ush ? F_DoubleToUint32 : F_DoubleToInt32, &a);
|
||||
LIns *args[] = { a };
|
||||
a = lir->insCall(op == LIR_ush ? F_DoubleToUint32 : F_DoubleToInt32, args);
|
||||
b = f2i(b);
|
||||
}
|
||||
a = lir->ins2(op, a, b);
|
||||
@ -2972,7 +3063,9 @@ TraceRecorder::test_property_cache(JSObject* obj, LIns* obj_ins, JSObject*& obj2
|
||||
}
|
||||
} else {
|
||||
#ifdef DEBUG
|
||||
ptrdiff_t pcoff = (mode == JOF_VARPROP) ? SLOTNO_LEN : 0;
|
||||
JSOp op = JSOp(*cx->fp->regs->pc);
|
||||
ptrdiff_t pcoff = (op == JSOP_GETARGPROP) ? ARGNO_LEN :
|
||||
(op == JSOP_GETLOCALPROP) ? SLOTNO_LEN : 0;
|
||||
jsatomid index = js_GetIndexFromBytecode(cx, cx->fp->script, cx->fp->regs->pc, pcoff);
|
||||
JS_ASSERT(entry->kpc == (jsbytecode*) atoms[index]);
|
||||
JS_ASSERT(entry->kshape == jsuword(aobj));
|
||||
@ -3103,7 +3196,7 @@ 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 = lir->insImm(JSVAL_TO_BOOLEAN(JSVAL_VOID));
|
||||
v_ins = INS_CONST(JSVAL_TO_BOOLEAN(JSVAL_VOID));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -3146,7 +3239,8 @@ TraceRecorder::unbox_jsval(jsval v, LIns*& v_ins)
|
||||
INS_CONST(JSVAL_TAGMASK)),
|
||||
JSVAL_DOUBLE))),
|
||||
MISMATCH_EXIT);
|
||||
v_ins = lir->insCall(F_UnboxDouble, &v_ins);
|
||||
LIns* args[] = { v_ins };
|
||||
v_ins = lir->insCall(F_UnboxDouble, args);
|
||||
return true;
|
||||
}
|
||||
switch (JSVAL_TAG(v)) {
|
||||
@ -3269,7 +3363,7 @@ TraceRecorder::record_EnterFrame()
|
||||
js_AtomToPrintableString(cx, cx->fp->fun->atom),
|
||||
callDepth););
|
||||
JSStackFrame* fp = cx->fp;
|
||||
LIns* void_ins = lir->insImm(JSVAL_TO_BOOLEAN(JSVAL_VOID));
|
||||
LIns* void_ins = INS_CONST(JSVAL_TO_BOOLEAN(JSVAL_VOID));
|
||||
|
||||
jsval* vp = &fp->argv[fp->argc];
|
||||
jsval* vpstop = vp + (fp->fun->nargs - fp->argc);
|
||||
@ -3313,7 +3407,7 @@ bool TraceRecorder::record_JSOP_INTERRUPT()
|
||||
bool
|
||||
TraceRecorder::record_JSOP_PUSH()
|
||||
{
|
||||
stack(0, lir->insImm(JSVAL_TO_BOOLEAN(JSVAL_VOID)));
|
||||
stack(0, INS_CONST(JSVAL_TO_BOOLEAN(JSVAL_VOID)));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -3415,108 +3509,40 @@ TraceRecorder::record_JSOP_BITAND()
|
||||
return binary(LIR_and);
|
||||
}
|
||||
|
||||
// See FIXME for JSOP_STRICTEQ before evolving JSOP_EQ to handle mixed types.
|
||||
bool
|
||||
TraceRecorder::record_JSOP_EQ()
|
||||
{
|
||||
jsval& r = stackval(-1);
|
||||
jsval& l = stackval(-2);
|
||||
if (JSVAL_IS_STRING(l) && JSVAL_IS_STRING(r)) {
|
||||
LIns* args[] = { get(&r), get(&l) };
|
||||
bool cond = js_EqualStrings(JSVAL_TO_STRING(l), JSVAL_TO_STRING(r));
|
||||
LIns* x = lir->ins_eq0(lir->ins_eq0(lir->insCall(F_EqualStrings, args)));
|
||||
/* The interpreter fuses comparisons and the following branch,
|
||||
so we have to do that here as well. */
|
||||
fuseIf(cx->fp->regs->pc + 1, cond, x);
|
||||
|
||||
/* We update the stack after the guard. This is safe since
|
||||
the guard bails out at the comparison and the interpreter
|
||||
will therefore 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(&l, x);
|
||||
return true;
|
||||
}
|
||||
if (JSVAL_IS_OBJECT(l) && JSVAL_IS_OBJECT(r)) {
|
||||
bool cond = (l == r);
|
||||
LIns* x = lir->ins2(LIR_eq, get(&l), get(&r));
|
||||
/* The interpreter fuses comparisons and the following branch,
|
||||
so we have to do that here as well. */
|
||||
fuseIf(cx->fp->regs->pc + 1, cond, x);
|
||||
|
||||
/* We update the stack after the guard. This is safe since
|
||||
the guard bails out at the comparison and the interpreter
|
||||
will therefore 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(&l, x);
|
||||
return true;
|
||||
}
|
||||
return cmp(LIR_feq);
|
||||
return equal(CMP_TRY_BRANCH_AFTER_COND);
|
||||
}
|
||||
|
||||
// See FIXME for JSOP_STRICTNE before evolving JSOP_NE to handle mixed types.
|
||||
bool
|
||||
TraceRecorder::record_JSOP_NE()
|
||||
{
|
||||
jsval& r = stackval(-1);
|
||||
jsval& l = stackval(-2);
|
||||
if (JSVAL_IS_STRING(l) && JSVAL_IS_STRING(r)) {
|
||||
LIns* args[] = { get(&r), get(&l) };
|
||||
bool cond = !js_EqualStrings(JSVAL_TO_STRING(l), JSVAL_TO_STRING(r));
|
||||
LIns* x = lir->ins_eq0(lir->insCall(F_EqualStrings, args));
|
||||
/* The interpreter fuses comparisons and the following branch,
|
||||
so we have to do that here as well. */
|
||||
fuseIf(cx->fp->regs->pc + 1, cond, x);
|
||||
|
||||
/* We update the stack after the guard. This is safe since
|
||||
the guard bails out at the comparison and the interpreter
|
||||
will therefore 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(&l, x);
|
||||
return true;
|
||||
}
|
||||
if (JSVAL_IS_OBJECT(l) && JSVAL_IS_OBJECT(r)) {
|
||||
bool cond = (l != r);
|
||||
LIns* x = lir->ins_eq0(lir->ins2(LIR_eq, get(&l), get(&r)));
|
||||
/* The interpreter fuses comparisons and the following branch,
|
||||
so we have to do that here as well. */
|
||||
fuseIf(cx->fp->regs->pc + 1, cond, x);
|
||||
|
||||
/* We update the stack after the guard. This is safe since
|
||||
the guard bails out at the comparison and the interpreter
|
||||
will therefore 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(&l, x);
|
||||
return true;
|
||||
}
|
||||
return cmp(LIR_feq, true);
|
||||
return equal(CMP_NEGATE | CMP_TRY_BRANCH_AFTER_COND);
|
||||
}
|
||||
|
||||
bool
|
||||
TraceRecorder::record_JSOP_LT()
|
||||
{
|
||||
return cmp(LIR_flt);
|
||||
return cmp(LIR_flt, CMP_TRY_BRANCH_AFTER_COND);
|
||||
}
|
||||
|
||||
bool
|
||||
TraceRecorder::record_JSOP_LE()
|
||||
{
|
||||
return cmp(LIR_fle);
|
||||
return cmp(LIR_fle, CMP_TRY_BRANCH_AFTER_COND);
|
||||
}
|
||||
|
||||
bool
|
||||
TraceRecorder::record_JSOP_GT()
|
||||
{
|
||||
return cmp(LIR_fgt);
|
||||
return cmp(LIR_fgt, CMP_TRY_BRANCH_AFTER_COND);
|
||||
}
|
||||
|
||||
bool
|
||||
TraceRecorder::record_JSOP_GE()
|
||||
{
|
||||
return cmp(LIR_fge);
|
||||
return cmp(LIR_fge, CMP_TRY_BRANCH_AFTER_COND);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -3863,7 +3889,7 @@ TraceRecorder::record_JSOP_TYPEOF()
|
||||
bool
|
||||
TraceRecorder::record_JSOP_VOID()
|
||||
{
|
||||
stack(-1, lir->insImm(JSVAL_TO_BOOLEAN(JSVAL_VOID)));
|
||||
stack(-1, INS_CONST(JSVAL_TO_BOOLEAN(JSVAL_VOID)));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -4030,6 +4056,12 @@ TraceRecorder::record_JSOP_GETELEM()
|
||||
jsval& l = stackval(-2);
|
||||
|
||||
if (JSVAL_IS_STRING(l) && JSVAL_IS_INT(r)) {
|
||||
int i;
|
||||
|
||||
i = JSVAL_TO_INT(r);
|
||||
if ((size_t)i >= JSSTRING_LENGTH(JSVAL_TO_STRING(l)))
|
||||
ABORT_TRACE("Invalid string index in JSOP_GETELEM");
|
||||
|
||||
LIns* args[] = { f2i(get(&r)), get(&l), cx_ins };
|
||||
LIns* unitstr_ins = lir->insCall(F_String_getelem, args);
|
||||
guard(false, lir->ins_eq0(unitstr_ins), MISMATCH_EXIT);
|
||||
@ -4196,7 +4228,7 @@ TraceRecorder::interpretedFunctionCall(jsval& fval, JSFunction* fun, uintN argc)
|
||||
callDepth * sizeof(FrameInfo) + offsetof(FrameInfo, callee));
|
||||
lir->insStorei(lir->insImmPtr(fi.callpc), lirbuf->rp,
|
||||
callDepth * sizeof(FrameInfo) + offsetof(FrameInfo, callpc));
|
||||
lir->insStorei(lir->insImm(fi.word), lirbuf->rp,
|
||||
lir->insStorei(INS_CONST(fi.word), lirbuf->rp,
|
||||
callDepth * sizeof(FrameInfo) + offsetof(FrameInfo, word));
|
||||
|
||||
atoms = fun->u.i.script->atomMap.vector;
|
||||
@ -4494,7 +4526,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 = lir->insImm(JSVAL_TO_BOOLEAN(JSVAL_VOID));
|
||||
v_ins = INS_CONST(JSVAL_TO_BOOLEAN(JSVAL_VOID));
|
||||
JS_ASSERT(cs.ndefs == 1);
|
||||
stack(-cs.nuses, v_ins);
|
||||
slot = SPROP_INVALID_SLOT;
|
||||
@ -4715,54 +4747,25 @@ TraceRecorder::record_JSOP_AND()
|
||||
bool
|
||||
TraceRecorder::record_JSOP_TABLESWITCH()
|
||||
{
|
||||
return false;
|
||||
return switchop();
|
||||
}
|
||||
|
||||
bool
|
||||
TraceRecorder::record_JSOP_LOOKUPSWITCH()
|
||||
{
|
||||
jsval& v = stackval(-1);
|
||||
if (isNumber(v)) {
|
||||
jsdouble d = asNumber(v);
|
||||
jsdpun u;
|
||||
u.d = d;
|
||||
guard(true,
|
||||
addName(lir->ins2(LIR_feq, get(&v), lir->insImmq(u.u64)),
|
||||
"guard(lookupswitch numeric)"),
|
||||
BRANCH_EXIT);
|
||||
} else if (JSVAL_IS_STRING(v)) {
|
||||
LIns* args[] = { get(&v), INS_CONSTPTR(JSVAL_TO_STRING(v)) };
|
||||
guard(true,
|
||||
addName(lir->ins_eq0(lir->ins_eq0(lir->insCall(F_EqualStrings, args))),
|
||||
"guard(lookupswitch string)"),
|
||||
BRANCH_EXIT);
|
||||
} else if (JSVAL_IS_BOOLEAN(v)) {
|
||||
guard(true,
|
||||
addName(lir->ins2(LIR_eq, get(&v), lir->insImm(JSVAL_TO_BOOLEAN(v))),
|
||||
"guard(lookupswitch boolean)"),
|
||||
BRANCH_EXIT);
|
||||
} else {
|
||||
ABORT_TRACE("lookupswitch on object, null, or undefined");
|
||||
}
|
||||
return true;
|
||||
return switchop();
|
||||
}
|
||||
|
||||
bool
|
||||
TraceRecorder::record_JSOP_STRICTEQ()
|
||||
{
|
||||
// FIXME: JSOP_EQ currently compares only like operand types; if it evolves
|
||||
// to handle conversions we must insist on like "types" here (care required
|
||||
// for 0 == -1, e.g.).
|
||||
return record_JSOP_EQ();
|
||||
return equal();
|
||||
}
|
||||
|
||||
bool
|
||||
TraceRecorder::record_JSOP_STRICTNE()
|
||||
{
|
||||
// FIXME: JSOP_NE currently compares only like operand types; if it evolves
|
||||
// to handle conversions we must insist on like "types" here (care required
|
||||
// for 0 == -1, e.g.).
|
||||
return record_JSOP_NE();
|
||||
return equal(CMP_NEGATE);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -5090,10 +5093,13 @@ TraceRecorder::record_JSOP_IN()
|
||||
ABORT_TRACE("JSOP_IN on E4X QName left operand");
|
||||
|
||||
jsid id;
|
||||
if (JSVAL_IS_INT(lval))
|
||||
if (JSVAL_IS_INT(lval)) {
|
||||
id = INT_JSVAL_TO_JSID(lval);
|
||||
else if (!JSVAL_IS_STRING(lval))
|
||||
ABORT_TRACE("non-string left operand to JSOP_IN");
|
||||
} else {
|
||||
if (!JSVAL_IS_STRING(lval))
|
||||
ABORT_TRACE("non-string left operand to JSOP_IN");
|
||||
id = ATOM_TO_JSID(lval);
|
||||
}
|
||||
|
||||
// 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
|
||||
@ -5200,13 +5206,13 @@ TraceRecorder::record_JSOP_CONDSWITCH()
|
||||
bool
|
||||
TraceRecorder::record_JSOP_CASE()
|
||||
{
|
||||
return false;
|
||||
return equal() && ifop();
|
||||
}
|
||||
|
||||
bool
|
||||
TraceRecorder::record_JSOP_DEFAULT()
|
||||
{
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -5383,25 +5389,25 @@ TraceRecorder::record_JSOP_GOSUBX()
|
||||
bool
|
||||
TraceRecorder::record_JSOP_CASEX()
|
||||
{
|
||||
return record_JSOP_CASE();
|
||||
return equal() && ifop();
|
||||
}
|
||||
|
||||
bool
|
||||
TraceRecorder::record_JSOP_DEFAULTX()
|
||||
{
|
||||
return record_JSOP_DEFAULT();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TraceRecorder::record_JSOP_TABLESWITCHX()
|
||||
{
|
||||
return record_JSOP_TABLESWITCH();
|
||||
return switchop();
|
||||
}
|
||||
|
||||
bool
|
||||
TraceRecorder::record_JSOP_LOOKUPSWITCHX()
|
||||
{
|
||||
return record_JSOP_LOOKUPSWITCH();
|
||||
return switchop();
|
||||
}
|
||||
|
||||
bool
|
||||
@ -5799,7 +5805,7 @@ TraceRecorder::record_JSOP_STOP()
|
||||
JS_ASSERT(OBJECT_TO_JSVAL(fp->thisp) == fp->argv[-1]);
|
||||
rval_ins = get(&fp->argv[-1]);
|
||||
} else {
|
||||
rval_ins = lir->insImm(JSVAL_TO_BOOLEAN(JSVAL_VOID));
|
||||
rval_ins = INS_CONST(JSVAL_TO_BOOLEAN(JSVAL_VOID));
|
||||
}
|
||||
clearFrameSlotsFromCache();
|
||||
return true;
|
||||
@ -6033,7 +6039,7 @@ TraceRecorder::record_JSOP_NEWARRAY()
|
||||
bool
|
||||
TraceRecorder::record_JSOP_HOLE()
|
||||
{
|
||||
stack(0, lir->insImm(JSVAL_TO_BOOLEAN(JSVAL_HOLE)));
|
||||
stack(0, INS_CONST(JSVAL_TO_BOOLEAN(JSVAL_HOLE)));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -271,12 +271,16 @@ class TraceRecorder {
|
||||
nanojit::LIns* f2i(nanojit::LIns* f);
|
||||
|
||||
bool ifop();
|
||||
bool switchop();
|
||||
bool inc(jsval& v, jsint incr, bool pre = true);
|
||||
bool inc(jsval& v, nanojit::LIns*& v_ins, jsint incr, bool pre = true);
|
||||
bool incProp(jsint incr, bool pre = true);
|
||||
bool incElem(jsint incr, bool pre = true);
|
||||
bool incName(jsint incr, bool pre = true);
|
||||
bool cmp(nanojit::LOpcode op, bool negate = false);
|
||||
|
||||
enum { CMP_NEGATE = 1, CMP_TRY_BRANCH_AFTER_COND = 2 };
|
||||
bool cmp(nanojit::LOpcode op, int flags = 0);
|
||||
bool equal(int flags = 0);
|
||||
|
||||
bool unary(nanojit::LOpcode op);
|
||||
bool binary(nanojit::LOpcode op);
|
||||
|
@ -1020,6 +1020,61 @@ function testDecayingInnerLoop() {
|
||||
testDecayingInnerLoop.expected = 5000;
|
||||
test(testDecayingInnerLoop);
|
||||
|
||||
function testContinue() {
|
||||
var i;
|
||||
var total = 0;
|
||||
for (i = 0; i < 20; ++i) {
|
||||
if (i == 11)
|
||||
continue;
|
||||
total++;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
testContinue.expected = 19;
|
||||
test(testContinue);
|
||||
|
||||
function testContinueWithLabel() {
|
||||
var i = 0;
|
||||
var j = 20;
|
||||
checkiandj :
|
||||
while (i<10) {
|
||||
i+=1;
|
||||
checkj :
|
||||
while (j>10) {
|
||||
j-=1;
|
||||
if ((j%2)==0)
|
||||
continue checkj;
|
||||
}
|
||||
}
|
||||
return i + j;
|
||||
}
|
||||
testContinueWithLabel.expected = 20;
|
||||
test(testContinueWithLabel);
|
||||
|
||||
function testDivision() {
|
||||
var a = 32768;
|
||||
var b;
|
||||
while (b !== 1) {
|
||||
b = a / 2;
|
||||
a = b;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
testDivision.expected = 1;
|
||||
test(testDivision);
|
||||
|
||||
function testDivisionFloat() {
|
||||
var a = 32768.0;
|
||||
var b;
|
||||
while (b !== 1) {
|
||||
b = a / 2.0;
|
||||
a = b;
|
||||
}
|
||||
return a === 1.0;
|
||||
}
|
||||
testDivisionFloat.expected = true;
|
||||
test(testDivisionFloat);
|
||||
|
||||
/* 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(","));
|
||||
|
Loading…
Reference in New Issue
Block a user