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;
|
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);
|
||||||
|
@ -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));*/
|
|
||||||
}
|
}
|
||||||
|
@ -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)),
|
||||||
|
@ -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; )
|
||||||
|
@ -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:
|
||||||
|
@ -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) {
|
||||||
|
@ -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
|
||||||
|
@ -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, ®Map);
|
assm->beginAssembly(®Map);
|
||||||
|
|
||||||
//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; )
|
||||||
|
@ -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__
|
||||||
|
@ -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")
|
||||||
|
@ -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
|
||||||
|
@ -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];
|
||||||
|
@ -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()
|
||||||
};
|
};
|
||||||
|
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user