Bug 584860 - Move TraceMonitor into compartment (r=gal,a=blocker)

This commit is contained in:
Bill McCloskey 2010-12-29 17:53:58 -08:00
parent 9e534cf31c
commit 6f47af60d7
14 changed files with 298 additions and 298 deletions

View File

@ -2662,7 +2662,7 @@ JS_GetGCParameterForThread(JSContext *cx, JSGCParamKey key)
{
JS_ASSERT(key == JSGC_MAX_CODE_CACHE_BYTES);
#ifdef JS_TRACER
return JS_THREAD_DATA(cx)->traceMonitor.maxCodeCacheBytes;
return JS_THREAD_DATA(cx)->maxCodeCacheBytes;
#else
return 0;
#endif

View File

@ -494,18 +494,16 @@ JSThreadData::init()
#endif
if (!stackSpace.init())
return false;
#ifdef JS_TRACER
if (!InitJIT(&traceMonitor)) {
finish();
return false;
}
#endif
dtoaState = js_NewDtoaState();
if (!dtoaState) {
finish();
return false;
}
nativeStackBase = GetNativeStackBase();
/* Set the default size for the code cache to 16MB. */
maxCodeCacheBytes = 16 * 1024 * 1024;
return true;
}
@ -522,19 +520,11 @@ JSThreadData::allocMathCache(JSContext *cx)
void
JSThreadData::finish()
{
#ifdef DEBUG
for (size_t i = 0; i != JS_ARRAY_LENGTH(scriptsToGC); ++i)
JS_ASSERT(!scriptsToGC[i]);
#endif
if (dtoaState)
js_DestroyDtoaState(dtoaState);
js_FinishGSNCache(&gsnCache);
propertyCache.~PropertyCache();
#if defined JS_TRACER
FinishJIT(&traceMonitor);
#endif
stackSpace.finish();
delete mathCache;
}
@ -553,18 +543,6 @@ JSThreadData::purge(JSContext *cx)
/* FIXME: bug 506341. */
propertyCache.purge(cx);
#ifdef JS_TRACER
/*
* If we are about to regenerate shapes, we have to flush the JIT cache,
* which will eventually abort any current recording.
*/
if (cx->runtime->gcRegenShapes)
traceMonitor.needFlush = JS_TRUE;
#endif
/* Destroy eval'ed scripts. */
js_DestroyScriptsToGC(cx, this);
/* Purge cached native iterators. */
memset(cachedNativeIterators, 0, sizeof(cachedNativeIterators));
lastNativeIterator = NULL;
@ -736,7 +714,6 @@ js_PurgeThreads(JSContext *cx)
if (JS_CLIST_IS_EMPTY(&thread->contextList)) {
JS_ASSERT(cx->thread != thread);
js_DestroyScriptsToGC(cx, &thread->data);
DestroyThread(thread);
e.removeFront();
@ -921,7 +898,7 @@ DumpEvalCacheMeter(JSContext *cx)
EVAL_CACHE_METER_LIST(frob)
#undef frob
};
JSEvalCacheMeter *ecm = &JS_THREAD_DATA(cx)->evalCacheMeter;
JSEvalCacheMeter *ecm = &cx->compartment->evalCacheMeter;
static JSAutoFile fp;
if (!fp && !fp.open(filename, "w"))
@ -2316,6 +2293,15 @@ JSContext::updateJITEnabled()
namespace js {
JS_FORCES_STACK JS_FRIEND_API(void)
LeaveTrace(JSContext *cx)
{
#ifdef JS_TRACER
if (JS_ON_TRACE(cx))
DeepBail(cx);
#endif
}
void
SetPendingException(JSContext *cx, const Value &v)
{

View File

@ -884,147 +884,6 @@ private:
JSStackFrame *curfp;
};
/* Holds the number of recording attemps for an address. */
typedef HashMap<jsbytecode*,
size_t,
DefaultHasher<jsbytecode*>,
SystemAllocPolicy> RecordAttemptMap;
/* Holds the profile data for loops. */
typedef HashMap<jsbytecode*,
LoopProfile*,
DefaultHasher<jsbytecode*>,
SystemAllocPolicy> LoopProfileMap;
class Oracle;
typedef HashSet<JSScript *,
DefaultHasher<JSScript *>,
SystemAllocPolicy> TracedScriptSet;
/*
* Trace monitor. Every JSThread (if JS_THREADSAFE) or JSRuntime (if not
* JS_THREADSAFE) has an associated trace monitor that keeps track of loop
* frequencies for all JavaScript code loaded into that runtime.
*/
struct TraceMonitor {
/*
* The context currently executing JIT-compiled code on this thread, or
* NULL if none. Among other things, this can in certain cases prevent
* last-ditch GC and suppress calls to JS_ReportOutOfMemory.
*
* !tracecx && !recorder: not on trace
* !tracecx && recorder: recording
* tracecx && !recorder: executing a trace
* tracecx && recorder: executing inner loop, recording outer loop
*/
JSContext *tracecx;
/*
* Cached storage to use when executing on trace. While we may enter nested
* traces, we always reuse the outer trace's storage, so never need more
* than of these.
*/
TraceNativeStorage *storage;
/*
* There are 4 allocators here. This might seem like overkill, but they
* have different lifecycles, and by keeping them separate we keep the
* amount of retained memory down significantly. They are flushed (ie.
* all the allocated memory is freed) periodically.
*
* - dataAlloc has the lifecycle of the monitor. It's flushed only when
* the monitor is flushed. It's used for fragments.
*
* - traceAlloc has the same flush lifecycle as the dataAlloc, but it is
* also *marked* when a recording starts and rewinds to the mark point
* if recording aborts. So you can put things in it that are only
* reachable on a successful record/compile cycle like GuardRecords and
* SideExits.
*
* - tempAlloc is flushed after each recording, successful or not. It's
* used to store LIR code and for all other elements in the LIR
* pipeline.
*
* - codeAlloc has the same lifetime as dataAlloc, but its API is
* different (CodeAlloc vs. VMAllocator). It's used for native code.
* It's also a good idea to keep code and data separate to avoid I-cache
* vs. D-cache issues.
*/
VMAllocator* dataAlloc;
VMAllocator* traceAlloc;
VMAllocator* tempAlloc;
nanojit::CodeAlloc* codeAlloc;
nanojit::Assembler* assembler;
FrameInfoCache* frameCache;
/* This gets incremented every time the monitor is flushed. */
uintN flushEpoch;
Oracle* oracle;
TraceRecorder* recorder;
/* If we are profiling a loop, this tracks the current profile. Otherwise NULL. */
LoopProfile* profile;
GlobalState globalStates[MONITOR_N_GLOBAL_STATES];
TreeFragment* vmfragments[FRAGMENT_TABLE_SIZE];
RecordAttemptMap* recordAttempts;
/* A hashtable mapping PC values to loop profiles for those loops. */
LoopProfileMap* loopProfiles;
/*
* Maximum size of the code cache before we start flushing. 1/16 of this
* size is used as threshold for the regular expression code cache.
*/
uint32 maxCodeCacheBytes;
/*
* If nonzero, do not flush the JIT cache after a deep bail. That would
* free JITted code pages that we will later return to. Instead, set the
* needFlush flag so that it can be flushed later.
*/
JSBool needFlush;
/*
* Fragment map for the regular expression compiler.
*/
REHashMap* reFragments;
// Cached temporary typemap to avoid realloc'ing every time we create one.
// This must be used in only one place at a given time. It must be cleared
// before use.
TypeMap* cachedTempTypeMap;
/* Scripts with recorded fragments. */
TracedScriptSet tracedScripts;
#ifdef DEBUG
/* Fields needed for fragment/guard profiling. */
nanojit::Seq<nanojit::Fragment*>* branches;
uint32 lastFragID;
/*
* profAlloc has a lifetime which spans exactly from js_InitJIT to
* js_FinishJIT.
*/
VMAllocator* profAlloc;
FragStatsMap* profTab;
#endif
bool ontrace() const {
return !!tracecx;
}
/* Flush the JIT cache. */
void flush();
/* Sweep any cache entry pointing to dead GC things. */
void sweep();
bool outOfMemory() const;
};
} /* namespace js */
/*
@ -1038,23 +897,6 @@ struct TraceMonitor {
# define JS_ON_TRACE(cx) false
#endif
/* Number of potentially reusable scriptsToGC to search for the eval cache. */
#ifndef JS_EVAL_CACHE_SHIFT
# define JS_EVAL_CACHE_SHIFT 6
#endif
#define JS_EVAL_CACHE_SIZE JS_BIT(JS_EVAL_CACHE_SHIFT)
#ifdef DEBUG
# define EVAL_CACHE_METER_LIST(_) _(probe), _(hit), _(step), _(noscope)
# define identity(x) x
struct JSEvalCacheMeter {
uint64 EVAL_CACHE_METER_LIST(identity);
};
# undef identity
#endif
#ifdef DEBUG
# define FUNCTION_KIND_METER_LIST(_) \
_(allfun), _(heavy), _(nofreeupvar), _(onlyfreevar), \
@ -1118,18 +960,11 @@ struct JSThreadData {
js::PropertyCache propertyCache;
#ifdef JS_TRACER
/* Trace-tree JIT recorder/interpreter state. */
js::TraceMonitor traceMonitor;
/* Counts the number of iterations run by a trace. */
unsigned iterationCounter;
#endif
/* Lock-free hashed lists of scripts created by eval to garbage-collect. */
JSScript *scriptsToGC[JS_EVAL_CACHE_SIZE];
#ifdef DEBUG
JSEvalCacheMeter evalCacheMeter;
/* Maximum size of the tracer's code cache before we start flushing. */
uint32 maxCodeCacheBytes;
#endif
/* State used by dtoa.c. */
@ -1725,14 +1560,6 @@ struct JSRuntime {
/* Common macros to access thread-local caches in JSThread or JSRuntime. */
#define JS_GSN_CACHE(cx) (JS_THREAD_DATA(cx)->gsnCache)
#define JS_PROPERTY_CACHE(cx) (JS_THREAD_DATA(cx)->propertyCache)
#define JS_TRACE_MONITOR(cx) (JS_THREAD_DATA(cx)->traceMonitor)
#define JS_SCRIPTS_TO_GC(cx) (JS_THREAD_DATA(cx)->scriptsToGC)
#ifdef DEBUG
# define EVAL_CACHE_METER(x) (JS_THREAD_DATA(cx)->evalCacheMeter.x++)
#else
# define EVAL_CACHE_METER(x) ((void) 0)
#endif
#ifdef DEBUG
# define JS_RUNTIME_METER(rt, which) JS_ATOMIC_INCREMENT(&(rt)->which)
@ -3238,50 +3065,14 @@ js_CurrentPCIsInImacro(JSContext *cx);
namespace js {
#ifdef JS_TRACER
/*
* Reconstruct the JS stack and clear cx->tracecx. We must be currently in a
* _FAIL builtin from trace on cx or another context on the same thread. The
* machine code for the trace remains on the C stack when js_DeepBail returns.
*
* Implemented in jstracer.cpp.
*/
JS_FORCES_STACK JS_FRIEND_API(void)
DeepBail(JSContext *cx);
#endif
static JS_FORCES_STACK JS_INLINE void
LeaveTrace(JSContext *cx)
{
#ifdef JS_TRACER
if (JS_ON_TRACE(cx))
DeepBail(cx);
#endif
}
static JS_INLINE void
LeaveTraceIfGlobalObject(JSContext *cx, JSObject *obj)
{
if (!obj->parent)
LeaveTrace(cx);
}
static JS_INLINE JSBool
CanLeaveTrace(JSContext *cx)
{
JS_ASSERT(JS_ON_TRACE(cx));
#ifdef JS_TRACER
return cx->bailExit != NULL;
#else
return JS_FALSE;
#endif
}
extern void
SetPendingException(JSContext *cx, const Value &v);
class RegExpStatics;
extern JS_FORCES_STACK JS_FRIEND_API(void)
LeaveTrace(JSContext *cx);
} /* namespace js */
/*

View File

@ -42,6 +42,7 @@
#define jscntxtinlines_h___
#include "jscntxt.h"
#include "jscompartment.h"
#include "jsparse.h"
#include "jsstaticcheck.h"
#include "jsxml.h"
@ -753,6 +754,36 @@ CallSetter(JSContext *cx, JSObject *obj, jsid id, PropertyOp op, uintN attrs, ui
return CallJSPropertyOpSetter(cx, op, obj, id, vp);
}
#ifdef JS_TRACER
/*
* Reconstruct the JS stack and clear cx->tracecx. We must be currently in a
* _FAIL builtin from trace on cx or another context on the same thread. The
* machine code for the trace remains on the C stack when js_DeepBail returns.
*
* Implemented in jstracer.cpp.
*/
JS_FORCES_STACK JS_FRIEND_API(void)
DeepBail(JSContext *cx);
#endif
static JS_INLINE void
LeaveTraceIfGlobalObject(JSContext *cx, JSObject *obj)
{
if (!obj->parent)
LeaveTrace(cx);
}
static JS_INLINE JSBool
CanLeaveTrace(JSContext *cx)
{
JS_ASSERT(JS_ON_TRACE(cx));
#ifdef JS_TRACER
return cx->bailExit != NULL;
#else
return JS_FALSE;
#endif
}
} /* namespace js */
#endif /* jscntxtinlines_h___ */

View File

@ -44,6 +44,7 @@
#include "jsiter.h"
#include "jsproxy.h"
#include "jsscope.h"
#include "jstracer.h"
#include "methodjit/MethodJIT.h"
#include "methodjit/PolyIC.h"
#include "methodjit/MonoIC.h"
@ -58,13 +59,23 @@ JSCompartment::JSCompartment(JSRuntime *rt)
anynameObject(NULL), functionNamespaceObject(NULL)
{
JS_INIT_CLIST(&scripts);
memset(scriptsToGC, 0, sizeof(scriptsToGC));
}
JSCompartment::~JSCompartment()
{
#if defined JS_TRACER
FinishJIT(&traceMonitor);
#endif
#ifdef JS_METHODJIT
delete jaegerCompartment;
#endif
#ifdef DEBUG
for (size_t i = 0; i != JS_ARRAY_LENGTH(scriptsToGC); ++i)
JS_ASSERT(!scriptsToGC[i]);
#endif
}
bool
@ -81,9 +92,19 @@ JSCompartment::init()
if (!crossCompartmentWrappers.init())
return false;
#ifdef JS_METHODJIT
if (!(jaegerCompartment = new mjit::JaegerCompartment))
#ifdef JS_TRACER
if (!InitJIT(&traceMonitor)) {
return false;
}
#endif
#ifdef JS_METHODJIT
if (!(jaegerCompartment = new mjit::JaegerCompartment)) {
#ifdef JS_TRACER
FinishJIT(&traceMonitor);
#endif
return false;
}
return jaegerCompartment->Initialize();
#else
return true;
@ -357,6 +378,18 @@ JSCompartment::purge(JSContext *cx)
{
freeLists.purge();
/* Destroy eval'ed scripts. */
js_DestroyScriptsToGC(cx, this);
#ifdef JS_TRACER
/*
* If we are about to regenerate shapes, we have to flush the JIT cache,
* which will eventually abort any current recording.
*/
if (cx->runtime->gcRegenShapes)
traceMonitor.needFlush = JS_TRUE;
#endif
#ifdef JS_METHODJIT
for (JSScript *script = (JSScript *)scripts.next;
&script->links != &scripts;

View File

@ -55,11 +55,170 @@
#endif
namespace js {
/* Holds the number of recording attemps for an address. */
typedef HashMap<jsbytecode*,
size_t,
DefaultHasher<jsbytecode*>,
SystemAllocPolicy> RecordAttemptMap;
/* Holds the profile data for loops. */
typedef HashMap<jsbytecode*,
LoopProfile*,
DefaultHasher<jsbytecode*>,
SystemAllocPolicy> LoopProfileMap;
class Oracle;
typedef HashSet<JSScript *,
DefaultHasher<JSScript *>,
SystemAllocPolicy> TracedScriptSet;
/*
* Trace monitor. Every JSThread (if JS_THREADSAFE) or JSRuntime (if not
* JS_THREADSAFE) has an associated trace monitor that keeps track of loop
* frequencies for all JavaScript code loaded into that runtime.
*/
struct TraceMonitor {
/*
* The context currently executing JIT-compiled code on this thread, or
* NULL if none. Among other things, this can in certain cases prevent
* last-ditch GC and suppress calls to JS_ReportOutOfMemory.
*
* !tracecx && !recorder: not on trace
* !tracecx && recorder: recording
* tracecx && !recorder: executing a trace
* tracecx && recorder: executing inner loop, recording outer loop
*/
JSContext *tracecx;
/*
* Cached storage to use when executing on trace. While we may enter nested
* traces, we always reuse the outer trace's storage, so never need more
* than of these.
*/
TraceNativeStorage *storage;
/*
* There are 4 allocators here. This might seem like overkill, but they
* have different lifecycles, and by keeping them separate we keep the
* amount of retained memory down significantly. They are flushed (ie.
* all the allocated memory is freed) periodically.
*
* - dataAlloc has the lifecycle of the monitor. It's flushed only when
* the monitor is flushed. It's used for fragments.
*
* - traceAlloc has the same flush lifecycle as the dataAlloc, but it is
* also *marked* when a recording starts and rewinds to the mark point
* if recording aborts. So you can put things in it that are only
* reachable on a successful record/compile cycle like GuardRecords and
* SideExits.
*
* - tempAlloc is flushed after each recording, successful or not. It's
* used to store LIR code and for all other elements in the LIR
* pipeline.
*
* - codeAlloc has the same lifetime as dataAlloc, but its API is
* different (CodeAlloc vs. VMAllocator). It's used for native code.
* It's also a good idea to keep code and data separate to avoid I-cache
* vs. D-cache issues.
*/
VMAllocator* dataAlloc;
VMAllocator* traceAlloc;
VMAllocator* tempAlloc;
nanojit::CodeAlloc* codeAlloc;
nanojit::Assembler* assembler;
FrameInfoCache* frameCache;
/* This gets incremented every time the monitor is flushed. */
uintN flushEpoch;
Oracle* oracle;
TraceRecorder* recorder;
/* If we are profiling a loop, this tracks the current profile. Otherwise NULL. */
LoopProfile* profile;
GlobalState globalStates[MONITOR_N_GLOBAL_STATES];
TreeFragment* vmfragments[FRAGMENT_TABLE_SIZE];
RecordAttemptMap* recordAttempts;
/* A hashtable mapping PC values to loop profiles for those loops. */
LoopProfileMap* loopProfiles;
/*
* Maximum size of the code cache before we start flushing. 1/16 of this
* size is used as threshold for the regular expression code cache.
*/
uint32 maxCodeCacheBytes;
/*
* If nonzero, do not flush the JIT cache after a deep bail. That would
* free JITted code pages that we will later return to. Instead, set the
* needFlush flag so that it can be flushed later.
*/
JSBool needFlush;
/*
* Fragment map for the regular expression compiler.
*/
REHashMap* reFragments;
// Cached temporary typemap to avoid realloc'ing every time we create one.
// This must be used in only one place at a given time. It must be cleared
// before use.
TypeMap* cachedTempTypeMap;
/* Scripts with recorded fragments. */
TracedScriptSet tracedScripts;
#ifdef DEBUG
/* Fields needed for fragment/guard profiling. */
nanojit::Seq<nanojit::Fragment*>* branches;
uint32 lastFragID;
/*
* profAlloc has a lifetime which spans exactly from js_InitJIT to
* js_FinishJIT.
*/
VMAllocator* profAlloc;
FragStatsMap* profTab;
#endif
bool ontrace() const {
return !!tracecx;
}
/* Flush the JIT cache. */
void flush();
/* Sweep any cache entry pointing to dead GC things. */
void sweep();
bool outOfMemory() const;
};
namespace mjit {
class JaegerCompartment;
}
}
/* Number of potentially reusable scriptsToGC to search for the eval cache. */
#ifndef JS_EVAL_CACHE_SHIFT
# define JS_EVAL_CACHE_SHIFT 6
#endif
#define JS_EVAL_CACHE_SIZE JS_BIT(JS_EVAL_CACHE_SHIFT)
#ifdef DEBUG
# define EVAL_CACHE_METER_LIST(_) _(probe), _(hit), _(step), _(noscope)
# define identity(x) x
struct JSEvalCacheMeter {
uint64 EVAL_CACHE_METER_LIST(identity);
};
# undef identity
#endif
struct JS_FRIEND_API(JSCompartment) {
JSRuntime *rt;
JSPrincipals *principals;
@ -72,6 +231,18 @@ struct JS_FRIEND_API(JSCompartment) {
js::gc::JSGCArenaStats compartmentStats[js::gc::FINALIZE_LIMIT];
#endif
#ifdef JS_TRACER
/* Trace-tree JIT recorder/interpreter state. */
js::TraceMonitor traceMonitor;
#endif
/* Lock-free hashed lists of scripts created by eval to garbage-collect. */
JSScript *scriptsToGC[JS_EVAL_CACHE_SIZE];
#ifdef DEBUG
JSEvalCacheMeter evalCacheMeter;
#endif
void *data;
bool marked;
js::WrapperMap crossCompartmentWrappers;
@ -113,6 +284,15 @@ struct JS_FRIEND_API(JSCompartment) {
bool arenaListsAreEmpty();
};
#define JS_TRACE_MONITOR(cx) (cx->compartment->traceMonitor)
#define JS_SCRIPTS_TO_GC(cx) (cx->compartment->scriptsToGC)
#ifdef DEBUG
# define EVAL_CACHE_METER(x) (cx->compartment->evalCacheMeter.x++)
#else
# define EVAL_CACHE_METER(x) ((void) 0)
#endif
#ifdef _MSC_VER
#pragma warning(pop)
#endif

View File

@ -485,17 +485,6 @@ JITInhibitingHookChange(JSRuntime *rt, bool wasInhibited)
js_ContextFromLinkField(cl)->traceJitEnabled = false;
}
}
static void
LeaveTraceRT(JSRuntime *rt)
{
JSThreadData *data = js_CurrentThreadData(rt);
JSContext *cx = data ? data->traceMonitor.tracecx : NULL;
JS_UNLOCK_GC(rt);
if (cx)
LeaveTrace(cx);
}
#endif
JS_PUBLIC_API(JSBool)
@ -511,7 +500,6 @@ JS_SetInterrupt(JSRuntime *rt, JSInterruptHook hook, void *closure)
#ifdef JS_TRACER
JITInhibitingHookChange(rt, wasInhibited);
}
LeaveTraceRT(rt);
#endif
return JS_TRUE;
}
@ -1672,8 +1660,6 @@ JS_SetCallHook(JSRuntime *rt, JSInterpreterHook hook, void *closure)
#ifdef JS_TRACER
JITInhibitingHookChange(rt, wasInhibited);
}
if (hook)
LeaveTraceRT(rt);
#endif
return JS_TRUE;
}

