switch.c
4221104f
 /* 
  * Copyright (C) 2009 iptelorg GmbH
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
1d0661db
 /*!
  * \file
6a0f4382
  * \brief Kamailio core :: 
1d0661db
  * \ingroup core
  * Module: \ref core
  */
 
4221104f
 #include "switch.h"
 #include "rvalue.h"
 #include "route.h"
 #include "mem/mem.h"
 #include "error.h"
 
 #define MAX_JT_SIZE 100  /* maximum jump table size */
 
 
 /** create a cond table structure (pkg_malloc'ed).
  * @return 0 on error, pointer on success
  */
 static struct switch_cond_table* mk_switch_cond_table(int n)
 {
 	struct switch_cond_table* sct;
 	
 	/* allocate everything in a single block, better for cache locality */
 	sct=pkg_malloc(ROUND_INT(sizeof(*sct))+
 					ROUND_POINTER(n*sizeof(sct->cond[0]))+
 					n*sizeof(sct->jump[0]));
 	if (sct==0) return 0;
 	sct->n=n;
 	sct->cond=(int*)((char*)sct+ROUND_INT(sizeof(*sct)));
 	sct->jump=(struct action**)
 				((char*)sct->cond+ROUND_POINTER(n*sizeof(sct->cond[0])));
 	sct->def=0;
 	return sct;
 }
 
 
 
 /** create a jump table structure (pkg_malloc'ed).
  * @param jmp_size - size of the jump table
  * @param rest - size of the fallback condition table
  * @return 0 on error, pointer on success
  */
 static struct switch_jmp_table* mk_switch_jmp_table(int jmp_size, int rest)
 {
 	struct switch_jmp_table* jt;
 	int size;
 	
 	/* alloc everything in a block */
 	size = 	ROUND_POINTER(sizeof(*jt))+
 			ROUND_INT(jmp_size*sizeof(jt->tbl[0]))+
 			ROUND_POINTER(rest*sizeof(jt->rest.cond[0]))+
 			rest*sizeof(jt->rest.jump[0]);
 	jt=pkg_malloc(size);
 	if (jt == 0) return 0;
 	memset(jt, 0, size);
 	jt->tbl = (struct action**)((char*) jt + ROUND_POINTER(sizeof(*jt)));
 	jt->rest.cond = (int*)
 					((char*) jt->tbl + ROUND_INT(jmp_size*sizeof(jt->tbl[0])));
 	jt->rest.jump = (struct action**) ((char*) jt->rest.cond + 
 								ROUND_POINTER(rest*sizeof(jt->rest.cond[0])));
 	jt->rest.n=rest;
 	return jt;
 }
 
 
 
cd26bc54
 /** create a match cond table structure (pkg_malloc'ed).
  * @return 0 on error, pointer on success
  */
 static struct match_cond_table* mk_match_cond_table(int n)
 {
 	struct match_cond_table* mct;
 	
 	/* allocate everything in a single block, better for cache locality */
 	mct=pkg_malloc(ROUND_POINTER(sizeof(*mct))+
 					ROUND_POINTER(n*sizeof(mct->match[0]))+
 					n*sizeof(mct->jump[0]));
 	if (mct==0) return 0;
 	mct->n=n;
 	mct->match=(struct match_str*)((char*)mct+ROUND_POINTER(sizeof(*mct)));
 	mct->jump=(struct action**)
 				((char*)mct->match+ROUND_POINTER(n*sizeof(mct->match[0])));
 	mct->def=0;
 	return mct;
 }
 
 
 
 static int fix_match(struct action* t);
 
 
 
