Bug 751618 - Add js/GCAPI.h (r=terrence)

This commit is contained in:
Bill McCloskey 2013-01-27 12:35:12 -08:00
Родитель a0c5a1f359
Коммит f192791e29
19 изменённых файлов: 324 добавлений и 310 удалений

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

@ -13,6 +13,7 @@
#include "nsIProgrammingLanguage.h"
#include "jsfriendapi.h"
#include "jspubtd.h"
#include "js/GCAPI.h"
class nsIScriptGlobalObject;
class nsIScriptSecurityManager;
@ -201,7 +202,7 @@ public:
*
* @return NS_OK if the method is successful
*/
virtual void GC(js::gcreason::Reason aReason) = 0;
virtual void GC(JS::gcreason::Reason aReason) = 0;
/**
* Inform the context that a script was evaluated.

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

@ -146,7 +146,7 @@ static PRTime sLastCCEndTime;
static bool sCCLockedOut;
static PRTime sCCLockedOutTime;
static js::GCSliceCallback sPrevGCSliceCallback;
static JS::GCSliceCallback sPrevGCSliceCallback;
static js::AnalysisPurgeCallback sPrevAnalysisPurgeCallback;
// The number of currently pending document loads. This count isn't
@ -235,7 +235,7 @@ nsJSEnvironmentObserver::Observe(nsISupports* aSubject, const char* aTopic,
const PRUnichar* aData)
{
if (sGCOnMemoryPressure && !nsCRT::strcmp(aTopic, "memory-pressure")) {
nsJSContext::GarbageCollectNow(js::gcreason::MEM_PRESSURE,
nsJSContext::GarbageCollectNow(JS::gcreason::MEM_PRESSURE,
nsJSContext::NonIncrementalGC,
nsJSContext::NonCompartmentGC,
nsJSContext::ShrinkingGC);
@ -1181,7 +1181,7 @@ nsJSContext::DestroyJSContext()
js_options_dot_str, this);
if (mGCOnDestruction) {
PokeGC(js::gcreason::NSJSCONTEXT_DESTROY);
PokeGC(JS::gcreason::NSJSCONTEXT_DESTROY);
}
// Let xpconnect destroy the JSContext when it thinks the time is right.
@ -2536,13 +2536,13 @@ FullGCTimerFired(nsITimer* aTimer, void* aClosure)
NS_RELEASE(sFullGCTimer);
uintptr_t reason = reinterpret_cast<uintptr_t>(aClosure);
nsJSContext::GarbageCollectNow(static_cast<js::gcreason::Reason>(reason),
nsJSContext::GarbageCollectNow(static_cast<JS::gcreason::Reason>(reason),
nsJSContext::IncrementalGC);
}
//static
void
nsJSContext::GarbageCollectNow(js::gcreason::Reason aReason,
nsJSContext::GarbageCollectNow(JS::gcreason::Reason aReason,
IsIncremental aIncremental,
IsCompartment aCompartment,
IsShrinking aShrinking,
@ -2570,8 +2570,8 @@ nsJSContext::GarbageCollectNow(js::gcreason::Reason aReason,
if (sCCLockedOut && aIncremental == IncrementalGC) {
// We're in the middle of incremental GC. Do another slice.
js::PrepareForIncrementalGC(nsJSRuntime::sRuntime);
js::IncrementalGC(nsJSRuntime::sRuntime, aReason, aSliceMillis);
JS::PrepareForIncrementalGC(nsJSRuntime::sRuntime);
JS::IncrementalGC(nsJSRuntime::sRuntime, aReason, aSliceMillis);
return;
}
@ -2581,20 +2581,20 @@ nsJSContext::GarbageCollectNow(js::gcreason::Reason aReason,
if (!sDisableExplicitCompartmentGC &&
aShrinking != ShrinkingGC && aCompartment != NonCompartmentGC &&
sCompartmentGCCount < NS_MAX_COMPARTMENT_GC_COUNT) {
js::PrepareForFullGC(nsJSRuntime::sRuntime);
JS::PrepareForFullGC(nsJSRuntime::sRuntime);
for (nsJSContext* cx = sContextList; cx; cx = cx->mNext) {
if (!cx->mActive && cx->mContext) {
if (JSObject* global = cx->GetNativeGlobal()) {
js::SkipCompartmentForGC(js::GetObjectCompartment(global));
JS::SkipCompartmentForGC(js::GetObjectCompartment(global));
}
}
cx->mActive = false;
}
if (js::IsGCScheduled(nsJSRuntime::sRuntime)) {
if (JS::IsGCScheduled(nsJSRuntime::sRuntime)) {
if (aIncremental == IncrementalGC) {
js::IncrementalGC(nsJSRuntime::sRuntime, aReason, aSliceMillis);
JS::IncrementalGC(nsJSRuntime::sRuntime, aReason, aSliceMillis);
} else {
js::GCForReason(nsJSRuntime::sRuntime, aReason);
JS::GCForReason(nsJSRuntime::sRuntime, aReason);
}
}
return;
@ -2603,11 +2603,11 @@ nsJSContext::GarbageCollectNow(js::gcreason::Reason aReason,
for (nsJSContext* cx = sContextList; cx; cx = cx->mNext) {
cx->mActive = false;
}
js::PrepareForFullGC(nsJSRuntime::sRuntime);
JS::PrepareForFullGC(nsJSRuntime::sRuntime);
if (aIncremental == IncrementalGC) {
js::IncrementalGC(nsJSRuntime::sRuntime, aReason, aSliceMillis);
JS::IncrementalGC(nsJSRuntime::sRuntime, aReason, aSliceMillis);
} else {
js::GCForReason(nsJSRuntime::sRuntime, aReason);
JS::GCForReason(nsJSRuntime::sRuntime, aReason);
}
}
@ -2619,7 +2619,7 @@ nsJSContext::ShrinkGCBuffersNow()
KillShrinkGCBuffersTimer();
JS_ShrinkGCBuffers(nsJSRuntime::sRuntime);
JS::ShrinkGCBuffers(nsJSRuntime::sRuntime);
}
// Return true if any JSContext has a "global object" with a gray
@ -2636,7 +2636,7 @@ AnyGrayGlobalParent()
while ((cx = JS_ContextIterator(nsJSRuntime::sRuntime, &iter))) {
if (JSObject *global = JS_GetGlobalObject(cx)) {
if (JSObject *parent = js::GetObjectParent(global)) {
if (js::GCThingIsMarkedGray(parent) &&
if (JS::GCThingIsMarkedGray(parent) &&
!js::IsSystemCompartment(js::GetGCThingCompartment(parent))) {
return true;
}
@ -2686,8 +2686,8 @@ FinishAnyIncrementalGC()
{
if (sCCLockedOut) {
// We're in the middle of an incremental GC, so finish it.
js::PrepareForIncrementalGC(nsJSRuntime::sRuntime);
js::FinishIncrementalGC(nsJSRuntime::sRuntime, js::gcreason::CC_FORCED);
JS::PrepareForIncrementalGC(nsJSRuntime::sRuntime);
JS::FinishIncrementalGC(nsJSRuntime::sRuntime, JS::gcreason::CC_FORCED);
}
}
@ -2770,7 +2770,7 @@ nsJSContext::CycleCollectNow(nsICycleCollectorListener *aListener,
// If we collected a substantial amount of cycles, poke the GC since more objects
// might be unreachable now.
if (sCCollectedWaitingForGC > 250) {
PokeGC(js::gcreason::CC_WAITING);
PokeGC(JS::gcreason::CC_WAITING);
}
PRTime endCCTime = PR_Now();
@ -2888,7 +2888,7 @@ void
InterSliceGCTimerFired(nsITimer *aTimer, void *aClosure)
{
NS_RELEASE(sInterSliceGCTimer);
nsJSContext::GarbageCollectNow(js::gcreason::INTER_SLICE_GC,
nsJSContext::GarbageCollectNow(JS::gcreason::INTER_SLICE_GC,
nsJSContext::IncrementalGC,
nsJSContext::CompartmentGC,
nsJSContext::NonShrinkingGC,
@ -2902,7 +2902,7 @@ GCTimerFired(nsITimer *aTimer, void *aClosure)
NS_RELEASE(sGCTimer);
uintptr_t reason = reinterpret_cast<uintptr_t>(aClosure);
nsJSContext::GarbageCollectNow(static_cast<js::gcreason::Reason>(reason),
nsJSContext::GarbageCollectNow(static_cast<JS::gcreason::Reason>(reason),
nsJSContext::IncrementalGC,
nsJSContext::CompartmentGC);
}
@ -3019,12 +3019,12 @@ nsJSContext::LoadEnd()
// Its probably a good idea to GC soon since we have finished loading.
sLoadingInProgress = false;
PokeGC(js::gcreason::LOAD_END);
PokeGC(JS::gcreason::LOAD_END);
}
// static
void
nsJSContext::PokeGC(js::gcreason::Reason aReason, int aDelay)
nsJSContext::PokeGC(JS::gcreason::Reason aReason, int aDelay)
{
if (sGCTimer || sShuttingDown) {
// There's already a timer for GC'ing, just return
@ -3145,7 +3145,7 @@ nsJSContext::KillCCTimer()
}
void
nsJSContext::GC(js::gcreason::Reason aReason)
nsJSContext::GC(JS::gcreason::Reason aReason)
{
mActive = true;
PokeGC(aReason);
@ -3179,11 +3179,11 @@ NotifyGCEndRunnable::Run()
}
static void
DOMGCSliceCallback(JSRuntime *aRt, js::GCProgress aProgress, const js::GCDescription &aDesc)
DOMGCSliceCallback(JSRuntime *aRt, JS::GCProgress aProgress, const JS::GCDescription &aDesc)
{
NS_ASSERTION(NS_IsMainThread(), "GCs must run on the main thread");
if (aProgress == js::GC_CYCLE_END) {
if (aProgress == JS::GC_CYCLE_END) {
PRTime delta = GetCollectionTimeDelta();
if (sPostGCEventsToConsole) {
@ -3208,15 +3208,15 @@ DOMGCSliceCallback(JSRuntime *aRt, js::GCProgress aProgress, const js::GCDescrip
}
// Prevent cycle collections and shrinking during incremental GC.
if (aProgress == js::GC_CYCLE_BEGIN) {
if (aProgress == JS::GC_CYCLE_BEGIN) {
sCCLockedOut = true;
nsJSContext::KillShrinkGCBuffersTimer();
} else if (aProgress == js::GC_CYCLE_END) {
} else if (aProgress == JS::GC_CYCLE_END) {
sCCLockedOut = false;
}
// The GC has more work to do, so schedule another GC slice.
if (aProgress == js::GC_SLICE_END) {
if (aProgress == JS::GC_SLICE_END) {
nsJSContext::KillInterSliceGCTimer();
if (!sShuttingDown) {
CallCreateInstance("@mozilla.org/timer;1", &sInterSliceGCTimer);
@ -3227,7 +3227,7 @@ DOMGCSliceCallback(JSRuntime *aRt, js::GCProgress aProgress, const js::GCDescrip
}
}
if (aProgress == js::GC_CYCLE_END) {
if (aProgress == JS::GC_CYCLE_END) {
// May need to kill the inter-slice GC timer
nsJSContext::KillInterSliceGCTimer();
@ -3240,7 +3240,7 @@ DOMGCSliceCallback(JSRuntime *aRt, js::GCProgress aProgress, const js::GCDescrip
++sCompartmentGCCount;
if (!sFullGCTimer && !sShuttingDown) {
CallCreateInstance("@mozilla.org/timer;1", &sFullGCTimer);
js::gcreason::Reason reason = js::gcreason::FULL_GC_TIMER;
JS::gcreason::Reason reason = JS::gcreason::FULL_GC_TIMER;
sFullGCTimer->InitWithFuncCallback(FullGCTimerFired,
reinterpret_cast<void *>(reason),
NS_FULL_GC_DELAY,
@ -3567,7 +3567,7 @@ nsJSRuntime::Init()
// Let's make sure that our main thread is the same as the xpcom main thread.
NS_ASSERTION(NS_IsMainThread(), "bad");
sPrevGCSliceCallback = js::SetGCSliceCallback(sRuntime, DOMGCSliceCallback);
sPrevGCSliceCallback = JS::SetGCSliceCallback(sRuntime, DOMGCSliceCallback);
sPrevAnalysisPurgeCallback = js::SetAnalysisPurgeCallback(sRuntime, DOMAnalysisPurgeCallback);
// Set up the structured clone callbacks.

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

@ -125,7 +125,7 @@ public:
NonIncrementalGC
};
static void GarbageCollectNow(js::gcreason::Reason reason,
static void GarbageCollectNow(JS::gcreason::Reason reason,
IsIncremental aIncremental = NonIncrementalGC,
IsCompartment aCompartment = NonCompartmentGC,
IsShrinking aShrinking = NonShrinkingGC,
@ -137,7 +137,7 @@ public:
int32_t aExtraForgetSkippableCalls = 0,
bool aForced = true);
static void PokeGC(js::gcreason::Reason aReason, int aDelay = 0);
static void PokeGC(JS::gcreason::Reason aReason, int aDelay = 0);
static void KillGCTimer();
static void PokeShrinkGCBuffers();
@ -148,7 +148,7 @@ public:
static void KillFullGCTimer();
static void KillInterSliceGCTimer();
virtual void GC(js::gcreason::Reason aReason);
virtual void GC(JS::gcreason::Reason aReason);
static uint32_t CleanupsSinceLastGC();

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

@ -8,6 +8,7 @@
#include "jsapi.h"
#include "jsfriendapi.h"
#include "js/Vector.h"
#include "js/GCAPI.h"
#include "mozilla/Util.h"
#include "nsAutoJSValHolder.h"
@ -77,8 +78,8 @@ struct ListenerData : PRCList
static void
Remove(JSContext* aCx, ListenerData* aListenerData)
{
if (js::IsIncrementalBarrierNeeded(aCx)) {
js:: IncrementalReferenceBarrier(aListenerData->mListener);
if (JS::IsIncrementalBarrierNeeded(aCx)) {
JS:: IncrementalReferenceBarrier(aListenerData->mListener);
}
PR_REMOVE_LINK(aListenerData);

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

@ -8,6 +8,8 @@
#include "jslock.h"
#include "jsd_xpc.h"
#include "js/GCAPI.h"
#include "nsIXPConnect.h"
#include "mozilla/ModuleUtils.h"
#include "nsIServiceManager.h"
@ -77,7 +79,7 @@
#define JSD_STARTUP_ENTRY "JSDebugger Startup Observer"
static void
jsds_GCSliceCallbackProc (JSRuntime *rt, js::GCProgress progress, const js::GCDescription &desc);
jsds_GCSliceCallbackProc (JSRuntime *rt, JS::GCProgress progress, const JS::GCDescription &desc);
/*******************************************************************************
* global vars
@ -98,7 +100,7 @@ uint32_t gFrameCount = 0;
#endif
static jsdService *gJsds = 0;
static js::GCSliceCallback gPrevGCSliceCallback = jsds_GCSliceCallbackProc;
static JS::GCSliceCallback gPrevGCSliceCallback = jsds_GCSliceCallbackProc;
static bool gGCRunning = false;
static struct DeadScript {
@ -478,9 +480,9 @@ jsds_NotifyPendingDeadScripts (JSRuntime *rt)
}
static void
jsds_GCSliceCallbackProc (JSRuntime *rt, js::GCProgress progress, const js::GCDescription &desc)
jsds_GCSliceCallbackProc (JSRuntime *rt, JS::GCProgress progress, const JS::GCDescription &desc)
{
if (progress == js::GC_CYCLE_END || progress == js::GC_SLICE_END) {
if (progress == JS::GC_CYCLE_END || progress == JS::GC_SLICE_END) {
NS_ASSERTION(gGCRunning, "GC slice callback was missed");
while (gDeadScripts)
@ -2556,7 +2558,7 @@ jsdService::ActivateDebugger (JSRuntime *rt)
if (gPrevGCSliceCallback == jsds_GCSliceCallbackProc)
/* condition indicates that the callback proc has not been set yet */
gPrevGCSliceCallback = js::SetGCSliceCallback (rt, jsds_GCSliceCallbackProc);
gPrevGCSliceCallback = JS::SetGCSliceCallback (rt, jsds_GCSliceCallbackProc);
mCx = JSD_DebuggerOnForUser (rt, NULL, NULL);
if (!mCx)

