Bug 569767: add separate trace-type 'magic' for JSVAL_HOLE, r=dvander
authorDavid Mandelin <dmandelin@mozilla.com>
Thu, 03 Jun 2010 10:38:44 -0700
changeset 43263 12dab806d2c509e08f0097884d2cd3f07e2c7b3f
parent 43262 02485857682cfbc64db06158c41f86f519515412
child 43264 caf9170f297109d11b66627dc4e6f95b1ae9fcee
push idunknown
push userunknown
push dateunknown
reviewersdvander
bugs569767
milestone1.9.3a5pre
Bug 569767: add separate trace-type 'magic' for JSVAL_HOLE, r=dvander
js/src/jstracer.cpp
js/src/jstracer.h
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -374,16 +374,23 @@ InitJITStatsClass(JSContext *cx, JSObjec
 #define INS_CONSTVAL(v)       addName(insImmVal(v), #v)
 #define INS_CONSTOBJ(obj)     addName(insImmObj(obj), #obj)
 #define INS_CONSTFUN(fun)     addName(insImmFun(fun), #fun)
 #define INS_CONSTSTR(str)     addName(insImmStr(str), #str)
 #define INS_CONSTSPROP(sprop) addName(insImmSprop(sprop), #sprop)
 #define INS_ATOM(atom)        INS_CONSTSTR(ATOM_TO_STRING(atom))
 #define INS_NULL()            INS_CONSTPTR(NULL)
 #define INS_VOID()            INS_CONST(JSVAL_TO_SPECIAL(JSVAL_VOID))
+#define INS_HOLE()            INS_CONST(JSVAL_TO_SPECIAL(JSVAL_HOLE))
+
+static JS_ALWAYS_INLINE JSBool
+JSVAL_IS_HOLE(jsval v)
+{
+    return v == JSVAL_HOLE;
+}
 
 static avmplus::AvmCore s_core = avmplus::AvmCore();
 static avmplus::AvmCore* core = &s_core;
 
 static void OutOfMemoryAbort()
 {
     JS_NOT_REACHED("out of memory");
     abort();
@@ -1043,19 +1050,21 @@ GetPromotedType(jsval v)
         return TT_DOUBLE;
     if (JSVAL_IS_OBJECT(v)) {
         if (JSVAL_IS_NULL(v))
             return TT_NULL;
         if (JSVAL_TO_OBJECT(v)->isFunction())
             return TT_FUNCTION;
         return TT_OBJECT;
     }
-    /* N.B. void is JSVAL_SPECIAL. */
+    /* N.B. void and hole are JSVAL_SPECIAL. */
     if (JSVAL_IS_VOID(v))
         return TT_VOID;
+    if (JSVAL_IS_HOLE(v))
+        return TT_MAGIC;
     uint8_t tag = JSVAL_TAG(v);
     JS_ASSERT(tag == JSVAL_DOUBLE || tag == JSVAL_STRING || tag == JSVAL_SPECIAL);
     JS_STATIC_ASSERT(static_cast<jsvaltag>(TT_DOUBLE) == JSVAL_DOUBLE);
     JS_STATIC_ASSERT(static_cast<jsvaltag>(TT_STRING) == JSVAL_STRING);
     JS_STATIC_ASSERT(static_cast<jsvaltag>(TT_SPECIAL) == JSVAL_SPECIAL);
     return TraceType(tag);
 }
 
@@ -1067,19 +1076,21 @@ getCoercedType(jsval v)
         return TT_INT32;
     if (JSVAL_IS_OBJECT(v)) {
         if (JSVAL_IS_NULL(v))
             return TT_NULL;
         if (JSVAL_TO_OBJECT(v)->isFunction())
             return TT_FUNCTION;
         return TT_OBJECT;
     }
-    /* N.B. void is JSVAL_SPECIAL. */
+    /* N.B. void and hole are JSVAL_SPECIAL. */
     if (JSVAL_IS_VOID(v))
         return TT_VOID;
+    if (JSVAL_IS_HOLE(v))
+        return TT_MAGIC;
     uint8_t tag = JSVAL_TAG(v);
     JS_ASSERT(tag == JSVAL_DOUBLE || tag == JSVAL_STRING || tag == JSVAL_SPECIAL);
     JS_STATIC_ASSERT(static_cast<jsvaltag>(TT_DOUBLE) == JSVAL_DOUBLE);
     JS_STATIC_ASSERT(static_cast<jsvaltag>(TT_STRING) == JSVAL_STRING);
     JS_STATIC_ASSERT(static_cast<jsvaltag>(TT_SPECIAL) == JSVAL_SPECIAL);
     return TraceType(tag);
 }
 
