RPA Toolkit
Moving away from RPA_BXL... 5
[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
247 //      r_printf("START: %s(%ld)\n", name.str, (rulong)tp);
248 }
249
250
251 static void rpavm_swi_emitend(rvmcpu_t *cpu, rvm_asmins_t *ins)
252 {
253         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
254         rparecord_t *rec;
255         rlong index;
256         rword tp = RVM_CPUREG_GETU(cpu, ins->op2);
257         rword tplen = RVM_CPUREG_GETU(cpu, ins->op3);
258         rstr_t name = {RVM_CPUREG_GETSTR(cpu, ins->op1), RVM_CPUREG_GETSIZE(cpu, ins->op1)};
259
260         index = r_array_add(stat->records, NULL);
261         rec = (rparecord_t *)r_array_slot(stat->records, index);
262         rec->rule = name.str;
263         rec->top = tp;
264         rec->size = tplen;
265         rec->type = RPA_RECORD_START;
266         rec->input = stat->instack[tp].input;
267         rec->inputsiz = stat->instack[tp + tplen].input - stat->instack[tp].input;
268
269         if (tplen) {
270                 rec->type = RPA_RECORD_END | RPA_RECORD_MATCH;
271 //              r_printf("MATCHED: %s(%ld, %ld): %p(%d)\n", name.str, (rulong)tp, (rulong)tplen, name.str, name.size);
272         } else {
273                 rec->type = RPA_RECORD_END;
274 //              r_printf("MATCHED: %s(%ld, %ld)\n", name.str, (rulong)tp, (rulong)tplen);
275         }
276         rpa_stat_cacheinvalidate(stat);
277 }
278
279
280 static void rpavm_swi_getreclen(rvmcpu_t *cpu, rvm_asmins_t *ins)
281 {
282         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
283         RVM_CPUREG_SETU(cpu, ins->op1, r_array_length(stat->records));
284 }
285
286
287 static void rpavm_swi_setreclen(rvmcpu_t *cpu, rvm_asmins_t *ins)
288 {
289         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
290
291         r_array_setlength(stat->records, (ruint)RVM_CPUREG_GETU(cpu, ins->op1));
292 }
293
294
295 static void rpavm_swi_setrecid(rvmcpu_t *cpu, rvm_asmins_t *ins)
296 {
297         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
298         rparecord_t *rec;
299         rword ruleid = RVM_CPUREG_GETU(cpu, ins->op1);
300
301         rec = (rparecord_t *)r_array_lastslot(stat->records);
302         if (rec) {
303                 rec->ruleid = ruleid;
304         }
305 }
306
307
308 static void rpavm_swi_loopdetect(rvmcpu_t *cpu, rvm_asmins_t *ins)
309 {
310         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
311         rparecord_t *rec;
312         rlong len;
313         rword ruleid = RVM_CPUREG_GETU(cpu, ins->op1);
314         rword tp = RVM_CPUREG_GETU(cpu, ins->op2);
315         rword fp = RVM_CPUREG_GETU(cpu, FP);
316         rvmreg_t loo, rid, top, pfp;
317
318         RVM_CPUREG_SETU(cpu, R0, -1);
319
320         while (fp > 5) {
321                 top = RVM_STACK_READ(cpu->stack, fp - 3);
322                 loo = RVM_STACK_READ(cpu->stack, fp - 4);
323                 rid = RVM_STACK_READ(cpu->stack, fp - 5);
324
325                 if (rid.v.l == ruleid && top.v.l == tp) {
326                         RVM_CPUREG_SETU(cpu, R0, loo.v.l);
327                         break;
328                 }
329                 RVM_REG_CLEAR(&loo);
330                 pfp = RVM_STACK_READ(cpu->stack, fp - 1);
331                 fp = pfp.v.l;
332         }
333
334 //      for (len = r_array_length(stat->records); len > 0; len--) {
335 //              rec = (rparecord_t *)r_array_slot(stat->records, len - 1);
336 //              if (rec->type == (RPA_RECORD_END | RPA_RECORD_MATCH)) {
337 //                      RVM_CPUREG_SETU(cpu, R0, -1);
338 //                      break;
339 //              } else if (rec->ruleid == ruleid && rec->top == tp) {
340 //                      RVM_CPUREG_SETU(cpu, R0, RVM_CPUREG_GETU(cpu, R_LOO));
341 //                      RVM_CPUREG_SETU(cpu, R_TOP, RVM_CPUREG_GETU(cpu, R_TOP) + RVM_CPUREG_GETU(cpu, R_LOO));
342 //                      r_printf("LOO = %ld, loo = %ld\n", RVM_CPUREG_GETU(cpu, R0), loo.v.l);
343 //                      RVM_CPUREG_SETU(cpu, R0, loo.v.l);
344 //                      break;
345 //              }
346 //      }
347 }
348
349
350 static void rpavm_swi_setcache(rvmcpu_t *cpu, rvm_asmins_t *ins)
351 {
352         rparecord_t *prec;
353         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
354         rlong ruleid = RVM_CPUREG_GETL(cpu, ins->op1);
355         rlong r0 = RVM_CPUREG_GETL(cpu, ins->op2);
356         rlong rec = RVM_CPUREG_GETL(cpu, ins->op3);
357         rlong nrecords = r_array_length(stat->records) - rec;
358
359         if (!RVM_STATUS_GETBIT(cpu, RVM_STATUS_N) && !RVM_STATUS_GETBIT(cpu, RVM_STATUS_Z)) {
360                 prec = (rparecord_t *)r_array_slot(stat->records, rec);
361                 R_ASSERT(nrecords);
362                 rpa_cache_set(stat->cache, prec->top, ruleid, r0, prec, nrecords);
363         }
364 }
365
366
367 static void rpavm_swi_checkcache(rvmcpu_t *cpu, rvm_asmins_t *ins)
368 {
369         rlong i;
370         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
371         rpacachedentry_t *entry;
372         rlong ruleid = RVM_CPUREG_GETL(cpu, ins->op1);
373         rlong top = RVM_CPUREG_GETL(cpu, ins->op2);
374         rlong r0 = 0;
375         entry = rpa_cache_lookup(stat->cache, top, ruleid);
376         if (entry) {
377                 for (i = 0; i < r_array_length(entry->records); i++) {
378                         r_array_add(stat->records, r_array_slot(entry->records, i));
379                 }
380                 r0 = entry->ret;
381                 top += r0;
382                 RVM_CPUREG_SETU(cpu, R_TOP, top);
383         }
384
385         RVM_STATUS_CLRALL(cpu);
386         RVM_CPUREG_SETU(cpu, R0, r0);
387         RVM_STATUS_UPDATE(cpu, RVM_STATUS_Z, !r0);
388 }
389
390
391 static void rpavm_swi_setrecuid(rvmcpu_t *cpu, rvm_asmins_t *ins)
392 {
393         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
394         rparecord_t *rec;
395         rword userid = RVM_CPUREG_GETU(cpu, ins->op1);
396
397         rec = (rparecord_t *)r_array_lastslot(stat->records);
398         if (rec) {
399                 rec->userid = (ruint32)userid;
400         }
401 }
402
403 static rvm_switable_t rpavm_swi_table[] = {
404                 {"RPA_MATCHCHR_NAN", rpavm_swi_matchchr_nan},
405                 {"RPA_MATCHCHR_OPT", rpavm_swi_matchchr_opt},
406                 {"RPA_MATCHCHR_MUL", rpavm_swi_matchchr_mul},
407                 {"RPA_MATCHCHR_MOP", rpavm_swi_matchchr_mop},
408                 {"RPA_MATCHRNG_NAN", rpavm_swi_matchrng_nan},
409                 {"RPA_MATCHRNG_OPT", rpavm_swi_matchrng_opt},
410                 {"RPA_MATCHRNG_MUL", rpavm_swi_matchrng_mul},
411                 {"RPA_MATCHRNG_MOP", rpavm_swi_matchrng_mop},
412                 {"RPA_MATCHSPCHR_NAN", rpavm_swi_matchspchr_nan},
413                 {"RPA_MATCHSPCHR_OPT", rpavm_swi_matchspchr_opt},
414                 {"RPA_MATCHSPCHR_MUL", rpavm_swi_matchspchr_mul},
415                 {"RPA_MATCHSPCHR_MOP", rpavm_swi_matchspchr_mop},
416                 {"RPA_SHIFT", rpavm_swi_shift},
417                 {"RPA_EMITSTART", rpavm_swi_emitstart},
418                 {"RPA_EMITEND", rpavm_swi_emitend},
419                 {"RPA_GETRECLEN", rpavm_swi_getreclen},
420                 {"RPA_SETRECLEN", rpavm_swi_setreclen},
421                 {"RPA_SETRECID", rpavm_swi_setrecid},
422                 {"RPA_LOOPDETECT", rpavm_swi_loopdetect},
423                 {"RPA_SETCACHE", rpavm_swi_setcache},
424                 {"RPA_CHECKCACHE", rpavm_swi_checkcache},
425                 {"RPA_SETRECUID", rpavm_swi_setrecuid},
426                 {NULL, NULL},
427 };
428
429
430 rvmcpu_t *rpavm_cpu_create(rulong stacksize)
431 {
432         rvmcpu_t *cpu = rvm_cpu_create(stacksize);
433         rint tableid = rvm_cpu_addswitable(cpu, "rpavm_swi_table", rpavm_swi_table);
434
435         if (tableid != RPAVM_SWI_TABLEID) {
436                 rpavm_cpu_destroy(cpu);
437                 return NULL;
438         }
439         return cpu;
440 }
441
442
443 void rpavm_cpu_destroy(rvmcpu_t * cpu)
444 {
445         rvm_cpu_destroy(cpu);
446 }
447
448