Module: sip-router Branch: andrei/script_vars Commit: 5184c21a634b700a3800665269ca659c53e86fe9 URL: http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=5184c21a...
Author: Andrei Pelinescu-Onciul andrei@iptel.org Committer: Andrei Pelinescu-Onciul andrei@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);