4221104f
 void destroy_case_stms(struct case_stms *lst)
 {
 	struct case_stms* l;
 	struct case_stms* n;
 	
 	for (l=lst; l; l=n){
 		n=l->next;
 		rve_destroy(l->ct_rve);
 		/* TODO: the action list is not freed (missing destroy_action() and
 		   there are some case when we need at least part of the action list
 		*/
 		pkg_free(l);
 	}
 }
 
 
 
 /** fixup function for SWITCH_T actions.
  * can produce 4 different action types:
  *  - BLOCK_T (actions) - actions grouped in a block, break ends the block
  *    execution.
  *  - EVAL_T (cond)  - null switch block, but the condition has to be
  *                       evaluated due to possible side-effects.
  *  - SWITCH_COND_T(cond, jumps) - condition table
  *  - SWITCH_JT_T(cond, jumptable) - jumptable + condition table
  * TODO: external optimizers that would "flatten" BLOCK_T w/no breaks or
  * breaks at the end.
  * 
  */
 int fix_switch(struct action* t)
 {
 	struct case_stms* c;
 	int n, i, j, ret, val;
 	struct action* a;
 	struct action* block;
 	struct action* def_a;
 	struct action* action_lst;
 	struct action** tail;
 	struct switch_jmp_table* jmp;
 	struct switch_cond_table* sct;
 	struct action** def_jmp_bm;
 	int* cond;
 	struct action*** jmp_bm;
 	int default_found;
 	int first, last, start, end, hits, best_hits;
 	struct rval_expr* sw_rve;
 	
 	ret=E_BUG;
 	cond=0;
 	jmp_bm=0;
 	def_jmp_bm=0;
 	default_found=0;
cd26bc54
 	/* check if string switch (first case is string or RE) */
 	for (c=(struct case_stms*)t->val[1].u.data; c && c->is_default; c=c->next);
 	if (c && (c->type==MATCH_STR || c->type==MATCH_RE))
 		return fix_match(t);
 	
4221104f
 	sw_rve=(struct rval_expr*)t->val[0].u.data;
 	/*  handle null actions: optimize away if no
 	   sideffects */
 	if (t->val[1].u.data==0){
 		if (!rve_has_side_effects(sw_rve)){
 			t->type=BLOCK_T;
 			rve_destroy(sw_rve);
 			t->val[0].type=BLOCK_ST;
 			t->val[0].u.data=0;
0a948535
 			LM_DBG("null switch optimized away\n");
4221104f
 		}else{
 			t->type=EVAL_T;
 			t->val[0].type=RVE_ST;
0a948535
 			LM_DBG("null switch turned to EVAL_T\n");
4221104f
 		}
 		return 0;
 	}
 	def_a=0;
 	n=0;
 	for (c=(struct case_stms*)t->val[1].u.data; c; c=c->next){
 		if (c->ct_rve){
cd26bc54
 			if (c->type!=MATCH_INT){
14839f06
 				LM_ERR("wrong case type %d (int expected)\n", c->type);
cd26bc54
 				return E_UNSPEC;
 			}
4221104f
 			if (!rve_is_constant(c->ct_rve)){
14839f06
 				LM_ERR("non constant expression in case\n");
4221104f
 				return E_BUG;
 			}
cd26bc54
 			if (rval_expr_eval_int(0, 0,  &c->label.match_int, c->ct_rve)
4221104f
 					<0){
14839f06
 				LM_ERR("case expression (%d,%d) has non-interger type\n",
4221104f
 						c->ct_rve->fpos.s_line,
 						c->ct_rve->fpos.s_col);
 				return E_BUG;
 			}
 			c->is_default=0;
 			n++; /* count only non-default cases */
 		}else{
 			if (default_found){
14839f06
 				LM_ERR("more then one \"default\"");
4221104f
 				return E_UNSPEC;
 			}
 			default_found=1;
cd26bc54
 			c->label.match_int=-1;
4221104f
 			c->is_default=1;
 			def_a=c->actions;
 		}
 		if ( c->actions && ((ret=fix_actions(c->actions))<0))
 			goto error;
 	}
0a948535
 	LM_DBG("%d cases, %d default\n", n, default_found);
4221104f
 	/*: handle n==0 (no case only a default:) */
 	if (n==0){
 		if (default_found){
 			if (!rve_has_side_effects(sw_rve)){
 				t->type=BLOCK_T;
 				rve_destroy(sw_rve);
 				destroy_case_stms(t->val[1].u.data);
 				t->val[0].type=BLOCK_ST;
 				t->val[0].u.data=def_a;
 				t->val[1].type=0;
 				t->val[1].u.data=0;
0a948535
 				LM_DBG("default only switch optimized away (BLOCK_T)\n");
4221104f
 				return 0;
 			}
0a948535
 			LM_DBG("default only switch with side-effect...\n");
4221104f
 		}else{
14839f06
 			LM_CRIT("empty switch not expected at this point\n");
4221104f
 			ret=E_BUG;
 			goto error;
 		}
 	}
 	cond=pkg_malloc(sizeof(cond[0])*n);
 	jmp_bm=pkg_malloc(sizeof(jmp_bm[0])*n);
 	if (cond==0 || jmp_bm==0){
14839f06
 		LM_ERR("memory allocation failure\n");
4221104f
 		ret=E_OUT_OF_MEM;
 		goto error;
 	}
 	
 	/* fill condition table and jump point bookmarks and "flatten" the action 
 	   lists (transform them into a single list for the entire switch, rather
 	    then one block per case ) */
 	n=0;
 	action_lst=0;
 	tail=&action_lst;
 	for (c=(struct case_stms*)t->val[1].u.data; c; c=c->next){
 		a=c->actions;
 		if (a){
 			for (; a->next; a=a->next);
 			if (action_lst==0)
 				action_lst=c->actions;
 			else
 				*tail=c->actions;
 		}
 		if (c->is_default){
 			def_jmp_bm=tail;
 		} else {
 			for (j=0; j<n; j++){
cd26bc54
 				if (cond[j]==c->label.match_int){
14839f06
 					LM_ERR("duplicate case (%d,%d)\n",
4221104f
 							c->ct_rve->fpos.s_line, c->ct_rve->fpos.s_col);
 					ret=E_UNSPEC;
 					goto error;
 				}
 			}
cd26bc54
 			cond[n]=c->label.match_int;
4221104f
 			jmp_bm[n]=tail;
 			n++;
 		}
 		if (c->actions)
 			tail=&a->next;
 	}
 	/* handle constant rve w/ no side-effects: replace the whole case 
 	   with the case rve block */
 	if ( (scr_opt_lev>=2) &&
 			!rve_has_side_effects(sw_rve) && rve_is_constant(sw_rve)){
 		if (rval_expr_eval_int(0, 0,  &val, sw_rve) <0){
14839f06
 			LM_ERR("wrong type for switch(...) expression (%d,%d)\n", 
4221104f
 					sw_rve->fpos.s_line, sw_rve->fpos.s_col);
 			ret=E_UNSPEC;
 			goto error;
 		}
 		/* start with the "default:" value in case nothing is found */
 		block=def_jmp_bm?*def_jmp_bm:0;
 		for (i=0; i<n; i++){
 			if (cond[i]==val){
 				block=*jmp_bm[i];
 				break;
 			}
 		}
 		t->type=BLOCK_T;
 		rve_destroy(sw_rve);
 		t->val[0].type=BLOCK_ST;
 		t->val[0].u.data=block;
 		destroy_case_stms(t->val[1].u.data);
 		t->val[1].type=0;
 		t->val[1].u.data=0;
 		ret=0;
0a948535
 		LM_DBG("constant switch(%d) with %d cases optimized away to case"
4221104f
 				" %d \n", val, n, i);
 		goto end;
 	}
 	/* try to create a jumptable */
 	/* cost: 2 cmp & table lookup
 	   => makes sense for more then 3 cases
 	   & if size< MAX_JT_SIZE
 	*/
 	best_hits=3; /* more then 3 hits needed */
 	start=end=0;
 	for (i=0; i<n; i++){
 		last=first=cond[i];
 		hits=1;
 		for (j=0; j<n; j++){
 			if ((i==j) || (cond[j]<=first)) continue;
 			if (cond[j]<last)
 				hits++;
 			else if ((cond[j]-first)<MAX_JT_SIZE){
 				last=cond[j];
 				hits++;
 			}
 		}
 		if (hits>best_hits){
 			best_hits=hits;
 			start=first;
 			end=last;
 			if (hits==n) break;
 		}
 	}
 	if (start!=end){
 		/* build jumptable: end-start entries and
 		 with a n-best_hits normal switch table */
 		jmp=mk_switch_jmp_table(end-start+1, n-best_hits);
 		if (jmp==0){
14839f06
 			LM_ERR("memory allocation error\n");
4221104f
 			ret=E_OUT_OF_MEM;
 			goto error;
 		}
 		jmp->first=start;
 		jmp->last=end;
 		jmp->rest.n=n-best_hits;
 		jmp->rest.def=def_jmp_bm?*def_jmp_bm:0;
 		/* fill it with default values */
 		for (i=0; i<=(end-start); i++)
 			jmp->tbl[i]=jmp->rest.def;
 		for (i=0, j=0; i<n; i++){
 			if (cond[i]>=start && cond[i]<=end){
 				jmp->tbl[cond[i]-start]=*jmp_bm[i];
 			}else{
 				jmp->rest.cond[j]=cond[i];
 				jmp->rest.jump[j]=*jmp_bm[i];
 				j++;
 			}
 		}
 		t->type=SWITCH_JT_T;
 		t->val[1].type=JUMPTABLE_ST;
 		t->val[1].u.data=jmp;
 		ret=0;
0a948535
 		LM_DBG("optimized to jumptable [%d, %d] and %d condtable,"
 				" default: %s\n ",
4221104f
 				jmp->first, jmp->last, jmp->rest.n, jmp->rest.def?"yes":"no");
 	}else{
 		sct=mk_switch_cond_table(n);
 		if (sct==0){
14839f06
 			LM_ERR("memory allocation error\n");
4221104f
 			ret=E_OUT_OF_MEM;
 			goto error;
 		}
 		sct->n=n;
 		for (i=0; i<n; i++){
 			sct->cond[i]=cond[i];
 			sct->jump[i]=*jmp_bm[i];
 		}
 		sct->def=def_jmp_bm?*def_jmp_bm:0;
 		t->type=SWITCH_COND_T;
 		t->val[1].type=CONDTABLE_ST;
 		t->val[1].u.data=sct;
0a948535
 		LM_DBG("optimized to condtable (%d) default: %s\n",
4221104f
 				sct->n, sct->def?"yes":"no");
 		ret=0;
 	}
 end:
 error:
 	if (cond) pkg_free(cond);
 	if (jmp_bm) pkg_free(jmp_bm);
 	return ret;
 }
 
