Fix a bug in tracing can_do_fast_inc_dec (wasn't tracking a copy and traced incorrect code). Merge with TT tip.

This commit is contained in:
Andreas Gal 2008-06-24 15:57:33 -07:00
parent d8e0d5edec
commit 4678be95aa
14 changed files with 363 additions and 503 deletions

View File

@ -4300,7 +4300,7 @@ JS_INTERPRET(JSContext *cx, JSInterpreterState *state)
vp = fp->vars + slot;
do_int_fast_incop:
rval = *vp;
prim_copy(cx, *vp, rval);
if (JS_LIKELY(guard_can_do_fast_inc_dec(cx, regs, rval))) {
prim_do_fast_inc_dec(cx, rval, incr, *vp);
prim_do_fast_inc_dec(cx, rval, incr2, rtmp);

View File

@ -102,50 +102,24 @@ Tracker::get(const void* v) const
JS_ASSERT(p != 0); /* we must have a page for the slot we are looking for */
LIns* i = p->map[(((long)v) & 0xfff) >> 2];
JS_ASSERT(i != 0);
#ifdef DEBUG
//printf("get %p, which is %s\n",v, nanojit::lirNames[i->opcode()]);
#endif
return i;
}
void
Tracker::set(const void* v, LIns* ins)
{
#ifdef DEBUG
//printf("set %p to %s\n", v, nanojit::lirNames[ins->opcode()]);
#endif
struct Tracker::Page* p = findPage(v);
if (!p)
p = addPage(v);
p->map[(((long)v) & 0xfff) >> 2] = ins;
}
template <int N>
class BitStream
{
uint32_t* ptr;
unsigned n;
public:
BitStream(uint32_t* p, int words)
{
ptr = p;
n = 0;
}
void write(int data)
{
if (n + N > sizeof(uint32_t)) {
n = 0;
++ptr;
}
*ptr |= ((data & 7) << n);
n += N;
}
unsigned read(int data)
{
if (n + N > sizeof(uint32_t)) {
n = 0;
++ptr;
}
return (*ptr >> n) & 7;
}
};
using namespace avmplus;
using namespace nanojit;
@ -240,12 +214,4 @@ js_EndRecording(JSContext* cx, JSFrameRegs& regs)
compile(tm->fragmento->assm(), tm->fragment);
}
tm->status = IDLE;
/*
uint32_t x[2];
BitStream<3> w(x, 2);
for (int n = 0; n < 12; ++n)
w.write(n);
BitStream<3> r(x, 2);
for (int n = 0; n < 12; ++n)
printf("bs: %d\n", r.read(n));*/
}

View File

@ -283,7 +283,7 @@ guard_jsval_is_null(JSContext* cx, JSFrameRegs& regs, jsval& v)
if (JSVAL_IS_OBJECT(v)) {
SideExit exit;
L.insGuard(G(ok),
L.ins2(LIR_eq, get(&v), L.insImm(0)),
L.ins_eq0(get(&v)),
snapshot(cx, regs, exit));
}
return ok;
@ -572,7 +572,7 @@ guard_can_do_fast_inc_dec(JSContext* cx, JSFrameRegs& regs, jsval& v)
L.ins2(LIR_eq,
L.ins2(LIR_and,
L.ins2(LIR_xor,
L.ins2(LIR_lsh, get(&v), L.insImm(1)),
L.ins2i(LIR_lsh, get(&v), 1),
get(&v)),
L.insImm(0x80000000)),
L.insImm(0)),

View File

