Back out 80d8431f209e (bug 639270) for failing to actually compile
authorPhil Ringnalda <philringnalda@gmail.com>
Tue, 08 Mar 2011 19:59:30 -0800
changeset 64257 38aba506e3c42ad153bf207143718a254c9d8d7d
parent 64256 80d8431f209ee23b4383e1d81aaf59ddc35b9117
child 64258 206d6b6b392ff8d315e6fc3daf41d54aa6f429cc
push idunknown
push userunknown
push dateunknown
bugs639270
milestone2.0b13pre
backs out80d8431f209ee23b4383e1d81aaf59ddc35b9117
Back out 80d8431f209e (bug 639270) for failing to actually compile
js/src/jsapi.cpp
js/src/jscntxt.h
js/src/jscompartment.cpp
js/src/jscompartment.h
js/src/jsgc.cpp
js/src/jsobj.cpp
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1328,17 +1328,17 @@ JS_TransplantObject(JSContext *cx, JSObj
     }
 
     // Now, iterate through other scopes looking for references to the
     // old outer window. They need to be updated to point at the new
     // outer window.  They also might transition between different
     // types of security wrappers based on whether the new compartment
     // is same origin with them.
     Value targetv = ObjectValue(*obj);
-    CompartmentVector &vector = cx->runtime->compartments;
+    WrapperVector &vector = cx->runtime->compartments;
     AutoValueVector toTransplant(cx);
     if (!toTransplant.reserve(vector.length()))
         return NULL;
 
     for (JSCompartment **p = vector.begin(), **end = vector.end(); p != end; ++p) {
         WrapperMap &pmap = (*p)->crossCompartmentWrappers;
         if (WrapperMap::Ptr wp = pmap.lookup(origv)) {
             // We found a wrapper. Remember and root it.
@@ -1422,17 +1422,17 @@ js_TransplantObjectWithWrapper(JSContext
         obj = targetwrapper;
     }
 
     // Now, iterate through other scopes looking for references to the old
     // location object. Note that the entries in the maps are for |origobj|
     // and not |origwrapper|. They need to be updated to point at the new
     // location object.
     Value targetv = ObjectValue(*targetobj);
-    CompartmentVector &vector = cx->runtime->compartments;
+    WrapperVector &vector = cx->runtime->compartments;
     AutoValueVector toTransplant(cx);
     if (!toTransplant.reserve(vector.length()))
         return NULL;
 
     for (JSCompartment **p = vector.begin(), **end = vector.end(); p != end; ++p) {
         WrapperMap &pmap = (*p)->crossCompartmentWrappers;
         if (WrapperMap::Ptr wp = pmap.lookup(origv)) {
             // We found a wrapper. Remember and root it.
@@ -3076,41 +3076,24 @@ JS_NewGlobalObject(JSContext *cx, JSClas
         !js_SetReservedSlot(cx, obj, JSRESERVED_GLOBAL_REGEXP_STATICS, ObjectValue(*res)) ||
         !js_SetReservedSlot(cx, obj, JSRESERVED_GLOBAL_FLAGS, Int32Value(0))) {
         return NULL;
     }
 
     return obj;
 }
 
-class AutoHoldCompartment {
-  public:
-    AutoHoldCompartment(JSCompartment *compartment JS_GUARD_OBJECT_NOTIFIER_PARAM) {
-        JS_GUARD_OBJECT_NOTIFIER_INIT;
-        *(holdp = &compartment->hold) = true;
-    }
-
-    ~AutoHoldCompartment() {
-        *holdp = false;
-    }
-  private:
-    bool *holdp;
-    JS_DECL_USE_GUARD_OBJECT_NOTIFIER
-};
-
 JS_PUBLIC_API(JSObject *)
 JS_NewCompartmentAndGlobalObject(JSContext *cx, JSClass *clasp, JSPrincipals *principals)
 {
     CHECK_REQUEST(cx);
     JSCompartment *compartment = NewCompartment(cx, principals);
     if (!compartment)
         return NULL;
 
-    AutoHoldCompartment hold(compartment);
-
     JSCompartment *saved = cx->compartment;
     cx->compartment = compartment;
     JSObject *obj = JS_NewGlobalObject(cx, clasp);
     cx->compartment = saved;
 
     return obj;
 }
 
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -983,29 +983,29 @@ typedef struct JSPropertyTreeEntry {
     js::Shape           *child;
 } JSPropertyTreeEntry;
 
 typedef void
 (* JSActivityCallback)(void *arg, JSBool active);
 
 namespace js {
 
-typedef js::Vector<JSCompartment *, 0, js::SystemAllocPolicy> CompartmentVector;
+typedef js::Vector<JSCompartment *, 0, js::SystemAllocPolicy> WrapperVector;
 
 }
 
 struct JSRuntime {
     /* Default compartment. */
     JSCompartment       *atomsCompartment;
 #ifdef JS_THREADSAFE
     bool                atomsCompartmentIsLocked;
 #endif
 
     /* List of compartments (protected by the GC lock). */
-    js::CompartmentVector compartments;
+    js::WrapperVector compartments;
 
     /* Runtime state, synchronized by the stateChange/gcLock condvar/lock. */
     JSRuntimeState      state;
 
     /* Context create/destroy callback. */
     JSContextCallback   cxCallback;
 
     /* Compartment create/destroy callback. */
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -61,34 +61,34 @@ using namespace js;
 using namespace js::gc;
 
 JSCompartment::JSCompartment(JSRuntime *rt)
   : rt(rt),
     principals(NULL),
     gcBytes(0),
     gcTriggerBytes(0),
     gcLastBytes(0),
-    hold(false),
     data(NULL),
     active(false),
 #ifdef JS_METHODJIT
     jaegerCompartment(NULL),
 #endif
     propertyTree(thisForCtor()),
     emptyArgumentsShape(NULL),
     emptyBlockShape(NULL),
     emptyCallShape(NULL),
     emptyDeclEnvShape(NULL),
     emptyEnumeratorShape(NULL),
     emptyWithShape(NULL),
     debugMode(rt->debugMode),
 #if ENABLE_YARR_JIT
     regExpAllocator(NULL),
 #endif
-    mathCache(NULL)
+    mathCache(NULL),
+    marked(false)
 {
     JS_INIT_CLIST(&scripts);
 
 #ifdef JS_TRACER
     /* InitJIT expects this area to be zero'd. */
     PodZero(&traceMonitor);
 #endif
 
@@ -442,33 +442,45 @@ ScriptPoolDestroyed(JSContext *cx, mjit:
         }
     }
     return pool->m_destroy;
 }
 #endif
 
 /*
  * This method marks pointers that cross compartment boundaries. It should be
- * called only for per-compartment GCs, since full GCs naturally follow pointers
+ * called only by per-compartment GCs, since full GCs naturally follow pointers
  * across compartments.
  */
 void
-JSCompartment::markCrossCompartmentWrappers(JSTracer *trc)
+JSCompartment::markCrossCompartment(JSTracer *trc)
 {
-    JS_ASSERT(trc->context->runtime->gcCurrentCompartment);
-
     for (WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront())
         MarkValue(trc, e.front().key, "cross-compartment wrapper");
 }
 
 void
+JSCompartment::mark(JSTracer *trc)
+{
+    if (IS_GC_MARKING_TRACER(trc)) {
+        JSRuntime *rt = trc->context->runtime;
+
+        if (rt->gcCurrentCompartment && rt->gcCurrentCompartment != this)
+            return;
+
+        if (marked)
+            return;
+        marked = true;
+    }
+}
+
+void
 JSCompartment::sweep(JSContext *cx, uint32 releaseInterval)
 {
     chunk = NULL;
-
     /* Remove dead wrappers from the table. */
     for (WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront()) {
         JS_ASSERT_IF(IsAboutToBeFinalized(cx, e.front().key.toGCThing()) &&
                      !IsAboutToBeFinalized(cx, e.front().value.toGCThing()),
                      e.front().key.isString());
         if (IsAboutToBeFinalized(cx, e.front().key.toGCThing()) ||
             IsAboutToBeFinalized(cx, e.front().value.toGCThing())) {
             e.removeFront();
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -376,18 +376,16 @@ struct JS_FRIEND_API(JSCompartment) {
 
     js::gc::ArenaList            arenas[js::gc::FINALIZE_LIMIT];
     js::gc::FreeLists            freeLists;
 
     size_t                       gcBytes;
     size_t                       gcTriggerBytes;
     size_t                       gcLastBytes;
 
-    bool                         hold;
-
 #ifdef JS_GCMETER
     js::gc::JSGCArenaStats       compartmentStats[js::gc::FINALIZE_LIMIT];
 #endif
 
 #ifdef JS_TRACER
     /* Trace-tree JIT recorder/interpreter state. */
     js::TraceMonitor             traceMonitor;
 #endif
@@ -448,17 +446,20 @@ struct JS_FRIEND_API(JSCompartment) {
     LazyToSourceCache            toSourceCache;
 
     JSCompartment(JSRuntime *rt);
     ~JSCompartment();
 
     bool init();
 
     /* Mark cross-compartment wrappers. */
-    void markCrossCompartmentWrappers(JSTracer *trc);
+    void markCrossCompartment(JSTracer *trc);
+
+    /* Mark this compartment's local roots. */
+    void mark(JSTracer *trc);
 
     bool wrap(JSContext *cx, js::Value *vp);
     bool wrap(JSContext *cx, JSString **strp);
     bool wrap(JSContext *cx, JSObject **objp);
     bool wrapId(JSContext *cx, jsid *idp);
     bool wrap(JSContext *cx, js::PropertyOp *op);
     bool wrap(JSContext *cx, js::StrictPropertyOp *op);
     bool wrap(JSContext *cx, js::PropertyDescriptor *desc);
@@ -475,29 +476,34 @@ struct JS_FRIEND_API(JSCompartment) {
 
     js::DtoaCache dtoaCache;
 
   private:
     js::MathCache                *mathCache;
 
     js::MathCache *allocMathCache(JSContext *cx);
 
+    bool                         marked;
+    
     typedef js::HashMap<jsbytecode*,
                         size_t,
                         js::DefaultHasher<jsbytecode*>,
                         js::SystemAllocPolicy> BackEdgeMap;
 
     BackEdgeMap                  backEdgeTable;
 
     JSCompartment *thisForCtor() { return this; }
   public:
     js::MathCache *getMathCache(JSContext *cx) {
         return mathCache ? mathCache : allocMathCache(cx);
     }
 
+    bool isMarked() { return marked; }
+    void clearMark() { marked = false; }
+
     size_t backEdgeCount(jsbytecode *pc) const;
     size_t incBackEdgeCount(jsbytecode *pc);
 };
 
 #define JS_SCRIPTS_TO_GC(cx)    ((cx)->compartment->scriptsToGC)
 #define JS_PROPERTY_TREE(cx)    ((cx)->compartment->propertyTree)
 
 #ifdef DEBUG
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -1628,16 +1628,19 @@ MarkContext(JSTracer *trc, JSContext *ac
 
     for (js::AutoGCRooter *gcr = acx->autoGCRooters; gcr; gcr = gcr->down)
         gcr->trace(trc);
 
     if (acx->sharpObjectMap.depth > 0)
         js_TraceSharpMap(trc, &acx->sharpObjectMap);
 
     MarkValue(trc, acx->iterValue, "iterValue");
+
+    if (acx->compartment)
+        acx->compartment->mark(trc);
 }
 
 JS_REQUIRES_STACK void
 MarkRuntime(JSTracer *trc)
 {
     JSRuntime *rt = trc->context->runtime;
 
     if (rt->state != JSRTS_LANDING)
@@ -1716,16 +1719,18 @@ MarkRuntime(JSTracer *trc)
 
     js_TraceAtomState(trc);
     js_MarkTraps(trc);
 
     iter = NULL;
     while (JSContext *acx = js_ContextIterator(rt, JS_TRUE, &iter))
         MarkContext(trc, acx);
 
+    rt->atomsCompartment->mark(trc);
+
 #ifdef JS_TRACER
     for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c)
         (*c)->traceMonitor.mark(trc);
 #endif
 
     for (ThreadDataIter i(rt); !i.empty(); i.popFront())
         i.threadData()->mark(trc);
 
@@ -2177,18 +2182,23 @@ SweepCompartments(JSContext *cx, JSGCInv
     JSCompartment **end = rt->compartments.end();
     JSCompartment **write = read;
     JS_ASSERT(rt->compartments.length() >= 1);
     JS_ASSERT(*rt->compartments.begin() == rt->atomsCompartment);
 
     while (read < end) {
         JSCompartment *compartment = *read++;
 
-        if (!compartment->hold &&
-            (compartment->arenaListsAreEmpty() || gckind == GC_LAST_CONTEXT)) {
+        /*
+         * Unmarked compartments containing marked objects don't get deleted,
+         * except when LAST_CONTEXT GC is performed.
+         */
+        if ((!compartment->isMarked() && compartment->arenaListsAreEmpty()) ||
+            gckind == GC_LAST_CONTEXT)
+        {
             JS_ASSERT(compartment->freeLists.isEmpty());
             if (callback)
                 (void) callback(cx, compartment, JSCOMPARTMENT_DESTROY);
             if (compartment->principals)
                 JSPRINCIPALS_DROP(cx, compartment->principals);
             js_delete(compartment);
             continue;
         }
@@ -2253,32 +2263,35 @@ PreGCCleanup(JSContext *cx, JSGCInvocati
 static void
 MarkAndSweepCompartment(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind GCTIMER_PARAM)
 {
     JSRuntime *rt = cx->runtime;
     rt->gcNumber++;
     JS_ASSERT(!rt->gcRegenShapes);
     JS_ASSERT(gckind != GC_LAST_CONTEXT);
     JS_ASSERT(comp != rt->atomsCompartment);
+    JS_ASSERT(!comp->isMarked());
     JS_ASSERT(comp->rt->gcMode == JSGC_MODE_COMPARTMENT);
 
     /*
      * Mark phase.
      */
     GCMarker gcmarker(cx);
     JS_ASSERT(IS_GC_MARKING_TRACER(&gcmarker));
     JS_ASSERT(gcmarker.getMarkColor() == BLACK);
     rt->gcMarkingTracer = &gcmarker;
     gcmarker.stackLimit = cx->stackLimit;
 
     for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront())
          r.front()->clearMarkBitmap();
 
     for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c)
-        (*c)->markCrossCompartmentWrappers(&gcmarker);
+        (*c)->markCrossCompartment(&gcmarker);
+
+    comp->mark(&gcmarker);
 
     MarkRuntime(&gcmarker);
 
     /*
      * Mark children of things that caused too deep recursion during the above
      * tracing.
      */
     gcmarker.markDelayedChildren();
@@ -2366,16 +2379,18 @@ MarkAndSweepCompartment(JSContext *cx, J
 
     /*
      * Destroy arenas after we finished the sweeping so finalizers can safely
      * use js_IsAboutToBeFinalized().
      */
     ExpireGCChunks(rt);
     TIMESTAMP(sweepDestroyEnd);
 
+    comp->clearMark();
+
     if (rt->gcCallback)
         (void) rt->gcCallback(cx, JSGC_FINALIZE_END);
 }
 
 /*
  * Perform mark-and-sweep GC.
  *
  * In a JS_THREADSAFE build, the calling thread must be rt->gcThread and each
@@ -2503,16 +2518,19 @@ MarkAndSweep(JSContext *cx, JSGCInvocati
 
     /*
      * Destroy arenas after we finished the sweeping so finalizers can safely
      * use js_IsAboutToBeFinalized().
      */
     ExpireGCChunks(rt);
     TIMESTAMP(sweepDestroyEnd);
 
+    for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c)
+        (*c)->clearMark();
+
     if (rt->gcCallback)
         (void) rt->gcCallback(cx, JSGC_FINALIZE_END);
 #ifdef DEBUG_srcnotesize
   { extern void DumpSrcNoteSizeHist();
     DumpSrcNoteSizeHist();
     printf("GC HEAP SIZE %lu\n", (unsigned long)rt->gcBytes);
   }
 #endif
@@ -2713,16 +2731,19 @@ GCUntilDone(JSContext *cx, JSCompartment
             LetOtherGCFinish(cx);
         }
 #endif
         return;
     }
 
     AutoGCSession gcsession(cx);
 
+    for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c)
+        JS_ASSERT(!(*c)->isMarked());
+
     /*
      * We should not be depending on cx->compartment in the GC, so set it to
      * NULL to look for violations.
      */
     SwitchToCompartment(cx, (JSCompartment *)NULL);
 
     JS_ASSERT(!rt->gcCurrentCompartment);
     rt->gcCurrentCompartment = comp;
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -6504,16 +6504,21 @@ js_TraceObject(JSTracer *trc, JSObject *
     }
 
 #ifdef JS_DUMP_SCOPE_METERS
     MeterEntryCount(obj->propertyCount);
 #endif
 
     obj->trace(trc);
 
+    if (obj->getClass()->flags & JSCLASS_IS_GLOBAL) {
+        JSCompartment *compartment = obj->getCompartment();
+        compartment->mark(trc);
+    }
+
     /*
      * NB: clasp->mark could mutate something (which would be a bug, but we are
      * defensive), so don't hoist this above calling clasp->mark.
      */
     uint32 nslots = Min(obj->numSlots(), obj->slotSpan());
     for (uint32 i = 0; i != nslots; ++i) {
         const Value &v = obj->getSlot(i);
         JS_SET_TRACING_DETAILS(trc, js_PrintObjectSlotName, obj, i);