Clean up stack and with/endwith balancing on abrupt exits.

This commit is contained in:
Tor Andersson
2014-01-22 16:24:45 +01:00
parent 424f7161be
commit f1e1171eef
4 changed files with 58 additions and 9 deletions
+50 -9
View File
@@ -242,8 +242,17 @@ static void cassign(JF, js_Ast *lhs, js_Ast *rhs)
}
}
static void cassignloop(JF, js_Ast *lhs)
static void cassignforin(JF, js_Ast *stm)
{
js_Ast *lhs = stm->a;
if (stm->type == STM_FOR_IN_VAR) {
if (lhs->b)
jsC_error(J, lhs->b, "more than one loop variable in for-in statement");
emitstring(J, F, OP_SETVAR, lhs->a->a->string); /* list(var-init(ident)) */
return;
}
switch (lhs->type) {
case AST_IDENTIFIER:
emitstring(J, F, OP_SETVAR, lhs->string);
@@ -261,7 +270,7 @@ static void cassignloop(JF, js_Ast *lhs)
emit(J, F, OP_SETPROP);
break;
default:
jsC_error(J, lhs, "invalid l-value in assignment");
jsC_error(J, lhs, "invalid l-value in for-in loop assignment");
break;
}
}
@@ -616,6 +625,38 @@ static js_Ast *continuetarget(JF, js_Ast *node, const char *label)
return NULL;
}
static js_Ast *returntarget(JF, js_Ast *node)
{
while (node) {
if (node->type == AST_FUNDEC || node->type == EXP_FUN)
return node;
node = node->parent;
}
return NULL;
}
/* Emit code to rebalance stack and scopes during an abrupt exit */
static void cexit(JF, js_AstType T, js_Ast *node, js_Ast *target)
{
do {
node = node->parent;
switch (node->type) {
case STM_WITH:
emit(J, F, OP_ENDWITH);
break;
case STM_FOR_IN:
case STM_FOR_IN_VAR:
/* pop the object and name pair we are iterating over if leaving the loop */
if (T == STM_RETURN || T == STM_THROW)
emit(J, F, OP_ROT3POP2); /* save the return / exception value */
if (T == STM_BREAK)
emit(J, F, OP_POP2);
break;
}
} while (node != target);
}
/* Statements */
static void cstm(JF, js_Ast *stm)
@@ -702,13 +743,7 @@ static void cstm(JF, js_Ast *stm)
loop = here(J, F);
emit(J, F, OP_NEXTPROP);
end = jump(J, F, OP_JFALSE);
if (stm->type == STM_FOR_IN_VAR) {
if (stm->a->b)
jsC_error(J, stm->a->b, "more than one loop variable in for-in statement");
emitstring(J, F, OP_SETVAR, stm->a->a->a->string); /* stm(list(var-init(ident))) */
} else {
cassignloop(J, F, stm->a);
}
cassignforin(J, F, stm);
cstm(J, F, stm->c);
jumpto(J, F, OP_JUMP, loop);
label(J, F, end);
@@ -740,6 +775,7 @@ static void cstm(JF, js_Ast *stm)
if (!stm->target)
jsC_error(J, stm, "unlabelled break must be inside loop or switch");
}
cexit(J, F, STM_BREAK, stm, stm->target);
stm->inst = jump(J, F, OP_JUMP);
break;
@@ -753,6 +789,7 @@ static void cstm(JF, js_Ast *stm)
if (!stm->target)
jsC_error(J, stm, "continue must be inside loop");
}
cexit(J, F, STM_CONTINUE, stm, stm->target);
stm->inst = jump(J, F, OP_JUMP);
break;
@@ -761,6 +798,10 @@ static void cstm(JF, js_Ast *stm)
cexp(J, F, stm->a);
else
emit(J, F, OP_UNDEF);
stm->target = returntarget(J, F, stm);
if (!stm->target)
jsC_error(J, stm, "return not in function");
cexit(J, F, STM_RETURN, stm, stm->target);
emit(J, F, OP_RETURN);
break;
+2
View File
@@ -4,10 +4,12 @@
enum
{
OP_POP, /* A -- */
OP_POP2, /* A B -- */
OP_DUP, /* A -- A A */
OP_DUP2, /* A B -- A B A B */
OP_ROT2, /* A B -- B A */
OP_ROT3, /* A B C -- C A B */
OP_ROT3POP2, /* A B C -- C */
OP_DUP1ROT4, /* A B C -- C A B C */
OP_NUMBER_0, /* -- 0 */
+4
View File
@@ -684,6 +684,10 @@ void js_dumpvalue(js_State *J, js_Value v)
case JS_TNUMBER: printf("%.9g", v.u.number); break;
case JS_TSTRING: printf("'%s'", v.u.string); break;
case JS_TOBJECT:
if (v.u.object == J->G) {
printf("[Global]");
break;
}
switch (v.u.object->type) {
case JS_COBJECT: printf("[Object %p]", v.u.object); break;
case JS_CARRAY: printf("[Array %p]", v.u.object); break;
+2
View File
@@ -518,10 +518,12 @@ static void jsR_run(js_State *J, js_Function *F)
opcode = *pc++;
switch (opcode) {
case OP_POP: js_pop(J, 1); break;
case OP_POP2: js_pop(J, 2); break;
case OP_DUP: js_dup(J); break;
case OP_DUP2: js_dup2(J); break;
case OP_ROT2: js_rot2(J); break;
case OP_ROT3: js_rot3(J); break;
case OP_ROT3POP2: js_rot3pop2(J); break;
case OP_DUP1ROT4: js_dup1rot4(J); break;
case OP_NUMBER_0: js_pushnumber(J, 0); break;