mirror of
https://github.com/dyne/FreeJ.git
synced 2026-06-16 12:59:33 +02:00
included javascript interpreter updated to spidermonkey 1.5
git-svn-id: svn://dyne.org/rastasoft/freej/trunk@736 383723c8-4afa-0310-b8a8-b1afb83214fc
This commit is contained in:
+264
-176
@@ -286,6 +286,7 @@ NewBinary(JSContext *cx, JSTokenType tt,
|
||||
left->pn_type == TOK_NUMBER &&
|
||||
right->pn_type == TOK_NUMBER) {
|
||||
left->pn_dval += right->pn_dval;
|
||||
left->pn_pos.end = right->pn_pos.end;
|
||||
RecycleTree(right, tc);
|
||||
return left;
|
||||
}
|
||||
@@ -416,6 +417,7 @@ js_CompileTokenStream(JSContext *cx, JSObject *chain, JSTokenStream *ts,
|
||||
JSCodeGenerator *cg)
|
||||
{
|
||||
JSStackFrame *fp, frame;
|
||||
uint32 flags;
|
||||
JSParseNode *pn;
|
||||
JSBool ok;
|
||||
#ifdef METER_PARSENODES
|
||||
@@ -438,6 +440,11 @@ js_CompileTokenStream(JSContext *cx, JSObject *chain, JSTokenStream *ts,
|
||||
frame.down = fp;
|
||||
cx->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);
|
||||
|
||||
/* Prevent GC activation while compiling. */
|
||||
JS_KEEP_ATOMS(cx->runtime);
|
||||
@@ -478,6 +485,7 @@ js_CompileTokenStream(JSContext *cx, JSObject *chain, JSTokenStream *ts,
|
||||
JS_DumpArenaStats(stdout);
|
||||
#endif
|
||||
JS_UNKEEP_ATOMS(cx->runtime);
|
||||
cx->fp->flags = flags;
|
||||
cx->fp = fp;
|
||||
return ok;
|
||||
}
|
||||
@@ -487,71 +495,87 @@ js_CompileTokenStream(JSContext *cx, JSObject *chain, JSTokenStream *ts,
|
||||
* smart about loops (do {...; return e2;} while(0) at the end of a function
|
||||
* that contains an early return e1 will get a strict-option-only warning).
|
||||
*/
|
||||
static JSBool
|
||||
#define ENDS_IN_OTHER 0
|
||||
#define ENDS_IN_RETURN 1
|
||||
#define ENDS_IN_BREAK 2
|
||||
|
||||
static int
|
||||
HasFinalReturn(JSParseNode *pn)
|
||||
{
|
||||
JSBool ok, hasDefault;
|
||||
uintN rv, rv2, hasDefault;
|
||||
JSParseNode *pn2, *pn3;
|
||||
|
||||
switch (pn->pn_type) {
|
||||
case TOK_LC:
|
||||
if (!pn->pn_head)
|
||||
return JS_FALSE;
|
||||
return ENDS_IN_OTHER;
|
||||
return HasFinalReturn(PN_LAST(pn));
|
||||
|
||||
case TOK_IF:
|
||||
ok = HasFinalReturn(pn->pn_kid2);
|
||||
ok &= pn->pn_kid3 && HasFinalReturn(pn->pn_kid3);
|
||||
return ok;
|
||||
rv = HasFinalReturn(pn->pn_kid2);
|
||||
if (pn->pn_kid3)
|
||||
rv &= HasFinalReturn(pn->pn_kid3);
|
||||
return rv;
|
||||
|
||||
#if JS_HAS_SWITCH_STATEMENT
|
||||
case TOK_SWITCH:
|
||||
ok = JS_TRUE;
|
||||
hasDefault = JS_FALSE;
|
||||
for (pn2 = pn->pn_kid2->pn_head; ok && pn2; pn2 = pn2->pn_next) {
|
||||
rv = ENDS_IN_RETURN;
|
||||
hasDefault = ENDS_IN_OTHER;
|
||||
for (pn2 = pn->pn_kid2->pn_head; rv && pn2; pn2 = pn2->pn_next) {
|
||||
if (pn2->pn_type == TOK_DEFAULT)
|
||||
hasDefault = JS_TRUE;
|
||||
hasDefault = ENDS_IN_RETURN;
|
||||
pn3 = pn2->pn_right;
|
||||
JS_ASSERT(pn3->pn_type == TOK_LC);
|
||||
if (pn3->pn_head)
|
||||
ok &= HasFinalReturn(PN_LAST(pn3));
|
||||
if (pn3->pn_head) {
|
||||
rv2 = HasFinalReturn(PN_LAST(pn3));
|
||||
if (rv2 == ENDS_IN_OTHER && pn2->pn_next)
|
||||
/* Falling through to next case or default. */;
|
||||
else
|
||||
rv &= rv2;
|
||||
}
|
||||
}
|
||||
/* If a final switch has no default case, we judge it harshly. */
|
||||
ok &= hasDefault;
|
||||
return ok;
|
||||
rv &= hasDefault;
|
||||
return rv;
|
||||
#endif /* JS_HAS_SWITCH_STATEMENT */
|
||||
|
||||
case TOK_BREAK:
|
||||
return ENDS_IN_BREAK;
|
||||
|
||||
case TOK_WITH:
|
||||
return HasFinalReturn(pn->pn_right);
|
||||
|
||||
case TOK_RETURN:
|
||||
return JS_TRUE;
|
||||
return ENDS_IN_RETURN;
|
||||
|
||||
#if JS_HAS_EXCEPTIONS
|
||||
case TOK_THROW:
|
||||
return JS_TRUE;
|
||||
return ENDS_IN_RETURN;
|
||||
|
||||
case TOK_TRY:
|
||||
/* If we have a finally block that returns, we are done. */
|
||||
if (pn->pn_kid3 && HasFinalReturn(pn->pn_kid3))
|
||||
return JS_TRUE;
|
||||
if (pn->pn_kid3) {
|
||||
rv = HasFinalReturn(pn->pn_kid3);
|
||||
if (rv == ENDS_IN_RETURN)
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* Else check the try block and any and all catch statements. */
|
||||
ok = HasFinalReturn(pn->pn_kid1);
|
||||
rv = HasFinalReturn(pn->pn_kid1);
|
||||
if (pn->pn_kid2)
|
||||
ok &= HasFinalReturn(pn->pn_kid2);
|
||||
return ok;
|
||||
rv &= HasFinalReturn(pn->pn_kid2);
|
||||
return rv;
|
||||
|
||||
case TOK_CATCH:
|
||||
/* Check this block's code and iterate over further catch blocks. */
|
||||
ok = HasFinalReturn(pn->pn_kid3);
|
||||
rv = HasFinalReturn(pn->pn_kid3);
|
||||
for (pn2 = pn->pn_kid2; pn2; pn2 = pn2->pn_kid2)
|
||||
ok &= HasFinalReturn(pn2->pn_kid3);
|
||||
return ok;
|
||||
rv &= HasFinalReturn(pn2->pn_kid3);
|
||||
return rv;
|
||||
#endif
|
||||
|
||||
default:
|
||||
return JS_FALSE;
|
||||
return ENDS_IN_OTHER;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -580,7 +604,7 @@ ReportNoReturnValue(JSContext *cx, JSTokenStream *ts)
|
||||
static JSBool
|
||||
CheckFinalReturn(JSContext *cx, JSTokenStream *ts, JSParseNode *pn)
|
||||
{
|
||||
return HasFinalReturn(pn) || ReportNoReturnValue(cx, ts);
|
||||
return HasFinalReturn(pn) == ENDS_IN_RETURN || ReportNoReturnValue(cx, ts);
|
||||
}
|
||||
|
||||
static JSParseNode *
|
||||
@@ -600,6 +624,7 @@ FunctionBody(JSContext *cx, JSTokenStream *ts, JSFunction *fun,
|
||||
frame.fun = fun;
|
||||
frame.varobj = frame.scopeChain = funobj;
|
||||
frame.down = fp;
|
||||
frame.flags = (fp->flags & JSFRAME_COMPILE_N_GO);
|
||||
cx->fp = &frame;
|
||||
}
|
||||
|
||||
@@ -644,15 +669,18 @@ js_CompileFunctionBody(JSContext *cx, JSTokenStream *ts, JSFunction *fun)
|
||||
/* Prevent GC activation while compiling. */
|
||||
JS_KEEP_ATOMS(cx->runtime);
|
||||
|
||||
/* Push a JSStackFrame for use by FunctionBody and js_EmitFunctionBody. */
|
||||
/* 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);
|
||||
JS_ASSERT(!fp || (fp->fun != fun && fp->varobj != funobj &&
|
||||
fp->scopeChain != funobj));
|
||||
memset(&frame, 0, sizeof frame);
|
||||
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;
|
||||
|
||||
/* Ensure that the body looks like a block statement to js_EmitTree. */
|
||||
@@ -665,10 +693,11 @@ js_CompileFunctionBody(JSContext *cx, JSTokenStream *ts, JSFunction *fun)
|
||||
* No need to emit code here -- Statements (via FunctionBody) already
|
||||
* has. See similar comment in js_CompileTokenStream, and bug 108257.
|
||||
*/
|
||||
fun->script = js_NewScriptFromCG(cx, &funcg, fun);
|
||||
if (!fun->script) {
|
||||
fun->u.script = js_NewScriptFromCG(cx, &funcg, fun);
|
||||
if (!fun->u.script) {
|
||||
ok = JS_FALSE;
|
||||
} else {
|
||||
fun->interpreted = JS_TRUE;
|
||||
if (funcg.treeContext.flags & TCF_FUN_HEAVYWEIGHT)
|
||||
fun->flags |= JSFUN_HEAVYWEIGHT;
|
||||
ok = JS_TRUE;
|
||||
@@ -688,39 +717,113 @@ static JSParseNode *
|
||||
FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
||||
JSBool lambda)
|
||||
{
|
||||
JSParseNode *pn, *body;
|
||||
JSOp op, prevop;
|
||||
JSParseNode *pn, *body;
|
||||
JSAtom *funAtom, *argAtom;
|
||||
JSStackFrame *fp;
|
||||
JSObject *varobj, *pobj;
|
||||
JSAtomListElement *ale;
|
||||
JSProperty *prop;
|
||||
JSFunction *fun;
|
||||
JSObject *parent;
|
||||
JSObject *pobj;
|
||||
JSScopeProperty *sprop;
|
||||
uintN dupflag;
|
||||
JSBool ok;
|
||||
JSTreeContext funtc;
|
||||
JSAtomListElement *ale;
|
||||
|
||||
/* Make a TOK_FUNCTION node. */
|
||||
pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_FUNC, tc);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
#if JS_HAS_GETTER_SETTER
|
||||
op = CURRENT_TOKEN(ts).t_op;
|
||||
#endif
|
||||
pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_FUNC, tc);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
|
||||
/* Scan the optional function name into funAtom. */
|
||||
if (js_MatchToken(cx, ts, TOK_NAME))
|
||||
funAtom = CURRENT_TOKEN(ts).t_atom;
|
||||
else
|
||||
funAtom = NULL;
|
||||
funAtom = js_MatchToken(cx, ts, TOK_NAME) ? CURRENT_TOKEN(ts).t_atom : NULL;
|
||||
|
||||
/* Find the nearest variable-declaring scope and use it as our parent. */
|
||||
parent = cx->fp->varobj;
|
||||
fun = js_NewFunction(cx, NULL, NULL, 0, lambda ? JSFUN_LAMBDA : 0, 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.
|
||||
*/
|
||||
if (!lambda && funAtom) {
|
||||
ATOM_LIST_SEARCH(ale, &tc->decls, funAtom);
|
||||
if (ale) {
|
||||
prevop = ALE_JSOP(ale);
|
||||
if (JS_HAS_STRICT_OPTION(cx) || prevop == JSOP_DEFCONST) {
|
||||
const char *name = js_AtomToPrintableString(cx, funAtom);
|
||||
if (!name ||
|
||||
!js_ReportCompileErrorNumber(cx, ts, NULL,
|
||||
(prevop != JSOP_DEFCONST)
|
||||
? JSREPORT_WARNING |
|
||||
JSREPORT_STRICT
|
||||
: JSREPORT_ERROR,
|
||||
JSMSG_REDECLARED_VAR,
|
||||
(prevop == JSOP_DEFFUN ||
|
||||
prevop == JSOP_CLOSURE)
|
||||
? js_function_str
|
||||
: (prevop == JSOP_DEFCONST)
|
||||
? js_const_str
|
||||
: js_var_str,
|
||||
name)) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (tc->topStmt && prevop == JSOP_DEFVAR)
|
||||
tc->flags |= TCF_FUN_CLOSURE_VS_VAR;
|
||||
} else {
|
||||
ale = js_IndexAtom(cx, funAtom, &tc->decls);
|
||||
if (!ale)
|
||||
return NULL;
|
||||
}
|
||||
ALE_SET_JSOP(ale, tc->topStmt ? JSOP_CLOSURE : JSOP_DEFFUN);
|
||||
|
||||
#if JS_HAS_LEXICAL_CLOSURE
|
||||
/*
|
||||
* A function nested at top level inside another's body needs only a
|
||||
* local variable to bind its name to its value, and not an activation
|
||||
* object property (it might also need the activation property, if the
|
||||
* outer function contains with statements, e.g., but the stack slot
|
||||
* wins when jsemit.c's LookupArgOrVar can optimize a JSOP_NAME into a
|
||||
* JSOP_GETVAR bytecode).
|
||||
*/
|
||||
if (!tc->topStmt && (tc->flags & TCF_IN_FUNCTION)) {
|
||||
/*
|
||||
* Define a property on the outer function so that LookupArgOrVar
|
||||
* can properly optimize accesses.
|
||||
*
|
||||
* XXX Here and in Variables, we use the function object's scope,
|
||||
* XXX arguably polluting it, when we could use a compiler-private
|
||||
* XXX scope structure. Tradition!
|
||||
*/
|
||||
JS_ASSERT(OBJ_GET_CLASS(cx, varobj) == &js_FunctionClass);
|
||||
JS_ASSERT(fp->fun == (JSFunction *) JS_GetPrivate(cx, varobj));
|
||||
if (!js_LookupProperty(cx, varobj, (jsid)funAtom, &pobj, &prop))
|
||||
return NULL;
|
||||
if (prop)
|
||||
OBJ_DROP_PROPERTY(cx, pobj, prop);
|
||||
if (!prop || pobj != varobj) {
|
||||
if (!js_DefineNativeProperty(cx, varobj, (jsid)funAtom,
|
||||
JSVAL_VOID,
|
||||
js_GetLocalVariable,
|
||||
js_SetLocalVariable,
|
||||
JSPROP_ENUMERATE | JSPROP_SHARED,
|
||||
SPROP_HAS_SHORTID, fp->fun->nvars,
|
||||
NULL)) {
|
||||
return NULL;
|
||||
}
|
||||
fp->fun->nvars++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
fun = js_NewFunction(cx, NULL, NULL, 0, lambda ? JSFUN_LAMBDA : 0, varobj,
|
||||
funAtom);
|
||||
if (!fun)
|
||||
return NULL;
|
||||
|
||||
#if JS_HAS_GETTER_SETTER
|
||||
if (op != JSOP_NOP)
|
||||
fun->flags |= (op == JSOP_GETTER) ? JSPROP_GETTER : JSPROP_SETTER;
|
||||
@@ -734,14 +837,14 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
||||
argAtom = CURRENT_TOKEN(ts).t_atom;
|
||||
pobj = NULL;
|
||||
if (!js_LookupProperty(cx, fun->object, (jsid)argAtom, &pobj,
|
||||
(JSProperty **)&sprop)) {
|
||||
&prop)) {
|
||||
return NULL;
|
||||
}
|
||||
dupflag = 0;
|
||||
if (sprop) {
|
||||
if (prop) {
|
||||
ok = JS_TRUE;
|
||||
if (pobj == fun->object &&
|
||||
sprop->getter == js_GetArgument) {
|
||||
((JSScopeProperty *) prop)->getter == js_GetArgument) {
|
||||
const char *name = js_AtomToPrintableString(cx, argAtom);
|
||||
|
||||
/*
|
||||
@@ -759,10 +862,10 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
||||
|
||||
dupflag = SPROP_IS_DUPLICATE;
|
||||
}
|
||||
OBJ_DROP_PROPERTY(cx, pobj, (JSProperty *)sprop);
|
||||
OBJ_DROP_PROPERTY(cx, pobj, prop);
|
||||
if (!ok)
|
||||
return NULL;
|
||||
sprop = NULL;
|
||||
prop = NULL;
|
||||
}
|
||||
if (!js_AddNativeProperty(cx, fun->object, (jsid)argAtom,
|
||||
js_GetArgument, js_SetArgument,
|
||||
@@ -815,81 +918,6 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Record names for function statements in tc->decls so we know when to
|
||||
* avoid optimizing variable references that might name a function.
|
||||
*/
|
||||
if (!lambda && funAtom) {
|
||||
ATOM_LIST_SEARCH(ale, &tc->decls, funAtom);
|
||||
if (ale) {
|
||||
prevop = ALE_JSOP(ale);
|
||||
if (JS_HAS_STRICT_OPTION(cx) || prevop == JSOP_DEFCONST) {
|
||||
const char *name = js_AtomToPrintableString(cx, funAtom);
|
||||
if (!name ||
|
||||
!js_ReportCompileErrorNumber(cx, ts, NULL,
|
||||
(prevop != JSOP_DEFCONST)
|
||||
? JSREPORT_WARNING |
|
||||
JSREPORT_STRICT
|
||||
: JSREPORT_ERROR,
|
||||
JSMSG_REDECLARED_VAR,
|
||||
(prevop == JSOP_DEFFUN ||
|
||||
prevop == JSOP_CLOSURE)
|
||||
? js_function_str
|
||||
: (prevop == JSOP_DEFCONST)
|
||||
? js_const_str
|
||||
: js_var_str,
|
||||
name)) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (tc->topStmt && prevop == JSOP_DEFVAR)
|
||||
tc->flags |= TCF_FUN_CLOSURE_VS_VAR;
|
||||
} else {
|
||||
ale = js_IndexAtom(cx, funAtom, &tc->decls);
|
||||
if (!ale)
|
||||
return NULL;
|
||||
}
|
||||
ALE_SET_JSOP(ale, tc->topStmt ? JSOP_CLOSURE : JSOP_DEFFUN);
|
||||
|
||||
#if JS_HAS_LEXICAL_CLOSURE
|
||||
/*
|
||||
* A function nested at top level inside another's body needs only a
|
||||
* local variable to bind its name to its value, and not an activation
|
||||
* object property (it might also need the activation property, if the
|
||||
* outer function contains with statements, e.g., but the stack slot
|
||||
* wins when jsemit.c's LookupArgOrVar can optimize a JSOP_NAME into a
|
||||
* JSOP_GETVAR bytecode).
|
||||
*/
|
||||
if (!tc->topStmt && (tc->flags & TCF_IN_FUNCTION)) {
|
||||
JSStackFrame *fp;
|
||||
JSObject *varobj;
|
||||
|
||||
/*
|
||||
* Define a property on the outer function so that LookupArgOrVar
|
||||
* can properly optimize accesses.
|
||||
*
|
||||
* XXX Here and in Variables, we use the function object's scope,
|
||||
* XXX arguably polluting it, when we could use a compiler-private
|
||||
* XXX scope structure. Tradition!
|
||||
*/
|
||||
fp = cx->fp;
|
||||
varobj = fp->varobj;
|
||||
JS_ASSERT(OBJ_GET_CLASS(cx, varobj) == &js_FunctionClass);
|
||||
JS_ASSERT(fp->fun == (JSFunction *) JS_GetPrivate(cx, varobj));
|
||||
if (!js_DefineNativeProperty(cx, varobj, (jsid)funAtom,
|
||||
OBJECT_TO_JSVAL(fun->object),
|
||||
js_GetLocalVariable,
|
||||
js_SetLocalVariable,
|
||||
JSPROP_ENUMERATE,
|
||||
SPROP_HAS_SHORTID, fp->fun->nvars,
|
||||
NULL)) {
|
||||
return NULL;
|
||||
}
|
||||
fp->fun->nvars++;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if JS_HAS_LEXICAL_CLOSURE
|
||||
if (lambda || !funAtom) {
|
||||
/*
|
||||
@@ -911,9 +939,11 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
||||
op = JSOP_NOP;
|
||||
|
||||
/*
|
||||
* Pending a better automatic GC root management scheme (see Mozilla bug
|
||||
* 40757, http://bugzilla.mozilla.org/show_bug.cgi?id=40757), we need to
|
||||
* atomize here to protect against a GC activation.
|
||||
* Absent use of the new scoped local GC roots API around compiler calls,
|
||||
* we need to atomize here to protect against a GC activation. Atoms are
|
||||
* protected from GC during compilation by the JS_FRIEND_API entry points
|
||||
* in this file. There doesn't seem to be any gain in switching from the
|
||||
* atom-keeping method to the bulkier, slower scoped local roots method.
|
||||
*/
|
||||
pn->pn_funAtom = js_AtomizeObject(cx, fun->object, 0);
|
||||
if (!pn->pn_funAtom)
|
||||
@@ -959,13 +989,13 @@ Statements(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
||||
return NULL;
|
||||
PN_INIT_LIST(pn);
|
||||
|
||||
ts->flags |= TSF_REGEXP;
|
||||
ts->flags |= TSF_OPERAND;
|
||||
while ((tt = js_PeekToken(cx, ts)) > TOK_EOF && tt != TOK_RC) {
|
||||
ts->flags &= ~TSF_REGEXP;
|
||||
ts->flags &= ~TSF_OPERAND;
|
||||
pn2 = Statement(cx, ts, tc);
|
||||
if (!pn2)
|
||||
return NULL;
|
||||
ts->flags |= TSF_REGEXP;
|
||||
ts->flags |= TSF_OPERAND;
|
||||
|
||||
/* If compiling top-level statements, emit as we go to save space. */
|
||||
if (!tc->topStmt && (tc->flags & TCF_COMPILING)) {
|
||||
@@ -1000,7 +1030,7 @@ Statements(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
||||
PN_APPEND(pn, pn2);
|
||||
}
|
||||
}
|
||||
ts->flags &= ~TSF_REGEXP;
|
||||
ts->flags &= ~TSF_OPERAND;
|
||||
if (tt == TOK_ERROR)
|
||||
return NULL;
|
||||
|
||||
@@ -1099,9 +1129,9 @@ ImportExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
||||
pn->pn_slot = -1;
|
||||
pn->pn_attrs = 0;
|
||||
|
||||
ts->flags |= TSF_REGEXP;
|
||||
ts->flags |= TSF_OPERAND;
|
||||
while ((tt = js_GetToken(cx, ts)) == TOK_DOT || tt == TOK_LB) {
|
||||
ts->flags &= ~TSF_REGEXP;
|
||||
ts->flags &= ~TSF_OPERAND;
|
||||
if (pn->pn_op == JSOP_IMPORTALL)
|
||||
goto bad_import;
|
||||
|
||||
@@ -1141,9 +1171,9 @@ ImportExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
||||
}
|
||||
|
||||
pn = pn2;
|
||||
ts->flags |= TSF_REGEXP;
|
||||
ts->flags |= TSF_OPERAND;
|
||||
}
|
||||
ts->flags &= ~TSF_REGEXP;
|
||||
ts->flags &= ~TSF_OPERAND;
|
||||
if (tt == TOK_ERROR)
|
||||
return NULL;
|
||||
js_UngetToken(ts);
|
||||
@@ -1178,9 +1208,11 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
||||
JSStmtInfo stmtInfo, *stmt, *stmt2;
|
||||
JSAtom *label;
|
||||
|
||||
ts->flags |= TSF_REGEXP;
|
||||
CHECK_RECURSION();
|
||||
|
||||
ts->flags |= TSF_OPERAND;
|
||||
tt = js_GetToken(cx, ts);
|
||||
ts->flags &= ~TSF_REGEXP;
|
||||
ts->flags &= ~TSF_OPERAND;
|
||||
|
||||
#if JS_HAS_GETTER_SETTER
|
||||
if (tt == TOK_NAME) {
|
||||
@@ -1400,6 +1432,15 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
||||
js_PopStatement(tc);
|
||||
pn->pn_pos.end = pn2->pn_pos.end;
|
||||
pn->pn_right = pn2;
|
||||
if (cx->version != JSVERSION_ECMA_3) {
|
||||
/*
|
||||
* All legacy and extended versions must do automatic semicolon
|
||||
* insertion after do-while. See the testcase and discussion in
|
||||
* http://bugzilla.mozilla.org/show_bug.cgi?id=238945.
|
||||
*/
|
||||
(void) js_MatchToken(cx, ts, TOK_SEMI);
|
||||
return pn;
|
||||
}
|
||||
break;
|
||||
#endif /* JS_HAS_DO_WHILE_LOOP */
|
||||
|
||||
@@ -1411,7 +1452,9 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
||||
js_PushStatement(tc, &stmtInfo, STMT_FOR_LOOP, -1);
|
||||
|
||||
MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR);
|
||||
ts->flags |= TSF_OPERAND;
|
||||
tt = js_PeekToken(cx, ts);
|
||||
ts->flags &= ~TSF_OPERAND;
|
||||
if (tt == TOK_SEMI) {
|
||||
/* No initializer -- set first kid of left sub-node to null. */
|
||||
pn1 = NULL;
|
||||
@@ -1463,9 +1506,13 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
||||
}
|
||||
|
||||
if (pn1->pn_type == TOK_VAR) {
|
||||
/* Tell js_EmitTree(TOK_VAR) to generate a final POP. */
|
||||
pn1->pn_extra = JS_TRUE;
|
||||
/* Tell js_EmitTree(TOK_VAR) that pn1 is part of a for/in. */
|
||||
pn1->pn_extra |= PNX_FORINVAR;
|
||||
|
||||
/* Generate a final POP only if the var has an initializer. */
|
||||
pn2 = pn1->pn_head;
|
||||
if (pn2->pn_expr)
|
||||
pn1->pn_extra |= PNX_POPVAR;
|
||||
} else {
|
||||
pn2 = pn1;
|
||||
}
|
||||
@@ -1484,7 +1531,10 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
||||
} else {
|
||||
/* Parse the loop condition or null into pn2. */
|
||||
MUST_MATCH_TOKEN(TOK_SEMI, JSMSG_SEMI_AFTER_FOR_INIT);
|
||||
if (js_PeekToken(cx, ts) == TOK_SEMI) {
|
||||
ts->flags |= TSF_OPERAND;
|
||||
tt = js_PeekToken(cx, ts);
|
||||
ts->flags &= ~TSF_OPERAND;
|
||||
if (tt == TOK_SEMI) {
|
||||
pn2 = NULL;
|
||||
} else {
|
||||
pn2 = Expr(cx, ts, tc);
|
||||
@@ -1494,7 +1544,10 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
||||
|
||||
/* Parse the update expression or null into pn3. */
|
||||
MUST_MATCH_TOKEN(TOK_SEMI, JSMSG_SEMI_AFTER_FOR_COND);
|
||||
if (js_PeekToken(cx, ts) == TOK_RP) {
|
||||
ts->flags |= TSF_OPERAND;
|
||||
tt = js_PeekToken(cx, ts);
|
||||
ts->flags &= ~TSF_OPERAND;
|
||||
if (tt == TOK_RP) {
|
||||
pn3 = NULL;
|
||||
} else {
|
||||
pn3 = Expr(cx, ts, tc);
|
||||
@@ -1645,6 +1698,19 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
||||
pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY, tc);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
|
||||
/* ECMA-262 Edition 3 says 'throw [no LineTerminator here] Expr'. */
|
||||
ts->flags |= TSF_OPERAND;
|
||||
tt = js_PeekTokenSameLine(cx, ts);
|
||||
ts->flags &= ~TSF_OPERAND;
|
||||
if (tt == TOK_ERROR)
|
||||
return NULL;
|
||||
if (tt == TOK_EOF || tt == TOK_EOL || tt == TOK_SEMI || tt == TOK_RC) {
|
||||
js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
|
||||
JSMSG_SYNTAX_ERROR);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pn2 = Expr(cx, ts, tc);
|
||||
if (!pn2)
|
||||
return NULL;
|
||||
@@ -1744,6 +1810,13 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
||||
break;
|
||||
|
||||
case TOK_WITH:
|
||||
if (!js_ReportCompileErrorNumber(cx, ts, NULL,
|
||||
JSREPORT_WARNING | JSREPORT_STRICT,
|
||||
JSMSG_DEPRECATED_USAGE,
|
||||
js_with_statement_str)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY, tc);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
@@ -1760,14 +1833,6 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
||||
return NULL;
|
||||
js_PopStatement(tc);
|
||||
|
||||
/* Deprecate after parsing, in case of WERROR option. */
|
||||
if (!js_ReportCompileErrorNumber(cx, ts, NULL,
|
||||
JSREPORT_WARNING | JSREPORT_STRICT,
|
||||
JSMSG_DEPRECATED_USAGE,
|
||||
js_with_statement_str)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pn->pn_pos.end = pn2->pn_pos.end;
|
||||
pn->pn_right = pn2;
|
||||
tc->flags |= TCF_FUN_HEAVYWEIGHT;
|
||||
@@ -1779,7 +1844,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
||||
return NULL;
|
||||
|
||||
/* Tell js_EmitTree to generate a final POP. */
|
||||
pn->pn_extra = JS_TRUE;
|
||||
pn->pn_extra |= PNX_POPVAR;
|
||||
break;
|
||||
|
||||
case TOK_RETURN:
|
||||
@@ -1793,9 +1858,9 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
||||
return NULL;
|
||||
|
||||
/* This is ugly, but we don't want to require a semicolon. */
|
||||
ts->flags |= TSF_REGEXP;
|
||||
ts->flags |= TSF_OPERAND;
|
||||
tt = js_PeekTokenSameLine(cx, ts);
|
||||
ts->flags &= ~TSF_REGEXP;
|
||||
ts->flags &= ~TSF_OPERAND;
|
||||
if (tt == TOK_ERROR)
|
||||
return NULL;
|
||||
|
||||
@@ -1945,7 +2010,7 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
||||
if (!pn)
|
||||
return NULL;
|
||||
pn->pn_op = CURRENT_TOKEN(ts).t_op;
|
||||
pn->pn_extra = JS_FALSE; /* assume no JSOP_POP needed */
|
||||
pn->pn_extra = 0; /* assume no JSOP_POP needed */
|
||||
PN_INIT_LIST(pn);
|
||||
|
||||
/*
|
||||
@@ -2032,11 +2097,14 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
||||
: JSPROP_ENUMERATE | JSPROP_PERMANENT;
|
||||
PN_APPEND(pn, pn2);
|
||||
|
||||
if (!OBJ_LOOKUP_PROPERTY(cx, obj, (jsid)atom, &pobj, &prop))
|
||||
return NULL;
|
||||
if (pobj == obj &&
|
||||
OBJ_IS_NATIVE(pobj) &&
|
||||
(sprop = (JSScopeProperty *)prop) != NULL) {
|
||||
if (!fun) {
|
||||
prop = NULL; /* don't lookup global variables at compile time */
|
||||
} else {
|
||||
if (!OBJ_LOOKUP_PROPERTY(cx, obj, (jsid)atom, &pobj, &prop))
|
||||
return NULL;
|
||||
}
|
||||
if (prop && pobj == obj && OBJ_IS_NATIVE(pobj)) {
|
||||
sprop = (JSScopeProperty *)prop;
|
||||
if (sprop->getter == js_GetArgument) {
|
||||
const char *name = js_AtomToPrintableString(cx, atom);
|
||||
if (!name) {
|
||||
@@ -2512,9 +2580,9 @@ UnaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
||||
JSTokenType tt;
|
||||
JSParseNode *pn, *pn2;
|
||||
|
||||
ts->flags |= TSF_REGEXP;
|
||||
ts->flags |= TSF_OPERAND;
|
||||
tt = js_GetToken(cx, ts);
|
||||
ts->flags &= ~TSF_REGEXP;
|
||||
ts->flags &= ~TSF_OPERAND;
|
||||
|
||||
switch (tt) {
|
||||
case TOK_UNARYOP:
|
||||
@@ -2597,9 +2665,9 @@ ArgumentList(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
||||
{
|
||||
JSBool matched;
|
||||
|
||||
ts->flags |= TSF_REGEXP;
|
||||
ts->flags |= TSF_OPERAND;
|
||||
matched = js_MatchToken(cx, ts, TOK_RP);
|
||||
ts->flags &= ~TSF_REGEXP;
|
||||
ts->flags &= ~TSF_OPERAND;
|
||||
if (!matched) {
|
||||
do {
|
||||
JSParseNode *argNode = AssignExpr(cx, ts, tc);
|
||||
@@ -2627,9 +2695,9 @@ MemberExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
||||
CHECK_RECURSION();
|
||||
|
||||
/* Check for new expression first. */
|
||||
ts->flags |= TSF_REGEXP;
|
||||
ts->flags |= TSF_OPERAND;
|
||||
tt = js_PeekToken(cx, ts);
|
||||
ts->flags &= ~TSF_REGEXP;
|
||||
ts->flags &= ~TSF_OPERAND;
|
||||
if (tt == TOK_NEW) {
|
||||
(void) js_GetToken(cx, ts);
|
||||
|
||||
@@ -2715,7 +2783,7 @@ MemberExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
||||
JSMSG_TOO_MANY_FUN_ARGS);
|
||||
return NULL;
|
||||
}
|
||||
pn2->pn_pos.end = PN_LAST(pn2)->pn_pos.end;
|
||||
pn2->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
|
||||
} else {
|
||||
js_UngetToken(ts);
|
||||
return pn;
|
||||
@@ -2748,16 +2816,16 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
||||
again:
|
||||
/*
|
||||
* Control flows here after #n= is scanned. If the following primary is
|
||||
* not valid after such a "sharp variable" definition, the token type case
|
||||
* not valid after such a "sharp variable" definition, the tt switch case
|
||||
* should set notsharp.
|
||||
*/
|
||||
#endif
|
||||
|
||||
CHECK_RECURSION();
|
||||
|
||||
ts->flags |= TSF_REGEXP;
|
||||
ts->flags |= TSF_OPERAND;
|
||||
tt = js_GetToken(cx, ts);
|
||||
ts->flags &= ~TSF_REGEXP;
|
||||
ts->flags &= ~TSF_OPERAND;
|
||||
|
||||
#if JS_HAS_GETTER_SETTER
|
||||
if (tt == TOK_NAME) {
|
||||
@@ -2786,7 +2854,7 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
||||
if (!pn)
|
||||
return NULL;
|
||||
pn->pn_type = TOK_RB;
|
||||
pn->pn_extra = JS_FALSE;
|
||||
pn->pn_extra = 0;
|
||||
|
||||
#if JS_HAS_SHARP_VARS
|
||||
if (defsharp) {
|
||||
@@ -2796,16 +2864,16 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
||||
#endif
|
||||
PN_INIT_LIST(pn);
|
||||
|
||||
ts->flags |= TSF_REGEXP;
|
||||
ts->flags |= TSF_OPERAND;
|
||||
matched = js_MatchToken(cx, ts, TOK_RB);
|
||||
ts->flags &= ~TSF_REGEXP;
|
||||
ts->flags &= ~TSF_OPERAND;
|
||||
if (!matched) {
|
||||
for (atomIndex = 0; atomIndex < ATOM_INDEX_LIMIT; atomIndex++) {
|
||||
ts->flags |= TSF_REGEXP;
|
||||
ts->flags |= TSF_OPERAND;
|
||||
tt = js_PeekToken(cx, ts);
|
||||
ts->flags &= ~TSF_REGEXP;
|
||||
ts->flags &= ~TSF_OPERAND;
|
||||
if (tt == TOK_RB) {
|
||||
pn->pn_extra = JS_TRUE;
|
||||
pn->pn_extra |= PNX_ENDCOMMA;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -3009,6 +3077,26 @@ 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 {
|
||||
JSAtomListElement *ale;
|
||||
JSStackFrame *fp;
|
||||
JSStmtInfo *stmt;
|
||||
|
||||
/* Measure optimizable global variable uses. */
|
||||
ATOM_LIST_SEARCH(ale, &tc->decls, pn->pn_atom);
|
||||
if (ale &&
|
||||
!(fp = cx->fp)->fun &&
|
||||
fp->scopeChain == fp->varobj &&
|
||||
!js_InWithStatement(tc) &&
|
||||
!js_InCatchBlock(tc, pn->pn_atom)) {
|
||||
tc->globalUses++;
|
||||
for (stmt = tc->topStmt; stmt; stmt = stmt->down) {
|
||||
if (STMT_IS_LOOP(stmt)) {
|
||||
tc->loopyGlobalUses++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user