Merge.
authorAndreas Gal <gal@mozilla.com>
Mon, 07 Jul 2008 02:51:36 -0700
changeset 17486 bc67eb0d7e8aa947e4549b5c352fc43646f93461
parent 17485 23d317c80d00330484a91f6bbc5afbc95fe3a588 (current diff)
parent 17484 5b4529458a560d4fabcb625f3eaadd23bb151c39 (diff)
child 17488 451aef0e1c4f24b60764dcad9340afb92d41dda5
child 17489 7716f42de1f01bb8840b51b13e9058a1eaa4f2cb
push id1452
push usershaver@mozilla.com
push dateFri, 22 Aug 2008 00:08:22 +0000
treeherderautoland@d13bb0868596 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone1.9.1a1pre
Merge.
js/src/jstracer.cpp
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -216,22 +216,22 @@ static bool isPromote(LIns *i)
 class FuncFilter: public LirWriter
 {
     TraceRecorder& recorder;
 public:
     FuncFilter(LirWriter *out, TraceRecorder& _recorder):
         LirWriter(out), recorder(_recorder)
     {
     }
-    
+
     LInsp ins1(LOpcode v, LInsp s0)
     {
         switch (v) {
         case LIR_i2f:
-            if (s0->oprnd1()->isCall() && s0->imm8() == F_doubleToInt32) 
+            if (s0->oprnd1()->isCall() && s0->imm8() == F_doubleToInt32)
                 return callArgN(s0->oprnd1(), 1);
             break;
         case LIR_u2f:
             if (s0->oprnd1()->isCall() && s0->imm8() == F_doubleToUint32)
                 return callArgN(s0->oprnd1(), 1);
             break;
         default:;
         }
@@ -314,97 +314,97 @@ public:
         LirWriter(out), recorder(_recorder)
     {
     }
 
     /* Determine the type of a store by looking at the current type of the actual value the
        interpreter is using. For numbers we have to check what kind of store we used last
        (integer or double) to figure out what the side exit show reflect in its typemap. */
     int getStoreType(jsval& v) {
-        int t = isNumber(v) 
+        int t = isNumber(v)
             ? (recorder.get(&v)->isQuad() ? JSVAL_DOUBLE : JSVAL_INT)
             : JSVAL_TAG(v);
 #ifdef DEBUG
          printf("%c", "OID?S?B"[t]);
-#endif         
+#endif
          return t;
     }
-    
+
     /* Write out a type map for the current scopes and all outer scopes,
        up until the entry scope. */
     void
     buildExitMap(JSStackFrame* fp, JSFrameRegs& regs, uint8* m)
     {
 #ifdef DEBUG
         printf("side exit type map: ");
-#endif        
+#endif
         if (fp != recorder.getEntryFrame())
             buildExitMap(fp->down, *fp->down->regs, m);
         for (unsigned n = 0; n < fp->argc; ++n)
             *m++ = getStoreType(fp->argv[n]);
         for (unsigned n = 0; n < fp->nvars; ++n)
             *m++ = getStoreType(fp->vars[n]);
         for (jsval* sp = fp->spbase; sp < regs.sp; ++sp)
             *m++ = getStoreType(*sp);
 #ifdef DEBUG
         printf("\n");
-#endif        
+#endif
     }
 
     virtual LInsp insGuard(LOpcode v, LIns *c, SideExit *x) {
         VMSideExitInfo* i = (VMSideExitInfo*)x->vmprivate;
         buildExitMap(recorder.getFp(), recorder.getRegs(), i->typeMap);
         return out->insGuard(v, c, x);
     }
 
     /* Sink all type casts into the stack into the side exit by simply storing the original
        (uncasted) value. Each guard generates the side exit map based on the types of the
        last stores to every stack location, so its safe to not perform them on-trace. */
     virtual LInsp insStore(LIns* value, LIns* base, LIns* disp) {
         if (base == recorder.getFragment()->sp && isPromote(value))
             value = demote(out, value);
         return out->insStore(value, base, disp);
     }
-    
+
     virtual LInsp insStorei(LIns* value, LIns* base, int32_t d) {
         if (base == recorder.getFragment()->sp && isPromote(value))
             value = demote(out, value);
         return out->insStorei(value, base, d);
     }
 };
 
 TraceRecorder::TraceRecorder(JSContext* cx, Fragmento* fragmento, Fragment* _fragment)
 {
     this->cx = cx;
     this->fragment = _fragment;
     entryFrame = cx->fp;
     entryRegs.pc = entryFrame->regs->pc;
     entryRegs.sp = entryFrame->regs->sp;
 
-#ifdef DEBUG    
+#ifdef DEBUG
     printf("entryRegs.pc=%p opcode=%d\n", entryRegs.pc, *entryRegs.pc);
 #endif
-    
+
     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);
 #endif
     lir = cse_filter = new (&gc) CseFilter(lir, &gc);
     lir = expr_filter = new (&gc) ExprFilter(lir);
     lir = exit_filter = new (&gc) ExitFilter(lir, *this);
     lir = func_filter = new (&gc) FuncFilter(lir, *this);
     lir->ins0(LIR_trace);
     if (fragment->vmprivate == NULL) {
         /* generate the entry map and stash it in the trace */
         unsigned entryNativeFrameSlots = nativeFrameSlots(entryFrame, entryRegs);
-        LIns* data = lir_buf_writer->skip(sizeof(VMFragmentInfo) + 
+        LIns* data = lir_buf_writer->skip(sizeof(VMFragmentInfo) +
                 entryNativeFrameSlots * sizeof(char));
         fragmentInfo = (VMFragmentInfo*)data->payload();
         fragmentInfo->entryNativeFrameSlots = entryNativeFrameSlots;
         fragmentInfo->maxNativeFrameSlots = entryNativeFrameSlots;
         /* build the entry type map */
         uint8* m = fragmentInfo->typeMap;
         for (unsigned n = 0; n < entryFrame->argc; ++n)
             *m++ = getCoercedType(entryFrame->argv[n]);
@@ -431,17 +431,17 @@ TraceRecorder::TraceRecorder(JSContext* 
     unsigned n;
     uint8* m = fragmentInfo->typeMap;
     for (n = 0; n < fp->argc; ++n)
         import(&fp->argv[n], *m, "arg", n);
     for (n = 0; n < fp->nvars; ++n)
         import(&fp->vars[n], *m, "var", n);
     for (n = 0; n < unsigned(fp->regs->sp - fp->spbase); ++n)
         import(&fp->spbase[n], *m, "stack", n);
-    
+
     recompileFlag = false;
 }
 
 TraceRecorder::~TraceRecorder()
 {
 #ifdef DEBUG
     delete lirbuf->names;
     delete verbose_filter;
@@ -561,17 +561,17 @@ unbox_jsval(jsval v, uint8 t, double* sl
         if (JSVAL_IS_INT(v))
             d = JSVAL_TO_INT(v);
         else if (JSVAL_IS_DOUBLE(v))
             d = *JSVAL_TO_DOUBLE(v);
         else
             return false;
         *(jsdouble*)slot = d;
         return true;
-    }        
+    }
     if (JSVAL_TAG(v) != type)
         return false;
     switch (JSVAL_TAG(v)) {
     case JSVAL_BOOLEAN:
         *(bool*)slot = JSVAL_TO_BOOLEAN(v);
         break;
     case JSVAL_STRING:
         *(JSString**)slot = JSVAL_TO_STRING(v);
@@ -619,17 +619,17 @@ box_jsval(JSContext* cx, jsval* vp, uint
       default:
         JS_ASSERT(t == JSVAL_OBJECT);
         *vp = OBJECT_TO_JSVAL(*(JSObject**)slot);
         break;
     }
     return true;
 }
 
-/* Attempt to unbox the given JS frame into a native frame, checking along the way that the 
+/* Attempt to unbox the given JS frame into a native frame, checking along the way that the
    supplied typemap holds. */
 static bool
 unbox(JSStackFrame* fp, JSFrameRegs& regs, uint8* m, double* native)
 {
     jsval* vp;
     for (vp = fp->argv; vp < fp->argv + fp->argc; ++vp)
         if (!unbox_jsval(*vp, *m++, native++))
             return false;
@@ -637,17 +637,17 @@ unbox(JSStackFrame* fp, JSFrameRegs& reg
         if (!unbox_jsval(*vp, *m++, native++))
             return false;
     for (vp = fp->spbase; vp < regs.sp; ++vp)
         if (!unbox_jsval(*vp, *m++, native++))
             return false;
     return true;
 }
 
-/* Box the given native frame into a JS frame. This only fails due to a hard error 
+/* Box the given native frame into a JS frame. This only fails due to a hard error
    (out of memory for example). */
 static bool
 box(JSContext* cx, JSStackFrame* fp, JSFrameRegs& regs, uint8* m, double* native)
 {
     jsval* vp;
     for (vp = fp->argv; vp < fp->argv + fp->argc; ++vp)
         if (!box_jsval(cx, vp, *m++, native++))
             return false;
@@ -670,17 +670,17 @@ TraceRecorder::import(jsval* p, uint8& t
        native stack. Arguments and locals are to the left of the stack pointer (offset
        less than 0). Stack cells start at offset 0. Ed defined the semantics of the stack,
        not me, so don't blame the messenger. */
     size_t offset = -fragmentInfo->nativeStackBase + nativeFrameOffset(p) + 8;
     if (TYPEMAP_GET_TYPE(t) == JSVAL_INT) { /* demoted */
         JS_ASSERT(isInt32(*p));
         /* Ok, we have a valid demotion attempt pending, so insert an integer
            read and promote it to double since all arithmetic operations expect
-           to see doubles on entry. The first op to use this slot will emit a 
+           to see doubles on entry. The first op to use this slot will emit a
            f2i cast which will cancel out the i2f we insert here. */
         ins = lir->ins1(LIR_i2f, lir->insLoadi(fragment->sp, offset));
     } else {
         JS_ASSERT(isNumber(*p) == (TYPEMAP_GET_TYPE(t) == JSVAL_DOUBLE));
         ins = lir->insLoad(t == JSVAL_DOUBLE ? LIR_ldq : LIR_ld, fragment->sp, offset);
     }
     tracker.set(p, ins);
 #ifdef DEBUG
@@ -704,29 +704,29 @@ TraceRecorder::set(void* p, LIns* i)
 }
 
 LIns*
 TraceRecorder::get(void* p)
 {
     return tracker.get(p);
 }
 
-JSStackFrame* 
+JSStackFrame*
 TraceRecorder::getEntryFrame() const
 {
     return entryFrame;
 }
 
 JSStackFrame*
 TraceRecorder::getFp() const
 {
     return cx->fp;
 }
 
-JSFrameRegs& 
+JSFrameRegs&
 TraceRecorder::getRegs() const
 {
     return *cx->fp->regs;
 }
 
 Fragment*
 TraceRecorder::getFragment() const
 {
@@ -762,62 +762,62 @@ TraceRecorder::guard(bool expected, LIns
                   snapshot());
 }
 
 bool
 TraceRecorder::checkType(jsval& v, uint8& t)
 {
     if (isNumber(v)) {
         /* Initially we start out all numbers as JSVAL_DOUBLE in the type map. If we still
-           see a number in v, its a valid trace but we might want to ask to demote the 
+           see a number in v, its a valid trace but we might want to ask to demote the
            slot if we know or suspect that its integer. */
         LIns* i = get(&v);
         if (TYPEMAP_GET_TYPE(t) == JSVAL_DOUBLE) {
             if (isInt32(v)) { /* value the interpreter calculated should be integer */
                 /* If the value associated with v via the tracker comes from a i2f operation,
                    we can be sure it will always be an int. If we see INCVAR, we similarly
                    speculate that the result will be int, even though this is not
                    guaranteed and this might cause the entry map to mismatch and thus
                    the trace never to be entered. */
-                if (i->isop(LIR_i2f) || 
-                        (i->isop(LIR_fadd) && i->oprnd2()->isconstq() && 
+                if (i->isop(LIR_i2f) ||
+                        (i->isop(LIR_fadd) && i->oprnd2()->isconstq() &&
                                 fabs(i->oprnd2()->constvalf()) == 1.0)) {
 #ifdef DEBUG
                     printf("demoting type of an entry slot #%d, triggering re-compilation\n",
                             nativeFrameOffset(&v));
-#endif                    
+#endif
                     JS_ASSERT(!TYPEMAP_GET_FLAG(t, TYPEMAP_FLAG_DEMOTE) ||
                             TYPEMAP_GET_FLAG(t, TYPEMAP_FLAG_DONT_DEMOTE));
                     TYPEMAP_SET_FLAG(t, TYPEMAP_FLAG_DEMOTE);
                     TYPEMAP_SET_TYPE(t, JSVAL_INT);
                     recompileFlag = true;
                     return true; /* keep going */
                 }
             }
-            return true; 
-        } 
+            return true;
+        }
         /* Looks like we are compiling an integer slot. The recorder always casts to doubles
            after each integer operation, or emits an operation that produces a double right
            away. If we started with an integer, we must arrive here pointing at a i2f cast.
            If not, than demoting the slot didn't work out. Flag the slot to be not
            demoted again. */
         JS_ASSERT(TYPEMAP_GET_TYPE(t) == JSVAL_INT &&
                 TYPEMAP_GET_FLAG(t, TYPEMAP_FLAG_DEMOTE) &&
                 !TYPEMAP_GET_FLAG(t, TYPEMAP_FLAG_DONT_DEMOTE));
         if (!i->isop(LIR_i2f)) {
-#ifdef DEBUG            
+#ifdef DEBUG
             printf("demoting type of a slot #%d failed, locking it and re-compiling\n",
                     nativeFrameOffset(&v));
 #endif
             TYPEMAP_SET_FLAG(t, TYPEMAP_FLAG_DONT_DEMOTE);
             TYPEMAP_SET_TYPE(t, JSVAL_DOUBLE);
             recompileFlag = true;
             return true; /* keep going, recompileFlag will trigger error when we are done with
                             all the slots */
-            
+
         }
         JS_ASSERT(isInt32(v));
         /* Looks like we got the final LIR_i2f as we expected. Overwrite the value in that
            slot with the argument of i2f since we want the integer store to flow along
            the loop edge, not the casted value. */
         set(&v, i->oprnd1());
         return true;
     }
@@ -898,56 +898,56 @@ js_LoopEdge(JSContext* cx)
         return false; /* done recording */
     }
 
     Fragment* f = tm->fragmento->getLoop(cx->fp->regs->pc);
     if (!f->code()) {
         int hits = ++f->hits();
         if (!f->isBlacklisted() && hits >= HOTLOOP1) {
             if (hits == HOTLOOP1 || hits == HOTLOOP2 || hits == HOTLOOP3) {
-                tm->recorder = new (&gc) TraceRecorder(cx, tm->fragmento, f);   
-                return true; /* start recording */ 
+                tm->recorder = new (&gc) TraceRecorder(cx, tm->fragmento, f);
+                return true; /* start recording */
             }
             if (hits > HOTLOOP3)
                 f->blacklist();
         }
         return false;
     }
 
     /* execute previously recorded race */
     VMFragmentInfo* fi = (VMFragmentInfo*)f->vmprivate;
     double native[fi->maxNativeFrameSlots+1];
 #ifdef DEBUG
     *(uint64*)&native[fi->maxNativeFrameSlots] = 0xdeadbeefdeadbeefLL;
 #endif
     if (!unbox(cx->fp, *cx->fp->regs, fi->typeMap, native)) {
 #ifdef DEBUG
         printf("typemap mismatch, skipping trace.\n");
-#endif        
+#endif
         return false;
     }
-    double* entry_sp = &native[fi->nativeStackBase/sizeof(double) + 
+    double* entry_sp = &native[fi->nativeStackBase/sizeof(double) +
                                (cx->fp->regs->sp - cx->fp->spbase - 1)];
     InterpState state;
     state.ip = cx->fp->regs->pc;
     state.sp = (void*)entry_sp;
     state.rp = NULL;
     state.f = NULL;
     state.cx = cx;
     union { NIns *code; GuardRecord* (FASTCALL *func)(InterpState*, Fragment*); } u;
     u.code = f->code();
-#ifdef DEBUG  
+#ifdef DEBUG
     printf("entering trace, pc=%p, sp=%p\n", state.ip, state.sp);
     uint64 start = rdtsc();
-#endif    
+#endif
     GuardRecord* lr = u.func(&state, NULL);
 #ifdef DEBUG
-    printf("leaving trace, pc=%p, sp=%p, cycles=%llu\n", state.ip, state.sp, 
+    printf("leaving trace, pc=%p, sp=%p, cycles=%llu\n", state.ip, state.sp,
             (rdtsc() - start));
-#endif    
+#endif
     cx->fp->regs->sp += (((double*)state.sp - entry_sp));
     cx->fp->regs->pc = (jsbytecode*)state.ip;
     box(cx, cx->fp, *cx->fp->regs, ((VMSideExitInfo*)lr->vmprivate)->typeMap, native);
 #ifdef DEBUG
     JS_ASSERT(*(uint64*)&native[fi->maxNativeFrameSlots] == 0xdeadbeefdeadbeefLL);
 #endif
 
     return false; /* continue with regular interpreter */
@@ -989,17 +989,17 @@ 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) && 
+    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));
@@ -1189,77 +1189,77 @@ TraceRecorder::test_property_cache(JSObj
     if (atom)
         return false;
 
     if (PCVCAP_TAG(entry->vcap == 1))
         return false; // need to look in the prototype, NYI
 
     if (OBJ_SCOPE(obj)->object != obj)
         return false; // need to normalize to the owner of the shared scope, NYI
-    
+
     LIns* shape_ins = lir->insLoadi(map_ins, offsetof(JSScope, shape));
 #ifdef DEBUG
     lirbuf->names->addName(shape_ins, "shape");
 #endif
     guard(true, lir->ins2i(LIR_eq, shape_ins, OBJ_SCOPE(obj)->shape));
     return true;
 }
 
 void
 TraceRecorder::stobj_set_slot(LIns* obj_ins, unsigned slot, LIns*& dslots_ins, LIns* v_ins)
 {
     if (slot < JS_INITIAL_NSLOTS)
-        lir->insStorei(v_ins, 
-                obj_ins, 
+        lir->insStorei(v_ins,
+                obj_ins,
                 offsetof(JSObject, fslots) + slot * sizeof(jsval));
     else {
         if (!dslots_ins)
             dslots_ins = lir->insLoadi(obj_ins, offsetof(JSObject, dslots));
-        lir->insStorei(v_ins, 
+        lir->insStorei(v_ins,
                 dslots_ins,
                 (slot - JS_INITIAL_NSLOTS) * 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, 
+        return lir->insLoadi(obj_ins,
                              offsetof(JSObject, fslots) + slot * sizeof(jsval));
-    }   
+    }
 
     if (!dslots_ins)
         dslots_ins = lir->insLoadi(obj_ins, offsetof(JSObject, dslots));
     return lir->insLoadi(dslots_ins, (slot - JS_INITIAL_NSLOTS) * sizeof(jsval));
-}    
+}
 
 bool
 TraceRecorder::native_set(LIns* obj_ins, JSScopeProperty* sprop, LIns*& dslots_ins, LIns* v_ins)
 {
     if (SPROP_HAS_STUB_SETTER(sprop) && sprop->slot != SPROP_INVALID_SLOT) {
         stobj_set_slot(obj_ins, sprop->slot, dslots_ins, v_ins);
         return true;
     }
     return false;
 }
 
 bool
-TraceRecorder::native_get(LIns* obj_ins, LIns* pobj_ins, JSScopeProperty* sprop, 
+TraceRecorder::native_get(LIns* obj_ins, LIns* pobj_ins, JSScopeProperty* sprop,
         LIns*& dslots_ins, LIns*& v_ins)
 {
     if (!SPROP_HAS_STUB_GETTER(sprop))
         return false;
 
-    if (sprop->slot != SPROP_INVALID_SLOT) 
+    if (sprop->slot != SPROP_INVALID_SLOT)
         v_ins = stobj_get_slot(pobj_ins, sprop->slot, dslots_ins);
     else
         v_ins = lir->insImm(JSVAL_VOID);
     return true;
-}    
+}
 
 bool
 TraceRecorder::box_jsval(jsval v, LIns*& v_ins)
 {
     if (isNumber(v)) {
         LIns* args[] = { v_ins, cx_ins };
         v_ins = lir->insCall(F_BoxDouble, args);
         guard(false, lir->ins2(LIR_eq, v_ins, lir->insImmPtr((void*)JSVAL_ERROR_COOKIE)));
@@ -1275,56 +1275,56 @@ TraceRecorder::box_jsval(jsval v, LIns*&
 
 bool
 TraceRecorder::unbox_jsval(jsval v, LIns*& v_ins)
 {
     if (isNumber(v)) {
         // JSVAL_IS_NUMBER(v)
         guard(true, lir->ins_eq0(
                 lir->ins_eq0(
-                        lir->ins2(LIR_and, v_ins, 
+                        lir->ins2(LIR_and, v_ins,
                                 lir->insImmPtr((void*)(JSVAL_INT | JSVAL_DOUBLE))))));
         v_ins = lir->insCall(F_UnboxDouble, &v_ins);
         return true;
     }
     switch (JSVAL_TAG(v)) {
     case JSVAL_BOOLEAN:
-        guard(true, lir->ins2i(LIR_eq, lir->ins2(LIR_and, v_ins, lir->insImmPtr((void*)~JSVAL_TRUE)), 
+        guard(true, lir->ins2i(LIR_eq, lir->ins2(LIR_and, v_ins, lir->insImmPtr((void*)~JSVAL_TRUE)),
                  JSVAL_BOOLEAN));
-         v_ins = lir->ins2i(LIR_ush, v_ins, JSVAL_TAGBITS); 
+         v_ins = lir->ins2i(LIR_ush, v_ins, JSVAL_TAGBITS);
          return true;
     }
     return false;
 }
 
 bool TraceRecorder::guardThatObjectIsDenseArray(JSObject* obj, LIns* obj_ins, LIns*& dslots_ins)
 {
     if (!OBJ_IS_DENSE_ARRAY(cx, obj))
         return false;
     // guard(OBJ_GET_CLASS(obj) == &js_ArrayClass);
     LIns* class_ins = stobj_get_slot(obj_ins, JSSLOT_CLASS, dslots_ins);
     class_ins = lir->ins2(LIR_and, class_ins, lir->insImmPtr((void*)~3));
     guard(true, lir->ins2(LIR_eq, class_ins, lir->insImmPtr(&js_ArrayClass)));
     return true;
 }
 
-bool TraceRecorder::guardDenseArrayIndexWithinBounds(JSObject* obj, jsint idx, 
+bool TraceRecorder::guardDenseArrayIndexWithinBounds(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);
     // 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, 
+    guard(true, lir->ins2(LIR_lt, idx_ins,
             lir->insLoadi(dslots_ins, -sizeof(jsval))));
     return true;
 }
 
 bool TraceRecorder::JSOP_INTERRUPT()
 {
     return false;
 }
@@ -1571,17 +1571,17 @@ bool TraceRecorder::JSOP_GETELEM()
     LIns* idx_ins = f2i(get(&r));
     /* 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))
         return false;
     jsval v = obj->dslots[idx];
     /* ok, we can trace this case since we now have the value and thus know the type */
-    LIns* addr = lir->ins2(LIR_add, dslots_ins, 
+    LIns* addr = lir->ins2(LIR_add, dslots_ins,
             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) */
     LIns* v_ins = lir->insLoadi(addr, 0);
     if (!unbox_jsval(v, v_ins))
         return false;
     set(&l, v_ins);
     return true;
 }
@@ -1603,17 +1603,17 @@ bool TraceRecorder::JSOP_SETELEM()
     jsint idx = JSVAL_TO_INT(r);
     LIns* idx_ins = f2i(get(&r));
     /* 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))
         return false;
     /* get us the address of the array slot */
-    LIns* addr = lir->ins2(LIR_add, dslots_ins, 
+    LIns* addr = lir->ins2(LIR_add, dslots_ins,
                            lir->ins2i(LIR_lsh, idx_ins, JS_BYTES_PER_WORD_LOG2));
     LIns* oldval = lir->insLoad(LIR_ld, addr, 0);
     LIns* isHole = lir->ins2(LIR_eq, oldval, lir->insImmPtr((void*)JSVAL_HOLE));
     LIns* count = lir->insLoadi(obj_ins,
                                 offsetof(JSObject, fslots[JSSLOT_ARRAY_COUNT]));
     lir->insStorei(lir->ins2(LIR_add, count, isHole), obj_ins,
                    offsetof(JSObject, fslots[JSSLOT_ARRAY_COUNT]));
     /* ok, box the value we are storing, store it and we are done */
@@ -1633,17 +1633,17 @@ bool TraceRecorder::JSOP_CALL()
 {
     return false;
 }
 bool TraceRecorder::JSOP_NAME()
 {
     JSObject* obj;
     JSObject* obj2;
     JSPropCacheEntry* entry;
-    
+
     LIns* obj_ins = lir->insLoadi(lir->insLoadi(cx_ins, offsetof(JSContext, fp)),
                                   offsetof(JSStackFrame, scopeChain));
     obj = cx->fp->scopeChain;
     if (!test_property_cache(obj, obj_ins, obj2, entry))
         return false;
 
     if (!PCVAL_IS_SLOT(entry->vword))
         return false;
--- a/js/src/jstracer.h
+++ b/js/src/jstracer.h
@@ -43,51 +43,51 @@
 #include "jsstddef.h"
 #include "jslock.h"
 #include "jsnum.h"
 #include "jsinterp.h"
 
 #include "nanojit/nanojit.h"
 
 /*
- * We use a magic boxed pointer value to represent error conditions that 
+ * We use a magic boxed pointer value to represent error conditions that
  * trigger a side exit. The address is so low that it should never be
  * actually in use. If it is, a performance regression occurs, not an
  * actual runtime error.
  */
 #define JSVAL_ERROR_COOKIE OBJECT_TO_JSVAL((void*)0x10)
 
 /*
  * We also need a magic unboxed 32-bit integer that signals an error.
  * Again if this number is hit we experience a performance regression,
  * not a runtime error.
  */
 #define INT32_ERROR_COOKIE 0xffffabcd
 
 /*
- * Tracker is used to keep track of values being manipulated by the 
+ * Tracker is used to keep track of values being manipulated by the
  * interpreter during trace recording.
  */
 template <typename T>
-class Tracker 
+class Tracker
 {
     struct Page {
         struct Page*    next;
         jsuword         base;
         T               map[0];
     };
     struct Page* pagelist;
-    
+
     jsuword         getPageBase(const void* v) const;
     struct Page*    findPage(const void* v) const;
     struct Page*    addPage(const void* v);
-public:    
+public:
     Tracker();
     ~Tracker();
-    
+
     T               get(const void* v) const;
     void            set(const void* v, T ins);
     void            clear();
 };
 
 struct VMFragmentInfo {
     unsigned                entryNativeFrameSlots;
     unsigned                maxNativeFrameSlots;
@@ -121,323 +121,95 @@ class TraceRecorder {
     nanojit::LirWriter*     verbose_filter;
     nanojit::LirWriter*     cse_filter;
     nanojit::LirWriter*     expr_filter;
     nanojit::LirWriter*     exit_filter;
     nanojit::LirWriter*     func_filter;
     nanojit::LIns*          cx_ins;
     nanojit::SideExit       exit;
     bool                    recompileFlag;
-    
+
     JSStackFrame* findFrame(void* p) const;
     bool onFrame(void* p) const;
     unsigned nativeFrameSlots(JSStackFrame* fp, JSFrameRegs& regs) const;
     size_t nativeFrameOffset(void* p) const;
     void import(jsval*, uint8& t, char *prefix, int index);
     void trackNativeFrameUse(unsigned slots);
-    
+
     unsigned getCallDepth() const;
     void guard(bool expected, nanojit::LIns* cond);
 
     void set(void* p, nanojit::LIns* l);
 
     bool checkType(jsval& v, uint8& type);
     bool verifyTypeStability(JSStackFrame* fp, JSFrameRegs& regs, uint8* m);
     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);
     void arg(unsigned n, nanojit::LIns* i);
     nanojit::LIns* var(unsigned n);
     void var(unsigned n, nanojit::LIns* i);
     nanojit::LIns* stack(int n);
     void stack(int n, nanojit::LIns* i);
-    
+
     nanojit::LIns* f2i(nanojit::LIns* f);
 
     bool ifop(bool sense);
     bool inc(jsval& v, jsint incr, bool pre);
     bool cmp(nanojit::LOpcode op, bool negate = false);
 
     bool unary(nanojit::LOpcode op);
     bool binary(nanojit::LOpcode op);
-    
-    bool ibinary(nanojit::LOpcode op); 
+
+    bool ibinary(nanojit::LOpcode op);
     bool iunary(nanojit::LOpcode op);
-    bool bbinary(nanojit::LOpcode op); 
+    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,
                              JSPropCacheEntry*& entry);
-    void stobj_set_slot(nanojit::LIns* obj_ins, unsigned slot, 
+    void stobj_set_slot(nanojit::LIns* obj_ins, unsigned slot,
             nanojit::LIns*& dslots_ins, nanojit::LIns* v_ins);
-    nanojit::LIns* stobj_get_slot(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, 
+    bool native_set(nanojit::LIns* obj_ins, JSScopeProperty* sprop,
             nanojit::LIns*& dslots_ins, nanojit::LIns* v_ins);
-    bool native_get(nanojit::LIns* obj_ins, nanojit::LIns* pobj_ins, JSScopeProperty* sprop, 
+    bool native_get(nanojit::LIns* obj_ins, nanojit::LIns* pobj_ins, JSScopeProperty* sprop,
             nanojit::LIns*& dslots_ins, nanojit::LIns*& v_ins);
 
     bool box_jsval(jsval v, nanojit::LIns*& v_ins);
     bool unbox_jsval(jsval v, nanojit::LIns*& v_ins);
-    bool guardThatObjectIsDenseArray(JSObject* obj, 
+    bool guardThatObjectIsDenseArray(JSObject* obj,
             nanojit::LIns* obj_ins, nanojit::LIns*& dslots_ins);
-    bool guardDenseArrayIndexWithinBounds(JSObject* obj, jsint idx, 
+    bool guardDenseArrayIndexWithinBounds(JSObject* obj, jsint idx,
             nanojit::LIns* obj_ins, nanojit::LIns*& dslots_ins, nanojit::LIns* idx_ins);
 public:
     TraceRecorder(JSContext* cx, nanojit::Fragmento*, nanojit::Fragment*);
     ~TraceRecorder();
 
     JSStackFrame* getEntryFrame() const;
     JSStackFrame* getFp() const;
     JSFrameRegs& getRegs() const;
     nanojit::Fragment* getFragment() const;
     nanojit::SideExit* snapshot();
 
     nanojit::LIns* get(void* p);
-    
+
     bool loopEdge();
     void stop();
-    
-    bool JSOP_INTERRUPT();
-    bool JSOP_PUSH();
-    bool JSOP_POPV();
-    bool JSOP_ENTERWITH();
-    bool JSOP_LEAVEWITH();
-    bool JSOP_RETURN();
-    bool JSOP_GOTO();
-    bool JSOP_IFEQ();
-    bool JSOP_IFNE();
-    bool JSOP_ARGUMENTS();
-    bool JSOP_FORARG();
-    bool JSOP_FORVAR();
-    bool JSOP_DUP();
-    bool JSOP_DUP2();
-    bool JSOP_SETCONST();
-    bool JSOP_BITOR();
-    bool JSOP_BITXOR();
-    bool JSOP_BITAND();
-    bool JSOP_EQ();
-    bool JSOP_NE();
-    bool JSOP_LT();
-    bool JSOP_LE();
-    bool JSOP_GT();
-    bool JSOP_GE();
-    bool JSOP_LSH();
-    bool JSOP_RSH();
-    bool JSOP_URSH();
-    bool JSOP_ADD();
-    bool JSOP_SUB();
-    bool JSOP_MUL();
-    bool JSOP_DIV();
-    bool JSOP_MOD();
-    bool JSOP_NOT();
-    bool JSOP_BITNOT();
-    bool JSOP_NEG();
-    bool JSOP_NEW();
-    bool JSOP_DELNAME();
-    bool JSOP_DELPROP();
-    bool JSOP_DELELEM();
-    bool JSOP_TYPEOF();
-    bool JSOP_VOID();
-    bool JSOP_INCNAME();
-    bool JSOP_INCPROP();
-    bool JSOP_INCELEM();
-    bool JSOP_DECNAME();
-    bool JSOP_DECPROP();
-    bool JSOP_DECELEM();
-    bool JSOP_NAMEINC();
-    bool JSOP_PROPINC();
-    bool JSOP_ELEMINC();
-    bool JSOP_NAMEDEC();
-    bool JSOP_PROPDEC();
-    bool JSOP_ELEMDEC();
-    bool JSOP_GETPROP();
-    bool JSOP_SETPROP();
-    bool JSOP_GETELEM();
-    bool JSOP_SETELEM();
-    bool JSOP_CALLNAME();
-    bool JSOP_CALL();
-    bool JSOP_NAME();
-    bool JSOP_DOUBLE();
-    bool JSOP_STRING();
-    bool JSOP_ZERO();
-    bool JSOP_ONE();
-    bool JSOP_NULL();
-    bool JSOP_THIS();
-    bool JSOP_FALSE();
-    bool JSOP_TRUE();
-    bool JSOP_OR();
-    bool JSOP_AND();
-    bool JSOP_TABLESWITCH();
-    bool JSOP_LOOKUPSWITCH();
-    bool JSOP_STRICTEQ();
-    bool JSOP_STRICTNE();
-    bool JSOP_CLOSURE();
-    bool JSOP_EXPORTALL();
-    bool JSOP_EXPORTNAME();
-    bool JSOP_IMPORTALL();
-    bool JSOP_IMPORTPROP();
-    bool JSOP_IMPORTELEM();
-    bool JSOP_OBJECT();
-    bool JSOP_POP();
-    bool JSOP_POS();
-    bool JSOP_TRAP();
-    bool JSOP_GETARG();
-    bool JSOP_SETARG();
-    bool JSOP_GETVAR();
-    bool JSOP_SETVAR();
-    bool JSOP_UINT16();
-    bool JSOP_NEWINIT();
-    bool JSOP_ENDINIT();
-    bool JSOP_INITPROP();
-    bool JSOP_INITELEM();
-    bool JSOP_DEFSHARP();
-    bool JSOP_USESHARP();
-    bool JSOP_INCARG();
-    bool JSOP_INCVAR();
-    bool JSOP_DECARG();
-    bool JSOP_DECVAR();
-    bool JSOP_ARGINC();
-    bool JSOP_VARINC();
-    bool JSOP_ARGDEC();
-    bool JSOP_VARDEC();
-    bool JSOP_ITER();
-    bool JSOP_FORNAME();
-    bool JSOP_FORPROP();
-    bool JSOP_FORELEM();
-    bool JSOP_POPN();
-    bool JSOP_BINDNAME();
-    bool JSOP_SETNAME();
-    bool JSOP_THROW();
-    bool JSOP_IN();
-    bool JSOP_INSTANCEOF();
-    bool JSOP_DEBUGGER();
-    bool JSOP_GOSUB();
-    bool JSOP_RETSUB();
-    bool JSOP_EXCEPTION();
-    bool JSOP_LINENO();
-    bool JSOP_CONDSWITCH();
-    bool JSOP_CASE();
-    bool JSOP_DEFAULT();
-    bool JSOP_EVAL();
-    bool JSOP_ENUMELEM();
-    bool JSOP_GETTER();
-    bool JSOP_SETTER();
-    bool JSOP_DEFFUN();
-    bool JSOP_DEFCONST();
-    bool JSOP_DEFVAR();
-    bool JSOP_ANONFUNOBJ();
-    bool JSOP_NAMEDFUNOBJ();
-    bool JSOP_SETLOCALPOP();
-    bool JSOP_GROUP();
-    bool JSOP_SETCALL();
-    bool JSOP_TRY();
-    bool JSOP_FINALLY();
-    bool JSOP_NOP();
-    bool JSOP_ARGSUB();
-    bool JSOP_ARGCNT();
-    bool JSOP_DEFLOCALFUN();
-    bool JSOP_GOTOX();
-    bool JSOP_IFEQX();
-    bool JSOP_IFNEX();
-    bool JSOP_ORX();
-    bool JSOP_ANDX();
-    bool JSOP_GOSUBX();
-    bool JSOP_CASEX();
-    bool JSOP_DEFAULTX();
-    bool JSOP_TABLESWITCHX();
-    bool JSOP_LOOKUPSWITCHX();
-    bool JSOP_BACKPATCH();
-    bool JSOP_BACKPATCH_POP();
-    bool JSOP_THROWING();
-    bool JSOP_SETRVAL();
-    bool JSOP_RETRVAL();
-    bool JSOP_GETGVAR();
-    bool JSOP_SETGVAR();
-    bool JSOP_INCGVAR();
-    bool JSOP_DECGVAR();
-    bool JSOP_GVARINC();
-    bool JSOP_GVARDEC();
-    bool JSOP_REGEXP();
-    bool JSOP_DEFXMLNS();
-    bool JSOP_ANYNAME();
-    bool JSOP_QNAMEPART();
-    bool JSOP_QNAMECONST();
-    bool JSOP_QNAME();
-    bool JSOP_TOATTRNAME();
-    bool JSOP_TOATTRVAL();
-    bool JSOP_ADDATTRNAME();
-    bool JSOP_ADDATTRVAL();
-    bool JSOP_BINDXMLNAME();
-    bool JSOP_SETXMLNAME();
-    bool JSOP_XMLNAME();
-    bool JSOP_DESCENDANTS();
-    bool JSOP_FILTER();
-    bool JSOP_ENDFILTER();
-    bool JSOP_TOXML();
-    bool JSOP_TOXMLLIST();
-    bool JSOP_XMLTAGEXPR();
-    bool JSOP_XMLELTEXPR();
-    bool JSOP_XMLOBJECT();
-    bool JSOP_XMLCDATA();
-    bool JSOP_XMLCOMMENT();
-    bool JSOP_XMLPI();
-    bool JSOP_CALLPROP();
-    bool JSOP_GETFUNNS();
-    bool JSOP_UNUSED186();
-    bool JSOP_DELDESC();
-    bool JSOP_UINT24();
-    bool JSOP_INDEXBASE();
-    bool JSOP_RESETBASE();
-    bool JSOP_RESETBASE0();
-    bool JSOP_STARTXML();
-    bool JSOP_STARTXMLEXPR();
-    bool JSOP_CALLELEM();
-    bool JSOP_STOP();
-    bool JSOP_GETXPROP();
-    bool JSOP_CALLXMLNAME();
-    bool JSOP_TYPEOFEXPR();
-    bool JSOP_ENTERBLOCK();
-    bool JSOP_LEAVEBLOCK();
-    bool JSOP_GETLOCAL();
-    bool JSOP_SETLOCAL();
-    bool JSOP_INCLOCAL();
-    bool JSOP_DECLOCAL();
-    bool JSOP_LOCALINC();
-    bool JSOP_LOCALDEC();
-    bool JSOP_FORLOCAL();
-    bool JSOP_FORCONST();
-    bool JSOP_ENDITER();
-    bool JSOP_GENERATOR();
-    bool JSOP_YIELD();
-    bool JSOP_ARRAYPUSH();
-    bool JSOP_UNUSED213();
-    bool JSOP_ENUMCONSTELEM();
-    bool JSOP_LEAVEBLOCKEXPR();
-    bool JSOP_GETTHISPROP();
-    bool JSOP_GETARGPROP();
-    bool JSOP_GETVARPROP();
-    bool JSOP_GETLOCALPROP();
-    bool JSOP_INDEXBASE1();
-    bool JSOP_INDEXBASE2();
-    bool JSOP_INDEXBASE3();
-    bool JSOP_CALLGVAR();
-    bool JSOP_CALLVAR();
-    bool JSOP_CALLARG();
-    bool JSOP_CALLLOCAL();
-    bool JSOP_INT8();
-    bool JSOP_INT32();
-    bool JSOP_LENGTH();
-    bool JSOP_NEWARRAY();
-    bool JSOP_HOLE();
+
+#define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format)               \
+    bool op();
+# include "jsopcode.tbl"
+#undef OPDEF
 };
 
 FASTCALL jsdouble builtin_dmod(jsdouble a, jsdouble b);
 FASTCALL jsval    builtin_BoxDouble(JSContext* cx, jsdouble d);
 FASTCALL jsval    builtin_BoxInt32(JSContext* cx, jsint i);
 FASTCALL jsdouble builtin_UnboxDouble(jsval v);
 FASTCALL jsint    builtin_UnboxInt32(jsval v);
 FASTCALL int32    builtin_doubleToInt32(jsdouble d);