mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
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:
parent
d8e0d5edec
commit
4678be95aa
@ -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);
|
||||
|
@ -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));*/
|
||||
}
|
||||
|
@ -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)),
|
||||
|
@ -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; )
|
||||
|
@ -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:
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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, ®Map);
|
||||
assm->beginAssembly(®Map);
|
||||
|
||||
//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; )
|
||||
|
@ -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__
|
||||
|
@ -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")
|
||||
|
@ -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
|
||||
|
@ -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];
|
||||
|
@ -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()
|
||||
};
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user