@@ -2626,16 +2637,22 @@ ValueToNative(JSContext* cx, jsval v, Tr
         return;
 
       case TT_VOID:
         JS_ASSERT(JSVAL_IS_VOID(v));
         *(JSBool*)slot = JSVAL_TO_SPECIAL(JSVAL_VOID);
         debug_only_print0(LC_TMTracer, "undefined ");
         return;
 
+      case TT_MAGIC:
+        JS_ASSERT(JSVAL_IS_HOLE(v));
+        *(JSBool*)slot = JSVAL_TO_SPECIAL(JSVAL_HOLE);
+        debug_only_print0(LC_TMTracer, "hole ");
+        return;
+
       case TT_FUNCTION: {
         JS_ASSERT(tag == JSVAL_OBJECT);
         JSObject* obj = JSVAL_TO_OBJECT(v);
         *(JSObject**)slot = obj;
 #ifdef DEBUG
         JSFunction* fun = GET_FUNCTION_PRIVATE(cx, obj);
         debug_only_printf(LC_TMTracer,
                           "function<%p:%s> ", (void*) obj,
@@ -2805,16 +2822,21 @@ NativeToValue(JSContext* cx, jsval& v, T
         debug_only_printf(LC_TMTracer, "special<%d> ", *(JSBool*)slot);
         break;
 
       case TT_VOID:
         v = JSVAL_VOID;
         debug_only_print0(LC_TMTracer, "undefined ");
         break;
 
+      case TT_MAGIC:
+        v = JSVAL_HOLE;
+        debug_only_print0(LC_TMTracer, "hole ");
+        break;
+
       case TT_FUNCTION: {
         JS_ASSERT((*(JSObject**)slot)->isFunction());
         v = OBJECT_TO_JSVAL(*(JSObject**)slot);
 #ifdef DEBUG
         JSFunction* fun = GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(v));
         debug_only_printf(LC_TMTracer,
                           "function<%p:%s> ", (void*)JSVAL_TO_OBJECT(v),
                           fun->atom
@@ -3351,16 +3373,18 @@ TraceRecorder::import(LIns* base, ptrdif
     } else {
         JS_ASSERT_IF(t != TT_JSVAL, isNumber(*p) == (t == TT_DOUBLE));
         if (t == TT_DOUBLE) {
             ins = lir->insLoad(LIR_ldd, base, offset, accSet);
         } else if (t == TT_SPECIAL) {
             ins = lir->insLoad(LIR_ldi, base, offset, accSet);
         } else if (t == TT_VOID) {
             ins = INS_VOID();
+        } else if (t == TT_MAGIC) {
+            ins = INS_HOLE();
         } else {
             ins = lir->insLoad(LIR_ldp, base, offset, accSet);
         }
     }
     checkForGlobalObjectReallocation();
     tracker.set(p, ins);
 
 #ifdef DEBUG
@@ -3852,16 +3876,19 @@ TraceRecorder::determineSlotType(jsval* 
             m = TT_NULL;
         else if (JSVAL_TO_OBJECT(*vp)->isFunction())
             m = TT_FUNCTION;
         else
             m = TT_OBJECT;
     } else if (JSVAL_IS_VOID(*vp)) {
         /* N.B. void is JSVAL_SPECIAL. */
         m = TT_VOID;
+    } else if (JSVAL_IS_HOLE(*vp)) {
+        /* N.B. hole is JSVAL_SPECIAL. */
+        m = TT_MAGIC;
     } else {
         JS_ASSERT(JSVAL_IS_STRING(*vp) || JSVAL_IS_SPECIAL(*vp));
         JS_STATIC_ASSERT(static_cast<jsvaltag>(TT_STRING) == JSVAL_STRING);
         JS_STATIC_ASSERT(static_cast<jsvaltag>(TT_SPECIAL) == JSVAL_SPECIAL);
         m = TraceType(JSVAL_TAG(*vp));
     }
     JS_ASSERT(m != TT_INT32 || isInt32(*vp));
     return m;
@@ -6074,26 +6101,31 @@ IsEntryTypeCompatible(jsval* vp, TraceTy
         debug_only_printf(LC_TMTracer, "string != tag%u ", tag);
         return false;
       case TT_NULL:
         if (JSVAL_IS_NULL(*vp))
             return true;
         debug_only_printf(LC_TMTracer, "null != tag%u ", tag);
         return false;
       case TT_SPECIAL:
-        /* N.B. void is JSVAL_SPECIAL. */
+        /* N.B. void and hole are JSVAL_SPECIAL. */
         if (JSVAL_IS_SPECIAL(*vp) && !JSVAL_IS_VOID(*vp))
             return true;
         debug_only_printf(LC_TMTracer, "bool != tag%u ", tag);
         return false;
       case TT_VOID:
         if (JSVAL_IS_VOID(*vp))
             return true;
         debug_only_printf(LC_TMTracer, "undefined != tag%u ", tag);
         return false;
+      case TT_MAGIC:
+        if (JSVAL_IS_HOLE(*vp))
+            return true;
+        debug_only_printf(LC_TMTracer, "hole != tag%u ", tag);
+        return false;
       default:
         JS_ASSERT(*m == TT_FUNCTION);
         if (tag == JSVAL_OBJECT && !JSVAL_IS_NULL(*vp) &&
             JSVAL_TO_OBJECT(*vp)->isFunction()) {
             return true;
         }
         debug_only_printf(LC_TMTracer, "fun != tag%u ", tag);
         return false;
@@ -9379,16 +9411,20 @@ TraceRecorder::unbox_jsval(jsval v, LIns
         return lir->insCall(&js_UnboxDouble_ci, args);
     }
     switch (JSVAL_TAG(v)) {
       case JSVAL_SPECIAL:
         if (JSVAL_IS_VOID(v)) {
             guard(true, lir->ins2(LIR_eqp, v_ins, INS_CONSTWORD(JSVAL_VOID)), exit);
             return INS_VOID();
         }
+        if (JSVAL_IS_HOLE(v)) {
+            guard(true, lir->ins2(LIR_eqp, v_ins, INS_CONSTWORD(JSVAL_HOLE)), exit);
+            return INS_HOLE();
+        }
         guard(true,
               lir->ins2(LIR_eqp,
                         lir->ins2(LIR_andp, v_ins, INS_CONSTWORD(JSVAL_TAGMASK)),
                         INS_CONSTWORD(JSVAL_SPECIAL)),
               exit);
         JS_ASSERT(!v_ins->isImmP());
         guard(false, lir->ins2(LIR_eqp, v_ins, INS_CONSTWORD(JSVAL_VOID)), exit);
         return p2i(lir->ins2ImmI(LIR_rshup, v_ins, JSVAL_TAGBITS));
@@ -12461,16 +12497,17 @@ TraceRecorder::stackLoad(LIns* base, Acc
       case TT_STRING:
       case TT_FUNCTION:
       case TT_NULL:
         loadOp = LIR_ldp;
         break;
       case TT_INT32:
       case TT_SPECIAL:
       case TT_VOID:
+      case TT_MAGIC:
         loadOp = LIR_ldi;
         break;
       case TT_JSVAL:
       default:
         JS_NOT_REACHED("found jsval type in an upvar type map entry");
         return NULL;
     }
 
@@ -13175,17 +13212,17 @@ TraceRecorder::denseArrayElement(jsval& 
     /* Load the value and guard on its type to unbox it. */
     vp = &obj->dslots[jsuint(idx)];
     addr_ins = lir->ins2(LIR_addp, dslots_ins,
                          lir->ins2ImmI(LIR_lshp, pidx_ins, (sizeof(jsval) == 4) ? 2 : 3));
     v_ins = unbox_jsval(*vp, lir->insLoad(LIR_ldp, addr_ins, 0, ACC_OTHER), exit);
 
     if (JSVAL_IS_SPECIAL(*vp) && !JSVAL_IS_VOID(*vp)) {
         JS_ASSERT_IF(!JSVAL_IS_BOOLEAN(*vp), *vp == JSVAL_HOLE);
-        guard(*vp == JSVAL_HOLE, lir->ins2(LIR_eqi, v_ins, INS_CONST(JSVAL_TO_SPECIAL(JSVAL_HOLE))), exit);
+        guard(*vp == JSVAL_HOLE, lir->ins2(LIR_eqi, v_ins, INS_HOLE()), exit);
 
         /* Don't let the hole value escape. Turn it into an undefined. */
         if (*vp == JSVAL_HOLE) {
             CHECK_STATUS(guardPrototypeHasNoIndexedProperties(obj, obj_ins, MISMATCH_EXIT));
             v_ins = INS_CONST(JSVAL_TO_SPECIAL(JSVAL_VOID));
         }
     }
     return RECORD_CONTINUE;
@@ -15284,17 +15321,17 @@ TraceRecorder::record_JSOP_NEWARRAY()
 
     stack(-int(len), v_ins);
     return ARECORD_CONTINUE;
 }
 
 JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_HOLE()
 {
-    stack(0, INS_CONST(JSVAL_TO_SPECIAL(JSVAL_HOLE)));
+    stack(0, INS_HOLE());
     return ARECORD_CONTINUE;
 }
 
 AbortableRecordingStatus
 TraceRecorder::record_JSOP_TRACE()
 {
     return ARECORD_CONTINUE;
 }
--- a/js/src/jstracer.h
+++ b/js/src/jstracer.h
@@ -337,26 +337,27 @@ public:
  * otherwise work correctly.  A static assertion in jstracer.cpp verifies that
  * this requirement is correctly enforced by these compilers.
  */
 enum TraceType_
 #if defined(_MSC_VER) && _MSC_VER >= 1400
 : int8_t
 #endif
 {
-    TT_OBJECT         = 0, /* pointer to JSObject whose class is not js_FunctionClass */
-    TT_INT32          = 1, /* 32-bit signed integer */
-    TT_DOUBLE         = 2, /* pointer to jsdouble */
-    TT_JSVAL          = 3, /* arbitrary jsval */
-    TT_STRING         = 4, /* pointer to JSString */
-    TT_NULL           = 5, /* null */
-    TT_SPECIAL        = 6, /* true, false, hole, or areturn (0, 1, 6, or 8) */
-    TT_VOID           = 7, /* undefined (2) */
-    TT_FUNCTION       = 8, /* pointer to JSObject whose class is js_FunctionClass */
-    TT_IGNORE         = 9
+    TT_OBJECT        =  0, /* pointer to JSObject whose class is not js_FunctionClass */
+    TT_INT32         =  1, /* 32-bit signed integer */
+    TT_DOUBLE        =  2, /* pointer to jsdouble */
+    TT_JSVAL         =  3, /* arbitrary jsval */
+    TT_STRING        =  4, /* pointer to JSString */
+    TT_NULL          =  5, /* null */
+    TT_SPECIAL       =  6, /* true, false, hole, or areturn (0, 1, 6, or 8) */
+    TT_VOID          =  7, /* undefined (2) */
+    TT_FUNCTION      =  8, /* pointer to JSObject whose class is js_FunctionClass */
+    TT_MAGIC         =  9, /* a 'magic' value, aka a hole */
+    TT_IGNORE        = 10
 }
 #if defined(__GNUC__) && defined(USE_TRACE_TYPE_ENUM)
 __attribute__((packed))
 #endif
 ;
 
 #ifdef USE_TRACE_TYPE_ENUM
 typedef TraceType_ TraceType;