Merge again

This commit is contained in:
Blake Kaplan 2008-08-27 17:48:56 -07:00
commit b9bf10f53c
8 changed files with 177 additions and 72 deletions

View File

@ -424,6 +424,7 @@ js_CallTree(InterpState* state, Fragment* f)
{
union { NIns *code; GuardRecord* (FASTCALL *func)(InterpState*, Fragment*); } u;
u.code = f->code();
JS_ASSERT(u.code);
return u.func(state, NULL);
}

View File

@ -79,9 +79,6 @@
/* Max number of type mismatchs before we trash the tree. */
#define MAX_MISMATCH 5
/* Max number of loop edges to follow. */
#define MAX_OUTERLINE 0
/* Max native stack size. */
#define MAX_NATIVE_STACK_SLOTS 1024
@ -660,6 +657,9 @@ mergeTypeMaps(uint8** partial, unsigned* plength, uint8* complete, unsigned clen
*plength = clength;
}
static void
js_TrashTree(JSContext* cx, Fragment* f);
TraceRecorder::TraceRecorder(JSContext* cx, GuardRecord* _anchor, Fragment* _fragment,
TreeInfo* ti, unsigned ngslots, uint8* globalTypeMap, uint8* stackTypeMap,
GuardRecord* innermostNestedGuard)
@ -677,7 +677,8 @@ TraceRecorder::TraceRecorder(JSContext* cx, GuardRecord* _anchor, Fragment* _fra
this->loopEdgeCount = 0;
JS_ASSERT(!_anchor || _anchor->calldepth == _fragment->calldepth);
this->atoms = cx->fp->script->atomMap.vector;
this->trashTree = false;
this->lastLoopEdge = NULL;
debug_only_v(printf("recording starting from %s:%u@%u\n", cx->fp->script->filename,
js_PCToLineNumber(cx, cx->fp->script, cx->fp->regs->pc),
@ -723,6 +724,8 @@ TraceRecorder::~TraceRecorder()
JS_ASSERT(!fragment->root->vmprivate);
delete treeInfo;
}
if (trashTree)
js_TrashTree(cx, fragment->root);
#ifdef DEBUG
delete verbose_filter;
#endif
@ -750,11 +753,15 @@ TraceRecorder::getCallDepth() const
}
/* Determine whether we should outerline along a loop edge. */
/* Determine whether we should unroll a loop (only do so at most once for every loop). */
bool
TraceRecorder::trackLoopEdges()
{
return loopEdgeCount++ < MAX_OUTERLINE;
jsbytecode* pc = cx->fp->regs->pc;
if (pc == lastLoopEdge)
return false;
lastLoopEdge = pc;
return true;
}
/* Determine the offset in the native global frame for a jsval we track */
@ -1300,9 +1307,6 @@ struct FrameInfo {
};
};
static void
js_TrashTree(JSContext* cx, Fragment* f);
/* Promote slots if necessary to match the called tree' type map and report error if thats
impossible. */
bool
@ -1339,8 +1343,9 @@ TraceRecorder::adjustCallerTypes(Fragment* f)
}
++m;
);
JS_ASSERT(f == f->root);
if (!ok)
js_TrashTree(cx, f);
trashTree = true;
return ok;
}
@ -1493,8 +1498,8 @@ TraceRecorder::verifyTypeStability()
}
++m
);
if (recompile)
js_TrashTree(cx, fragment);
if (recompile)
trashTree = true;
return !recompile;
}
@ -1624,6 +1629,8 @@ TraceRecorder::emitTreeCall(Fragment* inner, GuardRecord* lr)
/* Guard that we come out of the inner tree along the same side exit we came out when
we called the inner tree at recording time. */
guard(true, lir->ins2(LIR_eq, ret, lir->insImmPtr(lr)), NESTED_EXIT);
/* Register us as a dependent tree of the inner tree. */
((TreeInfo*)inner->vmprivate)->dependentTrees.addUnique(fragment->root);
}
int
@ -1713,14 +1720,21 @@ static void
js_TrashTree(JSContext* cx, Fragment* f)
{
JS_ASSERT((!f->code()) == (!f->vmprivate));
JS_ASSERT(f == f->root);
if (!f->code())
return;
AUDIT(treesTrashed);
debug_only_v(printf("Trashing tree info.\n");)
Fragmento* fragmento = JS_TRACE_MONITOR(cx).fragmento;
delete (TreeInfo*)f->vmprivate;
TreeInfo* ti = (TreeInfo*)f->vmprivate;
f->vmprivate = NULL;
f->releaseCode(fragmento);
Fragment** data = ti->dependentTrees.data();
unsigned length = ti->dependentTrees.length();
for (unsigned n = 0; n < length; ++n)
js_TrashTree(cx, data[n]);
delete ti;
JS_ASSERT(!f->code() && !f->vmprivate);
}
static unsigned
@ -2106,9 +2120,10 @@ js_ExecuteTree(JSContext* cx, Fragment** treep, uintN& inlineCallCount,
JS_ASSERT(lr->guard->oprnd1()->oprnd2()->isconstp());
lr = (GuardRecord*)lr->guard->oprnd1()->oprnd2()->constvalp();
} while (lr->exit->exitType == NESTED_EXIT);
/* We restored the nested frames, now we just need to deal with the innermost guard. */
lr = state.nestedExit;
JS_ASSERT(lr);
}
/* sp_adj and ip_adj are relative to the tree we exit out of, not the tree we
@ -3063,12 +3078,12 @@ TraceRecorder::box_jsval(jsval v, LIns*& v_ins)
}
switch (JSVAL_TAG(v)) {
case JSVAL_BOOLEAN:
v_ins = lir->ins2i(LIR_or, lir->ins2i(LIR_pilsh, v_ins, JSVAL_TAGBITS), JSVAL_BOOLEAN);
v_ins = lir->ins2i(LIR_pior, lir->ins2i(LIR_pilsh, v_ins, JSVAL_TAGBITS), JSVAL_BOOLEAN);
return true;
case JSVAL_OBJECT:
return true;
case JSVAL_STRING:
v_ins = lir->ins2(LIR_or, v_ins, INS_CONST(JSVAL_STRING));
v_ins = lir->ins2(LIR_pior, v_ins, INS_CONST(JSVAL_STRING));
return true;
}
return false;
@ -3080,11 +3095,11 @@ TraceRecorder::unbox_jsval(jsval v, LIns*& v_ins)
if (isNumber(v)) {
// JSVAL_IS_NUMBER(v)
guard(false,
lir->ins_eq0(lir->ins2(LIR_or,
lir->ins2(LIR_piand, v_ins, INS_CONSTPTR(JSVAL_INT)),
lir->ins_eq0(lir->ins2(LIR_pior,
lir->ins2(LIR_piand, v_ins, INS_CONST(JSVAL_INT)),
lir->ins2i(LIR_eq,
lir->ins2(LIR_piand, v_ins,
INS_CONSTPTR(JSVAL_TAGMASK)),
INS_CONST(JSVAL_TAGMASK)),
JSVAL_DOUBLE))),
MISMATCH_EXIT);
v_ins = lir->insCall(F_UnboxDouble, &v_ins);
@ -3094,7 +3109,7 @@ TraceRecorder::unbox_jsval(jsval v, LIns*& v_ins)
case JSVAL_BOOLEAN:
guard(true,
lir->ins2i(LIR_eq,
lir->ins2(LIR_piand, v_ins, INS_CONSTPTR(JSVAL_TAGMASK)),
lir->ins2(LIR_piand, v_ins, INS_CONST(JSVAL_TAGMASK)),
JSVAL_BOOLEAN),
MISMATCH_EXIT);
v_ins = lir->ins2i(LIR_ush, v_ins, JSVAL_TAGBITS);
@ -3102,17 +3117,17 @@ TraceRecorder::unbox_jsval(jsval v, LIns*& v_ins)
case JSVAL_OBJECT:
guard(true,
lir->ins2i(LIR_eq,
lir->ins2(LIR_piand, v_ins, INS_CONSTPTR(JSVAL_TAGMASK)),
lir->ins2(LIR_piand, v_ins, INS_CONST(JSVAL_TAGMASK)),
JSVAL_OBJECT),
MISMATCH_EXIT);
return true;
case JSVAL_STRING:
guard(true,
lir->ins2i(LIR_eq,
lir->ins2(LIR_piand, v_ins, INS_CONSTPTR(JSVAL_TAGMASK)),
lir->ins2(LIR_piand, v_ins, INS_CONST(JSVAL_TAGMASK)),
JSVAL_STRING),
MISMATCH_EXIT);
v_ins = lir->ins2(LIR_piand, v_ins, INS_CONSTPTR(~JSVAL_TAGMASK));
v_ins = lir->ins2(LIR_piand, v_ins, INS_CONST(~JSVAL_TAGMASK));
return true;
}
return false;
@ -3140,7 +3155,7 @@ TraceRecorder::guardClass(JSObject* obj, LIns* obj_ins, JSClass* clasp)
return false;
LIns* class_ins = stobj_get_fslot(obj_ins, JSSLOT_CLASS);
class_ins = lir->ins2(LIR_piand, class_ins, lir->insImmPtr((void*)~3));
class_ins = lir->ins2(LIR_piand, class_ins, lir->insImm(~3));
char namebuf[32];
JS_snprintf(namebuf, sizeof namebuf, "guard(class is %s)", clasp->name);

View File

@ -193,9 +193,10 @@ public:
unsigned maxCallDepth;
TypeMap stackTypeMap;
unsigned mismatchCount;
Queue<nanojit::Fragment*> dependentTrees;
TreeInfo(nanojit::Fragment* _fragment) {
fragment = _fragment;
fragment = _fragment;
}
};
@ -228,6 +229,8 @@ class TraceRecorder {
nanojit::LIns* rval_ins;
nanojit::LIns* inner_sp_ins;
nanojit::SideExit exit;
bool trashTree;
jsbytecode* lastLoopEdge;
bool isGlobal(jsval* p) const;
ptrdiff_t nativeGlobalOffset(jsval* p) const;

View File

@ -1041,6 +1041,7 @@ namespace nanojit
case LIR_qiadd:
case LIR_qiand:
case LIR_qilsh:
case LIR_qior:
{
asm_qbinop(ins);
break;

View File

@ -80,7 +80,7 @@ namespace nanojit
/* 70-79 */ "70","71","72","73","74","stq","ldq","77","stqi","79",
/* 80-89 */ "80","81","fcall","83","84","85","86","87","qiand","qiadd",
/* 90-99 */ "90","91","92","93","qcmov","95","96","quad","98","99",
/* 100-109 */ "fneg","fadd","fsub","fmul","fdiv","qjoin","i2f","u2f","108","qilsh",
/* 100-109 */ "fneg","fadd","fsub","fmul","fdiv","qjoin","i2f","u2f","qior","qilsh",
/* 110-119 */ "110","111","112","113","114","115","116","117","118","119",
/* 120-127 */ "120","121","122","123","124","125","126","127"
};
@ -1656,6 +1656,7 @@ namespace nanojit
case LIR_qiadd:
case LIR_qiand:
case LIR_qilsh:
case LIR_qior:
sprintf(s, "%s %s, %s", lirNames[op],
formatRef(i->oprnd1()),
formatRef(i->oprnd2()));