cd26bc54
 
 
 /** fixup function for MATCH_T actions.
  * can produce 3 different action types:
  *  - BLOCK_T (actions) - actions grouped in a block, break ends the block
  *    execution.
  *  - EVAL_T (cond)  - null switch block, but the condition has to be
  *                       evaluated due to possible side-effects.
  *  - MATCH_COND_T(cond, jumps) - condition table
  */
 static int fix_match(struct action* t)
 {
 	struct case_stms* c;
 	int n, i, j, ret;
 	struct action* a;
 	struct action* block;
 	struct action* def_a;
 	struct action* action_lst;
 	struct action** tail;
 	struct match_cond_table* mct;
 	struct action** def_jmp_bm;
 	struct match_str* match;
 	struct action*** jmp_bm;
 	int default_found;
 	struct rval_expr* m_rve;
 	struct rvalue* rv;
 	regex_t* regex;
 	str s;
 	
 	ret=E_BUG;
 	match=0;
 	jmp_bm=0;
 	def_jmp_bm=0;
 	default_found=0;
 	rv=0;
 	s.s=0;
 	s.len=0;
 	m_rve=(struct rval_expr*)t->val[0].u.data;
 	/*  handle null actions: optimize away if no
 	   sideffects */
 	if (t->val[1].u.data==0){
 		if (!rve_has_side_effects(m_rve)){
 			t->type=BLOCK_T;
 			rve_destroy(m_rve);
 			t->val[0].type=BLOCK_ST;
 			t->val[0].u.data=0;
0a948535
 			LM_DBG("null switch optimized away\n");
cd26bc54
 		}else{
 			t->type=EVAL_T;
 			t->val[0].type=RVE_ST;
0a948535
 			LM_DBG("null switch turned to EVAL_T\n");
cd26bc54
 		}
 		return 0;
 	}
 	def_a=0;
 	n=0;
 	for (c=(struct case_stms*)t->val[1].u.data; c; c=c->next){
 		if (c->ct_rve){
 			if (c->type!=MATCH_STR && c->type!=MATCH_RE){
14839f06
 				LM_ERR("wrong case type %d (string"
cd26bc54
 							"or RE expected)\n", c->type);
 				return E_UNSPEC;
 			}
 			if (!rve_is_constant(c->ct_rve)){
14839f06
 				LM_ERR("non constant expression in case\n");
cd26bc54
 				ret=E_BUG;
 				goto error;
 			}
 			if ((rv=rval_expr_eval(0, 0, c->ct_rve)) == 0 ){
14839f06
 				LM_ERR("bad case expression (%d,%d)\n",
cd26bc54
 						c->ct_rve->fpos.s_line,
 						c->ct_rve->fpos.s_col);
 				ret=E_BUG;
 				goto error;
 			}
 			if (rval_get_str(0, 0, &s, rv, 0)<0){
14839f06
 				LM_ERR("(%d,%d): out of memory?\n",
cd26bc54
 						c->ct_rve->fpos.s_line,
 						c->ct_rve->fpos.s_col);
 				ret=E_BUG;
 				goto error;
 			}
 			if (c->type==MATCH_RE){
 				if ((regex=pkg_malloc(sizeof(regex_t))) == 0){
14839f06
 					LM_ERR("out of memory\n");
cd26bc54
 					ret=E_OUT_OF_MEM;
 					goto error;
 				}
 				if (regcomp(regex, s.s, 
 							REG_EXTENDED | REG_NOSUB | c->re_flags) !=0){
 					pkg_free(regex);
 					regex=0;
14839f06
 					LM_ERR("(%d, %d): bad regular expression %.*s\n",
cd26bc54
 							c->ct_rve->fpos.s_line,
 							c->ct_rve->fpos.s_col,
 							s.len, ZSW(s.s));
 					ret=E_UNSPEC;
 					goto error;
 				}
 				c->label.match_re=regex;
 				regex=0;
 			}else if (c->type==MATCH_STR){
 				c->label.match_str=s;
 				s.s=0;
 				s.len=0;
 			}else{
14839f06
 				LM_CRIT("(%d,%d): wrong case type %d\n",
cd26bc54
 						c->ct_rve->fpos.s_line, c->ct_rve->fpos.s_col,
 						c->type);
 				ret=E_BUG;
 				goto error;
 			}
 			c->is_default=0;
 			n++; /* count only non-default cases */
 			/* cleanup */
 			rval_destroy(rv);
 			rv=0;
 			if (s.s){
 				pkg_free(s.s);
 				s.s=0;
 				s.len=0;
 			}
 		}else{
 			if (default_found){
14839f06
 				LM_ERR("more then one \"default\" label found (%d, %d)\n",
0bda1dc8
 						(c->ct_rve)?c->ct_rve->fpos.s_line:0,
 						(c->ct_rve)?c->ct_rve->fpos.s_col:0);
cd26bc54
 				ret=E_UNSPEC;
 				goto error;
 			}
 			default_found=1;
 			c->is_default=1;
 			def_a=c->actions;
 		}
 		if ( c->actions && ((ret=fix_actions(c->actions))<0))
 			goto error;
 	}
0a948535
 	LM_DBG("%d cases, %d default\n", n, default_found);
cd26bc54
 	/*: handle n==0 (no case only a default:) */
 	if (n==0){
 		if (default_found){
 			if (!rve_has_side_effects(m_rve)){
 				t->type=BLOCK_T;
 				rve_destroy(m_rve);
 				destroy_case_stms(t->val[1].u.data);
 				t->val[0].type=BLOCK_ST;
 				t->val[0].u.data=def_a;
 				t->val[1].type=0;
 				t->val[1].u.data=0;
0a948535
 				LM_DBG("default only switch optimized away (BLOCK_T)\n");
cd26bc54
 				return 0;
 			}
0a948535
 			LM_DBG("default only switch with side-effect...\n");
cd26bc54
 		}else{
14839f06
 			LM_CRIT("empty switch not expected at this point\n");
cd26bc54
 			ret=E_BUG;
 			goto error;
 		}
 	}
e4a75063
 	/* n is the number of labels here */
cd26bc54
 	match=pkg_malloc(sizeof(match[0])*n);
 	jmp_bm=pkg_malloc(sizeof(jmp_bm[0])*n);
 	if (match==0 || jmp_bm==0){
14839f06
 		LM_ERR("memory allocation failure\n");
cd26bc54
 		ret=E_OUT_OF_MEM;
 		goto error;
 	}
 	
 	/* fill condition table and jump point bookmarks and "flatten" the action 
 	   lists (transform them into a single list for the entire switch, rather
 	    then one block per case ) */
 	n=0;
 	action_lst=0;
 	tail=&action_lst;
 	for (c=(struct case_stms*)t->val[1].u.data; c; c=c->next){
 		a=c->actions;
 		if (a){
 			for (; a->next; a=a->next);
 			if (action_lst==0)
 				action_lst=c->actions;
 			else
 				*tail=c->actions;
 		}
 		if (c->is_default){
 			def_jmp_bm=tail;
 		} else{
 			match[n].type=c->type;
 			if (match[n].type == MATCH_STR){
 				for (j=0; j<n; j++){
 					if ( match[j].type == c->type &&
 						 match[j].l.s.len ==  c->label.match_str.len &&
 						 memcmp(match[j].l.s.s, c->label.match_str.s,
 							 		match[j].l.s.len) == 0 ){
14839f06
 						LM_ERR("duplicate case (%d,%d)\n",
 								c->ct_rve->fpos.s_line,
cd26bc54
 								c->ct_rve->fpos.s_col);
 						ret=E_UNSPEC;
 						goto error;
 					}
 				}
 				match[n].flags=0;
 				match[n].l.s=c->label.match_str;
 				c->label.match_str.s=0; /* prevent s being freed */
 				c->label.match_str.len=0;
 			} else {
 				match[n].flags=c->re_flags | REG_EXTENDED | REG_NOSUB;
 				match[n].l.regex=c->label.match_re;
 				c->label.match_re=0;
 			}
 			jmp_bm[n]=tail;
 			n++;
 		}
 		if (c->actions)
 			tail=&a->next;
 	}
 	/* handle constant rve w/ no side-effects: replace the whole case 
 	   with the case rve block */
 	if ( (scr_opt_lev>=2) &&
 			!rve_has_side_effects(m_rve) && rve_is_constant(m_rve)){
 		if ((rv=rval_expr_eval(0, 0, m_rve)) == 0){
14839f06
 			LM_ERR("bad expression (%d,%d)\n", 
cd26bc54
 					m_rve->fpos.s_line, m_rve->fpos.s_col);
 			ret=E_UNSPEC;
 			goto error;
 		}
 		if (rval_get_str(0, 0, &s, rv, 0) < 0 ){
14839f06
 				LM_ERR("(%d,%d): bad string expression\n",
cd26bc54
 						m_rve->fpos.s_line,
 						m_rve->fpos.s_col);
 			ret=E_UNSPEC;
 			goto error;
 		}
 		/* start with the "default:" value in case nothing is found */
 		block=def_jmp_bm?*def_jmp_bm:0;
 		for (i=0; i<n; i++){
 			if (((match[i].type == MATCH_STR) && (match[i].l.s.len == s.len) &&
 					(memcmp(match[i].l.s.s, s.s, s.len) == 0)) ||
 				((match[i].type == MATCH_RE) && 
 					regexec(match[i].l.regex, s.s, 0, 0, 0) == 0) ) {
 				block=*jmp_bm[i];
 				break;
 			}
 		}
0a948535
 		LM_DBG("constant switch(\"%.*s\") with %d cases optimized away"
cd26bc54
 				" to case no. %d\n", s.len, ZSW(s.s), n, i);
 		/* cleanup */
 		rval_destroy(rv);
 		rv=0;
 		pkg_free(s.s);
 		s.s=0;
 		s.len=0;
 		ret=0;
 		/* replace with BLOCK_ST */
 		rve_destroy(m_rve);
 		destroy_case_stms(t->val[1].u.data);
 		t->type=BLOCK_T;
 		t->val[0].type=BLOCK_ST;
 		t->val[0].u.data=block;
 		t->val[1].type=0;
 		t->val[1].u.data=0;
 		goto end;
 	}
 	mct=mk_match_cond_table(n);
 	if (mct==0){
14839f06
 		LM_ERR("memory allocation error\n");
cd26bc54
 		ret=E_OUT_OF_MEM;
 		goto error;
 	}
 	mct->n=n;
 	for (i=0; i<n; i++){
 		mct->match[i]=match[i];
 		mct->jump[i]=*jmp_bm[i];
 	}
 	mct->def=def_jmp_bm?*def_jmp_bm:0;
 	t->type=MATCH_COND_T;
 	t->val[1].type=MATCH_CONDTABLE_ST;
 	t->val[1].u.data=mct;
0a948535
 	LM_DBG("optimized to match condtable (%d) default: %s\n",
cd26bc54
 				mct->n, mct->def?"yes":"no");
 		ret=0;
 end:
 error:
 	if (match) pkg_free(match);
 	if (jmp_bm) pkg_free(jmp_bm);
 	/* cleanup rv & s*/
 	if (rv) rval_destroy(rv);
 	if (s.s) pkg_free(s.s);
 	return ret;
 }
4221104f
 /* vi: set ts=4 sw=4 tw=79:ai:cindent: */