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 283
 int fix_actions(struct action* a); /*fwd declaration*/
284 284
 
285 285
 
286
+/** optimize the left side of a struct expr.
287
+ *  @return 1 if optimized, 0 if not and -1 on error
288
+ */
289
+static int exp_optimize_left(struct expr* exp)
290
+{
291
+	struct rval_expr* rve;
292
+	struct rvalue* rval;
293
+	int old_type, old_op;
294
+	int ret;
295
+	
296
+	ret=0;
297
+	if (exp->type!=ELEM_T)
298
+		return 0;
299
+	old_type=exp->l_type;
300
+	old_op=exp->op;
301
+	if (exp->l_type==RVEXP_O){
302
+		rve=exp->l.param;
303
+		/* rve should be previously fixed/optimized */
304
+		/* optimize exp (rval(val)) -> exp(val) */
305
+		if (rve->op==RVE_RVAL_OP){
306
+			rval=&rve->left.rval;
307
+			switch(rval->type){
308
+				case RV_INT:
309
+					if (exp->op==NO_OP){
310
+						exp->l_type=NUMBER_O;
311
+						exp->l.param=0;
312
+						exp->r_type=NUMBER_ST;
313
+						exp->r.numval=rval->v.l;
314
+						rval_destroy(rval);
315
+						pkg_free(rve);
316
+						ret=1;
317
+					}
318
+					break;
319
+				case RV_STR:
320
+					/* string evaluated in expression context - not
321
+					   supported */
322
+					break;
323
+				case RV_BEXPR:
324
+					if (exp->op==NO_OP){
325
+						/* replace the current expr. */
326
+						*exp=*(rval->v.bexpr);
327
+						rval_destroy(rval);
328
+						pkg_free(rve);
329
+						ret=1;
330
+					};
331
+					break;
332
+				case RV_ACTION_ST:
333
+					if (exp->op==NO_OP){
334
+						exp->l_type=ACTION_O;
335
+						exp->l.param=0;
336
+						exp->r_type=ACTION_ST;
337
+						exp->r.param=rval->v.action;
338
+						rval_destroy(rval);
339
+						pkg_free(rve);
340
+						ret=1;
341
+					}
342
+					break;
343
+				case RV_SEL:
344
+					exp->l.select=pkg_malloc(sizeof(*exp->l.select));
345
+					if (exp->l.select){
346
+						exp->l_type=SELECT_O;
347
+						*exp->l.select=rval->v.sel;
348
+						rval_destroy(rval);
349
+						pkg_free(rve);
350
+						ret=1;
351
+					}else
352
+						ret=-1;
353
+					break;
354
+				case RV_AVP:
355
+					exp->l.attr=pkg_malloc(sizeof(*exp->l.attr));
356
+					if (exp->l.attr){
357
+						exp->l_type=AVP_O;
358
+						*exp->l.attr=rval->v.avps;
359
+						rval_destroy(rval);
360
+						pkg_free(rve);
361
+						ret=1;
362
+					}else
363
+						ret=-1;
364
+					break;
365
+				case RV_PVAR:
366
+					exp->l.param=pkg_malloc(sizeof(pv_spec_t));
367
+					if (exp->l.param){
368
+						exp->l_type=PVAR_O;
369
+						*((pv_spec_t*)exp->l.param)=rval->v.pvs;
370
+						rval_destroy(rval);
371
+						pkg_free(rve);
372
+						ret=1;
373
+					}else
374
+						ret=-1;
375
+					break;
376
+				case RV_NONE:
377
+					break;
378
+			}
379
+		}
380
+	}
381
+	if (ret>0)
382
+		DBG("left EXP optimized succesfully: %d op %d to %d op %d\n",
383
+			old_type, old_op, exp->l_type, exp->op);
384
+	return ret;
385
+}
386
+
387
+
388
+
389
+/** optimize the left side of a struct expr.
390
+ *  @return 1 if optimized, 0 if not and -1 on error
391
+ */
392
+static int exp_optimize_right(struct expr* exp)
393
+{
394
+	struct rval_expr* rve;
395
+	struct rvalue* rval;
396
+	int old_type, old_op;
397
+	int ret;
398
+	
399
+	ret=0;
400
+	if ((exp->type!=ELEM_T) ||(exp->op==NO_OP))
401
+		return 0;
402
+	old_type=exp->r_type;
403
+	old_op=exp->op;
404
+	if (exp->r_type==RVE_ST){
405
+		rve=exp->r.param;
406
+		/* rve should be previously fixed/optimized */
407
+		/* optimize exp (rval(val)) -> exp(val) */
408
+		if (rve->op==RVE_RVAL_OP){
409
+			rval=&rve->left.rval;
410
+			switch(rval->type){
411
+				case RV_INT:
412
+					exp->r_type=NUMBER_ST;
413
+					exp->r.numval=rval->v.l;
414
+					rval_destroy(rval);
415
+					pkg_free(rve);
416
+					ret=1;
417
+					break;
418
+				case RV_STR:
419
+					exp->r.str.s=pkg_malloc(rval->v.s.len+1);
420
+					if (exp->r.str.s){
421
+						exp->r.str.len=rval->v.s.len;
422
+						memcpy(exp->r.str.s, rval->v.s.s, rval->v.s.len);
423
+						exp->r_type=STRING_ST;
424
+						rval_destroy(rval);
425
+						pkg_free(rve);
426
+						ret=1;
427
+					}else
428
+						ret=-1;
429
+					break;
430
+				case RV_BEXPR:
431
+					/* cannot be optimized further, is an exp_elem
432
+					   which is not constant */
433
+					break;
434
+				case RV_ACTION_ST:
435
+					/* cannot be optimized further, is not constant and
436
+					  eval_elem() does not support ACTION_ST for op!=NO_OP*/
437
+					break;
438
+				case RV_SEL:
439
+					exp->r.select=pkg_malloc(sizeof(*exp->l.select));
440
+					if (exp->r.select){
441
+						exp->r_type=SELECT_ST;
442
+						*exp->r.select=rval->v.sel;
443
+						rval_destroy(rval);
444
+						pkg_free(rve);
445
+						ret=1;
446
+					}else
447
+						ret=-1;
448
+					break;
449
+				case RV_AVP:
450
+					exp->r.attr=pkg_malloc(sizeof(*exp->l.attr));
451
+					if (exp->r.attr){
452
+						exp->r_type=AVP_ST;
453
+						*exp->r.attr=rval->v.avps;
454
+						rval_destroy(rval);
455
+						pkg_free(rve);
456
+						ret=1;
457
+					}else
458
+						ret=-1;
459
+					break;
460
+				case RV_PVAR:
461
+					exp->r.param=pkg_malloc(sizeof(pv_spec_t));
462
+					if (exp->r.param){
463
+						exp->r_type=PVAR_ST;
464
+						*((pv_spec_t*)exp->r.param)=rval->v.pvs;
465
+						rval_destroy(rval);
466
+						pkg_free(rve);
467
+						ret=1;
468
+					}else
469
+						ret=-1;
470
+					break;
471
+				case RV_NONE:
472
+					ret=-1;
473
+					break;
474
+			}
475
+		}
476
+	}
477
+	if (ret>0)
478
+		DBG("right EXP optimized succesfully: %d op %d to %d op %d\n",
479
+			old_type, old_op, exp->r_type, exp->op);
480
+	return ret;
481
+}
482
+
483
+
484
+
286 485
 /* traverses an expr tree and compiles the REs where necessary)
287 486
  * returns: 0 for ok, <0 if errors */
