Browse code

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

Andrei Pelinescu-Onciul authored on 18/12/2008 11:51:50
Showing 1 changed files
... ...
@@ -1288,8 +1288,6 @@ int rval_expr_eval_int( struct run_act_ctx* h, struct sip_msg* msg,
1288 1288
 		case RVE_PLUS_OP:
1289 1289
 		case RVE_BOR_OP:
1290 1290
 		case RVE_BAND_OP:
1291
-		case RVE_LAND_OP:
1292
-		case RVE_LOR_OP:
1293 1291
 		case RVE_GT_OP:
1294 1292
 		case RVE_GTE_OP:
1295 1293
 		case RVE_LT_OP:
... ...
@@ -1302,6 +1300,34 @@ int rval_expr_eval_int( struct run_act_ctx* h, struct sip_msg* msg,
1302 1300
 				break;
1303 1301
 			ret=int_intop2(res, rve->op, i1, i2);
1304 1302
 			break;
1303
+		case RVE_LAND_OP:
1304
+			if (unlikely(
1305
+					(ret=rval_expr_eval_int(h, msg, &i1, rve->left.rve)) <0) )
1306
+				break;
1307
+			if (i1==0){
1308
+				*res=0;
1309
+			}else{
1310
+				if (unlikely( (ret=rval_expr_eval_int(h, msg, &i2,
1311
+										rve->right.rve)) <0) )
1312
+					break;
1313
+				*res=i1 && i2;
1314
+			}
1315
+			ret=0;
1316
+			break;
1317
+		case RVE_LOR_OP:
1318
+			if (unlikely(
1319
+					(ret=rval_expr_eval_int(h, msg, &i1, rve->left.rve)) <0) )
1320
+				break;
1321
+			if (i1){
1322
+				*res=1;
1323
+			}else{
1324
+				if (unlikely( (ret=rval_expr_eval_int(h, msg, &i2,
1325
+										rve->right.rve)) <0) )
1326
+					break;
1327
+				*res=i1 || i2;
1328
+			}
1329
+			ret=0;
1330
+			break;
1305 1331
 		case RVE_EQ_OP:
1306 1332
 		case RVE_DIFF_OP:
1307 1333
 			/* if left is string, eval left & right as string and
... ...
@@ -1593,6 +1619,32 @@ error:
1593 1619
 
1594 1620
 
1595 1621
 
1622
+/** evals a rval expr and always returns a new rval.
1623
+ * like rval_expr_eval, but always returns a new rvalue (never a reference
1624
+ * to an exisiting one).
1625
+ * WARNING: result must be rval_destroy()'ed if non-null (it might be
1626
+ * a reference to another rval). The result can be modified only
1627
+ * if rv_chg_in_place() returns true.
1628
+ * @result rvalue on success, 0 on error
1629
+ */
1630
+struct rvalue* rval_expr_eval_new(struct run_act_ctx* h, struct sip_msg* msg,
1631
+								struct rval_expr* rve)
1632
+{
1633
+	struct rvalue* ret;
1634
+	struct rvalue* rv;
1635
+	
1636
+	ret=rval_expr_eval(h, msg, rve);
1637
+	if (ret && !rv_chg_in_place(ret)){
1638
+		rv=ret;
1639
+		/* create a new rv */
1640
+		ret=rval_new(rv->type, &rv->v, 0);
1641
+		rval_destroy(rv);
1642
+	}
1643
+	return ret;
1644
+}
1645
+
1646
+
1647
+
1596 1648
 /** create a RVE_RVAL_OP rval_expr, containing a single rval of the given type.
1597 1649
  *
1598 1650
  * @param rv_type - rval type
... ...
@@ -1941,6 +1993,221 @@ static int rve_replace_with_ct_rv(struct rval_expr* rve, struct rvalue* rv)
1941 1993
 
1942 1994
 
1943 1995
 
1996
+/** optimize op($v, 0) or op($v, 1).
1997
+ * Note: internal use only from rve_optimize
1998
+ * It should be called after ct optimization, for non-contant
1999
+ *  expressions (the left or right side is not constant).
2000
+ * @return 1 on success (rve was changed), 0 on failure and -1 on error
2001
+ */
2002
+static int rve_opt_01(struct rval_expr* rve, enum rval_type rve_type)
2003
+{
2004
+	struct rvalue* rv;
2005
+	struct rval_expr* ct_rve;
2006
+	struct rval_expr* v_rve;
2007
+	int i;
2008
+	int ret;
2009
+	enum rval_expr_op op;
2010
+	int right; /* debugging msg */
2011
+	
2012
+	rv=0;
2013
+	ret=0;
2014
+	right=0;
2015
+	
2016
+	if (rve_is_constant(rve->right.rve)){
2017
+		ct_rve=rve->right.rve;
2018
+		v_rve=rve->left.rve;
2019
+		right=1;
2020
+	}else if (rve_is_constant(rve->left.rve)){
2021
+		ct_rve=rve->left.rve;
2022
+		v_rve=rve->right.rve;
2023
+		right=0;
2024
+	}else
2025
+		return 0; /* op($v, $w) */
2026
+	
2027
+	/* rval_expr_eval_new() instead of rval_expr_eval() to avoid
2028
+	   referencing a ct_rve->left.rval if ct_rve is a rval, which
2029
+	   would prevent rve_destroy(ct_rve) from working */
2030
+	if ((rv=rval_expr_eval_new(0, 0, ct_rve))==0){
2031
+		ERR("optimization failure, bad expression\n");
2032
+		goto error;
2033
+	}
2034
+	op=rve->op;
2035
+	if (rv->type==RV_INT){
2036
+		i=rv->v.l;
2037
+		switch(op){
2038
+			case RVE_MUL_OP:
2039
+				if (i==0){
2040
+					/* $v *  0 -> 0
2041
+					 *  0 * $v -> 0 */
2042
+					if (rve_replace_with_ct_rv(rve, rv)<0)
2043
+						goto error;
2044
+					ret=1;
2045
+				}else if (i==1){
2046
+					/* $v *  1 -> $v
2047
+					 *  1 * $v -> $v */
2048
+					rve_destroy(ct_rve);
2049
+					*rve=*v_rve; /* replace current expr. with $v */
2050
+					pkg_free(v_rve);/* rve_destroy(v_rve) would free
2051
+									   everything*/
2052
+					ret=1;
2053
+				}
2054
+				break;
2055
+			case RVE_DIV_OP:
2056
+				if (i==0){
2057
+					if (ct_rve==rve->left.rve){
2058
+						/* 0 / $v -> 0 */
2059
+						if (rve_replace_with_ct_rv(rve, rv)<0)
2060
+							goto error;
2061
+						ret=1;
2062
+					}else{
2063
+						/* $v / 0 */
2064
+						ERR("RVE divide by 0 at %d,%d\n",
2065
+								ct_rve->fpos.s_line, ct_rve->fpos.s_col);
2066
+					}
2067
+				}else if (i==1){
2068
+					if (ct_rve==rve->right.rve){
2069
+						/* $v / 1 -> $v */
2070
+						rve_destroy(ct_rve);
2071
+						*rve=*v_rve; /* replace current expr. with $v */
2072
+						pkg_free(v_rve);/* rve_destroy(v_rve) would free
2073
+										   everything*/
2074
+						ret=1;
2075
+					}
2076
+				}
2077
+				break;
2078
+			case RVE_MINUS_OP:
2079
+				if (i==0){
2080
+					if (ct_rve==rve->right.rve){
2081
+						/* $v - 0 -> $v */
2082
+						rve_destroy(ct_rve);
2083
+						*rve=*v_rve; /* replace current expr. with $v */
2084
+						pkg_free(v_rve);/* rve_destroy(v_rve) would free
2085
+										   everything*/
2086
+						ret=1;
2087
+					}
2088
+					/* ? 0 - $v -> -($v)  ? */
2089
+				}
2090
+				break;
2091
+			case RVE_BAND_OP:
2092
+				if (i==0){
2093
+					/* $v &  0 -> 0
2094
+					 *  0 & $v -> 0 */
2095
+					if (rve_replace_with_ct_rv(rve, rv)<0)
2096
+						goto error;
2097
+					ret=1;
2098
+				}
2099
+				/* no 0xffffff optimization for now (haven't decide on
2100
+				   the number of bits ) */
2101
+				break;
2102
+			case RVE_BOR_OP:
2103
+				if (i==0){
2104
+					/* $v |  0 -> $v
2105
+					 *  0 | $v -> $v */
2106
+					rve_destroy(ct_rve);
2107
+					*rve=*v_rve; /* replace current expr. with $v */
2108
+					pkg_free(v_rve);/* rve_destroy(v_rve) would free
2109
+									   everything*/
2110
+					ret=1;
2111
+				}
2112
+				break;
2113
+			case RVE_LAND_OP:
2114
+				if (i==0){
2115
+					/* $v &&  0 -> 0
2116
+					 *  0 && $v -> 0 */
2117
+					if (rve_replace_with_ct_rv(rve, rv)<0)
2118
+						goto error;
2119
+					ret=1;
2120
+				}else if (i==1){
2121
+					/* $v &&  1 -> $v
2122
+					 *  1 && $v -> $v */
2123
+					rve_destroy(ct_rve);
2124
+					*rve=*v_rve; /* replace current expr. with $v */
2125
+					pkg_free(v_rve);/* rve_destroy(v_rve) would free
2126
+									   everything*/
2127
+					ret=1;
2128
+				}
2129
+				break;
2130
+			case RVE_LOR_OP:
2131
+				if (i==1){
2132
+					/* $v ||  1 -> 1
2133
+					 *  1 || $v -> 1 */
2134
+					if (rve_replace_with_ct_rv(rve, rv)<0)
2135
+						goto error;
2136
+					ret=1;
2137
+				}else if (i==0){
2138
+					/* $v ||  0 -> $v
2139
+					 *  0 && $v -> $v */
2140
+					rve_destroy(ct_rve);
2141
+					*rve=*v_rve; /* replace current expr. with $v */
2142
+					pkg_free(v_rve);/* rve_destroy(v_rve) would free
2143
+									   everything*/
2144
+					ret=1;
2145
+				}
2146
+				break;
2147
+			case RVE_PLUS_OP:
2148
+				/* we must make sure that this is an int PLUS
2149
+				   (because "foo"+0 is valid => "foo0") */
2150
+				if ((i==0) && (rve_type==RV_INT)){
2151
+					/* $v +  0 -> $v
2152
+					 *  0 + $v -> $v */
2153
+					rve_destroy(ct_rve);
2154
+					*rve=*v_rve; /* replace current expr. with $v */
2155
+					pkg_free(v_rve);/* rve_destroy(v_rve) would free
2156
+									   everything*/
2157
+					ret=1;
2158
+				}
2159
+				break;
2160
+			default:
2161
+				/* do nothing */
2162
+				break;
2163
+		}
2164
+		/* debugging messages */
2165
+		if (ret==1){
2166
+			if (right){
2167
+				if ((rve->op==RVE_RVAL_OP) && (rve->left.rval.type==RV_INT))
2168
+					DBG("FIXUP RVE: (%d,%d-%d,%d) optimized"
2169
+							" op%d($v, %d) -> %d\n", 
2170
+							rve->fpos.s_line, rve->fpos.s_col,
2171
+							rve->fpos.e_line, rve->fpos.s_col,
2172
+							op, i, (int)rve->left.rval.v.l);
2173
+				else
2174
+					DBG("FIXUP RVE: (%d,%d-%d,%d) optimized"
2175
+							" op%d($v, %d) -> $v\n",
2176
+							rve->fpos.s_line, rve->fpos.s_col,
2177
+							rve->fpos.e_line, rve->fpos.s_col,
2178
+							op, i);
2179
+			}else{
2180
+				if ((rve->op==RVE_RVAL_OP) && (rve->left.rval.type==RV_INT))
2181
+					DBG("FIXUP RVE: (%d,%d-%d,%d) optimized"
2182
+							" op%d(%d, $v) -> %d\n", 
2183
+							rve->fpos.s_line, rve->fpos.s_col,
2184
+							rve->fpos.e_line, rve->fpos.s_col,
2185
+							op, i, (int)rve->left.rval.v.l);
2186
+				else
2187
+					DBG("FIXUP RVE: (%d,%d-%d,%d) optimized"
2188
+							" op%d(%d, $v) -> $v\n",
2189
+							rve->fpos.s_line, rve->fpos.s_col,
2190
+							rve->fpos.e_line, rve->fpos.s_col,
2191
+							op, i);
2192
+			}
2193
+		}
2194
+	}
2195
+	/* no optimization for strings for now
2196
+	   (We could optimize $v + "" or ""+$v, but this ""+$v is a way
2197
+	    to force convert $v to str , it might mess up type checking
2198
+	    (e.g. errors w/o optimization and no errors with) and it brings
2199
+	    a very small benefit anyway (it's unlikely we'll see a lot of
2200
+	    "")
2201
+	*/
2202
+	if (rv) rval_destroy(rv);
2203
+	return ret;
2204
+error:
2205
+	if (rv) rval_destroy(rv);
2206
+	return -1;
2207
+}
2208
+
2209
+
2210
+
1944 2211
 /** tries to optimize a rval_expr. */
1945 2212
 static int rve_optimize(struct rval_expr* rve)
1946 2213
 {
... ...
@@ -1987,8 +2254,9 @@ static int rve_optimize(struct rval_expr* rve)
1987 2254
 		rve_optimize(rve->left.rve);
1988 2255
 		rve_optimize(rve->right.rve);
1989 2256
 		if (!rve_check_type(&type, rve, &bad_rve, &bad_type, &exp_type)){
1990
-			ERR("optimization failure, type mismatch in expression, "
2257
+			ERR("optimization failure, type mismatch in expression (%d,%d), "
1991 2258
 					"type %s, but expected %s\n",
2259
+					bad_rve->fpos.s_line, bad_rve->fpos.s_col,
1992 2260
 					rval_type_name(bad_type), rval_type_name(exp_type));
1993 2261
 			return 0;
1994 2262
 		}
... ...
@@ -2010,7 +2278,14 @@ static int rve_optimize(struct rval_expr* rve)
2010 2278
 			rv=0;
2011 2279
 		}
2012 2280
 		
2013
-		/* TODO: $v * 0 => 0; $v * 1 => $v (for *, /, &, |, &&, ||, +, -) */
2281
+		/* $v * 0 => 0; $v * 1 => $v (for *, /, &, |, &&, ||, +, -) */
2282
+		if (rve_opt_01(rve, type)==1){
2283
+			/* success, rve was changed => return now
2284
+			  (since this is recursively invoked the "new" rve
2285
+			   is already optimized) */
2286
+			ret=1;
2287
+			goto end;
2288
+		}
2014 2289
 		
2015 2290
 		/* op(op($v, a), b) => op($v, op(a,b)) */
2016 2291
 		if (rve_is_constant(rve->right.rve)){
... ...
@@ -2170,6 +2445,7 @@ static int rve_optimize(struct rval_expr* rve)
2170 2445
 		}
2171 2446
 		/* op(op($v,a), op($w,b)) => no optimizations for now (TODO) */
2172 2447
 	}
2448
+end:
2173 2449
 	return ret;
2174 2450
 error:
2175 2451
 	if (rv) rval_destroy(rv);