244
js/public/GCAPI.h Normal file
Просмотреть файл

@ -0,0 +1,244 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef js_gc_api_h___
#define js_gc_api_h___
#include "HeapAPI.h"
namespace JS {
#define GCREASONS(D) \
/* Reasons internal to the JS engine */ \
D(API) \
D(MAYBEGC) \
D(LAST_CONTEXT) \
D(DESTROY_CONTEXT) \
D(LAST_DITCH) \
D(TOO_MUCH_MALLOC) \
D(ALLOC_TRIGGER) \
D(DEBUG_GC) \
D(DEBUG_MODE_GC) \
D(TRANSPLANT) \
D(RESET) \
\
/* Reasons from Firefox */ \
D(DOM_WINDOW_UTILS) \
D(COMPONENT_UTILS) \
D(MEM_PRESSURE) \
D(CC_WAITING) \
D(CC_FORCED) \
D(LOAD_END) \
D(POST_COMPARTMENT) \
D(PAGE_HIDE) \
D(NSJSCONTEXT_DESTROY) \
D(SET_NEW_DOCUMENT) \
D(SET_DOC_SHELL) \
D(DOM_UTILS) \
D(DOM_IPC) \
D(DOM_WORKER) \
D(INTER_SLICE_GC) \
D(REFRESH_FRAME) \
D(FULL_GC_TIMER) \
D(SHUTDOWN_CC)
namespace gcreason {
/* GCReasons will end up looking like JSGC_MAYBEGC */
enum Reason {
#define MAKE_REASON(name) name,
GCREASONS(MAKE_REASON)
#undef MAKE_REASON
NO_REASON,
NUM_REASONS,
/*
* For telemetry, we want to keep a fixed max bucket size over time so we
* don't have to switch histograms. 100 is conservative; as of this writing
* there are 26. But the cost of extra buckets seems to be low while the
* cost of switching histograms is high.
*/
NUM_TELEMETRY_REASONS = 100
};
} /* namespace gcreason */
extern JS_FRIEND_API(void)
PrepareCompartmentForGC(JSCompartment *comp);
extern JS_FRIEND_API(void)
PrepareForFullGC(JSRuntime *rt);
extern JS_FRIEND_API(void)
PrepareForIncrementalGC(JSRuntime *rt);
extern JS_FRIEND_API(bool)
IsGCScheduled(JSRuntime *rt);
extern JS_FRIEND_API(void)
SkipCompartmentForGC(JSCompartment *comp);
/*
* When triggering a GC using one of the functions below, it is first necessary
* to select the compartments to be collected. To do this, you can call
* PrepareCompartmentForGC on each compartment, or you can call PrepareForFullGC
* to select all compartments. Failing to select any compartment is an error.
*/
extern JS_FRIEND_API(void)
GCForReason(JSRuntime *rt, gcreason::Reason reason);
extern JS_FRIEND_API(void)
ShrinkingGC(JSRuntime *rt, gcreason::Reason reason);
extern JS_FRIEND_API(void)
ShrinkGCBuffers(JSRuntime *rt);
extern JS_FRIEND_API(void)
IncrementalGC(JSRuntime *rt, gcreason::Reason reason, int64_t millis = 0);
extern JS_FRIEND_API(void)
FinishIncrementalGC(JSRuntime *rt, gcreason::Reason reason);
enum GCProgress {
/*
* During non-incremental GC, the GC is bracketed by JSGC_CYCLE_BEGIN/END
* callbacks. During an incremental GC, the sequence of callbacks is as
* follows:
* JSGC_CYCLE_BEGIN, JSGC_SLICE_END (first slice)
* JSGC_SLICE_BEGIN, JSGC_SLICE_END (second slice)
* ...
* JSGC_SLICE_BEGIN, JSGC_CYCLE_END (last slice)
*/
GC_CYCLE_BEGIN,
GC_SLICE_BEGIN,
GC_SLICE_END,
GC_CYCLE_END
};
struct JS_FRIEND_API(GCDescription) {
bool isCompartment;
GCDescription(bool isCompartment)
: isCompartment(isCompartment) {}
jschar *formatMessage(JSRuntime *rt) const;
jschar *formatJSON(JSRuntime *rt, uint64_t timestamp) const;
};
typedef void
(* GCSliceCallback)(JSRuntime *rt, GCProgress progress, const GCDescription &desc);
extern JS_FRIEND_API(GCSliceCallback)
SetGCSliceCallback(JSRuntime *rt, GCSliceCallback callback);
/*
* Signals a good place to do an incremental slice, because the browser is
* drawing a frame.
*/
extern JS_FRIEND_API(void)
NotifyDidPaint(JSRuntime *rt);
extern JS_FRIEND_API(bool)
IsIncrementalGCEnabled(JSRuntime *rt);
JS_FRIEND_API(bool)
IsIncrementalGCInProgress(JSRuntime *rt);
extern JS_FRIEND_API(void)
DisableIncrementalGC(JSRuntime *rt);
extern JS_FRIEND_API(bool)
IsIncrementalBarrierNeeded(JSRuntime *rt);
extern JS_FRIEND_API(bool)
IsIncrementalBarrierNeeded(JSContext *cx);
extern JS_FRIEND_API(void)
IncrementalReferenceBarrier(void *ptr);
extern JS_FRIEND_API(void)
IncrementalValueBarrier(const Value &v);
extern JS_FRIEND_API(void)
PokeGC(JSRuntime *rt);
/* Was the most recent GC run incrementally? */
extern JS_FRIEND_API(bool)
WasIncrementalGC(JSRuntime *rt);
class ObjectPtr
{
JSObject *value;
public:
ObjectPtr() : value(NULL) {}
ObjectPtr(JSObject *obj) : value(obj) {}
/* Always call finalize before the destructor. */
~ObjectPtr() { JS_ASSERT(!value); }
void finalize(JSRuntime *rt) {
if (IsIncrementalBarrierNeeded(rt))
IncrementalReferenceBarrier(value);
value = NULL;
}
void init(JSObject *obj) { value = obj; }
JSObject *get() const { return value; }
void writeBarrierPre(JSRuntime *rt) {
IncrementalReferenceBarrier(value);
}
ObjectPtr &operator=(JSObject *obj) {
IncrementalReferenceBarrier(value);
value = obj;
return *this;
}
JSObject &operator*() const { return *value; }
JSObject *operator->() const { return value; }
operator JSObject *() const { return value; }
};
/*
* Unsets the gray bit for anything reachable from |thing|. |kind| should not be
* JSTRACE_SHAPE. |thing| should be non-null.
*/
extern JS_FRIEND_API(void)
UnmarkGrayGCThingRecursively(void *thing, JSGCTraceKind kind);
/*
* This should be called when an object that is marked gray is exposed to the JS
* engine (by handing it to running JS code or writing it into live JS
* data). During incremental GC, since the gray bits haven't been computed yet,
* we conservatively mark the object black.
*/
static JS_ALWAYS_INLINE void
ExposeGCThingToActiveJS(void *thing, JSGCTraceKind kind)
{
JS_ASSERT(kind != JSTRACE_SHAPE);
if (GCThingIsMarkedGray(thing))
UnmarkGrayGCThingRecursively(thing, kind);
else if (IsIncrementalBarrierNeededOnGCThing(thing, kind))
IncrementalReferenceBarrier(thing);
}
static JS_ALWAYS_INLINE void
ExposeValueToActiveJS(const Value &v)
{
if (v.isMarkable())
ExposeGCThingToActiveJS(v.toGCThing(), v.gcKind());
}
} /* namespace JS */
#endif /* js_gc_api_h___ */

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

