shithub: libmujs

Download patch

ref: cb1d50bca4a45057be56bc51856088effd6c316e
parent: 914ae72a242d91add6fbf97576723aeb31b089d7
author: Tor Andersson <tor.andersson@artifex.com>
date: Thu Mar 7 09:38:32 EST 2019

Improve line number tracking in compiler.

--- a/jscompile.c
+++ b/jscompile.c
@@ -232,6 +232,7 @@
 
 static int here(JF)
 {
+	F->lastline = -1; /* force the next emitline */
 	return F->codelen;
 }
 
@@ -268,10 +269,13 @@
 
 static void ctypeof(JF, js_Ast *exp)
 {
-	if (exp->type == EXP_IDENTIFIER)
-		emitlocal(J, F, OP_GETLOCAL, OP_HASVAR, exp);
-	else
-		cexp(J, F, exp);
+	if (exp->type == EXP_IDENTIFIER) {
+		emitline(J, F, exp->a);
+		emitlocal(J, F, OP_GETLOCAL, OP_HASVAR, exp->a);
+	} else {
+		cexp(J, F, exp->a);
+	}
+	emitline(J, F, exp);
 	emit(J, F, OP_TYPEOF);
 }
 
@@ -278,6 +282,7 @@
 static void cunary(JF, js_Ast *exp, int opcode)
 {
 	cexp(J, F, exp->a);
+	emitline(J, F, exp);
 	emit(J, F, opcode);
 }
 
@@ -285,6 +290,7 @@
 {
 	cexp(J, F, exp->a);
 	cexp(J, F, exp->b);
+	emitline(J, F, exp);
 	emit(J, F, opcode);
 }
 