288 487
 int fix_expr(struct expr* exp)
... ...
@@ -382,12 +587,16 @@ int fix_expr(struct expr* exp)
382 382
 					ERR("Unable to fix left rval expression\n");
383 383
 					return ret;
384 384
 				}
385
+				if (scr_opt_lev>=2)
386
+					exp_optimize_left(exp);
385 387
 			}
386 388
 			if (exp->r_type==RVE_ST){
387 389
 				if ((ret=fix_rval_expr(&exp->r.param))<0){
388 390
 					ERR("Unable to fix right rval expression\n");
389 391
 					return ret;
390 392
 				}
393
+				if (scr_opt_lev>=2)
394
+					exp_optimize_right(exp);
391 395
 			}
392 396
 			/* PVAR don't need fixing */
393 397
 			ret=0;
... ...
@@ -934,11 +1143,28 @@ inline static int comp_rve(int op, struct rval_expr* rve, int rtype,
934 934
 							struct run_act_ctx* h)
935 935
 {
936 936
 	int i;
937
+	struct rvalue* rv;
938
+	struct rvalue* rv1;
939
+	struct rval_cache c1;
937 940
 	
938
-	if (unlikely(rval_expr_eval_int(h,  msg, &i, rve)<0)){
941
+	rval_cache_init(&c1);
942
+	if (unlikely(rval_expr_eval_rvint(h,  msg, &rv, &i, rve, &c1)<0)){
939 943
 		ERR("failure evaluating expression: bad type\n");
940 944
 		i=0; /* false */
945
+		goto int_expr;
946
+	}
947
+	if (unlikely(rv)){
948
+		/* no int => str */
949
+		rv1=rval_convert(h, msg, RV_STR, rv, &c1);
950
+		i=comp_str(op, &rv1->v.s, rtype, r, msg, h);
951
+		rval_destroy(rv1);
952
+		rval_destroy(rv);
953
+		rval_cache_clean(&c1);
954
+		return i;
941 955
 	}
956
+	/* expr evaluated to int */
957
+int_expr:
958
+	rval_cache_clean(&c1);
942 959
 	if (op==NO_OP)
943 960
 		return !(!i); /* transform it into { 0, 1 } */
944 961
 	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();