@ -7,8 +7,6 @@
#ifndef js_heap_api_h___
#define js_heap_api_h___
#include "jsfriendapi.h"
/* These values are private to the JS engine. */
namespace js {
namespace gc {
@ -140,30 +138,6 @@ IsIncrementalBarrierNeededOnGCThing(void *thing, JSGCTraceKind kind)
return reinterpret_cast<shadow::Compartment *>(comp)->needsBarrier_;
}
/*
* This should be called when an object that is marked gray is exposed to the JS
* engine (by handing it to running JS code or writing it into live JS
* data). During incremental GC, since the gray bits haven't been computed yet,
* we conservatively mark the object black.
*/
static JS_ALWAYS_INLINE void
ExposeGCThingToActiveJS(void *thing, JSGCTraceKind kind)
{
JS_ASSERT(kind != JSTRACE_SHAPE);
if (GCThingIsMarkedGray(thing))
js::UnmarkGrayGCThingRecursively(thing, kind);
else if (IsIncrementalBarrierNeededOnGCThing(thing, kind))
js::IncrementalReferenceBarrier(thing);
}
static JS_ALWAYS_INLINE void
ExposeValueToActiveJS(const Value &v)
{
if (v.isMarkable())
ExposeGCThingToActiveJS(v.toGCThing(), v.gcKind());
}
} /* namespace JS */
#endif /* js_heap_api_h___ */

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

