Merge tracemonkey to mozilla-central.

This commit is contained in:
Robert Sayre 2009-05-22 21:21:16 -04:00
commit 5efc2c4778
8 changed files with 112 additions and 54 deletions

View File

@ -88,10 +88,16 @@ struct JSAtomListElement {
#define ALE_ATOM(ale) ((JSAtom *) (ale)->entry.key)
#define ALE_INDEX(ale) ((jsatomid) JS_PTR_TO_UINT32((ale)->entry.value))
#define ALE_DEFN(ale) ((JSDefinition *) (ale)->entry.value)
#define ALE_VALUE(ale) ((jsval) (ale)->entry.value)
#define ALE_NEXT(ale) ((JSAtomListElement *) (ale)->entry.next)
/*
* In an upvars list, ALE_DEFN(ale)->resolve() is the outermost definition the
* name may reference. If a with block or a function that calls eval encloses
* the use, the name may end up referring to something else at runtime.
*/
#define ALE_DEFN(ale) ((JSDefinition *) (ale)->entry.value)
#define ALE_SET_ATOM(ale,atom) ((ale)->entry.key = (const void *)(atom))
#define ALE_SET_INDEX(ale,index)((ale)->entry.value = JS_UINT32_TO_PTR(index))
#define ALE_SET_DEFN(ale, dn) ((ale)->entry.value = (void *)(dn))

View File

@ -3499,9 +3499,9 @@ js_EmitFunctionScript(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body)
}
/* A macro for inlining at the top of js_EmitTree (whence it came). */
#define UPDATE_LINE_NUMBER_NOTES(cx, cg, pn) \
#define UPDATE_LINE_NUMBER_NOTES(cx, cg, line) \
JS_BEGIN_MACRO \
uintN line_ = (pn)->pn_pos.begin.lineno; \
uintN line_ = (line); \
uintN delta_ = line_ - CG_CURRENT_LINE(cg); \
if (delta_ != 0) { \
/* \
@ -3530,9 +3530,9 @@ js_EmitFunctionScript(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body)
/* A function, so that we avoid macro-bloating all the other callsites. */
static JSBool
UpdateLineNumberNotes(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
UpdateLineNumberNotes(JSContext *cx, JSCodeGenerator *cg, uintN line)
{
UPDATE_LINE_NUMBER_NOTES(cx, cg, pn);
UPDATE_LINE_NUMBER_NOTES(cx, cg, line);
return JS_TRUE;
}
@ -3555,7 +3555,7 @@ MaybeEmitVarDecl(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp,
if (JOF_OPTYPE(pn->pn_op) == JOF_ATOM &&
(!(cg->flags & TCF_IN_FUNCTION) || (cg->flags & TCF_FUN_HEAVYWEIGHT))) {
CG_SWITCH_TO_PROLOG(cg);
if (!UpdateLineNumberNotes(cx, cg, pn))
if (!UpdateLineNumberNotes(cx, cg, pn->pn_pos.begin.lineno))
return JS_FALSE;
EMIT_INDEX_OP(prologOp, atomIndex);
CG_SWITCH_TO_MAIN(cg);
@ -4228,7 +4228,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
pn->pn_offset = top = CG_OFFSET(cg);
/* Emit notes to tell the current bytecode's source line number. */
UPDATE_LINE_NUMBER_NOTES(cx, cg, pn);
UPDATE_LINE_NUMBER_NOTES(cx, cg, pn->pn_pos.begin.lineno);
switch (pn->pn_type) {
case TOK_FUNCTION:
@ -5194,7 +5194,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
/* Indicate that we're emitting a subroutine body. */
stmtInfo.type = STMT_SUBROUTINE;
if (!UpdateLineNumberNotes(cx, cg, pn->pn_kid3))
if (!UpdateLineNumberNotes(cx, cg, pn->pn_kid3->pn_pos.begin.lineno))
return JS_FALSE;
if (js_Emit1(cx, cg, JSOP_FINALLY) < 0 ||
!js_EmitTree(cx, cg, pn->pn_kid3) ||
@ -6777,8 +6777,12 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
JS_ASSERT(0);
}
if (ok && --cg->emitLevel == 0 && cg->spanDeps)
ok = OptimizeSpanDeps(cx, cg);
if (ok && --cg->emitLevel == 0) {
if (cg->spanDeps)
ok = OptimizeSpanDeps(cx, cg);
if (!UpdateLineNumberNotes(cx, cg, pn->pn_pos.end.lineno))
return JS_FALSE;
}
return ok;
}

View File

@ -1956,21 +1956,42 @@ JSCompiler::setFunctionKinds(JSFunctionBox *funbox, uint16& tcflags)
afunbox = afunbox->parent;
/*
* We can't form a flat closure that reaches up
* across a funarg that encloses the closure, or
* into the top level (to a 'let' variable in an
* enclosing block in global code; this is the
* !afunbox case).
* afunbox cannot be null here. That is, we are
* sure to find a function box whose level ==
* lexdepLevel before walking off the top of the
* funbox tree.
*
* Proof: lexdepLevel is at least the base
* staticLevel for this compilation (often 0 but
* nonzero when compiling for local eval) and at
* most funbox->level. The path we are walking
* includes one function box each of precisely that
* range of levels.
*
* Assert but check anyway (bug 493260 comment 16).
*/
if (!afunbox || afunbox->node->isFunArg()) {
JS_ASSERT_IF(!afunbox,
lexdep->isLet() ||
(!(tcflags & TCF_IN_FUNCTION) &&
callerFrame && callerFrame->fun));
JS_ASSERT(afunbox);
/*
* If this function is reaching up across an
* enclosing funarg, we cannot make a flat
* closure. The display stops working once the
* funarg escapes.
*/
if (!afunbox || afunbox->node->isFunArg())
goto break2;
}
}
/*
* with and eval defeat lexical scoping; eval anywhere
* in a variable's scope can assign to it. Both defeat
* the flat closure optimization. The parser detects
* these cases and flags the function heavyweight.
*/
JSFunctionBox *parentbox = afunbox->parent ? afunbox->parent : afunbox;
if (parentbox->tcflags & TCF_FUN_HEAVYWEIGHT)
break;
/*
* If afunbox's function (which is at the same level as
* lexdep) is not a lambda, it will be hoisted, so it

View File

@ -141,9 +141,6 @@ static const char tagChar[] = "OIDISIBI";
/* Max global object size. */
#define MAX_GLOBAL_SLOTS 4096
/* Max memory you can allocate in a LIR buffer via a single insSkip() call. */
#define MAX_SKIP_BYTES (NJ_PAGE_SIZE - sizeof(LIns))
/* Max memory needed to rebuild the interpreter stack when falling off trace. */
#define MAX_INTERP_STACK_BYTES \
(MAX_NATIVE_STACK_SLOTS * sizeof(jsval) + \
@ -1844,39 +1841,49 @@ FlushNativeGlobalFrame(JSContext* cx, unsigned ngslots, uint16* gslots, uint8* m
* *result as an unboxed native. The return value is the typemap type.
*/
uint32 JS_FASTCALL
js_GetUpvarOnTrace(JSContext *cx, uint32 level, uint32 cookie, double* result)
js_GetUpvarOnTrace(JSContext* cx, uint32 level, uint32 cookie, uint32 callDepth, double* result)
{
uintN skip = UPVAR_FRAME_SKIP(cookie);
uintN upvarLevel = level - skip;
InterpState* state = cx->interpState;
uintN callDepth = state->rp - state->callstackBase;
FrameInfo** fip = state->rp + callDepth;
/*
* If we are skipping past all frames that are part of active traces,
* then we simply get the value from the interpreter state.
* First search the FrameInfo call stack for an entry containing
* our upvar, namely one with staticLevel == upvarLevel.
*/
if (skip > callDepth) {
jsval v = js_GetUpvar(cx, level, cookie);
uint8 type = getCoercedType(v);
ValueToNative(cx, v, type, result);
return type;
while (--fip >= state->callstackBase) {
FrameInfo* fi = *fip;
JSFunction* fun = GET_FUNCTION_PRIVATE(cx, fi->callee);
uintN calleeLevel = fun->u.i.script->staticLevel;
if (calleeLevel == upvarLevel) {
/*
* Now find the upvar's value in the native stack.
* nativeStackFramePos is the offset of the start of the
* activation record corresponding to *fip in the native
* stack.
*/
uintN nativeStackFramePos = state->callstackBase[0]->caller_argc;
for (FrameInfo** fip2 = state->callstackBase; fip2 <= fip; fip2++)
nativeStackFramePos += (*fip2)->s.spdist;
nativeStackFramePos -= (2 + (*fip)->s.argc);
uint8* typemap = (uint8*) (fi+1);
uintN slot = UPVAR_FRAME_SLOT(cookie);
slot = (slot == CALLEE_UPVAR_SLOT) ? 0 : 2/*callee,this*/ + slot;
*result = state->stackBase[nativeStackFramePos + slot];
return typemap[slot];
}
}
/*
* The value we need is logically in a stack frame that is part of
* an active trace. We reconstruct the value we need from the tracer
* stack records.
* If we did not find the upvar in the frames for the active traces,
* then we simply get the value from the interpreter state.
*/
uintN frameIndex = callDepth - skip; // pos of target frame in rp stack
uintN nativeStackFramePos = 0; // pos of target stack frame in sp stack
for (uintN i = 0; i < frameIndex; ++i)
nativeStackFramePos += state->callstackBase[i]->s.spdist;
FrameInfo* fi = state->callstackBase[frameIndex];
uint8* typemap = (uint8*) (fi+1);
uintN slot = UPVAR_FRAME_SLOT(cookie);
slot = slot == CALLEE_UPVAR_SLOT ? 0 : slot + 2;
*result = state->stackBase[nativeStackFramePos + slot];
return typemap[slot];
jsval v = js_GetUpvar(cx, level, cookie);
uint8 type = getCoercedType(v);
ValueToNative(cx, v, type, result);
return type;
}
/**
@ -8372,7 +8379,8 @@ TraceRecorder::record_JSOP_CALLNAME()
return JSRS_CONTINUE;
}
JS_DEFINE_CALLINFO_4(extern, UINT32, js_GetUpvarOnTrace, CONTEXT, UINT32, UINT32, DOUBLEPTR, 0, 0)
JS_DEFINE_CALLINFO_5(extern, UINT32, js_GetUpvarOnTrace, CONTEXT, UINT32, UINT32, UINT32,
DOUBLEPTR, 0, 0)
JS_REQUIRES_STACK JSRecordingStatus
TraceRecorder::record_JSOP_GETUPVAR()
@ -8400,8 +8408,9 @@ TraceRecorder::record_JSOP_GETUPVAR()
LIns* outp = lir->insAlloc(sizeof(double));
LIns* args[] = {
outp,
lir->insImm(uva->vector[index]),
lir->insImm(script->staticLevel),
INS_CONST(callDepth),
INS_CONST(uva->vector[index]),
INS_CONST(script->staticLevel),
cx_ins
};
const CallInfo* ci = &js_GetUpvarOnTrace_ci;
@ -8533,6 +8542,7 @@ TraceRecorder::interpretedFunctionCall(jsval& fval, JSFunction* fun, uintN argc,
fi->imacpc = fp->imacpc;
fi->s.spdist = fp->regs->sp - fp->slots;
fi->s.argc = argc | (constructing ? 0x8000 : 0);
fi->caller_argc = 2 + fp->argc;
unsigned callDepth = getCallDepth();
if (callDepth >= treeInfo->maxCallDepth)

View File

@ -298,6 +298,7 @@ struct FrameInfo {
} s;
uint32 word; // for spdist/argc LIR store in record_JSOP_CALL
};
uint32 caller_argc; // fp->argv - stackBase
};
struct UnstableExit

View File

@ -159,7 +159,7 @@ namespace nanojit
void LirBufWriter::ensureRoom(uint32_t count)
{
NanoAssert(count <= NJ_PAGE_SIZE - sizeof(LIns));
NanoAssert(count * sizeof(LIns) <= MAX_SKIP_BYTES);
LInsp before = _buf->next();
LInsp after = before+count+1;
// transition to the next page?
@ -315,12 +315,12 @@ namespace nanojit
LInsp LirBufWriter::insSkip(size_t size)
{
NanoAssert(size <= MAX_SKIP_BYTES);
const uint32_t nSlots = (size+sizeof(LIns)-1)/sizeof(LIns);
ensureRoom(nSlots); // make room for it
ensureRoom(nSlots+1); // make room for it (blob + skip instruction)
LInsp last = _buf->next()-1; // safe, next()-1+nSlots guaranteed to be on same page
_buf->commit(nSlots);
NanoAssert(samepage(last,_buf->next()));
ensureRoom(1);
return insSkipWithoutBuffer(last);
}

View File

@ -418,6 +418,18 @@ namespace nanojit
LIns* insImmf(double f);
};
// We want to keep the blob + skip together, plus we need room for a
// possible page-crossing skip, plus a spare slot to ensure we're never
// leaving _unused on a page boundary. That makes for 3 LIns we need to
// reserve. We throw in 3 more slots for paranoia's sake (we've
// mistakenly set this too high several times so far), and also reserve
// the size of the the page header, giving a total of 100 bytes
// reserved from end-of-page.
#define MAX_SKIP_BYTES (NJ_PAGE_SIZE \
- sizeof(PageHeader) \
- 6*sizeof(LIns))
#ifdef NJ_VERBOSE
extern const char* lirNames[];

View File

@ -332,7 +332,11 @@ Assembler::asm_arg(ArgSize sz, LInsp arg, Register& r, int& stkd)
} else {
int d = findMemFor(arg);
STR_preindex(IP, SP, -4);
LDR(IP, FP, d);
if (arg->isop(LIR_alloc)) {
asm_add_imm(IP, FP, d);
} else {
LDR(IP, FP, d);
}
stkd += 4;
}
} else {