mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge.
This commit is contained in:
commit
7cce9201aa
@ -1,4 +1,10 @@
|
||||
function run_test() {
|
||||
var x = JSON.stringify({key:2},function(k,v){return k?undefined:v;})
|
||||
do_check_eq("{}", x);
|
||||
|
||||
var x = JSON.stringify(["hmm", "hmm"],function(k,v){return k!==""?undefined:v;})
|
||||
do_check_eq("[null,null]", x);
|
||||
|
||||
var foo = ["hmm"];
|
||||
function censor(k, v) {
|
||||
if (v !== foo)
|
||||
|
@ -237,7 +237,10 @@ public:
|
||||
uint32 depth;
|
||||
};
|
||||
|
||||
static JSBool Str(JSContext *cx, jsid id, JSObject *holder, StringifyContext *scx, jsval *vp);
|
||||
static JSBool CallReplacerFunction(JSContext *cx, jsid id, JSObject *holder,
|
||||
StringifyContext *scx, jsval *vp);
|
||||
static JSBool Str(JSContext *cx, jsid id, JSObject *holder,
|
||||
StringifyContext *scx, jsval *vp, bool callReplacer = true);
|
||||
|
||||
static JSBool
|
||||
WriteIndent(JSContext *cx, StringifyContext *scx, uint32 limit)
|
||||
@ -342,6 +345,11 @@ JO(JSContext *cx, jsval *vp, StringifyContext *scx)
|
||||
break;
|
||||
}
|
||||
|
||||
// call this here, so we don't write out keys if the replacer function
|
||||
// wants to elide the value.
|
||||
if (!CallReplacerFunction(cx, id, obj, scx, &outputValue))
|
||||
return JS_FALSE;
|
||||
|
||||
JSType type = JS_TypeOfValue(cx, outputValue);
|
||||
|
||||
// elide undefined values and functions and XML
|
||||
@ -376,7 +384,7 @@ JO(JSContext *cx, jsval *vp, StringifyContext *scx)
|
||||
if (!ok)
|
||||
break;
|
||||
|
||||
ok = Str(cx, id, obj, scx, &outputValue);
|
||||
ok = Str(cx, id, obj, scx, &outputValue, false);
|
||||
if (!ok)
|
||||
break;
|
||||
|
||||
@ -449,7 +457,19 @@ JA(JSContext *cx, jsval *vp, StringifyContext *scx)
|
||||
}
|
||||
|
||||
static JSBool
|
||||
Str(JSContext *cx, jsid id, JSObject *holder, StringifyContext *scx, jsval *vp)
|
||||
CallReplacerFunction(JSContext *cx, jsid id, JSObject *holder, StringifyContext *scx, jsval *vp)
|
||||
{
|
||||
if (scx->replacer && js_IsCallable(scx->replacer, cx)) {
|
||||
jsval vec[2] = {ID_TO_VALUE(id), *vp};
|
||||
if (!JS_CallFunctionValue(cx, holder, OBJECT_TO_JSVAL(scx->replacer), 2, vec, vp))
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
Str(JSContext *cx, jsid id, JSObject *holder, StringifyContext *scx, jsval *vp, bool callReplacer)
|
||||
{
|
||||
JS_CHECK_RECURSION(cx, return JS_FALSE);
|
||||
|
||||
@ -459,11 +479,8 @@ Str(JSContext *cx, jsid id, JSObject *holder, StringifyContext *scx, jsval *vp)
|
||||
if (!JSVAL_IS_PRIMITIVE(*vp) && !js_TryJSON(cx, vp))
|
||||
return JS_FALSE;
|
||||
|
||||
if (scx->replacer && js_IsCallable(scx->replacer, cx)) {
|
||||
jsval vec[2] = {ID_TO_VALUE(id), *vp};
|
||||
if (!JS_CallFunctionValue(cx, holder, OBJECT_TO_JSVAL(scx->replacer), 2, vec, vp))
|
||||
return JS_FALSE;
|
||||
}
|
||||
if (callReplacer && !CallReplacerFunction(cx, id, holder, scx, vp))
|
||||
return JS_FALSE;
|
||||
|
||||
// catches string and number objects with no toJSON
|
||||
if (!JSVAL_IS_PRIMITIVE(*vp)) {
|
||||
|
@ -1227,8 +1227,7 @@ MakePlaceholder(JSParseNode *pn, JSTreeContext *tc)
|
||||
|
||||
ALE_SET_DEFN(ale, dn);
|
||||
dn->pn_defn = true;
|
||||
dn->pn_dflags |= PND_FORWARD | PND_PLACEHOLDER;
|
||||
pn->pn_dflags |= PND_FORWARD;
|
||||
dn->pn_dflags |= PND_PLACEHOLDER;
|
||||
return ale;
|
||||
}
|
||||
|
||||
@ -2025,9 +2024,6 @@ JSCompiler::setFunctionKinds(JSFunctionBox *funbox, uint16& tcflags)
|
||||
* so check forward-reference and blockid relations.
|
||||
*/
|
||||
if (lexdepKind != JSDefinition::FUNCTION) {
|
||||
if (lexdep->isForward())
|
||||
break;
|
||||
|
||||
/*
|
||||
* Watch out for code such as
|
||||
*
|
||||
@ -2298,7 +2294,7 @@ LeaveFunction(JSParseNode *fn, JSTreeContext *funtc, JSTreeContext *tc,
|
||||
*/
|
||||
*pnup = outer_dn->dn_uses;
|
||||
outer_dn->dn_uses = dn;
|
||||
outer_dn->pn_dflags |= dn->pn_dflags & ~(PND_FORWARD | PND_PLACEHOLDER);
|
||||
outer_dn->pn_dflags |= dn->pn_dflags & ~PND_PLACEHOLDER;
|
||||
dn->pn_defn = false;
|
||||
dn->pn_used = true;
|
||||
dn->pn_lexdef = outer_dn;
|
||||
@ -3257,10 +3253,11 @@ NoteLValue(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, uintN dflag = PND_
|
||||
* Save the win of PND_INITIALIZED if we can prove 'var x;' and 'x = y'
|
||||
* occur as direct kids of the same block with no forward refs to x.
|
||||
*/
|
||||
if (dn->isBlockChild() &&
|
||||
if ((dn->pn_dflags & PND_INITIALIZED) &&
|
||||
dn->isBlockChild() &&
|
||||
pn->isBlockChild() &&
|
||||
dn->pn_blockid == pn->pn_blockid &&
|
||||
!(~dn->pn_dflags & (PND_INITIALIZED | PND_FORWARD)) &&
|
||||
dn->pn_pos.end <= pn->pn_pos.begin &&
|
||||
dn->dn_uses == pn) {
|
||||
dflag = PND_INITIALIZED;
|
||||
}
|
||||
@ -4072,7 +4069,6 @@ NewBindingNode(JSTokenStream *ts, JSAtom *atom, JSTreeContext *tc, bool let = fa
|
||||
pn->pn_blockid != tc->bodyid);
|
||||
|
||||
if (pn->isPlaceholder() && pn->pn_blockid >= (let ? tc->blockid() : tc->bodyid)) {
|
||||
JS_ASSERT(pn->isForward());
|
||||
if (let)
|
||||
pn->pn_blockid = tc->blockid();
|
||||
|
||||
@ -6187,7 +6183,7 @@ CompExprTransplanter::transplant(JSParseNode *pn)
|
||||
dn2->pn_type = dn->pn_type;
|
||||
dn2->pn_pos = root->pn_pos;
|
||||
dn2->pn_defn = true;
|
||||
dn2->pn_dflags |= PND_FORWARD | PND_PLACEHOLDER;
|
||||
dn2->pn_dflags |= PND_PLACEHOLDER;
|
||||
|
||||
JSParseNode **pnup = &dn->dn_uses;
|
||||
JSParseNode *pnu;
|
||||
|
@ -412,12 +412,11 @@ struct JSParseNode {
|
||||
#define PND_ASSIGNED 0x08 /* set if ever LHS of assignment */
|
||||
#define PND_TOPLEVEL 0x10 /* function at top of body or prog */
|
||||
#define PND_BLOCKCHILD 0x20 /* use or def is direct block child */
|
||||
#define PND_FORWARD 0x40 /* forward referenced definition */
|
||||
#define PND_GVAR 0x40 /* gvar binding, can't close over
|
||||
because it could be deleted */
|
||||
#define PND_PLACEHOLDER 0x80 /* placeholder definition for lexdep */
|
||||
#define PND_FUNARG 0x100 /* downward or upward funarg usage */
|
||||
#define PND_BOUND 0x200 /* bound to a stack or global slot */
|
||||
#define PND_GVAR 0x400 /* gvar binding, can't close over
|
||||
because it could be deleted */
|
||||
|
||||
/* PN_LIST pn_xflags bits. */
|
||||
#define PNX_STRCAT 0x01 /* TOK_PLUS list has string term */
|
||||
@ -459,7 +458,6 @@ struct JSParseNode {
|
||||
bool isInitialized() const { return test(PND_INITIALIZED); }
|
||||
bool isTopLevel() const { return test(PND_TOPLEVEL); }
|
||||
bool isBlockChild() const { return test(PND_BLOCKCHILD); }
|
||||
bool isForward() const { return test(PND_FORWARD); }
|
||||
bool isPlaceholder() const { return test(PND_PLACEHOLDER); }
|
||||
|
||||
/* Defined below, see after struct JSDefinition. */
|
||||
|
@ -2401,7 +2401,7 @@ class RegExpNativeCompiler {
|
||||
|
||||
/* FIXME Use bug 463260 smart pointer when available. */
|
||||
#ifdef NJ_VERBOSE
|
||||
debug_only_v(fragment->lirbuf->names = new (&gc) LirNameMap(&gc, NULL, fragmento->labels);)
|
||||
debug_only_v(fragment->lirbuf->names = new (&gc) LirNameMap(&gc, fragmento->labels);)
|
||||
#endif
|
||||
/* FIXME Use bug 463260 smart pointer when available. */
|
||||
#ifdef NJ_VERBOSE
|
||||
|
@ -5164,7 +5164,7 @@ js_InitJIT(JSTraceMonitor *tm)
|
||||
tm->fragmento = fragmento;
|
||||
tm->lirbuf = new (&gc) LirBuffer(fragmento, NULL);
|
||||
#ifdef DEBUG
|
||||
tm->lirbuf->names = new (&gc) LirNameMap(&gc, NULL, tm->fragmento->labels);
|
||||
tm->lirbuf->names = new (&gc) LirNameMap(&gc, tm->fragmento->labels);
|
||||
#endif
|
||||
for (size_t i = 0; i < MONITOR_N_GLOBAL_STATES; ++i) {
|
||||
tm->globalStates[i].globalShape = -1;
|
||||
@ -6500,6 +6500,13 @@ TraceRecorder::test_property_cache(JSObject* obj, LIns* obj_ins, JSObject*& obj2
|
||||
return JSRS_CONTINUE;
|
||||
}
|
||||
|
||||
void
|
||||
TraceRecorder::stobj_set_fslot(LIns *obj_ins, unsigned slot, LIns* v_ins, const char *name)
|
||||
{
|
||||
addName(lir->insStorei(v_ins, obj_ins, offsetof(JSObject, fslots) + slot * sizeof(jsval)),
|
||||
name);
|
||||
}
|
||||
|
||||
void
|
||||
TraceRecorder::stobj_set_dslot(LIns *obj_ins, unsigned slot, LIns*& dslots_ins, LIns* v_ins,
|
||||
const char *name)
|
||||
@ -6513,9 +6520,7 @@ void
|
||||
TraceRecorder::stobj_set_slot(LIns* obj_ins, unsigned slot, LIns*& dslots_ins, LIns* v_ins)
|
||||
{
|
||||
if (slot < JS_INITIAL_NSLOTS) {
|
||||
addName(lir->insStorei(v_ins, obj_ins,
|
||||
offsetof(JSObject, fslots) + slot * sizeof(jsval)),
|
||||
"set_slot(fslots)");
|
||||
stobj_set_fslot(obj_ins, slot, v_ins, "set_slot(fslots)");
|
||||
} else {
|
||||
stobj_set_dslot(obj_ins, slot - JS_INITIAL_NSLOTS, dslots_ins, v_ins,
|
||||
"set_slot(dslots)");
|
||||
@ -7397,6 +7402,9 @@ TraceRecorder::newArray(JSObject* ctor, uint32 argc, jsval* argv, jsval* rval)
|
||||
box_jsval(argv[i], elt_ins);
|
||||
stobj_set_dslot(arr_ins, i, dslots_ins, elt_ins, "set_array_elt");
|
||||
}
|
||||
|
||||
if (argc > 0)
|
||||
stobj_set_fslot(arr_ins, JSSLOT_ARRAY_COUNT, INS_CONST(argc), "set_array_count");
|
||||
}
|
||||
|
||||
set(rval, arr_ins);
|
||||
@ -8428,7 +8436,7 @@ JS_REQUIRES_STACK JSRecordingStatus
|
||||
TraceRecorder::record_JSOP_GETDSLOT()
|
||||
{
|
||||
JSObject* callee = cx->fp->callee;
|
||||
LIns* callee_ins = (callDepth == 0) ? get(&cx->fp->argv[-2]) : INS_CONSTPTR(callee);
|
||||
LIns* callee_ins = get(&cx->fp->argv[-2]);
|
||||
|
||||
unsigned index = GET_UINT16(cx->fp->regs->pc);
|
||||
LIns* dslots_ins = NULL;
|
||||
@ -9695,7 +9703,7 @@ TraceRecorder::record_JSOP_LAMBDA_FC()
|
||||
JS_REQUIRES_STACK JSRecordingStatus
|
||||
TraceRecorder::record_JSOP_CALLEE()
|
||||
{
|
||||
stack(0, INS_CONSTPTR(cx->fp->callee));
|
||||
stack(0, get(&cx->fp->argv[-2]));
|
||||
return JSRS_CONTINUE;
|
||||
}
|
||||
|
||||
@ -10636,9 +10644,8 @@ TraceRecorder::record_JSOP_NEWARRAY()
|
||||
stobj_set_dslot(v_ins, i, dslots_ins, elt_ins, "set_array_elt");
|
||||
}
|
||||
|
||||
LIns* dummy = NULL;
|
||||
if (count > 0)
|
||||
stobj_set_slot(v_ins, JSSLOT_ARRAY_COUNT, dummy, INS_CONST(count));
|
||||
stobj_set_fslot(v_ins, JSSLOT_ARRAY_COUNT, INS_CONST(count), "set_array_count");
|
||||
|
||||
stack(-int(len), v_ins);
|
||||
return JSRS_CONTINUE;
|
||||
|
@ -555,10 +555,12 @@ class TraceRecorder : public avmplus::GCObject {
|
||||
nanojit::LIns*& ops_ins, size_t op_offset = 0);
|
||||
JS_REQUIRES_STACK JSRecordingStatus test_property_cache(JSObject* obj, nanojit::LIns* obj_ins,
|
||||
JSObject*& obj2, jsuword& pcval);
|
||||
void stobj_set_slot(nanojit::LIns* obj_ins, unsigned slot, nanojit::LIns*& dslots_ins,
|
||||
nanojit::LIns* v_ins);
|
||||
void stobj_set_fslot(nanojit::LIns *obj_ins, unsigned slot,
|
||||
nanojit::LIns* v_ins, const char *name);
|
||||
void stobj_set_dslot(nanojit::LIns *obj_ins, unsigned slot, nanojit::LIns*& dslots_ins,
|
||||
nanojit::LIns* v_ins, const char *name);
|
||||
void stobj_set_slot(nanojit::LIns* obj_ins, unsigned slot, nanojit::LIns*& dslots_ins,
|
||||
nanojit::LIns* v_ins);
|
||||
|
||||
nanojit::LIns* stobj_get_fslot(nanojit::LIns* obj_ins, unsigned slot);
|
||||
nanojit::LIns* stobj_get_dslot(nanojit::LIns* obj_ins, unsigned index,
|
||||
|
@ -68,10 +68,10 @@ namespace nanojit
|
||||
op == LIR_loop ||
|
||||
op == LIR_label ||
|
||||
op == LIR_live ||
|
||||
isRet(op)) {
|
||||
ins->isRet()) {
|
||||
return false;
|
||||
}
|
||||
return ins->resv() == 0;
|
||||
return !ins->resv()->used;
|
||||
}
|
||||
|
||||
public:
|
||||
@ -126,7 +126,7 @@ namespace nanojit
|
||||
if (i->oprnd1())
|
||||
block.add(i->oprnd1());
|
||||
}
|
||||
else if (isRet(i->opcode()) || i->isBranch()) {
|
||||
else if (i->isRet() || i->isBranch()) {
|
||||
flush_add(i);
|
||||
}
|
||||
else {
|
||||
@ -220,6 +220,7 @@ namespace nanojit
|
||||
NanoAssert(vic != NULL);
|
||||
|
||||
Reservation* resv = getresv(vic);
|
||||
NanoAssert(resv);
|
||||
|
||||
// restore vic
|
||||
Register r = resv->reg;
|
||||
@ -230,17 +231,6 @@ namespace nanojit
|
||||
return r;
|
||||
}
|
||||
|
||||
void Assembler::reserveReset()
|
||||
{
|
||||
_resvTable[0].arIndex = 0;
|
||||
int i;
|
||||
for(i=1; i<NJ_MAX_STACK_ENTRY; i++) {
|
||||
_resvTable[i].arIndex = i-1;
|
||||
_resvTable[i].used = 0;
|
||||
}
|
||||
_resvFree= i-1;
|
||||
}
|
||||
|
||||
/**
|
||||
* these instructions don't have to be saved & reloaded to spill,
|
||||
* they can just be recalculated w/out any inputs.
|
||||
@ -249,41 +239,10 @@ namespace nanojit
|
||||
return i->isconst() || i->isconstq() || i->isop(LIR_alloc);
|
||||
}
|
||||
|
||||
Reservation* Assembler::reserveAlloc(LInsp i)
|
||||
{
|
||||
uint32_t item = _resvFree;
|
||||
/* If there are no free reservations, mark the table as full and re-use an index.
|
||||
* This will clobber that reservation, but the error will be caught as soon as
|
||||
* the current LIR instruction returns back to gen().
|
||||
*/
|
||||
if (!item) {
|
||||
setError(ResvFull);
|
||||
item = 1;
|
||||
}
|
||||
Reservation *r = &_resvTable[item];
|
||||
_resvFree = r->arIndex;
|
||||
r->reg = UnknownReg;
|
||||
r->arIndex = 0;
|
||||
r->used = 1;
|
||||
i->setresv(item);
|
||||
return r;
|
||||
}
|
||||
|
||||
void Assembler::reserveFree(LInsp i)
|
||||
{
|
||||
Reservation *rs = getresv(i);
|
||||
NanoAssert(rs == &_resvTable[i->resv()]);
|
||||
rs->arIndex = _resvFree;
|
||||
rs->used = 0;
|
||||
_resvFree = i->resv();
|
||||
i->setresv(0);
|
||||
}
|
||||
|
||||
void Assembler::internalReset()
|
||||
{
|
||||
// readies for a brand spanking new code generation pass.
|
||||
registerResetAll();
|
||||
reserveReset();
|
||||
arReset();
|
||||
pending_lives.clear();
|
||||
}
|
||||
@ -396,9 +355,8 @@ namespace nanojit
|
||||
|
||||
void Assembler::pageValidate()
|
||||
{
|
||||
if (error()) return;
|
||||
// _nIns and _nExitIns need to be at least on
|
||||
// one of these pages
|
||||
NanoAssert(!error());
|
||||
// _nIns and _nExitIns need to be at least on one of these pages
|
||||
NanoAssertMsg( onPage(_nIns)&& onPage(_nExitIns,true), "Native instruction pointer overstep paging bounds; check overrideProtect for last instruction");
|
||||
}
|
||||
#endif
|
||||
@ -407,7 +365,7 @@ namespace nanojit
|
||||
|
||||
void Assembler::resourceConsistencyCheck()
|
||||
{
|
||||
if (error()) return;
|
||||
NanoAssert(!error());
|
||||
|
||||
#ifdef NANOJIT_IA32
|
||||
NanoAssert((_allocator.active[FST0] && _fpuStkDepth == -1) ||
|
||||
@ -426,8 +384,6 @@ namespace nanojit
|
||||
continue;
|
||||
Reservation *r = getresv(ins);
|
||||
NanoAssert(r != 0);
|
||||
int32_t idx = r - _resvTable;
|
||||
NanoAssertMsg(idx, "MUST have a resource for the instruction for it to have a stack location assigned to it");
|
||||
if (r->arIndex) {
|
||||
if (ins->isop(LIR_alloc)) {
|
||||
int j=i+1;
|
||||
@ -449,21 +405,6 @@ namespace nanojit
|
||||
}
|
||||
|
||||
registerConsistencyCheck();
|
||||
|
||||
// check resv table
|
||||
int32_t inuseCount = 0;
|
||||
int32_t notInuseCount = 0;
|
||||
for(uint32_t i=1; i < sizeof(_resvTable)/sizeof(_resvTable[0]); i++) {
|
||||
_resvTable[i].used ? inuseCount++ : notInuseCount++;
|
||||
}
|
||||
|
||||
int32_t freeCount = 0;
|
||||
uint32_t free = _resvFree;
|
||||
while(free) {
|
||||
free = _resvTable[free].arIndex;
|
||||
freeCount++;
|
||||
}
|
||||
NanoAssert( ( freeCount==notInuseCount && inuseCount+notInuseCount==(NJ_MAX_STACK_ENTRY-1) ) );
|
||||
}
|
||||
|
||||
void Assembler::registerConsistencyCheck()
|
||||
@ -486,9 +427,6 @@ namespace nanojit
|
||||
// @todo we should be able to check across RegAlloc's somehow (to include savedGP...)
|
||||
Reservation *v = getresv(ins);
|
||||
NanoAssert(v != 0);
|
||||
int32_t idx = v - _resvTable;
|
||||
NanoAssert(idx >= 0 && idx < NJ_MAX_STACK_ENTRY);
|
||||
NanoAssertMsg(idx, "MUST have a resource for the instruction for it to have a register assigned to it");
|
||||
NanoAssertMsg( regs->getActive(v->reg)==ins, "Register record mismatch");
|
||||
}
|
||||
}
|
||||
@ -570,7 +508,7 @@ namespace nanojit
|
||||
|
||||
// if we didn't have a reservation, allocate one now
|
||||
if (!resv)
|
||||
resv = reserveAlloc(i);
|
||||
resv = i->initResv();
|
||||
|
||||
r = resv->reg;
|
||||
|
||||
@ -619,7 +557,7 @@ namespace nanojit
|
||||
{
|
||||
Reservation* resv = getresv(i);
|
||||
if (!resv)
|
||||
resv = reserveAlloc(i);
|
||||
resv = i->initResv();
|
||||
if (!resv->arIndex) {
|
||||
resv->arIndex = arReserve(i);
|
||||
NanoAssert(resv->arIndex <= _activation.highwatermark);
|
||||
@ -658,7 +596,7 @@ namespace nanojit
|
||||
}
|
||||
if (index)
|
||||
arFree(index); // free any stack stack space associated with entry
|
||||
reserveFree(i); // clear fields of entry and add it to free list
|
||||
i->clearResv();
|
||||
}
|
||||
|
||||
void Assembler::evict(Register r)
|
||||
@ -1007,7 +945,7 @@ namespace nanojit
|
||||
|
||||
if (!resv->arIndex && resv->reg == UnknownReg)
|
||||
{
|
||||
reserveFree(i);
|
||||
i->clearResv();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1856,10 +1794,27 @@ namespace nanojit
|
||||
debug_only(saved.used = 0); // marker that we are no longer in exit path
|
||||
}
|
||||
|
||||
void Assembler::setCallTable(const CallInfo* functions)
|
||||
{
|
||||
_functions = functions;
|
||||
}
|
||||
// scan table for instruction with the lowest priority, meaning it is used
|
||||
// furthest in the future.
|
||||
LIns* Assembler::findVictim(RegAlloc ®s, RegisterMask allow)
|
||||
{
|
||||
NanoAssert(allow != 0);
|
||||
LIns *i, *a=0;
|
||||
int allow_pri = 0x7fffffff;
|
||||
for (Register r=FirstReg; r <= LastReg; r = nextreg(r))
|
||||
{
|
||||
if ((allow & rmask(r)) && (i = regs.getActive(r)) != 0)
|
||||
{
|
||||
int pri = canRemat(i) ? 0 : regs.getPriority(r);
|
||||
if (!a || pri < allow_pri) {
|
||||
a = i;
|
||||
allow_pri = pri;
|
||||
}
|
||||
}
|
||||
}
|
||||
NanoAssert(a != 0);
|
||||
return a;
|
||||
}
|
||||
|
||||
#ifdef NJ_VERBOSE
|
||||
char Assembler::outline[8192];
|
||||
|
@ -46,10 +46,6 @@ namespace nanojit
|
||||
/**
|
||||
* Some notes on this Assembler (Emitter).
|
||||
*
|
||||
* LIR_call is a generic call operation that is encoded using form [2]. The 24bit
|
||||
* integer is used as an index into a function look-up table that contains information
|
||||
* about the target that is to be called; including address, # parameters, etc.
|
||||
*
|
||||
* The class RegAlloc is essentially the register allocator from MIR
|
||||
*
|
||||
* The Assembler class parses the LIR instructions starting at any point and converts
|
||||
@ -67,16 +63,6 @@ namespace nanojit
|
||||
|
||||
#define STACK_GRANULARITY sizeof(void *)
|
||||
|
||||
/**
|
||||
* The Assembler is only concerned with transforming LIR to native instructions
|
||||
*/
|
||||
struct Reservation
|
||||
{
|
||||
uint32_t arIndex:16; /* index into stack frame. displ is -4*arIndex */
|
||||
Register reg:15; /* register UnkownReg implies not in register */
|
||||
uint32_t used:1;
|
||||
};
|
||||
|
||||
struct AR
|
||||
{
|
||||
LIns* entry[ NJ_MAX_STACK_ENTRY ]; /* maps to 4B contiguous locations relative to the frame pointer */
|
||||
@ -118,7 +104,6 @@ namespace nanojit
|
||||
None = 0
|
||||
,OutOMem
|
||||
,StackFull
|
||||
,ResvFull
|
||||
,RegionFull
|
||||
,MaxLength
|
||||
,MaxExit
|
||||
@ -162,7 +147,6 @@ namespace nanojit
|
||||
*/
|
||||
class Assembler MMGC_SUBCLASS_DECL
|
||||
{
|
||||
friend class DeadCodeFilter;
|
||||
friend class VerboseBlockReader;
|
||||
public:
|
||||
#ifdef NJ_VERBOSE
|
||||
@ -248,13 +232,9 @@ namespace nanojit
|
||||
void internalReset();
|
||||
bool canRemat(LIns*);
|
||||
|
||||
Reservation* reserveAlloc(LInsp i);
|
||||
void reserveFree(LInsp i);
|
||||
void reserveReset();
|
||||
|
||||
Reservation* getresv(LIns *x) {
|
||||
uint32_t resv_index = x->resv();
|
||||
return resv_index ? &_resvTable[resv_index] : 0;
|
||||
Reservation* r = x->resv();
|
||||
return r->used ? r : 0;
|
||||
}
|
||||
|
||||
DWB(Fragmento*) _frago;
|
||||
@ -262,8 +242,6 @@ namespace nanojit
|
||||
DWB(Fragment*) _thisfrag;
|
||||
RegAllocMap* _branchStateMap;
|
||||
|
||||
const CallInfo *_functions;
|
||||
|
||||
NIns* _nIns; // current native instruction
|
||||
NIns* _nExitIns; // current instruction in exit fragment page
|
||||
NIns* _startingIns; // starting location of code compilation for error handling
|
||||
@ -277,8 +255,6 @@ namespace nanojit
|
||||
|
||||
LabelStateMap _labels;
|
||||
NInsMap _patches;
|
||||
Reservation _resvTable[ NJ_MAX_STACK_ENTRY ]; // table where we house stack and register information
|
||||
uint32_t _resvFree;
|
||||
bool _inExit, vpad2[3];
|
||||
InsList pending_lives;
|
||||
|
||||
@ -341,7 +317,6 @@ namespace nanojit
|
||||
Register nRegisterAllocFromSet(int32_t set);
|
||||
void nRegisterResetAll(RegAlloc& a);
|
||||
void nMarkExecute(Page* page, int flags);
|
||||
void nFrameRestore(RegisterMask rmask);
|
||||
NIns* nPatchBranch(NIns* branch, NIns* location);
|
||||
void nFragExit(LIns* guard);
|
||||
|
||||
|
@ -226,13 +226,6 @@ namespace nanojit
|
||||
NJ_DELETE(f);
|
||||
}
|
||||
|
||||
void Fragmento::clearFrag(const void* ip)
|
||||
{
|
||||
if (_frags.containsKey(ip)) {
|
||||
clearFragment(_frags.remove(ip));
|
||||
}
|
||||
}
|
||||
|
||||
void Fragmento::clearFrags()
|
||||
{
|
||||
// reclaim any dangling native pages
|
||||
@ -295,29 +288,6 @@ namespace nanojit
|
||||
}
|
||||
#endif
|
||||
|
||||
Fragment *Fragmento::getMerge(GuardRecord *lr, const void* ip)
|
||||
{
|
||||
Fragment *anchor = lr->exit->from->anchor;
|
||||
for (Fragment *f = anchor->branches; f != 0; f = f->nextbranch) {
|
||||
if (f->kind == MergeTrace && f->ip == ip /*&& f->calldepth == lr->calldepth*/) {
|
||||
// found existing shared branch on anchor
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
Fragment *f = newBranch(anchor, ip);
|
||||
f->root = f;
|
||||
f->kind = MergeTrace;
|
||||
verbose_only(
|
||||
int mergeid = 1;
|
||||
for (Fragment *g = anchor->branches; g != 0; g = g->nextbranch)
|
||||
if (g->kind == MergeTrace)
|
||||
mergeid++;
|
||||
addLabel(f, "M", mergeid);
|
||||
)
|
||||
return f;
|
||||
}
|
||||
|
||||
Fragment *Fragmento::createBranch(SideExit* exit, const void* ip)
|
||||
{
|
||||
Fragment *f = newBranch(exit->from, ip);
|
||||
@ -561,7 +531,6 @@ namespace nanojit
|
||||
loopEntry(NULL),
|
||||
vmprivate(NULL),
|
||||
_code(NULL),
|
||||
_links(NULL),
|
||||
_hits(0),
|
||||
_pages(NULL)
|
||||
{
|
||||
@ -573,12 +542,6 @@ namespace nanojit
|
||||
NanoAssert(_pages == 0);
|
||||
}
|
||||
|
||||
void Fragment::resetHits()
|
||||
{
|
||||
blacklistLevel >>= 1;
|
||||
_hits = 0;
|
||||
}
|
||||
|
||||
void Fragment::blacklist()
|
||||
{
|
||||
blacklistLevel++;
|
||||
|
@ -107,9 +107,7 @@ namespace nanojit
|
||||
// that this does not destroy any resources shared with other
|
||||
// fragments (such as a LirBuffer or this fragment itself as a
|
||||
// jump target).
|
||||
void clearFrag(const void* ip);
|
||||
void clearFrags(); // clear all fragments from the cache
|
||||
Fragment* getMerge(GuardRecord *lr, const void* ip);
|
||||
Fragment* createBranch(SideExit *exit, const void* ip);
|
||||
Fragment* newFrag(const void* ip);
|
||||
Fragment* newBranch(Fragment *from, const void* ip);
|
||||
@ -180,12 +178,9 @@ namespace nanojit
|
||||
|
||||
NIns* code() { return _code; }
|
||||
void setCode(NIns* codee, Page* pages) { _code = codee; _pages = pages; }
|
||||
GuardRecord* links() { return _links; }
|
||||
int32_t& hits() { return _hits; }
|
||||
void resetHits();
|
||||
void blacklist();
|
||||
bool isBlacklisted() { return _hits < 0; }
|
||||
debug_only( bool hasOnlyTreeLinks(); )
|
||||
void releaseLirBuffer();
|
||||
void releaseCode(Fragmento* frago);
|
||||
void releaseTreeMem(Fragmento* frago);
|
||||
|
@ -366,16 +366,8 @@ namespace nanojit
|
||||
return cur;
|
||||
}
|
||||
|
||||
bool FASTCALL isCmp(LOpcode c) {
|
||||
return (c >= LIR_eq && c <= LIR_uge) || (c >= LIR_feq && c <= LIR_fge);
|
||||
}
|
||||
|
||||
bool FASTCALL isCond(LOpcode c) {
|
||||
return (c == LIR_ov) || (c == LIR_cs) || isCmp(c);
|
||||
}
|
||||
|
||||
bool FASTCALL isFloat(LOpcode c) {
|
||||
switch (c) {
|
||||
bool LIns::isFloat() const {
|
||||
switch (firstWord.code) {
|
||||
default:
|
||||
return false;
|
||||
case LIR_fadd:
|
||||
@ -392,20 +384,22 @@ namespace nanojit
|
||||
}
|
||||
|
||||
bool LIns::isCmp() const {
|
||||
return nanojit::isCmp(u.code);
|
||||
LOpcode op = firstWord.code;
|
||||
return (op >= LIR_eq && op <= LIR_uge) || (op >= LIR_feq && op <= LIR_fge);
|
||||
}
|
||||
|
||||
bool LIns::isCond() const {
|
||||
return nanojit::isCond(u.code);
|
||||
LOpcode op = firstWord.code;
|
||||
return (op == LIR_ov) || (op == LIR_cs) || isCmp();
|
||||
}
|
||||
|
||||
bool LIns::isQuad() const {
|
||||
#ifdef AVMPLUS_64BIT
|
||||
// callh in 64bit cpu's means a call that returns an int64 in a single register
|
||||
return (u.code & LIR64) != 0 || u.code == LIR_callh;
|
||||
return (firstWord.code & LIR64) != 0 || firstWord.code == LIR_callh;
|
||||
#else
|
||||
// callh in 32bit cpu's means the 32bit MSW of an int64 result in 2 registers
|
||||
return (u.code & LIR64) != 0;
|
||||
return (firstWord.code & LIR64) != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -416,7 +410,7 @@ namespace nanojit
|
||||
|
||||
bool LIns::isconstq() const
|
||||
{
|
||||
return isop(LIR_quad);
|
||||
return firstWord.code == LIR_quad;
|
||||
}
|
||||
|
||||
bool LIns::isconstp() const
|
||||
@ -428,21 +422,29 @@ namespace nanojit
|
||||
#endif
|
||||
}
|
||||
|
||||
bool FASTCALL isCse(LOpcode op) {
|
||||
op = LOpcode(op & ~LIR64);
|
||||
return op >= LIR_ldcs && op <= LIR_uge;
|
||||
}
|
||||
|
||||
bool LIns::isCse(const CallInfo *functions) const
|
||||
{
|
||||
return nanojit::isCse(u.code) || (isCall() && callInfo()->_cse);
|
||||
return nanojit::isCseOpcode(firstWord.code) || (isCall() && callInfo()->_cse);
|
||||
}
|
||||
|
||||
void LIns::initOpcodeAndClearResv(LOpcode op)
|
||||
{
|
||||
NanoAssert(4*sizeof(void*) == sizeof(LIns));
|
||||
u.code = op;
|
||||
u.resv = 0; // have to zero this; the Assembler relies on it
|
||||
firstWord.code = op;
|
||||
firstWord.used = 0;
|
||||
}
|
||||
|
||||
Reservation* LIns::initResv()
|
||||
{
|
||||
firstWord.reg = UnknownReg;
|
||||
firstWord.arIndex = 0;
|
||||
firstWord.used = 1;
|
||||
return &firstWord;
|
||||
}
|
||||
|
||||
void LIns::clearResv()
|
||||
{
|
||||
firstWord.used = 0;
|
||||
}
|
||||
|
||||
void LIns::setTarget(LInsp label)
|
||||
@ -466,37 +468,18 @@ namespace nanojit
|
||||
|
||||
uint64_t LIns::imm64() const
|
||||
{
|
||||
#ifdef AVMPLUS_UNALIGNED_ACCESS
|
||||
return *(const uint64_t*)i64.imm32;
|
||||
#else
|
||||
union { uint64_t tmp; int32_t dst[2]; } u;
|
||||
#ifdef AVMPLUS_BIG_ENDIAN
|
||||
u.dst[0] = i64.imm64_1;
|
||||
u.dst[1] = i64.imm64_0;
|
||||
#else
|
||||
u.dst[0] = i64.imm64_0;
|
||||
u.dst[1] = i64.imm64_1;
|
||||
#endif
|
||||
return u.tmp;
|
||||
#endif
|
||||
NanoAssert(isconstq());
|
||||
return (uint64_t(i64.imm64_1) << 32) | uint64_t(i64.imm64_0);
|
||||
}
|
||||
|
||||
double LIns::imm64f() const
|
||||
{
|
||||
NanoAssert(isconstq());
|
||||
#ifdef AVMPLUS_UNALIGNED_ACCESS
|
||||
return *(const double*)i64.imm32;
|
||||
#else
|
||||
union { uint32_t dst[2]; double tmpf; } u;
|
||||
#ifdef AVMPLUS_BIG_ENDIAN
|
||||
u.dst[0] = i64.imm64_1;
|
||||
u.dst[1] = i64.imm64_0;
|
||||
#else
|
||||
u.dst[0] = i64.imm64_0;
|
||||
u.dst[1] = i64.imm64_1;
|
||||
#endif
|
||||
return u.tmpf;
|
||||
#endif
|
||||
union {
|
||||
double f;
|
||||
uint64_t q;
|
||||
} u;
|
||||
u.q = imm64();
|
||||
return u.f;
|
||||
}
|
||||
|
||||
inline uint32_t argSlots(uint32_t argc) {
|
||||
@ -548,13 +531,13 @@ namespace nanojit
|
||||
{
|
||||
if (v == LIR_qlo) {
|
||||
if (i->isconstq())
|
||||
return insImm(int32_t(i->imm64()));
|
||||
return insImm(i->imm64_0());
|
||||
if (i->isop(LIR_qjoin))
|
||||
return i->oprnd1();
|
||||
}
|
||||
else if (v == LIR_qhi) {
|
||||
if (i->isconstq())
|
||||
return insImm(int32_t(i->imm64()>>32));
|
||||
return insImm(i->imm64_1());
|
||||
if (i->isop(LIR_qjoin))
|
||||
return i->oprnd2();
|
||||
}
|
||||
@ -924,7 +907,7 @@ namespace nanojit
|
||||
// N+4 arg operand #2 ----------------------
|
||||
// N+8 arg operand #1 ----------------------
|
||||
// N+12 arg operand #0 ---------------------- ]
|
||||
// N+16 [ code=LIR_call | resv | (pad16) ------ K+1
|
||||
// N+16 [ arIndex | reg | used | code=LIR_call K+1
|
||||
// imm8a | (pad24) ---------------------
|
||||
// imm8b | (pad24) ---------------------
|
||||
// ci ---------------------------------- ]
|
||||
@ -1464,7 +1447,7 @@ namespace nanojit
|
||||
NanoAssert(s < livebuf+sizeof(livebuf));
|
||||
}
|
||||
printf("%-60s %s\n", livebuf, names->formatIns(e->i));
|
||||
if (e->i->isGuard() || e->i->isBranch() || isRet(e->i->opcode())) {
|
||||
if (e->i->isGuard() || e->i->isBranch() || e->i->isRet()) {
|
||||
printf("\n");
|
||||
newblock = true;
|
||||
}
|
||||
@ -1535,10 +1518,10 @@ namespace nanojit
|
||||
#if defined NANOJIT_64BIT
|
||||
sprintf(buf, "#0x%lx", (nj_printf_ld)ref->imm64());
|
||||
#else
|
||||
formatImm(uint32_t(ref->imm64()>>32), buf);
|
||||
formatImm(ref->imm64_1(), buf);
|
||||
buf += strlen(buf);
|
||||
*buf++ = ':';
|
||||
formatImm(uint32_t(ref->imm64()), buf);
|
||||
formatImm(ref->imm64_0(), buf);
|
||||
#endif
|
||||
}
|
||||
else if (ref->isconst()) {
|
||||
@ -1791,7 +1774,7 @@ namespace nanojit
|
||||
|
||||
LIns* CseFilter::ins1(LOpcode v, LInsp a)
|
||||
{
|
||||
if (isCse(v)) {
|
||||
if (isCseOpcode(v)) {
|
||||
NanoAssert(operandCount[v]==1);
|
||||
uint32_t k;
|
||||
LInsp found = exprs.find1(v, a, k);
|
||||
@ -1804,7 +1787,7 @@ namespace nanojit
|
||||
|
||||
LIns* CseFilter::ins2(LOpcode v, LInsp a, LInsp b)
|
||||
{
|
||||
if (isCse(v)) {
|
||||
if (isCseOpcode(v)) {
|
||||
NanoAssert(operandCount[v]==2);
|
||||
uint32_t k;
|
||||
LInsp found = exprs.find2(v, a, b, k);
|
||||
@ -1817,7 +1800,7 @@ namespace nanojit
|
||||
|
||||
LIns* CseFilter::insLoad(LOpcode v, LInsp base, LInsp disp)
|
||||
{
|
||||
if (isCse(v)) {
|
||||
if (isCseOpcode(v)) {
|
||||
NanoAssert(operandCount[v]==2);
|
||||
uint32_t k;
|
||||
LInsp found = exprs.find2(v, base, disp, k);
|
||||
@ -1830,7 +1813,7 @@ namespace nanojit
|
||||
|
||||
LInsp CseFilter::insGuard(LOpcode v, LInsp c, LInsp x)
|
||||
{
|
||||
if (isCse(v)) {
|
||||
if (isCseOpcode(v)) {
|
||||
// conditional guard
|
||||
NanoAssert(operandCount[v]==1);
|
||||
uint32_t k;
|
||||
|
@ -146,26 +146,12 @@ namespace nanojit
|
||||
uint32_t index;
|
||||
};
|
||||
|
||||
inline bool isGuard(LOpcode op) {
|
||||
return op == LIR_x || op == LIR_xf || op == LIR_xt || op == LIR_loop || op == LIR_xbarrier || op == LIR_xtbl;
|
||||
}
|
||||
|
||||
inline bool isCall(LOpcode op) {
|
||||
inline bool isCseOpcode(LOpcode op) {
|
||||
op = LOpcode(op & ~LIR64);
|
||||
return op == LIR_call || op == LIR_calli;
|
||||
return op >= LIR_ldcs && op <= LIR_uge;
|
||||
}
|
||||
|
||||
inline bool isStore(LOpcode op) {
|
||||
op = LOpcode(op & ~LIR64);
|
||||
return op == LIR_sti;
|
||||
}
|
||||
|
||||
inline bool isConst(LOpcode op) {
|
||||
return op == LIR_int;
|
||||
}
|
||||
|
||||
inline bool isLoad(LOpcode op) {
|
||||
return op == LIR_ldq || op == LIR_ld || op == LIR_ldc || op == LIR_ldqc || op == LIR_ldcs;
|
||||
inline bool isRetOpcode(LOpcode op) {
|
||||
return (op & ~LIR64) == LIR_ret;
|
||||
}
|
||||
|
||||
// Sun Studio requires explicitly declaring signed int bit-field
|
||||
@ -175,56 +161,53 @@ namespace nanojit
|
||||
#define _sign_int int32_t
|
||||
#endif
|
||||
|
||||
// Low-level Instruction. 4 words per instruction.
|
||||
// had to lay it our as a union with duplicate code fields since msvc couldn't figure out how to compact it otherwise.
|
||||
// The opcode is not logically part of the Reservation, but we include it
|
||||
// in this struct to ensure that opcode plus the Reservation fits in a
|
||||
// single word. Yuk.
|
||||
struct Reservation
|
||||
{
|
||||
uint32_t arIndex:16; // index into stack frame. displ is -4*arIndex
|
||||
Register reg:7; // register UnknownReg implies not in register
|
||||
uint32_t used:1; // when set, the reservation is active
|
||||
LOpcode code:8;
|
||||
};
|
||||
|
||||
// Low-level Instruction. 4 words per instruction -- it's important this
|
||||
// doesn't change unintentionally, so it is checked in LIR.cpp by an
|
||||
// assertion in initOpcodeAndClearResv().
|
||||
// The first word is the same for all LIns kinds; the last three differ.
|
||||
class LIns
|
||||
{
|
||||
#define LI_BITS_PER_WORD (8 * sizeof(void*))
|
||||
|
||||
friend class LirBufWriter;
|
||||
|
||||
// 2-operand form. Also used for LIR_skip (for which oprnd_1 is the target).
|
||||
// 2-operand form. Used for most LIns kinds, including LIR_skip (for
|
||||
// which oprnd_1 is the target).
|
||||
struct u_type
|
||||
{
|
||||
LOpcode code:8;
|
||||
uintptr_t resv:8; // clobbered during assembly
|
||||
uintptr_t unused1:(LI_BITS_PER_WORD - 16);
|
||||
|
||||
// Nb: oprnd_1 and oprnd_2 layout must match that in sti_type.
|
||||
// Nb: oprnd_1 and oprnd_2 layout must match that in sti_type
|
||||
// because oprnd1() and oprnd2() are used for both.
|
||||
LIns* oprnd_1;
|
||||
|
||||
LIns* oprnd_2;
|
||||
|
||||
uintptr_t unused4;
|
||||
};
|
||||
|
||||
// Used for LIR_sti and LIR_stqi.
|
||||
struct sti_type
|
||||
{
|
||||
LOpcode code:8;
|
||||
uintptr_t resv:8; // clobbered during assembly
|
||||
uintptr_t :(LI_BITS_PER_WORD - 16);
|
||||
|
||||
// Nb: oprnd_1 and oprnd_2 layout must match that in u_type.
|
||||
// Nb: oprnd_1 and oprnd_2 layout must match that in u_type
|
||||
// because oprnd1() and oprnd2() are used for both.
|
||||
LIns* oprnd_1;
|
||||
|
||||
LIns* oprnd_2;
|
||||
|
||||
int32_t disp;
|
||||
uintptr_t :(LI_BITS_PER_WORD - 32);
|
||||
};
|
||||
|
||||
// Used for LIR_call and LIR_param.
|
||||
struct c_type
|
||||
{
|
||||
LOpcode code:8;
|
||||
uintptr_t resv:8; // clobbered during assembly
|
||||
uintptr_t :(LI_BITS_PER_WORD - 16);
|
||||
|
||||
uintptr_t imm8a:8; // call: 0 (not used); param: arg
|
||||
uintptr_t :(LI_BITS_PER_WORD - 8);
|
||||
|
||||
uintptr_t imm8b:8; // call: argc; param: kind
|
||||
uintptr_t :(LI_BITS_PER_WORD - 8);
|
||||
|
||||
const CallInfo* ci; // call: callInfo; param: NULL (not used)
|
||||
};
|
||||
@ -232,37 +215,23 @@ namespace nanojit
|
||||
// Used for LIR_int.
|
||||
struct i_type
|
||||
{
|
||||
LOpcode code:8;
|
||||
uintptr_t resv:8; // clobbered during assembly
|
||||
uintptr_t :(LI_BITS_PER_WORD - 16);
|
||||
|
||||
int32_t imm32;
|
||||
uintptr_t :(LI_BITS_PER_WORD - 32);
|
||||
|
||||
uintptr_t unused3;
|
||||
|
||||
uintptr_t unused4;
|
||||
};
|
||||
|
||||
// Used for LIR_quad.
|
||||
struct i64_type
|
||||
{
|
||||
LOpcode code:8;
|
||||
uintptr_t resv:8; // clobbered during assembly
|
||||
uintptr_t unused1:(LI_BITS_PER_WORD - 16);
|
||||
|
||||
int32_t imm64_0;
|
||||
uintptr_t :(LI_BITS_PER_WORD - 32);
|
||||
|
||||
int32_t imm64_1;
|
||||
uintptr_t :(LI_BITS_PER_WORD - 32);
|
||||
|
||||
uintptr_t unused4;
|
||||
};
|
||||
|
||||
#undef _sign_int
|
||||
|
||||
// Various forms of the instruction.
|
||||
// 1st word: fields shared by all LIns kinds. The reservation fields
|
||||
// are read/written during assembly.
|
||||
Reservation firstWord;
|
||||
|
||||
// 2nd, 3rd and 4th words: differ depending on the LIns kind.
|
||||
union
|
||||
{
|
||||
u_type u;
|
||||
@ -276,7 +245,7 @@ namespace nanojit
|
||||
LIns* oprnd1() const { return u.oprnd_1; }
|
||||
LIns* oprnd2() const { return u.oprnd_2; }
|
||||
|
||||
inline LOpcode opcode() const { return u.code; }
|
||||
inline LOpcode opcode() const { return firstWord.code; }
|
||||
inline uint8_t imm8() const { return c.imm8a; }
|
||||
inline uint8_t imm8b() const { return c.imm8b; }
|
||||
inline int32_t imm32() const { NanoAssert(isconst()); return i.imm32; }
|
||||
@ -284,7 +253,7 @@ namespace nanojit
|
||||
inline int32_t imm64_1() const { NanoAssert(isconstq()); return i64.imm64_1; }
|
||||
uint64_t imm64() const;
|
||||
double imm64f() const;
|
||||
inline uint8_t resv() const { return u.resv; }
|
||||
Reservation* resv() { return &firstWord; }
|
||||
void* payload() const;
|
||||
inline Page* page() { return (Page*) alignTo(this,NJ_PAGE_SIZE); }
|
||||
inline int32_t size() const {
|
||||
@ -314,16 +283,32 @@ namespace nanojit
|
||||
}
|
||||
|
||||
bool isCse(const CallInfo *functions) const;
|
||||
bool isop(LOpcode o) const { return u.code == o; }
|
||||
bool isRet() const { return nanojit::isRetOpcode(firstWord.code); }
|
||||
bool isop(LOpcode o) const { return firstWord.code == o; }
|
||||
bool isQuad() const;
|
||||
bool isCond() const;
|
||||
bool isFloat() const;
|
||||
bool isCmp() const;
|
||||
bool isCall() const { return nanojit::isCall(u.code); }
|
||||
bool isStore() const { return nanojit::isStore(u.code); }
|
||||
bool isLoad() const { return nanojit::isLoad(u.code); }
|
||||
bool isGuard() const { return nanojit::isGuard(u.code); }
|
||||
bool isCall() const {
|
||||
LOpcode op = LOpcode(firstWord.code & ~LIR64);
|
||||
return op == LIR_call || op == LIR_calli;
|
||||
}
|
||||
bool isStore() const {
|
||||
LOpcode op = LOpcode(firstWord.code & ~LIR64);
|
||||
return op == LIR_sti;
|
||||
}
|
||||
bool isLoad() const {
|
||||
LOpcode op = firstWord.code;
|
||||
return op == LIR_ldq || op == LIR_ld || op == LIR_ldc ||
|
||||
op == LIR_ldqc || op == LIR_ldcs;
|
||||
}
|
||||
bool isGuard() const {
|
||||
LOpcode op = firstWord.code;
|
||||
return op == LIR_x || op == LIR_xf || op == LIR_xt ||
|
||||
op == LIR_loop || op == LIR_xbarrier || op == LIR_xtbl;
|
||||
}
|
||||
// True if the instruction is a 32-bit or smaller constant integer.
|
||||
bool isconst() const { return nanojit::isConst(u.code); }
|
||||
bool isconst() const { return firstWord.code == LIR_int; }
|
||||
// True if the instruction is a 32-bit or smaller constant integer and
|
||||
// has the value val when treated as a 32-bit signed integer.
|
||||
bool isconstval(int32_t val) const;
|
||||
@ -335,14 +320,11 @@ namespace nanojit
|
||||
return isop(LIR_jt) || isop(LIR_jf) || isop(LIR_j);
|
||||
}
|
||||
void setimm32(int32_t x) { i.imm32 = x; }
|
||||
// Set the resv member. Should only be used on instructions that use
|
||||
// that. If you're not sure, you shouldn't be calling it.
|
||||
void setresv(uint32_t resv) {
|
||||
NanoAssert(isU8(resv));
|
||||
u.resv = resv;
|
||||
}
|
||||
// Set the opcode and clear resv.
|
||||
void initOpcodeAndClearResv(LOpcode);
|
||||
Reservation* initResv();
|
||||
void clearResv();
|
||||
|
||||
// operand-setting methods
|
||||
void setOprnd1(LIns* r) { u.oprnd_1 = r; }
|
||||
void setOprnd2(LIns* r) { u.oprnd_2 = r; }
|
||||
@ -361,13 +343,6 @@ namespace nanojit
|
||||
};
|
||||
typedef LIns* LInsp;
|
||||
|
||||
bool FASTCALL isCse(LOpcode v);
|
||||
bool FASTCALL isCmp(LOpcode v);
|
||||
bool FASTCALL isCond(LOpcode v);
|
||||
inline bool isRet(LOpcode c) {
|
||||
return (c & ~LIR64) == LIR_ret;
|
||||
}
|
||||
bool FASTCALL isFloat(LOpcode v);
|
||||
LIns* FASTCALL callArgN(LInsp i, uint32_t n);
|
||||
extern const uint8_t operandCount[];
|
||||
|
||||
@ -504,16 +479,14 @@ namespace nanojit
|
||||
DRCWB(avmplus::String*) name;
|
||||
};
|
||||
avmplus::SortedMap<LInsp, Entry*, avmplus::LIST_GCObjects> names;
|
||||
const CallInfo *_functions;
|
||||
LabelMap *labels;
|
||||
void formatImm(int32_t c, char *buf);
|
||||
public:
|
||||
|
||||
LirNameMap(avmplus::GC *gc, const CallInfo *_functions, LabelMap *r)
|
||||
LirNameMap(avmplus::GC *gc, LabelMap *r)
|
||||
: lircounts(gc),
|
||||
funccounts(gc),
|
||||
names(gc),
|
||||
_functions(_functions),
|
||||
labels(r)
|
||||
{}
|
||||
~LirNameMap();
|
||||
@ -576,7 +549,7 @@ namespace nanojit
|
||||
}
|
||||
|
||||
LIns* ins1(LOpcode v, LInsp a) {
|
||||
return isRet(v) ? add_flush(out->ins1(v, a)) : add(out->ins1(v, a));
|
||||
return isRetOpcode(v) ? add_flush(out->ins1(v, a)) : add(out->ins1(v, a));
|
||||
}
|
||||
LIns* ins2(LOpcode v, LInsp a, LInsp b) {
|
||||
return v == LIR_2 ? out->ins2(v,a,b) : add(out->ins2(v, a, b));
|
||||
@ -713,7 +686,6 @@ namespace nanojit
|
||||
class LirBufWriter : public LirWriter
|
||||
{
|
||||
DWB(LirBuffer*) _buf; // underlying buffer housing the instructions
|
||||
LInsp spref, rpref;
|
||||
|
||||
public:
|
||||
LirBufWriter(LirBuffer* buf)
|
||||
|
@ -226,7 +226,7 @@ OPDEF64(fsub, LIR_sub, 2)
|
||||
OPDEF64(fmul, LIR_mul, 2)
|
||||
OPDEF64(fdiv, 40, 2)
|
||||
|
||||
OPDEF64(qjoin, 41, 2)
|
||||
OPDEF64(qjoin, 41, 2) // 1st arg is low 32 bits, 2nd arg is high 32 bits
|
||||
OPDEF64(i2f, 42, 1) // convert an integer to a float
|
||||
OPDEF64(u2f, 43, 1) // convert an unsigned integer to a float
|
||||
OPDEF64(qior, 44, 2)
|
||||
|
@ -164,10 +164,11 @@ Assembler::nFragExit(LInsp guard)
|
||||
NIns*
|
||||
Assembler::genEpilogue()
|
||||
{
|
||||
BX(LR); // return
|
||||
|
||||
RegisterMask savingMask = rmask(FP) | rmask(LR);
|
||||
// On ARMv5+, loading directly to PC correctly handles interworking.
|
||||
// Note that we don't support anything older than ARMv5.
|
||||
NanoAssert(AvmCore::config.arch >= 5);
|
||||
|
||||
RegisterMask savingMask = rmask(FP) | rmask(PC);
|
||||
if (!_thisfrag->lirbuf->explicitSavedRegs)
|
||||
for (int i = 0; i < NumSavedRegs; ++i)
|
||||
savingMask |= rmask(savedRegs[i]);
|
||||
@ -603,7 +604,7 @@ Assembler::asm_restore(LInsp i, Reservation *resv, Register r)
|
||||
// asm_ld_imm will automatically select between LDR and MOV as
|
||||
// appropriate.
|
||||
if (!resv->arIndex)
|
||||
reserveFree(i);
|
||||
i->clearResv();
|
||||
asm_ld_imm(r, i->imm32());
|
||||
#endif
|
||||
} else {
|
||||
@ -1031,12 +1032,6 @@ Assembler::asm_ldr_chk(Register d, Register b, int32_t off, bool chk)
|
||||
return;
|
||||
}
|
||||
|
||||
// This function can't reliably be used to generate PC-relative loads
|
||||
// because it may emit other instructions before the LDR. Support for
|
||||
// PC-relative loads could be added, but isn't currently required so this
|
||||
// assertion is sufficient.
|
||||
NanoAssert(b != PC);
|
||||
|
||||
if (isU12(off)) {
|
||||
// LDR d, b, #+off
|
||||
if (chk) underrunProtect(4);
|
||||
@ -1048,8 +1043,15 @@ Assembler::asm_ldr_chk(Register d, Register b, int32_t off, bool chk)
|
||||
} else {
|
||||
// The offset is over 4096 (and outside the range of LDR), so we need
|
||||
// to add a level of indirection to get the address into IP.
|
||||
if (chk) underrunProtect(4+LD32_size);
|
||||
|
||||
// Because of that, we can't do a PC-relative load unless it fits within
|
||||
// the single-instruction forms above.
|
||||
|
||||
NanoAssert(b != PC);
|
||||
NanoAssert(b != IP);
|
||||
|
||||
if (chk) underrunProtect(4+LD32_size);
|
||||
|
||||
*(--_nIns) = (NIns)( COND_AL | (0x79<<20) | (b<<16) | (d<<12) | IP );
|
||||
LD32_nochk(IP, off);
|
||||
}
|
||||
@ -1060,15 +1062,17 @@ Assembler::asm_ldr_chk(Register d, Register b, int32_t off, bool chk)
|
||||
void
|
||||
Assembler::asm_ld_imm(Register d, int32_t imm)
|
||||
{
|
||||
if (imm == 0) {
|
||||
EOR(d, d, d);
|
||||
} else if (isS8(imm) || isU8(imm)) {
|
||||
NanoAssert(IsGpReg(d));
|
||||
if (isU8(imm)) {
|
||||
underrunProtect(4);
|
||||
if (imm < 0)
|
||||
*(--_nIns) = (NIns)( COND_AL | 0x3E<<20 | d<<12 | (imm^0xFFFFFFFF)&0xFF );
|
||||
else
|
||||
*(--_nIns) = (NIns)( COND_AL | 0x3B<<20 | d<<12 | imm&0xFF );
|
||||
asm_output("ld %s,0x%x",gpn(d), imm);
|
||||
// MOV d, #imm
|
||||
*(--_nIns) = (NIns)( COND_AL | 0x3B<<20 | d<<12 | imm);
|
||||
asm_output("mov %s,0x%x",gpn(d), imm);
|
||||
} else if (isU8(~imm)) {
|
||||
underrunProtect(4);
|
||||
// MVN d, #imm
|
||||
*(--_nIns) = (NIns)( COND_AL | 0x3E<<20 | d<<12 | ~imm);
|
||||
asm_output("mvn %s,0x%x",gpn(d), ~imm);
|
||||
} else {
|
||||
underrunProtect(LD32_size);
|
||||
LD32_nochk(d, imm);
|
||||
@ -1436,7 +1440,7 @@ Assembler::asm_cmp(LIns *cond)
|
||||
int c = rhs->imm32();
|
||||
if (c == 0 && cond->isop(LIR_eq)) {
|
||||
Register r = findRegFor(lhs, GpRegs);
|
||||
TEST(r,r);
|
||||
TST(r,r);
|
||||
// No 64-bit immediates so fall-back to below
|
||||
} else if (!rhs->isQuad()) {
|
||||
Register r = getBaseReg(lhs, c, GpRegs);
|
||||
@ -1587,7 +1591,7 @@ Assembler::asm_arith(LInsp ins)
|
||||
else if (op == LIR_sub)
|
||||
SUB(rr, ra, rb);
|
||||
else if (op == LIR_mul)
|
||||
MUL(rr, rb);
|
||||
MUL(rr, rb, rr);
|
||||
else if (op == LIR_and)
|
||||
AND(rr, ra, rb);
|
||||
else if (op == LIR_or)
|
||||
@ -1595,13 +1599,13 @@ Assembler::asm_arith(LInsp ins)
|
||||
else if (op == LIR_xor)
|
||||
EOR(rr, ra, rb);
|
||||
else if (op == LIR_lsh) {
|
||||
SHL(rr, ra, IP);
|
||||
LSL(rr, ra, IP);
|
||||
ANDi(IP, rb, 0x1f);
|
||||
} else if (op == LIR_rsh) {
|
||||
SAR(rr, ra, IP);
|
||||
ASR(rr, ra, IP);
|
||||
ANDi(IP, rb, 0x1f);
|
||||
} else if (op == LIR_ush) {
|
||||
SHR(rr, ra, IP);
|
||||
LSR(rr, ra, IP);
|
||||
ANDi(IP, rb, 0x1f);
|
||||
} else
|
||||
NanoAssertMsg(0, "Unsupported");
|
||||
@ -1618,11 +1622,11 @@ Assembler::asm_arith(LInsp ins)
|
||||
else if (op == LIR_xor)
|
||||
EORi(rr, ra, c);
|
||||
else if (op == LIR_lsh)
|
||||
SHLi(rr, ra, c);
|
||||
LSLi(rr, ra, c);
|
||||
else if (op == LIR_rsh)
|
||||
SARi(rr, ra, c);
|
||||
ASRi(rr, ra, c);
|
||||
else if (op == LIR_ush)
|
||||
SHRi(rr, ra, c);
|
||||
LSRi(rr, ra, c);
|
||||
else
|
||||
NanoAssertMsg(0, "Unsupported");
|
||||
}
|
||||
@ -1667,13 +1671,13 @@ Assembler::asm_ld(LInsp ins)
|
||||
|
||||
// these will be 2 or 4-byte aligned
|
||||
if (op == LIR_ldcs) {
|
||||
LDRH(rr, d, ra);
|
||||
LDRH(rr, ra, d);
|
||||
return;
|
||||
}
|
||||
|
||||
// aaand this is just any byte.
|
||||
if (op == LIR_ldcb) {
|
||||
LDRB(rr, d, ra);
|
||||
LDRB(rr, ra, d);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -101,13 +101,15 @@ typedef enum {
|
||||
D4 = 20,
|
||||
D5 = 21,
|
||||
D6 = 22,
|
||||
// S14 overlaps with D7 and is hard-coded into i2f and u2f operations, but
|
||||
// D7 is still listed here for completeness and to facilitate assertions.
|
||||
D7 = 23,
|
||||
|
||||
FirstFloatReg = 16,
|
||||
LastFloatReg = 22,
|
||||
|
||||
FirstReg = 0,
|
||||
LastReg = 23,
|
||||
LastReg = 22, // This excludes D7 from the register allocator.
|
||||
UnknownReg = 31,
|
||||
|
||||
// special value referring to S14
|
||||
@ -133,6 +135,7 @@ typedef enum {
|
||||
AL = 0xE, // ALways
|
||||
NV = 0xF // NeVer
|
||||
} ConditionCode;
|
||||
#define IsCond(_cc) (((_cc) & 0xf) == (_cc))
|
||||
|
||||
typedef int RegisterMask;
|
||||
typedef struct _FragInfo {
|
||||
@ -147,11 +150,11 @@ static const RegisterMask SavedRegs = 1<<R4 | 1<<R5 | 1<<R6 | 1<<R7 | 1<<R8 | 1<
|
||||
static const int NumSavedRegs = 7;
|
||||
|
||||
static const RegisterMask FpRegs = 1<<D0 | 1<<D1 | 1<<D2 | 1<<D3 | 1<<D4 | 1<<D5 | 1<<D6; // no D7; S14-S15 are used for i2f/u2f.
|
||||
static const RegisterMask GpRegs = 0x07FF;
|
||||
static const RegisterMask GpRegs = 0xFFFF;
|
||||
static const RegisterMask AllowableFlagRegs = 1<<R0 | 1<<R1 | 1<<R2 | 1<<R3 | 1<<R4 | 1<<R5 | 1<<R6 | 1<<R7 | 1<<R8 | 1<<R9 | 1<<R10;
|
||||
|
||||
#define IsFpReg(_r) ((rmask(_r) & (FpRegs | (1<<D7))) != 0)
|
||||
#define IsGpReg(_r) ((rmask(_r) & (GpRegs | (1<<IP))) != 0)
|
||||
#define IsFpReg(_r) ((rmask((Register)_r) & (FpRegs)) != 0)
|
||||
#define IsGpReg(_r) ((rmask((Register)_r) & (GpRegs)) != 0)
|
||||
#define FpRegNum(_fpr) ((_fpr) - FirstFloatReg)
|
||||
|
||||
#define firstreg() R0
|
||||
@ -226,6 +229,7 @@ typedef enum {
|
||||
RRX = 6, // Rotate Right one bit with extend (c == 0)
|
||||
ROR_reg = 7 // Rotate Right
|
||||
} ShiftOperator;
|
||||
#define IsShift(sh) (((sh) >= LSL_imm) && ((sh) <= ROR_reg))
|
||||
|
||||
#define LD32_size 8
|
||||
|
||||
@ -238,8 +242,9 @@ typedef enum {
|
||||
// BX
|
||||
#define BX(_r) do { \
|
||||
underrunProtect(4); \
|
||||
NanoAssert(IsGpReg(_r)); \
|
||||
*(--_nIns) = (NIns)( COND_AL | (0x12<<20) | (0xFFF<<8) | (1<<4) | (_r)); \
|
||||
asm_output("bx LR"); } while(0)
|
||||
asm_output("bx %s", gpn(_r)); } while(0)
|
||||
|
||||
/*
|
||||
* ALU operations
|
||||
@ -263,6 +268,7 @@ enum {
|
||||
ARM_bic = 14,
|
||||
ARM_mvn = 15
|
||||
};
|
||||
#define IsOp(op) (((ARM_##op) >= ARM_and) && ((ARM_##op) <= ARM_mvn))
|
||||
|
||||
// ALU operation with register and 8-bit immediate arguments
|
||||
// S - bit, 0 or 1, whether the CPSR register is updated
|
||||
@ -271,6 +277,10 @@ enum {
|
||||
// imm - immediate (max 8 bits)
|
||||
#define ALUi(cond, op, S, rd, rl, imm) do {\
|
||||
underrunProtect(4);\
|
||||
NanoAssert(IsCond(cond));\
|
||||
NanoAssert(IsOp(op));\
|
||||
NanoAssert(((S)==0) || ((S)==1));\
|
||||
NanoAssert(IsGpReg(rd) && IsGpReg(rl));\
|
||||
NanoAssert(isU8(imm));\
|
||||
*(--_nIns) = (NIns) ((cond)<<28 | OP_IMM | (ARM_##op)<<21 | (S)<<20 | (rl)<<16 | (rd)<<12 | (imm));\
|
||||
if (ARM_##op == ARM_mov || ARM_##op == ARM_mvn)\
|
||||
@ -290,6 +300,10 @@ enum {
|
||||
// rot - rotation to apply to imm
|
||||
#define ALUi_rot(cond, op, S, rd, rl, imm, rot) do {\
|
||||
underrunProtect(4);\
|
||||
NanoAssert(IsCond(cond));\
|
||||
NanoAssert(IsOp(op));\
|
||||
NanoAssert(((S)==0) || ((S)==1));\
|
||||
NanoAssert(IsGpReg(rd) && IsGpReg(rl));\
|
||||
NanoAssert(isU8(imm));\
|
||||
*(--_nIns) = (NIns) ((cond)<<28 | OP_IMM | (ARM_##op)<<21 | (S)<<20 | (rl)<<16 | (rd)<<12 | (rot)<<8 | (imm));\
|
||||
if (ARM_##op == ARM_mov || ARM_##op == ARM_mvn)\
|
||||
@ -309,6 +323,10 @@ enum {
|
||||
// rr - first (left) operand register
|
||||
#define ALUr(cond, op, S, rd, rl, rr) do {\
|
||||
underrunProtect(4);\
|
||||
NanoAssert(IsCond(cond));\
|
||||
NanoAssert(IsOp(op));\
|
||||
NanoAssert(((S)==0) || ((S)==1));\
|
||||
NanoAssert(IsGpReg(rd) && IsGpReg(rl) && IsGpReg(rr));\
|
||||
*(--_nIns) = (NIns) ((cond)<<28 |(ARM_##op)<<21 | (S)<<20 | (rl)<<16 | (rd)<<12 | (rr));\
|
||||
if (ARM_##op == ARM_mov || ARM_##op == ARM_mvn)\
|
||||
asm_output("%s%s%s %s, %s", #op, condNames[cond], (S)?"s":"", gpn(rd), gpn(rr));\
|
||||
@ -328,6 +346,11 @@ enum {
|
||||
// imm - immediate argument to shift operator, 5 bits (0..31)
|
||||
#define ALUr_shi(cond, op, S, rd, rl, rr, sh, imm) do {\
|
||||
underrunProtect(4);\
|
||||
NanoAssert(IsCond(cond));\
|
||||
NanoAssert(IsOp(op));\
|
||||
NanoAssert(((S)==0) || ((S)==1));\
|
||||
NanoAssert(IsGpReg(rd) && IsGpReg(rl) && IsGpReg(rr));\
|
||||
NanoAssert(IsShift(sh));\
|
||||
NanoAssert((imm)>=0 && (imm)<32);\
|
||||
*(--_nIns) = (NIns) ((cond)<<28 |(ARM_##op)<<21 | (S)<<20 | (rl)<<16 | (rd)<<12 | (imm)<<7 | (sh)<<4 | (rr));\
|
||||
if (ARM_##op == ARM_mov || ARM_##op == ARM_mvn)\
|
||||
@ -348,6 +371,11 @@ enum {
|
||||
// rs - shift operand register
|
||||
#define ALUr_shr(cond, op, S, rd, rl, rr, sh, rs) do {\
|
||||
underrunProtect(4);\
|
||||
NanoAssert(IsCond(cond));\
|
||||
NanoAssert(IsOp(op));\
|
||||
NanoAssert(((S)==0) || ((S)==1));\
|
||||
NanoAssert(IsGpReg(rd) && IsGpReg(rl) && IsGpReg(rr) && IsGpReg(rs));\
|
||||
NanoAssert(IsShift(sh));\
|
||||
*(--_nIns) = (NIns) ((cond)<<28 |(ARM_##op)<<21 | (S)<<20 | (rl)<<16 | (rd)<<12 | (rs)<<8 | (sh)<<4 | (rr));\
|
||||
if (ARM_##op == ARM_mov || ARM_##op == ARM_mvn)\
|
||||
asm_output("%s%s%s %s, %s, %s %s", #op, condNames[cond], (S)?"s":"", gpn(rd), gpn(rr), shiftNames[sh], gpn(rs));\
|
||||
@ -394,11 +422,14 @@ enum {
|
||||
// _d = _l - _imm; update flags
|
||||
#define SUBi(_d,_l,_imm) asm_sub_imm(_d, _l, _imm, 1)
|
||||
|
||||
// _l = _l * _r
|
||||
#define MUL(_l,_r) do { \
|
||||
underrunProtect(4); \
|
||||
*(--_nIns) = (NIns)( COND_AL | (_l)<<16 | (_l)<<8 | 0x90 | (_r) ); \
|
||||
asm_output("mul %s,%s",gpn(_l),gpn(_r)); } while(0)
|
||||
// _d = _l * _r
|
||||
#define MUL(_d,_l,_r) do { \
|
||||
underrunProtect(4); \
|
||||
NanoAssert((AvmCore::config.arch >= 6) || ((_d) != (_l))); \
|
||||
NanoAssert(IsGpReg(_d) && IsGpReg(_l) && IsGpReg(_r)); \
|
||||
NanoAssert(((_d) != PC) && ((_l) != PC) && ((_r) != PC)); \
|
||||
*(--_nIns) = (NIns)( COND_AL | (_d)<<16 | (_r)<<8 | 0x90 | (_l) ); \
|
||||
asm_output("mul %s,%s,%s",gpn(_d),gpn(_l),gpn(_r)); } while(0)
|
||||
|
||||
// _d = 0 - _r
|
||||
#define RSBS(_d,_r) ALUi(AL, rsb, 1, _d, _r, 0)
|
||||
@ -409,35 +440,35 @@ enum {
|
||||
// Logical Shift Right (LSR) rotates the bits without maintaining sign extensions.
|
||||
// MOVS _d, _r, LSR <_s>
|
||||
// _d = _r >> _s
|
||||
#define SHR(_d,_r,_s) ALUr_shr(AL, mov, 1, _d, 0, _r, LSR_reg, _s)
|
||||
#define LSR(_d,_r,_s) ALUr_shr(AL, mov, 1, _d, 0, _r, LSR_reg, _s)
|
||||
|
||||
// Logical Shift Right (LSR) rotates the bits without maintaining sign extensions.
|
||||
// MOVS _d, _r, LSR #(_imm & 0x1f)
|
||||
// _d = _r >> (_imm & 0x1f)
|
||||
#define SHRi(_d,_r,_imm) ALUr_shi(AL, mov, 1, _d, 0, _r, LSR_imm, (_imm & 0x1f))
|
||||
#define LSRi(_d,_r,_imm) ALUr_shi(AL, mov, 1, _d, 0, _r, LSR_imm, (_imm & 0x1f))
|
||||
|
||||
// Arithmetic Shift Right (ASR) maintains the sign extension.
|
||||
// MOVS _d, _r, ASR <_s>
|
||||
// _d = _r >> _s
|
||||
#define SAR(_d,_r,_s) ALUr_shr(AL, mov, 1, _d, 0, _r, ASR_reg, _s)
|
||||
#define ASR(_d,_r,_s) ALUr_shr(AL, mov, 1, _d, 0, _r, ASR_reg, _s)
|
||||
|
||||
// Arithmetic Shift Right (ASR) maintains the sign extension.
|
||||
// MOVS _r, _r, ASR #(_imm & 0x1f)
|
||||
// _d = _r >> (_imm & 0x1f)
|
||||
#define SARi(_d,_r,_imm) ALUr_shi(AL, mov, 1, _d, 0, _r, ASR_imm, (_imm & 0x1f))
|
||||
#define ASRi(_d,_r,_imm) ALUr_shi(AL, mov, 1, _d, 0, _r, ASR_imm, (_imm & 0x1f))
|
||||
|
||||
// Logical Shift Left (LSL).
|
||||
// MOVS _d, _r, LSL <_s>
|
||||
// _d = _r << _s
|
||||
#define SHL(_d, _r, _s) ALUr_shr(AL, mov, 1, _d, 0, _r, LSL_reg, _s)
|
||||
#define LSL(_d, _r, _s) ALUr_shr(AL, mov, 1, _d, 0, _r, LSL_reg, _s)
|
||||
|
||||
// Logical Shift Left (LSL).
|
||||
// MOVS _d, _r, LSL #(_imm & 0x1f)
|
||||
// _d = _r << (_imm & 0x1f)
|
||||
#define SHLi(_d, _r, _imm) ALUr_shi(AL, mov, 1, _d, 0, _r, LSL_imm, (_imm & 0x1f))
|
||||
#define LSLi(_d, _r, _imm) ALUr_shi(AL, mov, 1, _d, 0, _r, LSL_imm, (_imm & 0x1f))
|
||||
|
||||
// TST
|
||||
#define TEST(_l,_r) ALUr(AL, tst, 1, 0, _l, _r)
|
||||
#define TST(_l,_r) ALUr(AL, tst, 1, 0, _l, _r)
|
||||
#define TSTi(_d,_imm) ALUi(AL, tst, 1, 0, _d, _imm)
|
||||
|
||||
// CMP
|
||||
@ -454,10 +485,12 @@ enum {
|
||||
#define MOVLE(dr,sr) MOV_cond(LE, dr, sr)
|
||||
#define MOVGT(dr,sr) MOV_cond(GT, dr, sr)
|
||||
#define MOVGE(dr,sr) MOV_cond(GE, dr, sr)
|
||||
#define MOVCC(dr,sr) MOV_cond(CC, dr, sr)
|
||||
#define MOVLO(dr,sr) MOV_cond(LO, dr, sr) // Equivalent to MOVCC
|
||||
#define MOVCC(dr,sr) MOV_cond(CC, dr, sr) // Equivalent to MOVLO
|
||||
#define MOVLS(dr,sr) MOV_cond(LS, dr, sr)
|
||||
#define MOVHI(dr,sr) MOV_cond(HI, dr, sr)
|
||||
#define MOVCS(dr,sr) MOV_cond(CS, dr, sr)
|
||||
#define MOVHS(dr,sr) MOV_cond(HS, dr, sr) // Equivalent to MOVCS
|
||||
#define MOVCS(dr,sr) MOV_cond(CS, dr, sr) // Equivalent to MOVHS
|
||||
#define MOVVC(dr,sr) MOV_cond(VC, dr, sr) // overflow clear
|
||||
#define MOVNC(dr,sr) MOV_cond(CC, dr, sr) // carry clear
|
||||
|
||||
@ -495,27 +528,38 @@ enum {
|
||||
#define LD(reg,offset,base) asm_ldr_chk(reg,base,offset,1)
|
||||
#define ST(base,offset,reg) STR(reg,base,offset)
|
||||
|
||||
// load 8-bit, zero extend (aka LDRB) note, only 5-bit offsets (!) are
|
||||
// supported for this, but that's all we need at the moment.
|
||||
// (LDRB/LDRH actually allow a 12-bit offset in ARM mode but
|
||||
// constraining to 5-bit gives us advantage for Thumb)
|
||||
#define LDRB(_d,_off,_b) do { \
|
||||
NanoAssert((_off)>=0&&(_off)<=31); \
|
||||
// Load a byte (8 bits). The offset range is ±4095.
|
||||
#define LDRB(_d,_n,_off) do { \
|
||||
NanoAssert(IsGpReg(_d) && IsGpReg(_n)); \
|
||||
underrunProtect(4); \
|
||||
*(--_nIns) = (NIns)( COND_AL | (0x5D<<20) | ((_b)<<16) | ((_d)<<12) | ((_off)&0xfff) ); \
|
||||
asm_output("ldrb %s,%d(%s)", gpn(_d),(_off),gpn(_b)); \
|
||||
if (_off < 0) { \
|
||||
NanoAssert(isU12(-_off)); \
|
||||
*(--_nIns) = (NIns)( COND_AL | (0x55<<20) | ((_n)<<16) | ((_d)<<12) | ((-_off)&0xfff) ); \
|
||||
} else { \
|
||||
NanoAssert(isU12(_off)); \
|
||||
*(--_nIns) = (NIns)( COND_AL | (0x5D<<20) | ((_n)<<16) | ((_d)<<12) | ((_off)&0xfff) ); \
|
||||
} \
|
||||
asm_output("ldrb %s, [%s,#%d]", gpn(_d),gpn(_n),(_off)); \
|
||||
} while(0)
|
||||
|
||||
// P and U
|
||||
#define LDRH(_d,_off,_b) do { \
|
||||
NanoAssert((_off)>=0&&(_off)<=31); \
|
||||
underrunProtect(4); \
|
||||
*(--_nIns) = (NIns)( COND_AL | (0x1D<<20) | ((_b)<<16) | ((_d)<<12) | ((0xB)<<4) | (((_off)&0xf0)<<4) | ((_off)&0xf) ); \
|
||||
asm_output("ldrsh %s,%d(%s)", gpn(_d),(_off),gpn(_b)); \
|
||||
// Load a half word (16 bits). The offset range is ±255, and must be aligned to
|
||||
// two bytes on some architectures.
|
||||
#define LDRH(_d,_n,_off) do { \
|
||||
NanoAssert(IsGpReg(_d) && IsGpReg(_n)); \
|
||||
underrunProtect(4); \
|
||||
if (_off < 0) { \
|
||||
NanoAssert(isU8(-_off)); \
|
||||
*(--_nIns) = (NIns)( COND_AL | (0x15<<20) | ((_n)<<16) | ((_d)<<12) | ((0xB)<<4) | (((-_off)&0xf0)<<4) | ((-_off)&0xf) ); \
|
||||
} else { \
|
||||
NanoAssert(isU8(_off)); \
|
||||
*(--_nIns) = (NIns)( COND_AL | (0x1D<<20) | ((_n)<<16) | ((_d)<<12) | ((0xB)<<4) | (((_off)&0xf0)<<4) | ((_off)&0xf) ); \
|
||||
} \
|
||||
asm_output("ldrsh %s, [%s,#%d]", gpn(_d),gpn(_n),(_off)); \
|
||||
} while(0)
|
||||
|
||||
#define STR(_d,_n,_off) do { \
|
||||
NanoAssert(!IsFpReg(_d) && isS12(_off)); \
|
||||
NanoAssert(IsGpReg(_d) && IsGpReg(_n)); \
|
||||
NanoAssert(isS12(_off)); \
|
||||
underrunProtect(4); \
|
||||
if ((_off)<0) *(--_nIns) = (NIns)( COND_AL | (0x50<<20) | ((_n)<<16) | ((_d)<<12) | ((-(_off))&0xFFF) ); \
|
||||
else *(--_nIns) = (NIns)( COND_AL | (0x58<<20) | ((_n)<<16) | ((_d)<<12) | ((_off)&0xFFF) ); \
|
||||
@ -524,7 +568,8 @@ enum {
|
||||
|
||||
// Rd += _off; [Rd] = Rn
|
||||
#define STR_preindex(_d,_n,_off) do { \
|
||||
NanoAssert(!IsFpReg(_d) && isS12(_off)); \
|
||||
NanoAssert(IsGpReg(_d) && IsGpReg(_n)); \
|
||||
NanoAssert(isS12(_off)); \
|
||||
underrunProtect(4); \
|
||||
if ((_off)<0) *(--_nIns) = (NIns)( COND_AL | (0x52<<20) | ((_n)<<16) | ((_d)<<12) | ((-(_off))&0xFFF) ); \
|
||||
else *(--_nIns) = (NIns)( COND_AL | (0x5A<<20) | ((_n)<<16) | ((_d)<<12) | ((_off)&0xFFF) ); \
|
||||
@ -533,18 +578,14 @@ enum {
|
||||
|
||||
// [Rd] = Rn ; Rd += _off
|
||||
#define STR_postindex(_d,_n,_off) do { \
|
||||
NanoAssert(!IsFpReg(_d) && isS12(_off)); \
|
||||
NanoAssert(IsGpReg(_d) && IsGpReg(_n)); \
|
||||
NanoAssert(isS12(_off)); \
|
||||
underrunProtect(4); \
|
||||
if ((_off)<0) *(--_nIns) = (NIns)( COND_AL | (0x40<<20) | ((_n)<<16) | ((_d)<<12) | ((-(_off))&0xFFF) ); \
|
||||
else *(--_nIns) = (NIns)( COND_AL | (0x48<<20) | ((_n)<<16) | ((_d)<<12) | ((_off)&0xFFF) ); \
|
||||
asm_output("str %s, [%s]!, %d", gpn(_d), gpn(_n), (_off)); \
|
||||
} while(0)
|
||||
|
||||
//#define RET() underrunProtect(1); *(--_nIns) = 0xc3; asm_output("ret")
|
||||
//#define NOP() underrunProtect(1); *(--_nIns) = 0x90; asm_output("nop")
|
||||
//#define INT3() underrunProtect(1); *(--_nIns) = 0xcc; asm_output("int3")
|
||||
//#define RET() INT3()
|
||||
|
||||
#define BKPT_insn ((NIns)( COND_AL | (0x12<<20) | (0x7<<4) ))
|
||||
#define BKPT_nochk() do { \
|
||||
*(--_nIns) = BKPT_insn; } while (0)
|
||||
@ -554,34 +595,29 @@ enum {
|
||||
*(--_nIns) = (NIns)( COND_AL | (0xD<<21) | ((R0)<<12) | (R0) ); \
|
||||
asm_output("nop"); } while(0)
|
||||
|
||||
// this is pushing a reg
|
||||
// STMFD SP!, {reg}
|
||||
#define PUSHr(_r) do { \
|
||||
underrunProtect(4); \
|
||||
*(--_nIns) = (NIns)( COND_AL | (0x92<<20) | (SP<<16) | (1<<(_r)) ); \
|
||||
NanoAssert(IsGpReg(_r)); \
|
||||
*(--_nIns) = (NIns)( COND_AL | (0x92<<20) | (SP<<16) | rmask(_r) ); \
|
||||
asm_output("push %s",gpn(_r)); } while (0)
|
||||
|
||||
// STMDB
|
||||
// STMFD SP!,{reglist}
|
||||
#define PUSH_mask(_mask) do { \
|
||||
underrunProtect(4); \
|
||||
NanoAssert(isU16(_mask)); \
|
||||
*(--_nIns) = (NIns)( COND_AL | (0x92<<20) | (SP<<16) | (_mask) ); \
|
||||
asm_output("push %x", (_mask));} while (0)
|
||||
|
||||
// this form of PUSH takes a base + offset
|
||||
// we need to load into scratch reg, then push onto stack
|
||||
#define PUSHm(_off,_b) do { \
|
||||
NanoAssert( (int)(_off)>0 ); \
|
||||
underrunProtect(8); \
|
||||
*(--_nIns) = (NIns)( COND_AL | (0x92<<20) | (SP<<16) | (1<<(IP)) ); \
|
||||
*(--_nIns) = (NIns)( COND_AL | (0x59<<20) | ((_b)<<16) | ((IP)<<12) | ((_off)&0xFFF) ); \
|
||||
asm_output("push %d(%s)",(_off),gpn(_b)); } while (0)
|
||||
|
||||
#define POPr(_r) do { \
|
||||
underrunProtect(4); \
|
||||
*(--_nIns) = (NIns)( COND_AL | (0x8B<<20) | (SP<<16) | (1<<(_r)) ); \
|
||||
NanoAssert(IsGpReg(_r)); \
|
||||
*(--_nIns) = (NIns)( COND_AL | (0x8B<<20) | (SP<<16) | rmask(_r) ); \
|
||||
asm_output("pop %s",gpn(_r));} while (0)
|
||||
|
||||
#define POP_mask(_mask) do { \
|
||||
underrunProtect(4); \
|
||||
NanoAssert(isU16(_mask)); \
|
||||
*(--_nIns) = (NIns)( COND_AL | (0x8B<<20) | (SP<<16) | (_mask) ); \
|
||||
asm_output("pop %x", (_mask));} while (0)
|
||||
|
||||
|
@ -303,7 +303,7 @@ namespace nanojit
|
||||
}
|
||||
else if (i->isconst()) {
|
||||
if (!resv->arIndex) {
|
||||
reserveFree(i);
|
||||
i->clearResv();
|
||||
}
|
||||
int v = i->imm32();
|
||||
SET32(v, r);
|
||||
|
@ -445,7 +445,7 @@ namespace nanojit
|
||||
}
|
||||
else if (i->isconst()) {
|
||||
if (!resv->arIndex) {
|
||||
reserveFree(i);
|
||||
i->clearResv();
|
||||
}
|
||||
LDi(r, i->imm32());
|
||||
}
|
||||
|
@ -64,12 +64,6 @@ namespace nanojit
|
||||
free |= rmask(r);
|
||||
}
|
||||
|
||||
void RegAlloc::removeFree(Register r)
|
||||
{
|
||||
NanoAssert(isFree(r));
|
||||
free &= ~rmask(r);
|
||||
}
|
||||
|
||||
void RegAlloc::addActive(Register r, LIns* v)
|
||||
{
|
||||
// Count++;
|
||||
@ -102,28 +96,6 @@ namespace nanojit
|
||||
free |= rmask(r);
|
||||
}
|
||||
|
||||
// scan table for instruction with the lowest priority, meaning it is used
|
||||
// furthest in the future.
|
||||
LIns* Assembler::findVictim(RegAlloc ®s, RegisterMask allow)
|
||||
{
|
||||
NanoAssert(allow != 0);
|
||||
LIns *i, *a=0;
|
||||
int allow_pri = 0x7fffffff;
|
||||
for (Register r=FirstReg; r <= LastReg; r = nextreg(r))
|
||||
{
|
||||
if ((allow & rmask(r)) && (i = regs.getActive(r)) != 0)
|
||||
{
|
||||
int pri = canRemat(i) ? 0 : regs.getPriority(r);
|
||||
if (!a || pri < allow_pri) {
|
||||
a = i;
|
||||
allow_pri = pri;
|
||||
}
|
||||
}
|
||||
}
|
||||
NanoAssert(a != 0);
|
||||
return a;
|
||||
}
|
||||
|
||||
#ifdef NJ_VERBOSE
|
||||
/* static */ void RegAlloc::formatRegisters(RegAlloc& regs, char* s, Fragment *frag)
|
||||
{
|
||||
|
@ -55,7 +55,6 @@ namespace nanojit
|
||||
void clear();
|
||||
bool isFree(Register r);
|
||||
void addFree(Register r);
|
||||
void removeFree(Register r);
|
||||
void addActive(Register r, LIns* ins);
|
||||
void useActive(Register r);
|
||||
void removeActive(Register r);
|
||||
|
@ -5212,6 +5212,14 @@ function testNewArrayCount()
|
||||
}
|
||||
test(testNewArrayCount);
|
||||
|
||||
function testNewArrayCount2() {
|
||||
var x = 0;
|
||||
for (var i = 0; i < 10; ++i)
|
||||
x = new Array(1,2,3).__count__;
|
||||
return x;
|
||||
}
|
||||
testNewArrayCount2.expected = 3;
|
||||
test(testNewArrayCount2);
|
||||
|
||||
/*****************************************************************************
|
||||
* *
|
||||
|
Loading…
Reference in New Issue
Block a user