--- a/js/src/builtins.tbl
+++ b/js/src/builtins.tbl
@@ -31,20 +31,13 @@
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
-BUILTIN1(DOUBLE_IS_INT, F, LO, uint64, jsdouble, 1, 1)
-BUILTIN1(StringToDouble, LO, F, jsdouble, JSString*, 1, 1)
-BUILTIN1(ObjectToDouble, LO, F, jsdouble, JSObject*, 1, 1)
BUILTIN1(DoubleToECMAInt32, F, LO, jsint, jsdouble, 1, 1)
BUILTIN1(DoubleToECMAUint32, F, LO, jsint, jsdouble, 1, 1)
BUILTIN1(StringLength, LO, LO, jsint, JSString*, 1, 1)
BUILTIN2(dmod, F, F, F, jsdouble, jsdouble, jsdouble, 1, 1)
BUILTIN2(CompareStrings, LO, LO, LO, bool, JSString*, JSString*, 1, 1)
-/* the primitives below have to be specialized and then eliminated */
-BUILTIN2(ValueToNonNullObject, LO, Q, LO, JSObject*, JSContext*, Box, 1, 1)
-BUILTIN2(ValueToNumber, LO, Q, F, jsdouble, JSContext*, Box, 1, 1)
-BUILTIN3(obj_default_value, LO, LO, LO, Q, Box, JSContext*, JSObject*, JSType hint, 1, 1)
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -155,32 +155,16 @@ jsdouble builtin_dmod(jsdouble a, jsdoub
if (!(JSDOUBLE_IS_FINITE(a) && JSDOUBLE_IS_INFINITE(b)))
r = a;
else
#endif
r = fmod(a, b);
return r;
}
-#define builtin_DOUBLE_IS_INT builtin_unimplemented
-#define builtin_StringToDouble builtin_unimplemented
-#define builtin_ObjectToDouble builtin_unimplemented
-
-/* the following primitives are just placeholders and need to be broken down
- further (we need a concrete specialization, not "value") */
-
-#define builtin_ValueToNumber builtin_unimplemented
-#define builtin_ValueToNonNullObject builtin_unimplemented
-#define builtin_obj_default_value builtin_unimplemented
-
-void builtin_unimplemented(void)
-{
- JS_ASSERT(0);
-}
-
#define BUILTIN1(op, at0, atr, tr, t0, cse, fold) \
{ (intptr_t)&builtin_##op, (at0 << 2) | atr, cse, fold NAME(op) },
#define BUILTIN2(op, at0, at1, atr, tr, t0, t1, cse, fold) \
{ (intptr_t)&builtin_##op, (at0 << 4) | (at1 << 2) | atr, cse, fold NAME(op) },
#define BUILTIN3(op, at0, at1, at2, atr, tr, t0, t1, t2, cse, fold) \
{ (intptr_t)&builtin_##op, (at0 << 6) | (at1 << 4) | (at2 << 2) | atr, cse, fold NAME(op) },
static struct CallInfo builtins[] = {
@@ -195,17 +179,18 @@ static struct CallInfo builtins[] = {
static void
buildTypeMap(JSStackFrame* entryFrame, JSStackFrame* fp, JSFrameRegs& regs, char* m);
TraceRecorder::TraceRecorder(JSContext* cx, Fragmento* fragmento, Fragment* _fragment)
{
this->cx = cx;
this->fragment = _fragment;
entryFrame = cx->fp;
- entryRegs = *(entryFrame->regs);
+ entryRegs.pc = (jsbytecode*)_fragment->frid; /* regs->pc points to the branch, not the loop header */
+ entryRegs.sp = entryFrame->regs->sp;
fragment->calldepth = 0;
lirbuf = new (&gc) LirBuffer(fragmento, builtins);
fragment->lirbuf = lirbuf;
lir = lir_buf_writer = new (&gc) LirBufWriter(lirbuf);
#ifdef DEBUG
lirbuf->names = new (&gc) LirNameMap(&gc, builtins, fragmento->labels);
lir = verbose_filter = new (&gc) VerboseWriter(&gc, lir, lirbuf->names);
@@ -492,105 +477,19 @@ TraceRecorder::set(void* p, LIns* i)
tracker.set(p, i);
if (onFrame(p))
lir->insStorei(i, fragment->sp, nativeFrameOffset(p));
}
LIns*
TraceRecorder::get(void* p)
{
- if (p == cx)
- return cx_ins;
return tracker.get(p);
}
-void
-TraceRecorder::copy(void* a, void* v)
-{
- set(v, get(a));
-}
-
-void
-TraceRecorder::imm(jsint i, void* v)
-{
- set(v, lir->insImm(i));
-}
-
-void
-TraceRecorder::imm(jsdouble d, void* v)
-{
- set(v, lir->insImmq(*(uint64_t*)&d));
-}
-
-void
-TraceRecorder::unary(LOpcode op, void* a, void* v)
-{
- set(v, lir->ins1(op, get(a)));
-}
-
-void
-TraceRecorder::binary(LOpcode op, void* a, void* b, void* v)
-{
- set(v, lir->ins2(op, get(a), get(b)));
-}
-
-void
-TraceRecorder::binary0(LOpcode op, void* a, void* v)
-{
- set(v, lir->ins2i(op, get(a), 0));
-}
-
-void
-TraceRecorder::choose(void* cond, void* iftrue, void* iffalse, void* v)
-{
- set(v, lir->ins_choose(get(cond), get(iftrue), get(iffalse), true));
-}
-
-void
-TraceRecorder::choose_eqi(void* a, int32_t b, void* iftrue, void* iffalse, void* v)
-{
- set(v, lir->ins_choose(lir->ins2i(LIR_eq, get(a), b), get(iftrue), get(iffalse), true));
-}
-
-void
-TraceRecorder::call(int id, void* a, void* v)
-{
- LInsp args[] = { get(a) };
- set(v, lir->insCall(id, args));
-}
-
-void
-TraceRecorder::call(int id, void* a, void* b, void* v)
-{
- LInsp args[] = { get(a), get(b) };
- set(v, lir->insCall(id, args));
-}
-
-void
-TraceRecorder::call(int id, void* a, void* b, void* c, void* v)
-{
- LInsp args[] = { get(a), get(b), get(c) };
- set(v, lir->insCall(id, args));
-}
-
-void
-TraceRecorder::iinc(void* a, int incr, void* v)
-{
- LIns* ov = lir->ins2(LIR_add, get(a), lir->insImm(incr));
- // This check is actually supposed to happen before iinc, however,
- // we arrive at iinc only if CAN_DO_INC_DEC passed, so we know that the
- // inverse of it (overflow check) must evaluate to false in the trace.
- // We delay setting v to the result of the calculation until after the
- // guard to make sure the result is not communicated to the interpreter
- // in case this guard fails (as it was supposed to execute _before_ the
- // add, not after.)
- guard_ov(false, a);
- set(v, ov);
-}
-
SideExit*
TraceRecorder::snapshot()
{
/* generate the entry map and stash it in the trace */
unsigned slots = nativeFrameSlots(cx->fp, *cx->fp->regs);
trackNativeFrameUse(slots);
LIns* data = lir_buf_writer->skip(sizeof(VMSideExitInfo) + slots * sizeof(char));
VMSideExitInfo* si = (VMSideExitInfo*)data->payload();
@@ -603,62 +502,56 @@ TraceRecorder::snapshot()
exit.calldepth = calldepth();
exit.sp_adj = (cx->fp->regs->sp - entryRegs.sp + 1) * sizeof(double);
exit.ip_adj = cx->fp->regs->pc - entryRegs.pc;
exit.vmprivate = si;
return &exit;
}
void
-TraceRecorder::guard_0(bool expected, void* a)
+TraceRecorder::guard_0(bool expected, LIns* a)
{
lir->insGuard(expected ? LIR_xf : LIR_xt,
- get(a),
+ a,
snapshot());
}
void
-TraceRecorder::guard_h(bool expected, void* a)
+TraceRecorder::guard_h(bool expected, LIns* a)
{
lir->insGuard(expected ? LIR_xf : LIR_xt,
- lir->ins1(LIR_callh, get(a)),
+ lir->ins1(LIR_callh, a),
snapshot());
}
void
-TraceRecorder::guard_ov(bool expected, void* a)
+TraceRecorder::guard_ov(bool expected, LIns* a)
{
lir->insGuard(expected ? LIR_xf : LIR_xt,
- lir->ins1(LIR_ov, get(a)),
+ lir->ins1(LIR_ov, a),
snapshot());
}
void
-TraceRecorder::guard_eq(bool expected, void* a, void* b)
+TraceRecorder::guard_eq(bool expected, LIns* a, LIns* b)
{
lir->insGuard(expected ? LIR_xf : LIR_xt,
- lir->ins2(LIR_eq, get(a), get(b)),
+ lir->ins2(LIR_eq, a, b),
snapshot());
}
void
-TraceRecorder::guard_eqi(bool expected, void* a, int i)
+TraceRecorder::guard_eqi(bool expected, LIns* a, int i)
{
lir->insGuard(expected ? LIR_xf : LIR_xt,
- lir->ins2i(LIR_eq, get(a), i),
+ lir->ins2i(LIR_eq, a, i),
snapshot());
}
void
-TraceRecorder::load(void* a, int32_t i, void* v)
-{
- set(v, lir->insLoadi(get(a), i));
-}
-
-void
TraceRecorder::closeLoop(Fragmento* fragmento)
{
if (!verifyTypeStability(entryFrame, entryFrame, entryRegs, entryTypeMap)) {
#ifdef DEBUG
printf("Trace rejected: unstable loop variables.\n");
#endif
return;
}
@@ -746,16 +639,115 @@ js_AbortRecording(JSContext* cx, const c
#ifdef DEBUG
printf("Abort recording: %s.\n", reason);
#endif
JSTraceMonitor* tm = &JS_TRACE_MONITOR(cx);
JS_ASSERT(tm->recorder != NULL);
js_DeleteRecorder(cx);
}
+jsval&
+TraceRecorder::argval(unsigned n) const
+{
+ JS_ASSERT((n >= 0) && (n <= cx->fp->argc));
+ return cx->fp->argv[n];
+}
+
+jsval&
+TraceRecorder::varval(unsigned n) const
+{
+ JS_ASSERT((n >= 0) && (n <= cx->fp->nvars));
+ return cx->fp->vars[n];
+}
+
+jsval&
+TraceRecorder::stackval(int n) const
+{
+ JS_ASSERT((cx->fp->regs->sp + n < cx->fp->spbase + cx->fp->script->depth) && (cx->fp->regs->sp + n >= cx->fp->spbase));
+ return cx->fp->regs->sp[n];
+}
+
+LIns*
+TraceRecorder::arg(unsigned n)
+{
+ return get(&argval(n));
+}
+
+LIns*
+TraceRecorder::var(unsigned n)
+{
+ return get(&varval(n));
+}
+
+LIns*
+TraceRecorder::stack(int n)
+{
+ return get(&stackval(n));
+}
+
+void
+TraceRecorder::stack(int n, LIns* i)
+{
+ set(&stackval(n), i);
+}
+
+bool
+TraceRecorder::inc(jsval& v, jsint incr, bool pre)
+{
+ if (JSVAL_IS_INT(v)) {
+ LIns* before = get(&v);
+ LIns* after = lir->ins2i(LIR_add, before, incr);
+ guard_ov(false, after);
+ set(&v, after);
+ stack(0, pre ? after : before);
+ return true;
+ }
+ return false;
+}
+
+bool
+TraceRecorder::cmp(LOpcode op, bool negate)
+{
+ jsval& r = stackval(-1);
+ jsval& l = stackval(-2);
+ if (JSVAL_IS_INT(l) && JSVAL_IS_INT(r)) {
+ LIns* x = lir->ins2(op, get(&l), get(&r));
+ if (negate)
+ x = lir->ins2i(LIR_eq, x, 0);
+ set(&l, x);
+ bool cond;
+ switch (op) {
+ case LIR_lt:
+ cond = JSVAL_TO_INT(l) < JSVAL_TO_INT(r);
+ break;
+ case LIR_gt:
+ cond = JSVAL_TO_INT(l) > JSVAL_TO_INT(r);
+ break;
+ case LIR_le:
+ cond = JSVAL_TO_INT(l) <= JSVAL_TO_INT(r);
+ break;
+ case LIR_ge:
+ cond = JSVAL_TO_INT(l) >= JSVAL_TO_INT(r);
+ break;
+ default:
+ JS_ASSERT(cond == LIR_eq);
+ cond = JSVAL_TO_INT(l) == JSVAL_TO_INT(r);
+ break;
+ }
+ /* 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)
+ guard_0(!cond, x);
+ else if (cx->fp->regs->pc[1] == ::JSOP_IFNE)
+ guard_0(cond, x);
+ return true;
+ }
+ return false;
+}
+
bool TraceRecorder::JSOP_INTERRUPT()
{
return false;
}
bool TraceRecorder::JSOP_PUSH()
{
return false;
}
@@ -820,37 +812,37 @@ bool TraceRecorder::JSOP_BITXOR()
return false;
}
bool TraceRecorder::JSOP_BITAND()
{
return false;
}
bool TraceRecorder::JSOP_EQ()
{
- return false;
+ return cmp(LIR_eq);
}
bool TraceRecorder::JSOP_NE()
{
- return false;
+ return cmp(LIR_eq, true);
}
bool TraceRecorder::JSOP_LT()
{
- return false;
+ return cmp(LIR_lt);
}
bool TraceRecorder::JSOP_LE()
{
- return false;
+ return cmp(LIR_le);
}
bool TraceRecorder::JSOP_GT()
{
- return false;
+ return cmp(LIR_gt);
}
bool TraceRecorder::JSOP_GE()
{
- return false;
+ return cmp(LIR_ge);
}
bool TraceRecorder::JSOP_LSH()
{
return false;
}
bool TraceRecorder::JSOP_RSH()
{
return false;
@@ -1084,33 +1076,36 @@ bool TraceRecorder::JSOP_POS()
return false;
}
bool TraceRecorder::JSOP_TRAP()
{
return false;
}
bool TraceRecorder::JSOP_GETARG()
{
- return false;
+ stack(0, arg(GET_ARGNO(cx->fp->regs->pc)));
+ return true;
}
bool TraceRecorder::JSOP_SETARG()
{
return false;
}
bool TraceRecorder::JSOP_GETVAR()
{
- return false;
+ stack(0, var(GET_VARNO(cx->fp->regs->pc)));
+ return true;
}
bool TraceRecorder::JSOP_SETVAR()
{
return false;
}
bool TraceRecorder::JSOP_UINT16()
{
- return false;
+ stack(0, lir->insImm((jsint) GET_UINT16(cx->fp->regs->pc)));
+ return true;
}
bool TraceRecorder::JSOP_NEWINIT()
{
return false;
}
bool TraceRecorder::JSOP_ENDINIT()
{
return false;
@@ -1128,45 +1123,45 @@ bool TraceRecorder::JSOP_DEFSHARP()
return false;
}
bool TraceRecorder::JSOP_USESHARP()
{
return false;
}
bool TraceRecorder::JSOP_INCARG()
{
- return false;
+ return inc(argval(GET_ARGNO(cx->fp->regs->pc)), 1, true);
}
bool TraceRecorder::JSOP_INCVAR()
{
- return false;
+ return inc(varval(GET_VARNO(cx->fp->regs->pc)), 1, true);
}
bool TraceRecorder::JSOP_DECARG()
{
- return false;
+ return inc(argval(GET_ARGNO(cx->fp->regs->pc)), -1, true);
}
bool TraceRecorder::JSOP_DECVAR()
{
- return false;
+ return inc(varval(GET_VARNO(cx->fp->regs->pc)), -1, true);
}
bool TraceRecorder::JSOP_ARGINC()
{
- return false;
+ return inc(argval(GET_ARGNO(cx->fp->regs->pc)), 1, false);
}
bool TraceRecorder::JSOP_VARINC()
{
- return false;
+ return inc(varval(GET_VARNO(cx->fp->regs->pc)), 1, false);
}
bool TraceRecorder::JSOP_ARGDEC()
{
- return false;
+ return inc(argval(GET_ARGNO(cx->fp->regs->pc)), -1, false);
}
bool TraceRecorder::JSOP_VARDEC()
{
- return false;
+ return inc(varval(GET_VARNO(cx->fp->regs->pc)), -1, false);
}
bool TraceRecorder::JSOP_ITER()
{
return false;
}
bool TraceRecorder::JSOP_FORNAME()
{
return false;
@@ -1500,17 +1495,18 @@ bool TraceRecorder::JSOP_UNUSED186()
return false;
}
bool TraceRecorder::JSOP_DELDESC()
{
return false;
}
bool TraceRecorder::JSOP_UINT24()
{
- return false;
+ stack(0, lir->insImm((jsint) GET_UINT24(cx->fp->regs->pc)));
+ return true;
}
bool TraceRecorder::JSOP_INDEXBASE()
{
return false;
}
bool TraceRecorder::JSOP_RESETBASE()
{
return false;
@@ -1656,21 +1652,23 @@ bool TraceRecorder::JSOP_CALLARG()
return false;
}
bool TraceRecorder::JSOP_CALLLOCAL()
{
return false;
}
bool TraceRecorder::JSOP_INT8()
{
- return false;
+ stack(0, lir->insImm(GET_INT8(cx->fp->regs->pc)));
+ return true;
}
bool TraceRecorder::JSOP_INT32()
{
- return false;
+ stack(0, lir->insImm(GET_INT32(cx->fp->regs->pc)));
+ return true;
}
bool TraceRecorder::JSOP_LENGTH()
{
return false;
}
bool TraceRecorder::JSOP_NEWARRAY()
{
return false;
--- a/js/src/jstracer.h
+++ b/js/src/jstracer.h
@@ -104,41 +104,35 @@ class TraceRecorder {
nanojit::SideExit* snapshot();
unsigned calldepth() const;
void set(void* p, nanojit::LIns* l);
nanojit::LIns* get(void* p);
- void copy(void* a, void* v);
- void imm(jsint i, void* v);
- void imm(jsdouble d, void* v);
- void unary(nanojit::LOpcode op, void* a, void* v);
- void binary(nanojit::LOpcode op, void* a, void* b, void* v);
- void binary0(nanojit::LOpcode op, void* a, void* v);
- void choose(void* cond, void* iftrue, void* iffalse, void* v);
- void choose_eqi(void* a, int b, void* iftrue, void* iffalse, void* v);
-
- void call(int id, void* a, void* v);
- void call(int id, void* a, void* b, void* v);
- void call(int id, void* a, void* b, void* c, void* v);
-
- void iinc(void* a, int32_t incr, void* v);
-
- void load(void* a, int32_t i, void* v);
-
- void guard_0(bool expected, void* a);
- void guard_h(bool expected, void* a);
- void guard_ov(bool expected, void* a);
- void guard_eq(bool expected, void* a, void* b);
- void guard_eqi(bool expected, void* a, int i);
+ void guard_0(bool expected, nanojit::LIns* a);
+ void guard_h(bool expected, nanojit::LIns* a);
+ void guard_ov(bool expected, nanojit::LIns* a);
+ void guard_eq(bool expected, nanojit::LIns* a, nanojit::LIns* b);
+ void guard_eqi(bool expected, nanojit::LIns* a, int i);
void closeLoop(nanojit::Fragmento* fragmento);
-
+
+ jsval& argval(unsigned n) const;
+ jsval& varval(unsigned n) const;
+ jsval& stackval(int n) const;
+
+ nanojit::LIns* arg(unsigned n);
+ nanojit::LIns* var(unsigned n);
+ nanojit::LIns* stack(int n);
+ void stack(int n, nanojit::LIns* i);
+
+ bool inc(jsval& v, jsint incr, bool pre);
+ bool cmp(nanojit::LOpcode op, bool negate = false);
public:
TraceRecorder(JSContext* cx, nanojit::Fragmento*, nanojit::Fragment*);
~TraceRecorder();
bool loopEdge(JSContext* cx, jsbytecode* pc);
bool JSOP_INTERRUPT();
bool JSOP_PUSH();