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,bhackett1024
This commit is contained in:
parent
66072d5ad9
commit
486ba2f469
@ -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
|
||||
|
@ -308,7 +308,7 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
|
||||
|
||||
PodZero(escapedSlots, numSlots);
|
||||
|
||||
if (script->usesEval || script->usesArguments || script->compartment->debugMode()) {
|
||||
if (script->usesEval || script->usesArguments || script->compartment()->debugMode()) {
|
||||
for (unsigned i = 0; i < nargs; i++)
|
||||
escapedSlots[ArgSlot(i)] = true;
|
||||
} else {
|
||||
@ -319,7 +319,7 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
|
||||
}
|
||||
}
|
||||
|
||||
if (script->usesEval || script->compartment->debugMode()) {
|
||||
if (script->usesEval || script->compartment()->debugMode()) {
|
||||
for (unsigned i = 0; i < script->nfixed; i++) {
|
||||
escapedSlots[LocalSlot(script, i)] = true;
|
||||
setLocal(i, LOCAL_USE_BEFORE_DEF);
|
||||
@ -612,7 +612,7 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
|
||||
JSTryNote *tn = script->trynotes()->vector;
|
||||
JSTryNote *tnlimit = tn + script->trynotes()->length;
|
||||
for (; tn < tnlimit; tn++) {
|
||||
unsigned startOffset = script->main - script->code + tn->start;
|
||||
unsigned startOffset = script->mainOffset + tn->start;
|
||||
if (startOffset == offset + 1) {
|
||||
unsigned catchOffset = startOffset + tn->length;
|
||||
|
||||
@ -894,7 +894,7 @@ ScriptAnalysis::analyzeLifetimes(JSContext *cx)
|
||||
JSTryNote *tn = script->trynotes()->vector;
|
||||
JSTryNote *tnlimit = tn + script->trynotes()->length;
|
||||
for (; tn < tnlimit; tn++) {
|
||||
unsigned startOffset = script->main - script->code + tn->start;
|
||||
unsigned startOffset = script->mainOffset + tn->start;
|
||||
if (startOffset + tn->length == offset) {
|
||||
/*
|
||||
* Extend all live variables at exception entry to the start of
|
||||
@ -1674,7 +1674,7 @@ ScriptAnalysis::analyzeSSA(JSContext *cx)
|
||||
JSTryNote *tn = script->trynotes()->vector;
|
||||
JSTryNote *tnlimit = tn + script->trynotes()->length;
|
||||
for (; tn < tnlimit; tn++) {
|
||||
unsigned startOffset = script->main - script->code + tn->start;
|
||||
unsigned startOffset = script->mainOffset + tn->start;
|
||||
if (startOffset == offset + 1) {
|
||||
unsigned catchOffset = startOffset + tn->length;
|
||||
|
||||
|
@ -952,7 +952,7 @@ class ScriptAnalysis
|
||||
/* Accessors for bytecode information. */
|
||||
|
||||
Bytecode& getCode(uint32 offset) {
|
||||
JS_ASSERT(script->compartment->activeAnalysis);
|
||||
JS_ASSERT(script->compartment()->activeAnalysis);
|
||||
JS_ASSERT(offset < script->length);
|
||||
JS_ASSERT(codeArray[offset]);
|
||||
return *codeArray[offset];
|
||||
@ -960,7 +960,7 @@ class ScriptAnalysis
|
||||
Bytecode& getCode(const jsbytecode *pc) { return getCode(pc - script->code); }
|
||||
|
||||
Bytecode* maybeCode(uint32 offset) {
|
||||
JS_ASSERT(script->compartment->activeAnalysis);
|
||||
JS_ASSERT(script->compartment()->activeAnalysis);
|
||||
JS_ASSERT(offset < script->length);
|
||||
return codeArray[offset];
|
||||
}
|
||||
@ -1148,7 +1148,7 @@ class ScriptAnalysis
|
||||
* containing script (which does not imply the variable is closed).
|
||||
*/
|
||||
bool slotEscapes(uint32 slot) {
|
||||
JS_ASSERT(script->compartment->activeAnalysis);
|
||||
JS_ASSERT(script->compartment()->activeAnalysis);
|
||||
if (slot >= numSlots)
|
||||
return true;
|
||||
return escapedSlots[slot];
|
||||
@ -1163,7 +1163,7 @@ class ScriptAnalysis
|
||||
bool trackSlot(uint32 slot) { return !slotEscapes(slot) && canTrackVars; }
|
||||
|
||||
const LifetimeVariable & liveness(uint32 slot) {
|
||||
JS_ASSERT(script->compartment->activeAnalysis);
|
||||
JS_ASSERT(script->compartment()->activeAnalysis);
|
||||
JS_ASSERT(!slotEscapes(slot));
|
||||
return lifetimes[slot];
|
||||
}
|
||||
|
@ -1211,7 +1211,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;
|
||||
@ -1261,7 +1261,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;
|
||||
}
|
||||
@ -2195,7 +2195,8 @@ JS_PUBLIC_API(void)
|
||||
JS_CallTracer(JSTracer *trc, void *thing, uint32 kind)
|
||||
{
|
||||
JS_ASSERT(thing);
|
||||
MarkKind(trc, thing, kind);
|
||||
JS_ASSERT(kind <= JSTRACE_LAST);
|
||||
MarkKind(trc, thing, JSGCTraceKind(kind));
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
@ -2205,9 +2206,11 @@ JS_CallTracer(JSTracer *trc, void *thing, uint32 kind)
|
||||
#endif
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc, void *thing, uint32 kind,
|
||||
JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc, void *thing, uint32 kindIndex,
|
||||
JSBool details)
|
||||
{
|
||||
JS_ASSERT(kindIndex <= JSTRACE_LAST);
|
||||
JSGCTraceKind kind = JSGCTraceKind(kindIndex);
|
||||
const char *name;
|
||||
size_t n;
|
||||
|
||||
@ -2240,19 +2243,23 @@ JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc, void *thing, ui
|
||||
: "string";
|
||||
break;
|
||||
|
||||
case JSTRACE_SCRIPT:
|
||||
name = "script";
|
||||
break;
|
||||
|
||||
case JSTRACE_SHAPE:
|
||||
name = "shape";
|
||||
break;
|
||||
|
||||
case JSTRACE_TYPE_OBJECT:
|
||||
name = "type_object";
|
||||
break;
|
||||
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
case JSTRACE_XML:
|
||||
name = "xml";
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
JS_ASSERT(0);
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
n = strlen(name);
|
||||
@ -2299,12 +2306,17 @@ JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc, void *thing, ui
|
||||
break;
|
||||
}
|
||||
|
||||
case JSTRACE_SHAPE:
|
||||
case JSTRACE_SCRIPT:
|
||||
{
|
||||
JS_snprintf(buf, bufsize, "<shape>");
|
||||
JSScript *script = static_cast<JSScript *>(thing);
|
||||
JS_snprintf(buf, bufsize, "%s:%u", script->filename, unsigned(script->lineno));
|
||||
break;
|
||||
}
|
||||
|
||||
case JSTRACE_SHAPE:
|
||||
case JSTRACE_TYPE_OBJECT:
|
||||
break;
|
||||
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
case JSTRACE_XML:
|
||||
{
|
||||
@ -2315,9 +2327,6 @@ JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc, void *thing, ui
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
JS_ASSERT(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
buf[bufsize - 1] = '\0';
|
||||
@ -3206,7 +3215,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);
|
||||
}
|
||||
@ -4743,7 +4751,6 @@ CompileUCFunctionForPrincipalsCommon(JSContext *cx, JSObject *obj,
|
||||
}
|
||||
|
||||
Bindings bindings(cx);
|
||||
AutoBindingsRooter root(cx, bindings);
|
||||
for (uintN i = 0; i < nargs; i++) {
|
||||
uint16 dummy;
|
||||
JSAtom *argAtom = js_Atomize(cx, argnames[i], strlen(argnames[i]));
|
||||
@ -4842,8 +4849,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,
|
||||
|
@ -1601,16 +1601,25 @@ JS_SetExtraGCRoots(JSRuntime *rt, JSTraceDataOp traceOp, void *data);
|
||||
* other strong ref identified for debugging purposes by name or index or
|
||||
* a naming callback.
|
||||
*
|
||||
* By definition references to traceable things include non-null pointers
|
||||
* to JSObject, JSString and jsdouble and corresponding jsvals.
|
||||
*
|
||||
* See the JSTraceOp typedef in jspubtd.h.
|
||||
*/
|
||||
|
||||
/* Trace kinds to pass to JS_Tracing. */
|
||||
#define JSTRACE_OBJECT 0
|
||||
#define JSTRACE_STRING 1
|
||||
#define JSTRACE_SHAPE 2
|
||||
typedef enum {
|
||||
JSTRACE_OBJECT,
|
||||
JSTRACE_STRING,
|
||||
JSTRACE_SCRIPT,
|
||||
|
||||
/*
|
||||
* Trace kinds internal to the engine. JSTraceCallback implementation can
|
||||
* only call JS_TraceChildren on them.
|
||||
*/
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
JSTRACE_XML,
|
||||
#endif
|
||||
JSTRACE_SHAPE,
|
||||
JSTRACE_TYPE_OBJECT,
|
||||
JSTRACE_LAST = JSTRACE_TYPE_OBJECT
|
||||
} JSGCTraceKind;
|
||||
|
||||
/*
|
||||
* Use the following macros to check if a particular jsval is a traceable
|
||||
|
@ -645,19 +645,16 @@ js_DumpAtoms(JSContext *cx, FILE *fp)
|
||||
JS_STATIC_ASSERT(TEMP_SIZE_START >= sizeof(JSHashTable));
|
||||
|
||||
void
|
||||
js_InitAtomMap(JSContext *cx, JSAtomMap *map, AtomIndexMap *indices)
|
||||
js_InitAtomMap(JSContext *cx, AtomIndexMap *indices, JSAtom **atoms)
|
||||
{
|
||||
/* Map length must already be initialized. */
|
||||
JS_ASSERT(indices->count() == map->length);
|
||||
|
||||
if (indices->isMap()) {
|
||||
typedef AtomIndexMap::WordMap WordMap;
|
||||
const WordMap &wm = indices->asMap();
|
||||
for (WordMap::Range r = wm.all(); !r.empty(); r.popFront()) {
|
||||
JSAtom *atom = r.front().key;
|
||||
jsatomid index = r.front().value;
|
||||
JS_ASSERT(index < map->length);
|
||||
map->vector[index] = atom;
|
||||
JS_ASSERT(index < indices->count());
|
||||
atoms[index] = atom;
|
||||
}
|
||||
} else {
|
||||
for (const AtomIndexMap::InlineElem *it = indices->asInline(), *end = indices->inlineEnd();
|
||||
@ -665,8 +662,8 @@ js_InitAtomMap(JSContext *cx, JSAtomMap *map, AtomIndexMap *indices)
|
||||
JSAtom *atom = it->key;
|
||||
if (!atom)
|
||||
continue;
|
||||
JS_ASSERT(it->value < map->length);
|
||||
map->vector[it->value] = atom;
|
||||
JS_ASSERT(it->value < indices->count());
|
||||
atoms[it->value] = atom;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -162,11 +162,6 @@ struct DefaultHasher<jsid>
|
||||
extern const char *
|
||||
js_AtomToPrintableString(JSContext *cx, JSAtom *atom, JSAutoByteString *bytes);
|
||||
|
||||
struct JSAtomMap {
|
||||
JSAtom **vector; /* array of ptrs to indexed atoms */
|
||||
uint32 length; /* count of (to-be-)indexed atoms */
|
||||
};
|
||||
|
||||
namespace js {
|
||||
|
||||
typedef TaggedPointerEntry<JSAtom> AtomStateEntry;
|
||||
@ -542,6 +537,6 @@ js_InternNonIntElementId(JSContext *cx, JSObject *obj, const js::Value &idval,
|
||||
* the list and map->vector must point to pre-allocated memory.
|
||||
*/
|
||||
extern void
|
||||
js_InitAtomMap(JSContext *cx, JSAtomMap *map, js::AtomIndexMap *indices);
|
||||
js_InitAtomMap(JSContext *cx, js::AtomIndexMap *indices, JSAtom **atoms);
|
||||
|
||||
#endif /* jsatom_h___ */
|
||||
|
@ -114,6 +114,9 @@ ThreadData::ThreadData()
|
||||
pendingProxyOperation(NULL),
|
||||
interpreterFrames(NULL)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
noGCOrAllocationCheck = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
ThreadData::~ThreadData()
|
||||
|
@ -209,6 +209,10 @@ struct ThreadData {
|
||||
|
||||
ConservativeGCThreadData conservativeGC;
|
||||
|
||||
#ifdef DEBUG
|
||||
size_t noGCOrAllocationCheck;
|
||||
#endif
|
||||
|
||||
ThreadData();
|
||||
~ThreadData();
|
||||
|
||||
@ -1395,7 +1399,7 @@ FrameAtomBase(JSContext *cx, js::StackFrame *fp)
|
||||
{
|
||||
return fp->hasImacropc()
|
||||
? cx->runtime->atomState.commonAtomsStart()
|
||||
: fp->script()->atomMap.vector;
|
||||
: fp->script()->atoms;
|
||||
}
|
||||
|
||||
struct AutoResolving {
|
||||
@ -1478,9 +1482,9 @@ class AutoGCRooter {
|
||||
|
||||
enum {
|
||||
JSVAL = -1, /* js::AutoValueRooter */
|
||||
SHAPE = -2, /* js::AutoShapeRooter */
|
||||
VALARRAY = -2, /* js::AutoValueArrayRooter */
|
||||
PARSER = -3, /* js::Parser */
|
||||
SCRIPT = -4, /* js::AutoScriptRooter */
|
||||
SHAPEVECTOR = -4, /* js::AutoShapeVector */
|
||||
ENUMERATOR = -5, /* js::AutoEnumStateRooter */
|
||||
IDARRAY = -6, /* js::AutoIdArray */
|
||||
DESCRIPTORS = -7, /* js::AutoPropDescArrayRooter */
|
||||
@ -1492,11 +1496,8 @@ class AutoGCRooter {
|
||||
DESCRIPTOR = -13, /* js::AutoPropertyDescriptorRooter */
|
||||
STRING = -14, /* js::AutoStringRooter */
|
||||
IDVECTOR = -15, /* js::AutoIdVector */
|
||||
BINDINGS = -16, /* js::Bindings */
|
||||
SHAPEVECTOR = -17, /* js::AutoShapeVector */
|
||||
OBJVECTOR = -18, /* js::AutoObjectVector */
|
||||
TYPE = -19, /* js::types::AutoTypeRooter */
|
||||
VALARRAY = -20 /* js::AutoValueArrayRooter */
|
||||
OBJVECTOR = -16, /* js::AutoObjectVector */
|
||||
TYPE = -17 /* js::types::AutoTypeRooter */
|
||||
};
|
||||
|
||||
private:
|
||||
@ -1667,43 +1668,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:
|
||||
@ -1828,22 +1792,6 @@ class AutoXMLRooter : private AutoGCRooter {
|
||||
};
|
||||
#endif /* JS_HAS_XML_SUPPORT */
|
||||
|
||||
class AutoBindingsRooter : private AutoGCRooter {
|
||||
public:
|
||||
AutoBindingsRooter(JSContext *cx, Bindings &bindings
|
||||
JS_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: AutoGCRooter(cx, BINDINGS), bindings(bindings)
|
||||
{
|
||||
JS_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
}
|
||||
|
||||
friend void AutoGCRooter::trace(JSTracer *trc);
|
||||
|
||||
private:
|
||||
Bindings &bindings;
|
||||
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
class AutoLockGC {
|
||||
public:
|
||||
explicit AutoLockGC(JSRuntime *rt
|
||||
|
@ -210,7 +210,7 @@ class CompartmentChecker
|
||||
|
||||
void check(JSScript *script) {
|
||||
if (script) {
|
||||
check(script->compartment);
|
||||
check(script->compartment());
|
||||
if (script->u.object)
|
||||
check(script->u.object);
|
||||
}
|
||||
|
@ -100,9 +100,7 @@ JSCompartment::JSCompartment(JSRuntime *rt)
|
||||
breakpointSites(rt),
|
||||
watchpointMap(NULL)
|
||||
{
|
||||
JS_INIT_CLIST(&scripts);
|
||||
|
||||
PodArrayZero(scriptsToGC);
|
||||
PodArrayZero(evalCache);
|
||||
}
|
||||
|
||||
JSCompartment::~JSCompartment()
|
||||
@ -123,8 +121,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
|
||||
}
|
||||
|
||||
@ -492,27 +490,6 @@ JSCompartment::markCrossCompartmentWrappers(JSTracer *trc)
|
||||
MarkValue(trc, e.front().key, "cross-compartment wrapper");
|
||||
}
|
||||
|
||||
struct MarkSingletonObjectOp
|
||||
{
|
||||
JSTracer *trc;
|
||||
MarkSingletonObjectOp(JSTracer *trc) : trc(trc) {}
|
||||
void operator()(Cell *cell) {
|
||||
JSObject *object = static_cast<JSObject *>(cell);
|
||||
if (!object->isNewborn() && object->hasSingletonType())
|
||||
MarkObject(trc, *object, "mark_types_singleton");
|
||||
}
|
||||
};
|
||||
|
||||
struct MarkTypeObjectOp
|
||||
{
|
||||
JSTracer *trc;
|
||||
MarkTypeObjectOp(JSTracer *trc) : trc(trc) {}
|
||||
void operator()(Cell *cell) {
|
||||
types::TypeObject *object = static_cast<types::TypeObject *>(cell);
|
||||
MarkTypeObject(trc, object, "mark_types_scan");
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
JSCompartment::markTypes(JSTracer *trc)
|
||||
{
|
||||
@ -523,20 +500,23 @@ JSCompartment::markTypes(JSTracer *trc)
|
||||
*/
|
||||
JS_ASSERT(activeAnalysis);
|
||||
|
||||
for (JSCList *cursor = scripts.next; cursor != &scripts; cursor = cursor->next) {
|
||||
JSScript *script = reinterpret_cast<JSScript *>(cursor);
|
||||
js_TraceScript(trc, script, NULL);
|
||||
for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
|
||||
JSScript *script = i.get<JSScript>();
|
||||
MarkScript(trc, script, "mark_types_script");
|
||||
}
|
||||
|
||||
MarkSingletonObjectOp objectCellOp(trc);
|
||||
for (unsigned thingKind = FINALIZE_OBJECT0;
|
||||
thingKind <= FINALIZE_FUNCTION_AND_OBJECT_LAST;
|
||||
thingKind++) {
|
||||
gc::ForEachArenaAndCell(this, (FinalizeKind) thingKind, EmptyArenaOp, objectCellOp);
|
||||
for (CellIterUnderGC i(this, FinalizeKind(thingKind)); !i.done(); i.next()) {
|
||||
JSObject *object = i.get<JSObject>();
|
||||
if (!object->isNewborn() && object->hasSingletonType())
|
||||
MarkObject(trc, *object, "mark_types_singleton");
|
||||
}
|
||||
}
|
||||
|
||||
MarkTypeObjectOp typeCellOp(trc);
|
||||
gc::ForEachArenaAndCell(this, FINALIZE_TYPE_OBJECT, EmptyArenaOp, typeCellOp);
|
||||
for (CellIterUnderGC i(this, FINALIZE_TYPE_OBJECT); !i.done(); i.next())
|
||||
MarkTypeObject(trc, i.get<types::TypeObject>(), "mark_types_scan");
|
||||
}
|
||||
|
||||
void
|
||||
@ -584,8 +564,8 @@ JSCompartment::sweep(JSContext *cx, uint32 releaseInterval)
|
||||
* Purge all PICs in the compartment. These can reference type data and
|
||||
* need to know which types are pending collection.
|
||||
*/
|
||||
for (JSCList *cursor = scripts.next; cursor != &scripts; cursor = cursor->next) {
|
||||
JSScript *script = reinterpret_cast<JSScript *>(cursor);
|
||||
for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
|
||||
JSScript *script = i.get<JSScript>();
|
||||
if (script->hasJITCode())
|
||||
mjit::ic::PurgePICs(cx, script);
|
||||
}
|
||||
@ -606,8 +586,8 @@ JSCompartment::sweep(JSContext *cx, uint32 releaseInterval)
|
||||
if (discardScripts)
|
||||
hasDebugModeCodeToDrop = false;
|
||||
|
||||
for (JSCList *cursor = scripts.next; cursor != &scripts; cursor = cursor->next) {
|
||||
JSScript *script = reinterpret_cast<JSScript *>(cursor);
|
||||
for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
|
||||
JSScript *script = i.get<JSScript>();
|
||||
if (script->hasJITCode()) {
|
||||
mjit::ic::SweepCallICs(cx, script, discardScripts);
|
||||
if (discardScripts) {
|
||||
@ -636,9 +616,8 @@ JSCompartment::sweep(JSContext *cx, uint32 releaseInterval)
|
||||
#ifdef JS_METHODJIT
|
||||
mjit::ClearAllFrames(this);
|
||||
#endif
|
||||
|
||||
for (JSCList *cursor = scripts.next; cursor != &scripts; cursor = cursor->next) {
|
||||
JSScript *script = reinterpret_cast<JSScript *>(cursor);
|
||||
for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
|
||||
JSScript *script = i.get<JSScript>();
|
||||
if (script->types) {
|
||||
types::TypeScript::Sweep(cx, script);
|
||||
|
||||
@ -657,20 +636,14 @@ JSCompartment::sweep(JSContext *cx, uint32 releaseInterval)
|
||||
|
||||
types.sweep(cx);
|
||||
|
||||
for (JSCList *cursor = scripts.next; cursor != &scripts; cursor = cursor->next) {
|
||||
JSScript *script = reinterpret_cast<JSScript *>(cursor);
|
||||
for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
|
||||
JSScript *script = i.get<JSScript>();
|
||||
if (script->types)
|
||||
script->types->analysis = NULL;
|
||||
}
|
||||
|
||||
/* Reset the analysis pool, releasing all analysis and intermediate type data. */
|
||||
JS_FinishArenaPool(&oldPool);
|
||||
|
||||
/*
|
||||
* Destroy eval'ed scripts, now that any type inference information referring
|
||||
* to eval scripts has been removed.
|
||||
*/
|
||||
js_DestroyScriptsToGC(cx, this);
|
||||
}
|
||||
|
||||
active = false;
|
||||
@ -682,6 +655,21 @@ JSCompartment::purge(JSContext *cx)
|
||||
freeLists.purge();
|
||||
dtoaCache.purge();
|
||||
|
||||
/*
|
||||
* 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();
|
||||
|
||||
@ -695,19 +683,16 @@ JSCompartment::purge(JSContext *cx)
|
||||
traceMonitor()->needFlush = JS_TRUE;
|
||||
#endif
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
for (JSScript *script = (JSScript *)scripts.next;
|
||||
&script->links != &scripts;
|
||||
script = (JSScript *)script->links.next) {
|
||||
if (script->hasJITCode()) {
|
||||
# if defined JS_MONOIC
|
||||
/*
|
||||
* MICs do not refer to data which can be GC'ed and do not generate stubs
|
||||
* which might need to be discarded, but are sensitive to shape regeneration.
|
||||
*/
|
||||
if (cx->runtime->gcRegenShapes)
|
||||
#if defined JS_METHODJIT && defined JS_MONOIC
|
||||
/*
|
||||
* MICs do not refer to data which can be GC'ed and do not generate stubs
|
||||
* which might need to be discarded, but are sensitive to shape regeneration.
|
||||
*/
|
||||
if (cx->runtime->gcRegenShapes) {
|
||||
for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
|
||||
JSScript *script = i.get<JSScript>();
|
||||
if (script->hasJITCode())
|
||||
mjit::ic::PurgeMICs(cx, script);
|
||||
# endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -761,7 +746,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;
|
||||
@ -818,12 +803,12 @@ JSCompartment::updateForDebugMode(JSContext *cx)
|
||||
return;
|
||||
}
|
||||
|
||||
// Discard JIT code for any scripts that change debugMode. This assumes
|
||||
// that 'comp' is in the same thread as 'cx'.
|
||||
for (JSScript *script = (JSScript *) scripts.next;
|
||||
&script->links != &scripts;
|
||||
script = (JSScript *) script->links.next)
|
||||
{
|
||||
/*
|
||||
* Discard JIT code for any scripts that change debugMode. This assumes
|
||||
* that 'comp' is in the same thread as 'cx'.
|
||||
*/
|
||||
for (gc::CellIter i(cx, this, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
|
||||
JSScript *script = i.get<JSScript>();
|
||||
if (script->debugMode != enabled) {
|
||||
mjit::ReleaseScriptCode(cx, script);
|
||||
script->debugMode = enabled;
|
||||
@ -905,7 +890,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 {
|
||||
@ -426,7 +427,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
|
||||
@ -507,8 +508,6 @@ struct JS_FRIEND_API(JSCompartment) {
|
||||
uintN debugModeBits; // see debugMode() below
|
||||
|
||||
public:
|
||||
JSCList scripts; // scripts in this compartment
|
||||
|
||||
js::NativeIterCache nativeIterCache;
|
||||
|
||||
typedef js::Maybe<js::ToSourceCache> LazyToSourceCache;
|
||||
@ -540,6 +539,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);
|
||||
@ -633,7 +633,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)
|
||||
|
||||
/*
|
||||
|
@ -182,7 +182,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) {
|
||||
@ -212,7 +212,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));
|
||||
@ -222,7 +222,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);
|
||||
}
|
||||
|
||||
@ -230,7 +230,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)
|
||||
@ -243,7 +243,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)
|
||||
@ -1089,9 +1089,9 @@ JS_GetScriptTotalSize(JSContext *cx, JSScript *script)
|
||||
nbytes += JS_GetObjectTotalSize(cx, script->u.object);
|
||||
|
||||
nbytes += script->length * sizeof script->code[0];
|
||||
nbytes += script->atomMap.length * sizeof script->atomMap.vector[0];
|
||||
for (size_t i = 0; i < script->atomMap.length; i++)
|
||||
nbytes += GetAtomTotalSize(cx, script->atomMap.vector[i]);
|
||||
nbytes += script->natoms * sizeof script->atoms[0];
|
||||
for (size_t i = 0; i < script->natoms; i++)
|
||||
nbytes += GetAtomTotalSize(cx, script->atoms[i]);
|
||||
|
||||
if (script->filename)
|
||||
nbytes += strlen(script->filename) + 1;
|
||||
@ -2178,13 +2178,18 @@ JS_DumpBytecode(JSContext *cx, JSScript *script)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
DumpBytecodeScriptCallback(JSContext *cx, void *data, void *thing,
|
||||
JSGCTraceKind traceKind, size_t thingSize)
|
||||
{
|
||||
JS_ASSERT(traceKind == JSTRACE_SCRIPT);
|
||||
JS_ASSERT(!data);
|
||||
JSScript *script = static_cast<JSScript *>(thing);
|
||||
JS_DumpBytecode(cx, script);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_DumpCompartmentBytecode(JSContext *cx)
|
||||
{
|
||||
for (JSScript *script = (JSScript *) JS_LIST_HEAD(&cx->compartment->scripts);
|
||||
script != (JSScript *) &cx->compartment->scripts;
|
||||
script = (JSScript *) JS_NEXT_LINK((JSCList *)script))
|
||||
{
|
||||
JS_DumpBytecode(cx, script);
|
||||
}
|
||||
IterateCells(cx, cx->compartment, gc::FINALIZE_SCRIPT, NULL, DumpBytecodeScriptCallback);
|
||||
}
|
||||
|
@ -207,7 +207,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));
|
||||
@ -1632,9 +1631,6 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp)
|
||||
if (xdr->mode == JSXDR_DECODE) {
|
||||
*objp = fun;
|
||||
fun->u.i.script->setOwnerObject(fun);
|
||||
#ifdef CHECK_SCRIPT_OWNER
|
||||
fun->script()->owner = NULL;
|
||||
#endif
|
||||
if (!fun->u.i.script->typeSetFunction(cx, fun))
|
||||
return false;
|
||||
JS_ASSERT(fun->nargs == fun->script()->bindings.countArgs());
|
||||
@ -1705,30 +1701,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();
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1740,7 +1722,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 */
|
||||
@ -2180,8 +2163,6 @@ Function(JSContext *cx, uintN argc, Value *vp)
|
||||
}
|
||||
|
||||
Bindings bindings(cx);
|
||||
AutoBindingsRooter root(cx, bindings);
|
||||
|
||||
uintN lineno;
|
||||
const char *filename = CurrentScriptFileAndLine(cx, &lineno);
|
||||
|
||||
@ -2411,9 +2392,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;
|
||||
fun->getType(cx)->functionScript = script;
|
||||
script->hasFunction = true;
|
||||
@ -2532,8 +2510,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);
|
||||
|
||||
cfun->u.i.script = NULL;
|
||||
@ -2546,9 +2524,6 @@ js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent,
|
||||
return NULL;
|
||||
|
||||
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);
|
||||
}
|
||||
|
148
js/src/jsgc.cpp
148
js/src/jsgc.cpp
@ -106,21 +106,6 @@
|
||||
using namespace js;
|
||||
using namespace js::gc;
|
||||
|
||||
/*
|
||||
* Check that JSTRACE_XML follows JSTRACE_OBJECT and JSTRACE_STRING.
|
||||
*/
|
||||
JS_STATIC_ASSERT(JSTRACE_OBJECT == 0);
|
||||
JS_STATIC_ASSERT(JSTRACE_STRING == 1);
|
||||
JS_STATIC_ASSERT(JSTRACE_SHAPE == 2);
|
||||
JS_STATIC_ASSERT(JSTRACE_TYPE_OBJECT == 3);
|
||||
JS_STATIC_ASSERT(JSTRACE_XML == 4);
|
||||
|
||||
/*
|
||||
* JS_IS_VALID_TRACE_KIND assumes that JSTRACE_TYPE_OBJECT is the last non-xml
|
||||
* trace kind when JS_HAS_XML_SUPPORT is false.
|
||||
*/
|
||||
JS_STATIC_ASSERT(JSTRACE_TYPE_OBJECT + 1 == JSTRACE_XML);
|
||||
|
||||
namespace js {
|
||||
namespace gc {
|
||||
|
||||
@ -149,6 +134,7 @@ const uint8 GCThingSizeMap[] = {
|
||||
sizeof(JSObject_Slots16), /* FINALIZE_OBJECT16 */
|
||||
sizeof(JSObject_Slots16), /* FINALIZE_OBJECT16_BACKGROUND */
|
||||
sizeof(JSFunction), /* FINALIZE_FUNCTION */
|
||||
sizeof(JSScript), /* FINALIZE_SCRIPT */
|
||||
sizeof(Shape), /* FINALIZE_SHAPE */
|
||||
sizeof(types::TypeObject), /* FINALIZE_TYPE_OBJECT */
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
@ -198,6 +184,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 +777,9 @@ MarkIfGCThingWord(JSTracer *trc, jsuword w)
|
||||
case FINALIZE_FUNCTION:
|
||||
test = MarkArenaPtrConservatively<JSFunction>(trc, aheader, addr);
|
||||
break;
|
||||
case FINALIZE_SCRIPT:
|
||||
test = MarkArenaPtrConservatively<JSScript>(trc, aheader, addr);
|
||||
break;
|
||||
case FINALIZE_SHAPE:
|
||||
test = MarkArenaPtrConservatively<Shape>(trc, aheader, addr);
|
||||
break;
|
||||
@ -1253,6 +1246,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);
|
||||
@ -1264,7 +1258,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;
|
||||
@ -1305,6 +1305,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;
|
||||
@ -1463,6 +1466,8 @@ RefillFinalizableFreeList(JSContext *cx, unsigned thingKind)
|
||||
return RefillTypedFreeList<JSShortString>(cx, thingKind);
|
||||
case FINALIZE_FUNCTION:
|
||||
return RefillTypedFreeList<JSFunction>(cx, thingKind);
|
||||
case FINALIZE_SCRIPT:
|
||||
return RefillTypedFreeList<JSScript>(cx, thingKind);
|
||||
case FINALIZE_SHAPE:
|
||||
return RefillTypedFreeList<Shape>(cx, thingKind);
|
||||
case FINALIZE_TYPE_OBJECT:
|
||||
@ -1480,7 +1485,7 @@ RefillFinalizableFreeList(JSContext *cx, unsigned thingKind)
|
||||
} /* namespace gc */
|
||||
} /* namespace js */
|
||||
|
||||
uint32
|
||||
JSGCTraceKind
|
||||
js_GetGCThingTraceKind(void *thing)
|
||||
{
|
||||
return GetGCThingTraceKind(thing);
|
||||
@ -1578,7 +1583,7 @@ GCMarker::delayMarkingChildren(const void *thing)
|
||||
static void
|
||||
MarkDelayedChildren(JSTracer *trc, ArenaHeader *aheader)
|
||||
{
|
||||
unsigned traceKind = GetFinalizableTraceKind(aheader->getThingKind());
|
||||
JSGCTraceKind traceKind = GetFinalizableTraceKind(aheader->getThingKind());
|
||||
size_t thingSize = aheader->getThingSize();
|
||||
Arena *a = aheader->getArena();
|
||||
uintptr_t end = a->thingsEnd();
|
||||
@ -1675,8 +1680,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");
|
||||
}
|
||||
|
||||
@ -1701,19 +1706,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;
|
||||
@ -1793,23 +1789,12 @@ AutoGCRooter::trace(JSTracer *trc)
|
||||
return;
|
||||
}
|
||||
|
||||
case BINDINGS: {
|
||||
static_cast<js::AutoBindingsRooter *>(this)->bindings.trace(trc);
|
||||
return;
|
||||
}
|
||||
|
||||
case OBJVECTOR: {
|
||||
AutoObjectVector::VectorImpl &vector = static_cast<AutoObjectVector *>(this)->vector;
|
||||
MarkObjectRange(trc, vector.length(), vector.begin(), "js::AutoObjectVector.vector");
|
||||
return;
|
||||
}
|
||||
|
||||
case TYPE: {
|
||||
types::TypeObject *type = static_cast<types::AutoTypeRooter *>(this)->type;
|
||||
MarkTypeObject(trc, type, "js::AutoTypeRooter");
|
||||
return;
|
||||
}
|
||||
|
||||
case VALARRAY: {
|
||||
AutoValueArray *array = static_cast<AutoValueArray *>(this);
|
||||
MarkValueRange(trc, array->length(), array->start(), "js::AutoValueArray");
|
||||
@ -1988,21 +1973,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)
|
||||
{
|
||||
@ -2012,7 +1982,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);
|
||||
@ -2023,6 +1992,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
|
||||
@ -2048,6 +2028,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 {
|
||||
@ -2117,6 +2103,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)
|
||||
{
|
||||
@ -2160,6 +2155,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);
|
||||
@ -2376,6 +2376,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);
|
||||
@ -2401,6 +2403,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);
|
||||
@ -2553,6 +2561,7 @@ class AutoGCSession {
|
||||
AutoGCSession::AutoGCSession(JSContext *cx)
|
||||
: context(cx)
|
||||
{
|
||||
JS_ASSERT(!JS_THREAD_DATA(cx)->noGCOrAllocationCheck);
|
||||
JSRuntime *rt = cx->runtime;
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
@ -2679,8 +2688,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);
|
||||
@ -2848,10 +2857,10 @@ struct IterateArenaCallbackOp
|
||||
JSContext *cx;
|
||||
void *data;
|
||||
IterateArenaCallback callback;
|
||||
size_t traceKind;
|
||||
JSGCTraceKind traceKind;
|
||||
size_t thingSize;
|
||||
IterateArenaCallbackOp(JSContext *cx, void *data, IterateArenaCallback callback,
|
||||
size_t traceKind, size_t thingSize)
|
||||
JSGCTraceKind traceKind, size_t thingSize)
|
||||
: cx(cx), data(data), callback(callback), traceKind(traceKind), thingSize(thingSize)
|
||||
{}
|
||||
void operator()(Arena *arena) { (*callback)(cx, data, arena, traceKind, thingSize); }
|
||||
@ -2862,10 +2871,10 @@ struct IterateCellCallbackOp
|
||||
JSContext *cx;
|
||||
void *data;
|
||||
IterateCellCallback callback;
|
||||
size_t traceKind;
|
||||
JSGCTraceKind traceKind;
|
||||
size_t thingSize;
|
||||
IterateCellCallbackOp(JSContext *cx, void *data, IterateCellCallback callback,
|
||||
size_t traceKind, size_t thingSize)
|
||||
JSGCTraceKind traceKind, size_t thingSize)
|
||||
: cx(cx), data(data), callback(callback), traceKind(traceKind), thingSize(thingSize)
|
||||
{}
|
||||
void operator()(Cell *cell) { (*callback)(cx, data, cell, traceKind, thingSize); }
|
||||
@ -2896,7 +2905,7 @@ IterateCompartmentsArenasCells(JSContext *cx, void *data,
|
||||
(*compartmentCallback)(cx, data, compartment);
|
||||
|
||||
for (unsigned thingKind = 0; thingKind < FINALIZE_LIMIT; thingKind++) {
|
||||
size_t traceKind = GetFinalizableTraceKind(thingKind);
|
||||
JSGCTraceKind traceKind = GetFinalizableTraceKind(thingKind);
|
||||
size_t thingSize = GCThingSizeMap[thingKind];
|
||||
IterateArenaCallbackOp arenaOp(cx, data, arenaCallback, traceKind, thingSize);
|
||||
IterateCellCallbackOp cellOp(cx, data, cellCallback, traceKind, thingSize);
|
||||
@ -2927,11 +2936,18 @@ IterateCells(JSContext *cx, JSCompartment *compartment, FinalizeKind thingKind,
|
||||
|
||||
AutoCopyFreeListToArenas copy(rt);
|
||||
|
||||
size_t traceKind = GetFinalizableTraceKind(thingKind);
|
||||
JSGCTraceKind traceKind = GetFinalizableTraceKind(thingKind);
|
||||
size_t thingSize = GCThingSizeMap[thingKind];
|
||||
IterateCellCallbackOp cellOp(cx, data, cellCallback, traceKind, thingSize);
|
||||
|
||||
ForEachArenaAndCell(compartment, thingKind, EmptyArenaOp, cellOp);
|
||||
if (compartment) {
|
||||
for (CellIterUnderGC i(compartment, thingKind); !i.done(); i.next())
|
||||
cellCallback(cx, data, i.getCell(), traceKind, thingSize);
|
||||
} else {
|
||||
for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) {
|
||||
for (CellIterUnderGC i(*c, thingKind); !i.done(); i.next())
|
||||
cellCallback(cx, data, i.getCell(), traceKind, thingSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace gc {
|
||||
|
112
js/src/jsgc.h
112
js/src/jsgc.h
@ -97,6 +97,7 @@ enum FinalizeKind {
|
||||
FINALIZE_OBJECT_LAST = FINALIZE_OBJECT16_BACKGROUND,
|
||||
FINALIZE_FUNCTION,
|
||||
FINALIZE_FUNCTION_AND_OBJECT_LAST = FINALIZE_FUNCTION,
|
||||
FINALIZE_SCRIPT,
|
||||
FINALIZE_SHAPE,
|
||||
FINALIZE_TYPE_OBJECT,
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
@ -108,6 +109,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;
|
||||
@ -756,14 +763,6 @@ Cell::compartment() const
|
||||
return arenaHeader()->compartment;
|
||||
}
|
||||
|
||||
#define JSTRACE_TYPE_OBJECT 3
|
||||
#define JSTRACE_XML 4
|
||||
|
||||
/*
|
||||
* One past the maximum trace kind.
|
||||
*/
|
||||
#define JSTRACE_LIMIT 5
|
||||
|
||||
/*
|
||||
* Lower limit after which we limit the heap growth
|
||||
*/
|
||||
@ -779,12 +778,10 @@ const float GC_HEAP_GROWTH_FACTOR = 3.0f;
|
||||
/* Perform a Full GC every 20 seconds if MaybeGC is called */
|
||||
static const int64 GC_IDLE_FULL_SPAN = 20 * 1000 * 1000;
|
||||
|
||||
static inline size_t
|
||||
static inline JSGCTraceKind
|
||||
GetFinalizableTraceKind(size_t thingKind)
|
||||
{
|
||||
JS_STATIC_ASSERT(JSExternalString::TYPE_LIMIT == 8);
|
||||
|
||||
static const uint8 map[FINALIZE_LIMIT] = {
|
||||
static const JSGCTraceKind map[FINALIZE_LIMIT] = {
|
||||
JSTRACE_OBJECT, /* FINALIZE_OBJECT0 */
|
||||
JSTRACE_OBJECT, /* FINALIZE_OBJECT0_BACKGROUND */
|
||||
JSTRACE_OBJECT, /* FINALIZE_OBJECT2 */
|
||||
@ -798,6 +795,7 @@ GetFinalizableTraceKind(size_t thingKind)
|
||||
JSTRACE_OBJECT, /* FINALIZE_OBJECT16 */
|
||||
JSTRACE_OBJECT, /* FINALIZE_OBJECT16_BACKGROUND */
|
||||
JSTRACE_OBJECT, /* FINALIZE_FUNCTION */
|
||||
JSTRACE_SCRIPT, /* FINALIZE_SCRIPT */
|
||||
JSTRACE_SHAPE, /* FINALIZE_SHAPE */
|
||||
JSTRACE_TYPE_OBJECT,/* FINALIZE_TYPE_OBJECT */
|
||||
#if JS_HAS_XML_SUPPORT /* FINALIZE_XML */
|
||||
@ -812,7 +810,7 @@ GetFinalizableTraceKind(size_t thingKind)
|
||||
return map[thingKind];
|
||||
}
|
||||
|
||||
inline uint32
|
||||
inline JSGCTraceKind
|
||||
GetGCThingTraceKind(const void *thing);
|
||||
|
||||
static inline JSRuntime *
|
||||
@ -881,6 +879,10 @@ class ArenaList {
|
||||
bool willBeFinalizedLater() const {
|
||||
return backgroundFinalizeState == BFS_RUN;
|
||||
}
|
||||
|
||||
bool doneBackgroundFinalize() const {
|
||||
return backgroundFinalizeState == BFS_DONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
@ -966,13 +968,16 @@ struct FreeLists {
|
||||
* outside the GC.
|
||||
*/
|
||||
void copyToArenas() {
|
||||
for (size_t i = 0; i != size_t(FINALIZE_LIMIT); ++i) {
|
||||
FreeSpan *list = &lists[i];
|
||||
if (!list->isEmpty()) {
|
||||
ArenaHeader *aheader = list->arenaHeader();
|
||||
JS_ASSERT(!aheader->hasFreeThings());
|
||||
aheader->setFirstFreeSpan(list);
|
||||
}
|
||||
for (size_t i = 0; i != size_t(FINALIZE_LIMIT); ++i)
|
||||
copyToArena(FinalizeKind(i));
|
||||
}
|
||||
|
||||
void copyToArena(FinalizeKind thingKind) {
|
||||
FreeSpan *list = &lists[thingKind];
|
||||
if (!list->isEmpty()) {
|
||||
ArenaHeader *aheader = list->arenaHeader();
|
||||
JS_ASSERT(!aheader->hasFreeThings());
|
||||
aheader->setFirstFreeSpan(list);
|
||||
}
|
||||
}
|
||||
|
||||
@ -981,16 +986,40 @@ struct FreeLists {
|
||||
* copyToArenas.
|
||||
*/
|
||||
void clearInArenas() {
|
||||
for (size_t i = 0; i != size_t(FINALIZE_LIMIT); ++i) {
|
||||
FreeSpan *list = &lists[i];
|
||||
if (!list->isEmpty()) {
|
||||
ArenaHeader *aheader = list->arenaHeader();
|
||||
JS_ASSERT(aheader->getFirstFreeSpan().isSameNonEmptySpan(list));
|
||||
aheader->setAsFullyUsed();
|
||||
}
|
||||
for (size_t i = 0; i != size_t(FINALIZE_LIMIT); ++i)
|
||||
clearInArena(FinalizeKind(i));
|
||||
}
|
||||
|
||||
|
||||
void clearInArena(FinalizeKind thingKind) {
|
||||
FreeSpan *list = &lists[thingKind];
|
||||
if (!list->isEmpty()) {
|
||||
ArenaHeader *aheader = list->arenaHeader();
|
||||
JS_ASSERT(aheader->getFirstFreeSpan().isSameNonEmptySpan(list));
|
||||
aheader->setAsFullyUsed();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that the free list is either empty or were synchronized with the
|
||||
* arena using copyToArena().
|
||||
*/
|
||||
bool isSynchronizedWithArena(FinalizeKind thingKind) {
|
||||
FreeSpan *list = &lists[thingKind];
|
||||
if (list->isEmpty())
|
||||
return true;
|
||||
ArenaHeader *aheader = list->arenaHeader();
|
||||
if (aheader->hasFreeThings()) {
|
||||
/*
|
||||
* If the arena has a free list, it must be the same as one in
|
||||
* lists.
|
||||
*/
|
||||
JS_ASSERT(aheader->getFirstFreeSpan().isSameNonEmptySpan(list));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
JS_ALWAYS_INLINE void *getNext(unsigned thingKind, size_t thingSize) {
|
||||
return lists[thingKind].allocate(thingSize);
|
||||
}
|
||||
@ -1079,7 +1108,7 @@ extern bool
|
||||
CheckAllocation(JSContext *cx);
|
||||
#endif
|
||||
|
||||
extern JS_FRIEND_API(uint32)
|
||||
extern JS_FRIEND_API(JSGCTraceKind)
|
||||
js_GetGCThingTraceKind(void *thing);
|
||||
|
||||
extern JSBool
|
||||
@ -1194,10 +1223,6 @@ js_WaitForGC(JSRuntime *rt);
|
||||
|
||||
#endif
|
||||
|
||||
extern void
|
||||
js_DestroyScriptsToGC(JSContext *cx, JSCompartment *comp);
|
||||
|
||||
|
||||
namespace js {
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
@ -1273,7 +1298,7 @@ class GCHelperThread {
|
||||
replenishAndFreeLater(ptr);
|
||||
}
|
||||
|
||||
void setContext(JSContext *context) { cx = context; }
|
||||
bool prepareForBackgroundSweep(JSContext *context);
|
||||
};
|
||||
|
||||
#endif /* JS_THREADSAFE */
|
||||
@ -1474,10 +1499,10 @@ void
|
||||
MarkStackRangeConservatively(JSTracer *trc, Value *begin, Value *end);
|
||||
|
||||
typedef void (*IterateCompartmentCallback)(JSContext *cx, void *data, JSCompartment *compartment);
|
||||
typedef void (*IterateArenaCallback)(JSContext *cx, void *data, gc::Arena *arena, size_t traceKind,
|
||||
size_t thingSize);
|
||||
typedef void (*IterateCellCallback)(JSContext *cx, void *data, void *thing, size_t traceKind,
|
||||
size_t thingSize);
|
||||
typedef void (*IterateArenaCallback)(JSContext *cx, void *data, gc::Arena *arena,
|
||||
JSGCTraceKind traceKind, size_t thingSize);
|
||||
typedef void (*IterateCellCallback)(JSContext *cx, void *data, void *thing,
|
||||
JSGCTraceKind traceKind, size_t thingSize);
|
||||
|
||||
/*
|
||||
* This function calls |compartmentCallback| on every compartment,
|
||||
@ -1490,8 +1515,11 @@ IterateCompartmentsArenasCells(JSContext *cx, void *data,
|
||||
IterateArenaCallback arenaCallback,
|
||||
IterateCellCallback cellCallback);
|
||||
|
||||
/* Invoke cellCallback on every in-use object of the specified thing kind. */
|
||||
void
|
||||
/*
|
||||
* Invoke cellCallback on every in-use object of the specified thing kind for
|
||||
* the given compartment or for all compartments if it is null.
|
||||
*/
|
||||
extern JS_FRIEND_API(void)
|
||||
IterateCells(JSContext *cx, JSCompartment *compartment, gc::FinalizeKind thingKind,
|
||||
void *data, IterateCellCallback cellCallback);
|
||||
|
||||
@ -1505,12 +1533,6 @@ js_FinalizeStringRT(JSRuntime *rt, JSString *str);
|
||||
*/
|
||||
#define IS_GC_MARKING_TRACER(trc) ((trc)->callback == NULL)
|
||||
|
||||
#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_TYPE_OBJECT)
|
||||
#endif
|
||||
|
||||
namespace js {
|
||||
namespace gc {
|
||||
|
||||
|
@ -112,7 +112,7 @@ struct Shape;
|
||||
|
||||
namespace gc {
|
||||
|
||||
inline uint32
|
||||
inline JSGCTraceKind
|
||||
GetGCThingTraceKind(const void *thing)
|
||||
{
|
||||
JS_ASSERT(thing);
|
||||
@ -256,6 +256,118 @@ ForEachArenaAndCell(JSCompartment *compartment, FinalizeKind thingKind,
|
||||
}
|
||||
}
|
||||
|
||||
class CellIterImpl
|
||||
{
|
||||
size_t thingSize;
|
||||
ArenaHeader *aheader;
|
||||
FreeSpan firstSpan;
|
||||
const FreeSpan *span;
|
||||
uintptr_t thing;
|
||||
Cell *cell;
|
||||
|
||||
protected:
|
||||
CellIterImpl() {
|
||||
}
|
||||
|
||||
void init(JSCompartment *comp, FinalizeKind thingKind) {
|
||||
thingSize = GCThingSizeMap[thingKind];
|
||||
aheader = comp->arenas[thingKind].getHead();
|
||||
firstSpan.initAsEmpty();
|
||||
span = &firstSpan;
|
||||
thing = span->first;
|
||||
next();
|
||||
}
|
||||
|
||||
public:
|
||||
bool done() const {
|
||||
return !cell;
|
||||
}
|
||||
|
||||
template<typename T> T *get() const {
|
||||
JS_ASSERT(!done());
|
||||
return static_cast<T *>(cell);
|
||||
}
|
||||
|
||||
Cell *getCell() const {
|
||||
JS_ASSERT(!done());
|
||||
return cell;
|
||||
}
|
||||
|
||||
void next() {
|
||||
for (;;) {
|
||||
if (thing != span->first)
|
||||
break;
|
||||
if (JS_LIKELY(span->hasNext())) {
|
||||
thing = span->last + thingSize;
|
||||
span = span->nextSpan();
|
||||
break;
|
||||
}
|
||||
if (!aheader) {
|
||||
cell = NULL;
|
||||
return;
|
||||
}
|
||||
firstSpan = aheader->getFirstFreeSpan();
|
||||
span = &firstSpan;
|
||||
thing = aheader->getArena()->thingsStart(thingSize);
|
||||
aheader = aheader->next;
|
||||
}
|
||||
cell = reinterpret_cast<Cell *>(thing);
|
||||
thing += thingSize;
|
||||
}
|
||||
};
|
||||
|
||||
class CellIterUnderGC : public CellIterImpl {
|
||||
|
||||
public:
|
||||
CellIterUnderGC(JSCompartment *comp, FinalizeKind thingKind) {
|
||||
JS_ASSERT(comp->rt->gcRunning);
|
||||
JS_ASSERT(comp->freeLists.lists[thingKind].isEmpty());
|
||||
init(comp, thingKind);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* When using the iterator outside the GC the caller must ensure that no GC or
|
||||
* allocations of GC things are possible and that the background finalization
|
||||
* for the given thing kind is not enabled or is done.
|
||||
*/
|
||||
class CellIter: public CellIterImpl
|
||||
{
|
||||
FreeLists *lists;
|
||||
FinalizeKind thingKind;
|
||||
#ifdef DEBUG
|
||||
size_t *counter;
|
||||
#endif
|
||||
public:
|
||||
CellIter(JSContext *cx, JSCompartment *comp, FinalizeKind thingKind)
|
||||
: lists(&comp->freeLists),
|
||||
thingKind(thingKind) {
|
||||
#ifdef JS_THREADSAFE
|
||||
JS_ASSERT(comp->arenas[thingKind].doneBackgroundFinalize());
|
||||
#endif
|
||||
if (lists->isSynchronizedWithArena(thingKind)) {
|
||||
lists = NULL;
|
||||
} else {
|
||||
JS_ASSERT(!comp->rt->gcRunning);
|
||||
lists->copyToArena(thingKind);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
counter = &JS_THREAD_DATA(cx)->noGCOrAllocationCheck;
|
||||
++*counter;
|
||||
#endif
|
||||
init(comp, thingKind);
|
||||
}
|
||||
|
||||
~CellIter() {
|
||||
#ifdef DEBUG
|
||||
JS_ASSERT(*counter > 0);
|
||||
--*counter;
|
||||
#endif
|
||||
if (lists)
|
||||
lists->clearInArena(thingKind);
|
||||
}
|
||||
};
|
||||
|
||||
/* Signatures for ArenaOp and CellOp above. */
|
||||
|
||||
inline void EmptyArenaOp(Arena *arena) {}
|
||||
@ -283,6 +395,7 @@ NewGCThing(JSContext *cx, unsigned thingKind, size_t thingSize)
|
||||
(thingKind == js::gc::FINALIZE_SHORT_STRING));
|
||||
#endif
|
||||
JS_ASSERT(!cx->runtime->gcRunning);
|
||||
JS_ASSERT(!JS_THREAD_DATA(cx)->noGCOrAllocationCheck);
|
||||
|
||||
#ifdef JS_GC_ZEAL
|
||||
if (cx->runtime->needZealousGC())
|
||||
@ -333,6 +446,12 @@ js_NewGCFunction(JSContext *cx)
|
||||
return fun;
|
||||
}
|
||||
|
||||
inline JSScript *
|
||||
js_NewGCScript(JSContext *cx)
|
||||
{
|
||||
return NewGCThing<JSScript>(cx, js::gc::FINALIZE_SCRIPT, sizeof(JSScript));
|
||||
}
|
||||
|
||||
inline js::Shape *
|
||||
js_NewGCShape(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
|
||||
@ -91,6 +92,9 @@ PushMarkStack(GCMarker *gcmarker, JSObject *thing);
|
||||
static inline void
|
||||
PushMarkStack(GCMarker *gcmarker, JSFunction *thing);
|
||||
|
||||
static inline void
|
||||
PushMarkStack(GCMarker *gcmarker, JSScript *thing);
|
||||
|
||||
static inline void
|
||||
PushMarkStack(GCMarker *gcmarker, const Shape *thing);
|
||||
|
||||
@ -108,7 +112,6 @@ static inline void
|
||||
CheckMarkedThing(JSTracer *trc, T *thing)
|
||||
{
|
||||
JS_ASSERT(thing);
|
||||
JS_ASSERT(JS_IS_VALID_TRACE_KIND(GetGCThingTraceKind(thing)));
|
||||
JS_ASSERT(trc->debugPrinter || trc->debugPrintArg);
|
||||
JS_ASSERT_IF(trc->context->runtime->gcCurrentCompartment, IS_GC_MARKING_TRACER(trc));
|
||||
|
||||
@ -194,6 +197,15 @@ MarkObjectWithPrinter(JSTracer *trc, JSObject &obj, JSTraceNamePrinter printer,
|
||||
Mark(trc, &obj);
|
||||
}
|
||||
|
||||
void
|
||||
MarkScript(JSTracer *trc, JSScript *script, const char *name)
|
||||
{
|
||||
JS_ASSERT(trc);
|
||||
JS_ASSERT(script);
|
||||
JS_SET_TRACING_NAME(trc, name);
|
||||
Mark(trc, script);
|
||||
}
|
||||
|
||||
void
|
||||
MarkShape(JSTracer *trc, const Shape *shape, const char *name)
|
||||
{
|
||||
@ -223,7 +235,7 @@ MarkTypeObject(JSTracer *trc, types::TypeObject *type, const char *name)
|
||||
if (type->singleton)
|
||||
MarkObject(trc, *type->singleton, "type_singleton");
|
||||
if (type->functionScript)
|
||||
js_TraceScript(trc, type->functionScript, NULL);
|
||||
MarkScript(trc, type->functionScript, "functionScript");
|
||||
}
|
||||
}
|
||||
|
||||
@ -287,6 +299,21 @@ PushMarkStack(GCMarker *gcmarker, JSShortString *thing)
|
||||
(void) thing->markIfUnmarked(gcmarker->getMarkColor());
|
||||
}
|
||||
|
||||
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
|
||||
ScanShape(GCMarker *gcmarker, const Shape *shape);
|
||||
|
||||
@ -301,7 +328,7 @@ PushMarkStack(GCMarker *gcmarker, const Shape *thing)
|
||||
ScanShape(gcmarker, thing);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
MarkAtomRange(JSTracer *trc, size_t len, JSAtom **vec, const char *name)
|
||||
{
|
||||
for (uint32 i = 0; i < len; i++) {
|
||||
@ -370,30 +397,31 @@ MarkIdRange(JSTracer *trc, size_t len, jsid *vec, const char *name)
|
||||
}
|
||||
|
||||
void
|
||||
MarkKind(JSTracer *trc, void *thing, uint32 kind)
|
||||
MarkKind(JSTracer *trc, void *thing, JSGCTraceKind 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;
|
||||
case JSTRACE_TYPE_OBJECT:
|
||||
Mark(trc, reinterpret_cast<types::TypeObject *>(thing));
|
||||
break;
|
||||
case JSTRACE_OBJECT:
|
||||
Mark(trc, reinterpret_cast<JSObject *>(thing));
|
||||
break;
|
||||
case JSTRACE_STRING:
|
||||
MarkString(trc, reinterpret_cast<JSString *>(thing));
|
||||
break;
|
||||
case JSTRACE_SCRIPT:
|
||||
Mark(trc, static_cast<JSScript *>(thing));
|
||||
break;
|
||||
case JSTRACE_SHAPE:
|
||||
Mark(trc, reinterpret_cast<Shape *>(thing));
|
||||
break;
|
||||
case JSTRACE_TYPE_OBJECT:
|
||||
Mark(trc, reinterpret_cast<types::TypeObject *>(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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -462,7 +490,7 @@ MarkShapeRange(JSTracer *trc, size_t len, const Shape **vec, const char *name)
|
||||
|
||||
/* N.B. Assumes JS_SET_TRACING_NAME/INDEX has already been called. */
|
||||
void
|
||||
MarkGCThing(JSTracer *trc, void *thing, uint32 kind)
|
||||
MarkGCThing(JSTracer *trc, void *thing, JSGCTraceKind kind)
|
||||
{
|
||||
if (!thing)
|
||||
return;
|
||||
@ -493,7 +521,7 @@ MarkGCThing(JSTracer *trc, void *thing, const char *name, size_t index)
|
||||
}
|
||||
|
||||
void
|
||||
Mark(JSTracer *trc, void *thing, uint32 kind, const char *name)
|
||||
Mark(JSTracer *trc, void *thing, JSGCTraceKind kind, const char *name)
|
||||
{
|
||||
JS_ASSERT(thing);
|
||||
JS_SET_TRACING_NAME(trc, name);
|
||||
@ -512,6 +540,12 @@ MarkRoot(JSTracer *trc, JSString *thing, const char *name)
|
||||
MarkString(trc, thing, name);
|
||||
}
|
||||
|
||||
void
|
||||
MarkRoot(JSTracer *trc, JSScript *thing, const char *name)
|
||||
{
|
||||
MarkScript(trc, thing, name);
|
||||
}
|
||||
|
||||
void
|
||||
MarkRoot(JSTracer *trc, const Shape *thing, const char *name)
|
||||
{
|
||||
@ -568,19 +602,14 @@ static inline void
|
||||
ScanValue(GCMarker *gcmarker, const Value &v)
|
||||
{
|
||||
if (v.isMarkable()) {
|
||||
switch (v.gcKind()) {
|
||||
case JSTRACE_STRING: {
|
||||
JSGCTraceKind kind = v.gcKind();
|
||||
if (kind == JSTRACE_STRING) {
|
||||
JSString *str = (JSString *)v.toGCThing();
|
||||
if (!str->isStaticAtom())
|
||||
PushMarkStack(gcmarker, str);
|
||||
break;
|
||||
}
|
||||
case JSTRACE_OBJECT:
|
||||
} else {
|
||||
JS_ASSERT(kind == JSTRACE_OBJECT);
|
||||
PushMarkStack(gcmarker, (JSObject *)v.toGCThing());
|
||||
break;
|
||||
case JSTRACE_XML:
|
||||
PushMarkStack(gcmarker, (JSXML *)v.toGCThing());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -792,6 +821,52 @@ MarkChildren(JSTracer *trc, JSString *str)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
|
||||
MarkAtomRange(trc, script->natoms, script->atoms, "atoms");
|
||||
|
||||
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->isCachedEval && script->u.object)
|
||||
MarkObject(trc, *script->u.object, "object");
|
||||
if (script->hasFunction)
|
||||
MarkObject(trc, *script->function(), "script_fun");
|
||||
|
||||
if (IS_GC_MARKING_TRACER(trc) && script->filename)
|
||||
js_MarkScriptFilename(script->filename);
|
||||
|
||||
script->bindings.trace(trc);
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
if (script->jitNormal)
|
||||
script->jitNormal->trace(trc);
|
||||
if (script->jitCtor)
|
||||
script->jitCtor->trace(trc);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
MarkChildren(JSTracer *trc, const Shape *shape)
|
||||
{
|
||||
@ -838,7 +913,7 @@ ScanTypeObject(GCMarker *gcmarker, types::TypeObject *type)
|
||||
PushMarkStack(gcmarker, type->proto);
|
||||
|
||||
if (type->newScript) {
|
||||
js_TraceScript(gcmarker, type->newScript->script, NULL);
|
||||
PushMarkStack(gcmarker, type->newScript->script);
|
||||
PushMarkStack(gcmarker, type->newScript->shape);
|
||||
}
|
||||
|
||||
@ -878,12 +953,12 @@ MarkChildren(JSTracer *trc, types::TypeObject *type)
|
||||
MarkObject(trc, *type->singleton, "type_singleton");
|
||||
|
||||
if (type->newScript) {
|
||||
js_TraceScript(trc, type->newScript->script, NULL);
|
||||
MarkScript(trc, type->newScript->script, "type_new_script");
|
||||
MarkShape(trc, type->newScript->shape, "type_new_shape");
|
||||
}
|
||||
|
||||
if (type->functionScript)
|
||||
js_TraceScript(trc, type->functionScript, NULL);
|
||||
MarkScript(trc, type->functionScript, "functionScript");
|
||||
}
|
||||
|
||||
#ifdef JS_HAS_XML_SUPPORT
|
||||
@ -936,19 +1011,26 @@ GCMarker::drainMarkStack()
|
||||
} /* namespace js */
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_TraceChildren(JSTracer *trc, void *thing, uint32 kind)
|
||||
JS_TraceChildren(JSTracer *trc, void *thing, uint32 kindIndex)
|
||||
{
|
||||
JS_ASSERT(kindIndex <= JSTRACE_LAST);
|
||||
JSGCTraceKind kind = JSGCTraceKind(kindIndex);
|
||||
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_SCRIPT:
|
||||
MarkChildren(trc, static_cast<JSScript *>(thing));
|
||||
break;
|
||||
|
||||
case JSTRACE_SHAPE:
|
||||
MarkChildren(trc, (js::Shape *)thing);
|
||||
MarkChildren(trc, static_cast<Shape *>(thing));
|
||||
break;
|
||||
|
||||
case JSTRACE_TYPE_OBJECT:
|
||||
@ -957,7 +1039,7 @@ JS_TraceChildren(JSTracer *trc, void *thing, uint32 kind)
|
||||
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
case JSTRACE_XML:
|
||||
MarkChildren(trc, (JSXML *)thing);
|
||||
MarkChildren(trc, static_cast<JSXML *>(thing));
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
@ -73,6 +73,9 @@ void
|
||||
MarkObjectWithPrinter(JSTracer *trc, JSObject &obj, JSTraceNamePrinter printer,
|
||||
const void *arg, size_t index);
|
||||
|
||||
void
|
||||
MarkScript(JSTracer *trc, JSScript *script, const char *name);
|
||||
|
||||
void
|
||||
MarkShape(JSTracer *trc, const Shape *shape, const char *name);
|
||||
|
||||
@ -82,9 +85,6 @@ MarkTypeObject(JSTracer *trc, types::TypeObject *type, const char *name);
|
||||
void
|
||||
MarkXML(JSTracer *trc, JSXML *xml, const char *name);
|
||||
|
||||
void
|
||||
MarkAtomRange(JSTracer *trc, size_t len, JSAtom **vec, const char *name);
|
||||
|
||||
void
|
||||
MarkObjectRange(JSTracer *trc, size_t len, JSObject **vec, const char *name);
|
||||
|
||||
@ -104,7 +104,7 @@ void
|
||||
MarkIdRange(JSTracer *trc, size_t len, jsid *vec, const char *name);
|
||||
|
||||
void
|
||||
MarkKind(JSTracer *trc, void *thing, uint32 kind);
|
||||
MarkKind(JSTracer *trc, void *thing, JSGCTraceKind kind);
|
||||
|
||||
void
|
||||
MarkValueRaw(JSTracer *trc, const js::Value &v);
|
||||
@ -153,6 +153,9 @@ MarkRoot(JSTracer *trc, JSObject *thing, const char *name);
|
||||
void
|
||||
MarkRoot(JSTracer *trc, JSString *thing, const char *name);
|
||||
|
||||
void
|
||||
MarkRoot(JSTracer *trc, JSScript *thing, const char *name);
|
||||
|
||||
void
|
||||
MarkRoot(JSTracer *trc, const Shape *thing, const char *name);
|
||||
|
||||
@ -171,6 +174,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);
|
||||
|
||||
|
@ -155,18 +155,11 @@ GCMarker::dumpConservativeRoots()
|
||||
fprintf(fp, " %p: ", thing);
|
||||
|
||||
switch (GetGCThingTraceKind(thing)) {
|
||||
default:
|
||||
JS_NOT_REACHED("Unknown trace kind");
|
||||
|
||||
case JSTRACE_OBJECT: {
|
||||
JSObject *obj = (JSObject *) thing;
|
||||
fprintf(fp, "object %s", obj->getClass()->name);
|
||||
break;
|
||||
}
|
||||
case JSTRACE_SHAPE: {
|
||||
fprintf(fp, "shape");
|
||||
break;
|
||||
}
|
||||
case JSTRACE_STRING: {
|
||||
JSString *str = (JSString *) thing;
|
||||
if (str->isLinear()) {
|
||||
@ -178,6 +171,18 @@ GCMarker::dumpConservativeRoots()
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JSTRACE_SCRIPT: {
|
||||
fprintf(fp, "shape");
|
||||
break;
|
||||
}
|
||||
case JSTRACE_SHAPE: {
|
||||
fprintf(fp, "shape");
|
||||
break;
|
||||
}
|
||||
case JSTRACE_TYPE_OBJECT: {
|
||||
fprintf(fp, "type_object");
|
||||
break;
|
||||
}
|
||||
# if JS_HAS_XML_SUPPORT
|
||||
case JSTRACE_XML: {
|
||||
JSXML *xml = (JSXML *) thing;
|
||||
@ -258,7 +263,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 +281,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 +304,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 +314,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;
|
||||
|
@ -2063,16 +2063,14 @@ TypeCompartment::nukeTypes(JSContext *cx)
|
||||
mjit::ExpandInlineFrames(compartment);
|
||||
|
||||
/* Throw away all JIT code in the compartment, but leave everything else alone. */
|
||||
for (JSCList *cursor = compartment->scripts.next;
|
||||
cursor != &compartment->scripts;
|
||||
cursor = cursor->next) {
|
||||
JSScript *script = reinterpret_cast<JSScript *>(cursor);
|
||||
|
||||
for (gc::CellIter i(cx, cx->compartment, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
|
||||
JSScript *script = i.get<JSScript>();
|
||||
if (script->hasJITCode()) {
|
||||
mjit::Recompiler recompiler(cx, script);
|
||||
recompiler.recompile();
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* JS_METHODJIT */
|
||||
|
||||
}
|
||||
@ -2140,40 +2138,6 @@ TypeCompartment::monitorBytecode(JSContext *cx, JSScript *script, uint32 offset,
|
||||
ObjectStateChange(cx, script->function()->type(), false, true);
|
||||
}
|
||||
|
||||
/*
|
||||
* State for keeping track of which property type sets contain an object we are
|
||||
* scrubbing from all properties in the compartment. We make a list of
|
||||
* properties to update and fix them afterwards, as adding types can't be done
|
||||
* with the GC locked (as is done in IterateCells), and can potentially make
|
||||
* new type objects as well.
|
||||
*/
|
||||
struct MarkSetsUnknownState
|
||||
{
|
||||
TypeObject *target;
|
||||
Vector<TypeSet *> pending;
|
||||
|
||||
MarkSetsUnknownState(JSContext *cx, TypeObject *target)
|
||||
: target(target), pending(cx)
|
||||
{}
|
||||
};
|
||||
|
||||
static void
|
||||
MarkObjectSetsUnknownCallback(JSContext *cx, void *data, void *thing,
|
||||
size_t traceKind, size_t thingSize)
|
||||
{
|
||||
MarkSetsUnknownState *state = (MarkSetsUnknownState *) data;
|
||||
TypeObject *object = (TypeObject *) thing;
|
||||
|
||||
unsigned count = object->getPropertyCount();
|
||||
for (unsigned i = 0; i < count; i++) {
|
||||
Property *prop = object->getProperty(i);
|
||||
if (prop && prop->types.hasType(Type::ObjectType(state->target))) {
|
||||
if (!state->pending.append(&prop->types))
|
||||
cx->compartment->types.setPendingNukeTypes(cx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TypeCompartment::markSetsUnknown(JSContext *cx, TypeObject *target)
|
||||
{
|
||||
@ -2190,20 +2154,30 @@ TypeCompartment::markSetsUnknown(JSContext *cx, TypeObject *target)
|
||||
* a generic object type. It is not sufficient to mark just the persistent
|
||||
* sets, as analysis of individual opcodes can pull type objects from
|
||||
* static information (like initializer objects at various offsets).
|
||||
*
|
||||
* We make a list of properties to update and fix them afterwards, as adding
|
||||
* types can't be done while iterating over cells as it can potentially make
|
||||
* new type objects as well or trigger GC.
|
||||
*/
|
||||
Vector<TypeSet *> pending(cx);
|
||||
for (gc::CellIter i(cx, cx->compartment, gc::FINALIZE_TYPE_OBJECT); !i.done(); i.next()) {
|
||||
TypeObject *object = i.get<TypeObject>();
|
||||
|
||||
MarkSetsUnknownState state(cx, target);
|
||||
unsigned count = object->getPropertyCount();
|
||||
for (unsigned i = 0; i < count; i++) {
|
||||
Property *prop = object->getProperty(i);
|
||||
if (prop && prop->types.hasType(Type::ObjectType(target))) {
|
||||
if (!pending.append(&prop->types))
|
||||
cx->compartment->types.setPendingNukeTypes(cx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IterateCells(cx, cx->compartment, gc::FINALIZE_TYPE_OBJECT,
|
||||
(void *) &state, MarkObjectSetsUnknownCallback);
|
||||
for (unsigned i = 0; i < pending.length(); i++)
|
||||
pending[i]->addType(cx, Type::AnyObjectType());
|
||||
|
||||
for (unsigned i = 0; i < state.pending.length(); i++)
|
||||
state.pending[i]->addType(cx, Type::AnyObjectType());
|
||||
|
||||
for (JSCList *cursor = cx->compartment->scripts.next;
|
||||
cursor != &cx->compartment->scripts;
|
||||
cursor = cursor->next) {
|
||||
JSScript *script = reinterpret_cast<JSScript *>(cursor);
|
||||
for (gc::CellIter i(cx, cx->compartment, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
|
||||
JSScript *script = i.get<JSScript>();
|
||||
if (script->types) {
|
||||
unsigned count = TypeScript::NumTypeSets(script);
|
||||
TypeSet *typeArray = script->types->typeArray();
|
||||
@ -2306,11 +2280,23 @@ ScriptAnalysis::addSingletonTypeBarrier(JSContext *cx, const jsbytecode *pc, Typ
|
||||
code.typeBarriers = barrier;
|
||||
}
|
||||
|
||||
static void
|
||||
PrintScriptTypeCallback(JSContext *cx, void *data, void *thing,
|
||||
JSGCTraceKind traceKind, size_t thingSize)
|
||||
{
|
||||
JS_ASSERT(!data);
|
||||
JS_ASSERT(traceKind == JSTRACE_SCRIPT);
|
||||
JSScript *script = static_cast<JSScript *>(thing);
|
||||
if (script->hasAnalysis() && script->analysis()->ranInference())
|
||||
script->analysis()->printTypes(cx);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
static void
|
||||
PrintObjectCallback(JSContext *cx, void *data, void *thing,
|
||||
size_t traceKind, size_t thingSize)
|
||||
JSGCTraceKind traceKind, size_t thingSize)
|
||||
{
|
||||
JS_ASSERT(traceKind == JSTRACE_OBJECT);
|
||||
TypeObject *object = (TypeObject *) thing;
|
||||
object->print(cx);
|
||||
}
|
||||
@ -2321,17 +2307,12 @@ TypeCompartment::print(JSContext *cx, bool force)
|
||||
{
|
||||
JSCompartment *compartment = this->compartment();
|
||||
|
||||
if (JS_CLIST_IS_EMPTY(&compartment->scripts))
|
||||
return;
|
||||
|
||||
if (!force && !InferSpewActive(ISpewResult))
|
||||
return;
|
||||
|
||||
for (JSScript *script = (JSScript *)compartment->scripts.next;
|
||||
&script->links != &compartment->scripts;
|
||||
script = (JSScript *)script->links.next) {
|
||||
if (script->hasAnalysis() && script->analysis()->ranInference())
|
||||
script->analysis()->printTypes(cx);
|
||||
{
|
||||
AutoUnlockGC unlock(cx->runtime);
|
||||
IterateCells(cx, compartment, gc::FINALIZE_SCRIPT, cx, PrintScriptTypeCallback);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
@ -4473,7 +4454,7 @@ void
|
||||
ScriptAnalysis::printTypes(JSContext *cx)
|
||||
{
|
||||
AutoEnterAnalysis enter(cx);
|
||||
TypeCompartment *compartment = &script->compartment->types;
|
||||
TypeCompartment *compartment = &script->compartment()->types;
|
||||
|
||||
/*
|
||||
* Check if there are warnings for used values with unknown types, and build
|
||||
@ -5011,7 +4992,6 @@ JSScript::typeSetFunction(JSContext *cx, JSFunction *fun, bool singleton)
|
||||
JSProto_Function, fun->getProto());
|
||||
if (!type)
|
||||
return false;
|
||||
AutoTypeRooter root(cx, type);
|
||||
|
||||
fun->setType(type);
|
||||
type->functionScript = this;
|
||||
@ -5531,7 +5511,7 @@ TypeCompartment::~TypeCompartment()
|
||||
/* static */ void
|
||||
TypeScript::Sweep(JSContext *cx, JSScript *script)
|
||||
{
|
||||
JSCompartment *compartment = script->compartment;
|
||||
JSCompartment *compartment = script->compartment();
|
||||
JS_ASSERT(compartment->types.inferenceEnabled);
|
||||
|
||||
unsigned num = NumTypeSets(script);
|
||||
@ -5617,7 +5597,7 @@ GetScriptMemoryStats(JSScript *script, TypeInferenceMemoryStats *stats)
|
||||
if (!script->types)
|
||||
return;
|
||||
|
||||
if (!script->compartment->types.inferenceEnabled) {
|
||||
if (!script->compartment()->types.inferenceEnabled) {
|
||||
stats->scripts += sizeof(TypeScript);
|
||||
return;
|
||||
}
|
||||
@ -5653,12 +5633,8 @@ JS_GetTypeInferenceMemoryStats(JSContext *cx, JSCompartment *compartment,
|
||||
/* Pending arrays are cleared on GC along with the analysis pool. */
|
||||
stats->temporary += sizeof(TypeCompartment::PendingWork) * compartment->types.pendingCapacity;
|
||||
|
||||
for (JSCList *cursor = compartment->scripts.next;
|
||||
cursor != &compartment->scripts;
|
||||
cursor = cursor->next) {
|
||||
JSScript *script = reinterpret_cast<JSScript *>(cursor);
|
||||
GetScriptMemoryStats(script, stats);
|
||||
}
|
||||
for (gc::CellIter i(cx, compartment, gc::FINALIZE_SCRIPT); !i.done(); i.next())
|
||||
GetScriptMemoryStats(i.get<JSScript>(), stats);
|
||||
|
||||
if (compartment->types.allocationSiteTable)
|
||||
stats->tables += compartment->types.allocationSiteTable->allocatedSize();
|
||||
|
@ -1216,23 +1216,6 @@ TypeObject::setFlagsFromKey(JSContext *cx, JSProtoKey key)
|
||||
setFlags(cx, flags);
|
||||
}
|
||||
|
||||
class AutoTypeRooter : private AutoGCRooter {
|
||||
public:
|
||||
AutoTypeRooter(JSContext *cx, TypeObject *type
|
||||
JS_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: AutoGCRooter(cx, TYPE), type(type)
|
||||
{
|
||||
JS_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
}
|
||||
|
||||
friend void AutoGCRooter::trace(JSTracer *trc);
|
||||
friend void MarkRuntime(JSTracer *trc);
|
||||
|
||||
private:
|
||||
TypeObject *type;
|
||||
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
} } /* namespace js::types */
|
||||
|
||||
inline bool
|
||||
|
@ -914,7 +914,6 @@ ExecuteKernel(JSContext *cx, JSScript *script, JSObject &scopeChain, const Value
|
||||
}
|
||||
|
||||
LeaveTrace(cx);
|
||||
AutoScriptRooter root(cx, script);
|
||||
|
||||
ExecuteFrameGuard efg;
|
||||
if (!cx->stack.pushExecuteFrame(cx, script, thisv, scopeChain, type, evalInFrame, &efg))
|
||||
@ -1856,14 +1855,13 @@ Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode)
|
||||
JS_ASSERT(regs.fp()->hasImacropc() \
|
||||
? atoms == rt->atomState.commonAtomsStart() && \
|
||||
GET_INDEX(regs.pc + PCOFF) < js_common_atom_count \
|
||||
: (size_t)(atoms - script->atomMap.vector) < \
|
||||
(size_t)(script->atomMap.length - \
|
||||
GET_INDEX(regs.pc + PCOFF))); \
|
||||
: (size_t)(atoms - script->atoms) < \
|
||||
(size_t)(script->natoms - GET_INDEX(regs.pc + PCOFF))); \
|
||||
atom = atoms[GET_INDEX(regs.pc + PCOFF)]; \
|
||||
JS_END_MACRO
|
||||
|
||||
#define GET_FULL_INDEX(PCOFF) \
|
||||
(atoms - script->atomMap.vector + GET_INDEX(regs.pc + (PCOFF)))
|
||||
(atoms - script->atoms + GET_INDEX(regs.pc + (PCOFF)))
|
||||
|
||||
#define LOAD_OBJECT(PCOFF, obj) \
|
||||
(obj = script->getObject(GET_FULL_INDEX(PCOFF)))
|
||||
@ -2035,7 +2033,7 @@ Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode)
|
||||
* access. For less frequent object and regexp loads we have to recover
|
||||
* the segment from atoms pointer first.
|
||||
*/
|
||||
JSAtom **atoms = script->atomMap.vector;
|
||||
JSAtom **atoms = script->atoms;
|
||||
|
||||
#if JS_HAS_GENERATORS
|
||||
if (JS_UNLIKELY(regs.fp()->isGeneratorFrame())) {
|
||||
@ -2443,7 +2441,7 @@ BEGIN_CASE(JSOP_STOP)
|
||||
regs.pc += GetDecomposeLength(imacpc, js_CodeSpec[*imacpc].length);
|
||||
regs.fp()->clearImacropc();
|
||||
LEAVE_ON_SAFE_POINT();
|
||||
atoms = script->atomMap.vector;
|
||||
atoms = script->atoms;
|
||||
op = JSOp(*regs.pc);
|
||||
DO_OP();
|
||||
}
|
||||
@ -4359,7 +4357,7 @@ END_CASE(JSOP_INT32)
|
||||
|
||||
BEGIN_CASE(JSOP_INDEXBASE)
|
||||
/*
|
||||
* Here atoms can exceed script->atomMap.length as we use atoms as a
|
||||
* Here atoms can exceed script->natoms as we use atoms as a
|
||||
* segment register for object literals as well.
|
||||
*/
|
||||
atoms += GET_INDEXBASE(regs.pc);
|
||||
@ -4373,7 +4371,7 @@ END_CASE(JSOP_INDEXBASE3)
|
||||
|
||||
BEGIN_CASE(JSOP_RESETBASE0)
|
||||
BEGIN_CASE(JSOP_RESETBASE)
|
||||
atoms = script->atomMap.vector;
|
||||
atoms = script->atoms;
|
||||
END_CASE(JSOP_RESETBASE)
|
||||
|
||||
BEGIN_CASE(JSOP_DOUBLE)
|
||||
@ -4535,7 +4533,7 @@ BEGIN_CASE(JSOP_LOOKUPSWITCH)
|
||||
* index in it would exceed 64K limit.
|
||||
*/
|
||||
JS_ASSERT(!regs.fp()->hasImacropc());
|
||||
JS_ASSERT(atoms == script->atomMap.vector);
|
||||
JS_ASSERT(atoms == script->atoms);
|
||||
jsbytecode *pc2 = regs.pc;
|
||||
|
||||
Value lval = regs.sp[-1];
|
||||
@ -5499,7 +5497,7 @@ END_CASE(JSOP_SHARPINIT)
|
||||
{
|
||||
BEGIN_CASE(JSOP_GOSUB)
|
||||
PUSH_BOOLEAN(false);
|
||||
jsint i = (regs.pc - script->main) + JSOP_GOSUB_LENGTH;
|
||||
jsint i = (regs.pc - script->code) + JSOP_GOSUB_LENGTH;
|
||||
PUSH_INT32(i);
|
||||
len = GET_JUMP_OFFSET(regs.pc);
|
||||
END_VARLEN_CASE
|
||||
@ -5508,7 +5506,7 @@ END_VARLEN_CASE
|
||||
{
|
||||
BEGIN_CASE(JSOP_GOSUBX)
|
||||
PUSH_BOOLEAN(false);
|
||||
jsint i = (regs.pc - script->main) + JSOP_GOSUBX_LENGTH;
|
||||
jsint i = (regs.pc - script->code) + JSOP_GOSUBX_LENGTH;
|
||||
len = GET_JUMPX_OFFSET(regs.pc);
|
||||
PUSH_INT32(i);
|
||||
END_VARLEN_CASE
|
||||
@ -5533,7 +5531,7 @@ BEGIN_CASE(JSOP_RETSUB)
|
||||
}
|
||||
JS_ASSERT(rval.isInt32());
|
||||
len = rval.toInt32();
|
||||
regs.pc = script->main;
|
||||
regs.pc = script->code;
|
||||
END_VARLEN_CASE
|
||||
}
|
||||
|
||||
@ -6162,7 +6160,7 @@ END_CASE(JSOP_ARRAYPUSH)
|
||||
uint32 offset;
|
||||
|
||||
/* Restore atoms local in case we will resume. */
|
||||
atoms = script->atomMap.vector;
|
||||
atoms = script->atoms;
|
||||
|
||||
/* Call debugger throw hook if set. */
|
||||
if (cx->debugHooks->throwHook || !cx->compartment->getDebuggees().empty()) {
|
||||
@ -6197,7 +6195,7 @@ END_CASE(JSOP_ARRAYPUSH)
|
||||
if (!JSScript::isValidOffset(script->trynotesOffset))
|
||||
goto no_catch;
|
||||
|
||||
offset = (uint32)(regs.pc - script->main);
|
||||
offset = (uint32)(regs.pc - script->main());
|
||||
tn = script->trynotes()->vector;
|
||||
tnlimit = tn + script->trynotes()->length;
|
||||
do {
|
||||
@ -6231,7 +6229,7 @@ END_CASE(JSOP_ARRAYPUSH)
|
||||
* to the beginning of catch or finally or to [enditer] closing
|
||||
* the for-in loop.
|
||||
*/
|
||||
regs.pc = (script)->main + tn->start + tn->length;
|
||||
regs.pc = (script)->main() + tn->start + tn->length;
|
||||
|
||||
JSBool ok = js_UnwindScope(cx, tn->stackDepth, JS_TRUE);
|
||||
JS_ASSERT(regs.sp == regs.fp()->base() + tn->stackDepth);
|
||||
|
@ -984,7 +984,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 *
|
||||
@ -1032,7 +1032,7 @@ EvalCacheLookup(JSContext *cx, JSLinearString *str, StackFrame *caller, uintN st
|
||||
* Get the source string passed for safekeeping in the
|
||||
* atom map by the prior eval to Compiler::compileScript.
|
||||
*/
|
||||
JSAtom *src = script->atomMap.vector[0];
|
||||
JSAtom *src = script->atoms[0];
|
||||
|
||||
if (src == str || EqualStrings(src, str)) {
|
||||
/*
|
||||
@ -1056,8 +1056,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;
|
||||
}
|
||||
}
|
||||
@ -1066,7 +1066,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;
|
||||
}
|
||||
@ -1080,7 +1080,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
|
||||
{
|
||||
@ -1102,11 +1102,8 @@ class EvalScriptGuard
|
||||
js_CallDestroyScriptHook(cx_, script_);
|
||||
script_->isActiveEval = false;
|
||||
script_->isCachedEval = true;
|
||||
script_->u.nextToGC = *bucket_;
|
||||
script_->u.evalHashLink = *bucket_;
|
||||
*bucket_ = script_;
|
||||
#ifdef CHECK_SCRIPT_OWNER
|
||||
script_->owner = NULL;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -5578,12 +5575,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) ||
|
||||
@ -5646,14 +5639,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) ||
|
||||
|
@ -1132,6 +1132,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);
|
||||
|
||||
|
@ -655,6 +655,37 @@ JSObject::getFlatClosureUpvars() const
|
||||
return (js::Value *) getFixedSlot(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
|
||||
{
|
||||
|
@ -258,7 +258,6 @@ public:
|
||||
// No change needed
|
||||
newPC = origPC;
|
||||
} else {
|
||||
script->main += newCode - script->code;
|
||||
*pc = newPC = origPC + (newCode - script->code);
|
||||
script->code = newCode;
|
||||
#ifdef DEBUG
|
||||
@ -274,7 +273,6 @@ public:
|
||||
jsbytecode *oldCode = script->code - delta;
|
||||
cx->free_(script->code);
|
||||
script->code = oldCode;
|
||||
script->main -= delta;
|
||||
#ifdef DEBUG
|
||||
cx->stackIterAssertionEnabled = assertionBefore;
|
||||
#endif
|
||||
@ -313,7 +311,7 @@ js_DisassembleAtPC(JSContext *cx, JSScript *script, JSBool lines, jsbytecode *pc
|
||||
next = script->code;
|
||||
end = next + script->length;
|
||||
while (next < end) {
|
||||
if (next == script->main)
|
||||
if (next == script->main())
|
||||
SprintCString(sp, "main:\n");
|
||||
if (pc != NULL) {
|
||||
if (pc == next)
|
||||
@ -2023,8 +2021,8 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
||||
JS_BEGIN_MACRO \
|
||||
jsatomid atomIndex_ = (jsatomid) js_GetSrcNoteOffset((sn), 0); \
|
||||
\
|
||||
LOCAL_ASSERT(atomIndex_ < jp->script->atomMap.length); \
|
||||
(atom) = jp->script->atomMap.vector[atomIndex_]; \
|
||||
LOCAL_ASSERT(atomIndex_ < jp->script->natoms); \
|
||||
(atom) = jp->script->atoms[atomIndex_]; \
|
||||
JS_END_MACRO
|
||||
|
||||
/*
|
||||
@ -4110,8 +4108,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
||||
* Decompile only the main bytecode, to avoid tripping over
|
||||
* new prolog ops that have stack effects.
|
||||
*/
|
||||
ok = Decompile(&ss2, inner->main,
|
||||
inner->length - (inner->main - inner->code),
|
||||
ok = Decompile(&ss2, inner->main(), inner->length - inner->mainOffset,
|
||||
JSOP_NOP)
|
||||
!= NULL;
|
||||
jp->script = outer;
|
||||
@ -4997,7 +4994,7 @@ js_DecompileFunction(JSPrinter *jp)
|
||||
#endif
|
||||
|
||||
/* Print the parameters. */
|
||||
pc = script->main;
|
||||
pc = script->main();
|
||||
AutoScriptUntrapper untrapper(jp->sprinter.context, script, &pc);
|
||||
endpc = pc + script->length;
|
||||
ok = JS_TRUE;
|
||||
@ -5106,7 +5103,7 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v_in,
|
||||
pc = fp->hasImacropc() ? fp->imacropc() : cx->regs().pc;
|
||||
JS_ASSERT(script->code <= pc && pc < script->code + script->length);
|
||||
|
||||
if (pc < script->main)
|
||||
if (pc < script->main())
|
||||
goto do_fallback;
|
||||
|
||||
if (spindex != JSDVG_IGNORE_STACK) {
|
||||
|
@ -971,7 +971,7 @@ Compiler::compileScript(JSContext *cx, JSObject *scopeChain, StackFrame *callerF
|
||||
if (tcflags & TCF_COMPILE_N_GO) {
|
||||
if (source) {
|
||||
/*
|
||||
* Save eval program source in script->atomMap.vector[0] for the
|
||||
* Save eval program source in script->atoms[0] for the
|
||||
* eval cache (see EvalCacheLookup in jsobj.cpp).
|
||||
*/
|
||||
JSAtom *atom = js_AtomizeString(cx, source);
|
||||
@ -1114,11 +1114,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);
|
||||
@ -1128,11 +1125,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;
|
||||
}
|
||||
|
@ -92,7 +92,6 @@ typedef struct JSTreeContext JSTreeContext;
|
||||
typedef struct JSTryNote JSTryNote;
|
||||
|
||||
/* Friend "Advanced API" typedefs. */
|
||||
typedef struct JSAtomMap JSAtomMap;
|
||||
typedef struct JSAtomState JSAtomState;
|
||||
typedef struct JSCodeSpec JSCodeSpec;
|
||||
typedef struct JSPrinter JSPrinter;
|
||||
|
@ -291,30 +291,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) {
|
||||
if (script->cookie1[0] != JS_SCRIPT_COOKIE || script->cookie2[0] != 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 {
|
||||
@ -382,7 +382,6 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp)
|
||||
JS_ASSERT(nupvars != Bindings::BINDING_COUNT_LIMIT);
|
||||
|
||||
Bindings bindings(cx);
|
||||
AutoBindingsRooter rooter(cx, bindings);
|
||||
uint32 nameCount = nargs + nvars + nupvars;
|
||||
if (nameCount > 0) {
|
||||
struct AutoMark {
|
||||
@ -472,13 +471,13 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp)
|
||||
return JS_FALSE;
|
||||
|
||||
if (xdr->mode == JSXDR_ENCODE) {
|
||||
prologLength = script->main - script->code;
|
||||
prologLength = script->mainOffset;
|
||||
JS_ASSERT(script->getVersion() != JSVERSION_UNKNOWN);
|
||||
version = (uint32)script->getVersion() | (script->nfixed << 16);
|
||||
lineno = (uint32)script->lineno;
|
||||
nslots = (uint32)script->nslots;
|
||||
nslots = (uint32)((script->staticLevel << 16) | script->nslots);
|
||||
natoms = (uint32)script->atomMap.length;
|
||||
natoms = script->natoms;
|
||||
|
||||
notes = script->notes();
|
||||
nsrcnotes = script->numNotes();
|
||||
@ -544,8 +543,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,14 +557,13 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp)
|
||||
return JS_FALSE;
|
||||
|
||||
script->bindings.transfer(cx, &bindings);
|
||||
|
||||
script->main += prologLength;
|
||||
JS_ASSERT(!script->mainOffset);
|
||||
script->mainOffset = prologLength;
|
||||
script->nfixed = uint16(version >> 16);
|
||||
|
||||
/* 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;
|
||||
@ -657,7 +653,7 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp)
|
||||
}
|
||||
|
||||
for (i = 0; i != natoms; ++i) {
|
||||
if (!js_XDRAtom(xdr, &script->atomMap.vector[i]))
|
||||
if (!js_XDRAtom(xdr, &script->atoms[i]))
|
||||
goto error;
|
||||
}
|
||||
|
||||
@ -744,10 +740,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;
|
||||
}
|
||||
@ -774,20 +768,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 = {
|
||||
@ -801,7 +789,7 @@ Class js_ScriptClass = {
|
||||
EnumerateStub,
|
||||
ResolveStub,
|
||||
ConvertStub,
|
||||
script_finalize,
|
||||
NULL, /* finalize */
|
||||
NULL, /* reserved0 */
|
||||
NULL, /* checkAccess */
|
||||
NULL, /* call */
|
||||
@ -877,8 +865,8 @@ js_SweepScriptFilenames(JSCompartment *comp)
|
||||
* use script->regexps() to access it.
|
||||
* JSTryNoteArray script try notes' descriptor if JSScript.tryNotesOffset
|
||||
* != 0, use script->trynotes() to access it.
|
||||
* JSAtom *a[] array of JSScript.atomMap.length atoms pointed by
|
||||
* JSScript.atomMap.vector if any.
|
||||
* JSAtom *a[] array of JSScript.natoms atoms pointed by
|
||||
* JSScript.atoms if any.
|
||||
* JSObject *o[] array of script->objects()->length objects if any
|
||||
* pointed by script->objects()->vector.
|
||||
* JSObject *r[] array of script->regexps()->length regexps if any
|
||||
@ -925,16 +913,7 @@ JSScript::NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natom
|
||||
uint32 ntrynotes, uint32 nconsts, uint32 nglobals,
|
||||
uint16 nClosedArgs, uint16 nClosedVars, uint32 nTypeSets, JSVersion version)
|
||||
{
|
||||
size_t size, vectorSize;
|
||||
JSScript *script;
|
||||
uint8 *cursor;
|
||||
unsigned constPadding = 0;
|
||||
|
||||
uint32 totalClosed = nClosedArgs + nClosedVars;
|
||||
|
||||
size = sizeof(JSScript) +
|
||||
sizeof(JSAtom *) * natoms;
|
||||
|
||||
size_t size = sizeof(JSAtom *) * natoms;
|
||||
if (nobjects != 0)
|
||||
size += sizeof(JSObjectArray) + nobjects * sizeof(JSObject *);
|
||||
if (nupvars != 0)
|
||||
@ -945,31 +924,66 @@ JSScript::NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natom
|
||||
size += sizeof(JSTryNoteArray) + ntrynotes * sizeof(JSTryNote);
|
||||
if (nglobals != 0)
|
||||
size += sizeof(GlobalSlotArray) + nglobals * sizeof(GlobalSlotArray::Entry);
|
||||
uint32 totalClosed = nClosedArgs + nClosedVars;
|
||||
if (totalClosed != 0)
|
||||
size += totalClosed * sizeof(uint32);
|
||||
|
||||
if (nconsts != 0) {
|
||||
size += sizeof(JSConstArray);
|
||||
/*
|
||||
* To esnure jsval alignment for the const array we place it immediately
|
||||
* after JSSomethingArray structs as their sizes all divide sizeof(jsval).
|
||||
* This works as long as the data itself is allocated with proper
|
||||
* alignment which we ensure below.
|
||||
*/
|
||||
JS_STATIC_ASSERT(sizeof(JSObjectArray) % sizeof(jsval) == 0);
|
||||
JS_STATIC_ASSERT(sizeof(JSUpvarArray) % sizeof(jsval) == 0);
|
||||
JS_STATIC_ASSERT(sizeof(JSTryNoteArray) % sizeof(jsval) == 0);
|
||||
JS_STATIC_ASSERT(sizeof(GlobalSlotArray) % sizeof(jsval) == 0);
|
||||
JS_STATIC_ASSERT(sizeof(JSConstArray) % sizeof(jsval) == 0);
|
||||
if (nconsts != 0)
|
||||
size += sizeof(JSConstArray) + nconsts * sizeof(Value);
|
||||
|
||||
size += length * sizeof(jsbytecode) + nsrcnotes * sizeof(jssrcnote);
|
||||
|
||||
uint8 *data = NULL;
|
||||
#if JS_SCRIPT_INLINE_DATA_LIMIT
|
||||
if (size <= JS_SCRIPT_INLINE_DATA_LIMIT) {
|
||||
/*
|
||||
* Calculate padding assuming that consts go after the other arrays,
|
||||
* but before the bytecode and source notes.
|
||||
* Check that if inlineData is big enough to store const values, we
|
||||
* can do that without any special alignment requirements given that
|
||||
* the script as a GC thing is always aligned on Cell::CellSize.
|
||||
*/
|
||||
constPadding = (8 - (size % 8)) % 8;
|
||||
size += constPadding + nconsts * sizeof(Value);
|
||||
JS_STATIC_ASSERT(Cell::CellSize % sizeof(Value) == 0);
|
||||
JS_STATIC_ASSERT(JS_SCRIPT_INLINE_DATA_LIMIT < sizeof(Value) ||
|
||||
offsetof(JSScript, inlineData) % sizeof(Value) == 0);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
/*
|
||||
* We assume that calloc aligns on sizeof(Value) if the size we ask to
|
||||
* allocate divides sizeof(Value).
|
||||
*/
|
||||
JS_STATIC_ASSERT(sizeof(Value) == sizeof(jsdouble));
|
||||
data = static_cast<uint8 *>(cx->calloc_(JS_ROUNDUP(size, sizeof(Value))));
|
||||
if (!data)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size += length * sizeof(jsbytecode) +
|
||||
nsrcnotes * sizeof(jssrcnote);
|
||||
|
||||
script = (JSScript *) cx->malloc_(size);
|
||||
if (!script)
|
||||
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->cookie1[0] = script->cookie2[0] = JS_SCRIPT_COOKIE;
|
||||
script->ownerObject = JS_NEW_SCRIPT;
|
||||
#endif
|
||||
#if JS_SCRIPT_INLINE_DATA_LIMIT
|
||||
if (!data)
|
||||
data = script->inlineData;
|
||||
#endif
|
||||
script->data = data;
|
||||
script->length = length;
|
||||
script->version = version;
|
||||
new (&script->bindings) Bindings(cx);
|
||||
@ -977,42 +991,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;
|
||||
@ -1024,39 +1036,36 @@ JSScript::NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natom
|
||||
sizeof(JSTryNoteArray) +
|
||||
sizeof(GlobalSlotArray) < 0xFF);
|
||||
|
||||
if (natoms != 0) {
|
||||
script->atomMap.length = natoms;
|
||||
script->atomMap.vector = (JSAtom **)cursor;
|
||||
vectorSize = natoms * sizeof(script->atomMap.vector[0]);
|
||||
|
||||
/*
|
||||
* Clear object map's vector so the GC tracing can run when not yet
|
||||
* all atoms are copied to the array.
|
||||
*/
|
||||
memset(cursor, 0, vectorSize);
|
||||
cursor += vectorSize;
|
||||
if (nconsts != 0) {
|
||||
JS_ASSERT(reinterpret_cast<jsuword>(cursor) % sizeof(jsval) == 0);
|
||||
script->consts()->length = nconsts;
|
||||
script->consts()->vector = reinterpret_cast<Value *>(cursor);
|
||||
cursor += nconsts * sizeof(script->consts()->vector[0]);
|
||||
}
|
||||
|
||||
if (natoms != 0) {
|
||||
script->natoms = natoms;
|
||||
script->atoms = reinterpret_cast<JSAtom **>(cursor);
|
||||
cursor += natoms * sizeof(script->atoms[0]);
|
||||
}
|
||||
|
||||
if (nobjects != 0) {
|
||||
script->objects()->length = nobjects;
|
||||
script->objects()->vector = (JSObject **)cursor;
|
||||
vectorSize = nobjects * sizeof(script->objects()->vector[0]);
|
||||
memset(cursor, 0, vectorSize);
|
||||
cursor += vectorSize;
|
||||
script->objects()->vector = reinterpret_cast<JSObject **>(cursor);
|
||||
cursor += nobjects * sizeof(script->objects()->vector[0]);
|
||||
}
|
||||
|
||||
if (nregexps != 0) {
|
||||
script->regexps()->length = nregexps;
|
||||
script->regexps()->vector = (JSObject **)cursor;
|
||||
vectorSize = nregexps * sizeof(script->regexps()->vector[0]);
|
||||
memset(cursor, 0, vectorSize);
|
||||
cursor += vectorSize;
|
||||
script->regexps()->vector = reinterpret_cast<JSObject **>(cursor);
|
||||
cursor += nregexps * sizeof(script->regexps()->vector[0]);
|
||||
}
|
||||
|
||||
if (ntrynotes != 0) {
|
||||
script->trynotes()->length = ntrynotes;
|
||||
script->trynotes()->vector = (JSTryNote *)cursor;
|
||||
vectorSize = ntrynotes * sizeof(script->trynotes()->vector[0]);
|
||||
script->trynotes()->vector = reinterpret_cast<JSTryNote *>(cursor);
|
||||
size_t vectorSize = ntrynotes * sizeof(script->trynotes()->vector[0]);
|
||||
#ifdef DEBUG
|
||||
memset(cursor, 0, vectorSize);
|
||||
#endif
|
||||
@ -1065,15 +1074,14 @@ JSScript::NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natom
|
||||
|
||||
if (nglobals != 0) {
|
||||
script->globals()->length = nglobals;
|
||||
script->globals()->vector = (GlobalSlotArray::Entry *)cursor;
|
||||
vectorSize = nglobals * sizeof(script->globals()->vector[0]);
|
||||
cursor += vectorSize;
|
||||
script->globals()->vector = reinterpret_cast<GlobalSlotArray::Entry *>(cursor);
|
||||
cursor += nglobals * sizeof(script->globals()->vector[0]);
|
||||
}
|
||||
|
||||
if (totalClosed != 0) {
|
||||
script->nClosedArgs = nClosedArgs;
|
||||
script->nClosedVars = nClosedVars;
|
||||
script->closedSlots = (uint32 *)cursor;
|
||||
script->closedSlots = reinterpret_cast<uint32 *>(cursor);
|
||||
cursor += totalClosed * sizeof(uint32);
|
||||
}
|
||||
|
||||
@ -1087,39 +1095,16 @@ JSScript::NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natom
|
||||
if (nupvars != 0) {
|
||||
script->upvars()->length = nupvars;
|
||||
script->upvars()->vector = reinterpret_cast<UpvarCookie *>(cursor);
|
||||
vectorSize = nupvars * sizeof(script->upvars()->vector[0]);
|
||||
memset(cursor, 0, vectorSize);
|
||||
cursor += vectorSize;
|
||||
cursor += nupvars * sizeof(script->upvars()->vector[0]);
|
||||
}
|
||||
|
||||
/* Must go after other arrays; see constPadding definition. */
|
||||
if (nconsts != 0) {
|
||||
cursor += constPadding;
|
||||
script->consts()->length = nconsts;
|
||||
script->consts()->vector = (Value *)cursor;
|
||||
JS_ASSERT((size_t)cursor % sizeof(double) == 0);
|
||||
vectorSize = nconsts * sizeof(script->consts()->vector[0]);
|
||||
memset(cursor, 0, vectorSize);
|
||||
cursor += vectorSize;
|
||||
}
|
||||
|
||||
script->code = script->main = (jsbytecode *)cursor;
|
||||
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
|
||||
script->code = (jsbytecode *)cursor;
|
||||
JS_ASSERT(cursor + length * sizeof(jsbytecode) + nsrcnotes * sizeof(jssrcnote) == data + size);
|
||||
|
||||
#ifdef DEBUG
|
||||
script->id_ = ++cx->compartment->types.scriptCount;
|
||||
#endif
|
||||
|
||||
JS_APPEND_LINK(&script->links, &cx->compartment->scripts);
|
||||
|
||||
JS_ASSERT(script->getVersion() == version);
|
||||
return script;
|
||||
}
|
||||
@ -1159,29 +1144,28 @@ 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;
|
||||
JS_ASSERT(script->mainOffset == 0);
|
||||
script->mainOffset = prologLength;
|
||||
memcpy(script->code, CG_PROLOG_BASE(cg), prologLength * sizeof(jsbytecode));
|
||||
memcpy(script->main, CG_BASE(cg), mainLength * sizeof(jsbytecode));
|
||||
memcpy(script->main(), CG_BASE(cg), mainLength * sizeof(jsbytecode));
|
||||
nfixed = cg->inFunction()
|
||||
? cg->bindings.countVars()
|
||||
: cg->sharpSlots();
|
||||
JS_ASSERT(nfixed < SLOTNO_LIMIT);
|
||||
script->nfixed = (uint16) nfixed;
|
||||
js_InitAtomMap(cx, &script->atomMap, cg->atomIndices.getMap());
|
||||
js_InitAtomMap(cx, cg->atomIndices.getMap(), script->atoms);
|
||||
|
||||
filename = cg->parser->tokenStream.getFilename();
|
||||
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);
|
||||
@ -1192,7 +1176,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)
|
||||
@ -1265,9 +1249,6 @@ JSScript::NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
|
||||
JS_ASSERT(script->upvars()->length == script->bindings.countUpvars());
|
||||
else
|
||||
JS_ASSERT(script->bindings.countUpvars() == 0);
|
||||
#endif
|
||||
#ifdef CHECK_SCRIPT_OWNER
|
||||
script->owner = NULL;
|
||||
#endif
|
||||
if (cg->flags & TCF_FUN_HEAVYWEIGHT)
|
||||
fun->flags |= JSFUN_HEAVYWEIGHT;
|
||||
@ -1278,7 +1259,7 @@ JSScript::NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
|
||||
cg->parent->asCodeGenerator()->checkSingletonContext();
|
||||
|
||||
if (!script->typeSetFunction(cx, fun, singleton))
|
||||
goto bad;
|
||||
return NULL;
|
||||
|
||||
fun->u.i.script = script;
|
||||
script->setOwnerObject(fun);
|
||||
@ -1288,7 +1269,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. */
|
||||
@ -1302,20 +1283,19 @@ 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;
|
||||
#if JS_SCRIPT_INLINE_DATA_LIMIT
|
||||
if (data == inlineData)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
uint8 *dataEnd = code + length * sizeof(jsbytecode) + numNotes() * sizeof(jssrcnote);
|
||||
JS_ASSERT(dataEnd >= data);
|
||||
return dataEnd - data;
|
||||
}
|
||||
|
||||
void
|
||||
@ -1344,200 +1324,67 @@ 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
|
||||
|
||||
if (script->types)
|
||||
script->types->destroy();
|
||||
if (types)
|
||||
types->destroy();
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
mjit::ReleaseScriptCode(cx, script);
|
||||
mjit::ReleaseScriptCode(cx, this);
|
||||
#endif
|
||||
|
||||
JS_REMOVE_LINK(&script->links);
|
||||
pcCounters.destroy(cx);
|
||||
|
||||
script->pcCounters.destroy(cx);
|
||||
if (sourceMap)
|
||||
cx->free_(sourceMap);
|
||||
|
||||
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);
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
/* Keep the hook from trying to recompile while the GC is running. */
|
||||
mjit::ReleaseScriptCode(cx, script);
|
||||
#if JS_SCRIPT_INLINE_DATA_LIMIT
|
||||
if (data != inlineData)
|
||||
#endif
|
||||
|
||||
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)
|
||||
{
|
||||
JS_ASSERT_IF(trc->context->runtime->gcCurrentCompartment, IS_GC_MARKING_TRACER(trc));
|
||||
|
||||
CheckScript(script, NULL);
|
||||
if (owner)
|
||||
CheckScriptOwner(script, owner);
|
||||
|
||||
JSRuntime *rt = trc->context->runtime;
|
||||
|
||||
/*
|
||||
* During per-compartment GCs we may attempt to trace scripts that are out
|
||||
* of the target compartment. Ignore such attempts, marking the children is
|
||||
* wasted work and if we mark external type objects they will not get
|
||||
* unmarked at the end of the GC cycle.
|
||||
*/
|
||||
if (rt->gcCurrentCompartment && rt->gcCurrentCompartment != script->compartment)
|
||||
return;
|
||||
|
||||
#ifdef JS_CRASH_DIAGNOSTICS
|
||||
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");
|
||||
{
|
||||
JS_POISON(data, 0xdb, dataSize());
|
||||
cx->free_(data);
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark the object keeping this script alive. The script can be traced
|
||||
* separately if, e.g. we are GC'ing while type inference code is active,
|
||||
* and we need to make sure both the script and the object survive the GC.
|
||||
*/
|
||||
if (!script->isCachedEval && script->u.object)
|
||||
MarkObject(trc, *script->u.object, "object");
|
||||
if (script->hasFunction)
|
||||
MarkObject(trc, *script->function(), "script_fun");
|
||||
|
||||
if (IS_GC_MARKING_TRACER(trc) && script->filename)
|
||||
js_MarkScriptFilename(script->filename);
|
||||
|
||||
script->bindings.trace(trc);
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
if (script->jitNormal)
|
||||
script->jitNormal->trace(trc);
|
||||
if (script->jitCtor)
|
||||
script->jitCtor->trace(trc);
|
||||
#endif
|
||||
}
|
||||
|
||||
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);
|
||||
@ -1553,10 +1400,6 @@ js_NewScriptObject(JSContext *cx, JSScript *script)
|
||||
*/
|
||||
obj->clearType();
|
||||
|
||||
#ifdef CHECK_SCRIPT_OWNER
|
||||
script->owner = NULL;
|
||||
#endif
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
@ -1706,7 +1549,7 @@ js_LineNumberToPC(JSScript *script, uintN target)
|
||||
* Exact-match only if offset is not in the prolog; otherwise use
|
||||
* nearest greater-or-equal line number match.
|
||||
*/
|
||||
if (lineno == target && script->code + offset >= script->main)
|
||||
if (lineno == target && offset >= ptrdiff_t(script->mainOffset))
|
||||
goto out;
|
||||
if (lineno >= target) {
|
||||
diff = lineno - target;
|
||||
@ -1838,8 +1681,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));
|
||||
@ -1879,7 +1721,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);
|
||||
|
||||
@ -1942,7 +1784,7 @@ JSScript::changeStepModeCount(JSContext *cx, int delta)
|
||||
|
||||
uint32 count = stepMode & stepCountMask;
|
||||
JS_ASSERT(((count + delta) & stepCountMask) == count + delta);
|
||||
return tryNewStepMode(cx,
|
||||
return tryNewStepMode(cx,
|
||||
(stepMode & stepFlagMask) |
|
||||
((count + delta) & stepCountMask));
|
||||
}
|
||||
|
@ -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 *****
|
||||
@ -362,10 +362,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;
|
||||
@ -432,7 +428,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,
|
||||
@ -452,42 +448,27 @@ struct JSScript {
|
||||
|
||||
static JSScript *NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg);
|
||||
|
||||
/* 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;
|
||||
/*
|
||||
* Make sure that the cookie size does not affect the GC alignment
|
||||
* requirements.
|
||||
*/
|
||||
uint32 cookie1[Cell::CellSize / sizeof(uint32)];
|
||||
#endif
|
||||
jsbytecode *code; /* bytecodes and their immediate operands */
|
||||
uint8 *data; /* pointer to variable-length data array */
|
||||
|
||||
uint32 length; /* length of code vector */
|
||||
private:
|
||||
size_t useCount_; /* Number of times the script has been called
|
||||
* or has had backedges taken. Reset if the
|
||||
* script's JIT code is forcibly discarded. */
|
||||
|
||||
uint16 version; /* JS version under which script was compiled */
|
||||
|
||||
public:
|
||||
uint16 nfixed; /* number of slots besides stack operands in
|
||||
slot array */
|
||||
uint16 nTypeSets; /* number of type sets used in this script for
|
||||
dynamic type monitoring */
|
||||
|
||||
/*
|
||||
* When non-zero, compile script in single-step mode. The top bit is set and
|
||||
* cleared by setStepMode, as used by JSD. The lower bits are a count,
|
||||
* adjusted by changeStepModeCount, used by the Debugger object. Only
|
||||
* when the bit is clear and the count is zero may we compile the script
|
||||
* without single-step support.
|
||||
*/
|
||||
uint32 stepMode;
|
||||
|
||||
/*
|
||||
* Offsets to various array structures from the end of this script, or
|
||||
* JSScript::INVALID_OFFSET if the array has length 0.
|
||||
*/
|
||||
public:
|
||||
uint8 objectsOffset; /* offset to the array of nested function,
|
||||
block, scope, xml and one-time regexps
|
||||
objects */
|
||||
@ -499,6 +480,22 @@ struct JSScript {
|
||||
uint8 globalsOffset; /* offset to the array of global slots */
|
||||
uint8 constOffset; /* offset to the array of constants */
|
||||
|
||||
uint16 nTypeSets; /* number of type sets used in this script for
|
||||
dynamic type monitoring */
|
||||
|
||||
/*
|
||||
* When non-zero, compile script in single-step mode. The top bit is set and
|
||||
* cleared by setStepMode, as used by JSD. The lower bits are a count,
|
||||
* adjusted by changeStepModeCount, used by the Debugger object. Only
|
||||
* when the bit is clear and the count is zero may we compile the script
|
||||
* without single-step support.
|
||||
*/
|
||||
uint32 stepMode;
|
||||
|
||||
uint32 lineno; /* base line number of script */
|
||||
|
||||
uint32 mainOffset; /* offset of main entry point from code, after
|
||||
predef'ing prolog */
|
||||
bool noScriptRval:1; /* no need for result value of last
|
||||
expression statement */
|
||||
bool savedCallerFun:1; /* can call getCallerFunction() */
|
||||
@ -524,27 +521,35 @@ struct JSScript {
|
||||
bool debugMode:1; /* script was compiled in debug mode */
|
||||
bool failedBoundsCheck:1; /* script has had hoisted bounds checks fail */
|
||||
#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 */
|
||||
uint32 lineno; /* base line number of script */
|
||||
uint32 natoms; /* length of atoms array */
|
||||
uint16 nslots; /* vars plus maximum stack depth */
|
||||
uint16 staticLevel;/* static level for display maintenance */
|
||||
|
||||
uint16 nClosedArgs; /* number of args which are closed over. */
|
||||
uint16 nClosedVars; /* number of vars which are closed over. */
|
||||
|
||||
/*
|
||||
* To ensure sizeof(JSScript) % gc::Cell::CellSize == 0 on we must pad
|
||||
* the script with 4 bytes. We use them to store tiny scripts like empty
|
||||
* scripts.
|
||||
*/
|
||||
#define JS_SCRIPT_INLINE_DATA_LIMIT 4
|
||||
uint8 inlineData[JS_SCRIPT_INLINE_DATA_LIMIT];
|
||||
|
||||
const char *filename; /* source filename or null */
|
||||
JSAtom **atoms; /* maps immediate index to literal struct */
|
||||
private:
|
||||
size_t useCount; /* Number of times the script has been called
|
||||
* or has had backedges taken. Reset if the
|
||||
* script's JIT code is forcibly discarded. */
|
||||
public:
|
||||
js::Bindings bindings; /* names of top-level variables in this script
|
||||
(and arguments if this is a function script) */
|
||||
JSPrincipals *principals;/* principals for this script */
|
||||
jschar *sourceMap; /* source map file or null */
|
||||
|
||||
#ifdef JS_CRASH_DIAGNOSTICS
|
||||
JSObject *ownerObject;
|
||||
#endif
|
||||
|
||||
void setOwnerObject(JSObject *owner);
|
||||
|
||||
union {
|
||||
/*
|
||||
* A script object of class js_ScriptClass, to ensure the script is GC'd.
|
||||
@ -557,24 +562,16 @@ 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. */
|
||||
|
||||
/* array of execution counters for every JSOp in the script, by runmode */
|
||||
JSPCCounters pcCounters;
|
||||
|
||||
#ifdef JS_CRASH_DIAGNOSTICS
|
||||
uint32 cookie2;
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
union {
|
||||
/* Function this script is the body for, if there is one. */
|
||||
JSFunction *fun;
|
||||
@ -588,6 +585,15 @@ struct JSScript {
|
||||
return where.fun;
|
||||
}
|
||||
|
||||
#ifdef JS_CRASH_DIAGNOSTICS
|
||||
JSObject *ownerObject;
|
||||
|
||||
/* All diagnostic fields must be multiples of Cell::CellSize. */
|
||||
uint32 cookie2[sizeof(JSObject *) == 4 ? 1 : 2];
|
||||
#endif
|
||||
|
||||
void setOwnerObject(JSObject *owner);
|
||||
|
||||
/*
|
||||
* Associates this script with a specific function, constructing a new type
|
||||
* object for the function.
|
||||
@ -604,7 +610,8 @@ struct JSScript {
|
||||
* Unique identifier within the compartment for this script, used for
|
||||
* printing analysis information.
|
||||
*/
|
||||
unsigned id_;
|
||||
uint32 id_;
|
||||
uint32 idpad;
|
||||
unsigned id() { return id_; }
|
||||
#else
|
||||
unsigned id() { return 0; }
|
||||
@ -639,7 +646,9 @@ struct JSScript {
|
||||
|
||||
js::mjit::JITScript *jitNormal; /* Extra JIT info for normal scripts */
|
||||
js::mjit::JITScript *jitCtor; /* Extra JIT info for constructors */
|
||||
#endif
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
bool hasJITCode() {
|
||||
return jitNormal || jitCtor;
|
||||
}
|
||||
@ -653,10 +662,10 @@ struct JSScript {
|
||||
return constructing ? jitCtor : jitNormal;
|
||||
}
|
||||
|
||||
size_t useCount() const { return useCount_; }
|
||||
size_t incUseCount() { return ++useCount_; }
|
||||
size_t *addressOfUseCount() { return &useCount_; }
|
||||
void resetUseCount() { useCount_ = 0; }
|
||||
size_t getUseCount() const { return useCount; }
|
||||
size_t incUseCount() { return ++useCount; }
|
||||
size_t *addressOfUseCount() { return &useCount; }
|
||||
void resetUseCount() { useCount = 0; }
|
||||
|
||||
JITScriptStatus getJITStatus(bool constructing) {
|
||||
void *addr = constructing ? jitArityCheckCtor : jitArityCheckNormal;
|
||||
@ -671,7 +680,11 @@ 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 */
|
||||
jsbytecode *main() {
|
||||
return code + mainOffset;
|
||||
}
|
||||
|
||||
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. */
|
||||
@ -682,37 +695,37 @@ 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) {
|
||||
JS_ASSERT(index < atomMap.length);
|
||||
return atomMap.vector[index];
|
||||
JS_ASSERT(index < natoms);
|
||||
return atoms[index];
|
||||
}
|
||||
|
||||
JSObject *getObject(size_t index) {
|
||||
@ -802,11 +815,14 @@ struct JSScript {
|
||||
#ifdef DEBUG
|
||||
uint32 stepModeCount() { return stepMode & stepCountMask; }
|
||||
#endif
|
||||
|
||||
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 */
|
||||
|
||||
static JS_INLINE uintN
|
||||
StackDepth(JSScript *script)
|
||||
{
|
||||
@ -852,27 +868,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);
|
||||
|
||||
extern void
|
||||
js_TraceScript(JSTracer *trc, 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 JSObject *
|
||||
js_NewScriptObject(JSContext *cx, JSScript *script);
|
||||
|
@ -8097,7 +8097,7 @@ TraceRecorder::updateAtoms()
|
||||
JS_REQUIRES_STACK void
|
||||
TraceRecorder::updateAtoms(JSScript *script)
|
||||
{
|
||||
atoms = script->atomMap.vector;
|
||||
atoms = script->atoms;
|
||||
consts = JSScript::isValidOffset(script->constOffset) ? script->consts()->vector : 0;
|
||||
strictModeCode_ins = w.name(w.immi(script->strictModeCode), "strict");
|
||||
}
|
||||
@ -14516,7 +14516,7 @@ TraceRecorder::record_JSOP_OBJECT()
|
||||
{
|
||||
StackFrame* const fp = cx->fp();
|
||||
JSScript* script = fp->script();
|
||||
unsigned index = atoms - script->atomMap.vector + GET_INDEX(cx->regs().pc);
|
||||
unsigned index = atoms - script->atoms + GET_INDEX(cx->regs().pc);
|
||||
|
||||
JSObject* obj;
|
||||
obj = script->getObject(index);
|
||||
@ -15444,7 +15444,7 @@ jsatomid
|
||||
TraceRecorder::getFullIndex(ptrdiff_t pcoff)
|
||||
{
|
||||
jsatomid index = GET_INDEX(cx->regs().pc + pcoff);
|
||||
index += atoms - cx->fp()->script()->atomMap.vector;
|
||||
index += atoms - cx->fp()->script()->atoms;
|
||||
return index;
|
||||
}
|
||||
|
||||
@ -15831,7 +15831,7 @@ TraceRecorder::record_JSOP_REGEXP()
|
||||
{
|
||||
StackFrame* const fp = cx->fp();
|
||||
JSScript* script = fp->script();
|
||||
unsigned index = atoms - script->atomMap.vector + GET_INDEX(cx->regs().pc);
|
||||
unsigned index = atoms - script->atoms + GET_INDEX(cx->regs().pc);
|
||||
|
||||
LIns* proto_ins;
|
||||
CHECK_STATUS_A(getClassPrototype(JSProto_RegExp, proto_ins));
|
||||
@ -16979,7 +16979,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);
|
||||
|
@ -565,9 +565,9 @@ class Value
|
||||
}
|
||||
|
||||
JS_ALWAYS_INLINE
|
||||
int32 gcKind() const {
|
||||
JSGCTraceKind gcKind() const {
|
||||
JS_ASSERT(isMarkable());
|
||||
return JSVAL_TRACE_KIND_IMPL(data);
|
||||
return JSGCTraceKind(JSVAL_TRACE_KIND_IMPL(data));
|
||||
}
|
||||
|
||||
JS_ALWAYS_INLINE
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -148,7 +148,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) {
|
||||
|
@ -142,7 +142,7 @@ mjit::Compiler::Compiler(JSContext *cx, JSScript *outerScript, bool isConstructi
|
||||
|
||||
/* Once a script starts getting really hot we will inline calls in it. */
|
||||
if (!debugMode() && cx->typeInferenceEnabled() && globalObj &&
|
||||
(outerScript->useCount() >= USES_BEFORE_INLINING ||
|
||||
(outerScript->getUseCount() >= USES_BEFORE_INLINING ||
|
||||
cx->hasRunOption(JSOPTION_METHODJIT_ALWAYS))) {
|
||||
inlining_ = true;
|
||||
}
|
||||
@ -860,7 +860,7 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
|
||||
jumpTableOffsets.length() * sizeof(void *);
|
||||
|
||||
JSC::ExecutablePool *execPool;
|
||||
uint8 *result = (uint8 *)script->compartment->jaegerCompartment()->execAlloc()->
|
||||
uint8 *result = (uint8 *)script->compartment()->jaegerCompartment()->execAlloc()->
|
||||
alloc(codeSize, &execPool, JSC::METHOD_CODE);
|
||||
if (!result) {
|
||||
js_ReportOutOfMemory(cx);
|
||||
@ -2817,7 +2817,7 @@ mjit::Compiler::fullAtomIndex(jsbytecode *pc)
|
||||
|
||||
/* If we ever enable INDEXBASE garbage, use this below. */
|
||||
#if 0
|
||||
return GET_SLOTNO(pc) + (atoms - script->atomMap.vector);
|
||||
return GET_SLOTNO(pc) + (atoms - script->atoms);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -5497,7 +5497,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);
|
||||
|
@ -87,7 +87,7 @@ FindExceptionHandler(JSContext *cx)
|
||||
top:
|
||||
if (cx->isExceptionPending() && JSScript::isValidOffset(script->trynotesOffset)) {
|
||||
// The PC is updated before every stub call, so we can use it here.
|
||||
unsigned offset = cx->regs().pc - script->main;
|
||||
unsigned offset = cx->regs().pc - script->main();
|
||||
|
||||
JSTryNoteArray *tnarray = script->trynotes();
|
||||
for (unsigned i = 0; i < tnarray->length; ++i) {
|
||||
@ -113,7 +113,7 @@ top:
|
||||
if (tn->stackDepth > cx->regs().sp - fp->base())
|
||||
continue;
|
||||
|
||||
jsbytecode *pc = script->main + tn->start + tn->length;
|
||||
jsbytecode *pc = script->main() + tn->start + tn->length;
|
||||
cx->regs().pc = pc;
|
||||
JSBool ok = js_UnwindScope(cx, tn->stackDepth, JS_TRUE);
|
||||
JS_ASSERT(cx->regs().sp == fp->base() + tn->stackDepth);
|
||||
|
@ -132,7 +132,7 @@ static uint32 StubCallsForOp[STUB_CALLS_FOR_OP_COUNT];
|
||||
extern "C" void JS_FASTCALL
|
||||
PushActiveVMFrame(VMFrame &f)
|
||||
{
|
||||
f.entryfp->script()->compartment->jaegerCompartment()->pushActiveFrame(&f);
|
||||
f.entryfp->script()->compartment()->jaegerCompartment()->pushActiveFrame(&f);
|
||||
f.entryfp->setNativeReturnAddress(JS_FUNC_TO_DATA_PTR(void*, JaegerTrampolineReturn));
|
||||
f.regs.clearInlined();
|
||||
}
|
||||
@ -140,7 +140,7 @@ PushActiveVMFrame(VMFrame &f)
|
||||
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
|
||||
|
@ -437,7 +437,7 @@ Recompiler::recompile(bool resetUses)
|
||||
|
||||
// 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) {
|
||||
|
||||
|
@ -1935,7 +1935,7 @@ SrcNotes(JSContext *cx, JSScript *script, Sprinter *sp)
|
||||
case SRC_CATCH:
|
||||
delta = (uintN) js_GetSrcNoteOffset(sn, 0);
|
||||
if (delta) {
|
||||
if (script->main[offset] == JSOP_LEAVEBLOCK)
|
||||
if (script->main()[offset] == JSOP_LEAVEBLOCK)
|
||||
Sprint(sp, " stack depth %u", delta);
|
||||
else
|
||||
Sprint(sp, " guard delta %u", delta);
|
||||
@ -3912,11 +3912,16 @@ struct FreeOnReturn {
|
||||
const char *ptr;
|
||||
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
|
||||
FreeOnReturn(JSContext *cx, const char *ptr JS_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
FreeOnReturn(JSContext *cx, const char *ptr = NULL JS_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: cx(cx), ptr(ptr) {
|
||||
JS_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
}
|
||||
|
||||
void init(const char *ptr) {
|
||||
JS_ASSERT(!this->ptr);
|
||||
this->ptr = ptr;
|
||||
}
|
||||
|
||||
~FreeOnReturn() {
|
||||
JS_free(cx, (void*)ptr);
|
||||
}
|
||||
@ -3926,7 +3931,6 @@ static JSBool
|
||||
Snarf(JSContext *cx, uintN argc, jsval *vp)
|
||||
{
|
||||
JSString *str;
|
||||
const char *pathname;
|
||||
|
||||
if (!argc)
|
||||
return JS_FALSE;
|
||||
@ -3942,13 +3946,15 @@ Snarf(JSContext *cx, uintN argc, jsval *vp)
|
||||
JSStackFrame *fp = JS_GetScriptedCaller(cx, NULL);
|
||||
JSScript *script = JS_GetFrameScript(cx, fp);
|
||||
JS_ASSERT(fp && script->filename);
|
||||
const char *pathname = filename.ptr();
|
||||
#ifdef XP_UNIX
|
||||
pathname = MakeAbsolutePathname(cx, script->filename, filename.ptr());
|
||||
if (!pathname)
|
||||
return JS_FALSE;
|
||||
FreeOnReturn pnGuard(cx, pathname);
|
||||
#else
|
||||
pathname = filename.ptr();
|
||||
FreeOnReturn pnGuard(cx);
|
||||
if (pathname[0] != '/') {
|
||||
pathname = MakeAbsolutePathname(cx, script->filename, pathname);
|
||||
if (!pathname)
|
||||
return JS_FALSE;
|
||||
pnGuard.init(pathname);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (argc > 1) {
|
||||
@ -4060,21 +4066,26 @@ MJitCodeStats(JSContext *cx, uintN argc, jsval *vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
|
||||
static void
|
||||
SumJitDataSizeCallabck(JSContext *cx, void *data, void *thing,
|
||||
JSGCTraceKind traceKind, size_t thingSize)
|
||||
{
|
||||
size_t *sump = static_cast<size_t *>(data);
|
||||
JS_ASSERT(traceKind == JSTRACE_SCRIPT);
|
||||
JSScript *script = static_cast<JSScript *>(thing);
|
||||
*sump += script->jitDataSize();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
JSBool
|
||||
MJitDataStats(JSContext *cx, uintN argc, jsval *vp)
|
||||
{
|
||||
#ifdef JS_METHODJIT
|
||||
JSRuntime *rt = cx->runtime;
|
||||
AutoLockGC lock(rt);
|
||||
size_t n = 0;
|
||||
for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) {
|
||||
for (JSScript *script = (JSScript *)(*c)->scripts.next;
|
||||
&script->links != &(*c)->scripts;
|
||||
script = (JSScript *)script->links.next)
|
||||
{
|
||||
n += script->jitDataSize();
|
||||
}
|
||||
}
|
||||
IterateCells(cx, NULL, gc::FINALIZE_TYPE_OBJECT, &n, SumJitDataSizeCallabck);
|
||||
JS_SET_RVAL(cx, vp, INT_TO_JSVAL(n));
|
||||
#else
|
||||
JS_SET_RVAL(cx, vp, JSVAL_VOID);
|
||||
|
@ -237,7 +237,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);
|
||||
}
|
||||
}
|
||||
@ -479,7 +479,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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -837,7 +837,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;
|
||||
@ -1898,8 +1898,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) {
|
||||
@ -1931,7 +1931,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) {
|
||||
@ -1950,7 +1950,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++)
|
||||
@ -2395,7 +2395,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)
|
||||
@ -2430,7 +2430,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)) {
|
||||
@ -2458,7 +2458,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;
|
||||
}
|
||||
@ -2468,7 +2468,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;
|
||||
}
|
||||
@ -2881,8 +2881,7 @@ EvaluateInScope(JSContext *cx, JSObject *scobj, StackFrame *fp, const jschar *ch
|
||||
if (!script)
|
||||
return false;
|
||||
|
||||
bool ok = ExecuteKernel(cx, script, *scobj, fp->thisValue(), EXECUTE_DEBUG, fp, rval);
|
||||
return ok;
|
||||
return ExecuteKernel(cx, script, *scobj, fp->thisValue(), EXECUTE_DEBUG, fp, rval);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -568,14 +568,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);
|
||||
}
|
||||
|
||||
|
@ -584,7 +584,7 @@ ContextStack::currentScript(jsbytecode **ppc) const
|
||||
JS_ASSERT(inlined->inlineIndex < fp->jit()->nInlineFrames);
|
||||
mjit::InlineFrame *frame = &fp->jit()->inlineFrames()[inlined->inlineIndex];
|
||||
JSScript *script = frame->fun->script();
|
||||
if (script->compartment != cx_->compartment)
|
||||
if (script->compartment() != cx_->compartment)
|
||||
return NULL;
|
||||
if (ppc)
|
||||
*ppc = script->code + inlined->pcOffset;
|
||||
@ -593,7 +593,7 @@ ContextStack::currentScript(jsbytecode **ppc) const
|
||||
#endif
|
||||
|
||||
JSScript *script = fp->script();
|
||||
if (script->compartment != cx_->compartment)
|
||||
if (script->compartment() != cx_->compartment)
|
||||
return NULL;
|
||||
|
||||
if (ppc)
|
||||
|
@ -892,7 +892,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();
|
||||
}
|
||||
|
||||
|
@ -845,11 +845,15 @@ nsXPConnect::Traverse(void *p, nsCycleCollectionTraversalCallback &cb)
|
||||
}
|
||||
else
|
||||
{
|
||||
static const char trace_types[JSTRACE_LIMIT][7] = {
|
||||
static const char trace_types[][11] = {
|
||||
"Object",
|
||||
"String",
|
||||
"Xml"
|
||||
"Script",
|
||||
"Xml",
|
||||
"Shape",
|
||||
"TypeObject",
|
||||
};
|
||||
JS_STATIC_ASSERT(JS_ARRAY_LENGTH(trace_types) == JSTRACE_LAST + 1);
|
||||
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
|
||||
@ -851,7 +851,7 @@ JSBool XPCJSRuntime::GCCallback(JSContext *cx, JSGCStatus status)
|
||||
if(threadLock)
|
||||
{
|
||||
// Do the marking...
|
||||
|
||||
|
||||
{ // scoped lock
|
||||
MutexAutoLock lock(*threadLock);
|
||||
|
||||
@ -870,7 +870,7 @@ JSBool XPCJSRuntime::GCCallback(JSContext *cx, JSGCStatus status)
|
||||
// possibly be valid.
|
||||
if(ccxp->CanGetTearOff())
|
||||
{
|
||||
XPCWrappedNativeTearOff* to =
|
||||
XPCWrappedNativeTearOff* to =
|
||||
ccxp->GetTearOff();
|
||||
if(to)
|
||||
to->Mark();
|
||||
@ -1042,7 +1042,7 @@ static JSDHashOperator
|
||||
DetachedWrappedNativeProtoShutdownMarker(JSDHashTable *table, JSDHashEntryHdr *hdr,
|
||||
uint32 number, void *arg)
|
||||
{
|
||||
XPCWrappedNativeProto* proto =
|
||||
XPCWrappedNativeProto* proto =
|
||||
(XPCWrappedNativeProto*)((JSDHashEntryStub*)hdr)->key;
|
||||
|
||||
proto->SystemIsBeingShutDown((JSContext*)arg);
|
||||
@ -1250,43 +1250,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
|
||||
|
||||
void
|
||||
GetCompartmentMjitCodeStats(JSCompartment *c, size_t& method, size_t& regexp,
|
||||
size_t& unused)
|
||||
{
|
||||
c->getMjitCodeStats(method, regexp, unused);
|
||||
}
|
||||
|
||||
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
|
||||
@ -1338,14 +1301,12 @@ CompartmentCallback(JSContext *cx, void *vdata, JSCompartment *compartment)
|
||||
data->currCompartmentStats = curr;
|
||||
|
||||
// Get the compartment-level numbers.
|
||||
curr->scripts = GetCompartmentScriptsSize(compartment);
|
||||
#ifdef JS_METHODJIT
|
||||
size_t method, regexp, unused;
|
||||
GetCompartmentMjitCodeStats(compartment, method, regexp, unused);
|
||||
compartment->getMjitCodeStats(method, regexp, unused);
|
||||
curr->mjitCodeMethod = method;
|
||||
curr->mjitCodeRegexp = regexp;
|
||||
curr->mjitCodeUnused = unused;
|
||||
curr->mjitData = GetCompartmentMjitDataSize(compartment);
|
||||
#endif
|
||||
#ifdef JS_TRACER
|
||||
curr->tjitCode = GetCompartmentTjitCodeSize(compartment);
|
||||
@ -1358,7 +1319,7 @@ CompartmentCallback(JSContext *cx, void *vdata, JSCompartment *compartment)
|
||||
|
||||
void
|
||||
ArenaCallback(JSContext *cx, void *vdata, js::gc::Arena *arena,
|
||||
size_t traceKind, size_t thingSize)
|
||||
JSGCTraceKind traceKind, size_t thingSize)
|
||||
{
|
||||
IterateData *data = static_cast<IterateData *>(vdata);
|
||||
data->currCompartmentStats->gcHeapArenaHeaders +=
|
||||
@ -1373,39 +1334,52 @@ ArenaCallback(JSContext *cx, void *vdata, js::gc::Arena *arena,
|
||||
}
|
||||
|
||||
void
|
||||
CellCallback(JSContext *cx, void *vdata, void *thing, size_t traceKind,
|
||||
CellCallback(JSContext *cx, void *vdata, void *thing, JSGCTraceKind traceKind,
|
||||
size_t thingSize)
|
||||
{
|
||||
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);
|
||||
curr->objectSlots += JS_ObjectCountDynamicSlots(obj) * 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 if(traceKind == JSTRACE_TYPE_OBJECT)
|
||||
{
|
||||
js::types::TypeObject *obj = static_cast<js::types::TypeObject *>(thing);
|
||||
JS_GetTypeInferenceObjectStats(obj, &curr->typeInferenceMemory);
|
||||
}
|
||||
else
|
||||
{
|
||||
JS_ASSERT(traceKind == JSTRACE_XML);
|
||||
curr->gcHeapXml += thingSize;
|
||||
case JSTRACE_OBJECT:
|
||||
{
|
||||
JSObject *obj = static_cast<JSObject *>(thing);
|
||||
curr->objectSlots += JS_ObjectCountDynamicSlots(obj) * 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;
|
||||
}
|
||||
case JSTRACE_TYPE_OBJECT:
|
||||
{
|
||||
js::types::TypeObject *obj = static_cast<js::types::TypeObject *>(thing);
|
||||
JS_GetTypeInferenceObjectStats(obj, &curr->typeInferenceMemory);
|
||||
break;
|
||||
}
|
||||
case JSTRACE_XML:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Yes, this is a subtraction: see ArenaCallback() for details.
|
||||
curr->gcHeapArenaUnused -= thingSize;
|
||||
@ -1670,12 +1644,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;
|
||||
}
|
||||
|
||||
@ -1686,7 +1661,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.
|
||||
@ -1728,14 +1703,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 "
|
||||
@ -1743,17 +1718,32 @@ ReportCompartmentStats(const CompartmentStats &stats,
|
||||
"under 'gc-heap/string-chars' instead.",
|
||||
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/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/shapes"),
|
||||
JS_GC_HEAP_KIND, stats.gcHeapKinds[JSTRACE_TYPE_OBJECT],
|
||||
"Memory on the compartment's garbage-collected JavaScript heap that holds "
|
||||
"type inference information.",
|
||||
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);
|
||||
@ -1795,11 +1785,18 @@ ReportCompartmentStats(const CompartmentStats &stats,
|
||||
|
||||
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
|
||||
"scripts"),
|
||||
nsIMemoryReporter::KIND_HEAP, stats.scripts,
|
||||
nsIMemoryReporter::KIND_HEAP,
|
||||
stats.gcHeapKinds[JSTRACE_SCRIPT],
|
||||
"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.",
|
||||
"the top-level code in a script.",
|
||||
callback, closure);
|
||||
|
||||
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
|
||||
"script-data"),
|
||||
nsIMemoryReporter::KIND_HEAP, stats.scriptData,
|
||||
"Memory allocated for JSScript bytecode and various variable-length "
|
||||
"tables.",
|
||||
callback, closure);
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
|
@ -202,16 +202,13 @@ struct CompartmentStats
|
||||
PRInt64 gcHeapArenaPadding;
|
||||
PRInt64 gcHeapArenaUnused;
|
||||
|
||||
PRInt64 gcHeapObjects;
|
||||
PRInt64 gcHeapStrings;
|
||||
PRInt64 gcHeapShapes;
|
||||
PRInt64 gcHeapXml;
|
||||
PRInt64 gcHeapKinds[JSTRACE_LAST + 1];
|
||||
|
||||
PRInt64 objectSlots;
|
||||
PRInt64 stringChars;
|
||||
PRInt64 propertyTables;
|
||||
PRInt64 scriptData;
|
||||
|
||||
PRInt64 scripts;
|
||||
#ifdef JS_METHODJIT
|
||||
PRInt64 mjitCodeMethod;
|
||||
PRInt64 mjitCodeRegexp;
|
||||
|
Loading…
Reference in New Issue
Block a user