mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Synced nanojit with TT tip.
This commit is contained in:
parent
ef9a5dc216
commit
5dca2ad552
@ -408,13 +408,13 @@ public:
|
||||
(uncasted) value. Each guard generates the side exit map based on the types of the
|
||||
last stores to every stack location, so its safe to not perform them on-trace. */
|
||||
virtual LInsp insStore(LIns* value, LIns* base, LIns* disp) {
|
||||
if (base == _fragment->sp && isPromoteInt(value))
|
||||
if (base == _fragment->lirbuf->sp && isPromoteInt(value))
|
||||
value = demote(out, value);
|
||||
return out->insStore(value, base, disp);
|
||||
}
|
||||
|
||||
virtual LInsp insStorei(LIns* value, LIns* base, int32_t d) {
|
||||
if (base == _fragment->sp && isPromoteInt(value))
|
||||
if (base == _fragment->lirbuf->sp && isPromoteInt(value))
|
||||
value = demote(out, value);
|
||||
return out->insStorei(value, base, d);
|
||||
}
|
||||
@ -491,15 +491,15 @@ TraceRecorder::TraceRecorder(JSContext* cx, Fragmento* fragmento, Fragment* _fra
|
||||
}
|
||||
fragment->vmprivate = fragmentInfo;
|
||||
|
||||
fragment->state = lir->insImm8(LIR_param, Assembler::argRegs[0], 0);
|
||||
fragment->param1 = lir->insImm8(LIR_param, Assembler::argRegs[1], 0);
|
||||
fragment->sp = lir->insLoadi(fragment->state, offsetof(InterpState, sp));
|
||||
fragment->rp = lir->insLoadi(fragment->state, offsetof(InterpState, rp));
|
||||
cx_ins = lir->insLoadi(fragment->state, offsetof(InterpState, cx));
|
||||
fragment->lirbuf->state = lir->insParam(0);
|
||||
fragment->lirbuf->param1 = lir->insParam(1);
|
||||
fragment->lirbuf->sp = lir->insLoadi(fragment->lirbuf->state, offsetof(InterpState, sp));
|
||||
fragment->lirbuf->rp = lir->insLoadi(fragment->lirbuf->state, offsetof(InterpState, rp));
|
||||
cx_ins = lir->insLoadi(fragment->lirbuf->state, offsetof(InterpState, cx));
|
||||
#ifdef DEBUG
|
||||
lirbuf->names->addName(fragment->state, "state");
|
||||
lirbuf->names->addName(fragment->sp, "sp");
|
||||
lirbuf->names->addName(fragment->rp, "rp");
|
||||
lirbuf->names->addName(fragment->lirbuf->state, "state");
|
||||
lirbuf->names->addName(fragment->lirbuf->sp, "sp");
|
||||
lirbuf->names->addName(fragment->lirbuf->rp, "rp");
|
||||
lirbuf->names->addName(cx_ins, "cx");
|
||||
#endif
|
||||
|
||||
@ -854,10 +854,10 @@ TraceRecorder::import(jsval* p, uint8& t, const char *prefix, int index)
|
||||
read and promote it to double since all arithmetic operations expect
|
||||
to see doubles on entry. The first op to use this slot will emit a
|
||||
f2i cast which will cancel out the i2f we insert here. */
|
||||
ins = lir->ins1(LIR_i2f, lir->insLoadi(fragment->sp, offset));
|
||||
ins = lir->ins1(LIR_i2f, lir->insLoadi(fragment->lirbuf->sp, offset));
|
||||
} else {
|
||||
JS_ASSERT(isNumber(*p) == (TYPEMAP_GET_TYPE(t) == JSVAL_DOUBLE));
|
||||
ins = lir->insLoad(t == JSVAL_DOUBLE ? LIR_ldq : LIR_ld, fragment->sp, offset);
|
||||
ins = lir->insLoad(t == JSVAL_DOUBLE ? LIR_ldq : LIR_ld, fragment->lirbuf->sp, offset);
|
||||
}
|
||||
tracker.set(p, ins);
|
||||
#ifdef DEBUG
|
||||
@ -879,7 +879,7 @@ TraceRecorder::set(jsval* p, LIns* i)
|
||||
{
|
||||
tracker.set(p, i);
|
||||
if (onFrame(p))
|
||||
lir->insStorei(i, fragment->sp, -fragmentInfo->nativeStackBase + nativeFrameOffset(p) + 8);
|
||||
lir->insStorei(i, fragment->lirbuf->sp, -fragmentInfo->nativeStackBase + nativeFrameOffset(p) + 8);
|
||||
}
|
||||
|
||||
LIns*
|
||||
@ -1032,9 +1032,9 @@ TraceRecorder::stop()
|
||||
int
|
||||
nanojit::StackFilter::getTop(LInsp guard)
|
||||
{
|
||||
if (sp == frag->sp)
|
||||
if (sp == frag->lirbuf->sp)
|
||||
return guard->exit()->sp_adj + 8;
|
||||
JS_ASSERT(sp == frag->rp);
|
||||
JS_ASSERT(sp == frag->lirbuf->rp);
|
||||
return guard->exit()->rp_adj + 4;
|
||||
}
|
||||
|
||||
|
@ -60,14 +60,9 @@ namespace nanojit
|
||||
for (;;) {
|
||||
LInsp i = in->read();
|
||||
if (!i || i->isGuard()
|
||||
|| i->isCall() && !assm->_functions[i->imm8()]._cse
|
||||
|| i->isCall() && !assm->_functions[i->fid()]._cse
|
||||
|| !assm->ignoreInstruction(i))
|
||||
return i;
|
||||
if (i->isCall()) {
|
||||
// skip args
|
||||
while (in->pos()->isArg())
|
||||
in->read();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -103,7 +98,7 @@ namespace nanojit
|
||||
if (i->oprnd1())
|
||||
block.add(i->oprnd1());
|
||||
}
|
||||
else if (!i->isArg()) {
|
||||
else {
|
||||
block.add(i);
|
||||
}
|
||||
return i;
|
||||
@ -215,7 +210,7 @@ namespace nanojit
|
||||
|
||||
if (i->isconst() || i->isconstq())
|
||||
r->cost = 0;
|
||||
else if (i == _thisfrag->sp || i == _thisfrag->rp)
|
||||
else if (i == _thisfrag->lirbuf->sp || i == _thisfrag->lirbuf->rp)
|
||||
r->cost = 2;
|
||||
else
|
||||
r->cost = 1;
|
||||
@ -314,7 +309,7 @@ namespace nanojit
|
||||
}
|
||||
#endif
|
||||
|
||||
const CallInfo* Assembler::callInfoFor(int32_t fid)
|
||||
const CallInfo* Assembler::callInfoFor(uint32_t fid)
|
||||
{
|
||||
NanoAssert(fid < CI_Max);
|
||||
return &_functions[fid];
|
||||
@ -625,7 +620,7 @@ namespace nanojit
|
||||
|
||||
// if/when we patch this exit to jump over to another fragment,
|
||||
// that fragment will need its parameters set up just like ours.
|
||||
LInsp stateins = _thisfrag->state;
|
||||
LInsp stateins = _thisfrag->lirbuf->state;
|
||||
Register state = findSpecificRegFor(stateins, Register(stateins->imm8()));
|
||||
asm_bailout(guard, state);
|
||||
|
||||
@ -660,7 +655,7 @@ namespace nanojit
|
||||
bool Assembler::ignoreInstruction(LInsp ins)
|
||||
{
|
||||
LOpcode op = ins->opcode();
|
||||
if (ins->isStore() || op == LIR_loop || ins->isArg())
|
||||
if (ins->isStore() || op == LIR_loop)
|
||||
return false;
|
||||
return getresv(ins) == 0;
|
||||
}
|
||||
@ -706,8 +701,8 @@ namespace nanojit
|
||||
|
||||
// set up backwards pipeline: assembler -> StackFilter -> LirReader
|
||||
LirReader bufreader(frag->lastIns);
|
||||
StackFilter storefilter1(&bufreader, gc, frag, frag->sp);
|
||||
StackFilter storefilter2(&storefilter1, gc, frag, frag->rp);
|
||||
StackFilter storefilter1(&bufreader, gc, frag, frag->lirbuf->sp);
|
||||
StackFilter storefilter2(&storefilter1, gc, frag, frag->lirbuf->rp);
|
||||
DeadCodeFilter deadfilter(&storefilter2, this);
|
||||
LirFilter* rdr = &deadfilter;
|
||||
verbose_only(
|
||||
@ -831,11 +826,6 @@ namespace nanojit
|
||||
|
||||
void Assembler::gen(LirFilter* reader, NInsList& loopJumps)
|
||||
{
|
||||
_call = NULL;
|
||||
_iargs = 0;
|
||||
_fargs = 0;
|
||||
_stackUsed = 0;
|
||||
|
||||
// trace must start with LIR_x or LIR_loop
|
||||
NanoAssert(reader->pos()->isop(LIR_x) || reader->pos()->isop(LIR_loop));
|
||||
|
||||
@ -1243,7 +1233,7 @@ namespace nanojit
|
||||
#endif
|
||||
|
||||
// restore first parameter, the only one we use
|
||||
LInsp state = _thisfrag->state;
|
||||
LInsp state = _thisfrag->lirbuf->state;
|
||||
Register a0 = Register(state->imm8());
|
||||
findSpecificRegFor(state, a0);
|
||||
break;
|
||||
@ -1305,66 +1295,12 @@ namespace nanojit
|
||||
asm_cmp(ins);
|
||||
break;
|
||||
}
|
||||
case LIR_ref:
|
||||
{
|
||||
// ref arg - use lea
|
||||
LIns *p = ins->oprnd1();
|
||||
if (ins->resv())
|
||||
{
|
||||
// arg in specific reg
|
||||
Register r = imm2register(ins->resv());
|
||||
int da = findMemFor(p);
|
||||
LEA(r, da, FP);
|
||||
}
|
||||
else
|
||||
{
|
||||
NanoAssert(0); // not supported
|
||||
}
|
||||
++_iargs;
|
||||
nArgEmitted(_call, 0, _iargs, _fargs);
|
||||
break;
|
||||
}
|
||||
case LIR_arg:
|
||||
{
|
||||
LIns* p = ins->oprnd1();
|
||||
if (ins->resv())
|
||||
{
|
||||
// arg goes in specific register
|
||||
Register r = imm2register(ins->resv());
|
||||
if (p->isconst())
|
||||
LDi(r, p->constval());
|
||||
else
|
||||
findSpecificRegFor(p, r);
|
||||
}
|
||||
else
|
||||
{
|
||||
asm_pusharg(p);
|
||||
_stackUsed += 1;
|
||||
}
|
||||
++_iargs;
|
||||
nArgEmitted(_call, _stackUsed, _iargs, _fargs);
|
||||
break;
|
||||
}
|
||||
#if defined NANOJIT_IA32 || defined NANOJIT_AMD64
|
||||
case LIR_farg:
|
||||
{
|
||||
asm_farg(ins);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef NJ_SOFTFLOAT
|
||||
case LIR_fcall:
|
||||
#endif
|
||||
case LIR_call:
|
||||
{
|
||||
const FunctionID fid = (FunctionID) ins->imm8();
|
||||
// bogus assertion: zero is a legal value right now, with fmod() in that slot
|
||||
// NanoAssertMsg(fid!=0, "Function does not exist in the call table");
|
||||
_call = &_functions[ fid ];
|
||||
_iargs = 0;
|
||||
_fargs = 0;
|
||||
|
||||
Register rr = UnknownReg;
|
||||
#ifndef NJ_SOFTFLOAT
|
||||
if (op == LIR_fcall)
|
||||
@ -1383,47 +1319,7 @@ namespace nanojit
|
||||
// force the call result to be spilled unnecessarily.
|
||||
restoreCallerSaved();
|
||||
|
||||
nPostCallCleanup(_call);
|
||||
#ifdef NJ_VERBOSE
|
||||
CALL(_call->_address, _call->_name);
|
||||
#else
|
||||
CALL(_call->_address, "");
|
||||
#endif
|
||||
|
||||
_stackUsed = 0;
|
||||
LirReader argReader(reader->pos());
|
||||
|
||||
#ifdef NANOJIT_ARM
|
||||
// pre-assign registers R0-R3 for arguments (if they fit)
|
||||
int regsUsed = 0;
|
||||
for (LInsp a = argReader.read(); a->isArg(); a = argReader.read())
|
||||
{
|
||||
if (a->isop(LIR_arg) || a->isop(LIR_ref))
|
||||
{
|
||||
a->setresv((int)R0 + 1 + regsUsed);
|
||||
regsUsed++;
|
||||
}
|
||||
if (regsUsed>=4)
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#ifdef NANOJIT_IA32
|
||||
debug_only( if (rr == FST0) fpu_push(); )
|
||||
// make sure fpu stack is empty before call (restoreCallerSaved)
|
||||
NanoAssert(_allocator.isFree(FST0));
|
||||
// note: this code requires that LIR_ref arguments be one of the first two arguments
|
||||
// pre-assign registers to the first 2 4B args
|
||||
const uint32_t iargs = _call->count_iargs();
|
||||
const int max_regs = (iargs < 2) ? iargs : 2;
|
||||
int n = 0;
|
||||
for(LIns* a = argReader.read(); a->isArg() && n<max_regs; a = argReader.read())
|
||||
{
|
||||
if (a->isop(LIR_arg)||a->isop(LIR_ref))
|
||||
{
|
||||
a->setresv(argRegs[n++]); // tell LIR_arg what reg to use
|
||||
}
|
||||
}
|
||||
#endif
|
||||
asm_call(ins);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1433,6 +1329,43 @@ namespace nanojit
|
||||
}
|
||||
}
|
||||
|
||||
void Assembler::asm_arg(ArgSize sz, LInsp p, Register r)
|
||||
{
|
||||
if (sz == ARGSIZE_Q)
|
||||
{
|
||||
// ref arg - use lea
|
||||
if (r != UnknownReg)
|
||||
{
|
||||
// arg in specific reg
|
||||
int da = findMemFor(p);
|
||||
LEA(r, da, FP);
|
||||
}
|
||||
else
|
||||
{
|
||||
NanoAssert(0); // not supported
|
||||
}
|
||||
}
|
||||
else if (sz == ARGSIZE_LO)
|
||||
{
|
||||
if (r != UnknownReg)
|
||||
{
|
||||
// arg goes in specific register
|
||||
if (p->isconst())
|
||||
LDi(r, p->constval());
|
||||
else
|
||||
findSpecificRegFor(p, r);
|
||||
}
|
||||
else
|
||||
{
|
||||
asm_pusharg(p);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
asm_farg(p);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t Assembler::arFree(uint32_t idx)
|
||||
{
|
||||
if (idx > 0 && _activation.entry[idx] == _activation.entry[idx+stack_direction(1)])
|
||||
@ -1491,7 +1424,7 @@ namespace nanojit
|
||||
|
||||
uint32_t Assembler::arReserve(LIns* l)
|
||||
{
|
||||
NanoAssert(!l->isop(LIR_tramp));
|
||||
NanoAssert(!l->isTramp());
|
||||
|
||||
//verbose_only(printActivationState());
|
||||
const bool quad = l->isQuad();
|
||||
@ -1692,6 +1625,26 @@ namespace nanojit
|
||||
}
|
||||
return argc;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint32_t CallInfo::get_sizes(ArgSize* sizes) const
|
||||
{
|
||||
uint32_t argt = _argtypes;
|
||||
uint32_t argc = 0;
|
||||
for (int32_t i = 0; i < 5; i++) {
|
||||
argt >>= 2;
|
||||
ArgSize a = ArgSize(argt&3);
|
||||
#ifdef NJ_SOFTFLOAT
|
||||
if (a == ARGSIZE_F) {
|
||||
sizes[argc++] = ARGSIZE_LO;
|
||||
sizes[argc++] = ARGSIZE_LO;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
if (a != ARGSIZE_NONE) {
|
||||
sizes[argc++] = a;
|
||||
}
|
||||
}
|
||||
return argc;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -84,12 +84,14 @@ namespace nanojit
|
||||
LIns* parameter[ NJ_MAX_PARAMETERS ]; /* incoming parameters */
|
||||
};
|
||||
|
||||
const uint32_t ARGSIZE_NONE = 0;
|
||||
const uint32_t ARGSIZE_F = 1;
|
||||
const uint32_t ARGSIZE_LO = 2;
|
||||
const uint32_t ARGSIZE_Q = 3;
|
||||
const uint32_t _ARGSIZE_MASK_INT = 2;
|
||||
const uint32_t _ARGSIZE_MASK_ANY = 3;
|
||||
enum ArgSize {
|
||||
ARGSIZE_NONE = 0,
|
||||
ARGSIZE_F = 1,
|
||||
ARGSIZE_LO = 2,
|
||||
ARGSIZE_Q = 3,
|
||||
_ARGSIZE_MASK_INT = 2,
|
||||
_ARGSIZE_MASK_ANY = 3
|
||||
};
|
||||
|
||||
struct CallInfo
|
||||
{
|
||||
@ -100,6 +102,7 @@ namespace nanojit
|
||||
verbose_only ( const char* _name; )
|
||||
|
||||
uint32_t FASTCALL _count_args(uint32_t mask) const;
|
||||
uint32_t get_sizes(ArgSize*) const;
|
||||
|
||||
inline uint32_t FASTCALL count_args() const { return _count_args(_ARGSIZE_MASK_ANY); }
|
||||
inline uint32_t FASTCALL count_iargs() const { return _count_args(_ARGSIZE_MASK_INT); }
|
||||
@ -214,10 +217,10 @@ namespace nanojit
|
||||
|
||||
Stats _stats;
|
||||
|
||||
const CallInfo* callInfoFor(int32_t fid);
|
||||
const CallInfo* callInfoFor(uint32_t fid);
|
||||
const CallInfo* callInfoFor(LInsp call)
|
||||
{
|
||||
return callInfoFor(call->imm8());
|
||||
return callInfoFor(call->fid());
|
||||
}
|
||||
|
||||
private:
|
||||
@ -265,11 +268,6 @@ namespace nanojit
|
||||
DWB(Fragment*) _thisfrag;
|
||||
RegAllocMap* _branchStateMap;
|
||||
GuardRecord* _latestGuard;
|
||||
|
||||
const CallInfo *_call;
|
||||
uint32_t _iargs;
|
||||
uint32_t _fargs;
|
||||
int32_t _stackUsed;
|
||||
|
||||
const CallInfo *_functions;
|
||||
|
||||
@ -305,13 +303,14 @@ namespace nanojit
|
||||
void asm_quad(LInsp i);
|
||||
bool asm_qlo(LInsp ins, LInsp q);
|
||||
void asm_fneg(LInsp ins);
|
||||
void asm_farg(LInsp ins);
|
||||
void asm_fop(LInsp ins);
|
||||
void asm_i2f(LInsp ins);
|
||||
void asm_u2f(LInsp ins);
|
||||
Register asm_prep_fcall(Reservation *rR, LInsp ins);
|
||||
void asm_nongp_copy(Register r, Register s);
|
||||
void asm_bailout(LInsp guard, Register state);
|
||||
void asm_call(LInsp);
|
||||
void asm_arg(ArgSize, LInsp, Register);
|
||||
|
||||
// platform specific implementation (see NativeXXX.cpp file)
|
||||
void nInit(uint32_t flags);
|
||||
@ -319,8 +318,6 @@ namespace nanojit
|
||||
Register nRegisterAllocFromSet(int32_t set);
|
||||
void nRegisterResetAll(RegAlloc& a);
|
||||
void nMarkExecute(Page* page, int32_t count=1, bool enable=true);
|
||||
void nPostCallCleanup(const CallInfo* call);
|
||||
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);
|
||||
void nFragExit(LIns* guard);
|
||||
|
@ -139,23 +139,8 @@ namespace nanojit
|
||||
#endif
|
||||
NanoAssert((int*)memory == pageTop(memory));
|
||||
//fprintf(stderr,"head alloc of %d at %x of %d pages using nj page size of %d\n", gcpages, (intptr_t)memory, (intptr_t)_gcHeap->kNativePageSize, NJ_PAGE_SIZE);
|
||||
|
||||
// can't add memory if its not addressable from all locations
|
||||
for(uint32_t i=0; i<_allocList.size(); i++)
|
||||
{
|
||||
Page* a = _allocList.get(i);
|
||||
int32_t delta = (a < memory) ? (intptr_t)memory+(NJ_PAGE_SIZE*(count+1))-(intptr_t)a : (intptr_t)a+(NJ_PAGE_SIZE*(count+1))-(intptr_t)memory;
|
||||
if ( delta > 16777215 )
|
||||
{
|
||||
// can't use this memory
|
||||
#ifdef MEMORY_INFO
|
||||
ChangeSizeExplicit("NanoJitMem", -1, _gcHeap->Size(memory));
|
||||
#endif
|
||||
_gcHeap->Free(memory);
|
||||
return;
|
||||
}
|
||||
}
|
||||
_allocList.add(memory);
|
||||
|
||||
_allocList.add(memory);
|
||||
|
||||
Page* page = memory;
|
||||
_pageList = page;
|
||||
@ -395,13 +380,15 @@ namespace nanojit
|
||||
Fragment *f = _frags->at(i);
|
||||
fragstats stat = { 0,0,0,0,0 };
|
||||
dumpFragStats(f, 0, stat);
|
||||
if (stat.lir) {
|
||||
totalstat.lir += stat.lir;
|
||||
totalstat.lirbytes += stat.lirbytes;
|
||||
}
|
||||
uint64_t bothDur = stat.traceDur + stat.interpDur;
|
||||
if (bothDur) {
|
||||
totalstat.interpDur += stat.interpDur;
|
||||
totalstat.traceDur += stat.traceDur;
|
||||
totalstat.size += stat.size;
|
||||
totalstat.lir += stat.lir;
|
||||
totalstat.lirbytes += stat.lirbytes;
|
||||
totaldur += bothDur;
|
||||
while (durs.containsKey(bothDur)) bothDur++;
|
||||
DurData d(f, stat.traceDur, stat.interpDur, stat.size);
|
||||
@ -412,7 +399,8 @@ namespace nanojit
|
||||
int totalsize = totalstat.size;
|
||||
|
||||
_assm->outputf("");
|
||||
_assm->outputf("avg %.1f bytes/lir", double(totalstat.lirbytes)/totalstat.lir);
|
||||
_assm->outputf("lirbytes %d / lir %d = %.1f bytes/lir", totalstat.lirbytes,
|
||||
totalstat.lir, double(totalstat.lirbytes)/totalstat.lir);
|
||||
_assm->outputf(" trace interp");
|
||||
_assm->outputf("%9lld (%2d%%) %9lld (%2d%%)",
|
||||
totaltrace/1000, int(100.0*totaltrace/totaldur),
|
||||
|
@ -215,7 +215,6 @@ namespace nanojit
|
||||
uint32_t xjumpCount;
|
||||
int32_t blacklistLevel;
|
||||
NIns* fragEntry;
|
||||
LInsp state,param1,sp,rp;
|
||||
int32_t calldepth;
|
||||
void* vmprivate;
|
||||
|
||||
|
@ -46,14 +46,14 @@ namespace nanojit
|
||||
#ifdef FEATURE_NANOJIT
|
||||
|
||||
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,
|
||||
/* 0 */ 2, 2, /*trace*/0, /*nearskip*/0, /*skip*/0, /*neartramp*/0, /*tramp*/0, 2, 2, 2,
|
||||
/* 10 */ /*param*/0, 2, 2, 2, 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, /*ov*/1, /*cs*/1, 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,
|
||||
/* 70 */ 2, 2, 2, 2, 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,
|
||||
@ -65,15 +65,15 @@ namespace nanojit
|
||||
#ifdef NJ_VERBOSE
|
||||
|
||||
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",
|
||||
/* 0-9 */ "0","1","trace","nearskip","skip","neartramp","tramp","7","8","9",
|
||||
/* 10-19 */ "param","st","ld","13","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","ov","cs","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",
|
||||
/* 70-79 */ "70","71","72","73","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",
|
||||
@ -209,12 +209,11 @@ namespace nanojit
|
||||
bool LirBufWriter::ensureRoom(uint32_t count)
|
||||
{
|
||||
LInsp last = _buf->next();
|
||||
if (!samepage(last,last+count)
|
||||
if (!samepage(last,last+2*count)
|
||||
&& _buf->addPage())
|
||||
{
|
||||
// link LIR stream back to prior instruction (careful insFar relies on _unused...)
|
||||
LInsp next = _buf->next();
|
||||
insFar(LIR_skip, last-1-next);
|
||||
insFar(LIR_skip, last-1);
|
||||
}
|
||||
return !_buf->outOmem();
|
||||
}
|
||||
@ -226,24 +225,41 @@ namespace nanojit
|
||||
return _unused += count;
|
||||
}
|
||||
|
||||
uint32_t LIns::reference(LIns *r)
|
||||
uint32_t LIns::reference(LIns *r) const
|
||||
{
|
||||
int delta = this-r-1;
|
||||
NanoAssert(isU8(delta));
|
||||
return delta;
|
||||
}
|
||||
|
||||
LIns* LIns::deref(int32_t off) const
|
||||
{
|
||||
LInsp i = (LInsp) this-1 - off;
|
||||
while (i->isTramp())
|
||||
i = i->ref();
|
||||
return i;
|
||||
}
|
||||
|
||||
LInsp LirBufWriter::ensureReferenceable(LInsp i, int32_t addedDistance)
|
||||
{
|
||||
NanoAssert(!i->isop(LIR_tramp));
|
||||
NanoAssert(!i->isTramp());
|
||||
LInsp next = _buf->next();
|
||||
LInsp from = next + addedDistance;
|
||||
if ( canReference(from,i) )
|
||||
LInsp from = next + 2*addedDistance;
|
||||
if (canReference(from,i))
|
||||
return i;
|
||||
if (i == _buf->sp && spref && canReference(from, spref))
|
||||
return spref;
|
||||
if (i == _buf->rp && rpref && canReference(from, rpref))
|
||||
return rpref;
|
||||
|
||||
// need a trampoline to get to i
|
||||
LInsp tramp = insFar(LIR_tramp, i-next);
|
||||
NanoAssert( tramp+tramp->imm24() == i );
|
||||
LInsp tramp = insFar(LIR_tramp, i);
|
||||
NanoAssert( tramp->ref() == i );
|
||||
|
||||
if (i == _buf->sp)
|
||||
spref = tramp;
|
||||
else if (i == _buf->rp)
|
||||
rpref = tramp;
|
||||
return tramp;
|
||||
}
|
||||
|
||||
@ -341,28 +357,41 @@ namespace nanojit
|
||||
return ins2(op, c, data);
|
||||
}
|
||||
|
||||
LInsp LirBufWriter::insImm8(LOpcode op, int32_t a, int32_t b)
|
||||
{
|
||||
LInsp LirBufWriter::insParam(int32_t arg)
|
||||
{
|
||||
ensureRoom(1);
|
||||
LInsp l = _buf->next();
|
||||
l->initOpcode(op);
|
||||
l->setimm8(a,b);
|
||||
l->initOpcode(LIR_param);
|
||||
l->c.imm8a = Assembler::argRegs[arg];
|
||||
|
||||
_buf->commit(1);
|
||||
_buf->_stats.lir++;
|
||||
return l;
|
||||
}
|
||||
}
|
||||
|
||||
LInsp LirBufWriter::insFar(LOpcode op, int32_t imm)
|
||||
#define isS24(x) (((int32_t(x)<<8)>>8) == (x))
|
||||
|
||||
LInsp LirBufWriter::insFar(LOpcode op, LInsp target)
|
||||
{
|
||||
ensureRoom(1);
|
||||
|
||||
LInsp l = _buf->next();
|
||||
l->initOpcode(op);
|
||||
l->setimm24(imm);
|
||||
|
||||
_buf->commit(1);
|
||||
return l;
|
||||
NanoAssert(op == LIR_skip || op == LIR_tramp);
|
||||
LInsp l = _buf->next();
|
||||
int d = target-l;
|
||||
if (isS24(d)) {
|
||||
ensureRoom(1);
|
||||
l->initOpcode(LOpcode(op-1)); // nearskip or neartramp
|
||||
l->t.imm24 = d;
|
||||
_buf->commit(1);
|
||||
return l;
|
||||
}
|
||||
else {
|
||||
ensureRoom(2);
|
||||
// write the pointer and instruction
|
||||
l = _buf->next()+1;
|
||||
*((LInsp*)(l-1)) = target;
|
||||
l->initOpcode(op);
|
||||
_buf->commit(2);
|
||||
return l;
|
||||
}
|
||||
}
|
||||
|
||||
LInsp LirBufWriter::insImm(int32_t imm)
|
||||
@ -397,10 +426,10 @@ namespace nanojit
|
||||
LInsp LirBufWriter::skip(size_t size)
|
||||
{
|
||||
const uint32_t n = (size+sizeof(LIns)-1)/sizeof(LIns);
|
||||
ensureRoom(n+1);
|
||||
LInsp i = _buf->next();
|
||||
ensureRoom(n+2);
|
||||
LInsp last = _buf->next()-1;
|
||||
_buf->commit(n);
|
||||
return insFar(LIR_skip, i-1-_buf->next());
|
||||
return insFar(LIR_skip, last);
|
||||
}
|
||||
|
||||
LInsp LirReader::read()
|
||||
@ -418,18 +447,25 @@ namespace nanojit
|
||||
i--;
|
||||
break;
|
||||
|
||||
case LIR_skip:
|
||||
NanoAssert(i->imm24() != 0);
|
||||
i += i->imm24();
|
||||
case LIR_call:
|
||||
case LIR_fcall:
|
||||
i -= argwords(i->argc())+1;
|
||||
break;
|
||||
|
||||
|
||||
case LIR_skip:
|
||||
case LIR_nearskip:
|
||||
NanoAssert(i->ref() != i);
|
||||
i = i->ref();
|
||||
break;
|
||||
|
||||
case LIR_tramp:
|
||||
case LIR_int:
|
||||
NanoAssert(samepage(i, i-2));
|
||||
i -= 2;
|
||||
break;
|
||||
|
||||
case LIR_quad:
|
||||
NanoAssert(samepage(i,i-3));
|
||||
NanoAssert(samepage(i, i-3));
|
||||
i -= 3;
|
||||
break;
|
||||
|
||||
@ -503,27 +539,15 @@ namespace nanojit
|
||||
|
||||
bool LIns::isCse(const CallInfo *functions) const
|
||||
{
|
||||
return nanojit::isCse(u.code) || isCall() && functions[imm8()]._cse;
|
||||
return nanojit::isCse(u.code) || isCall() && functions[fid()]._cse;
|
||||
}
|
||||
|
||||
void LIns::setimm8(int32_t a, int32_t b)
|
||||
{
|
||||
NanoAssert(isS8(a) && isS8(b));
|
||||
c.imm8a = int8_t(a);
|
||||
c.imm8b = int8_t(b);
|
||||
}
|
||||
|
||||
void LIns::setimm16(int32_t x)
|
||||
{
|
||||
NanoAssert(isS16(x));
|
||||
i.imm16 = int16_t(x);
|
||||
}
|
||||
|
||||
void LIns::setimm24(int32_t x)
|
||||
{
|
||||
t.imm24 = x;
|
||||
}
|
||||
|
||||
void LIns::setresv(uint32_t resv)
|
||||
{
|
||||
NanoAssert(isU8(resv));
|
||||
@ -532,8 +556,9 @@ namespace nanojit
|
||||
|
||||
void LIns::initOpcode(LOpcode op)
|
||||
{
|
||||
t.code = op;
|
||||
t.imm24 = 0;
|
||||
i.code = op;
|
||||
i.imm16 = 0;
|
||||
i.resv = 0;
|
||||
}
|
||||
|
||||
void LIns::setOprnd1(LInsp r)
|
||||
@ -557,33 +582,24 @@ namespace nanojit
|
||||
}
|
||||
|
||||
LInsp LIns::oprnd1() const
|
||||
{
|
||||
LInsp i = (LInsp) this - u.oprnd_1 - 1;
|
||||
while (i->isop(LIR_tramp))
|
||||
i += i->imm24();
|
||||
return i;
|
||||
{
|
||||
return deref(u.oprnd_1);
|
||||
}
|
||||
|
||||
LInsp LIns::oprnd2() const
|
||||
{
|
||||
LInsp i = (LInsp) this - u.oprnd_2 - 1;
|
||||
while (i->isop(LIR_tramp))
|
||||
i += i->imm24();
|
||||
return i;
|
||||
return deref(u.oprnd_2);
|
||||
}
|
||||
|
||||
LInsp LIns::oprnd3() const
|
||||
{
|
||||
LInsp i = (LInsp) this - u.oprnd_3 - 1;
|
||||
while (i->isop(LIR_tramp))
|
||||
i += i->imm24();
|
||||
return i;
|
||||
return deref(u.oprnd_3);
|
||||
}
|
||||
|
||||
void *LIns::payload() const
|
||||
{
|
||||
NanoAssert(opcode() == LIR_skip);
|
||||
return (void*) (this+imm24()+1);
|
||||
NanoAssert(opcode()==LIR_skip || opcode()==LIR_nearskip);
|
||||
return (void*) (ref()+1);
|
||||
}
|
||||
|
||||
LIns* LirWriter::ins2i(LOpcode v, LIns* oprnd1, int32_t imm)
|
||||
@ -873,50 +889,52 @@ namespace nanojit
|
||||
ins2(LIR_and, iffalse, ins1(LIR_not, ncond)));
|
||||
}
|
||||
|
||||
LIns* LirBufWriter::insCall(int32_t fid, LInsp args[])
|
||||
LIns* LirBufWriter::insCall(uint32_t fid, LInsp args[])
|
||||
{
|
||||
static const LOpcode k_argmap[] = { LIR_farg, LIR_arg, LIR_ref };
|
||||
static const LOpcode k_callmap[] = { LIR_call, LIR_fcall, LIR_call, LIR_callh };
|
||||
|
||||
const CallInfo& ci = _functions[fid];
|
||||
uint32_t argt = ci._argtypes;
|
||||
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, lirNames[op]);
|
||||
LOpcode op = k_callmap[argt & 3];
|
||||
|
||||
ArgSize sizes[10];
|
||||
uint32_t argc = ci.get_sizes(sizes);
|
||||
|
||||
#ifdef NJ_SOFTFLOAT
|
||||
if (op == LIR_fcall)
|
||||
op = LIR_callh;
|
||||
LInsp args2[5*2]; // arm could require 2 args per double
|
||||
int32_t j = 0;
|
||||
uint32_t argt2 = argt&3; // copy of return type
|
||||
for (int32_t i = 0; i < argc; i++) {
|
||||
for (int32_t i = 0; i < 5; i++) {
|
||||
argt >>= 2;
|
||||
uint32_t a = argt&3;
|
||||
ArgSize a = ArgSize(argt&3);
|
||||
if (a == ARGSIZE_F) {
|
||||
LInsp q = args[i];
|
||||
args2[j++] = ins1(LIR_qhi, q);
|
||||
argt2 |= ARGSIZE_LO << (j*2);
|
||||
args2[j++] = ins1(LIR_qlo, q);
|
||||
argt2 |= ARGSIZE_LO << (j*2);
|
||||
} else {
|
||||
} else if (a != ARGSIZE_NONE) {
|
||||
args2[j++] = args[i];
|
||||
argt2 |= a << (j*2);
|
||||
}
|
||||
}
|
||||
args = args2;
|
||||
argt = argt2;
|
||||
argc = j;
|
||||
NanoAssert(j == argc);
|
||||
#endif
|
||||
|
||||
for (int32_t i = 0; i < argc; i++) {
|
||||
argt >>= 2;
|
||||
AvmAssert((argt&3)!=0);
|
||||
ins1(k_argmap[(argt&3)-1], args[i]);
|
||||
}
|
||||
|
||||
return insImm8(op==LIR_callh ? LIR_call : op, fid, argc);
|
||||
NanoAssert(argc < 8);
|
||||
uint32_t words = argwords(argc);
|
||||
ensureRoom(words+argc+1); // ins size + possible tramps
|
||||
for (uint32_t i=0; i < argc; i++)
|
||||
args[i] = ensureReferenceable(args[i], argc-i);
|
||||
uint8_t* offs = (uint8_t*)_buf->next();
|
||||
LIns *l = _buf->next() + words;
|
||||
for (uint32_t i=0; i < argc; i++)
|
||||
offs[i] = (uint8_t) l->reference(args[i]);
|
||||
l->initOpcode(op==LIR_callh ? LIR_call : op);
|
||||
l->c.imm8a = fid;
|
||||
l->c.imm8b = argc;
|
||||
_buf->commit(words+1);
|
||||
_buf->_stats.lir++;
|
||||
return l;
|
||||
}
|
||||
|
||||
using namespace avmplus;
|
||||
@ -1041,12 +1059,11 @@ namespace nanojit
|
||||
case LIR_fcall:
|
||||
{
|
||||
LInsp args[10];
|
||||
int32_t argc = i->imm8b();
|
||||
int32_t argc = i->argc();
|
||||
NanoAssert(argc < 10);
|
||||
LirReader ri(i);
|
||||
for (int32_t j=argc; j > 0; )
|
||||
args[--j] = ri.previous()->oprnd1();
|
||||
return hashcall(i->imm8(), argc, args);
|
||||
for (int32_t j=0; j < argc; j++)
|
||||
args[j] = i->arg(j);
|
||||
return hashcall(i->fid(), argc, args);
|
||||
}
|
||||
default:
|
||||
if (operandCount[op] == 2)
|
||||
@ -1079,12 +1096,11 @@ namespace nanojit
|
||||
case LIR_call:
|
||||
case LIR_fcall:
|
||||
{
|
||||
uint32_t argc;
|
||||
if (a->imm8() != b->imm8()) return false;
|
||||
if ((argc=a->imm8b()) != b->imm8b()) return false;
|
||||
LirReader ra(a), rb(b);
|
||||
while (argc-- > 0)
|
||||
if (ra.previous()->oprnd1() != rb.previous()->oprnd1())
|
||||
if (a->fid() != b->fid()) return false;
|
||||
uint32_t argc=a->argc();
|
||||
NanoAssert(argc == b->argc());
|
||||
for (uint32_t i=0; i < argc; i++)
|
||||
if (a->arg(i) != b->arg(i))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
@ -1178,7 +1194,7 @@ namespace nanojit
|
||||
return _hashfinish(_hashptr(hash, b));
|
||||
}
|
||||
|
||||
uint32_t LInsHashSet::hashcall(int32_t fid, uint32_t argc, LInsp args[]) {
|
||||
uint32_t LInsHashSet::hashcall(uint32_t fid, uint32_t argc, LInsp args[]) {
|
||||
uint32_t hash = _hash32(0,fid);
|
||||
for (int32_t j=argc-1; j >= 0; j--)
|
||||
hash = _hashptr(hash,args[j]);
|
||||
@ -1255,15 +1271,13 @@ namespace nanojit
|
||||
|
||||
bool argsmatch(LInsp i, uint32_t argc, LInsp args[])
|
||||
{
|
||||
// we don't have callinfo here so we cannot use argiterator
|
||||
LirReader r(i);
|
||||
for (LInsp a = r.previous(); a->isArg(); a=r.previous())
|
||||
if (a->oprnd1() != args[--argc])
|
||||
for (uint32_t j=0; j < argc; j++)
|
||||
if (i->arg(j) != args[j])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
LInsp LInsHashSet::findcall(int32_t fid, uint32_t argc, LInsp args[], uint32_t &i)
|
||||
LInsp LInsHashSet::findcall(uint32_t fid, uint32_t argc, LInsp args[], uint32_t &i)
|
||||
{
|
||||
uint32_t cap = m_list.size();
|
||||
const InsList& list = m_list;
|
||||
@ -1272,7 +1286,7 @@ namespace nanojit
|
||||
uint32_t n = 7 << 1;
|
||||
LInsp k;
|
||||
while ((k = list.get(hash)) != NULL &&
|
||||
(!k->isCall() || k->imm8() != fid || !argsmatch(k, argc, args)))
|
||||
(!k->isCall() || k->fid() != fid || !argsmatch(k, argc, args)))
|
||||
{
|
||||
hash = (hash + (n += 2)) & bitmask; // quadratic probe
|
||||
}
|
||||
@ -1311,7 +1325,7 @@ namespace nanojit
|
||||
e->i = i;
|
||||
for (int j=0, n=live.size(); j < n; j++) {
|
||||
LInsp l = live.keyAt(j);
|
||||
if (!l->isStore() && !l->isGuard() && !l->isArg())
|
||||
if (!l->isStore() && !l->isGuard())
|
||||
e->live.add(l);
|
||||
}
|
||||
int size=0;
|
||||
@ -1330,31 +1344,23 @@ namespace nanojit
|
||||
{
|
||||
// traverse backwards to find live exprs and a few other stats.
|
||||
|
||||
LInsp sp = frag->sp;
|
||||
LInsp rp = frag->rp;
|
||||
LInsp sp = frag->lirbuf->sp;
|
||||
LInsp rp = frag->lirbuf->rp;
|
||||
LiveTable live(gc);
|
||||
uint32_t exits = 0;
|
||||
LirBuffer *lirbuf = frag->lirbuf;
|
||||
LirReader br(lirbuf);
|
||||
StackFilter sf(&br, gc, frag, sp);
|
||||
StackFilter r(&sf, gc, frag, rp);
|
||||
bool skipargs = false;
|
||||
int total = 0;
|
||||
live.add(frag->state, r.pos());
|
||||
live.add(frag->lirbuf->state, r.pos());
|
||||
for (LInsp i = r.read(); i != 0; i = r.read())
|
||||
{
|
||||
total++;
|
||||
|
||||
if (i->isArg()) {
|
||||
if (!skipargs)
|
||||
live.add(i->oprnd1(),0);
|
||||
} else {
|
||||
skipargs = false;
|
||||
}
|
||||
|
||||
// first handle side-effect instructions
|
||||
if (i->isStore() || i->isGuard() ||
|
||||
i->isCall() && !assm->callInfoFor(i->imm8())->_cse)
|
||||
i->isCall() && !assm->callInfoFor(i->fid())->_cse)
|
||||
{
|
||||
live.add(i,0);
|
||||
if (i->isGuard())
|
||||
@ -1381,10 +1387,10 @@ namespace nanojit
|
||||
live.add(i->oprnd1(),i);
|
||||
live.add(i->oprnd2(),i);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
skipargs = i->isCall();
|
||||
else if (i->isCall()) {
|
||||
for (int j=0, c=i->argc(); j < c; j++)
|
||||
live.add(i->arg(j),i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1454,7 +1460,7 @@ namespace nanojit
|
||||
}
|
||||
else {
|
||||
if (ref->isCall()) {
|
||||
copyName(ref, _functions[ref->imm8()]._name, funccounts.add(ref->imm8()));
|
||||
copyName(ref, _functions[ref->fid()]._name, funccounts.add(ref->fid()));
|
||||
} else {
|
||||
copyName(ref, lirNames[ref->opcode()], lircounts.add(ref->opcode()));
|
||||
}
|
||||
@ -1497,11 +1503,10 @@ namespace nanojit
|
||||
|
||||
case LIR_fcall:
|
||||
case LIR_call: {
|
||||
sprintf(s, "%s ( ", _functions[i->imm8()]._name);
|
||||
LirReader r(i);
|
||||
for (LInsp a = r.previous(); a->isArg(); a = r.previous()) {
|
||||
sprintf(s, "%s ( ", _functions[i->fid()]._name);
|
||||
for (int32_t j=i->argc()-1; j >= 0; j--) {
|
||||
s += strlen(s);
|
||||
sprintf(s, "%s ",formatRef(a->oprnd1()));
|
||||
sprintf(s, "%s ",formatRef(i->arg(j)));
|
||||
}
|
||||
s += strlen(s);
|
||||
sprintf(s, ")");
|
||||
@ -1515,15 +1520,13 @@ namespace nanojit
|
||||
case LIR_callh:
|
||||
case LIR_neg:
|
||||
case LIR_fneg:
|
||||
case LIR_arg:
|
||||
case LIR_farg:
|
||||
case LIR_i2f:
|
||||
case LIR_u2f:
|
||||
case LIR_qlo:
|
||||
case LIR_qhi:
|
||||
case LIR_ref:
|
||||
case LIR_ov:
|
||||
case LIR_cs:
|
||||
case LIR_not:
|
||||
sprintf(s, "%s %s", lirNames[op], formatRef(i->oprnd1()));
|
||||
break;
|
||||
|
||||
@ -1542,7 +1545,6 @@ namespace nanojit
|
||||
case LIR_fdiv:
|
||||
case LIR_and:
|
||||
case LIR_or:
|
||||
case LIR_not:
|
||||
case LIR_xor:
|
||||
case LIR_lsh:
|
||||
case LIR_rsh:
|
||||
@ -1676,12 +1678,13 @@ namespace nanojit
|
||||
return out->insGuard(v, c, x);
|
||||
}
|
||||
|
||||
LInsp CseFilter::insCall(int32_t fid, LInsp args[])
|
||||
LInsp CseFilter::insCall(uint32_t fid, LInsp args[])
|
||||
{
|
||||
const CallInfo *c = &_functions[fid];
|
||||
if (c->_cse) {
|
||||
uint32_t k;
|
||||
LInsp found = exprs.findcall(fid, c->count_args(), args, k);
|
||||
uint32_t argc = c->count_args();
|
||||
LInsp found = exprs.findcall(fid, argc, args, k);
|
||||
if (found)
|
||||
return found;
|
||||
return exprs.add(out->insCall(fid, args), k);
|
||||
@ -1705,12 +1708,7 @@ namespace nanojit
|
||||
|
||||
LIns* FASTCALL callArgN(LIns* i, uint32_t n)
|
||||
{
|
||||
// @todo clean up; shouldn't have to create a reader
|
||||
LirReader rdr(i);
|
||||
do
|
||||
i = rdr.read();
|
||||
while (n-- > 0);
|
||||
return i;
|
||||
return i->arg(i->argc()-n-1);
|
||||
}
|
||||
|
||||
void compile(Assembler* assm, Fragment* triggerFrag)
|
||||
|
@ -52,15 +52,15 @@ namespace nanojit
|
||||
|
||||
// special operations (must be 0..N)
|
||||
LIR_trace = 2,
|
||||
LIR_skip = 3,
|
||||
LIR_tramp = 4,
|
||||
LIR_nearskip = 3, // must be LIR_skip-1 and lsb=1
|
||||
LIR_skip = 4,
|
||||
LIR_neartramp = 5, // must be LIR_tramp-1 and lsb=1
|
||||
LIR_tramp = 6,
|
||||
|
||||
// non-pure operations
|
||||
LIR_arg = 9,
|
||||
LIR_param = 10,
|
||||
LIR_st = 11,
|
||||
LIR_ld = 12,
|
||||
LIR_ref = 13, // ref arg
|
||||
LIR_sti = 14,
|
||||
LIR_call = 18,
|
||||
|
||||
@ -120,7 +120,6 @@ namespace nanojit
|
||||
LIR_quad = LIR_int | LIR64,
|
||||
LIR_ldq = LIR_ld | LIR64,
|
||||
|
||||
LIR_farg = LIR_arg | LIR64,
|
||||
LIR_fcall = LIR_call | LIR64,
|
||||
LIR_fneg = LIR_neg | LIR64,
|
||||
LIR_fadd = LIR_add | LIR64,
|
||||
@ -133,6 +132,10 @@ namespace nanojit
|
||||
LIR_u2f = 43 | LIR64
|
||||
};
|
||||
|
||||
inline uint32_t argwords(uint32_t argc) {
|
||||
return (argc+3)>>2;
|
||||
}
|
||||
|
||||
struct SideExit;
|
||||
struct Page;
|
||||
struct CallInfo;
|
||||
@ -141,53 +144,54 @@ namespace nanojit
|
||||
// had to lay it our as a union with duplicate code fields since msvc couldn't figure out how to compact it otherwise.
|
||||
class LIns
|
||||
{
|
||||
friend class LirBufWriter;
|
||||
// 3-operand form (backwards reach only)
|
||||
struct u_type
|
||||
{
|
||||
LOpcode code:8;
|
||||
uint32_t oprnd_3:8; // only used for store, since this location gets clobbered during generation
|
||||
uint32_t oprnd_1:8; // 256 ins window and since they only point backwards this is sufficient.
|
||||
uint32_t oprnd_2:8;
|
||||
uint32_t oprnd_3:8; // only used for store, since this location gets clobbered during generation
|
||||
};
|
||||
|
||||
struct sti_type
|
||||
{
|
||||
LOpcode code:8;
|
||||
int32_t disp:8;
|
||||
uint32_t oprnd_1:8; // 256 ins window and since they only point backwards this is sufficient.
|
||||
uint32_t oprnd_2:8;
|
||||
int32_t disp:8;
|
||||
};
|
||||
|
||||
// imm8 form
|
||||
struct c_type
|
||||
{
|
||||
LOpcode code:8;
|
||||
uint32_t resv:8; // cobberred during assembly
|
||||
uint32_t imm8a:8;
|
||||
uint32_t imm8b:8;
|
||||
uint32_t resv:8; // cobberred during assembly
|
||||
};
|
||||
|
||||
// imm24 form for short tramp & skip
|
||||
struct t_type
|
||||
{
|
||||
LOpcode code:8;
|
||||
int32_t imm24:24;
|
||||
};
|
||||
|
||||
// imm16 form
|
||||
struct i_type
|
||||
{
|
||||
LOpcode code:8;
|
||||
int32_t imm16:16;
|
||||
uint32_t resv:8; // cobberred during assembly
|
||||
};
|
||||
|
||||
// tramp form (imm24)
|
||||
struct t_type
|
||||
{
|
||||
LOpcode code:8;
|
||||
int32_t imm24:24; // +/- 8MB
|
||||
int32_t imm16:16;
|
||||
};
|
||||
|
||||
// overlay used during code generation ( note that last byte is reserved for allocation )
|
||||
struct g_type
|
||||
{
|
||||
LOpcode code:8;
|
||||
uint32_t unused:16;
|
||||
uint32_t resv:8; // cobberred during assembly
|
||||
uint32_t unused:16;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -204,12 +208,13 @@ namespace nanojit
|
||||
u_type u;
|
||||
c_type c;
|
||||
i_type i;
|
||||
t_type t;
|
||||
t_type t;
|
||||
g_type g;
|
||||
sti_type sti;
|
||||
};
|
||||
|
||||
uint32_t reference(LIns*);
|
||||
uint32_t reference(LIns*) const;
|
||||
LIns* deref(int32_t off) const;
|
||||
|
||||
public:
|
||||
LIns* FASTCALL oprnd1() const;
|
||||
@ -218,14 +223,23 @@ namespace nanojit
|
||||
|
||||
inline LOpcode opcode() const { return u.code; }
|
||||
inline uint8_t imm8() const { return c.imm8a; }
|
||||
inline uint8_t imm8b() const { return c.imm8b; }
|
||||
inline int16_t imm16() const { return i.imm16; }
|
||||
inline int32_t imm24() const { return t.imm24; }
|
||||
inline LIns* ref() const {
|
||||
return (t.code & 1) ? (LIns*)this+t.imm24 : *(LIns**)(this-1);
|
||||
}
|
||||
inline int32_t imm32() const { return *(int32_t*)(this-1); }
|
||||
inline uint8_t resv() const { return g.resv; }
|
||||
void* payload() const;
|
||||
inline Page* page() { return (Page*) alignTo(this,NJ_PAGE_SIZE); }
|
||||
|
||||
// index args in r-l order. arg(0) is rightmost arg
|
||||
inline LIns* arg(uint32_t i) {
|
||||
uint32_t c = argc();
|
||||
NanoAssert(i < c);
|
||||
uint8_t* offs = (uint8_t*) (this-argwords(c));
|
||||
return deref(offs[i]);
|
||||
}
|
||||
|
||||
inline int32_t immdisp()const
|
||||
{
|
||||
return (u.code&~LIR64) == LIR_sti ? sti.disp : oprnd3()->constval();
|
||||
@ -255,7 +269,7 @@ namespace nanojit
|
||||
return *(const uint64_t*)(this-2);
|
||||
#else
|
||||
uint64_t tmp;
|
||||
memcpy(&tmp, this-2, sizeof(tmp));
|
||||
memcpy(&tmp, this-2, sizeof(tmp));
|
||||
return tmp;
|
||||
#endif
|
||||
}
|
||||
@ -266,16 +280,15 @@ namespace nanojit
|
||||
#ifdef AVMPLUS_UNALIGNED_ACCESS
|
||||
return *(const double*)(this-2);
|
||||
#else
|
||||
double tmpf;
|
||||
memcpy(&tmpf, this-2, sizeof(tmpf));
|
||||
return tmpf;
|
||||
union { uint64_t tmp; double tmpf; } u;
|
||||
memcpy(&u.tmpf, this-2, sizeof(u.tmpf));
|
||||
return u.tmpf;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool isCse(const CallInfo *functions) const;
|
||||
bool isop(LOpcode o) const { return u.code == o; }
|
||||
bool isQuad() const { return (u.code & LIR64) != 0; }
|
||||
bool isArg() const { return (u.code & ~LIR64)==LIR_arg || u.code == LIR_ref; }
|
||||
bool isCond() const;
|
||||
bool isCmp() const;
|
||||
bool isCall() const;
|
||||
@ -285,8 +298,10 @@ namespace nanojit
|
||||
bool isconst() const;
|
||||
bool isconstval(int32_t val) const;
|
||||
bool isconstq() const;
|
||||
bool isTramp() {
|
||||
return isop(LIR_neartramp) || isop(LIR_tramp);
|
||||
}
|
||||
|
||||
void setimm8(int32_t a, int32_t b);
|
||||
void setimm16(int32_t i);
|
||||
void setimm24(int32_t i);
|
||||
void setresv(uint32_t resv);
|
||||
@ -297,6 +312,15 @@ namespace nanojit
|
||||
void setDisp(int8_t d);
|
||||
|
||||
SideExit *exit();
|
||||
|
||||
inline uint32_t argc() {
|
||||
NanoAssert(isCall());
|
||||
return c.imm8b;
|
||||
}
|
||||
inline uint8_t fid() const {
|
||||
NanoAssert(isCall());
|
||||
return c.imm8a;
|
||||
}
|
||||
};
|
||||
typedef LIns* LInsp;
|
||||
|
||||
@ -334,8 +358,8 @@ namespace nanojit
|
||||
virtual LInsp insGuard(LOpcode v, LIns *c, SideExit *x) {
|
||||
return out->insGuard(v, c, x);
|
||||
}
|
||||
virtual LInsp insImm8(LOpcode v, int32_t a, int32_t b) {
|
||||
return out->insImm8(v, a, b);
|
||||
virtual LInsp insParam(int32_t i) {
|
||||
return out->insParam(i);
|
||||
}
|
||||
virtual LInsp insImm(int32_t imm) {
|
||||
return out->insImm(imm);
|
||||
@ -353,7 +377,7 @@ namespace nanojit
|
||||
return isS8(d) ? out->insStorei(value, base, d)
|
||||
: out->insStore(value, base, insImm(d));
|
||||
}
|
||||
virtual LInsp insCall(int32_t fid, LInsp args[]) {
|
||||
virtual LInsp insCall(uint32_t fid, LInsp args[]) {
|
||||
return out->insCall(fid, args);
|
||||
}
|
||||
|
||||
@ -484,11 +508,11 @@ namespace nanojit
|
||||
LIns* ins2(LOpcode v, LInsp a, LInsp b) {
|
||||
return v == LIR_2 ? out->ins2(v,a,b) : add(out->ins2(v, a, b));
|
||||
}
|
||||
LIns* insCall(int32_t fid, LInsp args[]) {
|
||||
LIns* insCall(uint32_t fid, LInsp args[]) {
|
||||
return add(out->insCall(fid, args));
|
||||
}
|
||||
LIns* insImm8(LOpcode v, int32_t a, int32_t b) {
|
||||
return add(out->insImm8(v, a, b));
|
||||
LIns* insParam(int32_t i) {
|
||||
return add(out->insParam(i));
|
||||
}
|
||||
LIns* insLoad(LOpcode v, LInsp base, LInsp disp) {
|
||||
return add(out->insLoad(v, base, disp));
|
||||
@ -536,7 +560,7 @@ namespace nanojit
|
||||
LInsp find64(uint64_t a, uint32_t &i);
|
||||
LInsp find1(LOpcode v, LInsp a, 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(uint32_t fid, uint32_t argc, LInsp args[], uint32_t &i);
|
||||
LInsp add(LInsp i, uint32_t k);
|
||||
void replace(LInsp i);
|
||||
|
||||
@ -544,7 +568,7 @@ namespace nanojit
|
||||
static uint32_t FASTCALL hashimmq(uint64_t);
|
||||
static uint32_t FASTCALL hash1(LOpcode v, LInsp);
|
||||
static uint32_t FASTCALL hash2(LOpcode v, LInsp, LInsp);
|
||||
static uint32_t FASTCALL hashcall(int32_t fid, uint32_t argc, LInsp args[]);
|
||||
static uint32_t FASTCALL hashcall(uint32_t fid, uint32_t argc, LInsp args[]);
|
||||
};
|
||||
|
||||
class CseFilter: public LirWriter
|
||||
@ -557,7 +581,7 @@ namespace nanojit
|
||||
LIns* ins1(LOpcode v, LInsp);
|
||||
LIns* ins2(LOpcode v, LInsp, LInsp);
|
||||
LIns* insLoad(LOpcode v, LInsp b, LInsp d);
|
||||
LIns* insCall(int32_t fid, LInsp args[]);
|
||||
LIns* insCall(uint32_t fid, LInsp args[]);
|
||||
LIns* insGuard(LOpcode op, LInsp cond, SideExit *x);
|
||||
};
|
||||
|
||||
@ -566,7 +590,6 @@ namespace nanojit
|
||||
{
|
||||
public:
|
||||
DWB(Fragmento*) _frago;
|
||||
public:
|
||||
LirBuffer(Fragmento* frago, const CallInfo* functions);
|
||||
virtual ~LirBuffer();
|
||||
void clear();
|
||||
@ -588,6 +611,7 @@ namespace nanojit
|
||||
_stats;
|
||||
|
||||
const CallInfo* _functions;
|
||||
LInsp state,param1,sp,rp;
|
||||
|
||||
private:
|
||||
Page* pageAlloc();
|
||||
@ -600,6 +624,7 @@ namespace nanojit
|
||||
class LirBufWriter : public LirWriter
|
||||
{
|
||||
DWB(LirBuffer*) _buf; // underlying buffer housing the instructions
|
||||
LInsp spref, rpref;
|
||||
|
||||
public:
|
||||
LirBufWriter(LirBuffer* buf)
|
||||
@ -614,15 +639,15 @@ namespace nanojit
|
||||
LInsp ins0(LOpcode op);
|
||||
LInsp ins1(LOpcode op, LInsp o1);
|
||||
LInsp ins2(LOpcode op, LInsp o1, LInsp o2);
|
||||
LInsp insImm8(LOpcode op, int32_t a, int32_t b);
|
||||
LInsp insParam(int32_t i);
|
||||
LInsp insImm(int32_t imm);
|
||||
LInsp insImmq(uint64_t imm);
|
||||
LInsp insCall(int32_t fid, LInsp args[]);
|
||||
LInsp insCall(uint32_t fid, LInsp args[]);
|
||||
LInsp insGuard(LOpcode op, LInsp cond, SideExit *x);
|
||||
|
||||
// buffer mgmt
|
||||
LInsp skip(size_t);
|
||||
LInsp insFar(LOpcode op, int32_t imm);
|
||||
LInsp insFar(LOpcode op, LInsp target);
|
||||
LInsp ensureReferenceable(LInsp i, int32_t addedDistance);
|
||||
bool ensureRoom(uint32_t count);
|
||||
bool canReference(LInsp from, LInsp to) {
|
||||
@ -643,11 +668,6 @@ namespace nanojit
|
||||
virtual LInsp pos() {
|
||||
return in->pos();
|
||||
}
|
||||
|
||||
LInsp previous() {
|
||||
read();
|
||||
return pos();
|
||||
}
|
||||
};
|
||||
|
||||
// concrete
|
||||
|
@ -55,7 +55,8 @@
|
||||
#error "unknown nanojit architecture"
|
||||
#endif
|
||||
|
||||
namespace nanojit {
|
||||
namespace nanojit
|
||||
{
|
||||
const uint32_t NJ_PAGE_SIZE = 1 << NJ_LOG2_PAGE_SIZE;
|
||||
}
|
||||
|
||||
|
@ -149,7 +149,7 @@ namespace nanojit
|
||||
#define DECLARE_PLATFORM_ASSEMBLER()\
|
||||
const static Register argRegs[4], retRegs[2];\
|
||||
void LD32_nochk(Register r, int32_t imm);\
|
||||
void CALL(intptr_t addr, const char* nm);\
|
||||
void CALL(const CallInfo*);\
|
||||
void underrunProtect(int bytes);\
|
||||
bool has_cmov;\
|
||||
void nativePageReset();\
|
||||
@ -157,6 +157,9 @@ namespace nanojit
|
||||
int* _nSlot;\
|
||||
int* _nExitSlot;
|
||||
|
||||
|
||||
#define asm_farg(i) NanoAssert(false)
|
||||
|
||||
//printf("jmp_l_n count=%d, nins=%X, %X = %X\n", (_c), nins, _nIns, ((intptr_t)(nins+(_c))-(intptr_t)_nIns - 4) );
|
||||
|
||||
#define swapptrs() { NIns* _tins = _nIns; _nIns=_nExitIns; _nExitIns=_tins; \
|
||||
|
@ -193,60 +193,21 @@ namespace nanojit
|
||||
#endif
|
||||
}
|
||||
|
||||
void Assembler::nArgEmitted(const CallInfo* call, uint32_t stackSlotCount, uint32_t iargs, uint32_t fargs)
|
||||
void Assembler::asm_call(LInsp ins)
|
||||
{
|
||||
#if 1
|
||||
(void)call;
|
||||
(void)stackSlotCount;
|
||||
(void)iargs;
|
||||
(void)fargs;
|
||||
#else
|
||||
// see if we have finished emitting all args. If so then make sure the
|
||||
// new stack pointer is NJ_ALIGN_STACK aligned
|
||||
if (iargs == call->iargs && fargs == call->fargs)
|
||||
const CallInfo* call = callInfoFor(ins->fid());
|
||||
CALL(call);
|
||||
ArgSize sizes[10];
|
||||
uint32_t argc = call->get_sizes(sizes);
|
||||
for(uint32_t i=0; i < argc; i++)
|
||||
{
|
||||
int32_t istack = iargs;
|
||||
istack -= 4;
|
||||
if (istack<=0)
|
||||
return; // nothing on stack
|
||||
|
||||
const int32_t size = 4*stackSlotCount;
|
||||
const int32_t extra = alignUp(size, NJ_ALIGN_STACK) - size;
|
||||
if (extra > 0)
|
||||
SUBi(SP, extra);
|
||||
uint32_t j = argc - i - 1;
|
||||
ArgSize sz = sizes[j];
|
||||
NanoAssert(sz == ARGSIZES_LO || sz == ARGSIZES_Q);
|
||||
// pre-assign registers R0-R3 for arguments (if they fit)
|
||||
Register r = i < 4 ? argRegs[i] : UnknownReg;
|
||||
asm_arg(sz, ins->arg(j), r);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Assembler::nPostCallCleanup(const CallInfo* call)
|
||||
{
|
||||
#if 1
|
||||
(void)call;
|
||||
#else
|
||||
int32_t istack = call->iargs;
|
||||
int32_t fstack = call->fargs;
|
||||
|
||||
istack -= 4; // first 4 4B args are in registers
|
||||
if (istack <= 0)
|
||||
{
|
||||
return; // nothing on stack
|
||||
|
||||
//istack = 0;
|
||||
//if (fstack == 0)
|
||||
//return; // only using ECX/EDX nothing passed on the stack so no cleanup needed
|
||||
}
|
||||
|
||||
const int32_t size = 4*istack + 8*fstack; // actual stack space used
|
||||
NanoAssert( size > 0 );
|
||||
|
||||
const int32_t extra = alignUp(size, NJ_ALIGN_STACK);
|
||||
|
||||
// stack re-alignment
|
||||
// only pop our adjustment amount since callee pops args in FASTCALL mode
|
||||
if (extra > 0)
|
||||
{ ADDi(SP, extra); }
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
void Assembler::nMarkExecute(Page* page, int32_t count, bool enable)
|
||||
@ -858,14 +819,14 @@ namespace nanojit
|
||||
}
|
||||
}
|
||||
|
||||
void Assembler::CALL(intptr_t addr, const char* nm)
|
||||
void Assembler::CALL(const CallInfo *ci)
|
||||
{
|
||||
(void)nm;
|
||||
intptr_t addr = ci->_address;
|
||||
if (isB22((NIns*)addr, _nIns)) {
|
||||
int offset = int(addr)-int(_nIns-2+2);
|
||||
*(--_nIns) = (NIns)(0xF800 | ((offset>>1)&0x7FF) );
|
||||
*(--_nIns) = (NIns)(0xF000 | ((offset>>12)&0x7FF) );
|
||||
asm_output2("call %08X:%s",(addr),(nm));
|
||||
asm_output2("call %08X:%s", addr, ci->_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -884,7 +845,7 @@ namespace nanojit
|
||||
*(--_nIns) = (NIns)(0x4700 | (IP<<3));
|
||||
*(--_nIns) = (NIns)(0xE000 | (4>>1));
|
||||
*(--_nIns) = (NIns)(0x4800 | (Scratch<<8) | (1));
|
||||
asm_output2("call %08X:%s",(addr),(nm));
|
||||
asm_output2("call %08X:%s", addr, ci->_name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -908,16 +869,16 @@ namespace nanojit
|
||||
return (-(1<<24) <= offset && offset < (1<<24));
|
||||
}
|
||||
|
||||
void Assembler::CALL(intptr_t addr, const char* nm)
|
||||
void Assembler::CALL(const CallInfo *ci)
|
||||
{
|
||||
(void)nm;
|
||||
if (isB24((NIns*)addr,_nIns))
|
||||
intptr_t addr = ci->_address;
|
||||
if (isB24((NIns*)addr, _nIns))
|
||||
{
|
||||
// we can do this with a single BL call
|
||||
underrunProtect(4);
|
||||
|
||||
BL(addr);
|
||||
asm_output2("call %08X:%s",(addr),(nm));
|
||||
asm_output2("call %08X:%s", addr, ci->_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -926,7 +887,7 @@ namespace nanojit
|
||||
*(--_nIns) = (NIns)( COND_AL | (0x9<<21) | (0xFFF<<8) | (1<<4) | (IP) );
|
||||
*(--_nIns) = (NIns)( COND_AL | OP_IMM | (1<<23) | (PC<<16) | (LR<<12) | (4) );
|
||||
*(--_nIns) = (NIns)( COND_AL | (0x59<<20) | (PC<<16) | (IP<<12) | (4));
|
||||
asm_output2("call %08X:%s",(addr),(nm));
|
||||
asm_output2("call %08X:%s", addr, ci->_name);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -144,7 +144,7 @@ namespace nanojit
|
||||
void SUBi8(Register r, int32_t imm);\
|
||||
void JMP(NIns *target);\
|
||||
void LD32_nochk(Register r, int32_t imm);\
|
||||
void CALL(intptr_t addr, const char* nm);\
|
||||
void CALL(const CallInfo*);\
|
||||
void nativePageReset();\
|
||||
void nativePageSetup();\
|
||||
int* _nPool;\
|
||||
@ -152,6 +152,7 @@ namespace nanojit
|
||||
int* _nExitPool;\
|
||||
int* _nExitSlot;
|
||||
|
||||
#define asm_farg(i) NanoAssert(false)
|
||||
|
||||
#define swapptrs() { NIns* _tins = _nIns; _nIns=_nExitIns; _nExitIns=_tins; \
|
||||
int* _npool = _nPool;\
|
||||
|
@ -182,47 +182,55 @@ namespace nanojit
|
||||
return _nIns;
|
||||
}
|
||||
|
||||
void Assembler::nArgEmitted(const CallInfo* call, uint32_t stackSlotCount, uint32_t iargs, uint32_t fargs)
|
||||
{
|
||||
// see if we have finished emitting all args. If so then make sure the
|
||||
// new stack pointer is NJ_ALIGN_STACK aligned
|
||||
const uint32_t istack = call->count_iargs();
|
||||
const uint32_t fstack = call->count_args() - istack;
|
||||
//printf("call %s iargs %d fargs %d istack %d fstack %d\n",call->_name,iargs,fargs,istack,fstack);
|
||||
AvmAssert(iargs <= istack);
|
||||
AvmAssert(fargs <= fstack);
|
||||
if (iargs == istack && fargs == fstack)
|
||||
{
|
||||
const int32_t size = 4*stackSlotCount;
|
||||
const int32_t extra = alignUp(size, NJ_ALIGN_STACK) - size;
|
||||
if (extra > 0)
|
||||
SUBi(SP, extra);
|
||||
}
|
||||
}
|
||||
|
||||
void Assembler::nPostCallCleanup(const CallInfo* call)
|
||||
void Assembler::asm_call(LInsp ins)
|
||||
{
|
||||
uint32_t fid = ins->fid();
|
||||
const CallInfo* call = callInfoFor(fid);
|
||||
// must be signed, not unsigned
|
||||
int32_t istack = call->count_iargs();
|
||||
int32_t fstack = call->count_args() - istack;
|
||||
const uint32_t iargs = call->count_iargs();
|
||||
int32_t fstack = call->count_args() - iargs;
|
||||
|
||||
istack -= 2; // first 2 4B args are in registers
|
||||
int32_t extra = 0;
|
||||
int32_t istack = iargs-2; // first 2 4B args are in registers
|
||||
if (istack <= 0)
|
||||
{
|
||||
istack = 0;
|
||||
if (fstack == 0)
|
||||
return; // only using ECX/EDX nothing passed on the stack so no cleanup needed
|
||||
}
|
||||
|
||||
const int32_t size = 4*istack + 8*fstack; // actual stack space used
|
||||
NanoAssert( size > 0 );
|
||||
|
||||
const int32_t extra = alignUp(size, NJ_ALIGN_STACK) - (size);
|
||||
if (size) {
|
||||
// stack re-alignment
|
||||
// only pop our adjustment amount since callee pops args in FASTCALL mode
|
||||
extra = alignUp(size, NJ_ALIGN_STACK) - (size);
|
||||
if (extra > 0)
|
||||
ADDi(SP, extra);
|
||||
}
|
||||
|
||||
CALL(call);
|
||||
|
||||
// make sure fpu stack is empty before call (restoreCallerSaved)
|
||||
NanoAssert(_allocator.isFree(FST0));
|
||||
// note: this code requires that ref arguments (ARGSIZE_Q)
|
||||
// be one of the first two arguments
|
||||
// pre-assign registers to the first 2 4B args
|
||||
const int max_regs = (iargs < 2) ? iargs : 2;
|
||||
int n = 0;
|
||||
|
||||
ArgSize sizes[10];
|
||||
uint32_t argc = call->get_sizes(sizes);
|
||||
|
||||
for(uint32_t i=0; i < argc; i++)
|
||||
{
|
||||
uint32_t j = argc-i-1;
|
||||
ArgSize sz = sizes[j];
|
||||
Register r = UnknownReg;
|
||||
if (n < max_regs && sz != ARGSIZE_F)
|
||||
r = argRegs[n++]; // tell asm_arg what reg to use
|
||||
asm_arg(sz, ins->arg(j), r);
|
||||
}
|
||||
|
||||
// stack re-alignment
|
||||
// only pop our adjustment amount since callee pops args in FASTCALL mode
|
||||
if (extra > 0)
|
||||
{ ADDi(SP, extra); }
|
||||
SUBi(SP, extra);
|
||||
}
|
||||
|
||||
void Assembler::nMarkExecute(Page* page, int32_t count, bool enable)
|
||||
@ -669,9 +677,8 @@ namespace nanojit
|
||||
}
|
||||
}
|
||||
|
||||
void Assembler::asm_farg(LInsp ins)
|
||||
void Assembler::asm_farg(LInsp p)
|
||||
{
|
||||
LIns* p = ins->oprnd1();
|
||||
Register r = findRegFor(p, FpRegs);
|
||||
if (rmask(r) & XmmRegs) {
|
||||
STQ(0, SP, r);
|
||||
@ -680,9 +687,6 @@ namespace nanojit
|
||||
}
|
||||
PUSHr(ECX); // 2*pushr is smaller than sub
|
||||
PUSHr(ECX);
|
||||
_stackUsed += 2;
|
||||
++_fargs;
|
||||
nArgEmitted(_call, _stackUsed, _iargs, _fargs);
|
||||
}
|
||||
|
||||
void Assembler::asm_fop(LInsp ins)
|
||||
@ -774,13 +778,12 @@ namespace nanojit
|
||||
|
||||
Register Assembler::asm_prep_fcall(Reservation *rR, LInsp ins)
|
||||
{
|
||||
Register rr;
|
||||
if (rR) {
|
||||
Register rr;
|
||||
if ((rr=rR->reg) != UnknownReg && (rmask(rr) & XmmRegs))
|
||||
evict(rr);
|
||||
}
|
||||
prepResultReg(ins, rmask(FST0));
|
||||
return FST0;
|
||||
return prepResultReg(ins, rmask(FST0));
|
||||
}
|
||||
|
||||
void Assembler::asm_u2f(LInsp ins)
|
||||
|
@ -133,7 +133,8 @@ namespace nanojit
|
||||
bool has_cmov; \
|
||||
bool pad[1];\
|
||||
void nativePageReset();\
|
||||
void nativePageSetup();
|
||||
void nativePageSetup();\
|
||||
void asm_farg(LInsp);
|
||||
|
||||
#define swapptrs() { NIns* _tins = _nIns; _nIns=_nExitIns; _nExitIns=_tins; }
|
||||
|
||||
@ -658,12 +659,14 @@ namespace nanojit
|
||||
#define FLDr(r) do { FPU(0xd9c0,r); asm_output1("fld %s",fpn(r)); fpu_push(); } while(0)
|
||||
#define EMMS() do { FPUc(0x0f77); asm_output("emms"); } while (0)
|
||||
|
||||
#define CALL(a,nm) do { \
|
||||
underrunProtect(5); \
|
||||
int offset = (a) - ((int)_nIns); \
|
||||
IMM32( (uint32_t)offset ); \
|
||||
*(--_nIns) = 0xE8; \
|
||||
asm_output1("call %s",(nm)); \
|
||||
} while (0)
|
||||
#define CALL(c) do { \
|
||||
underrunProtect(5); \
|
||||
int offset = (c->_address) - ((int)_nIns); \
|
||||
IMM32( (uint32_t)offset ); \
|
||||
*(--_nIns) = 0xE8; \
|
||||
verbose_only(asm_output1("call %s",(c->_name));) \
|
||||
debug_only(if ((c->_argtypes&3)==ARGSIZE_F) fpu_push();)\
|
||||
} while (0)
|
||||
|
||||
}
|
||||
#endif // __nanojit_Nativei386__
|
||||
|
Loading…
Reference in New Issue
Block a user