View File

@ -2060,7 +2060,7 @@ fun_finalize(JSContext *cx, JSObject *obj)
* very early.
*/
if (FUN_INTERPRETED(fun) && fun->u.i.script)
js_DestroyScriptFromGC(cx, fun->u.i.script, NULL);
js_DestroyScriptFromGC(cx, fun->u.i.script, obj->compartment());
}
int

View File

@ -1732,16 +1732,16 @@ TriggerGC(JSRuntime *rt)
} /* namespace js */
void
js_DestroyScriptsToGC(JSContext *cx, JSThreadData *data)
js_DestroyScriptsToGC(JSContext *cx, JSCompartment *comp)
{
JSScript **listp, *script;
for (size_t i = 0; i != JS_ARRAY_LENGTH(data->scriptsToGC); ++i) {
listp = &data->scriptsToGC[i];
for (size_t i = 0; i != JS_ARRAY_LENGTH(comp->scriptsToGC); ++i) {
listp = &comp->scriptsToGC[i];
while ((script = *listp) != NULL) {
*listp = script->u.nextToGC;
script->u.nextToGC = NULL;
js_DestroyScriptFromGC(cx, script, data);
js_DestroyScriptFromGC(cx, script, comp);
}
}
}
@ -2178,8 +2178,9 @@ MarkAndSweep(JSContext *cx, JSGCInvocationKind gckind GCTIMER_PARAM)
#endif
#ifdef JS_TRACER
for (ThreadDataIter i(rt); !i.empty(); i.popFront())
i.threadData()->traceMonitor.sweep();
for (JSCompartment **comp = rt->compartments.begin(); comp != rt->compartments.end(); comp++) {
(*comp)->traceMonitor.sweep();
}
#endif
/*

View File

@ -827,7 +827,7 @@ js_WaitForGC(JSRuntime *rt);
#endif
extern void
js_DestroyScriptsToGC(JSContext *cx, JSThreadData *data);
js_DestroyScriptsToGC(JSContext *cx, JSCompartment *comp);
namespace js {

View File

@ -422,7 +422,7 @@ script_finalize(JSContext *cx, JSObject *obj)
{
JSScript *script = (JSScript *) obj->getPrivate();
if (script)
js_DestroyScriptFromGC(cx, script, NULL);
js_DestroyScriptFromGC(cx, script, obj->compartment());
}
static void
@ -1218,7 +1218,7 @@ js_CallDestroyScriptHook(JSContext *cx, JSScript *script)
}
static void
DestroyScript(JSContext *cx, JSScript *script, JSThreadData *data)
DestroyScript(JSContext *cx, JSScript *script, JSCompartment *comp)
{
#ifdef DEBUG
if (script->isEmpty())
@ -1277,16 +1277,7 @@ DestroyScript(JSContext *cx, JSScript *script, JSThreadData *data)
}
#ifdef JS_TRACER
# ifdef JS_THREADSAFE
if (data) {
PurgeScriptFragments(&data->traceMonitor, script);
} else {
for (ThreadDataIter i(cx->runtime); !i.empty(); i.popFront())
PurgeScriptFragments(&i.threadData()->traceMonitor, script);
}
# else
PurgeScriptFragments(&JS_TRACE_MONITOR(cx), script);
# endif
PurgeScriptFragments(&comp->traceMonitor, script);
#endif
#if defined(JS_METHODJIT)
@ -1301,14 +1292,14 @@ void
js_DestroyScript(JSContext *cx, JSScript *script)
{
JS_ASSERT(!cx->runtime->gcRunning);
DestroyScript(cx, script, JS_THREAD_DATA(cx));
DestroyScript(cx, script, cx->compartment);
}
void
js_DestroyScriptFromGC(JSContext *cx, JSScript *script, JSThreadData *data)
js_DestroyScriptFromGC(JSContext *cx, JSScript *script, JSCompartment *comp)
{
JS_ASSERT(cx->runtime->gcRunning);
DestroyScript(cx, script, data);
DestroyScript(cx, script, comp);
}
void

View File

@ -502,7 +502,7 @@ js_DestroyScript(JSContext *cx, JSScript *script);
* from that thread.
*/
extern void
js_DestroyScriptFromGC(JSContext *cx, JSScript *script, JSThreadData *data);
js_DestroyScriptFromGC(JSContext *cx, JSScript *script, JSCompartment *comp);
extern void
js_TraceScript(JSTracer *trc, JSScript *script);

View File

@ -60,6 +60,7 @@
#include "jsarray.h"
#include "jsbool.h"
#include "jscntxt.h"
#include "jscompartment.h"
#include "jsdate.h"
#include "jsdbgapi.h"
#include "jsemit.h"
@ -2430,7 +2431,7 @@ TraceRecorder::finishSuccessfully()
delete this;
/* Catch OOM that occurred during recording. */
if (localtm->outOfMemory() || OverfullJITCache(localtm)) {
if (localtm->outOfMemory() || OverfullJITCache(localcx, localtm)) {
ResetJIT(localcx, FR_OOM);
return ARECORD_ABORTED;
}
@ -2480,7 +2481,7 @@ TraceRecorder::finishAbort(const char* reason)
localtm->recorder = NULL;
delete this;
if (localtm->outOfMemory() || OverfullJITCache(localtm)) {
if (localtm->outOfMemory() || OverfullJITCache(localcx, localtm)) {
ResetJIT(localcx, FR_OOM);
return JIT_RESET;
}
@ -5522,7 +5523,7 @@ TraceRecorder::startRecorder(JSContext* cx, VMSideExit* anchor, VMFragment* f,
expectedInnerExit, outerScript, outerPC, outerArgc,
speculate);
if (!tm->recorder || tm->outOfMemory() || OverfullJITCache(tm)) {
if (!tm->recorder || tm->outOfMemory() || OverfullJITCache(cx, tm)) {
ResetJIT(cx, FR_OOM);
return false;
}
@ -5647,9 +5648,9 @@ RecordTree(JSContext* cx, TreeFragment* first, JSScript* outerScript, jsbytecode
AUDIT(recorderStarted);
if (tm->outOfMemory() ||
OverfullJITCache(tm) ||
OverfullJITCache(cx, tm) ||
!tm->tracedScripts.put(cx->fp()->script())) {
if (!OverfullJITCache(tm))
if (!OverfullJITCache(cx, tm))
js_ReportOutOfMemory(cx);
Backoff(cx, (jsbytecode*) f->root->ip);
ResetJIT(cx, FR_OOM);
@ -7257,7 +7258,7 @@ TraceRecorder::monitorRecording(JSOp op)
return status == ARECORD_ERROR ? ARECORD_ERROR : ARECORD_ABORTED;
}
if (outOfMemory() || OverfullJITCache(&localtm)) {
if (outOfMemory() || OverfullJITCache(cx, &localtm)) {
ResetJIT(cx, FR_OOM);
/*
@ -7526,18 +7527,21 @@ disable_debugger_exceptions() { }
void
SetMaxCodeCacheBytes(JSContext* cx, uint32 bytes)
{
TraceMonitor* tm = &JS_THREAD_DATA(cx)->traceMonitor;
TraceMonitor* tm = &JS_TRACE_MONITOR(cx);
JS_ASSERT(tm->codeAlloc && tm->dataAlloc && tm->traceAlloc);
if (bytes > 1 G)
bytes = 1 G;
if (bytes < 128 K)
bytes = 128 K;
tm->maxCodeCacheBytes = bytes;
JS_THREAD_DATA(cx)->maxCodeCacheBytes = bytes;
}
bool
InitJIT(TraceMonitor *tm)
{
// InitJIT expects this area to be zero'd
memset(tm, 0, sizeof(*tm));
#if defined JS_JIT_SPEW
tm->profAlloc = NULL;
/* Set up debug logging. */
@ -7581,9 +7585,6 @@ InitJIT(TraceMonitor *tm)
did_we_check_processor_features = true;
}
/* Set the default size for the code cache to 16MB. */
tm->maxCodeCacheBytes = 16 M;
tm->oracle = new Oracle();
tm->profile = NULL;
@ -7598,7 +7599,6 @@ InitJIT(TraceMonitor *tm)
tm->flushEpoch = 0;
JS_ASSERT(!tm->dataAlloc && !tm->traceAlloc && !tm->codeAlloc);
tm->dataAlloc = new VMAllocator();
tm->traceAlloc = new VMAllocator();
tm->tempAlloc = new VMAllocator();
@ -7793,7 +7793,7 @@ PurgeScriptFragments(TraceMonitor* tm, JSScript* script)
}
bool
OverfullJITCache(TraceMonitor* tm)
OverfullJITCache(JSContext *cx, TraceMonitor* tm)
{
/*
* You might imagine the outOfMemory flag on the allocator is sufficient
@ -7829,7 +7829,7 @@ OverfullJITCache(TraceMonitor* tm)
* handled by the (few) callers of this function.
*
*/
jsuint maxsz = tm->maxCodeCacheBytes;
jsuint maxsz = JS_THREAD_DATA(cx)->maxCodeCacheBytes;
VMAllocator *dataAlloc = tm->dataAlloc;
VMAllocator *traceAlloc = tm->traceAlloc;
CodeAlloc *codeAlloc = tm->codeAlloc;

View File

@ -52,6 +52,7 @@
#include "jslock.h"
#include "jsnum.h"
#include "jsvector.h"
#include "jscompartment.h"
#include "Writer.h"
namespace js {
@ -1675,7 +1676,7 @@ extern void
PurgeScriptFragments(TraceMonitor* tm, JSScript* script);
extern bool
OverfullJITCache(TraceMonitor* tm);
OverfullJITCache(JSContext *cx, TraceMonitor* tm);
extern void
FlushJITCache(JSContext* cx);