@@ -293,9 +299,10 @@
 	int i = 0;
 	while (list) {
 		if (list->a->type != EXP_UNDEF) {
-			emitnumber(J, F, i++);
 			emitline(J, F, list->a);
+			emitnumber(J, F, i++);
 			cexp(J, F, list->a);
+			emitline(J, F, list->a);
 			emit(J, F, OP_INITPROP);
 		} else {
 			++i;
@@ -336,12 +343,15 @@
 		js_Ast *kv = list->a;
 		js_Ast *prop = kv->a;
 
-		if (prop->type == AST_IDENTIFIER || prop->type == EXP_STRING)
+		if (prop->type == AST_IDENTIFIER || prop->type == EXP_STRING) {
+			emitline(J, F, prop);
 			emitstring(J, F, OP_STRING, prop->string);
-		else if (prop->type == EXP_NUMBER)
+		} else if (prop->type == EXP_NUMBER) {
+			emitline(J, F, prop);
 			emitnumber(J, F, prop->number);
-		else
+		} else {
 			jsC_error(J, prop, "invalid property name in object initializer");
+		}
 
 		if (F->strict)
 			checkdup(J, F, head, kv);
@@ -349,16 +359,18 @@
 		switch (kv->type) {
 		default: /* impossible */ break;
 		case EXP_PROP_VAL:
-			emitline(J, F, kv->b);
 			cexp(J, F, kv->b);
+			emitline(J, F, kv);
 			emit(J, F, OP_INITPROP);
 			break;
 		case EXP_PROP_GET:
 			emitfunction(J, F, newfun(J, prop->line, NULL, NULL, kv->c, 0, F->strict));
+			emitline(J, F, kv);
 			emit(J, F, OP_INITGETTER);
 			break;
 		case EXP_PROP_SET:
 			emitfunction(J, F, newfun(J, prop->line, NULL, kv->b, kv->c, 0, F->strict));
+			emitline(J, F, kv);
 			emit(J, F, OP_INITSETTER);
 			break;
 		}
@@ -385,6 +397,7 @@
 	switch (lhs->type) {
 	case EXP_IDENTIFIER:
 		cexp(J, F, rhs);
+		emitline(J, F, exp);
 		emitlocal(J, F, OP_SETLOCAL, OP_SETVAR, lhs);
 		break;
 	case EXP_INDEX:
@@ -391,11 +404,13 @@
 		cexp(J, F, lhs->a);
 		cexp(J, F, lhs->b);
 		cexp(J, F, rhs);
+		emitline(J, F, exp);
 		emit(J, F, OP_SETPROP);
 		break;
 	case EXP_MEMBER:
 		cexp(J, F, lhs->a);
 		cexp(J, F, rhs);
+		emitline(J, F, exp);
 		emitstring(J, F, OP_SETPROP_S, lhs->b->string);
 		break;
 	default:
@@ -410,6 +425,7 @@
 	if (stm->type == STM_FOR_IN_VAR) {
 		if (lhs->b)
 			jsC_error(J, lhs->b, "more than one loop variable in for-in statement");
+		emitline(J, F, lhs->a);
 		emitlocal(J, F, OP_SETLOCAL, OP_SETVAR, lhs->a->a); /* list(var-init(ident)) */
 		emit(J, F, OP_POP);
 		return;
@@ -417,6 +433,7 @@
 
 	switch (lhs->type) {
 	case EXP_IDENTIFIER:
+		emitline(J, F, lhs);
 		emitlocal(J, F, OP_SETLOCAL, OP_SETVAR, lhs);
 		emit(J, F, OP_POP);
 		break;
@@ -423,6 +440,7 @@
 	case EXP_INDEX:
 		cexp(J, F, lhs->a);
 		cexp(J, F, lhs->b);
+		emitline(J, F, lhs);
 		emit(J, F, OP_ROT3);
 		emit(J, F, OP_SETPROP);
 		emit(J, F, OP_POP);
@@ -429,6 +447,7 @@
 		break;
 	case EXP_MEMBER:
 		cexp(J, F, lhs->a);
+		emitline(J, F, lhs);
 		emit(J, F, OP_ROT2);
 		emitstring(J, F, OP_SETPROP_S, lhs->b->string);
 		emit(J, F, OP_POP);
@@ -442,16 +461,19 @@
 {
 	switch (lhs->type) {
 	case EXP_IDENTIFIER:
+		emitline(J, F, lhs);
 		emitlocal(J, F, OP_GETLOCAL, OP_GETVAR, lhs);
 		break;
 	case EXP_INDEX:
 		cexp(J, F, lhs->a);
 		cexp(J, F, lhs->b);
+		emitline(J, F, lhs);
 		emit(J, F, OP_DUP2);
 		emit(J, F, OP_GETPROP);
 		break;
 	case EXP_MEMBER:
 		cexp(J, F, lhs->a);
+		emitline(J, F, lhs);
 		emit(J, F, OP_DUP);
 		emitstring(J, F, OP_GETPROP_S, lhs->b->string);
 		break;
@@ -464,14 +486,17 @@
 {
 	switch (lhs->type) {
 	case EXP_IDENTIFIER:
+		emitline(J, F, lhs);
 		if (postfix) emit(J, F, OP_ROT2);
 		emitlocal(J, F, OP_SETLOCAL, OP_SETVAR, lhs);
 		break;
 	case EXP_INDEX:
+		emitline(J, F, lhs);
 		if (postfix) emit(J, F, OP_ROT4);
 		emit(J, F, OP_SETPROP);
 		break;
 	case EXP_MEMBER:
+		emitline(J, F, lhs);
 		if (postfix) emit(J, F, OP_ROT3);
 		emitstring(J, F, OP_SETPROP_S, lhs->b->string);
 		break;
@@ -486,6 +511,7 @@
 	js_Ast *rhs = exp->b;
 	cassignop1(J, F, lhs);
 	cexp(J, F, rhs);
+	emitline(J, F, exp);
 	emit(J, F, opcode);
 	cassignop2(J, F, lhs, 0);
 }
@@ -492,20 +518,24 @@
 
 static void cdelete(JF, js_Ast *exp)
 {
-	switch (exp->type) {
+	js_Ast *arg = exp->a;
+	switch (arg->type) {
 	case EXP_IDENTIFIER:
 		if (F->strict)
 			jsC_error(J, exp, "delete on an unqualified name is not allowed in strict mode");
-		emitlocal(J, F, OP_DELLOCAL, OP_DELVAR, exp);
+		emitline(J, F, exp);
+		emitlocal(J, F, OP_DELLOCAL, OP_DELVAR, arg);
 		break;
 	case EXP_INDEX:
-		cexp(J, F, exp->a);
-		cexp(J, F, exp->b);
+		cexp(J, F, arg->a);
+		cexp(J, F, arg->b);
+		emitline(J, F, exp);
 		emit(J, F, OP_DELPROP);
 		break;
 	case EXP_MEMBER:
-		cexp(J, F, exp->a);
-		emitstring(J, F, OP_DELPROP_S, exp->b->string);
+		cexp(J, F, arg->a);
+		emitline(J, F, exp);
+		emitstring(J, F, OP_DELPROP_S, arg->b->string);
 		break;
 	default:
 		jsC_error(J, exp, "invalid l-value in delete expression");
@@ -561,15 +591,37 @@
 	int n;
 
 	switch (exp->type) {
-	case EXP_STRING: emitstring(J, F, OP_STRING, exp->string); break;
-	case EXP_NUMBER: emitnumber(J, F, exp->number); break;
-	case EXP_UNDEF: emit(J, F, OP_UNDEF); break;
-	case EXP_NULL: emit(J, F, OP_NULL); break;
-	case EXP_TRUE: emit(J, F, OP_TRUE); break;
-	case EXP_FALSE: emit(J, F, OP_FALSE); break;
-	case EXP_THIS: emit(J, F, OP_THIS); break;
+	case EXP_STRING:
+		emitline(J, F, exp);
+		emitstring(J, F, OP_STRING, exp->string);
+		break;
+	case EXP_NUMBER:
+		emitline(J, F, exp);
+		emitnumber(J, F, exp->number);
+		break;
+	case EXP_UNDEF:
+		emitline(J, F, exp);
+		emit(J, F, OP_UNDEF);
+		break;
+	case EXP_NULL:
+		emitline(J, F, exp);
+		emit(J, F, OP_NULL);
+		break;
+	case EXP_TRUE:
+		emitline(J, F, exp);
+		emit(J, F, OP_TRUE);
+		break;
+	case EXP_FALSE:
+		emitline(J, F, exp);
+		emit(J, F, OP_FALSE);
+		break;
+	case EXP_THIS:
+		emitline(J, F, exp);
+		emit(J, F, OP_THIS);
+		break;
 
 	case EXP_REGEXP:
+		emitline(J, F, exp);
 		emit(J, F, OP_NEWREGEXP);
 		emitarg(J, F, addstring(J, F, exp->string));
 		emitarg(J, F, exp->number);
@@ -576,20 +628,24 @@
 		break;
 
 	case EXP_OBJECT:
+		emitline(J, F, exp);
 		emit(J, F, OP_NEWOBJECT);
 		cobject(J, F, exp->a);
 		break;
 
 	case EXP_ARRAY:
+		emitline(J, F, exp);
 		emit(J, F, OP_NEWARRAY);
 		carray(J, F, exp->a);
 		break;
 
 	case EXP_FUN:
+		emitline(J, F, exp);
 		emitfunction(J, F, newfun(J, exp->line, exp->a, exp->b, exp->c, 0, F->strict));
 		break;
 
 	case EXP_IDENTIFIER:
+		emitline(J, F, exp);
 		emitlocal(J, F, OP_GETLOCAL, OP_GETVAR, exp);
 		break;
 
@@ -596,11 +652,13 @@
 	case EXP_INDEX:
 		cexp(J, F, exp->a);
 		cexp(J, F, exp->b);
+		emitline(J, F, exp);
 		emit(J, F, OP_GETPROP);
 		break;
 
 	case EXP_MEMBER:
 		cexp(J, F, exp->a);
+		emitline(J, F, exp);
 		emitstring(J, F, OP_GETPROP_S, exp->b->string);
 		break;
 
@@ -611,16 +669,18 @@
 	case EXP_NEW:
 		cexp(J, F, exp->a);
 		n = cargs(J, F, exp->b);
+		emitline(J, F, exp);
 		emit(J, F, OP_NEW);
 		emitarg(J, F, n);
 		break;
 
 	case EXP_DELETE:
-		cdelete(J, F, exp->a);
+		cdelete(J, F, exp);
 		break;
 
 	case EXP_PREINC:
 		cassignop1(J, F, exp->a);
+		emitline(J, F, exp);
 		emit(J, F, OP_INC);
 		cassignop2(J, F, exp->a, 0);
 		break;
@@ -627,6 +687,7 @@
 
 	case EXP_PREDEC:
 		cassignop1(J, F, exp->a);
+		emitline(J, F, exp);
 		emit(J, F, OP_DEC);
 		cassignop2(J, F, exp->a, 0);
 		break;
@@ -633,6 +694,7 @@
 
 	case EXP_POSTINC:
 		cassignop1(J, F, exp->a);
+		emitline(J, F, exp);
 		emit(J, F, OP_POSTINC);
 		cassignop2(J, F, exp->a, 1);
 		emit(J, F, OP_POP);
@@ -640,6 +702,7 @@
 
 	case EXP_POSTDEC:
 		cassignop1(J, F, exp->a);
+		emitline(J, F, exp);
 		emit(J, F, OP_POSTDEC);
 		cassignop2(J, F, exp->a, 1);
 		emit(J, F, OP_POP);
@@ -647,11 +710,12 @@
 
 	case EXP_VOID:
 		cexp(J, F, exp->a);
+		emitline(J, F, exp);
 		emit(J, F, OP_POP);
 		emit(J, F, OP_UNDEF);
 		break;
 
-	case EXP_TYPEOF: ctypeof(J, F, exp->a); break;
+	case EXP_TYPEOF: ctypeof(J, F, exp); break;
 	case EXP_POS: cunary(J, F, exp, OP_POS); break;
 	case EXP_NEG: cunary(J, F, exp, OP_NEG); break;
 	case EXP_BITNOT: cunary(J, F, exp, OP_BITNOT); break;
@@ -694,6 +758,7 @@
 
 	case EXP_COMMA:
 		cexp(J, F, exp->a);
+		emitline(J, F, exp);
 		emit(J, F, OP_POP);
 		cexp(J, F, exp->b);
 		break;
@@ -700,6 +765,7 @@
 
 	case EXP_LOGOR:
 		cexp(J, F, exp->a);
+		emitline(J, F, exp);
 		emit(J, F, OP_DUP);
 		end = emitjump(J, F, OP_JTRUE);
 		emit(J, F, OP_POP);
@@ -709,6 +775,7 @@
 
 	case EXP_LOGAND:
 		cexp(J, F, exp->a);
+		emitline(J, F, exp);
 		emit(J, F, OP_DUP);
 		end = emitjump(J, F, OP_JFALSE);
 		emit(J, F, OP_POP);
@@ -718,6 +785,7 @@
 
 	case EXP_COND:
 		cexp(J, F, exp->a);
+		emitline(J, F, exp);
 		then = emitjump(J, F, OP_JTRUE);
 		cexp(J, F, exp->c);
 		end = emitjump(J, F, OP_JUMP);
@@ -825,6 +893,7 @@
 	js_Ast *prev;
 	do {
 		prev = node, node = node->parent;
+		emitline(J, F, node);
 		switch (node->type) {
 		default: /* impossible */ break;
 		case STM_WITH:
@@ -903,6 +972,7 @@
 			if (!strcmp(catchvar->string, "eval"))
 				jsC_error(J, catchvar, "redefining 'eval' is not allowed in strict mode");
 		}
+		emitline(J, F, catchvar);
 		emitstring(J, F, OP_CATCH, catchvar->string);
 		cstm(J, F, catchstm);
 		emit(J, F, OP_ENDCATCH);
@@ -934,6 +1004,7 @@
 			if (!strcmp(catchvar->string, "eval"))
 				jsC_error(J, catchvar, "redefining 'eval' is not allowed in strict mode");
 		}
+		emitline(J, F, catchvar);
 		emitstring(J, F, OP_CATCH, catchvar->string);
 		cstm(J, F, catchstm);
 		emit(J, F, OP_ENDCATCH);
@@ -964,11 +1035,13 @@
 			def = clause;
 		} else {
 			cexp(J, F, clause->a);
+			emitline(J, F, clause);
 			clause->casejump = emitjump(J, F, OP_JCASE);
 		}
 	}
 	emit(J, F, OP_POP);
 	if (def) {
+		emitline(J, F, def);
 		def->casejump = emitjump(J, F, OP_JUMP);
 		end = 0;
 	} else {
@@ -975,7 +1048,7 @@
 		end = emitjump(J, F, OP_JUMP);
 	}
 
-	/* emit the casue clause bodies */
+	/* emit the case clause bodies */
 	for (node = head; node; node = node->b) {
 		clause = node->a;
 		label(J, F, clause->casejump);
@@ -997,6 +1070,7 @@
 		js_Ast *var = list->a;
 		if (var->b) {
 			cexp(J, F, var->b);
+			emitline(J, F, var);
 			emitlocal(J, F, OP_SETLOCAL, OP_SETVAR, var->a);
 			emit(J, F, OP_POP);
 		}
@@ -1021,6 +1095,7 @@
 
 	case STM_EMPTY:
 		if (F->script) {
+			emitline(J, F, stm);
 			emit(J, F, OP_POP);
 			emit(J, F, OP_UNDEF);
 		}
@@ -1033,8 +1108,10 @@
 	case STM_IF:
 		if (stm->c) {
 			cexp(J, F, stm->a);
+			emitline(J, F, stm);
 			then = emitjump(J, F, OP_JTRUE);
 			cstm(J, F, stm->c);
+			emitline(J, F, stm);
 			end = emitjump(J, F, OP_JUMP);
 			label(J, F, then);
 			cstm(J, F, stm->b);
@@ -1041,6 +1118,7 @@
 			label(J, F, end);
 		} else {
 			cexp(J, F, stm->a);
+			emitline(J, F, stm);
 			end = emitjump(J, F, OP_JFALSE);
 			cstm(J, F, stm->b);
 			label(J, F, end);
@@ -1052,6 +1130,7 @@
 		cstm(J, F, stm->a);
 		cont = here(J, F);
 		cexp(J, F, stm->b);
+		emitline(J, F, stm);
 		emitjumpto(J, F, OP_JTRUE, loop);
 		labeljumps(J, F, stm->jumps, here(J,F), cont);
 		break;
@@ -1059,8 +1138,10 @@
 	case STM_WHILE:
 		loop = here(J, F);
 		cexp(J, F, stm->a);
+		emitline(J, F, stm);
 		end = emitjump(J, F, OP_JFALSE);
 		cstm(J, F, stm->b);
+		emitline(J, F, stm);
 		emitjumpto(J, F, OP_JUMP, loop);
 		label(J, F, end);
 		labeljumps(J, F, stm->jumps, here(J,F), loop);
@@ -1079,6 +1160,7 @@
 		loop = here(J, F);
 		if (stm->b) {
 			cexp(J, F, stm->b);
+			emitline(J, F, stm);
 			end = emitjump(J, F, OP_JFALSE);
 		} else {
 			end = 0;
@@ -1089,6 +1171,7 @@
 			cexp(J, F, stm->c);
 			emit(J, F, OP_POP);
 		}
+		emitline(J, F, stm);
 		emitjumpto(J, F, OP_JUMP, loop);
 		if (end)
 			label(J, F, end);
@@ -1098,9 +1181,11 @@
 	case STM_FOR_IN:
 	case STM_FOR_IN_VAR:
 		cexp(J, F, stm->b);
+		emitline(J, F, stm);
 		emit(J, F, OP_ITERATOR);
 		loop = here(J, F);
 		{
+			emitline(J, F, stm);
 			emit(J, F, OP_NEXTITER);
 			end = emitjump(J, F, OP_JFALSE);
 			cassignforin(J, F, stm);
@@ -1111,6 +1196,7 @@
 			} else {
 				cstm(J, F, stm->c);
 			}
+			emitline(J, F, stm);
 			emitjumpto(J, F, OP_JUMP, loop);
 		}
 		label(J, F, end);
@@ -1144,6 +1230,7 @@
 				jsC_error(J, stm, "unlabelled break must be inside loop or switch");
 		}
 		cexit(J, F, STM_BREAK, stm, target);
+		emitline(J, F, stm);
 		addjump(J, F, STM_BREAK, target, emitjump(J, F, OP_JUMP));
 		break;
 
@@ -1159,6 +1246,7 @@
 				jsC_error(J, stm, "continue must be inside loop");
 		}
 		cexit(J, F, STM_CONTINUE, stm, target);
+		emitline(J, F, stm);
 		addjump(J, F, STM_CONTINUE, target, emitjump(J, F, OP_JUMP));
 		break;
 
@@ -1171,11 +1259,13 @@
 		if (!target)
 			jsC_error(J, stm, "return not in function");
 		cexit(J, F, STM_RETURN, stm, target);
+		emitline(J, F, stm);
 		emit(J, F, OP_RETURN);
 		break;
 
 	case STM_THROW:
 		cexp(J, F, stm->a);
+		emitline(J, F, stm);
 		emit(J, F, OP_THROW);
 		break;
 
@@ -1183,12 +1273,15 @@
 		if (F->strict)
 			jsC_error(J, stm->a, "'with' statements are not allowed in strict mode");
 		cexp(J, F, stm->a);
+		emitline(J, F, stm);
 		emit(J, F, OP_WITH);
 		cstm(J, F, stm->b);
+		emitline(J, F, stm);
 		emit(J, F, OP_ENDWITH);
 		break;
 
 	case STM_TRY:
+		emitline(J, F, stm);
 		if (stm->b && stm->c) {
 			if (stm->d)
 				ctrycatchfinally(J, F, stm->a, stm->b, stm->c, stm->d);
@@ -1200,15 +1293,18 @@
 		break;
 
 	case STM_DEBUGGER:
+		emitline(J, F, stm);
 		emit(J, F, OP_DEBUGGER);
 		break;
 
 	default:
 		if (F->script) {
+			emitline(J, F, stm);
 			emit(J, F, OP_POP);
 			cexp(J, F, stm);
 		} else {
 			cexp(J, F, stm);
+			emitline(J, F, stm);
 			emit(J, F, OP_POP);
 		}
 		break;
@@ -1321,7 +1417,9 @@
 	while (list) {
 		js_Ast *stm = list->a;
 		if (stm->type == AST_FUNDEC) {
+			emitline(J, F, stm);
 			emitfunction(J, F, newfun(J, stm->line, stm->a, stm->b, stm->c, 0, F->strict));
+			emitline(J, F, stm);
 			emitstring(J, F, OP_INITVAR, stm->a->string);
 		}
 		list = list->b;
@@ -1345,6 +1443,10 @@
 	if (body && body->type == AST_LIST && body->a && body->a->type == EXP_STRING)
 		if (!strcmp(body->a->string, "use strict"))
 			F->strict = 1;
+
+	emit(J, F, OP_LINE);
+	emitraw(J, F, F->line);
+	F->lastline = F->line;
 
 	shadow = cparams(J, F, params, name);