зеркало из https://github.com/mozilla/gecko-dev.git
Back out bug 1308039 - GC interrupt callbacks (a=backout)
This reverts commit 1fc1a2e080a1d9012f0ad651243766540daf139f. MozReview-Commit-ID: BvHIIj1t3M8
This commit is contained in:
Родитель
2f7dff12ca
Коммит
fbf4345dc9
|
@ -721,18 +721,6 @@ PokeGC(JSContext* cx);
|
|||
extern JS_FRIEND_API(void)
|
||||
NotifyDidPaint(JSContext* cx);
|
||||
|
||||
// GC Interrupt callbacks are run during GC. You should not run JS code or use
|
||||
// the JS engine at all while the callback is running. Otherwise they resemble
|
||||
// normal JS interrupt callbacks.
|
||||
typedef bool
|
||||
(* GCInterruptCallback)(JSContext* cx);
|
||||
|
||||
extern JS_FRIEND_API(bool)
|
||||
AddGCInterruptCallback(JSContext* cx, GCInterruptCallback callback);
|
||||
|
||||
extern JS_FRIEND_API(void)
|
||||
RequestGCInterruptCallback(JSContext* cx);
|
||||
|
||||
} /* namespace JS */
|
||||
|
||||
#endif /* js_GCAPI_h */
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
#ifndef js_SliceBudget_h
|
||||
#define js_SliceBudget_h
|
||||
|
||||
#include "mozilla/Atomics.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace js {
|
||||
|
@ -38,7 +36,7 @@ class JS_PUBLIC_API(SliceBudget)
|
|||
static const int64_t unlimitedDeadline = INT64_MAX;
|
||||
static const intptr_t unlimitedStartCounter = INTPTR_MAX;
|
||||
|
||||
bool checkOverBudget(JSContext* maybeCx);
|
||||
bool checkOverBudget();
|
||||
|
||||
SliceBudget();
|
||||
|
||||
|
@ -50,7 +48,7 @@ class JS_PUBLIC_API(SliceBudget)
|
|||
WorkBudget workBudget;
|
||||
|
||||
int64_t deadline; /* in microseconds */
|
||||
mozilla::Atomic<intptr_t, mozilla::Relaxed> counter;
|
||||
intptr_t counter;
|
||||
|
||||
static const intptr_t CounterReset = 1000;
|
||||
|
||||
|
@ -66,44 +64,19 @@ class JS_PUBLIC_API(SliceBudget)
|
|||
/* Instantiate as SliceBudget(WorkBudget(n)). */
|
||||
explicit SliceBudget(WorkBudget work);
|
||||
|
||||
// Need an explicit copy constructor because Atomic fails to provide one.
|
||||
SliceBudget(const SliceBudget& other)
|
||||
: timeBudget(other.timeBudget),
|
||||
workBudget(other.workBudget),
|
||||
deadline(other.deadline),
|
||||
counter(other.counter)
|
||||
{}
|
||||
|
||||
// Need an explicit operator= because Atomic fails to provide one.
|
||||
SliceBudget& operator=(const SliceBudget& other) {
|
||||
timeBudget = other.timeBudget;
|
||||
workBudget = other.workBudget;
|
||||
deadline = other.deadline;
|
||||
counter = intptr_t(other.counter);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void makeUnlimited() {
|
||||
deadline = unlimitedDeadline;
|
||||
counter = unlimitedStartCounter;
|
||||
}
|
||||
|
||||
// Request that checkOverBudget be called the next time isOverBudget is
|
||||
// called.
|
||||
void requestFullCheck() {
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
void step(intptr_t amt = 1) {
|
||||
counter -= amt;
|
||||
}
|
||||
|
||||
// Only need to pass maybeCx if the GC interrupt callback should be checked
|
||||
// (and possibly invoked).
|
||||
bool isOverBudget(JSContext* maybeCx = nullptr) {
|
||||
bool isOverBudget() {
|
||||
if (counter > 0)
|
||||
return false;
|
||||
return checkOverBudget(maybeCx);
|
||||
return checkOverBudget();
|
||||
}
|
||||
|
||||
bool isWorkBudget() const { return deadline == 0; }
|
||||
|
|
|
@ -24,7 +24,6 @@ namespace js {
|
|||
|
||||
class AutoLockGC;
|
||||
class AutoLockHelperThreadState;
|
||||
class SliceBudget;
|
||||
class VerifyPreTracer;
|
||||
|
||||
namespace gc {
|
||||
|
@ -858,19 +857,6 @@ class GCRuntime
|
|||
bool isVerifyPreBarriersEnabled() const { return false; }
|
||||
#endif
|
||||
|
||||
// GC interrupt callbacks.
|
||||
bool addInterruptCallback(JS::GCInterruptCallback callback);
|
||||
void requestInterruptCallback();
|
||||
|
||||
bool checkInterruptCallback(JSContext* cx) {
|
||||
if (interruptCallbackRequested) {
|
||||
invokeInterruptCallback(cx);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void invokeInterruptCallback(JSContext* cx);
|
||||
|
||||
// Free certain LifoAlloc blocks when it is safe to do so.
|
||||
void freeUnusedLifoBlocksAfterSweeping(LifoAlloc* lifo);
|
||||
void freeAllLifoBlocksAfterSweeping(LifoAlloc* lifo);
|
||||
|
@ -1086,13 +1072,6 @@ class GCRuntime
|
|||
mozilla::Atomic<uint32_t, mozilla::ReleaseAcquire> numArenasFreeCommitted;
|
||||
VerifyPreTracer* verifyPreData;
|
||||
|
||||
// GC interrupt callbacks.
|
||||
using GCInterruptCallbackVector = js::Vector<JS::GCInterruptCallback, 2, js::SystemAllocPolicy>;
|
||||
GCInterruptCallbackVector interruptCallbacks;
|
||||
|
||||
mozilla::Atomic<bool, mozilla::Relaxed> interruptCallbackRequested;
|
||||
SliceBudget* currentBudget;
|
||||
|
||||
private:
|
||||
bool chunkAllocationSinceLastGC;
|
||||
int64_t lastGCTime;
|
||||
|
|
|
@ -1559,15 +1559,13 @@ GCMarker::drainMarkStack(SliceBudget& budget)
|
|||
auto acc = mozilla::MakeScopeExit([&] {strictCompartmentChecking = false;});
|
||||
#endif
|
||||
|
||||
JSContext* cx = runtime()->contextFromMainThread();
|
||||
|
||||
if (budget.isOverBudget(cx))
|
||||
if (budget.isOverBudget())
|
||||
return false;
|
||||
|
||||
for (;;) {
|
||||
while (!stack.isEmpty()) {
|
||||
processMarkStackTop(budget);
|
||||
if (budget.isOverBudget(cx)) {
|
||||
if (budget.isOverBudget()) {
|
||||
saveValueRanges();
|
||||
return false;
|
||||
}
|
||||
|
@ -1642,8 +1640,6 @@ GCMarker::processMarkStackTop(SliceBudget& budget)
|
|||
uintptr_t tag = addr & StackTagMask;
|
||||
addr &= ~StackTagMask;
|
||||
|
||||
JSContext* cx = runtime()->contextFromMainThread();
|
||||
|
||||
// Dispatch
|
||||
switch (tag) {
|
||||
case ValueArrayTag: {
|
||||
|
@ -1697,7 +1693,7 @@ GCMarker::processMarkStackTop(SliceBudget& budget)
|
|||
MOZ_ASSERT(vp <= end);
|
||||
while (vp != end) {
|
||||
budget.step();
|
||||
if (budget.isOverBudget(cx)) {
|
||||
if (budget.isOverBudget()) {
|
||||
pushValueArray(obj, vp, end);
|
||||
return;
|
||||
}
|
||||
|
@ -1727,7 +1723,7 @@ GCMarker::processMarkStackTop(SliceBudget& budget)
|
|||
AssertZoneIsMarking(obj);
|
||||
|
||||
budget.step();
|
||||
if (budget.isOverBudget(cx)) {
|
||||
if (budget.isOverBudget()) {
|
||||
repush(obj);
|
||||
return;
|
||||
}
|
||||
|
@ -2175,7 +2171,7 @@ GCMarker::markDelayedChildren(SliceBudget& budget)
|
|||
markDelayedChildren(arena);
|
||||
|
||||
budget.step(150);
|
||||
if (budget.isOverBudget(runtime()->contextFromMainThread()))
|
||||
if (budget.isOverBudget())
|
||||
return false;
|
||||
} while (unmarkedArenaStackTop);
|
||||
MOZ_ASSERT(!markLaterArenas);
|
||||
|
|
|
@ -511,8 +511,6 @@ FinalizeTypedArenas(FreeOp* fop,
|
|||
size_t thingSize = Arena::thingSize(thingKind);
|
||||
size_t thingsPerArena = Arena::thingsPerArena(thingKind);
|
||||
|
||||
JSContext* cx = fop->onMainThread() ? fop->runtime()->contextFromMainThread() : nullptr;
|
||||
|
||||
while (Arena* arena = *src) {
|
||||
*src = arena->next;
|
||||
size_t nmarked = arena->finalize<T>(fop, thingKind, thingSize);
|
||||
|
@ -526,7 +524,7 @@ FinalizeTypedArenas(FreeOp* fop,
|
|||
fop->runtime()->gc.releaseArena(arena, maybeLock.ref());
|
||||
|
||||
budget.step(thingsPerArena);
|
||||
if (budget.isOverBudget(cx))
|
||||
if (budget.isOverBudget())
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -815,8 +813,6 @@ GCRuntime::GCRuntime(JSRuntime* rt) :
|
|||
nextCellUniqueId_(LargestTaggedNullCellPointer + 1), // Ensure disjoint from null tagged pointers.
|
||||
numArenasFreeCommitted(0),
|
||||
verifyPreData(nullptr),
|
||||
interruptCallbackRequested(false),
|
||||
currentBudget(nullptr),
|
||||
chunkAllocationSinceLastGC(false),
|
||||
lastGCTime(PRMJ_Now()),
|
||||
mode(JSGC_MODE_INCREMENTAL),
|
||||
|
@ -2911,11 +2907,8 @@ SliceBudget::describe(char* buffer, size_t maxlen) const
|
|||
}
|
||||
|
||||
bool
|
||||
SliceBudget::checkOverBudget(JSContext* cx)
|
||||
SliceBudget::checkOverBudget()
|
||||
{
|
||||
if (cx)
|
||||
cx->gc.checkInterruptCallback(cx);
|
||||
|
||||
bool over = PRMJ_Now() >= deadline;
|
||||
if (!over)
|
||||
counter = CounterReset;
|
||||
|
@ -5509,7 +5502,7 @@ GCRuntime::compactPhase(JS::gcreason::Reason reason, SliceBudget& sliceBudget,
|
|||
updatePointersToRelocatedCells(zone, lock);
|
||||
zone->setGCState(Zone::Finished);
|
||||
zonesToMaybeCompact.removeFront();
|
||||
if (sliceBudget.isOverBudget(rt->contextFromMainThread()))
|
||||
if (sliceBudget.isOverBudget())
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -5891,7 +5884,7 @@ GCRuntime::incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason rea
|
|||
* now exhasted.
|
||||
*/
|
||||
beginSweepPhase(destroyingRuntime, lock);
|
||||
if (budget.isOverBudget(rt->contextFromMainThread()))
|
||||
if (budget.isOverBudget())
|
||||
break;
|
||||
|
||||
/*
|
||||
|
@ -6316,16 +6309,6 @@ GCRuntime::collect(bool nonincrementalByAPI, SliceBudget budget, JS::gcreason::R
|
|||
if (!checkIfGCAllowedInCurrentState(reason))
|
||||
return;
|
||||
|
||||
interruptCallbackRequested = false;
|
||||
{
|
||||
AutoLockGC lock(rt);
|
||||
currentBudget = &budget;
|
||||
}
|
||||
auto guard = mozilla::MakeScopeExit([&] {
|
||||
AutoLockGC lock(rt);
|
||||
currentBudget = nullptr;
|
||||
});
|
||||
|
||||
AutoTraceLog logGC(TraceLoggerForMainThread(rt), TraceLogger_GC);
|
||||
AutoStopVerifyingBarriers av(rt, IsShutdownGC(reason));
|
||||
AutoEnqueuePendingParseTasksAfterGC aept(*this);
|
||||
|
@ -7692,48 +7675,3 @@ js::gc::Cell::dump() const
|
|||
dump(stderr);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
JS::AddGCInterruptCallback(JSContext* cx, GCInterruptCallback callback)
|
||||
{
|
||||
return cx->runtime()->gc.addInterruptCallback(callback);
|
||||
}
|
||||
|
||||
void
|
||||
JS::RequestGCInterruptCallback(JSContext* cx)
|
||||
{
|
||||
cx->runtime()->gc.requestInterruptCallback();
|
||||
}
|
||||
|
||||
bool
|
||||
GCRuntime::addInterruptCallback(JS::GCInterruptCallback callback)
|
||||
{
|
||||
return interruptCallbacks.append(callback);
|
||||
}
|
||||
|
||||
void
|
||||
GCRuntime::requestInterruptCallback()
|
||||
{
|
||||
AutoLockGC lock(rt);
|
||||
if (currentBudget) {
|
||||
interruptCallbackRequested = true;
|
||||
currentBudget->requestFullCheck();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GCRuntime::invokeInterruptCallback(JSContext* cx)
|
||||
{
|
||||
interruptCallbackRequested = false;
|
||||
|
||||
stats.suspendPhases();
|
||||
|
||||
JS::AutoAssertNoGC nogc(cx);
|
||||
JS::AutoAssertOnBarrier nobarrier(cx);
|
||||
JS::AutoSuppressGCAnalysis suppress(cx);
|
||||
for (JS::GCInterruptCallback callback : interruptCallbacks) {
|
||||
(*callback)(cx);
|
||||
}
|
||||
|
||||
stats.resumePhases();
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче