Browse code

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

Andrei Pelinescu-Onciul authored on 10/12/2008 13:43:58
Showing 2 changed files
... ...
@@ -93,6 +93,12 @@ struct route_list branch_rt;
93 93
 struct route_list onsend_rt;
94 94
 
95 95
 
96
+/** script optimization level, useful for debugging.
97
+ *  0 - no optimization
98
+ *  1 - optimize rval expressions
99
+ *  2 - optimize expr elems
100
+ */
101
+int scr_opt_lev=9;
96 102
 
97 103
 inline static void destroy_rlist(struct route_list* rt)
98 104
 {
... ...
@@ -283,6 +289,205 @@ int route_lookup(struct route_list* rt, char* name)
283 289
 int fix_actions(struct action* a); /*fwd declaration*/
284 290
 
285 291
 
292
+/** optimize the left side of a struct expr.
293
+ *  @return 1 if optimized, 0 if not and -1 on error
294
+ */
295
+static int exp_optimize_left(struct expr* exp)
296
+{
297
+	struct rval_expr* rve;
298
+	struct rvalue* rval;
299
+	int old_type, old_op;
300
+	int ret;
301
+	
302
+	ret=0;
303
+	if (exp->type!=ELEM_T)
304
+		return 0;
305
+	old_type=exp->l_type;
306
+	old_op=exp->op;
307
+	if (exp->l_type==RVEXP_O){
308
+		rve=exp->l.param;
309
+		/* rve should be previously fixed/optimized */
310
+		/* optimize exp (rval(val)) -> exp(val) */
311
+		if (rve->op==RVE_RVAL_OP){
312
+			rval=&rve->left.rval;
313
+			switch(rval->type){
314
+				case RV_INT:
315
+					if (exp->op==NO_OP){
316
+						exp->l_type=NUMBER_O;
317
+						exp->l.param=0;
318
+						exp->r_type=NUMBER_ST;
319
+						exp->r.numval=rval->v.l;
320
+						rval_destroy(rval);
321
+						pkg_free(rve);
322
+						ret=1;
323
+					}
324
+					break;
325
+				case RV_STR:
326
+					/* string evaluated in expression context - not
327
+					   supported */
328
+					break;
329
+				case RV_BEXPR:
330
+					if (exp->op==NO_OP){
331
+						/* replace the current expr. */
332
+						*exp=*(rval->v.bexpr);
333
+						rval_destroy(rval);
334
+						pkg_free(rve);
335
+						ret=1;
336
+					};
337
+					break;
338
+				case RV_ACTION_ST:
339
+					if (exp->op==NO_OP){
340
+						exp->l_type=ACTION_O;
341
+						exp->l.param=0;
342
+						exp->r_type=ACTION_ST;
343
+						exp->r.param=rval->v.action;
344
+						rval_destroy(rval);
345
+						pkg_free(rve);
346
+						ret=1;
347
+					}
348
+					break;
349
+				case RV_SEL:
350
+					exp->l.select=pkg_malloc(sizeof(*exp->l.select));
351
+					if (exp->l.select){
352
+						exp->l_type=SELECT_O;
353
+						*exp->l.select=rval->v.sel;
354
+						rval_destroy(rval);
355
+						pkg_free(rve);
356
+						ret=1;
357
+					}else
358
+						ret=-1;
359
+					break;
360
+				case RV_AVP:
361
+					exp->l.attr=pkg_malloc(sizeof(*exp->l.attr));
362
+					if (exp->l.attr){
363
+						exp->l_type=AVP_O;
364
+						*exp->l.attr=rval->v.avps;
365
+						rval_destroy(rval);
366
+						pkg_free(rve);
367
+						ret=1;
368
+					}else
369
+						ret=-1;
370
+					break;
371
+				case RV_PVAR:
372
+					exp->l.param=pkg_malloc(sizeof(pv_spec_t));
373
+					if (exp->l.param){
374
+						exp->l_type=PVAR_O;
375
+						*((pv_spec_t*)exp->l.param)=rval->v.pvs;
376
+						rval_destroy(rval);
377
+						pkg_free(rve);
378
+						ret=1;
379
+					}else
380
+						ret=-1;
381
+					break;
382
+				case RV_NONE:
383
+					break;
384
+			}
385
+		}
386
+	}
387
+	if (ret>0)
388
+		DBG("left EXP optimized succesfully: %d op %d to %d op %d\n",
389
+			old_type, old_op, exp->l_type, exp->op);
390
+	return ret;
391
+}
392
+
393
+
394
+
395
+/** optimize the left side of a struct expr.
396
+ *  @return 1 if optimized, 0 if not and -1 on error
397
+ */
398
+static int exp_optimize_right(struct expr* exp)
399
+{
400
+	struct rval_expr* rve;
401
+	struct rvalue* rval;
402
+	int old_type, old_op;
403
+	int ret;
404
+	
405
+	ret=0;
406
+	if ((exp->type!=ELEM_T) ||(exp->op==NO_OP))
407
+		return 0;
408
+	old_type=exp->r_type;
409
+	old_op=exp->op;
410
+	if (exp->r_type==RVE_ST){
411
+		rve=exp->r.param;
412
+		/* rve should be previously fixed/optimized */
413
+		/* optimize exp (rval(val)) -> exp(val) */
414
+		if (rve->op==RVE_RVAL_OP){
415
+			rval=&rve->left.rval;
416
+			switch(rval->type){
417
+				case RV_INT:
418
+					exp->r_type=NUMBER_ST;
419
+					exp->r.numval=rval->v.l;
420
+					rval_destroy(rval);
421
+					pkg_free(rve);
422
+					ret=1;
423
+					break;
424
+				case RV_STR:
425
+					exp->r.str.s=pkg_malloc(rval->v.s.len+1);
426
+					if (exp->r.str.s){
427
+						exp->r.str.len=rval->v.s.len;
428
+						memcpy(exp->r.str.s, rval->v.s.s, rval->v.s.len);
429
+						exp->r_type=STRING_ST;
430
+						rval_destroy(rval);
431
+						pkg_free(rve);
432
+						ret=1;
433
+					}else
434
+						ret=-1;
435
+					break;
436
+				case RV_BEXPR:
437
+					/* cannot be optimized further, is an exp_elem
438
+					   which is not constant */
439
+					break;
440
+				case RV_ACTION_ST:
441
+					/* cannot be optimized further, is not constant and
442
+					  eval_elem() does not support ACTION_ST for op!=NO_OP*/
443
+					break;
444
+				case RV_SEL:
445
+					exp->r.select=pkg_malloc(sizeof(*exp->l.select));
446
+					if (exp->r.select){
447
+						exp->r_type=SELECT_ST;
448
+						*exp->r.select=rval->v.sel;
449
+						rval_destroy(rval);
450
+						pkg_free(rve);
451
+						ret=1;
452
+					}else
453
+						ret=-1;
454
+					break;
455
+				case RV_AVP:
456
+					exp->r.attr=pkg_malloc(sizeof(*exp->l.attr));
457
+					if (exp->r.attr){
458
+						exp->r_type=AVP_ST;
459
+						*exp->r.attr=rval->v.avps;
460
+						rval_destroy(rval);
461
+						pkg_free(rve);
462
+						ret=1;
463
+					}else
464
+						ret=-1;
465
+					break;
466
+				case RV_PVAR:
467
+					exp->r.param=pkg_malloc(sizeof(pv_spec_t));
468
+					if (exp->r.param){
469
+						exp->r_type=PVAR_ST;
470
+						*((pv_spec_t*)exp->r.param)=rval->v.pvs;
471
+						rval_destroy(rval);
472
+						pkg_free(rve);
473
+						ret=1;
474
+					}else
475
+						ret=-1;
476
+					break;
477
+				case RV_NONE:
478
+					ret=-1;
479
+					break;
480
+			}
481
+		}
482
+	}
483
+	if (ret>0)
484
+		DBG("right EXP optimized succesfully: %d op %d to %d op %d\n",
485
+			old_type, old_op, exp->r_type, exp->op);
486
+	return ret;
487
+}
488
+
489
+
490
+
286 491
 /* traverses an expr tree and compiles the REs where necessary)
287 492
  * returns: 0 for ok, <0 if errors */
288 493
 int fix_expr(struct expr* exp)
... ...
@@ -382,12 +587,16 @@ int fix_expr(struct expr* exp)
382 587
 					ERR("Unable to fix left rval expression\n");
383 588
 					return ret;
384 589
 				}
