Bug 612829 - fix JS_DUMP_CONSERVATIVE_GC_ROOTS, r=igor
authorGregor Wagner <anygregor@gmail.com>
Wed, 17 Nov 2010 12:39:45 -0800
changeset 57836 7a0bb2b04bbd9979eb8b6fdf1b6747579b711354
parent 57835 7aaac92a5e110efdded8ca2d5748686b8a86d524
child 57837 08794e076dedf23252ac6c7f03c2cd1f5a896d0f
push id1
push usershaver@mozilla.com
push dateTue, 04 Jan 2011 17:58:04 +0000
reviewersigor
bugs612829
milestone2.0b8pre
Bug 612829 - fix JS_DUMP_CONSERVATIVE_GC_ROOTS, r=igor
js/src/jsgc.cpp
js/src/jsgc.h
js/src/jsgcstats.cpp
js/src/jsgcstats.h
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -209,29 +209,31 @@ Arena<T>::inFreeList(void *thing) const
 }
 
 template<typename T>
 inline ConservativeGCTest
 Arena<T>::mark(T *thing, JSTracer *trc)
 {
     JS_ASSERT(sizeof(T) == aheader.thingSize);
 
-    thing = getAlignedThing(thing);
+    T *alignedThing = getAlignedThing(thing);
 
-    if (thing > &t.things[ThingsPerArena-1].t || thing < &t.things[0].t)
+    if (alignedThing > &t.things[ThingsPerArena-1].t || alignedThing < &t.things[0].t)
         return CGCT_NOTARENA;
 
-    if (!aheader.isUsed || inFreeList(thing))
+    if (!aheader.isUsed || inFreeList(alignedThing))
         return CGCT_NOTLIVE;
 
-    JS_ASSERT(assureThingIsAligned(thing));
+    JS_SET_TRACING_NAME(trc, "machine stack");
+    Mark(trc, alignedThing);
 
-    JS_SET_TRACING_NAME(trc, "machine stack");
-    Mark(trc, thing);
-
+#ifdef JS_DUMP_CONSERVATIVE_GC_ROOTS
+    if (alignedThing != thing)
+        return CGCT_VALIDWITHOFFSET;
+#endif
     return CGCT_VALID;
 }
 
 #ifdef DEBUG
 bool
 checkArenaListsForThing(JSCompartment *comp, void *thing) {
     if (comp->arenas[FINALIZE_OBJECT0].arenasContainThing<JSObject>(thing) ||
         comp->arenas[FINALIZE_OBJECT2].arenasContainThing<JSObject_Slots2>(thing) ||
@@ -546,21 +548,22 @@ namespace js {
 template <typename T>
 static inline ConservativeGCTest
 MarkCell(Cell *cell, JSTracer *trc)
 {
     return GetArena<T>(cell)->mark((T *)cell, trc);
 }
 
 /*
- * Returns CGCT_VALID and mark it if the w can be a live GC thing and sets traceKind
- * accordingly. Otherwise returns the reason for rejection.
+ * Returns CGCT_VALID or CGCT_VALIDWITHOFFSET and mark it if the w can be a 
+ * live GC thing and sets thingKind accordingly. Otherwise returns the 
+ * reason for rejection.
  */
 inline ConservativeGCTest
-MarkIfGCThingWord(JSTracer *trc, jsuword w, uint32 &traceKind)
+MarkIfGCThingWord(JSTracer *trc, jsuword w, uint32 &thingKind)
 {
     JSRuntime *rt = trc->context->runtime;
     /*
      * The conservative scanner may access words that valgrind considers as
      * undefined. To avoid false positives and not to alter valgrind view of
      * the memory we make as memcheck-defined the argument, a copy of the
      * original word. See bug 572678.
      */
@@ -600,19 +603,19 @@ MarkIfGCThingWord(JSTracer *trc, jsuword
         return CGCT_NOTARENA;
 
     ArenaHeader *aheader = cell->arena()->header();
 
     if (!aheader->isUsed)
         return CGCT_FREEARENA;
 
     ConservativeGCTest test;
-    traceKind = aheader->thingKind;
+    thingKind = aheader->thingKind;
 
-    switch (traceKind) {
+    switch (thingKind) {
         case FINALIZE_OBJECT0:
             test = MarkCell<JSObject>(cell, trc);
             break;
         case FINALIZE_OBJECT2:
             test = MarkCell<JSObject_Slots2>(cell, trc);
             break;
         case FINALIZE_OBJECT4:
             test = MarkCell<JSObject_Slots4>(cell, trc);
@@ -649,43 +652,52 @@ MarkIfGCThingWord(JSTracer *trc, jsuword
     }
 
     return test;
 }
 
 inline ConservativeGCTest
 MarkIfGCThingWord(JSTracer *trc, jsuword w)
 {
-    uint32 traceKind;
-    return MarkIfGCThingWord(trc, w, traceKind);
+    uint32 thingKind;
+    return MarkIfGCThingWord(trc, w, thingKind);
 }
 
 static void
 MarkWordConservatively(JSTracer *trc, jsuword w)
 {
     /*
      * The conservative scanner may access words that valgrind considers as
      * undefined. To avoid false positives and not to alter valgrind view of
      * the memory we make as memcheck-defined the argument, a copy of the
      * original word. See bug 572678.
      */
 #ifdef JS_VALGRIND
     VALGRIND_MAKE_MEM_DEFINED(&w, sizeof(w));
 #endif
 
-    uint32 traceKind;
+    uint32 thingKind;
 #if defined JS_DUMP_CONSERVATIVE_GC_ROOTS || defined JS_GCMETER
     ConservativeGCTest test =
 #endif
-    MarkIfGCThingWord(trc, w, traceKind);
+    MarkIfGCThingWord(trc, w, thingKind);
 
 #ifdef JS_DUMP_CONSERVATIVE_GC_ROOTS
-    if (test == CGCT_VALID) {
+    if (test == CGCT_VALID || test == CGCT_VALIDWITHOFFSET) {
         if (IS_GC_MARKING_TRACER(trc) && static_cast<GCMarker *>(trc)->conservativeDumpFileName) {
-            GCMarker::ConservativeRoot root = {(void *)w, traceKind};
+            const jsuword JSID_PAYLOAD_MASK = ~jsuword(JSID_TYPE_MASK);
+#if JS_BITS_PER_WORD == 32
+            jsuword payload = w & JSID_PAYLOAD_MASK;
+#elif JS_BITS_PER_WORD == 64
+            jsuword payload = w & JSID_PAYLOAD_MASK & JSVAL_PAYLOAD_MASK;
+#endif
+            void *thing = (test == CGCT_VALIDWITHOFFSET) 
+                          ? GetAlignedThing((void *)payload, thingKind) 
+                          : (void *)payload;
+            GCMarker::ConservativeRoot root = {thing, thingKind};
             static_cast<GCMarker *>(trc)->conservativeRoots.append(root);
         }
     }
 #endif
 
 #if defined JS_DUMP_CONSERVATIVE_GC_ROOTS || defined JS_GCMETER
     if (IS_GC_MARKING_TRACER(trc))
         static_cast<GCMarker *>(trc)->conservativeStats.counter[test]++;
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -971,17 +971,17 @@ struct GCMarker : public JSTracer {
     size_t              markLaterCount;
 #endif
 
 #if defined(JS_DUMP_CONSERVATIVE_GC_ROOTS) || defined(JS_GCMETER)
     js::gc::ConservativeGCStats conservativeStats;
 #endif
 
 #ifdef JS_DUMP_CONSERVATIVE_GC_ROOTS
-    struct ConservativeRoot { void *thing; uint32 traceKind; };
+    struct ConservativeRoot { void *thing; uint32 thingKind; };
     Vector<ConservativeRoot, 0, SystemAllocPolicy> conservativeRoots;
     const char *conservativeDumpFileName;
 
     void dumpConservativeRoots();
 #endif
 
     js::Vector<JSObject *, 0, js::SystemAllocPolicy> arraysToSlowify;
 
--- a/js/src/jsgcstats.cpp
+++ b/js/src/jsgcstats.cpp
@@ -67,16 +67,17 @@ ConservativeGCStats::dump(FILE *fp)
     fprintf(fp, "      number of stack words: %lu\n", ULSTAT(words));
     fprintf(fp, "      excluded, low bit set: %lu\n", ULSTAT(counter[CGCT_LOWBITSET]));
     fprintf(fp, "        not withing a chunk: %lu\n", ULSTAT(counter[CGCT_NOTCHUNK]));
     fprintf(fp, "     not within arena range: %lu\n", ULSTAT(counter[CGCT_NOTARENA]));
     fprintf(fp, "       points to free arena: %lu\n", ULSTAT(counter[CGCT_FREEARENA]));
     fprintf(fp, "        excluded, wrong tag: %lu\n", ULSTAT(counter[CGCT_WRONGTAG]));
     fprintf(fp, "         excluded, not live: %lu\n", ULSTAT(counter[CGCT_NOTLIVE]));
     fprintf(fp, "            valid GC things: %lu\n", ULSTAT(counter[CGCT_VALID]));
+    fprintf(fp, "      valid but not aligned: %lu\n", ULSTAT(counter[CGCT_VALIDWITHOFFSET]));
 #undef ULSTAT
 }
 #endif
 
 #ifdef JS_GCMETER
 void
 UpdateCompartmentStats(JSCompartment *comp, unsigned thingKind, uint32 nlivearenas,
                        uint32 nkilledArenas, uint32 nthings)
@@ -130,16 +131,53 @@ JS_STATIC_ASSERT(JS_ARRAY_LENGTH(GC_AREN
 template <typename T>
 static inline void
 GetSizeAndThings(size_t &thingSize, size_t &thingsPerArena)
 {
     thingSize = sizeof(T);
     thingsPerArena = Arena<T>::ThingsPerArena;
 }
 
+#if defined JS_DUMP_CONSERVATIVE_GC_ROOTS
+void *
+GetAlignedThing(void *thing, int thingKind)
+{
+    Cell *cell = (Cell *)thing;
+    switch (thingKind) {
+        case FINALIZE_OBJECT0:
+            return (void *)GetArena<JSObject>(cell)->getAlignedThing(thing);
+        case FINALIZE_OBJECT2:
+            return (void *)GetArena<JSObject_Slots2>(cell)->getAlignedThing(thing);
+        case FINALIZE_OBJECT4:
+            return (void *)GetArena<JSObject_Slots4>(cell)->getAlignedThing(thing);
+        case FINALIZE_OBJECT8:
+            return (void *)GetArena<JSObject_Slots8>(cell)->getAlignedThing(thing);
+        case FINALIZE_OBJECT12:
+            return (void *)GetArena<JSObject_Slots12>(cell)->getAlignedThing(thing);
+        case FINALIZE_OBJECT16:
+            return (void *)GetArena<JSObject_Slots16>(cell)->getAlignedThing(thing);
+        case FINALIZE_STRING:
+            return (void *)GetArena<JSString>(cell)->getAlignedThing(thing);
+        case FINALIZE_EXTERNAL_STRING:
+            return (void *)GetArena<JSExternalString>(cell)->getAlignedThing(thing);
+        case FINALIZE_SHORT_STRING:
+            return (void *)GetArena<JSShortString>(cell)->getAlignedThing(thing);
+        case FINALIZE_FUNCTION:
+            return (void *)GetArena<JSFunction>(cell)->getAlignedThing(thing);
+#if JS_HAS_XML_SUPPORT
+        case FINALIZE_XML:
+            return (void *)GetArena<JSXML>(cell)->getAlignedThing(thing);
+#endif
+        default:
+            JS_ASSERT(false);
+            return NULL;
+    }
+}
+#endif
+
 void GetSizeAndThingsPerArena(int thingKind, size_t &thingSize, size_t &thingsPerArena)
 {
     switch (thingKind) {
         case FINALIZE_OBJECT0:
             GetSizeAndThings<JSObject>(thingSize, thingsPerArena);
             break;
         case FINALIZE_OBJECT2:
             GetSizeAndThings<JSObject_Slots2>(thingSize, thingsPerArena);
@@ -308,17 +346,17 @@ GCMarker::dumpConservativeRoots()
     }
 
     conservativeStats.dump(fp);
 
     for (ConservativeRoot *i = conservativeRoots.begin();
          i != conservativeRoots.end();
          ++i) {
         fprintf(fp, "  %p: ", i->thing);
-        switch (i->traceKind) {
+        switch (GetFinalizableTraceKind(i->thingKind)) {
           default:
             JS_NOT_REACHED("Unknown trace kind");
 
           case JSTRACE_OBJECT: {
             JSObject *obj = (JSObject *) i->thing;
             fprintf(fp, "object %s", obj->getClass()->name);
             break;
           }
--- a/js/src/jsgcstats.h
+++ b/js/src/jsgcstats.h
@@ -58,16 +58,17 @@ const bool JS_WANT_CONSERVATIVE_GC_PRINT
 namespace js {
 namespace gc {
 /*
  * The conservative GC test for a word shows that it is either a valid GC
  * thing or is not for one of the following reasons.
  */
 enum ConservativeGCTest {
     CGCT_VALID,
+    CGCT_VALIDWITHOFFSET, /* points within an object */
     CGCT_LOWBITSET, /* excluded because one of the low bits was set */
     CGCT_NOTARENA,  /* not within arena range in a chunk */
     CGCT_NOTCHUNK,  /* not within a valid chunk */
     CGCT_FREEARENA, /* within arena containing only free things */
     CGCT_WRONGTAG,  /* tagged pointer but wrong type */
     CGCT_NOTLIVE,   /* gcthing is not allocated */
     CGCT_END
 };
@@ -123,16 +124,20 @@ struct JSGCStats {
     ConservativeGCStats conservative;
 };
 
 extern void
 UpdateCompartmentStats(JSCompartment *comp, unsigned thingKind, uint32 nlivearenas,
                        uint32 nkilledArenas, uint32 nthings);
 #endif /* JS_GCMETER */
 
+#if defined JS_DUMP_CONSERVATIVE_GC_ROOTS
+void *GetAlignedThing(void *thing, int thingKind);
+#endif
+
 } //gc
 
 #ifdef MOZ_GCTIMER
 
 const bool JS_WANT_GC_SUITE_PRINT = false;  //false for gnuplot output
 
 extern jsrefcount newChunkCount;
 extern jsrefcount destroyChunkCount;