Use the garbage collector to manage code (bug 670816 part 4, r=billm).

--HG--
extra : rebase_source : 8c93cd92ecd1266e12d6b42afadd63bcef3bac93
This commit is contained in:
David Anderson 2011-07-18 17:41:49 -07:00
parent 4a035b6b2f
commit 1271075287
11 changed files with 153 additions and 23 deletions

View file

@ -59,12 +59,17 @@
# include "arm/Lowering-arm.h" # include "arm/Lowering-arm.h"
# include "arm/CodeGenerator-arm.h" # include "arm/CodeGenerator-arm.h"
#endif #endif
#include "jsgcmark.h"
#include "jsgcinlines.h"
using namespace js; using namespace js;
using namespace js::ion; using namespace js::ion;
IonOptions ion::js_IonOptions; IonOptions ion::js_IonOptions;
// Assert that IonCode is gc::Cell aligned.
JS_STATIC_ASSERT(sizeof(IonCode) % gc::Cell::CellSize == 0);
#ifdef JS_THREADSAFE #ifdef JS_THREADSAFE
static bool IonTLSInitialized = false; static bool IonTLSInitialized = false;
static PRUintn IonTLSIndex; static PRUintn IonTLSIndex;
@ -128,15 +133,31 @@ ion::SetIonContext(IonContext *ctx)
} }
#endif #endif
IonCode *
IonCode::New(JSContext *cx, uint8 *code, uint32 size, JSC::ExecutablePool *pool)
{
IonCode *codeObj = NewGCThing<IonCode>(cx, gc::FINALIZE_IONCODE, sizeof(IonCode));
if (!codeObj) {
pool->release();
return NULL;
}
new (codeObj) IonCode(code, size, pool);
return codeObj;
}
void void
IonCode::release() IonCode::finalize(JSContext *cx)
{ {
if (pool_) if (pool_)
pool_->release(); pool_->release();
#ifdef DEBUG }
pool_ = NULL;
code_ = NULL; void
#endif IonScript::trace(JSTracer *trc, JSScript *script)
{
if (method)
MarkIonCode(trc, method, "method");
} }
void void
@ -145,7 +166,6 @@ IonScript::Destroy(JSContext *cx, JSScript *script)
if (!script->ion || script->ion == ION_DISABLED_SCRIPT) if (!script->ion || script->ion == ION_DISABLED_SCRIPT)
return; return;
script->ion->method.release();
cx->free_(script->ion); cx->free_(script->ion);
} }

View file

