mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-14 13:55:43 +00:00
Merge tracemonkey to mozilla-central.
This commit is contained in:
commit
5efc2c4778
@ -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))
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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[];
|
||||
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user