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