RPA Toolkit
work on conditional instruction execution
[rpatk.git] / rpa2 / rpavm.c
1 #include "rpavm.h"
2 #include "rpastat.h"
3 #include "rutf.h"
4 #include "rmem.h"
5
6
7 //static void rpavm_swi_shift(rvmcpu_t *cpu, rvm_asmins_t *ins)
8 //{
9 //      rpastat_t *stat = (rpastat_t *)cpu->userdata1;
10 //      rlong tp = RVM_CPUREG_GETL(cpu, R_TOP);
11 //      rpainput_t * ptp = &stat->instack[tp];
12 //
13 //      if (ptp->eof)
14 //              return;
15 //      ptp++;
16 //      tp++;
17 //      if (tp >= (rlong)stat->ip.serial) {
18 //              rint inc = 0;
19 //              ptp->input = stat->ip.input;
20 //              if (ptp->input < stat->end) {
21 //                      inc = r_utf8_mbtowc(&ptp->wc, (const ruchar*)stat->ip.input, (const ruchar*)stat->end);
22 //                      stat->ip.input += inc;
23 //                      stat->ip.serial += 1;
24 //                      ptp->eof = 0;
25 //              } else {
26 //                      ptp->wc = (ruint32)-1;
27 //                      ptp->eof = 1;
28 //              }
29 //      }
30 //      RVM_CPUREG_SETL(cpu, R_TOP, tp);
31 //}
32
33 static void rpavm_swi_shift(rvmcpu_t *cpu, rvm_asmins_t *ins)
34 {
35         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
36         rlong top = RVM_CPUREG_GETL(cpu, R_TOP);
37
38         if ((top = rpa_stat_shift(stat, top)) >= 0)
39                 RVM_CPUREG_SETL(cpu, R_TOP, top);
40 }
41
42 static void rpavm_matchchr_do(rvmcpu_t *cpu, rvm_asmins_t *ins, rword flags)
43 {
44         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
45         rword wc = RVM_CPUREG_GETU(cpu, ins->op1);
46         rword matched = 0;
47
48         if (flags == RPA_MATCH_OPTIONAL) {
49                 if (rpa_stat_matchchr(stat, RVM_CPUREG_GETL(cpu, R_TOP), wc) > 0) {
50                         rpavm_swi_shift(cpu, ins);
51                         matched = 1;
52                 }
53                 cpu->status = matched ? 0 : RVM_STATUS_Z;
54                 RVM_CPUREG_SETU(cpu, R0, matched);
55         } else if (flags == RPA_MATCH_MULTIPLE) {
56                 while (rpa_stat_matchchr(stat, RVM_CPUREG_GETL(cpu, R_TOP), wc) > 0) {
57                         rpavm_swi_shift(cpu, ins);
58                         matched += 1;
59                 }
60                 cpu->status = matched ? 0 : RVM_STATUS_N;
61                 RVM_CPUREG_SETU(cpu, R0, matched ? matched : (rword)-1);
62         } else if (flags == RPA_MATCH_MULTIOPT) {
63                 while (rpa_stat_matchchr(stat, RVM_CPUREG_GETL(cpu, R_TOP), wc) > 0) {
64                         rpavm_swi_shift(cpu, ins);
65                         matched += 1;
66                 }
67                 cpu->status = matched ? 0 : RVM_STATUS_Z;
68                 RVM_CPUREG_SETU(cpu, R0, matched );
69         } else {
70                 if (rpa_stat_matchchr(stat, RVM_CPUREG_GETL(cpu, R_TOP), wc) > 0) {
71                         rpavm_swi_shift(cpu, ins);
72                         matched = 1;
73                 }
74                 cpu->status = matched ? 0 : RVM_STATUS_N;
75                 RVM_CPUREG_SETU(cpu, R0, matched ? matched : (rword)-1);
76         }
77 }
78
79
80 static void rpavm_matchspchr_do(rvmcpu_t *cpu, rvm_asmins_t *ins, rword flags)
81 {
82         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
83         rword wc = RVM_CPUREG_GETU(cpu, ins->op1);
84         rword matched = 0;
85
86         if (flags == RPA_MATCH_OPTIONAL) {
87                 if (rpa_stat_matchspchr(stat, RVM_CPUREG_GETL(cpu, R_TOP), wc) > 0) {
88                         rpavm_swi_shift(cpu, ins);
89                         matched = 1;
90                 }
91                 cpu->status = matched ? 0 : RVM_STATUS_Z;
92                 RVM_CPUREG_SETU(cpu, R0, matched);
93         } else if (flags == RPA_MATCH_MULTIPLE) {
94                 while (rpa_stat_matchspchr(stat, RVM_CPUREG_GETL(cpu, R_TOP), wc) > 0) {
95                         rpavm_swi_shift(cpu, ins);
96                         matched += 1;
97                 }
98                 cpu->status = matched ? 0 : RVM_STATUS_N;
99                 RVM_CPUREG_SETU(cpu, R0, matched ? matched : (rword)-1);
100         } else if (flags == RPA_MATCH_MULTIOPT) {
101                 while (rpa_stat_matchspchr(stat, RVM_CPUREG_GETL(cpu, R_TOP), wc) > 0) {
102                         rpavm_swi_shift(cpu, ins);
103                         matched += 1;
104                 }
105                 cpu->status = matched ? 0 : RVM_STATUS_Z;
106                 RVM_CPUREG_SETU(cpu, R0, matched );
107         } else {
108                 if (rpa_stat_matchspchr(stat, RVM_CPUREG_GETL(cpu, R_TOP), wc) > 0) {
109                         rpavm_swi_shift(cpu, ins);
110                         matched = 1;
111                 }
112                 cpu->status = matched ? 0 : RVM_STATUS_N;
113                 RVM_CPUREG_SETU(cpu, R0, matched ? matched : (rword)-1);
114         }
115 }
116
117
118 static void rpavm_swi_matchchr_nan(rvmcpu_t *cpu, rvm_asmins_t *ins)
119 {
120         rpavm_matchchr_do(cpu, ins, RPA_MATCH_NONE);
121 }
122
123
124 static void rpavm_swi_matchchr_opt(rvmcpu_t *cpu, rvm_asmins_t *ins)
125 {
126         rpavm_matchchr_do(cpu, ins, RPA_MATCH_OPTIONAL);
127 }
128
129
130 static void rpavm_swi_matchchr_mul(rvmcpu_t *cpu, rvm_asmins_t *ins)
131 {
132         rpavm_matchchr_do(cpu, ins, RPA_MATCH_MULTIPLE);
133 }
134
135
136 static void rpavm_swi_matchchr_mop(rvmcpu_t *cpu, rvm_asmins_t *ins)
137 {
138         rpavm_matchchr_do(cpu, ins, RPA_MATCH_MULTIOPT);
139 }
140
141
142
143
144 static void rpavm_swi_matchspchr_nan(rvmcpu_t *cpu, rvm_asmins_t *ins)
145 {
146         rpavm_matchspchr_do(cpu, ins, RPA_MATCH_NONE);
147 }
148
149
150 static void rpavm_swi_matchspchr_opt(rvmcpu_t *cpu, rvm_asmins_t *ins)
151 {
152         rpavm_matchspchr_do(cpu, ins, RPA_MATCH_OPTIONAL);
153 }
154
155
156 static void rpavm_swi_matchspchr_mul(rvmcpu_t *cpu, rvm_asmins_t *ins)
157 {
158         rpavm_matchspchr_do(cpu, ins, RPA_MATCH_MULTIPLE);
159 }
160
161
162 static void rpavm_swi_matchspchr_mop(rvmcpu_t *cpu, rvm_asmins_t *ins)
163 {
164         rpavm_matchspchr_do(cpu, ins, RPA_MATCH_MULTIOPT);
165 }
166
167
168 static void rpavm_matchrng_do(rvmcpu_t *cpu, rvm_asmins_t *ins, rword flags)
169 {
170         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
171         rpair_t pr = RVM_CPUREG_GETPAIR(cpu, ins->op1);
172         rword matched = 0;
173
174         if (flags == RPA_MATCH_OPTIONAL) {
175                 if (rpa_stat_matchrng(stat, RVM_CPUREG_GETL(cpu, R_TOP), pr.p1, pr.p2) > 0) {
176                         rpavm_swi_shift(cpu, ins);
177                         matched = 1;
178                 }
179                 cpu->status = matched ? 0 : RVM_STATUS_Z;
180                 RVM_CPUREG_SETU(cpu, R0, matched);
181         } else if (flags == RPA_MATCH_MULTIPLE) {
182                 while (rpa_stat_matchrng(stat, RVM_CPUREG_GETL(cpu, R_TOP), pr.p1, pr.p2) > 0) {
183                         rpavm_swi_shift(cpu, ins);
184                         matched += 1;
185                 }
186                 cpu->status = matched ? 0 : RVM_STATUS_N;
187                 RVM_CPUREG_SETU(cpu, R0, matched ? matched : (rword)-1);
188         } else if (flags == RPA_MATCH_MULTIOPT) {
189                 while (rpa_stat_matchrng(stat, RVM_CPUREG_GETL(cpu, R_TOP), pr.p1, pr.p2) > 0) {
190                         rpavm_swi_shift(cpu, ins);
191                         matched += 1;
192                 }
193                 cpu->status = matched ? 0 : RVM_STATUS_Z;
194                 RVM_CPUREG_SETU(cpu, R0, matched );
195         } else {
196                 if (rpa_stat_matchrng(stat, RVM_CPUREG_GETL(cpu, R_TOP), pr.p1, pr.p2) > 0) {
197                         rpavm_swi_shift(cpu, ins);
198                         matched = 1;
199                 }
200                 cpu->status = matched ? 0 : RVM_STATUS_N;
201                 RVM_CPUREG_SETU(cpu, R0, matched ? matched : (rword)-1);
202         }
203 }
204
205
206 static void rpavm_swi_matchrng_nan(rvmcpu_t *cpu, rvm_asmins_t *ins)
207 {
208         rpavm_matchrng_do(cpu, ins, RPA_MATCH_NONE);
209 }
210
211
212 static void rpavm_swi_matchrng_opt(rvmcpu_t *cpu, rvm_asmins_t *ins)
213 {
214         rpavm_matchrng_do(cpu, ins, RPA_MATCH_OPTIONAL);
215 }
216
217
218 static void rpavm_swi_matchrng_mul(rvmcpu_t *cpu, rvm_asmins_t *ins)
219 {
220         rpavm_matchrng_do(cpu, ins, RPA_MATCH_MULTIPLE);
221 }
222
223
224 static void rpavm_swi_matchrng_mop(rvmcpu_t *cpu, rvm_asmins_t *ins)
225 {
226         rpavm_matchrng_do(cpu, ins, RPA_MATCH_MULTIOPT);
227 }
228
229
230
231 static void rpavm_swi_emitstart(rvmcpu_t *cpu, rvm_asmins_t *ins)
232 {
233         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
234         rparecord_t *rec;
235         rlong index;
236         rword tp = RVM_CPUREG_GETU(cpu, ins->op2);
237         rstr_t name = {RVM_CPUREG_GETSTR(cpu, ins->op1), RVM_CPUREG_GETSIZE(cpu, ins->op1)};
238
239         index = r_array_add(stat->records, NULL);
240         rec = (rparecord_t *)r_array_slot(stat->records, index);
241         rec->rule = name.str;
242         rec->top = tp;
243         rec->type = RPA_RECORD_START;
244         rec->input = stat->instack[tp].input;
245         rec->inputsiz = 0;
246         RVM_CPUREG_SETU(cpu, R_REC, r_array_length(stat->records));
247
248 //      r_printf("START: %s(%ld)\n", name.str, (rulong)tp);
249 }
250
251
252 static void rpavm_swi_emitend(rvmcpu_t *cpu, rvm_asmins_t *ins)
253 {
254         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
255         rparecord_t *rec;
256         rlong index;
257         rword tp = RVM_CPUREG_GETU(cpu, ins->op2);
258         rword tplen = RVM_CPUREG_GETU(cpu, ins->op3);
259         rstr_t name = {RVM_CPUREG_GETSTR(cpu, ins->op1), RVM_CPUREG_GETSIZE(cpu, ins->op1)};
260
261         index = r_array_add(stat->records, NULL);
262         rec = (rparecord_t *)r_array_slot(stat->records, index);
263         rec->rule = name.str;
264         rec->top = tp;
265         rec->size = tplen;
266         rec->type = RPA_RECORD_START;
267         rec->input = stat->instack[tp].input;
268         rec->inputsiz = stat->instack[tp + tplen].input - stat->instack[tp].input;
269
270         if (tplen) {
271                 rec->type = RPA_RECORD_END | RPA_RECORD_MATCH;
272 //              r_printf("MATCHED: %s(%ld, %ld): %p(%d)\n", name.str, (rulong)tp, (rulong)tplen, name.str, name.size);
273         } else {
274                 rec->type = RPA_RECORD_END;
275 //              r_printf("MATCHED: %s(%ld, %ld)\n", name.str, (rulong)tp, (rulong)tplen);
276         }
277         RVM_CPUREG_SETU(cpu, R_REC, r_array_length(stat->records));
278 }
279
280
281 static void rpavm_swi_getreclen(rvmcpu_t *cpu, rvm_asmins_t *ins)
282 {
283         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
284         RVM_CPUREG_SETU(cpu, ins->op1, r_array_length(stat->records));
285 }
286
287
288 static void rpavm_swi_setreclen(rvmcpu_t *cpu, rvm_asmins_t *ins)
289 {
290         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
291
292         r_array_setlength(stat->records, (ruint)RVM_CPUREG_GETU(cpu, ins->op1));
293
294
295 //      if (RVM_CPUREG_GETU(cpu, ins->op1) != RVM_CPUREG_GETU(cpu, R_REC)) {
296 //              r_printf("setreclen = %ld, R_REC = %ld\n", RVM_CPUREG_GETU(cpu, ins->op1), RVM_CPUREG_GETU(cpu, R_REC));
297 //      }
298 }
299
300
301 static void rpavm_swi_setrecid(rvmcpu_t *cpu, rvm_asmins_t *ins)
302 {
303         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
304         rparecord_t *rec;
305         rword ruleid = RVM_CPUREG_GETU(cpu, ins->op1);
306
307         rec = (rparecord_t *)r_array_lastslot(stat->records);
308         if (rec) {
309                 rec->ruleid = ruleid;
310         }
311 }
312
313
314 static void rpavm_swi_loopdetect(rvmcpu_t *cpu, rvm_asmins_t *ins)
315 {
316         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
317         rparecord_t *rec;
318         rlong len;
319         rword ruleid = RVM_CPUREG_GETU(cpu, ins->op1);
320         rword tp = RVM_CPUREG_GETU(cpu, ins->op2);
321         rword fp = RVM_CPUREG_GETU(cpu, FP);
322         rvmreg_t loo, rid, top, pfp;
323
324         RVM_CPUREG_SETU(cpu, R0, -1);
325
326         while (fp > 5) {
327                 top = RVM_STACK_READ(cpu->stack, fp - 3);
328                 loo = RVM_STACK_READ(cpu->stack, fp - 4);
329                 rid = RVM_STACK_READ(cpu->stack, fp - 5);
330
331                 if (rid.v.l == ruleid && top.v.l == tp) {
332                         RVM_CPUREG_SETU(cpu, R0, loo.v.l);
333                         break;
334                 }
335                 RVM_REG_CLEAR(&loo);
336                 pfp = RVM_STACK_READ(cpu->stack, fp - 1);
337                 fp = pfp.v.l;
338         }
339
340 //      for (len = r_array_length(stat->records); len > 0; len--) {
341 //              rec = (rparecord_t *)r_array_slot(stat->records, len - 1);
342 //              if (rec->type == (RPA_RECORD_END | RPA_RECORD_MATCH)) {
343 //                      RVM_CPUREG_SETU(cpu, R0, -1);
344 //                      break;
345 //              } else if (rec->ruleid == ruleid && rec->top == tp) {
346 //                      RVM_CPUREG_SETU(cpu, R0, RVM_CPUREG_GETU(cpu, R_LOO));
347 //                      RVM_CPUREG_SETU(cpu, R_TOP, RVM_CPUREG_GETU(cpu, R_TOP) + RVM_CPUREG_GETU(cpu, R_LOO));
348 //                      r_printf("LOO = %ld, loo = %ld\n", RVM_CPUREG_GETU(cpu, R0), loo.v.l);
349 //                      RVM_CPUREG_SETU(cpu, R0, loo.v.l);
350 //                      break;
351 //              }
352 //      }
353 }
354
355
356 static void rpavm_swi_setcache(rvmcpu_t *cpu, rvm_asmins_t *ins)
357 {
358         rparecord_t *prec;
359         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
360         rlong ruleid = RVM_CPUREG_GETL(cpu, ins->op1);
361         rlong r0 = RVM_CPUREG_GETL(cpu, ins->op2);
362         rlong rec = RVM_CPUREG_GETL(cpu, ins->op3);
363         rlong nrecords = r_array_length(stat->records) - rec;
364
365         /*
366          * If the record set is too big, don't use the cache
367          */
368         if (nrecords > 50)
369                 return;
370
371         if (!RVM_STATUS_GETBIT(cpu, RVM_STATUS_N) && !RVM_STATUS_GETBIT(cpu, RVM_STATUS_Z)) {
372                 prec = (rparecord_t *)r_array_slot(stat->records, rec);
373 //              r_printf("Set the cache for: %s (%ld)\n", prec->rule, nrecords);
374                 R_ASSERT(nrecords);
375                 rpa_cache_set(stat->cache, prec->top, ruleid, r0, prec, nrecords);
376         }
377 }
378
379
380 static void rpavm_swi_checkcache(rvmcpu_t *cpu, rvm_asmins_t *ins)
381 {
382         rlong i;
383         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
384         rpacachedentry_t *entry;
385         rlong ruleid = RVM_CPUREG_GETL(cpu, ins->op1);
386         rlong top = RVM_CPUREG_GETL(cpu, ins->op2);
387         rlong r0 = 0;
388         entry = rpa_cache_lookup(stat->cache, top, ruleid);
389         if (entry) {
390 //              rparecord_t *prec = (rparecord_t *)r_array_slot(entry->records, 0);
391 //              r_printf("Hit the cache for: %s (%ld), r0 = %ld\n", prec->rule, r_array_length(entry->records), entry->ret);
392                 for (i = 0; i < r_array_length(entry->records); i++) {
393                         r_array_add(stat->records, r_array_slot(entry->records, i));
394                 }
395                 r0 = entry->ret;
396                 top += r0;
397                 RVM_CPUREG_SETU(cpu, R_TOP, top);
398         }
399
400         RVM_STATUS_CLRALL(cpu);
401         RVM_CPUREG_SETU(cpu, R0, r0);
402         RVM_STATUS_UPDATE(cpu, RVM_STATUS_Z, !r0);
403 }
404
405
406 static void rpavm_swi_setrecuid(rvmcpu_t *cpu, rvm_asmins_t *ins)
407 {
408         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
409         rparecord_t *rec;
410         rword userid = RVM_CPUREG_GETU(cpu, ins->op1);
411
412         rec = (rparecord_t *)r_array_lastslot(stat->records);
413         if (rec) {
414                 rec->userid = (ruint32)userid;
415         }
416 }
417
418 static rvm_switable_t rpavm_swi_table[] = {
419                 {"RPA_MATCHCHR_NAN", rpavm_swi_matchchr_nan},
420                 {"RPA_MATCHCHR_OPT", rpavm_swi_matchchr_opt},
421                 {"RPA_MATCHCHR_MUL", rpavm_swi_matchchr_mul},
422                 {"RPA_MATCHCHR_MOP", rpavm_swi_matchchr_mop},
423                 {"RPA_MATCHRNG_NAN", rpavm_swi_matchrng_nan},
424                 {"RPA_MATCHRNG_OPT", rpavm_swi_matchrng_opt},
425                 {"RPA_MATCHRNG_MUL", rpavm_swi_matchrng_mul},
426                 {"RPA_MATCHRNG_MOP", rpavm_swi_matchrng_mop},
427                 {"RPA_MATCHSPCHR_NAN", rpavm_swi_matchspchr_nan},
428                 {"RPA_MATCHSPCHR_OPT", rpavm_swi_matchspchr_opt},
429                 {"RPA_MATCHSPCHR_MUL", rpavm_swi_matchspchr_mul},
430                 {"RPA_MATCHSPCHR_MOP", rpavm_swi_matchspchr_mop},
431                 {"RPA_SHIFT", rpavm_swi_shift},
432                 {"RPA_EMITSTART", rpavm_swi_emitstart},
433                 {"RPA_EMITEND", rpavm_swi_emitend},
434                 {"RPA_GETRECLEN", rpavm_swi_getreclen},
435                 {"RPA_SETRECLEN", rpavm_swi_setreclen},
436                 {"RPA_SETRECID", rpavm_swi_setrecid},
437                 {"RPA_LOOPDETECT", rpavm_swi_loopdetect},
438                 {"RPA_SETCACHE", rpavm_swi_setcache},
439                 {"RPA_CHECKCACHE", rpavm_swi_checkcache},
440                 {"RPA_SETRECUID", rpavm_swi_setrecuid},
441                 {NULL, NULL},
442 };
443
444
445 rvmcpu_t *rpavm_cpu_create(rulong stacksize)
446 {
447         rvmcpu_t *cpu = rvm_cpu_create(stacksize);
448         rint tableid = rvm_cpu_addswitable(cpu, "rpavm_swi_table", rpavm_swi_table);
449
450         if (tableid != RPAVM_SWI_TABLEID) {
451                 rpavm_cpu_destroy(cpu);
452                 return NULL;
453         }
454         return cpu;
455 }
456
457
458 void rpavm_cpu_destroy(rvmcpu_t * cpu)
459 {
460         rvm_cpu_destroy(cpu);
461 }
462
463