shithub: libmujs

Download patch

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;