From 62fea907a6a488285e58a5aa3daec72e51696f0f Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Sun, 12 Jan 2014 13:34:57 +0100 Subject: [PATCH] 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. --- jscompile.c | 84 +++++++++++++++++++++++++++++++++++++---------------- jscompile.h | 2 -- jsparse.c | 8 ++--- 3 files changed, 63 insertions(+), 31 deletions(-) diff --git a/jscompile.c b/jscompile.c index e3c65de..6b9f0be 100644 --- a/jscompile.c +++ b/jscompile.c @@ -68,6 +68,22 @@ static void emitstring(JF, int opcode, const char *s) 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 assignop(JF, js_Ast *exp, int opcode) static void cexp(JF, js_Ast *exp) { + int then, end; int n; switch (exp->type) { @@ -233,8 +250,6 @@ static void cexp(JF, js_Ast *exp) 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 @@ static void cexp(JF, js_Ast *exp) 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 void cvardeclist(JF, js_Ast *list) } } -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 @@ static void cstm(JF, js_Ast *stm) 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; diff --git a/jscompile.h b/jscompile.h index a9e5dc4..7392b7c 100644 --- a/jscompile.h +++ b/jscompile.h @@ -49,8 +49,6 @@ enum OP_BITNOT, OP_LOGNOT, - OP_LOGOR, - OP_LOGAND, OP_BITOR, OP_BITXOR, OP_BITAND, diff --git a/jsparse.c b/jsparse.c index f89b19a..bc3816f 100644 --- a/jsparse.c +++ b/jsparse.c @@ -458,16 +458,16 @@ static js_Ast *bitor(js_State *J, int notin) 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; } 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; }