View File

@ -133,7 +133,8 @@ namespace nanojit
LIR_qjoin = 41 | LIR64,
LIR_i2f = 42 | LIR64,
LIR_u2f = 43 | LIR64
LIR_u2f = 43 | LIR64,
LIR_qior = 44 | LIR64
};
#if defined NANOJIT_64BIT
@ -142,12 +143,14 @@ namespace nanojit
#define LIR_piand LIR_qiand
#define LIR_pilsh LIR_qilsh
#define LIR_pcmov LIR_qcmov
#define LIR_pior LIR_qior
#else
#define LIR_ldp LIR_ld
#define LIR_piadd LIR_add
#define LIR_piand LIR_and
#define LIR_pilsh LIR_lsh
#define LIR_pcmov LIR_cmov
#define LIR_pior LIR_or
#endif
inline uint32_t argwords(uint32_t argc) {

View File

@ -175,9 +175,11 @@ namespace nanojit
{ \
NIns *tt = _nIns; \
_nIns = pageAlloc(_inExit); \
_pageData = 0; \
_dblNegPtr = NULL; \
_negOnePtr = NULL; \
if (!_inExit) { \
_pageData = 0; \
_dblNegPtr = NULL; \
_negOnePtr = NULL; \
} \
intptr_t d = tt-_nIns; \
if (d <= INT_MAX && d >= INT_MIN) { \
JMP_long_nochk_offset(d); \
@ -185,9 +187,7 @@ namespace nanojit
/* Insert a 64-bit jump... */ \
_nIns -= 8; \
*(intptr_t *)_nIns = intptr_t(tt); \
IMM32(0); \
*(_nIns--) = 0x25; \
*(_nIns--) = 0xFF; \
JMPm_nochk(0); \
} \
} \
overrideProtect = _nIns; \
@ -458,6 +458,12 @@ namespace nanojit
} while(0)
#define ORQ(l,r) do { \
AMD64_PRIMQ(AMD64_OR_REG_RM, l, r); \
asm_output2("or %s,%s",gpn(l),gpn(r)); \
} while(0)
#define SHRi(r,i) do { \
if (i == 1) { \
underrunProtect(3); \
@ -487,6 +493,11 @@ namespace nanojit
} while(0)
#define ORQi(r,i) do { \
AMD64_ALU(AMD64_OR_RAX, r, i, 1); \
asm_output2("or %s,%d",gpn(r),i); \
} while(0)
#define XORi(r,i) do { \
AMD64_ALU(AMD64_XOR_RAX, r, i, 0); \
asm_output2("xor %s,%d",gpn(r),i); \
@ -852,23 +863,59 @@ namespace nanojit
asm_output1("pop %s",gpn(r)); \
} while(0)
#define JCC(o,t,n) do { \
underrunProtect(6); \
intptr_t tt = (intptr_t)t - (intptr_t)_nIns; \
if (isS8(tt)) { \
verbose_only( NIns* next = _nIns; (void)next; ) \
_nIns -= 2; \
_nIns[0] = (uint8_t) ( 0x70 | (o) ); \
_nIns[1] = (uint8_t) (tt); \
asm_output2("%s %lX",(n),(ptrdiff_t)(next+tt)); \
} else { \
verbose_only( NIns* next = _nIns; ) \
IMM32(tt); \
_nIns -= 2; \
_nIns[0] = 0x0f; \
_nIns[1] = (uint8_t) ( 0x80 | (o) ); \
asm_output2("%s %lX",(n),(ptrdiff_t)(next+tt)); \
} } while(0)
#define JCC(o,t,n) do { \
underrunProtect(6); \
intptr_t tt = (intptr_t)t - (intptr_t)_nIns; \
if (isS8(tt)) { \
verbose_only( NIns* next = _nIns; (void)next; ) \
_nIns -= 2; \
_nIns[0] = (uint8_t) ( 0x70 | (o) ); \
_nIns[1] = (uint8_t) (tt); \
asm_output2("%s %lX",(n),(ptrdiff_t)(next+tt)); \
} else if (tt <= INT_MAX && tt >= INT_MIN) { \
verbose_only( NIns* next = _nIns; ) \
IMM32(tt); \
_nIns -= 2; \
_nIns[0] = 0x0f; \
_nIns[1] = (uint8_t) ( 0x80 | (o) ); \
asm_output2("%s %lX",(n),(ptrdiff_t)(next+tt)); \
} else { \
underrunProtect(20); \
NanoAssert(!_inExit); \
/* We could now be in range, but assume we're not. */ \
/* Note we generate the thunk forwards, and the */ \
/* jcc to the thunk backwards. */ \
uint8_t* base; \
intptr_t offs; \
base = (uint8_t *)((uintptr_t)_nIns & ~((uintptr_t)NJ_PAGE_SIZE-1)); \
base += sizeof(PageHeader) + _pageData; \
_pageData += 14; \
*(base++) = 0xFF; \
*(base++) = 0x25; \
*(int *)base = 0; \
base += 4; \
*(intptr_t *)base = intptr_t(t); \
offs = intptr_t(base-6) - intptr_t(_nIns); \
NanoAssert(offs >= INT_MIN && offs <= INT_MAX); \
if (isS8(offs)) { \
_nIns -= 2; \
_nIns[0] = uint8_t( 0x70 | (o) ); \
_nIns[1] = uint8_t( (offs) ); \
} else { \
IMM32(offs); \
_nIns -= 2; \
_nIns[0] = 0x0f; \
_nIns[1] = uint8_t( 0x80 | (o) ); \
} \
asm_output3("%s %d(rip) #%lX",n,offs,intptr_t(t)); \
} \
} while(0)
#define JMPm_nochk(rip) do { \
IMM32(rip); \
*(--_nIns) = 0x25; \
*(--_nIns) = 0xFF; \
} while (0)
#define JMP_long(t) do { \
underrunProtect(5); \
@ -876,17 +923,24 @@ namespace nanojit
JMP_long_nochk_offset(tt); \
} while(0)
#define JMP(t) do { \
underrunProtect(5); \
intptr_t tt = (intptr_t)t - (intptr_t)_nIns; \
if (isS8(tt)) { \
#define JMP(t) do { \
underrunProtect(5); \
intptr_t tt = (intptr_t)t - (intptr_t)_nIns; \
if (isS8(tt)) { \
verbose_only( NIns* next = _nIns; (void)next; ) \
_nIns -= 2; \
_nIns[0] = 0xeb; \
_nIns[1] = (uint8_t) ( (tt)&0xff ); \
asm_output1("jmp %lX",(ptrdiff_t)(next+tt)); \
} else { \
JMP_long_nochk_offset(tt); \
_nIns -= 2; \
_nIns[0] = 0xeb; \
_nIns[1] = (uint8_t) ( (tt)&0xff ); \
asm_output1("jmp %lX",(ptrdiff_t)(next+tt)); \
} else { \
if (tt >= INT_MIN && tt <= INT_MAX) { \
JMP_long_nochk_offset(tt); \
} else { \
underrunProtect(14); \
_nIns -= 8; \
*(intptr_t *)_nIns = intptr_t(t); \
JMPm_nochk(0); \
} \
} } while(0)
#define JMP_long_nochk(t) do { \
@ -896,9 +950,11 @@ namespace nanojit
#define JMPc 0xe9
#define JMP_long_placeholder() do {\
underrunProtect(5); \
JMP_long_nochk_offset(-1); } while(0)
#define JMP_long_placeholder() do { \
underrunProtect(14); \
IMM64(-1); \
JMPm_nochk(0); \
} while (0)
// this should only be used when you can guarantee there is enough room on the page
#define JMP_long_nochk_offset(o) do {\
@ -908,13 +964,11 @@ namespace nanojit
*(--_nIns) = JMPc; \
asm_output1("jmp %lX",(ptrdiff_t)(next+(o))); } while(0)
#if 0
#define JMPr(r) do { \
underrunProtect(2); \
*(--_nIns) = AMD64_MODRM_REG(4, r); \
*(--_nIns) = 0xFF; \
} while (0)
#endif
#define JE(t) JCC(0x04, t, "je")
#define JNE(t) JCC(0x05, t, "jne")

