зеркало из https://github.com/mozilla/pjs.git
Bug 661903 - Move script filename table to compartment (r=igor)
This commit is contained in:
Родитель
36aa990a80
Коммит
5f330a0e50
|
@ -660,7 +660,7 @@ check-malloc-function-usage: $(filter-out %jsalloc.h %jscntxt.h %jsutil.h, $(ALL
|
|||
|
||||
# We desire these numbers to go down, not up. See "User guide to memory
|
||||
# management within SpiderMonkey" in jsutil.h.
|
||||
$(srcdir)/config/check_source_count.py OffTheBooks:: 54 \
|
||||
$(srcdir)/config/check_source_count.py OffTheBooks:: 52 \
|
||||
"in Makefile.in" "{cx,rt}->{new_,new_array,malloc_,calloc_,realloc_}" $^
|
||||
# This should go to zero, if possible.
|
||||
$(srcdir)/config/check_source_count.py UnwantedForeground:: 33 \
|
||||
|
|
|
@ -695,8 +695,6 @@ JSRuntime::init(uint32 maxbytes)
|
|||
return false;
|
||||
if (!InitRuntimeNumberState(this))
|
||||
return false;
|
||||
if (!InitRuntimeScriptState(this))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -724,7 +722,6 @@ JSRuntime::~JSRuntime()
|
|||
FinishJIT();
|
||||
#endif
|
||||
|
||||
FreeRuntimeScriptState(this);
|
||||
FinishRuntimeNumberState(this);
|
||||
js_FinishThreads(this);
|
||||
js_FinishAtomState(this);
|
||||
|
|
|
@ -131,6 +131,9 @@ JSCompartment::init()
|
|||
if (!crossCompartmentWrappers.init())
|
||||
return false;
|
||||
|
||||
if (!scriptFilenameTable.init())
|
||||
return false;
|
||||
|
||||
regExpAllocator = rt->new_<WTF::BumpPointerAllocator>();
|
||||
if (!regExpAllocator)
|
||||
return false;
|
||||
|
|
|
@ -363,6 +363,25 @@ class DtoaCache {
|
|||
|
||||
};
|
||||
|
||||
struct ScriptFilenameEntry
|
||||
{
|
||||
bool marked;
|
||||
char filename[1];
|
||||
};
|
||||
|
||||
struct ScriptFilenameHasher
|
||||
{
|
||||
typedef const char *Lookup;
|
||||
static HashNumber hash(const char *l) { return JS_HashString(l); }
|
||||
static bool match(const ScriptFilenameEntry *e, const char *l) {
|
||||
return strcmp(e->filename, l) == 0;
|
||||
}
|
||||
};
|
||||
|
||||
typedef HashSet<ScriptFilenameEntry *,
|
||||
ScriptFilenameHasher,
|
||||
SystemAllocPolicy> ScriptFilenameTable;
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
struct JS_FRIEND_API(JSCompartment) {
|
||||
|
@ -473,6 +492,8 @@ struct JS_FRIEND_API(JSCompartment) {
|
|||
typedef js::Maybe<js::ToSourceCache> LazyToSourceCache;
|
||||
LazyToSourceCache toSourceCache;
|
||||
|
||||
js::ScriptFilenameTable scriptFilenameTable;
|
||||
|
||||
JSCompartment(JSRuntime *rt);
|
||||
~JSCompartment();
|
||||
|
||||
|
|
|
@ -1820,6 +1820,17 @@ MarkContext(JSTracer *trc, JSContext *acx)
|
|||
MarkValue(trc, acx->iterValue, "iterValue");
|
||||
}
|
||||
|
||||
#define PER_COMPARTMENT_OP(rt, op) \
|
||||
if ((rt)->gcCurrentCompartment) { \
|
||||
JSCompartment *c = (rt)->gcCurrentCompartment; \
|
||||
op; \
|
||||
} else { \
|
||||
for (JSCompartment **i = rt->compartments.begin(); i != rt->compartments.end(); ++i) { \
|
||||
JSCompartment *c = *i; \
|
||||
op; \
|
||||
} \
|
||||
}
|
||||
|
||||
JS_REQUIRES_STACK void
|
||||
MarkRuntime(JSTracer *trc)
|
||||
{
|
||||
|
@ -1842,9 +1853,7 @@ MarkRuntime(JSTracer *trc)
|
|||
MarkContext(trc, acx);
|
||||
|
||||
#ifdef JS_TRACER
|
||||
for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c)
|
||||
if ((*c)->hasTraceMonitor())
|
||||
(*c)->traceMonitor()->mark(trc);
|
||||
PER_COMPARTMENT_OP(rt, if (c->hasTraceMonitor()) c->traceMonitor()->mark(trc));
|
||||
#endif
|
||||
|
||||
for (ThreadDataIter i(rt); !i.empty(); i.popFront())
|
||||
|
@ -2250,12 +2259,7 @@ MarkAndSweep(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind GCTIM
|
|||
rt->protoHazardShape = 0;
|
||||
}
|
||||
|
||||
if (rt->gcCurrentCompartment) {
|
||||
rt->gcCurrentCompartment->purge(cx);
|
||||
} else {
|
||||
for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c)
|
||||
(*c)->purge(cx);
|
||||
}
|
||||
PER_COMPARTMENT_OP(rt, c->purge(cx));
|
||||
|
||||
js_PurgeThreads(cx);
|
||||
{
|
||||
|
@ -2284,8 +2288,6 @@ MarkAndSweep(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind GCTIM
|
|||
if (comp) {
|
||||
for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c)
|
||||
(*c)->markCrossCompartmentWrappers(&gcmarker);
|
||||
} else {
|
||||
js_MarkScriptFilenames(rt);
|
||||
}
|
||||
|
||||
MarkRuntime(&gcmarker);
|
||||
|
@ -2385,16 +2387,16 @@ MarkAndSweep(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind GCTIM
|
|||
PropertyTree::dumpShapes(cx);
|
||||
#endif
|
||||
|
||||
if (!comp) {
|
||||
SweepCompartments(cx, gckind);
|
||||
|
||||
/*
|
||||
* Sweep script filenames after sweeping functions in the generic loop
|
||||
* above. In this way when a scripted function's finalizer destroys the
|
||||
* script and calls rt->destroyScriptHook, the hook can still access the
|
||||
* script's filename. See bug 323267.
|
||||
*/
|
||||
js_SweepScriptFilenames(rt);
|
||||
PER_COMPARTMENT_OP(rt, js_SweepScriptFilenames(c));
|
||||
|
||||
if (!comp) {
|
||||
SweepCompartments(cx, gckind);
|
||||
|
||||
/* non-compartmental sweep pieces */
|
||||
Probes::GCEndSweepPhase(NULL);
|
||||
|
|
|
@ -783,112 +783,29 @@ Class js_ScriptClass = {
|
|||
/*
|
||||
* Shared script filename management.
|
||||
*/
|
||||
static int
|
||||
js_compare_strings(const void *k1, const void *k2)
|
||||
{
|
||||
return strcmp((const char *) k1, (const char *) k2) == 0;
|
||||
}
|
||||
|
||||
/* NB: This struct overlays JSHashEntry -- see jshash.h, do not reorganize. */
|
||||
typedef struct ScriptFilenameEntry {
|
||||
JSHashEntry *next; /* hash chain linkage */
|
||||
JSHashNumber keyHash; /* key hash function result */
|
||||
const void *key; /* ptr to filename, below */
|
||||
JSPackedBool mark; /* GC mark flag */
|
||||
char filename[3]; /* two or more bytes, NUL-terminated */
|
||||
} ScriptFilenameEntry;
|
||||
|
||||
static void *
|
||||
js_alloc_table_space(void *priv, size_t size)
|
||||
{
|
||||
return OffTheBooks::malloc_(size);
|
||||
}
|
||||
|
||||
static void
|
||||
js_free_table_space(void *priv, void *item, size_t size)
|
||||
{
|
||||
UnwantedForeground::free_(item);
|
||||
}
|
||||
|
||||
static JSHashEntry *
|
||||
js_alloc_sftbl_entry(void *priv, const void *key)
|
||||
{
|
||||
size_t nbytes = offsetof(ScriptFilenameEntry, filename) +
|
||||
strlen((const char *) key) + 1;
|
||||
|
||||
return (JSHashEntry *) OffTheBooks::malloc_(JS_MAX(nbytes, sizeof(JSHashEntry)));
|
||||
}
|
||||
|
||||
static void
|
||||
js_free_sftbl_entry(void *priv, JSHashEntry *he, uintN flag)
|
||||
{
|
||||
if (flag != HT_FREE_ENTRY)
|
||||
return;
|
||||
UnwantedForeground::free_(he);
|
||||
}
|
||||
|
||||
static JSHashAllocOps sftbl_alloc_ops = {
|
||||
js_alloc_table_space, js_free_table_space,
|
||||
js_alloc_sftbl_entry, js_free_sftbl_entry
|
||||
};
|
||||
|
||||
namespace js {
|
||||
|
||||
bool
|
||||
InitRuntimeScriptState(JSRuntime *rt)
|
||||
{
|
||||
#ifdef JS_THREADSAFE
|
||||
JS_ASSERT(!rt->scriptFilenameTableLock);
|
||||
rt->scriptFilenameTableLock = JS_NEW_LOCK();
|
||||
if (!rt->scriptFilenameTableLock)
|
||||
return false;
|
||||
#endif
|
||||
JS_ASSERT(!rt->scriptFilenameTable);
|
||||
rt->scriptFilenameTable =
|
||||
JS_NewHashTable(16, JS_HashString, js_compare_strings, NULL,
|
||||
&sftbl_alloc_ops, NULL);
|
||||
if (!rt->scriptFilenameTable)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
FreeRuntimeScriptState(JSRuntime *rt)
|
||||
{
|
||||
if (rt->scriptFilenameTable)
|
||||
JS_HashTableDestroy(rt->scriptFilenameTable);
|
||||
#ifdef JS_THREADSAFE
|
||||
if (rt->scriptFilenameTableLock)
|
||||
JS_DESTROY_LOCK(rt->scriptFilenameTableLock);
|
||||
#endif
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
static const char *
|
||||
SaveScriptFilename(JSContext *cx, const char *filename)
|
||||
{
|
||||
JSRuntime *rt = cx->runtime;
|
||||
JS_AUTO_LOCK_GUARD(g, rt->scriptFilenameTableLock);
|
||||
JSCompartment *comp = cx->compartment;
|
||||
|
||||
JSHashTable *table = rt->scriptFilenameTable;
|
||||
JSHashNumber hash = JS_HashString(filename);
|
||||
JSHashEntry **hep = JS_HashTableRawLookup(table, hash, filename);
|
||||
ScriptFilenameTable::AddPtr p = comp->scriptFilenameTable.lookupForAdd(filename);
|
||||
if (!p) {
|
||||
size_t size = offsetof(ScriptFilenameEntry, filename) + strlen(filename) + 1;
|
||||
ScriptFilenameEntry *entry = (ScriptFilenameEntry *) cx->malloc_(size);
|
||||
if (!entry)
|
||||
return NULL;
|
||||
entry->marked = false;
|
||||
strcpy(entry->filename, filename);
|
||||
|
||||
ScriptFilenameEntry *sfe = (ScriptFilenameEntry *) *hep;
|
||||
if (!sfe) {
|
||||
sfe = (ScriptFilenameEntry *)
|
||||
JS_HashTableRawAdd(table, hep, hash, filename, NULL);
|
||||
if (!sfe) {
|
||||
if (!comp->scriptFilenameTable.add(p, entry)) {
|
||||
Foreground::free_(entry);
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return NULL;
|
||||
}
|
||||
sfe->key = strcpy(sfe->filename, filename);
|
||||
sfe->mark = JS_FALSE;
|
||||
}
|
||||
|
||||
return sfe->filename;
|
||||
return (*p)->filename;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -897,70 +814,26 @@ SaveScriptFilename(JSContext *cx, const char *filename)
|
|||
#define FILENAME_TO_SFE(fn) \
|
||||
((ScriptFilenameEntry *) ((fn) - offsetof(ScriptFilenameEntry, filename)))
|
||||
|
||||
/*
|
||||
* The sfe->key member, redundant given sfe->filename but required by the old
|
||||
* jshash.c code, here gives us a useful sanity check. This assertion will
|
||||
* very likely botch if someone tries to mark a string that wasn't allocated
|
||||
* as an sfe->filename.
|
||||
*/
|
||||
#define ASSERT_VALID_SFE(sfe) JS_ASSERT((sfe)->key == (sfe)->filename)
|
||||
|
||||
void
|
||||
js_MarkScriptFilename(const char *filename)
|
||||
{
|
||||
ScriptFilenameEntry *sfe;
|
||||
|
||||
sfe = FILENAME_TO_SFE(filename);
|
||||
ASSERT_VALID_SFE(sfe);
|
||||
sfe->mark = JS_TRUE;
|
||||
}
|
||||
|
||||
static intN
|
||||
js_script_filename_marker(JSHashEntry *he, intN i, void *arg)
|
||||
{
|
||||
ScriptFilenameEntry *sfe = (ScriptFilenameEntry *) he;
|
||||
|
||||
sfe->mark = JS_TRUE;
|
||||
return HT_ENUMERATE_NEXT;
|
||||
ScriptFilenameEntry *sfe = FILENAME_TO_SFE(filename);
|
||||
sfe->marked = true;
|
||||
}
|
||||
|
||||
void
|
||||
js_MarkScriptFilenames(JSRuntime *rt)
|
||||
js_SweepScriptFilenames(JSCompartment *comp)
|
||||
{
|
||||
if (!rt->scriptFilenameTable)
|
||||
return;
|
||||
|
||||
if (rt->gcKeepAtoms) {
|
||||
JS_HashTableEnumerateEntries(rt->scriptFilenameTable,
|
||||
js_script_filename_marker,
|
||||
rt);
|
||||
ScriptFilenameTable &table = comp->scriptFilenameTable;
|
||||
for (ScriptFilenameTable::Enum e(table); !e.empty(); e.popFront()) {
|
||||
ScriptFilenameEntry *entry = e.front();
|
||||
if (entry->marked) {
|
||||
entry->marked = false;
|
||||
} else if (!comp->rt->gcKeepAtoms) {
|
||||
Foreground::free_(entry);
|
||||
e.removeFront();
|
||||
}
|
||||
}
|
||||
|
||||
static intN
|
||||
js_script_filename_sweeper(JSHashEntry *he, intN i, void *arg)
|
||||
{
|
||||
ScriptFilenameEntry *sfe = (ScriptFilenameEntry *) he;
|
||||
|
||||
if (!sfe->mark)
|
||||
return HT_ENUMERATE_REMOVE;
|
||||
sfe->mark = JS_FALSE;
|
||||
return HT_ENUMERATE_NEXT;
|
||||
}
|
||||
|
||||
void
|
||||
js_SweepScriptFilenames(JSRuntime *rt)
|
||||
{
|
||||
if (!rt->scriptFilenameTable)
|
||||
return;
|
||||
|
||||
/*
|
||||
* JS_HashTableEnumerateEntries shrinks the table if many entries are
|
||||
* removed preventing wasting memory on a too sparse table.
|
||||
*/
|
||||
JS_HashTableEnumerateEntries(rt->scriptFilenameTable,
|
||||
js_script_filename_sweeper,
|
||||
rt);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -695,30 +695,11 @@ extern JS_FRIEND_DATA(js::Class) js_ScriptClass;
|
|||
extern JSObject *
|
||||
js_InitScriptClass(JSContext *cx, JSObject *obj);
|
||||
|
||||
namespace js {
|
||||
|
||||
extern bool
|
||||
InitRuntimeScriptState(JSRuntime *rt);
|
||||
|
||||
/*
|
||||
* On JS_DestroyRuntime(rt), forcibly free script filename prefixes and any
|
||||
* script filename table entries that have not been GC'd.
|
||||
*
|
||||
* This allows script filename prefixes to outlive any context in rt.
|
||||
*/
|
||||
extern void
|
||||
FreeRuntimeScriptState(JSRuntime *rt);
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
extern void
|
||||
js_MarkScriptFilename(const char *filename);
|
||||
|
||||
extern void
|
||||
js_MarkScriptFilenames(JSRuntime *rt);
|
||||
|
||||
extern void
|
||||
js_SweepScriptFilenames(JSRuntime *rt);
|
||||
js_SweepScriptFilenames(JSCompartment *comp);
|
||||
|
||||
/*
|
||||
* New-script-hook calling is factored from js_NewScriptFromCG so that it
|
||||
|
|
Загрузка…
Ссылка в новой задаче