Added back support for the instructions required to compile trace.js.
authorAndreas Gal <gal@mozilla.com>
Fri, 04 Jul 2008 03:06:18 -0700
changeset 17412 db124a3fb5a5ed207ec9e63188b287d04dc8659f
parent 17411 9c29b510c584784de3902c4f65b2db17fc02186f
child 17413 ae9f7adc0762254128de1a62b38617935dd9e589
push id1452
push usershaver@mozilla.com
push dateFri, 22 Aug 2008 00:08:22 +0000
treeherdermozilla-central@d13bb0868596 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone1.9.1a1pre
Added back support for the instructions required to compile trace.js.
js/src/builtins.tbl
js/src/jstracer.cpp
js/src/jstracer.h
js/src/nanojit/avmplus.h
--- 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();
--- a/js/src/nanojit/avmplus.h
+++ b/js/src/nanojit/avmplus.h
@@ -176,17 +176,16 @@ operator new(size_t size, GC* gc)
 
 #define MMGC_MEM_TYPE(x)
 
 typedef int FunctionID;
 
 namespace avmplus
 {
     typedef const uint16_t* FOpcodep;
-    typedef long long Box;
     
     struct InterpState
     {
         FOpcodep ip;
         void* sp;
         void* rp;
         void* f;
     };