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

View file

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

View file

@ -49,37 +49,53 @@ namespace JSC {
namespace js {
namespace ion {
class IonCode
class IonCode : public gc::Cell
{
uint8 *code_;
size_t size_;
uint32 size_;
JSC::ExecutablePool *pool_;
uint32 padding_;
public:
IonCode()
: code_(NULL),
pool_(NULL)
{ }
IonCode(uint8 *code, size_t size, JSC::ExecutablePool *pool)
IonCode(uint8 *code, uint32 size, JSC::ExecutablePool *pool)
: code_(code),
size_(size),
pool_(pool)
{ }
public:
uint8 *code() const {
return code_;
}
size_t size() const {
uint32 size() const {
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.
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);
};

View file

@ -402,6 +402,7 @@ struct JSRuntime {
void *gcMarkStackRopes[js::ROPES_MARK_STACK_SIZE / sizeof(void *)];
void *gcMarkStackXMLs[js::XML_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,

View file

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

View file

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

View file

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

View file

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

View file

@ -48,6 +48,11 @@
#include "jstl.h"
namespace js {
namespace ion {
class IonCode;
}
namespace gc {
template<typename T>
@ -62,6 +67,9 @@ MarkString(JSTracer *trc, JSString *str, const char *name);
void
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
* 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
MarkRoot(JSTracer *trc, JSXML *thing, const char *name);
void
MarkRoot(JSTracer *trc, ion::IonCode *code, const char *name);
void
MarkChildren(JSTracer *trc, JSObject *obj);

View file

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

View file

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