mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-11 20:35:50 +00:00
bug 674251 - making JSScript a GC-thing. r=jorendorff
--HG-- extra : rebase_source : 8cec41c8afb99951e469eb3a97c0d48cb5da0b4f
This commit is contained in:
parent
c483d7d865
commit
3b1ac8c317
@ -20,4 +20,5 @@ plot 'gcTimer.dat' using 2 title columnheader(2), \
|
||||
'' u 7 title columnheader(7) with points, \
|
||||
'' u 8 title columnheader(8) with points, \
|
||||
'' u 9 title columnheader(9) with points, \
|
||||
'' u 10 title columnheader(10) with points
|
||||
'' u 10 title columnheader(10) with points, \
|
||||
'' u 11 title columnheader(11) with points
|
||||
|
@ -1238,7 +1238,7 @@ JS_EnterCrossCompartmentCallScript(JSContext *cx, JSScript *target)
|
||||
|
||||
JSObject *scriptObject = target->u.object;
|
||||
if (!scriptObject) {
|
||||
SwitchToCompartment sc(cx, target->compartment);
|
||||
SwitchToCompartment sc(cx, target->compartment());
|
||||
scriptObject = JS_NewGlobalObject(cx, &js_dummy_class);
|
||||
if (!scriptObject)
|
||||
return NULL;
|
||||
@ -1288,7 +1288,7 @@ bool
|
||||
AutoEnterScriptCompartment::enter(JSContext *cx, JSScript *target)
|
||||
{
|
||||
JS_ASSERT(!call);
|
||||
if (cx->compartment == target->compartment) {
|
||||
if (cx->compartment == target->compartment()) {
|
||||
call = reinterpret_cast<JSCrossCompartmentCall*>(1);
|
||||
return true;
|
||||
}
|
||||
@ -3226,7 +3226,6 @@ LookupResult(JSContext *cx, JSObject *obj, JSObject *obj2, jsid id,
|
||||
Shape *shape = (Shape *) prop;
|
||||
|
||||
if (shape->isMethod()) {
|
||||
AutoShapeRooter root(cx, shape);
|
||||
vp->setObject(shape->methodObject());
|
||||
return !!obj2->methodReadBarrier(cx, *shape, vp);
|
||||
}
|
||||
@ -4757,9 +4756,7 @@ CompileUCFunctionForPrincipalsCommon(JSContext *cx, JSObject *obj,
|
||||
fun = NULL;
|
||||
goto out2;
|
||||
}
|
||||
AutoShapeRooter shapeRoot(cx, emptyCallShape);
|
||||
|
||||
AutoObjectRooter tvr(cx, FUN_OBJECT(fun));
|
||||
MUST_FLOW_THROUGH("out");
|
||||
|
||||
Bindings bindings(cx, emptyCallShape);
|
||||
@ -4868,8 +4865,8 @@ JS_DecompileScript(JSContext *cx, JSScript *script, const char *name, uintN inde
|
||||
|
||||
CHECK_REQUEST(cx);
|
||||
#ifdef DEBUG
|
||||
if (cx->compartment != script->compartment)
|
||||
CompartmentChecker::fail(cx->compartment, script->compartment);
|
||||
if (cx->compartment != script->compartment())
|
||||
CompartmentChecker::fail(cx->compartment, script->compartment());
|
||||
#endif
|
||||
jp = js_NewPrinter(cx, name, NULL,
|
||||
indent & ~JS_DONT_PRETTY_PRINT,
|
||||
@ -4958,8 +4955,8 @@ EvaluateUCScriptForPrincipalsCommon(JSContext *cx, JSObject *obj,
|
||||
JS_ASSERT(script->getVersion() == compileVersion);
|
||||
|
||||
bool ok = ExternalExecute(cx, script, *obj, Valueify(rval));
|
||||
js_CallDestroyScriptHook(cx, script);
|
||||
LAST_FRAME_CHECKS(cx, ok);
|
||||
js_DestroyScript(cx, script, 5);
|
||||
return ok;
|
||||
|
||||
}
|
||||
|
@ -1618,6 +1618,7 @@ JS_SetExtraGCRoots(JSRuntime *rt, JSTraceDataOp traceOp, void *data);
|
||||
#define JSTRACE_OBJECT 0
|
||||
#define JSTRACE_STRING 1
|
||||
#define JSTRACE_SHAPE 2
|
||||
#define JSTRACE_SCRIPT 3
|
||||
|
||||
/*
|
||||
* Use the following macros to check if a particular jsval is a traceable
|
||||
|
@ -1467,9 +1467,9 @@ class AutoGCRooter {
|
||||
|
||||
enum {
|
||||
JSVAL = -1, /* js::AutoValueRooter */
|
||||
SHAPE = -2, /* js::AutoShapeRooter */
|
||||
BINDINGS = -2, /* js::Bindings */
|
||||
PARSER = -3, /* js::Parser */
|
||||
SCRIPT = -4, /* js::AutoScriptRooter */
|
||||
SHAPEVECTOR = -4, /* js::AutoShapeVector */
|
||||
ENUMERATOR = -5, /* js::AutoEnumStateRooter */
|
||||
IDARRAY = -6, /* js::AutoIdArray */
|
||||
DESCRIPTORS = -7, /* js::AutoPropDescArrayRooter */
|
||||
@ -1480,9 +1480,7 @@ class AutoGCRooter {
|
||||
VALVECTOR = -12, /* js::AutoValueVector */
|
||||
DESCRIPTOR = -13, /* js::AutoPropertyDescriptorRooter */
|
||||
STRING = -14, /* js::AutoStringRooter */
|
||||
IDVECTOR = -15, /* js::AutoIdVector */
|
||||
BINDINGS = -16, /* js::Bindings */
|
||||
SHAPEVECTOR = -17 /* js::AutoShapeVector */
|
||||
IDVECTOR = -15 /* js::AutoIdVector */
|
||||
};
|
||||
|
||||
private:
|
||||
@ -1653,43 +1651,6 @@ class AutoArrayRooter : private AutoGCRooter {
|
||||
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
class AutoShapeRooter : private AutoGCRooter {
|
||||
public:
|
||||
AutoShapeRooter(JSContext *cx, const js::Shape *shape
|
||||
JS_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: AutoGCRooter(cx, SHAPE), shape(shape)
|
||||
{
|
||||
JS_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
}
|
||||
|
||||
friend void AutoGCRooter::trace(JSTracer *trc);
|
||||
friend void MarkRuntime(JSTracer *trc);
|
||||
|
||||
private:
|
||||
const js::Shape * const shape;
|
||||
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
class AutoScriptRooter : private AutoGCRooter {
|
||||
public:
|
||||
AutoScriptRooter(JSContext *cx, JSScript *script
|
||||
JS_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: AutoGCRooter(cx, SCRIPT), script(script)
|
||||
{
|
||||
JS_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
}
|
||||
|
||||
void setScript(JSScript *script) {
|
||||
this->script = script;
|
||||
}
|
||||
|
||||
friend void AutoGCRooter::trace(JSTracer *trc);
|
||||
|
||||
private:
|
||||
JSScript *script;
|
||||
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
class AutoIdRooter : private AutoGCRooter
|
||||
{
|
||||
public:
|
||||
|
@ -191,7 +191,7 @@ class CompartmentChecker
|
||||
|
||||
void check(JSScript *script) {
|
||||
if (script) {
|
||||
check(script->compartment);
|
||||
check(script->compartment());
|
||||
if (script->u.object)
|
||||
check(script->u.object);
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ JSCompartment::JSCompartment(JSRuntime *rt)
|
||||
{
|
||||
JS_INIT_CLIST(&scripts);
|
||||
|
||||
PodArrayZero(scriptsToGC);
|
||||
PodArrayZero(evalCache);
|
||||
}
|
||||
|
||||
JSCompartment::~JSCompartment()
|
||||
@ -122,8 +122,8 @@ JSCompartment::~JSCompartment()
|
||||
Foreground::delete_(watchpointMap);
|
||||
|
||||
#ifdef DEBUG
|
||||
for (size_t i = 0; i != JS_ARRAY_LENGTH(scriptsToGC); ++i)
|
||||
JS_ASSERT(!scriptsToGC[i]);
|
||||
for (size_t i = 0; i != JS_ARRAY_LENGTH(evalCache); ++i)
|
||||
JS_ASSERT(!evalCache[i]);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -549,8 +549,20 @@ JSCompartment::purge(JSContext *cx)
|
||||
freeLists.purge();
|
||||
dtoaCache.purge();
|
||||
|
||||
/* Destroy eval'ed scripts. */
|
||||
js_DestroyScriptsToGC(cx, this);
|
||||
/*
|
||||
* Clear the hash and reset all evalHashLink to null before the GC. This
|
||||
* way MarkChildren(trc, JSScript *) can assume that JSScript::u.object is
|
||||
* not null when we have script owned by an object and not from the eval
|
||||
* cache.
|
||||
*/
|
||||
for (size_t i = 0; i != JS_ARRAY_LENGTH(evalCache); ++i) {
|
||||
for (JSScript **listHeadp = &evalCache[i]; *listHeadp; ) {
|
||||
JSScript *script = *listHeadp;
|
||||
JS_ASSERT(GetGCThingTraceKind(script) == JSTRACE_SCRIPT);
|
||||
*listHeadp = NULL;
|
||||
listHeadp = &script->u.evalHashLink;
|
||||
}
|
||||
}
|
||||
|
||||
nativeIterCache.purge();
|
||||
toSourceCache.destroyIfConstructed();
|
||||
@ -634,7 +646,7 @@ JSCompartment::hasScriptsOnStack(JSContext *cx)
|
||||
{
|
||||
for (AllFramesIter i(cx->stack.space()); !i.done(); ++i) {
|
||||
JSScript *script = i.fp()->maybeScript();
|
||||
if (script && script->compartment == this)
|
||||
if (script && script->compartment() == this)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -772,7 +784,7 @@ void
|
||||
JSCompartment::clearBreakpointsIn(JSContext *cx, js::Debugger *dbg, JSScript *script,
|
||||
JSObject *handler)
|
||||
{
|
||||
JS_ASSERT_IF(script, script->compartment == this);
|
||||
JS_ASSERT_IF(script, script->compartment() == this);
|
||||
|
||||
for (BreakpointSiteMap::Enum e(breakpointSites); !e.empty(); e.popFront()) {
|
||||
BreakpointSite *site = e.front().value;
|
||||
|
@ -298,10 +298,11 @@ class JaegerCompartment;
|
||||
/* Defined in jsapi.cpp */
|
||||
extern JSClass js_dummy_class;
|
||||
|
||||
/* Number of potentially reusable scriptsToGC to search for the eval cache. */
|
||||
#ifndef JS_EVAL_CACHE_SHIFT
|
||||
# define JS_EVAL_CACHE_SHIFT 6
|
||||
#endif
|
||||
|
||||
/* Number of buckets in the hash of eval scripts. */
|
||||
#define JS_EVAL_CACHE_SIZE JS_BIT(JS_EVAL_CACHE_SHIFT)
|
||||
|
||||
namespace js {
|
||||
@ -414,7 +415,7 @@ struct JS_FRIEND_API(JSCompartment) {
|
||||
|
||||
public:
|
||||
/* Hashed lists of scripts created by eval to garbage-collect. */
|
||||
JSScript *scriptsToGC[JS_EVAL_CACHE_SIZE];
|
||||
JSScript *evalCache[JS_EVAL_CACHE_SIZE];
|
||||
|
||||
void *data;
|
||||
bool active; // GC flag, whether there are active frames
|
||||
@ -527,6 +528,7 @@ struct JS_FRIEND_API(JSCompartment) {
|
||||
void finalizeObjectArenaLists(JSContext *cx);
|
||||
void finalizeStringArenaLists(JSContext *cx);
|
||||
void finalizeShapeArenaLists(JSContext *cx);
|
||||
void finalizeScriptArenaLists(JSContext *cx);
|
||||
bool arenaListsAreEmpty();
|
||||
|
||||
void setGCLastBytes(size_t lastBytes, JSGCInvocationKind gckind);
|
||||
@ -620,7 +622,6 @@ struct JS_FRIEND_API(JSCompartment) {
|
||||
js::WatchpointMap *watchpointMap;
|
||||
};
|
||||
|
||||
#define JS_SCRIPTS_TO_GC(cx) ((cx)->compartment->scriptsToGC)
|
||||
#define JS_PROPERTY_TREE(cx) ((cx)->compartment->propertyTree)
|
||||
|
||||
/*
|
||||
|
@ -212,7 +212,7 @@ jsbytecode *
|
||||
js_UntrapScriptCode(JSContext *cx, JSScript *script)
|
||||
{
|
||||
jsbytecode *code = script->code;
|
||||
BreakpointSiteMap &sites = script->compartment->breakpointSites;
|
||||
BreakpointSiteMap &sites = script->compartment()->breakpointSites;
|
||||
for (BreakpointSiteMap::Range r = sites.all(); !r.empty(); r.popFront()) {
|
||||
BreakpointSite *site = r.front().value;
|
||||
if (site->script == script && size_t(site->pc - script->code) < script->length) {
|
||||
@ -242,7 +242,7 @@ JS_SetTrap(JSContext *cx, JSScript *script, jsbytecode *pc, JSTrapHandler handle
|
||||
if (!CheckDebugMode(cx))
|
||||
return false;
|
||||
|
||||
BreakpointSite *site = script->compartment->getOrCreateBreakpointSite(cx, script, pc, NULL);
|
||||
BreakpointSite *site = script->compartment()->getOrCreateBreakpointSite(cx, script, pc, NULL);
|
||||
if (!site)
|
||||
return false;
|
||||
site->setTrap(cx, handler, Valueify(closure));
|
||||
@ -252,7 +252,7 @@ JS_SetTrap(JSContext *cx, JSScript *script, jsbytecode *pc, JSTrapHandler handle
|
||||
JS_PUBLIC_API(JSOp)
|
||||
JS_GetTrapOpcode(JSContext *cx, JSScript *script, jsbytecode *pc)
|
||||
{
|
||||
BreakpointSite *site = script->compartment->getBreakpointSite(pc);
|
||||
BreakpointSite *site = script->compartment()->getBreakpointSite(pc);
|
||||
return site ? site->realOpcode : JSOp(*pc);
|
||||
}
|
||||
|
||||
@ -260,7 +260,7 @@ JS_PUBLIC_API(void)
|
||||
JS_ClearTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
JSTrapHandler *handlerp, jsval *closurep)
|
||||
{
|
||||
if (BreakpointSite *site = script->compartment->getBreakpointSite(pc)) {
|
||||
if (BreakpointSite *site = script->compartment()->getBreakpointSite(pc)) {
|
||||
site->clearTrap(cx, NULL, handlerp, Valueify(closurep));
|
||||
} else {
|
||||
if (handlerp)
|
||||
@ -273,7 +273,7 @@ JS_ClearTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
JS_PUBLIC_API(void)
|
||||
JS_ClearScriptTraps(JSContext *cx, JSScript *script)
|
||||
{
|
||||
script->compartment->clearTraps(cx, script);
|
||||
script->compartment()->clearTraps(cx, script);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
|
@ -202,7 +202,6 @@ ArgumentsObject::create(JSContext *cx, uint32 argc, JSObject &callee)
|
||||
EmptyShape *emptyArgumentsShape = EmptyShape::getEmptyArgumentsShape(cx);
|
||||
if (!emptyArgumentsShape)
|
||||
return NULL;
|
||||
AutoShapeRooter shapeRoot(cx, emptyArgumentsShape);
|
||||
|
||||
ArgumentsData *data = (ArgumentsData *)
|
||||
cx->malloc_(offsetof(ArgumentsData, slots) + argc * sizeof(Value));
|
||||
@ -1599,9 +1598,6 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp)
|
||||
if (xdr->mode == JSXDR_DECODE) {
|
||||
*objp = FUN_OBJECT(fun);
|
||||
fun->u.i.script->setOwnerObject(fun);
|
||||
#ifdef CHECK_SCRIPT_OWNER
|
||||
fun->script()->owner = NULL;
|
||||
#endif
|
||||
JS_ASSERT(fun->nargs == fun->script()->bindings.countArgs());
|
||||
js_CallNewScriptHook(cx, fun->script(), fun);
|
||||
}
|
||||
@ -1670,30 +1666,16 @@ fun_trace(JSTracer *trc, JSObject *obj)
|
||||
if (fun->atom)
|
||||
MarkString(trc, fun->atom, "atom");
|
||||
|
||||
if (fun->isInterpreted() && fun->script())
|
||||
js_TraceScript(trc, fun->script(), obj);
|
||||
if (fun->isInterpreted() && fun->script()) {
|
||||
CheckScriptOwner(fun->script(), obj);
|
||||
MarkScript(trc, fun->script(), "script");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fun_finalize(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
/* Ignore newborn function objects. */
|
||||
JSFunction *fun = obj->getFunctionPrivate();
|
||||
if (!fun)
|
||||
return;
|
||||
|
||||
/* Cloned function objects may be flat closures with upvars to free. */
|
||||
if (fun != obj) {
|
||||
if (fun->isFlatClosure() && fun->script()->bindings.hasUpvars())
|
||||
cx->free_((void *) obj->getFlatClosureUpvars());
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Null-check fun->script() because the parser sets interpreted very early.
|
||||
*/
|
||||
if (fun->isInterpreted() && fun->script())
|
||||
js_DestroyScriptFromGC(cx, fun->script(), obj);
|
||||
obj->finalizeUpvarsIfFlatClosure();
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1705,7 +1687,8 @@ JS_PUBLIC_DATA(Class) js_FunctionClass = {
|
||||
js_Function_str,
|
||||
JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE |
|
||||
JSCLASS_HAS_RESERVED_SLOTS(JSFunction::CLASS_RESERVED_SLOTS) |
|
||||
JSCLASS_HAS_CACHED_PROTO(JSProto_Function),
|
||||
JSCLASS_HAS_CACHED_PROTO(JSProto_Function) |
|
||||
JSCLASS_CONCURRENT_FINALIZER,
|
||||
PropertyStub, /* addProperty */
|
||||
PropertyStub, /* delProperty */
|
||||
PropertyStub, /* getProperty */
|
||||
@ -2155,7 +2138,6 @@ Function(JSContext *cx, uintN argc, Value *vp)
|
||||
EmptyShape *emptyCallShape = EmptyShape::getEmptyCallShape(cx);
|
||||
if (!emptyCallShape)
|
||||
return false;
|
||||
AutoShapeRooter shapeRoot(cx, emptyCallShape);
|
||||
|
||||
Bindings bindings(cx, emptyCallShape);
|
||||
AutoBindingsRooter root(cx, bindings);
|
||||
@ -2372,9 +2354,6 @@ js_InitFunctionClass(JSContext *cx, JSObject *obj)
|
||||
script->noScriptRval = true;
|
||||
script->code[0] = JSOP_STOP;
|
||||
script->code[1] = SRC_NULL;
|
||||
#ifdef CHECK_SCRIPT_OWNER
|
||||
script->owner = NULL;
|
||||
#endif
|
||||
fun->u.i.script = script;
|
||||
script->setOwnerObject(fun);
|
||||
js_CallNewScriptHook(cx, script, fun);
|
||||
@ -2477,8 +2456,8 @@ js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent,
|
||||
if (cfun->isInterpreted()) {
|
||||
JSScript *script = cfun->script();
|
||||
JS_ASSERT(script);
|
||||
JS_ASSERT(script->compartment == fun->compartment());
|
||||
JS_ASSERT(script->compartment != cx->compartment);
|
||||
JS_ASSERT(script->compartment() == fun->compartment());
|
||||
JS_ASSERT(script->compartment() != cx->compartment);
|
||||
JS_OPT_ASSERT(script->ownerObject == fun);
|
||||
|
||||
JSScript *cscript = js_CloneScript(cx, script);
|
||||
@ -2486,9 +2465,6 @@ js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent,
|
||||
return NULL;
|
||||
cfun->u.i.script = cscript;
|
||||
cfun->script()->setOwnerObject(cfun);
|
||||
#ifdef CHECK_SCRIPT_OWNER
|
||||
cfun->script()->owner = NULL;
|
||||
#endif
|
||||
js_CallNewScriptHook(cx, cfun->script(), cfun);
|
||||
Debugger::onNewScript(cx, cfun->script(), cfun, Debugger::NewHeldScript);
|
||||
}
|
||||
|
@ -112,13 +112,14 @@ using namespace js::gc;
|
||||
JS_STATIC_ASSERT(JSTRACE_OBJECT == 0);
|
||||
JS_STATIC_ASSERT(JSTRACE_STRING == 1);
|
||||
JS_STATIC_ASSERT(JSTRACE_SHAPE == 2);
|
||||
JS_STATIC_ASSERT(JSTRACE_XML == 3);
|
||||
JS_STATIC_ASSERT(JSTRACE_SCRIPT == 3);
|
||||
JS_STATIC_ASSERT(JSTRACE_XML == 4);
|
||||
|
||||
/*
|
||||
* JS_IS_VALID_TRACE_KIND assumes that JSTRACE_SHAPE is the last non-xml
|
||||
* trace kind when JS_HAS_XML_SUPPORT is false.
|
||||
*/
|
||||
JS_STATIC_ASSERT(JSTRACE_SHAPE + 1 == JSTRACE_XML);
|
||||
JS_STATIC_ASSERT(JSTRACE_SCRIPT + 1 == JSTRACE_XML);
|
||||
|
||||
namespace js {
|
||||
namespace gc {
|
||||
@ -149,6 +150,7 @@ const uint8 GCThingSizeMap[] = {
|
||||
sizeof(JSObject_Slots16), /* FINALIZE_OBJECT16_BACKGROUND */
|
||||
sizeof(JSFunction), /* FINALIZE_FUNCTION */
|
||||
sizeof(Shape), /* FINALIZE_SHAPE */
|
||||
sizeof(JSScript), /* FINALIZE_SCRIPT */
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
sizeof(JSXML), /* FINALIZE_XML */
|
||||
#endif
|
||||
@ -196,6 +198,10 @@ template<typename T>
|
||||
inline bool
|
||||
Arena::finalize(JSContext *cx)
|
||||
{
|
||||
/* Enforce requirements on size of T. */
|
||||
JS_STATIC_ASSERT(sizeof(T) % Cell::CellSize == 0);
|
||||
JS_STATIC_ASSERT(sizeof(T) <= 255);
|
||||
|
||||
JS_ASSERT(aheader.allocated());
|
||||
JS_ASSERT(!aheader.getMarkingDelay()->link);
|
||||
|
||||
@ -787,6 +793,9 @@ MarkIfGCThingWord(JSTracer *trc, jsuword w)
|
||||
case FINALIZE_SHAPE:
|
||||
test = MarkArenaPtrConservatively<Shape>(trc, aheader, addr);
|
||||
break;
|
||||
case FINALIZE_SCRIPT:
|
||||
test = MarkArenaPtrConservatively<JSScript>(trc, aheader, addr);
|
||||
break;
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
case FINALIZE_XML:
|
||||
test = MarkArenaPtrConservatively<JSXML>(trc, aheader, addr);
|
||||
@ -1247,6 +1256,7 @@ ArenaList::finalizeLater(JSContext *cx)
|
||||
head->getThingKind() == FINALIZE_OBJECT8_BACKGROUND ||
|
||||
head->getThingKind() == FINALIZE_OBJECT12_BACKGROUND ||
|
||||
head->getThingKind() == FINALIZE_OBJECT16_BACKGROUND ||
|
||||
head->getThingKind() == FINALIZE_FUNCTION ||
|
||||
head->getThingKind() == FINALIZE_SHORT_STRING ||
|
||||
head->getThingKind() == FINALIZE_STRING);
|
||||
JS_ASSERT(!cx->runtime->gcHelperThread.sweeping);
|
||||
@ -1258,7 +1268,13 @@ ArenaList::finalizeLater(JSContext *cx)
|
||||
JS_ASSERT(backgroundFinalizeState == BFS_DONE ||
|
||||
backgroundFinalizeState == BFS_JUST_FINISHED);
|
||||
|
||||
if (head && cx->gcBackgroundFree && cx->gcBackgroundFree->finalizeVector.append(head)) {
|
||||
if (head && cx->gcBackgroundFree) {
|
||||
/*
|
||||
* To ensure the finalization order even during the background GC we
|
||||
* must use infallibleAppend so arenas scheduled for background
|
||||
* finalization would not be finalized now if the append fails.
|
||||
*/
|
||||
cx->gcBackgroundFree->finalizeVector.infallibleAppend(head);
|
||||
head = NULL;
|
||||
cursor = &head;
|
||||
backgroundFinalizeState = BFS_RUN;
|
||||
@ -1299,6 +1315,9 @@ ArenaList::backgroundFinalize(JSContext *cx, ArenaHeader *listHead)
|
||||
case FINALIZE_OBJECT16_BACKGROUND:
|
||||
FinalizeArenas<JSObject_Slots16>(cx, &listHead);
|
||||
break;
|
||||
case FINALIZE_FUNCTION:
|
||||
FinalizeArenas<JSFunction>(cx, &listHead);
|
||||
break;
|
||||
case FINALIZE_STRING:
|
||||
FinalizeArenas<JSString>(cx, &listHead);
|
||||
break;
|
||||
@ -1459,6 +1478,8 @@ RefillFinalizableFreeList(JSContext *cx, unsigned thingKind)
|
||||
return RefillTypedFreeList<JSFunction>(cx, thingKind);
|
||||
case FINALIZE_SHAPE:
|
||||
return RefillTypedFreeList<Shape>(cx, thingKind);
|
||||
case FINALIZE_SCRIPT:
|
||||
return RefillTypedFreeList<JSScript>(cx, thingKind);
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
case FINALIZE_XML:
|
||||
return RefillTypedFreeList<JSXML>(cx, thingKind);
|
||||
@ -1662,8 +1683,8 @@ js_TraceStackFrame(JSTracer *trc, StackFrame *fp)
|
||||
return;
|
||||
if (fp->hasArgsObj())
|
||||
MarkObject(trc, fp->argsObj(), "arguments");
|
||||
js_TraceScript(trc, fp->script(), NULL);
|
||||
fp->script()->compartment->active = true;
|
||||
MarkScript(trc, fp->script(), "script");
|
||||
fp->script()->compartment()->active = true;
|
||||
MarkValue(trc, fp->returnValue(), "rval");
|
||||
}
|
||||
|
||||
@ -1688,19 +1709,10 @@ AutoGCRooter::trace(JSTracer *trc)
|
||||
MarkValue(trc, static_cast<AutoValueRooter *>(this)->val, "js::AutoValueRooter.val");
|
||||
return;
|
||||
|
||||
case SHAPE:
|
||||
MarkShape(trc, static_cast<AutoShapeRooter *>(this)->shape, "js::AutoShapeRooter.val");
|
||||
return;
|
||||
|
||||
case PARSER:
|
||||
static_cast<Parser *>(this)->trace(trc);
|
||||
return;
|
||||
|
||||
case SCRIPT:
|
||||
if (JSScript *script = static_cast<AutoScriptRooter *>(this)->script)
|
||||
js_TraceScript(trc, script, NULL);
|
||||
return;
|
||||
|
||||
case ENUMERATOR:
|
||||
static_cast<AutoEnumStateRooter *>(this)->trace(trc);
|
||||
return;
|
||||
@ -1956,21 +1968,6 @@ MaybeGC(JSContext *cx)
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
void
|
||||
js_DestroyScriptsToGC(JSContext *cx, JSCompartment *comp)
|
||||
{
|
||||
JSScript **listp, *script;
|
||||
|
||||
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_DestroyCachedScript(cx, script);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
JSCompartment::finalizeObjectArenaLists(JSContext *cx)
|
||||
{
|
||||
@ -1980,7 +1977,6 @@ JSCompartment::finalizeObjectArenaLists(JSContext *cx)
|
||||
arenas[FINALIZE_OBJECT8]. finalizeNow<JSObject_Slots8>(cx);
|
||||
arenas[FINALIZE_OBJECT12].finalizeNow<JSObject_Slots12>(cx);
|
||||
arenas[FINALIZE_OBJECT16].finalizeNow<JSObject_Slots16>(cx);
|
||||
arenas[FINALIZE_FUNCTION].finalizeNow<JSFunction>(cx);
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
arenas[FINALIZE_OBJECT0_BACKGROUND]. finalizeLater<JSObject>(cx);
|
||||
@ -1991,6 +1987,17 @@ JSCompartment::finalizeObjectArenaLists(JSContext *cx)
|
||||
arenas[FINALIZE_OBJECT16_BACKGROUND].finalizeLater<JSObject_Slots16>(cx);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We must finalize Function instances after finalizing any other objects
|
||||
* even if we use the background finalization for the latter. See comments
|
||||
* in JSObject::finalizeUpvarsIfFlatClosure.
|
||||
*/
|
||||
#ifdef JS_THREADSAFE
|
||||
arenas[FINALIZE_FUNCTION].finalizeLater<JSFunction>(cx);
|
||||
#else
|
||||
arenas[FINALIZE_FUNCTION].finalizeNow<JSFunction>(cx);
|
||||
#endif
|
||||
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
arenas[FINALIZE_XML].finalizeNow<JSXML>(cx);
|
||||
#endif
|
||||
@ -2015,6 +2022,12 @@ JSCompartment::finalizeShapeArenaLists(JSContext *cx)
|
||||
arenas[FINALIZE_SHAPE].finalizeNow<Shape>(cx);
|
||||
}
|
||||
|
||||
void
|
||||
JSCompartment::finalizeScriptArenaLists(JSContext *cx)
|
||||
{
|
||||
arenas[FINALIZE_SCRIPT].finalizeNow<JSScript>(cx);
|
||||
}
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
|
||||
namespace js {
|
||||
@ -2084,6 +2097,15 @@ GCHelperThread::threadLoop(JSRuntime *rt)
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
GCHelperThread::prepareForBackgroundSweep(JSContext *context) {
|
||||
size_t maxArenaLists = MAX_BACKGROUND_FINALIZE_KINDS * context->runtime->compartments.length();
|
||||
if (!finalizeVector.reserve(maxArenaLists))
|
||||
return false;
|
||||
cx = context;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
GCHelperThread::startBackgroundSweep(JSRuntime *rt, JSGCInvocationKind gckind)
|
||||
{
|
||||
@ -2127,6 +2149,11 @@ void
|
||||
GCHelperThread::doSweep()
|
||||
{
|
||||
JS_ASSERT(cx);
|
||||
|
||||
/*
|
||||
* We must finalize in the insert order, see comments in
|
||||
* finalizeObjectArenaLists.
|
||||
*/
|
||||
for (ArenaHeader **i = finalizeVector.begin(); i != finalizeVector.end(); ++i)
|
||||
ArenaList::backgroundFinalize(cx, *i);
|
||||
finalizeVector.resize(0);
|
||||
@ -2343,6 +2370,8 @@ MarkAndSweep(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind GCTIM
|
||||
GCTIMESTAMP(sweepObjectEnd);
|
||||
comp->finalizeStringArenaLists(cx);
|
||||
GCTIMESTAMP(sweepStringEnd);
|
||||
comp->finalizeScriptArenaLists(cx);
|
||||
GCTIMESTAMP(sweepScriptEnd);
|
||||
comp->finalizeShapeArenaLists(cx);
|
||||
GCTIMESTAMP(sweepShapeEnd);
|
||||
Probes::GCEndSweepPhase(comp);
|
||||
@ -2368,6 +2397,12 @@ MarkAndSweep(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind GCTIM
|
||||
|
||||
GCTIMESTAMP(sweepStringEnd);
|
||||
|
||||
for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); c++) {
|
||||
(*c)->finalizeScriptArenaLists(cx);
|
||||
}
|
||||
|
||||
GCTIMESTAMP(sweepScriptEnd);
|
||||
|
||||
for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); c++) {
|
||||
(*c)->finalizeShapeArenaLists(cx);
|
||||
Probes::GCEndSweepPhase(*c);
|
||||
@ -2646,8 +2681,8 @@ GCCycle(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind GCTIMER_P
|
||||
JS_ASSERT(!cx->gcBackgroundFree);
|
||||
rt->gcHelperThread.waitBackgroundSweepEnd(rt);
|
||||
if (gckind != GC_LAST_CONTEXT && rt->state != JSRTS_LANDING) {
|
||||
cx->gcBackgroundFree = &rt->gcHelperThread;
|
||||
cx->gcBackgroundFree->setContext(cx);
|
||||
if (rt->gcHelperThread.prepareForBackgroundSweep(cx))
|
||||
cx->gcBackgroundFree = &rt->gcHelperThread;
|
||||
}
|
||||
#endif
|
||||
MarkAndSweep(cx, comp, gckind GCTIMER_ARG);
|
||||
|
@ -98,6 +98,7 @@ enum FinalizeKind {
|
||||
FINALIZE_FUNCTION,
|
||||
FINALIZE_FUNCTION_AND_OBJECT_LAST = FINALIZE_FUNCTION,
|
||||
FINALIZE_SHAPE,
|
||||
FINALIZE_SCRIPT,
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
FINALIZE_XML,
|
||||
#endif
|
||||
@ -107,6 +108,12 @@ enum FinalizeKind {
|
||||
FINALIZE_LIMIT
|
||||
};
|
||||
|
||||
/*
|
||||
* This must be an upper bound, but we do not need the least upper bound, so
|
||||
* we just exclude non-background objects.
|
||||
*/
|
||||
const size_t MAX_BACKGROUND_FINALIZE_KINDS = FINALIZE_LIMIT - (FINALIZE_OBJECT_LAST + 1) / 2;
|
||||
|
||||
extern JS_FRIEND_DATA(const uint8) GCThingSizeMap[];
|
||||
|
||||
const size_t ArenaShift = 12;
|
||||
@ -755,12 +762,12 @@ Cell::compartment() const
|
||||
return arenaHeader()->compartment;
|
||||
}
|
||||
|
||||
#define JSTRACE_XML 3
|
||||
#define JSTRACE_XML 4
|
||||
|
||||
/*
|
||||
* One past the maximum trace kind.
|
||||
*/
|
||||
#define JSTRACE_LIMIT 4
|
||||
#define JSTRACE_LIMIT 5
|
||||
|
||||
/*
|
||||
* Lower limit after which we limit the heap growth
|
||||
@ -797,6 +804,7 @@ GetFinalizableTraceKind(size_t thingKind)
|
||||
JSTRACE_OBJECT, /* FINALIZE_OBJECT16_BACKGROUND */
|
||||
JSTRACE_OBJECT, /* FINALIZE_FUNCTION */
|
||||
JSTRACE_SHAPE, /* FINALIZE_SHAPE */
|
||||
JSTRACE_SCRIPT, /* FINALIZE_SCRIPT */
|
||||
#if JS_HAS_XML_SUPPORT /* FINALIZE_XML */
|
||||
JSTRACE_XML,
|
||||
#endif
|
||||
@ -1191,10 +1199,6 @@ js_WaitForGC(JSRuntime *rt);
|
||||
|
||||
#endif
|
||||
|
||||
extern void
|
||||
js_DestroyScriptsToGC(JSContext *cx, JSCompartment *comp);
|
||||
|
||||
|
||||
namespace js {
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
@ -1270,7 +1274,7 @@ class GCHelperThread {
|
||||
replenishAndFreeLater(ptr);
|
||||
}
|
||||
|
||||
void setContext(JSContext *context) { cx = context; }
|
||||
bool prepareForBackgroundSweep(JSContext *context);
|
||||
};
|
||||
|
||||
#endif /* JS_THREADSAFE */
|
||||
@ -1492,7 +1496,7 @@ js_FinalizeStringRT(JSRuntime *rt, JSString *str);
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
# define JS_IS_VALID_TRACE_KIND(kind) ((uint32)(kind) < JSTRACE_LIMIT)
|
||||
#else
|
||||
# define JS_IS_VALID_TRACE_KIND(kind) ((uint32)(kind) <= JSTRACE_SHAPE)
|
||||
# define JS_IS_VALID_TRACE_KIND(kind) ((uint32)(kind) <= JSTRACE_SCRIPT)
|
||||
#endif
|
||||
|
||||
namespace js {
|
||||
|
@ -255,6 +255,12 @@ js_NewGCShape(JSContext *cx)
|
||||
return NewGCThing<js::Shape>(cx, js::gc::FINALIZE_SHAPE, sizeof(js::Shape));
|
||||
}
|
||||
|
||||
inline JSScript *
|
||||
js_NewGCScript(JSContext *cx)
|
||||
{
|
||||
return NewGCThing<JSScript>(cx, js::gc::FINALIZE_SCRIPT, sizeof(JSScript));
|
||||
}
|
||||
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
extern JSXML *
|
||||
js_NewGCXML(JSContext *cx);
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include "jsscopeinlines.h"
|
||||
|
||||
#include "vm/String-inl.h"
|
||||
#include "methodjit/MethodJIT.h"
|
||||
|
||||
/*
|
||||
* There are two mostly separate mark paths. The first is a fast path used
|
||||
@ -94,6 +95,9 @@ PushMarkStack(GCMarker *gcmarker, JSFunction *thing);
|
||||
static inline void
|
||||
PushMarkStack(GCMarker *gcmarker, const Shape *thing);
|
||||
|
||||
static inline void
|
||||
PushMarkStack(GCMarker *gcmarker, JSScript *thing);
|
||||
|
||||
static inline void
|
||||
PushMarkStack(GCMarker *gcmarker, JSShortString *thing);
|
||||
|
||||
@ -191,6 +195,15 @@ MarkShape(JSTracer *trc, const Shape *shape, const char *name)
|
||||
Mark(trc, shape);
|
||||
}
|
||||
|
||||
void
|
||||
MarkScript(JSTracer *trc, JSScript *script, const char *name)
|
||||
{
|
||||
JS_ASSERT(trc);
|
||||
JS_ASSERT(script);
|
||||
JS_SET_TRACING_NAME(trc, name);
|
||||
Mark(trc, script);
|
||||
}
|
||||
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
void
|
||||
MarkXML(JSTracer *trc, JSXML *xml, const char *name)
|
||||
@ -256,6 +269,21 @@ PushMarkStack(GCMarker *gcmarker, const Shape *thing)
|
||||
}
|
||||
|
||||
void
|
||||
PushMarkStack(GCMarker *gcmarker, JSScript *thing)
|
||||
{
|
||||
JS_ASSERT_IF(gcmarker->context->runtime->gcCurrentCompartment,
|
||||
thing->compartment() == gcmarker->context->runtime->gcCurrentCompartment);
|
||||
|
||||
/*
|
||||
* We mark scripts directly rather than pushing on the stack as they can
|
||||
* refer to other scripts only indirectly (like via nested functions) and
|
||||
* we cannot get to deep recursion.
|
||||
*/
|
||||
if (thing->markIfUnmarked(gcmarker->getMarkColor()))
|
||||
MarkChildren(gcmarker, thing);
|
||||
}
|
||||
|
||||
static void
|
||||
MarkAtomRange(JSTracer *trc, size_t len, JSAtom **vec, const char *name)
|
||||
{
|
||||
for (uint32 i = 0; i < len; i++) {
|
||||
@ -329,22 +357,24 @@ MarkKind(JSTracer *trc, void *thing, uint32 kind)
|
||||
JS_ASSERT(thing);
|
||||
JS_ASSERT(kind == GetGCThingTraceKind(thing));
|
||||
switch (kind) {
|
||||
case JSTRACE_OBJECT:
|
||||
Mark(trc, reinterpret_cast<JSObject *>(thing));
|
||||
break;
|
||||
case JSTRACE_STRING:
|
||||
MarkString(trc, reinterpret_cast<JSString *>(thing));
|
||||
break;
|
||||
case JSTRACE_SHAPE:
|
||||
Mark(trc, reinterpret_cast<Shape *>(thing));
|
||||
break;
|
||||
default:
|
||||
JS_ASSERT(kind == JSTRACE_OBJECT);
|
||||
Mark(trc, static_cast<JSObject *>(thing));
|
||||
break;
|
||||
case JSTRACE_STRING:
|
||||
MarkString(trc, static_cast<JSString *>(thing));
|
||||
break;
|
||||
case JSTRACE_SHAPE:
|
||||
Mark(trc, static_cast<Shape *>(thing));
|
||||
break;
|
||||
case JSTRACE_SCRIPT:
|
||||
Mark(trc, static_cast<JSScript *>(thing));
|
||||
break;
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
case JSTRACE_XML:
|
||||
Mark(trc, reinterpret_cast<JSXML *>(thing));
|
||||
break;
|
||||
case JSTRACE_XML:
|
||||
Mark(trc, static_cast<JSXML *>(thing));
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
JS_ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -469,6 +499,12 @@ MarkRoot(JSTracer *trc, const Shape *thing, const char *name)
|
||||
MarkShape(trc, thing, name);
|
||||
}
|
||||
|
||||
void
|
||||
MarkRoot(JSTracer *trc, JSScript *thing, const char *name)
|
||||
{
|
||||
MarkScript(trc, thing, name);
|
||||
}
|
||||
|
||||
void
|
||||
MarkRoot(JSTracer *trc, JSXML *thing, const char *name)
|
||||
{
|
||||
@ -765,6 +801,54 @@ restart:
|
||||
goto restart;
|
||||
}
|
||||
|
||||
void
|
||||
MarkChildren(JSTracer *trc, JSScript *script)
|
||||
{
|
||||
CheckScript(script, NULL);
|
||||
|
||||
#ifdef JS_CRASH_DIAGNOSTICS
|
||||
JSRuntime *rt = trc->context->runtime;
|
||||
JS_OPT_ASSERT_IF(rt->gcCheckCompartment, script->compartment() == rt->gcCheckCompartment);
|
||||
#endif
|
||||
|
||||
JSAtomMap *map = &script->atomMap;
|
||||
MarkAtomRange(trc, map->length, map->vector, "atomMap");
|
||||
|
||||
if (JSScript::isValidOffset(script->objectsOffset)) {
|
||||
JSObjectArray *objarray = script->objects();
|
||||
MarkObjectRange(trc, objarray->length, objarray->vector, "objects");
|
||||
}
|
||||
|
||||
if (JSScript::isValidOffset(script->regexpsOffset)) {
|
||||
JSObjectArray *objarray = script->regexps();
|
||||
MarkObjectRange(trc, objarray->length, objarray->vector, "objects");
|
||||
}
|
||||
|
||||
if (JSScript::isValidOffset(script->constOffset)) {
|
||||
JSConstArray *constarray = script->consts();
|
||||
MarkValueRange(trc, constarray->length, constarray->vector, "consts");
|
||||
}
|
||||
|
||||
/*
|
||||
* For cached eval scripts JSScript::u.evalHashLink is cleared during the
|
||||
* purge phase. So we can assume that if JSScript::u is not null, it
|
||||
* points to JSObject, not another script.
|
||||
*/
|
||||
if (script->u.object) {
|
||||
JS_ASSERT(GetGCThingTraceKind(script->u.object) == JSTRACE_OBJECT);
|
||||
MarkObject(trc, *script->u.object, "object");
|
||||
}
|
||||
|
||||
if (IS_GC_MARKING_TRACER(trc) && script->filename)
|
||||
js_MarkScriptFilename(script->filename);
|
||||
|
||||
script->bindings.trace(trc);
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
mjit::TraceScript(trc, script);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef JS_HAS_XML_SUPPORT
|
||||
void
|
||||
MarkChildren(JSTracer *trc, JSXML *xml)
|
||||
@ -815,22 +899,28 @@ JS_PUBLIC_API(void)
|
||||
JS_TraceChildren(JSTracer *trc, void *thing, uint32 kind)
|
||||
{
|
||||
switch (kind) {
|
||||
case JSTRACE_OBJECT:
|
||||
MarkChildren(trc, (JSObject *)thing);
|
||||
default:
|
||||
JS_ASSERT(kind == JSTRACE_OBJECT);
|
||||
MarkChildren(trc, static_cast<JSObject *>(thing));
|
||||
break;
|
||||
|
||||
case JSTRACE_STRING:
|
||||
MarkChildren(trc, (JSString *)thing);
|
||||
MarkChildren(trc, static_cast<JSString *>(thing));
|
||||
break;
|
||||
|
||||
case JSTRACE_SHAPE:
|
||||
MarkChildren(trc, (js::Shape *)thing);
|
||||
MarkChildren(trc, static_cast<Shape *>(thing));
|
||||
break;
|
||||
|
||||
case JSTRACE_SCRIPT:
|
||||
MarkChildren(trc, static_cast<JSScript *>(thing));
|
||||
break;
|
||||
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
case JSTRACE_XML:
|
||||
MarkChildren(trc, (JSXML *)thing);
|
||||
MarkChildren(trc, static_cast<JSXML *>(thing));
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -77,10 +77,10 @@ void
|
||||
MarkShape(JSTracer *trc, const Shape *shape, const char *name);
|
||||
|
||||
void
|
||||
MarkXML(JSTracer *trc, JSXML *xml, const char *name);
|
||||
MarkScript(JSTracer *trc, JSScript *script, const char *name);
|
||||
|
||||
void
|
||||
MarkAtomRange(JSTracer *trc, size_t len, JSAtom **vec, const char *name);
|
||||
MarkXML(JSTracer *trc, JSXML *xml, const char *name);
|
||||
|
||||
void
|
||||
MarkObjectRange(JSTracer *trc, size_t len, JSObject **vec, const char *name);
|
||||
@ -153,6 +153,9 @@ MarkRoot(JSTracer *trc, JSString *thing, const char *name);
|
||||
void
|
||||
MarkRoot(JSTracer *trc, const Shape *thing, const char *name);
|
||||
|
||||
void
|
||||
MarkRoot(JSTracer *trc, JSScript *thing, const char *name);
|
||||
|
||||
void
|
||||
MarkRoot(JSTracer *trc, JSXML *thing, const char *name);
|
||||
|
||||
@ -165,6 +168,9 @@ MarkChildren(JSTracer *trc, JSString *str);
|
||||
void
|
||||
MarkChildren(JSTracer *trc, const Shape *shape);
|
||||
|
||||
void
|
||||
MarkChildren(JSTracer *trc, JSScript *script);
|
||||
|
||||
void
|
||||
MarkChildren(JSTracer *trc, JSXML *xml);
|
||||
|
||||
|
@ -258,7 +258,8 @@ GCTimer::finish(bool lastGC)
|
||||
double sweepTime = TIMEDIFF(startSweep, sweepDestroyEnd);
|
||||
double sweepObjTime = TIMEDIFF(startSweep, sweepObjectEnd);
|
||||
double sweepStringTime = TIMEDIFF(sweepObjectEnd, sweepStringEnd);
|
||||
double sweepShapeTime = TIMEDIFF(sweepStringEnd, sweepShapeEnd);
|
||||
double sweepScriptTime = TIMEDIFF(sweepStringEnd, sweepScriptEnd);
|
||||
double sweepShapeTime = TIMEDIFF(sweepScriptEnd, sweepShapeEnd);
|
||||
double destroyTime = TIMEDIFF(sweepShapeEnd, sweepDestroyEnd);
|
||||
double endTime = TIMEDIFF(sweepDestroyEnd, end);
|
||||
|
||||
@ -275,6 +276,7 @@ GCTimer::finish(bool lastGC)
|
||||
info.sweepTime = sweepTime;
|
||||
info.sweepObjTime = sweepObjTime;
|
||||
info.sweepStringTime = sweepStringTime;
|
||||
info.sweepScriptTime = sweepScriptTime;
|
||||
info.sweepShapeTime = sweepShapeTime;
|
||||
info.destroyTime = destroyTime;
|
||||
info.endTime = endTime;
|
||||
@ -297,7 +299,7 @@ GCTimer::finish(bool lastGC)
|
||||
JS_ASSERT(gcFile);
|
||||
fullFormat = true;
|
||||
fprintf(gcFile, " AppTime, Total, Wait, Mark, Sweep, FinObj,"
|
||||
" FinStr, SwShapes, Destroy, End, +Chu, -Chu, T, Reason\n");
|
||||
" FinStr, SwScripts, SwShapes, Destroy, End, +Chu, -Chu, T, Reason\n");
|
||||
}
|
||||
}
|
||||
|
||||
@ -307,10 +309,10 @@ GCTimer::finish(bool lastGC)
|
||||
TIMEDIFF(startMark, startSweep),
|
||||
TIMEDIFF(startSweep, sweepDestroyEnd));
|
||||
} else {
|
||||
/* App , Tot , Wai , Mar , Swe , FiO , FiS , SwS , Des , End */
|
||||
fprintf(gcFile, "%12.0f, %6.1f, %6.1f, %6.1f, %6.1f, %6.1f, %6.1f, %8.1f, %6.1f, %6.1f, ",
|
||||
/* App , Tot , Wai , Mar , Swe , FiO , FiS , SwScr , SwS , Des , End */
|
||||
fprintf(gcFile, "%12.0f, %6.1f, %6.1f, %6.1f, %6.1f, %6.1f, %6.1f, %6.1f, %8.1f, %6.1f, %6.1f, ",
|
||||
appTime, gcTime, waitTime, markTime, sweepTime, sweepObjTime, sweepStringTime,
|
||||
sweepShapeTime, destroyTime, endTime);
|
||||
sweepScriptTime, sweepShapeTime, destroyTime, endTime);
|
||||
fprintf(gcFile, "%4d, %4d,", newChunkCount, destroyChunkCount);
|
||||
fprintf(gcFile, " %s, %s\n", isCompartmental ? "C" : "G", gcReasons[gcReason]);
|
||||
}
|
||||
|
@ -49,7 +49,8 @@ JS_BEGIN_EXTERN_C
|
||||
struct JSGCInfo
|
||||
{
|
||||
double appTime, gcTime, waitTime, markTime, sweepTime;
|
||||
double sweepObjTime, sweepStringTime, sweepShapeTime, destroyTime, endTime;
|
||||
double sweepObjTime, sweepStringTime, sweepScriptTime, sweepShapeTime;
|
||||
double destroyTime, endTime;
|
||||
bool isCompartmental;
|
||||
};
|
||||
|
||||
@ -134,6 +135,7 @@ struct GCTimer
|
||||
uint64 startSweep;
|
||||
uint64 sweepObjectEnd;
|
||||
uint64 sweepStringEnd;
|
||||
uint64 sweepScriptEnd;
|
||||
uint64 sweepShapeEnd;
|
||||
uint64 sweepDestroyEnd;
|
||||
uint64 end;
|
||||
|
@ -890,7 +890,6 @@ Execute(JSContext *cx, JSScript *script, JSObject &scopeChain, const Value &this
|
||||
}
|
||||
|
||||
LeaveTrace(cx);
|
||||
AutoScriptRooter root(cx, script);
|
||||
|
||||
ExecuteFrameGuard efg;
|
||||
if (!cx->stack.pushExecuteFrame(cx, script, thisv, scopeChain, type, evalInFrame, &efg))
|
||||
|
@ -982,7 +982,7 @@ EvalCacheHash(JSContext *cx, JSLinearString *str)
|
||||
|
||||
h *= JS_GOLDEN_RATIO;
|
||||
h >>= 32 - JS_EVAL_CACHE_SHIFT;
|
||||
return &JS_SCRIPTS_TO_GC(cx)[h];
|
||||
return &cx->compartment->evalCache[h];
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE JSScript *
|
||||
@ -1054,8 +1054,8 @@ EvalCacheLookup(JSContext *cx, JSLinearString *str, StackFrame *caller, uintN st
|
||||
if (i < 0 ||
|
||||
objarray->vector[i]->getParent() == &scopeobj) {
|
||||
JS_ASSERT(staticLevel == script->staticLevel);
|
||||
*scriptp = script->u.nextToGC;
|
||||
script->u.nextToGC = NULL;
|
||||
*scriptp = script->u.evalHashLink;
|
||||
script->u.evalHashLink = NULL;
|
||||
return script;
|
||||
}
|
||||
}
|
||||
@ -1064,7 +1064,7 @@ EvalCacheLookup(JSContext *cx, JSLinearString *str, StackFrame *caller, uintN st
|
||||
|
||||
if (++count == EVAL_CACHE_CHAIN_LIMIT)
|
||||
return NULL;
|
||||
scriptp = &script->u.nextToGC;
|
||||
scriptp = &script->u.evalHashLink;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@ -1078,7 +1078,7 @@ EvalCacheLookup(JSContext *cx, JSLinearString *str, StackFrame *caller, uintN st
|
||||
* a jsdbgapi user's perspective, we want each eval() to create and destroy a
|
||||
* script. This hides implementation details and means we don't have to deal
|
||||
* with calls to JS_GetScriptObject for scripts in the eval cache (currently,
|
||||
* script->u.object aliases script->u.nextToGC).
|
||||
* script->u.object aliases script->u.evalHashLink).
|
||||
*/
|
||||
class EvalScriptGuard
|
||||
{
|
||||
@ -1098,11 +1098,8 @@ class EvalScriptGuard
|
||||
~EvalScriptGuard() {
|
||||
if (script_) {
|
||||
js_CallDestroyScriptHook(cx_, script_);
|
||||
script_->u.nextToGC = *bucket_;
|
||||
script_->u.evalHashLink = *bucket_;
|
||||
*bucket_ = script_;
|
||||
#ifdef CHECK_SCRIPT_OWNER
|
||||
script_->owner = NULL;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -5164,12 +5161,8 @@ js_NativeGetInline(JSContext *cx, JSObject *receiver, JSObject *obj, JSObject *p
|
||||
}
|
||||
|
||||
sample = cx->runtime->propertyRemovals;
|
||||
{
|
||||
AutoShapeRooter tvr(cx, shape);
|
||||
AutoObjectRooter tvr2(cx, pobj);
|
||||
if (!shape->get(cx, receiver, obj, pobj, vp))
|
||||
return false;
|
||||
}
|
||||
if (!shape->get(cx, receiver, obj, pobj, vp))
|
||||
return false;
|
||||
|
||||
if (pobj->containsSlot(slot) &&
|
||||
(JS_LIKELY(cx->runtime->propertyRemovals == sample) ||
|
||||
@ -5227,14 +5220,11 @@ js_NativeSet(JSContext *cx, JSObject *obj, const Shape *shape, bool added, bool
|
||||
}
|
||||
|
||||
sample = cx->runtime->propertyRemovals;
|
||||
{
|
||||
AutoShapeRooter tvr(cx, shape);
|
||||
if (!shape->set(cx, obj, strict, vp))
|
||||
return false;
|
||||
|
||||
JS_ASSERT_IF(!obj->inDictionaryMode(), shape->slot == slot);
|
||||
slot = shape->slot;
|
||||
}
|
||||
if (!shape->set(cx, obj, strict, vp))
|
||||
return false;
|
||||
|
||||
JS_ASSERT_IF(!obj->inDictionaryMode(), shape->slot == slot);
|
||||
slot = shape->slot;
|
||||
|
||||
if (obj->containsSlot(slot) &&
|
||||
(JS_LIKELY(cx->runtime->propertyRemovals == sample) ||
|
||||
|
@ -990,6 +990,9 @@ struct JSObject : js::gc::Cell {
|
||||
inline void setFlatClosureUpvar(uint32 i, const js::Value &v);
|
||||
inline void setFlatClosureUpvars(js::Value *upvars);
|
||||
|
||||
/* See comments in fun_finalize. */
|
||||
inline void finalizeUpvarsIfFlatClosure();
|
||||
|
||||
inline bool hasMethodObj(const JSObject& obj) const;
|
||||
inline void setMethodObj(JSObject& obj);
|
||||
|
||||
|
@ -525,6 +525,37 @@ JSObject::getFlatClosureUpvars() const
|
||||
return (js::Value *) getSlot(JSSLOT_FLAT_CLOSURE_UPVARS).toPrivate();
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::finalizeUpvarsIfFlatClosure()
|
||||
{
|
||||
/*
|
||||
* Cloned function objects may be flat closures with upvars to free.
|
||||
*
|
||||
* We do not record in the closure objects any flags. Rather we use flags
|
||||
* stored in the compiled JSFunction that we get via getFunctionPrivate()
|
||||
* to distinguish between closure types. Then during finalization we must
|
||||
* ensure that the compiled JSFunction always finalized after the closures
|
||||
* so we can safely access it here. Currently the GC ensures that through
|
||||
* finalizing JSFunction instances after finalizing any other objects even
|
||||
* during the background finalization.
|
||||
*
|
||||
* But we must not access JSScript here that is stored in JSFunction. The
|
||||
* script can be finalized before the function or closure instances. So we
|
||||
* just check if JSSLOT_FLAT_CLOSURE_UPVARS holds a private value encoded
|
||||
* as a double. We must also ignore newborn closures that do not have the
|
||||
* private pointer set.
|
||||
*
|
||||
* FIXME bug 648320 - allocate upvars on the GC heap to avoid doing it
|
||||
* here explicitly.
|
||||
*/
|
||||
JSFunction *fun = getFunctionPrivate();
|
||||
if (fun && fun != this && fun->isFlatClosure()) {
|
||||
const js::Value &v = getSlot(JSSLOT_FLAT_CLOSURE_UPVARS);
|
||||
if (v.isDouble())
|
||||
js::Foreground::free_(v.toPrivate());
|
||||
}
|
||||
}
|
||||
|
||||
inline js::Value
|
||||
JSObject::getFlatClosureUpvar(uint32 i) const
|
||||
{
|
||||
|
@ -372,7 +372,7 @@ AddNodeToFreeList(JSParseNode *pn, js::Parser *parser)
|
||||
/* Catch back-to-back dup recycles. */
|
||||
JS_ASSERT(pn != parser->nodeList);
|
||||
|
||||
/*
|
||||
/*
|
||||
* It's too hard to clear these nodes from the AtomDefnMaps, etc. that
|
||||
* hold references to them, so we never free them. It's our caller's job to
|
||||
* recognize and process these, since their children do need to be dealt
|
||||
@ -585,7 +585,7 @@ PushNodeChildren(JSParseNode *pn, NodeStack *stack)
|
||||
stack->pushUnlessNull(pn->pn_kid);
|
||||
break;
|
||||
case PN_NULLARY:
|
||||
/*
|
||||
/*
|
||||
* E4X function namespace nodes are PN_NULLARY, but can appear on use
|
||||
* lists.
|
||||
*/
|
||||
@ -1123,11 +1123,8 @@ Compiler::compileScript(JSContext *cx, JSObject *scopeChain, StackFrame *callerF
|
||||
|
||||
JS_ASSERT(script->savedCallerFun == savedCallerFun);
|
||||
|
||||
{
|
||||
AutoScriptRooter root(cx, script);
|
||||
if (!defineGlobals(cx, globalScope, script))
|
||||
goto late_error;
|
||||
}
|
||||
if (!defineGlobals(cx, globalScope, script))
|
||||
script = NULL;
|
||||
|
||||
out:
|
||||
JS_FinishArenaPool(&codePool);
|
||||
@ -1137,11 +1134,6 @@ Compiler::compileScript(JSContext *cx, JSObject *scopeChain, StackFrame *callerF
|
||||
|
||||
too_many_slots:
|
||||
parser.reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_TOO_MANY_LOCALS);
|
||||
/* Fall through. */
|
||||
|
||||
late_error:
|
||||
if (script && !script->u.object)
|
||||
js_DestroyScript(cx, script, 7);
|
||||
script = NULL;
|
||||
goto out;
|
||||
}
|
||||
@ -2617,13 +2609,13 @@ Parser::setFunctionKinds(JSFunctionBox *funbox, uint32 *tcflags)
|
||||
* js::Bindings::extensibleParents explain why.
|
||||
*/
|
||||
void
|
||||
Parser::markExtensibleScopeDescendants(JSFunctionBox *funbox, bool hasExtensibleParent)
|
||||
Parser::markExtensibleScopeDescendants(JSFunctionBox *funbox, bool hasExtensibleParent)
|
||||
{
|
||||
for (; funbox; funbox = funbox->siblings) {
|
||||
/*
|
||||
* It would be nice to use FUN_KIND(fun) here to recognize functions
|
||||
* that will never consult their parent chains, and thus don't need
|
||||
* their 'extensible parents' flag set. Filed as bug 619750.
|
||||
* their 'extensible parents' flag set. Filed as bug 619750.
|
||||
*/
|
||||
|
||||
JS_ASSERT(!funbox->bindings.extensibleParents());
|
||||
@ -3229,11 +3221,11 @@ Parser::functionDef(JSAtom *funAtom, FunctionType type, FunctionSyntaxKind kind)
|
||||
* parent to call eval. We need this for two reasons: (1) the Jaegermonkey
|
||||
* optimizations really need to know if eval is called transitively, and
|
||||
* (2) in strict mode, eval called transitively requires eager argument
|
||||
* creation in strict mode parent functions.
|
||||
* creation in strict mode parent functions.
|
||||
*
|
||||
* For the latter, we really only need to propagate callsEval if both
|
||||
* functions are strict mode, but we don't lose much by always propagating.
|
||||
* The only optimization we lose this way is in the case where a function
|
||||
* For the latter, we really only need to propagate callsEval if both
|
||||
* functions are strict mode, but we don't lose much by always propagating.
|
||||
* The only optimization we lose this way is in the case where a function
|
||||
* is strict, does not mutate arguments, does not call eval directly, but
|
||||
* calls eval transitively.
|
||||
*/
|
||||
@ -3732,7 +3724,7 @@ DefineGlobal(JSParseNode *pn, JSCodeGenerator *cg, JSAtom *atom)
|
||||
!shape->hasDefaultSetter()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
def = GlobalScope::GlobalDef(shape->slot);
|
||||
} else {
|
||||
def = GlobalScope::GlobalDef(atom, funbox);
|
||||
@ -6771,7 +6763,7 @@ class CompExprTransplanter {
|
||||
* Use in any context which may turn out to be inside a generator expression. This
|
||||
* includes parenthesized expressions and argument lists, and it includes the tail
|
||||
* of generator expressions.
|
||||
*
|
||||
*
|
||||
* The guard will keep track of any |yield| or |arguments| tokens that occur while
|
||||
* parsing the body. As soon as the parser reaches the end of the body expression,
|
||||
* call endBody() to reset the context's state, and then immediately call:
|
||||
@ -7013,7 +7005,7 @@ CompExprTransplanter::transplant(JSParseNode *pn)
|
||||
return false;
|
||||
dn2->pn_pos = root->pn_pos;
|
||||
|
||||
/*
|
||||
/*
|
||||
* Change all uses of |dn| that lie within the generator's
|
||||
* |yield| expression into uses of dn2.
|
||||
*/
|
||||
|
@ -287,30 +287,30 @@ Bindings::trace(JSTracer *trc)
|
||||
MarkShape(trc, lastBinding, "shape");
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
#ifdef JS_CRASH_DIAGNOSTICS
|
||||
|
||||
static void
|
||||
void
|
||||
CheckScript(JSScript *script, JSScript *prev)
|
||||
{
|
||||
#ifdef JS_CRASH_DIAGNOSTICS
|
||||
if (script->cookie1 != JS_SCRIPT_COOKIE || script->cookie2 != JS_SCRIPT_COOKIE) {
|
||||
crash::StackBuffer<sizeof(JSScript), 0x87> buf1(script);
|
||||
crash::StackBuffer<sizeof(JSScript), 0x88> buf2(prev);
|
||||
JS_OPT_ASSERT(false);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
CheckScriptOwner(JSScript *script, JSObject *owner)
|
||||
{
|
||||
#ifdef JS_CRASH_DIAGNOSTICS
|
||||
JS_OPT_ASSERT(script->ownerObject == owner);
|
||||
if (owner != JS_NEW_SCRIPT && owner != JS_CACHED_SCRIPT)
|
||||
JS_OPT_ASSERT(script->compartment == owner->compartment());
|
||||
#endif
|
||||
JS_OPT_ASSERT(script->compartment() == owner->compartment());
|
||||
}
|
||||
|
||||
#endif /* JS_CRASH_DIAGNOSTICS */
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#if JS_HAS_XDR
|
||||
|
||||
enum ScriptBits {
|
||||
@ -379,7 +379,6 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp)
|
||||
EmptyShape *emptyCallShape = EmptyShape::getEmptyCallShape(cx);
|
||||
if (!emptyCallShape)
|
||||
return false;
|
||||
AutoShapeRooter shapeRoot(cx, emptyCallShape);
|
||||
|
||||
Bindings bindings(cx, emptyCallShape);
|
||||
AutoBindingsRooter rooter(cx, bindings);
|
||||
@ -537,8 +536,6 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp)
|
||||
if (!JS_XDRUint32(xdr, &scriptBits))
|
||||
return JS_FALSE;
|
||||
|
||||
AutoScriptRooter tvr(cx, NULL);
|
||||
|
||||
if (xdr->mode == JSXDR_DECODE) {
|
||||
nClosedArgs = encodedClosedCount >> 16;
|
||||
nClosedVars = encodedClosedCount & 0xFFFF;
|
||||
@ -560,7 +557,6 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp)
|
||||
/* If we know nsrcnotes, we allocated space for notes in script. */
|
||||
notes = script->notes();
|
||||
*scriptp = script;
|
||||
tvr.setScript(script);
|
||||
|
||||
if (scriptBits & (1 << NoScriptRval))
|
||||
script->noScriptRval = true;
|
||||
@ -737,10 +733,8 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp)
|
||||
return JS_TRUE;
|
||||
|
||||
error:
|
||||
if (xdr->mode == JSXDR_DECODE) {
|
||||
js_DestroyScript(cx, script, 1);
|
||||
if (xdr->mode == JSXDR_DECODE)
|
||||
*scriptp = NULL;
|
||||
}
|
||||
xdr->script = oldscript;
|
||||
return JS_FALSE;
|
||||
}
|
||||
@ -768,20 +762,14 @@ JSPCCounters::destroy(JSContext *cx)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
script_finalize(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
JSScript *script = (JSScript *) obj->getPrivate();
|
||||
if (script)
|
||||
js_DestroyScriptFromGC(cx, script, obj);
|
||||
}
|
||||
|
||||
static void
|
||||
script_trace(JSTracer *trc, JSObject *obj)
|
||||
{
|
||||
JSScript *script = (JSScript *) obj->getPrivate();
|
||||
if (script)
|
||||
js_TraceScript(trc, script, obj);
|
||||
if (script) {
|
||||
CheckScriptOwner(script, obj);
|
||||
MarkScript(trc, script, "script");
|
||||
}
|
||||
}
|
||||
|
||||
Class js_ScriptClass = {
|
||||
@ -795,7 +783,7 @@ Class js_ScriptClass = {
|
||||
EnumerateStub,
|
||||
ResolveStub,
|
||||
ConvertStub,
|
||||
script_finalize,
|
||||
NULL, /* finalize */
|
||||
NULL, /* reserved0 */
|
||||
NULL, /* checkAccess */
|
||||
NULL, /* call */
|
||||
@ -922,17 +910,13 @@ JSScript::NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natom
|
||||
EmptyShape *emptyCallShape = EmptyShape::getEmptyCallShape(cx);
|
||||
if (!emptyCallShape)
|
||||
return NULL;
|
||||
AutoShapeRooter shapeRoot(cx, emptyCallShape);
|
||||
|
||||
size_t size, vectorSize;
|
||||
JSScript *script;
|
||||
uint8 *cursor;
|
||||
unsigned constPadding = 0;
|
||||
|
||||
uint32 totalClosed = nClosedArgs + nClosedVars;
|
||||
|
||||
size = sizeof(JSScript) +
|
||||
sizeof(JSAtom *) * natoms;
|
||||
size = sizeof(JSAtom *) * natoms;
|
||||
|
||||
if (nobjects != 0)
|
||||
size += sizeof(JSObjectArray) + nobjects * sizeof(JSObject *);
|
||||
@ -960,15 +944,21 @@ JSScript::NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natom
|
||||
size += length * sizeof(jsbytecode) +
|
||||
nsrcnotes * sizeof(jssrcnote);
|
||||
|
||||
script = (JSScript *) cx->malloc_(size);
|
||||
if (!script)
|
||||
uint8 *data = static_cast<uint8 *>(cx->malloc_(size));
|
||||
if (!data)
|
||||
return NULL;
|
||||
JSScript *script = js_NewGCScript(cx);
|
||||
if (!script) {
|
||||
Foreground::free_(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PodZero(script);
|
||||
#ifdef JS_CRASH_DIAGNOSTICS
|
||||
script->cookie1 = script->cookie2 = JS_SCRIPT_COOKIE;
|
||||
script->ownerObject = JS_NEW_SCRIPT;
|
||||
#endif
|
||||
script->data = data;
|
||||
script->length = length;
|
||||
script->version = version;
|
||||
new (&script->bindings) Bindings(cx, emptyCallShape);
|
||||
@ -976,42 +966,40 @@ JSScript::NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natom
|
||||
if (cx->hasRunOption(JSOPTION_PCCOUNT))
|
||||
(void) script->pcCounters.init(cx, length);
|
||||
|
||||
uint8 *scriptEnd = reinterpret_cast<uint8 *>(script + 1);
|
||||
|
||||
cursor = scriptEnd;
|
||||
uint8 *cursor = data;
|
||||
if (nobjects != 0) {
|
||||
script->objectsOffset = (uint8)(cursor - scriptEnd);
|
||||
script->objectsOffset = (uint8)(cursor - data);
|
||||
cursor += sizeof(JSObjectArray);
|
||||
} else {
|
||||
script->objectsOffset = JSScript::INVALID_OFFSET;
|
||||
}
|
||||
if (nupvars != 0) {
|
||||
script->upvarsOffset = (uint8)(cursor - scriptEnd);
|
||||
script->upvarsOffset = (uint8)(cursor - data);
|
||||
cursor += sizeof(JSUpvarArray);
|
||||
} else {
|
||||
script->upvarsOffset = JSScript::INVALID_OFFSET;
|
||||
}
|
||||
if (nregexps != 0) {
|
||||
script->regexpsOffset = (uint8)(cursor - scriptEnd);
|
||||
script->regexpsOffset = (uint8)(cursor - data);
|
||||
cursor += sizeof(JSObjectArray);
|
||||
} else {
|
||||
script->regexpsOffset = JSScript::INVALID_OFFSET;
|
||||
}
|
||||
if (ntrynotes != 0) {
|
||||
script->trynotesOffset = (uint8)(cursor - scriptEnd);
|
||||
script->trynotesOffset = (uint8)(cursor - data);
|
||||
cursor += sizeof(JSTryNoteArray);
|
||||
} else {
|
||||
script->trynotesOffset = JSScript::INVALID_OFFSET;
|
||||
}
|
||||
if (nglobals != 0) {
|
||||
script->globalsOffset = (uint8)(cursor - scriptEnd);
|
||||
script->globalsOffset = (uint8)(cursor - data);
|
||||
cursor += sizeof(GlobalSlotArray);
|
||||
} else {
|
||||
script->globalsOffset = JSScript::INVALID_OFFSET;
|
||||
}
|
||||
JS_ASSERT(cursor - scriptEnd < 0xFF);
|
||||
JS_ASSERT(cursor - data < 0xFF);
|
||||
if (nconsts != 0) {
|
||||
script->constOffset = (uint8)(cursor - scriptEnd);
|
||||
script->constOffset = (uint8)(cursor - data);
|
||||
cursor += sizeof(JSConstArray);
|
||||
} else {
|
||||
script->constOffset = JSScript::INVALID_OFFSET;
|
||||
@ -1103,12 +1091,7 @@ JSScript::NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natom
|
||||
JS_ASSERT(cursor +
|
||||
length * sizeof(jsbytecode) +
|
||||
nsrcnotes * sizeof(jssrcnote) ==
|
||||
(uint8 *)script + size);
|
||||
|
||||
script->compartment = cx->compartment;
|
||||
#ifdef CHECK_SCRIPT_OWNER
|
||||
script->owner = cx->thread();
|
||||
#endif
|
||||
data + size);
|
||||
|
||||
JS_APPEND_LINK(&script->links, &cx->compartment->scripts);
|
||||
|
||||
@ -1147,9 +1130,7 @@ JSScript::NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
|
||||
return NULL;
|
||||
|
||||
cg->bindings.makeImmutable();
|
||||
AutoShapeRooter shapeRoot(cx, cg->bindings.lastShape());
|
||||
|
||||
/* Now that we have script, error control flow must go to label bad. */
|
||||
script->main += prologLength;
|
||||
memcpy(script->code, CG_PROLOG_BASE(cg), prologLength * sizeof(jsbytecode));
|
||||
memcpy(script->main, CG_BASE(cg), mainLength * sizeof(jsbytecode));
|
||||
@ -1164,12 +1145,12 @@ JSScript::NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
|
||||
if (filename) {
|
||||
script->filename = SaveScriptFilename(cx, filename);
|
||||
if (!script->filename)
|
||||
goto bad;
|
||||
return NULL;
|
||||
}
|
||||
script->lineno = cg->firstLine;
|
||||
if (script->nfixed + cg->maxStackDepth >= JS_BIT(16)) {
|
||||
ReportCompileErrorNumber(cx, CG_TS(cg), NULL, JSREPORT_ERROR, JSMSG_NEED_DIET, "script");
|
||||
goto bad;
|
||||
return NULL;
|
||||
}
|
||||
script->nslots = script->nfixed + cg->maxStackDepth;
|
||||
script->staticLevel = uint16(cg->staticLevel);
|
||||
@ -1180,7 +1161,7 @@ JSScript::NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
|
||||
script->sourceMap = (jschar *) cg->parser->tokenStream.releaseSourceMap();
|
||||
|
||||
if (!js_FinishTakingSrcNotes(cx, cg, script->notes()))
|
||||
goto bad;
|
||||
return NULL;
|
||||
if (cg->ntrynotes != 0)
|
||||
js_FinishTakingTryNotes(cg, script->trynotes());
|
||||
if (cg->objectList.length != 0)
|
||||
@ -1247,9 +1228,6 @@ JSScript::NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
|
||||
#endif
|
||||
fun->u.i.script = script;
|
||||
script->setOwnerObject(fun);
|
||||
#ifdef CHECK_SCRIPT_OWNER
|
||||
script->owner = NULL;
|
||||
#endif
|
||||
if (cg->flags & TCF_FUN_HEAVYWEIGHT)
|
||||
fun->flags |= JSFUN_HEAVYWEIGHT;
|
||||
} else {
|
||||
@ -1258,7 +1236,7 @@ JSScript::NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
|
||||
* valid holder object.
|
||||
*/
|
||||
if ((cg->flags & TCF_NEED_SCRIPT_OBJECT) && !js_NewScriptObject(cx, script))
|
||||
goto bad;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Tell the debugger about this compiled script. */
|
||||
@ -1272,20 +1250,14 @@ JSScript::NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
|
||||
}
|
||||
|
||||
return script;
|
||||
|
||||
bad:
|
||||
if (!script->u.object)
|
||||
js_DestroyScript(cx, script, 2);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t
|
||||
JSScript::totalSize()
|
||||
JSScript::dataSize()
|
||||
{
|
||||
return code +
|
||||
length * sizeof(jsbytecode) +
|
||||
numNotes() * sizeof(jssrcnote) -
|
||||
(uint8 *) this;
|
||||
uint8 *dataEnd = code + length * sizeof(jsbytecode) + numNotes() * sizeof(jssrcnote);
|
||||
JS_ASSERT(dataEnd > data);
|
||||
return dataEnd - data;
|
||||
}
|
||||
|
||||
void
|
||||
@ -1314,168 +1286,64 @@ JSScript::numNotes()
|
||||
JS_FRIEND_API(void)
|
||||
js_CallNewScriptHook(JSContext *cx, JSScript *script, JSFunction *fun)
|
||||
{
|
||||
JSNewScriptHook hook;
|
||||
|
||||
hook = cx->debugHooks->newScriptHook;
|
||||
if (hook) {
|
||||
JS_ASSERT(!script->callDestroyHook);
|
||||
if (JSNewScriptHook hook = cx->debugHooks->newScriptHook) {
|
||||
AutoKeepAtoms keep(cx->runtime);
|
||||
hook(cx, script->filename, script->lineno, script, fun,
|
||||
cx->debugHooks->newScriptHookData);
|
||||
}
|
||||
script->callDestroyHook = true;
|
||||
}
|
||||
|
||||
void
|
||||
js_CallDestroyScriptHook(JSContext *cx, JSScript *script)
|
||||
{
|
||||
JSDestroyScriptHook hook;
|
||||
if (!script->callDestroyHook)
|
||||
return;
|
||||
|
||||
hook = cx->debugHooks->destroyScriptHook;
|
||||
if (hook)
|
||||
if (JSDestroyScriptHook hook = cx->debugHooks->destroyScriptHook)
|
||||
hook(cx, script, cx->debugHooks->destroyScriptHookData);
|
||||
script->callDestroyHook = false;
|
||||
Debugger::onDestroyScript(script);
|
||||
JS_ClearScriptTraps(cx, script);
|
||||
}
|
||||
|
||||
static void
|
||||
DestroyScript(JSContext *cx, JSScript *script, JSObject *owner, uint32 caller)
|
||||
void
|
||||
JSScript::finalize(JSContext *cx)
|
||||
{
|
||||
CheckScript(script, NULL);
|
||||
CheckScriptOwner(script, owner);
|
||||
CheckScript(this, NULL);
|
||||
|
||||
if (script->principals)
|
||||
JSPRINCIPALS_DROP(cx, script->principals);
|
||||
js_CallDestroyScriptHook(cx, this);
|
||||
|
||||
GSNCache *gsnCache = GetGSNCache(cx);
|
||||
if (gsnCache->code == script->code)
|
||||
gsnCache->purge();
|
||||
|
||||
/*
|
||||
* Worry about purging the property cache and any compiled traces related
|
||||
* to its bytecode if this script is being destroyed from JS_DestroyScript
|
||||
* or equivalent according to a mandatory "New/Destroy" protocol.
|
||||
*
|
||||
* The GC purges all property caches when regenerating shapes upon shape
|
||||
* generator overflow, so no need in that event to purge just the entries
|
||||
* for this script.
|
||||
*
|
||||
* The GC purges trace-JITted code on every GC activation, not just when
|
||||
* regenerating shapes, so we don't have to purge fragments if the GC is
|
||||
* currently running.
|
||||
*
|
||||
* JS_THREADSAFE note: The code below purges only the current thread's
|
||||
* property cache, so a script not owned by a function or object, which
|
||||
* hands off lifetime management for that script to the GC, must be used by
|
||||
* only one thread over its lifetime.
|
||||
*
|
||||
* This should be an API-compatible change, since a script is never safe
|
||||
* against premature GC if shared among threads without a rooted object
|
||||
* wrapping it to protect the script's mapped atoms against GC. We use
|
||||
* script->owner to enforce this requirement via assertions.
|
||||
*/
|
||||
#ifdef CHECK_SCRIPT_OWNER
|
||||
JS_ASSERT_IF(cx->runtime->gcRunning, !script->owner);
|
||||
#endif
|
||||
|
||||
/* FIXME: bug 506341; would like to do this only if regenerating shapes. */
|
||||
if (!cx->runtime->gcRunning) {
|
||||
JS_PROPERTY_CACHE(cx).purgeForScript(cx, script);
|
||||
|
||||
#ifdef CHECK_SCRIPT_OWNER
|
||||
JS_ASSERT(script->owner == cx->thread());
|
||||
#endif
|
||||
}
|
||||
if (principals)
|
||||
JSPRINCIPALS_DROP(cx, principals);
|
||||
|
||||
#ifdef JS_TRACER
|
||||
if (script->compartment->hasTraceMonitor())
|
||||
PurgeScriptFragments(script->compartment->traceMonitor(), script);
|
||||
if (compartment()->hasTraceMonitor())
|
||||
PurgeScriptFragments(compartment()->traceMonitor(), this);
|
||||
#endif
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
mjit::ReleaseScriptCode(cx, script);
|
||||
mjit::ReleaseScriptCode(cx, this);
|
||||
#endif
|
||||
JS_REMOVE_LINK(&script->links);
|
||||
JS_REMOVE_LINK(&links);
|
||||
|
||||
script->pcCounters.destroy(cx);
|
||||
pcCounters.destroy(cx);
|
||||
|
||||
if (script->sourceMap)
|
||||
cx->free_(script->sourceMap);
|
||||
|
||||
JS_POISON(script, 0xdb, sizeof(JSScript));
|
||||
*(uint32 *)script = caller;
|
||||
cx->free_(script);
|
||||
}
|
||||
|
||||
void
|
||||
js_DestroyScript(JSContext *cx, JSScript *script, uint32 caller)
|
||||
{
|
||||
JS_ASSERT(!cx->runtime->gcRunning);
|
||||
js_CallDestroyScriptHook(cx, script);
|
||||
DestroyScript(cx, script, JS_NEW_SCRIPT, caller);
|
||||
}
|
||||
|
||||
void
|
||||
js_DestroyScriptFromGC(JSContext *cx, JSScript *script, JSObject *owner)
|
||||
{
|
||||
JS_ASSERT(cx->runtime->gcRunning);
|
||||
js_CallDestroyScriptHook(cx, script);
|
||||
DestroyScript(cx, script, owner, 100);
|
||||
}
|
||||
|
||||
void
|
||||
js_DestroyCachedScript(JSContext *cx, JSScript *script)
|
||||
{
|
||||
JS_ASSERT(cx->runtime->gcRunning);
|
||||
DestroyScript(cx, script, JS_CACHED_SCRIPT, 101);
|
||||
}
|
||||
|
||||
void
|
||||
js_TraceScript(JSTracer *trc, JSScript *script, JSObject *owner)
|
||||
{
|
||||
CheckScript(script, NULL);
|
||||
if (owner)
|
||||
CheckScriptOwner(script, owner);
|
||||
if (sourceMap)
|
||||
cx->free_(sourceMap);
|
||||
|
||||
#ifdef JS_CRASH_DIAGNOSTICS
|
||||
JSRuntime *rt = trc->context->runtime;
|
||||
JS_OPT_ASSERT_IF(rt->gcCheckCompartment, script->compartment == rt->gcCheckCompartment);
|
||||
if (data)
|
||||
JS_POISON(data, 0xdb, dataSize());
|
||||
#endif
|
||||
|
||||
JSAtomMap *map = &script->atomMap;
|
||||
MarkAtomRange(trc, map->length, map->vector, "atomMap");
|
||||
|
||||
if (JSScript::isValidOffset(script->objectsOffset)) {
|
||||
JSObjectArray *objarray = script->objects();
|
||||
MarkObjectRange(trc, objarray->length, objarray->vector, "objects");
|
||||
}
|
||||
|
||||
if (JSScript::isValidOffset(script->regexpsOffset)) {
|
||||
JSObjectArray *objarray = script->regexps();
|
||||
MarkObjectRange(trc, objarray->length, objarray->vector, "objects");
|
||||
}
|
||||
|
||||
if (JSScript::isValidOffset(script->constOffset)) {
|
||||
JSConstArray *constarray = script->consts();
|
||||
MarkValueRange(trc, constarray->length, constarray->vector, "consts");
|
||||
}
|
||||
|
||||
if (script->u.object)
|
||||
MarkObject(trc, *script->u.object, "object");
|
||||
|
||||
if (IS_GC_MARKING_TRACER(trc) && script->filename)
|
||||
js_MarkScriptFilename(script->filename);
|
||||
|
||||
script->bindings.trace(trc);
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
mjit::TraceScript(trc, script);
|
||||
#endif
|
||||
cx->free_(data);
|
||||
}
|
||||
|
||||
JSObject *
|
||||
js_NewScriptObject(JSContext *cx, JSScript *script)
|
||||
{
|
||||
AutoScriptRooter root(cx, script);
|
||||
|
||||
JS_ASSERT(!script->u.object);
|
||||
|
||||
JSObject *obj = NewNonFunction<WithProto::Class>(cx, &js_ScriptClass, NULL, NULL);
|
||||
@ -1491,10 +1359,6 @@ js_NewScriptObject(JSContext *cx, JSScript *script)
|
||||
*/
|
||||
obj->clearProto();
|
||||
|
||||
#ifdef CHECK_SCRIPT_OWNER
|
||||
script->owner = NULL;
|
||||
#endif
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
@ -1776,8 +1640,7 @@ private:
|
||||
JSScript *
|
||||
js_CloneScript(JSContext *cx, JSScript *script)
|
||||
{
|
||||
JS_ASSERT(cx->compartment != script->compartment);
|
||||
JS_ASSERT(script->compartment);
|
||||
JS_ASSERT(cx->compartment != script->compartment());
|
||||
|
||||
// serialize script
|
||||
AutoJSXDRState w(JS_XDRNewMem(cx, JSXDR_ENCODE));
|
||||
@ -1817,7 +1680,7 @@ js_CloneScript(JSContext *cx, JSScript *script)
|
||||
return NULL;
|
||||
|
||||
// set the proper principals for the script
|
||||
script->principals = script->compartment->principals;
|
||||
script->principals = script->compartment()->principals;
|
||||
if (script->principals)
|
||||
JSPRINCIPALS_HOLD(cx, script->principals);
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=4 sw=4 et tw=79 ft=cpp:
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
@ -358,10 +358,6 @@ class Bindings {
|
||||
#define JS_OBJECT_ARRAY_SIZE(length) \
|
||||
(offsetof(JSObjectArray, vector) + sizeof(JSObject *) * (length))
|
||||
|
||||
#if defined DEBUG && defined JS_THREADSAFE
|
||||
# define CHECK_SCRIPT_OWNER 1
|
||||
#endif
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
namespace JSC {
|
||||
class ExecutablePool;
|
||||
@ -425,7 +421,7 @@ static const uint32 JS_SCRIPT_COOKIE = 0xc00cee;
|
||||
static JSObject * const JS_NEW_SCRIPT = (JSObject *)0x12345678;
|
||||
static JSObject * const JS_CACHED_SCRIPT = (JSObject *)0x12341234;
|
||||
|
||||
struct JSScript {
|
||||
struct JSScript : public js::gc::Cell {
|
||||
/*
|
||||
* Two successively less primitive ways to make a new JSScript. The first
|
||||
* does *not* call a non-null cx->runtime->newScriptHook -- only the second,
|
||||
@ -447,12 +443,12 @@ struct JSScript {
|
||||
/* FIXME: bug 586181 */
|
||||
JSCList links; /* Links for compartment script list */
|
||||
jsbytecode *code; /* bytecodes and their immediate operands */
|
||||
uint32 length; /* length of code vector */
|
||||
|
||||
#ifdef JS_CRASH_DIAGNOSTICS
|
||||
uint32 cookie1;
|
||||
#endif
|
||||
|
||||
uint8 *data; /* pointer to variable-length data array */
|
||||
uint32 length; /* length of code vector */
|
||||
private:
|
||||
uint16 version; /* JS version under which script was compiled */
|
||||
|
||||
@ -494,11 +490,11 @@ struct JSScript {
|
||||
bool debugMode:1; /* script was compiled in debug mode */
|
||||
bool singleStepMode:1; /* compile script in single-step mode */
|
||||
#endif
|
||||
bool callDestroyHook:1;/* need to call destroy hook */
|
||||
|
||||
jsbytecode *main; /* main entry point, after predef'ing prolog */
|
||||
JSAtomMap atomMap; /* maps immediate index to literal struct */
|
||||
JSCompartment *compartment; /* compartment the script was compiled for */
|
||||
const char *filename; /* source filename or null */
|
||||
JSAtomMap atomMap; /* maps immediate index to literal struct */
|
||||
uint32 lineno; /* base line number of script */
|
||||
uint16 nslots; /* vars plus maximum stack depth */
|
||||
uint16 staticLevel;/* static level for display maintenance */
|
||||
@ -527,12 +523,10 @@ struct JSScript {
|
||||
* explicitly destroyed by the code that created them.
|
||||
*/
|
||||
JSObject *object;
|
||||
JSScript *nextToGC; /* next to GC in rt->scriptsToGC list */
|
||||
} u;
|
||||
|
||||
#ifdef CHECK_SCRIPT_OWNER
|
||||
JSThread *owner; /* for thread-safe life-cycle assertions */
|
||||
#endif
|
||||
/* Hash table chaining for JSCompartment::evalCache. */
|
||||
JSScript *evalHashLink;
|
||||
} u;
|
||||
|
||||
uint32 *closedSlots; /* vector of closed slots; args first, then vars. */
|
||||
|
||||
@ -554,7 +548,14 @@ struct JSScript {
|
||||
|
||||
js::mjit::JITScript *jitNormal; /* Extra JIT info for normal scripts */
|
||||
js::mjit::JITScript *jitCtor; /* Extra JIT info for constructors */
|
||||
#endif
|
||||
|
||||
#if JS_BYTES_PER_WORD == 4 && !defined JS_CRASH_DIAGNOSTICS
|
||||
uint32 gcpad; /* sizeof(JSScript) must be multiple of
|
||||
js::gc::Cell::CellSize. */
|
||||
#endif
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
bool hasJITCode() {
|
||||
return jitNormal || jitCtor;
|
||||
}
|
||||
@ -584,7 +585,7 @@ struct JSScript {
|
||||
JS_FRIEND_API(size_t) jitDataSize();/* Size of the JITScript and all sections */
|
||||
#endif
|
||||
|
||||
JS_FRIEND_API(size_t) totalSize(); /* Size of the JSScript and all sections */
|
||||
JS_FRIEND_API(size_t) dataSize(); /* Size of all data sections */
|
||||
uint32 numNotes(); /* Number of srcnote slots in the srcnotes section */
|
||||
|
||||
/* Script notes are allocated right after the code. */
|
||||
@ -595,32 +596,32 @@ struct JSScript {
|
||||
|
||||
JSObjectArray *objects() {
|
||||
JS_ASSERT(isValidOffset(objectsOffset));
|
||||
return reinterpret_cast<JSObjectArray *>(uintptr_t(this + 1) + objectsOffset);
|
||||
return reinterpret_cast<JSObjectArray *>(data + objectsOffset);
|
||||
}
|
||||
|
||||
JSUpvarArray *upvars() {
|
||||
JS_ASSERT(isValidOffset(upvarsOffset));
|
||||
return reinterpret_cast<JSUpvarArray *>(uintptr_t(this + 1) + upvarsOffset);
|
||||
return reinterpret_cast<JSUpvarArray *>(data + upvarsOffset);
|
||||
}
|
||||
|
||||
JSObjectArray *regexps() {
|
||||
JS_ASSERT(isValidOffset(regexpsOffset));
|
||||
return reinterpret_cast<JSObjectArray *>(uintptr_t(this + 1) + regexpsOffset);
|
||||
return reinterpret_cast<JSObjectArray *>(data + regexpsOffset);
|
||||
}
|
||||
|
||||
JSTryNoteArray *trynotes() {
|
||||
JS_ASSERT(isValidOffset(trynotesOffset));
|
||||
return reinterpret_cast<JSTryNoteArray *>(uintptr_t(this + 1) + trynotesOffset);
|
||||
return reinterpret_cast<JSTryNoteArray *>(data + trynotesOffset);
|
||||
}
|
||||
|
||||
js::GlobalSlotArray *globals() {
|
||||
JS_ASSERT(isValidOffset(globalsOffset));
|
||||
return reinterpret_cast<js::GlobalSlotArray *>(uintptr_t(this + 1) + globalsOffset);
|
||||
return reinterpret_cast<js::GlobalSlotArray *>(data + globalsOffset);
|
||||
}
|
||||
|
||||
JSConstArray *consts() {
|
||||
JS_ASSERT(isValidOffset(constOffset));
|
||||
return reinterpret_cast<JSConstArray *>(uintptr_t(this + 1) + constOffset);
|
||||
return reinterpret_cast<JSConstArray *>(data + constOffset);
|
||||
}
|
||||
|
||||
JSAtom *getAtom(size_t index) {
|
||||
@ -679,8 +680,12 @@ struct JSScript {
|
||||
}
|
||||
|
||||
void copyClosedSlotsTo(JSScript *other);
|
||||
|
||||
void finalize(JSContext *cx);
|
||||
};
|
||||
|
||||
JS_STATIC_ASSERT(sizeof(JSScript) % js::gc::Cell::CellSize== 0);
|
||||
|
||||
#define SHARP_NSLOTS 2 /* [#array, #depth] slots if the script
|
||||
uses sharp variables */
|
||||
|
||||
@ -729,24 +734,31 @@ js_CallNewScriptHook(JSContext *cx, JSScript *script, JSFunction *fun);
|
||||
extern void
|
||||
js_CallDestroyScriptHook(JSContext *cx, JSScript *script);
|
||||
|
||||
/*
|
||||
* The function must be used only outside the GC for a script that was run
|
||||
* only on the current thread.
|
||||
*/
|
||||
extern void
|
||||
js_DestroyScript(JSContext *cx, JSScript *script, uint32 caller);
|
||||
namespace js {
|
||||
|
||||
extern void
|
||||
js_DestroyScriptFromGC(JSContext *cx, JSScript *script, JSObject *owner);
|
||||
#ifdef JS_CRASH_DIAGNOSTICS
|
||||
|
||||
/*
|
||||
* Script objects may be cached and reused, in which case their JSD-visible
|
||||
* lifetimes may be shorter than their actual lifetimes. Destroy one such
|
||||
* script for real as part of a GC pass. From JSD's point of view, the script
|
||||
* is already dead.
|
||||
*/
|
||||
extern void
|
||||
js_DestroyCachedScript(JSContext *cx, JSScript *script);
|
||||
void
|
||||
CheckScriptOwner(JSScript *script, JSObject *owner);
|
||||
|
||||
void
|
||||
CheckScript(JSScript *script, JSScript *prev);
|
||||
|
||||
#else
|
||||
|
||||
inline void
|
||||
CheckScriptOwner(JSScript *script, JSObject *owner)
|
||||
{
|
||||
}
|
||||
|
||||
inline void
|
||||
CheckScript(JSScript *script, JSScript *prev)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* !JS_CRASH_DIAGNOSTICS */
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
extern void
|
||||
js_TraceScript(JSTracer *trc, JSScript *script, JSObject *owner);
|
||||
|
@ -16975,7 +16975,7 @@ LoopProfile::profileOperation(JSContext* cx, JSOp op)
|
||||
TraceMonitor* tm = JS_TRACE_MONITOR_FROM_CONTEXT(cx);
|
||||
|
||||
JS_ASSERT(tm == traceMonitor);
|
||||
JS_ASSERT(entryScript->compartment->traceMonitor() == tm);
|
||||
JS_ASSERT(entryScript->compartment()->traceMonitor() == tm);
|
||||
|
||||
if (profiled) {
|
||||
stopProfiling(cx);
|
||||
|
@ -719,10 +719,8 @@ JS_XDRScriptObject(JSXDRState *xdr, JSObject **scriptObjp)
|
||||
|
||||
if (xdr->mode == JSXDR_DECODE) {
|
||||
*scriptObjp = js_NewScriptObject(xdr->cx, script);
|
||||
if (!*scriptObjp) {
|
||||
js_DestroyScript(xdr->cx, script, 8);
|
||||
if (!*scriptObjp)
|
||||
return false;
|
||||
}
|
||||
js_CallNewScriptHook(xdr->cx, script, NULL);
|
||||
Debugger::onNewScript(xdr->cx, script, *scriptObjp, Debugger::NewHeldScript);
|
||||
}
|
||||
|
@ -147,7 +147,7 @@ class LinkerHelper : public JSC::LinkBuffer
|
||||
// The pool is incref'd after this call, so it's necessary to release()
|
||||
// on any failure.
|
||||
JSScript *script = cx->fp()->script();
|
||||
JSC::ExecutableAllocator *allocator = script->compartment->jaegerCompartment()->execAlloc();
|
||||
JSC::ExecutableAllocator *allocator = script->compartment()->jaegerCompartment()->execAlloc();
|
||||
JSC::ExecutablePool *pool;
|
||||
m_code = executableAllocAndCopy(masm, allocator, &pool);
|
||||
if (!m_code) {
|
||||
|
@ -424,7 +424,7 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
|
||||
|
||||
JSC::ExecutablePool *execPool;
|
||||
uint8 *result =
|
||||
(uint8 *)script->compartment->jaegerCompartment()->execAlloc()->alloc(codeSize, &execPool);
|
||||
(uint8 *)script->compartment()->jaegerCompartment()->execAlloc()->alloc(codeSize, &execPool);
|
||||
if (!result) {
|
||||
js_ReportOutOfMemory(cx);
|
||||
return Compile_Error;
|
||||
@ -4054,7 +4054,7 @@ mjit::Compiler::iter(uintN flags)
|
||||
frame.unpinReg(reg);
|
||||
|
||||
/* Fetch the most recent iterator. */
|
||||
masm.loadPtr(&script->compartment->nativeIterCache.last, ioreg);
|
||||
masm.loadPtr(&script->compartment()->nativeIterCache.last, ioreg);
|
||||
|
||||
/* Test for NULL. */
|
||||
Jump nullIterator = masm.branchTest32(Assembler::Zero, ioreg, ioreg);
|
||||
|
@ -119,14 +119,14 @@ extern "C" void JaegerTrampolineReturn();
|
||||
extern "C" void JS_FASTCALL
|
||||
PushActiveVMFrame(VMFrame &f)
|
||||
{
|
||||
f.entryfp->script()->compartment->jaegerCompartment()->pushActiveFrame(&f);
|
||||
f.entryfp->script()->compartment()->jaegerCompartment()->pushActiveFrame(&f);
|
||||
f.regs.fp()->setNativeReturnAddress(JS_FUNC_TO_DATA_PTR(void*, JaegerTrampolineReturn));
|
||||
}
|
||||
|
||||
extern "C" void JS_FASTCALL
|
||||
PopActiveVMFrame(VMFrame &f)
|
||||
{
|
||||
f.entryfp->script()->compartment->jaegerCompartment()->popActiveFrame();
|
||||
f.entryfp->script()->compartment()->jaegerCompartment()->popActiveFrame();
|
||||
}
|
||||
|
||||
extern "C" void JS_FASTCALL
|
||||
|
@ -128,7 +128,7 @@ Recompiler::recompile()
|
||||
|
||||
// Find all JIT'd stack frames to account for return addresses that will
|
||||
// need to be patched after recompilation.
|
||||
for (VMFrame *f = script->compartment->jaegerCompartment()->activeFrame();
|
||||
for (VMFrame *f = script->compartment()->jaegerCompartment()->activeFrame();
|
||||
f != NULL;
|
||||
f = f->previous) {
|
||||
|
||||
|
@ -236,7 +236,7 @@ BreakpointSite::destroyIfEmpty(JSRuntime *rt, BreakpointSiteMap::Enum *e)
|
||||
if (e)
|
||||
e->removeFront();
|
||||
else
|
||||
script->compartment->breakpointSites.remove(pc);
|
||||
script->compartment()->breakpointSites.remove(pc);
|
||||
rt->delete_(this);
|
||||
}
|
||||
}
|
||||
@ -446,7 +446,7 @@ Debugger::slowPathOnLeaveFrame(JSContext *cx)
|
||||
*/
|
||||
if (fp->isEvalFrame()) {
|
||||
JSScript *script = fp->script();
|
||||
script->compartment->clearBreakpointsIn(cx, NULL, script, NULL);
|
||||
script->compartment()->clearBreakpointsIn(cx, NULL, script, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@ -804,7 +804,7 @@ Debugger::slowPathOnNewScript(JSContext *cx, JSScript *script, JSObject *obj, Ne
|
||||
}
|
||||
} else {
|
||||
global = NULL;
|
||||
GlobalObjectSet &debuggees = script->compartment->getDebuggees();
|
||||
GlobalObjectSet &debuggees = script->compartment()->getDebuggees();
|
||||
for (GlobalObjectSet::Range r = debuggees.all(); !r.empty(); r.popFront()) {
|
||||
if (!AddNewScriptRecipients(r.front()->getDebuggers(), &triggered))
|
||||
return;
|
||||
@ -1742,8 +1742,8 @@ JSObject *
|
||||
Debugger::wrapHeldScript(JSContext *cx, JSScript *script, JSObject *obj)
|
||||
{
|
||||
assertSameCompartment(cx, object);
|
||||
JS_ASSERT(cx->compartment != script->compartment);
|
||||
JS_ASSERT(script->compartment == obj->compartment());
|
||||
JS_ASSERT(cx->compartment != script->compartment());
|
||||
JS_ASSERT(script->compartment() == obj->compartment());
|
||||
|
||||
ScriptWeakMap::AddPtr p = heldScripts.lookupForAdd(obj);
|
||||
if (!p) {
|
||||
@ -1775,7 +1775,7 @@ JSObject *
|
||||
Debugger::wrapNonHeldScript(JSContext *cx, JSScript *script)
|
||||
{
|
||||
assertSameCompartment(cx, object);
|
||||
JS_ASSERT(cx->compartment != script->compartment);
|
||||
JS_ASSERT(cx->compartment != script->compartment());
|
||||
|
||||
ScriptMap::AddPtr p = nonHeldScripts.lookupForAdd(script);
|
||||
if (!p) {
|
||||
@ -1794,7 +1794,7 @@ void
|
||||
Debugger::slowPathOnDestroyScript(JSScript *script)
|
||||
{
|
||||
/* Find all debuggers that might have Debugger.Script referring to this script. */
|
||||
js::GlobalObjectSet *debuggees = &script->compartment->getDebuggees();
|
||||
js::GlobalObjectSet *debuggees = &script->compartment()->getDebuggees();
|
||||
for (GlobalObjectSet::Range r = debuggees->all(); !r.empty(); r.popFront()) {
|
||||
GlobalObject::DebuggerVector *debuggers = r.front()->getDebuggers();
|
||||
for (Debugger **p = debuggers->begin(); p != debuggers->end(); p++)
|
||||
@ -2239,7 +2239,7 @@ DebuggerScript_setBreakpoint(JSContext *cx, uintN argc, Value *vp)
|
||||
if (!handler)
|
||||
return false;
|
||||
|
||||
JSCompartment *comp = script->compartment;
|
||||
JSCompartment *comp = script->compartment();
|
||||
jsbytecode *pc = script->code + offset;
|
||||
BreakpointSite *site = comp->getOrCreateBreakpointSite(cx, script, pc, holder);
|
||||
if (!site)
|
||||
@ -2274,7 +2274,7 @@ DebuggerScript_getBreakpoints(JSContext *cx, uintN argc, Value *vp)
|
||||
JSObject *arr = NewDenseEmptyArray(cx);
|
||||
if (!arr)
|
||||
return false;
|
||||
JSCompartment *comp = script->compartment;
|
||||
JSCompartment *comp = script->compartment();
|
||||
for (BreakpointSiteMap::Range r = comp->breakpointSites.all(); !r.empty(); r.popFront()) {
|
||||
BreakpointSite *site = r.front().value;
|
||||
if (site->script == script && (!pc || site->pc == pc)) {
|
||||
@ -2302,7 +2302,7 @@ DebuggerScript_clearBreakpoint(JSContext *cx, uintN argc, Value *vp)
|
||||
if (!handler)
|
||||
return false;
|
||||
|
||||
script->compartment->clearBreakpointsIn(cx, dbg, script, handler);
|
||||
script->compartment()->clearBreakpointsIn(cx, dbg, script, handler);
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
@ -2312,7 +2312,7 @@ DebuggerScript_clearAllBreakpoints(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
THIS_DEBUGSCRIPT_LIVE_SCRIPT(cx, argc, vp, "clearBreakpoint", args, obj, script);
|
||||
Debugger *dbg = Debugger::fromChildJSObject(obj);
|
||||
script->compartment->clearBreakpointsIn(cx, dbg, script, NULL);
|
||||
script->compartment()->clearBreakpointsIn(cx, dbg, script, NULL);
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
@ -2672,8 +2672,8 @@ EvaluateInScope(JSContext *cx, JSObject *scobj, StackFrame *fp, const jschar *ch
|
||||
if (!script)
|
||||
return false;
|
||||
|
||||
bool ok = Execute(cx, script, *scobj, fp->thisValue(), EXECUTE_DEBUG, fp, rval);
|
||||
js_DestroyScript(cx, script, 6);
|
||||
JSBool ok = Execute(cx, script, *scobj, fp->thisValue(), EXECUTE_DEBUG, fp, rval);
|
||||
js_CallDestroyScriptHook(cx, script);
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
@ -548,14 +548,14 @@ void
|
||||
Debugger::onNewScript(JSContext *cx, JSScript *script, JSObject *obj, NewScriptKind kind)
|
||||
{
|
||||
JS_ASSERT_IF(kind == NewHeldScript || script->compileAndGo, obj);
|
||||
if (!script->compartment->getDebuggees().empty())
|
||||
if (!script->compartment()->getDebuggees().empty())
|
||||
slowPathOnNewScript(cx, script, obj, kind);
|
||||
}
|
||||
|
||||
void
|
||||
Debugger::onDestroyScript(JSScript *script)
|
||||
{
|
||||
if (!script->compartment->getDebuggees().empty())
|
||||
if (!script->compartment()->getDebuggees().empty())
|
||||
slowPathOnDestroyScript(script);
|
||||
}
|
||||
|
||||
|
@ -831,7 +831,7 @@ class StackFrame
|
||||
*/
|
||||
|
||||
JSCompartment *compartment() const {
|
||||
JS_ASSERT_IF(isScriptFrame(), scopeChain().compartment() == script()->compartment);
|
||||
JS_ASSERT_IF(isScriptFrame(), scopeChain().compartment() == script()->compartment());
|
||||
return scopeChain().compartment();
|
||||
}
|
||||
|
||||
|
@ -873,11 +873,14 @@ nsXPConnect::Traverse(void *p, nsCycleCollectionTraversalCallback &cb)
|
||||
}
|
||||
else
|
||||
{
|
||||
static const char trace_types[JSTRACE_LIMIT][7] = {
|
||||
static const char trace_types[][7] = {
|
||||
"Object",
|
||||
"String",
|
||||
"Shape",
|
||||
"Script",
|
||||
"Xml"
|
||||
};
|
||||
JS_STATIC_ASSERT(JS_ARRAY_LENGTH(trace_types) == JSTRACE_LIMIT);
|
||||
JS_snprintf(name, sizeof(name), "JS %s", trace_types[traceKind]);
|
||||
}
|
||||
|
||||
|
@ -226,7 +226,7 @@ static JSDHashOperator
|
||||
DetachedWrappedNativeProtoMarker(JSDHashTable *table, JSDHashEntryHdr *hdr,
|
||||
uint32 number, void *arg)
|
||||
{
|
||||
XPCWrappedNativeProto* proto =
|
||||
XPCWrappedNativeProto* proto =
|
||||
(XPCWrappedNativeProto*)((JSDHashEntryStub*)hdr)->key;
|
||||
|
||||
proto->Mark();
|
||||
@ -510,7 +510,7 @@ XPCJSRuntime::SuspectWrappedNative(JSContext *cx, XPCWrappedNative *wrapper,
|
||||
if(!wrapper->IsValid() || wrapper->IsWrapperExpired())
|
||||
return;
|
||||
|
||||
NS_ASSERTION(NS_IsMainThread() || NS_IsCycleCollectorThread(),
|
||||
NS_ASSERTION(NS_IsMainThread() || NS_IsCycleCollectorThread(),
|
||||
"Suspecting wrapped natives from non-CC thread");
|
||||
|
||||
// Only suspect wrappedJSObjects that are in a compartment that
|
||||
@ -850,7 +850,7 @@ JSBool XPCJSRuntime::GCCallback(JSContext *cx, JSGCStatus status)
|
||||
if(threadLock)
|
||||
{
|
||||
// Do the marking...
|
||||
|
||||
|
||||
{ // scoped lock
|
||||
MutexAutoLock lock(*threadLock);
|
||||
|
||||
@ -869,7 +869,7 @@ JSBool XPCJSRuntime::GCCallback(JSContext *cx, JSGCStatus status)
|
||||
// possibly be valid.
|
||||
if(ccxp->CanGetTearOff())
|
||||
{
|
||||
XPCWrappedNativeTearOff* to =
|
||||
XPCWrappedNativeTearOff* to =
|
||||
ccxp->GetTearOff();
|
||||
if(to)
|
||||
to->Mark();
|
||||
@ -1041,7 +1041,7 @@ static JSDHashOperator
|
||||
DetachedWrappedNativeProtoShutdownMarker(JSDHashTable *table, JSDHashEntryHdr *hdr,
|
||||
uint32 number, void *arg)
|
||||
{
|
||||
XPCWrappedNativeProto* proto =
|
||||
XPCWrappedNativeProto* proto =
|
||||
(XPCWrappedNativeProto*)((JSDHashEntryStub*)hdr)->key;
|
||||
|
||||
proto->SystemIsBeingShutDown((JSContext*)arg);
|
||||
@ -1249,42 +1249,6 @@ XPCJSRuntime::~XPCJSRuntime()
|
||||
|
||||
namespace {
|
||||
|
||||
PRInt64
|
||||
GetCompartmentScriptsSize(JSCompartment *c)
|
||||
{
|
||||
PRInt64 n = 0;
|
||||
for(JSScript *script = (JSScript *)c->scripts.next;
|
||||
&script->links != &c->scripts;
|
||||
script = (JSScript *)script->links.next)
|
||||
{
|
||||
n += script->totalSize();
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
|
||||
PRInt64
|
||||
GetCompartmentMjitCodeSize(JSCompartment *c)
|
||||
{
|
||||
return c->getMjitCodeSize();
|
||||
}
|
||||
|
||||
PRInt64
|
||||
GetCompartmentMjitDataSize(JSCompartment *c)
|
||||
{
|
||||
PRInt64 n = 0;
|
||||
for(JSScript *script = (JSScript *)c->scripts.next;
|
||||
&script->links != &c->scripts;
|
||||
script = (JSScript *)script->links.next)
|
||||
{
|
||||
n += script->jitDataSize();
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
#endif // JS_METHODJIT
|
||||
|
||||
#ifdef JS_TRACER
|
||||
|
||||
PRInt64
|
||||
@ -1336,10 +1300,8 @@ CompartmentCallback(JSContext *cx, void *vdata, JSCompartment *compartment)
|
||||
data->currCompartmentStats = curr;
|
||||
|
||||
// Get the compartment-level numbers.
|
||||
curr->scripts = GetCompartmentScriptsSize(compartment);
|
||||
#ifdef JS_METHODJIT
|
||||
curr->mjitCode = GetCompartmentMjitCodeSize(compartment);
|
||||
curr->mjitData = GetCompartmentMjitDataSize(compartment);
|
||||
curr->mjitCode = compartment->getMjitCodeSize();
|
||||
#endif
|
||||
#ifdef JS_TRACER
|
||||
curr->tjitCode = GetCompartmentTjitCodeSize(compartment);
|
||||
@ -1371,30 +1333,43 @@ CellCallback(JSContext *cx, void *vdata, void *thing, size_t traceKind,
|
||||
{
|
||||
IterateData *data = static_cast<IterateData *>(vdata);
|
||||
CompartmentStats *curr = data->currCompartmentStats;
|
||||
if(traceKind == JSTRACE_OBJECT)
|
||||
curr->gcHeapKinds[traceKind] += thingSize;
|
||||
switch (traceKind)
|
||||
{
|
||||
curr->gcHeapObjects += thingSize;
|
||||
JSObject *obj = static_cast<JSObject *>(thing);
|
||||
if(obj->hasSlotsArray())
|
||||
curr->objectSlots += obj->numSlots() * sizeof(js::Value);
|
||||
}
|
||||
else if(traceKind == JSTRACE_STRING)
|
||||
{
|
||||
curr->gcHeapStrings += thingSize;
|
||||
JSString *str = static_cast<JSString *>(thing);
|
||||
curr->stringChars += str->charsHeapSize();
|
||||
}
|
||||
else if(traceKind == JSTRACE_SHAPE)
|
||||
{
|
||||
curr->gcHeapShapes += thingSize;
|
||||
js::Shape *shape = static_cast<js::Shape *>(thing);
|
||||
if(shape->hasTable())
|
||||
curr->propertyTables += shape->getTable()->sizeOf();
|
||||
}
|
||||
else
|
||||
{
|
||||
JS_ASSERT(traceKind == JSTRACE_XML);
|
||||
curr->gcHeapXml += thingSize;
|
||||
case JSTRACE_OBJECT:
|
||||
{
|
||||
JSObject *obj = static_cast<JSObject *>(thing);
|
||||
if(obj->hasSlotsArray())
|
||||
curr->objectSlots += obj->numSlots() * sizeof(js::Value);
|
||||
break;
|
||||
}
|
||||
case JSTRACE_STRING:
|
||||
{
|
||||
JSString *str = static_cast<JSString *>(thing);
|
||||
curr->stringChars += str->charsHeapSize();
|
||||
break;
|
||||
}
|
||||
case JSTRACE_SHAPE:
|
||||
{
|
||||
js::Shape *shape = static_cast<js::Shape *>(thing);
|
||||
if(shape->hasTable())
|
||||
curr->propertyTables += shape->getTable()->sizeOf();
|
||||
break;
|
||||
}
|
||||
case JSTRACE_SCRIPT:
|
||||
{
|
||||
JSScript *script = static_cast<JSScript *>(thing);
|
||||
curr->scriptData += script->dataSize();
|
||||
#ifdef JS_METHODJIT
|
||||
curr->mjitData += script->jitDataSize();
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
JS_ASSERT(traceKind == JSTRACE_XML);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Yes, this is a subtraction: see ArenaCallback() for details.
|
||||
curr->gcHeapArenaUnused -= thingSize;
|
||||
@ -1651,12 +1626,13 @@ CollectCompartmentStatsForRuntime(JSRuntime *rt, IterateData *data)
|
||||
{
|
||||
CompartmentStats &stats = data->compartmentStatsVector[index];
|
||||
|
||||
data->gcHeapChunkDirtyUnused -=
|
||||
stats.gcHeapArenaHeaders + stats.gcHeapArenaPadding +
|
||||
stats.gcHeapArenaUnused +
|
||||
stats.gcHeapObjects + stats.gcHeapStrings +
|
||||
stats.gcHeapShapes + stats.gcHeapXml;
|
||||
|
||||
PRInt64 used = stats.gcHeapArenaHeaders +
|
||||
stats.gcHeapArenaPadding +
|
||||
stats.gcHeapArenaUnused;
|
||||
for (size_t i = 0; i != JS_ARRAY_LENGTH(stats.gcHeapKinds); ++i)
|
||||
used += stats.gcHeapKinds[i];
|
||||
|
||||
data->gcHeapChunkDirtyUnused -= used;
|
||||
data->gcHeapArenaUnused += stats.gcHeapArenaUnused;
|
||||
}
|
||||
|
||||
@ -1667,7 +1643,7 @@ CollectCompartmentStatsForRuntime(JSRuntime *rt, IterateData *data)
|
||||
sizeof(js::gc::Chunk) - (sizeof(js::gc::Arena) * js::gc::ArenasPerChunk);
|
||||
data->gcHeapChunkAdmin = numDirtyChunks * perChunkAdmin;
|
||||
data->gcHeapChunkDirtyUnused -= data->gcHeapChunkAdmin;
|
||||
|
||||
|
||||
// Why 10000x? 100x because it's a percentage, and another 100x
|
||||
// because nsIMemoryReporter requires that for percentage amounts so
|
||||
// they can be fractional.
|
||||
@ -1709,14 +1685,14 @@ ReportCompartmentStats(const CompartmentStats &stats,
|
||||
|
||||
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
|
||||
"gc-heap/objects"),
|
||||
JS_GC_HEAP_KIND, stats.gcHeapObjects,
|
||||
JS_GC_HEAP_KIND, stats.gcHeapKinds[JSTRACE_OBJECT],
|
||||
"Memory on the compartment's garbage-collected JavaScript heap that holds "
|
||||
"objects.",
|
||||
callback, closure);
|
||||
|
||||
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
|
||||
"gc-heap/strings"),
|
||||
JS_GC_HEAP_KIND, stats.gcHeapStrings,
|
||||
JS_GC_HEAP_KIND, stats.gcHeapKinds[JSTRACE_STRING],
|
||||
"Memory on the compartment's garbage-collected JavaScript heap that holds "
|
||||
"string headers. String headers contain various pieces of information "
|
||||
"about a string, but do not contain (except in the case of very short "
|
||||
@ -1726,15 +1702,23 @@ ReportCompartmentStats(const CompartmentStats &stats,
|
||||
|
||||
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
|
||||
"gc-heap/shapes"),
|
||||
JS_GC_HEAP_KIND, stats.gcHeapShapes,
|
||||
JS_GC_HEAP_KIND, stats.gcHeapKinds[JSTRACE_SHAPE],
|
||||
"Memory on the compartment's garbage-collected JavaScript heap that holds "
|
||||
"shapes. A shape is an internal data structure that makes JavaScript "
|
||||
"property accesses fast.",
|
||||
callback, closure);
|
||||
|
||||
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
|
||||
"gc-heap/scripts"),
|
||||
JS_GC_HEAP_KIND, stats.gcHeapKinds[JSTRACE_SCRIPT],
|
||||
"Memory on the compartment's garbage-collected JavaScript heap that holds "
|
||||
"JSScript instances. A JSScript is created for each user-defined function "
|
||||
"in a script. One is also created for the top-level code in a script.",
|
||||
callback, closure);
|
||||
|
||||
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
|
||||
"gc-heap/xml"),
|
||||
JS_GC_HEAP_KIND, stats.gcHeapXml,
|
||||
JS_GC_HEAP_KIND, stats.gcHeapKinds[JSTRACE_XML],
|
||||
"Memory on the compartment's garbage-collected JavaScript heap that holds "
|
||||
"E4X XML objects.",
|
||||
callback, closure);
|
||||
@ -1768,12 +1752,10 @@ ReportCompartmentStats(const CompartmentStats &stats,
|
||||
callback, closure);
|
||||
|
||||
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
|
||||
"scripts"),
|
||||
nsIMemoryReporter::KIND_HEAP, stats.scripts,
|
||||
"Memory allocated for the compartment's JSScripts. A JSScript is created "
|
||||
"for each user-defined function in a script. One is also created for "
|
||||
"the top-level code in a script. Each JSScript includes byte-code and "
|
||||
"various other things.",
|
||||
"script-data"),
|
||||
nsIMemoryReporter::KIND_HEAP, stats.scriptData,
|
||||
"Memory allocated for JSScript bytecode and various variable-length "
|
||||
"tables.",
|
||||
callback, closure);
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
|
@ -201,16 +201,13 @@ struct CompartmentStats
|
||||
PRInt64 gcHeapArenaPadding;
|
||||
PRInt64 gcHeapArenaUnused;
|
||||
|
||||
PRInt64 gcHeapObjects;
|
||||
PRInt64 gcHeapStrings;
|
||||
PRInt64 gcHeapShapes;
|
||||
PRInt64 gcHeapXml;
|
||||
PRInt64 gcHeapKinds[JSTRACE_LIMIT];
|
||||
|
||||
PRInt64 objectSlots;
|
||||
PRInt64 stringChars;
|
||||
PRInt64 propertyTables;
|
||||
PRInt64 scriptData;
|
||||
|
||||
PRInt64 scripts;
|
||||
#ifdef JS_METHODJIT
|
||||
PRInt64 mjitCode;
|
||||
PRInt64 mjitData;
|
||||
|
Loading…
Reference in New Issue
Block a user