bug 446386 - removal of the compiler pseud-frames. r=brendan,mrbkap

This commit is contained in:
Igor Bukanov 2008-09-02 08:10:26 +02:00
parent b78b594ba0
commit 4509b7601e
11 changed files with 165 additions and 261 deletions

View File

@ -4569,7 +4569,7 @@ JS_CompileUCScriptForPrincipals(JSContext *cx, JSObject *obj,
CHECK_REQUEST(cx);
tcflags = JS_OPTIONS_TO_TCFLAGS(cx);
script = js_CompileScript(cx, obj, principals, tcflags,
script = js_CompileScript(cx, obj, NULL, principals, tcflags,
chars, length, NULL, filename, lineno);
LAST_FRAME_CHECKS(cx, script);
return script;
@ -4596,7 +4596,8 @@ JS_BufferIsCompilableUnit(JSContext *cx, JSObject *obj,
*/
result = JS_TRUE;
exnState = JS_SaveExceptionState(cx);
if (js_InitParseContext(cx, &pc, NULL, chars, length, NULL, NULL, 1)) {
if (js_InitParseContext(cx, &pc, NULL, NULL, chars, length, NULL, NULL,
1)) {
older = JS_SetErrorReporter(cx, NULL);
if (!js_ParseScript(cx, obj, &pc) &&
(pc.tokenStream.flags & TSF_UNEXPECTED_EOF)) {
@ -4635,7 +4636,7 @@ JS_CompileFile(JSContext *cx, JSObject *obj, const char *filename)
}
tcflags = JS_OPTIONS_TO_TCFLAGS(cx);
script = js_CompileScript(cx, obj, NULL, tcflags,
script = js_CompileScript(cx, obj, NULL, NULL, tcflags,
NULL, 0, fp, filename, 1);
if (fp != stdin)
fclose(fp);
@ -4660,7 +4661,7 @@ JS_CompileFileHandleForPrincipals(JSContext *cx, JSObject *obj,
CHECK_REQUEST(cx);
tcflags = JS_OPTIONS_TO_TCFLAGS(cx);
script = js_CompileScript(cx, obj, principals, tcflags,
script = js_CompileScript(cx, obj, NULL, principals, tcflags,
NULL, 0, file, filename, 1);
LAST_FRAME_CHECKS(cx, script);
return script;
@ -4998,7 +4999,7 @@ JS_EvaluateUCScriptForPrincipals(JSContext *cx, JSObject *obj,
JSBool ok;
CHECK_REQUEST(cx);
script = js_CompileScript(cx, obj, principals,
script = js_CompileScript(cx, obj, NULL, principals,
!rval
? TCF_COMPILE_N_GO | TCF_NO_SCRIPT_RVAL
: TCF_COMPILE_N_GO,

View File

@ -1155,19 +1155,12 @@ JS_GetFrameFunction(JSContext *cx, JSStackFrame *fp)
JS_PUBLIC_API(JSObject *)
JS_GetFrameFunctionObject(JSContext *cx, JSStackFrame *fp)
{
/*
* Test both fp->fun and fp->argv to defend against any control flow from
* the compiler reaching this API entry point, where fp is a frame pushed
* by the compiler that has non-null fun but null argv.
*/
if (fp->fun && fp->argv) {
JSObject *obj = fp->callee;
if (!fp->fun)
return NULL;
JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_FunctionClass);
JS_ASSERT(OBJ_GET_PRIVATE(cx, obj) == fp->fun);
return obj;
}
return NULL;
JS_ASSERT(OBJ_GET_CLASS(cx, fp->callee) == &js_FunctionClass);
JS_ASSERT(OBJ_GET_PRIVATE(cx, fp->callee) == fp->fun);
return fp->callee;
}
JS_PUBLIC_API(JSBool)
@ -1252,7 +1245,6 @@ JS_EvaluateUCInStackFrame(JSContext *cx, JSStackFrame *fp,
jsval *rval)
{
JSObject *scobj;
uint32 flags;
JSScript *script;
JSBool ok;
@ -1260,18 +1252,11 @@ JS_EvaluateUCInStackFrame(JSContext *cx, JSStackFrame *fp,
if (!scobj)
return JS_FALSE;
/*
* XXX Hack around ancient compiler API to propagate the JSFRAME_SPECIAL
* flags to the code generator.
*/
flags = fp->flags;
fp->flags |= JSFRAME_DEBUGGER | JSFRAME_EVAL;
script = js_CompileScript(cx, scobj, JS_StackFramePrincipals(cx, fp),
script = js_CompileScript(cx, scobj, fp, JS_StackFramePrincipals(cx, fp),
TCF_COMPILE_N_GO |
TCF_PUT_STATIC_DEPTH(fp->script->staticDepth + 1),
chars, length, NULL,
filename, lineno);
fp->flags = flags;
if (!script)
return JS_FALSE;

View File

@ -1575,8 +1575,7 @@ LookupCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom,
*/
*vp = JSVAL_HOLE;
do {
if ((cg->treeContext.flags & TCF_IN_FUNCTION) ||
cx->fp->varobj == cx->fp->scopeChain) {
if (cg->treeContext.flags & (TCF_IN_FUNCTION | TCF_COMPILE_N_GO)) {
/* XXX this will need revising when 'let const' is added. */
stmt = js_LexicalLookup(&cg->treeContext, atom, NULL);
if (stmt)
@ -1597,12 +1596,13 @@ LookupCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom,
* nor can prop be deleted.
*/
if (cg->treeContext.flags & TCF_IN_FUNCTION) {
if (js_LookupLocal(cx, cg->treeContext.fun, atom, NULL) !=
if (js_LookupLocal(cx, cg->treeContext.u.fun, atom, NULL) !=
JSLOCAL_NONE) {
break;
}
} else if (cg->treeContext.flags & TCF_COMPILE_N_GO) {
obj = cx->fp->varobj;
} else {
JS_ASSERT(cg->treeContext.flags & TCF_COMPILE_N_GO);
obj = cg->treeContext.u.scopeChain;
ok = OBJ_LOOKUP_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &pobj,
&prop);
if (!ok)
@ -1780,7 +1780,7 @@ AdjustBlockSlot(JSContext *cx, JSCodeGenerator *cg, jsint slot)
{
JS_ASSERT((jsuint) slot < cg->maxStackDepth);
if (cg->treeContext.flags & TCF_IN_FUNCTION) {
slot += cg->treeContext.fun->u.i.nvars;
slot += cg->treeContext.u.fun->u.i.nvars;
if ((uintN) slot >= SLOTNO_LIMIT) {
js_ReportCompileErrorNumber(cx, CG_TS(cg), NULL,
JSREPORT_ERROR,
@ -1817,7 +1817,6 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
JSStmtInfo *stmt;
jsint slot;
JSOp op;
JSStackFrame *fp;
JSLocalKind localKind;
uintN index;
JSAtomListElement *ale;
@ -1877,80 +1876,65 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
return JS_TRUE;
if (!(tc->flags & TCF_IN_FUNCTION)) {
if ((cx->fp->flags & JSFRAME_SPECIAL) && cx->fp->fun) {
if (cg->staticDepth > JS_DISPLAY_SIZE)
goto out;
JSStackFrame *caller;
localKind = js_LookupLocal(cx, cx->fp->fun, atom, &index);
if (localKind != JSLOCAL_NONE) {
if (PN_OP(pn) == JSOP_NAME) {
ATOM_LIST_SEARCH(ale, &cg->upvarList, atom);
if (!ale) {
uint32 cookie, length, *vector;
caller = tc->parseContext->callerFrame;
if (caller) {
JS_ASSERT(tc->flags & TCF_COMPILE_N_GO);
JS_ASSERT(caller->script);
if (!caller->fun || caller->varobj != tc->u.scopeChain)
return JS_TRUE;
ale = js_IndexAtom(cx, atom, &cg->upvarList);
if (!ale)
return JS_FALSE;
JS_ASSERT(ALE_INDEX(ale) == cg->upvarList.count - 1);
/*
* We are compiling eval or debug script inside a function frame
* and the scope chain matches function's variable object.
* Optimize access to function's arguments and variable and the
* arguments object.
*/
if (PN_OP(pn) != JSOP_NAME || cg->staticDepth > JS_DISPLAY_SIZE)
goto arguments_check;
localKind = js_LookupLocal(cx, caller->fun, atom, &index);
if (localKind == JSLOCAL_NONE)
goto arguments_check;
length = cg->upvarMap.length;
JS_ASSERT(ALE_INDEX(ale) <= length);
if (ALE_INDEX(ale) == length) {
length = 2 * JS_MAX(2, length);
vector = (uint32 *)
JS_realloc(cx, cg->upvarMap.vector,
length * sizeof *vector);
if (!vector)
return JS_FALSE;
cg->upvarMap.vector = vector;
cg->upvarMap.length = length;
}
ATOM_LIST_SEARCH(ale, &cg->upvarList, atom);
if (!ale) {
uint32 cookie, length, *vector;
if (localKind != JSLOCAL_ARG)
index += cx->fp->fun->nargs;
if (index >= JS_BIT(16)) {
cg->treeContext.flags |= TCF_FUN_USES_NONLOCALS;
return JS_TRUE;
}
ale = js_IndexAtom(cx, atom, &cg->upvarList);
if (!ale)
return JS_FALSE;
JS_ASSERT(ALE_INDEX(ale) == cg->upvarList.count - 1);
cookie = MAKE_UPVAR_COOKIE(1, index);
cg->upvarMap.vector[ALE_INDEX(ale)] = cookie;
}
length = cg->upvarMap.length;
JS_ASSERT(ALE_INDEX(ale) <= length);
if (ALE_INDEX(ale) == length) {
length = 2 * JS_MAX(2, length);
vector = (uint32 *)
JS_realloc(cx, cg->upvarMap.vector,
length * sizeof *vector);
if (!vector)
return JS_FALSE;
cg->upvarMap.vector = vector;
cg->upvarMap.length = length;
}
pn->pn_op = JSOP_GETUPVAR;
pn->pn_slot = ALE_INDEX(ale);
if (localKind != JSLOCAL_ARG)
index += caller->fun->nargs;
if (index >= JS_BIT(16)) {
cg->treeContext.flags |= TCF_FUN_USES_NONLOCALS;
return JS_TRUE;
}
cookie = MAKE_UPVAR_COOKIE(1, index);
cg->upvarMap.vector[ALE_INDEX(ale)] = cookie;
}
goto out;
pn->pn_op = JSOP_GETUPVAR;
pn->pn_slot = ALE_INDEX(ale);
return JS_TRUE;
}
/*
* We are compiling a script or eval, and eval is not inside a function
* activation.
*/
fp = cx->fp;
if (fp->scopeChain != fp->varobj)
return JS_TRUE;
/*
* A Script object can be used to split an eval into a compile step
* done at construction time, and an execute step done separately,
* possibly in a different scope altogether. We therefore cannot do
* any name-to-slot optimizations, but must lookup names at runtime.
* Note that script_exec ensures that its caller's frame has a Call
* object, so arg and var name lookups will succeed.
*/
if (fp->flags & JSFRAME_SCRIPT_OBJECT)
return JS_TRUE;
/*
* We cannot optimize the name access when compiling with an eval or
* debugger frame.
*/
if (fp->flags & JSFRAME_SPECIAL)
return JS_TRUE;
/*
* We are optimizing global variables and there may be no pre-existing
* global property named atom. If atom was declared via const or var,
@ -2003,7 +1987,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
* to stack slot. Look for an argument or variable in the function and
* rewrite pn_op and update pn accordingly.
*/
localKind = js_LookupLocal(cx, tc->fun, atom, &index);
localKind = js_LookupLocal(cx, tc->u.fun, atom, &index);
if (localKind != JSLOCAL_NONE) {
op = PN_OP(pn);
if (localKind == JSLOCAL_ARG) {
@ -2043,17 +2027,17 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
tc->flags |= TCF_FUN_USES_NONLOCALS;
}
out:
arguments_check:
/*
* Here we either compiling a function body or an eval script inside a
* function and couldn't optimize pn, so it's not a global or local slot
* name.
*
* Now we must check for the predefined arguments variable. It may be
* overridden by assignment, in which case the function is heavyweight
* and the interpreter will look up 'arguments' in the function's call
* object.
* Here we either compiling a function body or an eval or debug script
* inside a function and couldn't optimize pn, so it's not a global or
* local slot name. We are also outside of any with blocks. Check if we
* can optimize the predefined arguments variable.
*/
JS_ASSERT((tc->flags & TCF_IN_FUNCTION) ||
(tc->parseContext->callerFrame &&
tc->parseContext->callerFrame->fun &&
tc->parseContext->callerFrame->varobj == tc->u.scopeChain));
if (pn->pn_op == JSOP_NAME &&
atom == cx->runtime->atomState.argumentsAtom) {
pn->pn_op = JSOP_ARGUMENTS;
@ -3182,11 +3166,6 @@ js_EmitFunctionScript(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body)
CG_SWITCH_TO_MAIN(cg);
}
if (!(cg->treeContext.flags & TCF_FUN_HEAVYWEIGHT) &&
(cg->treeContext.flags & TCF_COMPILE_N_GO)) {
STOBJ_SET_PARENT(FUN_OBJECT(cg->treeContext.fun), cx->fp->scopeChain);
}
return js_EmitTree(cx, cg, body) &&
js_Emit1(cx, cg, JSOP_STOP) >= 0 &&
js_NewScriptFromCG(cx, cg);
@ -4011,7 +3990,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
cg->codePool, cg->notePool,
pn->pn_pos.begin.lineno);
cg2->treeContext.flags = (uint16) (pn->pn_flags | TCF_IN_FUNCTION);
cg2->treeContext.fun = fun;
cg2->treeContext.u.fun = fun;
cg2->staticDepth = cg->staticDepth + 1;
cg2->parent = cg;
@ -4066,7 +4045,9 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
* instantiating top-level functions in the non-eval case.
*/
JS_ASSERT(!cg->treeContext.topStmt);
op = (cx->fp->flags & JSFRAME_EVAL) ? JSOP_CLOSURE : JSOP_DEFFUN;
op = (cg->treeContext.parseContext->callerFrame)
? JSOP_CLOSURE
: JSOP_DEFFUN;
EMIT_INDEX_OP(op, index);
CG_SWITCH_TO_MAIN(cg);
@ -4077,7 +4058,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
#ifdef DEBUG
JSLocalKind localKind =
#endif
js_LookupLocal(cx, cg->treeContext.fun, fun->atom, &slot);
js_LookupLocal(cx, cg->treeContext.u.fun, fun->atom, &slot);
JS_ASSERT(localKind == JSLOCAL_VAR || localKind == JSLOCAL_CONST);
JS_ASSERT(pn->pn_index == (uint32) -1);
pn->pn_index = index;

View File

@ -171,8 +171,14 @@ struct JSTreeContext { /* tree context for semantic checks */
XXX combine with blockChain? */
JSAtomList decls; /* function, const, and var declarations */
JSParseContext *parseContext;
JSFunction *fun; /* function to store argument and variable
union {
JSFunction *fun; /* function to store argument and variable
names when flags & TCF_IN_FUNCTION */
JSObject *scopeChain; /* scope chain object for the script */
} u;
#ifdef JS_SCOPE_DEPTH_METER
uint16 scopeDepth; /* current lexical scope chain depth */
uint16 maxScopeDepth; /* maximum lexical scope chain depth */
@ -195,7 +201,6 @@ struct JSTreeContext { /* tree context for semantic checks */
chain */
#define TCF_NO_SCRIPT_RVAL 0x1000 /* API caller does not want result value
from global script */
/*
* Flags to propagate out of the blocks.
*/
@ -230,7 +235,7 @@ struct JSTreeContext { /* tree context for semantic checks */
ATOM_LIST_INIT(&(tc)->decls), \
(tc)->blockNode = NULL, \
(tc)->parseContext = (pc), \
(tc)->fun = NULL, \
(tc)->u.scopeChain = NULL, \
JS_SCOPE_DEPTH_METERING((tc)->scopeDepth = (tc)->maxScopeDepth = 0))
/*

View File

@ -791,7 +791,7 @@ CallPropertyOp(JSContext *cx, JSObject *obj, jsid id, jsval *vp,
}
}
return JS_TRUE;
}
}
JS_ASSERT((int16) JSVAL_TO_INT(id) == JSVAL_TO_INT(id));
i = (uint16) JSVAL_TO_INT(id);

View File

@ -128,12 +128,11 @@ typedef struct JSInlineFrame {
is currently assigning to a property */
#define JSFRAME_DEBUGGER 0x08 /* frame for JS_EvaluateInStackFrame */
#define JSFRAME_EVAL 0x10 /* frame for obj_eval */
#define JSFRAME_SCRIPT_OBJECT 0x20 /* compiling source for a Script object */
#define JSFRAME_ROOTED_ARGV 0x20 /* frame.argv is rooted by the caller */
#define JSFRAME_YIELDING 0x40 /* js_Interpret dispatched JSOP_YIELD */
#define JSFRAME_ITERATOR 0x80 /* trying to get an iterator for for-in */
#define JSFRAME_POP_BLOCKS 0x100 /* scope chain contains blocks to pop */
#define JSFRAME_GENERATOR 0x200 /* frame belongs to generator-iterator */
#define JSFRAME_ROOTED_ARGV 0x400 /* frame.argv is rooted by the caller */
#define JSFRAME_OVERRIDE_SHIFT 24 /* override bit-set params; see jsfun.c */
#define JSFRAME_OVERRIDE_BITS 8

View File

@ -1176,6 +1176,7 @@ js_obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
const char *file;
uintN line;
JSPrincipals *principals;
uint32 tcflags;
JSScript *script;
JSBool ok;
#if JS_HAS_EVAL_THIS_SCOPE
@ -1306,21 +1307,10 @@ js_obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
principals = NULL;
}
/*
* Set JSFRAME_EVAL on fp and any frames (e.g., fun_call if eval.call was
* invoked) between fp and its scripted caller, to help the compiler easily
* find the same caller whose scope and var obj we've set.
*
* XXX this nonsense could, and perhaps should, go away with a better way
* to pass params to the compiler than via the top-most frame.
*/
do {
fp->flags |= JSFRAME_EVAL;
} while ((fp = fp->down) != caller);
script = js_CompileScript(cx, scopeobj, principals,
TCF_COMPILE_N_GO |
TCF_PUT_STATIC_DEPTH(caller->script->staticDepth + 1),
tcflags = TCF_COMPILE_N_GO;
if (caller)
tcflags |= TCF_PUT_STATIC_DEPTH(caller->script->staticDepth + 1);
script = js_CompileScript(cx, scopeobj, caller, principals, tcflags,
JSSTRING_CHARS(str), JSSTRING_LENGTH(str),
NULL, file, line);
if (!script) {

View File

@ -158,9 +158,12 @@ static uint32 recyclednodes = 0;
JSBool
js_InitParseContext(JSContext *cx, JSParseContext *pc, JSPrincipals *principals,
JSStackFrame *callerFrame,
const jschar *base, size_t length,
FILE *fp, const char *filename, uintN lineno)
{
JS_ASSERT_IF(callerFrame, callerFrame->script);
pc->tempPoolMark = JS_ARENA_MARK(&cx->tempPool);
if (!js_InitTokenStream(cx, TS(pc), base, length, fp, filename, lineno)) {
JS_ARENA_RELEASE(&cx->tempPool, pc->tempPoolMark);
@ -169,6 +172,7 @@ js_InitParseContext(JSContext *cx, JSParseContext *pc, JSPrincipals *principals,
if (principals)
JSPRINCIPALS_HOLD(cx, principals);
pc->principals = principals;
pc->callerFrame = callerFrame;
pc->nodeList = NULL;
pc->traceListHead = NULL;
@ -455,70 +459,15 @@ CheckGetterOrSetter(JSContext *cx, JSTokenStream *ts, JSTokenType tt)
}
#endif
static void
MaybeSetupFrame(JSContext *cx, JSObject *chain, JSStackFrame *oldfp,
JSStackFrame *newfp)
{
/*
* Always push a new frame if the current frame is special, so that
* Variables gets the correct variables object: the one from the special
* frame's caller.
*/
if (oldfp &&
oldfp->varobj &&
oldfp->scopeChain == chain &&
!(oldfp->flags & JSFRAME_SPECIAL)) {
return;
}
memset(newfp, 0, sizeof *newfp);
/* Default to sharing the same variables object and scope chain. */
newfp->varobj = newfp->scopeChain = chain;
if (cx->options & JSOPTION_VAROBJFIX) {
while ((chain = JS_GetParent(cx, chain)) != NULL)
newfp->varobj = chain;
}
newfp->down = oldfp;
if (oldfp) {
/*
* In the case of eval and debugger frames, we need to dig down and find
* the real variables objects and function that our new stack frame is
* going to use.
*/
newfp->flags = oldfp->flags & (JSFRAME_SPECIAL | JSFRAME_SCRIPT_OBJECT);
while (oldfp->flags & JSFRAME_SPECIAL) {
oldfp = oldfp->down;
if (!oldfp)
break;
}
if (oldfp && (newfp->flags & JSFRAME_SPECIAL)) {
newfp->varobj = oldfp->varobj;
newfp->callee = oldfp->callee;
newfp->fun = oldfp->fun;
}
}
cx->fp = newfp;
}
/*
* Parse a top-level JS script.
*/
JSParseNode *
js_ParseScript(JSContext *cx, JSObject *chain, JSParseContext *pc)
{
JSStackFrame *fp, frame;
JSTreeContext tc;
JSParseNode *pn;
/*
* Push a compiler frame if we have no frames, or if the top frame is a
* lightweight function activation, or if its scope chain doesn't match
* the one passed to us.
*/
fp = cx->fp;
MaybeSetupFrame(cx, chain, fp, &frame);
/*
* Protect atoms from being collected by a GC activation, which might
* - nest on this thread due to out of memory (the so-called "last ditch"
@ -528,6 +477,7 @@ js_ParseScript(JSContext *cx, JSObject *chain, JSParseContext *pc)
* protected from the GC by a root or a stack frame reference.
*/
TREE_CONTEXT_INIT(&tc, pc);
tc.u.scopeChain = chain;
pn = Statements(cx, TS(pc), &tc);
if (pn) {
if (!js_MatchToken(cx, TS(pc), TOK_EOF)) {
@ -542,20 +492,19 @@ js_ParseScript(JSContext *cx, JSObject *chain, JSParseContext *pc)
}
TREE_CONTEXT_FINISH(cx, &tc);
cx->fp = fp;
return pn;
}
/*
* Compile a top-level script.
*/
JSScript *
js_CompileScript(JSContext *cx, JSObject *obj, JSPrincipals *principals,
uint32 tcflags, const jschar *chars, size_t length,
extern JSScript *
js_CompileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *callerFrame,
JSPrincipals *principals, uint32 tcflags,
const jschar *chars, size_t length,
FILE *file, const char *filename, uintN lineno)
{
JSParseContext pc;
JSStackFrame *fp, frame;
JSArenaPool codePool, notePool;
JSCodeGenerator cg;
JSTokenType tt;
@ -566,22 +515,20 @@ js_CompileScript(JSContext *cx, JSObject *obj, JSPrincipals *principals,
void *sbrk(ptrdiff_t), *before = sbrk(0);
#endif
JS_ASSERT(!(tcflags & ~(TCF_COMPILE_N_GO | TCF_NO_SCRIPT_RVAL | TCF_STATIC_DEPTH_MASK)));
if (!js_InitParseContext(cx, &pc, principals, chars, length, file,
filename, lineno)) {
return NULL;
}
JS_ASSERT(!(tcflags & ~(TCF_COMPILE_N_GO | TCF_NO_SCRIPT_RVAL |
TCF_STATIC_DEPTH_MASK)));
/*
* From this point the control must flow through the label out.
*
* Push a compiler frame if we have no frames, or if the top frame is a
* lightweight function activation, or if its scope chain doesn't match
* the one passed to us.
* The scripted callerFrame can only be given for compile-and-go scripts
* and non-zero static depth requires callerFrame.
*/
fp = cx->fp;
MaybeSetupFrame(cx, obj, fp, &frame);
JS_ASSERT_IF(callerFrame, tcflags & TCF_COMPILE_N_GO);
JS_ASSERT_IF(TCF_GET_STATIC_DEPTH(tcflags) != 0, callerFrame);
if (!js_InitParseContext(cx, &pc, principals, callerFrame, chars, length,
file, filename, lineno)) {
return NULL;
}
JS_INIT_ARENA_POOL(&codePool, "code", 1024, sizeof(jsbytecode),
&cx->scriptStackQuota);
@ -592,11 +539,10 @@ js_CompileScript(JSContext *cx, JSObject *obj, JSPrincipals *principals,
/* From this point the control must flow via the label out. */
cg.treeContext.flags |= (uint16) tcflags;
cg.treeContext.u.scopeChain = scopeChain;
cg.staticDepth = TCF_GET_STATIC_DEPTH(tcflags);
/*
* Inline Statements() to emit as we go to save space.
*/
/* Inline Statements() to emit as we go to save space. */
for (;;) {
pc.tokenStream.flags |= TSF_OPERAND;
tt = js_PeekToken(cx, &pc.tokenStream);
@ -614,7 +560,6 @@ js_CompileScript(JSContext *cx, JSObject *obj, JSPrincipals *principals,
script = NULL;
goto out;
}
JS_ASSERT(!cg.treeContext.blockNode);
if (!js_FoldConstants(cx, pn, &cg.treeContext) ||
@ -692,9 +637,9 @@ js_CompileScript(JSContext *cx, JSObject *obj, JSPrincipals *principals,
#ifdef JS_SCOPE_DEPTH_METER
if (script) {
JSObject *pobj = obj;
JSObject *obj = scopeChain;
uintN depth = 1;
while ((pobj = OBJ_GET_PARENT(cx, pobj)) != NULL)
while ((obj = OBJ_GET_PARENT(cx, obj)) != NULL)
++depth;
JS_BASIC_STATS_ACCUM(&cx->runtime->hostenvScopeDepthStats, depth);
}
@ -704,7 +649,6 @@ js_CompileScript(JSContext *cx, JSObject *obj, JSPrincipals *principals,
js_FinishCodeGenerator(cx, &cg);
JS_FinishArenaPool(&codePool);
JS_FinishArenaPool(&notePool);
cx->fp = fp;
js_FinishParseContext(cx, &pc);
return script;
@ -849,8 +793,8 @@ ReportBadReturn(JSContext *cx, JSTreeContext *tc, uintN flags, uintN errnum,
const char *name;
JS_ASSERT(tc->flags & TCF_IN_FUNCTION);
if (tc->fun->atom) {
name = js_AtomToPrintableString(cx, tc->fun->atom);
if (tc->u.fun->atom) {
name = js_AtomToPrintableString(cx, tc->u.fun->atom);
} else {
errnum = anonerrnum;
name = NULL;
@ -944,7 +888,7 @@ js_CompileFunctionBody(JSContext *cx, JSFunction *fun, JSPrincipals *principals,
JSCodeGenerator funcg;
JSParseNode *pn;
if (!js_InitParseContext(cx, &pc, principals, chars, length, NULL,
if (!js_InitParseContext(cx, &pc, principals, NULL, chars, length, NULL,
filename, lineno)) {
return JS_FALSE;
}
@ -957,7 +901,7 @@ js_CompileFunctionBody(JSContext *cx, JSFunction *fun, JSPrincipals *principals,
js_InitCodeGenerator(cx, &funcg, &pc, &codePool, &notePool,
pc.tokenStream.lineno);
funcg.treeContext.flags |= TCF_IN_FUNCTION;
funcg.treeContext.fun = fun;
funcg.treeContext.u.fun = fun;
/*
* Farble the body so that it looks like a block statement to js_EmitTree,
@ -1025,7 +969,7 @@ BindArg(JSContext *cx, JSAtom *atom, JSTreeContext *tc)
* Check for a duplicate parameter name, a "feature" required by ECMA-262.
*/
JS_ASSERT(tc->flags & TCF_IN_FUNCTION);
if (js_LookupLocal(cx, tc->fun, atom, NULL) != JSLOCAL_NONE) {
if (js_LookupLocal(cx, tc->u.fun, atom, NULL) != JSLOCAL_NONE) {
name = js_AtomToPrintableString(cx, atom);
if (!name ||
!js_ReportCompileErrorNumber(cx, TS(tc->parseContext), NULL,
@ -1036,7 +980,7 @@ BindArg(JSContext *cx, JSAtom *atom, JSTreeContext *tc)
}
}
return js_AddLocal(cx, tc->fun, atom, JSLOCAL_ARG);
return js_AddLocal(cx, tc->u.fun, atom, JSLOCAL_ARG);
}
static JSBool
@ -1081,7 +1025,7 @@ BindDestructuringArg(JSContext *cx, BindData *data, JSAtom *atom,
ALE_SET_JSOP(ale, data->op);
}
if (js_LookupLocal(cx, tc->fun, atom, NULL) != JSLOCAL_NONE) {
if (js_LookupLocal(cx, tc->u.fun, atom, NULL) != JSLOCAL_NONE) {
name = js_AtomToPrintableString(cx, atom);
if (!name ||
!js_ReportCompileErrorNumber(cx, TS(tc->parseContext), data->pn,
@ -1091,7 +1035,7 @@ BindDestructuringArg(JSContext *cx, BindData *data, JSAtom *atom,
return JS_FALSE;
}
} else {
if (!BindLocalVariable(cx, tc->fun, atom, JSLOCAL_VAR))
if (!BindLocalVariable(cx, tc->u.fun, atom, JSLOCAL_VAR))
return JS_FALSE;
}
return JS_TRUE;
@ -1106,7 +1050,9 @@ NewCompilerFunction(JSContext *cx, JSTreeContext *tc, JSAtom *atom,
JSFunction *fun;
JS_ASSERT((lambda & ~JSFUN_LAMBDA) == 0);
parent = (tc->flags & TCF_IN_FUNCTION) ? FUN_OBJECT(tc->fun) : cx->fp->varobj;
parent = (tc->flags & TCF_IN_FUNCTION)
? FUN_OBJECT(tc->u.fun)
: tc->u.scopeChain;
fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED | lambda,
parent, atom);
if (fun && !(tc->flags & TCF_COMPILE_N_GO)) {
@ -1213,9 +1159,9 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
* variable even if the parameter with the given name already
* exists.
*/
localKind = js_LookupLocal(cx, tc->fun, funAtom, NULL);
localKind = js_LookupLocal(cx, tc->u.fun, funAtom, NULL);
if (localKind == JSLOCAL_NONE || localKind == JSLOCAL_ARG) {
if (!js_AddLocal(cx, tc->fun, funAtom, JSLOCAL_VAR))
if (!js_AddLocal(cx, tc->u.fun, funAtom, JSLOCAL_VAR))
return NULL;
}
}
@ -1241,7 +1187,7 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
/* Initialize early for possible flags mutation via DestructuringExpr. */
TREE_CONTEXT_INIT(&funtc, tc->parseContext);
funtc.flags |= TCF_IN_FUNCTION | (tc->flags & TCF_COMPILE_N_GO);
funtc.fun = fun;
funtc.u.fun = fun;
/* Now parse formal argument list and compute fun->nargs. */
MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_FORMAL);
@ -1680,7 +1626,7 @@ BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc)
return JS_TRUE;
}
localKind = js_LookupLocal(cx, tc->fun, atom, NULL);
localKind = js_LookupLocal(cx, tc->u.fun, atom, NULL);
if (localKind == JSLOCAL_NONE) {
/*
* Property not found in current variable scope: we have not seen this
@ -1692,7 +1638,7 @@ BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc)
*/
localKind = (data->op == JSOP_DEFCONST) ? JSLOCAL_CONST : JSLOCAL_VAR;
if (!js_InWithStatement(tc) &&
!BindLocalVariable(cx, tc->fun, atom, localKind)) {
!BindLocalVariable(cx, tc->u.fun, atom, localKind)) {
return JS_FALSE;
}
} else if (localKind == JSLOCAL_ARG) {
@ -3455,7 +3401,6 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
JSStmtInfo *scopeStmt;
BindData data;
JSParseNode *pn, *pn2;
JSStackFrame *fp;
JSAtom *atom;
/*
@ -3495,7 +3440,6 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
* this by looking up the variable's id in the current variable object.
* Fortunately, we can avoid doing this for let declared variables.
*/
fp = cx->fp;
if (let) {
JS_ASSERT(tc->blockChain == scopeStmt->u.blockObj);
data.binder = BindLet;
@ -5206,7 +5150,6 @@ JS_FRIEND_API(JSParseNode *)
js_ParseXMLText(JSContext *cx, JSObject *chain, JSParseContext *pc,
JSBool allowList)
{
JSStackFrame *fp, frame;
JSParseNode *pn;
JSTreeContext tc;
JSTokenType tt;
@ -5216,9 +5159,8 @@ js_ParseXMLText(JSContext *cx, JSObject *chain, JSParseContext *pc,
* lightweight function activation, or if its scope chain doesn't match
* the one passed to us.
*/
fp = cx->fp;
MaybeSetupFrame(cx, chain, fp, &frame);
TREE_CONTEXT_INIT(&tc, pc);
tc.u.scopeChain = chain;
/* Set XML-only mode to turn off special treatment of {expr} in XML. */
TS(pc)->flags |= TSF_OPERAND | TSF_XMLONLYMODE;
@ -5235,7 +5177,6 @@ js_ParseXMLText(JSContext *cx, JSObject *chain, JSParseContext *pc,
TS(pc)->flags &= ~TSF_XMLONLYMODE;
TREE_CONTEXT_FINISH(cx, &tc);
cx->fp = fp;
return pn;
}

View File

@ -432,6 +432,8 @@ struct JSParseContext {
JSTokenStream tokenStream;
void *tempPoolMark; /* initial JSContext.tempPool mark */
JSPrincipals *principals; /* principals associated with source */
JSStackFrame *callerFrame; /* scripted caller frame for eval and
debug scripts */
JSParseNode *nodeList; /* list of recyclable parse-node
structs */
JSParsedObjectBox *traceListHead; /* list of parsed object for GC
@ -451,8 +453,9 @@ extern JSParseNode *
js_ParseScript(JSContext *cx, JSObject *chain, JSParseContext *pc);
extern JSScript *
js_CompileScript(JSContext *cx, JSObject *obj, JSPrincipals *principals,
uint32 tcflags, const jschar *chars, size_t length,
js_CompileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *callerFrame,
JSPrincipals *principals, uint32 tcflags,
const jschar *chars, size_t length,
FILE *file, const char *filename, uintN lineno);
extern JSBool
@ -479,6 +482,7 @@ js_ParseXMLText(JSContext *cx, JSObject *chain, JSParseContext *pc,
*/
extern JSBool
js_InitParseContext(JSContext *cx, JSParseContext *pc, JSPrincipals *principals,
JSStackFrame *callerFrame,
const jschar *base, size_t length, FILE *fp,
const char *filename, uintN lineno);

View File

@ -58,6 +58,7 @@
#include "jsnum.h"
#include "jsopcode.h"
#include "jsparse.h"
#include "jsscope.h"
#include "jsscript.h"
#if JS_HAS_XDR
#include "jsxdrapi.h"
@ -200,7 +201,7 @@ script_compile_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
JSObject *scopeobj;
jsval v;
JSScript *script, *oldscript;
JSStackFrame *fp, *caller;
JSStackFrame *caller;
const char *file;
uintN line;
JSPrincipals *principals;
@ -229,19 +230,17 @@ script_compile_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
}
/* Compile using the caller's scope chain, which js_Invoke passes to fp. */
fp = cx->fp;
caller = JS_GetScriptedCaller(cx, fp);
JS_ASSERT(!caller || fp->scopeChain == caller->scopeChain);
caller = JS_GetScriptedCaller(cx, cx->fp);
JS_ASSERT(!caller || cx->fp->scopeChain == caller->scopeChain);
if (caller) {
if (!scopeobj) {
scopeobj = js_GetScopeChain(cx, caller);
if (!scopeobj)
return JS_FALSE;
fp->scopeChain = scopeobj; /* for the compiler's benefit */
}
principals = JS_EvalFramePrincipals(cx, fp, caller);
principals = JS_EvalFramePrincipals(cx, cx->fp, caller);
file = js_ComputeFilename(cx, caller, principals, &line);
} else {
file = NULL;
@ -257,14 +256,13 @@ script_compile_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
/*
* Compile the new script using the caller's scope chain, a la eval().
* Unlike jsobj.c:obj_eval, however, we do not pass TCF_COMPILE_N_GO in
* tcflags, because compilation is here separated from execution, and the
* run-time scope chain may not match the compile-time. JSFRAME_EVAL is
* tested in jsemit.c and jsscan.c to optimize based on identity of run-
* and compile-time scope.
* tcflags and use NULL for the callerFrame argument, because compilation
* is here separated from execution, and the run-time scope chain may not
* match the compile-time. TCF_COMPILE_N_GO is tested in jsemit.c and
* jsparse.c to optimize based on identity of run- and compile-time scope.
*/
fp->flags |= JSFRAME_SCRIPT_OBJECT;
tcflags = caller ? TCF_PUT_STATIC_DEPTH(caller->staticDepth + 1) : 0;
script = js_CompileScript(cx, scopeobj, principals, tcflags,
tcflags = 0;
script = js_CompileScript(cx, scopeobj, NULL, principals, tcflags,
JSSTRING_CHARS(str), JSSTRING_LENGTH(str),
NULL, file, line);
if (!script)
@ -839,14 +837,14 @@ static const char js_thaw_str[] = "thaw";
static JSFunctionSpec script_methods[] = {
#if JS_HAS_TOSOURCE
JS_FN(js_toSource_str, script_toSource, 0,0,0),
JS_FN(js_toSource_str, script_toSource, 0,0),
#endif
JS_FN(js_toString_str, script_toString, 0,0,0),
JS_FN("compile", script_compile, 0,2,0),
JS_FN("exec", script_exec, 0,1,0),
JS_FN(js_toString_str, script_toString, 0,0),
JS_FN("compile", script_compile, 2,0),
JS_FN("exec", script_exec, 1,0),
#if JS_HAS_XDR_FREEZE_THAW
JS_FN("freeze", script_freeze, 0,0,0),
JS_FN(js_thaw_str, script_thaw, 0,1,0),
JS_FN("freeze", script_freeze, 0,0),
JS_FN(js_thaw_str, script_thaw, 1,0),
#endif /* JS_HAS_XDR_FREEZE_THAW */
JS_FS_END
};
@ -932,14 +930,14 @@ script_static_thaw(JSContext *cx, uintN argc, jsval *vp)
if (!obj)
return JS_FALSE;
vp[1] = OBJECT_TO_JSVAL(obj);
if (!script_thaw(cx, vp))
if (!script_thaw(cx, argc, vp))
return JS_FALSE;
*vp = OBJECT_TO_JSVAL(obj);
return JS_TRUE;
}
static JSFunctionSpec script_static_methods[] = {
JS_FN(js_thaw_str, script_static_thaw, 1,1,0),
JS_FN(js_thaw_str, script_static_thaw, 1,0),
JS_FS_END
};
@ -1473,7 +1471,7 @@ js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
memcpy(script->code, CG_PROLOG_BASE(cg), prologLength * sizeof(jsbytecode));
memcpy(script->main, CG_BASE(cg), mainLength * sizeof(jsbytecode));
nfixed = (cg->treeContext.flags & TCF_IN_FUNCTION)
? cg->treeContext.fun->u.i.nvars
? cg->treeContext.u.fun->u.i.nvars
: cg->treeContext.ngvars + cg->regexpList.length;
JS_ASSERT(nfixed < SLOTNO_LIMIT);
script->nfixed = (uint16) nfixed;
@ -1523,7 +1521,7 @@ js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
*/
fun = NULL;
if (cg->treeContext.flags & TCF_IN_FUNCTION) {
fun = cg->treeContext.fun;
fun = cg->treeContext.u.fun;
JS_ASSERT(FUN_INTERPRETED(fun) && !FUN_SCRIPT(fun));
JS_ASSERT_IF(script->upvarsOffset != 0,
JS_SCRIPT_UPVARS(script)->length == fun->u.i.nupvars);

View File

@ -1887,7 +1887,7 @@ ParseXMLSource(JSContext *cx, JSString *src)
}
}
if (!js_InitParseContext(cx, &pc, NULL, chars, length, NULL,
if (!js_InitParseContext(cx, &pc, NULL, NULL, chars, length, NULL,
filename, lineno))
goto out;
pn = js_ParseXMLText(cx, cx->fp->scopeChain, &pc, JS_FALSE);