@ -228,6 +228,7 @@ EXPORTS_js = \
CharacterEncoding.h \
HashTable.h \
HeapAPI.h \
GCAPI.h \
LegacyIntTypes.h \
MemoryMetrics.h \
TemplateLib.h \

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

@ -1660,7 +1660,7 @@ UnmarkGrayChildren(JSTracer *trc, void **thingp, JSGCTraceKind kind)
}
JS_FRIEND_API(void)
js::UnmarkGrayGCThingRecursively(void *thing, JSGCTraceKind kind)
JS::UnmarkGrayGCThingRecursively(void *thing, JSGCTraceKind kind)
{
JS_ASSERT(kind != JSTRACE_SHAPE);

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

@ -17,6 +17,8 @@
#include "jspubtd.h"
#include "jsutil.h"
#include "js/GCAPI.h"
struct JSCompartment;
namespace js {

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

@ -127,20 +127,20 @@ JS_NewObjectWithUniqueType(JSContext *cx, JSClass *clasp, JSObject *protoArg, JS
}
JS_FRIEND_API(void)
js::PrepareCompartmentForGC(JSCompartment *comp)
JS::PrepareCompartmentForGC(JSCompartment *comp)
{
comp->scheduleGC();
}
JS_FRIEND_API(void)
js::PrepareForFullGC(JSRuntime *rt)
JS::PrepareForFullGC(JSRuntime *rt)
{
for (CompartmentsIter c(rt); !c.done(); c.next())
c->scheduleGC();
}
JS_FRIEND_API(void)
js::PrepareForIncrementalGC(JSRuntime *rt)
JS::PrepareForIncrementalGC(JSRuntime *rt)
{
if (!IsIncrementalGCInProgress(rt))
return;
@ -152,7 +152,7 @@ js::PrepareForIncrementalGC(JSRuntime *rt)
}
JS_FRIEND_API(bool)
js::IsGCScheduled(JSRuntime *rt)
JS::IsGCScheduled(JSRuntime *rt)
{
for (CompartmentsIter c(rt); !c.done(); c.next()) {
if (c->isGCScheduled())
@ -163,41 +163,35 @@ js::IsGCScheduled(JSRuntime *rt)
}
JS_FRIEND_API(void)
js::SkipCompartmentForGC(JSCompartment *comp)
JS::SkipCompartmentForGC(JSCompartment *comp)
{
comp->unscheduleGC();
}
JS_FRIEND_API(void)
js::GCForReason(JSRuntime *rt, gcreason::Reason reason)
JS::GCForReason(JSRuntime *rt, gcreason::Reason reason)
{
GC(rt, GC_NORMAL, reason);
}
JS_FRIEND_API(void)
js::ShrinkingGC(JSRuntime *rt, gcreason::Reason reason)
JS::ShrinkingGC(JSRuntime *rt, gcreason::Reason reason)
{
GC(rt, GC_SHRINK, reason);
}
JS_FRIEND_API(void)
js::IncrementalGC(JSRuntime *rt, gcreason::Reason reason, int64_t millis)
JS::IncrementalGC(JSRuntime *rt, gcreason::Reason reason, int64_t millis)
{
GCSlice(rt, GC_NORMAL, reason, millis);
}
JS_FRIEND_API(void)
js::FinishIncrementalGC(JSRuntime *rt, gcreason::Reason reason)
JS::FinishIncrementalGC(JSRuntime *rt, gcreason::Reason reason)
{
GCFinalSlice(rt, GC_NORMAL, reason);
}
JS_FRIEND_API(void)
JS_ShrinkGCBuffers(JSRuntime *rt)
{
ShrinkGCBuffers(rt);
}
JS_FRIEND_API(JSPrincipals *)
JS_GetCompartmentPrincipals(JSCompartment *compartment)
{
@ -786,7 +780,7 @@ js::GetRuntimeCompartments(JSRuntime *rt)
}
JS_FRIEND_API(GCSliceCallback)
js::SetGCSliceCallback(JSRuntime *rt, GCSliceCallback callback)
JS::SetGCSliceCallback(JSRuntime *rt, GCSliceCallback callback)
{
GCSliceCallback old = rt->gcSliceCallback;
rt->gcSliceCallback = callback;
@ -794,7 +788,7 @@ js::SetGCSliceCallback(JSRuntime *rt, GCSliceCallback callback)
}
JS_FRIEND_API(bool)
js::WasIncrementalGC(JSRuntime *rt)
JS::WasIncrementalGC(JSRuntime *rt)
{
return rt->gcIsIncremental;
}
@ -820,7 +814,7 @@ js::SetAnalysisPurgeCallback(JSRuntime *rt, AnalysisPurgeCallback callback)
}
JS_FRIEND_API(void)
js::NotifyDidPaint(JSRuntime *rt)
JS::NotifyDidPaint(JSRuntime *rt)
{
if (rt->gcZeal() == gc::ZealFrameVerifierPreValue) {
gc::VerifyBarriers(rt, gc::PreBarrierVerifier);
@ -847,37 +841,37 @@ js::NotifyDidPaint(JSRuntime *rt)
}
JS_FRIEND_API(bool)
js::IsIncrementalGCEnabled(JSRuntime *rt)
JS::IsIncrementalGCEnabled(JSRuntime *rt)
{
return rt->gcIncrementalEnabled && rt->gcMode == JSGC_MODE_INCREMENTAL;
}
JS_FRIEND_API(bool)
js::IsIncrementalGCInProgress(JSRuntime *rt)
JS::IsIncrementalGCInProgress(JSRuntime *rt)
{
return (rt->gcIncrementalState != gc::NO_INCREMENTAL && !rt->gcVerifyPreData);
}
JS_FRIEND_API(void)
js::DisableIncrementalGC(JSRuntime *rt)
JS::DisableIncrementalGC(JSRuntime *rt)
{
rt->gcIncrementalEnabled = false;
}
JS_FRIEND_API(bool)
js::IsIncrementalBarrierNeeded(JSRuntime *rt)
JS::IsIncrementalBarrierNeeded(JSRuntime *rt)
{
return (rt->gcIncrementalState == gc::MARK && !rt->isHeapBusy());
}
JS_FRIEND_API(bool)
js::IsIncrementalBarrierNeeded(JSContext *cx)
JS::IsIncrementalBarrierNeeded(JSContext *cx)
{
return IsIncrementalBarrierNeeded(cx->runtime);
}
JS_FRIEND_API(void)
js::IncrementalReferenceBarrier(void *ptr)
JS::IncrementalReferenceBarrier(void *ptr)
{
if (!ptr)
return;
@ -905,13 +899,13 @@ js::IncrementalReferenceBarrier(void *ptr)
}
JS_FRIEND_API(void)
js::IncrementalValueBarrier(const Value &v)
JS::IncrementalValueBarrier(const Value &v)
{
HeapValue::writeBarrierPre(v);
}
JS_FRIEND_API(void)
js::PokeGC(JSRuntime *rt)
JS::PokeGC(JSRuntime *rt)
{
rt->gcPoke = true;
}

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

@ -50,9 +50,6 @@ JS_NewObjectWithUniqueType(JSContext *cx, JSClass *clasp, JSObject *proto, JSObj
extern JS_FRIEND_API(uint32_t)
JS_ObjectCountDynamicSlots(JSHandleObject obj);
extern JS_FRIEND_API(void)
JS_ShrinkGCBuffers(JSRuntime *rt);
extern JS_FRIEND_API(size_t)
JS_GetE4XObjectsCreated(JSContext *cx);
@ -272,13 +269,6 @@ TraceWeakMaps(WeakMapTracer *trc);
extern JS_FRIEND_API(bool)
AreGCGrayBitsValid(JSRuntime *rt);
/*
* Unsets the gray bit for anything reachable from |thing|. |kind| should not be
* JSTRACE_SHAPE. |thing| should be non-null.
*/
extern JS_FRIEND_API(void)
UnmarkGrayGCThingRecursively(void *thing, JSGCTraceKind kind);
typedef void
(*GCThingCallback)(void *closure, void *gcthing);
@ -739,138 +729,12 @@ typedef Vector<JSCompartment*, 0, SystemAllocPolicy> CompartmentVector;
extern JS_FRIEND_API(const CompartmentVector&)
GetRuntimeCompartments(JSRuntime *rt);
#define GCREASONS(D) \
/* Reasons internal to the JS engine */ \
D(API) \
D(MAYBEGC) \
D(LAST_CONTEXT) \
D(DESTROY_CONTEXT) \
D(LAST_DITCH) \
D(TOO_MUCH_MALLOC) \
D(ALLOC_TRIGGER) \
D(DEBUG_GC) \
D(DEBUG_MODE_GC) \
D(TRANSPLANT) \
D(RESET) \
\
/* Reasons from Firefox */ \
D(DOM_WINDOW_UTILS) \
D(COMPONENT_UTILS) \
D(MEM_PRESSURE) \
D(CC_WAITING) \
D(CC_FORCED) \
D(LOAD_END) \
D(POST_COMPARTMENT) \
D(PAGE_HIDE) \
D(NSJSCONTEXT_DESTROY) \
D(SET_NEW_DOCUMENT) \
D(SET_DOC_SHELL) \
D(DOM_UTILS) \
D(DOM_IPC) \
D(DOM_WORKER) \
D(INTER_SLICE_GC) \
D(REFRESH_FRAME) \
D(FULL_GC_TIMER) \
D(SHUTDOWN_CC)
namespace gcreason {
/* GCReasons will end up looking like JSGC_MAYBEGC */
enum Reason {
#define MAKE_REASON(name) name,
GCREASONS(MAKE_REASON)
#undef MAKE_REASON
NO_REASON,
NUM_REASONS,
/*
* For telemetry, we want to keep a fixed max bucket size over time so we
* don't have to switch histograms. 100 is conservative; as of this writing
* there are 26. But the cost of extra buckets seems to be low while the
* cost of switching histograms is high.
*/
NUM_TELEMETRY_REASONS = 100
};
} /* namespace gcreason */
extern JS_FRIEND_API(void)
PrepareCompartmentForGC(JSCompartment *comp);
extern JS_FRIEND_API(void)
PrepareForFullGC(JSRuntime *rt);
extern JS_FRIEND_API(void)
PrepareForIncrementalGC(JSRuntime *rt);
extern JS_FRIEND_API(bool)
IsGCScheduled(JSRuntime *rt);
extern JS_FRIEND_API(void)
SkipCompartmentForGC(JSCompartment *comp);
/*
* When triggering a GC using one of the functions below, it is first necessary
* to select the compartments to be collected. To do this, you can call
* PrepareCompartmentForGC on each compartment, or you can call PrepareForFullGC
* to select all compartments. Failing to select any compartment is an error.
*/
extern JS_FRIEND_API(void)
GCForReason(JSRuntime *rt, gcreason::Reason reason);
extern JS_FRIEND_API(void)
ShrinkingGC(JSRuntime *rt, gcreason::Reason reason);
extern JS_FRIEND_API(void)
IncrementalGC(JSRuntime *rt, gcreason::Reason reason, int64_t millis = 0);
extern JS_FRIEND_API(void)
FinishIncrementalGC(JSRuntime *rt, gcreason::Reason reason);
enum GCProgress {
/*
* During non-incremental GC, the GC is bracketed by JSGC_CYCLE_BEGIN/END
* callbacks. During an incremental GC, the sequence of callbacks is as
* follows:
* JSGC_CYCLE_BEGIN, JSGC_SLICE_END (first slice)
* JSGC_SLICE_BEGIN, JSGC_SLICE_END (second slice)
* ...
* JSGC_SLICE_BEGIN, JSGC_CYCLE_END (last slice)
*/
GC_CYCLE_BEGIN,
GC_SLICE_BEGIN,
GC_SLICE_END,
GC_CYCLE_END
};
struct JS_FRIEND_API(GCDescription) {
bool isCompartment;
GCDescription(bool isCompartment)
: isCompartment(isCompartment) {}
jschar *formatMessage(JSRuntime *rt) const;
jschar *formatJSON(JSRuntime *rt, uint64_t timestamp) const;
};
typedef void
(* GCSliceCallback)(JSRuntime *rt, GCProgress progress, const GCDescription &desc);
extern JS_FRIEND_API(GCSliceCallback)
SetGCSliceCallback(JSRuntime *rt, GCSliceCallback callback);
typedef void
(* AnalysisPurgeCallback)(JSRuntime *rt, JSFlatString *desc);
extern JS_FRIEND_API(AnalysisPurgeCallback)
SetAnalysisPurgeCallback(JSRuntime *rt, AnalysisPurgeCallback callback);
/* Was the most recent GC run incrementally? */
extern JS_FRIEND_API(bool)
WasIncrementalGC(JSRuntime *rt);
typedef JSBool
(* DOMInstanceClassMatchesProto)(JSHandleObject protoObject, uint32_t protoID,
uint32_t depth);
@ -885,74 +749,6 @@ SetDOMCallbacks(JSRuntime *rt, const DOMCallbacks *callbacks);
extern JS_FRIEND_API(const DOMCallbacks *)
GetDOMCallbacks(JSRuntime *rt);
/*
* Signals a good place to do an incremental slice, because the browser is
* drawing a frame.
*/
extern JS_FRIEND_API(void)
NotifyDidPaint(JSRuntime *rt);
extern JS_FRIEND_API(bool)
IsIncrementalGCEnabled(JSRuntime *rt);
JS_FRIEND_API(bool)
IsIncrementalGCInProgress(JSRuntime *rt);
extern JS_FRIEND_API(void)
DisableIncrementalGC(JSRuntime *rt);
extern JS_FRIEND_API(bool)
IsIncrementalBarrierNeeded(JSRuntime *rt);
extern JS_FRIEND_API(bool)
IsIncrementalBarrierNeeded(JSContext *cx);
extern JS_FRIEND_API(void)
IncrementalReferenceBarrier(void *ptr);
extern JS_FRIEND_API(void)
IncrementalValueBarrier(const Value &v);
extern JS_FRIEND_API(void)
PokeGC(JSRuntime *rt);
class ObjectPtr
{
JSObject *value;
public:
ObjectPtr() : value(NULL) {}
ObjectPtr(JSObject *obj) : value(obj) {}
/* Always call finalize before the destructor. */
~ObjectPtr() { JS_ASSERT(!value); }
void finalize(JSRuntime *rt) {
if (IsIncrementalBarrierNeeded(rt))
IncrementalReferenceBarrier(value);
value = NULL;
}
void init(JSObject *obj) { value = obj; }
JSObject *get() const { return value; }
void writeBarrierPre(JSRuntime *rt) {
IncrementalReferenceBarrier(value);
}
ObjectPtr &operator=(JSObject *obj) {
IncrementalReferenceBarrier(value);
value = obj;
return *this;
}
JSObject &operator*() const { return *value; }
JSObject *operator->() const { return value; }
operator JSObject *() const { return value; }
};
extern JS_FRIEND_API(JSObject *)
GetTestingFunctions(JSContext *cx);

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

@ -4513,8 +4513,8 @@ js::PrepareForDebugGC(JSRuntime *rt)
PrepareForFullGC(rt);
}
void
js::ShrinkGCBuffers(JSRuntime *rt)
JS_FRIEND_API(void)
JS::ShrinkGCBuffers(JSRuntime *rt)
{
AutoLockGC lock(rt);
JS_ASSERT(!rt->isHeapBusy());

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

@ -544,9 +544,6 @@ TriggerCompartmentGC(JSCompartment *comp, js::gcreason::Reason reason);
extern void
MaybeGC(JSContext *cx);
extern void
ShrinkGCBuffers(JSRuntime *rt);
extern void
ReleaseAllJITCode(FreeOp *op);

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

@ -513,7 +513,7 @@ private:
if (delegateMightNeedMarking && kkind == JSTRACE_OBJECT) {
JSObject *kdelegate = js::GetWeakmapKeyDelegate((JSObject *)k);
if (kdelegate && !xpc_IsGrayGCThing(kdelegate)) {
js::UnmarkGrayGCThingRecursively(k, JSTRACE_OBJECT);
JS::UnmarkGrayGCThingRecursively(k, JSTRACE_OBJECT);
tracer->mAnyMarked = true;
}
}
@ -523,7 +523,7 @@ private:
(!m || !xpc_IsGrayGCThing(m)) &&
vkind != JSTRACE_SHAPE)
{
js::UnmarkGrayGCThingRecursively(v, vkind);
JS::UnmarkGrayGCThingRecursively(v, vkind);
tracer->mAnyMarked = true;
}

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

@ -15,6 +15,7 @@
#include "jspubtd.h"
#include "jsproxy.h"
#include "js/HeapAPI.h"
#include "js/GCAPI.h"
#include "nsISupports.h"
#include "nsIPrincipal.h"

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

@ -84,7 +84,7 @@
},
"GC_REASON_2": {
"kind": "enumerated",
"n_values": "js::gcreason::NUM_TELEMETRY_REASONS",
"n_values": "JS::gcreason::NUM_TELEMETRY_REASONS",
"description": "Reason (enum value) for initiating a GC"
},
"GC_IS_COMPARTMENTAL": {

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

@ -27,6 +27,7 @@
#include "mozilla/Services.h"
#include "jsapi.h"
#include "jsfriendapi.h"
#include "js/GCAPI.h"
#include "nsStringGlue.h"
#include "nsITelemetry.h"
#include "nsIFile.h"

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

@ -2820,7 +2820,7 @@ nsCycleCollector::FixGrayBits(bool aForceGC)
// mJSRuntime->Collect() must be called from the main thread,
// because it invokes XPCJSRuntime::GCCallback(cx, JSGC_BEGIN)
// which returns false if not in the main thread.
mJSRuntime->Collect(aForceGC ? js::gcreason::SHUTDOWN_CC : js::gcreason::CC_FORCED);
mJSRuntime->Collect(aForceGC ? JS::gcreason::SHUTDOWN_CC : JS::gcreason::CC_FORCED);
timeLog.Checkpoint("GC()");
}