switch.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696
  1. /*
  2. * $Id$
  3. *
  4. * Copyright (C) 2009 iptelorg GmbH
  5. *
  6. * Permission to use, copy, modify, and distribute this software for any
  7. * purpose with or without fee is hereby granted, provided that the above
  8. * copyright notice and this permission notice appear in all copies.
  9. *
  10. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  11. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  12. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  13. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  14. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  15. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  16. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  17. */
  18. /*
  19. * switch.c
  20. */
  21. /*
  22. * History:
  23. * --------
  24. * 2009-02-02 initial version (andrei)
  25. * 2009-02-19 string and RE switch support added (andrei)
  26. */
  27. /*!
  28. * \file
  29. * \brief SIP-router core ::
  30. * \ingroup core
  31. * Module: \ref core
  32. */
  33. #include "switch.h"
  34. #include "rvalue.h"
  35. #include "route.h"
  36. #include "mem/mem.h"
  37. #include "error.h"
  38. #define MAX_JT_SIZE 100 /* maximum jump table size */
  39. /** create a cond table structure (pkg_malloc'ed).
  40. * @return 0 on error, pointer on success
  41. */
  42. static struct switch_cond_table* mk_switch_cond_table(int n)
  43. {
  44. struct switch_cond_table* sct;
  45. /* allocate everything in a single block, better for cache locality */
  46. sct=pkg_malloc(ROUND_INT(sizeof(*sct))+
  47. ROUND_POINTER(n*sizeof(sct->cond[0]))+
  48. n*sizeof(sct->jump[0]));
  49. if (sct==0) return 0;
  50. sct->n=n;
  51. sct->cond=(int*)((char*)sct+ROUND_INT(sizeof(*sct)));
  52. sct->jump=(struct action**)
  53. ((char*)sct->cond+ROUND_POINTER(n*sizeof(sct->cond[0])));
  54. sct->def=0;
  55. return sct;
  56. }
  57. /** create a jump table structure (pkg_malloc'ed).
  58. * @param jmp_size - size of the jump table
  59. * @param rest - size of the fallback condition table
  60. * @return 0 on error, pointer on success
  61. */
  62. static struct switch_jmp_table* mk_switch_jmp_table(int jmp_size, int rest)
  63. {
  64. struct switch_jmp_table* jt;
  65. int size;
  66. /* alloc everything in a block */
  67. size = ROUND_POINTER(sizeof(*jt))+
  68. ROUND_INT(jmp_size*sizeof(jt->tbl[0]))+
  69. ROUND_POINTER(rest*sizeof(jt->rest.cond[0]))+
  70. rest*sizeof(jt->rest.jump[0]);
  71. jt=pkg_malloc(size);
  72. if (jt == 0) return 0;
  73. memset(jt, 0, size);
  74. jt->tbl = (struct action**)((char*) jt + ROUND_POINTER(sizeof(*jt)));
  75. jt->rest.cond = (int*)
  76. ((char*) jt->tbl + ROUND_INT(jmp_size*sizeof(jt->tbl[0])));
  77. jt->rest.jump = (struct action**) ((char*) jt->rest.cond +
  78. ROUND_POINTER(rest*sizeof(jt->rest.cond[0])));
  79. jt->rest.n=rest;
  80. return jt;
  81. }
  82. /** create a match cond table structure (pkg_malloc'ed).
  83. * @return 0 on error, pointer on success
  84. */
  85. static struct match_cond_table* mk_match_cond_table(int n)
  86. {
  87. struct match_cond_table* mct;
  88. /* allocate everything in a single block, better for cache locality */
  89. mct=pkg_malloc(ROUND_POINTER(sizeof(*mct))+
  90. ROUND_POINTER(n*sizeof(mct->match[0]))+
  91. n*sizeof(mct->jump[0]));
  92. if (mct==0) return 0;
  93. mct->n=n;
  94. mct->match=(struct match_str*)((char*)mct+ROUND_POINTER(sizeof(*mct)));
  95. mct->jump=(struct action**)
  96. ((char*)mct->match+ROUND_POINTER(n*sizeof(mct->match[0])));
  97. mct->def=0;
  98. return mct;
  99. }
  100. static int fix_match(struct action* t);
  101. void destroy_case_stms(struct case_stms *lst)
  102. {
  103. struct case_stms* l;
  104. struct case_stms* n;
  105. for (l=lst; l; l=n){
  106. n=l->next;
  107. rve_destroy(l->ct_rve);
  108. /* TODO: the action list is not freed (missing destroy_action() and
  109. there are some case when we need at least part of the action list
  110. */
  111. pkg_free(l);
  112. }
  113. }
  114. /** fixup function for SWITCH_T actions.
  115. * can produce 4 different action types:
  116. * - BLOCK_T (actions) - actions grouped in a block, break ends the block
  117. * execution.
  118. * - EVAL_T (cond) - null switch block, but the condition has to be
  119. * evaluated due to possible side-effects.
  120. * - SWITCH_COND_T(cond, jumps) - condition table
  121. * - SWITCH_JT_T(cond, jumptable) - jumptable + condition table
  122. * TODO: external optimizers that would "flatten" BLOCK_T w/no breaks or
  123. * breaks at the end.
  124. *
  125. */
  126. int fix_switch(struct action* t)
  127. {
  128. struct case_stms* c;
  129. int n, i, j, ret, val;
  130. struct action* a;
  131. struct action* block;
  132. struct action* def_a;
  133. struct action* action_lst;
  134. struct action** tail;
  135. struct switch_jmp_table* jmp;
  136. struct switch_cond_table* sct;
  137. struct action** def_jmp_bm;
  138. int* cond;
  139. struct action*** jmp_bm;
  140. int default_found;
  141. int first, last, start, end, hits, best_hits;
  142. struct rval_expr* sw_rve;
  143. ret=E_BUG;
  144. cond=0;
  145. jmp_bm=0;
  146. def_jmp_bm=0;
  147. default_found=0;
  148. /* check if string switch (first case is string or RE) */
  149. for (c=(struct case_stms*)t->val[1].u.data; c && c->is_default; c=c->next);
  150. if (c && (c->type==MATCH_STR || c->type==MATCH_RE))
  151. return fix_match(t);
  152. sw_rve=(struct rval_expr*)t->val[0].u.data;
  153. /* handle null actions: optimize away if no
  154. sideffects */
  155. if (t->val[1].u.data==0){
  156. if (!rve_has_side_effects(sw_rve)){
  157. t->type=BLOCK_T;
  158. rve_destroy(sw_rve);
  159. t->val[0].type=BLOCK_ST;
  160. t->val[0].u.data=0;
  161. DBG("SWITCH: null switch optimized away\n");
  162. }else{
  163. t->type=EVAL_T;
  164. t->val[0].type=RVE_ST;
  165. DBG("SWITCH: null switch turned to EVAL_T\n");
  166. }
  167. return 0;
  168. }
  169. def_a=0;
  170. n=0;
  171. for (c=(struct case_stms*)t->val[1].u.data; c; c=c->next){
  172. if (c->ct_rve){
  173. if (c->type!=MATCH_INT){
  174. LM_ERR("wrong case type %d (int expected)\n", c->type);
  175. return E_UNSPEC;
  176. }
  177. if (!rve_is_constant(c->ct_rve)){
  178. LM_ERR("non constant expression in case\n");
  179. return E_BUG;
  180. }
  181. if (rval_expr_eval_int(0, 0, &c->label.match_int, c->ct_rve)
  182. <0){
  183. LM_ERR("case expression (%d,%d) has non-interger type\n",
  184. c->ct_rve->fpos.s_line,
  185. c->ct_rve->fpos.s_col);
  186. return E_BUG;
  187. }
  188. c->is_default=0;
  189. n++; /* count only non-default cases */
  190. }else{
  191. if (default_found){
  192. LM_ERR("more then one \"default\"");
  193. return E_UNSPEC;
  194. }
  195. default_found=1;
  196. c->label.match_int=-1;
  197. c->is_default=1;
  198. def_a=c->actions;
  199. }
  200. if ( c->actions && ((ret=fix_actions(c->actions))<0))
  201. goto error;
  202. }
  203. DBG("SWITCH: %d cases, %d default\n", n, default_found);
  204. /*: handle n==0 (no case only a default:) */
  205. if (n==0){
  206. if (default_found){
  207. if (!rve_has_side_effects(sw_rve)){
  208. t->type=BLOCK_T;
  209. rve_destroy(sw_rve);
  210. destroy_case_stms(t->val[1].u.data);
  211. t->val[0].type=BLOCK_ST;
  212. t->val[0].u.data=def_a;
  213. t->val[1].type=0;
  214. t->val[1].u.data=0;
  215. DBG("SWITCH: default only switch optimized away (BLOCK_T)\n");
  216. return 0;
  217. }
  218. DBG("SWITCH: default only switch with side-effect...\n");
  219. }else{
  220. LM_CRIT("empty switch not expected at this point\n");
  221. ret=E_BUG;
  222. goto error;
  223. }
  224. }
  225. cond=pkg_malloc(sizeof(cond[0])*n);
  226. jmp_bm=pkg_malloc(sizeof(jmp_bm[0])*n);
  227. if (cond==0 || jmp_bm==0){
  228. LM_ERR("memory allocation failure\n");
  229. ret=E_OUT_OF_MEM;
  230. goto error;
  231. }
  232. /* fill condition table and jump point bookmarks and "flatten" the action
  233. lists (transform them into a single list for the entire switch, rather
  234. then one block per case ) */
  235. n=0;
  236. action_lst=0;
  237. tail=&action_lst;
  238. for (c=(struct case_stms*)t->val[1].u.data; c; c=c->next){
  239. a=c->actions;
  240. if (a){
  241. for (; a->next; a=a->next);
  242. if (action_lst==0)
  243. action_lst=c->actions;
  244. else
  245. *tail=c->actions;
  246. }
  247. if (c->is_default){
  248. def_jmp_bm=tail;
  249. } else {
  250. for (j=0; j<n; j++){
  251. if (cond[j]==c->label.match_int){
  252. LM_ERR("duplicate case (%d,%d)\n",
  253. c->ct_rve->fpos.s_line, c->ct_rve->fpos.s_col);
  254. ret=E_UNSPEC;
  255. goto error;
  256. }
  257. }
  258. cond[n]=c->label.match_int;
  259. jmp_bm[n]=tail;
  260. n++;
  261. }
  262. if (c->actions)
  263. tail=&a->next;
  264. }
  265. /* handle constant rve w/ no side-effects: replace the whole case
  266. with the case rve block */
  267. if ( (scr_opt_lev>=2) &&
  268. !rve_has_side_effects(sw_rve) && rve_is_constant(sw_rve)){
  269. if (rval_expr_eval_int(0, 0, &val, sw_rve) <0){
  270. LM_ERR("wrong type for switch(...) expression (%d,%d)\n",
  271. sw_rve->fpos.s_line, sw_rve->fpos.s_col);
  272. ret=E_UNSPEC;
  273. goto error;
  274. }
  275. /* start with the "default:" value in case nothing is found */
  276. block=def_jmp_bm?*def_jmp_bm:0;
  277. for (i=0; i<n; i++){
  278. if (cond[i]==val){
  279. block=*jmp_bm[i];
  280. break;
  281. }
  282. }
  283. t->type=BLOCK_T;
  284. rve_destroy(sw_rve);
  285. t->val[0].type=BLOCK_ST;
  286. t->val[0].u.data=block;
  287. destroy_case_stms(t->val[1].u.data);
  288. t->val[1].type=0;
  289. t->val[1].u.data=0;
  290. ret=0;
  291. DBG("SWITCH: constant switch(%d) with %d cases optimized away to case "
  292. " %d \n", val, n, i);
  293. goto end;
  294. }
  295. /* try to create a jumptable */
  296. /* cost: 2 cmp & table lookup
  297. => makes sense for more then 3 cases
  298. & if size< MAX_JT_SIZE
  299. */
  300. best_hits=3; /* more then 3 hits needed */
  301. start=end=0;
  302. for (i=0; i<n; i++){
  303. last=first=cond[i];
  304. hits=1;
  305. for (j=0; j<n; j++){
  306. if ((i==j) || (cond[j]<=first)) continue;
  307. if (cond[j]<last)
  308. hits++;
  309. else if ((cond[j]-first)<MAX_JT_SIZE){
  310. last=cond[j];
  311. hits++;
  312. }
  313. }
  314. if (hits>best_hits){
  315. best_hits=hits;
  316. start=first;
  317. end=last;
  318. if (hits==n) break;
  319. }
  320. }
  321. if (start!=end){
  322. /* build jumptable: end-start entries and
  323. with a n-best_hits normal switch table */
  324. jmp=mk_switch_jmp_table(end-start+1, n-best_hits);
  325. if (jmp==0){
  326. LM_ERR("memory allocation error\n");
  327. ret=E_OUT_OF_MEM;
  328. goto error;
  329. }
  330. jmp->first=start;
  331. jmp->last=end;
  332. jmp->rest.n=n-best_hits;
  333. jmp->rest.def=def_jmp_bm?*def_jmp_bm:0;
  334. /* fill it with default values */
  335. for (i=0; i<=(end-start); i++)
  336. jmp->tbl[i]=jmp->rest.def;
  337. for (i=0, j=0; i<n; i++){
  338. if (cond[i]>=start && cond[i]<=end){
  339. jmp->tbl[cond[i]-start]=*jmp_bm[i];
  340. }else{
  341. jmp->rest.cond[j]=cond[i];
  342. jmp->rest.jump[j]=*jmp_bm[i];
  343. j++;
  344. }
  345. }
  346. t->type=SWITCH_JT_T;
  347. t->val[1].type=JUMPTABLE_ST;
  348. t->val[1].u.data=jmp;
  349. ret=0;
  350. DBG("SWITCH: optimized to jumptable [%d, %d] and %d condtable,"
  351. "default: %s\n ",
  352. jmp->first, jmp->last, jmp->rest.n, jmp->rest.def?"yes":"no");
  353. }else{
  354. sct=mk_switch_cond_table(n);
  355. if (sct==0){
  356. LM_ERR("memory allocation error\n");
  357. ret=E_OUT_OF_MEM;
  358. goto error;
  359. }
  360. sct->n=n;
  361. for (i=0; i<n; i++){
  362. sct->cond[i]=cond[i];
  363. sct->jump[i]=*jmp_bm[i];
  364. }
  365. sct->def=def_jmp_bm?*def_jmp_bm:0;
  366. t->type=SWITCH_COND_T;
  367. t->val[1].type=CONDTABLE_ST;
  368. t->val[1].u.data=sct;
  369. DBG("SWITCH: optimized to condtable (%d) default: %s\n ",
  370. sct->n, sct->def?"yes":"no");
  371. ret=0;
  372. }
  373. end:
  374. error:
  375. if (cond) pkg_free(cond);
  376. if (jmp_bm) pkg_free(jmp_bm);
  377. return ret;
  378. }
  379. /** fixup function for MATCH_T actions.
  380. * can produce 3 different action types:
  381. * - BLOCK_T (actions) - actions grouped in a block, break ends the block
  382. * execution.
  383. * - EVAL_T (cond) - null switch block, but the condition has to be
  384. * evaluated due to possible side-effects.
  385. * - MATCH_COND_T(cond, jumps) - condition table
  386. */
  387. static int fix_match(struct action* t)
  388. {
  389. struct case_stms* c;
  390. int n, i, j, ret;
  391. struct action* a;
  392. struct action* block;
  393. struct action* def_a;
  394. struct action* action_lst;
  395. struct action** tail;
  396. struct match_cond_table* mct;
  397. struct action** def_jmp_bm;
  398. struct match_str* match;
  399. struct action*** jmp_bm;
  400. int default_found;
  401. struct rval_expr* m_rve;
  402. struct rvalue* rv;
  403. regex_t* regex;
  404. str s;
  405. ret=E_BUG;
  406. match=0;
  407. jmp_bm=0;
  408. def_jmp_bm=0;
  409. default_found=0;
  410. rv=0;
  411. s.s=0;
  412. s.len=0;
  413. m_rve=(struct rval_expr*)t->val[0].u.data;
  414. /* handle null actions: optimize away if no
  415. sideffects */
  416. if (t->val[1].u.data==0){
  417. if (!rve_has_side_effects(m_rve)){
  418. t->type=BLOCK_T;
  419. rve_destroy(m_rve);
  420. t->val[0].type=BLOCK_ST;
  421. t->val[0].u.data=0;
  422. DBG("MATCH: null switch optimized away\n");
  423. }else{
  424. t->type=EVAL_T;
  425. t->val[0].type=RVE_ST;
  426. DBG("MATCH: null switch turned to EVAL_T\n");
  427. }
  428. return 0;
  429. }
  430. def_a=0;
  431. n=0;
  432. for (c=(struct case_stms*)t->val[1].u.data; c; c=c->next){
  433. if (c->ct_rve){
  434. if (c->type!=MATCH_STR && c->type!=MATCH_RE){
  435. LM_ERR("wrong case type %d (string"
  436. "or RE expected)\n", c->type);
  437. return E_UNSPEC;
  438. }
  439. if (!rve_is_constant(c->ct_rve)){
  440. LM_ERR("non constant expression in case\n");
  441. ret=E_BUG;
  442. goto error;
  443. }
  444. if ((rv=rval_expr_eval(0, 0, c->ct_rve)) == 0 ){
  445. LM_ERR("bad case expression (%d,%d)\n",
  446. c->ct_rve->fpos.s_line,
  447. c->ct_rve->fpos.s_col);
  448. ret=E_BUG;
  449. goto error;
  450. }
  451. if (rval_get_str(0, 0, &s, rv, 0)<0){
  452. LM_ERR("(%d,%d): out of memory?\n",
  453. c->ct_rve->fpos.s_line,
  454. c->ct_rve->fpos.s_col);
  455. ret=E_BUG;
  456. goto error;
  457. }
  458. if (c->type==MATCH_RE){
  459. if ((regex=pkg_malloc(sizeof(regex_t))) == 0){
  460. LM_ERR("out of memory\n");
  461. ret=E_OUT_OF_MEM;
  462. goto error;
  463. }
  464. if (regcomp(regex, s.s,
  465. REG_EXTENDED | REG_NOSUB | c->re_flags) !=0){
  466. pkg_free(regex);
  467. regex=0;
  468. LM_ERR("(%d, %d): bad regular expression %.*s\n",
  469. c->ct_rve->fpos.s_line,
  470. c->ct_rve->fpos.s_col,
  471. s.len, ZSW(s.s));
  472. ret=E_UNSPEC;
  473. goto error;
  474. }
  475. c->label.match_re=regex;
  476. regex=0;
  477. }else if (c->type==MATCH_STR){
  478. c->label.match_str=s;
  479. s.s=0;
  480. s.len=0;
  481. }else{
  482. LM_CRIT("(%d,%d): wrong case type %d\n",
  483. c->ct_rve->fpos.s_line, c->ct_rve->fpos.s_col,
  484. c->type);
  485. ret=E_BUG;
  486. goto error;
  487. }
  488. c->is_default=0;
  489. n++; /* count only non-default cases */
  490. /* cleanup */
  491. rval_destroy(rv);
  492. rv=0;
  493. if (s.s){
  494. pkg_free(s.s);
  495. s.s=0;
  496. s.len=0;
  497. }
  498. }else{
  499. if (default_found){
  500. LM_ERR("more then one \"default\" label found (%d, %d)\n",
  501. (c->ct_rve)?c->ct_rve->fpos.s_line:0,
  502. (c->ct_rve)?c->ct_rve->fpos.s_col:0);
  503. ret=E_UNSPEC;
  504. goto error;
  505. }
  506. default_found=1;
  507. c->is_default=1;
  508. def_a=c->actions;
  509. }
  510. if ( c->actions && ((ret=fix_actions(c->actions))<0))
  511. goto error;
  512. }
  513. DBG("MATCH: %d cases, %d default\n", n, default_found);
  514. /*: handle n==0 (no case only a default:) */
  515. if (n==0){
  516. if (default_found){
  517. if (!rve_has_side_effects(m_rve)){
  518. t->type=BLOCK_T;
  519. rve_destroy(m_rve);
  520. destroy_case_stms(t->val[1].u.data);
  521. t->val[0].type=BLOCK_ST;
  522. t->val[0].u.data=def_a;
  523. t->val[1].type=0;
  524. t->val[1].u.data=0;
  525. DBG("MATCH: default only switch optimized away (BLOCK_T)\n");
  526. return 0;
  527. }
  528. DBG("MATCH: default only switch with side-effect...\n");
  529. }else{
  530. LM_CRIT("empty switch not expected at this point\n");
  531. ret=E_BUG;
  532. goto error;
  533. }
  534. }
  535. /* n is the number of labels here */
  536. match=pkg_malloc(sizeof(match[0])*n);
  537. jmp_bm=pkg_malloc(sizeof(jmp_bm[0])*n);
  538. if (match==0 || jmp_bm==0){
  539. LM_ERR("memory allocation failure\n");
  540. ret=E_OUT_OF_MEM;
  541. goto error;
  542. }
  543. /* fill condition table and jump point bookmarks and "flatten" the action
  544. lists (transform them into a single list for the entire switch, rather
  545. then one block per case ) */
  546. n=0;
  547. action_lst=0;
  548. tail=&action_lst;
  549. for (c=(struct case_stms*)t->val[1].u.data; c; c=c->next){
  550. a=c->actions;
  551. if (a){
  552. for (; a->next; a=a->next);
  553. if (action_lst==0)
  554. action_lst=c->actions;
  555. else
  556. *tail=c->actions;
  557. }
  558. if (c->is_default){
  559. def_jmp_bm=tail;
  560. } else{
  561. match[n].type=c->type;
  562. if (match[n].type == MATCH_STR){
  563. for (j=0; j<n; j++){
  564. if ( match[j].type == c->type &&
  565. match[j].l.s.len == c->label.match_str.len &&
  566. memcmp(match[j].l.s.s, c->label.match_str.s,
  567. match[j].l.s.len) == 0 ){
  568. LM_ERR("duplicate case (%d,%d)\n",
  569. c->ct_rve->fpos.s_line,
  570. c->ct_rve->fpos.s_col);
  571. ret=E_UNSPEC;
  572. goto error;
  573. }
  574. }
  575. match[n].flags=0;
  576. match[n].l.s=c->label.match_str;
  577. c->label.match_str.s=0; /* prevent s being freed */
  578. c->label.match_str.len=0;
  579. } else {
  580. match[n].flags=c->re_flags | REG_EXTENDED | REG_NOSUB;
  581. match[n].l.regex=c->label.match_re;
  582. c->label.match_re=0;
  583. }
  584. jmp_bm[n]=tail;
  585. n++;
  586. }
  587. if (c->actions)
  588. tail=&a->next;
  589. }
  590. /* handle constant rve w/ no side-effects: replace the whole case
  591. with the case rve block */
  592. if ( (scr_opt_lev>=2) &&
  593. !rve_has_side_effects(m_rve) && rve_is_constant(m_rve)){
  594. if ((rv=rval_expr_eval(0, 0, m_rve)) == 0){
  595. LM_ERR("bad expression (%d,%d)\n",
  596. m_rve->fpos.s_line, m_rve->fpos.s_col);
  597. ret=E_UNSPEC;
  598. goto error;
  599. }
  600. if (rval_get_str(0, 0, &s, rv, 0) < 0 ){
  601. LM_ERR("(%d,%d): bad string expression\n",
  602. m_rve->fpos.s_line,
  603. m_rve->fpos.s_col);
  604. ret=E_UNSPEC;
  605. goto error;
  606. }
  607. /* start with the "default:" value in case nothing is found */
  608. block=def_jmp_bm?*def_jmp_bm:0;
  609. for (i=0; i<n; i++){
  610. if (((match[i].type == MATCH_STR) && (match[i].l.s.len == s.len) &&
  611. (memcmp(match[i].l.s.s, s.s, s.len) == 0)) ||
  612. ((match[i].type == MATCH_RE) &&
  613. regexec(match[i].l.regex, s.s, 0, 0, 0) == 0) ) {
  614. block=*jmp_bm[i];
  615. break;
  616. }
  617. }
  618. DBG("MATCH: constant switch(\"%.*s\") with %d cases optimized away"
  619. " to case no. %d\n", s.len, ZSW(s.s), n, i);
  620. /* cleanup */
  621. rval_destroy(rv);
  622. rv=0;
  623. pkg_free(s.s);
  624. s.s=0;
  625. s.len=0;
  626. ret=0;
  627. /* replace with BLOCK_ST */
  628. rve_destroy(m_rve);
  629. destroy_case_stms(t->val[1].u.data);
  630. t->type=BLOCK_T;
  631. t->val[0].type=BLOCK_ST;
  632. t->val[0].u.data=block;
  633. t->val[1].type=0;
  634. t->val[1].u.data=0;
  635. goto end;
  636. }
  637. mct=mk_match_cond_table(n);
  638. if (mct==0){
  639. LM_ERR("memory allocation error\n");
  640. ret=E_OUT_OF_MEM;
  641. goto error;
  642. }
  643. mct->n=n;
  644. for (i=0; i<n; i++){
  645. mct->match[i]=match[i];
  646. mct->jump[i]=*jmp_bm[i];
  647. }
  648. mct->def=def_jmp_bm?*def_jmp_bm:0;
  649. t->type=MATCH_COND_T;
  650. t->val[1].type=MATCH_CONDTABLE_ST;
  651. t->val[1].u.data=mct;
  652. DBG("MATCH: optimized to match condtable (%d) default: %s\n ",
  653. mct->n, mct->def?"yes":"no");
  654. ret=0;
  655. end:
  656. error:
  657. if (match) pkg_free(match);
  658. if (jmp_bm) pkg_free(jmp_bm);
  659. /* cleanup rv & s*/
  660. if (rv) rval_destroy(rv);
  661. if (s.s) pkg_free(s.s);
  662. return ret;
  663. }
  664. /* vi: set ts=4 sw=4 tw=79:ai:cindent: */