[SR-Dev] git:andrei/script_vars: script engine: expression optimizations

Andrei Pelinescu-Onciul andrei at iptel.org
Wed Dec 10 14:53:46 CET 2008


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

Author: Andrei Pelinescu-Onciul <andrei at iptel.org>
Committer: Andrei Pelinescu-Onciul <andrei at iptel.org>
Date:   Wed Dec 10 14:43:58 2008 +0100

script engine: expression optimizations

- optimizations for logical expressions
  (  exp(rval(v)) -> exp(v), exp_elem(x, rval(v)) -> exp_elem(x, v) )
- comp_rve() fix

---

 route.c |  228 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 route.h |    2 +
 2 files changed, 229 insertions(+), 1 deletions(-)

diff --git a/route.c b/route.c
index f098b0f..a36483b 100644
--- a/route.c
+++ b/route.c
@@ -93,6 +93,12 @@ struct route_list branch_rt;
 struct route_list onsend_rt;
 
 
+/** script optimization level, useful for debugging.
+ *  0 - no optimization
+ *  1 - optimize rval expressions
+ *  2 - optimize expr elems
+ */
+int scr_opt_lev=9;
 
 inline static void destroy_rlist(struct route_list* rt)
 {
@@ -283,6 +289,205 @@ int route_lookup(struct route_list* rt, char* name)
 int fix_actions(struct action* a); /*fwd declaration*/
 
 
+/** optimize the left side of a struct expr.
+ *  @return 1 if optimized, 0 if not and -1 on error
+ */
+static int exp_optimize_left(struct expr* exp)
+{
+	struct rval_expr* rve;
+	struct rvalue* rval;
+	int old_type, old_op;
+	int ret;
+	
+	ret=0;
+	if (exp->type!=ELEM_T)
+		return 0;
+	old_type=exp->l_type;
+	old_op=exp->op;
+	if (exp->l_type==RVEXP_O){
+		rve=exp->l.param;
+		/* rve should be previously fixed/optimized */
+		/* optimize exp (rval(val)) -> exp(val) */
+		if (rve->op==RVE_RVAL_OP){
+			rval=&rve->left.rval;
+			switch(rval->type){
+				case RV_INT:
+					if (exp->op==NO_OP){
+						exp->l_type=NUMBER_O;
+						exp->l.param=0;
+						exp->r_type=NUMBER_ST;
+						exp->r.numval=rval->v.l;
+						rval_destroy(rval);
+						pkg_free(rve);
+						ret=1;
+					}
+					break;
+				case RV_STR:
+					/* string evaluated in expression context - not
+					   supported */
+					break;
+				case RV_BEXPR:
+					if (exp->op==NO_OP){
+						/* replace the current expr. */
+						*exp=*(rval->v.bexpr);
+						rval_destroy(rval);
+						pkg_free(rve);
+						ret=1;
+					};
+					break;
+				case RV_ACTION_ST:
+					if (exp->op==NO_OP){
+						exp->l_type=ACTION_O;
+						exp->l.param=0;
+						exp->r_type=ACTION_ST;
+						exp->r.param=rval->v.action;
+						rval_destroy(rval);
+						pkg_free(rve);
+						ret=1;
+					}
+					break;
+				case RV_SEL:
+					exp->l.select=pkg_malloc(sizeof(*exp->l.select));
+					if (exp->l.select){
+						exp->l_type=SELECT_O;
+						*exp->l.select=rval->v.sel;
+						rval_destroy(rval);
+						pkg_free(rve);
+						ret=1;
+					}else
+						ret=-1;
+					break;
+				case RV_AVP:
+					exp->l.attr=pkg_malloc(sizeof(*exp->l.attr));
+					if (exp->l.attr){
+						exp->l_type=AVP_O;
+						*exp->l.attr=rval->v.avps;
+						rval_destroy(rval);
+						pkg_free(rve);
+						ret=1;
+					}else
+						ret=-1;
+					break;
+				case RV_PVAR:
+					exp->l.param=pkg_malloc(sizeof(pv_spec_t));
+					if (exp->l.param){
+						exp->l_type=PVAR_O;
+						*((pv_spec_t*)exp->l.param)=rval->v.pvs;
+						rval_destroy(rval);
+						pkg_free(rve);
+						ret=1;
+					}else
+						ret=-1;
+					break;
+				case RV_NONE:
+					break;
+			}
+		}
+	}
+	if (ret>0)
+		DBG("left EXP optimized succesfully: %d op %d to %d op %d\n",
+			old_type, old_op, exp->l_type, exp->op);
+	return ret;
+}
+
+
+
+/** optimize the left side of a struct expr.
+ *  @return 1 if optimized, 0 if not and -1 on error
+ */
+static int exp_optimize_right(struct expr* exp)
+{
+	struct rval_expr* rve;
+	struct rvalue* rval;
+	int old_type, old_op;
+	int ret;
+	
+	ret=0;
+	if ((exp->type!=ELEM_T) ||(exp->op==NO_OP))
+		return 0;
+	old_type=exp->r_type;
+	old_op=exp->op;
+	if (exp->r_type==RVE_ST){
+		rve=exp->r.param;
+		/* rve should be previously fixed/optimized */
+		/* optimize exp (rval(val)) -> exp(val) */
+		if (rve->op==RVE_RVAL_OP){
+			rval=&rve->left.rval;
+			switch(rval->type){
+				case RV_INT:
+					exp->r_type=NUMBER_ST;
+					exp->r.numval=rval->v.l;
+					rval_destroy(rval);
+					pkg_free(rve);
+					ret=1;
+					break;
+				case RV_STR:
+					exp->r.str.s=pkg_malloc(rval->v.s.len+1);
+					if (exp->r.str.s){
+						exp->r.str.len=rval->v.s.len;
+						memcpy(exp->r.str.s, rval->v.s.s, rval->v.s.len);
+						exp->r_type=STRING_ST;
+						rval_destroy(rval);
+						pkg_free(rve);
+						ret=1;
+					}else
+						ret=-1;
+					break;
+				case RV_BEXPR:
+					/* cannot be optimized further, is an exp_elem
+					   which is not constant */
+					break;
+				case RV_ACTION_ST:
+					/* cannot be optimized further, is not constant and
+					  eval_elem() does not support ACTION_ST for op!=NO_OP*/
+					break;
+				case RV_SEL:
+					exp->r.select=pkg_malloc(sizeof(*exp->l.select));
+					if (exp->r.select){
+						exp->r_type=SELECT_ST;
+						*exp->r.select=rval->v.sel;
+						rval_destroy(rval);
+						pkg_free(rve);
+						ret=1;
+					}else
+						ret=-1;
+					break;
+				case RV_AVP:
+					exp->r.attr=pkg_malloc(sizeof(*exp->l.attr));
+					if (exp->r.attr){
+						exp->r_type=AVP_ST;
+						*exp->r.attr=rval->v.avps;
+						rval_destroy(rval);
+						pkg_free(rve);
+						ret=1;
+					}else
+						ret=-1;
+					break;
+				case RV_PVAR:
+					exp->r.param=pkg_malloc(sizeof(pv_spec_t));
+					if (exp->r.param){
+						exp->r_type=PVAR_ST;
+						*((pv_spec_t*)exp->r.param)=rval->v.pvs;
+						rval_destroy(rval);
+						pkg_free(rve);
+						ret=1;
+					}else
+						ret=-1;
+					break;
+				case RV_NONE:
+					ret=-1;
+					break;
+			}
+		}
+	}
+	if (ret>0)
+		DBG("right EXP optimized succesfully: %d op %d to %d op %d\n",
+			old_type, old_op, exp->r_type, exp->op);
+	return ret;
+}
+
+
+
 /* traverses an expr tree and compiles the REs where necessary)
  * returns: 0 for ok, <0 if errors */
 int fix_expr(struct expr* exp)
@@ -382,12 +587,16 @@ int fix_expr(struct expr* exp)
 					ERR("Unable to fix left rval expression\n");
 					return ret;
 				}
