switch.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706
  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. LOG(L_ERR, "ERROR: fix_switch: wrong case type %d (int"
  175. "expected)\n", c->type);
  176. return E_UNSPEC;
  177. }
  178. if (!rve_is_constant(c->ct_rve)){
  179. LOG(L_ERR, "ERROR: fix_switch: non constant "
  180. "expression in case\n");
  181. return E_BUG;
  182. }
  183. if (rval_expr_eval_int(0, 0, &c->label.match_int, c->ct_rve)
  184. <0){
  185. LOG(L_ERR, "ERROR: fix_switch: case expression"
  186. " (%d,%d) has non-interger type\n",
  187. c->ct_rve->fpos.s_line,
  188. c->ct_rve->fpos.s_col);
  189. return E_BUG;
  190. }
  191. c->is_default=0;
  192. n++; /* count only non-default cases */
  193. }else{
  194. if (default_found){
  195. LOG(L_ERR, "ERROR: fix_switch: more then one \"default\"");
  196. return E_UNSPEC;
  197. }
  198. default_found=1;
  199. c->label.match_int=-1;
  200. c->is_default=1;
  201. def_a=c->actions;
  202. }
  203. if ( c->actions && ((ret=fix_actions(c->actions))<0))
  204. goto error;
  205. }
  206. DBG("SWITCH: %d cases, %d default\n", n, default_found);
  207. /*: handle n==0 (no case only a default:) */
  208. if (n==0){
  209. if (default_found){
  210. if (!rve_has_side_effects(sw_rve)){
  211. t->type=BLOCK_T;
  212. rve_destroy(sw_rve);
  213. destroy_case_stms(t->val[1].u.data);
  214. t->val[0].type=BLOCK_ST;
  215. t->val[0].u.data=def_a;
  216. t->val[1].type=0;
  217. t->val[1].u.data=0;
  218. DBG("SWITCH: default only switch optimized away (BLOCK_T)\n");
  219. return 0;
  220. }
  221. DBG("SWITCH: default only switch with side-effect...\n");
  222. }else{
  223. LOG(L_CRIT, "BUG: fix_switch: empty switch not expected at this"
  224. " point\n");
  225. ret=E_BUG;
  226. goto error;
  227. }
  228. }
  229. cond=pkg_malloc(sizeof(cond[0])*n);
  230. jmp_bm=pkg_malloc(sizeof(jmp_bm[0])*n);
  231. if (cond==0 || jmp_bm==0){
  232. LOG(L_ERR, "ERROR: fix_switch: memory allocation failure\n");
  233. ret=E_OUT_OF_MEM;
  234. goto error;
  235. }
  236. /* fill condition table and jump point bookmarks and "flatten" the action
  237. lists (transform them into a single list for the entire switch, rather
  238. then one block per case ) */
  239. n=0;
  240. action_lst=0;
  241. tail=&action_lst;
  242. for (c=(struct case_stms*)t->val[1].u.data; c; c=c->next){
  243. a=c->actions;
  244. if (a){
  245. for (; a->next; a=a->next);
  246. if (action_lst==0)
  247. action_lst=c->actions;
  248. else
  249. *tail=c->actions;
  250. }
  251. if (c->is_default){
  252. def_jmp_bm=tail;
  253. } else {
  254. for (j=0; j<n; j++){
  255. if (cond[j]==c->label.match_int){
  256. LOG(L_ERR, "ERROR: fix_switch: duplicate case (%d,%d)\n",
  257. c->ct_rve->fpos.s_line, c->ct_rve->fpos.s_col);
  258. ret=E_UNSPEC;
  259. goto error;
  260. }
  261. }
  262. cond[n]=c->label.match_int;
  263. jmp_bm[n]=tail;
  264. n++;
  265. }
  266. if (c->actions)
  267. tail=&a->next;
  268. }
  269. /* handle constant rve w/ no side-effects: replace the whole case
  270. with the case rve block */
  271. if ( (scr_opt_lev>=2) &&
  272. !rve_has_side_effects(sw_rve) && rve_is_constant(sw_rve)){
  273. if (rval_expr_eval_int(0, 0, &val, sw_rve) <0){
  274. LOG(L_ERR, "ERROR: fix_switch: wrong type for switch(...) "
  275. "expression (%d,%d)\n",
  276. sw_rve->fpos.s_line, sw_rve->fpos.s_col);
  277. ret=E_UNSPEC;
  278. goto error;
  279. }
  280. /* start with the "default:" value in case nothing is found */
  281. block=def_jmp_bm?*def_jmp_bm:0;
  282. for (i=0; i<n; i++){
  283. if (cond[i]==val){
  284. block=*jmp_bm[i];
  285. break;
  286. }
  287. }
  288. t->type=BLOCK_T;
  289. rve_destroy(sw_rve);
  290. t->val[0].type=BLOCK_ST;
  291. t->val[0].u.data=block;
  292. destroy_case_stms(t->val[1].u.data);
  293. t->val[1].type=0;
  294. t->val[1].u.data=0;
  295. ret=0;
  296. DBG("SWITCH: constant switch(%d) with %d cases optimized away to case "
  297. " %d \n", val, n, i);
  298. goto end;
  299. }
  300. /* try to create a jumptable */
  301. /* cost: 2 cmp & table lookup
  302. => makes sense for more then 3 cases
  303. & if size< MAX_JT_SIZE
  304. */
  305. best_hits=3; /* more then 3 hits needed */
  306. start=end=0;
  307. for (i=0; i<n; i++){
  308. last=first=cond[i];
  309. hits=1;
  310. for (j=0; j<n; j++){
  311. if ((i==j) || (cond[j]<=first)) continue;
  312. if (cond[j]<last)
  313. hits++;
  314. else if ((cond[j]-first)<MAX_JT_SIZE){
  315. last=cond[j];
  316. hits++;
  317. }
  318. }
  319. if (hits>best_hits){
  320. best_hits=hits;
  321. start=first;
  322. end=last;
  323. if (hits==n) break;
  324. }
  325. }
  326. if (start!=end){
  327. /* build jumptable: end-start entries and
  328. with a n-best_hits normal switch table */
  329. jmp=mk_switch_jmp_table(end-start+1, n-best_hits);
  330. if (jmp==0){
  331. LOG(L_ERR, "ERROR: fix_switch: memory allocation error\n");
  332. ret=E_OUT_OF_MEM;
  333. goto error;
  334. }
  335. jmp->first=start;
  336. jmp->last=end;
  337. jmp->rest.n=n-best_hits;
  338. jmp->rest.def=def_jmp_bm?*def_jmp_bm:0;
  339. /* fill it with default values */
  340. for (i=0; i<=(end-start); i++)
  341. jmp->tbl[i]=jmp->rest.def;
  342. for (i=0, j=0; i<n; i++){
  343. if (cond[i]>=start && cond[i]<=end){
  344. jmp->tbl[cond[i]-start]=*jmp_bm[i];
  345. }else{
  346. jmp->rest.cond[j]=cond[i];
  347. jmp->rest.jump[j]=*jmp_bm[i];
  348. j++;
  349. }
  350. }
  351. t->type=SWITCH_JT_T;
  352. t->val[1].type=JUMPTABLE_ST;
  353. t->val[1].u.data=jmp;
  354. ret=0;
  355. DBG("SWITCH: optimized to jumptable [%d, %d] and %d condtable,"
  356. "default: %s\n ",
  357. jmp->first, jmp->last, jmp->rest.n, jmp->rest.def?"yes":"no");
  358. }else{
  359. sct=mk_switch_cond_table(n);
  360. if (sct==0){
  361. LOG(L_ERR, "ERROR: fix_switch: memory allocation error\n");
  362. ret=E_OUT_OF_MEM;
  363. goto error;
  364. }
  365. sct->n=n;
  366. for (i=0; i<n; i++){
  367. sct->cond[i]=cond[i];
  368. sct->jump[i]=*jmp_bm[i];
  369. }
  370. sct->def=def_jmp_bm?*def_jmp_bm:0;
  371. t->type=SWITCH_COND_T;
  372. t->val[1].type=CONDTABLE_ST;
  373. t->val[1].u.data=sct;
  374. DBG("SWITCH: optimized to condtable (%d) default: %s\n ",
  375. sct->n, sct->def?"yes":"no");
  376. ret=0;
  377. }
  378. end:
  379. error:
  380. if (cond) pkg_free(cond);
  381. if (jmp_bm) pkg_free(jmp_bm);
  382. return ret;
  383. }
  384. /** fixup function for MATCH_T actions.
  385. * can produce 3 different action types:
  386. * - BLOCK_T (actions) - actions grouped in a block, break ends the block
  387. * execution.
  388. * - EVAL_T (cond) - null switch block, but the condition has to be
  389. * evaluated due to possible side-effects.
  390. * - MATCH_COND_T(cond, jumps) - condition table
  391. */
  392. static int fix_match(struct action* t)
  393. {
  394. struct case_stms* c;
  395. int n, i, j, ret;
  396. struct action* a;
  397. struct action* block;
  398. struct action* def_a;
  399. struct action* action_lst;
  400. struct action** tail;
  401. struct match_cond_table* mct;
  402. struct action** def_jmp_bm;
  403. struct match_str* match;
  404. struct action*** jmp_bm;
  405. int default_found;
  406. struct rval_expr* m_rve;
  407. struct rvalue* rv;
  408. regex_t* regex;
  409. str s;
  410. ret=E_BUG;
  411. match=0;
  412. jmp_bm=0;
  413. def_jmp_bm=0;
  414. default_found=0;
  415. rv=0;
  416. s.s=0;
  417. s.len=0;
  418. m_rve=(struct rval_expr*)t->val[0].u.data;
  419. /* handle null actions: optimize away if no
  420. sideffects */
  421. if (t->val[1].u.data==0){
  422. if (!rve_has_side_effects(m_rve)){
  423. t->type=BLOCK_T;
  424. rve_destroy(m_rve);
  425. t->val[0].type=BLOCK_ST;
  426. t->val[0].u.data=0;
  427. DBG("MATCH: null switch optimized away\n");
  428. }else{
  429. t->type=EVAL_T;
  430. t->val[0].type=RVE_ST;
  431. DBG("MATCH: null switch turned to EVAL_T\n");
  432. }
  433. return 0;
  434. }
  435. def_a=0;
  436. n=0;
  437. for (c=(struct case_stms*)t->val[1].u.data; c; c=c->next){
  438. if (c->ct_rve){
  439. if (c->type!=MATCH_STR && c->type!=MATCH_RE){
  440. LOG(L_ERR, "ERROR: fix_match: wrong case type %d (string"
  441. "or RE expected)\n", c->type);
  442. return E_UNSPEC;
  443. }
  444. if (!rve_is_constant(c->ct_rve)){
  445. LOG(L_ERR, "ERROR: fix_match: non constant "
  446. "expression in case\n");
  447. ret=E_BUG;
  448. goto error;
  449. }
  450. if ((rv=rval_expr_eval(0, 0, c->ct_rve)) == 0 ){
  451. LOG(L_ERR, "ERROR: fix_match: bad case expression"
  452. " (%d,%d)\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 (rval_get_str(0, 0, &s, rv, 0)<0){
  459. LOG(L_ERR, "ERROR: fix_match (%d,%d): out of memory?\n",
  460. c->ct_rve->fpos.s_line,
  461. c->ct_rve->fpos.s_col);
  462. ret=E_BUG;
  463. goto error;
  464. }
  465. if (c->type==MATCH_RE){
  466. if ((regex=pkg_malloc(sizeof(regex_t))) == 0){
  467. LOG(L_ERR, "ERROR: fix_match: out of memory\n");
  468. ret=E_OUT_OF_MEM;
  469. goto error;
  470. }
  471. if (regcomp(regex, s.s,
  472. REG_EXTENDED | REG_NOSUB | c->re_flags) !=0){
  473. pkg_free(regex);
  474. regex=0;
  475. LOG(L_ERR, "ERROR: fix_match (%d, %d): bad regular"
  476. " expression %.*s\n",
  477. c->ct_rve->fpos.s_line,
  478. c->ct_rve->fpos.s_col,
  479. s.len, ZSW(s.s));
  480. ret=E_UNSPEC;
  481. goto error;
  482. }
  483. c->label.match_re=regex;
  484. regex=0;
  485. }else if (c->type==MATCH_STR){
  486. c->label.match_str=s;
  487. s.s=0;
  488. s.len=0;
  489. }else{
  490. LOG(L_CRIT, "BUG: fix_match (%d,%d): wrong case type %d\n",
  491. c->ct_rve->fpos.s_line, c->ct_rve->fpos.s_col,
  492. c->type);
  493. ret=E_BUG;
  494. goto error;
  495. }
  496. c->is_default=0;
  497. n++; /* count only non-default cases */
  498. /* cleanup */
  499. rval_destroy(rv);
  500. rv=0;
  501. if (s.s){
  502. pkg_free(s.s);
  503. s.s=0;
  504. s.len=0;
  505. }
  506. }else{
  507. if (default_found){
  508. LOG(L_ERR, "ERROR: fix_match: more then one \"default\""
  509. " label found (%d, %d)\n",
  510. (c->ct_rve)?c->ct_rve->fpos.s_line:0,
  511. (c->ct_rve)?c->ct_rve->fpos.s_col:0);
  512. ret=E_UNSPEC;
  513. goto error;
  514. }
  515. default_found=1;
  516. c->is_default=1;
  517. def_a=c->actions;
  518. }
  519. if ( c->actions && ((ret=fix_actions(c->actions))<0))
  520. goto error;
  521. }
  522. DBG("MATCH: %d cases, %d default\n", n, default_found);
  523. /*: handle n==0 (no case only a default:) */
  524. if (n==0){
  525. if (default_found){
  526. if (!rve_has_side_effects(m_rve)){
  527. t->type=BLOCK_T;
  528. rve_destroy(m_rve);
  529. destroy_case_stms(t->val[1].u.data);
  530. t->val[0].type=BLOCK_ST;
  531. t->val[0].u.data=def_a;
  532. t->val[1].type=0;
  533. t->val[1].u.data=0;
  534. DBG("MATCH: default only switch optimized away (BLOCK_T)\n");
  535. return 0;
  536. }
  537. DBG("MATCH: default only switch with side-effect...\n");
  538. }else{
  539. LOG(L_CRIT, "BUG: fix_match: empty switch not expected at this"
  540. " point\n");
  541. ret=E_BUG;
  542. goto error;
  543. }
  544. }
  545. /* n is the number of labels here */
  546. match=pkg_malloc(sizeof(match[0])*n);
  547. jmp_bm=pkg_malloc(sizeof(jmp_bm[0])*n);
  548. if (match==0 || jmp_bm==0){
  549. LOG(L_ERR, "ERROR: fix_match: memory allocation failure\n");
  550. ret=E_OUT_OF_MEM;
  551. goto error;
  552. }
  553. /* fill condition table and jump point bookmarks and "flatten" the action
  554. lists (transform them into a single list for the entire switch, rather
  555. then one block per case ) */
  556. n=0;
  557. action_lst=0;
  558. tail=&action_lst;
  559. for (c=(struct case_stms*)t->val[1].u.data; c; c=c->next){
  560. a=c->actions;
  561. if (a){
  562. for (; a->next; a=a->next);
  563. if (action_lst==0)
  564. action_lst=c->actions;
  565. else
  566. *tail=c->actions;
  567. }
  568. if (c->is_default){
  569. def_jmp_bm=tail;
  570. } else{
  571. match[n].type=c->type;
  572. if (match[n].type == MATCH_STR){
  573. for (j=0; j<n; j++){
  574. if ( match[j].type == c->type &&
  575. match[j].l.s.len == c->label.match_str.len &&
  576. memcmp(match[j].l.s.s, c->label.match_str.s,
  577. match[j].l.s.len) == 0 ){
  578. LOG(L_ERR, "ERROR: fix_match: duplicate case"
  579. " (%d,%d)\n", c->ct_rve->fpos.s_line,
  580. c->ct_rve->fpos.s_col);
  581. ret=E_UNSPEC;
  582. goto error;
  583. }
  584. }
  585. match[n].flags=0;
  586. match[n].l.s=c->label.match_str;
  587. c->label.match_str.s=0; /* prevent s being freed */
  588. c->label.match_str.len=0;
  589. } else {
  590. match[n].flags=c->re_flags | REG_EXTENDED | REG_NOSUB;
  591. match[n].l.regex=c->label.match_re;
  592. c->label.match_re=0;
  593. }
  594. jmp_bm[n]=tail;
  595. n++;
  596. }
  597. if (c->actions)
  598. tail=&a->next;
  599. }
  600. /* handle constant rve w/ no side-effects: replace the whole case
  601. with the case rve block */
  602. if ( (scr_opt_lev>=2) &&
  603. !rve_has_side_effects(m_rve) && rve_is_constant(m_rve)){
  604. if ((rv=rval_expr_eval(0, 0, m_rve)) == 0){
  605. LOG(L_ERR, "ERROR: fix_match: bad expression (%d,%d)\n",
  606. m_rve->fpos.s_line, m_rve->fpos.s_col);
  607. ret=E_UNSPEC;
  608. goto error;
  609. }
  610. if (rval_get_str(0, 0, &s, rv, 0) < 0 ){
  611. LOG(L_ERR, "ERROR: fix_match (%d,%d): bad string expression\n",
  612. m_rve->fpos.s_line,
  613. m_rve->fpos.s_col);
  614. ret=E_UNSPEC;
  615. goto error;
  616. }
  617. /* start with the "default:" value in case nothing is found */
  618. block=def_jmp_bm?*def_jmp_bm:0;
  619. for (i=0; i<n; i++){
  620. if (((match[i].type == MATCH_STR) && (match[i].l.s.len == s.len) &&
  621. (memcmp(match[i].l.s.s, s.s, s.len) == 0)) ||
  622. ((match[i].type == MATCH_RE) &&
  623. regexec(match[i].l.regex, s.s, 0, 0, 0) == 0) ) {
  624. block=*jmp_bm[i];
  625. break;
  626. }
  627. }
  628. DBG("MATCH: constant switch(\"%.*s\") with %d cases optimized away"
  629. " to case no. %d\n", s.len, ZSW(s.s), n, i);
  630. /* cleanup */
  631. rval_destroy(rv);
  632. rv=0;
  633. pkg_free(s.s);
  634. s.s=0;
  635. s.len=0;
  636. ret=0;
  637. /* replace with BLOCK_ST */
  638. rve_destroy(m_rve);
  639. destroy_case_stms(t->val[1].u.data);
  640. t->type=BLOCK_T;
  641. t->val[0].type=BLOCK_ST;
  642. t->val[0].u.data=block;
  643. t->val[1].type=0;
  644. t->val[1].u.data=0;
  645. goto end;
  646. }
  647. mct=mk_match_cond_table(n);
  648. if (mct==0){
  649. LOG(L_ERR, "ERROR: fix_match: memory allocation error\n");
  650. ret=E_OUT_OF_MEM;
  651. goto error;
  652. }
  653. mct->n=n;
  654. for (i=0; i<n; i++){
  655. mct->match[i]=match[i];
  656. mct->jump[i]=*jmp_bm[i];
  657. }
  658. mct->def=def_jmp_bm?*def_jmp_bm:0;
  659. t->type=MATCH_COND_T;
  660. t->val[1].type=MATCH_CONDTABLE_ST;
  661. t->val[1].u.data=mct;
  662. DBG("MATCH: optimized to match condtable (%d) default: %s\n ",
  663. mct->n, mct->def?"yes":"no");
  664. ret=0;
  665. end:
  666. error:
  667. if (match) pkg_free(match);
  668. if (jmp_bm) pkg_free(jmp_bm);
  669. /* cleanup rv & s*/
  670. if (rv) rval_destroy(rv);
  671. if (s.s) pkg_free(s.s);
  672. return ret;
  673. }
  674. /* vi: set ts=4 sw=4 tw=79:ai:cindent: */