ref: f1e1171eef004a7073a543989bf5151472826929
parent: 424f7161be70d3e19938430d6281dedbec4d27ac
author: Tor Andersson <[email protected]>
date: Wed Jan 22 11:24:45 EST 2014
Clean up stack and with/endwith balancing on abrupt exits.
--- a/jscompile.c
+++ b/jscompile.c
@@ -242,8 +242,17 @@
}
}
-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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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;
--- a/jscompile.h
+++ b/jscompile.h
@@ -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 */
--- a/jsdump.c
+++ b/jsdump.c
@@ -684,6 +684,10 @@
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;
--- a/jsrun.c
+++ b/jsrun.c
@@ -518,10 +518,12 @@
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;