зеркало из https://github.com/mozilla/pjs.git
Bug 408271: check for missing return when parsing a function body in one place. r,a=brendan
This commit is contained in:
Родитель
cb4075c49b
Коммит
8ddf830a10
|
@ -89,7 +89,6 @@ js_InitCodeGenerator(JSContext *cx, JSCodeGenerator *cg, JSParseContext *pc,
|
||||||
{
|
{
|
||||||
memset(cg, 0, sizeof *cg);
|
memset(cg, 0, sizeof *cg);
|
||||||
TREE_CONTEXT_INIT(&cg->treeContext, pc);
|
TREE_CONTEXT_INIT(&cg->treeContext, pc);
|
||||||
cg->treeContext.flags |= TCF_COMPILING;
|
|
||||||
cg->codePool = codePool;
|
cg->codePool = codePool;
|
||||||
cg->notePool = notePool;
|
cg->notePool = notePool;
|
||||||
cg->codeMark = JS_ARENA_MARK(codePool);
|
cg->codeMark = JS_ARENA_MARK(codePool);
|
||||||
|
@ -1842,9 +1841,10 @@ EmitSlotIndexOp(JSContext *cx, JSOp op, uintN slot, uintN index,
|
||||||
* in js_EmitTree.
|
* in js_EmitTree.
|
||||||
*/
|
*/
|
||||||
static JSBool
|
static JSBool
|
||||||
BindNameToSlot(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
|
BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
|
||||||
uintN decltype)
|
uintN decltype)
|
||||||
{
|
{
|
||||||
|
JSTreeContext *tc;
|
||||||
JSAtom *atom;
|
JSAtom *atom;
|
||||||
JSStmtInfo *stmt;
|
JSStmtInfo *stmt;
|
||||||
jsint slot;
|
jsint slot;
|
||||||
|
@ -1869,6 +1869,7 @@ BindNameToSlot(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
|
||||||
* as this node. FIXME: we should be able to optimize catch vars to be
|
* as this node. FIXME: we should be able to optimize catch vars to be
|
||||||
* block-locals.
|
* block-locals.
|
||||||
*/
|
*/
|
||||||
|
tc = &cg->treeContext;
|
||||||
atom = pn->pn_atom;
|
atom = pn->pn_atom;
|
||||||
if (decltype != VAR_DECL &&
|
if (decltype != VAR_DECL &&
|
||||||
(stmt = js_LexicalLookup(tc, atom, &slot, decltype))) {
|
(stmt = js_LexicalLookup(tc, atom, &slot, decltype))) {
|
||||||
|
@ -1960,8 +1961,7 @@ BindNameToSlot(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
|
||||||
constOp = (ALE_JSOP(ale) == JSOP_DEFCONST);
|
constOp = (ALE_JSOP(ale) == JSOP_DEFCONST);
|
||||||
|
|
||||||
/* Index atom so we can map fast global number to name. */
|
/* Index atom so we can map fast global number to name. */
|
||||||
JS_ASSERT(tc->flags & TCF_COMPILING);
|
ale = js_IndexAtom(cx, atom, &cg->atomList);
|
||||||
ale = js_IndexAtom(cx, atom, &((JSCodeGenerator *) tc)->atomList);
|
|
||||||
if (!ale)
|
if (!ale)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|
||||||
|
@ -2071,7 +2071,7 @@ BindNameToSlot(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
|
||||||
* pop bytecode.
|
* pop bytecode.
|
||||||
*/
|
*/
|
||||||
static JSBool
|
static JSBool
|
||||||
CheckSideEffects(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
|
CheckSideEffects(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
|
||||||
JSBool *answer)
|
JSBool *answer)
|
||||||
{
|
{
|
||||||
JSBool ok;
|
JSBool ok;
|
||||||
|
@ -2120,14 +2120,14 @@ CheckSideEffects(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
|
||||||
*answer = JS_TRUE;
|
*answer = JS_TRUE;
|
||||||
} else {
|
} else {
|
||||||
for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next)
|
for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next)
|
||||||
ok &= CheckSideEffects(cx, tc, pn2, answer);
|
ok &= CheckSideEffects(cx, cg, pn2, answer);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PN_TERNARY:
|
case PN_TERNARY:
|
||||||
ok = CheckSideEffects(cx, tc, pn->pn_kid1, answer) &&
|
ok = CheckSideEffects(cx, cg, pn->pn_kid1, answer) &&
|
||||||
CheckSideEffects(cx, tc, pn->pn_kid2, answer) &&
|
CheckSideEffects(cx, cg, pn->pn_kid2, answer) &&
|
||||||
CheckSideEffects(cx, tc, pn->pn_kid3, answer);
|
CheckSideEffects(cx, cg, pn->pn_kid3, answer);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PN_BINARY:
|
case PN_BINARY:
|
||||||
|
@ -2145,9 +2145,9 @@ CheckSideEffects(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
|
||||||
if (pn2->pn_type != TOK_NAME) {
|
if (pn2->pn_type != TOK_NAME) {
|
||||||
*answer = JS_TRUE;
|
*answer = JS_TRUE;
|
||||||
} else {
|
} else {
|
||||||
if (!BindNameToSlot(cx, tc, pn2, 0))
|
if (!BindNameToSlot(cx, cg, pn2, 0))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
if (!CheckSideEffects(cx, tc, pn->pn_right, answer))
|
if (!CheckSideEffects(cx, cg, pn->pn_right, answer))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
if (!*answer &&
|
if (!*answer &&
|
||||||
(pn->pn_op != JSOP_NOP ||
|
(pn->pn_op != JSOP_NOP ||
|
||||||
|
@ -2168,7 +2168,7 @@ CheckSideEffects(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
|
||||||
case PN_UNARY:
|
case PN_UNARY:
|
||||||
switch (pn->pn_type) {
|
switch (pn->pn_type) {
|
||||||
case TOK_RP:
|
case TOK_RP:
|
||||||
ok = CheckSideEffects(cx, tc, pn->pn_kid, answer);
|
ok = CheckSideEffects(cx, cg, pn->pn_kid, answer);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOK_DELETE:
|
case TOK_DELETE:
|
||||||
|
@ -2187,7 +2187,7 @@ CheckSideEffects(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
|
||||||
*answer = JS_TRUE;
|
*answer = JS_TRUE;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ok = CheckSideEffects(cx, tc, pn2, answer);
|
ok = CheckSideEffects(cx, cg, pn2, answer);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -2211,7 +2211,7 @@ CheckSideEffects(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
|
||||||
* defaulted to JSOP_NOP).
|
* defaulted to JSOP_NOP).
|
||||||
*/
|
*/
|
||||||
if (pn->pn_type == TOK_NAME && pn->pn_op != JSOP_NOP) {
|
if (pn->pn_type == TOK_NAME && pn->pn_op != JSOP_NOP) {
|
||||||
if (!BindNameToSlot(cx, tc, pn, 0))
|
if (!BindNameToSlot(cx, cg, pn, 0))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
if (pn->pn_slot < 0 && pn->pn_op != JSOP_ARGUMENTS) {
|
if (pn->pn_slot < 0 && pn->pn_op != JSOP_ARGUMENTS) {
|
||||||
/*
|
/*
|
||||||
|
@ -2223,10 +2223,8 @@ CheckSideEffects(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
|
||||||
}
|
}
|
||||||
pn2 = pn->pn_expr;
|
pn2 = pn->pn_expr;
|
||||||
if (pn->pn_type == TOK_DOT) {
|
if (pn->pn_type == TOK_DOT) {
|
||||||
if (pn2->pn_type == TOK_NAME &&
|
if (pn2->pn_type == TOK_NAME && !BindNameToSlot(cx, cg, pn2, 0))
|
||||||
!BindNameToSlot(cx, tc, pn2, 0)) {
|
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
|
||||||
if (!(pn2->pn_op == JSOP_ARGUMENTS &&
|
if (!(pn2->pn_op == JSOP_ARGUMENTS &&
|
||||||
pn->pn_atom == cx->runtime->atomState.lengthAtom)) {
|
pn->pn_atom == cx->runtime->atomState.lengthAtom)) {
|
||||||
/*
|
/*
|
||||||
|
@ -2236,7 +2234,7 @@ CheckSideEffects(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
|
||||||
*answer = JS_TRUE;
|
*answer = JS_TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ok = CheckSideEffects(cx, tc, pn2, answer);
|
ok = CheckSideEffects(cx, cg, pn2, answer);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PN_NULLARY:
|
case PN_NULLARY:
|
||||||
|
@ -2253,7 +2251,7 @@ EmitNameOp(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
|
||||||
{
|
{
|
||||||
JSOp op;
|
JSOp op;
|
||||||
|
|
||||||
if (!BindNameToSlot(cx, &cg->treeContext, pn, 0))
|
if (!BindNameToSlot(cx, cg, pn, 0))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
op = PN_OP(pn);
|
op = PN_OP(pn);
|
||||||
|
|
||||||
|
@ -2349,7 +2347,7 @@ EmitPropOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg,
|
||||||
* - varname.prop into JSOP_GETVARPROP
|
* - varname.prop into JSOP_GETVARPROP
|
||||||
* - localname.prop into JSOP_GETLOCALPROP
|
* - localname.prop into JSOP_GETLOCALPROP
|
||||||
*/
|
*/
|
||||||
if (!BindNameToSlot(cx, &cg->treeContext, pn2, 0))
|
if (!BindNameToSlot(cx, cg, pn2, 0))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
switch (pn2->pn_op) {
|
switch (pn2->pn_op) {
|
||||||
case JSOP_ARGUMENTS:
|
case JSOP_ARGUMENTS:
|
||||||
|
@ -2461,7 +2459,7 @@ EmitElemOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg)
|
||||||
* one or more index expression and JSOP_GETELEM op pairs.
|
* one or more index expression and JSOP_GETELEM op pairs.
|
||||||
*/
|
*/
|
||||||
if (left->pn_type == TOK_NAME && next->pn_type == TOK_NUMBER) {
|
if (left->pn_type == TOK_NAME && next->pn_type == TOK_NUMBER) {
|
||||||
if (!BindNameToSlot(cx, &cg->treeContext, left, 0))
|
if (!BindNameToSlot(cx, cg, left, 0))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
if (left->pn_op == JSOP_ARGUMENTS &&
|
if (left->pn_op == JSOP_ARGUMENTS &&
|
||||||
JSDOUBLE_IS_INT(next->pn_dval, slot) &&
|
JSDOUBLE_IS_INT(next->pn_dval, slot) &&
|
||||||
|
@ -2536,7 +2534,7 @@ EmitElemOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg)
|
||||||
if (op == JSOP_GETELEM &&
|
if (op == JSOP_GETELEM &&
|
||||||
left->pn_type == TOK_NAME &&
|
left->pn_type == TOK_NAME &&
|
||||||
right->pn_type == TOK_NUMBER) {
|
right->pn_type == TOK_NUMBER) {
|
||||||
if (!BindNameToSlot(cx, &cg->treeContext, left, 0))
|
if (!BindNameToSlot(cx, cg, left, 0))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
if (left->pn_op == JSOP_ARGUMENTS &&
|
if (left->pn_op == JSOP_ARGUMENTS &&
|
||||||
JSDOUBLE_IS_INT(right->pn_dval, slot) &&
|
JSDOUBLE_IS_INT(right->pn_dval, slot) &&
|
||||||
|
@ -3273,13 +3271,12 @@ static JSBool
|
||||||
EmitDestructuringDecl(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp,
|
EmitDestructuringDecl(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp,
|
||||||
JSParseNode *pn)
|
JSParseNode *pn)
|
||||||
{
|
{
|
||||||
|
JSOp decltype;
|
||||||
|
|
||||||
JS_ASSERT(pn->pn_type == TOK_NAME);
|
JS_ASSERT(pn->pn_type == TOK_NAME);
|
||||||
if (!BindNameToSlot(cx, &cg->treeContext, pn,
|
decltype = (prologOp == JSOP_NOP) ? LET_DECL : VAR_DECL;
|
||||||
(prologOp == JSOP_NOP)
|
if (!BindNameToSlot(cx, cg, pn, decltype))
|
||||||
? LET_DECL
|
|
||||||
: VAR_DECL)) {
|
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
|
||||||
|
|
||||||
JS_ASSERT(pn->pn_op != JSOP_ARGUMENTS);
|
JS_ASSERT(pn->pn_op != JSOP_ARGUMENTS);
|
||||||
return MaybeEmitVarDecl(cx, cg, prologOp, pn, NULL);
|
return MaybeEmitVarDecl(cx, cg, prologOp, pn, NULL);
|
||||||
|
@ -3340,10 +3337,8 @@ EmitDestructuringLHS(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||||
if (js_Emit1(cx, cg, JSOP_POP) < 0)
|
if (js_Emit1(cx, cg, JSOP_POP) < 0)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
} else {
|
} else {
|
||||||
if (pn->pn_type == TOK_NAME &&
|
if (pn->pn_type == TOK_NAME && !BindNameToSlot(cx, cg, pn, 0))
|
||||||
!BindNameToSlot(cx, &cg->treeContext, pn, 0)) {
|
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
|
||||||
|
|
||||||
switch (pn->pn_op) {
|
switch (pn->pn_op) {
|
||||||
case JSOP_SETNAME:
|
case JSOP_SETNAME:
|
||||||
|
@ -3715,7 +3710,7 @@ EmitVariables(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
|
||||||
JSBool useful = JS_FALSE;
|
JSBool useful = JS_FALSE;
|
||||||
|
|
||||||
JS_ASSERT(pn->pn_count == 1);
|
JS_ASSERT(pn->pn_count == 1);
|
||||||
if (!CheckSideEffects(cx, tc, pn2->pn_right, &useful))
|
if (!CheckSideEffects(cx, cg, pn2->pn_right, &useful))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
if (!useful)
|
if (!useful)
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
|
@ -3762,8 +3757,7 @@ EmitVariables(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
|
||||||
JS_ASSERT(pn2->pn_type == TOK_NAME);
|
JS_ASSERT(pn2->pn_type == TOK_NAME);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!BindNameToSlot(cx, &cg->treeContext, pn2,
|
if (!BindNameToSlot(cx, cg, pn2, let ? LET_DECL : VAR_DECL))
|
||||||
let ? LET_DECL : VAR_DECL))
|
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
JS_ASSERT(pn2->pn_slot >= 0 || !let);
|
JS_ASSERT(pn2->pn_slot >= 0 || !let);
|
||||||
|
|
||||||
|
@ -3790,7 +3784,7 @@ EmitVariables(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
|
||||||
JSBool useful = JS_FALSE;
|
JSBool useful = JS_FALSE;
|
||||||
|
|
||||||
JS_ASSERT(pn->pn_count == 1);
|
JS_ASSERT(pn->pn_count == 1);
|
||||||
if (!CheckSideEffects(cx, tc, pn3, &useful))
|
if (!CheckSideEffects(cx, cg, pn3, &useful))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
if (!useful)
|
if (!useful)
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
|
@ -4409,7 +4403,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
pn3->pn_op = JSOP_FORNAME;
|
pn3->pn_op = JSOP_FORNAME;
|
||||||
if (!BindNameToSlot(cx, &cg->treeContext, pn3, 0))
|
if (!BindNameToSlot(cx, cg, pn3, 0))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
op = PN_OP(pn3);
|
op = PN_OP(pn3);
|
||||||
}
|
}
|
||||||
|
@ -4428,10 +4422,8 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||||
|
|
||||||
case TOK_DOT:
|
case TOK_DOT:
|
||||||
useful = JS_FALSE;
|
useful = JS_FALSE;
|
||||||
if (!CheckSideEffects(cx, &cg->treeContext, pn3->pn_expr,
|
if (!CheckSideEffects(cx, cg, pn3->pn_expr, &useful))
|
||||||
&useful)) {
|
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
|
||||||
if (!useful) {
|
if (!useful) {
|
||||||
if (!EmitPropOp(cx, pn3, JSOP_FORPROP, cg, JS_FALSE))
|
if (!EmitPropOp(cx, pn3, JSOP_FORPROP, cg, JS_FALSE))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
@ -5194,7 +5186,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||||
*/
|
*/
|
||||||
useful = wantval = !(cg->treeContext.flags & TCF_IN_FUNCTION);
|
useful = wantval = !(cg->treeContext.flags & TCF_IN_FUNCTION);
|
||||||
if (!useful) {
|
if (!useful) {
|
||||||
if (!CheckSideEffects(cx, &cg->treeContext, pn2, &useful))
|
if (!CheckSideEffects(cx, cg, pn2, &useful))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5308,7 +5300,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||||
atomIndex = (jsatomid) -1; /* quell GCC overwarning */
|
atomIndex = (jsatomid) -1; /* quell GCC overwarning */
|
||||||
switch (pn2->pn_type) {
|
switch (pn2->pn_type) {
|
||||||
case TOK_NAME:
|
case TOK_NAME:
|
||||||
if (!BindNameToSlot(cx, &cg->treeContext, pn2, 0))
|
if (!BindNameToSlot(cx, cg, pn2, 0))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
if (pn2->pn_slot >= 0) {
|
if (pn2->pn_slot >= 0) {
|
||||||
atomIndex = (jsatomid) pn2->pn_slot;
|
atomIndex = (jsatomid) pn2->pn_slot;
|
||||||
|
@ -5681,7 +5673,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||||
switch (pn2->pn_type) {
|
switch (pn2->pn_type) {
|
||||||
case TOK_NAME:
|
case TOK_NAME:
|
||||||
pn2->pn_op = op;
|
pn2->pn_op = op;
|
||||||
if (!BindNameToSlot(cx, &cg->treeContext, pn2, 0))
|
if (!BindNameToSlot(cx, cg, pn2, 0))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
op = PN_OP(pn2);
|
op = PN_OP(pn2);
|
||||||
if (pn2->pn_slot >= 0) {
|
if (pn2->pn_slot >= 0) {
|
||||||
|
@ -5754,7 +5746,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||||
switch (pn2->pn_type) {
|
switch (pn2->pn_type) {
|
||||||
case TOK_NAME:
|
case TOK_NAME:
|
||||||
pn2->pn_op = JSOP_DELNAME;
|
pn2->pn_op = JSOP_DELNAME;
|
||||||
if (!BindNameToSlot(cx, &cg->treeContext, pn2, 0))
|
if (!BindNameToSlot(cx, cg, pn2, 0))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
op = PN_OP(pn2);
|
op = PN_OP(pn2);
|
||||||
if (op == JSOP_FALSE) {
|
if (op == JSOP_FALSE) {
|
||||||
|
@ -5797,7 +5789,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||||
* also JSOP_GROUP for correctly parenthesized decompilation).
|
* also JSOP_GROUP for correctly parenthesized decompilation).
|
||||||
*/
|
*/
|
||||||
useful = JS_FALSE;
|
useful = JS_FALSE;
|
||||||
if (!CheckSideEffects(cx, &cg->treeContext, pn2, &useful))
|
if (!CheckSideEffects(cx, cg, pn2, &useful))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
if (!useful) {
|
if (!useful) {
|
||||||
off = noteIndex = -1;
|
off = noteIndex = -1;
|
||||||
|
|
|
@ -175,24 +175,34 @@ struct JSTreeContext { /* tree context for semantic checks */
|
||||||
names when flags & TCF_IN_FUNCTION */
|
names when flags & TCF_IN_FUNCTION */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define TCF_COMPILING 0x01 /* generating bytecode; this tc is a cg */
|
#define TCF_IN_FUNCTION 0x01 /* parsing inside function body */
|
||||||
#define TCF_IN_FUNCTION 0x02 /* parsing inside function body */
|
#define TCF_RETURN_EXPR 0x02 /* function has 'return expr;' */
|
||||||
#define TCF_RETURN_EXPR 0x04 /* function has 'return expr;' */
|
#define TCF_RETURN_VOID 0x04 /* function has 'return;' */
|
||||||
#define TCF_RETURN_VOID 0x08 /* function has 'return;' */
|
#define TCF_IN_FOR_INIT 0x08 /* parsing init expr of for; exclude 'in' */
|
||||||
#define TCF_RETURN_FLAGS 0x0C /* propagate these out of blocks */
|
#define TCF_FUN_CLOSURE_VS_VAR 0x10 /* function and var with same name */
|
||||||
#define TCF_IN_FOR_INIT 0x10 /* parsing init expr of for; exclude 'in' */
|
#define TCF_FUN_USES_NONLOCALS 0x20 /* function refers to non-local names */
|
||||||
#define TCF_FUN_CLOSURE_VS_VAR 0x20 /* function and var with same name */
|
#define TCF_FUN_HEAVYWEIGHT 0x40 /* function needs Call object per call */
|
||||||
#define TCF_FUN_USES_NONLOCALS 0x40 /* function refers to non-local names */
|
#define TCF_FUN_IS_GENERATOR 0x80 /* parsed yield statement in function */
|
||||||
#define TCF_FUN_HEAVYWEIGHT 0x80 /* function needs Call object per call */
|
#define TCF_HAS_DEFXMLNS 0x100 /* default xml namespace = ...; parsed */
|
||||||
#define TCF_FUN_IS_GENERATOR 0x100 /* parsed yield statement in function */
|
#define TCF_HAS_FUNCTION_STMT 0x200 /* block contains a function statement */
|
||||||
#define TCF_FUN_FLAGS 0x1E0 /* flags to propagate from FunctionBody */
|
#define TCF_GENEXP_LAMBDA 0x400 /* flag lambda from generator expression */
|
||||||
#define TCF_HAS_DEFXMLNS 0x200 /* default xml namespace = ...; parsed */
|
#define TCF_COMPILE_N_GO 0x800 /* compiler-and-go mode of script, can
|
||||||
#define TCF_HAS_FUNCTION_STMT 0x400 /* block contains a function statement */
|
|
||||||
#define TCF_GENEXP_LAMBDA 0x800 /* flag lambda from generator expression */
|
|
||||||
#define TCF_COMPILE_N_GO 0x1000 /* compiler-and-go mode of script, can
|
|
||||||
optimize name references based on scope
|
optimize name references based on scope
|
||||||
chain */
|
chain */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Flags to propagate out of the blocks.
|
||||||
|
*/
|
||||||
|
#define TCF_RETURN_FLAGS (TCF_RETURN_EXPR | TCF_RETURN_VOID)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Flags to propagate from FunctionBody.
|
||||||
|
*/
|
||||||
|
#define TCF_FUN_FLAGS (TCF_FUN_IS_GENERATOR | \
|
||||||
|
TCF_FUN_HEAVYWEIGHT | \
|
||||||
|
TCF_FUN_USES_NONLOCALS | \
|
||||||
|
TCF_FUN_CLOSURE_VS_VAR)
|
||||||
|
|
||||||
#define TREE_CONTEXT_INIT(tc, pc) \
|
#define TREE_CONTEXT_INIT(tc, pc) \
|
||||||
((tc)->flags = (tc)->ngvars = 0, \
|
((tc)->flags = (tc)->ngvars = 0, \
|
||||||
(tc)->globalUses = (tc)->loopyGlobalUses = 0, \
|
(tc)->globalUses = (tc)->loopyGlobalUses = 0, \
|
||||||
|
|
|
@ -567,6 +567,7 @@ js_CompileScript(JSContext *cx, JSObject *obj, JSPrincipals *principals,
|
||||||
JSStackFrame *fp, frame;
|
JSStackFrame *fp, frame;
|
||||||
JSArenaPool codePool, notePool;
|
JSArenaPool codePool, notePool;
|
||||||
JSCodeGenerator cg;
|
JSCodeGenerator cg;
|
||||||
|
JSTokenType tt;
|
||||||
JSParseNode *pn;
|
JSParseNode *pn;
|
||||||
JSScript *script;
|
JSScript *script;
|
||||||
#ifdef METER_PARSENODES
|
#ifdef METER_PARSENODES
|
||||||
|
@ -599,17 +600,42 @@ js_CompileScript(JSContext *cx, JSObject *obj, JSPrincipals *principals,
|
||||||
|
|
||||||
/* From this point the control must flow via the label out. */
|
/* From this point the control must flow via the label out. */
|
||||||
cg.treeContext.flags |= tcflags;
|
cg.treeContext.flags |= tcflags;
|
||||||
pn = Statements(cx, &pc.tokenStream, &cg.treeContext);
|
|
||||||
|
/*
|
||||||
|
* Inline Statements() to emit as we go to save space.
|
||||||
|
*/
|
||||||
|
for (;;) {
|
||||||
|
pc.tokenStream.flags |= TSF_OPERAND;
|
||||||
|
tt = js_PeekToken(cx, &pc.tokenStream);
|
||||||
|
pc.tokenStream.flags &= ~TSF_OPERAND;
|
||||||
|
if (tt <= TOK_EOF) {
|
||||||
|
if (tt == TOK_EOF)
|
||||||
|
break;
|
||||||
|
JS_ASSERT(tt == TOK_ERROR);
|
||||||
|
script = NULL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
pn = Statement(cx, &pc.tokenStream, &cg.treeContext);
|
||||||
if (!pn) {
|
if (!pn) {
|
||||||
script = NULL;
|
script = NULL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (!js_MatchToken(cx, &pc.tokenStream, TOK_EOF)) {
|
|
||||||
js_ReportCompileErrorNumber(cx, &pc.tokenStream, NULL, JSREPORT_ERROR,
|
/*
|
||||||
JSMSG_SYNTAX_ERROR);
|
* FIXME bug 346749: let declarations at the top level in a script are
|
||||||
|
* turned into var declarations and do not introduce block nodes.
|
||||||
|
*/
|
||||||
|
JS_ASSERT(!cg.treeContext.blockNode);
|
||||||
|
|
||||||
|
if (!js_FoldConstants(cx, pn, &cg.treeContext) ||
|
||||||
|
!js_EmitTree(cx, &cg, pn)) {
|
||||||
script = NULL;
|
script = NULL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
RecycleTree(pn, &cg.treeContext);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef METER_PARSENODES
|
#ifdef METER_PARSENODES
|
||||||
printf("Parser growth: %d (%u nodes, %u max, %u unrecycled)\n",
|
printf("Parser growth: %d (%u nodes, %u max, %u unrecycled)\n",
|
||||||
(char *)sbrk(0) - (char *)before,
|
(char *)sbrk(0) - (char *)before,
|
||||||
|
@ -620,16 +646,9 @@ js_CompileScript(JSContext *cx, JSObject *obj, JSPrincipals *principals,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* No need to emit bytecode here -- Statements already has, for each
|
|
||||||
* statement in turn. Search for TCF_COMPILING in Statements, below.
|
|
||||||
* That flag is set for every tc == &cg->treeContext, and it implies
|
|
||||||
* that the tc can be downcast to a cg and used to emit code during
|
|
||||||
* parsing, rather than at the end of the parse phase.
|
|
||||||
*
|
|
||||||
* Nowadays the threaded interpreter needs a stop instruction, so we
|
* Nowadays the threaded interpreter needs a stop instruction, so we
|
||||||
* do have to emit that here.
|
* do have to emit that here.
|
||||||
*/
|
*/
|
||||||
JS_ASSERT(cg.treeContext.flags & TCF_COMPILING);
|
|
||||||
if (js_Emit1(cx, &cg, JSOP_STOP) < 0) {
|
if (js_Emit1(cx, &cg, JSOP_STOP) < 0) {
|
||||||
script = NULL;
|
script = NULL;
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -1420,51 +1439,25 @@ Statements(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
||||||
tc->blockNode = pn;
|
tc->blockNode = pn;
|
||||||
PN_INIT_LIST(pn);
|
PN_INIT_LIST(pn);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
ts->flags |= TSF_OPERAND;
|
ts->flags |= TSF_OPERAND;
|
||||||
while ((tt = js_PeekToken(cx, ts)) > TOK_EOF && tt != TOK_RC) {
|
tt = js_PeekToken(cx, ts);
|
||||||
ts->flags &= ~TSF_OPERAND;
|
ts->flags &= ~TSF_OPERAND;
|
||||||
|
if (tt <= TOK_EOF || tt == TOK_RC)
|
||||||
|
break;
|
||||||
pn2 = Statement(cx, ts, tc);
|
pn2 = Statement(cx, ts, tc);
|
||||||
if (!pn2) {
|
if (!pn2) {
|
||||||
if (ts->flags & TSF_EOF)
|
if (ts->flags & TSF_EOF)
|
||||||
ts->flags |= TSF_UNEXPECTED_EOF;
|
ts->flags |= TSF_UNEXPECTED_EOF;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
ts->flags |= TSF_OPERAND;
|
|
||||||
|
|
||||||
/* Detect a function statement for the TOK_LC case in Statement. */
|
/* Detect a function statement for the TOK_LC case in Statement. */
|
||||||
if (pn2->pn_type == TOK_FUNCTION && !AT_TOP_LEVEL(tc))
|
if (pn2->pn_type == TOK_FUNCTION && !AT_TOP_LEVEL(tc))
|
||||||
tc->flags |= TCF_HAS_FUNCTION_STMT;
|
tc->flags |= TCF_HAS_FUNCTION_STMT;
|
||||||
|
|
||||||
/* If compiling top-level statements, emit as we go to save space. */
|
|
||||||
if (!tc->topStmt && (tc->flags & TCF_COMPILING)) {
|
|
||||||
if (JS_HAS_STRICT_OPTION(cx) && (tc->flags & TCF_RETURN_EXPR)) {
|
|
||||||
/*
|
|
||||||
* Check pn2 for lack of a final return statement if it is the
|
|
||||||
* last statement in the block.
|
|
||||||
*/
|
|
||||||
tt = js_PeekToken(cx, ts);
|
|
||||||
if ((tt == TOK_EOF || tt == TOK_RC) &&
|
|
||||||
!CheckFinalReturn(cx, tc, pn2)) {
|
|
||||||
tt = TOK_ERROR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Clear TCF_RETURN_EXPR so FunctionBody doesn't try to
|
|
||||||
* CheckFinalReturn again.
|
|
||||||
*/
|
|
||||||
tc->flags &= ~TCF_RETURN_EXPR;
|
|
||||||
}
|
|
||||||
if (!js_FoldConstants(cx, pn2, tc) ||
|
|
||||||
!js_EmitTree(cx, (JSCodeGenerator *)tc, pn2)) {
|
|
||||||
tt = TOK_ERROR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
RecycleTree(pn2, tc);
|
|
||||||
} else {
|
|
||||||
PN_APPEND(pn, pn2);
|
PN_APPEND(pn, pn2);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handle the case where there was a let declaration under this block. If
|
* Handle the case where there was a let declaration under this block. If
|
||||||
|
|
Загрузка…
Ссылка в новой задаче