@ -122,7 +122,6 @@ namespace nanojit
verbose_only( _verbose = !core->quiet_opt() && core->verbose() );
verbose_only( _outputCache = 0);
verbose_only(Lir::initEngine();)
internalReset();
pageReset();
}
@ -567,22 +566,22 @@ namespace nanojit
void Assembler::asm_fcmp(LIns *cond)
{
LOpcode condop = cond->opcode();
NanoAssert(condop == LIR_eq || condop == LIR_le || condop == LIR_lt || condop == LIR_gt || condop == LIR_ge);
NanoAssert(condop >= LIR_feq && condop <= LIR_fge);
LIns* lhs = cond->oprnd1();
LIns* rhs = cond->oprnd2();
int mask;
if (condop == LIR_eq)
if (condop == LIR_feq)
mask = 0x44;
else if (condop == LIR_le)
else if (condop == LIR_fle)
mask = 0x41;
else if (condop == LIR_lt)
else if (condop == LIR_flt)
mask = 0x05;
else if (condop == LIR_ge) {
else if (condop == LIR_fge) {
// swap, use le
LIns* t = lhs; lhs = rhs; rhs = t;
mask = 0x41;
} else { // if (condop == LIR_gt)
} else { // if (condop == LIR_fgt)
// swap, use lt
LIns* t = lhs; lhs = rhs; rhs = t;
mask = 0x05;
@ -595,7 +594,7 @@ namespace nanojit
// LESS_THAN: ZF,PF,CF <- 001;
// EQUAL: ZF,PF,CF <- 100;
if (condop == LIR_eq && lhs == rhs) {
if (condop == LIR_feq && lhs == rhs) {
// nan check
Register r = findRegFor(lhs, XmmRegs);
UCOMISD(r, r);
@ -649,41 +648,48 @@ namespace nanojit
NanoAssert(frag->fragEntry);
NIns* was = asm_adjustBranch(lr->jmp, frag->fragEntry);
if (!lr->origTarget) lr->origTarget = was;
verbose_only(verbose_outputf("patching jump at %X to target %X (was %X)\n",(int)lr->jmp,(int)frag->fragEntry,was);)
verbose_only(verbose_outputf("patching jump at %p to target %p (was %p)\n",
lr->jmp, frag->fragEntry, was);)
}
void Assembler::unpatch(GuardRecord *lr)
{
NIns* was = asm_adjustBranch(lr->jmp, lr->origTarget);
(void)was;
verbose_only(verbose_outputf("unpatching jump at %X to original target %X (was %X)\n",(int)lr->jmp,(int)lr->origTarget,(int)was);)
verbose_only(verbose_outputf("unpatching jump at %p to original target %p (was %p)\n",
lr->jmp, lr->origTarget, was);)
}
NIns* Assembler::asm_exit(SideExit *exit)
NIns* Assembler::asm_exit(LInsp guard)
{
SideExit *exit = guard->exit();
NIns* at = 0;
if (!_branchStateMap->get(exit))
{
at = asm_leave_trace(exit);
at = asm_leave_trace(guard);
}
else
{
RegAlloc* captured = _branchStateMap->get(exit);
verbose_only(verbose_outputf("merged trunk with branch for SID %d",exit->sid);)
mergeRegisterState(*captured);
verbose_only(verbose_outputf("merging trunk with branch for SID %d",exit->sid);)
verbose_only(
verbose_outputf(" merging trunk with %s",
_frago->labels->format(exit->target));
verbose_outputf(" %p:",_nIns);
)
at = exit->target->fragEntry;
NanoAssert(at);
_branchStateMap->remove(exit);
}
return at;
}
NIns* Assembler::asm_leave_trace(SideExit* exit)
NIns* Assembler::asm_leave_trace(LInsp guard)
{
verbose_only(bool priorVerbose = _verbose; )
verbose_only( _verbose = verbose_enabled() && _frago->core()->config.verbose_exits; )
verbose_only( int32_t nativeSave = _stats.native );
verbose_only(verbose_outputf("--------------------------------------- end exit block SID %d",exit->sid);)
verbose_only(verbose_outputf("--------------------------------------- end exit block SID %d", guard->exit()->sid);)
RegAlloc capture = _allocator;
@ -698,8 +704,7 @@ namespace nanojit
//verbose_only( verbose_outputf(" LIR_xend swapptrs, _nIns is now %08X(%08X), _nExitIns is now %08X(%08X)",_nIns, *_nIns,_nExitIns,*_nExitIns) );
debug_only( _sv_fpuStkDepth = _fpuStkDepth; _fpuStkDepth = 0; )
GuardRecord *lr = nFragExit(exit); (void)lr;
verbose_only( if (lr) lr->gid = ++gid; )
GuardRecord *lr = nFragExit(guard); (void)lr;
mergeRegisterState(capture);
@ -737,13 +742,11 @@ namespace nanojit
return getresv(ins) == 0;
}
NIns* Assembler::beginAssembly(Fragment* frag, RegAllocMap* branchStateMap)
void Assembler::beginAssembly(RegAllocMap* branchStateMap)
{
_activation.lowwatermark = 1;
_activation.tos = _activation.lowwatermark;
_activation.highwatermark = _activation.tos;
_thisfrag = frag;
counter_reset(native);
counter_reset(exitnative);
@ -757,26 +760,25 @@ namespace nanojit
nativePageSetup();
// make sure we got memory at least one page
if (error()) return 0;
if (error()) return;
_epilogue = genEpilogue(SavedRegs);
_branchStateMap = branchStateMap;
verbose_only( verbose_outputf(" %p:",_nIns) );
verbose_only( verbose_output(" epilogue:") );
return _epilogue;
}
NIns* Assembler::assemble(Fragment* frag)
void Assembler::assemble(Fragment* frag, NInsList& loopJumps)
{
if (error()) return 0;
if (error()) return;
AvmCore *core = _frago->core();
GC *gc = core->gc;
_thisfrag = frag;
// set up backwards pipeline: assembler -> StoreFilter -> LirReader
LirReader bufreader(frag->lastIns);
StoreFilter storefilter(&bufreader, gc, this,
StoreFilter storefilter(&bufreader, gc,
frag->param0, frag->sp, frag->rp);
DeadCodeFilter deadfilter(&storefilter, this);
LirFilter* rdr = &deadfilter;
@ -788,16 +790,16 @@ namespace nanojit
verbose_only(_thisfrag->compileNbr++; )
verbose_only(_frago->_stats.compiles++; )
verbose_only(_frago->_stats.totalCompiles++; )
_latestGuard = 0;
_inExit = false;
NIns* loopJump = gen(rdr);
gen(rdr, loopJumps);
frag->fragEntry = _nIns;
frag->outbound = core->config.tree_opt? _latestGuard : 0;
//fprintf(stderr, "assemble frag %X entry %X\n", (int)frag, (int)frag->fragEntry);
return loopJump;
}
NIns* Assembler::endAssembly(Fragment* frag, NInsList& loopJumps)
void Assembler::endAssembly(Fragment* frag, NInsList& loopJumps)
{
while(!loopJumps.isEmpty())
{
@ -805,10 +807,14 @@ namespace nanojit
nPatchBranch(loopJump, _nIns);
}
NIns* patchEntry = genPrologue(SavedRegs);
verbose_only( verbose_outputf(" %p:",_nIns); )
verbose_only( verbose_output(" prologue"); )
NIns* patchEntry = 0;
if (!error())
{
patchEntry = genPrologue(SavedRegs);
verbose_only( verbose_outputf(" %p:",_nIns); )
verbose_only( verbose_output(" prologue"); )
}
// something bad happened?
if (!error())
{
@ -820,14 +826,19 @@ namespace nanojit
)
frag->fragEntry = patchEntry;
frag->setCode(_nIns);
NIns* code = _nIns;
// let the fragment manage the pages if we're using trees and there are branches
Page* manage = (_frago->core()->config.tree_opt) ? handoverPages() : 0;
frag->setCode(code, manage); // root of tree should manage all pages
NanoAssert(!_frago->core()->config.tree_opt || frag == frag->anchor || frag->kind == MergeTrace);
//fprintf(stderr, "endAssembly frag %X entry %X\n", (int)frag, (int)frag->fragEntry);
}
AvmAssertMsg(error() || _fpuStkDepth == 0, ("_fpuStkDepth %d\n",_fpuStkDepth));
internalReset(); // clear the reservation tables and regalloc
NanoAssert(_branchStateMap->isEmpty());
_branchStateMap = 0;
#ifdef UNDER_CE
@ -835,8 +846,6 @@ namespace nanojit
// to execute junk
FlushInstructionCache(GetCurrentProcess(), NULL, NULL);
#endif
return patchEntry;
}
void Assembler::copyRegisters(RegAlloc* copyTo)
@ -866,9 +875,8 @@ namespace nanojit
}
}
NIns* Assembler::gen(LirFilter* reader)
void Assembler::gen(LirFilter* reader, NInsList& loopJumps)
{
NIns *loopJump = 0;
const CallInfo* call = 0; // current call being emitted; if any
uint32_t iargs = 0;
uint32_t fargs = 0;
@ -1010,8 +1018,6 @@ namespace nanojit
LIns* values = ins->oprnd2();
// note that 'LIR_eq' is just a placeholder to hold two values...
// can't use the 123 form because we need space for reservation
NanoAssert(values->opcode() == LIR_2);
LIns* iftrue = values->oprnd1();
LIns* iffalse = values->oprnd2();
@ -1397,19 +1403,29 @@ namespace nanojit
case LIR_st:
case LIR_sti:
{
asm_store32(ins->oprnd1(), ins->immdisp(), ins->oprnd2());
break;
}
case LIR_stq:
case LIR_stqi:
{
LIns* value = ins->oprnd1();
LIns* base = ins->oprnd2();
int dr = ins->immdisp();
if (!value->isQuad())
asm_store32(value, dr, base);
else
if (value->isop(LIR_qjoin)) {
// this is correct for little-endian only
asm_store32(value->oprnd1(), dr, base);
asm_store32(value->oprnd2(), dr+4, base);
}
else {
asm_store64(value, dr, base);
}
break;
}
case LIR_xt:
case LIR_xf:
{
NIns* exit = asm_exit(ins->exit());
NIns* exit = asm_exit(ins);
// we only support cmp with guard right now, also assume it is 'close' and only emit the branch
LIns* cond = ins->oprnd1();
@ -1478,7 +1494,7 @@ namespace nanojit
{
verbose_only(verbose_output(""));
// generate the side exit branch on the main trace.
NIns *exit = asm_exit(ins->exit());
NIns *exit = asm_exit(ins);
JMP( exit );
break;
}
@ -1487,7 +1503,7 @@ namespace nanojit
JMP_long_placeholder(); // jump to SOT
verbose_only( if (_verbose && _outputCache) { _outputCache->removeLast(); outputf(" jmp SOT"); } );
loopJump = _nIns;
loopJumps.add(_nIns);
#ifdef NJ_VERBOSE
// branching from this frag to ourself.
@ -1495,12 +1511,28 @@ namespace nanojit
LDi(argRegs[1], int((Fragment*)_thisfrag));
#endif
// restore parameter 1, the only one we use
// restore first parameter, the only one we use
LInsp param0 = _thisfrag->param0;
Register a0 = Register(param0->imm8());
findSpecificRegFor(param0, a0);
break;
}
#ifndef NJ_SOFTFLOAT
case LIR_feq:
case LIR_fle:
case LIR_flt:
case LIR_fgt:
case LIR_fge:
{
// only want certain regs
Register r = prepResultReg(ins, AllowableFlagRegs);
// SETcc only sets low 8 bits, so extend
MOVZX8(r,r);
SETNP(r);
asm_fcmp(ins);
break;
}
#endif
case LIR_eq:
case LIR_le:
case LIR_lt:
@ -1512,19 +1544,9 @@ namespace nanojit
case LIR_uge:
{
// only want certain regs
uint32_t allow = AllowableFlagRegs;
Register r = prepResultReg(ins, allow);
Register r = prepResultReg(ins, AllowableFlagRegs);
// SETcc only sets low 8 bits, so extend
MOVZX8(r,r);
#ifndef NJ_SOFTFLOAT
if (ins->oprnd1()->isQuad())
{
SETNP(r);
asm_fcmp(ins);
break;
}
#endif
if (op == LIR_eq)
SETE(r);
else if (op == LIR_lt)
@ -1687,7 +1709,6 @@ namespace nanojit
debug_only( pageValidate(); )
debug_only( resourceConsistencyCheck(); )
}
return loopJump;
}
uint32_t Assembler::arFree(uint32_t idx)
@ -1817,7 +1838,8 @@ namespace nanojit
LIns * savedins = saved.getActive(r);
if (curins == savedins)
{
verbose_only( if (curins) verbose_outputf("skip %s", regNames[r]); )
verbose_only( if (curins)
verbose_outputf(" skip %s", regNames[r]); )
skip |= rmask(r);
}
else
@ -1864,8 +1886,9 @@ namespace nanojit
* NOTE: It is also not guaranteed that the native code
* is contained on a single page.
*/
GuardRecord* Assembler::placeGuardRecord(SideExit *exit)
GuardRecord* Assembler::placeGuardRecord(LInsp guard)
{
SideExit *exit = guard->exit();
// we align the guards to 4Byte boundary
NIns* ptr = (NIns*)alignTo(_nIns-sizeof(GuardRecord), 4);
underrunProtect( (int)_nIns-(int)ptr ); // either got us a new page or there is enough space for us
@ -1876,9 +1899,10 @@ namespace nanojit
rec->next = 0;
rec->origTarget = 0;
rec->target = exit->target;
rec->calldepth = exit->calldepth;
rec->from = _thisfrag;
rec->exit = exit;
rec->guard = guard;
rec->calldepth = exit->calldepth;
verbose_only( rec->sid = exit->sid; )
if (exit->target)
exit->target->addLink(rec);
verbose_only( rec->compileNbr = _thisfrag->compileNbr; )

View File

@ -78,9 +78,9 @@ namespace nanojit
NIns* jmp;
NIns* origTarget;
int32_t calldepth;
SideExit* exit;
LInsp guard;
GuardRecord* outgoing; /* list of guards in a fragment */
verbose_only( uint32_t gid; )
verbose_only( uint32_t sid; )
verbose_only( uint32_t compileNbr; )
};
@ -173,6 +173,8 @@ namespace nanojit
,MaxXJump
,UnknownPrim
};
typedef avmplus::List<NIns*, avmplus::LIST_NonGCObjects> NInsList;
/**
* Information about the activation record for the method is built up
@ -205,9 +207,9 @@ namespace nanojit
LInsp begin(LirWriter *writer); // @todo remove this
NIns* assemble(Fragment* frag);
NIns* endAssembly(Fragment* frag, NInsList& loopJumps);
NIns* beginAssembly(Fragment* frag, RegAllocMap* map);
void assemble(Fragment* frag, NInsList& loopJumps);
void endAssembly(Fragment* frag, NInsList& loopJumps);
void beginAssembly(RegAllocMap* map);
void copyRegisters(RegAlloc* copyTo);
void releaseRegisters();
void patch(GuardRecord *lr);
@ -235,13 +237,13 @@ namespace nanojit
private:
NIns* gen(LirFilter* toCompile);
void gen(LirFilter* toCompile, NInsList& loopJumps);
NIns* genPrologue(RegisterMask);
NIns* genEpilogue(RegisterMask);
bool ignoreInstruction(LInsp ins);
GuardRecord* placeGuardRecord(SideExit *exit);
GuardRecord* placeGuardRecord(LInsp guard);
uint32_t arReserve(LIns* l);
uint32_t arFree(uint32_t idx);
@ -292,7 +294,6 @@ namespace nanojit
Reservation _resvTable[ NJ_MAX_STACK_ENTRY ]; // table where we house stack and register information
uint32_t _resvFree;
verbose_only( uint32_t gid;)
bool _inExit,vpad2[3];
void asm_cmp(LIns *cond);
@ -300,8 +301,8 @@ namespace nanojit
void asm_fcmp(LIns *cond);
#endif
void asm_mmq(Register rd, int dd, Register rs, int ds);
NIns* asm_exit(SideExit *exit);
NIns* asm_leave_trace(SideExit* exit);
NIns* asm_exit(LInsp guard);
NIns* asm_leave_trace(LInsp guard);
void asm_qjoin(LIns *ins);
void asm_store32(LIns *val, int d, LIns *base);
void asm_store64(LIns *val, int d, LIns *base);
@ -321,7 +322,7 @@ namespace nanojit
void nArgEmitted(const CallInfo* call, uint32_t stackSlotCount, uint32_t iargs, uint32_t fargs);
void nFrameRestore(RegisterMask rmask);
static void nPatchBranch(NIns* branch, NIns* location);
GuardRecord *nFragExit(SideExit *exit);
GuardRecord *nFragExit(LInsp guard);
// platform specific methods
public:

View File

@ -46,7 +46,8 @@ namespace nanojit
/**
* This is the main control center for creating and managing fragments.
*/
Fragmento::Fragmento(AvmCore* core) : _allocList(core->GetGC())
Fragmento::Fragmento(AvmCore* core)
: _allocList(core->GetGC())
{
_core = core;
GC *gc = core->GetGC();
@ -59,14 +60,13 @@ namespace nanojit
Fragmento::~Fragmento()
{
debug_only( clearFrags() );
NanoAssert(_stats.freePages == _stats.pages);
_frags->clear();
while( _allocList.size() > 0 )
{
//fprintf(stderr,"dealloc %x\n", (intptr_t)_allocList.get(_allocList.size()-1));
_gcHeap->Free( _allocList.removeLast() );
}
NanoAssert(_stats.freePages == _stats.pages );
}
Page* Fragmento::pageAlloc()
@ -78,10 +78,10 @@ namespace nanojit
if (page)
{
_pageList = page->next;
debug_only(_stats.freePages--;)
verbose_only(_stats.freePages--;)
}
//fprintf(stderr, "Fragmento::pageAlloc %X, %d free pages of %d\n", (int)page, _stats.freePages, _stats.pages);
debug_only( NanoAssert(pageCount()==_stats.freePages); )
NanoAssert(pageCount()==_stats.freePages);
return page;
}
@ -92,8 +92,8 @@ namespace nanojit
// link in the page
page->next = _pageList;
_pageList = page;
debug_only(_stats.freePages++;)
debug_only( NanoAssert(pageCount()==_stats.freePages); )
verbose_only(_stats.freePages++;)
NanoAssert(pageCount()==_stats.freePages);
}
void Fragmento::pagesGrow(int32_t count)
@ -131,7 +131,7 @@ namespace nanojit
Page* page = memory;
_pageList = page;
_stats.pages += count;
debug_only(_stats.freePages += count;)
verbose_only(_stats.freePages += count;)
while(--count > 0)
{
Page *next = page + 1;
@ -140,26 +140,26 @@ namespace nanojit
page = next;
}
page->next = 0;
debug_only( NanoAssert(pageCount()==_stats.freePages); )
NanoAssert(pageCount()==_stats.freePages);
//fprintf(stderr,"Fragmento::pageGrow adding page %x ; %d\n", (intptr_t)page, count);
}
}
void Fragmento::clearFrags()
{
//fprintf(stderr, "Fragmento::clearFrags()\n");
// reclaim any dangling native pages
_assm->pageReset();
while (!_frags->isEmpty()) {
Fragment *f = _frags->removeLast();
f->clear();
}
// reclaim native pages @todo this is to be moved into tree code.
_assm->pageReset();
f->releaseTreeMem(this);
}
verbose_only( enterCounts->clear();)
verbose_only( mergeCounts->clear();)
verbose_only( _flushes++ );
verbose_only( _stats.flushes++ );
verbose_only( _stats.compiles = 0 );
//fprintf(stderr, "Fragmento.clearFrags %d free pages of %d\n", _stats.freePages, _stats.pages);
}
Assembler* Fragmento::assm()
@ -179,6 +179,7 @@ namespace nanojit
f = newFrag(is);
_frags->put(is.ip, f);
f->anchor = f;
f->root = f;
f->kind = LoopTrace;
f->mergeCounts = new (_core->gc) BlockHist(_core->gc);
verbose_only( addLabel(f, "T", _frags->size()); )
@ -206,6 +207,7 @@ namespace nanojit
}
Fragment *f = newBranch(anchor, is);
f->root = f;
f->kind = MergeTrace;
f->calldepth = lr->calldepth;
verbose_only(addLabel(f, "M", ++anchor->mergeid); )
@ -218,9 +220,8 @@ namespace nanojit
Fragment *f = newBranch(from, is);
f->kind = BranchTrace;
f->calldepth = lr->calldepth;
f->treeBranches = f->anchor->treeBranches;
f->anchor->treeBranches = f;
verbose_only( labels->add(f, sizeof(Fragment), 0, "-"); );
f->treeBranches = f->root->treeBranches;
f->root->treeBranches = f;
return f;
}
@ -286,7 +287,7 @@ namespace nanojit
if (x->kind == MergeTrace)
dumpFragStats(x,level+1,size,traceDur,interpDur);
if (f->anchor == f && f->branches != 0) {
if (f->isAnchor() && f->branches != 0) {
//_assm->outputf("tree size %d ticks %llu",size,dur);
_assm->output("");
}
@ -337,17 +338,20 @@ namespace nanojit
int32_t count = _frags->size();
int32_t pages = _stats.pages;
int32_t free = _stats.freePages;
int32_t flushes = _stats.flushes;
if (!count)
{
_assm->outputf("No fragments in cache, %d flushes", _flushes);
_assm->outputf("No fragments in cache, %d flushes", flushes);
_assm->_verbose = vsave;
return;
}
_assm->outputf("\nFragment statistics for %d entries after %d cache flushes of %d pages (%dKB) where %d used and %d free",
count, _flushes, pages, pages<<NJ_LOG2_PAGE_SIZE>>10, pages-free,free);
_assm->outputf("h=loop header, x=exit trace, L=loop");
_assm->output(" location calls guards main native gen T-trace T-interp");
_assm->outputf("\nFragment statistics");
_assm->outputf(" loop trees: %d", count);
_assm->outputf(" flushes: %d", flushes);
_assm->outputf(" compiles: %d / %d", _stats.compiles, _stats.totalCompiles);
_assm->outputf(" used: %dk / %dk", (pages-free)<<(NJ_LOG2_PAGE_SIZE-10), pages<<(NJ_LOG2_PAGE_SIZE-10));
_assm->output("\n location calls guards main native gen T-trace T-interp");
avmplus::SortedMap<uint64_t, DurData, avmplus::LIST_NonGCObjects> durs(_core->gc);
uint64_t totaldur=0;
@ -414,6 +418,11 @@ namespace nanojit
// Fragment is a gc object which is zero'd by the GC, no need to clear fields
}
Fragment::~Fragment()
{
NanoAssert(_pages == 0);
}
void Fragment::addLink(GuardRecord* lnk)
{
//fprintf(stderr,"addLink %x from %X target %X\n",(int)lnk,(int)lnk->from,(int)lnk->target);
@ -470,7 +479,6 @@ namespace nanojit
GuardRecord* next = lr->outgoing;
Fragment* targ = lr->target;
if (targ) targ->removeLink(lr);
verbose_only( lr->gid = 0; )
lr = next;
}
@ -481,11 +489,11 @@ namespace nanojit
GuardRecord* next = lr->next;
Fragment* from = lr->target;
if (from && from->fragEntry) assm->unpatch(lr);
verbose_only( lr->gid = 0; )
lr = next;
}
}
#ifdef _DEBUG
bool Fragment::hasOnlyTreeLinks()
{
// check that all incoming links are on the same tree
@ -495,7 +503,7 @@ namespace nanojit
{
GuardRecord *next = lr->next;
NanoAssert(lr->target == this); // def'n of GuardRecord
if (lr->from->anchor != anchor)
if (lr->from->root != root)
{
isIt = false;
break;
@ -504,17 +512,18 @@ namespace nanojit
}
return isIt;
}
#endif
void Fragment::removeIntraLinks()
{
// should only be called on root of tree
NanoAssert(this == anchor);
NanoAssert(isRoot());
GuardRecord *lr = _links;
while (lr)
{
GuardRecord *next = lr->next;
NanoAssert(lr->target == this); // def'n of GuardRecord
if (lr->from->anchor == anchor && lr->from->kind != MergeTrace)
if (lr->from->root == root)
removeLink(lr);
lr = next;
}
@ -523,7 +532,7 @@ namespace nanojit
void Fragment::unlinkBranches(Assembler* /*assm*/)
{
// should only be called on root of tree
NanoAssert(this == anchor);
NanoAssert(isRoot());
Fragment* frag = treeBranches;
while(frag)
{
@ -537,7 +546,7 @@ namespace nanojit
void Fragment::linkBranches(Assembler* assm)
{
// should only be called on root of tree
NanoAssert(this == anchor);
NanoAssert(isRoot());
Fragment* frag = treeBranches;
while(frag)
{
@ -571,6 +580,7 @@ namespace nanojit
{
Fragment *f = newFrag(interp);
f->anchor = from->anchor;
f->root = from->root;
f->mergeCounts = from->anchor->mergeCounts;
f->xjumpCount = from->xjumpCount;
/*// prepend
@ -588,15 +598,41 @@ namespace nanojit
return f;
}
void Fragment::clear()
{
void Fragment::releaseLirBuffer()
{
if (lirbuf) {
lirbuf->clear();
lirbuf = 0;
}
lastIns = 0;
}
lastIns = 0;
}
void Fragment::releaseCode(Fragmento* frago)
{
_code = 0;
while(_pages)
{
Page* next = _pages->next;
frago->pageFree(_pages);
_pages = next;
}
}
void Fragment::releaseTreeMem(Fragmento* frago)
{
releaseLirBuffer();
releaseCode(frago);
// now do it for all branches
Fragment* branch = branches;
while(branch)
{
Fragment* next = branch->nextbranch;
branch->releaseTreeMem(frago); // @todo safer here to recurse in case we support nested trees
branch = next;
}
}
void Fragment::removeExit(Fragment *target)
{
if (target && target == branches) {

View File

@ -110,7 +110,7 @@ namespace nanojit
struct
{
uint32_t pages; // pages consumed
uint32_t ilsize, abcsize, compiles, freePages;
uint32_t flushes, ilsize, abcsize, compiles, totalCompiles, freePages;
}
_stats;
@ -127,10 +127,8 @@ namespace nanojit
Page* _pageList;
/* unmanaged mem */
AllocList _allocList;
AllocList _allocList;
GCHeap* _gcHeap;
verbose_only( uint32_t _flushes; )
};
struct SideExit
@ -139,11 +137,10 @@ namespace nanojit
int32_t ip_adj;
int32_t sp_adj;
int32_t rp_adj;
Fragment *from;
Fragment *target;
int32_t calldepth;
LInsp ins;
verbose_only( uint32_t sid; )
verbose_only(Fragment *from;)
};
enum TraceKind {
@ -159,13 +156,14 @@ namespace nanojit
* It may turn out that that this arrangement causes too much traffic
* between d and i-caches and that we need to carve up the structure differently.
*/
class Fragment
class Fragment : public GCFinalizedObject
{
public:
Fragment(FragID);
~Fragment();
NIns* code() { return _code; }
void setCode(NIns* codee) { _code = codee; }
void setCode(NIns* codee, Page* pages) { _code = codee; _pages = pages; }
GuardRecord* links() { return _links; }
int32_t& hits() { return _hits; }
void blacklist();
@ -177,11 +175,14 @@ namespace nanojit
void linkBranches(Assembler* assm);
void unlink(Assembler* assm);
void unlinkBranches(Assembler* assm);
bool hasOnlyTreeLinks();
debug_only( bool hasOnlyTreeLinks(); )
void removeIntraLinks();
void removeExit(Fragment *target);
void clear();
void releaseLirBuffer();
void releaseCode(Fragmento* frago);
void releaseTreeMem(Fragmento* frago);
bool isAnchor() { return anchor == this; }
bool isRoot() { return root == this; }
verbose_only( uint32_t _called; )
verbose_only( uint32_t _native; )
@ -201,10 +202,11 @@ namespace nanojit
DWB(Fragment*) branches;
DWB(Fragment*) nextbranch;
DWB(Fragment*) anchor;
DWB(Fragment*) root;
DWB(BlockHist*) mergeCounts;
DWB(LirBuffer*) lirbuf;
LIns* lastIns;
SideExit* spawnedFrom;
LIns* spawnedFrom;
GuardRecord* outbound;
TraceKind kind;
@ -220,6 +222,7 @@ namespace nanojit
NIns* _code; // ptr to start of code
GuardRecord* _links; // code which is linked (or pending to be) to this fragment
int32_t _hits;
Page* _pages; // native code pages
};
#ifdef NJ_VERBOSE

View File

@ -44,117 +44,42 @@ namespace nanojit
using namespace avmplus;
#ifdef FEATURE_NANOJIT
// @todo -- a lookup table would be better here
uint32_t FASTCALL operandCount(LOpcode op)
{
switch(op)
{
case LIR_trace:
case LIR_skip:
case LIR_tramp:
case LIR_loop:
case LIR_x:
case LIR_short:
case LIR_int:
case LIR_quad:
case LIR_call:
case LIR_fcall:
case LIR_param:
return 0;
case LIR_callh:
case LIR_arg:
case LIR_ref:
case LIR_farg:
case LIR_not:
case LIR_xt:
case LIR_xf:
case LIR_qlo:
case LIR_qhi:
case LIR_neg:
case LIR_fneg:
case LIR_i2f:
case LIR_u2f:
return 1;
default:
return 2;
}
}
const uint8_t operandCount[] = {
/* 0 */ 2, 2, /*trace*/0, /*skip*/0, /*tramp*/0, 2, 2, 2, 2, /*arg*/1,
/* 10 */ /*param*/0, 2, 2, /*ref*/1, 2, 2, 2, 2, /*call*/0, /*loop*/0,
/* 20 */ /*x*/0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
/* 30 */ 2, 2, /*short*/0, /*int*/0, 2, 2, /*neg*/1, 2, 2, 2,
/* 40 */ /*callh*/1, 2, 2, 2, /*not*/1, 2, 2, 2, /*xt*/1, /*xf*/1,
/* 50 */ /*qlo*/1, /*qhi*/1, 2, 2, 2, 2, 2, 2, 2, 2,
/* 60 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
/* 70 */ 2, 2, 2, /*farg*/1, 2, 2, 2, 2, 2, 2,
/* 80 */ 2, 2, /*fcall*/0, 2, 2, 2, 2, 2, 2, 2,
/* 90 */ 2, 2, 2, 2, 2, 2, 2, /*quad*/0, 2, 2,
/* 100 */ /*fneg*/1, 2, 2, 2, 2, 2, /*i2f*/1, /*u2f*/1, 2, 2,
/* 110 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
/* 120 */ 2, 2, 2, 2, 2, 2, 2, 2,
};
// LIR verbose specific
#ifdef NJ_VERBOSE
void Lir::initEngine()
{
debug_only( { LIns l; l.initOpcode(LIR_last); NanoAssert(l.opcode()>0); } );
NanoAssert( LIR_last < (1<<8)-1 ); // only 8 bits or the opcode
verbose_only( initVerboseStructures() );
}
const char* lirNames[] = {
/* 0-9 */ "0","1","trace","skip","tramp","5","6","7","8","arg",
/* 10-19 */ "param","st","ld","ref","sti","15","16","17","call","loop",
/* 20-29 */ "x","21","22","23","24","25","feq","flt","fgt","fle",
/* 30-39 */ "fge","cmov","short","int","ldc","","neg","add","sub","mul",
/* 40-49 */ "callh","and","or","xor","not","lsh","rsh","ush","xt","xf",
/* 50-59 */ "qlo","qhi","ldcb","53","54","eq","lt","gt","le","ge",
/* 60-63 */ "ult","ugt","ule","uge",
/* 64-69 */ "LIR64","65","66","67","68","69",
/* 70-79 */ "70","71","72","farg","74","stq","ldq","77","stqi","79",
/* 80-89 */ "80","81","fcall","83","84","85","86","87","88","89",
/* 90-99 */ "90","91","92","93","94","95","96","quad","98","99",
/* 100-109 */ "fneg","fadd","fsub","fmul","fdiv","qjoin","i2f","u2f","108","109",
/* 110-119 */ "110","111","112","113","114","115","116","117","118","119",
/* 120-127 */ "120","121","122","123","124","125","126","127"
};
const char* Lir::_lirNames[LIR_last+1];
void Lir::initVerboseStructures()
{
memset(_lirNames, 0, sizeof(_lirNames));
_lirNames[LIR_short] = "short";
_lirNames[LIR_int] = "int";
_lirNames[LIR_quad] = "quad";
_lirNames[LIR_trace] = "trace";
_lirNames[LIR_skip] = "skip";
_lirNames[LIR_tramp] = "tramp";
_lirNames[LIR_loop] = "loop";
_lirNames[LIR_x] = "x";
_lirNames[LIR_xt] = "xt";
_lirNames[LIR_xf] = "xf";
_lirNames[LIR_eq] = "eq";
_lirNames[LIR_lt] = "lt";
_lirNames[LIR_le] = "le";
_lirNames[LIR_gt] = "gt";
_lirNames[LIR_ge] = "ge";
_lirNames[LIR_ult] = "ult";
_lirNames[LIR_ule] = "ule";
_lirNames[LIR_ugt] = "ugt";
_lirNames[LIR_uge] = "uge";
_lirNames[LIR_neg] = "neg";
_lirNames[LIR_add] = "add";
_lirNames[LIR_sub] = "sub";
_lirNames[LIR_mul] = "mul";
_lirNames[LIR_and] = "and";
_lirNames[LIR_or] = "or";
_lirNames[LIR_xor] = "xor";
_lirNames[LIR_not] = "not";
_lirNames[LIR_lsh] = "lsh";
_lirNames[LIR_rsh] = "rsh";
_lirNames[LIR_ush] = "ush";
_lirNames[LIR_fneg] = "fneg";
_lirNames[LIR_fadd] = "fadd";
_lirNames[LIR_fsub] = "fsub";
_lirNames[LIR_fmul] = "fmul";
_lirNames[LIR_fdiv] = "fdiv";
_lirNames[LIR_i2f] = "i2f";
_lirNames[LIR_u2f] = "u2f";
_lirNames[LIR_ld] = "ld";
_lirNames[LIR_ldc] = "ldc";
_lirNames[LIR_ldcb] = "ldcb";
_lirNames[LIR_cmov] = "cmov";
_lirNames[LIR_2] = "";
_lirNames[LIR_ldq] = "ldq";
_lirNames[LIR_st] = "st";
_lirNames[LIR_sti] = "sti";
_lirNames[LIR_arg] = "arg";
_lirNames[LIR_param] = "param";
_lirNames[LIR_call] = "call";
_lirNames[LIR_callh] = "callh";
_lirNames[LIR_qjoin] = "qjoin";
_lirNames[LIR_qlo] = "qlo";
_lirNames[LIR_qhi] = "qhi";
_lirNames[LIR_ref] = "ref";
_lirNames[LIR_last]= "???";
_lirNames[LIR_farg] = "farg";
_lirNames[LIR_fcall] = "fcall";
}
#endif /* NANOJIT_VEBROSE */
// implementation
@ -180,13 +105,13 @@ namespace nanojit
_unused = &_start->lir[0];
}
//buffer_count++;
//fprintf(stderr, "LirBuffer %x start %x count %d\n", (int)this, (int)_start, buffer_count);
//fprintf(stderr, "LirBuffer %x start %x\n", (int)this, (int)_start);
}
LirBuffer::~LirBuffer()
{
//buffer_count--;
//fprintf(stderr, "~LirBuffer %x count %d\n", (int)this, buffer_count);
//fprintf(stderr, "~LirBuffer %x start %x\n", (int)this, (int)_start);
clear();
_frago = 0;
}
@ -305,7 +230,6 @@ namespace nanojit
LInsp LirBufWriter::ensureReferenceable(LInsp i, int32_t addedDistance)
{
if (!i) return 0;
NanoAssert(!i->isop(LIR_tramp));
LInsp next = _buf->next();
LInsp from = next + addedDistance;
@ -318,14 +242,14 @@ namespace nanojit
return tramp;
}
LInsp LirBufWriter::insStore(LInsp o1, LInsp o2, LInsp o3)
LInsp LirBufWriter::insStore(LInsp val, LInsp base, LInsp off)
{
LOpcode op = LIR_st;
NanoAssert(o1 && o2 && o3);
LOpcode op = val->isQuad() ? LIR_stq : LIR_st;
NanoAssert(val && base && off);
ensureRoom(4);
LInsp r1 = ensureReferenceable(o1,3);
LInsp r2 = ensureReferenceable(o2,2);
LInsp r3 = ensureReferenceable(o3,1);
LInsp r1 = ensureReferenceable(val,3);
LInsp r2 = ensureReferenceable(base,2);
LInsp r3 = ensureReferenceable(off,1);
LInsp l = _buf->next();
l->initOpcode(op);
@ -338,13 +262,13 @@ namespace nanojit
return l;
}
LInsp LirBufWriter::insStorei(LInsp o1, LInsp o2, int32_t d)
LInsp LirBufWriter::insStorei(LInsp val, LInsp base, int32_t d)
{
LOpcode op = LIR_sti;
NanoAssert(o1 && o2 && isS8(d));
LOpcode op = val->isQuad() ? LIR_stqi : LIR_sti;
NanoAssert(val && base && isS8(d));
ensureRoom(3);
LInsp r1 = ensureReferenceable(o1,2);
LInsp r2 = ensureReferenceable(o2,1);
LInsp r1 = ensureReferenceable(val,2);
LInsp r2 = ensureReferenceable(base,1);
LInsp l = _buf->next();
l->initOpcode(op);
@ -359,7 +283,7 @@ namespace nanojit
LInsp LirBufWriter::ins0(LOpcode op)
{
if (!ensureRoom(1)) return 0;
ensureRoom(1);
LInsp l = _buf->next();
l->initOpcode(op);
_buf->commit(1);
@ -516,7 +440,7 @@ namespace nanojit
}
bool FASTCALL isCmp(LOpcode c) {
return c >= LIR_eq && c <= LIR_uge;
return c >= LIR_eq && c <= LIR_uge || c >= LIR_feq && c <= LIR_fge;
}
bool LIns::isCmp() const {
@ -535,7 +459,8 @@ namespace nanojit
bool LIns::isStore() const
{
return u.code == LIR_st || u.code == LIR_sti;
int c = u.code & ~LIR64;
return c == LIR_st || c == LIR_sti;
}
bool LIns::isLoad() const
@ -560,7 +485,7 @@ namespace nanojit
bool FASTCALL isCse(LOpcode op) {
op = LOpcode(op & ~LIR64);
return op >= LIR_cmov && op <= LIR_uge;
return op >= LIR_feq && op <= LIR_uge;
}
bool LIns::isCse(const CallInfo *functions) const
@ -717,11 +642,11 @@ namespace nanojit
if (oprnd1 == oprnd2)
{
if (v == LIR_xor || v == LIR_sub ||
!oprnd1->isQuad() && (v == LIR_ult || v == LIR_ugt || v == LIR_gt || v == LIR_lt))
v == LIR_ult || v == LIR_ugt || v == LIR_gt || v == LIR_lt)
return insImm(0);
if (v == LIR_or || v == LIR_and)
return oprnd1;
if (!oprnd1->isQuad() && (v == LIR_le || v == LIR_ule || v == LIR_ge || v == LIR_uge)) {
if (v == LIR_le || v == LIR_ule || v == LIR_ge || v == LIR_uge) {
// x <= x == 1; x >= x == 1
return insImm(1);
}
@ -763,15 +688,15 @@ namespace nanojit
{
double c1 = oprnd1->constvalf();
double c2 = oprnd1->constvalf();
if (v == LIR_eq)
if (v == LIR_feq)
return insImm(c1 == c2);
if (v == LIR_lt)
if (v == LIR_flt)
return insImm(c1 < c2);
if (v == LIR_gt)
if (v == LIR_fgt)
return insImm(c1 > c2);
if (v == LIR_le)
if (v == LIR_fle)
return insImm(c1 <= c2);
if (v == LIR_ge)
if (v == LIR_fge)
return insImm(c1 >= c2);
}
else if (oprnd1->isconst() && !oprnd2->isconst())
@ -785,7 +710,7 @@ namespace nanojit
oprnd2 = oprnd1;
oprnd1 = t;
}
else if (v >= LIR_lt && v <= LIR_uge && !oprnd2->isQuad()) {
else if (v >= LIR_lt && v <= LIR_uge) {
// move const to rhs, swap the operator
LIns *t = oprnd2;
oprnd2 = oprnd1;
@ -948,7 +873,7 @@ namespace nanojit
int32_t argc = ci.count_args();
const uint32_t ret = argt & 3;
LOpcode op = k_callmap[ret];
//printf(" ret is type %d %s\n", ret, Lir::_lirNames[op]);
//printf(" ret is type %d %s\n", ret, lirNames[op]);
#ifdef NJ_SOFTFLOAT
if (op == LIR_fcall)
@ -984,144 +909,10 @@ namespace nanojit
return insImm8(op==LIR_callh ? LIR_call : op, fid, argc);
}
/*
#ifdef AVMPLUS_VERBOSE
void printTracker(const char* s, RegionTracker& trk, Assembler* assm)
{
assm->outputf("%s tracker width %d starting %X zeroth %X indexOf(starting) %d", s, trk.width, trk.starting, trk.zeroth, trk.indexOf(trk.starting));
assm->output_ins(" location ", trk.location);
for(int k=0;k<trk.length;k++)
{
if (trk.element[k])
{
assm->outputf(" [%d]", k+1);
assm->output_ins(" val ", trk.element[k]);
}
}
}
#endif
LInsp adjustTracker(RegionTracker& trk, int32_t adj, LInsp i)
{
int32_t d = i->immdisp();
LInsp unaligned = 0;
if ( d&((1<<trk.width)-1) )
{
unaligned = i;
}
else
{
// put() if there is nothing at this slot
void* at = (void*)(d+adj);
if (!trk.get(at))
{
LInsp v = i->oprnd1();
trk.set(at, v);
}
}
return unaligned;
}
void trackersAtExit(SideExit* exit, RegionTracker& rtrk, RegionTracker& strk, Assembler *assm)
{
(void)assm;
int32_t s_adj=(int32_t)strk.starting, r_adj=(int32_t)rtrk.starting;
Fragment* frag = exit->from;
LInsp param0=frag->param0, sp=frag->sp, rp=frag->rp;
LirReader *r = frag->lirbuf->reader();
AvmCore *core = frag->lirbuf->_frago->core();
InsList live(core->gc);
rtrk.location->setresv(0);
strk.location->setresv(0);
verbose_only(if (assm->_verbose) assm->output_ins("Reconstituting region trackers, starting from ", exit->ins);)
LInsp i = 0;
bool checkLive = true;
#if 0
// @todo needed for partial tree compile
bool checkLive = true;
// build a list of known live-valued instructions at the exit
verbose_only(if (assm->_verbose) assm->output(" compile-time live values at exit");)
LInsp i = r->setPos(exit->arAtExit);
while(i)
{
if (i->isop(LIR_2))
{
LInsp t = i->oprnd1();
if (live.indexOf(t)<0)
{
verbose_only(if (assm->_verbose) assm->output_ins(" ", t);)
live.add(t);
}
}
i = r->previous();
}
#endif
// traverse backward starting from the exit instruction
i = r->setPos(exit->ins);
while(i)
{
if (i->isStore())
{
LInsp base = i->oprnd2();
if (base == param0)
{
// update stop/rstop
int32_t d = i->immdisp();
if (d == offsetof(InterpState,sp))
{
s_adj += i->oprnd1()->oprnd2()->constval();
}
else if (d == offsetof(InterpState,rp))
{
r_adj += i->oprnd1()->oprnd2()->constval();
}
}
else if (base == sp)
{
LInsp what = i->oprnd1();
bool imm = what->isconst() || what->isconstq();
if (!checkLive || (imm || live.indexOf(what)>=0))
{
verbose_only(if (assm->_verbose) assm->output_ins(" strk-adding ", i);)
adjustTracker(strk, s_adj, i);
}
else
{
verbose_only(if (assm->_verbose) assm->output_ins(" strk-ignoring ", i);)
}
}
else if (base == rp)
{
LInsp what = i->oprnd1();
bool imm = what->isconst() || what->isconstq();
if (!checkLive || imm || live.indexOf(what))
{
verbose_only(if (assm->_verbose) assm->output_ins(" rtrk-adding ", i);)
adjustTracker(rtrk, r_adj, i);
}
else
{
verbose_only(if (assm->_verbose) assm->output_ins(" rtrk-adding ", i);)
}
}
}
i = r->previous();
}
verbose_only(if (assm->_verbose) { printTracker("rtrk", rtrk,assm); } )
verbose_only(if (assm->_verbose) { printTracker("strk", strk,assm); } )
}
*/
using namespace avmplus;
StoreFilter::StoreFilter(LirFilter *in, GC *gc, Assembler *assm, LInsp p0, LInsp sp, LInsp rp)
: LirFilter(in), gc(gc), assm(assm), param0(p0), sp(sp), rp(rp), stop(0), rtop(0)
StoreFilter::StoreFilter(LirFilter *in, GC *gc, LInsp p0, LInsp sp, LInsp rp)
: LirFilter(in), gc(gc), param0(p0), sp(sp), rp(rp), stop(0), rtop(0)
{}
LInsp StoreFilter::read()
@ -1276,7 +1067,7 @@ namespace nanojit
return hashcall(i->imm8(), argc, args);
}
default:
if (operandCount(op) == 2)
if (operandCount[op] == 2)
return hash2(op, i->oprnd1(), i->oprnd2());
else
return hash1(op, i->oprnd1());
@ -1317,7 +1108,7 @@ namespace nanojit
}
default:
{
const uint32_t count = operandCount(op);
const uint32_t count = operandCount[op];
if ((count >= 1 && a->oprnd1() != b->oprnd1()) ||
(count >= 2 && a->oprnd2() != b->oprnd2()))
return false;
@ -1371,6 +1162,17 @@ namespace nanojit
return name;
}
void LInsHashSet::replace(LInsp i)
{
uint32_t k = find(i, hashcode(i), m_list, m_list.size());
if (m_list.get(k)) {
// already there, so replace it
m_list.set(k, i);
} else {
add(i, k);
}
}
uint32_t LInsHashSet::hashimm(int32_t a) {
return _hashfinish(_hash32(0,a));
}
@ -1549,7 +1351,7 @@ namespace nanojit
uint32_t exits = 0;
LirBuffer *lirbuf = frag->lirbuf;
LirReader br(lirbuf);
StoreFilter r(&br, gc, 0, frag->param0, sp, rp);
StoreFilter r(&br, gc, frag->param0, sp, rp);
bool skipargs = false;
int total = 0;
live.add(frag->param0, r.pos());
@ -1586,10 +1388,10 @@ namespace nanojit
live.add(i->oprnd2()->oprnd1(),i);
live.add(i->oprnd2()->oprnd2(),i);
}
else if (operandCount(i->opcode()) == 1) {
else if (operandCount[i->opcode()] == 1) {
live.add(i->oprnd1(),i);
}
else if (operandCount(i->opcode()) == 2) {
else if (operandCount[i->opcode()] == 2) {
live.add(i->oprnd1(),i);
live.add(i->oprnd2(),i);
}
@ -1624,8 +1426,10 @@ namespace nanojit
}
void LirNameMap::addName(LInsp i, Stringp name) {
Entry *e = new (labels->core->gc) Entry(name);
names.put(i, e);
if (!names.containsKey(i)) {
Entry *e = new (labels->core->gc) Entry(name);
names.put(i, e);
}
}
void LirNameMap::addName(LInsp i, const char *name) {
addName(i, labels->core->newString(name));
@ -1666,7 +1470,7 @@ namespace nanojit
if (ref->isCall()) {
copyName(ref, _functions[ref->imm8()]._name, funccounts.add(ref->imm8()));
} else {
copyName(ref, nameof(ref), lircounts.add(ref->opcode()));
copyName(ref, lirNames[ref->opcode()], lircounts.add(ref->opcode()));
}
StringNullTerminatedUTF8 cname(gc, names.get(ref)->name);
strcat(buf, cname.c_str());
@ -1683,7 +1487,8 @@ namespace nanojit
s += strlen(s);
}
switch(i->opcode())
LOpcode op = i->opcode();
switch(op)
{
case LIR_short:
case LIR_int:
@ -1701,7 +1506,7 @@ namespace nanojit
case LIR_loop:
case LIR_trace:
sprintf(s, "%s", nameof(i));
sprintf(s, "%s", lirNames[op]);
break;
case LIR_fcall:
@ -1718,13 +1523,14 @@ namespace nanojit
}
case LIR_param:
sprintf(s, "%s %s", nameof(i), gpn(i->imm8()));
sprintf(s, "%s %s", lirNames[op], gpn(i->imm8()));
break;
case LIR_x: {
SideExit *x = (SideExit*) i->oprnd2()->payload();
uint32_t ip = uint32_t(x->from->frid) + x->ip_adj;
sprintf(s, "%s -> %s sp%+d rp%+d f%+d", nameof(i),
sprintf(s, "%s: %s -> %s sp%+d rp%+d f%+d",
formatRef(i), lirNames[op],
labels->format((void*)ip),
x->sp_adj, x->rp_adj, x->f_adj);
break;
@ -1740,14 +1546,15 @@ namespace nanojit
case LIR_qlo:
case LIR_qhi:
case LIR_ref:
sprintf(s, "%s %s", nameof(i), formatRef(i->oprnd1()));
sprintf(s, "%s %s", lirNames[op], formatRef(i->oprnd1()));
break;
case LIR_xt:
case LIR_xf: {
SideExit *x = (SideExit*) i->oprnd2()->payload();
uint32_t ip = int32_t(x->from->frid) + x->ip_adj;
sprintf(s, "%s %s -> %s sp%+d rp%+d f%+d", nameof(i),
sprintf(s, "%s: %s %s -> %s sp%+d rp%+d f%+d",
formatRef(i), lirNames[op],
formatRef(i->oprnd1()),
labels->format((void*)ip),
x->sp_adj, x->rp_adj, x->f_adj);
@ -1776,8 +1583,13 @@ namespace nanojit
case LIR_ule:
case LIR_ugt:
case LIR_uge:
case LIR_feq:
case LIR_flt:
case LIR_fle:
case LIR_fgt:
case LIR_fge:
case LIR_qjoin:
sprintf(s, "%s %s, %s", nameof(i),
sprintf(s, "%s %s, %s", lirNames[op],
formatRef(i->oprnd1()),
formatRef(i->oprnd2()));
break;
@ -1793,13 +1605,15 @@ namespace nanojit
case LIR_ldc:
case LIR_ldq:
case LIR_ldcb:
sprintf(s, "%s %s[%s]", nameof(i),
sprintf(s, "%s %s[%s]", lirNames[op],
formatRef(i->oprnd1()),
formatRef(i->oprnd2()));
break;
case LIR_st:
case LIR_sti:
case LIR_stq:
case LIR_stqi:
sprintf(s, "%s[%d] = %s",
formatRef(i->oprnd2()),
i->immdisp(),
@ -1840,7 +1654,7 @@ namespace nanojit
LIns* CseFilter::ins1(LOpcode v, LInsp a)
{
if (isCse(v)) {
NanoAssert(operandCount(v)==1);
NanoAssert(operandCount[v]==1);
uint32_t k;
LInsp found = exprs.find1(v, a, k);
if (found)
@ -1853,7 +1667,7 @@ namespace nanojit
LIns* CseFilter::ins2(LOpcode v, LInsp a, LInsp b)
{
if (isCse(v)) {
NanoAssert(operandCount(v)==2);
NanoAssert(operandCount[v]==2);
uint32_t k;
LInsp found = exprs.find2(v, a, b, k);
if (found)
@ -1866,7 +1680,7 @@ namespace nanojit
LIns* CseFilter::insLoad(LOpcode v, LInsp base, LInsp disp)
{
if (isCse(v)) {
NanoAssert(operandCount(v)==2);
NanoAssert(operandCount[v]==2);
uint32_t k;
LInsp found = exprs.find2(v, base, disp, k);
if (found)
@ -1880,7 +1694,7 @@ namespace nanojit
{
if (isCse(v)) {
// conditional guard
NanoAssert(operandCount(v)==1);
NanoAssert(operandCount[v]==1);
uint32_t k;
LInsp found = exprs.find1(v, c, k);
if (found)
@ -1903,6 +1717,20 @@ namespace nanojit
return out->insCall(fid, args);
}
CseReader::CseReader(LirFilter *in, LInsHashSet *exprs, const CallInfo *functions)
: LirFilter(in), exprs(exprs), functions(functions)
{}
LInsp CseReader::read()
{
LInsp i = in->read();
if (i) {
if (i->isCse(functions))
exprs->replace(i);
}
return i;
}
LIns* FASTCALL callArgN(LIns* i, uint32_t n)
{
// @todo clean up; shouldn't have to create a reader
@ -1915,7 +1743,8 @@ namespace nanojit
void compile(Assembler* assm, Fragment* triggerFrag)
{
AvmCore *core = triggerFrag->lirbuf->_frago->core();
Fragmento *frago = triggerFrag->lirbuf->_frago;
AvmCore *core = frago->core();
GC *gc = core->gc;
verbose_only( StringList asmOutput(gc); )
@ -1927,18 +1756,19 @@ namespace nanojit
bool treeCompile = core->config.tree_opt && (triggerFrag->kind == BranchTrace);
RegAllocMap regMap(gc);
NInsList loopJumps(gc);
assm->beginAssembly(triggerFrag, &regMap);
assm->beginAssembly(&regMap);
//fprintf(stderr, "recompile trigger %X kind %d\n", (int)triggerFrag, triggerFrag->kind);
Fragment* root = triggerFrag;
if (treeCompile)
{
// recompile the entire tree
root = triggerFrag->anchor;
root = triggerFrag->root;
root->removeIntraLinks();
root->unlink(assm); // unlink all incoming jumps ; since the compile() can fail
root->unlinkBranches(assm); // no one jumps into a branch (except from within the tree) so safe to clear the links table
root->fragEntry = 0;
root->releaseCode(frago);
// do the tree branches
Fragment* frag = root->treeBranches;
@ -1947,15 +1777,17 @@ namespace nanojit
// compile til no more frags
if (frag->lastIns)
{
NIns* loopJump = assm->assemble(frag);
verbose_only(if (assm->_verbose) assm->outputf("compiling branch %X that exits from SID %d",frag->frid,frag->spawnedFrom->sid);)
if (loopJump) loopJumps.add((intptr_t)loopJump);
assm->assemble(frag, loopJumps);
verbose_only(if (assm->_verbose)
assm->outputf("compiling branch %s ip %s",
frago->labels->format(frag),
frago->labels->format(frag->frid)); )
NanoAssert(frag->kind == BranchTrace);
RegAlloc* regs = new (gc) RegAlloc();
assm->copyRegisters(regs);
assm->releaseRegisters();
SideExit* exit = frag->spawnedFrom;
SideExit* exit = frag->spawnedFrom->exit();
regMap.put(exit, regs);
}
frag = frag->treeBranches;
@ -1963,15 +1795,11 @@ namespace nanojit
}
// now the the main trunk
NIns* loopJump = assm->assemble(root);
verbose_only(if (assm->_verbose) assm->output("compiling trunk");)
if (loopJump) loopJumps.add((intptr_t)loopJump);
assm->assemble(root, loopJumps);
verbose_only(if (assm->_verbose)
assm->outputf("compiling trunk %s",
frago->labels->format(root));)
assm->endAssembly(root, loopJumps);
// remove the map enties
while(!regMap.isEmpty())
gc->Free(regMap.removeLast());
// reverse output so that assembly is displayed low-to-high
verbose_only( assm->_outputCache = 0; )

View File

@ -67,9 +67,13 @@ namespace nanojit
LIR_loop = 19, // loop fragment
LIR_x = 20, // exit always
/**
* Integer operations
*/
// operators
LIR_feq = 26,
LIR_flt = 27,
LIR_fgt = 28,
LIR_fle = 29,
LIR_fge = 30,
LIR_cmov = 31, // conditional move (op1=cond, op2=cond(iftrue,iffalse))
LIR_short = 32,
LIR_int = 33,
@ -106,8 +110,10 @@ namespace nanojit
LIR_uge = 63, // 0x3F 0011 1111
/**
* Floating point operations
* 64bit operations
*/
LIR_stq = LIR_st | LIR64,
LIR_stqi = LIR_sti | LIR64,
LIR_quad = LIR_int | LIR64,
LIR_ldq = LIR_ld | LIR64,
@ -117,13 +123,11 @@ namespace nanojit
LIR_fadd = LIR_add | LIR64,
LIR_fsub = LIR_sub | LIR64,
LIR_fmul = LIR_mul | LIR64,
LIR_fdiv = 8 | LIR64,
LIR_fdiv = 40 | LIR64,
LIR_qjoin = 41 | LIR64,
LIR_i2f = 42 | LIR64,
LIR_u2f = 43 | LIR64,
LIR_last = 56 | LIR64 // highest ordinal value possible ( must be <127 )
};
struct SideExit;
@ -221,7 +225,7 @@ namespace nanojit
inline int32_t immdisp()const
{
return u.code == LIR_sti ? sti.disp : oprnd3()->constval();
return (u.code&~LIR64) == LIR_sti ? sti.disp : oprnd3()->constval();
}
inline static bool sameop(LIns* a, LIns* b)
@ -301,7 +305,7 @@ namespace nanojit
bool FASTCALL isCse(LOpcode v);
bool FASTCALL isCmp(LOpcode v);
LIns* FASTCALL callArgN(LInsp i, uint32_t n);
uint32_t FASTCALL operandCount(LOpcode op);
extern const uint8_t operandCount[];
class Fragmento; // @todo remove this ; needed for minbuild for some reason?!? Should not be compiling this code at all
class LirFilter;
@ -363,15 +367,7 @@ namespace nanojit
};
#ifdef NJ_VERBOSE
class Lir
{
public:
static void initEngine();
verbose_only( static const char* _lirNames[LIR_last+1]; )
verbose_only( static void initVerboseStructures(); )
private:
Lir() { NanoAssertMsg(1, "Cannot instantiate this singleton"); }
};
extern const char* lirNames[];
/**
* map address ranges to meaningful names.
@ -434,10 +430,6 @@ namespace nanojit
labels(r)
{}
const char *nameof(LInsp i) {
return Lir::_lirNames[i->opcode()];
}
void addName(LInsp i, const char *s);
void addName(LInsp i, avmplus::String *s);
void copyName(LInsp i, const char *s, int suffix);
@ -482,6 +474,7 @@ namespace nanojit
LInsp find2(LOpcode v, LInsp a, LInsp b, uint32_t &i);
LInsp findcall(int32_t fid, uint32_t argc, LInsp args[], uint32_t &i);
LInsp add(LInsp i, uint32_t k);
void replace(LInsp i);
static uint32_t FASTCALL hashimm(int32_t);
static uint32_t FASTCALL hashimmq(uint64_t);
@ -492,8 +485,8 @@ namespace nanojit
class CseFilter: public LirWriter
{
LInsHashSet exprs;
public:
LInsHashSet exprs;
CseFilter(LirWriter *out, GC *gc);
LIns* insImm(int32_t imm);
LIns* insImmq(uint64_t q);
@ -615,22 +608,28 @@ namespace nanojit
class Assembler;
void compile(Assembler *assm, Fragment *frag);
void trackersAtExit(SideExit* exit, avmplus::RegionTracker& rtrk, avmplus::RegionTracker& strk, Assembler *assm);
verbose_only( void printTracker(const char* s, avmplus::RegionTracker& trk, Assembler* assm); )
verbose_only(void live(GC *gc, Assembler *assm, Fragment *frag);)
class StoreFilter: public LirFilter
{
GC *gc;
Assembler *assm;
LInsp param0, sp, rp;
avmplus::BitSet rstk, stk;
int stop, rtop;
public:
StoreFilter(LirFilter *in, GC *gc, Assembler *assm,
LInsp p0, LInsp sp, LInsp rp);
StoreFilter(LirFilter *in, GC *gc, LInsp p0, LInsp sp, LInsp rp);
virtual ~StoreFilter() {}
LInsp read();
};
class CseReader: public LirFilter
{
LInsHashSet *exprs;
const CallInfo *functions;
public:
CseReader(LirFilter *in, LInsHashSet *exprs, const CallInfo*);
LInsp read();
};
}
#endif // __nanojit_LIR__

View File

@ -69,7 +69,7 @@
sprintf(outline, " ");\
sprintf(&outline[19]
#define PSFX Assembler::outputAlign(outline, 45);\
RegAlloc::formatRegisters(_allocator, outline, _thisfrag->lirbuf->names);\
RegAlloc::formatRegisters(_allocator, outline, _thisfrag);\
Assembler::output_asm(outline); }
//#define PRFX fprintf(stdout
//#define PSFX fprintf(stdout,"\n")

View File

@ -108,8 +108,9 @@ namespace nanojit
return patchEntry;
}
GuardRecord * Assembler::nFragExit(SideExit *exit)
GuardRecord * Assembler::nFragExit(LInsp guard)
{
SideExit *exit = guard->exit();
bool trees = _frago->core()->config.tree_opt;
Fragment *frag = exit->target;
GuardRecord *lr = 0;
@ -123,7 +124,7 @@ namespace nanojit
else
{
// target doesn't exit yet. emit jump to epilog, and set up to patch later.
lr = placeGuardRecord(exit);
lr = placeGuardRecord(guard);
JMP_long(_epilogue);
lr->jmp = _nIns;
#if 0

View File

@ -127,8 +127,11 @@ namespace nanojit
}
#ifdef NJ_VERBOSE
/* static */ void RegAlloc::formatRegisters(RegAlloc& regs, char* s, LirNameMap *names)
/* static */ void RegAlloc::formatRegisters(RegAlloc& regs, char* s, Fragment *frag)
{
if (!frag || !frag->lirbuf)
return;
LirNameMap *names = frag->lirbuf->names;
for(int i=0; i<NJ_MAX_REGISTERS; i++)
{
LIns* ins = regs.active[i];

View File

@ -71,7 +71,7 @@ namespace nanojit
RegisterMask free;
RegisterMask used;
verbose_only( static void formatRegisters(RegAlloc& regs, char* s, LirNameMap*); )
verbose_only( static void formatRegisters(RegAlloc& regs, char* s, Fragment*); )
DECLARE_PLATFORM_REGALLOC()
};

View File

@ -68,13 +68,12 @@ namespace nanojit
typedef avmplus::SortedMap<FragID,Fragment*,avmplus::LIST_GCObjects> FragmentMap;
typedef avmplus::SortedMap<SideExit*,RegAlloc*,avmplus::LIST_GCObjects> RegAllocMap;
typedef avmplus::List<LIns*,avmplus::LIST_NonGCObjects> InsList;
typedef avmplus::List<intptr_t, avmplus::LIST_GCObjects> NInsList;
typedef avmplus::List<char*, avmplus::LIST_GCObjects> StringList;
#if defined(_DEBUG)
#ifndef WIN32
inline void DebugBreak() { AvmAssert(0); }
#define DebugBreak() AvmAssert(0)
#endif
#define _NanoAssertMsg(a,m) do { if ((a)==0) { AvmDebugLog(("%s", m)); DebugBreak(); } } while (0)