[SR-Dev] git:andrei/script_vars: script engine: optimize op($v, ct) where ct=0 or 1

Andrei Pelinescu-Onciul andrei at iptel.org
Thu Dec 18 17:00:55 CET 2008


Module: sip-router
Branch: andrei/script_vars
Commit: 5184c21a634b700a3800665269ca659c53e86fe9
URL:    http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=5184c21a634b700a3800665269ca659c53e86fe9

Author: Andrei Pelinescu-Onciul <andrei at iptel.org>
Committer: Andrei Pelinescu-Onciul <andrei at iptel.org>
Date:   Thu Dec 18 12:51:50 2008 +0100

script engine: optimize op($v, ct) where ct=0 or 1

- optimize: $v*0->0,  0*$v->0, $v*1->$v 1*$v->$v
            $v/1->$v, 0/$v->0
            $v-0->$v
            $v&0->0,  0&$v->0
            $v|0->$v, 0|$v->$v
            $v&&0->0, 0&&$v->0, $v&&1->$v, 1&&$v->$v
            $v||1->1, 1||$v->1, $v||0->$v, 0||$v->$v
            $v+0->$v, 0+$v->$v if typeof(expression) is int (forced
             by the context)
- fix runtime && and ||:
            0 && expr -> don't evaluate expr, return 0
            1 || expr -> don't evaluate expr, return 1

---

 rvalue.c |  284 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 280 insertions(+), 4 deletions(-)