View File

@ -173,8 +173,17 @@ namespace nanojit
{
// target doesn't exit yet. emit jump to epilog, and set up to patch later.
lr = placeGuardRecord(guard);
#if defined NANOJIT_AMD64
/* 8 bytes for address, 4 for imm32, 2 for jmp */
underrunProtect(14);
_nIns -= 8;
*(intptr_t *)_nIns = intptr_t(_epilogue);
lr->jmp = _nIns;
JMPm_nochk(0);
#else
JMP_long(_epilogue);
lr->jmp = _nIns;
#endif
#if 0
// @todo optimization ; is it worth it? It means we can remove the loop over outbound in Fragment.link()
// for trees we need the patch entry on the incoming fragment so we can unhook it later if needed
@ -363,11 +372,22 @@ namespace nanojit
void Assembler::nPatchBranch(NIns* branch, NIns* location)
{
uint32_t offset = location - branch;
#if defined NANOJIT_IA32
intptr_t offset = intptr_t(location) - intptr_t(branch);
if (branch[0] == JMPc)
*(uint32_t*)&branch[1] = offset - 5;
else
*(uint32_t*)&branch[2] = offset - 6;
#else
if (branch[0] == 0xFF && branch[1] == 0x25) {
NIns *mem;
mem = &branch[6] + *(int32_t *)&branch[2];
*(intptr_t *)mem = intptr_t(location);
} else {
NanoAssert(0);
}
#endif
}
RegisterMask Assembler::hint(LIns* i, RegisterMask allow)
@ -1214,16 +1234,19 @@ namespace nanojit
NIns* Assembler::asm_adjustBranch(NIns* at, NIns* target)
{
NIns* was;
#if defined NANOJIT_AMD64
was = (NIns*)( *(intptr_t*)(at) );
*(intptr_t *)(at) = intptr_t(target);
#else
NIns* save = _nIns;
NIns* was = (NIns*)( (intptr_t)*(int32_t*)(at+1)+(intptr_t)(at+5) );
was = (NIns*)( (intptr_t)*(int32_t*)(at+1)+(intptr_t)(at+5) );
_nIns = at +5; // +5 is size of JMP
intptr_t tt = (intptr_t)target - (intptr_t)_nIns;
#if defined NANOJIT_AMD64
NanoAssert(tt <= INT_MAX && tt >= INT_MIN);
#endif
IMM32(tt);
*(--_nIns) = JMPc;
_nIns = save;
_nIns = save;
#endif
return was;
}
@ -1281,6 +1304,8 @@ namespace nanojit
ANDQi(rr, c);
} else if (op == LIR_qilsh) {
SHLQi(rr, c);
} else if (op == LIR_qior) {
ORQi(rr, c);
}
} else {
Register rv;
@ -1295,6 +1320,8 @@ namespace nanojit
ADDQ(rr, rv);
} else if (op == LIR_qiand) {
ANDQ(rr, rv);
} else if (op == LIR_qior) {
ORQ(rr, rv);
} else {
NanoAssert(rhs->isconst());
NanoAssert(false);