590
+				if (scr_opt_lev>=2)
591
+					exp_optimize_left(exp);
385 592
 			}
386 593
 			if (exp->r_type==RVE_ST){
387 594
 				if ((ret=fix_rval_expr(&exp->r.param))<0){
388 595
 					ERR("Unable to fix right rval expression\n");
389 596
 					return ret;
390 597
 				}
598
+				if (scr_opt_lev>=2)
599
+					exp_optimize_right(exp);
391 600
 			}
392 601
 			/* PVAR don't need fixing */
393 602
 			ret=0;
... ...
@@ -934,11 +1143,28 @@ inline static int comp_rve(int op, struct rval_expr* rve, int rtype,
934 1143
 							struct run_act_ctx* h)
935 1144
 {
936 1145
 	int i;
1146
+	struct rvalue* rv;
1147
+	struct rvalue* rv1;
1148
+	struct rval_cache c1;
937 1149
 	
938
-	if (unlikely(rval_expr_eval_int(h,  msg, &i, rve)<0)){
1150
+	rval_cache_init(&c1);
1151
+	if (unlikely(rval_expr_eval_rvint(h,  msg, &rv, &i, rve, &c1)<0)){
939 1152
 		ERR("failure evaluating expression: bad type\n");
940 1153
 		i=0; /* false */
1154
+		goto int_expr;
1155
+	}
1156
+	if (unlikely(rv)){
1157
+		/* no int => str */
1158
+		rv1=rval_convert(h, msg, RV_STR, rv, &c1);
1159
+		i=comp_str(op, &rv1->v.s, rtype, r, msg, h);
1160
+		rval_destroy(rv1);
1161
+		rval_destroy(rv);
1162
+		rval_cache_clean(&c1);
1163
+		return i;
941 1164
 	}
1165
+	/* expr evaluated to int */
1166
+int_expr:
1167
+	rval_cache_clean(&c1);
942 1168
 	if (op==NO_OP)
943 1169
 		return !(!i); /* transform it into { 0, 1 } */
944 1170
 	return comp_num(op, i, rtype, r, msg, h);
... ...
@@ -59,6 +59,8 @@ extern struct route_list failure_rt;
59 59
 extern struct route_list branch_rt;
60 60
 extern struct route_list onsend_rt;
61 61
 
62
+/* script optimization level */
63
+extern int scr_opt_lev;
62 64
 
63 65
 int init_routes();
64 66
 void destroy_routes();