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; vp = fp->vars + slot;
do_int_fast_incop: do_int_fast_incop:
rval = *vp; prim_copy(cx, *vp, rval);
if (JS_LIKELY(guard_can_do_fast_inc_dec(cx, regs, 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, incr, *vp);
prim_do_fast_inc_dec(cx, rval, incr2, rtmp); 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 */ JS_ASSERT(p != 0); /* we must have a page for the slot we are looking for */
LIns* i = p->map[(((long)v) & 0xfff) >> 2]; LIns* i = p->map[(((long)v) & 0xfff) >> 2];
JS_ASSERT(i != 0); JS_ASSERT(i != 0);
#ifdef DEBUG
//printf("get %p, which is %s\n",v, nanojit::lirNames[i->opcode()]);
#endif
return i; return i;
} }
void void
Tracker::set(const void* v, LIns* ins) 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); struct Tracker::Page* p = findPage(v);
if (!p) if (!p)
p = addPage(v); p = addPage(v);
p->map[(((long)v) & 0xfff) >> 2] = ins; 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 avmplus;
using namespace nanojit; using namespace nanojit;
@ -240,12 +214,4 @@ js_EndRecording(JSContext* cx, JSFrameRegs& regs)
compile(tm->fragmento->assm(), tm->fragment); compile(tm->fragmento->assm(), tm->fragment);
} }
tm->status = IDLE; 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)) { if (JSVAL_IS_OBJECT(v)) {
SideExit exit; SideExit exit;
L.insGuard(G(ok), L.insGuard(G(ok),
L.ins2(LIR_eq, get(&v), L.insImm(0)), L.ins_eq0(get(&v)),
snapshot(cx, regs, exit)); snapshot(cx, regs, exit));
} }
return ok; 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_eq,
L.ins2(LIR_and, L.ins2(LIR_and,
L.ins2(LIR_xor, L.ins2(LIR_xor,
L.ins2(LIR_lsh, get(&v), L.insImm(1)), L.ins2i(LIR_lsh, get(&v), 1),
get(&v)), get(&v)),
L.insImm(0x80000000)), L.insImm(0x80000000)),
L.insImm(0)), L.insImm(0)),

View File

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

View File

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

View File

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

View File

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

View File

@ -44,117 +44,42 @@ namespace nanojit
using namespace avmplus; using namespace avmplus;
#ifdef FEATURE_NANOJIT #ifdef FEATURE_NANOJIT
// @todo -- a lookup table would be better here const uint8_t operandCount[] = {
uint32_t FASTCALL operandCount(LOpcode op) /* 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,
switch(op) /* 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,
case LIR_trace: /* 40 */ /*callh*/1, 2, 2, 2, /*not*/1, 2, 2, 2, /*xt*/1, /*xf*/1,
case LIR_skip: /* 50 */ /*qlo*/1, /*qhi*/1, 2, 2, 2, 2, 2, 2, 2, 2,
case LIR_tramp: /* 60 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
case LIR_loop: /* 70 */ 2, 2, 2, /*farg*/1, 2, 2, 2, 2, 2, 2,
case LIR_x: /* 80 */ 2, 2, /*fcall*/0, 2, 2, 2, 2, 2, 2, 2,
case LIR_short: /* 90 */ 2, 2, 2, 2, 2, 2, 2, /*quad*/0, 2, 2,
case LIR_int: /* 100 */ /*fneg*/1, 2, 2, 2, 2, 2, /*i2f*/1, /*u2f*/1, 2, 2,
case LIR_quad: /* 110 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
case LIR_call: /* 120 */ 2, 2, 2, 2, 2, 2, 2, 2,
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;
}
}
// LIR verbose specific // LIR verbose specific
#ifdef NJ_VERBOSE #ifdef NJ_VERBOSE
void Lir::initEngine() const char* lirNames[] = {
{ /* 0-9 */ "0","1","trace","skip","tramp","5","6","7","8","arg",
debug_only( { LIns l; l.initOpcode(LIR_last); NanoAssert(l.opcode()>0); } ); /* 10-19 */ "param","st","ld","ref","sti","15","16","17","call","loop",
NanoAssert( LIR_last < (1<<8)-1 ); // only 8 bits or the opcode /* 20-29 */ "x","21","22","23","24","25","feq","flt","fgt","fle",
verbose_only( initVerboseStructures() ); /* 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 */ #endif /* NANOJIT_VEBROSE */
// implementation // implementation
@ -180,13 +105,13 @@ namespace nanojit
_unused = &_start->lir[0]; _unused = &_start->lir[0];
} }
//buffer_count++; //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() LirBuffer::~LirBuffer()
{ {
//buffer_count--; //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(); clear();
_frago = 0; _frago = 0;
} }
@ -305,7 +230,6 @@ namespace nanojit
LInsp LirBufWriter::ensureReferenceable(LInsp i, int32_t addedDistance) LInsp LirBufWriter::ensureReferenceable(LInsp i, int32_t addedDistance)
{ {
if (!i) return 0;
NanoAssert(!i->isop(LIR_tramp)); NanoAssert(!i->isop(LIR_tramp));
LInsp next = _buf->next(); LInsp next = _buf->next();
LInsp from = next + addedDistance; LInsp from = next + addedDistance;
@ -318,14 +242,14 @@ namespace nanojit
return tramp; return tramp;
} }
LInsp LirBufWriter::insStore(LInsp o1, LInsp o2, LInsp o3) LInsp LirBufWriter::insStore(LInsp val, LInsp base, LInsp off)
{ {
LOpcode op = LIR_st; LOpcode op = val->isQuad() ? LIR_stq : LIR_st;
NanoAssert(o1 && o2 && o3); NanoAssert(val && base && off);
ensureRoom(4); ensureRoom(4);
LInsp r1 = ensureReferenceable(o1,3); LInsp r1 = ensureReferenceable(val,3);
LInsp r2 = ensureReferenceable(o2,2); LInsp r2 = ensureReferenceable(base,2);
LInsp r3 = ensureReferenceable(o3,1); LInsp r3 = ensureReferenceable(off,1);
LInsp l = _buf->next(); LInsp l = _buf->next();
l->initOpcode(op); l->initOpcode(op);
@ -338,13 +262,13 @@ namespace nanojit
return l; 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; LOpcode op = val->isQuad() ? LIR_stqi : LIR_sti;
NanoAssert(o1 && o2 && isS8(d)); NanoAssert(val && base && isS8(d));
ensureRoom(3); ensureRoom(3);
LInsp r1 = ensureReferenceable(o1,2); LInsp r1 = ensureReferenceable(val,2);
LInsp r2 = ensureReferenceable(o2,1); LInsp r2 = ensureReferenceable(base,1);
LInsp l = _buf->next(); LInsp l = _buf->next();
l->initOpcode(op); l->initOpcode(op);
@ -359,7 +283,7 @@ namespace nanojit
LInsp LirBufWriter::ins0(LOpcode op) LInsp LirBufWriter::ins0(LOpcode op)
{ {
if (!ensureRoom(1)) return 0; ensureRoom(1);
LInsp l = _buf->next(); LInsp l = _buf->next();
l->initOpcode(op); l->initOpcode(op);
_buf->commit(1); _buf->commit(1);
@ -516,7 +440,7 @@ namespace nanojit
} }
bool FASTCALL isCmp(LOpcode c) { 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 { bool LIns::isCmp() const {
@ -535,7 +459,8 @@ namespace nanojit
bool LIns::isStore() const 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 bool LIns::isLoad() const
@ -560,7 +485,7 @@ namespace nanojit
bool FASTCALL isCse(LOpcode op) { bool FASTCALL isCse(LOpcode op) {
op = LOpcode(op & ~LIR64); 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 bool LIns::isCse(const CallInfo *functions) const
@ -717,11 +642,11 @@ namespace nanojit
if (oprnd1 == oprnd2) if (oprnd1 == oprnd2)
{ {
if (v == LIR_xor || v == LIR_sub || 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); return insImm(0);
if (v == LIR_or || v == LIR_and) if (v == LIR_or || v == LIR_and)
return oprnd1; 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 // x <= x == 1; x >= x == 1
return insImm(1); return insImm(1);
} }
@ -763,15 +688,15 @@ namespace nanojit
{ {
double c1 = oprnd1->constvalf(); double c1 = oprnd1->constvalf();
double c2 = oprnd1->constvalf(); double c2 = oprnd1->constvalf();
if (v == LIR_eq) if (v == LIR_feq)
return insImm(c1 == c2); return insImm(c1 == c2);
if (v == LIR_lt) if (v == LIR_flt)
return insImm(c1 < c2); return insImm(c1 < c2);
if (v == LIR_gt) if (v == LIR_fgt)
return insImm(c1 > c2); return insImm(c1 > c2);
if (v == LIR_le) if (v == LIR_fle)
return insImm(c1 <= c2); return insImm(c1 <= c2);
if (v == LIR_ge) if (v == LIR_fge)
return insImm(c1 >= c2); return insImm(c1 >= c2);
} }
else if (oprnd1->isconst() && !oprnd2->isconst()) else if (oprnd1->isconst() && !oprnd2->isconst())
@ -785,7 +710,7 @@ namespace nanojit
oprnd2 = oprnd1; oprnd2 = oprnd1;
oprnd1 = t; 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 // move const to rhs, swap the operator
LIns *t = oprnd2; LIns *t = oprnd2;
oprnd2 = oprnd1; oprnd2 = oprnd1;
@ -948,7 +873,7 @@ namespace nanojit
int32_t argc = ci.count_args(); int32_t argc = ci.count_args();
const uint32_t ret = argt & 3; const uint32_t ret = argt & 3;
LOpcode op = k_callmap[ret]; 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 #ifdef NJ_SOFTFLOAT
if (op == LIR_fcall) if (op == LIR_fcall)
@ -984,144 +909,10 @@ namespace nanojit
return insImm8(op==LIR_callh ? LIR_call : op, fid, argc); 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; using namespace avmplus;
StoreFilter::StoreFilter(LirFilter *in, GC *gc, Assembler *assm, LInsp p0, LInsp sp, LInsp rp) StoreFilter::StoreFilter(LirFilter *in, GC *gc, LInsp p0, LInsp sp, LInsp rp)
: LirFilter(in), gc(gc), assm(assm), param0(p0), sp(sp), rp(rp), stop(0), rtop(0) : LirFilter(in), gc(gc), param0(p0), sp(sp), rp(rp), stop(0), rtop(0)
{} {}
LInsp StoreFilter::read() LInsp StoreFilter::read()
@ -1276,7 +1067,7 @@ namespace nanojit
return hashcall(i->imm8(), argc, args); return hashcall(i->imm8(), argc, args);
} }
default: default:
if (operandCount(op) == 2) if (operandCount[op] == 2)
return hash2(op, i->oprnd1(), i->oprnd2()); return hash2(op, i->oprnd1(), i->oprnd2());
else else
return hash1(op, i->oprnd1()); return hash1(op, i->oprnd1());
@ -1317,7 +1108,7 @@ namespace nanojit
} }
default: default:
{ {
const uint32_t count = operandCount(op); const uint32_t count = operandCount[op];
if ((count >= 1 && a->oprnd1() != b->oprnd1()) || if ((count >= 1 && a->oprnd1() != b->oprnd1()) ||
(count >= 2 && a->oprnd2() != b->oprnd2())) (count >= 2 && a->oprnd2() != b->oprnd2()))
return false; return false;
@ -1371,6 +1162,17 @@ namespace nanojit
return name; 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) { uint32_t LInsHashSet::hashimm(int32_t a) {
return _hashfinish(_hash32(0,a)); return _hashfinish(_hash32(0,a));
} }
@ -1549,7 +1351,7 @@ namespace nanojit
uint32_t exits = 0; uint32_t exits = 0;
LirBuffer *lirbuf = frag->lirbuf; LirBuffer *lirbuf = frag->lirbuf;
LirReader br(lirbuf); LirReader br(lirbuf);
StoreFilter r(&br, gc, 0, frag->param0, sp, rp); StoreFilter r(&br, gc, frag->param0, sp, rp);
bool skipargs = false; bool skipargs = false;
int total = 0; int total = 0;
live.add(frag->param0, r.pos()); live.add(frag->param0, r.pos());
@ -1586,10 +1388,10 @@ namespace nanojit
live.add(i->oprnd2()->oprnd1(),i); live.add(i->oprnd2()->oprnd1(),i);
live.add(i->oprnd2()->oprnd2(),i); live.add(i->oprnd2()->oprnd2(),i);
} }
else if (operandCount(i->opcode()) == 1) { else if (operandCount[i->opcode()] == 1) {
live.add(i->oprnd1(),i); 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->oprnd1(),i);
live.add(i->oprnd2(),i); live.add(i->oprnd2(),i);
} }
@ -1624,8 +1426,10 @@ namespace nanojit
} }
void LirNameMap::addName(LInsp i, Stringp name) { void LirNameMap::addName(LInsp i, Stringp name) {
Entry *e = new (labels->core->gc) Entry(name); if (!names.containsKey(i)) {
names.put(i, e); Entry *e = new (labels->core->gc) Entry(name);
names.put(i, e);
}
} }
void LirNameMap::addName(LInsp i, const char *name) { void LirNameMap::addName(LInsp i, const char *name) {
addName(i, labels->core->newString(name)); addName(i, labels->core->newString(name));
@ -1666,7 +1470,7 @@ namespace nanojit
if (ref->isCall()) { if (ref->isCall()) {
copyName(ref, _functions[ref->imm8()]._name, funccounts.add(ref->imm8())); copyName(ref, _functions[ref->imm8()]._name, funccounts.add(ref->imm8()));
} else { } 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); StringNullTerminatedUTF8 cname(gc, names.get(ref)->name);
strcat(buf, cname.c_str()); strcat(buf, cname.c_str());
@ -1683,7 +1487,8 @@ namespace nanojit
s += strlen(s); s += strlen(s);
} }
switch(i->opcode()) LOpcode op = i->opcode();
switch(op)
{ {
case LIR_short: case LIR_short:
case LIR_int: case LIR_int:
@ -1701,7 +1506,7 @@ namespace nanojit
case LIR_loop: case LIR_loop:
case LIR_trace: case LIR_trace:
sprintf(s, "%s", nameof(i)); sprintf(s, "%s", lirNames[op]);
break; break;
case LIR_fcall: case LIR_fcall:
@ -1718,13 +1523,14 @@ namespace nanojit
} }
case LIR_param: case LIR_param:
sprintf(s, "%s %s", nameof(i), gpn(i->imm8())); sprintf(s, "%s %s", lirNames[op], gpn(i->imm8()));
break; break;
case LIR_x: { case LIR_x: {
SideExit *x = (SideExit*) i->oprnd2()->payload(); SideExit *x = (SideExit*) i->oprnd2()->payload();
uint32_t ip = uint32_t(x->from->frid) + x->ip_adj; 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), labels->format((void*)ip),
x->sp_adj, x->rp_adj, x->f_adj); x->sp_adj, x->rp_adj, x->f_adj);
break; break;
@ -1740,14 +1546,15 @@ namespace nanojit
case LIR_qlo: case LIR_qlo:
case LIR_qhi: case LIR_qhi:
case LIR_ref: case LIR_ref:
sprintf(s, "%s %s", nameof(i), formatRef(i->oprnd1())); sprintf(s, "%s %s", lirNames[op], formatRef(i->oprnd1()));
break; break;
case LIR_xt: case LIR_xt:
case LIR_xf: { case LIR_xf: {
SideExit *x = (SideExit*) i->oprnd2()->payload(); SideExit *x = (SideExit*) i->oprnd2()->payload();
uint32_t ip = int32_t(x->from->frid) + x->ip_adj; 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()), formatRef(i->oprnd1()),
labels->format((void*)ip), labels->format((void*)ip),
x->sp_adj, x->rp_adj, x->f_adj); x->sp_adj, x->rp_adj, x->f_adj);
@ -1776,8 +1583,13 @@ namespace nanojit
case LIR_ule: case LIR_ule:
case LIR_ugt: case LIR_ugt:
case LIR_uge: case LIR_uge:
case LIR_feq:
case LIR_flt:
case LIR_fle:
case LIR_fgt:
case LIR_fge:
case LIR_qjoin: case LIR_qjoin:
sprintf(s, "%s %s, %s", nameof(i), sprintf(s, "%s %s, %s", lirNames[op],
formatRef(i->oprnd1()), formatRef(i->oprnd1()),
formatRef(i->oprnd2())); formatRef(i->oprnd2()));
break; break;
@ -1793,13 +1605,15 @@ namespace nanojit
case LIR_ldc: case LIR_ldc:
case LIR_ldq: case LIR_ldq:
case LIR_ldcb: case LIR_ldcb:
sprintf(s, "%s %s[%s]", nameof(i), sprintf(s, "%s %s[%s]", lirNames[op],
formatRef(i->oprnd1()), formatRef(i->oprnd1()),
formatRef(i->oprnd2())); formatRef(i->oprnd2()));
break; break;
case LIR_st: case LIR_st:
case LIR_sti: case LIR_sti:
case LIR_stq:
case LIR_stqi:
sprintf(s, "%s[%d] = %s", sprintf(s, "%s[%d] = %s",
formatRef(i->oprnd2()), formatRef(i->oprnd2()),
i->immdisp(), i->immdisp(),
@ -1840,7 +1654,7 @@ namespace nanojit
LIns* CseFilter::ins1(LOpcode v, LInsp a) LIns* CseFilter::ins1(LOpcode v, LInsp a)
{ {
if (isCse(v)) { if (isCse(v)) {
NanoAssert(operandCount(v)==1); NanoAssert(operandCount[v]==1);
uint32_t k; uint32_t k;
LInsp found = exprs.find1(v, a, k); LInsp found = exprs.find1(v, a, k);
if (found) if (found)
@ -1853,7 +1667,7 @@ namespace nanojit
LIns* CseFilter::ins2(LOpcode v, LInsp a, LInsp b) LIns* CseFilter::ins2(LOpcode v, LInsp a, LInsp b)
{ {
if (isCse(v)) { if (isCse(v)) {
NanoAssert(operandCount(v)==2); NanoAssert(operandCount[v]==2);
uint32_t k; uint32_t k;
LInsp found = exprs.find2(v, a, b, k); LInsp found = exprs.find2(v, a, b, k);
if (found) if (found)
@ -1866,7 +1680,7 @@ namespace nanojit
LIns* CseFilter::insLoad(LOpcode v, LInsp base, LInsp disp) LIns* CseFilter::insLoad(LOpcode v, LInsp base, LInsp disp)
{ {
if (isCse(v)) { if (isCse(v)) {
NanoAssert(operandCount(v)==2); NanoAssert(operandCount[v]==2);
uint32_t k; uint32_t k;
LInsp found = exprs.find2(v, base, disp, k); LInsp found = exprs.find2(v, base, disp, k);
if (found) if (found)
@ -1880,7 +1694,7 @@ namespace nanojit
{ {
if (isCse(v)) { if (isCse(v)) {
// conditional guard // conditional guard
NanoAssert(operandCount(v)==1); NanoAssert(operandCount[v]==1);
uint32_t k; uint32_t k;
LInsp found = exprs.find1(v, c, k); LInsp found = exprs.find1(v, c, k);
if (found) if (found)
@ -1903,6 +1717,20 @@ namespace nanojit
return out->insCall(fid, args); 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) LIns* FASTCALL callArgN(LIns* i, uint32_t n)
{ {
// @todo clean up; shouldn't have to create a reader // @todo clean up; shouldn't have to create a reader
@ -1915,7 +1743,8 @@ namespace nanojit
void compile(Assembler* assm, Fragment* triggerFrag) 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; GC *gc = core->gc;
verbose_only( StringList asmOutput(gc); ) verbose_only( StringList asmOutput(gc); )
@ -1927,18 +1756,19 @@ namespace nanojit
bool treeCompile = core->config.tree_opt && (triggerFrag->kind == BranchTrace); bool treeCompile = core->config.tree_opt && (triggerFrag->kind == BranchTrace);
RegAllocMap regMap(gc); RegAllocMap regMap(gc);
NInsList loopJumps(gc); NInsList loopJumps(gc);
assm->beginAssembly(triggerFrag, &regMap); assm->beginAssembly(&regMap);
//fprintf(stderr, "recompile trigger %X kind %d\n", (int)triggerFrag, triggerFrag->kind); //fprintf(stderr, "recompile trigger %X kind %d\n", (int)triggerFrag, triggerFrag->kind);
Fragment* root = triggerFrag; Fragment* root = triggerFrag;
if (treeCompile) if (treeCompile)
{ {
// recompile the entire tree // recompile the entire tree
root = triggerFrag->anchor; root = triggerFrag->root;
root->removeIntraLinks(); root->removeIntraLinks();
root->unlink(assm); // unlink all incoming jumps ; since the compile() can fail 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->unlinkBranches(assm); // no one jumps into a branch (except from within the tree) so safe to clear the links table
root->fragEntry = 0; root->fragEntry = 0;
root->releaseCode(frago);
// do the tree branches // do the tree branches
Fragment* frag = root->treeBranches; Fragment* frag = root->treeBranches;
@ -1947,15 +1777,17 @@ namespace nanojit
// compile til no more frags // compile til no more frags
if (frag->lastIns) if (frag->lastIns)
{ {
NIns* loopJump = assm->assemble(frag); assm->assemble(frag, loopJumps);
verbose_only(if (assm->_verbose) assm->outputf("compiling branch %X that exits from SID %d",frag->frid,frag->spawnedFrom->sid);) verbose_only(if (assm->_verbose)
if (loopJump) loopJumps.add((intptr_t)loopJump); assm->outputf("compiling branch %s ip %s",
frago->labels->format(frag),
frago->labels->format(frag->frid)); )
NanoAssert(frag->kind == BranchTrace); NanoAssert(frag->kind == BranchTrace);
RegAlloc* regs = new (gc) RegAlloc(); RegAlloc* regs = new (gc) RegAlloc();
assm->copyRegisters(regs); assm->copyRegisters(regs);
assm->releaseRegisters(); assm->releaseRegisters();
SideExit* exit = frag->spawnedFrom; SideExit* exit = frag->spawnedFrom->exit();
regMap.put(exit, regs); regMap.put(exit, regs);
} }
frag = frag->treeBranches; frag = frag->treeBranches;
@ -1963,15 +1795,11 @@ namespace nanojit
} }
// now the the main trunk // now the the main trunk
assm->assemble(root, loopJumps);
NIns* loopJump = assm->assemble(root); verbose_only(if (assm->_verbose)
verbose_only(if (assm->_verbose) assm->output("compiling trunk");) assm->outputf("compiling trunk %s",
if (loopJump) loopJumps.add((intptr_t)loopJump); frago->labels->format(root));)
assm->endAssembly(root, loopJumps); 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 // reverse output so that assembly is displayed low-to-high
verbose_only( assm->_outputCache = 0; ) verbose_only( assm->_outputCache = 0; )

View File

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

View File

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

View File

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

View File

@ -127,8 +127,11 @@ namespace nanojit
} }
#ifdef NJ_VERBOSE #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++) for(int i=0; i<NJ_MAX_REGISTERS; i++)
{ {
LIns* ins = regs.active[i]; LIns* ins = regs.active[i];

View File

@ -71,7 +71,7 @@ namespace nanojit
RegisterMask free; RegisterMask free;
RegisterMask used; 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() DECLARE_PLATFORM_REGALLOC()
}; };

View File

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