forked from mirrors/gecko-dev
Use the garbage collector to manage code (bug 670816 part 4, r=billm).
--HG-- extra : rebase_source : 8c93cd92ecd1266e12d6b42afadd63bcef3bac93
This commit is contained in:
parent
4a035b6b2f
commit
1271075287
11 changed files with 153 additions and 23 deletions
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -88,8 +88,6 @@ struct IonOptions
|
|||
{ }
|
||||
};
|
||||
|
||||
#define ION_DISABLED_SCRIPT ((IonScript *)0x1)
|
||||
|
||||
enum MethodStatus
|
||||
{
|
||||
Method_CantCompile,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -136,6 +136,7 @@ struct GCTimer
|
|||
uint64 sweepStringEnd;
|
||||
uint64 sweepShapeEnd;
|
||||
uint64 sweepDestroyEnd;
|
||||
uint64 sweepIonCodeEnd;
|
||||
uint64 end;
|
||||
|
||||
bool isCompartmental;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue