RPA Toolkit
Added RJS to the project. Reduced the size of the rparecord_t.
[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 top = RVM_CPUREG_GETL(cpu, R_TOP);
11
12         if ((top = rpa_stat_shift(stat, top)) >= 0)
13                 RVM_CPUREG_SETL(cpu, R_TOP, top);
14 }
15
16
17 static void rpavm_swi_matchchr_nan(rvmcpu_t *cpu, rvm_asmins_t *ins)
18 {
19         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
20         rword wc = RVM_CPUREG_GETU(cpu, ins->op1);
21         rword matched = 0;
22
23         if (rpa_stat_matchchr(stat, RVM_CPUREG_GETL(cpu, R_TOP), wc) > 0) {
24                 rpavm_swi_shift(cpu, ins);
25                 matched = 1;
26         }
27         cpu->status = matched ? 0 : RVM_STATUS_N;
28         RVM_CPUREG_SETU(cpu, R0, matched ? matched : (rword)-1);
29 }
30
31
32 static void rpavm_swi_matchchr_opt(rvmcpu_t *cpu, rvm_asmins_t *ins)
33 {
34         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
35         rword wc = RVM_CPUREG_GETU(cpu, ins->op1);
36         rword matched = 0;
37
38         if (rpa_stat_matchspchr(stat, RVM_CPUREG_GETL(cpu, R_TOP), wc) > 0) {
39                 rpavm_swi_shift(cpu, ins);
40                 matched = 1;
41         }
42         cpu->status = matched ? 0 : RVM_STATUS_Z;
43         RVM_CPUREG_SETU(cpu, R0, matched);
44 }
45
46
47 static void rpavm_swi_matchchr_mul(rvmcpu_t *cpu, rvm_asmins_t *ins)
48 {
49         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
50         rword wc = RVM_CPUREG_GETU(cpu, ins->op1);
51         rword matched = 0;
52
53         while (rpa_stat_matchspchr(stat, RVM_CPUREG_GETL(cpu, R_TOP), wc) > 0) {
54                 rpavm_swi_shift(cpu, ins);
55                 matched += 1;
56         }
57         cpu->status = matched ? 0 : RVM_STATUS_N;
58         RVM_CPUREG_SETU(cpu, R0, matched ? matched : (rword)-1);
59 }
60
61
62 static void rpavm_swi_matchchr_mop(rvmcpu_t *cpu, rvm_asmins_t *ins)
63 {
64         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
65         rword wc = RVM_CPUREG_GETU(cpu, ins->op1);
66         rword matched = 0;
67
68         while (rpa_stat_matchchr(stat, RVM_CPUREG_GETL(cpu, R_TOP), wc) > 0) {
69                 rpavm_swi_shift(cpu, ins);
70                 matched += 1;
71         }
72         cpu->status = matched ? 0 : RVM_STATUS_Z;
73         RVM_CPUREG_SETU(cpu, R0, matched );
74 }
75
76
77 static void rpavm_swi_matchspchr_nan(rvmcpu_t *cpu, rvm_asmins_t *ins)
78 {
79         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
80         rword wc = RVM_CPUREG_GETU(cpu, ins->op1);
81         rword matched = 0;
82
83         if (rpa_stat_matchspchr(stat, RVM_CPUREG_GETL(cpu, R_TOP), wc) > 0) {
84                 rpavm_swi_shift(cpu, ins);
85                 matched = 1;
86         }
87         cpu->status = matched ? 0 : RVM_STATUS_N;
88         RVM_CPUREG_SETU(cpu, R0, matched ? matched : (rword)-1);
89 }
90
91
92 static void rpavm_swi_matchspchr_opt(rvmcpu_t *cpu, rvm_asmins_t *ins)
93 {
94         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
95         rword wc = RVM_CPUREG_GETU(cpu, ins->op1);
96         rword matched = 0;
97
98         if (rpa_stat_matchspchr(stat, RVM_CPUREG_GETL(cpu, R_TOP), wc) > 0) {
99                 rpavm_swi_shift(cpu, ins);
100                 matched = 1;
101         }
102         cpu->status = matched ? 0 : RVM_STATUS_Z;
103         RVM_CPUREG_SETU(cpu, R0, matched);
104
105 }
106
107
108 static void rpavm_swi_matchspchr_mul(rvmcpu_t *cpu, rvm_asmins_t *ins)
109 {
110         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
111         rword wc = RVM_CPUREG_GETU(cpu, ins->op1);
112         rword matched = 0;
113
114         while (rpa_stat_matchspchr(stat, RVM_CPUREG_GETL(cpu, R_TOP), wc) > 0) {
115                 rpavm_swi_shift(cpu, ins);
116                 matched += 1;
117         }
118         cpu->status = matched ? 0 : RVM_STATUS_N;
119         RVM_CPUREG_SETU(cpu, R0, matched ? matched : (rword)-1);
120
121 }
122
123
124 static void rpavm_swi_matchspchr_mop(rvmcpu_t *cpu, rvm_asmins_t *ins)
125 {
126         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
127         rword wc = RVM_CPUREG_GETU(cpu, ins->op1);
128         rword matched = 0;
129
130         while (rpa_stat_matchspchr(stat, RVM_CPUREG_GETL(cpu, R_TOP), wc) > 0) {
131                 rpavm_swi_shift(cpu, ins);
132                 matched += 1;
133         }
134         cpu->status = matched ? 0 : RVM_STATUS_Z;
135         RVM_CPUREG_SETU(cpu, R0, matched );
136 }
137
138
139 static void rpavm_swi_matchrng_peek(rvmcpu_t *cpu, rvm_asmins_t *ins)
140 {
141         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
142         rpair_t pr = RVM_CPUREG_GETPAIR(cpu, ins->op1);
143         rword matched = 0;
144
145         if (rpa_stat_matchrng(stat, RVM_CPUREG_GETL(cpu, R_TOP), pr.p1, pr.p2) <= 0) {
146                 cpu->status = matched ? 0 : RVM_STATUS_N;
147                 RVM_CPUREG_SETU(cpu, R0, matched ? matched : (rword)-1);
148         }
149 }
150
151
152 static void rpavm_swi_matchrng_nan(rvmcpu_t *cpu, rvm_asmins_t *ins)
153 {
154         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
155         rpair_t pr = RVM_CPUREG_GETPAIR(cpu, ins->op1);
156         rword matched = 0;
157
158         if (rpa_stat_matchrng(stat, RVM_CPUREG_GETL(cpu, R_TOP), pr.p1, pr.p2) > 0) {
159                 rpavm_swi_shift(cpu, ins);
160                 matched = 1;
161         }
162         cpu->status = matched ? 0 : RVM_STATUS_N;
163         RVM_CPUREG_SETU(cpu, R0, matched ? matched : (rword)-1);
164 }
165
166
167 static void rpavm_swi_matchrng_opt(rvmcpu_t *cpu, rvm_asmins_t *ins)
168 {
169         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
170         rpair_t pr = RVM_CPUREG_GETPAIR(cpu, ins->op1);
171         rword matched = 0;
172
173         if (rpa_stat_matchrng(stat, RVM_CPUREG_GETL(cpu, R_TOP), pr.p1, pr.p2) > 0) {
174                 rpavm_swi_shift(cpu, ins);
175                 matched = 1;
176         }
177         cpu->status = matched ? 0 : RVM_STATUS_Z;
178         RVM_CPUREG_SETU(cpu, R0, matched);
179 }
180
181
182 static void rpavm_swi_matchrng_mul(rvmcpu_t *cpu, rvm_asmins_t *ins)
183 {
184         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
185         rpair_t pr = RVM_CPUREG_GETPAIR(cpu, ins->op1);
186         rword matched = 0;
187
188         while (rpa_stat_matchrng(stat, RVM_CPUREG_GETL(cpu, R_TOP), pr.p1, pr.p2) > 0) {
189                 rpavm_swi_shift(cpu, ins);
190                 matched += 1;
191         }
192         cpu->status = matched ? 0 : RVM_STATUS_N;
193         RVM_CPUREG_SETU(cpu, R0, matched ? matched : (rword)-1);
194 }
195
196
197 static void rpavm_swi_matchrng_mop(rvmcpu_t *cpu, rvm_asmins_t *ins)
198 {
199         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
200         rpair_t pr = RVM_CPUREG_GETPAIR(cpu, ins->op1);
201         rword matched = 0;
202
203         while (rpa_stat_matchrng(stat, RVM_CPUREG_GETL(cpu, R_TOP), pr.p1, pr.p2) > 0) {
204                 rpavm_swi_shift(cpu, ins);
205                 matched += 1;
206         }
207         cpu->status = matched ? 0 : RVM_STATUS_Z;
208         RVM_CPUREG_SETU(cpu, R0, matched );
209 }
210
211
212
213 static void rpavm_swi_emithead(rvmcpu_t *cpu, rvm_asmins_t *ins)
214 {
215         rparecord_t *rec;
216         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
217         rlong index = RVM_CPUREG_GETL(cpu, R_REC);
218
219         index = r_array_add(stat->records, NULL);
220         RVM_CPUREG_SETL(cpu, R_REC, index);
221         rec = (rparecord_t *)r_array_slot(stat->records, index);
222         rec->type = RPA_RECORD_HEAD;
223 }
224
225
226 static void rpavm_swi_emittail(rvmcpu_t *cpu, rvm_asmins_t *ins)
227 {
228         rparecord_t *rec, *crec;
229         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
230         rlong index = RVM_CPUREG_GETL(cpu, R_REC);
231
232         index = r_array_add(stat->records, NULL);
233         crec = (rparecord_t *)r_array_slot(stat->records, RVM_CPUREG_GETL(cpu, R_REC));
234         RVM_CPUREG_SETL(cpu, R_REC, index);
235         rec = (rparecord_t *)r_array_slot(stat->records, index);
236         rec->type = RPA_RECORD_TAIL;
237         crec->next = index;
238 }
239
240
241 static void rpavm_swi_emitstart(rvmcpu_t *cpu, rvm_asmins_t *ins)
242 {
243         rpa_ruledata_t *ruledata = RVM_CPUREG_GETP(cpu, ins->op1);
244         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
245         rparecord_t *rec, *crec;
246         rlong index = RVM_CPUREG_GETL(cpu, R_REC);
247         rword tp = RVM_CPUREG_GETU(cpu, ins->op2);
248         rstr_t name = {(rchar*)ruledata + ruledata->name, ruledata->namesize};
249
250         if (!(ruledata->flags & RPA_RFLAG_EMITRECORD))
251                 return;
252 //      r_printf("%ld: %s, %s, tp = %ld\n", RVM_CPUREG_GETU(cpu, FP), "START", name.str, tp);
253         R_ASSERT(RVM_CPUREG_GETL(cpu, R_REC) >= 0);
254 //      index = r_array_replace(stat->records, index + 1, NULL);
255         index = r_array_add(stat->records, NULL);
256
257         /*
258          * Important: get the pointer to crec after modifying the array, because if
259          * it gets reallocated the pointer will be invalid.
260          */
261         crec = (rparecord_t *)r_array_slot(stat->records, RVM_CPUREG_GETL(cpu, R_REC));
262         RVM_CPUREG_SETL(cpu, R_REC, index);
263         rec = (rparecord_t *)r_array_slot(stat->records, index);
264         rec->rule = name.str;
265         rec->top = tp;
266         rec->ruleuid = ruledata->ruleuid;
267         rec->type = RPA_RECORD_START;
268         rec->input = stat->instack[tp].input;
269         rec->inputsiz = 0;
270         crec->next = index;
271 }
272
273
274
275 static void rpavm_swi_emitend(rvmcpu_t *cpu, rvm_asmins_t *ins)
276 {
277         rpa_ruledata_t *ruledata = RVM_CPUREG_GETP(cpu, ins->op1);
278         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
279         rparecord_t *rec, *crec;
280         rlong index = RVM_CPUREG_GETL(cpu, R_REC);
281         rword tp = RVM_CPUREG_GETU(cpu, ins->op2);
282         rword tplen = RVM_CPUREG_GETU(cpu, ins->op3);
283         rstr_t name = {(rchar*)ruledata + ruledata->name, ruledata->namesize};
284
285         if (!(ruledata->flags & RPA_RFLAG_EMITRECORD))
286                 return;
287 //      r_printf("%ld: %s, %s, tp = %ld, tplen = %ld\n", RVM_CPUREG_GETU(cpu, FP), "END ", name.str, tp, tplen);
288         R_ASSERT(RVM_CPUREG_GETL(cpu, R_REC) >= 0);
289 //      index = r_array_replace(stat->records, index + 1, NULL);
290         index = r_array_add(stat->records, NULL);
291
292         /*
293          * Important: get the pointer to crec after modifying the array, because if
294          * it gets reallocated the pointer will be invalid.
295          */
296         crec = (rparecord_t *)r_array_slot(stat->records, RVM_CPUREG_GETL(cpu, R_REC));
297         RVM_CPUREG_SETL(cpu, R_REC, index);
298         rec = (rparecord_t *)r_array_slot(stat->records, index);
299         rec->rule = name.str;
300         rec->top = tp;
301         rec->size = tplen;
302         rec->type = RPA_RECORD_END;
303         rec->ruleuid = ruledata->ruleuid;
304         rec->input = stat->instack[tp].input;
305         rec->inputsiz = stat->instack[tp + tplen].input - stat->instack[tp].input;
306         crec->next = index;
307
308         if (tplen) {
309                 rec->type |= RPA_RECORD_MATCH;
310         }
311 }
312
313
314 static void rpavm_swi_prninfo(rvmcpu_t *cpu, rvm_asmins_t *ins)
315 {
316         rpa_ruledata_t *ruledata = RVM_CPUREG_GETP(cpu, ins->op1);
317         rstr_t name = {(rchar*)ruledata + ruledata->name, ruledata->namesize};
318
319         if (!(ruledata->flags & RPA_RFLAG_EMITRECORD))
320                 return;
321         r_printf("%s: ", name.str);
322         rvm_cpu_dumpregs(cpu, ins);
323 }
324
325
326 static void rpavm_swi_getnextrec(rvmcpu_t *cpu, rvm_asmins_t *ins)
327 {
328         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
329         rlong rec = RVM_CPUREG_GETL(cpu, ins->op2);
330
331         rparecord_t *prec = (rparecord_t *)r_array_slot(stat->records, rec);
332
333 //      r_printf("%s, rec = %ld, next = %ld\n", __FUNCTION__, rec, prec->next);
334         RVM_CPUREG_SETL(cpu, ins->op1, prec->next);
335 }
336
337
338 static void rpavm_swi_getreclen(rvmcpu_t *cpu, rvm_asmins_t *ins)
339 {
340         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
341         RVM_CPUREG_SETU(cpu, ins->op1, r_array_length(stat->records));
342 }
343
344
345 static void rpavm_swi_setreclen(rvmcpu_t *cpu, rvm_asmins_t *ins)
346 {
347         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
348
349         r_array_setlength(stat->records, (ruint)RVM_CPUREG_GETU(cpu, ins->op1));
350         RVM_CPUREG_SETL(cpu, R_REC, RVM_CPUREG_GETU(cpu, ins->op1) - 1);
351 }
352
353
354 static void rpavm_swi_getcurrec(rvmcpu_t *cpu, rvm_asmins_t *ins)
355 {
356         RVM_CPUREG_SETL(cpu, ins->op1, RVM_CPUREG_GETL(cpu, R_REC));
357 }
358
359
360 static void rpavm_swi_setcurrec(rvmcpu_t *cpu, rvm_asmins_t *ins)
361 {
362         RVM_CPUREG_SETL(cpu, R_REC, RVM_CPUREG_GETU(cpu, ins->op1));
363 }
364
365
366 static void rpavm_swi_setcache(rvmcpu_t *cpu, rvm_asmins_t *ins)
367 {
368         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
369         rlong r0 = RVM_CPUREG_GETL(cpu, R0);
370         rlong ruleid = RVM_CPUREG_GETL(cpu, ins->op1);
371         rlong prevrec = RVM_CPUREG_GETL(cpu, ins->op2);
372         rlong endrec = RVM_CPUREG_GETL(cpu, ins->op3);
373         rlong top = RVM_CPUREG_GETL(cpu, R_OTP);
374         rlong startrec = 0;
375         rparecord_t *prec = NULL;
376
377         if (stat->cache->disalbled)
378                 return;
379
380         if (r0 > 0 && prevrec != endrec) {
381                 prec = (rparecord_t *)r_array_slot(stat->records, prevrec);
382                 startrec = prec->next;
383                 prec = (rparecord_t *)r_array_slot(stat->records, startrec);
384 //              r_printf("Set the cache for: %s (%ld, %ld), top = %ld, ret = %ld, ruleid=%ld\n", prec->rule, startrec, endrec, prec->top, r0, ruleid);
385                 rpa_cache_set(stat->cache, top, ruleid, r0, startrec, endrec);
386
387                 /*
388                  * The next optimization is supposed to reduce the size of
389                  * garbage records.
390                  */
391                 if (stat->cursize < endrec + 1)
392                         stat->cursize = endrec + 1;
393         } else {
394                 rpa_cache_set(stat->cache, top, ruleid, r0, 0, 0);
395                 /*
396                  * The next optimization is supposed to reduce the size of
397                  * garbage records.
398                  */
399                 if (stat->cursize < endrec + 1) {
400                         r_array_setlength(stat->records, endrec + 1);
401                         stat->cursize = endrec + 1;
402                 }
403         }
404 }
405
406
407 static void rpavm_swi_checkcache(rvmcpu_t *cpu, rvm_asmins_t *ins)
408 {
409         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
410         rpacachedentry_t *entry;
411         rlong ruleid = RVM_CPUREG_GETL(cpu, ins->op1);
412         rlong top = RVM_CPUREG_GETL(cpu, ins->op2);
413         rlong r0 = 0;
414         entry = rpa_cache_lookup(stat->cache, top, ruleid);
415         if (entry) {
416 //              rparecord_t *prec = (rparecord_t *)r_array_slot(stat->records, entry->startrec);
417 //              r_printf("Hit the cache for: %s (%ld, %ld), r0 = %ld\n", prec->rule, entry->startrec, entry->endrec, entry->ret);
418
419                 r0 = entry->ret;
420                 if (entry->startrec != entry->endrec) {
421                         rparecord_t *crec = (rparecord_t *)r_array_slot(stat->records, RVM_CPUREG_GETL(cpu, R_REC));
422                         crec->next = entry->startrec;
423                         RVM_CPUREG_SETL(cpu, R_REC, entry->endrec);
424                 }
425                 if (r0 > 0) {
426                         top += r0;
427                         RVM_CPUREG_SETU(cpu, R_TOP, top);
428                 }
429         }
430
431         RVM_STATUS_CLRALL(cpu);
432         RVM_CPUREG_SETU(cpu, R0, r0);
433         RVM_STATUS_UPDATE(cpu, RVM_STATUS_Z, !r0);
434         if (r0 < 0 && entry) {
435                 RVM_STATUS_UPDATE(cpu, RVM_STATUS_N, (r0 < 0));
436 //              r_printf("Hit the cache for: %ld, r0 = %ld\n", entry->ruleid, entry->ret);
437         }
438 }
439
440
441 static void rpavm_swi_matchchrinstr_nan(rvmcpu_t *cpu, rvm_asmins_t *ins)
442 {
443         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
444         rchar *str = RVM_CPUREG_GETSTR(cpu, ins->op1);
445         rword matched = 0;
446         rword wc;
447
448         while (*str) {
449                 wc = *str++;
450                 if (rpa_stat_matchchr(stat, RVM_CPUREG_GETL(cpu, R_TOP), wc) > 0) {
451                         rpavm_swi_shift(cpu, ins);
452                         matched = 1;
453                         break;
454                 }
455         }
456         cpu->status = matched ? 0 : RVM_STATUS_N;
457         RVM_CPUREG_SETU(cpu, R0, matched ? matched : (rword)-1);
458 }
459
460
461
462
463 static rvm_switable_t rpavm_swi_table[] = {
464                 {"RPA_MATCHCHR_NAN", rpavm_swi_matchchr_nan},
465                 {"RPA_MATCHCHR_OPT", rpavm_swi_matchchr_opt},
466                 {"RPA_MATCHCHR_MUL", rpavm_swi_matchchr_mul},
467                 {"RPA_MATCHCHR_MOP", rpavm_swi_matchchr_mop},
468                 {"RPA_MATCHRNG_NAN", rpavm_swi_matchrng_nan},
469                 {"RPA_MATCHRNG_OPT", rpavm_swi_matchrng_opt},
470                 {"RPA_MATCHRNG_MUL", rpavm_swi_matchrng_mul},
471                 {"RPA_MATCHRNG_MOP", rpavm_swi_matchrng_mop},
472                 {"RPA_MATCHRNG_PEEK", rpavm_swi_matchrng_peek},
473                 {"RPA_MATCHSPCHR_NAN", rpavm_swi_matchspchr_nan},
474                 {"RPA_MATCHSPCHR_OPT", rpavm_swi_matchspchr_opt},
475                 {"RPA_MATCHSPCHR_MUL", rpavm_swi_matchspchr_mul},
476                 {"RPA_MATCHSPCHR_MOP", rpavm_swi_matchspchr_mop},
477                 {"RPA_SHIFT", rpavm_swi_shift},
478                 {"RPA_SETCACHE", rpavm_swi_setcache},
479                 {"RPA_CHECKCACHE", rpavm_swi_checkcache},
480                 {"RPA_EMITSTART", rpavm_swi_emitstart},
481                 {"RPA_EMITEND", rpavm_swi_emitend},
482                 {"RPA_EMITHEAD", rpavm_swi_emithead},
483                 {"RPA_EMITTAIL", rpavm_swi_emittail},
484                 {"RPA_GETNEXTREC", rpavm_swi_getnextrec},
485                 {"RPA_PRNINFO", rpavm_swi_prninfo},
486                 {"RPA_MATCHCHRINSTR_NAN", rpavm_swi_matchchrinstr_nan},
487
488                 {"RPA_GETRECLEN", rpavm_swi_getreclen},
489                 {"RPA_SETRECLEN", rpavm_swi_setreclen},
490                 {"RPA_GETCURREC", rpavm_swi_getcurrec},
491                 {"RPA_SETCURREC", rpavm_swi_setcurrec},
492                 {NULL, NULL},
493 };
494
495
496 rvmcpu_t *rpavm_cpu_create(rulong stacksize)
497 {
498         rvmcpu_t *cpu = rvm_cpu_create(stacksize);
499         rint tableid = rvm_cpu_addswitable(cpu, "rpavm_swi_table", rpavm_swi_table);
500
501         if (tableid != RPAVM_SWI_TABLEID) {
502                 rpavm_cpu_destroy(cpu);
503                 return NULL;
504         }
505         return cpu;
506 }
507
508
509 void rpavm_cpu_destroy(rvmcpu_t * cpu)
510 {
511         rvm_cpu_destroy(cpu);
512 }
513
514