RPA Toolkit
dd7bc244c5d6c938755d673209771c87720a2fae
[rpatk.git] / rjs / rjs.c
1 /*
2  *  Regular Pattern Analyzer (RPA)
3  *  Copyright (c) 2009-2010 Martin Stoilov
4  *
5  *  This program is free software: you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation, either version 3 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  *
18  *  Martin Stoilov <martin@rpasearch.com>
19  */
20
21 #include <stdarg.h>
22 #include "rlib/rmem.h"
23 #include "rlib/rmap.h"
24 #include "rjs/rjs.h"
25 #include "rvm/rvmcodegen.h"
26 #include "rvmoperator.h"
27 #include "rvmoperatorbin.h"
28 #include "rvmoperatorcast.h"
29 #include "rvmoperatornot.h"
30 #include "rvmoperatorlogicnot.h"
31
32
33 static void rjs_engine_initgp(rjs_engine_t *jse);
34 static void rjs_engine_print(rvmcpu_t *cpu, rvm_asmins_t *ins);
35 static void rjs_engine_dbgprint(rvmcpu_t *cpu, rvm_asmins_t *ins);
36 static void rjs_engine_object(rvmcpu_t *cpu, rvm_asmins_t *ins);
37 static void rjs_string_ltrim(rvmcpu_t *cpu, rvm_asmins_t *ins);
38
39 static rvm_switable_t rjsswitable[] = {
40                 {"print", rjs_engine_print},
41                 {"dbgprint", rjs_engine_dbgprint},
42                 {"Object", rjs_engine_object},
43                 {"Array", rjs_engine_object},
44                 {"string.ltrim", rjs_string_ltrim},
45                 {NULL, NULL},
46 };
47
48
49 static void rjs_op_cast(rvmcpu_t *cpu, rvm_asmins_t *ins)
50 {
51         rvmreg_type_t type = (rvmreg_type_t)RVM_CPUREG_GETU(cpu, ins->op3);
52         rvmreg_t tmp;
53
54         RVM_REG_CLEAR(&tmp);
55         RVM_REG_SETTYPE(&tmp, type);
56         rjs_opmap_invoke_binary_handler(RJS_USERDATA2MAP(cpu->userdata2), RJS_OPID_CAST, cpu, RVM_CPUREG_PTR(cpu, ins->op1), RVM_CPUREG_PTR(cpu, ins->op2), &tmp);
57 }
58
59
60 static void rjs_op_eadd(rvmcpu_t *cpu, rvm_asmins_t *ins)
61 {
62         rvmreg_t *arg2 = RVM_CPUREG_PTR(cpu, ins->op2);
63         rvmreg_t *arg3 = RVM_CPUREG_PTR(cpu, ins->op3);
64
65         rjs_opmap_invoke_binary_handler(RJS_USERDATA2MAP(cpu->userdata2), RJS_OPID_ADD, cpu, RVM_CPUREG_PTR(cpu, ins->op1), arg2, arg3);
66 }
67
68
69 static void rjs_op_esub(rvmcpu_t *cpu, rvm_asmins_t *ins)
70 {
71         rvmreg_t *arg2 = RVM_CPUREG_PTR(cpu, ins->op2);
72         rvmreg_t *arg3 = RVM_CPUREG_PTR(cpu, ins->op3);
73
74         rjs_opmap_invoke_binary_handler(RJS_USERDATA2MAP(cpu->userdata2), RJS_OPID_SUB, cpu, RVM_CPUREG_PTR(cpu, ins->op1), arg2, arg3);
75 }
76
77
78 static void rjs_op_eneg(rvmcpu_t *cpu, rvm_asmins_t *ins)
79 {
80         rvmreg_t *arg2 = RVM_CPUREG_PTR(cpu, ins->op2);
81         rvmreg_t zero;
82
83         rvm_reg_setunsigned(&zero, 0);
84         rjs_opmap_invoke_binary_handler(RJS_USERDATA2MAP(cpu->userdata2), RJS_OPID_SUB, cpu, RVM_CPUREG_PTR(cpu, ins->op1), &zero, arg2);
85 }
86
87
88
89 static void rjs_op_emul(rvmcpu_t *cpu, rvm_asmins_t *ins)
90 {
91         rvmreg_t *arg2 = RVM_CPUREG_PTR(cpu, ins->op2);
92         rvmreg_t *arg3 = RVM_CPUREG_PTR(cpu, ins->op3);
93
94         rjs_opmap_invoke_binary_handler(RJS_USERDATA2MAP(cpu->userdata2), RJS_OPID_MUL, cpu, RVM_CPUREG_PTR(cpu, ins->op1), arg2, arg3);
95 }
96
97
98 static void rjs_op_ediv(rvmcpu_t *cpu, rvm_asmins_t *ins)
99 {
100         rvmreg_t *arg2 = RVM_CPUREG_PTR(cpu, ins->op2);
101         rvmreg_t *arg3 = RVM_CPUREG_PTR(cpu, ins->op3);
102
103         rjs_opmap_invoke_binary_handler(RJS_USERDATA2MAP(cpu->userdata2), RJS_OPID_DIV, cpu, RVM_CPUREG_PTR(cpu, ins->op1), arg2, arg3);
104 }
105
106
107 static void rjs_op_emod(rvmcpu_t *cpu, rvm_asmins_t *ins)
108 {
109         rvmreg_t *arg2 = RVM_CPUREG_PTR(cpu, ins->op2);
110         rvmreg_t *arg3 = RVM_CPUREG_PTR(cpu, ins->op3);
111
112         rjs_opmap_invoke_binary_handler(RJS_USERDATA2MAP(cpu->userdata2), RJS_OPID_MOD, cpu, RVM_CPUREG_PTR(cpu, ins->op1), arg2, arg3);
113 }
114
115
116 static void rjs_op_elsl(rvmcpu_t *cpu, rvm_asmins_t *ins)
117 {
118         rvmreg_t *arg2 = RVM_CPUREG_PTR(cpu, ins->op2);
119         rvmreg_t *arg3 = RVM_CPUREG_PTR(cpu, ins->op3);
120
121         rjs_opmap_invoke_binary_handler(RJS_USERDATA2MAP(cpu->userdata2), RJS_OPID_LSL, cpu, RVM_CPUREG_PTR(cpu, ins->op1), arg2, arg3);
122 }
123
124
125 static void rjs_op_elsr(rvmcpu_t *cpu, rvm_asmins_t *ins)
126 {
127         rvmreg_t *arg2 = RVM_CPUREG_PTR(cpu, ins->op2);
128         rvmreg_t *arg3 = RVM_CPUREG_PTR(cpu, ins->op3);
129
130         rjs_opmap_invoke_binary_handler(RJS_USERDATA2MAP(cpu->userdata2), RJS_OPID_LSR, cpu, RVM_CPUREG_PTR(cpu, ins->op1), arg2, arg3);
131 }
132
133
134 static void rjs_op_elsru(rvmcpu_t *cpu, rvm_asmins_t *ins)
135 {
136         rvmreg_t *arg2 = RVM_CPUREG_PTR(cpu, ins->op2);
137         rvmreg_t *arg3 = RVM_CPUREG_PTR(cpu, ins->op3);
138
139         rjs_opmap_invoke_binary_handler(RJS_USERDATA2MAP(cpu->userdata2), RJS_OPID_LSRU, cpu, RVM_CPUREG_PTR(cpu, ins->op1), arg2, arg3);
140 }
141
142
143 static void rjs_op_eand(rvmcpu_t *cpu, rvm_asmins_t *ins)
144 {
145         rvmreg_t *arg2 = RVM_CPUREG_PTR(cpu, ins->op2);
146         rvmreg_t *arg3 = RVM_CPUREG_PTR(cpu, ins->op3);
147
148         rjs_opmap_invoke_binary_handler(RJS_USERDATA2MAP(cpu->userdata2), RJS_OPID_AND, cpu, RVM_CPUREG_PTR(cpu, ins->op1), arg2, arg3);
149 }
150
151
152 static void rjs_op_eorr(rvmcpu_t *cpu, rvm_asmins_t *ins)
153 {
154         rvmreg_t *arg2 = RVM_CPUREG_PTR(cpu, ins->op2);
155         rvmreg_t *arg3 = RVM_CPUREG_PTR(cpu, ins->op3);
156
157         rjs_opmap_invoke_binary_handler(RJS_USERDATA2MAP(cpu->userdata2), RJS_OPID_OR, cpu, RVM_CPUREG_PTR(cpu, ins->op1), arg2, arg3);
158 }
159
160
161 static void rjs_op_exor(rvmcpu_t *cpu, rvm_asmins_t *ins)
162 {
163         rvmreg_t *arg2 = RVM_CPUREG_PTR(cpu, ins->op2);
164         rvmreg_t *arg3 = RVM_CPUREG_PTR(cpu, ins->op3);
165
166         rjs_opmap_invoke_binary_handler(RJS_USERDATA2MAP(cpu->userdata2), RJS_OPID_XOR, cpu, RVM_CPUREG_PTR(cpu, ins->op1), arg2, arg3);
167 }
168
169
170 static void rjs_op_enot(rvmcpu_t *cpu, rvm_asmins_t *ins)
171 {
172         rvmreg_t *arg2 = RVM_CPUREG_PTR(cpu, ins->op2);
173
174         rjs_opmap_invoke_unary_handler(RJS_USERDATA2MAP(cpu->userdata2), RJS_OPID_NOT, cpu, RVM_CPUREG_PTR(cpu, ins->op1), arg2);
175 }
176
177
178 static void rjs_op_eland(rvmcpu_t *cpu, rvm_asmins_t *ins)
179 {
180         rvmreg_t *arg2 = RVM_CPUREG_PTR(cpu, ins->op2);
181         rvmreg_t *arg3 = RVM_CPUREG_PTR(cpu, ins->op3);
182
183         rjs_opmap_invoke_binary_handler(RJS_USERDATA2MAP(cpu->userdata2), RJS_OPID_LOGICAND, cpu, RVM_CPUREG_PTR(cpu, ins->op1), arg2, arg3);
184 }
185
186
187 static void rjs_op_elor(rvmcpu_t *cpu, rvm_asmins_t *ins)
188 {
189         rvmreg_t *arg2 = RVM_CPUREG_PTR(cpu, ins->op2);
190         rvmreg_t *arg3 = RVM_CPUREG_PTR(cpu, ins->op3);
191
192         rjs_opmap_invoke_binary_handler(RJS_USERDATA2MAP(cpu->userdata2), RJS_OPID_LOGICOR, cpu, RVM_CPUREG_PTR(cpu, ins->op1), arg2, arg3);
193 }
194
195
196 static void rjs_op_elnot(rvmcpu_t *cpu, rvm_asmins_t *ins)
197 {
198         rvmreg_t *arg2 = RVM_CPUREG_PTR(cpu, ins->op2);
199
200         rjs_opmap_invoke_unary_handler(RJS_USERDATA2MAP(cpu->userdata2), RJS_OPID_LOGICNOT, cpu, RVM_CPUREG_PTR(cpu, ins->op1), arg2);
201 }
202
203
204 static void rjs_op_eeq(rvmcpu_t *cpu, rvm_asmins_t *ins)
205 {
206         rvmreg_t *arg2 = RVM_CPUREG_PTR(cpu, ins->op2);
207         rvmreg_t *arg3 = RVM_CPUREG_PTR(cpu, ins->op3);
208
209         rjs_opmap_invoke_binary_handler(RJS_USERDATA2MAP(cpu->userdata2), RJS_OPID_EQ, cpu, RVM_CPUREG_PTR(cpu, ins->op1), arg2, arg3);
210 }
211
212
213 static void rjs_op_enoteq(rvmcpu_t *cpu, rvm_asmins_t *ins)
214 {
215         rvmreg_t *arg2 = RVM_CPUREG_PTR(cpu, ins->op2);
216         rvmreg_t *arg3 = RVM_CPUREG_PTR(cpu, ins->op3);
217
218         rjs_opmap_invoke_binary_handler(RJS_USERDATA2MAP(cpu->userdata2), RJS_OPID_NOTEQ, cpu, RVM_CPUREG_PTR(cpu, ins->op1), arg2, arg3);
219 }
220
221
222 static void rjs_op_egreat(rvmcpu_t *cpu, rvm_asmins_t *ins)
223 {
224         rvmreg_t *arg2 = RVM_CPUREG_PTR(cpu, ins->op2);
225         rvmreg_t *arg3 = RVM_CPUREG_PTR(cpu, ins->op3);
226
227         rjs_opmap_invoke_binary_handler(RJS_USERDATA2MAP(cpu->userdata2), RJS_OPID_GREATER, cpu, RVM_CPUREG_PTR(cpu, ins->op1), arg2, arg3);
228 }
229
230
231 static void rjs_op_egreateq(rvmcpu_t *cpu, rvm_asmins_t *ins)
232 {
233         rvmreg_t *arg2 = RVM_CPUREG_PTR(cpu, ins->op2);
234         rvmreg_t *arg3 = RVM_CPUREG_PTR(cpu, ins->op3);
235
236         rjs_opmap_invoke_binary_handler(RJS_USERDATA2MAP(cpu->userdata2), RJS_OPID_GREATEREQ, cpu, RVM_CPUREG_PTR(cpu, ins->op1), arg2, arg3);
237 }
238
239
240 static void rjs_op_elesseq(rvmcpu_t *cpu, rvm_asmins_t *ins)
241 {
242         rvmreg_t *arg2 = RVM_CPUREG_PTR(cpu, ins->op2);
243         rvmreg_t *arg3 = RVM_CPUREG_PTR(cpu, ins->op3);
244
245         rjs_opmap_invoke_binary_handler(RJS_USERDATA2MAP(cpu->userdata2), RJS_OPID_LESSEQ, cpu, RVM_CPUREG_PTR(cpu, ins->op1), arg2, arg3);
246 }
247
248
249 static void rjs_op_eless(rvmcpu_t *cpu, rvm_asmins_t *ins)
250 {
251         rvmreg_t *arg2 = RVM_CPUREG_PTR(cpu, ins->op2);
252         rvmreg_t *arg3 = RVM_CPUREG_PTR(cpu, ins->op3);
253
254         rjs_opmap_invoke_binary_handler(RJS_USERDATA2MAP(cpu->userdata2), RJS_OPID_LESS, cpu, RVM_CPUREG_PTR(cpu, ins->op1), arg2, arg3);
255 }
256
257
258 static void rjs_op_ecmp(rvmcpu_t *cpu, rvm_asmins_t *ins)
259 {
260         rvmreg_t *arg1 = RVM_CPUREG_PTR(cpu, ins->op1);
261         rvmreg_t *arg2 = RVM_CPUREG_PTR(cpu, ins->op2);
262
263         rjs_opmap_invoke_binary_handler(RJS_USERDATA2MAP(cpu->userdata2), RJS_OPID_CMP, cpu, NULL, arg1, arg2);
264 }
265
266
267 static void rjs_op_ecmn(rvmcpu_t *cpu, rvm_asmins_t *ins)
268 {
269         rvmreg_t *arg1 = RVM_CPUREG_PTR(cpu, ins->op1);
270         rvmreg_t *arg2 = RVM_CPUREG_PTR(cpu, ins->op2);
271
272         rjs_opmap_invoke_binary_handler(RJS_USERDATA2MAP(cpu->userdata2), RJS_OPID_CMN, cpu, NULL, arg1, arg2);
273 }
274
275
276 static void rjs_op_stralloc(rvmcpu_t *cpu, rvm_asmins_t *ins)
277 {
278         rvmreg_t *arg1 = RVM_CPUREG_PTR(cpu, ins->op1);
279         rstring_t *s = r_string_create_strsize((const char*)RVM_CPUREG_GETP(cpu, ins->op2), (unsigned long)RVM_CPUREG_GETU(cpu, ins->op3));
280         if (!s) {
281                 RVM_ABORT(cpu, RVM_E_ILLEGAL);
282         }
283         r_gc_add(cpu->gc, (robject_t*)s);
284         rvm_reg_setstring(arg1, s);
285 }
286
287
288 static void rjs_op_mapalloc(rvmcpu_t *cpu, rvm_asmins_t *ins)
289 {
290         rvmreg_t *arg1 = RVM_CPUREG_PTR(cpu, ins->op1);
291         rmap_t *a = r_map_create(sizeof(rvmreg_t), 7);
292         if (!a) {
293                 RVM_ABORT(cpu, RVM_E_ILLEGAL);
294         }
295         r_gc_add(cpu->gc, (robject_t*)a);
296         rvm_reg_setjsobject(arg1, (robject_t*)a);
297 }
298
299
300 static long rjs_op_mapproplookupadd(rmap_t *map, rvmcpu_t *cpu, rvm_asmins_t *ins)
301 {
302         long index;
303         rvmreg_t *arg3 = RVM_CPUREG_PTR(cpu, ins->op3);
304
305         if (RVM_REG_GETTYPE(arg3) == RVM_DTYPE_SIGNED || RVM_REG_GETTYPE(arg3) == RVM_DTYPE_UNSIGNED) {
306                 index = r_map_lookup_l(map, -1, (long)RVM_REG_GETL(arg3));
307                 if (index < 0)
308                         index = r_map_gckey_add_l(map, cpu->gc, (long)RVM_REG_GETL(arg3), NULL);
309         } else if (RVM_REG_GETTYPE(arg3) == RVM_DTYPE_DOUBLE) {
310                 index = r_map_lookup_d(map, -1, RVM_REG_GETD(arg3));
311                 if (index < 0)
312                         index = r_map_gckey_add_d(map, cpu->gc, RVM_REG_GETD(arg3), NULL);
313         } else if (RVM_REG_GETTYPE(arg3) == RVM_DTYPE_STRING) {
314                 index = r_map_lookup(map, -1, ((rstring_t *)RVM_CPUREG_GETP(cpu, ins->op3))->s.str, ((rstring_t *)RVM_CPUREG_GETP(cpu, ins->op3))->s.size);
315                 if (index < 0)
316                         index = r_map_gckey_add(map, cpu->gc, ((rstring_t *)RVM_CPUREG_GETP(cpu, ins->op3))->s.str, ((rstring_t *)RVM_CPUREG_GETP(cpu, ins->op3))->s.size, NULL);
317         } else if (RVM_REG_GETTYPE(arg3) == RVM_DTYPE_POINTER) {
318                 index = r_map_lookup(map, -1, (char*)RVM_CPUREG_GETP(cpu, ins->op3), (unsigned int)RVM_CPUREG_GETL(cpu, ins->op1));
319                 if (index < 0)
320                         index = r_map_gckey_add(map, cpu->gc, (char*)RVM_CPUREG_GETP(cpu, ins->op3), (unsigned int)RVM_CPUREG_GETL(cpu, ins->op1), NULL);
321         } else {
322                 index = -1;
323         }
324
325         return index;
326 }
327
328
329 static void rjs_op_proplookupadd(rvmcpu_t *cpu, rvm_asmins_t *ins)
330 {
331         long index = -1;
332         rvmreg_t *arg1 = RVM_CPUREG_PTR(cpu, ins->op1);
333         rvmreg_t *arg2 = RVM_CPUREG_PTR(cpu, ins->op2);
334         rmap_t *map = (rmap_t*)RVM_REG_GETP(arg2);
335
336         if (rvm_reg_gettype(arg2) == RVM_DTYPE_MAP) {
337                 index = rjs_op_mapproplookupadd(map, cpu, ins);
338         } else {
339
340         }
341         RVM_REG_CLEAR(arg1);
342         RVM_REG_SETTYPE(arg1, RVM_DTYPE_SIGNED);
343         RVM_REG_SETL(arg1, index);
344 }
345
346
347 static long rjs_op_mapproplookup(rmap_t *map, rvmcpu_t *cpu, rvm_asmins_t *ins)
348 {
349         long index = -1;
350         rvmreg_t *arg3 = RVM_CPUREG_PTR(cpu, ins->op3);
351
352         if (RVM_REG_GETTYPE(arg3) == RVM_DTYPE_SIGNED || RVM_REG_GETTYPE(arg3) == RVM_DTYPE_UNSIGNED) {
353                 index = r_map_lookup_l(map, -1, (long)RVM_REG_GETL(arg3));
354         } else if (RVM_REG_GETTYPE(arg3) == RVM_DTYPE_DOUBLE) {
355                 index = r_map_lookup_d(map, -1, RVM_REG_GETD(arg3));
356         } else if (RVM_REG_GETTYPE(arg3) == RVM_DTYPE_STRING) {
357                 index = r_map_lookup(map, -1, ((rstring_t *)RVM_CPUREG_GETP(cpu, ins->op3))->s.str, ((rstring_t *)RVM_CPUREG_GETP(cpu, ins->op3))->s.size);
358         } else if (RVM_REG_GETTYPE(arg3) == RVM_DTYPE_POINTER) {
359                 index = r_map_lookup(map, -1, (char*)RVM_CPUREG_GETP(cpu, ins->op3), (unsigned int)RVM_CPUREG_GETL(cpu, ins->op1));
360         }
361         return index;
362 }
363
364
365 static long rjs_op_stringproplookup(rstring_t *str, rvmcpu_t *cpu, rvm_asmins_t *ins)
366 {
367         long index = -1;
368         rvmreg_t *arg3 = RVM_CPUREG_PTR(cpu, ins->op3);
369
370         if (RVM_REG_GETTYPE(arg3) == RVM_DTYPE_SIGNED || RVM_REG_GETTYPE(arg3) == RVM_DTYPE_UNSIGNED) {
371                 index = RVM_REG_GETL(arg3);
372         } else if (RVM_REG_GETTYPE(arg3) == RVM_DTYPE_DOUBLE) {
373                 index = (long)RVM_REG_GETD(arg3);
374         } else if (RVM_REG_GETTYPE(arg3) == RVM_DTYPE_STRING) {
375                 index = r_strtol(((rstring_t *)RVM_CPUREG_GETP(cpu, ins->op3))->s.str, NULL, 10);
376         }
377         return index;
378 }
379
380
381 static void rjs_op_proplookup(rvmcpu_t *cpu, rvm_asmins_t *ins)
382 {
383         long index = -1;
384         rboolean globalprop = 0;
385         rvmreg_t *arg1 = RVM_CPUREG_PTR(cpu, ins->op1);
386         rvmreg_t *arg2 = RVM_CPUREG_PTR(cpu, ins->op2);
387
388         if (rvm_reg_gettype(arg2) == RVM_DTYPE_MAP) {
389                 rmap_t *map = (rmap_t*)RVM_REG_GETP(arg2);
390                 index = rjs_op_mapproplookup(map, cpu, ins);
391                 rvm_reg_setsigned(arg1, index);
392         } else if (rvm_reg_gettype(arg2) == RVM_DTYPE_STRING) {
393                 rstring_t *str = (rstring_t*)RVM_REG_GETP(arg2);
394                 index = rjs_op_stringproplookup(str, cpu, ins);
395                 if (index < 0) {
396                         index = rjs_op_mapproplookup(RJS_CPU2JSE(cpu)->props[RVM_DTYPE_STRING], cpu, ins);
397                         if (index >= 0)
398                                 globalprop = TRUE;
399                 }
400                 rvm_reg_setsigned(arg1, index);
401                 if (globalprop)
402                         RVM_REG_SETFLAG(arg1, RVM_INFOBIT_GLOBAL);
403         }
404 }
405
406
407 static void rjs_op_propstr(rvmcpu_t *cpu, rvm_asmins_t *ins)
408 {
409         rvmreg_t *arg1 = RVM_CPUREG_PTR(cpu, ins->op1);
410         rvmreg_t *arg2 = RVM_CPUREG_PTR(cpu, ins->op2);
411         rvmreg_t tmp = rvm_reg_create_signed(0);
412         rmap_t *a = NULL;
413         rpointer value;
414         long index;
415
416         rjs_opmap_invoke_binary_handler(RJS_USERDATA2MAP(cpu->userdata2), RJS_OPID_CAST, cpu, &tmp, RVM_CPUREG_PTR(cpu, ins->op3), &tmp);
417         index = (long)RVM_REG_GETL(&tmp);
418         if (rvm_reg_gettype(arg2) != RVM_DTYPE_MAP) {
419
420                 return;
421         }
422         a = (rmap_t*)RVM_REG_GETP(arg2);
423         value = r_map_value(a, index);
424         if (!value)
425                 RVM_ABORT(cpu, RVM_E_ILLEGAL);
426         r_map_setvalue(a, index, arg1);
427 }
428
429
430 static void rjs_op_propldr(rvmcpu_t *cpu, rvm_asmins_t *ins)
431 {
432         rvmreg_t *arg1 = RVM_CPUREG_PTR(cpu, ins->op1);
433         rvmreg_t *arg2 = RVM_CPUREG_PTR(cpu, ins->op2);
434         rvmreg_t tmp = rvm_reg_create_signed(0);
435         rpointer value;
436         long index;
437
438         index = (long)RVM_REG_GETL(arg1);
439         rvm_reg_setundef(arg1);
440         if (rvm_reg_gettype(arg2) == RVM_DTYPE_MAP) {
441                 rmap_t *a = (rmap_t*)RVM_REG_GETP(arg2);
442                 value = r_map_value(a, index);
443                 if (value) {
444                         *arg1 = *((rvmreg_t*)value);
445                 }
446         } else if (rvm_reg_gettype(arg2) == RVM_DTYPE_STRING) {
447                 rstring_t *s = (rstring_t*)RVM_REG_GETP(arg2);
448                 if (index >= s->s.size) {
449                         rvm_reg_setundef(arg1);
450                 } else {
451                         if (1||RVM_REG_TSTFLAG(arg1, RVM_INFOBIT_GLOBAL)) {
452                                 rmap_t *a = RJS_CPU2JSE(cpu)->props[RVM_DTYPE_STRING];
453                                 value = r_map_value(a, index);
454                                 if (value) {
455                                         *arg1 = *((rvmreg_t*)value);
456                                 }
457                         } else {
458                                 rstring_t *allocstr = r_string_create_strsize(&s->s.str[index], 1);
459                                 r_gc_add(cpu->gc, (robject_t*)allocstr);
460                                 rvm_reg_setstring(arg1, allocstr);
461                         }
462                 }
463         }
464 }
465
466
467 static void rjs_op_propkeyldr(rvmcpu_t *cpu, rvm_asmins_t *ins)
468 {
469         rvmreg_t *arg1 = RVM_CPUREG_PTR(cpu, ins->op1);
470         rvmreg_t *arg2 = RVM_CPUREG_PTR(cpu, ins->op2);
471         rvmreg_t tmp = rvm_reg_create_signed(0);
472         rmap_t *map = NULL;
473         rstring_t *key;
474         long index;
475
476         rjs_opmap_invoke_binary_handler(RJS_USERDATA2MAP(cpu->userdata2), RJS_OPID_CAST, cpu, &tmp, RVM_CPUREG_PTR(cpu, ins->op3), &tmp);
477         index = (long)RVM_REG_GETL(&tmp);
478         RVM_REG_CLEAR(arg1);
479         RVM_REG_SETTYPE(arg1, RVM_DTYPE_UNDEF);
480         if (rvm_reg_gettype(arg2) == RVM_DTYPE_MAP) {
481                 map = (rmap_t*)RVM_REG_GETP(arg2);
482                 key = r_map_key(map, index);
483                 if (key) {
484                         rvm_reg_setstring(arg1, key);
485                 }
486         } else if (rvm_reg_gettype(arg2) == RVM_DTYPE_STRING) {
487
488         }
489 }
490
491
492 static void rjs_op_propdel(rvmcpu_t *cpu, rvm_asmins_t *ins)
493 {
494         int ret;
495         long index;
496         rvmreg_t *arg1 = RVM_CPUREG_PTR(cpu, ins->op1);
497         rvmreg_t *arg2 = RVM_CPUREG_PTR(cpu, ins->op2);
498         rvmreg_t tmp = rvm_reg_create_signed(0);
499         rmap_t *a = NULL;
500
501         rjs_opmap_invoke_binary_handler(RJS_USERDATA2MAP(cpu->userdata2), RJS_OPID_CAST, cpu, &tmp, RVM_CPUREG_PTR(cpu, ins->op3), &tmp);
502         index = (long)RVM_REG_GETL(&tmp);
503         rvm_reg_setboolean(arg1, 0);
504         if (rvm_reg_gettype(arg2) == RVM_DTYPE_MAP) {
505                 a = (rmap_t*)RVM_REG_GETP(arg2);
506                 ret = r_map_delete(a, index);
507                 rvm_reg_setboolean(arg1, ret == 0 ? 1 : 0);
508         }
509 }
510
511
512 static void rjs_op_propaddr(rvmcpu_t *cpu, rvm_asmins_t *ins)
513 {
514         rvmreg_t *arg1 = RVM_CPUREG_PTR(cpu, ins->op1);
515         rvmreg_t *arg2 = RVM_CPUREG_PTR(cpu, ins->op2);
516         rvmreg_t tmp = rvm_reg_create_signed(0);
517         rmap_t *a;
518         rpointer value;
519         long index;
520
521         rjs_opmap_invoke_binary_handler(RJS_USERDATA2MAP(cpu->userdata2), RJS_OPID_CAST, cpu, &tmp, RVM_CPUREG_PTR(cpu, ins->op3), &tmp);
522         index = (long)RVM_REG_GETL(&tmp);
523         if (rvm_reg_gettype(arg2) != RVM_DTYPE_MAP)
524                 RVM_ABORT(cpu, RVM_E_NOTOBJECT);
525         a = (rmap_t*)RVM_REG_GETP(arg2);
526         value = r_map_value(a, index);
527         if (!value)
528                 RVM_ABORT(cpu, RVM_E_ILLEGAL);
529         RVM_REG_CLEAR(arg1);
530         RVM_REG_SETTYPE(arg1, RVM_DTYPE_POINTER);
531         RVM_REG_SETP(arg1, value);
532 }
533
534
535 static void rjs_op_propnext(rvmcpu_t *cpu, rvm_asmins_t *ins)
536 {
537         rvmreg_t *arg1 = RVM_CPUREG_PTR(cpu, ins->op1);
538         rvmreg_t *arg2 = RVM_CPUREG_PTR(cpu, ins->op2);
539         rvmreg_t tmp = rvm_reg_create_signed(0);
540         rmap_t *map = NULL;
541         long index = -1;
542
543         rjs_opmap_invoke_binary_handler(RJS_USERDATA2MAP(cpu->userdata2), RJS_OPID_CAST, cpu, &tmp, RVM_CPUREG_PTR(cpu, ins->op3), &tmp);
544         index = (long)RVM_REG_GETL(&tmp);
545         if (rvm_reg_gettype(arg2) == RVM_DTYPE_MAP) {
546                 map = (rmap_t*)RVM_REG_GETP(arg2);
547                 if (index < 0)
548                         index = r_map_first(map);
549                 else
550                         index = r_map_next(map, index);
551         }
552         RVM_REG_CLEAR(arg1);
553         RVM_REG_SETTYPE(arg1, RVM_DTYPE_SIGNED);
554         RVM_REG_SETL(arg1, index);
555 }
556
557
558 static void rjs_op_propprev(rvmcpu_t *cpu, rvm_asmins_t *ins)
559 {
560         rvmreg_t *arg1 = RVM_CPUREG_PTR(cpu, ins->op1);
561         rvmreg_t *arg2 = RVM_CPUREG_PTR(cpu, ins->op2);
562         rvmreg_t tmp = rvm_reg_create_signed(0);
563         rmap_t *map = NULL;
564         long index = -1;
565
566         rjs_opmap_invoke_binary_handler(RJS_USERDATA2MAP(cpu->userdata2), RJS_OPID_CAST, cpu, &tmp, RVM_CPUREG_PTR(cpu, ins->op3), &tmp);
567         index = (long)RVM_REG_GETL(&tmp);
568         if (rvm_reg_gettype(arg2) == RVM_DTYPE_MAP) {
569                 map = (rmap_t*)RVM_REG_GETP(arg2);
570                 if (index < 0)
571                         index = r_map_last(map);
572                 else
573                         index = r_map_prev(map, index);
574         }
575         RVM_REG_CLEAR(arg1);
576         RVM_REG_SETTYPE(arg1, RVM_DTYPE_SIGNED);
577         RVM_REG_SETL(arg1, index);
578 }
579
580
581 static void rjs_op_mapdel(rvmcpu_t *cpu, rvm_asmins_t *ins)
582 {
583         int ret;
584         long index;
585         rvmreg_t *arg1 = RVM_CPUREG_PTR(cpu, ins->op1);
586         rvmreg_t *arg2 = RVM_CPUREG_PTR(cpu, ins->op2);
587         rvmreg_t tmp = rvm_reg_create_signed(0);
588         rmap_t *a = NULL;
589
590         rjs_opmap_invoke_binary_handler(RJS_USERDATA2MAP(cpu->userdata2), RJS_OPID_CAST, cpu, &tmp, RVM_CPUREG_PTR(cpu, ins->op3), &tmp);
591         index = (long)RVM_REG_GETL(&tmp);
592         if (rvm_reg_gettype(arg2) != RVM_DTYPE_MAP)
593                 RVM_ABORT(cpu, RVM_E_NOTOBJECT);
594         a = (rmap_t*)RVM_REG_GETP(arg2);
595         ret = r_map_delete(a, index);
596         rvm_reg_setboolean(arg1, ret == 0 ? 1 : 0);
597 }
598
599
600 static void rjs_op_maplookup(rvmcpu_t *cpu, rvm_asmins_t *ins)
601 {
602         long index;
603         rvmreg_t *arg1 = RVM_CPUREG_PTR(cpu, ins->op1);
604         rvmreg_t *arg2 = RVM_CPUREG_PTR(cpu, ins->op2);
605         rvmreg_t *arg3 = RVM_CPUREG_PTR(cpu, ins->op3);
606         rmap_t *a = (rmap_t*)RVM_REG_GETP(arg2);
607
608         if (rvm_reg_gettype(arg2) != RVM_DTYPE_MAP) {
609                 RVM_ABORT(cpu, RVM_E_NOTOBJECT);
610         }
611         if (RVM_REG_GETTYPE(arg3) == RVM_DTYPE_SIGNED || RVM_REG_GETTYPE(arg3) == RVM_DTYPE_UNSIGNED) {
612                 index = r_map_lookup_l(a, -1, (long)RVM_REG_GETL(arg3));
613         } else if (RVM_REG_GETTYPE(arg3) == RVM_DTYPE_DOUBLE) {
614                 index = r_map_lookup_d(a, -1, RVM_REG_GETD(arg3));
615         } else if (RVM_REG_GETTYPE(arg3) == RVM_DTYPE_STRING) {
616                 index = r_map_lookup(a, -1, ((rstring_t *)RVM_CPUREG_GETP(cpu, ins->op3))->s.str, ((rstring_t *)RVM_CPUREG_GETP(cpu, ins->op3))->s.size);
617         } else if (RVM_REG_GETTYPE(arg3) == RVM_DTYPE_POINTER) {
618                 index = r_map_lookup(a, -1, (char*)RVM_CPUREG_GETP(cpu, ins->op3), (unsigned int)RVM_CPUREG_GETL(cpu, ins->op1));
619         } else {
620                 RVM_ABORT(cpu, RVM_E_ILLEGAL);
621         }
622
623         RVM_REG_CLEAR(arg1);
624         RVM_REG_SETTYPE(arg1, RVM_DTYPE_SIGNED);
625         RVM_REG_SETL(arg1, index);
626 }
627
628
629 static void rjs_op_mapadd(rvmcpu_t *cpu, rvm_asmins_t *ins)
630 {
631         long index;
632         rvmreg_t *arg1 = RVM_CPUREG_PTR(cpu, ins->op1);
633         rvmreg_t *arg2 = RVM_CPUREG_PTR(cpu, ins->op2);
634         rvmreg_t *arg3 = RVM_CPUREG_PTR(cpu, ins->op3);
635         rmap_t *a = (rmap_t*)RVM_REG_GETP(arg2);
636
637         if (rvm_reg_gettype(arg2) != RVM_DTYPE_MAP) {
638                 RVM_ABORT(cpu, RVM_E_NOTOBJECT);
639         }
640         if (RVM_REG_GETTYPE(arg3) == RVM_DTYPE_SIGNED || RVM_REG_GETTYPE(arg3) == RVM_DTYPE_UNSIGNED) {
641                 index = r_map_gckey_add_l(a, cpu->gc, (long)RVM_REG_GETL(arg3), NULL);
642         } else if (RVM_REG_GETTYPE(arg3) == RVM_DTYPE_DOUBLE) {
643                 index = r_map_gckey_add_d(a, cpu->gc, RVM_REG_GETD(arg3), NULL);
644         } else if (RVM_REG_GETTYPE(arg3) == RVM_DTYPE_STRING) {
645                 index = r_map_gckey_add(a, cpu->gc, ((rstring_t *)RVM_CPUREG_GETP(cpu, ins->op3))->s.str, ((rstring_t *)RVM_CPUREG_GETP(cpu, ins->op3))->s.size, NULL);
646         } else if (RVM_REG_GETTYPE(arg3) == RVM_DTYPE_POINTER) {
647                 index = r_map_gckey_add(a, cpu->gc, (char*)RVM_CPUREG_GETP(cpu, ins->op3), (unsigned int)RVM_CPUREG_GETL(cpu, ins->op1), NULL);
648         } else {
649                 RVM_ABORT(cpu, RVM_E_ILLEGAL);
650         }
651
652         RVM_REG_CLEAR(arg1);
653         RVM_REG_SETTYPE(arg1, RVM_DTYPE_SIGNED);
654         RVM_REG_SETL(arg1, index);
655 }
656
657
658 static void rjs_op_maplookupadd(rvmcpu_t *cpu, rvm_asmins_t *ins)
659 {
660         long index;
661         rvmreg_t *arg1 = RVM_CPUREG_PTR(cpu, ins->op1);
662         rvmreg_t *arg2 = RVM_CPUREG_PTR(cpu, ins->op2);
663         rvmreg_t *arg3 = RVM_CPUREG_PTR(cpu, ins->op3);
664         rmap_t *a = (rmap_t*)RVM_REG_GETP(arg2);
665
666         if (rvm_reg_gettype(arg2) != RVM_DTYPE_MAP) {
667                 RVM_ABORT(cpu, RVM_E_NOTOBJECT);
668         }
669         if (RVM_REG_GETTYPE(arg3) == RVM_DTYPE_SIGNED || RVM_REG_GETTYPE(arg3) == RVM_DTYPE_UNSIGNED) {
670                 index = r_map_lookup_l(a, -1, (long)RVM_REG_GETL(arg3));
671                 if (index < 0)
672                         index = r_map_gckey_add_l(a, cpu->gc, (long)RVM_REG_GETL(arg3), NULL);
673         } else if (RVM_REG_GETTYPE(arg3) == RVM_DTYPE_DOUBLE) {
674                 index = r_map_lookup_d(a, -1, RVM_REG_GETD(arg3));
675                 if (index < 0)
676                         index = r_map_gckey_add_d(a, cpu->gc, RVM_REG_GETD(arg3), NULL);
677         } else if (RVM_REG_GETTYPE(arg3) == RVM_DTYPE_STRING) {
678                 index = r_map_lookup(a, -1, ((rstring_t *)RVM_CPUREG_GETP(cpu, ins->op3))->s.str, ((rstring_t *)RVM_CPUREG_GETP(cpu, ins->op3))->s.size);
679                 if (index < 0)
680                         index = r_map_gckey_add(a, cpu->gc, ((rstring_t *)RVM_CPUREG_GETP(cpu, ins->op3))->s.str, ((rstring_t *)RVM_CPUREG_GETP(cpu, ins->op3))->s.size, NULL);
681         } else if (RVM_REG_GETTYPE(arg3) == RVM_DTYPE_POINTER) {
682                 index = r_map_lookup(a, -1, (char*)RVM_CPUREG_GETP(cpu, ins->op3), (unsigned int)RVM_CPUREG_GETL(cpu, ins->op1));
683                 if (index < 0)
684                         index = r_map_gckey_add(a, cpu->gc, (char*)RVM_CPUREG_GETP(cpu, ins->op3), (unsigned int)RVM_CPUREG_GETL(cpu, ins->op1), NULL);
685         } else {
686                 RVM_ABORT(cpu, RVM_E_ILLEGAL);
687         }
688         RVM_REG_CLEAR(arg1);
689         RVM_REG_SETTYPE(arg1, RVM_DTYPE_SIGNED);
690         RVM_REG_SETL(arg1, index);
691 }
692
693
694 static void rjs_op_mapaddr(rvmcpu_t *cpu, rvm_asmins_t *ins)
695 {
696         rvmreg_t *arg1 = RVM_CPUREG_PTR(cpu, ins->op1);
697         rvmreg_t *arg2 = RVM_CPUREG_PTR(cpu, ins->op2);
698         rvmreg_t tmp = rvm_reg_create_signed(0);
699         rmap_t *a;
700         rpointer value;
701         long index;
702
703         rjs_opmap_invoke_binary_handler(RJS_USERDATA2MAP(cpu->userdata2), RJS_OPID_CAST, cpu, &tmp, RVM_CPUREG_PTR(cpu, ins->op3), &tmp);
704         index = (long)RVM_REG_GETL(&tmp);
705         if (rvm_reg_gettype(arg2) != RVM_DTYPE_MAP)
706                 RVM_ABORT(cpu, RVM_E_NOTOBJECT);
707         a = (rmap_t*)RVM_REG_GETP(arg2);
708         value = r_map_value(a, index);
709         if (!value)
710                 RVM_ABORT(cpu, RVM_E_ILLEGAL);
711         RVM_REG_CLEAR(arg1);
712         RVM_REG_SETTYPE(arg1, RVM_DTYPE_POINTER);
713         RVM_REG_SETP(arg1, value);
714 }
715
716
717 static void rjs_op_mapldr(rvmcpu_t *cpu, rvm_asmins_t *ins)
718 {
719         rvmreg_t *arg1 = RVM_CPUREG_PTR(cpu, ins->op1);
720         rvmreg_t *arg2 = RVM_CPUREG_PTR(cpu, ins->op2);
721         rvmreg_t tmp = rvm_reg_create_signed(0);
722         rmap_t *a = NULL;
723         rpointer value;
724         long index;
725
726         rjs_opmap_invoke_binary_handler(RJS_USERDATA2MAP(cpu->userdata2), RJS_OPID_CAST, cpu, &tmp, RVM_CPUREG_PTR(cpu, ins->op3), &tmp);
727         index = (long)RVM_REG_GETL(&tmp);
728         if (rvm_reg_gettype(arg2) != RVM_DTYPE_MAP)
729                 RVM_ABORT(cpu, RVM_E_NOTOBJECT);
730         a = (rmap_t*)RVM_REG_GETP(arg2);
731         value = r_map_value(a, index);
732         if (!value) {
733                 RVM_REG_CLEAR(arg1);
734                 RVM_REG_SETTYPE(arg1, RVM_DTYPE_UNDEF);
735         } else {
736                 *arg1 = *((rvmreg_t*)value);
737         }
738 }
739
740
741 static void rjs_op_mapkeyldr(rvmcpu_t *cpu, rvm_asmins_t *ins)
742 {
743         rvmreg_t *arg1 = RVM_CPUREG_PTR(cpu, ins->op1);
744         rvmreg_t *arg2 = RVM_CPUREG_PTR(cpu, ins->op2);
745         rvmreg_t tmp = rvm_reg_create_signed(0);
746         rmap_t *a = NULL;
747         rstring_t *key;
748         long index;
749
750         rjs_opmap_invoke_binary_handler(RJS_USERDATA2MAP(cpu->userdata2), RJS_OPID_CAST, cpu, &tmp, RVM_CPUREG_PTR(cpu, ins->op3), &tmp);
751         index = (long)RVM_REG_GETL(&tmp);
752         if (rvm_reg_gettype(arg2) != RVM_DTYPE_MAP)
753                 RVM_ABORT(cpu, RVM_E_NOTOBJECT);
754         a = (rmap_t*)RVM_REG_GETP(arg2);
755         key = r_map_key(a, index);
756         if (!key) {
757                 RVM_REG_CLEAR(arg1);
758                 RVM_REG_SETTYPE(arg1, RVM_DTYPE_UNDEF);
759         } else {
760                 rvm_reg_setstring(arg1, key);
761         }
762 }
763
764
765 static void rjs_op_mapnext(rvmcpu_t *cpu, rvm_asmins_t *ins)
766 {
767         rvmreg_t *arg1 = RVM_CPUREG_PTR(cpu, ins->op1);
768         rvmreg_t *arg2 = RVM_CPUREG_PTR(cpu, ins->op2);
769         rvmreg_t tmp = rvm_reg_create_signed(0);
770         rmap_t *a = NULL;
771         long index;
772
773         rjs_opmap_invoke_binary_handler(RJS_USERDATA2MAP(cpu->userdata2), RJS_OPID_CAST, cpu, &tmp, RVM_CPUREG_PTR(cpu, ins->op3), &tmp);
774         index = (long)RVM_REG_GETL(&tmp);
775         if (rvm_reg_gettype(arg2) != RVM_DTYPE_MAP)
776                 RVM_ABORT(cpu, RVM_E_NOTOBJECT);
777         a = (rmap_t*)RVM_REG_GETP(arg2);
778         if (index < 0)
779                 index = r_map_first(a);
780         else
781                 index = r_map_next(a, index);
782         RVM_REG_CLEAR(arg1);
783         RVM_REG_SETTYPE(arg1, RVM_DTYPE_SIGNED);
784         RVM_REG_SETL(arg1, index);
785 }
786
787
788 static void rjs_op_mapprev(rvmcpu_t *cpu, rvm_asmins_t *ins)
789 {
790         rvmreg_t *arg1 = RVM_CPUREG_PTR(cpu, ins->op1);
791         rvmreg_t *arg2 = RVM_CPUREG_PTR(cpu, ins->op2);
792         rvmreg_t tmp = rvm_reg_create_signed(0);
793         rmap_t *a = NULL;
794         long index;
795
796         rjs_opmap_invoke_binary_handler(RJS_USERDATA2MAP(cpu->userdata2), RJS_OPID_CAST, cpu, &tmp, RVM_CPUREG_PTR(cpu, ins->op3), &tmp);
797         index = (long)RVM_REG_GETL(&tmp);
798         if (rvm_reg_gettype(arg2) != RVM_DTYPE_MAP)
799                 RVM_ABORT(cpu, RVM_E_NOTOBJECT);
800         a = (rmap_t*)RVM_REG_GETP(arg2);
801         if (index < 0)
802                 index = r_map_last(a);
803         else
804                 index = r_map_prev(a, index);
805         RVM_REG_CLEAR(arg1);
806         RVM_REG_SETTYPE(arg1, RVM_DTYPE_SIGNED);
807         RVM_REG_SETL(arg1, index);
808 }
809
810
811 static void rjs_op_mapstr(rvmcpu_t *cpu, rvm_asmins_t *ins)
812 {
813         rvmreg_t *arg1 = RVM_CPUREG_PTR(cpu, ins->op1);
814         rvmreg_t *arg2 = RVM_CPUREG_PTR(cpu, ins->op2);
815         rvmreg_t tmp = rvm_reg_create_signed(0);
816         rmap_t *a = NULL;
817         rpointer value;
818         long index;
819
820         rjs_opmap_invoke_binary_handler(RJS_USERDATA2MAP(cpu->userdata2), RJS_OPID_CAST, cpu, &tmp, RVM_CPUREG_PTR(cpu, ins->op3), &tmp);
821         index = (long)RVM_REG_GETL(&tmp);
822         if (rvm_reg_gettype(arg2) != RVM_DTYPE_MAP)
823                 RVM_ABORT(cpu, RVM_E_NOTOBJECT);
824         a = (rmap_t*)RVM_REG_GETP(arg2);
825         value = r_map_value(a, index);
826         if (!value)
827                 RVM_ABORT(cpu, RVM_E_ILLEGAL);
828         r_map_setvalue(a, index, arg1);
829 }
830
831
832 const char *rjs_version()
833 {
834         return RJS_VERSION_STRING;
835 }
836
837
838 static void rjs_string_ltrim(rvmcpu_t *cpu, rvm_asmins_t *ins)
839 {
840         const char *ptr, *list;
841         unsigned long size;
842         rvmreg_t *r = NULL, *l = NULL;
843         rstring_t *src, *dest;
844
845         r = (rvmreg_t *) RVM_CPUREG_PTR(cpu, TP);
846         if (RJS_SWI_PARAMS(cpu) > 0) {
847                 l = (rvmreg_t *) RJS_SWI_PARAM(cpu, 1);
848                 if (rvm_reg_gettype(l) != RVM_DTYPE_STRING)
849                         RJS_SWI_ABORT(rjs_engine_get(cpu), NULL);
850         }
851         if (rvm_reg_gettype(r) != RVM_DTYPE_STRING)
852                 RJS_SWI_ABORT(rjs_engine_get(cpu), NULL);
853         if (l)
854                 list = ((rstring_t *)RVM_REG_GETP(l))->s.str;
855         else
856                 list = " \t\n\r\0";
857         src = (rstring_t *)RVM_REG_GETP(r);
858         ptr = src->s.str;
859         size = src->s.size;
860         while (size > 0) {
861                 if (!r_strchr(list, *ptr))
862                         break;
863                 size--;
864                 ptr++;
865         }
866         dest = r_string_create_strsize(ptr, size);
867         r_gc_add(cpu->gc, (robject_t*)dest);
868         rvm_reg_setstring(RVM_CPUREG_PTR(cpu, R0), dest);
869 }
870
871
872 rjs_engine_t *rjs_engine_create()
873 {
874         rvmcpu_t *cpu;
875         rvmreg_t *tp;
876         rvmreg_t tmp;
877         rjs_engine_t *jse = (rjs_engine_t *) r_zmalloc(sizeof(*jse));
878
879         jse->pa = rjs_parser_create();
880         jse->cpu = cpu = rvm_cpu_create_default();
881         jse->co = rjs_compiler_create(jse->cpu);
882         jse->cgs = r_array_create(sizeof(rvm_codegen_t*));
883         jse->errors = r_array_create(sizeof(rjs_error_t));
884         jse->cpu->userdata1 = jse;
885         rvm_cpu_addswitable(jse->cpu, "rjsswitable", rjsswitable);
886         if (!jse->pa || !jse->cpu || !jse->co || !jse->cgs)
887                 goto error;
888         rjs_engine_initgp(jse);
889         tp = rvm_cpu_alloc_global(jse->cpu);
890         rvm_reg_setjsobject(tp, (robject_t *)r_map_create(sizeof(rvmreg_t), 7));
891         r_gc_add(jse->cpu->gc, (robject_t*)RVM_REG_GETP(tp));
892         rvm_cpu_setreg(jse->cpu, TP, tp);
893
894         rvm_cpu_setophandler(cpu, RJS_CAST, "RJS_CAST", rjs_op_cast);
895         rvm_cpu_setophandler(cpu, RJS_ENEG, "RJS_ENEG", rjs_op_eneg);
896         rvm_cpu_setophandler(cpu, RJS_EADD, "RJS_EADD", rjs_op_eadd);
897         rvm_cpu_setophandler(cpu, RJS_ESUB, "RJS_ESUB", rjs_op_esub);
898         rvm_cpu_setophandler(cpu, RJS_EMUL, "RJS_EMUL", rjs_op_emul);
899         rvm_cpu_setophandler(cpu, RJS_EDIV, "RJS_EDIV", rjs_op_ediv);
900         rvm_cpu_setophandler(cpu, RJS_EMOD, "RJS_EMOD", rjs_op_emod);
901         rvm_cpu_setophandler(cpu, RJS_ELSL, "RJS_ELSL", rjs_op_elsl);
902         rvm_cpu_setophandler(cpu, RJS_ELSR, "RJS_ELSR", rjs_op_elsr);
903         rvm_cpu_setophandler(cpu, RJS_ELSRU, "RJS_ELSRU", rjs_op_elsru);
904         rvm_cpu_setophandler(cpu, RJS_EAND, "RJS_EAND", rjs_op_eand);
905         rvm_cpu_setophandler(cpu, RJS_EORR, "RJS_EORR", rjs_op_eorr);
906         rvm_cpu_setophandler(cpu, RJS_EXOR, "RJS_EXOR", rjs_op_exor);
907         rvm_cpu_setophandler(cpu, RJS_ENOT, "RJS_ENOT", rjs_op_enot);
908         rvm_cpu_setophandler(cpu, RJS_ELAND, "RJS_ELAND", rjs_op_eland);
909         rvm_cpu_setophandler(cpu, RJS_ELOR, "RJS_ELOR", rjs_op_elor);
910         rvm_cpu_setophandler(cpu, RJS_ELNOT, "RJS_ELNOT", rjs_op_elnot);
911         rvm_cpu_setophandler(cpu, RJS_EEQ, "RJS_EEQ", rjs_op_eeq);
912         rvm_cpu_setophandler(cpu, RJS_ENOTEQ, "RJS_ENOTEQ", rjs_op_enoteq);
913         rvm_cpu_setophandler(cpu, RJS_EGREAT, "RJS_EGREAT", rjs_op_egreat);
914         rvm_cpu_setophandler(cpu, RJS_EGREATEQ, "RJS_EGREATEQ", rjs_op_egreateq);
915         rvm_cpu_setophandler(cpu, RJS_ELESS, "RJS_ELESS", rjs_op_eless);
916         rvm_cpu_setophandler(cpu, RJS_ELESSEQ, "RJS_ELESSEQ", rjs_op_elesseq);
917         rvm_cpu_setophandler(cpu, RJS_ECMP, "RJS_ECMP", rjs_op_ecmp);
918         rvm_cpu_setophandler(cpu, RJS_ECMN, "RJS_ECMN", rjs_op_ecmn);
919         rvm_cpu_setophandler(cpu, RJS_PROPLKUP, "RJS_PROPLKUP", rjs_op_proplookup);
920         rvm_cpu_setophandler(cpu, RJS_PROPLKUPADD, "RJS_PROPLKUPADD", rjs_op_proplookupadd);
921         rvm_cpu_setophandler(cpu, RJS_PROPLDR, "RJS_PROPLDR", rjs_op_propldr);
922         rvm_cpu_setophandler(cpu, RJS_PROPSTR, "RJS_PROPSTR", rjs_op_propstr);
923         rvm_cpu_setophandler(cpu, RJS_PROPADDR, "RJS_PROPADDR", rjs_op_propaddr);
924         rvm_cpu_setophandler(cpu, RJS_PROPKEYLDR, "RJS_PROPKEYLDR", rjs_op_propkeyldr);
925         rvm_cpu_setophandler(cpu, RJS_PROPDEL, "RJS_PROPDEL", rjs_op_propdel);
926         rvm_cpu_setophandler(cpu, RJS_PROPNEXT, "RJS_PROPNEXT", rjs_op_propnext);
927         rvm_cpu_setophandler(cpu, RJS_PROPPREV, "RJS_PROPPREV", rjs_op_propprev);
928         rvm_cpu_setophandler(cpu, RJS_STRALLOC, "RJS_STRALLOC", rjs_op_stralloc);
929         rvm_cpu_setophandler(cpu, RJS_MAPALLOC, "RJS_MAPALLOC", rjs_op_mapalloc);
930
931         cpu->userdata2 = rjs_opmap_create();
932         rjs_op_binary_init(RJS_USERDATA2MAP(cpu->userdata2));
933         rjs_op_cast_init(RJS_USERDATA2MAP(cpu->userdata2));
934         rjs_op_not_init(RJS_USERDATA2MAP(cpu->userdata2));
935         rjs_op_logicnot_init(RJS_USERDATA2MAP(cpu->userdata2));
936
937
938         jse->props[RVM_DTYPE_STRING] = r_map_create(sizeof(rvmreg_t), 3);
939         tmp = rvm_reg_create_swi(rvm_cpu_swilookup_s(cpu, "rjsswitable", "string.ltrim"));
940         r_map_add_s(jse->props[RVM_DTYPE_STRING], "ltrim", &tmp);
941         r_gc_add(jse->cpu->gc, (robject_t*)jse->props[RVM_DTYPE_STRING]);
942
943         return jse;
944 error:
945         rjs_engine_destroy(jse);
946         return NULL;
947 }
948
949
950 void rjs_engine_destroy(rjs_engine_t *jse)
951 {
952         unsigned long i;
953
954         if (jse) {
955                 if (jse->cgs) {
956                         for (i = 0; i < r_array_length(jse->cgs); i++) {
957                                 rvm_codegen_destroy(r_array_index(jse->cgs, i, rvm_codegen_t*));
958                         }
959                 }
960                 r_array_destroy(jse->cgs);
961                 r_array_destroy(jse->errors);
962                 rjs_parser_destroy(jse->pa);
963                 rjs_opmap_destroy(RJS_USERDATA2MAP(jse->cpu->userdata2));
964                 rvm_cpu_destroy(jse->cpu);
965                 rjs_compiler_destroy(jse->co);
966                 r_free(jse);
967         }
968 }
969
970
971 static void rjs_engine_addtypename(rjs_engine_t *jse, rmap_t *types, unsigned long type, const char *typename)
972 {
973         rvmreg_t rs;
974         rstring_t *s;
975
976         s = r_string_create_from_ansistr(typename);
977         r_gc_add(jse->cpu->gc, (robject_t*)s);
978         rvm_reg_setstring(&rs, s);
979         r_map_add_l(types, type, &rs);
980 }
981
982
983 static void rjs_engine_inittypes(rjs_engine_t *jse)
984 {
985         rmap_t *gmap = (rmap_t *)RVM_CPUREG_GETP(jse->cpu, GP);
986         rmap_t *types;
987         rvmreg_t rt;
988
989         types = r_map_create(sizeof(rvmreg_t), 3);
990         r_gc_add(jse->cpu->gc, (robject_t*)types);
991         rvm_reg_setjsobject(&rt, (robject_t *)types);
992         r_map_add_l(gmap, RJS_GPKEY_TYPES, &rt);
993         rjs_engine_addtypename(jse, types, RVM_DTYPE_UNDEF, "undefined");
994         rjs_engine_addtypename(jse, types, RVM_DTYPE_BOOLEAN, "boolean");
995         rjs_engine_addtypename(jse, types, RVM_DTYPE_DOUBLE, "number");
996         rjs_engine_addtypename(jse, types, RVM_DTYPE_UNSIGNED, "number");
997         rjs_engine_addtypename(jse, types, RVM_DTYPE_SIGNED, "number");
998         rjs_engine_addtypename(jse, types, RVM_DTYPE_STRING, "string");
999         rjs_engine_addtypename(jse, types, RVM_DTYPE_FUNCTION, "object");
1000         rjs_engine_addtypename(jse, types, RVM_DTYPE_NAN, "object");
1001         rjs_engine_addtypename(jse, types, RVM_DTYPE_MAP, "object");
1002         rjs_engine_addtypename(jse, types, RVM_DTYPE_POINTER, "object");
1003 }
1004
1005
1006 static void rjs_engine_initgp(rjs_engine_t *jse)
1007 {
1008         rvmreg_t gp;
1009         rmap_t *gmap;
1010
1011         rvm_reg_init(&gp);
1012         gmap = r_map_create(sizeof(rvmreg_t), 7);
1013         r_gc_add(jse->cpu->gc, (robject_t*)gmap);
1014         rvm_reg_setjsobject(RVM_CPUREG_PTR(jse->cpu, GP), (robject_t *)gmap);
1015         rjs_engine_inittypes(jse);
1016 }
1017
1018
1019 int rjs_engine_open(rjs_engine_t *jse)
1020 {
1021         return 0;
1022 }
1023
1024
1025 int rjs_engine_addswitable(rjs_engine_t *jse, const char *tabname, rvm_switable_t *switalbe)
1026 {
1027         return rvm_cpu_addswitable(jse->cpu, tabname, switalbe);
1028 }
1029
1030
1031 static int rjs_engine_parse(rjs_engine_t *jse, const char *script, unsigned long size, rarray_t *records, rjs_error_t *error)
1032 {
1033         long res = 0;
1034
1035         res = rjs_parser_exec(jse->pa, script, size, records, error);
1036         return res;
1037 }
1038
1039
1040 int rjs_engine_compile(rjs_engine_t *jse, const char *script, unsigned long size)
1041 {
1042         rvm_codegen_t *topcg = NULL;
1043         rarray_t *records = rpa_records_create();
1044         rjs_error_t error;
1045         jse->co->debug = jse->debugcompile;
1046
1047         r_memset(&error, 0, sizeof(error));
1048         if (rjs_engine_parse(jse, script, size, records, &error) < 0) {
1049
1050                 goto err;
1051         }
1052
1053         topcg =  r_array_empty(jse->cgs) ? NULL : r_array_last(jse->cgs, rvm_codegen_t*);
1054         if (!topcg || (topcg->userdata & RJS_COMPILER_CODEGENKEEP)) {
1055                 /*
1056                  * Keep this script codegen object. Allocate a new one for the
1057                  * next script.
1058                  */
1059                 topcg = rvm_codegen_create();
1060                 r_array_add(jse->cgs, &topcg);
1061         } else {
1062                 rvm_codegen_clear(topcg);
1063         }
1064         topcg->userdata = 0;
1065         if (rjs_compiler_compile(jse->co, script, size, records, topcg, &error) < 0) {
1066                 topcg->userdata = 0;
1067                 goto err;
1068         }
1069
1070         rpa_records_destroy(records);
1071         return 0;
1072
1073 err:
1074         r_array_add(jse->errors, &error);
1075         rpa_records_destroy(records);
1076         return -1;
1077 }
1078
1079
1080 int rjs_engine_dumpast(rjs_engine_t *jse, const char *script, unsigned long size)
1081 {
1082         rjs_error_t error;
1083         rarray_t *records = rpa_records_create();
1084
1085         if (rjs_engine_parse(jse, script, size, records, &error) < 0) {
1086
1087
1088                 return -1;
1089         }
1090
1091         if (records) {
1092                 long i;
1093                 for (i = 0; i < rpa_records_length(records); i++)
1094                         rpa_record_dump(records, i);
1095         }
1096
1097         rpa_records_destroy(records);
1098         return 0;
1099 }
1100
1101
1102 int rjs_engine_compile_s(rjs_engine_t *jse, const char *script)
1103 {
1104         return rjs_engine_compile(jse, script, r_strlen(script));
1105 }
1106
1107
1108 int rjs_engine_close(rjs_engine_t *jse)
1109 {
1110
1111         return 0;
1112 }
1113
1114
1115 int rjs_engine_run(rjs_engine_t *jse)
1116 {
1117         int res = 0;
1118         rvm_codegen_t *cg = r_array_empty(jse->cgs) ? NULL : r_array_last(jse->cgs, rvm_codegen_t*);
1119
1120         if (!cg) {
1121
1122                 return -1;
1123         }
1124         if (jse->debugexec) {
1125                 res = rvm_cpu_exec_debug(jse->cpu, rvm_codegen_getcode(cg, 0), 0);
1126         } else {
1127                 res = rvm_cpu_exec(jse->cpu, rvm_codegen_getcode(cg, 0), 0);
1128         }
1129
1130         if (jse->cpu->error == RVM_E_USERABORT) {
1131                 rword idx = RVM_CPUREG_GETIP(jse->cpu, PC) - rvm_codegen_getcode(cg, 0);
1132                 if (idx >= 0) {
1133                         r_printf("Aborted at source index: %ld\n", rvm_codegen_getsource(cg, (unsigned long)idx));
1134                 }
1135         }
1136         return res;
1137 }
1138
1139
1140 rvmreg_t * rjs_engine_exec(rjs_engine_t *jse, const char *script, unsigned long size)
1141 {
1142         if (rjs_engine_compile(jse, script, size) < 0)
1143                 return NULL;
1144         RVM_CPUREG_SETU(jse->cpu, FP, 0);
1145         RVM_CPUREG_SETU(jse->cpu, SP, 0);
1146         if (rjs_engine_run(jse) < 0)
1147                 return NULL;
1148         return RVM_CPUREG_PTR(jse->cpu, R0);
1149 }
1150
1151
1152 rvmreg_t *rjs_engine_exec_s(rjs_engine_t *jse, const char *script)
1153 {
1154         return rjs_engine_exec(jse, script, r_strlen(script));
1155 }
1156
1157
1158 static int rjs_compiler_argarray_setup(rjs_compiler_t *co)
1159 {
1160         rvm_varmap_t *v;
1161         rvmreg_t count = rvm_reg_create_signed(0);
1162         rmap_t *a;
1163
1164         v = rvm_scope_tiplookup_s(co->scope, "ARGS");
1165         if (!v) {
1166                 return -1;
1167         }
1168         a = r_map_create(sizeof(rvmreg_t), 7);
1169         r_gc_add(co->cpu->gc, (robject_t*)a);
1170         r_map_add_s(a, "count", &count);
1171         rvm_reg_setjsobject((rvmreg_t*)v->data.ptr, (robject_t*)a);
1172         return 0;
1173 }
1174
1175
1176 static int rjs_compiler_addarg(rjs_compiler_t *co, rvmreg_t *arg)
1177 {
1178         rvm_varmap_t *v;
1179         rmap_t *a;
1180         rvmreg_t *count;
1181         long index;
1182
1183         v = rvm_scope_tiplookup_s(co->scope, "ARGS");
1184         if (!v) {
1185                 return -1;
1186         }
1187         a = (rmap_t*)RVM_REG_GETP((rvmreg_t*)v->data.ptr);
1188         index = r_map_lookup_s(a, -1, "count");
1189         R_ASSERT(index >= 0);
1190         count = (rvmreg_t *)r_map_value(a, index);
1191         r_map_add_l(a, (long)RVM_REG_GETL(count), arg);
1192         rvm_reg_setsigned(count, RVM_REG_GETL(count) + 1);
1193
1194         return 0;
1195 }
1196
1197
1198 rvmreg_t *rjs_engine_vexec(rjs_engine_t *jse, const char *script, unsigned long size, unsigned long nargs, va_list args)
1199 {
1200         rvmreg_t arg;
1201         unsigned long i = 0;
1202
1203         if (rjs_engine_compile(jse, script, size) < 0)
1204                 return NULL;
1205         if (nargs > 0) {
1206                 rjs_compiler_argarray_setup(jse->co);
1207                 for (i = 0; i < nargs; i++) {
1208                         arg = va_arg(args, rvmreg_t);
1209                         rjs_compiler_addarg(jse->co, &arg);
1210                 }
1211         }
1212         RVM_CPUREG_SETU(jse->cpu, FP, 0);
1213         RVM_CPUREG_SETU(jse->cpu, SP, 0);
1214         if (rjs_engine_run(jse) < 0)
1215                 return NULL;
1216         return RVM_CPUREG_PTR(jse->cpu, R0);
1217 }
1218
1219
1220 rvmreg_t *rjs_engine_args_exec(rjs_engine_t *jse, const char *script, unsigned long size, unsigned long nargs, ...)
1221 {
1222         rvmreg_t *ret;
1223         va_list args;
1224         va_start(args, nargs);
1225         ret = rjs_engine_vexec(jse, script, size, nargs, args);
1226         va_end(args);
1227         return ret;
1228 }
1229
1230
1231 rvmreg_t *rjs_engine_args_exec_s(rjs_engine_t *jse, const char *script, unsigned long nargs, ...)
1232 {
1233         rvmreg_t *ret;
1234         va_list args;
1235         va_start(args, nargs);
1236         ret = rjs_engine_vexec(jse, script, r_strlen(script), nargs, args);
1237         va_end(args);
1238         return ret;
1239 }
1240
1241
1242 static void rjs_engine_print(rvmcpu_t *cpu, rvm_asmins_t *ins)
1243 {
1244         rvmreg_t *r = (rvmreg_t *)RVM_STACK_ADDR(cpu->stack, RVM_CPUREG_GETU(cpu, FP) + 1);
1245
1246         if (rvm_reg_gettype(r) == RVM_DTYPE_UNSIGNED)
1247                 r_printf("%lu\n", RVM_REG_GETU(r));
1248         else if (rvm_reg_gettype(r) == RVM_DTYPE_NAN)
1249                 r_printf("NaN\n");
1250         else if (rvm_reg_gettype(r) == RVM_DTYPE_UNDEF)
1251                 r_printf("undefined\n");
1252         else if (rvm_reg_gettype(r) == RVM_DTYPE_BOOLEAN)
1253                 r_printf("%s\n", RVM_REG_GETU(r) ? "true" : "false");
1254         else if (rvm_reg_gettype(r) == RVM_DTYPE_POINTER)
1255                 r_printf("%p\n", RVM_REG_GETP(r));
1256         else if (rvm_reg_gettype(r) == RVM_DTYPE_SIGNED)
1257                 r_printf("%ld\n", RVM_REG_GETL(r));
1258         else if (rvm_reg_gettype(r) == RVM_DTYPE_DOUBLE)
1259                 r_printf("%f\n", RVM_REG_GETD(r));
1260         else if (rvm_reg_gettype(r) == RVM_DTYPE_STRING)
1261                 r_printf("%s\n", ((rstring_t*) RVM_REG_GETP(r))->s.str);
1262         else if (rvm_reg_gettype(r) == RVM_DTYPE_STRPTR)
1263                 r_printf("(STRPTR) %s\n", (RVM_REG_GETSTR(r)));
1264         else if (rvm_reg_gettype(r) == RVM_DTYPE_MAP)
1265                 r_printf("(object) %p\n",RVM_REG_GETP(r));
1266         else if (rvm_reg_gettype(r) == RVM_DTYPE_HARRAY)
1267                 r_printf("(hashed array) %p\n",RVM_REG_GETP(r));
1268         else if (rvm_reg_gettype(r) == RVM_DTYPE_SWIID)
1269                 r_printf("(function) %p\n",RVM_REG_GETP(r));
1270         else
1271                 r_printf("%p\n", RVM_REG_GETP(r));
1272 }
1273
1274
1275 static void rjs_engine_dbgprint(rvmcpu_t *cpu, rvm_asmins_t *ins)
1276 {
1277         rvmreg_t *r = (rvmreg_t *)RVM_STACK_ADDR(cpu->stack, RVM_CPUREG_GETU(cpu, FP) + 1);
1278
1279         if (rvm_reg_gettype(r) == RVM_DTYPE_UNSIGNED)
1280                 r_printf("(UNSIGNED) %lu\n", RVM_REG_GETU(r));
1281         else if (rvm_reg_gettype(r) == RVM_DTYPE_NAN)
1282                 r_printf("(NAN) NaN\n");
1283         else if (rvm_reg_gettype(r) == RVM_DTYPE_UNDEF)
1284                 r_printf("(UNDEF) undefined\n");
1285         else if (rvm_reg_gettype(r) == RVM_DTYPE_BOOLEAN)
1286                 r_printf("(BOOLEAN) %s\n", RVM_REG_GETU(r) ? "true" : "false");
1287         else if (rvm_reg_gettype(r) == RVM_DTYPE_POINTER)
1288                 r_printf("(POINTER) %p\n", RVM_REG_GETP(r));
1289         else if (rvm_reg_gettype(r) == RVM_DTYPE_SIGNED)
1290                 r_printf("(LONG) %ld\n", RVM_REG_GETL(r));
1291         else if (rvm_reg_gettype(r) == RVM_DTYPE_DOUBLE)
1292                 r_printf("(DOUBLE) %f\n", RVM_REG_GETD(r));
1293         else if (rvm_reg_gettype(r) == RVM_DTYPE_STRING)
1294                 r_printf("(STRING) %s\n", ((rstring_t*) RVM_REG_GETP(r))->s.str);
1295         else if (rvm_reg_gettype(r) == RVM_DTYPE_STRPTR)
1296                 r_printf("(STRPTR) %s\n", (RVM_REG_GETSTR(r)));
1297         else if (rvm_reg_gettype(r) == RVM_DTYPE_MAP)
1298                 r_printf("(object) %p\n",RVM_REG_GETP(r));
1299         else if (rvm_reg_gettype(r) == RVM_DTYPE_HARRAY)
1300                 r_printf("(hashed array) %p\n",RVM_REG_GETP(r));
1301         else if (rvm_reg_gettype(r) == RVM_DTYPE_SWIID)
1302                 r_printf("(swi function) %p\n",RVM_REG_GETP(r));
1303         else if (rvm_reg_gettype(r) == RVM_DTYPE_FUNCTION)
1304                 r_printf("(function) %p\n",RVM_REG_GETP(r));
1305         else
1306                 r_printf("%p\n", RVM_REG_GETP(r));
1307 }
1308
1309
1310 static void rjs_engine_object(rvmcpu_t *cpu, rvm_asmins_t *ins)
1311 {
1312
1313 }
1314
1315
1316 void rjs_engine_abort(rjs_engine_t *jse, rjs_error_t *error)
1317 {
1318         if (error) {
1319                 r_array_add(jse->errors, error);
1320         }
1321         rvm_cpu_abort(jse->cpu);
1322 }
1323
1324
1325 rjs_engine_t *rjs_engine_get(rvmcpu_t *cpu)
1326 {
1327         return (rjs_engine_t *)cpu->userdata1;
1328 }