mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 403878: No compiler pseudo-frames when compiling functions. r,a=brendan
This commit is contained in:
parent
2dce87330b
commit
22c2a33a75
@ -4437,15 +4437,13 @@ JS_CompileUCScriptForPrincipals(JSContext *cx, JSObject *obj,
|
||||
const jschar *chars, size_t length,
|
||||
const char *filename, uintN lineno)
|
||||
{
|
||||
JSParseContext pc;
|
||||
uint32 tcflags;
|
||||
JSScript *script;
|
||||
|
||||
CHECK_REQUEST(cx);
|
||||
if (!js_InitParseContext(cx, &pc, chars, length, NULL, filename, lineno))
|
||||
return NULL;
|
||||
js_InitCompilePrincipals(cx, &pc, principals);
|
||||
script = js_CompileScript(cx, obj, &pc);
|
||||
js_FinishParseContext(cx, &pc);
|
||||
tcflags = JS_HAS_COMPILE_N_GO_OPTION(cx) ? TCF_COMPILE_N_GO : 0;
|
||||
script = js_CompileScript(cx, obj, principals, tcflags,
|
||||
chars, length, NULL, filename, lineno);
|
||||
LAST_FRAME_CHECKS(cx, script);
|
||||
return script;
|
||||
}
|
||||
@ -4471,7 +4469,7 @@ JS_BufferIsCompilableUnit(JSContext *cx, JSObject *obj,
|
||||
*/
|
||||
result = JS_TRUE;
|
||||
exnState = JS_SaveExceptionState(cx);
|
||||
if (js_InitParseContext(cx, &pc, chars, length, NULL, NULL, 1)) {
|
||||
if (js_InitParseContext(cx, &pc, NULL, chars, length, NULL, NULL, 1)) {
|
||||
older = JS_SetErrorReporter(cx, NULL);
|
||||
if (!js_ParseScript(cx, obj, &pc) &&
|
||||
(pc.tokenStream.flags & TSF_UNEXPECTED_EOF)) {
|
||||
@ -4494,7 +4492,7 @@ JS_PUBLIC_API(JSScript *)
|
||||
JS_CompileFile(JSContext *cx, JSObject *obj, const char *filename)
|
||||
{
|
||||
FILE *fp;
|
||||
JSParseContext pc;
|
||||
uint32 tcflags;
|
||||
JSScript *script;
|
||||
|
||||
CHECK_REQUEST(cx);
|
||||
@ -4509,12 +4507,9 @@ JS_CompileFile(JSContext *cx, JSObject *obj, const char *filename)
|
||||
}
|
||||
}
|
||||
|
||||
if (!js_InitParseContext(cx, &pc, NULL, 0, fp, filename, 1)) {
|
||||
script = NULL;
|
||||
} else {
|
||||
script = js_CompileScript(cx, obj, &pc);
|
||||
js_FinishParseContext(cx, &pc);
|
||||
}
|
||||
tcflags = JS_HAS_COMPILE_N_GO_OPTION(cx) ? TCF_COMPILE_N_GO : 0;
|
||||
script = js_CompileScript(cx, obj, NULL, tcflags,
|
||||
NULL, 0, fp, filename, 1);
|
||||
if (fp != stdin)
|
||||
fclose(fp);
|
||||
LAST_FRAME_CHECKS(cx, script);
|
||||
@ -4533,15 +4528,13 @@ JS_CompileFileHandleForPrincipals(JSContext *cx, JSObject *obj,
|
||||
const char *filename, FILE *file,
|
||||
JSPrincipals *principals)
|
||||
{
|
||||
JSParseContext pc;
|
||||
uint32 tcflags;
|
||||
JSScript *script;
|
||||
|
||||
CHECK_REQUEST(cx);
|
||||
if (!js_InitParseContext(cx, &pc, NULL, 0, file, filename, 1))
|
||||
return NULL;
|
||||
js_InitCompilePrincipals(cx, &pc, principals);
|
||||
script = js_CompileScript(cx, obj, &pc);
|
||||
js_FinishParseContext(cx, &pc);
|
||||
tcflags = JS_HAS_COMPILE_N_GO_OPTION(cx) ? TCF_COMPILE_N_GO : 0;
|
||||
script = js_CompileScript(cx, obj, principals, tcflags,
|
||||
NULL, 0, file, filename, 1);
|
||||
LAST_FRAME_CHECKS(cx, script);
|
||||
return script;
|
||||
}
|
||||
@ -4641,8 +4634,6 @@ JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj,
|
||||
JSFunction *fun;
|
||||
JSAtom *funAtom, *argAtom;
|
||||
uintN i;
|
||||
JSParseContext pc;
|
||||
JSBool ok;
|
||||
|
||||
CHECK_REQUEST(cx);
|
||||
if (!name) {
|
||||
@ -4669,13 +4660,8 @@ JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj,
|
||||
}
|
||||
}
|
||||
|
||||
ok = js_InitParseContext(cx, &pc, chars, length, NULL, filename, lineno);
|
||||
if (ok) {
|
||||
js_InitCompilePrincipals(cx, &pc, principals);
|
||||
ok = js_CompileFunctionBody(cx, &pc, fun);
|
||||
js_FinishParseContext(cx, &pc);
|
||||
}
|
||||
if (!ok) {
|
||||
if (!js_CompileFunctionBody(cx, fun, principals, chars, length,
|
||||
filename, lineno)) {
|
||||
fun = NULL;
|
||||
goto out;
|
||||
}
|
||||
@ -4856,16 +4842,12 @@ JS_EvaluateUCScriptForPrincipals(JSContext *cx, JSObject *obj,
|
||||
const char *filename, uintN lineno,
|
||||
jsval *rval)
|
||||
{
|
||||
uint32 options;
|
||||
JSScript *script;
|
||||
JSBool ok;
|
||||
|
||||
CHECK_REQUEST(cx);
|
||||
options = cx->options;
|
||||
cx->options = options | JSOPTION_COMPILE_N_GO;
|
||||
script = JS_CompileUCScriptForPrincipals(cx, obj, principals, chars, length,
|
||||
filename, lineno);
|
||||
cx->options = options;
|
||||
script = js_CompileScript(cx, obj, principals, TCF_COMPILE_N_GO,
|
||||
chars, length, NULL, filename, lineno);
|
||||
if (!script)
|
||||
return JS_FALSE;
|
||||
ok = js_Execute(cx, obj, script, NULL, 0, rval);
|
||||
|
@ -50,12 +50,14 @@
|
||||
#include "jscntxt.h"
|
||||
#include "jsconfig.h"
|
||||
#include "jsdbgapi.h"
|
||||
#include "jsemit.h"
|
||||
#include "jsfun.h"
|
||||
#include "jsgc.h"
|
||||
#include "jsinterp.h"
|
||||
#include "jslock.h"
|
||||
#include "jsobj.h"
|
||||
#include "jsopcode.h"
|
||||
#include "jsparse.h"
|
||||
#include "jsscope.h"
|
||||
#include "jsscript.h"
|
||||
#include "jsstr.h"
|
||||
@ -1202,7 +1204,7 @@ JS_EvaluateUCInStackFrame(JSContext *cx, JSStackFrame *fp,
|
||||
jsval *rval)
|
||||
{
|
||||
JSObject *scobj;
|
||||
uint32 flags, options;
|
||||
uint32 flags;
|
||||
JSScript *script;
|
||||
JSBool ok;
|
||||
|
||||
@ -1212,17 +1214,14 @@ JS_EvaluateUCInStackFrame(JSContext *cx, JSStackFrame *fp,
|
||||
|
||||
/*
|
||||
* XXX Hack around ancient compiler API to propagate the JSFRAME_SPECIAL
|
||||
* flags to the code generator (see js_EmitTree's TOK_SEMI case).
|
||||
* flags to the code generator.
|
||||
*/
|
||||
flags = fp->flags;
|
||||
fp->flags |= JSFRAME_DEBUGGER | JSFRAME_EVAL;
|
||||
options = cx->options;
|
||||
cx->options = options | JSOPTION_COMPILE_N_GO;
|
||||
script = JS_CompileUCScriptForPrincipals(cx, scobj,
|
||||
JS_StackFramePrincipals(cx, fp),
|
||||
chars, length, filename, lineno);
|
||||
script = js_CompileScript(cx, scobj, JS_StackFramePrincipals(cx, fp),
|
||||
TCF_COMPILE_N_GO, chars, length, NULL,
|
||||
filename, lineno);
|
||||
fp->flags = flags;
|
||||
cx->options = options;
|
||||
if (!script)
|
||||
return JS_FALSE;
|
||||
|
||||
|
151
js/src/jsemit.c
151
js/src/jsemit.c
@ -1608,7 +1608,6 @@ js_LookupCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom,
|
||||
jsval *vp)
|
||||
{
|
||||
JSBool ok;
|
||||
JSStackFrame *fp;
|
||||
JSStmtInfo *stmt;
|
||||
jsint slot;
|
||||
JSAtomListElement *ale;
|
||||
@ -1617,20 +1616,14 @@ js_LookupCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom,
|
||||
uintN attrs;
|
||||
|
||||
/*
|
||||
* fp chases cg down the stack, but only until we reach the outermost cg.
|
||||
* Chase down the cg stack, but only until we reach the outermost cg.
|
||||
* This enables propagating consts from top-level into switch cases in a
|
||||
* function compiled along with the top-level script. All stack frames
|
||||
* with matching code generators should be flagged with JSFRAME_COMPILING;
|
||||
* we check sanity here.
|
||||
* function compiled along with the top-level script.
|
||||
*/
|
||||
*vp = JSVAL_VOID;
|
||||
ok = JS_TRUE;
|
||||
fp = cx->fp;
|
||||
do {
|
||||
JS_ASSERT(fp->flags & JSFRAME_COMPILING);
|
||||
|
||||
obj = fp->varobj;
|
||||
if (obj == fp->scopeChain) {
|
||||
if ((cg->treeContext.flags & TCF_IN_FUNCTION) ||
|
||||
cx->fp->varobj == cx->fp->scopeChain) {
|
||||
/* XXX this will need revising when 'let const' is added. */
|
||||
stmt = js_LexicalLookup(&cg->treeContext, atom, &slot, 0);
|
||||
if (stmt)
|
||||
@ -1649,16 +1642,18 @@ js_LookupCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom,
|
||||
* with object or catch variable; nor can prop's value be changed,
|
||||
* nor can prop be deleted.
|
||||
*/
|
||||
if (OBJ_GET_CLASS(cx, obj) == &js_FunctionClass) {
|
||||
JS_ASSERT(fp->fun == GET_FUNCTION_PRIVATE(cx, obj));
|
||||
if (js_LookupLocal(cx, fp->fun, atom, NULL) != JSLOCAL_NONE)
|
||||
if (cg->treeContext.flags & TCF_IN_FUNCTION) {
|
||||
if (js_LookupLocal(cx, cg->treeContext.fun, atom, NULL) !=
|
||||
JSLOCAL_NONE) {
|
||||
break;
|
||||
}
|
||||
|
||||
ok = OBJ_LOOKUP_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &pobj, &prop);
|
||||
if (ok) {
|
||||
if (pobj == obj &&
|
||||
(fp->flags & (JSFRAME_EVAL | JSFRAME_COMPILE_N_GO))) {
|
||||
}
|
||||
} else if (cg->treeContext.flags & TCF_COMPILE_N_GO) {
|
||||
obj = cx->fp->varobj;
|
||||
ok = OBJ_LOOKUP_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &pobj,
|
||||
&prop);
|
||||
if (!ok)
|
||||
return JS_FALSE;
|
||||
if (pobj == obj) {
|
||||
/*
|
||||
* We're compiling code that will be executed immediately,
|
||||
* not re-executed against a different scope chain and/or
|
||||
@ -1672,13 +1667,14 @@ js_LookupCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom,
|
||||
}
|
||||
if (prop)
|
||||
OBJ_DROP_PROPERTY(cx, pobj, prop);
|
||||
if (!ok)
|
||||
return JS_FALSE;
|
||||
if (prop)
|
||||
break;
|
||||
}
|
||||
if (!ok || prop)
|
||||
break;
|
||||
}
|
||||
fp = fp->down;
|
||||
} while ((cg = cg->parent) != NULL);
|
||||
return ok;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1838,7 +1834,6 @@ BindNameToSlot(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
|
||||
jsint slot;
|
||||
JSOp op;
|
||||
JSStackFrame *fp;
|
||||
JSClass *clasp;
|
||||
JSLocalKind localKind;
|
||||
uintN index;
|
||||
JSAtomListElement *ale;
|
||||
@ -1884,18 +1879,6 @@ BindNameToSlot(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
|
||||
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.
|
||||
*/
|
||||
fp = cx->fp;
|
||||
if (fp->flags & JSFRAME_SCRIPT_OBJECT)
|
||||
return JS_TRUE;
|
||||
|
||||
/*
|
||||
* We can't optimize if var and closure (a local function not in a larger
|
||||
* expression and not at top-level within another's body) collide.
|
||||
@ -1904,14 +1887,30 @@ BindNameToSlot(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
|
||||
if (tc->flags & TCF_FUN_CLOSURE_VS_VAR)
|
||||
return JS_TRUE;
|
||||
|
||||
/*
|
||||
* We can't optimize if we are in an eval called inside a with statement.
|
||||
*/
|
||||
if (fp->scopeChain != fp->varobj)
|
||||
return JS_TRUE;
|
||||
if (!(tc->flags & TCF_IN_FUNCTION) &&
|
||||
!((cx->fp->flags & JSFRAME_SPECIAL) && cx->fp->fun)) {
|
||||
/*
|
||||
* We are compiling a script or eval and eval is not inside a function
|
||||
* frame.
|
||||
*
|
||||
* We can't optimize if we are in an eval called inside a with
|
||||
* statement.
|
||||
*/
|
||||
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;
|
||||
|
||||
clasp = OBJ_GET_CLASS(cx, fp->varobj);
|
||||
if (clasp != &js_FunctionClass && clasp != &js_CallClass) {
|
||||
/*
|
||||
* We cannot optimize the name access when compiling with an eval or
|
||||
* debugger frame.
|
||||
@ -1977,14 +1976,13 @@ BindNameToSlot(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
if (clasp == &js_FunctionClass) {
|
||||
if (tc->flags & TCF_IN_FUNCTION) {
|
||||
/*
|
||||
* We are compiling a function body and may be able to optimize name
|
||||
* to stack slot. Look for an argument or variable in the function and
|
||||
* rewrite pn_op and update pn accordingly.
|
||||
*/
|
||||
JS_ASSERT(fp->fun == GET_FUNCTION_PRIVATE(cx, fp->varobj));
|
||||
localKind = js_LookupLocal(cx, fp->fun, atom, &index);
|
||||
localKind = js_LookupLocal(cx, tc->fun, atom, &index);
|
||||
if (localKind != JSLOCAL_NONE) {
|
||||
op = PN_OP(pn);
|
||||
if (localKind == JSLOCAL_ARG) {
|
||||
@ -2021,6 +2019,7 @@ BindNameToSlot(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
|
||||
pn->pn_slot = index;
|
||||
return JS_TRUE;
|
||||
}
|
||||
tc->flags |= TCF_FUN_USES_NONLOCALS;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2038,7 +2037,6 @@ BindNameToSlot(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
|
||||
pn->pn_op = JSOP_ARGUMENTS;
|
||||
return JS_TRUE;
|
||||
}
|
||||
tc->flags |= TCF_FUN_USES_NONLOCALS;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
@ -3171,39 +3169,6 @@ js_EmitFunctionBytecode(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body)
|
||||
js_Emit1(cx, cg, JSOP_STOP) >= 0;
|
||||
}
|
||||
|
||||
JSBool
|
||||
js_EmitFunctionBody(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body,
|
||||
JSFunction *fun)
|
||||
{
|
||||
JSStackFrame *fp, frame;
|
||||
JSObject *funobj;
|
||||
JSBool ok;
|
||||
|
||||
fp = cx->fp;
|
||||
funobj = fun->object;
|
||||
JS_ASSERT(!fp || (fp->fun != fun && fp->varobj != funobj &&
|
||||
fp->scopeChain != funobj));
|
||||
memset(&frame, 0, sizeof frame);
|
||||
frame.callee = funobj;
|
||||
frame.fun = fun;
|
||||
frame.varobj = frame.scopeChain = funobj;
|
||||
frame.down = fp;
|
||||
frame.flags = JS_HAS_COMPILE_N_GO_OPTION(cx)
|
||||
? JSFRAME_COMPILING | JSFRAME_COMPILE_N_GO
|
||||
: JSFRAME_COMPILING;
|
||||
cx->fp = &frame;
|
||||
ok = js_EmitFunctionBytecode(cx, cg, body);
|
||||
cx->fp = fp;
|
||||
if (!ok)
|
||||
return JS_FALSE;
|
||||
|
||||
if (!js_NewScriptFromCG(cx, cg, fun))
|
||||
return JS_FALSE;
|
||||
|
||||
JS_ASSERT(FUN_INTERPRETED(fun));
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/* A macro for inlining at the top of js_EmitTree (whence it came). */
|
||||
#define UPDATE_LINE_NUMBER_NOTES(cx, cg, pn) \
|
||||
JS_BEGIN_MACRO \
|
||||
@ -3998,10 +3963,13 @@ 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->parent = cg;
|
||||
fun = GET_FUNCTION_PRIVATE(cx, pn->pn_funpob->object);
|
||||
if (!js_EmitFunctionBody(cx, cg2, pn->pn_body, fun))
|
||||
cg2->treeContext.fun = fun;
|
||||
cg2->parent = cg;
|
||||
if (!js_EmitFunctionBytecode(cx, cg2, pn->pn_body) ||
|
||||
!js_NewScriptFromCG(cx, cg2)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* We need an activation object if an inner peeks out, or if such
|
||||
@ -4055,14 +4023,9 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
JSFunction *parentFun;
|
||||
JSLocalKind localKind;
|
||||
|
||||
if (cg->treeContext.flags & TCF_IN_FUNCTION) {
|
||||
JS_ASSERT(OBJ_GET_CLASS(cx, OBJ_GET_PARENT(cx, fun->object)) ==
|
||||
&js_FunctionClass);
|
||||
parentFun =
|
||||
GET_FUNCTION_PRIVATE(cx, OBJ_GET_PARENT(cx, fun->object));
|
||||
} else {
|
||||
parentFun = cx->fp->fun;
|
||||
}
|
||||
parentFun = (cg->treeContext.flags & TCF_IN_FUNCTION)
|
||||
? cg->treeContext.fun
|
||||
: cx->fp->fun;
|
||||
localKind = js_LookupLocal(cx, parentFun, fun->atom, &slot);
|
||||
if (localKind == JSLOCAL_VAR || localKind == JSLOCAL_CONST)
|
||||
op = JSOP_DEFLOCALFUN;
|
||||
@ -5217,9 +5180,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
* expression statement as the script's result, despite the fact
|
||||
* that it appears useless to the compiler.
|
||||
*/
|
||||
useful = wantval = !cx->fp->fun ||
|
||||
!FUN_INTERPRETED(cx->fp->fun) ||
|
||||
(cx->fp->flags & JSFRAME_SPECIAL);
|
||||
useful = wantval = !(cg->treeContext.flags & TCF_IN_FUNCTION);
|
||||
if (!useful) {
|
||||
if (!CheckSideEffects(cx, &cg->treeContext, pn2, &useful))
|
||||
return JS_FALSE;
|
||||
@ -6267,7 +6228,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
* select JSOP_REGEXP.
|
||||
*/
|
||||
JS_ASSERT(pn->pn_op == JSOP_REGEXP);
|
||||
if (cx->fp->flags & (JSFRAME_EVAL | JSFRAME_COMPILE_N_GO)) {
|
||||
if (cg->treeContext.flags & TCF_COMPILE_N_GO) {
|
||||
ok = EmitObjectOp(cx, pn->pn_pob, JSOP_OBJECT, cg);
|
||||
} else {
|
||||
ok = EmitIndexOp(cx, JSOP_REGEXP,
|
||||
|
@ -171,6 +171,8 @@ 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
|
||||
names when flags & TCF_IN_FUNCTION */
|
||||
};
|
||||
|
||||
#define TCF_COMPILING 0x01 /* generating bytecode; this tc is a cg */
|
||||
@ -187,6 +189,9 @@ struct JSTreeContext { /* tree context for semantic checks */
|
||||
#define TCF_HAS_DEFXMLNS 0x200 /* default xml namespace = ...; parsed */
|
||||
#define TCF_HAS_FUNCTION_STMT 0x400 /* block contains a function statement */
|
||||
#define TCF_GENEXP_LAMBDA 0x800 /* flag lambda from generator expression */
|
||||
#define TCF_COMPILE_N_GO 0x1000 /* compiler-and-go mode of script, can
|
||||
optimize name references based on scope
|
||||
chain */
|
||||
|
||||
#define TREE_CONTEXT_INIT(tc, pc) \
|
||||
((tc)->flags = (tc)->ngvars = 0, \
|
||||
@ -195,7 +200,8 @@ struct JSTreeContext { /* tree context for semantic checks */
|
||||
(tc)->blockChain = NULL, \
|
||||
ATOM_LIST_INIT(&(tc)->decls), \
|
||||
(tc)->blockNode = NULL, \
|
||||
(tc)->parseContext = (pc))
|
||||
(tc)->parseContext = (pc), \
|
||||
(tc)->fun = NULL)
|
||||
|
||||
#define TREE_CONTEXT_FINISH(tc) \
|
||||
((void)0)
|
||||
@ -502,14 +508,6 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn);
|
||||
extern JSBool
|
||||
js_EmitFunctionBytecode(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body);
|
||||
|
||||
/*
|
||||
* Emit code into cg for the tree rooted at body, then create a persistent
|
||||
* script for fun from cg.
|
||||
*/
|
||||
extern JSBool
|
||||
js_EmitFunctionBody(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body,
|
||||
JSFunction *fun);
|
||||
|
||||
/*
|
||||
* Source notes generated along with bytecode for decompiling and debugging.
|
||||
* A source note is a uint8 with 5 bits of type and 3 of offset from the pc of
|
||||
|
@ -1701,7 +1701,7 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
const char *filename;
|
||||
JSBool ok;
|
||||
JSString *str, *arg;
|
||||
JSParseContext pc;
|
||||
JSTokenStream ts;
|
||||
JSPrincipals *principals;
|
||||
jschar *collected_args, *cp;
|
||||
void *mark;
|
||||
@ -1839,14 +1839,14 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
}
|
||||
|
||||
/* Initialize a tokenstream that reads from the given string. */
|
||||
if (!js_InitTokenStream(cx, &pc.tokenStream, collected_args,
|
||||
args_length, NULL, filename, lineno)) {
|
||||
if (!js_InitTokenStream(cx, &ts, collected_args, args_length,
|
||||
NULL, filename, lineno)) {
|
||||
JS_ARENA_RELEASE(&cx->tempPool, mark);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/* The argument string may be empty or contain no tokens. */
|
||||
tt = js_GetToken(cx, &pc.tokenStream);
|
||||
tt = js_GetToken(cx, &ts);
|
||||
if (tt != TOK_EOF) {
|
||||
for (;;) {
|
||||
/*
|
||||
@ -1857,10 +1857,11 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
goto after_args;
|
||||
|
||||
/*
|
||||
* Get the atom corresponding to the name from the tokenstream;
|
||||
* we're assured at this point that it's a valid identifier.
|
||||
* Get the atom corresponding to the name from the token
|
||||
* stream; we're assured at this point that it's a valid
|
||||
* identifier.
|
||||
*/
|
||||
atom = CURRENT_TOKEN(&pc.tokenStream).t_atom;
|
||||
atom = CURRENT_TOKEN(&ts).t_atom;
|
||||
|
||||
/* Check for a duplicate parameter name. */
|
||||
if (js_LookupLocal(cx, fun, atom, NULL) != JSLOCAL_NONE) {
|
||||
@ -1868,7 +1869,7 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
|
||||
name = js_AtomToPrintableString(cx, atom);
|
||||
ok = name &&
|
||||
js_ReportCompileErrorNumber(cx, &pc.tokenStream, NULL,
|
||||
js_ReportCompileErrorNumber(cx, &ts, NULL,
|
||||
JSREPORT_WARNING |
|
||||
JSREPORT_STRICT,
|
||||
JSMSG_DUPLICATE_FORMAL,
|
||||
@ -1883,18 +1884,18 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
* Get the next token. Stop on end of stream. Otherwise
|
||||
* insist on a comma, get another name, and iterate.
|
||||
*/
|
||||
tt = js_GetToken(cx, &pc.tokenStream);
|
||||
tt = js_GetToken(cx, &ts);
|
||||
if (tt == TOK_EOF)
|
||||
break;
|
||||
if (tt != TOK_COMMA)
|
||||
goto after_args;
|
||||
tt = js_GetToken(cx, &pc.tokenStream);
|
||||
tt = js_GetToken(cx, &ts);
|
||||
}
|
||||
}
|
||||
|
||||
state = OK;
|
||||
after_args:
|
||||
if (state == BAD_FORMAL && !(pc.tokenStream.flags & TSF_ERROR)) {
|
||||
if (state == BAD_FORMAL && !(ts.flags & TSF_ERROR)) {
|
||||
/*
|
||||
* Report "malformed formal parameter" iff no illegal char or
|
||||
* similar scanner error was already reported.
|
||||
@ -1902,7 +1903,7 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_BAD_FORMAL);
|
||||
}
|
||||
js_CloseTokenStream(cx, &pc.tokenStream);
|
||||
js_CloseTokenStream(cx, &ts);
|
||||
JS_ARENA_RELEASE(&cx->tempPool, mark);
|
||||
if (state != OK)
|
||||
return JS_FALSE;
|
||||
@ -1917,14 +1918,9 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
str = cx->runtime->emptyString;
|
||||
}
|
||||
|
||||
ok = js_InitParseContext(cx, &pc, JSSTRING_CHARS(str), JSSTRING_LENGTH(str),
|
||||
NULL, filename, lineno);
|
||||
if (ok) {
|
||||
js_InitCompilePrincipals(cx, &pc, principals);
|
||||
ok = js_CompileFunctionBody(cx, &pc, fun);
|
||||
js_FinishParseContext(cx, &pc);
|
||||
}
|
||||
return ok;
|
||||
return js_CompileFunctionBody(cx, fun, principals,
|
||||
JSSTRING_CHARS(str), JSSTRING_LENGTH(str),
|
||||
filename, lineno);
|
||||
}
|
||||
|
||||
JSObject *
|
||||
|
@ -99,21 +99,19 @@ 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_SPECIAL 0x18 /* special evaluation frame flags */
|
||||
#define JSFRAME_COMPILING 0x20 /* frame is being used by compiler */
|
||||
#define JSFRAME_COMPILE_N_GO 0x40 /* compiler-and-go mode, can optimize name
|
||||
references based on scope chain */
|
||||
#define JSFRAME_SCRIPT_OBJECT 0x80 /* compiling source for a Script object */
|
||||
#define JSFRAME_YIELDING 0x100 /* js_Interpret dispatched JSOP_YIELD */
|
||||
#define JSFRAME_FILTERING 0x200 /* XML filtering predicate expression */
|
||||
#define JSFRAME_ITERATOR 0x400 /* trying to get an iterator for for-in */
|
||||
#define JSFRAME_POP_BLOCKS 0x800 /* scope chain contains blocks to pop */
|
||||
#define JSFRAME_GENERATOR 0x1000 /* frame belongs to generator-iterator */
|
||||
#define JSFRAME_ROOTED_ARGV 0x2000 /* frame.argv is rooted by the caller */
|
||||
#define JSFRAME_SCRIPT_OBJECT 0x20 /* compiling source for a Script object */
|
||||
#define JSFRAME_YIELDING 0x40 /* js_Interpret dispatched JSOP_YIELD */
|
||||
#define JSFRAME_FILTERING 0x80 /* XML filtering predicate expression */
|
||||
#define JSFRAME_ITERATOR 0x100 /* trying to get an iterator for for-in */
|
||||
#define JSFRAME_POP_BLOCKS 0x200 /* scope chain contains blocks to pop */
|
||||
#define JSFRAME_GENERATOR 0x400 /* frame belongs to generator-iterator */
|
||||
#define JSFRAME_ROOTED_ARGV 0x800 /* frame.argv is rooted by the caller */
|
||||
|
||||
#define JSFRAME_OVERRIDE_SHIFT 24 /* override bit-set params; see jsfun.c */
|
||||
#define JSFRAME_OVERRIDE_BITS 8
|
||||
|
||||
#define JSFRAME_SPECIAL (JSFRAME_DEBUGGER | JSFRAME_EVAL)
|
||||
|
||||
extern JS_FRIEND_API(jsval *)
|
||||
js_AllocStack(JSContext *cx, uintN nslots, void **markp);
|
||||
|
||||
|
@ -57,6 +57,7 @@
|
||||
#include "jsbool.h"
|
||||
#include "jscntxt.h"
|
||||
#include "jsconfig.h"
|
||||
#include "jsemit.h"
|
||||
#include "jsfun.h"
|
||||
#include "jsgc.h"
|
||||
#include "jsinterp.h"
|
||||
@ -64,7 +65,7 @@
|
||||
#include "jsnum.h"
|
||||
#include "jsobj.h"
|
||||
#include "jsopcode.h"
|
||||
#include "jsscan.h"
|
||||
#include "jsparse.h"
|
||||
#include "jsscope.h"
|
||||
#include "jsscript.h"
|
||||
#include "jsstr.h"
|
||||
@ -1431,10 +1432,9 @@ obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
fp->flags |= JSFRAME_EVAL;
|
||||
} while ((fp = fp->down) != caller);
|
||||
|
||||
script = JS_CompileUCScriptForPrincipals(cx, scopeobj, principals,
|
||||
JSSTRING_CHARS(str),
|
||||
JSSTRING_LENGTH(str),
|
||||
file, line);
|
||||
script = js_CompileScript(cx, scopeobj, principals, TCF_COMPILE_N_GO,
|
||||
JSSTRING_CHARS(str), JSSTRING_LENGTH(str),
|
||||
NULL, file, line);
|
||||
if (!script) {
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
|
329
js/src/jsparse.c
329
js/src/jsparse.c
@ -156,8 +156,8 @@ static uint32 maxparsenodes = 0;
|
||||
static uint32 recyclednodes = 0;
|
||||
#endif
|
||||
|
||||
JS_FRIEND_API(JSBool)
|
||||
js_InitParseContext(JSContext *cx, JSParseContext *pc,
|
||||
JSBool
|
||||
js_InitParseContext(JSContext *cx, JSParseContext *pc, JSPrincipals *principals,
|
||||
const jschar *base, size_t length,
|
||||
FILE *fp, const char *filename, uintN lineno)
|
||||
{
|
||||
@ -166,7 +166,9 @@ js_InitParseContext(JSContext *cx, JSParseContext *pc,
|
||||
JS_ARENA_RELEASE(&cx->tempPool, pc->tempPoolMark);
|
||||
return JS_FALSE;
|
||||
}
|
||||
pc->principals = NULL;
|
||||
if (principals)
|
||||
JSPRINCIPALS_HOLD(cx, principals);
|
||||
pc->principals = principals;
|
||||
pc->nodeList = NULL;
|
||||
pc->traceListHead = NULL;
|
||||
|
||||
@ -176,7 +178,7 @@ js_InitParseContext(JSContext *cx, JSParseContext *pc,
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(void)
|
||||
void
|
||||
js_FinishParseContext(JSContext *cx, JSParseContext *pc)
|
||||
{
|
||||
if (pc->principals)
|
||||
@ -492,8 +494,7 @@ MaybeSetupFrame(JSContext *cx, JSObject *chain, JSStackFrame *oldfp,
|
||||
* the real variables objects and function that our new stack frame is
|
||||
* going to use.
|
||||
*/
|
||||
newfp->flags = oldfp->flags & (JSFRAME_SPECIAL | JSFRAME_COMPILE_N_GO |
|
||||
JSFRAME_SCRIPT_OBJECT);
|
||||
newfp->flags = oldfp->flags & (JSFRAME_SPECIAL | JSFRAME_SCRIPT_OBJECT);
|
||||
while (oldfp->flags & JSFRAME_SPECIAL) {
|
||||
oldfp = oldfp->down;
|
||||
if (!oldfp)
|
||||
@ -512,7 +513,7 @@ MaybeSetupFrame(JSContext *cx, JSObject *chain, JSStackFrame *oldfp,
|
||||
/*
|
||||
* Parse a top-level JS script.
|
||||
*/
|
||||
JS_FRIEND_API(JSParseNode *)
|
||||
JSParseNode *
|
||||
js_ParseScript(JSContext *cx, JSObject *chain, JSParseContext *pc)
|
||||
{
|
||||
JSStackFrame *fp, frame;
|
||||
@ -557,11 +558,13 @@ js_ParseScript(JSContext *cx, JSObject *chain, JSParseContext *pc)
|
||||
/*
|
||||
* Compile a top-level script.
|
||||
*/
|
||||
JS_FRIEND_API(JSScript *)
|
||||
js_CompileScript(JSContext *cx, JSObject *chain, JSParseContext *pc)
|
||||
JSScript *
|
||||
js_CompileScript(JSContext *cx, JSObject *obj, JSPrincipals *principals,
|
||||
uint32 tcflags, const jschar *chars, size_t length,
|
||||
FILE *file, const char *filename, uintN lineno)
|
||||
{
|
||||
JSParseContext pc;
|
||||
JSStackFrame *fp, frame;
|
||||
uint32 flags;
|
||||
JSArenaPool codePool, notePool;
|
||||
JSCodeGenerator cg;
|
||||
JSParseNode *pn;
|
||||
@ -570,33 +573,39 @@ js_CompileScript(JSContext *cx, JSObject *chain, JSParseContext *pc)
|
||||
void *sbrk(ptrdiff_t), *before = sbrk(0);
|
||||
#endif
|
||||
|
||||
JS_ASSERT(!(tcflags & ~TCF_COMPILE_N_GO));
|
||||
|
||||
if (!js_InitParseContext(cx, &pc, principals, chars, length, file,
|
||||
filename, lineno)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
fp = cx->fp;
|
||||
MaybeSetupFrame(cx, chain, fp, &frame);
|
||||
flags = cx->fp->flags;
|
||||
cx->fp->flags = flags |
|
||||
(JS_HAS_COMPILE_N_GO_OPTION(cx)
|
||||
? JSFRAME_COMPILING | JSFRAME_COMPILE_N_GO
|
||||
: JSFRAME_COMPILING);
|
||||
MaybeSetupFrame(cx, obj, fp, &frame);
|
||||
|
||||
JS_INIT_ARENA_POOL(&codePool, "code", 1024, sizeof(jsbytecode),
|
||||
&cx->scriptStackQuota);
|
||||
JS_INIT_ARENA_POOL(¬ePool, "note", 1024, sizeof(jssrcnote),
|
||||
&cx->scriptStackQuota);
|
||||
js_InitCodeGenerator(cx, &cg, pc, &codePool, ¬ePool, TS(pc)->lineno);
|
||||
js_InitCodeGenerator(cx, &cg, &pc, &codePool, ¬ePool,
|
||||
pc.tokenStream.lineno);
|
||||
|
||||
/* From this point the control must flow via the label out. */
|
||||
pn = Statements(cx, TS(pc), &cg.treeContext);
|
||||
cg.treeContext.flags |= tcflags;
|
||||
pn = Statements(cx, &pc.tokenStream, &cg.treeContext);
|
||||
if (!pn) {
|
||||
script = NULL;
|
||||
goto out;
|
||||
}
|
||||
if (!js_MatchToken(cx, TS(pc), TOK_EOF)) {
|
||||
js_ReportCompileErrorNumber(cx, TS(pc), NULL, JSREPORT_ERROR,
|
||||
if (!js_MatchToken(cx, &pc.tokenStream, TOK_EOF)) {
|
||||
js_ReportCompileErrorNumber(cx, &pc.tokenStream, NULL, JSREPORT_ERROR,
|
||||
JSMSG_SYNTAX_ERROR);
|
||||
script = NULL;
|
||||
goto out;
|
||||
@ -632,15 +641,14 @@ js_CompileScript(JSContext *cx, JSObject *chain, JSParseContext *pc)
|
||||
#ifdef JS_ARENAMETER
|
||||
JS_DumpArenaStats(stdout);
|
||||
#endif
|
||||
script = js_NewScriptFromCG(cx, &cg, NULL);
|
||||
script = js_NewScriptFromCG(cx, &cg);
|
||||
|
||||
out:
|
||||
js_FinishCodeGenerator(cx, &cg);
|
||||
JS_FinishArenaPool(&codePool);
|
||||
JS_FinishArenaPool(¬ePool);
|
||||
|
||||
cx->fp->flags = flags;
|
||||
cx->fp = fp;
|
||||
js_FinishParseContext(cx, &pc);
|
||||
return script;
|
||||
}
|
||||
|
||||
@ -772,61 +780,44 @@ HasFinalReturn(JSParseNode *pn)
|
||||
}
|
||||
|
||||
static JSBool
|
||||
ReportBadReturn(JSContext *cx, JSTokenStream *ts, uintN flags, uintN errnum,
|
||||
ReportBadReturn(JSContext *cx, JSTreeContext *tc, uintN flags, uintN errnum,
|
||||
uintN anonerrnum)
|
||||
{
|
||||
JSFunction *fun;
|
||||
const char *name;
|
||||
|
||||
fun = cx->fp->fun;
|
||||
if (fun->atom) {
|
||||
name = js_AtomToPrintableString(cx, fun->atom);
|
||||
JS_ASSERT(tc->flags & TCF_IN_FUNCTION);
|
||||
if (tc->fun->atom) {
|
||||
name = js_AtomToPrintableString(cx, tc->fun->atom);
|
||||
} else {
|
||||
errnum = anonerrnum;
|
||||
name = NULL;
|
||||
}
|
||||
return js_ReportCompileErrorNumber(cx, ts, NULL, flags, errnum, name);
|
||||
return js_ReportCompileErrorNumber(cx, TS(tc->parseContext), NULL, flags,
|
||||
errnum, name);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
CheckFinalReturn(JSContext *cx, JSTokenStream *ts, JSParseNode *pn)
|
||||
CheckFinalReturn(JSContext *cx, JSTreeContext *tc, JSParseNode *pn)
|
||||
{
|
||||
JS_ASSERT(tc->flags & TCF_IN_FUNCTION);
|
||||
return HasFinalReturn(pn) == ENDS_IN_RETURN ||
|
||||
ReportBadReturn(cx, ts, JSREPORT_WARNING | JSREPORT_STRICT,
|
||||
ReportBadReturn(cx, tc, JSREPORT_WARNING | JSREPORT_STRICT,
|
||||
JSMSG_NO_RETURN_VALUE, JSMSG_ANON_NO_RETURN_VALUE);
|
||||
}
|
||||
|
||||
static JSParseNode *
|
||||
FunctionBody(JSContext *cx, JSTokenStream *ts, JSFunction *fun,
|
||||
JSTreeContext *tc)
|
||||
FunctionBody(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
||||
{
|
||||
JSStackFrame *fp, frame;
|
||||
JSObject *funobj;
|
||||
JSStmtInfo stmtInfo;
|
||||
uintN oldflags, firstLine;
|
||||
JSParseNode *pn;
|
||||
|
||||
JS_ASSERT(FUN_INTERPRETED(fun));
|
||||
fp = cx->fp;
|
||||
funobj = fun->object;
|
||||
if (!fp || fp->fun != fun || fp->varobj != funobj ||
|
||||
fp->scopeChain != funobj) {
|
||||
memset(&frame, 0, sizeof frame);
|
||||
frame.callee = funobj;
|
||||
frame.fun = fun;
|
||||
frame.varobj = frame.scopeChain = funobj;
|
||||
frame.down = fp;
|
||||
if (fp)
|
||||
frame.flags = fp->flags & JSFRAME_COMPILE_N_GO;
|
||||
cx->fp = &frame;
|
||||
}
|
||||
|
||||
JS_ASSERT(tc->flags & TCF_IN_FUNCTION);
|
||||
js_PushStatement(tc, &stmtInfo, STMT_BLOCK, -1);
|
||||
stmtInfo.flags = SIF_BODY_BLOCK;
|
||||
|
||||
oldflags = tc->flags;
|
||||
tc->flags &= ~(TCF_RETURN_EXPR | TCF_RETURN_VOID);
|
||||
tc->flags |= TCF_IN_FUNCTION;
|
||||
|
||||
/*
|
||||
* Save the body's first line, and store it in pn->pn_pos.begin.lineno
|
||||
@ -845,7 +836,7 @@ FunctionBody(JSContext *cx, JSTokenStream *ts, JSFunction *fun,
|
||||
pn = NULL;
|
||||
} else {
|
||||
if (tc->flags & TCF_FUN_IS_GENERATOR) {
|
||||
ReportBadReturn(cx, ts, JSREPORT_ERROR,
|
||||
ReportBadReturn(cx, tc, JSREPORT_ERROR,
|
||||
JSMSG_BAD_GENERATOR_RETURN,
|
||||
JSMSG_BAD_ANON_GENERATOR_RETURN);
|
||||
pn = NULL;
|
||||
@ -865,28 +856,13 @@ FunctionBody(JSContext *cx, JSTokenStream *ts, JSFunction *fun,
|
||||
|
||||
/* Check for falling off the end of a function that returns a value. */
|
||||
if (pn && JS_HAS_STRICT_OPTION(cx) && (tc->flags & TCF_RETURN_EXPR)) {
|
||||
if (!CheckFinalReturn(cx, ts, pn))
|
||||
if (!CheckFinalReturn(cx, tc, pn))
|
||||
pn = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have a parse tree in pn and a code generator in tc, emit this
|
||||
* function's code. We must do this here, not in js_CompileFunctionBody,
|
||||
* in order to detect TCF_IN_FUNCTION among tc->flags.
|
||||
*/
|
||||
if (pn) {
|
||||
if (pn)
|
||||
pn->pn_pos.begin.lineno = firstLine;
|
||||
if ((tc->flags & TCF_COMPILING)) {
|
||||
JSCodeGenerator *cg = (JSCodeGenerator *) tc;
|
||||
|
||||
if (!js_FoldConstants(cx, pn, tc) ||
|
||||
!js_EmitFunctionBytecode(cx, cg, pn)) {
|
||||
pn = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cx->fp = fp;
|
||||
tc->flags = oldflags | (tc->flags & (TCF_FUN_FLAGS | TCF_HAS_DEFXMLNS));
|
||||
return pn;
|
||||
}
|
||||
@ -896,34 +872,29 @@ FunctionBody(JSContext *cx, JSTokenStream *ts, JSFunction *fun,
|
||||
* handler attribute in an HTML <INPUT> tag.
|
||||
*/
|
||||
JSBool
|
||||
js_CompileFunctionBody(JSContext *cx, JSParseContext *pc, JSFunction *fun)
|
||||
js_CompileFunctionBody(JSContext *cx, JSFunction *fun, JSPrincipals *principals,
|
||||
const jschar *chars, size_t length,
|
||||
const char *filename, uintN lineno)
|
||||
{
|
||||
JSParseContext pc;
|
||||
JSArenaPool codePool, notePool;
|
||||
JSCodeGenerator funcg;
|
||||
JSStackFrame *fp, frame;
|
||||
JSObject *funobj;
|
||||
JSParseNode *pn;
|
||||
|
||||
if (!js_InitParseContext(cx, &pc, principals, chars, length, NULL,
|
||||
filename, lineno)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/* No early return from this point until js_FinishParseContext call. */
|
||||
JS_INIT_ARENA_POOL(&codePool, "code", 1024, sizeof(jsbytecode),
|
||||
&cx->scriptStackQuota);
|
||||
JS_INIT_ARENA_POOL(¬ePool, "note", 1024, sizeof(jssrcnote),
|
||||
&cx->scriptStackQuota);
|
||||
js_InitCodeGenerator(cx, &funcg, pc, &codePool, ¬ePool, TS(pc)->lineno);
|
||||
|
||||
/* Push a JSStackFrame for use by FunctionBody. */
|
||||
fp = cx->fp;
|
||||
funobj = fun->object;
|
||||
JS_ASSERT(!fp || (fp->fun != fun && fp->varobj != funobj &&
|
||||
fp->scopeChain != funobj));
|
||||
memset(&frame, 0, sizeof frame);
|
||||
frame.callee = funobj;
|
||||
frame.fun = fun;
|
||||
frame.varobj = frame.scopeChain = funobj;
|
||||
frame.down = fp;
|
||||
frame.flags = JS_HAS_COMPILE_N_GO_OPTION(cx)
|
||||
? JSFRAME_COMPILING | JSFRAME_COMPILE_N_GO
|
||||
: JSFRAME_COMPILING;
|
||||
cx->fp = &frame;
|
||||
js_InitCodeGenerator(cx, &funcg, &pc, &codePool, ¬ePool,
|
||||
pc.tokenStream.lineno);
|
||||
funcg.treeContext.flags |= TCF_IN_FUNCTION;
|
||||
funcg.treeContext.fun = fun;
|
||||
|
||||
/*
|
||||
* Farble the body so that it looks like a block statement to js_EmitTree,
|
||||
@ -936,24 +907,27 @@ js_CompileFunctionBody(JSContext *cx, JSParseContext *pc, JSFunction *fun)
|
||||
* Therefore we must fold constants, allocate try notes, and generate code
|
||||
* for this function, including a stop opcode at the end.
|
||||
*/
|
||||
CURRENT_TOKEN(TS(pc)).type = TOK_LC;
|
||||
pn = FunctionBody(cx, TS(pc), fun, &funcg.treeContext);
|
||||
CURRENT_TOKEN(&pc.tokenStream).type = TOK_LC;
|
||||
pn = FunctionBody(cx, &pc.tokenStream, &funcg.treeContext);
|
||||
if (pn) {
|
||||
if (!js_MatchToken(cx, TS(pc), TOK_EOF)) {
|
||||
js_ReportCompileErrorNumber(cx, TS(pc), NULL, JSREPORT_ERROR,
|
||||
JSMSG_SYNTAX_ERROR);
|
||||
if (!js_MatchToken(cx, &pc.tokenStream, TOK_EOF)) {
|
||||
js_ReportCompileErrorNumber(cx, &pc.tokenStream, NULL,
|
||||
JSREPORT_ERROR, JSMSG_SYNTAX_ERROR);
|
||||
pn = NULL;
|
||||
} else {
|
||||
if (!js_NewScriptFromCG(cx, &funcg, fun))
|
||||
if (!js_FoldConstants(cx, pn, &funcg.treeContext) ||
|
||||
!js_EmitFunctionBytecode(cx, &funcg, pn) ||
|
||||
!js_NewScriptFromCG(cx, &funcg)) {
|
||||
pn = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Restore saved state and release code generation arenas. */
|
||||
cx->fp = fp;
|
||||
js_FinishCodeGenerator(cx, &funcg);
|
||||
JS_FinishArenaPool(&codePool);
|
||||
JS_FinishArenaPool(¬ePool);
|
||||
js_FinishParseContext(cx, &pc);
|
||||
return pn != NULL;
|
||||
}
|
||||
|
||||
@ -971,18 +945,9 @@ typedef JSBool
|
||||
|
||||
struct BindData {
|
||||
JSParseNode *pn; /* error source coordinate */
|
||||
JSObject *obj; /* the variable object */
|
||||
JSOp op; /* prolog bytecode or nop */
|
||||
Binder binder; /* binder, discriminates u */
|
||||
union {
|
||||
struct {
|
||||
JSFunction *fun; /* must come first! see next */
|
||||
} arg;
|
||||
struct {
|
||||
JSFunction *fun; /* this overlays u.arg.fun */
|
||||
JSClass *clasp;
|
||||
JSLocalKind kind;
|
||||
} var;
|
||||
struct {
|
||||
jsuint index;
|
||||
uintN overflow;
|
||||
@ -991,17 +956,18 @@ struct BindData {
|
||||
};
|
||||
|
||||
static JSBool
|
||||
BindArg(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc)
|
||||
BindArg(JSContext *cx, JSAtom *atom, JSTreeContext *tc)
|
||||
{
|
||||
const char *name;
|
||||
|
||||
/*
|
||||
* Check for a duplicate parameter name, a "feature" required by ECMA-262.
|
||||
*/
|
||||
if (js_LookupLocal(cx, data->u.arg.fun, atom, NULL) != JSLOCAL_NONE) {
|
||||
JS_ASSERT(tc->flags & TCF_IN_FUNCTION);
|
||||
if (js_LookupLocal(cx, tc->fun, atom, NULL) != JSLOCAL_NONE) {
|
||||
name = js_AtomToPrintableString(cx, atom);
|
||||
if (!name ||
|
||||
!js_ReportCompileErrorNumber(cx, TS(tc->parseContext), data->pn,
|
||||
!js_ReportCompileErrorNumber(cx, TS(tc->parseContext), NULL,
|
||||
JSREPORT_WARNING | JSREPORT_STRICT,
|
||||
JSMSG_DUPLICATE_FORMAL,
|
||||
name)) {
|
||||
@ -1009,19 +975,14 @@ BindArg(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc)
|
||||
}
|
||||
}
|
||||
|
||||
return js_AddLocal(cx, data->u.arg.fun, atom, JSLOCAL_ARG);
|
||||
return js_AddLocal(cx, tc->fun, atom, JSLOCAL_ARG);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
BindLocalVariable(JSContext *cx, BindData *data, JSAtom *atom)
|
||||
BindLocalVariable(JSContext *cx, JSFunction *fun, JSAtom *atom,
|
||||
JSLocalKind localKind)
|
||||
{
|
||||
/*
|
||||
* Can't increase fun->nvars in an active frame when kind is JSFL_NONE.
|
||||
*/
|
||||
if (data->u.var.kind == JSLOCAL_NONE)
|
||||
return JS_TRUE;
|
||||
JS_ASSERT(data->u.var.kind == JSLOCAL_VAR ||
|
||||
data->u.var.kind == JSLOCAL_CONST);
|
||||
JS_ASSERT(localKind == JSLOCAL_VAR || localKind == JSLOCAL_CONST);
|
||||
|
||||
/*
|
||||
* Don't bind a variable with the hidden name 'arguments', per ECMA-262.
|
||||
@ -1032,7 +993,7 @@ BindLocalVariable(JSContext *cx, BindData *data, JSAtom *atom)
|
||||
if (atom == cx->runtime->atomState.argumentsAtom)
|
||||
return JS_TRUE;
|
||||
|
||||
return js_AddLocal(cx, data->u.var.fun, atom, data->u.var.kind);
|
||||
return js_AddLocal(cx, fun, atom, localKind);
|
||||
}
|
||||
|
||||
#if JS_HAS_DESTRUCTURING
|
||||
@ -1050,6 +1011,7 @@ BindDestructuringArg(JSContext *cx, BindData *data, JSAtom *atom,
|
||||
JSAtomListElement *ale;
|
||||
const char *name;
|
||||
|
||||
JS_ASSERT(tc->flags & TCF_IN_FUNCTION);
|
||||
ATOM_LIST_SEARCH(ale, &tc->decls, atom);
|
||||
if (!ale) {
|
||||
ale = js_IndexAtom(cx, atom, &tc->decls);
|
||||
@ -1058,7 +1020,7 @@ BindDestructuringArg(JSContext *cx, BindData *data, JSAtom *atom,
|
||||
ALE_SET_JSOP(ale, data->op);
|
||||
}
|
||||
|
||||
if (js_LookupLocal(cx, data->u.var.fun, atom, NULL) != JSLOCAL_NONE) {
|
||||
if (js_LookupLocal(cx, tc->fun, atom, NULL) != JSLOCAL_NONE) {
|
||||
name = js_AtomToPrintableString(cx, atom);
|
||||
if (!name ||
|
||||
!js_ReportCompileErrorNumber(cx, TS(tc->parseContext), data->pn,
|
||||
@ -1068,13 +1030,25 @@ BindDestructuringArg(JSContext *cx, BindData *data, JSAtom *atom,
|
||||
return JS_FALSE;
|
||||
}
|
||||
} else {
|
||||
if (!BindLocalVariable(cx, data, atom))
|
||||
if (!BindLocalVariable(cx, tc->fun, atom, JSLOCAL_VAR))
|
||||
return JS_FALSE;
|
||||
}
|
||||
return JS_TRUE;
|
||||
}
|
||||
#endif /* JS_HAS_DESTRUCTURING */
|
||||
|
||||
static JSFunction *
|
||||
NewCompilerFunction(JSContext *cx, JSTreeContext *tc, JSAtom *atom,
|
||||
JSBool lambda)
|
||||
{
|
||||
JSObject *parent;
|
||||
|
||||
parent = (tc->flags & TCF_IN_FUNCTION) ? tc->fun->object : cx->fp->varobj;
|
||||
return js_NewFunction(cx, NULL, NULL, 0,
|
||||
JSFUN_INTERPRETED | (lambda ? JSFUN_LAMBDA : 0),
|
||||
parent, atom);
|
||||
}
|
||||
|
||||
static JSParseNode *
|
||||
FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
||||
JSBool lambda)
|
||||
@ -1084,8 +1058,6 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
||||
JSTokenType tt;
|
||||
JSAtom *funAtom;
|
||||
JSParsedObjectBox *funpob;
|
||||
JSStackFrame *fp;
|
||||
JSObject *varobj;
|
||||
JSAtomListElement *ale;
|
||||
JSFunction *fun;
|
||||
JSTreeContext funtc;
|
||||
@ -1117,10 +1089,6 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
||||
js_UngetToken(ts);
|
||||
}
|
||||
|
||||
/* Find the nearest variable-declaring scope and use it as our parent. */
|
||||
fp = cx->fp;
|
||||
varobj = fp->varobj;
|
||||
|
||||
/*
|
||||
* Record names for function statements in tc->decls so we know when to
|
||||
* avoid optimizing variable references that might name a function.
|
||||
@ -1175,19 +1143,15 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
||||
* variable even if the parameter with the given name already
|
||||
* exists.
|
||||
*/
|
||||
JS_ASSERT(OBJ_GET_CLASS(cx, varobj) == &js_FunctionClass);
|
||||
JS_ASSERT(fp->fun == GET_FUNCTION_PRIVATE(cx, varobj));
|
||||
localKind = js_LookupLocal(cx, fp->fun, funAtom, NULL);
|
||||
localKind = js_LookupLocal(cx, tc->fun, funAtom, NULL);
|
||||
if (localKind == JSLOCAL_NONE || localKind == JSLOCAL_ARG) {
|
||||
if (!js_AddLocal(cx, fp->fun, funAtom, JSLOCAL_VAR))
|
||||
if (!js_AddLocal(cx, tc->fun, funAtom, JSLOCAL_VAR))
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun = js_NewFunction(cx, NULL, NULL, 0,
|
||||
JSFUN_INTERPRETED | (lambda ? JSFUN_LAMBDA : 0),
|
||||
varobj, funAtom);
|
||||
fun = NewCompilerFunction(cx, tc, funAtom, lambda);
|
||||
if (!fun)
|
||||
return NULL;
|
||||
|
||||
@ -1206,18 +1170,12 @@ 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;
|
||||
funtc.fun = fun;
|
||||
|
||||
/* Now parse formal argument list and compute fun->nargs. */
|
||||
MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_FORMAL);
|
||||
if (!js_MatchToken(cx, ts, TOK_RP)) {
|
||||
BindData data;
|
||||
|
||||
data.pn = NULL;
|
||||
data.obj = fun->object;
|
||||
data.op = JSOP_NOP;
|
||||
data.binder = BindArg;
|
||||
data.u.arg.fun = fun;
|
||||
|
||||
do {
|
||||
tt = js_GetToken(cx, ts);
|
||||
switch (tt) {
|
||||
@ -1225,6 +1183,7 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
||||
case TOK_LB:
|
||||
case TOK_LC:
|
||||
{
|
||||
BindData data;
|
||||
JSParseNode *lhs, *rhs;
|
||||
jsint slot;
|
||||
|
||||
@ -1234,20 +1193,13 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
||||
* anonymous positional parameter, so here we must tweak our
|
||||
* binder and its data.
|
||||
*/
|
||||
data.pn = NULL;
|
||||
data.op = JSOP_DEFVAR;
|
||||
data.binder = BindDestructuringArg;
|
||||
data.u.var.clasp = &js_FunctionClass;
|
||||
data.u.var.kind = JSLOCAL_VAR;
|
||||
lhs = DestructuringExpr(cx, &data, &funtc, tt);
|
||||
if (!lhs)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Restore the formal parameter binder in case there are more
|
||||
* non-destructuring formals in the parameter list.
|
||||
*/
|
||||
data.binder = BindArg;
|
||||
|
||||
/*
|
||||
* Adjust fun->nargs to count the single anonymous positional
|
||||
* parameter that is to be destructured.
|
||||
@ -1285,7 +1237,7 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
||||
#endif /* JS_HAS_DESTRUCTURING */
|
||||
|
||||
case TOK_NAME:
|
||||
if (!data.binder(cx, &data, CURRENT_TOKEN(ts).t_atom, tc))
|
||||
if (!BindArg(cx, CURRENT_TOKEN(ts).t_atom, &funtc))
|
||||
return NULL;
|
||||
break;
|
||||
|
||||
@ -1312,7 +1264,7 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
||||
#endif
|
||||
pn->pn_pos.begin = CURRENT_TOKEN(ts).pos.begin;
|
||||
|
||||
body = FunctionBody(cx, ts, fun, &funtc);
|
||||
body = FunctionBody(cx, ts, &funtc);
|
||||
if (!body)
|
||||
return NULL;
|
||||
|
||||
@ -1381,8 +1333,8 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
||||
*
|
||||
* The TCF_FUN_USES_NONLOCALS flag is set only by the code generator,
|
||||
* so it won't be set here. Assert that it's not. We have to check
|
||||
* it later, in js_EmitTree, after js_EmitFunctionBody has traversed
|
||||
* the function's body
|
||||
* it later, in js_EmitTree, after js_EmitFunctionBytecode has
|
||||
* traversed the function's body
|
||||
*/
|
||||
JS_ASSERT(!(funtc.flags & TCF_FUN_USES_NONLOCALS));
|
||||
if (!lambda && funAtom && !AT_TOP_LEVEL(tc))
|
||||
@ -1479,16 +1431,14 @@ Statements(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
||||
|
||||
/* If compiling top-level statements, emit as we go to save space. */
|
||||
if (!tc->topStmt && (tc->flags & TCF_COMPILING)) {
|
||||
if (cx->fp->fun &&
|
||||
JS_HAS_STRICT_OPTION(cx) &&
|
||||
(tc->flags & TCF_RETURN_EXPR)) {
|
||||
if (JS_HAS_STRICT_OPTION(cx) && (tc->flags & TCF_RETURN_EXPR)) {
|
||||
/*
|
||||
* Check pn2 for lack of a final return statement if it is the
|
||||
* last statement in the block.
|
||||
*/
|
||||
tt = js_PeekToken(cx, ts);
|
||||
if ((tt == TOK_EOF || tt == TOK_RC) &&
|
||||
!CheckFinalReturn(cx, ts, pn2)) {
|
||||
!CheckFinalReturn(cx, tc, pn2)) {
|
||||
tt = TOK_ERROR;
|
||||
break;
|
||||
}
|
||||
@ -1658,7 +1608,7 @@ BindLet(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc)
|
||||
JSScopeProperty *sprop;
|
||||
JSAtomListElement *ale;
|
||||
|
||||
blockObj = data->obj;
|
||||
blockObj = tc->blockChain;
|
||||
sprop = SCOPE_GET_PROPERTY(OBJ_SCOPE(blockObj), ATOM_TO_JSID(atom));
|
||||
ATOM_LIST_SEARCH(ale, &tc->decls, atom);
|
||||
if (sprop || (ale && ALE_JSOP(ale) == JSOP_DEFCONST)) {
|
||||
@ -1703,8 +1653,6 @@ BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc)
|
||||
JSAtomListElement *ale;
|
||||
JSOp op, prevop;
|
||||
const char *name;
|
||||
JSFunction *fun;
|
||||
JSObject *obj;
|
||||
JSLocalKind localKind;
|
||||
|
||||
stmt = js_LexicalLookup(tc, atom, NULL, 0);
|
||||
@ -1744,9 +1692,7 @@ BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc)
|
||||
}
|
||||
ALE_SET_JSOP(ale, op);
|
||||
|
||||
fun = data->u.var.fun;
|
||||
obj = data->obj;
|
||||
if (!fun || OBJ_GET_CLASS(cx, obj) != &js_FunctionClass) {
|
||||
if (!(tc->flags & TCF_IN_FUNCTION)) {
|
||||
/*
|
||||
* Don't lookup global variables or variables in an active frame at
|
||||
* compile time.
|
||||
@ -1754,19 +1700,19 @@ BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc)
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
localKind = js_LookupLocal(cx, fun, atom, NULL);
|
||||
localKind = js_LookupLocal(cx, tc->fun, atom, NULL);
|
||||
if (localKind == JSLOCAL_NONE) {
|
||||
/*
|
||||
* Property not found in current variable scope: we have not seen this
|
||||
* variable before. Define a new local variable by adding a property
|
||||
* to the function's scope, allocating one slot in the function's vars
|
||||
* frame. Global variables and any locals declared in with statement
|
||||
* bodies are handled at runtime, by script prolog JSOP_DEFVAR opcodes
|
||||
* generated for slot-less vars.
|
||||
* frame. Any locals declared in with statement bodies are handled at
|
||||
* runtime, by script prolog JSOP_DEFVAR opcodes generated for
|
||||
* slot-less vars.
|
||||
*/
|
||||
if (cx->fp->scopeChain == obj &&
|
||||
!js_InWithStatement(tc) &&
|
||||
!BindLocalVariable(cx, data, atom)) {
|
||||
localKind = (data->op == JSOP_DEFCONST) ? JSLOCAL_CONST : JSLOCAL_VAR;
|
||||
if (!js_InWithStatement(tc) &&
|
||||
!BindLocalVariable(cx, tc->fun, atom, localKind)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
} else if (localKind == JSLOCAL_ARG) {
|
||||
@ -1821,10 +1767,13 @@ BindDestructuringVar(JSContext *cx, BindData *data, JSParseNode *pn,
|
||||
* point, we can't select the optimal final opcode, yet we must preserve
|
||||
* the CONST bit and convey "set", not "get".
|
||||
*/
|
||||
pn->pn_op = (data->op == JSOP_DEFCONST)
|
||||
? JSOP_SETCONST
|
||||
: JSOP_SETNAME;
|
||||
pn->pn_const = (data->u.var.kind == JSLOCAL_CONST);
|
||||
if (data->op == JSOP_DEFCONST) {
|
||||
pn->pn_op = JSOP_SETCONST;
|
||||
pn->pn_const = JS_TRUE;
|
||||
} else {
|
||||
pn->pn_op = JSOP_SETNAME;
|
||||
pn->pn_const = JS_FALSE;
|
||||
}
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
@ -2284,7 +2233,7 @@ ReturnOrYield(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
||||
|
||||
if ((~tc->flags & (TCF_RETURN_EXPR | TCF_FUN_IS_GENERATOR)) == 0) {
|
||||
/* As in Python (see PEP-255), disallow return v; in generators. */
|
||||
ReportBadReturn(cx, ts, JSREPORT_ERROR,
|
||||
ReportBadReturn(cx, tc, JSREPORT_ERROR,
|
||||
JSMSG_BAD_GENERATOR_RETURN,
|
||||
JSMSG_BAD_ANON_GENERATOR_RETURN);
|
||||
return NULL;
|
||||
@ -2292,7 +2241,7 @@ ReturnOrYield(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
||||
|
||||
if (JS_HAS_STRICT_OPTION(cx) &&
|
||||
(~tc->flags & (TCF_RETURN_EXPR | TCF_RETURN_VOID)) == 0 &&
|
||||
!ReportBadReturn(cx, ts, JSREPORT_WARNING | JSREPORT_STRICT,
|
||||
!ReportBadReturn(cx, tc, JSREPORT_WARNING | JSREPORT_STRICT,
|
||||
JSMSG_NO_RETURN_VALUE,
|
||||
JSMSG_ANON_NO_RETURN_VALUE)) {
|
||||
return NULL;
|
||||
@ -2997,7 +2946,6 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
||||
* an intentional change that anticipates ECMA Ed. 4.
|
||||
*/
|
||||
data.pn = NULL;
|
||||
data.obj = tc->blockChain;
|
||||
data.op = JSOP_NOP;
|
||||
data.binder = BindLet;
|
||||
data.u.let.index = 0;
|
||||
@ -3531,7 +3479,6 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
||||
|
||||
data.pn = NULL;
|
||||
data.op = let ? JSOP_NOP : CURRENT_TOKEN(ts).t_op;
|
||||
data.binder = let ? BindLet : BindVarOrConst;
|
||||
pn = NewParseNode(cx, ts, PN_LIST, tc);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
@ -3550,25 +3497,11 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
||||
fp = cx->fp;
|
||||
if (let) {
|
||||
JS_ASSERT(tc->blockChain == scopeStmt->u.blockObj);
|
||||
data.obj = tc->blockChain;
|
||||
data.u.let.index = OBJ_BLOCK_COUNT(cx, data.obj);
|
||||
data.binder = BindLet;
|
||||
data.u.let.index = OBJ_BLOCK_COUNT(cx, tc->blockChain);
|
||||
data.u.let.overflow = JSMSG_TOO_MANY_FUN_VARS;
|
||||
} else {
|
||||
data.obj = fp->varobj;
|
||||
data.u.var.fun = fp->fun;
|
||||
data.u.var.clasp = OBJ_GET_CLASS(cx, data.obj);
|
||||
if (data.u.var.fun && data.u.var.clasp == &js_FunctionClass) {
|
||||
/* We are compiling code inside a function */
|
||||
data.u.var.kind = (data.op == JSOP_DEFCONST)
|
||||
? JSLOCAL_CONST
|
||||
: JSLOCAL_VAR;
|
||||
} else {
|
||||
/*
|
||||
* We are compiling global code or code from an eval inside a
|
||||
* function
|
||||
*/
|
||||
data.u.var.kind = JSLOCAL_NONE;
|
||||
}
|
||||
data.binder = BindVarOrConst;
|
||||
}
|
||||
|
||||
do {
|
||||
@ -3621,7 +3554,7 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
||||
pn2->pn_atom = atom;
|
||||
pn2->pn_slot = -1;
|
||||
if (!let)
|
||||
pn2->pn_const = (data.u.var.kind == JSLOCAL_CONST);
|
||||
pn2->pn_const = (data.op == JSOP_DEFCONST);
|
||||
PN_APPEND(pn, pn2);
|
||||
|
||||
if (js_MatchToken(cx, ts, TOK_ASSIGN)) {
|
||||
@ -4170,7 +4103,6 @@ ComprehensionTail(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
||||
pnp = &pn->pn_expr;
|
||||
|
||||
data.pn = NULL;
|
||||
data.obj = tc->blockChain;
|
||||
data.op = JSOP_NOP;
|
||||
data.binder = BindLet;
|
||||
data.u.let.index = 0;
|
||||
@ -4327,8 +4259,7 @@ GeneratorExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
||||
* Make the generator function and flag it as interpreted ASAP (see the
|
||||
* comment in FunctionBody).
|
||||
*/
|
||||
fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_LAMBDA | JSFUN_INTERPRETED,
|
||||
cx->fp->varobj, NULL);
|
||||
fun = NewCompilerFunction(cx, tc, NULL, JS_TRUE);
|
||||
if (!fun)
|
||||
return NULL;
|
||||
|
||||
@ -5754,7 +5685,7 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
||||
if (pn->pn_atom == cx->runtime->atomState.parentAtom ||
|
||||
pn->pn_atom == cx->runtime->atomState.protoAtom) {
|
||||
tc->flags |= TCF_FUN_HEAVYWEIGHT;
|
||||
} else {
|
||||
} else if (!(tc->flags & TCF_IN_FUNCTION)) {
|
||||
JSAtomListElement *ale;
|
||||
JSStackFrame *fp;
|
||||
JSBool loopy;
|
||||
|
@ -451,14 +451,18 @@ struct JSParseContext {
|
||||
/*
|
||||
* Parse a top-level JS script.
|
||||
*/
|
||||
extern JS_FRIEND_API(JSParseNode *)
|
||||
extern JSParseNode *
|
||||
js_ParseScript(JSContext *cx, JSObject *chain, JSParseContext *pc);
|
||||
|
||||
extern JS_FRIEND_API(JSScript *)
|
||||
js_CompileScript(JSContext *cx, JSObject *chain, JSParseContext *pc);
|
||||
extern JSScript *
|
||||
js_CompileScript(JSContext *cx, JSObject *obj, JSPrincipals *principals,
|
||||
uint32 tcflags, const jschar *chars, size_t length,
|
||||
FILE *file, const char *filename, uintN lineno);
|
||||
|
||||
extern JSBool
|
||||
js_CompileFunctionBody(JSContext *cx, JSParseContext *pc, JSFunction *fun);
|
||||
js_CompileFunctionBody(JSContext *cx, JSFunction *fun, JSPrincipals *principals,
|
||||
const jschar *chars, size_t length,
|
||||
const char *filename, uintN lineno);
|
||||
|
||||
extern JSBool
|
||||
js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc);
|
||||
@ -477,12 +481,12 @@ js_ParseXMLText(JSContext *cx, JSObject *chain, JSParseContext *pc,
|
||||
* current JSContext.tempPool mark. This means you cannot allocate from
|
||||
* tempPool and save the pointer beyond the next js_FinishParseContext.
|
||||
*/
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
js_InitParseContext(JSContext *cx, JSParseContext *pc,
|
||||
extern JSBool
|
||||
js_InitParseContext(JSContext *cx, JSParseContext *pc, JSPrincipals *principals,
|
||||
const jschar *base, size_t length, FILE *fp,
|
||||
const char *filename, uintN lineno);
|
||||
|
||||
extern JS_FRIEND_API(void)
|
||||
extern void
|
||||
js_FinishParseContext(JSContext *cx, JSParseContext *pc);
|
||||
|
||||
extern void
|
||||
|
@ -198,6 +198,7 @@ script_compile_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
||||
const char *file;
|
||||
uintN line;
|
||||
JSPrincipals *principals;
|
||||
uint32 tcflags;
|
||||
jsint execDepth;
|
||||
|
||||
/* Make sure obj is a Script object. */
|
||||
@ -250,17 +251,17 @@ 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 set JSFRAME_EVAL in fp's
|
||||
* flags, because compilation is here separated from execution, and the
|
||||
* 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.
|
||||
*/
|
||||
fp->flags |= JSFRAME_SCRIPT_OBJECT;
|
||||
script = JS_CompileUCScriptForPrincipals(cx, scopeobj, principals,
|
||||
JSSTRING_CHARS(str),
|
||||
JSSTRING_LENGTH(str),
|
||||
file, line);
|
||||
tcflags = 0;
|
||||
script = js_CompileScript(cx, scopeobj, principals, tcflags,
|
||||
JSSTRING_CHARS(str), JSSTRING_LENGTH(str),
|
||||
NULL, file, line);
|
||||
if (!script)
|
||||
return JS_FALSE;
|
||||
|
||||
@ -1387,12 +1388,13 @@ js_NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natoms,
|
||||
return script;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(JSScript *)
|
||||
js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg, JSFunction *fun)
|
||||
JSScript *
|
||||
js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
|
||||
{
|
||||
uint32 mainLength, prologLength, nsrcnotes;
|
||||
JSScript *script;
|
||||
const char *filename;
|
||||
JSFunction *fun;
|
||||
|
||||
/* The counts of indexed things must be checked during code generation. */
|
||||
JS_ASSERT(cg->atomList.count <= INDEX_LIMIT);
|
||||
@ -1441,7 +1443,9 @@ js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg, JSFunction *fun)
|
||||
* We initialize fun->u.script to be the script constructed above
|
||||
* so that the debugger has a valid FUN_SCRIPT(fun).
|
||||
*/
|
||||
if (fun) {
|
||||
fun = NULL;
|
||||
if (cg->treeContext.flags & TCF_IN_FUNCTION) {
|
||||
fun = cg->treeContext.fun;
|
||||
JS_ASSERT(FUN_INTERPRETED(fun) && !FUN_SCRIPT(fun));
|
||||
js_FreezeLocalNames(cx, fun);
|
||||
fun->u.i.script = script;
|
||||
|
@ -212,8 +212,8 @@ extern JSScript *
|
||||
js_NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natoms,
|
||||
uint32 nobjects, uint32 nregexps, uint32 ntrynotes);
|
||||
|
||||
extern JS_FRIEND_API(JSScript *)
|
||||
js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg, JSFunction *fun);
|
||||
extern JSScript *
|
||||
js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg);
|
||||
|
||||
/*
|
||||
* New-script-hook calling is factored from js_NewScriptFromCG so that it
|
||||
|
@ -2018,7 +2018,8 @@ ParseXMLSource(JSContext *cx, JSString *src)
|
||||
}
|
||||
}
|
||||
|
||||
if (!js_InitParseContext(cx, &pc, chars, length, NULL, filename, lineno))
|
||||
if (!js_InitParseContext(cx, &pc, NULL, chars, length, NULL,
|
||||
filename, lineno))
|
||||
goto out;
|
||||
pn = js_ParseXMLText(cx, cx->fp->scopeChain, &pc, JS_FALSE);
|
||||
if (pn && XMLArrayInit(cx, &nsarray, 1)) {
|
||||
|
Loading…
Reference in New Issue
Block a user