+				if (scr_opt_lev>=2)
+					exp_optimize_left(exp);
 			}
 			if (exp->r_type==RVE_ST){
 				if ((ret=fix_rval_expr(&exp->r.param))<0){
 					ERR("Unable to fix right rval expression\n");
 					return ret;
 				}
+				if (scr_opt_lev>=2)
+					exp_optimize_right(exp);
 			}
 			/* PVAR don't need fixing */
 			ret=0;
@@ -934,11 +1143,28 @@ inline static int comp_rve(int op, struct rval_expr* rve, int rtype,
 							struct run_act_ctx* h)
 {
 	int i;
+	struct rvalue* rv;
+	struct rvalue* rv1;
+	struct rval_cache c1;
 	
-	if (unlikely(rval_expr_eval_int(h,  msg, &i, rve)<0)){
+	rval_cache_init(&c1);
+	if (unlikely(rval_expr_eval_rvint(h,  msg, &rv, &i, rve, &c1)<0)){
 		ERR("failure evaluating expression: bad type\n");
 		i=0; /* false */
+		goto int_expr;
+	}
+	if (unlikely(rv)){
+		/* no int => str */
+		rv1=rval_convert(h, msg, RV_STR, rv, &c1);
+		i=comp_str(op, &rv1->v.s, rtype, r, msg, h);
+		rval_destroy(rv1);
+		rval_destroy(rv);
+		rval_cache_clean(&c1);
+		return i;
 	}
+	/* expr evaluated to int */
+int_expr:
+	rval_cache_clean(&c1);
 	if (op==NO_OP)
 		return !(!i); /* transform it into { 0, 1 } */
 	return comp_num(op, i, rtype, r, msg, h);
diff --git a/route.h b/route.h
index 31c9785..732d4a9 100644
--- a/route.h
+++ b/route.h
@@ -59,6 +59,8 @@ extern struct route_list failure_rt;
 extern struct route_list branch_rt;
 extern struct route_list onsend_rt;
 
+/* script optimization level */
+extern int scr_opt_lev;
 
 int init_routes();
 void destroy_routes();




More information about the sr-dev mailing list