- different operators for integer + (RVE_IPLUS_OP) and str plus
(RVE_CONCAT_OP). The generic plus (RVE_PLUS_OP) is still
present, the new operators are only used in internal
optimizations (see below) for now.
- if an expression involving the generic '+' is always of type int
or str, replace the generic '+' with the interger or string
version (makes further optimizations possible).
... | ... |
@@ -385,10 +385,13 @@ enum rval_type rve_guess_type( struct rval_expr* rve) |
385 | 385 |
case RVE_LTE_OP: |
386 | 386 |
case RVE_EQ_OP: |
387 | 387 |
case RVE_DIFF_OP: |
388 |
+ case RVE_IPLUS_OP: |
|
388 | 389 |
return RV_INT; |
389 | 390 |
case RVE_PLUS_OP: |
390 | 391 |
/* '+' evaluates to the type of the left operand */ |
391 | 392 |
return rve_guess_type(rve->left.rve); |
393 |
+ case RVE_CONCAT_OP: |
|
394 |
+ return RV_STR; |
|
392 | 395 |
case RVE_NONE_OP: |
393 | 396 |
break; |
394 | 397 |
} |
... | ... |
@@ -437,6 +440,8 @@ int rve_is_constant(struct rval_expr* rve) |
437 | 440 |
case RVE_EQ_OP: |
438 | 441 |
case RVE_DIFF_OP: |
439 | 442 |
case RVE_PLUS_OP: |
443 |
+ case RVE_IPLUS_OP: |
|
444 |
+ case RVE_CONCAT_OP: |
|
440 | 445 |
return rve_is_constant(rve->left.rve) && |
441 | 446 |
rve_is_constant(rve->right.rve); |
442 | 447 |
case RVE_NONE_OP: |
... | ... |
@@ -473,6 +478,8 @@ static int rve_op_unary(enum rval_expr_op op) |
473 | 478 |
case RVE_EQ_OP: |
474 | 479 |
case RVE_DIFF_OP: |
475 | 480 |
case RVE_PLUS_OP: |
481 |
+ case RVE_IPLUS_OP: |
|
482 |
+ case RVE_CONCAT_OP: |
|
476 | 483 |
return 0; |
477 | 484 |
case RVE_NONE_OP: |
478 | 485 |
return -1; |
... | ... |
@@ -532,6 +539,7 @@ int rve_check_type(enum rval_type* type, struct rval_expr* rve, |
532 | 539 |
case RVE_GTE_OP: |
533 | 540 |
case RVE_LT_OP: |
534 | 541 |
case RVE_LTE_OP: |
542 |
+ case RVE_IPLUS_OP: |
|
535 | 543 |
*type=RV_INT; |
536 | 544 |
if (rve_check_type(&type1, rve->left.rve, bad_rve, bad_t, exp_t)){ |
537 | 545 |
if (type1==RV_STR){ |
... | ... |
@@ -587,6 +595,28 @@ int rve_check_type(enum rval_type* type, struct rval_expr* rve, |
587 | 595 |
return 1; |
588 | 596 |
} |
589 | 597 |
} |
598 |
+ case RVE_CONCAT_OP: |
|
599 |
+ *type=RV_STR; |
|
600 |
+ if (rve_check_type(&type1, rve->left.rve, bad_rve, bad_t, exp_t)){ |
|
601 |
+ if (rve_check_type(&type2, rve->right.rve, bad_rve, bad_t, |
|
602 |
+ exp_t)){ |
|
603 |
+ if ((type2!=type1) && (type1!=RV_NONE) && |
|
604 |
+ (type2!=RV_NONE) && |
|
605 |
+ !(type1==RV_STR && type2==RV_INT)){ |
|
606 |
+ if (bad_rve) *bad_rve=rve->right.rve; |
|
607 |
+ if (bad_t) *bad_t=type2; |
|
608 |
+ if (exp_t) *exp_t=type1; |
|
609 |
+ return 0; |
|
610 |
+ } |
|
611 |
+ if (type1==RV_INT){ |
|
612 |
+ if (bad_rve) *bad_rve=rve->left.rve; |
|
613 |
+ if (bad_t) *bad_t=type1; |
|
614 |
+ if (exp_t) *exp_t=RV_STR; |
|
615 |
+ return 0; |
|
616 |
+ } |
|
617 |
+ return 1; |
|
618 |
+ } |
|
619 |
+ } |
|
590 | 620 |
case RVE_NONE_OP: |
591 | 621 |
break; |
592 | 622 |
} |
... | ... |
@@ -936,6 +966,7 @@ inline static int int_intop2(int* res, enum rval_expr_op op, int v1, int v2) |
936 | 966 |
{ |
937 | 967 |
switch(op){ |
938 | 968 |
case RVE_PLUS_OP: |
969 |
+ case RVE_IPLUS_OP: |
|
939 | 970 |
*res=v1+v2; |
940 | 971 |
break; |
941 | 972 |
case RVE_MINUS_OP: |
... | ... |
@@ -981,6 +1012,10 @@ inline static int int_intop2(int* res, enum rval_expr_op op, int v1, int v2) |
981 | 1012 |
case RVE_DIFF_OP: |
982 | 1013 |
*res=v1 != v2; |
983 | 1014 |
break; |
1015 |
+ case RVE_CONCAT_OP: |
|
1016 |
+ *res=0; |
|
1017 |
+ /* invalid operand for int */ |
|
1018 |
+ return -1; |
|
984 | 1019 |
default: |
985 | 1020 |
BUG("rv unsupported intop %d\n", op); |
986 | 1021 |
return -1; |
... | ... |
@@ -1286,6 +1321,7 @@ int rval_expr_eval_int( struct run_act_ctx* h, struct sip_msg* msg, |
1286 | 1321 |
case RVE_DIV_OP: |
1287 | 1322 |
case RVE_MINUS_OP: |
1288 | 1323 |
case RVE_PLUS_OP: |
1324 |
+ case RVE_IPLUS_OP: |
|
1289 | 1325 |
case RVE_BOR_OP: |
1290 | 1326 |
case RVE_BAND_OP: |
1291 | 1327 |
case RVE_GT_OP: |
... | ... |
@@ -1376,6 +1412,10 @@ int rval_expr_eval_int( struct run_act_ctx* h, struct sip_msg* msg, |
1376 | 1412 |
rval_destroy(rv2); |
1377 | 1413 |
break; |
1378 | 1414 |
#endif |
1415 |
+ case RVE_CONCAT_OP: |
|
1416 |
+ *res=0; |
|
1417 |
+ ret=-1; |
|
1418 |
+ break; |
|
1379 | 1419 |
case RVE_NONE_OP: |
1380 | 1420 |
/*default:*/ |
1381 | 1421 |
BUG("invalid rval int expression operation %d\n", rve->op); |
... | ... |
@@ -1446,6 +1486,7 @@ int rval_expr_eval_rvint( struct run_act_ctx* h, |
1446 | 1486 |
case RVE_LTE_OP: |
1447 | 1487 |
case RVE_EQ_OP: |
1448 | 1488 |
case RVE_DIFF_OP: |
1489 |
+ case RVE_IPLUS_OP: |
|
1449 | 1490 |
/* operator forces integer type */ |
1450 | 1491 |
ret=rval_expr_eval_int(h, msg, res_i, rve); |
1451 | 1492 |
*res_rv=0; |
... | ... |
@@ -1479,6 +1520,10 @@ int rval_expr_eval_rvint( struct run_act_ctx* h, |
1479 | 1520 |
} |
1480 | 1521 |
rval_cache_clean(&c1); |
1481 | 1522 |
break; |
1523 |
+ case RVE_CONCAT_OP: |
|
1524 |
+ *res_rv=rval_expr_eval(h, msg, rve); |
|
1525 |
+ ret=-(*res_rv==0); |
|
1526 |
+ break; |
|
1482 | 1527 |
case RVE_NONE_OP: |
1483 | 1528 |
/*default:*/ |
1484 | 1529 |
BUG("invalid rval expression operation %d\n", rve->op); |
... | ... |
@@ -1535,6 +1580,7 @@ struct rvalue* rval_expr_eval(struct run_act_ctx* h, struct sip_msg* msg, |
1535 | 1580 |
case RVE_LTE_OP: |
1536 | 1581 |
case RVE_EQ_OP: |
1537 | 1582 |
case RVE_DIFF_OP: |
1583 |
+ case RVE_IPLUS_OP: |
|
1538 | 1584 |
/* operator forces integer type */ |
1539 | 1585 |
r=rval_expr_eval_int(h, msg, &i, rve); |
1540 | 1586 |
if (likely(r==0)){ |
... | ... |
@@ -1603,6 +1649,19 @@ struct rvalue* rval_expr_eval(struct run_act_ctx* h, struct sip_msg* msg, |
1603 | 1649 |
} |
1604 | 1650 |
rval_cache_clean(&c1); |
1605 | 1651 |
break; |
1652 |
+ case RVE_CONCAT_OP: |
|
1653 |
+ rv1=rval_expr_eval(h, msg, rve->left.rve); |
|
1654 |
+ if (unlikely(rv1==0)){ |
|
1655 |
+ ERR("rval expression evaluation failed\n"); |
|
1656 |
+ goto error; |
|
1657 |
+ } |
|
1658 |
+ rv2=rval_expr_eval(h, msg, rve->right.rve); |
|
1659 |
+ if (unlikely(rv2==0)){ |
|
1660 |
+ ERR("rval expression evaluation failed\n"); |
|
1661 |
+ goto error; |
|
1662 |
+ } |
|
1663 |
+ ret=rval_str_add2(h, msg, rv1, 0, rv2, 0); |
|
1664 |
+ break; |
|
1606 | 1665 |
case RVE_NONE_OP: |
1607 | 1666 |
/*default:*/ |
1608 | 1667 |
BUG("invalid rval expression operation %d\n", rve->op); |
... | ... |
@@ -1767,8 +1826,10 @@ struct rval_expr* mk_rval_expr2(enum rval_expr_op op, struct rval_expr* rve1, |
1767 | 1826 |
case RVE_LT_OP: |
1768 | 1827 |
case RVE_LTE_OP: |
1769 | 1828 |
case RVE_PLUS_OP: |
1829 |
+ case RVE_IPLUS_OP: |
|
1770 | 1830 |
case RVE_EQ_OP: |
1771 | 1831 |
case RVE_DIFF_OP: |
1832 |
+ case RVE_CONCAT_OP: |
|
1772 | 1833 |
break; |
1773 | 1834 |
default: |
1774 | 1835 |
BUG("unsupported operator %d\n", op); |
... | ... |
@@ -1802,6 +1863,8 @@ static int rve_op_is_assoc(enum rval_expr_op op) |
1802 | 1863 |
case RVE_MINUS_OP: |
1803 | 1864 |
return 0; |
1804 | 1865 |
case RVE_PLUS_OP: |
1866 |
+ case RVE_IPLUS_OP: |
|
1867 |
+ case RVE_CONCAT_OP: |
|
1805 | 1868 |
case RVE_MUL_OP: |
1806 | 1869 |
case RVE_BAND_OP: |
1807 | 1870 |
case RVE_BOR_OP: |
... | ... |
@@ -1838,6 +1901,7 @@ static int rve_op_is_commutative(enum rval_expr_op op, enum rval_type type) |
1838 | 1901 |
return 0; |
1839 | 1902 |
case RVE_PLUS_OP: |
1840 | 1903 |
return type==RV_INT; /* commutative only for INT*/ |
1904 |
+ case RVE_IPLUS_OP: |
|
1841 | 1905 |
case RVE_MUL_OP: |
1842 | 1906 |
case RVE_BAND_OP: |
1843 | 1907 |
case RVE_BOR_OP: |
... | ... |
@@ -1851,6 +1915,7 @@ static int rve_op_is_commutative(enum rval_expr_op op, enum rval_type type) |
1851 | 1915 |
case RVE_LTE_OP: |
1852 | 1916 |
case RVE_EQ_OP: |
1853 | 1917 |
case RVE_DIFF_OP: |
1918 |
+ case RVE_CONCAT_OP: |
|
1854 | 1919 |
return 0; |
1855 | 1920 |
} |
1856 | 1921 |
return 0; |
... | ... |
@@ -2158,9 +2223,10 @@ static int rve_opt_01(struct rval_expr* rve, enum rval_type rve_type) |
2158 | 2223 |
} |
2159 | 2224 |
break; |
2160 | 2225 |
case RVE_PLUS_OP: |
2226 |
+ case RVE_IPLUS_OP: |
|
2161 | 2227 |
/* we must make sure that this is an int PLUS |
2162 | 2228 |
(because "foo"+0 is valid => "foo0") */ |
2163 |
- if ((i==0) && (rve_type==RV_INT)){ |
|
2229 |
+ if ((i==0) && ((op==RVE_IPLUS_OP)||(rve_type==RV_INT))){ |
|
2164 | 2230 |
/* $v + 0 -> $v |
2165 | 2231 |
* 0 + $v -> $v */ |
2166 | 2232 |
rve_destroy(ct_rve); |
... | ... |
@@ -2206,14 +2272,32 @@ static int rve_opt_01(struct rval_expr* rve, enum rval_type rve_type) |
2206 | 2272 |
op, i); |
2207 | 2273 |
} |
2208 | 2274 |
} |
2209 |
- } |
|
2210 |
- /* no optimization for strings for now |
|
2275 |
+ }else if (rv->type==RV_STR){ |
|
2276 |
+ switch(op){ |
|
2277 |
+ case RVE_CONCAT_OP: |
|
2278 |
+ if (rv->v.s.len==0){ |
|
2279 |
+ /* $v . "" -> $v |
|
2280 |
+ "" . $v -> $v */ |
|
2281 |
+ rve_destroy(ct_rve); |
|
2282 |
+ pos=rve->fpos; |
|
2283 |
+ *rve=*v_rve; /* replace current expr. with $v */ |
|
2284 |
+ rve->fpos=pos; |
|
2285 |
+ pkg_free(v_rve);/* rve_destroy(v_rve) would free |
|
2286 |
+ everything*/ |
|
2287 |
+ ret=1; |
|
2288 |
+ } |
|
2289 |
+ break; |
|
2290 |
+ default: |
|
2291 |
+ break; |
|
2292 |
+ } |
|
2293 |
+ /* no optimization for generic RVE_PLUS_OP for now, only for RVE_CONCAT_OP |
|
2211 | 2294 |
(We could optimize $v + "" or ""+$v, but this ""+$v is a way |
2212 | 2295 |
to force convert $v to str , it might mess up type checking |
2213 | 2296 |
(e.g. errors w/o optimization and no errors with) and it brings |
2214 | 2297 |
a very small benefit anyway (it's unlikely we'll see a lot of |
2215 | 2298 |
"") |
2216 | 2299 |
*/ |
2300 |
+ } |
|
2217 | 2301 |
if (rv) rval_destroy(rv); |
2218 | 2302 |
return ret; |
2219 | 2303 |
error: |
... | ... |
@@ -2232,7 +2316,7 @@ static int rve_optimize(struct rval_expr* rve) |
2232 | 2316 |
enum rval_expr_op op; |
2233 | 2317 |
int flags; |
2234 | 2318 |
struct rval_expr tmp_rve; |
2235 |
- enum rval_type type; |
|
2319 |
+ enum rval_type type, l_type; |
|
2236 | 2320 |
struct rval_expr* bad_rve; |
2237 | 2321 |
enum rval_type bad_type, exp_type; |
2238 | 2322 |
|
... | ... |
@@ -2285,7 +2369,7 @@ static int rve_optimize(struct rval_expr* rve) |
2285 | 2369 |
rv->v.l=-rv->v.l; |
2286 | 2370 |
if (rve_replace_with_ct_rv(rve->right.rve, rv)<0) |
2287 | 2371 |
goto error; |
2288 |
- rve->op=RVE_PLUS_OP; |
|
2372 |
+ rve->op=RVE_IPLUS_OP; |
|
2289 | 2373 |
DBG("FIXUP RVE: optimized $v - a into $v + (%d)\n", |
2290 | 2374 |
(int)rve->right.rve->left.rval.v.l); |
2291 | 2375 |
} |
... | ... |
@@ -2293,6 +2377,22 @@ static int rve_optimize(struct rval_expr* rve) |
2293 | 2377 |
rv=0; |
2294 | 2378 |
} |
2295 | 2379 |
|
2380 |
+ /* e1 PLUS_OP e2 -> change op if we know e1 basic type */ |
|
2381 |
+ if (rve->op==RVE_PLUS_OP){ |
|
2382 |
+ l_type=rve_guess_type(rve->left.rve); |
|
2383 |
+ if (l_type==RV_INT){ |
|
2384 |
+ rve->op=RVE_IPLUS_OP; |
|
2385 |
+ DBG("FIXUP RVE (%d,%d-%d,%d): changed + into interger plus\n", |
|
2386 |
+ rve->fpos.s_line, rve->fpos.s_col, |
|
2387 |
+ rve->fpos.e_line, rve->fpos.e_col); |
|
2388 |
+ }else if (l_type==RV_STR){ |
|
2389 |
+ rve->op=RVE_CONCAT_OP; |
|
2390 |
+ DBG("FIXUP RVE (%d,%d-%d,%d): changed + into string concat\n", |
|
2391 |
+ rve->fpos.s_line, rve->fpos.s_col, |
|
2392 |
+ rve->fpos.e_line, rve->fpos.e_col); |
|
2393 |
+ } |
|
2394 |
+ } |
|
2395 |
+ |
|
2296 | 2396 |
/* $v * 0 => 0; $v * 1 => $v (for *, /, &, |, &&, ||, +, -) */ |
2297 | 2397 |
if (rve_opt_01(rve, type)==1){ |
2298 | 2398 |
/* success, rve was changed => return now |
... | ... |
@@ -2510,8 +2610,10 @@ int fix_rval_expr(void** p) |
2510 | 2610 |
case RVE_LT_OP: |
2511 | 2611 |
case RVE_LTE_OP: |
2512 | 2612 |
case RVE_PLUS_OP: |
2613 |
+ case RVE_IPLUS_OP: |
|
2513 | 2614 |
case RVE_EQ_OP: |
2514 | 2615 |
case RVE_DIFF_OP: |
2616 |
+ case RVE_CONCAT_OP: |
|
2515 | 2617 |
ret=fix_rval_expr((void**)&rve->left.rve); |
2516 | 2618 |
if (ret<0) return ret; |
2517 | 2619 |
ret=fix_rval_expr((void**)&rve->right.rve); |
... | ... |
@@ -59,10 +59,12 @@ enum rval_expr_op{ |
59 | 59 |
RVE_GTE_OP, /* 2 members, returns left >= right */ |
60 | 60 |
RVE_LT_OP, /* 2 members, returns left < right */ |
61 | 61 |
RVE_LTE_OP, /* 2 members, returns left <= right */ |
62 |
+ RVE_IPLUS_OP, /* 2 members, integer +, returns int(a)+int(b) */ |
|
62 | 63 |
/* common int & str */ |
63 |
- RVE_PLUS_OP, /* 2 members, returns left + right (int or str)*/ |
|
64 |
+ RVE_PLUS_OP, /* generic plus (int or str) returns left + right */ |
|
64 | 65 |
RVE_EQ_OP, /* 2 members, returns left == right (int)*/ |
65 | 66 |
RVE_DIFF_OP, /* 2 members, returns left != right (int)*/ |
67 |
+ RVE_CONCAT_OP,/* string concatenation, returns left . right */ |
|
66 | 68 |
/* str only */ |
67 | 69 |
}; |
68 | 70 |
|