shithub: libmujs

Download patch

ref: 62fea907a6a488285e58a5aa3daec72e51696f0f
parent: 67de4965c6190526606344edc59af8b621835e50
author: Tor Andersson <tor.andersson@artifex.com>
date: Sun Jan 12 08:34:57 EST 2014

Compile logical or/and operators with early termination.

Make the && and || operators right-associative since that generates
better code, and should make no difference in semantics.

--- a/jscompile.c
+++ b/jscompile.c
@@ -68,6 +68,22 @@
 	emit(J, F, addconst(J, F, v));
 }
 
+static int jump(JF, int opcode)
+{
+	int addr = F->len + 1;
+	emit(J, F, opcode);
+	emit(J, F, 0);
+	emit(J, F, 0);
+	return addr;
+}
+
+static void label(JF, int addr)
+{
+	int dest = F->len;
+	F->code[addr+0] = (dest >> 8) & 0xFF;
+	F->code[addr+1] = (dest) & 0xFF;
+}
+
 static void unary(JF, js_Ast *exp, int opcode)
 {
 	cexp(J, F, exp->a);
@@ -152,6 +168,7 @@
 
 static void cexp(JF, js_Ast *exp)
 {
+	int then, end;
 	int n;
 
 	switch (exp->type) {
@@ -233,8 +250,6 @@
 	case EXP_POSTINC: clval(J, F, exp->a); emit(J, F, OP_POSTINC); break;
 	case EXP_POSTDEC: clval(J, F, exp->a); emit(J, F, OP_POSTDEC); break;
 
-	case EXP_LOGOR: binary(J, F, exp, OP_LOGOR); break;
-	case EXP_LOGAND: binary(J, F, exp, OP_LOGAND); break;
 	case EXP_BITOR: binary(J, F, exp, OP_BITOR); break;
 	case EXP_BITXOR: binary(J, F, exp, OP_BITXOR); break;
 	case EXP_BITAND: binary(J, F, exp, OP_BITAND); break;
@@ -281,6 +296,36 @@
 		cexp(J, F, exp->b);
 		break;
 
+	case EXP_LOGOR:
+		/* if a == true then a else b */
+		cexp(J, F, exp->a);
+		emit(J, F, OP_DUP);
+		end = jump(J, F, OP_JTRUE);
+		emit(J, F, OP_POP);
+		cexp(J, F, exp->b);
+		label(J, F, end);
+		break;
+
+	case EXP_LOGAND:
+		/* if a == false then a else b */
+		cexp(J, F, exp->a);
+		emit(J, F, OP_DUP);
+		end = jump(J, F, OP_JFALSE);
+		emit(J, F, OP_POP);
+		cexp(J, F, exp->b);
+		label(J, F, end);
+		break;
+
+	case EXP_COND:
+		cexp(J, F, exp->a);
+		then = jump(J, F, OP_JTRUE);
+		cexp(J, F, exp->c);
+		end = jump(J, F, OP_JUMP);
+		label(J, F, then);
+		cexp(J, F, exp->b);
+		label(J, F, end);
+		break;
+
 	default:
 		jsC_error(J, exp, "unknown expression");
 	}
@@ -303,25 +348,9 @@
 	}
 }
 
-static int emitjump(JF, int opcode)
-{
-	int addr = F->len + 1;
-	emit(J, F, opcode);
-	emit(J, F, 0);
-	emit(J, F, 0);
-	return addr;
-}
-
-static void emitlabel(JF, int addr)
-{
-	int dest = F->len;
-	F->code[addr+0] = (dest >> 8) & 0xFF;
-	F->code[addr+1] = (dest) & 0xFF;
-}
-
 static void cstm(JF, js_Ast *stm)
 {
-	int lelse, lend;
+	int then, end;
 
 	switch (stm->type) {
 	case STM_BLOCK:
@@ -336,14 +365,19 @@
 		break;
 
 	case STM_IF:
-		cexp(J, F, stm->a);
-		lelse = emitjump(J, F, OP_JFALSE);
-		cstm(J, F, stm->b);
-		emitlabel(J, F, lelse);
 		if (stm->c) {
-			lend = emitjump(J, F, OP_JUMP);
+			cexp(J, F, stm->a);
+			then = jump(J, F, OP_JTRUE);
 			cstm(J, F, stm->c);
-			emitlabel(J, F, lend);
+			end = jump(J, F, OP_JUMP);
+			label(J, F, then);
+			cstm(J, F, stm->b);
+			label(J, F, end);
+		} else {
+			cexp(J, F, stm->a);
+			end = jump(J, F, OP_JFALSE);
+			cstm(J, F, stm->b);
+			label(J, F, end);
 		}
 		break;
 
--- a/jscompile.h
+++ b/jscompile.h
@@ -49,8 +49,6 @@
 	OP_BITNOT,
 	OP_LOGNOT,
 
-	OP_LOGOR,
-	OP_LOGAND,
 	OP_BITOR,
 	OP_BITXOR,
 	OP_BITAND,
--- a/jsparse.c
+++ b/jsparse.c
@@ -458,8 +458,8 @@
 static js_Ast *logand(js_State *J, int notin)
 {
 	js_Ast *a = bitor(J, notin);
-	while (accept(J, TK_AND))
-		a = EXP2(LOGAND, a, bitor(J, notin));
+	if (accept(J, TK_AND))
+		a = EXP2(LOGAND, a, logand(J, notin));
 	return a;
 }
 
@@ -466,8 +466,8 @@
 static js_Ast *logor(js_State *J, int notin)
 {
 	js_Ast *a = logand(J, notin);
-	while (accept(J, TK_OR))
-		a = EXP2(LOGOR, a, logand(J, notin));
+	if (accept(J, TK_OR))
+		a = EXP2(LOGOR, a, logor(J, notin));
 	return a;
 }