mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Give root fragments a treeInfo decorator only if the trace was successfully compiled. Otherwise just keep a reference in the recorder and delete it when the recorder is destroyed. Review welcome. The involved state machine is a bit complex. Added lots of asserts as safety net.
This commit is contained in:
parent
26fc76213a
commit
ef8a6041cc
@ -634,16 +634,17 @@ mergeTypeMaps(uint8** partial, unsigned* plength, uint8* complete, unsigned clen
|
||||
*plength = clength;
|
||||
}
|
||||
|
||||
TraceRecorder::TraceRecorder(JSContext* cx, GuardRecord* _anchor,
|
||||
Fragment* _fragment, unsigned ngslots, uint8* globalTypeMap, uint8* stackTypeMap)
|
||||
TraceRecorder::TraceRecorder(JSContext* cx, GuardRecord* _anchor, Fragment* _fragment,
|
||||
TreeInfo* ti, unsigned ngslots, uint8* globalTypeMap, uint8* stackTypeMap)
|
||||
{
|
||||
JS_ASSERT(!_fragment->vmprivate && ti);
|
||||
|
||||
this->cx = cx;
|
||||
this->globalObj = JS_GetGlobalForObject(cx, cx->fp->scopeChain);
|
||||
this->anchor = _anchor;
|
||||
this->fragment = _fragment;
|
||||
this->lirbuf = _fragment->lirbuf;
|
||||
this->treeInfo = (TreeInfo*)_fragment->root->vmprivate;
|
||||
JS_ASSERT(treeInfo);
|
||||
this->treeInfo = ti;
|
||||
this->callDepth = _fragment->calldepth;
|
||||
JS_ASSERT(!_anchor || _anchor->calldepth == _fragment->calldepth);
|
||||
this->atoms = cx->fp->script->atomMap.vector;
|
||||
@ -697,6 +698,11 @@ TraceRecorder::TraceRecorder(JSContext* cx, GuardRecord* _anchor,
|
||||
|
||||
TraceRecorder::~TraceRecorder()
|
||||
{
|
||||
JS_ASSERT(treeInfo);
|
||||
if (fragment->root == fragment && !fragment->root->code()) {
|
||||
JS_ASSERT(!fragment->root->vmprivate);
|
||||
delete treeInfo;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
delete verbose_filter;
|
||||
#endif
|
||||
@ -1381,6 +1387,10 @@ TraceRecorder::closeLoop(Fragmento* fragmento)
|
||||
fragment->addLink(anchor);
|
||||
fragmento->assm()->patch(anchor);
|
||||
}
|
||||
JS_ASSERT(fragment->code());
|
||||
JS_ASSERT(!fragment->vmprivate);
|
||||
if (fragment == fragment->root)
|
||||
fragment->vmprivate = treeInfo;
|
||||
/* :TODO: windows support */
|
||||
#if defined DEBUG && !defined WIN32
|
||||
char* label = (char*)malloc(strlen(cx->fp->script->filename) + 64);
|
||||
@ -1517,11 +1527,11 @@ js_DeleteRecorder(JSContext* cx)
|
||||
}
|
||||
|
||||
static bool
|
||||
js_StartRecorder(JSContext* cx, GuardRecord* anchor, Fragment* f,
|
||||
js_StartRecorder(JSContext* cx, GuardRecord* anchor, Fragment* f, TreeInfo* ti,
|
||||
unsigned ngslots, uint8* globalTypeMap, uint8* stackTypeMap)
|
||||
{
|
||||
/* start recording if no exception during construction */
|
||||
JS_TRACE_MONITOR(cx).recorder = new (&gc) TraceRecorder(cx, anchor, f,
|
||||
JS_TRACE_MONITOR(cx).recorder = new (&gc) TraceRecorder(cx, anchor, f, ti,
|
||||
ngslots, globalTypeMap, stackTypeMap);
|
||||
if (cx->throwing) {
|
||||
js_AbortRecording(cx, NULL, "setting up recorder failed");
|
||||
@ -1535,22 +1545,23 @@ js_StartRecorder(JSContext* cx, GuardRecord* anchor, Fragment* f,
|
||||
static void
|
||||
js_TrashTree(JSContext* cx, Fragment* f)
|
||||
{
|
||||
JS_ASSERT((!f->code()) == (!f->vmprivate));
|
||||
if (!f->code())
|
||||
return;
|
||||
AUDIT(treesTrashed);
|
||||
debug_only(printf("Trashing tree info.\n");)
|
||||
Fragmento* fragmento = JS_TRACE_MONITOR(cx).fragmento;
|
||||
TreeInfo* ti = (TreeInfo*)f->vmprivate;
|
||||
if (ti) {
|
||||
/* trash the code of all dependent trees */
|
||||
unsigned length = ti->dependentTrees.length();
|
||||
Fragment** data = ti->dependentTrees.data();
|
||||
while (length-- > 0) {
|
||||
debug_only(printf("Trashing dependent tree.\n");)
|
||||
(*data++)->releaseCode(fragmento);
|
||||
}
|
||||
/* now we can kill the tree info object */
|
||||
delete ti;
|
||||
f->vmprivate = NULL;
|
||||
/* trash the code of all dependent trees */
|
||||
unsigned length = ti->dependentTrees.length();
|
||||
Fragment** data = ti->dependentTrees.data();
|
||||
while (length-- > 0) {
|
||||
debug_only(printf("Trashing dependent tree.\n");)
|
||||
(*data++)->releaseCode(fragmento);
|
||||
}
|
||||
/* now we can kill the tree info object */
|
||||
delete ti;
|
||||
f->vmprivate = NULL;
|
||||
f->releaseCode(fragmento);
|
||||
}
|
||||
|
||||
@ -1645,12 +1656,10 @@ js_RecordTree(JSContext* cx, JSTraceMonitor* tm, Fragment* f)
|
||||
#endif
|
||||
}
|
||||
|
||||
if (f->vmprivate)
|
||||
js_TrashTree(cx, f);
|
||||
JS_ASSERT(!f->code() && !f->vmprivate);
|
||||
|
||||
/* setup the VM-private treeInfo structure for this fragment */
|
||||
TreeInfo* ti = new (&gc) TreeInfo(f); // TODO: deallocate when fragment dies
|
||||
f->vmprivate = ti;
|
||||
TreeInfo* ti = new (&gc) TreeInfo(f);
|
||||
|
||||
/* we shouldn't have any interned globals for a new tree */
|
||||
JS_ASSERT(!ti->globalSlots.length());
|
||||
@ -1667,14 +1676,14 @@ js_RecordTree(JSContext* cx, JSTraceMonitor* tm, Fragment* f)
|
||||
ti->maxCallDepth = 0;
|
||||
|
||||
/* recording primary trace */
|
||||
return js_StartRecorder(cx, NULL, f, ti->globalSlots.length(),
|
||||
ti->globalTypeMap.data(), ti->stackTypeMap.data());
|
||||
return js_StartRecorder(cx, NULL, f, ti,
|
||||
ti->globalSlots.length(), ti->globalTypeMap.data(), ti->stackTypeMap.data());
|
||||
}
|
||||
|
||||
static bool
|
||||
js_AttemptToExtendTree(JSContext* cx, GuardRecord* lr, Fragment* f)
|
||||
{
|
||||
JS_ASSERT(lr->from->root == f);
|
||||
JS_ASSERT(lr->from->root == f && f->vmprivate);
|
||||
|
||||
debug_only(printf("trying to attach another branch to the tree\n");)
|
||||
|
||||
@ -1695,7 +1704,8 @@ js_AttemptToExtendTree(JSContext* cx, GuardRecord* lr, Fragment* f)
|
||||
unsigned ngslots = e->numGlobalSlots;
|
||||
uint8* globalTypeMap = e->typeMap;
|
||||
uint8* stackTypeMap = globalTypeMap + ngslots;
|
||||
return js_StartRecorder(cx, lr, c, ngslots, globalTypeMap, stackTypeMap);
|
||||
return js_StartRecorder(cx, lr, c, (TreeInfo*)f->vmprivate,
|
||||
ngslots, globalTypeMap, stackTypeMap);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -1988,10 +1998,13 @@ js_AbortRecording(JSContext* cx, jsbytecode* abortpc, const char* reason)
|
||||
}
|
||||
JS_ASSERT(JS_TRACE_MONITOR(cx).recorder != NULL);
|
||||
Fragment* f = JS_TRACE_MONITOR(cx).recorder->getFragment();
|
||||
JS_ASSERT(!f->vmprivate);
|
||||
f->blacklist();
|
||||
js_DeleteRecorder(cx);
|
||||
if (f->root == f)
|
||||
if (f->root == f) {
|
||||
/* we are recording a primary trace */
|
||||
js_TrashTree(cx, f);
|
||||
}
|
||||
}
|
||||
|
||||
extern void
|
||||
|
@ -189,7 +189,9 @@ public:
|
||||
unsigned mismatchCount;
|
||||
Queue<nanojit::Fragment*> dependentTrees;
|
||||
|
||||
TreeInfo(nanojit::Fragment* _fragment) { fragment = _fragment; }
|
||||
TreeInfo(nanojit::Fragment* _fragment) {
|
||||
fragment = _fragment;
|
||||
}
|
||||
};
|
||||
|
||||
extern struct nanojit::CallInfo builtins[];
|
||||
@ -304,7 +306,7 @@ class TraceRecorder {
|
||||
bool forInLoop(jsval* vp);
|
||||
|
||||
public:
|
||||
TraceRecorder(JSContext* cx, nanojit::GuardRecord*, nanojit::Fragment*,
|
||||
TraceRecorder(JSContext* cx, nanojit::GuardRecord*, nanojit::Fragment*, TreeInfo*,
|
||||
unsigned ngslots, uint8* globalTypeMap, uint8* stackTypeMap);
|
||||
~TraceRecorder();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user