Backed out changeset 0d61bcf08362 (bug 1013531) for bustage.

CLOSED TREE
This commit is contained in:
Ryan VanderMeulen 2014-05-29 13:26:55 -04:00
Родитель f97a6f77b4
Коммит 5822c2ae12
17 изменённых файлов: 43 добавлений и 120 удалений

Просмотреть файл

@ -81,10 +81,7 @@ CallbackObject::CallSetup::CallSetup(CallbackObject* aCallback,
nsIGlobalObject* globalObject = nullptr; nsIGlobalObject* globalObject = nullptr;
{ {
// Bug 955660: we cannot do "proper" rooting here because we need the JS::AutoAssertNoGC nogc;
// global to get a context. Everything here is simple getters that cannot
// GC, so just paper over the necessary dataflow inversion.
JS::AutoSuppressGCAnalysis nogc;
if (mIsMainThread) { if (mIsMainThread) {
// Now get the global and JSContext for this callback. // Now get the global and JSContext for this callback.
nsGlobalWindow* win = xpc::WindowGlobalOrNull(realCallback); nsGlobalWindow* win = xpc::WindowGlobalOrNull(realCallback);

Просмотреть файл

@ -369,27 +369,9 @@ extern JS_FRIEND_API(void)
ShrinkGCBuffers(JSRuntime *rt); ShrinkGCBuffers(JSRuntime *rt);
/* /*
* Assert if a GC occurs while this class is live. This class does not disable * Assert if any GC occured while this guard object was live. This is most
* the static rooting hazard analysis. * useful to help the exact rooting hazard analysis in complex regions, since
*/ * it cannot understand dataflow.
class JS_PUBLIC_API(AutoAssertOnGC)
{
JSRuntime *runtime;
size_t gcNumber;
public:
AutoAssertOnGC();
explicit AutoAssertOnGC(JSRuntime *rt);
~AutoAssertOnGC();
static void VerifyIsSafeToGC(JSRuntime *rt);
};
/*
* Disable the static rooting hazard analysis in the live region, but assert if
* any GC occurs while this guard object is live. This is most useful to help
* the exact rooting hazard analysis in complex regions, since it cannot
* understand dataflow.
* *
* Note: GC behavior is unpredictable even when deterministice and is generally * Note: GC behavior is unpredictable even when deterministice and is generally
* non-deterministic in practice. The fact that this guard has not * non-deterministic in practice. The fact that this guard has not
@ -399,28 +381,22 @@ class JS_PUBLIC_API(AutoAssertOnGC)
* that the hazard analysis is correct for that code, rather than relying * that the hazard analysis is correct for that code, rather than relying
* on this class. * on this class.
*/ */
class JS_PUBLIC_API(AutoSuppressGCAnalysis) : public AutoAssertOnGC class JS_PUBLIC_API(AutoAssertNoGC)
{ {
public: #ifdef JS_DEBUG
AutoSuppressGCAnalysis() : AutoAssertOnGC() {} JSRuntime *runtime;
explicit AutoSuppressGCAnalysis(JSRuntime *rt) : AutoAssertOnGC(rt) {} size_t gcNumber;
};
/*
* Place AutoCheckCannotGC in scopes that you believe can never GC. These
* annotations will be verified both dynamically via AutoAssertOnGC, and
* statically with the rooting hazard analysis (implemented by making the
* analysis consider AutoCheckCannotGC to be a GC pointer, and therefore
* complain if it is live across a GC call.) It is useful when dealing with
* internal pointers to GC things where the GC thing itself may not be present
* for the static analysis: e.g. acquiring inline chars from a JSString* on the
* heap.
*/
class JS_PUBLIC_API(AutoCheckCannotGC) : public AutoAssertOnGC
{
public: public:
AutoCheckCannotGC() : AutoAssertOnGC() {} AutoAssertNoGC();
explicit AutoCheckCannotGC(JSRuntime *rt) : AutoAssertOnGC(rt) {} AutoAssertNoGC(JSRuntime *rt);
~AutoAssertNoGC();
#else
public:
/* Prevent unreferenced local warnings in opt builds. */
AutoAssertNoGC() {}
explicit AutoAssertNoGC(JSRuntime *) {}
#endif
}; };
class JS_PUBLIC_API(ObjectPtr) class JS_PUBLIC_API(ObjectPtr)

Просмотреть файл

@ -138,7 +138,7 @@ var ignoreFunctions = {
"PR_ExplodeTime" : true, "PR_ExplodeTime" : true,
"PR_ErrorInstallTable" : true, "PR_ErrorInstallTable" : true,
"PR_SetThreadPrivate" : true, "PR_SetThreadPrivate" : true,
"JSObject* js::GetWeakmapKeyDelegate(JSObject*)" : true, // FIXME: mark with AutoSuppressGCAnalysis instead "JSObject* js::GetWeakmapKeyDelegate(JSObject*)" : true, // FIXME: mark with AutoAssertNoGC instead
"uint8 NS_IsMainThread()" : true, "uint8 NS_IsMainThread()" : true,
// FIXME! // FIXME!
@ -161,7 +161,7 @@ var ignoreFunctions = {
// Bug 948646 - the only thing AutoJSContext's constructor calls // Bug 948646 - the only thing AutoJSContext's constructor calls
// is an Init() routine whose entire body is covered with an // is an Init() routine whose entire body is covered with an
// AutoSuppressGCAnalysis. AutoSafeJSContext is the same thing, just with // AutoAssertNoGC. AutoSafeJSContext is the same thing, just with
// a different value for the 'aSafe' parameter. // a different value for the 'aSafe' parameter.
"void mozilla::AutoJSContext::AutoJSContext(mozilla::detail::GuardObjectNotifier*)" : true, "void mozilla::AutoJSContext::AutoJSContext(mozilla::detail::GuardObjectNotifier*)" : true,
"void mozilla::AutoSafeJSContext::~AutoSafeJSContext(int32)" : true, "void mozilla::AutoSafeJSContext::~AutoSafeJSContext(int32)" : true,
@ -230,7 +230,7 @@ function isSuppressConstructor(name)
{ {
return name.indexOf("::AutoSuppressGC") != -1 return name.indexOf("::AutoSuppressGC") != -1
|| name.indexOf("::AutoEnterAnalysis") != -1 || name.indexOf("::AutoEnterAnalysis") != -1
|| name.indexOf("::AutoSuppressGCAnalysis") != -1 || name.indexOf("::AutoAssertNoGC") != -1
|| name.indexOf("::AutoIgnoreRootingHazards") != -1; || name.indexOf("::AutoIgnoreRootingHazards") != -1;
} }

Просмотреть файл

@ -133,7 +133,6 @@ addGCType('js::LazyScript');
addGCType('js::ion::IonCode'); addGCType('js::ion::IonCode');
addGCPointer('JS::Value'); addGCPointer('JS::Value');
addGCPointer('jsid'); addGCPointer('jsid');
addGCPointer('JS::AutoCheckCannotGC');
function explain(csu, indent, seen) { function explain(csu, indent, seen) {
if (!seen) if (!seen)

Просмотреть файл

@ -537,14 +537,6 @@ class GCRuntime
/* Strong references on scripts held for PCCount profiling API. */ /* Strong references on scripts held for PCCount profiling API. */
js::ScriptAndCountsVector *scriptAndCountsVector; js::ScriptAndCountsVector *scriptAndCountsVector;
/*
* Some regions of code are hard for the static rooting hazard analysis to
* understand. In those cases, we trade the static analysis for a dynamic
* analysis. When this is non-zero, we should assert if we trigger, or
* might trigger, a GC.
*/
int inUnsafeRegion;
private: private:
/* Always preserve JIT code during GCs, for testing. */ /* Always preserve JIT code during GCs, for testing. */
bool alwaysPreserveCode; bool alwaysPreserveCode;

Просмотреть файл

@ -21,17 +21,3 @@ BEGIN_TEST(testGCExactRooting)
return true; return true;
} }
END_TEST(testGCExactRooting) END_TEST(testGCExactRooting)
BEGIN_TEST(testGCSuppressions)
{
JS::AutoAssertOnGC nogc;
JS::AutoCheckCannotGC checkgc;
JS::AutoSuppressGCAnalysis noanalysis;
JS::AutoAssertOnGC nogcRt(cx->runtime());
JS::AutoCheckCannotGC checkgcRt(cx->runtime());
JS::AutoSuppressGCAnalysis noanalysisRt(cx->runtime());
return true;
}
END_TEST(testGCSuppressions)

Просмотреть файл

@ -188,7 +188,6 @@
#include "jscntxt.h" #include "jscntxt.h"
#include "jscompartment.h" #include "jscompartment.h"
#include "jsobj.h" #include "jsobj.h"
#include "jsprf.h"
#include "jsscript.h" #include "jsscript.h"
#include "jstypes.h" #include "jstypes.h"
#include "jsutil.h" #include "jsutil.h"
@ -1115,14 +1114,13 @@ GCRuntime::GCRuntime(JSRuntime *rt) :
mallocBytes(0), mallocBytes(0),
mallocGCTriggered(false), mallocGCTriggered(false),
scriptAndCountsVector(nullptr), scriptAndCountsVector(nullptr),
helperState(rt),
alwaysPreserveCode(false), alwaysPreserveCode(false),
#ifdef DEBUG #ifdef DEBUG
noGCOrAllocationCheck(0), noGCOrAllocationCheck(0),
#endif #endif
lock(nullptr), lock(nullptr),
lockOwner(nullptr), lockOwner(nullptr),
inUnsafeRegion(0) helperState(rt)
{ {
} }
@ -4334,9 +4332,6 @@ AutoGCSession::AutoGCSession(GCRuntime *gc)
// It's ok if threads other than the main thread have suppressGC set, as // It's ok if threads other than the main thread have suppressGC set, as
// they are operating on zones which will not be collected from here. // they are operating on zones which will not be collected from here.
JS_ASSERT(!gc->rt->mainThread.suppressGC); JS_ASSERT(!gc->rt->mainThread.suppressGC);
// Assert if this is a GC unsafe region.
JS::AutoAssertOnGC::VerifyIsSafeToGC(gc->rt);
} }
AutoGCSession::~AutoGCSession() AutoGCSession::~AutoGCSession()
@ -5626,50 +5621,32 @@ JS::GetGCNumber()
return 0; return 0;
return rt->gc.number; return rt->gc.number;
} }
#endif
JS::AutoAssertOnGC::AutoAssertOnGC() JS::AutoAssertNoGC::AutoAssertNoGC()
: runtime(nullptr), gcNumber(0) : runtime(nullptr), gcNumber(0)
{ {
js::PerThreadData *data = js::TlsPerThreadData.get(); js::PerThreadData *data = js::TlsPerThreadData.get();
if (data) { if (data) {
/* /*
* GC's from off-thread will always assert, so off-thread is implicitly * GC's from off-thread will always assert, so off-thread is implicitly
* AutoAssertOnGC. We still need to allow AutoAssertOnGC to be used in * AutoAssertNoGC. We still need to allow AutoAssertNoGC to be used in
* code that works from both threads, however. We also use this to * code that works from both threads, however. We also use this to
* annotate the off thread run loops. * annotate the off thread run loops.
*/ */
runtime = data->runtimeIfOnOwnerThread(); runtime = data->runtimeIfOnOwnerThread();
if (runtime) { if (runtime)
gcNumber = runtime->gc.number; gcNumber = runtime->gc.number;
++runtime->gc.inUnsafeRegion;
}
} }
} }
JS::AutoAssertOnGC::AutoAssertOnGC(JSRuntime *rt) JS::AutoAssertNoGC::AutoAssertNoGC(JSRuntime *rt)
: runtime(rt), gcNumber(rt->gc.number) : runtime(rt), gcNumber(rt->gc.number)
{ {
++rt->gc.inUnsafeRegion;
} }
JS::AutoAssertOnGC::~AutoAssertOnGC() JS::AutoAssertNoGC::~AutoAssertNoGC()
{ {
if (runtime) { if (runtime)
--runtime->gc.inUnsafeRegion; MOZ_ASSERT(gcNumber == runtime->gc.number, "GC ran inside an AutoAssertNoGC scope.");
MOZ_ASSERT(runtime->gc.inUnsafeRegion >= 0);
/*
* The following backstop assertion should never fire: if we bumped the
* gcNumber, we should have asserted because inUnsafeRegion was true.
*/
MOZ_ASSERT(gcNumber == runtime->gc.number, "GC ran inside an AutoAssertOnGC scope.");
}
}
/* static */ void
JS::AutoAssertOnGC::VerifyIsSafeToGC(JSRuntime *rt)
{
if (rt->gc.inUnsafeRegion > 0)
MOZ_CRASH("[AutoAssertOnGC] possible GC in GC-unsafe region");
} }
#endif

Просмотреть файл

@ -504,10 +504,6 @@ CheckAllocatorState(ThreadSafeContext *cx, AllocKind kind)
JS_ASSERT(rt->gc.isAllocAllowed()); JS_ASSERT(rt->gc.isAllocAllowed());
#endif #endif
// Crash if we perform a GC action when it is not safe.
if (allowGC && !rt->mainThread.suppressGC)
JS::AutoAssertOnGC::VerifyIsSafeToGC(rt);
// For testing out of memory conditions // For testing out of memory conditions
if (!PossiblyFail()) { if (!PossiblyFail()) {
js_ReportOutOfMemory(cx); js_ReportOutOfMemory(cx);

Просмотреть файл

@ -1203,7 +1203,7 @@ inline JSObject *
GetInnerObject(JSObject *obj) GetInnerObject(JSObject *obj)
{ {
if (js::InnerObjectOp op = obj->getClass()->ext.innerObject) { if (js::InnerObjectOp op = obj->getClass()->ext.innerObject) {
JS::AutoSuppressGCAnalysis nogc; JS::AutoAssertNoGC nogc;
return op(obj); return op(obj);
} }
return obj; return obj;

Просмотреть файл

@ -165,7 +165,7 @@ ObjectValueMap::findZoneEdges()
* edge to ensure that the delegate zone does finish marking after the key * edge to ensure that the delegate zone does finish marking after the key
* zone. * zone.
*/ */
JS::AutoSuppressGCAnalysis nogc; JS::AutoAssertNoGC nogc;
Zone *mapZone = compartment->zone(); Zone *mapZone = compartment->zone();
for (Range r = all(); !r.empty(); r.popFront()) { for (Range r = all(); !r.empty(); r.popFront()) {
JSObject *key = r.front().key(); JSObject *key = r.front().key();

Просмотреть файл

@ -1047,7 +1047,7 @@ WorkerThread::handleGCHelperWorkload()
void void
WorkerThread::threadLoop() WorkerThread::threadLoop()
{ {
JS::AutoSuppressGCAnalysis nogc; JS::AutoAssertNoGC nogc;
AutoLockWorkerThreadState lock; AutoLockWorkerThreadState lock;
js::TlsPerThreadData.set(threadData.addr()); js::TlsPerThreadData.set(threadData.addr());

Просмотреть файл

@ -1503,15 +1503,15 @@ ForkJoinShared::executePortion(PerThreadData *perThread, ThreadPoolWorker *worke
// WARNING: This code runs ON THE PARALLEL WORKER THREAD. // WARNING: This code runs ON THE PARALLEL WORKER THREAD.
// Be careful when accessing cx_. // Be careful when accessing cx_.
// ForkJoinContext already contains an AutoAssertNoGC; however, the analysis
// does not propagate this type information. We duplicate the assertion
// here for maximum clarity.
JS::AutoAssertNoGC nogc(runtime());
Allocator *allocator = allocators_[worker->id()]; Allocator *allocator = allocators_[worker->id()];
ForkJoinContext cx(perThread, worker, allocator, this, &records_[worker->id()]); ForkJoinContext cx(perThread, worker, allocator, this, &records_[worker->id()]);
AutoSetForkJoinContext autoContext(&cx); AutoSetForkJoinContext autoContext(&cx);
// ForkJoinContext already contains an AutoSuppressGCAnalysis; however, the
// analysis does not propagate this type information. We duplicate the
// assertion here for maximum clarity.
JS::AutoSuppressGCAnalysis nogc;
#ifdef DEBUG #ifdef DEBUG
// Set the maximum worker and slice number for prettier spewing. // Set the maximum worker and slice number for prettier spewing.
cx.maxWorkerId = threadPool_->numWorkers(); cx.maxWorkerId = threadPool_->numWorkers();
@ -1622,7 +1622,7 @@ ForkJoinContext::ForkJoinContext(PerThreadData *perThreadData, ThreadPoolWorker
shared_(shared), shared_(shared),
worker_(worker), worker_(worker),
acquiredJSContext_(false), acquiredJSContext_(false),
nogc_() nogc_(shared->runtime())
{ {
/* /*
* Unsafely set the zone. This is used to track malloc counters and to * Unsafely set the zone. This is used to track malloc counters and to

Просмотреть файл

@ -426,7 +426,7 @@ class ForkJoinContext : public ThreadSafeContext
// ForkJoinContext is allocated on the stack. It would be dangerous to GC // ForkJoinContext is allocated on the stack. It would be dangerous to GC
// with it live because of the GC pointer fields stored in the context. // with it live because of the GC pointer fields stored in the context.
JS::AutoSuppressGCAnalysis nogc_; JS::AutoAssertNoGC nogc_;
}; };
// Locks a JSContext for its scope. Be very careful, because locking a // Locks a JSContext for its scope. Be very careful, because locking a

Просмотреть файл

@ -143,7 +143,7 @@ SPSProfiler::markEvent(const char *event)
{ {
JS_ASSERT(enabled()); JS_ASSERT(enabled());
if (eventMarker_) { if (eventMarker_) {
JS::AutoSuppressGCAnalysis nogc; JS::AutoAssertNoGC nogc;
eventMarker_(event); eventMarker_(event);
} }
} }

Просмотреть файл

@ -559,7 +559,7 @@ FrameIter::settleOnActivation()
if (data_.principals_) { if (data_.principals_) {
JSContext *cx = data_.cx_->asJSContext(); JSContext *cx = data_.cx_->asJSContext();
if (JSSubsumesOp subsumes = cx->runtime()->securityCallbacks->subsumes) { if (JSSubsumesOp subsumes = cx->runtime()->securityCallbacks->subsumes) {
JS::AutoSuppressGCAnalysis nogc; JS::AutoAssertNoGC nogc;
if (!subsumes(data_.principals_, activation->compartment()->principals)) { if (!subsumes(data_.principals_, activation->compartment()->principals)) {
++data_.activations_; ++data_.activations_;
continue; continue;

Просмотреть файл

@ -370,7 +370,7 @@ Discard(uint64_t *buffer, size_t nbytes, const JSStructuredCloneCallbacks *cb, v
return; return;
// freeTransfer should not GC // freeTransfer should not GC
JS::AutoSuppressGCAnalysis nogc; JS::AutoAssertNoGC nogc;
uint64_t numTransferables = LittleEndian::readUint64(point++); uint64_t numTransferables = LittleEndian::readUint64(point++);
while (numTransferables--) { while (numTransferables--) {

Просмотреть файл

@ -183,7 +183,7 @@ AutoJSContext::AutoJSContext(bool aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
void void
AutoJSContext::Init(bool aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL) AutoJSContext::Init(bool aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
{ {
JS::AutoSuppressGCAnalysis nogc; JS::AutoAssertNoGC nogc;
MOZ_ASSERT(!mCx, "mCx should not be initialized!"); MOZ_ASSERT(!mCx, "mCx should not be initialized!");
MOZ_GUARD_OBJECT_NOTIFIER_INIT; MOZ_GUARD_OBJECT_NOTIFIER_INIT;