diff --git a/rvalue.c b/rvalue.c
index 558ab70..ce9e3d3 100644
--- a/rvalue.c
+++ b/rvalue.c
@@ -1288,8 +1288,6 @@ int rval_expr_eval_int( struct run_act_ctx* h, struct sip_msg* msg,
 		case RVE_PLUS_OP:
 		case RVE_BOR_OP:
 		case RVE_BAND_OP:
-		case RVE_LAND_OP:
-		case RVE_LOR_OP:
 		case RVE_GT_OP:
 		case RVE_GTE_OP:
 		case RVE_LT_OP:
@@ -1302,6 +1300,34 @@ int rval_expr_eval_int( struct run_act_ctx* h, struct sip_msg* msg,
 				break;
 			ret=int_intop2(res, rve->op, i1, i2);
 			break;
+		case RVE_LAND_OP:
+			if (unlikely(
+					(ret=rval_expr_eval_int(h, msg, &i1, rve->left.rve)) <0) )
+				break;
+			if (i1==0){
+				*res=0;
+			}else{
+				if (unlikely( (ret=rval_expr_eval_int(h, msg, &i2,
+										rve->right.rve)) <0) )
+					break;
+				*res=i1 && i2;
+			}
+			ret=0;
+			break;
+		case RVE_LOR_OP:
+			if (unlikely(
+					(ret=rval_expr_eval_int(h, msg, &i1, rve->left.rve)) <0) )
+				break;
+			if (i1){
+				*res=1;
+			}else{
+				if (unlikely( (ret=rval_expr_eval_int(h, msg, &i2,
+										rve->right.rve)) <0) )
+					break;
+				*res=i1 || i2;
+			}
+			ret=0;
+			break;
 		case RVE_EQ_OP:
 		case RVE_DIFF_OP:
 			/* if left is string, eval left & right as string and
@@ -1593,6 +1619,32 @@ error:
 
 
 
+/** evals a rval expr and always returns a new rval.
+ * like rval_expr_eval, but always returns a new rvalue (never a reference
+ * to an exisiting one).
+ * WARNING: result must be rval_destroy()'ed if non-null (it might be
+ * a reference to another rval). The result can be modified only
+ * if rv_chg_in_place() returns true.
+ * @result rvalue on success, 0 on error
+ */
+struct rvalue* rval_expr_eval_new(struct run_act_ctx* h, struct sip_msg* msg,
+								struct rval_expr* rve)
+{
+	struct rvalue* ret;
+	struct rvalue* rv;
+	
+	ret=rval_expr_eval(h, msg, rve);
+	if (ret && !rv_chg_in_place(ret)){
+		rv=ret;
+		/* create a new rv */
+		ret=rval_new(rv->type, &rv->v, 0);
+		rval_destroy(rv);
+	}
+	return ret;
+}
+
+
+
 /** create a RVE_RVAL_OP rval_expr, containing a single rval of the given type.
  *
  * @param rv_type - rval type
@@ -1941,6 +1993,221 @@ static int rve_replace_with_ct_rv(struct rval_expr* rve, struct rvalue* rv)
 
 
 
+/** optimize op($v, 0) or op($v, 1).
+ * Note: internal use only from rve_optimize
+ * It should be called after ct optimization, for non-contant
+ *  expressions (the left or right side is not constant).
+ * @return 1 on success (rve was changed), 0 on failure and -1 on error
+ */
+static int rve_opt_01(struct rval_expr* rve, enum rval_type rve_type)
+{
+	struct rvalue* rv;
+	struct rval_expr* ct_rve;
+	struct rval_expr* v_rve;
+	int i;
+	int ret;
+	enum rval_expr_op op;
+	int right; /* debugging msg */
+	
+	rv=0;
+	ret=0;
+	right=0;
+	
+	if (rve_is_constant(rve->right.rve)){
+		ct_rve=rve->right.rve;
+		v_rve=rve->left.rve;
+		right=1;
+	}else if (rve_is_constant(rve->left.rve)){
+		ct_rve=rve->left.rve;
+		v_rve=rve->right.rve;
+		right=0;
+	}else
+		return 0; /* op($v, $w) */
+	
+	/* rval_expr_eval_new() instead of rval_expr_eval() to avoid
+	   referencing a ct_rve->left.rval if ct_rve is a rval, which
+	   would prevent rve_destroy(ct_rve) from working */
+	if ((rv=rval_expr_eval_new(0, 0, ct_rve))==0){
+		ERR("optimization failure, bad expression\n");
+		goto error;
+	}
+	op=rve->op;
+	if (rv->type==RV_INT){
+		i=rv->v.l;
+		switch(op){
+			case RVE_MUL_OP:
+				if (i==0){
+					/* $v *  0 -> 0
+					 *  0 * $v -> 0 */
+					if (rve_replace_with_ct_rv(rve, rv)<0)
+						goto error;
+					ret=1;
+				}else if (i==1){
+					/* $v *  1 -> $v
+					 *  1 * $v -> $v */
+					rve_destroy(ct_rve);
+					*rve=*v_rve; /* replace current expr. with $v */
+					pkg_free(v_rve);/* rve_destroy(v_rve) would free
+									   everything*/
+					ret=1;
+				}
+				break;
+			case RVE_DIV_OP:
+				if (i==0){
+					if (ct_rve==rve->left.rve){
+						/* 0 / $v -> 0 */
+						if (rve_replace_with_ct_rv(rve, rv)<0)
+							goto error;
+						ret=1;
+					}else{
+						/* $v / 0 */
+						ERR("RVE divide by 0 at %d,%d\n",
+								ct_rve->fpos.s_line, ct_rve->fpos.s_col);
+					}
+				}else if (i==1){
+					if (ct_rve==rve->right.rve){
+						/* $v / 1 -> $v */
+						rve_destroy(ct_rve);
+						*rve=*v_rve; /* replace current expr. with $v */
+						pkg_free(v_rve);/* rve_destroy(v_rve) would free
+										   everything*/
+						ret=1;
+					}
+				}
+				break;
+			case RVE_MINUS_OP:
+				if (i==0){
+					if (ct_rve==rve->right.rve){
+						/* $v - 0 -> $v */
+						rve_destroy(ct_rve);
+						*rve=*v_rve; /* replace current expr. with $v */
+						pkg_free(v_rve);/* rve_destroy(v_rve) would free
+										   everything*/
+						ret=1;
+					}
+					/* ? 0 - $v -> -($v)  ? */
+				}
+				break;
+			case RVE_BAND_OP:
+				if (i==0){
+					/* $v &  0 -> 0
+					 *  0 & $v -> 0 */
+					if (rve_replace_with_ct_rv(rve, rv)<0)
+						goto error;
+					ret=1;
+				}
+				/* no 0xffffff optimization for now (haven't decide on
+				   the number of bits ) */
+				break;
+			case RVE_BOR_OP:
+				if (i==0){
+					/* $v |  0 -> $v
+					 *  0 | $v -> $v */
+					rve_destroy(ct_rve);
+					*rve=*v_rve; /* replace current expr. with $v */
+					pkg_free(v_rve);/* rve_destroy(v_rve) would free
+									   everything*/
+					ret=1;
+				}
+				break;
+			case RVE_LAND_OP:
+				if (i==0){
+					/* $v &&  0 -> 0
+					 *  0 && $v -> 0 */
+					if (rve_replace_with_ct_rv(rve, rv)<0)
+						goto error;
+					ret=1;
+				}else if (i==1){
+					/* $v &&  1 -> $v
+					 *  1 && $v -> $v */
+					rve_destroy(ct_rve);
+					*rve=*v_rve; /* replace current expr. with $v */
+					pkg_free(v_rve);/* rve_destroy(v_rve) would free
+									   everything*/
+					ret=1;
+				}
+				break;
+			case RVE_LOR_OP:
+				if (i==1){
+					/* $v ||  1 -> 1
+					 *  1 || $v -> 1 */
+					if (rve_replace_with_ct_rv(rve, rv)<0)
+						goto error;
+					ret=1;
+				}else if (i==0){
+					/* $v ||  0 -> $v
+					 *  0 && $v -> $v */
+					rve_destroy(ct_rve);
+					*rve=*v_rve; /* replace current expr. with $v */
+					pkg_free(v_rve);/* rve_destroy(v_rve) would free
+									   everything*/
+					ret=1;
+				}
+				break;
+			case RVE_PLUS_OP:
+				/* we must make sure that this is an int PLUS
+				   (because "foo"+0 is valid => "foo0") */
+				if ((i==0) && (rve_type==RV_INT)){
+					/* $v +  0 -> $v
+					 *  0 + $v -> $v */
+					rve_destroy(ct_rve);
+					*rve=*v_rve; /* replace current expr. with $v */
+					pkg_free(v_rve);/* rve_destroy(v_rve) would free
+									   everything*/
+					ret=1;
+				}
+				break;
+			default:
+				/* do nothing */
+				break;
+		}
+		/* debugging messages */
+		if (ret==1){
+			if (right){
+				if ((rve->op==RVE_RVAL_OP) && (rve->left.rval.type==RV_INT))
+					DBG("FIXUP RVE: (%d,%d-%d,%d) optimized"
+							" op%d($v, %d) -> %d\n", 
+							rve->fpos.s_line, rve->fpos.s_col,
+							rve->fpos.e_line, rve->fpos.s_col,
+							op, i, (int)rve->left.rval.v.l);
+				else
+					DBG("FIXUP RVE: (%d,%d-%d,%d) optimized"
+							" op%d($v, %d) -> $v\n",
+							rve->fpos.s_line, rve->fpos.s_col,
+							rve->fpos.e_line, rve->fpos.s_col,
+							op, i);
+			}else{
+				if ((rve->op==RVE_RVAL_OP) && (rve->left.rval.type==RV_INT))
+					DBG("FIXUP RVE: (%d,%d-%d,%d) optimized"
+							" op%d(%d, $v) -> %d\n", 
+							rve->fpos.s_line, rve->fpos.s_col,
+							rve->fpos.e_line, rve->fpos.s_col,
+							op, i, (int)rve->left.rval.v.l);
+				else
+					DBG("FIXUP RVE: (%d,%d-%d,%d) optimized"
+							" op%d(%d, $v) -> $v\n",
+							rve->fpos.s_line, rve->fpos.s_col,
+							rve->fpos.e_line, rve->fpos.s_col,
+							op, i);
+			}
+		}
+	}
+	/* no optimization for strings for now
+	   (We could optimize $v + "" or ""+$v, but this ""+$v is a way
+	    to force convert $v to str , it might mess up type checking
+	    (e.g. errors w/o optimization and no errors with) and it brings
+	    a very small benefit anyway (it's unlikely we'll see a lot of
+	    "")
+	*/
+	if (rv) rval_destroy(rv);
+	return ret;
+error:
+	if (rv) rval_destroy(rv);
+	return -1;
+}
+
+
+
 /** tries to optimize a rval_expr. */
 static int rve_optimize(struct rval_expr* rve)
 {
@@ -1987,8 +2254,9 @@ static int rve_optimize(struct rval_expr* rve)
 		rve_optimize(rve->left.rve);
 		rve_optimize(rve->right.rve);
 		if (!rve_check_type(&type, rve, &bad_rve, &bad_type, &exp_type)){
-			ERR("optimization failure, type mismatch in expression, "
+			ERR("optimization failure, type mismatch in expression (%d,%d), "
 					"type %s, but expected %s\n",
+					bad_rve->fpos.s_line, bad_rve->fpos.s_col,
 					rval_type_name(bad_type), rval_type_name(exp_type));
 			return 0;
 		}
@@ -2010,7 +2278,14 @@ static int rve_optimize(struct rval_expr* rve)
 			rv=0;
 		}
 		
-		/* TODO: $v * 0 => 0; $v * 1 => $v (for *, /, &, |, &&, ||, +, -) */
+		/* $v * 0 => 0; $v * 1 => $v (for *, /, &, |, &&, ||, +, -) */
+		if (rve_opt_01(rve, type)==1){
+			/* success, rve was changed => return now
+			  (since this is recursively invoked the "new" rve
+			   is already optimized) */
+			ret=1;
+			goto end;
+		}
 		
 		/* op(op($v, a), b) => op($v, op(a,b)) */
 		if (rve_is_constant(rve->right.rve)){
@@ -2170,6 +2445,7 @@ static int rve_optimize(struct rval_expr* rve)
 		}
 		/* op(op($v,a), op($w,b)) => no optimizations for now (TODO) */
 	}
+end:
 	return ret;
 error:
 	if (rv) rval_destroy(rv);




More information about the sr-dev mailing list