@ -88,8 +88,6 @@ struct IonOptions
{ } { }
}; };
#define ION_DISABLED_SCRIPT ((IonScript *)0x1)
enum MethodStatus enum MethodStatus
{ {
Method_CantCompile, Method_CantCompile,

View file

@ -49,37 +49,53 @@ namespace JSC {
namespace js { namespace js {
namespace ion { namespace ion {
class IonCode class IonCode : public gc::Cell
{ {
uint8 *code_; uint8 *code_;
size_t size_; uint32 size_;
JSC::ExecutablePool *pool_; JSC::ExecutablePool *pool_;
uint32 padding_;
public:
IonCode() IonCode()
: code_(NULL), : code_(NULL),
pool_(NULL) pool_(NULL)
{ } { }
IonCode(uint8 *code, size_t size, JSC::ExecutablePool *pool) IonCode(uint8 *code, uint32 size, JSC::ExecutablePool *pool)
: code_(code), : code_(code),
size_(size), size_(size),
pool_(pool) pool_(pool)
{ } { }
public:
uint8 *code() const { uint8 *code() const {
return code_; return code_;
} }
size_t size() const { uint32 size() const {
return size_; return size_;
} }
void release(); void finalize(JSContext *cx);
// Allocates a new IonCode object which will be managed by the GC. If no
// object can be allocated, NULL is returned. On failure, |pool| is
// automatically released, so the code may be freed.
static IonCode *New(JSContext *cx, uint8 *code, uint32 size, JSC::ExecutablePool *pool);
}; };
#define ION_DISABLED_SCRIPT ((IonScript *)0x1)
// An IonScript attaches Ion-generated information to a JSScript. // An IonScript attaches Ion-generated information to a JSScript.
struct IonScript struct IonScript
{ {
IonCode method; IonCode *method;
private:
void trace(JSTracer *trc, JSScript *script);
public:
static void Trace(JSTracer *trc, JSScript *script) {
if (script->ion && script->ion != ION_DISABLED_SCRIPT)
script->ion->trace(trc, script);
}
static void Destroy(JSContext *cx, JSScript *script); static void Destroy(JSContext *cx, JSScript *script);
}; };

View file

@ -402,6 +402,7 @@ struct JSRuntime {
void *gcMarkStackRopes[js::ROPES_MARK_STACK_SIZE / sizeof(void *)]; void *gcMarkStackRopes[js::ROPES_MARK_STACK_SIZE / sizeof(void *)];
void *gcMarkStackXMLs[js::XML_MARK_STACK_SIZE / sizeof(void *)]; void *gcMarkStackXMLs[js::XML_MARK_STACK_SIZE / sizeof(void *)];
void *gcMarkStackLarges[js::LARGE_MARK_STACK_SIZE / sizeof(void *)]; void *gcMarkStackLarges[js::LARGE_MARK_STACK_SIZE / sizeof(void *)];
void *gcMarkStackIonCode[js::IONCODE_MARK_STACK_SIZE / sizeof(void *)];
/* /*
* Compartment that triggered GC. If more than one Compatment need GC, * Compartment that triggered GC. If more than one Compatment need GC,

View file

@ -496,6 +496,7 @@ struct JS_FRIEND_API(JSCompartment) {
void finalizeObjectArenaLists(JSContext *cx); void finalizeObjectArenaLists(JSContext *cx);
void finalizeStringArenaLists(JSContext *cx); void finalizeStringArenaLists(JSContext *cx);
void finalizeShapeArenaLists(JSContext *cx); void finalizeShapeArenaLists(JSContext *cx);
void finalizeIonCodeArenaLists(JSContext *cx);
bool arenaListsAreEmpty(); bool arenaListsAreEmpty();
void setGCLastBytes(size_t lastBytes, JSGCInvocationKind gckind); void setGCLastBytes(size_t lastBytes, JSGCInvocationKind gckind);

View file

@ -93,6 +93,7 @@
#include "jsobjinlines.h" #include "jsobjinlines.h"
#include "vm/String-inl.h" #include "vm/String-inl.h"
#include "ion/IonCode.h"
#ifdef MOZ_VALGRIND #ifdef MOZ_VALGRIND
# define JS_VALGRIND # define JS_VALGRIND
@ -110,13 +111,14 @@ using namespace js::gc;
JS_STATIC_ASSERT(JSTRACE_OBJECT == 0); JS_STATIC_ASSERT(JSTRACE_OBJECT == 0);
JS_STATIC_ASSERT(JSTRACE_STRING == 1); JS_STATIC_ASSERT(JSTRACE_STRING == 1);
JS_STATIC_ASSERT(JSTRACE_SHAPE == 2); JS_STATIC_ASSERT(JSTRACE_SHAPE == 2);
JS_STATIC_ASSERT(JSTRACE_XML == 3); JS_STATIC_ASSERT(JSTRACE_IONCODE == 3);
JS_STATIC_ASSERT(JSTRACE_XML == 4);
/* /*
* JS_IS_VALID_TRACE_KIND assumes that JSTRACE_SHAPE is the last non-xml * JS_IS_VALID_TRACE_KIND assumes that JSTRACE_IONCODE is the last non-xml
* trace kind when JS_HAS_XML_SUPPORT is false. * trace kind when JS_HAS_XML_SUPPORT is false.
*/ */
JS_STATIC_ASSERT(JSTRACE_SHAPE + 1 == JSTRACE_XML); JS_STATIC_ASSERT(JSTRACE_IONCODE + 1 == JSTRACE_XML);
namespace js { namespace js {
namespace gc { namespace gc {
@ -153,6 +155,7 @@ const uint8 GCThingSizeMap[] = {
sizeof(JSShortString), /* FINALIZE_SHORT_STRING */ sizeof(JSShortString), /* FINALIZE_SHORT_STRING */
sizeof(JSString), /* FINALIZE_STRING */ sizeof(JSString), /* FINALIZE_STRING */
sizeof(JSExternalString), /* FINALIZE_EXTERNAL_STRING */ sizeof(JSExternalString), /* FINALIZE_EXTERNAL_STRING */
sizeof(ion::IonCode), /* FINALIZE_IONCODE */
}; };
JS_STATIC_ASSERT(JS_ARRAY_LENGTH(GCThingSizeMap) == FINALIZE_LIMIT); JS_STATIC_ASSERT(JS_ARRAY_LENGTH(GCThingSizeMap) == FINALIZE_LIMIT);
@ -806,6 +809,9 @@ MarkIfGCThingWord(JSTracer *trc, jsuword w)
test = MarkArenaPtrConservatively<JSXML>(trc, aheader, addr); test = MarkArenaPtrConservatively<JSXML>(trc, aheader, addr);
break; break;
#endif #endif
case FINALIZE_IONCODE:
test = MarkArenaPtrConservatively<ion::IonCode>(trc, aheader, addr);
break;
default: default:
test = CGCT_WRONGTAG; test = CGCT_WRONGTAG;
JS_NOT_REACHED("wrong tag"); JS_NOT_REACHED("wrong tag");
@ -1471,6 +1477,8 @@ RefillFinalizableFreeList(JSContext *cx, unsigned thingKind)
case FINALIZE_XML: case FINALIZE_XML:
return RefillTypedFreeList<JSXML>(cx, thingKind); return RefillTypedFreeList<JSXML>(cx, thingKind);
#endif #endif
case FINALIZE_IONCODE:
return RefillTypedFreeList<ion::IonCode>(cx, thingKind);
default: default:
JS_NOT_REACHED("bad finalize kind"); JS_NOT_REACHED("bad finalize kind");
return NULL; return NULL;
@ -1539,7 +1547,8 @@ GCMarker::GCMarker(JSContext *cx)
objStack(cx->runtime->gcMarkStackObjs, sizeof(cx->runtime->gcMarkStackObjs)), objStack(cx->runtime->gcMarkStackObjs, sizeof(cx->runtime->gcMarkStackObjs)),
ropeStack(cx->runtime->gcMarkStackRopes, sizeof(cx->runtime->gcMarkStackRopes)), ropeStack(cx->runtime->gcMarkStackRopes, sizeof(cx->runtime->gcMarkStackRopes)),
xmlStack(cx->runtime->gcMarkStackXMLs, sizeof(cx->runtime->gcMarkStackXMLs)), xmlStack(cx->runtime->gcMarkStackXMLs, sizeof(cx->runtime->gcMarkStackXMLs)),
largeStack(cx->runtime->gcMarkStackLarges, sizeof(cx->runtime->gcMarkStackLarges)) largeStack(cx->runtime->gcMarkStackLarges, sizeof(cx->runtime->gcMarkStackLarges)),
ionCodeStack(cx->runtime->gcMarkStackIonCode, sizeof(cx->runtime->gcMarkStackIonCode))
{ {
JS_TRACER_INIT(this, cx, NULL); JS_TRACER_INIT(this, cx, NULL);
#ifdef DEBUG #ifdef DEBUG
@ -2014,6 +2023,12 @@ JSCompartment::finalizeShapeArenaLists(JSContext *cx)
arenas[FINALIZE_SHAPE].finalizeNow<Shape>(cx); arenas[FINALIZE_SHAPE].finalizeNow<Shape>(cx);
} }
void
JSCompartment::finalizeIonCodeArenaLists(JSContext *cx)
{
arenas[FINALIZE_IONCODE].finalizeNow<ion::IonCode>(cx);
}
#ifdef JS_THREADSAFE #ifdef JS_THREADSAFE
namespace js { namespace js {
@ -2351,6 +2366,8 @@ MarkAndSweep(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind GCTIM
GCTIMESTAMP(sweepObjectEnd); GCTIMESTAMP(sweepObjectEnd);
comp->finalizeStringArenaLists(cx); comp->finalizeStringArenaLists(cx);
GCTIMESTAMP(sweepStringEnd); GCTIMESTAMP(sweepStringEnd);
comp->finalizeIonCodeArenaLists(cx);
GCTIMESTAMP(sweepIonCodeEnd);
comp->finalizeShapeArenaLists(cx); comp->finalizeShapeArenaLists(cx);
GCTIMESTAMP(sweepShapeEnd); GCTIMESTAMP(sweepShapeEnd);
} else { } else {
@ -2373,6 +2390,11 @@ MarkAndSweep(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind GCTIM
GCTIMESTAMP(sweepStringEnd); GCTIMESTAMP(sweepStringEnd);
for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); c++)
(*c)->finalizeIonCodeArenaLists(cx);
GCTIMESTAMP(sweepIonCodeEnd);
for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); c++) { for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); c++) {
(*c)->finalizeShapeArenaLists(cx); (*c)->finalizeShapeArenaLists(cx);
Probes::GCEndSweepPhase(*c); Probes::GCEndSweepPhase(*c);

View file

@ -75,6 +75,10 @@ namespace js {
class GCHelperThread; class GCHelperThread;
struct Shape; struct Shape;
namespace ion {
class IonCode;
}
namespace gc { namespace gc {
struct Arena; struct Arena;
@ -104,6 +108,7 @@ enum FinalizeKind {
FINALIZE_SHORT_STRING, FINALIZE_SHORT_STRING,
FINALIZE_STRING, FINALIZE_STRING,
FINALIZE_EXTERNAL_STRING, FINALIZE_EXTERNAL_STRING,
FINALIZE_IONCODE,
FINALIZE_LIMIT FINALIZE_LIMIT
}; };
@ -607,12 +612,13 @@ Cell::compartment() const
return arenaHeader()->compartment; return arenaHeader()->compartment;
} }
#define JSTRACE_XML 3 #define JSTRACE_IONCODE 3
#define JSTRACE_XML 4
/* /*
* One past the maximum trace kind. * One past the maximum trace kind.
*/ */
#define JSTRACE_LIMIT 4 #define JSTRACE_LIMIT 5
/* /*
* Lower limit after which we limit the heap growth * Lower limit after which we limit the heap growth
@ -656,6 +662,7 @@ GetFinalizableTraceKind(size_t thingKind)
JSTRACE_STRING, /* FINALIZE_SHORT_STRING */ JSTRACE_STRING, /* FINALIZE_SHORT_STRING */
JSTRACE_STRING, /* FINALIZE_STRING */ JSTRACE_STRING, /* FINALIZE_STRING */
JSTRACE_STRING, /* FINALIZE_EXTERNAL_STRING */ JSTRACE_STRING, /* FINALIZE_EXTERNAL_STRING */
JSTRACE_IONCODE, /* FINALIZE_IONCODE */
}; };
JS_ASSERT(thingKind < FINALIZE_LIMIT); JS_ASSERT(thingKind < FINALIZE_LIMIT);
@ -1261,6 +1268,7 @@ static const size_t OBJECT_MARK_STACK_SIZE = 32768 * sizeof(JSObject *);
static const size_t ROPES_MARK_STACK_SIZE = 1024 * sizeof(JSString *); static const size_t ROPES_MARK_STACK_SIZE = 1024 * sizeof(JSString *);
static const size_t XML_MARK_STACK_SIZE = 1024 * sizeof(JSXML *); static const size_t XML_MARK_STACK_SIZE = 1024 * sizeof(JSXML *);
static const size_t LARGE_MARK_STACK_SIZE = 64 * sizeof(LargeMarkItem); static const size_t LARGE_MARK_STACK_SIZE = 64 * sizeof(LargeMarkItem);
static const size_t IONCODE_MARK_STACK_SIZE = 1024 * sizeof(ion::IonCode *);
struct GCMarker : public JSTracer { struct GCMarker : public JSTracer {
private: private:
@ -1285,6 +1293,7 @@ struct GCMarker : public JSTracer {
MarkStack<JSRope *> ropeStack; MarkStack<JSRope *> ropeStack;
MarkStack<JSXML *> xmlStack; MarkStack<JSXML *> xmlStack;
MarkStack<LargeMarkItem> largeStack; MarkStack<LargeMarkItem> largeStack;
MarkStack<ion::IonCode *> ionCodeStack;
public: public:
explicit GCMarker(JSContext *cx); explicit GCMarker(JSContext *cx);
@ -1308,7 +1317,8 @@ struct GCMarker : public JSTracer {
return objStack.isEmpty() && return objStack.isEmpty() &&
ropeStack.isEmpty() && ropeStack.isEmpty() &&
xmlStack.isEmpty() && xmlStack.isEmpty() &&
largeStack.isEmpty(); largeStack.isEmpty() &&
ionCodeStack.isEmpty();
} }
JS_FRIEND_API(void) drainMarkStack(); JS_FRIEND_API(void) drainMarkStack();
@ -1327,6 +1337,11 @@ struct GCMarker : public JSTracer {
if (!xmlStack.push(xml)) if (!xmlStack.push(xml))
delayMarkingChildren(xml); delayMarkingChildren(xml);
} }
void pushIonCode(ion::IonCode *code) {
if (!ionCodeStack.push(code))
delayMarkingChildren(code);
}
}; };
void void
@ -1369,7 +1384,7 @@ js_MarkTraps(JSTracer *trc);
#if JS_HAS_XML_SUPPORT #if JS_HAS_XML_SUPPORT
# define JS_IS_VALID_TRACE_KIND(kind) ((uint32)(kind) < JSTRACE_LIMIT) # define JS_IS_VALID_TRACE_KIND(kind) ((uint32)(kind) < JSTRACE_LIMIT)
#else #else
# define JS_IS_VALID_TRACE_KIND(kind) ((uint32)(kind) <= JSTRACE_SHAPE) # define JS_IS_VALID_TRACE_KIND(kind) ((uint32)(kind) <= JSTRACE_IONCODE)
#endif #endif
namespace js { namespace js {

View file

@ -45,6 +45,7 @@
#include "jsobjinlines.h" #include "jsobjinlines.h"
#include "jsscopeinlines.h" #include "jsscopeinlines.h"
#include "ion/IonCode.h"
#include "vm/String-inl.h" #include "vm/String-inl.h"
/* /*
@ -193,6 +194,15 @@ MarkShape(JSTracer *trc, const Shape *shape, const char *name)
Mark(trc, shape); Mark(trc, shape);
} }
void
MarkIonCode(JSTracer *trc, ion::IonCode *code, const char *name)
{
JS_ASSERT(trc);
JS_ASSERT(code);
JS_SET_TRACING_NAME(trc, name);
Mark(trc, code);
}
#if JS_HAS_XML_SUPPORT #if JS_HAS_XML_SUPPORT
void void
MarkXML(JSTracer *trc, JSXML *xml, const char *name) MarkXML(JSTracer *trc, JSXML *xml, const char *name)
@ -243,6 +253,16 @@ PushMarkStack(GCMarker *gcmarker, JSShortString *thing)
(void) thing->markIfUnmarked(gcmarker->getMarkColor()); (void) thing->markIfUnmarked(gcmarker->getMarkColor());
} }
void
PushMarkStack(GCMarker *gcmarker, ion::IonCode *thing)
{
JS_ASSERT_IF(gcmarker->context->runtime->gcCurrentCompartment,
thing->compartment() == gcmarker->context->runtime->gcCurrentCompartment);
if (thing->markIfUnmarked(gcmarker->getMarkColor()))
gcmarker->pushIonCode(thing);
}
static void static void
ScanShape(GCMarker *gcmarker, const Shape *shape); ScanShape(GCMarker *gcmarker, const Shape *shape);
@ -340,6 +360,9 @@ MarkKind(JSTracer *trc, void *thing, uint32 kind)
case JSTRACE_SHAPE: case JSTRACE_SHAPE:
Mark(trc, reinterpret_cast<Shape *>(thing)); Mark(trc, reinterpret_cast<Shape *>(thing));
break; break;
case JSTRACE_IONCODE:
Mark(trc, reinterpret_cast<ion::IonCode *>(thing));
break;
#if JS_HAS_XML_SUPPORT #if JS_HAS_XML_SUPPORT
case JSTRACE_XML: case JSTRACE_XML:
Mark(trc, reinterpret_cast<JSXML *>(thing)); Mark(trc, reinterpret_cast<JSXML *>(thing));
@ -477,6 +500,12 @@ MarkRoot(JSTracer *trc, JSXML *thing, const char *name)
MarkXML(trc, thing, name); MarkXML(trc, thing, name);
} }
void
MarkRoot(JSTracer *trc, ion::IonCode *code, const char *name)
{
MarkIonCode(trc, code, name);
}
static void static void
PrintPropertyGetterOrSetter(JSTracer *trc, char *buf, size_t bufsize) PrintPropertyGetterOrSetter(JSTracer *trc, char *buf, size_t bufsize)
{ {
@ -767,6 +796,11 @@ restart:
goto restart; goto restart;
} }
void
MarkChildren(JSTracer *trc, ion::IonCode *code)
{
}
#ifdef JS_HAS_XML_SUPPORT #ifdef JS_HAS_XML_SUPPORT
void void
MarkChildren(JSTracer *trc, JSXML *xml) MarkChildren(JSTracer *trc, JSXML *xml)
@ -793,6 +827,9 @@ GCMarker::drainMarkStack()
while (!xmlStack.isEmpty()) while (!xmlStack.isEmpty())
MarkChildren(this, xmlStack.pop()); MarkChildren(this, xmlStack.pop());
while (!ionCodeStack.isEmpty())
MarkChildren(this, ionCodeStack.pop());
if (!largeStack.isEmpty()) { if (!largeStack.isEmpty()) {
LargeMarkItem &item = largeStack.peek(); LargeMarkItem &item = largeStack.peek();
if (ScanLargeObject(this, item)) if (ScanLargeObject(this, item))
@ -829,6 +866,10 @@ JS_TraceChildren(JSTracer *trc, void *thing, uint32 kind)
MarkChildren(trc, (js::Shape *)thing); MarkChildren(trc, (js::Shape *)thing);
break; break;
case JSTRACE_IONCODE:
MarkChildren(trc, (js::ion::IonCode *)thing);
break;
#if JS_HAS_XML_SUPPORT #if JS_HAS_XML_SUPPORT
case JSTRACE_XML: case JSTRACE_XML:
MarkChildren(trc, (JSXML *)thing); MarkChildren(trc, (JSXML *)thing);

View file

@ -48,6 +48,11 @@
#include "jstl.h" #include "jstl.h"
namespace js { namespace js {
namespace ion {
class IonCode;
}
namespace gc { namespace gc {
template<typename T> template<typename T>
@ -62,6 +67,9 @@ MarkString(JSTracer *trc, JSString *str, const char *name);
void void
MarkObject(JSTracer *trc, JSObject &obj, const char *name); MarkObject(JSTracer *trc, JSObject &obj, const char *name);
void
MarkIonCode(JSTracer *trc, ion::IonCode *code, const char *name);
/* /*
* Mark an object that may be in a different compartment from the compartment * Mark an object that may be in a different compartment from the compartment
* being GC'd. (Although it won't be marked if it's in the wrong compartment.) * being GC'd. (Although it won't be marked if it's in the wrong compartment.)
@ -156,6 +164,9 @@ MarkRoot(JSTracer *trc, const Shape *thing, const char *name);
void void
MarkRoot(JSTracer *trc, JSXML *thing, const char *name); MarkRoot(JSTracer *trc, JSXML *thing, const char *name);
void
MarkRoot(JSTracer *trc, ion::IonCode *code, const char *name);
void void
MarkChildren(JSTracer *trc, JSObject *obj); MarkChildren(JSTracer *trc, JSObject *obj);

View file

@ -136,6 +136,7 @@ struct GCTimer
uint64 sweepStringEnd; uint64 sweepStringEnd;
uint64 sweepShapeEnd; uint64 sweepShapeEnd;
uint64 sweepDestroyEnd; uint64 sweepDestroyEnd;
uint64 sweepIonCodeEnd;
uint64 end; uint64 end;
bool isCompartmental; bool isCompartmental;

View file

@ -1518,6 +1518,10 @@ js_TraceScript(JSTracer *trc, JSScript *script)
if (IS_GC_MARKING_TRACER(trc) && script->filename) if (IS_GC_MARKING_TRACER(trc) && script->filename)
js_MarkScriptFilename(script->filename); js_MarkScriptFilename(script->filename);
#ifdef JS_ION
ion::IonScript::Trace(trc, script);
#endif
script->bindings.trace(trc); script->bindings.trace(trc);
} }