[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