/src/mruby/mrbgems/mruby-compiler/core/codegen.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | ** codegen.c - mruby code generator |
3 | | ** |
4 | | ** See Copyright Notice in mruby.h |
5 | | */ |
6 | | |
7 | | #include <mruby.h> |
8 | | #include <mruby/compile.h> |
9 | | #include <mruby/proc.h> |
10 | | #include <mruby/dump.h> |
11 | | #include <mruby/numeric.h> |
12 | | #include <mruby/string.h> |
13 | | #include <mruby/debug.h> |
14 | | #include <mruby/presym.h> |
15 | | #include "node.h" |
16 | | #include <mruby/opcode.h> |
17 | | #include <mruby/re.h> |
18 | | #include <mruby/throw.h> |
19 | | #include <ctype.h> |
20 | | #include <string.h> |
21 | | #include <mruby/internal.h> |
22 | | |
23 | | #ifndef MRB_CODEGEN_LEVEL_MAX |
24 | 1.58M | #define MRB_CODEGEN_LEVEL_MAX 256 |
25 | | #endif |
26 | | |
27 | | #define MAXARG_S (1<<16) |
28 | | |
29 | | typedef mrb_ast_node node; |
30 | | typedef struct mrb_parser_state parser_state; |
31 | | |
32 | | enum looptype { |
33 | | LOOP_NORMAL, |
34 | | LOOP_BLOCK, |
35 | | LOOP_FOR, |
36 | | LOOP_BEGIN, |
37 | | LOOP_RESCUE, |
38 | | }; |
39 | | |
40 | | struct loopinfo { |
41 | | enum looptype type; |
42 | | uint32_t pc0; /* `next` destination */ |
43 | | uint32_t pc1; /* `redo` destination */ |
44 | | uint32_t pc2; /* `break` destination */ |
45 | | int reg; /* destination register */ |
46 | | struct loopinfo *prev; |
47 | | }; |
48 | | |
49 | | typedef struct scope { |
50 | | mrb_state *mrb; |
51 | | mrb_pool *mpool; |
52 | | |
53 | | struct scope *prev; |
54 | | |
55 | | node *lv; |
56 | | |
57 | | uint16_t sp; |
58 | | uint32_t pc; |
59 | | uint32_t lastpc; |
60 | | uint32_t lastlabel; |
61 | | uint16_t ainfo:15; |
62 | | mrb_bool mscope:1; |
63 | | |
64 | | struct loopinfo *loop; |
65 | | mrb_sym filename_sym; |
66 | | uint16_t lineno; |
67 | | |
68 | | mrb_code *iseq; |
69 | | uint16_t *lines; |
70 | | uint32_t icapa; |
71 | | |
72 | | mrb_irep *irep; |
73 | | mrb_pool_value *pool; |
74 | | mrb_sym *syms; |
75 | | mrb_irep **reps; |
76 | | struct mrb_irep_catch_handler *catch_table; |
77 | | uint32_t pcapa, scapa, rcapa; |
78 | | |
79 | | uint16_t nlocals; |
80 | | uint16_t nregs; |
81 | | int ai; |
82 | | |
83 | | int debug_start_pos; |
84 | | uint16_t filename_index; |
85 | | parser_state* parser; |
86 | | |
87 | | int rlev; /* recursion levels */ |
88 | | } codegen_scope; |
89 | | |
90 | | static codegen_scope* scope_new(mrb_state *mrb, codegen_scope *prev, node *lv); |
91 | | static void scope_finish(codegen_scope *s); |
92 | | static struct loopinfo *loop_push(codegen_scope *s, enum looptype t); |
93 | | static void loop_break(codegen_scope *s, node *tree); |
94 | | static void loop_pop(codegen_scope *s, int val); |
95 | | |
96 | | /* |
97 | | * The search for catch handlers starts at the end of the table in mrb_vm_run(). |
98 | | * Therefore, the next handler to be added must meet one of the following conditions. |
99 | | * - Larger start position |
100 | | * - Same start position but smaller end position |
101 | | */ |
102 | | static int catch_handler_new(codegen_scope *s); |
103 | | static void catch_handler_set(codegen_scope *s, int ent, enum mrb_catch_type type, uint32_t begin, uint32_t end, uint32_t target); |
104 | | |
105 | | static void gen_assignment(codegen_scope *s, node *tree, node *rhs, int sp, int val); |
106 | | static void gen_massignment(codegen_scope *s, node *tree, int sp, int val); |
107 | | |
108 | | static void codegen(codegen_scope *s, node *tree, int val); |
109 | | static void raise_error(codegen_scope *s, const char *msg); |
110 | | |
111 | | static void |
112 | | codegen_error(codegen_scope *s, const char *message) |
113 | 72 | { |
114 | 72 | if (!s) return; |
115 | 72 | #ifndef MRB_NO_STDIO |
116 | 72 | if (s->filename_sym && s->lineno) { |
117 | 0 | const char *filename = mrb_sym_name_len(s->mrb, s->filename_sym, NULL); |
118 | 0 | fprintf(stderr, "%s:%d: %s\n", filename, s->lineno, message); |
119 | 0 | } |
120 | 72 | else { |
121 | 72 | fprintf(stderr, "%s\n", message); |
122 | 72 | } |
123 | 72 | #endif |
124 | 216 | while (s->prev) { |
125 | 144 | codegen_scope *tmp = s->prev; |
126 | 144 | if (s->irep) { |
127 | 144 | mrb_free(s->mrb, s->iseq); |
128 | 675 | for (int i=0; i<s->irep->plen; i++) { |
129 | 531 | mrb_pool_value *pv = &s->pool[i]; |
130 | 531 | if ((pv->tt & 0x3) == IREP_TT_STR || pv->tt == IREP_TT_BIGINT) { |
131 | 465 | mrb_free(s->mrb, (void*)pv->u.str); |
132 | 465 | } |
133 | 531 | } |
134 | 144 | mrb_free(s->mrb, s->pool); |
135 | 144 | mrb_free(s->mrb, s->syms); |
136 | 144 | mrb_free(s->mrb, s->catch_table); |
137 | 144 | if (s->reps) { |
138 | | /* copied from mrb_irep_free() in state.c */ |
139 | 216 | for (int i=0; i<s->irep->rlen; i++) { |
140 | 72 | if (s->reps[i]) |
141 | 72 | mrb_irep_decref(s->mrb, (mrb_irep*)s->reps[i]); |
142 | 72 | } |
143 | 144 | mrb_free(s->mrb, s->reps); |
144 | 144 | } |
145 | 144 | mrb_free(s->mrb, s->lines); |
146 | 144 | } |
147 | 144 | mrb_pool_close(s->mpool); |
148 | 144 | s = tmp; |
149 | 144 | } |
150 | 72 | MRB_THROW(s->mrb->jmp); |
151 | 0 | } |
152 | | |
153 | | static void* |
154 | | codegen_palloc(codegen_scope *s, size_t len) |
155 | 0 | { |
156 | 0 | void *p = mrb_pool_alloc(s->mpool, len); |
157 | |
|
158 | 0 | if (!p) codegen_error(s, "pool memory allocation"); |
159 | 0 | return p; |
160 | 0 | } |
161 | | |
162 | | static void* |
163 | | codegen_realloc(codegen_scope *s, void *p, size_t len) |
164 | 7.65k | { |
165 | 7.65k | p = mrb_realloc_simple(s->mrb, p, len); |
166 | | |
167 | 7.65k | if (!p && len > 0) codegen_error(s, "mrb_realloc"); |
168 | 7.65k | return p; |
169 | 7.65k | } |
170 | | |
171 | | static void |
172 | | check_no_ext_ops(codegen_scope *s, uint16_t a, uint16_t b) |
173 | 1.48M | { |
174 | 1.48M | if (s->parser->no_ext_ops && (a | b) > 0xff) { |
175 | 0 | codegen_error(s, "need OP_EXTs instruction (currently OP_EXTs are prohibited)"); |
176 | 0 | } |
177 | 1.48M | } |
178 | | |
179 | | static int |
180 | | new_label(codegen_scope *s) |
181 | 466 | { |
182 | 466 | return s->lastlabel = s->pc; |
183 | 466 | } |
184 | | |
185 | | static void |
186 | | emit_B(codegen_scope *s, uint32_t pc, uint8_t i) |
187 | 5.14M | { |
188 | 5.14M | if (pc >= s->icapa) { |
189 | 1.24k | if (pc == UINT32_MAX) { |
190 | 0 | codegen_error(s, "too big code block"); |
191 | 0 | } |
192 | 1.24k | if (pc >= UINT32_MAX / 2) { |
193 | 0 | pc = UINT32_MAX; |
194 | 0 | } |
195 | 1.24k | else { |
196 | 1.24k | s->icapa *= 2; |
197 | 1.24k | } |
198 | 1.24k | s->iseq = (mrb_code*)codegen_realloc(s, s->iseq, sizeof(mrb_code)*s->icapa); |
199 | 1.24k | if (s->lines) { |
200 | 0 | s->lines = (uint16_t*)codegen_realloc(s, s->lines, sizeof(uint16_t)*s->icapa); |
201 | 0 | } |
202 | 1.24k | } |
203 | 5.14M | if (s->lines) { |
204 | 0 | if (s->lineno > 0 || pc == 0) |
205 | 0 | s->lines[pc] = s->lineno; |
206 | 0 | else |
207 | 0 | s->lines[pc] = s->lines[pc-1]; |
208 | 0 | } |
209 | 5.14M | s->iseq[pc] = i; |
210 | 5.14M | } |
211 | | |
212 | | static void |
213 | | emit_S(codegen_scope *s, int pc, uint16_t i) |
214 | 631k | { |
215 | 631k | uint8_t hi = i>>8; |
216 | 631k | uint8_t lo = i&0xff; |
217 | | |
218 | 631k | emit_B(s, pc, hi); |
219 | 631k | emit_B(s, pc+1, lo); |
220 | 631k | } |
221 | | |
222 | | static void |
223 | | gen_B(codegen_scope *s, uint8_t i) |
224 | 3.88M | { |
225 | 3.88M | emit_B(s, s->pc, i); |
226 | 3.88M | s->pc++; |
227 | 3.88M | } |
228 | | |
229 | | static void |
230 | | gen_S(codegen_scope *s, uint16_t i) |
231 | 580k | { |
232 | 580k | emit_S(s, s->pc, i); |
233 | 580k | s->pc += 2; |
234 | 580k | } |
235 | | |
236 | | static void |
237 | | genop_0(codegen_scope *s, mrb_code i) |
238 | 50.9k | { |
239 | 50.9k | s->lastpc = s->pc; |
240 | 50.9k | gen_B(s, i); |
241 | 50.9k | } |
242 | | |
243 | | static void |
244 | | genop_1(codegen_scope *s, mrb_code i, uint16_t a) |
245 | 736k | { |
246 | 736k | s->lastpc = s->pc; |
247 | 736k | check_no_ext_ops(s, a, 0); |
248 | 736k | if (a > 0xff) { |
249 | 291k | gen_B(s, OP_EXT1); |
250 | 291k | gen_B(s, i); |
251 | 291k | gen_S(s, a); |
252 | 291k | } |
253 | 444k | else { |
254 | 444k | gen_B(s, i); |
255 | 444k | gen_B(s, (uint8_t)a); |
256 | 444k | } |
257 | 736k | } |
258 | | |
259 | | static void |
260 | | genop_2(codegen_scope *s, mrb_code i, uint16_t a, uint16_t b) |
261 | 746k | { |
262 | 746k | s->lastpc = s->pc; |
263 | 746k | check_no_ext_ops(s, a, b); |
264 | 746k | if (a > 0xff && b > 0xff) { |
265 | 2.86k | gen_B(s, OP_EXT3); |
266 | 2.86k | gen_B(s, i); |
267 | 2.86k | gen_S(s, a); |
268 | 2.86k | gen_S(s, b); |
269 | 2.86k | } |
270 | 743k | else if (b > 0xff) { |
271 | 1.34k | gen_B(s, OP_EXT2); |
272 | 1.34k | gen_B(s, i); |
273 | 1.34k | gen_B(s, (uint8_t)a); |
274 | 1.34k | gen_S(s, b); |
275 | 1.34k | } |
276 | 742k | else if (a > 0xff) { |
277 | 224k | gen_B(s, OP_EXT1); |
278 | 224k | gen_B(s, i); |
279 | 224k | gen_S(s, a); |
280 | 224k | gen_B(s, (uint8_t)b); |
281 | 224k | } |
282 | 517k | else { |
283 | 517k | gen_B(s, i); |
284 | 517k | gen_B(s, (uint8_t)a); |
285 | 517k | gen_B(s, (uint8_t)b); |
286 | 517k | } |
287 | 746k | } |
288 | | |
289 | | static void |
290 | | genop_3(codegen_scope *s, mrb_code i, uint16_t a, uint16_t b, uint16_t c) |
291 | 82.9k | { |
292 | 82.9k | genop_2(s, i, a, b); |
293 | 82.9k | gen_B(s, (uint8_t)c); |
294 | 82.9k | } |
295 | | |
296 | | static void |
297 | | genop_2S(codegen_scope *s, mrb_code i, uint16_t a, uint16_t b) |
298 | 1.30k | { |
299 | 1.30k | genop_1(s, i, a); |
300 | 1.30k | gen_S(s, b); |
301 | 1.30k | } |
302 | | |
303 | | static void |
304 | | genop_2SS(codegen_scope *s, mrb_code i, uint16_t a, uint32_t b) |
305 | 1.12k | { |
306 | 1.12k | genop_1(s, i, a); |
307 | 1.12k | gen_S(s, b>>16); |
308 | 1.12k | gen_S(s, b&0xffff); |
309 | 1.12k | } |
310 | | |
311 | | static void |
312 | | genop_W(codegen_scope *s, mrb_code i, uint32_t a) |
313 | 466 | { |
314 | 466 | uint8_t a1 = (a>>16) & 0xff; |
315 | 466 | uint8_t a2 = (a>>8) & 0xff; |
316 | 466 | uint8_t a3 = a & 0xff; |
317 | | |
318 | 466 | s->lastpc = s->pc; |
319 | 466 | gen_B(s, i); |
320 | 466 | gen_B(s, a1); |
321 | 466 | gen_B(s, a2); |
322 | 466 | gen_B(s, a3); |
323 | 466 | } |
324 | | |
325 | 225k | #define NOVAL 0 |
326 | 484k | #define VAL 1 |
327 | | |
328 | | static mrb_bool |
329 | | no_optimize(codegen_scope *s) |
330 | 472k | { |
331 | 472k | if (s && s->parser && s->parser->no_optimize) |
332 | 0 | return TRUE; |
333 | 472k | return FALSE; |
334 | 472k | } |
335 | | |
336 | | struct mrb_insn_data |
337 | | mrb_decode_insn(const mrb_code *pc) |
338 | 390k | { |
339 | 390k | struct mrb_insn_data data = { 0 }; |
340 | 390k | if (pc == 0) return data; |
341 | 390k | data.addr = pc; |
342 | 390k | mrb_code insn = READ_B(); |
343 | 390k | uint16_t a = 0; |
344 | 390k | uint16_t b = 0; |
345 | 390k | uint16_t c = 0; |
346 | | |
347 | 390k | switch (insn) { |
348 | 0 | #define FETCH_Z() /* empty */ |
349 | 390k | #define OPCODE(i,x) case OP_ ## i: FETCH_ ## x (); break; |
350 | 390k | #include "mruby/ops.h" |
351 | 390k | #undef OPCODE |
352 | 390k | } |
353 | 390k | switch (insn) { |
354 | 118k | case OP_EXT1: |
355 | 118k | insn = READ_B(); |
356 | 118k | switch (insn) { |
357 | 118k | #define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _1 (); break; |
358 | 118k | #include "mruby/ops.h" |
359 | 118k | #undef OPCODE |
360 | 118k | } |
361 | 118k | break; |
362 | 118k | case OP_EXT2: |
363 | 471 | insn = READ_B(); |
364 | 471 | switch (insn) { |
365 | 471 | #define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _2 (); break; |
366 | 471 | #include "mruby/ops.h" |
367 | 471 | #undef OPCODE |
368 | 471 | } |
369 | 471 | break; |
370 | 1.45k | case OP_EXT3: |
371 | 1.45k | insn = READ_B(); |
372 | 1.45k | switch (insn) { |
373 | 1.45k | #define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _3 (); break; |
374 | 1.45k | #include "mruby/ops.h" |
375 | 1.45k | #undef OPCODE |
376 | 1.45k | } |
377 | 1.45k | break; |
378 | 269k | default: |
379 | 269k | break; |
380 | 390k | } |
381 | 390k | data.insn = insn; |
382 | 390k | data.a = a; |
383 | 390k | data.b = b; |
384 | 390k | data.c = c; |
385 | 390k | return data; |
386 | 390k | } |
387 | | |
388 | | #undef OPCODE |
389 | | #define Z 1 |
390 | | #define S 3 |
391 | | #define W 4 |
392 | | #define OPCODE(_,x) x, |
393 | | /* instruction sizes */ |
394 | | static uint8_t mrb_insn_size[] = { |
395 | | #define B 2 |
396 | | #define BB 3 |
397 | | #define BBB 4 |
398 | | #define BS 4 |
399 | | #define BSS 6 |
400 | | #include "mruby/ops.h" |
401 | | #undef B |
402 | | #undef BB |
403 | | #undef BBB |
404 | | #undef BS |
405 | | #undef BSS |
406 | | }; |
407 | | /* EXT1 instruction sizes */ |
408 | | static uint8_t mrb_insn_size1[] = { |
409 | | #define B 3 |
410 | | #define BB 4 |
411 | | #define BBB 5 |
412 | | #define BS 5 |
413 | | #define BSS 7 |
414 | | #include "mruby/ops.h" |
415 | | #undef B |
416 | | #undef BS |
417 | | #undef BSS |
418 | | }; |
419 | | /* EXT2 instruction sizes */ |
420 | | static uint8_t mrb_insn_size2[] = { |
421 | | #define B 2 |
422 | | #define BS 4 |
423 | | #define BSS 6 |
424 | | #include "mruby/ops.h" |
425 | | #undef B |
426 | | #undef BB |
427 | | #undef BBB |
428 | | #undef BS |
429 | | #undef BSS |
430 | | }; |
431 | | /* EXT3 instruction sizes */ |
432 | | #define B 3 |
433 | | #define BB 5 |
434 | | #define BBB 6 |
435 | | #define BS 5 |
436 | | #define BSS 7 |
437 | | static uint8_t mrb_insn_size3[] = { |
438 | | #include "mruby/ops.h" |
439 | | }; |
440 | | #undef B |
441 | | #undef BB |
442 | | #undef BBB |
443 | | #undef BS |
444 | | #undef BSS |
445 | | #undef OPCODE |
446 | | |
447 | | static const mrb_code* |
448 | | mrb_prev_pc(codegen_scope *s, const mrb_code *pc) |
449 | 98.9k | { |
450 | 98.9k | const mrb_code *prev_pc = NULL; |
451 | 98.9k | const mrb_code *i = s->iseq; |
452 | | |
453 | 172M | while (i<pc) { |
454 | 171M | uint8_t insn = i[0]; |
455 | 171M | prev_pc = i; |
456 | 171M | switch (insn) { |
457 | 17.9M | case OP_EXT1: |
458 | 17.9M | i += mrb_insn_size1[i[1]] + 1; |
459 | 17.9M | break; |
460 | 210k | case OP_EXT2: |
461 | 210k | i += mrb_insn_size2[i[1]] + 1; |
462 | 210k | break; |
463 | 216k | case OP_EXT3: |
464 | 216k | i += mrb_insn_size3[i[1]] + 1; |
465 | 216k | break; |
466 | 153M | default: |
467 | 153M | i += mrb_insn_size[insn]; |
468 | 153M | break; |
469 | 171M | } |
470 | 171M | } |
471 | 98.9k | return prev_pc; |
472 | 98.9k | } |
473 | | |
474 | | #define pc_addr(s) &((s)->iseq[(s)->pc]) |
475 | 159k | #define addr_pc(s, addr) (uint32_t)((addr) - s->iseq) |
476 | 115k | #define rewind_pc(s) s->pc = s->lastpc |
477 | | |
478 | | static struct mrb_insn_data |
479 | | mrb_last_insn(codegen_scope *s) |
480 | 295k | { |
481 | 295k | if (s->pc == 0) { |
482 | 0 | struct mrb_insn_data data = { OP_NOP, 0 }; |
483 | 0 | return data; |
484 | 0 | } |
485 | 295k | return mrb_decode_insn(&s->iseq[s->lastpc]); |
486 | 295k | } |
487 | | |
488 | | static mrb_bool |
489 | | no_peephole(codegen_scope *s) |
490 | 317k | { |
491 | 317k | return no_optimize(s) || s->lastlabel == s->pc || s->pc == 0 || s->pc == s->lastpc; |
492 | 317k | } |
493 | | |
494 | 161k | #define JMPLINK_START UINT32_MAX |
495 | | |
496 | | static void |
497 | | gen_jmpdst(codegen_scope *s, uint32_t pc) |
498 | 50.5k | { |
499 | | |
500 | 50.5k | if (pc == JMPLINK_START) { |
501 | 50.5k | pc = 0; |
502 | 50.5k | } |
503 | 50.5k | uint32_t pos2 = s->pc+2; |
504 | 50.5k | int32_t off = pc - pos2; |
505 | | |
506 | 50.5k | if (off > INT16_MAX || INT16_MIN > off) { |
507 | 9 | codegen_error(s, "too big jump offset"); |
508 | 9 | } |
509 | 50.5k | gen_S(s, (uint16_t)off); |
510 | 50.5k | } |
511 | | |
512 | | static uint32_t |
513 | | genjmp(codegen_scope *s, mrb_code i, uint32_t pc) |
514 | 14.9k | { |
515 | 14.9k | uint32_t pos; |
516 | | |
517 | 14.9k | genop_0(s, i); |
518 | 14.9k | pos = s->pc; |
519 | 14.9k | gen_jmpdst(s, pc); |
520 | 14.9k | return pos; |
521 | 14.9k | } |
522 | | |
523 | 14.3k | #define genjmp_0(s,i) genjmp(s,i,JMPLINK_START) |
524 | | |
525 | | static uint32_t |
526 | | genjmp2(codegen_scope *s, mrb_code i, uint16_t a, uint32_t pc, int val) |
527 | 39.4k | { |
528 | 39.4k | uint32_t pos; |
529 | | |
530 | 39.4k | if (!no_peephole(s) && !val) { |
531 | 24.7k | struct mrb_insn_data data = mrb_last_insn(s); |
532 | | |
533 | 24.7k | switch (data.insn) { |
534 | 1.59k | case OP_MOVE: |
535 | 1.59k | if (data.a == a && data.a > s->nlocals) { |
536 | 0 | rewind_pc(s); |
537 | 0 | a = data.b; |
538 | 0 | } |
539 | 1.59k | break; |
540 | 0 | case OP_LOADNIL: |
541 | 0 | case OP_LOADF: |
542 | 0 | if (data.a == a || data.a > s->nlocals) { |
543 | 0 | s->pc = addr_pc(s, data.addr); |
544 | 0 | if (i == OP_JMPNOT || (i == OP_JMPNIL && data.insn == OP_LOADNIL)) { |
545 | 0 | return genjmp(s, OP_JMP, pc); |
546 | 0 | } |
547 | 0 | else { /* OP_JMPIF */ |
548 | 0 | return JMPLINK_START; |
549 | 0 | } |
550 | 0 | } |
551 | 0 | break; |
552 | 857 | case OP_LOADT: case OP_LOADI: case OP_LOADINEG: case OP_LOADI__1: |
553 | 2.66k | case OP_LOADI_0: case OP_LOADI_1: case OP_LOADI_2: case OP_LOADI_3: |
554 | 3.87k | case OP_LOADI_4: case OP_LOADI_5: case OP_LOADI_6: case OP_LOADI_7: |
555 | 3.87k | if (data.a == a || data.a > s->nlocals) { |
556 | 3.87k | s->pc = addr_pc(s, data.addr); |
557 | 3.87k | if (i == OP_JMPIF) { |
558 | 605 | return genjmp(s, OP_JMP, pc); |
559 | 605 | } |
560 | 3.27k | else { /* OP_JMPNOT and OP_JMPNIL */ |
561 | 3.27k | return JMPLINK_START; |
562 | 3.27k | } |
563 | 3.87k | } |
564 | 0 | break; |
565 | 24.7k | } |
566 | 24.7k | } |
567 | | |
568 | 35.5k | if (a > 0xff) { |
569 | 2.88k | check_no_ext_ops(s, a, 0); |
570 | 2.88k | gen_B(s, OP_EXT1); |
571 | 2.88k | genop_0(s, i); |
572 | 2.88k | gen_S(s, a); |
573 | 2.88k | } |
574 | 32.7k | else { |
575 | 32.7k | genop_0(s, i); |
576 | 32.7k | gen_B(s, (uint8_t)a); |
577 | 32.7k | } |
578 | 35.5k | pos = s->pc; |
579 | 35.5k | gen_jmpdst(s, pc); |
580 | 35.5k | return pos; |
581 | 39.4k | } |
582 | | |
583 | 40.2k | #define genjmp2_0(s,i,a,val) genjmp2(s,i,a,JMPLINK_START,val) |
584 | | |
585 | | static mrb_bool get_int_operand(codegen_scope *s, struct mrb_insn_data *data, mrb_int *ns); |
586 | | static void gen_int(codegen_scope *s, uint16_t dst, mrb_int i); |
587 | | |
588 | | static void |
589 | | gen_move(codegen_scope *s, uint16_t dst, uint16_t src, int nopeep) |
590 | 180k | { |
591 | 180k | if (nopeep || no_peephole(s)) goto normal; |
592 | 119k | else if (dst == src) return; |
593 | 119k | else { |
594 | 119k | struct mrb_insn_data data = mrb_last_insn(s); |
595 | | |
596 | 119k | switch (data.insn) { |
597 | 4.97k | case OP_MOVE: |
598 | 4.97k | if (dst == src) return; /* remove useless MOVE */ |
599 | 4.97k | if (data.a == src) { |
600 | 4.50k | if (data.b == dst) /* skip swapping MOVE */ |
601 | 0 | return; |
602 | 4.50k | if (data.a < s->nlocals) goto normal; |
603 | 4.49k | rewind_pc(s); |
604 | 4.49k | s->lastpc = addr_pc(s, mrb_prev_pc(s, data.addr)); |
605 | 4.49k | gen_move(s, dst, data.b, FALSE); |
606 | 4.49k | return; |
607 | 4.50k | } |
608 | 470 | if (dst == data.a) { /* skip overwritten move */ |
609 | 0 | rewind_pc(s); |
610 | 0 | s->lastpc = addr_pc(s, mrb_prev_pc(s, data.addr)); |
611 | 0 | gen_move(s, dst, src, FALSE); |
612 | 0 | return; |
613 | 0 | } |
614 | 470 | goto normal; |
615 | 470 | case OP_LOADNIL: case OP_LOADSELF: case OP_LOADT: case OP_LOADF: |
616 | 110 | case OP_LOADI__1: |
617 | 105k | case OP_LOADI_0: case OP_LOADI_1: case OP_LOADI_2: case OP_LOADI_3: |
618 | 106k | case OP_LOADI_4: case OP_LOADI_5: case OP_LOADI_6: case OP_LOADI_7: |
619 | 106k | if (data.a != src || data.a < s->nlocals) goto normal; |
620 | 104k | rewind_pc(s); |
621 | 104k | genop_1(s, data.insn, dst); |
622 | 104k | return; |
623 | 0 | case OP_HASH: |
624 | 0 | if (data.b != 0) goto normal; |
625 | | /* fall through */ |
626 | 919 | case OP_LOADI: case OP_LOADINEG: |
627 | 1.07k | case OP_LOADL: case OP_LOADSYM: |
628 | 1.07k | case OP_GETGV: case OP_GETSV: case OP_GETIV: case OP_GETCV: |
629 | 1.07k | case OP_GETCONST: case OP_STRING: |
630 | 1.07k | case OP_LAMBDA: case OP_BLOCK: case OP_METHOD: case OP_BLKPUSH: |
631 | 1.07k | if (data.a != src || data.a < s->nlocals) goto normal; |
632 | 1.04k | rewind_pc(s); |
633 | 1.04k | genop_2(s, data.insn, dst, data.b); |
634 | 1.04k | return; |
635 | 260 | case OP_LOADI16: |
636 | 260 | if (data.a != src || data.a < s->nlocals) goto normal; |
637 | 176 | rewind_pc(s); |
638 | 176 | genop_2S(s, data.insn, dst, data.b); |
639 | 176 | return; |
640 | 274 | case OP_LOADI32: |
641 | 274 | if (data.a != src || data.a < s->nlocals) goto normal; |
642 | 196 | else { |
643 | 196 | uint32_t i = (uint32_t)data.b<<16|data.c; |
644 | 196 | rewind_pc(s); |
645 | 196 | genop_2SS(s, data.insn, dst, i); |
646 | 196 | } |
647 | 196 | return; |
648 | 196 | case OP_ARRAY: |
649 | 0 | if (data.a != src || data.a < s->nlocals || data.a < dst) goto normal; |
650 | 0 | rewind_pc(s); |
651 | 0 | if (data.b == 0 || dst == data.a) |
652 | 0 | genop_2(s, OP_ARRAY, dst, 0); |
653 | 0 | else |
654 | 0 | genop_3(s, OP_ARRAY2, dst, data.a, data.b); |
655 | 0 | return; |
656 | 0 | case OP_ARRAY2: |
657 | 0 | if (data.a != src || data.a < s->nlocals || data.a < dst) goto normal; |
658 | 0 | rewind_pc(s); |
659 | 0 | genop_3(s, OP_ARRAY2, dst, data.b, data.c); |
660 | 0 | return; |
661 | 0 | case OP_AREF: |
662 | 0 | case OP_GETUPVAR: |
663 | 0 | if (data.a != src || data.a < s->nlocals) goto normal; |
664 | 0 | rewind_pc(s); |
665 | 0 | genop_3(s, data.insn, dst, data.b, data.c); |
666 | 0 | return; |
667 | 865 | case OP_ADDI: case OP_SUBI: |
668 | 865 | if (addr_pc(s, data.addr) == s->lastlabel || data.a != src || data.a < s->nlocals) goto normal; |
669 | 849 | else { |
670 | 849 | struct mrb_insn_data data0 = mrb_decode_insn(mrb_prev_pc(s, data.addr)); |
671 | 849 | if (data0.insn != OP_MOVE || data0.a != data.a || data0.b != dst) goto normal; |
672 | 0 | s->pc = addr_pc(s, data0.addr); |
673 | 0 | if (addr_pc(s, data0.addr) != s->lastlabel) { |
674 | | /* constant folding */ |
675 | 0 | data0 = mrb_decode_insn(mrb_prev_pc(s, data0.addr)); |
676 | 0 | mrb_int n; |
677 | 0 | if (data0.a == dst && get_int_operand(s, &data0, &n)) { |
678 | 0 | if ((data.insn == OP_ADDI && !mrb_int_add_overflow(n, data.b, &n)) || |
679 | 0 | (data.insn == OP_SUBI && !mrb_int_sub_overflow(n, data.b, &n))) { |
680 | 0 | s->pc = addr_pc(s, data0.addr); |
681 | 0 | gen_int(s, dst, n); |
682 | 0 | return; |
683 | 0 | } |
684 | 0 | } |
685 | 0 | } |
686 | 0 | } |
687 | 0 | genop_2(s, data.insn, dst, data.b); |
688 | 0 | return; |
689 | 5.36k | default: |
690 | 5.36k | break; |
691 | 119k | } |
692 | 119k | } |
693 | 69.9k | normal: |
694 | 69.9k | genop_2(s, OP_MOVE, dst, src); |
695 | 69.9k | return; |
696 | 180k | } |
697 | | |
698 | | static int search_upvar(codegen_scope *s, mrb_sym id, int *idx); |
699 | | |
700 | | static void |
701 | | gen_getupvar(codegen_scope *s, uint16_t dst, mrb_sym id) |
702 | 0 | { |
703 | 0 | int idx; |
704 | 0 | int lv = search_upvar(s, id, &idx); |
705 | |
|
706 | 0 | if (!no_peephole(s)) { |
707 | 0 | struct mrb_insn_data data = mrb_last_insn(s); |
708 | 0 | if (data.insn == OP_SETUPVAR && data.a == dst && data.b == idx && data.c == lv) { |
709 | | /* skip GETUPVAR right after SETUPVAR */ |
710 | 0 | return; |
711 | 0 | } |
712 | 0 | } |
713 | 0 | genop_3(s, OP_GETUPVAR, dst, idx, lv); |
714 | 0 | } |
715 | | |
716 | | static void |
717 | | gen_setupvar(codegen_scope *s, uint16_t dst, mrb_sym id) |
718 | 0 | { |
719 | 0 | int idx; |
720 | 0 | int lv = search_upvar(s, id, &idx); |
721 | |
|
722 | 0 | if (!no_peephole(s)) { |
723 | 0 | struct mrb_insn_data data = mrb_last_insn(s); |
724 | 0 | if (data.insn == OP_MOVE && data.a == dst) { |
725 | 0 | dst = data.b; |
726 | 0 | rewind_pc(s); |
727 | 0 | } |
728 | 0 | } |
729 | 0 | genop_3(s, OP_SETUPVAR, dst, idx, lv); |
730 | 0 | } |
731 | | |
732 | | static void |
733 | | gen_return(codegen_scope *s, uint8_t op, uint16_t src) |
734 | 845 | { |
735 | 845 | if (no_peephole(s)) { |
736 | 451 | genop_1(s, op, src); |
737 | 451 | } |
738 | 394 | else { |
739 | 394 | struct mrb_insn_data data = mrb_last_insn(s); |
740 | | |
741 | 394 | if (data.insn == OP_MOVE && src == data.a) { |
742 | 0 | rewind_pc(s); |
743 | 0 | genop_1(s, op, data.b); |
744 | 0 | } |
745 | 394 | else if (data.insn != OP_RETURN) { |
746 | 394 | genop_1(s, op, src); |
747 | 394 | } |
748 | 394 | } |
749 | 845 | } |
750 | | |
751 | | static mrb_bool |
752 | | get_int_operand(codegen_scope *s, struct mrb_insn_data *data, mrb_int *n) |
753 | 233k | { |
754 | 233k | switch (data->insn) { |
755 | 1.52k | case OP_LOADI__1: |
756 | 1.52k | *n = -1; |
757 | 1.52k | return TRUE; |
758 | | |
759 | 5.57k | case OP_LOADINEG: |
760 | 5.57k | *n = -data->b; |
761 | 5.57k | return TRUE; |
762 | | |
763 | 94.3k | case OP_LOADI_0: case OP_LOADI_1: case OP_LOADI_2: case OP_LOADI_3: |
764 | 101k | case OP_LOADI_4: case OP_LOADI_5: case OP_LOADI_6: case OP_LOADI_7: |
765 | 101k | *n = data->insn - OP_LOADI_0; |
766 | 101k | return TRUE; |
767 | | |
768 | 10.3k | case OP_LOADI: |
769 | 11.1k | case OP_LOADI16: |
770 | 11.1k | *n = (int16_t)data->b; |
771 | 11.1k | return TRUE; |
772 | | |
773 | 699 | case OP_LOADI32: |
774 | 699 | *n = (int32_t)((uint32_t)data->b<<16)+data->c; |
775 | 699 | return TRUE; |
776 | | |
777 | 1.59k | case OP_LOADL: |
778 | 1.59k | { |
779 | 1.59k | mrb_pool_value *pv = &s->pool[data->b]; |
780 | | |
781 | 1.59k | if (pv->tt == IREP_TT_INT32) { |
782 | 0 | *n = (mrb_int)pv->u.i32; |
783 | 0 | } |
784 | 1.59k | #ifdef MRB_INT64 |
785 | 1.59k | else if (pv->tt == IREP_TT_INT64) { |
786 | 1.59k | *n = (mrb_int)pv->u.i64; |
787 | 1.59k | } |
788 | 0 | #endif |
789 | 0 | else { |
790 | 0 | return FALSE; |
791 | 0 | } |
792 | 1.59k | } |
793 | 1.59k | return TRUE; |
794 | | |
795 | 110k | default: |
796 | 110k | return FALSE; |
797 | 233k | } |
798 | 233k | } |
799 | | |
800 | | static void |
801 | | gen_addsub(codegen_scope *s, uint8_t op, uint16_t dst) |
802 | 32.8k | { |
803 | 32.8k | if (no_peephole(s)) { |
804 | 14.0k | normal: |
805 | 14.0k | genop_1(s, op, dst); |
806 | 14.0k | return; |
807 | 193 | } |
808 | 32.6k | else { |
809 | 32.6k | struct mrb_insn_data data = mrb_last_insn(s); |
810 | 32.6k | mrb_int n; |
811 | | |
812 | 32.6k | if (!get_int_operand(s, &data, &n)) { |
813 | | /* not integer immediate */ |
814 | 13.4k | goto normal; |
815 | 13.4k | } |
816 | 19.1k | struct mrb_insn_data data0 = mrb_decode_insn(mrb_prev_pc(s, data.addr)); |
817 | 19.1k | mrb_int n0; |
818 | 19.1k | if (addr_pc(s, data.addr) == s->lastlabel || !get_int_operand(s, &data0, &n0)) { |
819 | | /* OP_ADDI/OP_SUBI takes upto 8bits */ |
820 | 5.08k | if (n > INT8_MAX || n < INT8_MIN) goto normal; |
821 | 4.67k | rewind_pc(s); |
822 | 4.67k | if (n == 0) return; |
823 | 4.33k | if (n > 0) { |
824 | 4.15k | if (op == OP_ADD) genop_2(s, OP_ADDI, dst, (uint16_t)n); |
825 | 2.31k | else genop_2(s, OP_SUBI, dst, (uint16_t)n); |
826 | 4.15k | } |
827 | 174 | else { /* n < 0 */ |
828 | 174 | n = -n; |
829 | 174 | if (op == OP_ADD) genop_2(s, OP_SUBI, dst, (uint16_t)n); |
830 | 28 | else genop_2(s, OP_ADDI, dst, (uint16_t)n); |
831 | 174 | } |
832 | 4.33k | return; |
833 | 4.67k | } |
834 | 14.1k | if (op == OP_ADD) { |
835 | 4.31k | if (mrb_int_add_overflow(n0, n, &n)) goto normal; |
836 | 4.31k | } |
837 | 9.79k | else { /* OP_SUB */ |
838 | 9.79k | if (mrb_int_sub_overflow(n0, n, &n)) goto normal; |
839 | 9.79k | } |
840 | 14.0k | s->pc = addr_pc(s, data0.addr); |
841 | 14.0k | gen_int(s, dst, n); |
842 | 14.0k | } |
843 | 32.8k | } |
844 | | |
845 | | static void |
846 | | gen_muldiv(codegen_scope *s, uint8_t op, uint16_t dst) |
847 | 20.6k | { |
848 | 20.6k | if (no_peephole(s)) { |
849 | 14.8k | normal: |
850 | 14.8k | genop_1(s, op, dst); |
851 | 14.8k | return; |
852 | 972 | } |
853 | 19.6k | else { |
854 | 19.6k | struct mrb_insn_data data = mrb_last_insn(s); |
855 | 19.6k | mrb_int n, n0; |
856 | 19.6k | if (addr_pc(s, data.addr) == s->lastlabel || !get_int_operand(s, &data, &n)) { |
857 | | /* not integer immediate */ |
858 | 11.5k | goto normal; |
859 | 11.5k | } |
860 | 8.10k | struct mrb_insn_data data0 = mrb_decode_insn(mrb_prev_pc(s, data.addr)); |
861 | 8.10k | if (!get_int_operand(s, &data0, &n0)) { |
862 | 2.13k | goto normal; |
863 | 2.13k | } |
864 | 5.97k | if (op == OP_MUL) { |
865 | 3.15k | if (mrb_int_mul_overflow(n0, n, &n)) goto normal; |
866 | 3.15k | } |
867 | 2.82k | else { /* OP_DIV */ |
868 | 2.82k | if (n == 0) goto normal; |
869 | 2.65k | if (n0 == MRB_INT_MIN && n == -1) goto normal; |
870 | 2.60k | n = mrb_div_int(n0, n); |
871 | 2.60k | } |
872 | 5.75k | s->pc = addr_pc(s, data0.addr); |
873 | 5.75k | gen_int(s, dst, n); |
874 | 5.75k | } |
875 | 20.6k | } |
876 | | |
877 | | mrb_bool mrb_num_shift(mrb_state *mrb, mrb_int val, mrb_int width, mrb_int *num); |
878 | | |
879 | | static mrb_bool |
880 | | gen_binop(codegen_scope *s, mrb_sym op, uint16_t dst) |
881 | 84.1k | { |
882 | 84.1k | if (no_peephole(s)) return FALSE; |
883 | 84.0k | else if (op == MRB_OPSYM_2(s->mrb, aref)) { |
884 | 0 | genop_1(s, OP_GETIDX, dst); |
885 | 0 | return TRUE; |
886 | 0 | } |
887 | 84.0k | else { |
888 | 84.0k | struct mrb_insn_data data = mrb_last_insn(s); |
889 | 84.0k | mrb_int n, n0; |
890 | 84.0k | if (addr_pc(s, data.addr) == s->lastlabel || !get_int_operand(s, &data, &n)) { |
891 | | /* not integer immediate */ |
892 | 17.7k | return FALSE; |
893 | 17.7k | } |
894 | 66.3k | struct mrb_insn_data data0 = mrb_decode_insn(mrb_prev_pc(s, data.addr)); |
895 | 66.3k | if (!get_int_operand(s, &data0, &n0)) { |
896 | 57.6k | return FALSE; |
897 | 57.6k | } |
898 | 8.65k | if (op == MRB_OPSYM_2(s->mrb, lshift)) { |
899 | 0 | if (!mrb_num_shift(s->mrb, n0, n, &n)) return FALSE; |
900 | 0 | } |
901 | 8.65k | else if (op == MRB_OPSYM_2(s->mrb, rshift)) { |
902 | 6.23k | if (n == MRB_INT_MIN) return FALSE; |
903 | 5.94k | if (!mrb_num_shift(s->mrb, n0, -n, &n)) return FALSE; |
904 | 5.94k | } |
905 | 2.41k | else if (op == MRB_OPSYM_2(s->mrb, mod) && n != 0) { |
906 | 687 | if (n0 == MRB_INT_MIN && n == -1) { |
907 | 1 | n = 0; |
908 | 1 | } |
909 | 686 | else { |
910 | 686 | mrb_int n1 = n0 % n; |
911 | 686 | if ((n0 < 0) != (n < 0) && n1 != 0) { |
912 | 310 | n1 += n; |
913 | 310 | } |
914 | 686 | n = n1; |
915 | 686 | } |
916 | 687 | } |
917 | 1.73k | else if (op == MRB_OPSYM_2(s->mrb, and)) { |
918 | 0 | n = n0 & n; |
919 | 0 | } |
920 | 1.73k | else if (op == MRB_OPSYM_2(s->mrb, or)) { |
921 | 0 | n = n0 | n; |
922 | 0 | } |
923 | 1.73k | else if (op == MRB_OPSYM_2(s->mrb, xor)) { |
924 | 1.21k | n = n0 ^ n; |
925 | 1.21k | } |
926 | 514 | else { |
927 | 514 | return FALSE; |
928 | 514 | } |
929 | 7.47k | s->pc = addr_pc(s, data0.addr); |
930 | 7.47k | gen_int(s, dst, n); |
931 | 7.47k | return TRUE; |
932 | 8.65k | } |
933 | 84.1k | } |
934 | | |
935 | | static uint32_t |
936 | | dispatch(codegen_scope *s, uint32_t pos0) |
937 | 53.7k | { |
938 | 53.7k | int32_t pos1; |
939 | 53.7k | int32_t offset; |
940 | 53.7k | int16_t newpos; |
941 | | |
942 | 53.7k | if (pos0 == JMPLINK_START) return 0; |
943 | | |
944 | 50.5k | pos1 = pos0 + 2; |
945 | 50.5k | offset = s->pc - pos1; |
946 | 50.5k | if (offset > INT16_MAX) { |
947 | 6 | codegen_error(s, "too big jmp offset"); |
948 | 6 | } |
949 | 50.5k | s->lastlabel = s->pc; |
950 | 50.5k | newpos = (int16_t)PEEK_S(s->iseq+pos0); |
951 | 50.5k | emit_S(s, pos0, (uint16_t)offset); |
952 | 50.5k | if (newpos == 0) return 0; |
953 | 50.5k | return pos1+newpos; |
954 | 50.5k | } |
955 | | |
956 | | static void |
957 | | dispatch_linked(codegen_scope *s, uint32_t pos) |
958 | 0 | { |
959 | 0 | if (pos==JMPLINK_START) return; |
960 | 0 | for (;;) { |
961 | 0 | pos = dispatch(s, pos); |
962 | 0 | if (pos==0) break; |
963 | 0 | } |
964 | 0 | } |
965 | | |
966 | 1.44M | #define nregs_update do {if (s->sp > s->nregs) s->nregs = s->sp;} while (0) |
967 | | static void |
968 | | push_n_(codegen_scope *s, int n) |
969 | 1.44M | { |
970 | 1.44M | if (s->sp+n >= 0xffff) { |
971 | 0 | codegen_error(s, "too complex expression"); |
972 | 0 | } |
973 | 1.44M | s->sp+=n; |
974 | 1.44M | nregs_update; |
975 | 1.44M | } |
976 | | |
977 | | static void |
978 | | pop_n_(codegen_scope *s, int n) |
979 | 645k | { |
980 | 645k | if ((int)s->sp-n < 0) { |
981 | 0 | codegen_error(s, "stack pointer underflow"); |
982 | 0 | } |
983 | 645k | s->sp-=n; |
984 | 645k | } |
985 | | |
986 | 1.44M | #define push() push_n_(s,1) |
987 | 0 | #define push_n(n) push_n_(s,n) |
988 | 468k | #define pop() pop_n_(s,1) |
989 | 177k | #define pop_n(n) pop_n_(s,n) |
990 | 2.57M | #define cursp() (s->sp) |
991 | | |
992 | | static mrb_pool_value* |
993 | | lit_pool_extend(codegen_scope *s) |
994 | 3.46k | { |
995 | 3.46k | if (s->irep->plen == s->pcapa) { |
996 | 47 | s->pcapa *= 2; |
997 | 47 | s->pool = (mrb_pool_value*)codegen_realloc(s, s->pool, sizeof(mrb_pool_value)*s->pcapa); |
998 | 47 | } |
999 | | |
1000 | 3.46k | return &s->pool[s->irep->plen++]; |
1001 | 3.46k | } |
1002 | | |
1003 | | static int |
1004 | | new_litbint(codegen_scope *s, const char *p, int base, mrb_bool neg) |
1005 | 0 | { |
1006 | 0 | int i; |
1007 | 0 | size_t plen; |
1008 | 0 | mrb_pool_value *pv; |
1009 | |
|
1010 | 0 | plen = strlen(p); |
1011 | 0 | if (plen > 255) { |
1012 | 0 | codegen_error(s, "integer too big"); |
1013 | 0 | } |
1014 | 0 | for (i=0; i<s->irep->plen; i++) { |
1015 | 0 | size_t len; |
1016 | 0 | pv = &s->pool[i]; |
1017 | 0 | if (pv->tt != IREP_TT_BIGINT) continue; |
1018 | 0 | len = pv->u.str[0]; |
1019 | 0 | if (len == plen && pv->u.str[1] == base && memcmp(pv->u.str+2, p, len) == 0) |
1020 | 0 | return i; |
1021 | 0 | } |
1022 | | |
1023 | 0 | pv = lit_pool_extend(s); |
1024 | |
|
1025 | 0 | char *buf; |
1026 | 0 | pv->tt = IREP_TT_BIGINT; |
1027 | 0 | buf = (char*)codegen_realloc(s, NULL, plen+3); |
1028 | 0 | buf[0] = (char)plen; |
1029 | 0 | if (neg) buf[1] = -base; |
1030 | 0 | else buf[1] = base; |
1031 | 0 | memcpy(buf+2, p, plen); |
1032 | 0 | buf[plen+2] = '\0'; |
1033 | 0 | pv->u.str = buf; |
1034 | |
|
1035 | 0 | return i; |
1036 | 0 | } |
1037 | | |
1038 | | static int |
1039 | | new_lit_str(codegen_scope *s, const char *str, mrb_int len) |
1040 | 327k | { |
1041 | 327k | int i; |
1042 | 327k | mrb_pool_value *pv; |
1043 | | |
1044 | 681k | for (i=0; i<s->irep->plen; i++) { |
1045 | 678k | pv = &s->pool[i]; |
1046 | 678k | if (pv->tt & IREP_TT_NFLAG) continue; |
1047 | 670k | mrb_int plen = pv->tt>>2; |
1048 | 670k | if (len != plen) continue; |
1049 | 351k | if (memcmp(pv->u.str, str, plen) == 0) |
1050 | 324k | return i; |
1051 | 351k | } |
1052 | | |
1053 | 3.20k | pv = lit_pool_extend(s); |
1054 | | |
1055 | 3.20k | if (mrb_ro_data_p(str)) { |
1056 | 0 | pv->tt = (uint32_t)(len<<2) | IREP_TT_SSTR; |
1057 | 0 | pv->u.str = str; |
1058 | 0 | } |
1059 | 3.20k | else { |
1060 | 3.20k | char *p; |
1061 | 3.20k | pv->tt = (uint32_t)(len<<2) | IREP_TT_STR; |
1062 | 3.20k | p = (char*)codegen_realloc(s, NULL, len+1); |
1063 | 3.20k | memcpy(p, str, len); |
1064 | 3.20k | p[len] = '\0'; |
1065 | 3.20k | pv->u.str = p; |
1066 | 3.20k | } |
1067 | | |
1068 | 3.20k | return i; |
1069 | 327k | } |
1070 | | |
1071 | | static int |
1072 | | new_lit_cstr(codegen_scope *s, const char *str) |
1073 | 0 | { |
1074 | 0 | return new_lit_str(s, str, (mrb_int)strlen(str)); |
1075 | 0 | } |
1076 | | |
1077 | | static int |
1078 | | new_lit_int(codegen_scope *s, mrb_int num) |
1079 | 1.84k | { |
1080 | 1.84k | int i; |
1081 | 1.84k | mrb_pool_value *pv; |
1082 | | |
1083 | 87.6k | for (i=0; i<s->irep->plen; i++) { |
1084 | 87.4k | pv = &s->pool[i]; |
1085 | 87.4k | if (pv->tt == IREP_TT_INT32) { |
1086 | 0 | if (num == pv->u.i32) return i; |
1087 | 0 | } |
1088 | 87.4k | #ifdef MRB_64BIT |
1089 | 87.4k | else if (pv->tt == IREP_TT_INT64) { |
1090 | 10.9k | if (num == pv->u.i64) return i; |
1091 | 10.9k | } |
1092 | 85.8k | continue; |
1093 | 87.4k | #endif |
1094 | 87.4k | } |
1095 | | |
1096 | 262 | pv = lit_pool_extend(s); |
1097 | | |
1098 | 262 | #ifdef MRB_INT64 |
1099 | 262 | pv->tt = IREP_TT_INT64; |
1100 | 262 | pv->u.i64 = num; |
1101 | | #else |
1102 | | pv->tt = IREP_TT_INT32; |
1103 | | pv->u.i32 = num; |
1104 | | #endif |
1105 | | |
1106 | 262 | return i; |
1107 | 1.84k | } |
1108 | | |
1109 | | #ifndef MRB_NO_FLOAT |
1110 | | static int |
1111 | | new_lit_float(codegen_scope *s, mrb_float num) |
1112 | 0 | { |
1113 | 0 | int i; |
1114 | 0 | mrb_pool_value *pv; |
1115 | |
|
1116 | 0 | for (i=0; i<s->irep->plen; i++) { |
1117 | 0 | mrb_float f; |
1118 | 0 | pv = &s->pool[i]; |
1119 | 0 | if (pv->tt != IREP_TT_FLOAT) continue; |
1120 | 0 | f = pv->u.f; |
1121 | 0 | if (f == num && !signbit(f) == !signbit(num)) return i; |
1122 | 0 | } |
1123 | | |
1124 | 0 | pv = lit_pool_extend(s); |
1125 | |
|
1126 | 0 | pv->tt = IREP_TT_FLOAT; |
1127 | 0 | pv->u.f = num; |
1128 | |
|
1129 | 0 | return i; |
1130 | 0 | } |
1131 | | #endif |
1132 | | |
1133 | | static int |
1134 | | new_sym(codegen_scope *s, mrb_sym sym) |
1135 | 144k | { |
1136 | 144k | int i, len; |
1137 | | |
1138 | 144k | mrb_assert(s->irep); |
1139 | | |
1140 | 144k | len = s->irep->slen; |
1141 | 531k | for (i=0; i<len; i++) { |
1142 | 525k | if (s->syms[i] == sym) return i; |
1143 | 525k | } |
1144 | 5.31k | if (s->irep->slen >= s->scapa) { |
1145 | 0 | s->scapa *= 2; |
1146 | 0 | if (s->scapa > 0xffff) { |
1147 | 0 | codegen_error(s, "too many symbols"); |
1148 | 0 | } |
1149 | 0 | s->syms = (mrb_sym*)codegen_realloc(s, s->syms, sizeof(mrb_sym)*s->scapa); |
1150 | 0 | } |
1151 | 5.31k | s->syms[s->irep->slen] = sym; |
1152 | 5.31k | return s->irep->slen++; |
1153 | 144k | } |
1154 | | |
1155 | | static void |
1156 | | gen_setxv(codegen_scope *s, uint8_t op, uint16_t dst, mrb_sym sym, int val) |
1157 | 20.1k | { |
1158 | 20.1k | int idx = new_sym(s, sym); |
1159 | 20.1k | if (!val && !no_peephole(s)) { |
1160 | 8.61k | struct mrb_insn_data data = mrb_last_insn(s); |
1161 | 8.61k | if (data.insn == OP_MOVE && data.a == dst) { |
1162 | 186 | dst = data.b; |
1163 | 186 | rewind_pc(s); |
1164 | 186 | } |
1165 | 8.61k | } |
1166 | 20.1k | genop_2(s, op, dst, idx); |
1167 | 20.1k | } |
1168 | | |
1169 | | static void |
1170 | | gen_int(codegen_scope *s, uint16_t dst, mrb_int i) |
1171 | 602k | { |
1172 | 602k | if (i < 0) { |
1173 | 10.0k | if (i == -1) genop_1(s, OP_LOADI__1, dst); |
1174 | 8.21k | else if (i >= -0xff) genop_2(s, OP_LOADINEG, dst, (uint16_t)-i); |
1175 | 1.92k | else if (i >= INT16_MIN) genop_2S(s, OP_LOADI16, dst, (uint16_t)i); |
1176 | 1.48k | else if (i >= INT32_MIN) genop_2SS(s, OP_LOADI32, dst, (uint32_t)i); |
1177 | 1.01k | else goto int_lit; |
1178 | 10.0k | } |
1179 | 592k | else if (i < 8) genop_1(s, OP_LOADI_0 + (uint8_t)i, dst); |
1180 | 15.9k | else if (i <= 0xff) genop_2(s, OP_LOADI, dst, (uint16_t)i); |
1181 | 1.97k | else if (i <= INT16_MAX) genop_2S(s, OP_LOADI16, dst, (uint16_t)i); |
1182 | 1.28k | else if (i <= INT32_MAX) genop_2SS(s, OP_LOADI32, dst, (uint32_t)i); |
1183 | 830 | else { |
1184 | 1.84k | int_lit: |
1185 | 1.84k | genop_2(s, OP_LOADL, dst, new_lit_int(s, i)); |
1186 | 1.84k | } |
1187 | 602k | } |
1188 | | |
1189 | | static mrb_bool |
1190 | | gen_uniop(codegen_scope *s, mrb_sym sym, uint16_t dst) |
1191 | 5.91k | { |
1192 | 5.91k | if (no_peephole(s)) return FALSE; |
1193 | 5.91k | struct mrb_insn_data data = mrb_last_insn(s); |
1194 | 5.91k | mrb_int n; |
1195 | | |
1196 | 5.91k | if (!get_int_operand(s, &data, &n)) return FALSE; |
1197 | 0 | if (sym == MRB_OPSYM_2(s->mrb, plus)) { |
1198 | | /* unary plus does nothing */ |
1199 | 0 | } |
1200 | 0 | else if (sym == MRB_OPSYM_2(s->mrb, minus)) { |
1201 | 0 | if (n == MRB_INT_MIN) return FALSE; |
1202 | 0 | n = -n; |
1203 | 0 | } |
1204 | 0 | else if (sym == MRB_OPSYM_2(s->mrb, neg)) { |
1205 | 0 | n = ~n; |
1206 | 0 | } |
1207 | 0 | else { |
1208 | 0 | return FALSE; |
1209 | 0 | } |
1210 | 0 | s->pc = addr_pc(s, data.addr); |
1211 | 0 | gen_int(s, dst, n); |
1212 | 0 | return TRUE; |
1213 | 0 | } |
1214 | | |
1215 | | static int |
1216 | | node_len(node *tree) |
1217 | 2.33k | { |
1218 | 2.33k | int n = 0; |
1219 | | |
1220 | 71.5k | while (tree) { |
1221 | 69.2k | n++; |
1222 | 69.2k | tree = tree->cdr; |
1223 | 69.2k | } |
1224 | 2.33k | return n; |
1225 | 2.33k | } |
1226 | | |
1227 | 3.43M | #define nint(x) ((int)(intptr_t)(x)) |
1228 | 0 | #define nchar(x) ((char)(intptr_t)(x)) |
1229 | 57.3M | #define nsym(x) ((mrb_sym)(intptr_t)(x)) |
1230 | | |
1231 | 56.8M | #define lv_name(lv) nsym((lv)->car) |
1232 | | |
1233 | | static int |
1234 | | lv_idx(codegen_scope *s, mrb_sym id) |
1235 | 176k | { |
1236 | 176k | node *lv = s->lv; |
1237 | 176k | int n = 1; |
1238 | | |
1239 | 56.8M | while (lv) { |
1240 | 56.8M | if (lv_name(lv) == id) return n; |
1241 | 56.6M | n++; |
1242 | 56.6M | lv = lv->cdr; |
1243 | 56.6M | } |
1244 | 0 | return 0; |
1245 | 176k | } |
1246 | | |
1247 | | static int |
1248 | | search_upvar(codegen_scope *s, mrb_sym id, int *idx) |
1249 | 0 | { |
1250 | 0 | const struct RProc *u; |
1251 | 0 | int lv = 0; |
1252 | 0 | codegen_scope *up = s->prev; |
1253 | |
|
1254 | 0 | while (up) { |
1255 | 0 | *idx = lv_idx(up, id); |
1256 | 0 | if (*idx > 0) { |
1257 | 0 | return lv; |
1258 | 0 | } |
1259 | 0 | lv++; |
1260 | 0 | up = up->prev; |
1261 | 0 | } |
1262 | | |
1263 | 0 | if (lv < 1) lv = 1; |
1264 | 0 | u = s->parser->upper; |
1265 | 0 | while (u && !MRB_PROC_CFUNC_P(u)) { |
1266 | 0 | const struct mrb_irep *ir = u->body.irep; |
1267 | 0 | uint_fast16_t n = ir->nlocals; |
1268 | 0 | int i; |
1269 | |
|
1270 | 0 | const mrb_sym *v = ir->lv; |
1271 | 0 | if (v) { |
1272 | 0 | for (i=1; n > 1; n--, v++, i++) { |
1273 | 0 | if (*v == id) { |
1274 | 0 | *idx = i; |
1275 | 0 | return lv - 1; |
1276 | 0 | } |
1277 | 0 | } |
1278 | 0 | } |
1279 | 0 | if (MRB_PROC_SCOPE_P(u)) break; |
1280 | 0 | u = u->upper; |
1281 | 0 | lv++; |
1282 | 0 | } |
1283 | | |
1284 | 0 | if (id == MRB_OPSYM_2(s->mrb, and)) { |
1285 | 0 | codegen_error(s, "No anonymous block parameter"); |
1286 | 0 | } |
1287 | 0 | else if (id == MRB_OPSYM_2(s->mrb, mul)) { |
1288 | 0 | codegen_error(s, "No anonymous rest parameter"); |
1289 | 0 | } |
1290 | 0 | else if (id == MRB_OPSYM_2(s->mrb, pow)) { |
1291 | 0 | codegen_error(s, "No anonymous keyword rest parameter"); |
1292 | 0 | } |
1293 | 0 | else { |
1294 | 0 | codegen_error(s, "Can't find local variables"); |
1295 | 0 | } |
1296 | 0 | return -1; /* not reached */ |
1297 | 0 | } |
1298 | | |
1299 | | static void |
1300 | | for_body(codegen_scope *s, node *tree) |
1301 | 0 | { |
1302 | 0 | codegen_scope *prev = s; |
1303 | 0 | int idx; |
1304 | 0 | struct loopinfo *lp; |
1305 | 0 | node *n2; |
1306 | | |
1307 | | /* generate receiver */ |
1308 | 0 | codegen(s, tree->cdr->car, VAL); |
1309 | | /* generate loop-block */ |
1310 | 0 | s = scope_new(s->mrb, s, NULL); |
1311 | |
|
1312 | 0 | push(); /* push for a block parameter */ |
1313 | | |
1314 | | /* generate loop variable */ |
1315 | 0 | n2 = tree->car; |
1316 | 0 | genop_W(s, OP_ENTER, 0x40000); |
1317 | 0 | if (n2->car && !n2->car->cdr && !n2->cdr) { |
1318 | 0 | gen_assignment(s, n2->car->car, NULL, 1, NOVAL); |
1319 | 0 | } |
1320 | 0 | else { |
1321 | 0 | gen_massignment(s, n2, 1, VAL); |
1322 | 0 | } |
1323 | | /* construct loop */ |
1324 | 0 | lp = loop_push(s, LOOP_FOR); |
1325 | 0 | lp->pc1 = new_label(s); |
1326 | | |
1327 | | /* loop body */ |
1328 | 0 | codegen(s, tree->cdr->cdr->car, VAL); |
1329 | 0 | pop(); |
1330 | 0 | gen_return(s, OP_RETURN, cursp()); |
1331 | 0 | loop_pop(s, NOVAL); |
1332 | 0 | scope_finish(s); |
1333 | 0 | s = prev; |
1334 | 0 | genop_2(s, OP_BLOCK, cursp(), s->irep->rlen-1); |
1335 | 0 | push();pop(); /* space for a block */ |
1336 | 0 | pop(); |
1337 | 0 | idx = new_sym(s, MRB_SYM_2(s->mrb, each)); |
1338 | 0 | genop_3(s, OP_SENDB, cursp(), idx, 0); |
1339 | 0 | } |
1340 | | |
1341 | | static int |
1342 | | lambda_body(codegen_scope *s, node *tree, int blk) |
1343 | 466 | { |
1344 | 466 | codegen_scope *parent = s; |
1345 | 466 | s = scope_new(s->mrb, s, tree->car); |
1346 | | |
1347 | 466 | s->mscope = !blk; |
1348 | | |
1349 | 466 | if (blk) { |
1350 | 0 | struct loopinfo *lp = loop_push(s, LOOP_BLOCK); |
1351 | 0 | lp->pc0 = new_label(s); |
1352 | 0 | } |
1353 | 466 | tree = tree->cdr; |
1354 | 466 | if (tree->car == NULL) { |
1355 | 0 | genop_W(s, OP_ENTER, 0); |
1356 | 0 | s->ainfo = 0; |
1357 | 0 | } |
1358 | 466 | else { |
1359 | 466 | mrb_aspec a; |
1360 | 466 | int ma, oa, ra, pa, ka, kd, ba, i; |
1361 | 466 | uint32_t pos; |
1362 | 466 | node *opt; |
1363 | 466 | node *margs, *pargs; |
1364 | 466 | node *tail; |
1365 | | |
1366 | | /* mandatory arguments */ |
1367 | 466 | ma = node_len(tree->car->car); |
1368 | 466 | margs = tree->car->car; |
1369 | 466 | tail = tree->car->cdr->cdr->cdr->cdr; |
1370 | | |
1371 | | /* optional arguments */ |
1372 | 466 | oa = node_len(tree->car->cdr->car); |
1373 | | /* rest argument? */ |
1374 | 466 | ra = tree->car->cdr->cdr->car ? 1 : 0; |
1375 | | /* mandatory arguments after rest argument */ |
1376 | 466 | pa = node_len(tree->car->cdr->cdr->cdr->car); |
1377 | 466 | pargs = tree->car->cdr->cdr->cdr->car; |
1378 | | /* keyword arguments */ |
1379 | 466 | ka = tail? node_len(tail->cdr->car) : 0; |
1380 | | /* keyword dictionary? */ |
1381 | 466 | kd = tail && tail->cdr->cdr->car? 1 : 0; |
1382 | | /* block argument? */ |
1383 | 466 | ba = tail && tail->cdr->cdr->cdr->car ? 1 : 0; |
1384 | | |
1385 | 466 | if (ma > 0x1f || oa > 0x1f || pa > 0x1f || ka > 0x1f) { |
1386 | 0 | codegen_error(s, "too many formal arguments"); |
1387 | 0 | } |
1388 | | /* (23bits = 5:5:1:5:5:1:1) */ |
1389 | 466 | a = MRB_ARGS_REQ(ma) |
1390 | 466 | | MRB_ARGS_OPT(oa) |
1391 | 466 | | (ra? MRB_ARGS_REST() : 0) |
1392 | 466 | | MRB_ARGS_POST(pa) |
1393 | 466 | | MRB_ARGS_KEY(ka, kd) |
1394 | 466 | | (ba? MRB_ARGS_BLOCK() : 0); |
1395 | 466 | genop_W(s, OP_ENTER, a); |
1396 | | /* (12bits = 5:1:5:1) */ |
1397 | 466 | s->ainfo = (((ma+oa) & 0x3f) << 7) |
1398 | 466 | | ((ra & 0x1) << 6) |
1399 | 466 | | ((pa & 0x1f) << 1) |
1400 | 466 | | ((ka | kd) ? 1 : 0); |
1401 | | /* generate jump table for optional arguments initializer */ |
1402 | 466 | pos = new_label(s); |
1403 | 466 | for (i=0; i<oa; i++) { |
1404 | 0 | new_label(s); |
1405 | 0 | genjmp_0(s, OP_JMP); |
1406 | 0 | } |
1407 | 466 | if (oa > 0) { |
1408 | 0 | genjmp_0(s, OP_JMP); |
1409 | 0 | } |
1410 | 466 | opt = tree->car->cdr->car; |
1411 | 466 | i = 0; |
1412 | 466 | while (opt) { |
1413 | 0 | int idx; |
1414 | 0 | mrb_sym id = nsym(opt->car->car); |
1415 | |
|
1416 | 0 | dispatch(s, pos+i*3+1); |
1417 | 0 | codegen(s, opt->car->cdr, VAL); |
1418 | 0 | pop(); |
1419 | 0 | idx = lv_idx(s, id); |
1420 | 0 | if (idx > 0) { |
1421 | 0 | gen_move(s, idx, cursp(), 0); |
1422 | 0 | } |
1423 | 0 | else { |
1424 | 0 | gen_getupvar(s, cursp(), id); |
1425 | 0 | } |
1426 | 0 | i++; |
1427 | 0 | opt = opt->cdr; |
1428 | 0 | } |
1429 | 466 | if (oa > 0) { |
1430 | 0 | dispatch(s, pos+i*3+1); |
1431 | 0 | } |
1432 | | |
1433 | | /* keyword arguments */ |
1434 | 466 | if (tail) { |
1435 | 0 | node *kwds = tail->cdr->car; |
1436 | 0 | int kwrest = 0; |
1437 | |
|
1438 | 0 | if (tail->cdr->cdr->car) { |
1439 | 0 | kwrest = 1; |
1440 | 0 | } |
1441 | 0 | mrb_assert(nint(tail->car) == NODE_ARGS_TAIL); |
1442 | 0 | mrb_assert(node_len(tail) == 4); |
1443 | |
|
1444 | 0 | while (kwds) { |
1445 | 0 | int jmpif_key_p, jmp_def_set = -1; |
1446 | 0 | node *kwd = kwds->car, *def_arg = kwd->cdr->cdr->car; |
1447 | 0 | mrb_sym kwd_sym = nsym(kwd->cdr->car); |
1448 | |
|
1449 | 0 | mrb_assert(nint(kwd->car) == NODE_KW_ARG); |
1450 | |
|
1451 | 0 | if (def_arg) { |
1452 | 0 | int idx; |
1453 | 0 | genop_2(s, OP_KEY_P, lv_idx(s, kwd_sym), new_sym(s, kwd_sym)); |
1454 | 0 | jmpif_key_p = genjmp2_0(s, OP_JMPIF, lv_idx(s, kwd_sym), NOVAL); |
1455 | 0 | codegen(s, def_arg, VAL); |
1456 | 0 | pop(); |
1457 | 0 | idx = lv_idx(s, kwd_sym); |
1458 | 0 | if (idx > 0) { |
1459 | 0 | gen_move(s, idx, cursp(), 0); |
1460 | 0 | } |
1461 | 0 | else { |
1462 | 0 | gen_getupvar(s, cursp(), kwd_sym); |
1463 | 0 | } |
1464 | 0 | jmp_def_set = genjmp_0(s, OP_JMP); |
1465 | 0 | dispatch(s, jmpif_key_p); |
1466 | 0 | } |
1467 | 0 | genop_2(s, OP_KARG, lv_idx(s, kwd_sym), new_sym(s, kwd_sym)); |
1468 | 0 | if (jmp_def_set != -1) { |
1469 | 0 | dispatch(s, jmp_def_set); |
1470 | 0 | } |
1471 | 0 | i++; |
1472 | |
|
1473 | 0 | kwds = kwds->cdr; |
1474 | 0 | } |
1475 | 0 | if (tail->cdr->car && !kwrest) { |
1476 | 0 | genop_0(s, OP_KEYEND); |
1477 | 0 | } |
1478 | 0 | } |
1479 | | |
1480 | | /* argument destructuring */ |
1481 | 466 | if (margs) { |
1482 | 0 | node *n = margs; |
1483 | |
|
1484 | 0 | pos = 1; |
1485 | 0 | while (n) { |
1486 | 0 | if (nint(n->car->car) == NODE_MASGN) { |
1487 | 0 | gen_massignment(s, n->car->cdr->car, pos, NOVAL); |
1488 | 0 | } |
1489 | 0 | pos++; |
1490 | 0 | n = n->cdr; |
1491 | 0 | } |
1492 | 0 | } |
1493 | 466 | if (pargs) { |
1494 | 0 | node *n = pargs; |
1495 | |
|
1496 | 0 | pos = ma+oa+ra+1; |
1497 | 0 | while (n) { |
1498 | 0 | if (nint(n->car->car) == NODE_MASGN) { |
1499 | 0 | gen_massignment(s, n->car->cdr->car, pos, NOVAL); |
1500 | 0 | } |
1501 | 0 | pos++; |
1502 | 0 | n = n->cdr; |
1503 | 0 | } |
1504 | 0 | } |
1505 | 466 | } |
1506 | | |
1507 | 466 | codegen(s, tree->cdr->car, VAL); |
1508 | 466 | pop(); |
1509 | 466 | if (s->pc > 0) { |
1510 | 451 | gen_return(s, OP_RETURN, cursp()); |
1511 | 451 | } |
1512 | 466 | if (blk) { |
1513 | 0 | loop_pop(s, NOVAL); |
1514 | 0 | } |
1515 | 466 | scope_finish(s); |
1516 | 466 | return parent->irep->rlen - 1; |
1517 | 466 | } |
1518 | | |
1519 | | static int |
1520 | | scope_body(codegen_scope *s, node *tree, int val) |
1521 | 466 | { |
1522 | 466 | codegen_scope *scope = scope_new(s->mrb, s, tree->car); |
1523 | | |
1524 | 466 | codegen(scope, tree->cdr, VAL); |
1525 | 466 | gen_return(scope, OP_RETURN, scope->sp-1); |
1526 | 466 | if (!s->iseq) { |
1527 | 394 | genop_0(scope, OP_STOP); |
1528 | 394 | } |
1529 | 466 | scope_finish(scope); |
1530 | 466 | if (!s->irep) { |
1531 | | /* should not happen */ |
1532 | 0 | return 0; |
1533 | 0 | } |
1534 | 466 | return s->irep->rlen - 1; |
1535 | 466 | } |
1536 | | |
1537 | | static mrb_bool |
1538 | | nosplat(node *t) |
1539 | 0 | { |
1540 | 0 | while (t) { |
1541 | 0 | if (nint(t->car->car) == NODE_SPLAT) return FALSE; |
1542 | 0 | t = t->cdr; |
1543 | 0 | } |
1544 | 0 | return TRUE; |
1545 | 0 | } |
1546 | | |
1547 | | static mrb_sym |
1548 | | attrsym(codegen_scope *s, mrb_sym a) |
1549 | 0 | { |
1550 | 0 | const char *name; |
1551 | 0 | mrb_int len; |
1552 | 0 | char *name2; |
1553 | |
|
1554 | 0 | name = mrb_sym_name_len(s->mrb, a, &len); |
1555 | 0 | name2 = (char*)codegen_palloc(s, |
1556 | 0 | (size_t)len |
1557 | 0 | + 1 /* '=' */ |
1558 | 0 | + 1 /* '\0' */ |
1559 | 0 | ); |
1560 | 0 | mrb_assert_int_fit(mrb_int, len, size_t, SIZE_MAX); |
1561 | 0 | memcpy(name2, name, (size_t)len); |
1562 | 0 | name2[len] = '='; |
1563 | 0 | name2[len+1] = '\0'; |
1564 | |
|
1565 | 0 | return mrb_intern(s->mrb, name2, len+1); |
1566 | 0 | } |
1567 | | |
1568 | 0 | #define CALL_MAXARGS 15 |
1569 | 52.5k | #define GEN_LIT_ARY_MAX 64 |
1570 | 196k | #define GEN_VAL_STACK_MAX 99 |
1571 | | |
1572 | | static int |
1573 | | gen_values(codegen_scope *s, node *t, int val, int limit) |
1574 | 194k | { |
1575 | 194k | int n = 0; |
1576 | 194k | int first = 1; |
1577 | 194k | int slimit = GEN_VAL_STACK_MAX; |
1578 | | |
1579 | 194k | if (limit == 0) limit = GEN_LIT_ARY_MAX; |
1580 | 194k | if (cursp() >= slimit) slimit = INT16_MAX; |
1581 | | |
1582 | 194k | if (!val) { |
1583 | 0 | while (t) { |
1584 | 0 | codegen(s, t->car, NOVAL); |
1585 | 0 | n++; |
1586 | 0 | t = t->cdr; |
1587 | 0 | } |
1588 | 0 | return n; |
1589 | 0 | } |
1590 | | |
1591 | 688k | while (t) { |
1592 | 493k | int is_splat = nint(t->car->car) == NODE_SPLAT; |
1593 | | |
1594 | 493k | if (is_splat || cursp() >= slimit) { /* flush stack */ |
1595 | 127k | pop_n(n); |
1596 | 127k | if (first) { |
1597 | 2.05k | if (n == 0) { |
1598 | 0 | genop_1(s, OP_LOADNIL, cursp()); |
1599 | 0 | } |
1600 | 2.05k | else { |
1601 | 2.05k | genop_2(s, OP_ARRAY, cursp(), n); |
1602 | 2.05k | } |
1603 | 2.05k | push(); |
1604 | 2.05k | first = 0; |
1605 | 2.05k | limit = GEN_LIT_ARY_MAX; |
1606 | 2.05k | } |
1607 | 125k | else if (n > 0) { |
1608 | 125k | pop(); |
1609 | 125k | genop_2(s, OP_ARYPUSH, cursp(), n); |
1610 | 125k | push(); |
1611 | 125k | } |
1612 | 127k | n = 0; |
1613 | 127k | } |
1614 | 493k | codegen(s, t->car, val); |
1615 | 493k | if (is_splat) { |
1616 | 0 | pop(); pop(); |
1617 | 0 | genop_1(s, OP_ARYCAT, cursp()); |
1618 | 0 | push(); |
1619 | 0 | } |
1620 | 493k | else { |
1621 | 493k | n++; |
1622 | 493k | } |
1623 | 493k | t = t->cdr; |
1624 | 493k | } |
1625 | 194k | if (!first) { |
1626 | 2.05k | pop(); |
1627 | 2.05k | if (n > 0) { |
1628 | 2.05k | pop_n(n); |
1629 | 2.05k | genop_2(s, OP_ARYPUSH, cursp(), n); |
1630 | 2.05k | } |
1631 | 2.05k | return -1; /* variable length */ |
1632 | 2.05k | } |
1633 | 192k | else if (n > limit) { |
1634 | 96 | pop_n(n); |
1635 | 96 | genop_2(s, OP_ARRAY, cursp(), n); |
1636 | 96 | return -1; |
1637 | 96 | } |
1638 | 192k | return n; |
1639 | 194k | } |
1640 | | |
1641 | | static int |
1642 | | gen_hash(codegen_scope *s, node *tree, int val, int limit) |
1643 | 2.01k | { |
1644 | 2.01k | int slimit = GEN_VAL_STACK_MAX; |
1645 | 2.01k | if (cursp() >= GEN_LIT_ARY_MAX) slimit = INT16_MAX; |
1646 | 2.01k | int len = 0; |
1647 | 2.01k | mrb_bool update = FALSE; |
1648 | 2.01k | mrb_bool first = TRUE; |
1649 | | |
1650 | 165k | while (tree) { |
1651 | 163k | if (nint(tree->car->car->car) == NODE_KW_REST_ARGS) { |
1652 | 0 | if (val && first) { |
1653 | 0 | genop_2(s, OP_HASH, cursp(), 0); |
1654 | 0 | push(); |
1655 | 0 | update = TRUE; |
1656 | 0 | } |
1657 | 0 | else if (val && len > 0) { |
1658 | 0 | pop_n(len*2); |
1659 | 0 | if (!update) { |
1660 | 0 | genop_2(s, OP_HASH, cursp(), len); |
1661 | 0 | } |
1662 | 0 | else { |
1663 | 0 | pop(); |
1664 | 0 | genop_2(s, OP_HASHADD, cursp(), len); |
1665 | 0 | } |
1666 | 0 | push(); |
1667 | 0 | } |
1668 | 0 | codegen(s, tree->car->cdr, val); |
1669 | 0 | if (val && (len > 0 || update)) { |
1670 | 0 | pop(); pop(); |
1671 | 0 | genop_1(s, OP_HASHCAT, cursp()); |
1672 | 0 | push(); |
1673 | 0 | } |
1674 | 0 | update = TRUE; |
1675 | 0 | len = 0; |
1676 | 0 | } |
1677 | 163k | else { |
1678 | 163k | codegen(s, tree->car->car, val); |
1679 | 163k | codegen(s, tree->car->cdr, val); |
1680 | 163k | len++; |
1681 | 163k | } |
1682 | 163k | tree = tree->cdr; |
1683 | 163k | if (val && cursp() >= slimit) { |
1684 | 1.33k | pop_n(len*2); |
1685 | 1.33k | if (!update) { |
1686 | 200 | genop_2(s, OP_HASH, cursp(), len); |
1687 | 200 | } |
1688 | 1.13k | else { |
1689 | 1.13k | pop(); |
1690 | 1.13k | genop_2(s, OP_HASHADD, cursp(), len); |
1691 | 1.13k | } |
1692 | 1.33k | push(); |
1693 | 1.33k | update = TRUE; |
1694 | 1.33k | len = 0; |
1695 | 1.33k | } |
1696 | 163k | first = FALSE; |
1697 | 163k | } |
1698 | 2.01k | if (val && len > limit) { |
1699 | 333 | pop_n(len*2); |
1700 | 333 | genop_2(s, OP_HASH, cursp(), len); |
1701 | 333 | push(); |
1702 | 333 | return -1; |
1703 | 333 | } |
1704 | 1.68k | if (update) { |
1705 | 200 | if (val && len > 0) { |
1706 | 200 | pop_n(len*2+1); |
1707 | 200 | genop_2(s, OP_HASHADD, cursp(), len); |
1708 | 200 | push(); |
1709 | 200 | } |
1710 | 200 | return -1; /* variable length */ |
1711 | 200 | } |
1712 | 1.48k | return len; |
1713 | 1.68k | } |
1714 | | |
1715 | | static void |
1716 | | gen_call(codegen_scope *s, node *tree, int val, int safe) |
1717 | 154k | { |
1718 | 154k | mrb_sym sym = nsym(tree->cdr->car); |
1719 | 154k | int skip = 0, n = 0, nk = 0, noop = no_optimize(s), noself = 0, blk = 0, sp_save = cursp(); |
1720 | | |
1721 | 154k | if (!tree->car) { |
1722 | 394 | noself = noop = 1; |
1723 | 394 | push(); |
1724 | 394 | } |
1725 | 154k | else { |
1726 | 154k | codegen(s, tree->car, VAL); /* receiver */ |
1727 | 154k | } |
1728 | 154k | if (safe) { |
1729 | 0 | int recv = cursp()-1; |
1730 | 0 | gen_move(s, cursp(), recv, 1); |
1731 | 0 | skip = genjmp2_0(s, OP_JMPNIL, cursp(), val); |
1732 | 0 | } |
1733 | 154k | tree = tree->cdr->cdr->car; |
1734 | 154k | if (tree) { |
1735 | 148k | if (tree->car) { /* positional arguments */ |
1736 | 148k | n = gen_values(s, tree->car, VAL, 14); |
1737 | 148k | if (n < 0) { /* variable length */ |
1738 | 0 | noop = 1; /* not operator */ |
1739 | 0 | n = 15; |
1740 | 0 | push(); |
1741 | 0 | } |
1742 | 148k | } |
1743 | 148k | if (tree->cdr->car) { /* keyword arguments */ |
1744 | 0 | noop = 1; |
1745 | 0 | nk = gen_hash(s, tree->cdr->car->cdr, VAL, 14); |
1746 | 0 | if (nk < 0) nk = 15; |
1747 | 0 | } |
1748 | 148k | } |
1749 | 154k | if (tree && tree->cdr && tree->cdr->cdr) { |
1750 | 0 | codegen(s, tree->cdr->cdr, VAL); |
1751 | 0 | pop(); |
1752 | 0 | noop = 1; |
1753 | 0 | blk = 1; |
1754 | 0 | } |
1755 | 154k | push();pop(); |
1756 | 154k | s->sp = sp_save; |
1757 | 154k | if (!noop && sym == MRB_OPSYM_2(s->mrb, add) && n == 1) { |
1758 | 11.9k | gen_addsub(s, OP_ADD, cursp()); |
1759 | 11.9k | } |
1760 | 142k | else if (!noop && sym == MRB_OPSYM_2(s->mrb, sub) && n == 1) { |
1761 | 20.8k | gen_addsub(s, OP_SUB, cursp()); |
1762 | 20.8k | } |
1763 | 121k | else if (!noop && sym == MRB_OPSYM_2(s->mrb, mul) && n == 1) { |
1764 | 8.24k | gen_muldiv(s, OP_MUL, cursp()); |
1765 | 8.24k | } |
1766 | 113k | else if (!noop && sym == MRB_OPSYM_2(s->mrb, div) && n == 1) { |
1767 | 12.3k | gen_muldiv(s, OP_DIV, cursp()); |
1768 | 12.3k | } |
1769 | 101k | else if (!noop && sym == MRB_OPSYM_2(s->mrb, lt) && n == 1) { |
1770 | 1.30k | genop_1(s, OP_LT, cursp()); |
1771 | 1.30k | } |
1772 | 100k | else if (!noop && sym == MRB_OPSYM_2(s->mrb, le) && n == 1) { |
1773 | 3.70k | genop_1(s, OP_LE, cursp()); |
1774 | 3.70k | } |
1775 | 96.3k | else if (!noop && sym == MRB_OPSYM_2(s->mrb, gt) && n == 1) { |
1776 | 2.27k | genop_1(s, OP_GT, cursp()); |
1777 | 2.27k | } |
1778 | 94.0k | else if (!noop && sym == MRB_OPSYM_2(s->mrb, ge) && n == 1) { |
1779 | 1.64k | genop_1(s, OP_GE, cursp()); |
1780 | 1.64k | } |
1781 | 92.4k | else if (!noop && sym == MRB_OPSYM_2(s->mrb, eq) && n == 1) { |
1782 | 1.93k | genop_1(s, OP_EQ, cursp()); |
1783 | 1.93k | } |
1784 | 90.4k | else if (!noop && sym == MRB_OPSYM_2(s->mrb, aset) && n == 2) { |
1785 | 0 | genop_1(s, OP_SETIDX, cursp()); |
1786 | 0 | } |
1787 | 90.4k | else if (!noop && n == 0 && gen_uniop(s, sym, cursp())) { |
1788 | | /* constant folding succeeded */ |
1789 | 0 | } |
1790 | 90.4k | else if (!noop && n == 1 && gen_binop(s, sym, cursp())) { |
1791 | | /* constant folding succeeded */ |
1792 | 7.47k | } |
1793 | 82.9k | else if (noself){ |
1794 | 394 | genop_3(s, blk ? OP_SSENDB : OP_SSEND, cursp(), new_sym(s, sym), n|(nk<<4)); |
1795 | 394 | } |
1796 | 82.6k | else { |
1797 | 82.6k | genop_3(s, blk ? OP_SENDB : OP_SEND, cursp(), new_sym(s, sym), n|(nk<<4)); |
1798 | 82.6k | } |
1799 | 154k | if (safe) { |
1800 | 0 | dispatch(s, skip); |
1801 | 0 | } |
1802 | 154k | if (val) { |
1803 | 91.1k | push(); |
1804 | 91.1k | } |
1805 | 154k | } |
1806 | | |
1807 | | static void |
1808 | | gen_assignment(codegen_scope *s, node *tree, node *rhs, int sp, int val) |
1809 | 139k | { |
1810 | 139k | int idx; |
1811 | 139k | int type = nint(tree->car); |
1812 | | |
1813 | 139k | switch (type) { |
1814 | 0 | case NODE_GVAR: |
1815 | 0 | case NODE_ARG: |
1816 | 119k | case NODE_LVAR: |
1817 | 139k | case NODE_IVAR: |
1818 | 139k | case NODE_CVAR: |
1819 | 139k | case NODE_CONST: |
1820 | 139k | case NODE_NIL: |
1821 | 139k | case NODE_MASGN: |
1822 | 139k | if (rhs) { |
1823 | 119k | codegen(s, rhs, VAL); |
1824 | 119k | pop(); |
1825 | 119k | sp = cursp(); |
1826 | 119k | } |
1827 | 139k | break; |
1828 | | |
1829 | 0 | case NODE_COLON2: |
1830 | 0 | case NODE_COLON3: |
1831 | 0 | case NODE_CALL: |
1832 | 0 | case NODE_SCALL: |
1833 | | /* keep evaluation order */ |
1834 | 0 | break; |
1835 | | |
1836 | 0 | case NODE_NVAR: |
1837 | | /* never happens; should have already checked in the parser */ |
1838 | 0 | codegen_error(s, "Can't assign to numbered parameter"); |
1839 | 0 | break; |
1840 | | |
1841 | 0 | default: |
1842 | 0 | codegen_error(s, "unknown lhs"); |
1843 | 0 | break; |
1844 | 139k | } |
1845 | | |
1846 | 139k | tree = tree->cdr; |
1847 | 139k | switch (type) { |
1848 | 0 | case NODE_GVAR: |
1849 | 0 | gen_setxv(s, OP_SETGV, sp, nsym(tree), val); |
1850 | 0 | break; |
1851 | 0 | case NODE_ARG: |
1852 | 119k | case NODE_LVAR: |
1853 | 119k | idx = lv_idx(s, nsym(tree)); |
1854 | 119k | if (idx > 0) { |
1855 | 119k | if (idx != sp) { |
1856 | 119k | gen_move(s, idx, sp, val); |
1857 | 119k | } |
1858 | 119k | break; |
1859 | 119k | } |
1860 | 0 | else { /* upvar */ |
1861 | 0 | gen_setupvar(s, sp, nsym(tree)); |
1862 | 0 | } |
1863 | 0 | break; |
1864 | 20.1k | case NODE_IVAR: |
1865 | 20.1k | gen_setxv(s, OP_SETIV, sp, nsym(tree), val); |
1866 | 20.1k | break; |
1867 | 0 | case NODE_CVAR: |
1868 | 0 | gen_setxv(s, OP_SETCV, sp, nsym(tree), val); |
1869 | 0 | break; |
1870 | 0 | case NODE_CONST: |
1871 | 0 | gen_setxv(s, OP_SETCONST, sp, nsym(tree), val); |
1872 | 0 | break; |
1873 | 0 | case NODE_COLON2: |
1874 | 0 | case NODE_COLON3: |
1875 | 0 | if (sp) { |
1876 | 0 | gen_move(s, cursp(), sp, 0); |
1877 | 0 | } |
1878 | 0 | sp = cursp(); |
1879 | 0 | push(); |
1880 | 0 | if (type == NODE_COLON2) { |
1881 | 0 | codegen(s, tree->car, VAL); |
1882 | 0 | idx = new_sym(s, nsym(tree->cdr)); |
1883 | 0 | } |
1884 | 0 | else { /* NODE_COLON3 */ |
1885 | 0 | genop_1(s, OP_OCLASS, cursp()); |
1886 | 0 | push(); |
1887 | 0 | idx = new_sym(s, nsym(tree)); |
1888 | 0 | } |
1889 | 0 | if (rhs) { |
1890 | 0 | codegen(s, rhs, VAL); pop(); |
1891 | 0 | gen_move(s, sp, cursp(), 0); |
1892 | 0 | } |
1893 | 0 | pop_n(2); |
1894 | 0 | genop_2(s, OP_SETMCNST, sp, idx); |
1895 | 0 | break; |
1896 | | |
1897 | 0 | case NODE_CALL: |
1898 | 0 | case NODE_SCALL: |
1899 | 0 | { |
1900 | 0 | int noself = 0, safe = (type == NODE_SCALL), skip = 0, top, call, n = 0; |
1901 | 0 | mrb_sym mid = nsym(tree->cdr->car); |
1902 | |
|
1903 | 0 | top = cursp(); |
1904 | 0 | if (val || sp == cursp()) { |
1905 | 0 | push(); /* room for retval */ |
1906 | 0 | } |
1907 | 0 | call = cursp(); |
1908 | 0 | if (!tree->car) { |
1909 | 0 | noself = 1; |
1910 | 0 | push(); |
1911 | 0 | } |
1912 | 0 | else { |
1913 | 0 | codegen(s, tree->car, VAL); /* receiver */ |
1914 | 0 | } |
1915 | 0 | if (safe) { |
1916 | 0 | int recv = cursp()-1; |
1917 | 0 | gen_move(s, cursp(), recv, 1); |
1918 | 0 | skip = genjmp2_0(s, OP_JMPNIL, cursp(), val); |
1919 | 0 | } |
1920 | 0 | tree = tree->cdr->cdr->car; |
1921 | 0 | if (tree) { |
1922 | 0 | if (tree->car) { /* positional arguments */ |
1923 | 0 | n = gen_values(s, tree->car, VAL, (tree->cdr->car)?13:14); |
1924 | 0 | if (n < 0) { /* variable length */ |
1925 | 0 | n = 15; |
1926 | 0 | push(); |
1927 | 0 | } |
1928 | 0 | } |
1929 | 0 | if (tree->cdr->car) { /* keyword arguments */ |
1930 | 0 | if (n == 13 || n == 14) { |
1931 | 0 | pop_n(n); |
1932 | 0 | genop_2(s, OP_ARRAY, cursp(), n); |
1933 | 0 | push(); |
1934 | 0 | n = 15; |
1935 | 0 | } |
1936 | 0 | gen_hash(s, tree->cdr->car->cdr, VAL, 0); |
1937 | 0 | if (n < 14) { |
1938 | 0 | n++; |
1939 | 0 | } |
1940 | 0 | else { |
1941 | 0 | pop_n(2); |
1942 | 0 | genop_2(s, OP_ARYPUSH, cursp(), 1); |
1943 | 0 | } |
1944 | 0 | push(); |
1945 | 0 | } |
1946 | 0 | } |
1947 | 0 | if (rhs) { |
1948 | 0 | codegen(s, rhs, VAL); |
1949 | 0 | pop(); |
1950 | 0 | } |
1951 | 0 | else { |
1952 | 0 | gen_move(s, cursp(), sp, 0); |
1953 | 0 | } |
1954 | 0 | if (val) { |
1955 | 0 | gen_move(s, top, cursp(), 1); |
1956 | 0 | } |
1957 | 0 | if (n < 15) { |
1958 | 0 | n++; |
1959 | 0 | if (n == 15) { |
1960 | 0 | pop_n(14); |
1961 | 0 | genop_2(s, OP_ARRAY, cursp(), 15); |
1962 | 0 | } |
1963 | 0 | } |
1964 | 0 | else { |
1965 | 0 | pop(); |
1966 | 0 | genop_2(s, OP_ARYPUSH, cursp(), 1); |
1967 | 0 | } |
1968 | 0 | push(); pop(); |
1969 | 0 | s->sp = call; |
1970 | 0 | if (mid == MRB_OPSYM_2(s->mrb, aref) && n == 2) { |
1971 | 0 | push_n(4); pop_n(4); /* self + idx + value + (invisible block for OP_SEND) */ |
1972 | 0 | genop_1(s, OP_SETIDX, cursp()); |
1973 | 0 | } |
1974 | 0 | else { |
1975 | 0 | int st = 2 /* self + block */ + |
1976 | 0 | (((n >> 0) & 0x0f) < 15 ? ((n >> 0) & 0x0f) : 1) + |
1977 | 0 | (((n >> 4) & 0x0f) < 15 ? ((n >> 4) & 0x0f) * 2 : 1); |
1978 | 0 | push_n(st); pop_n(st); |
1979 | 0 | genop_3(s, noself ? OP_SSEND : OP_SEND, cursp(), new_sym(s, attrsym(s, mid)), n); |
1980 | 0 | } |
1981 | 0 | if (safe) { |
1982 | 0 | dispatch(s, skip); |
1983 | 0 | } |
1984 | 0 | s->sp = top; |
1985 | 0 | } |
1986 | 0 | break; |
1987 | | |
1988 | 0 | case NODE_MASGN: |
1989 | 0 | gen_massignment(s, tree->car, sp, val); |
1990 | 0 | break; |
1991 | | |
1992 | | /* splat without assignment */ |
1993 | 0 | case NODE_NIL: |
1994 | 0 | break; |
1995 | | |
1996 | 0 | default: |
1997 | 0 | codegen_error(s, "unknown lhs"); |
1998 | 0 | break; |
1999 | 139k | } |
2000 | 139k | if (val) push(); |
2001 | 139k | } |
2002 | | |
2003 | | static void |
2004 | | gen_massignment(codegen_scope *s, node *tree, int rhs, int val) |
2005 | 0 | { |
2006 | 0 | int n = 0, post = 0; |
2007 | 0 | node *t, *p; |
2008 | |
|
2009 | 0 | if (tree->car) { /* pre */ |
2010 | 0 | t = tree->car; |
2011 | 0 | n = 0; |
2012 | 0 | while (t) { |
2013 | 0 | int sp = cursp(); |
2014 | |
|
2015 | 0 | genop_3(s, OP_AREF, sp, rhs, n); |
2016 | 0 | push(); |
2017 | 0 | gen_assignment(s, t->car, NULL, sp, NOVAL); |
2018 | 0 | pop(); |
2019 | 0 | n++; |
2020 | 0 | t = t->cdr; |
2021 | 0 | } |
2022 | 0 | } |
2023 | 0 | t = tree->cdr; |
2024 | 0 | if (t) { |
2025 | 0 | if (t->cdr) { /* post count */ |
2026 | 0 | p = t->cdr->car; |
2027 | 0 | while (p) { |
2028 | 0 | post++; |
2029 | 0 | p = p->cdr; |
2030 | 0 | } |
2031 | 0 | } |
2032 | 0 | gen_move(s, cursp(), rhs, val); |
2033 | 0 | push_n(post+1); |
2034 | 0 | pop_n(post+1); |
2035 | 0 | genop_3(s, OP_APOST, cursp(), n, post); |
2036 | 0 | n = 1; |
2037 | 0 | if (t->car && t->car != (node*)-1) { /* rest */ |
2038 | 0 | gen_assignment(s, t->car, NULL, cursp(), NOVAL); |
2039 | 0 | } |
2040 | 0 | if (t->cdr && t->cdr->car) { |
2041 | 0 | t = t->cdr->car; |
2042 | 0 | while (t) { |
2043 | 0 | gen_assignment(s, t->car, NULL, cursp()+n, NOVAL); |
2044 | 0 | t = t->cdr; |
2045 | 0 | n++; |
2046 | 0 | } |
2047 | 0 | } |
2048 | 0 | if (val) { |
2049 | 0 | gen_move(s, cursp(), rhs, 0); |
2050 | 0 | } |
2051 | 0 | } |
2052 | 0 | } |
2053 | | |
2054 | | static void |
2055 | | gen_intern(codegen_scope *s) |
2056 | 0 | { |
2057 | 0 | pop(); |
2058 | 0 | if (!no_peephole(s)) { |
2059 | 0 | struct mrb_insn_data data = mrb_last_insn(s); |
2060 | |
|
2061 | 0 | if (data.insn == OP_STRING && data.a == cursp()) { |
2062 | 0 | rewind_pc(s); |
2063 | 0 | genop_2(s, OP_SYMBOL, data.a, data.b); |
2064 | 0 | push(); |
2065 | 0 | return; |
2066 | 0 | } |
2067 | 0 | } |
2068 | 0 | genop_1(s, OP_INTERN, cursp()); |
2069 | 0 | push(); |
2070 | 0 | } |
2071 | | |
2072 | | static void |
2073 | | gen_literal_array(codegen_scope *s, node *tree, mrb_bool sym, int val) |
2074 | 0 | { |
2075 | 0 | if (val) { |
2076 | 0 | int i = 0, j = 0, gen = 0; |
2077 | |
|
2078 | 0 | while (tree) { |
2079 | 0 | switch (nint(tree->car->car)) { |
2080 | 0 | case NODE_STR: |
2081 | 0 | if ((tree->cdr == NULL) && (nint(tree->car->cdr->cdr) == 0)) |
2082 | 0 | break; |
2083 | | /* fall through */ |
2084 | 0 | case NODE_BEGIN: |
2085 | 0 | codegen(s, tree->car, VAL); |
2086 | 0 | j++; |
2087 | 0 | break; |
2088 | | |
2089 | 0 | case NODE_LITERAL_DELIM: |
2090 | 0 | if (j > 0) { |
2091 | 0 | j = 0; |
2092 | 0 | i++; |
2093 | 0 | if (sym) |
2094 | 0 | gen_intern(s); |
2095 | 0 | } |
2096 | 0 | break; |
2097 | 0 | } |
2098 | 0 | while (j >= 2) { |
2099 | 0 | pop(); pop(); |
2100 | 0 | genop_1(s, OP_STRCAT, cursp()); |
2101 | 0 | push(); |
2102 | 0 | j--; |
2103 | 0 | } |
2104 | 0 | if (i > GEN_LIT_ARY_MAX) { |
2105 | 0 | pop_n(i); |
2106 | 0 | if (gen) { |
2107 | 0 | pop(); |
2108 | 0 | genop_2(s, OP_ARYPUSH, cursp(), i); |
2109 | 0 | } |
2110 | 0 | else { |
2111 | 0 | genop_2(s, OP_ARRAY, cursp(), i); |
2112 | 0 | gen = 1; |
2113 | 0 | } |
2114 | 0 | push(); |
2115 | 0 | i = 0; |
2116 | 0 | } |
2117 | 0 | tree = tree->cdr; |
2118 | 0 | } |
2119 | 0 | if (j > 0) { |
2120 | 0 | i++; |
2121 | 0 | if (sym) |
2122 | 0 | gen_intern(s); |
2123 | 0 | } |
2124 | 0 | pop_n(i); |
2125 | 0 | if (gen) { |
2126 | 0 | pop(); |
2127 | 0 | genop_2(s, OP_ARYPUSH, cursp(), i); |
2128 | 0 | } |
2129 | 0 | else { |
2130 | 0 | genop_2(s, OP_ARRAY, cursp(), i); |
2131 | 0 | } |
2132 | 0 | push(); |
2133 | 0 | } |
2134 | 0 | else { |
2135 | 0 | while (tree) { |
2136 | 0 | switch (nint(tree->car->car)) { |
2137 | 0 | case NODE_BEGIN: case NODE_BLOCK: |
2138 | 0 | codegen(s, tree->car, NOVAL); |
2139 | 0 | } |
2140 | 0 | tree = tree->cdr; |
2141 | 0 | } |
2142 | 0 | } |
2143 | 0 | } |
2144 | | |
2145 | | static void |
2146 | | raise_error(codegen_scope *s, const char *msg) |
2147 | 0 | { |
2148 | 0 | int idx = new_lit_cstr(s, msg); |
2149 | |
|
2150 | 0 | genop_1(s, OP_ERR, idx); |
2151 | 0 | } |
2152 | | |
2153 | | static mrb_int |
2154 | | readint(codegen_scope *s, const char *p, int base, mrb_bool neg, mrb_bool *overflow) |
2155 | 575k | { |
2156 | 575k | const char *e = p + strlen(p); |
2157 | 575k | mrb_int result = 0; |
2158 | | |
2159 | 575k | mrb_assert(base >= 2 && base <= 16); |
2160 | 575k | if (*p == '+') p++; |
2161 | 1.15M | while (p < e) { |
2162 | 579k | int n; |
2163 | 579k | char c = *p; |
2164 | 579k | switch (c) { |
2165 | 560k | case '0': case '1': case '2': case '3': |
2166 | 571k | case '4': case '5': case '6': case '7': |
2167 | 571k | n = c - '0'; break; |
2168 | 7.98k | case '8': case '9': |
2169 | 7.98k | n = c - '0'; break; |
2170 | 0 | case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': |
2171 | 0 | n = c - 'a' + 10; break; |
2172 | 0 | case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': |
2173 | 0 | n = c - 'A' + 10; break; |
2174 | 0 | default: |
2175 | 0 | codegen_error(s, "malformed readint input"); |
2176 | 0 | *overflow = TRUE; |
2177 | | /* not reached */ |
2178 | 0 | return result; |
2179 | 579k | } |
2180 | 579k | if (mrb_int_mul_overflow(result, base, &result)) { |
2181 | 0 | overflow: |
2182 | 0 | *overflow = TRUE; |
2183 | 0 | return 0; |
2184 | 0 | } |
2185 | 579k | mrb_uint tmp = ((mrb_uint)result)+n; |
2186 | 579k | if (neg && tmp == (mrb_uint)MRB_INT_MAX+1) { |
2187 | 0 | *overflow = FALSE; |
2188 | 0 | return MRB_INT_MIN; |
2189 | 0 | } |
2190 | 579k | if (tmp > MRB_INT_MAX) goto overflow; |
2191 | 579k | result = (mrb_int)tmp; |
2192 | 579k | p++; |
2193 | 579k | } |
2194 | 575k | *overflow = FALSE; |
2195 | 575k | if (neg) return -result; |
2196 | 575k | return result; |
2197 | 575k | } |
2198 | | |
2199 | | static void |
2200 | | gen_retval(codegen_scope *s, node *tree) |
2201 | 0 | { |
2202 | 0 | if (nint(tree->car) == NODE_SPLAT) { |
2203 | 0 | codegen(s, tree, VAL); |
2204 | 0 | pop(); |
2205 | 0 | genop_1(s, OP_ARYSPLAT, cursp()); |
2206 | 0 | } |
2207 | 0 | else { |
2208 | 0 | codegen(s, tree, VAL); |
2209 | 0 | pop(); |
2210 | 0 | } |
2211 | 0 | } |
2212 | | |
2213 | | static mrb_bool |
2214 | | true_always(node *tree) |
2215 | 31.0k | { |
2216 | 31.0k | switch (nint(tree->car)) { |
2217 | 0 | case NODE_TRUE: |
2218 | 11.7k | case NODE_INT: |
2219 | 11.7k | case NODE_STR: |
2220 | 11.7k | case NODE_SYM: |
2221 | 11.7k | return TRUE; |
2222 | 19.3k | default: |
2223 | 19.3k | return FALSE; |
2224 | 31.0k | } |
2225 | 31.0k | } |
2226 | | |
2227 | | static mrb_bool |
2228 | | false_always(node *tree) |
2229 | 19.3k | { |
2230 | 19.3k | switch (nint(tree->car)) { |
2231 | 0 | case NODE_FALSE: |
2232 | 0 | case NODE_NIL: |
2233 | 0 | return TRUE; |
2234 | 19.3k | default: |
2235 | 19.3k | return FALSE; |
2236 | 19.3k | } |
2237 | 19.3k | } |
2238 | | |
2239 | | static void |
2240 | | gen_blkmove(codegen_scope *s, uint16_t ainfo, int lv) |
2241 | 0 | { |
2242 | 0 | int m1 = (ainfo>>7)&0x3f; |
2243 | 0 | int r = (ainfo>>6)&0x1; |
2244 | 0 | int m2 = (ainfo>>1)&0x1f; |
2245 | 0 | int kd = (ainfo)&0x1; |
2246 | 0 | int off = m1+r+m2+kd+1; |
2247 | 0 | if (lv == 0) { |
2248 | 0 | gen_move(s, cursp(), off, 0); |
2249 | 0 | } |
2250 | 0 | else { |
2251 | 0 | genop_3(s, OP_GETUPVAR, cursp(), off, lv); |
2252 | 0 | } |
2253 | 0 | push(); |
2254 | 0 | } |
2255 | | |
2256 | | static void |
2257 | | codegen(codegen_scope *s, node *tree, int val) |
2258 | 1.58M | { |
2259 | 1.58M | int nt; |
2260 | 1.58M | int rlev = s->rlev; |
2261 | | |
2262 | 1.58M | if (!tree) { |
2263 | 0 | if (val) { |
2264 | 0 | genop_1(s, OP_LOADNIL, cursp()); |
2265 | 0 | push(); |
2266 | 0 | } |
2267 | 0 | return; |
2268 | 0 | } |
2269 | | |
2270 | 1.58M | s->rlev++; |
2271 | 1.58M | if (s->rlev > MRB_CODEGEN_LEVEL_MAX) { |
2272 | 0 | codegen_error(s, "too complex expression"); |
2273 | 0 | } |
2274 | 1.58M | if (s->irep && s->filename_index != tree->filename_index) { |
2275 | 0 | mrb_sym fname = mrb_parser_get_filename(s->parser, s->filename_index); |
2276 | 0 | const char *filename = mrb_sym_name_len(s->mrb, fname, NULL); |
2277 | |
|
2278 | 0 | mrb_debug_info_append_file(s->mrb, s->irep->debug_info, |
2279 | 0 | filename, s->lines, s->debug_start_pos, s->pc); |
2280 | 0 | s->debug_start_pos = s->pc; |
2281 | 0 | s->filename_index = tree->filename_index; |
2282 | 0 | s->filename_sym = mrb_parser_get_filename(s->parser, tree->filename_index); |
2283 | 0 | } |
2284 | | |
2285 | 1.58M | nt = nint(tree->car); |
2286 | 1.58M | s->lineno = tree->lineno; |
2287 | 1.58M | tree = tree->cdr; |
2288 | 1.58M | switch (nt) { |
2289 | 189k | case NODE_BEGIN: |
2290 | 189k | if (val && !tree) { |
2291 | 9.21k | genop_1(s, OP_LOADNIL, cursp()); |
2292 | 9.21k | push(); |
2293 | 9.21k | } |
2294 | 576k | while (tree) { |
2295 | 386k | codegen(s, tree->car, tree->cdr ? NOVAL : val); |
2296 | 386k | tree = tree->cdr; |
2297 | 386k | } |
2298 | 189k | break; |
2299 | | |
2300 | 0 | case NODE_RESCUE: |
2301 | 0 | { |
2302 | 0 | int noexc; |
2303 | 0 | uint32_t exend, pos1, pos2, tmp; |
2304 | 0 | struct loopinfo *lp; |
2305 | 0 | int catch_entry, begin, end; |
2306 | |
|
2307 | 0 | if (tree->car == NULL) goto exit; |
2308 | 0 | lp = loop_push(s, LOOP_BEGIN); |
2309 | 0 | lp->pc0 = new_label(s); |
2310 | 0 | catch_entry = catch_handler_new(s); |
2311 | 0 | begin = s->pc; |
2312 | 0 | codegen(s, tree->car, VAL); |
2313 | 0 | pop(); |
2314 | 0 | lp->type = LOOP_RESCUE; |
2315 | 0 | end = s->pc; |
2316 | 0 | noexc = genjmp_0(s, OP_JMP); |
2317 | 0 | catch_handler_set(s, catch_entry, MRB_CATCH_RESCUE, begin, end, s->pc); |
2318 | 0 | tree = tree->cdr; |
2319 | 0 | exend = JMPLINK_START; |
2320 | 0 | pos1 = JMPLINK_START; |
2321 | 0 | if (tree->car) { |
2322 | 0 | node *n2 = tree->car; |
2323 | 0 | int exc = cursp(); |
2324 | |
|
2325 | 0 | genop_1(s, OP_EXCEPT, exc); |
2326 | 0 | push(); |
2327 | 0 | while (n2) { |
2328 | 0 | node *n3 = n2->car; |
2329 | 0 | node *n4 = n3->car; |
2330 | |
|
2331 | 0 | dispatch(s, pos1); |
2332 | 0 | pos2 = JMPLINK_START; |
2333 | 0 | do { |
2334 | 0 | if (n4 && n4->car && nint(n4->car->car) == NODE_SPLAT) { |
2335 | 0 | codegen(s, n4->car, VAL); |
2336 | 0 | gen_move(s, cursp(), exc, 0); |
2337 | 0 | push_n(2); pop_n(2); /* space for one arg and a block */ |
2338 | 0 | pop(); |
2339 | 0 | genop_3(s, OP_SEND, cursp(), new_sym(s, MRB_SYM_2(s->mrb, __case_eqq)), 1); |
2340 | 0 | } |
2341 | 0 | else { |
2342 | 0 | if (n4) { |
2343 | 0 | codegen(s, n4->car, VAL); |
2344 | 0 | } |
2345 | 0 | else { |
2346 | 0 | genop_2(s, OP_GETCONST, cursp(), new_sym(s, MRB_SYM_2(s->mrb, StandardError))); |
2347 | 0 | push(); |
2348 | 0 | } |
2349 | 0 | pop(); |
2350 | 0 | genop_2(s, OP_RESCUE, exc, cursp()); |
2351 | 0 | } |
2352 | 0 | tmp = genjmp2(s, OP_JMPIF, cursp(), pos2, val); |
2353 | 0 | pos2 = tmp; |
2354 | 0 | if (n4) { |
2355 | 0 | n4 = n4->cdr; |
2356 | 0 | } |
2357 | 0 | } while (n4); |
2358 | 0 | pos1 = genjmp_0(s, OP_JMP); |
2359 | 0 | dispatch_linked(s, pos2); |
2360 | |
|
2361 | 0 | pop(); |
2362 | 0 | if (n3->cdr->car) { |
2363 | 0 | gen_assignment(s, n3->cdr->car, NULL, exc, NOVAL); |
2364 | 0 | } |
2365 | 0 | if (n3->cdr->cdr->car) { |
2366 | 0 | codegen(s, n3->cdr->cdr->car, val); |
2367 | 0 | if (val) pop(); |
2368 | 0 | } |
2369 | 0 | tmp = genjmp(s, OP_JMP, exend); |
2370 | 0 | exend = tmp; |
2371 | 0 | n2 = n2->cdr; |
2372 | 0 | push(); |
2373 | 0 | } |
2374 | 0 | if (pos1 != JMPLINK_START) { |
2375 | 0 | dispatch(s, pos1); |
2376 | 0 | genop_1(s, OP_RAISEIF, exc); |
2377 | 0 | } |
2378 | 0 | } |
2379 | 0 | pop(); |
2380 | 0 | tree = tree->cdr; |
2381 | 0 | dispatch(s, noexc); |
2382 | 0 | if (tree->car) { |
2383 | 0 | codegen(s, tree->car, val); |
2384 | 0 | } |
2385 | 0 | else if (val) { |
2386 | 0 | push(); |
2387 | 0 | } |
2388 | 0 | dispatch_linked(s, exend); |
2389 | 0 | loop_pop(s, NOVAL); |
2390 | 0 | } |
2391 | 0 | break; |
2392 | | |
2393 | 0 | case NODE_ENSURE: |
2394 | 0 | if (!tree->cdr || !tree->cdr->cdr || |
2395 | 0 | (nint(tree->cdr->cdr->car) == NODE_BEGIN && |
2396 | 0 | tree->cdr->cdr->cdr)) { |
2397 | 0 | int catch_entry, begin, end, target; |
2398 | 0 | int idx; |
2399 | |
|
2400 | 0 | catch_entry = catch_handler_new(s); |
2401 | 0 | begin = s->pc; |
2402 | 0 | codegen(s, tree->car, val); |
2403 | 0 | end = target = s->pc; |
2404 | 0 | push(); |
2405 | 0 | idx = cursp(); |
2406 | 0 | genop_1(s, OP_EXCEPT, idx); |
2407 | 0 | push(); |
2408 | 0 | codegen(s, tree->cdr->cdr, NOVAL); |
2409 | 0 | pop(); |
2410 | 0 | genop_1(s, OP_RAISEIF, idx); |
2411 | 0 | pop(); |
2412 | 0 | catch_handler_set(s, catch_entry, MRB_CATCH_ENSURE, begin, end, target); |
2413 | 0 | } |
2414 | 0 | else { /* empty ensure ignored */ |
2415 | 0 | codegen(s, tree->car, val); |
2416 | 0 | } |
2417 | 0 | break; |
2418 | | |
2419 | 0 | case NODE_LAMBDA: |
2420 | 0 | if (val) { |
2421 | 0 | int idx = lambda_body(s, tree, 1); |
2422 | |
|
2423 | 0 | genop_2(s, OP_LAMBDA, cursp(), idx); |
2424 | 0 | push(); |
2425 | 0 | } |
2426 | 0 | break; |
2427 | | |
2428 | 0 | case NODE_BLOCK: |
2429 | 0 | if (val) { |
2430 | 0 | int idx = lambda_body(s, tree, 1); |
2431 | |
|
2432 | 0 | genop_2(s, OP_BLOCK, cursp(), idx); |
2433 | 0 | push(); |
2434 | 0 | } |
2435 | 0 | break; |
2436 | | |
2437 | 24.9k | case NODE_IF: |
2438 | 24.9k | { |
2439 | 24.9k | uint32_t pos1, pos2; |
2440 | 24.9k | mrb_bool nil_p = FALSE; |
2441 | 24.9k | node *elsepart = tree->cdr->cdr->car; |
2442 | | |
2443 | 24.9k | if (!tree->car) { |
2444 | 0 | codegen(s, elsepart, val); |
2445 | 0 | goto exit; |
2446 | 0 | } |
2447 | 24.9k | if (true_always(tree->car)) { |
2448 | 10.6k | codegen(s, tree->cdr->car, val); |
2449 | 10.6k | goto exit; |
2450 | 10.6k | } |
2451 | 14.3k | if (false_always(tree->car)) { |
2452 | 0 | codegen(s, elsepart, val); |
2453 | 0 | goto exit; |
2454 | 0 | } |
2455 | 14.3k | if (nint(tree->car->car) == NODE_CALL) { |
2456 | 0 | node *n = tree->car->cdr; |
2457 | 0 | mrb_sym mid = nsym(n->cdr->car); |
2458 | 0 | mrb_sym sym_nil_p = MRB_SYM_Q_2(s->mrb, nil); |
2459 | 0 | if (mid == sym_nil_p && n->cdr->cdr->car == NULL) { |
2460 | 0 | nil_p = TRUE; |
2461 | 0 | codegen(s, n->car, VAL); |
2462 | 0 | } |
2463 | 0 | } |
2464 | 14.3k | if (!nil_p) { |
2465 | 14.3k | codegen(s, tree->car, VAL); |
2466 | 14.3k | } |
2467 | 14.3k | pop(); |
2468 | 14.3k | if (val || tree->cdr->car) { |
2469 | 14.3k | if (nil_p) { |
2470 | 0 | pos2 = genjmp2_0(s, OP_JMPNIL, cursp(), val); |
2471 | 0 | pos1 = genjmp_0(s, OP_JMP); |
2472 | 0 | dispatch(s, pos2); |
2473 | 0 | } |
2474 | 14.3k | else { |
2475 | 14.3k | pos1 = genjmp2_0(s, OP_JMPNOT, cursp(), val); |
2476 | 14.3k | } |
2477 | 14.3k | codegen(s, tree->cdr->car, val); |
2478 | 14.3k | if (val) pop(); |
2479 | 14.3k | if (elsepart || val) { |
2480 | 14.3k | pos2 = genjmp_0(s, OP_JMP); |
2481 | 14.3k | dispatch(s, pos1); |
2482 | 14.3k | codegen(s, elsepart, val); |
2483 | 14.3k | dispatch(s, pos2); |
2484 | 14.3k | } |
2485 | 4 | else { |
2486 | 4 | dispatch(s, pos1); |
2487 | 4 | } |
2488 | 14.3k | } |
2489 | 0 | else { /* empty then-part */ |
2490 | 0 | if (elsepart) { |
2491 | 0 | if (nil_p) { |
2492 | 0 | pos1 = genjmp2_0(s, OP_JMPNIL, cursp(), val); |
2493 | 0 | } |
2494 | 0 | else { |
2495 | 0 | pos1 = genjmp2_0(s, OP_JMPIF, cursp(), val); |
2496 | 0 | } |
2497 | 0 | codegen(s, elsepart, val); |
2498 | 0 | dispatch(s, pos1); |
2499 | 0 | } |
2500 | 0 | else if (val && !nil_p) { |
2501 | 0 | genop_1(s, OP_LOADNIL, cursp()); |
2502 | 0 | push(); |
2503 | 0 | } |
2504 | 0 | } |
2505 | 14.3k | } |
2506 | 0 | break; |
2507 | | |
2508 | 4.33k | case NODE_AND: |
2509 | 4.33k | { |
2510 | 4.33k | uint32_t pos; |
2511 | | |
2512 | 4.33k | if (true_always(tree->car)) { |
2513 | 739 | codegen(s, tree->cdr, val); |
2514 | 739 | goto exit; |
2515 | 739 | } |
2516 | 3.59k | if (false_always(tree->car)) { |
2517 | 0 | codegen(s, tree->car, val); |
2518 | 0 | goto exit; |
2519 | 0 | } |
2520 | 3.59k | codegen(s, tree->car, VAL); |
2521 | 3.59k | pop(); |
2522 | 3.59k | pos = genjmp2_0(s, OP_JMPNOT, cursp(), val); |
2523 | 3.59k | codegen(s, tree->cdr, val); |
2524 | 3.59k | dispatch(s, pos); |
2525 | 3.59k | } |
2526 | 0 | break; |
2527 | | |
2528 | 1.78k | case NODE_OR: |
2529 | 1.78k | { |
2530 | 1.78k | uint32_t pos; |
2531 | | |
2532 | 1.78k | if (true_always(tree->car)) { |
2533 | 376 | codegen(s, tree->car, val); |
2534 | 376 | goto exit; |
2535 | 376 | } |
2536 | 1.40k | if (false_always(tree->car)) { |
2537 | 0 | codegen(s, tree->cdr, val); |
2538 | 0 | goto exit; |
2539 | 0 | } |
2540 | 1.40k | codegen(s, tree->car, VAL); |
2541 | 1.40k | pop(); |
2542 | 1.40k | pos = genjmp2_0(s, OP_JMPIF, cursp(), val); |
2543 | 1.40k | codegen(s, tree->cdr, val); |
2544 | 1.40k | dispatch(s, pos); |
2545 | 1.40k | } |
2546 | 0 | break; |
2547 | | |
2548 | 0 | case NODE_WHILE: |
2549 | 0 | case NODE_UNTIL: |
2550 | 0 | { |
2551 | 0 | if (true_always(tree->car)) { |
2552 | 0 | if (nt == NODE_UNTIL) { |
2553 | 0 | if (val) { |
2554 | 0 | genop_1(s, OP_LOADNIL, cursp()); |
2555 | 0 | push(); |
2556 | 0 | } |
2557 | 0 | goto exit; |
2558 | 0 | } |
2559 | 0 | } |
2560 | 0 | else if (false_always(tree->car)) { |
2561 | 0 | if (nt == NODE_WHILE) { |
2562 | 0 | if (val) { |
2563 | 0 | genop_1(s, OP_LOADNIL, cursp()); |
2564 | 0 | push(); |
2565 | 0 | } |
2566 | 0 | goto exit; |
2567 | 0 | } |
2568 | 0 | } |
2569 | | |
2570 | 0 | uint32_t pos = JMPLINK_START; |
2571 | 0 | struct loopinfo *lp = loop_push(s, LOOP_NORMAL); |
2572 | |
|
2573 | 0 | if (!val) lp->reg = -1; |
2574 | 0 | lp->pc0 = new_label(s); |
2575 | 0 | codegen(s, tree->car, VAL); |
2576 | 0 | pop(); |
2577 | 0 | if (nt == NODE_WHILE) { |
2578 | 0 | pos = genjmp2_0(s, OP_JMPNOT, cursp(), NOVAL); |
2579 | 0 | } |
2580 | 0 | else { |
2581 | 0 | pos = genjmp2_0(s, OP_JMPIF, cursp(), NOVAL); |
2582 | 0 | } |
2583 | 0 | lp->pc1 = new_label(s); |
2584 | 0 | codegen(s, tree->cdr, NOVAL); |
2585 | 0 | genjmp(s, OP_JMP, lp->pc0); |
2586 | 0 | dispatch(s, pos); |
2587 | 0 | loop_pop(s, val); |
2588 | 0 | } |
2589 | 0 | break; |
2590 | | |
2591 | 0 | case NODE_FOR: |
2592 | 0 | for_body(s, tree); |
2593 | 0 | if (val) push(); |
2594 | 0 | break; |
2595 | | |
2596 | 0 | case NODE_CASE: |
2597 | 0 | { |
2598 | 0 | int head = 0; |
2599 | 0 | uint32_t pos1, pos2, pos3, tmp; |
2600 | 0 | node *n; |
2601 | |
|
2602 | 0 | pos3 = JMPLINK_START; |
2603 | 0 | if (tree->car) { |
2604 | 0 | head = cursp(); |
2605 | 0 | codegen(s, tree->car, VAL); |
2606 | 0 | } |
2607 | 0 | tree = tree->cdr; |
2608 | 0 | while (tree) { |
2609 | 0 | n = tree->car->car; |
2610 | 0 | pos1 = pos2 = JMPLINK_START; |
2611 | 0 | while (n) { |
2612 | 0 | codegen(s, n->car, VAL); |
2613 | 0 | if (head) { |
2614 | 0 | gen_move(s, cursp(), head, 0); |
2615 | 0 | push(); push(); pop(); pop(); pop(); |
2616 | 0 | if (nint(n->car->car) == NODE_SPLAT) { |
2617 | 0 | genop_3(s, OP_SEND, cursp(), new_sym(s, MRB_SYM_2(s->mrb, __case_eqq)), 1); |
2618 | 0 | } |
2619 | 0 | else { |
2620 | 0 | genop_3(s, OP_SEND, cursp(), new_sym(s, MRB_OPSYM_2(s->mrb, eqq)), 1); |
2621 | 0 | } |
2622 | 0 | } |
2623 | 0 | else { |
2624 | 0 | pop(); |
2625 | 0 | } |
2626 | 0 | tmp = genjmp2(s, OP_JMPIF, cursp(), pos2, !head); |
2627 | 0 | pos2 = tmp; |
2628 | 0 | n = n->cdr; |
2629 | 0 | } |
2630 | 0 | if (tree->car->car) { |
2631 | 0 | pos1 = genjmp_0(s, OP_JMP); |
2632 | 0 | dispatch_linked(s, pos2); |
2633 | 0 | } |
2634 | 0 | codegen(s, tree->car->cdr, val); |
2635 | 0 | if (val) pop(); |
2636 | 0 | tmp = genjmp(s, OP_JMP, pos3); |
2637 | 0 | pos3 = tmp; |
2638 | 0 | dispatch(s, pos1); |
2639 | 0 | tree = tree->cdr; |
2640 | 0 | } |
2641 | 0 | if (val) { |
2642 | 0 | uint32_t pos = cursp(); |
2643 | 0 | genop_1(s, OP_LOADNIL, cursp()); |
2644 | 0 | if (pos3 != JMPLINK_START) dispatch_linked(s, pos3); |
2645 | 0 | if (head) pop(); |
2646 | 0 | if (cursp() != pos) { |
2647 | 0 | gen_move(s, cursp(), pos, 0); |
2648 | 0 | } |
2649 | 0 | push(); |
2650 | 0 | } |
2651 | 0 | else { |
2652 | 0 | if (pos3 != JMPLINK_START) { |
2653 | 0 | dispatch_linked(s, pos3); |
2654 | 0 | } |
2655 | 0 | if (head) { |
2656 | 0 | pop(); |
2657 | 0 | } |
2658 | 0 | } |
2659 | 0 | } |
2660 | 0 | break; |
2661 | | |
2662 | 466 | case NODE_SCOPE: |
2663 | 466 | scope_body(s, tree, NOVAL); |
2664 | 466 | break; |
2665 | | |
2666 | 394 | case NODE_FCALL: |
2667 | 154k | case NODE_CALL: |
2668 | 154k | gen_call(s, tree, val, 0); |
2669 | 154k | break; |
2670 | 0 | case NODE_SCALL: |
2671 | 0 | gen_call(s, tree, val, 1); |
2672 | 0 | break; |
2673 | | |
2674 | 0 | case NODE_DOT2: |
2675 | 0 | codegen(s, tree->car, val); |
2676 | 0 | codegen(s, tree->cdr, val); |
2677 | 0 | if (val) { |
2678 | 0 | pop(); pop(); |
2679 | 0 | genop_1(s, OP_RANGE_INC, cursp()); |
2680 | 0 | push(); |
2681 | 0 | } |
2682 | 0 | break; |
2683 | | |
2684 | 0 | case NODE_DOT3: |
2685 | 0 | codegen(s, tree->car, val); |
2686 | 0 | codegen(s, tree->cdr, val); |
2687 | 0 | if (val) { |
2688 | 0 | pop(); pop(); |
2689 | 0 | genop_1(s, OP_RANGE_EXC, cursp()); |
2690 | 0 | push(); |
2691 | 0 | } |
2692 | 0 | break; |
2693 | | |
2694 | 774 | case NODE_COLON2: |
2695 | 774 | { |
2696 | 774 | int sym = new_sym(s, nsym(tree->cdr)); |
2697 | | |
2698 | 774 | codegen(s, tree->car, VAL); |
2699 | 774 | pop(); |
2700 | 774 | genop_2(s, OP_GETMCNST, cursp(), sym); |
2701 | 774 | if (val) push(); |
2702 | 774 | } |
2703 | 774 | break; |
2704 | | |
2705 | 0 | case NODE_COLON3: |
2706 | 0 | { |
2707 | 0 | int sym = new_sym(s, nsym(tree)); |
2708 | |
|
2709 | 0 | genop_1(s, OP_OCLASS, cursp()); |
2710 | 0 | genop_2(s, OP_GETMCNST, cursp(), sym); |
2711 | 0 | if (val) push(); |
2712 | 0 | } |
2713 | 0 | break; |
2714 | | |
2715 | 46.4k | case NODE_ARRAY: |
2716 | 46.4k | { |
2717 | 46.4k | int n; |
2718 | | |
2719 | 46.4k | n = gen_values(s, tree, val, 0); |
2720 | 46.4k | if (val) { |
2721 | 46.4k | if (n >= 0) { |
2722 | 44.2k | pop_n(n); |
2723 | 44.2k | genop_2(s, OP_ARRAY, cursp(), n); |
2724 | 44.2k | } |
2725 | 46.4k | push(); |
2726 | 46.4k | } |
2727 | 46.4k | } |
2728 | 46.4k | break; |
2729 | | |
2730 | 2.01k | case NODE_HASH: |
2731 | 2.01k | case NODE_KW_HASH: |
2732 | 2.01k | { |
2733 | 2.01k | int nk = gen_hash(s, tree, val, GEN_LIT_ARY_MAX); |
2734 | 2.01k | if (val && nk >= 0) { |
2735 | 1.48k | pop_n(nk*2); |
2736 | 1.48k | genop_2(s, OP_HASH, cursp(), nk); |
2737 | 1.48k | push(); |
2738 | 1.48k | } |
2739 | 2.01k | } |
2740 | 2.01k | break; |
2741 | | |
2742 | 0 | case NODE_SPLAT: |
2743 | 0 | codegen(s, tree, val); |
2744 | 0 | break; |
2745 | | |
2746 | 119k | case NODE_ASGN: |
2747 | 119k | gen_assignment(s, tree->car, tree->cdr, 0, val); |
2748 | 119k | break; |
2749 | | |
2750 | 0 | case NODE_MASGN: |
2751 | 0 | { |
2752 | 0 | int len = 0, n = 0, post = 0; |
2753 | 0 | node *t = tree->cdr, *p; |
2754 | 0 | int rhs = cursp(); |
2755 | |
|
2756 | 0 | if (!val && nint(t->car) == NODE_ARRAY && t->cdr && nosplat(t->cdr)) { |
2757 | | /* fixed rhs */ |
2758 | 0 | t = t->cdr; |
2759 | 0 | while (t) { |
2760 | 0 | codegen(s, t->car, VAL); |
2761 | 0 | len++; |
2762 | 0 | t = t->cdr; |
2763 | 0 | } |
2764 | 0 | tree = tree->car; |
2765 | 0 | if (tree->car) { /* pre */ |
2766 | 0 | t = tree->car; |
2767 | 0 | n = 0; |
2768 | 0 | while (t) { |
2769 | 0 | if (n < len) { |
2770 | 0 | gen_assignment(s, t->car, NULL, rhs+n, NOVAL); |
2771 | 0 | n++; |
2772 | 0 | } |
2773 | 0 | else { |
2774 | 0 | genop_1(s, OP_LOADNIL, rhs+n); |
2775 | 0 | gen_assignment(s, t->car, NULL, rhs+n, NOVAL); |
2776 | 0 | } |
2777 | 0 | t = t->cdr; |
2778 | 0 | } |
2779 | 0 | } |
2780 | 0 | t = tree->cdr; |
2781 | 0 | if (t) { |
2782 | 0 | if (t->cdr) { /* post count */ |
2783 | 0 | p = t->cdr->car; |
2784 | 0 | while (p) { |
2785 | 0 | post++; |
2786 | 0 | p = p->cdr; |
2787 | 0 | } |
2788 | 0 | } |
2789 | 0 | if (t->car) { /* rest (len - pre - post) */ |
2790 | 0 | int rn; |
2791 | |
|
2792 | 0 | if (len < post + n) { |
2793 | 0 | rn = 0; |
2794 | 0 | } |
2795 | 0 | else { |
2796 | 0 | rn = len - post - n; |
2797 | 0 | } |
2798 | 0 | if (cursp() == rhs+n) { |
2799 | 0 | genop_2(s, OP_ARRAY, cursp(), rn); |
2800 | 0 | } |
2801 | 0 | else { |
2802 | 0 | genop_3(s, OP_ARRAY2, cursp(), rhs+n, rn); |
2803 | 0 | } |
2804 | 0 | gen_assignment(s, t->car, NULL, cursp(), NOVAL); |
2805 | 0 | n += rn; |
2806 | 0 | } |
2807 | 0 | if (t->cdr && t->cdr->car) { |
2808 | 0 | t = t->cdr->car; |
2809 | 0 | while (t) { |
2810 | 0 | if (n<len) { |
2811 | 0 | gen_assignment(s, t->car, NULL, rhs+n, NOVAL); |
2812 | 0 | } |
2813 | 0 | else { |
2814 | 0 | genop_1(s, OP_LOADNIL, cursp()); |
2815 | 0 | gen_assignment(s, t->car, NULL, cursp(), NOVAL); |
2816 | 0 | } |
2817 | 0 | t = t->cdr; |
2818 | 0 | n++; |
2819 | 0 | } |
2820 | 0 | } |
2821 | 0 | } |
2822 | 0 | pop_n(len); |
2823 | 0 | } |
2824 | 0 | else { |
2825 | | /* variable rhs */ |
2826 | 0 | codegen(s, t, VAL); |
2827 | 0 | gen_massignment(s, tree->car, rhs, val); |
2828 | 0 | if (!val) { |
2829 | 0 | pop(); |
2830 | 0 | } |
2831 | 0 | } |
2832 | 0 | } |
2833 | 0 | break; |
2834 | | |
2835 | 20.1k | case NODE_OP_ASGN: |
2836 | 20.1k | { |
2837 | 20.1k | mrb_sym sym = nsym(tree->cdr->car); |
2838 | 20.1k | mrb_int len; |
2839 | 20.1k | const char *name = mrb_sym_name_len(s->mrb, sym, &len); |
2840 | 20.1k | int idx, callargs = -1, vsp = -1; |
2841 | | |
2842 | 20.1k | if ((len == 2 && name[0] == '|' && name[1] == '|') && |
2843 | 20.1k | (nint(tree->car->car) == NODE_CONST || |
2844 | 20.1k | nint(tree->car->car) == NODE_CVAR)) { |
2845 | 0 | int catch_entry, begin, end; |
2846 | 0 | int noexc, exc; |
2847 | 0 | struct loopinfo *lp; |
2848 | |
|
2849 | 0 | lp = loop_push(s, LOOP_BEGIN); |
2850 | 0 | lp->pc0 = new_label(s); |
2851 | 0 | catch_entry = catch_handler_new(s); |
2852 | 0 | begin = s->pc; |
2853 | 0 | exc = cursp(); |
2854 | 0 | codegen(s, tree->car, VAL); |
2855 | 0 | end = s->pc; |
2856 | 0 | noexc = genjmp_0(s, OP_JMP); |
2857 | 0 | lp->type = LOOP_RESCUE; |
2858 | 0 | catch_handler_set(s, catch_entry, MRB_CATCH_RESCUE, begin, end, s->pc); |
2859 | 0 | genop_1(s, OP_EXCEPT, exc); |
2860 | 0 | genop_1(s, OP_LOADF, exc); |
2861 | 0 | dispatch(s, noexc); |
2862 | 0 | loop_pop(s, NOVAL); |
2863 | 0 | } |
2864 | 20.1k | else if (nint(tree->car->car) == NODE_CALL) { |
2865 | 0 | node *n = tree->car->cdr; |
2866 | 0 | int base, i, nargs = 0; |
2867 | 0 | callargs = 0; |
2868 | |
|
2869 | 0 | if (val) { |
2870 | 0 | vsp = cursp(); |
2871 | 0 | push(); |
2872 | 0 | } |
2873 | 0 | codegen(s, n->car, VAL); /* receiver */ |
2874 | 0 | idx = new_sym(s, nsym(n->cdr->car)); |
2875 | 0 | base = cursp()-1; |
2876 | 0 | if (n->cdr->cdr->car) { |
2877 | 0 | nargs = gen_values(s, n->cdr->cdr->car->car, VAL, 13); |
2878 | 0 | if (nargs >= 0) { |
2879 | 0 | callargs = nargs; |
2880 | 0 | } |
2881 | 0 | else { /* varargs */ |
2882 | 0 | push(); |
2883 | 0 | nargs = 1; |
2884 | 0 | callargs = CALL_MAXARGS; |
2885 | 0 | } |
2886 | 0 | } |
2887 | | /* copy receiver and arguments */ |
2888 | 0 | gen_move(s, cursp(), base, 1); |
2889 | 0 | for (i=0; i<nargs; i++) { |
2890 | 0 | gen_move(s, cursp()+i+1, base+i+1, 1); |
2891 | 0 | } |
2892 | 0 | push_n(nargs+2);pop_n(nargs+2); /* space for receiver, arguments and a block */ |
2893 | 0 | genop_3(s, OP_SEND, cursp(), idx, callargs); |
2894 | 0 | push(); |
2895 | 0 | } |
2896 | 20.1k | else { |
2897 | 20.1k | codegen(s, tree->car, VAL); |
2898 | 20.1k | } |
2899 | 20.1k | if (len == 2 && |
2900 | 20.1k | ((name[0] == '|' && name[1] == '|') || |
2901 | 20.1k | (name[0] == '&' && name[1] == '&'))) { |
2902 | 20.1k | uint32_t pos; |
2903 | | |
2904 | 20.1k | pop(); |
2905 | 20.1k | if (val) { |
2906 | 6.51k | if (vsp >= 0) { |
2907 | 0 | gen_move(s, vsp, cursp(), 1); |
2908 | 0 | } |
2909 | 6.51k | pos = genjmp2_0(s, name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), val); |
2910 | 6.51k | } |
2911 | 13.6k | else { |
2912 | 13.6k | pos = genjmp2_0(s, name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), val); |
2913 | 13.6k | } |
2914 | 20.1k | codegen(s, tree->cdr->cdr->car, VAL); |
2915 | 20.1k | pop(); |
2916 | 20.1k | if (val && vsp >= 0) { |
2917 | 0 | gen_move(s, vsp, cursp(), 1); |
2918 | 0 | } |
2919 | 20.1k | if (nint(tree->car->car) == NODE_CALL) { |
2920 | 0 | if (callargs == CALL_MAXARGS) { |
2921 | 0 | pop(); |
2922 | 0 | genop_2(s, OP_ARYPUSH, cursp(), 1); |
2923 | 0 | } |
2924 | 0 | else { |
2925 | 0 | pop_n(callargs); |
2926 | 0 | callargs++; |
2927 | 0 | } |
2928 | 0 | pop(); |
2929 | 0 | idx = new_sym(s, attrsym(s, nsym(tree->car->cdr->cdr->car))); |
2930 | 0 | genop_3(s, OP_SEND, cursp(), idx, callargs); |
2931 | 0 | } |
2932 | 20.1k | else { |
2933 | 20.1k | gen_assignment(s, tree->car, NULL, cursp(), val); |
2934 | 20.1k | } |
2935 | 20.1k | dispatch(s, pos); |
2936 | 20.1k | goto exit; |
2937 | 20.1k | } |
2938 | 0 | codegen(s, tree->cdr->cdr->car, VAL); |
2939 | 0 | push(); pop(); |
2940 | 0 | pop(); pop(); |
2941 | |
|
2942 | 0 | if (len == 1 && name[0] == '+') { |
2943 | 0 | gen_addsub(s, OP_ADD, cursp()); |
2944 | 0 | } |
2945 | 0 | else if (len == 1 && name[0] == '-') { |
2946 | 0 | gen_addsub(s, OP_SUB, cursp()); |
2947 | 0 | } |
2948 | 0 | else if (len == 1 && name[0] == '*') { |
2949 | 0 | genop_1(s, OP_MUL, cursp()); |
2950 | 0 | } |
2951 | 0 | else if (len == 1 && name[0] == '/') { |
2952 | 0 | genop_1(s, OP_DIV, cursp()); |
2953 | 0 | } |
2954 | 0 | else if (len == 1 && name[0] == '<') { |
2955 | 0 | genop_1(s, OP_LT, cursp()); |
2956 | 0 | } |
2957 | 0 | else if (len == 2 && name[0] == '<' && name[1] == '=') { |
2958 | 0 | genop_1(s, OP_LE, cursp()); |
2959 | 0 | } |
2960 | 0 | else if (len == 1 && name[0] == '>') { |
2961 | 0 | genop_1(s, OP_GT, cursp()); |
2962 | 0 | } |
2963 | 0 | else if (len == 2 && name[0] == '>' && name[1] == '=') { |
2964 | 0 | genop_1(s, OP_GE, cursp()); |
2965 | 0 | } |
2966 | 0 | else { |
2967 | 0 | idx = new_sym(s, sym); |
2968 | 0 | genop_3(s, OP_SEND, cursp(), idx, 1); |
2969 | 0 | } |
2970 | 0 | if (callargs < 0) { |
2971 | 0 | gen_assignment(s, tree->car, NULL, cursp(), val); |
2972 | 0 | } |
2973 | 0 | else { |
2974 | 0 | if (val && vsp >= 0) { |
2975 | 0 | gen_move(s, vsp, cursp(), 0); |
2976 | 0 | } |
2977 | 0 | if (callargs == CALL_MAXARGS) { |
2978 | 0 | pop(); |
2979 | 0 | genop_2(s, OP_ARYPUSH, cursp(), 1); |
2980 | 0 | } |
2981 | 0 | else { |
2982 | 0 | pop_n(callargs); |
2983 | 0 | callargs++; |
2984 | 0 | } |
2985 | 0 | pop(); |
2986 | 0 | idx = new_sym(s, attrsym(s,nsym(tree->car->cdr->cdr->car))); |
2987 | 0 | genop_3(s, OP_SEND, cursp(), idx, callargs); |
2988 | 0 | } |
2989 | 0 | } |
2990 | 0 | break; |
2991 | | |
2992 | 0 | case NODE_SUPER: |
2993 | 0 | { |
2994 | 0 | codegen_scope *s2 = s; |
2995 | 0 | int lv = 0; |
2996 | 0 | int n = 0, nk = 0, st = 0; |
2997 | |
|
2998 | 0 | push(); |
2999 | 0 | while (!s2->mscope) { |
3000 | 0 | lv++; |
3001 | 0 | s2 = s2->prev; |
3002 | 0 | if (!s2) break; |
3003 | 0 | } |
3004 | 0 | if (tree) { |
3005 | 0 | node *args = tree->car; |
3006 | 0 | if (args) { |
3007 | 0 | st = n = gen_values(s, args, VAL, 14); |
3008 | 0 | if (n < 0) { |
3009 | 0 | st = 1; n = 15; |
3010 | 0 | push(); |
3011 | 0 | } |
3012 | 0 | } |
3013 | | /* keyword arguments */ |
3014 | 0 | if (tree->cdr->car) { |
3015 | 0 | nk = gen_hash(s, tree->cdr->car->cdr, VAL, 14); |
3016 | 0 | if (nk < 0) {st++; nk = 15;} |
3017 | 0 | else st += nk*2; |
3018 | 0 | n |= nk<<4; |
3019 | 0 | } |
3020 | | /* block arguments */ |
3021 | 0 | if (tree->cdr->cdr) { |
3022 | 0 | codegen(s, tree->cdr->cdr, VAL); |
3023 | 0 | } |
3024 | 0 | else if (s2) gen_blkmove(s, s2->ainfo, lv); |
3025 | 0 | else { |
3026 | 0 | genop_1(s, OP_LOADNIL, cursp()); |
3027 | 0 | push(); |
3028 | 0 | } |
3029 | 0 | } |
3030 | 0 | else { |
3031 | 0 | if (s2) gen_blkmove(s, s2->ainfo, lv); |
3032 | 0 | else { |
3033 | 0 | genop_1(s, OP_LOADNIL, cursp()); |
3034 | 0 | push(); |
3035 | 0 | } |
3036 | 0 | } |
3037 | 0 | st++; |
3038 | 0 | pop_n(st+1); |
3039 | 0 | genop_2(s, OP_SUPER, cursp(), n); |
3040 | 0 | if (val) push(); |
3041 | 0 | } |
3042 | 0 | break; |
3043 | | |
3044 | 0 | case NODE_ZSUPER: |
3045 | 0 | { |
3046 | 0 | codegen_scope *s2 = s; |
3047 | 0 | int lv = 0; |
3048 | 0 | uint16_t ainfo = 0; |
3049 | 0 | int n = CALL_MAXARGS; |
3050 | 0 | int sp = cursp(); |
3051 | |
|
3052 | 0 | push(); /* room for receiver */ |
3053 | 0 | while (!s2->mscope) { |
3054 | 0 | lv++; |
3055 | 0 | s2 = s2->prev; |
3056 | 0 | if (!s2) break; |
3057 | 0 | } |
3058 | 0 | if (s2 && s2->ainfo > 0) { |
3059 | 0 | ainfo = s2->ainfo; |
3060 | 0 | } |
3061 | 0 | if (ainfo > 0) { |
3062 | 0 | genop_2S(s, OP_ARGARY, cursp(), (ainfo<<4)|(lv & 0xf)); |
3063 | 0 | push(); push(); push(); /* ARGARY pushes 3 values at most */ |
3064 | 0 | pop(); pop(); pop(); |
3065 | | /* keyword arguments */ |
3066 | 0 | if (ainfo & 0x1) { |
3067 | 0 | n |= CALL_MAXARGS<<4; |
3068 | 0 | push(); |
3069 | 0 | } |
3070 | | /* block argument */ |
3071 | 0 | if (tree && tree->cdr && tree->cdr->cdr) { |
3072 | 0 | push(); |
3073 | 0 | codegen(s, tree->cdr->cdr, VAL); |
3074 | 0 | } |
3075 | 0 | } |
3076 | 0 | else { |
3077 | | /* block argument */ |
3078 | 0 | if (tree && tree->cdr && tree->cdr->cdr) { |
3079 | 0 | codegen(s, tree->cdr->cdr, VAL); |
3080 | 0 | } |
3081 | 0 | else { |
3082 | 0 | gen_blkmove(s, 0, lv); |
3083 | 0 | } |
3084 | 0 | n = 0; |
3085 | 0 | } |
3086 | 0 | s->sp = sp; |
3087 | 0 | genop_2(s, OP_SUPER, cursp(), n); |
3088 | 0 | if (val) push(); |
3089 | 0 | } |
3090 | 0 | break; |
3091 | | |
3092 | 0 | case NODE_RETURN: |
3093 | 0 | if (tree) { |
3094 | 0 | gen_retval(s, tree); |
3095 | 0 | } |
3096 | 0 | else { |
3097 | 0 | genop_1(s, OP_LOADNIL, cursp()); |
3098 | 0 | } |
3099 | 0 | if (s->loop) { |
3100 | 0 | gen_return(s, OP_RETURN_BLK, cursp()); |
3101 | 0 | } |
3102 | 0 | else { |
3103 | 0 | gen_return(s, OP_RETURN, cursp()); |
3104 | 0 | } |
3105 | 0 | if (val) push(); |
3106 | 0 | break; |
3107 | | |
3108 | 0 | case NODE_YIELD: |
3109 | 0 | { |
3110 | 0 | codegen_scope *s2 = s; |
3111 | 0 | int lv = 0, ainfo = -1; |
3112 | 0 | int n = 0, sendv = 0; |
3113 | |
|
3114 | 0 | while (!s2->mscope) { |
3115 | 0 | lv++; |
3116 | 0 | s2 = s2->prev; |
3117 | 0 | if (!s2) break; |
3118 | 0 | } |
3119 | 0 | if (s2) { |
3120 | 0 | ainfo = (int)s2->ainfo; |
3121 | 0 | } |
3122 | 0 | if (ainfo < 0) codegen_error(s, "invalid yield (SyntaxError)"); |
3123 | 0 | push(); |
3124 | 0 | if (tree) { |
3125 | 0 | n = gen_values(s, tree, VAL, 14); |
3126 | 0 | if (n < 0) { |
3127 | 0 | n = sendv = 1; |
3128 | 0 | push(); |
3129 | 0 | } |
3130 | 0 | } |
3131 | 0 | push();pop(); /* space for a block */ |
3132 | 0 | pop_n(n+1); |
3133 | 0 | genop_2S(s, OP_BLKPUSH, cursp(), (ainfo<<4)|(lv & 0xf)); |
3134 | 0 | if (sendv) n = CALL_MAXARGS; |
3135 | 0 | genop_3(s, OP_SEND, cursp(), new_sym(s, MRB_SYM_2(s->mrb, call)), n); |
3136 | 0 | if (val) push(); |
3137 | 0 | } |
3138 | 0 | break; |
3139 | | |
3140 | 0 | case NODE_BREAK: |
3141 | 0 | loop_break(s, tree); |
3142 | 0 | if (val) push(); |
3143 | 0 | break; |
3144 | | |
3145 | 0 | case NODE_NEXT: |
3146 | 0 | if (!s->loop) { |
3147 | 0 | raise_error(s, "unexpected next"); |
3148 | 0 | } |
3149 | 0 | else if (s->loop->type == LOOP_NORMAL) { |
3150 | 0 | codegen(s, tree, NOVAL); |
3151 | 0 | genjmp(s, OP_JMPUW, s->loop->pc0); |
3152 | 0 | } |
3153 | 0 | else { |
3154 | 0 | if (tree) { |
3155 | 0 | codegen(s, tree, VAL); |
3156 | 0 | pop(); |
3157 | 0 | } |
3158 | 0 | else { |
3159 | 0 | genop_1(s, OP_LOADNIL, cursp()); |
3160 | 0 | } |
3161 | 0 | gen_return(s, OP_RETURN, cursp()); |
3162 | 0 | } |
3163 | 0 | if (val) push(); |
3164 | 0 | break; |
3165 | | |
3166 | 0 | case NODE_REDO: |
3167 | 0 | if (!s->loop || s->loop->type == LOOP_BEGIN || s->loop->type == LOOP_RESCUE) { |
3168 | 0 | raise_error(s, "unexpected redo"); |
3169 | 0 | } |
3170 | 0 | else { |
3171 | 0 | genjmp(s, OP_JMPUW, s->loop->pc1); |
3172 | 0 | } |
3173 | 0 | if (val) push(); |
3174 | 0 | break; |
3175 | | |
3176 | 0 | case NODE_RETRY: |
3177 | 0 | { |
3178 | 0 | const char *msg = "unexpected retry"; |
3179 | 0 | const struct loopinfo *lp = s->loop; |
3180 | |
|
3181 | 0 | while (lp && lp->type != LOOP_RESCUE) { |
3182 | 0 | lp = lp->prev; |
3183 | 0 | } |
3184 | 0 | if (!lp) { |
3185 | 0 | raise_error(s, msg); |
3186 | 0 | } |
3187 | 0 | else { |
3188 | 0 | genjmp(s, OP_JMPUW, lp->pc0); |
3189 | 0 | } |
3190 | 0 | if (val) push(); |
3191 | 0 | } |
3192 | 0 | break; |
3193 | | |
3194 | 57.3k | case NODE_LVAR: |
3195 | 57.3k | if (val) { |
3196 | 56.6k | int idx = lv_idx(s, nsym(tree)); |
3197 | | |
3198 | 56.6k | if (idx > 0) { |
3199 | 56.6k | gen_move(s, cursp(), idx, val); |
3200 | 56.6k | } |
3201 | 0 | else { |
3202 | 0 | gen_getupvar(s, cursp(), nsym(tree)); |
3203 | 0 | } |
3204 | 56.6k | push(); |
3205 | 56.6k | } |
3206 | 57.3k | break; |
3207 | | |
3208 | 0 | case NODE_NVAR: |
3209 | 0 | if (val) { |
3210 | 0 | int idx = nint(tree); |
3211 | |
|
3212 | 0 | gen_move(s, cursp(), idx, val); |
3213 | |
|
3214 | 0 | push(); |
3215 | 0 | } |
3216 | 0 | break; |
3217 | | |
3218 | 0 | case NODE_GVAR: |
3219 | 0 | { |
3220 | 0 | int sym = new_sym(s, nsym(tree)); |
3221 | |
|
3222 | 0 | genop_2(s, OP_GETGV, cursp(), sym); |
3223 | 0 | if (val) push(); |
3224 | 0 | } |
3225 | 0 | break; |
3226 | | |
3227 | 20.1k | case NODE_IVAR: |
3228 | 20.1k | { |
3229 | 20.1k | int sym = new_sym(s, nsym(tree)); |
3230 | | |
3231 | 20.1k | genop_2(s, OP_GETIV, cursp(), sym); |
3232 | 20.1k | if (val) push(); |
3233 | 20.1k | } |
3234 | 20.1k | break; |
3235 | | |
3236 | 0 | case NODE_CVAR: |
3237 | 0 | { |
3238 | 0 | int sym = new_sym(s, nsym(tree)); |
3239 | |
|
3240 | 0 | genop_2(s, OP_GETCV, cursp(), sym); |
3241 | 0 | if (val) push(); |
3242 | 0 | } |
3243 | 0 | break; |
3244 | | |
3245 | 19.8k | case NODE_CONST: |
3246 | 19.8k | { |
3247 | 19.8k | int sym = new_sym(s, nsym(tree)); |
3248 | | |
3249 | 19.8k | genop_2(s, OP_GETCONST, cursp(), sym); |
3250 | 19.8k | if (val) push(); |
3251 | 19.8k | } |
3252 | 19.8k | break; |
3253 | | |
3254 | 0 | case NODE_BACK_REF: |
3255 | 0 | if (val) { |
3256 | 0 | char buf[] = {'$', nchar(tree)}; |
3257 | 0 | int sym = new_sym(s, mrb_intern(s->mrb, buf, sizeof(buf))); |
3258 | |
|
3259 | 0 | genop_2(s, OP_GETGV, cursp(), sym); |
3260 | 0 | push(); |
3261 | 0 | } |
3262 | 0 | break; |
3263 | | |
3264 | 0 | case NODE_NTH_REF: |
3265 | 0 | if (val) { |
3266 | 0 | mrb_state *mrb = s->mrb; |
3267 | 0 | mrb_value str; |
3268 | 0 | int sym; |
3269 | |
|
3270 | 0 | str = mrb_format(mrb, "$%d", nint(tree)); |
3271 | 0 | sym = new_sym(s, mrb_intern_str(mrb, str)); |
3272 | 0 | genop_2(s, OP_GETGV, cursp(), sym); |
3273 | 0 | push(); |
3274 | 0 | } |
3275 | 0 | break; |
3276 | | |
3277 | 0 | case NODE_ARG: |
3278 | | /* should not happen */ |
3279 | 0 | break; |
3280 | | |
3281 | 0 | case NODE_BLOCK_ARG: |
3282 | 0 | if (!tree) { |
3283 | 0 | int idx = lv_idx(s, MRB_OPSYM_2(s->mrb, and)); |
3284 | |
|
3285 | 0 | if (idx == 0) { |
3286 | 0 | gen_getupvar(s, cursp(), MRB_OPSYM_2(s->mrb, and)); |
3287 | 0 | } |
3288 | 0 | else { |
3289 | 0 | gen_move(s, cursp(), idx, val); |
3290 | 0 | } |
3291 | 0 | if (val) push(); |
3292 | 0 | } |
3293 | 0 | else { |
3294 | 0 | codegen(s, tree, val); |
3295 | 0 | } |
3296 | 0 | break; |
3297 | | |
3298 | 598k | case NODE_INT: |
3299 | 598k | if (val) { |
3300 | 575k | char *p = (char*)tree->car; |
3301 | 575k | int base = nint(tree->cdr->car); |
3302 | 575k | mrb_int i; |
3303 | 575k | mrb_bool overflow; |
3304 | | |
3305 | 575k | i = readint(s, p, base, FALSE, &overflow); |
3306 | 575k | if (overflow) { |
3307 | 0 | int off = new_litbint(s, p, base, FALSE); |
3308 | 0 | genop_2(s, OP_LOADL, cursp(), off); |
3309 | 0 | } |
3310 | 575k | else { |
3311 | 575k | gen_int(s, cursp(), i); |
3312 | 575k | } |
3313 | 575k | push(); |
3314 | 575k | } |
3315 | 598k | break; |
3316 | | |
3317 | 0 | #ifndef MRB_NO_FLOAT |
3318 | 0 | case NODE_FLOAT: |
3319 | 0 | if (val) { |
3320 | 0 | char *p = (char*)tree; |
3321 | 0 | double f; |
3322 | 0 | mrb_read_float(p, NULL, &f); |
3323 | 0 | int off = new_lit_float(s, (mrb_float)f); |
3324 | |
|
3325 | 0 | genop_2(s, OP_LOADL, cursp(), off); |
3326 | 0 | push(); |
3327 | 0 | } |
3328 | 0 | break; |
3329 | 0 | #endif |
3330 | | |
3331 | 0 | case NODE_NEGATE: |
3332 | 0 | { |
3333 | 0 | nt = nint(tree->car); |
3334 | 0 | switch (nt) { |
3335 | 0 | #ifndef MRB_NO_FLOAT |
3336 | 0 | case NODE_FLOAT: |
3337 | 0 | if (val) { |
3338 | 0 | char *p = (char*)tree->cdr; |
3339 | 0 | double f; |
3340 | 0 | mrb_read_float(p, NULL, &f); |
3341 | 0 | int off = new_lit_float(s, (mrb_float)-f); |
3342 | |
|
3343 | 0 | genop_2(s, OP_LOADL, cursp(), off); |
3344 | 0 | push(); |
3345 | 0 | } |
3346 | 0 | break; |
3347 | 0 | #endif |
3348 | | |
3349 | 0 | case NODE_INT: |
3350 | 0 | if (val) { |
3351 | 0 | char *p = (char*)tree->cdr->car; |
3352 | 0 | int base = nint(tree->cdr->cdr->car); |
3353 | 0 | mrb_int i; |
3354 | 0 | mrb_bool overflow; |
3355 | |
|
3356 | 0 | i = readint(s, p, base, TRUE, &overflow); |
3357 | 0 | if (overflow) { |
3358 | 0 | int off = new_litbint(s, p, base, TRUE); |
3359 | 0 | genop_2(s, OP_LOADL, cursp(), off); |
3360 | 0 | } |
3361 | 0 | else { |
3362 | 0 | gen_int(s, cursp(), i); |
3363 | 0 | } |
3364 | 0 | push(); |
3365 | 0 | } |
3366 | 0 | break; |
3367 | | |
3368 | 0 | default: |
3369 | 0 | if (val) { |
3370 | 0 | codegen(s, tree, VAL); |
3371 | 0 | pop(); |
3372 | 0 | push_n(2);pop_n(2); /* space for receiver&block */ |
3373 | 0 | mrb_sym minus = MRB_OPSYM_2(s->mrb, minus); |
3374 | 0 | if (!gen_uniop(s, minus, cursp())) { |
3375 | 0 | genop_3(s, OP_SEND, cursp(), new_sym(s, minus), 0); |
3376 | 0 | } |
3377 | 0 | push(); |
3378 | 0 | } |
3379 | 0 | else { |
3380 | 0 | codegen(s, tree, NOVAL); |
3381 | 0 | } |
3382 | 0 | break; |
3383 | 0 | } |
3384 | 0 | } |
3385 | 0 | break; |
3386 | | |
3387 | 327k | case NODE_STR: |
3388 | 327k | if (val) { |
3389 | 327k | char *p = (char*)tree->car; |
3390 | 327k | mrb_int len = nint(tree->cdr); |
3391 | 327k | int off = new_lit_str(s, p, len); |
3392 | | |
3393 | 327k | genop_2(s, OP_STRING, cursp(), off); |
3394 | 327k | push(); |
3395 | 327k | } |
3396 | 327k | break; |
3397 | | |
3398 | 0 | case NODE_HEREDOC: |
3399 | 0 | tree = ((struct mrb_parser_heredoc_info*)tree)->doc; |
3400 | | /* fall through */ |
3401 | 0 | case NODE_DSTR: |
3402 | 0 | if (val) { |
3403 | 0 | node *n = tree; |
3404 | |
|
3405 | 0 | if (!n) { |
3406 | 0 | genop_1(s, OP_LOADNIL, cursp()); |
3407 | 0 | push(); |
3408 | 0 | break; |
3409 | 0 | } |
3410 | 0 | codegen(s, n->car, VAL); |
3411 | 0 | n = n->cdr; |
3412 | 0 | while (n) { |
3413 | 0 | codegen(s, n->car, VAL); |
3414 | 0 | pop(); pop(); |
3415 | 0 | genop_1(s, OP_STRCAT, cursp()); |
3416 | 0 | push(); |
3417 | 0 | n = n->cdr; |
3418 | 0 | } |
3419 | 0 | } |
3420 | 0 | else { |
3421 | 0 | node *n = tree; |
3422 | |
|
3423 | 0 | while (n) { |
3424 | 0 | if (nint(n->car->car) != NODE_STR) { |
3425 | 0 | codegen(s, n->car, NOVAL); |
3426 | 0 | } |
3427 | 0 | n = n->cdr; |
3428 | 0 | } |
3429 | 0 | } |
3430 | 0 | break; |
3431 | | |
3432 | 0 | case NODE_WORDS: |
3433 | 0 | gen_literal_array(s, tree, FALSE, val); |
3434 | 0 | break; |
3435 | | |
3436 | 0 | case NODE_SYMBOLS: |
3437 | 0 | gen_literal_array(s, tree, TRUE, val); |
3438 | 0 | break; |
3439 | | |
3440 | 0 | case NODE_DXSTR: |
3441 | 0 | { |
3442 | 0 | node *n; |
3443 | 0 | int sym = new_sym(s, MRB_SYM_2(s->mrb, Kernel)); |
3444 | |
|
3445 | 0 | genop_1(s, OP_LOADSELF, cursp()); |
3446 | 0 | push(); |
3447 | 0 | codegen(s, tree->car, VAL); |
3448 | 0 | n = tree->cdr; |
3449 | 0 | while (n) { |
3450 | 0 | if (nint(n->car->car) == NODE_XSTR) { |
3451 | 0 | n->car->car = (struct mrb_ast_node*)(intptr_t)NODE_STR; |
3452 | 0 | mrb_assert(!n->cdr); /* must be the end */ |
3453 | 0 | } |
3454 | 0 | codegen(s, n->car, VAL); |
3455 | 0 | pop(); pop(); |
3456 | 0 | genop_1(s, OP_STRCAT, cursp()); |
3457 | 0 | push(); |
3458 | 0 | n = n->cdr; |
3459 | 0 | } |
3460 | 0 | push(); /* for block */ |
3461 | 0 | pop_n(3); |
3462 | 0 | sym = new_sym(s, MRB_OPSYM_2(s->mrb, tick)); /* ` */ |
3463 | 0 | genop_3(s, OP_SEND, cursp(), sym, 1); |
3464 | 0 | if (val) push(); |
3465 | 0 | } |
3466 | 0 | break; |
3467 | | |
3468 | 0 | case NODE_XSTR: |
3469 | 0 | { |
3470 | 0 | char *p = (char*)tree->car; |
3471 | 0 | mrb_int len = nint(tree->cdr); |
3472 | 0 | int off = new_lit_str(s, p, len); |
3473 | 0 | int sym; |
3474 | |
|
3475 | 0 | genop_1(s, OP_LOADSELF, cursp()); |
3476 | 0 | push(); |
3477 | 0 | genop_2(s, OP_STRING, cursp(), off); |
3478 | 0 | push(); push(); |
3479 | 0 | pop_n(3); |
3480 | 0 | sym = new_sym(s, MRB_OPSYM_2(s->mrb, tick)); /* ` */ |
3481 | 0 | genop_3(s, OP_SEND, cursp(), sym, 1); |
3482 | 0 | if (val) push(); |
3483 | 0 | } |
3484 | 0 | break; |
3485 | | |
3486 | 0 | case NODE_REGX: |
3487 | 0 | if (val) { |
3488 | 0 | char *p1 = (char*)tree->car; |
3489 | 0 | char *p2 = (char*)tree->cdr->car; |
3490 | 0 | char *p3 = (char*)tree->cdr->cdr; |
3491 | 0 | int sym = new_sym(s, mrb_intern_lit(s->mrb, REGEXP_CLASS)); |
3492 | 0 | int off = new_lit_cstr(s, p1); |
3493 | 0 | int argc = 1; |
3494 | |
|
3495 | 0 | genop_1(s, OP_OCLASS, cursp()); |
3496 | 0 | genop_2(s, OP_GETMCNST, cursp(), sym); |
3497 | 0 | push(); |
3498 | 0 | genop_2(s, OP_STRING, cursp(), off); |
3499 | 0 | push(); |
3500 | 0 | if (p2 || p3) { |
3501 | 0 | if (p2) { /* opt */ |
3502 | 0 | off = new_lit_cstr(s, p2); |
3503 | 0 | genop_2(s, OP_STRING, cursp(), off); |
3504 | 0 | } |
3505 | 0 | else { |
3506 | 0 | genop_1(s, OP_LOADNIL, cursp()); |
3507 | 0 | } |
3508 | 0 | push(); |
3509 | 0 | argc++; |
3510 | 0 | if (p3) { /* enc */ |
3511 | 0 | off = new_lit_str(s, p3, 1); |
3512 | 0 | genop_2(s, OP_STRING, cursp(), off); |
3513 | 0 | push(); |
3514 | 0 | argc++; |
3515 | 0 | } |
3516 | 0 | } |
3517 | 0 | push(); /* space for a block */ |
3518 | 0 | pop_n(argc+2); |
3519 | 0 | sym = new_sym(s, MRB_SYM_2(s->mrb, compile)); |
3520 | 0 | genop_3(s, OP_SEND, cursp(), sym, argc); |
3521 | 0 | push(); |
3522 | 0 | } |
3523 | 0 | break; |
3524 | | |
3525 | 0 | case NODE_DREGX: |
3526 | 0 | if (val) { |
3527 | 0 | node *n = tree->car; |
3528 | 0 | int sym = new_sym(s, mrb_intern_lit(s->mrb, REGEXP_CLASS)); |
3529 | 0 | int argc = 1; |
3530 | 0 | int off; |
3531 | 0 | char *p; |
3532 | |
|
3533 | 0 | genop_1(s, OP_OCLASS, cursp()); |
3534 | 0 | genop_2(s, OP_GETMCNST, cursp(), sym); |
3535 | 0 | push(); |
3536 | 0 | codegen(s, n->car, VAL); |
3537 | 0 | n = n->cdr; |
3538 | 0 | while (n) { |
3539 | 0 | codegen(s, n->car, VAL); |
3540 | 0 | pop(); pop(); |
3541 | 0 | genop_1(s, OP_STRCAT, cursp()); |
3542 | 0 | push(); |
3543 | 0 | n = n->cdr; |
3544 | 0 | } |
3545 | 0 | n = tree->cdr->cdr; |
3546 | 0 | if (n->car) { /* tail */ |
3547 | 0 | p = (char*)n->car; |
3548 | 0 | off = new_lit_cstr(s, p); |
3549 | 0 | codegen(s, tree->car, VAL); |
3550 | 0 | genop_2(s, OP_STRING, cursp(), off); |
3551 | 0 | pop(); |
3552 | 0 | genop_1(s, OP_STRCAT, cursp()); |
3553 | 0 | push(); |
3554 | 0 | } |
3555 | 0 | if (n->cdr->car) { /* opt */ |
3556 | 0 | char *p2 = (char*)n->cdr->car; |
3557 | 0 | off = new_lit_cstr(s, p2); |
3558 | 0 | genop_2(s, OP_STRING, cursp(), off); |
3559 | 0 | push(); |
3560 | 0 | argc++; |
3561 | 0 | } |
3562 | 0 | if (n->cdr->cdr) { /* enc */ |
3563 | 0 | char *p2 = (char*)n->cdr->cdr; |
3564 | 0 | off = new_lit_cstr(s, p2); |
3565 | 0 | genop_2(s, OP_STRING, cursp(), off); |
3566 | 0 | push(); |
3567 | 0 | argc++; |
3568 | 0 | } |
3569 | 0 | push(); /* space for a block */ |
3570 | 0 | pop_n(argc+2); |
3571 | 0 | sym = new_sym(s, MRB_SYM_2(s->mrb, compile)); |
3572 | 0 | genop_3(s, OP_SEND, cursp(), sym, argc); |
3573 | 0 | push(); |
3574 | 0 | } |
3575 | 0 | else { |
3576 | 0 | node *n = tree->car; |
3577 | |
|
3578 | 0 | while (n) { |
3579 | 0 | if (nint(n->car->car) != NODE_STR) { |
3580 | 0 | codegen(s, n->car, NOVAL); |
3581 | 0 | } |
3582 | 0 | n = n->cdr; |
3583 | 0 | } |
3584 | 0 | } |
3585 | 0 | break; |
3586 | | |
3587 | 0 | case NODE_SYM: |
3588 | 0 | if (val) { |
3589 | 0 | int sym = new_sym(s, nsym(tree)); |
3590 | |
|
3591 | 0 | genop_2(s, OP_LOADSYM, cursp(), sym); |
3592 | 0 | push(); |
3593 | 0 | } |
3594 | 0 | break; |
3595 | | |
3596 | 0 | case NODE_DSYM: |
3597 | 0 | codegen(s, tree, val); |
3598 | 0 | if (val) { |
3599 | 0 | gen_intern(s); |
3600 | 0 | } |
3601 | 0 | break; |
3602 | | |
3603 | 0 | case NODE_SELF: |
3604 | 0 | if (val) { |
3605 | 0 | genop_1(s, OP_LOADSELF, cursp()); |
3606 | 0 | push(); |
3607 | 0 | } |
3608 | 0 | break; |
3609 | | |
3610 | 0 | case NODE_NIL: |
3611 | 0 | if (val) { |
3612 | 0 | genop_1(s, OP_LOADNIL, cursp()); |
3613 | 0 | push(); |
3614 | 0 | } |
3615 | 0 | break; |
3616 | | |
3617 | 0 | case NODE_TRUE: |
3618 | 0 | if (val) { |
3619 | 0 | genop_1(s, OP_LOADT, cursp()); |
3620 | 0 | push(); |
3621 | 0 | } |
3622 | 0 | break; |
3623 | | |
3624 | 0 | case NODE_FALSE: |
3625 | 0 | if (val) { |
3626 | 0 | genop_1(s, OP_LOADF, cursp()); |
3627 | 0 | push(); |
3628 | 0 | } |
3629 | 0 | break; |
3630 | | |
3631 | 0 | case NODE_ALIAS: |
3632 | 0 | { |
3633 | 0 | int a = new_sym(s, nsym(tree->car)); |
3634 | 0 | int b = new_sym(s, nsym(tree->cdr)); |
3635 | |
|
3636 | 0 | genop_2(s, OP_ALIAS, a, b); |
3637 | 0 | if (val) { |
3638 | 0 | genop_1(s, OP_LOADNIL, cursp()); |
3639 | 0 | push(); |
3640 | 0 | } |
3641 | 0 | } |
3642 | 0 | break; |
3643 | | |
3644 | 0 | case NODE_UNDEF: |
3645 | 0 | { |
3646 | 0 | node *t = tree; |
3647 | |
|
3648 | 0 | while (t) { |
3649 | 0 | int symbol = new_sym(s, nsym(t->car)); |
3650 | 0 | genop_1(s, OP_UNDEF, symbol); |
3651 | 0 | t = t->cdr; |
3652 | 0 | } |
3653 | 0 | if (val) { |
3654 | 0 | genop_1(s, OP_LOADNIL, cursp()); |
3655 | 0 | push(); |
3656 | 0 | } |
3657 | 0 | } |
3658 | 0 | break; |
3659 | | |
3660 | 0 | case NODE_CLASS: |
3661 | 0 | { |
3662 | 0 | int idx; |
3663 | 0 | node *body; |
3664 | |
|
3665 | 0 | if (tree->car->car == (node*)0) { |
3666 | 0 | genop_1(s, OP_LOADNIL, cursp()); |
3667 | 0 | push(); |
3668 | 0 | } |
3669 | 0 | else if (tree->car->car == (node*)1) { |
3670 | 0 | genop_1(s, OP_OCLASS, cursp()); |
3671 | 0 | push(); |
3672 | 0 | } |
3673 | 0 | else { |
3674 | 0 | codegen(s, tree->car->car, VAL); |
3675 | 0 | } |
3676 | 0 | if (tree->cdr->car) { |
3677 | 0 | codegen(s, tree->cdr->car, VAL); |
3678 | 0 | } |
3679 | 0 | else { |
3680 | 0 | genop_1(s, OP_LOADNIL, cursp()); |
3681 | 0 | push(); |
3682 | 0 | } |
3683 | 0 | pop(); pop(); |
3684 | 0 | idx = new_sym(s, nsym(tree->car->cdr)); |
3685 | 0 | genop_2(s, OP_CLASS, cursp(), idx); |
3686 | 0 | body = tree->cdr->cdr->car; |
3687 | 0 | if (nint(body->cdr->car) == NODE_BEGIN && body->cdr->cdr == NULL) { |
3688 | 0 | genop_1(s, OP_LOADNIL, cursp()); |
3689 | 0 | } |
3690 | 0 | else { |
3691 | 0 | idx = scope_body(s, body, val); |
3692 | 0 | genop_2(s, OP_EXEC, cursp(), idx); |
3693 | 0 | } |
3694 | 0 | if (val) { |
3695 | 0 | push(); |
3696 | 0 | } |
3697 | 0 | } |
3698 | 0 | break; |
3699 | | |
3700 | 0 | case NODE_MODULE: |
3701 | 0 | { |
3702 | 0 | int idx; |
3703 | |
|
3704 | 0 | if (tree->car->car == (node*)0) { |
3705 | 0 | genop_1(s, OP_LOADNIL, cursp()); |
3706 | 0 | push(); |
3707 | 0 | } |
3708 | 0 | else if (tree->car->car == (node*)1) { |
3709 | 0 | genop_1(s, OP_OCLASS, cursp()); |
3710 | 0 | push(); |
3711 | 0 | } |
3712 | 0 | else { |
3713 | 0 | codegen(s, tree->car->car, VAL); |
3714 | 0 | } |
3715 | 0 | pop(); |
3716 | 0 | idx = new_sym(s, nsym(tree->car->cdr)); |
3717 | 0 | genop_2(s, OP_MODULE, cursp(), idx); |
3718 | 0 | if (nint(tree->cdr->car->cdr->car) == NODE_BEGIN && |
3719 | 0 | tree->cdr->car->cdr->cdr == NULL) { |
3720 | 0 | genop_1(s, OP_LOADNIL, cursp()); |
3721 | 0 | } |
3722 | 0 | else { |
3723 | 0 | idx = scope_body(s, tree->cdr->car, val); |
3724 | 0 | genop_2(s, OP_EXEC, cursp(), idx); |
3725 | 0 | } |
3726 | 0 | if (val) { |
3727 | 0 | push(); |
3728 | 0 | } |
3729 | 0 | } |
3730 | 0 | break; |
3731 | | |
3732 | 0 | case NODE_SCLASS: |
3733 | 0 | { |
3734 | 0 | int idx; |
3735 | |
|
3736 | 0 | codegen(s, tree->car, VAL); |
3737 | 0 | pop(); |
3738 | 0 | genop_1(s, OP_SCLASS, cursp()); |
3739 | 0 | if (nint(tree->cdr->car->cdr->car) == NODE_BEGIN && |
3740 | 0 | tree->cdr->car->cdr->cdr == NULL) { |
3741 | 0 | genop_1(s, OP_LOADNIL, cursp()); |
3742 | 0 | } |
3743 | 0 | else { |
3744 | 0 | idx = scope_body(s, tree->cdr->car, val); |
3745 | 0 | genop_2(s, OP_EXEC, cursp(), idx); |
3746 | 0 | } |
3747 | 0 | if (val) { |
3748 | 0 | push(); |
3749 | 0 | } |
3750 | 0 | } |
3751 | 0 | break; |
3752 | | |
3753 | 466 | case NODE_DEF: |
3754 | 466 | { |
3755 | 466 | int sym = new_sym(s, nsym(tree->car)); |
3756 | 466 | int idx = lambda_body(s, tree->cdr, 0); |
3757 | | |
3758 | 466 | genop_1(s, OP_TCLASS, cursp()); |
3759 | 466 | push(); |
3760 | 466 | genop_2(s, OP_METHOD, cursp(), idx); |
3761 | 466 | push(); pop(); |
3762 | 466 | pop(); |
3763 | 466 | genop_2(s, OP_DEF, cursp(), sym); |
3764 | 466 | if (val) push(); |
3765 | 466 | } |
3766 | 466 | break; |
3767 | | |
3768 | 0 | case NODE_SDEF: |
3769 | 0 | { |
3770 | 0 | node *recv = tree->car; |
3771 | 0 | int sym = new_sym(s, nsym(tree->cdr->car)); |
3772 | 0 | int idx = lambda_body(s, tree->cdr->cdr, 0); |
3773 | |
|
3774 | 0 | codegen(s, recv, VAL); |
3775 | 0 | pop(); |
3776 | 0 | genop_1(s, OP_SCLASS, cursp()); |
3777 | 0 | push(); |
3778 | 0 | genop_2(s, OP_METHOD, cursp(), idx); |
3779 | 0 | push(); pop(); |
3780 | 0 | pop(); |
3781 | 0 | genop_2(s, OP_DEF, cursp(), sym); |
3782 | 0 | if (val) push(); |
3783 | 0 | } |
3784 | 0 | break; |
3785 | | |
3786 | 0 | case NODE_POSTEXE: |
3787 | 0 | codegen(s, tree, NOVAL); |
3788 | 0 | break; |
3789 | | |
3790 | 0 | default: |
3791 | 0 | break; |
3792 | 1.58M | } |
3793 | 1.58M | exit: |
3794 | 1.58M | s->rlev = rlev; |
3795 | 1.58M | } |
3796 | | |
3797 | | static void |
3798 | | scope_add_irep(codegen_scope *s) |
3799 | 932 | { |
3800 | 932 | mrb_irep *irep; |
3801 | 932 | codegen_scope *prev = s->prev; |
3802 | | |
3803 | 932 | if (prev->irep == NULL) { |
3804 | 466 | irep = mrb_add_irep(s->mrb); |
3805 | 466 | prev->irep = s->irep = irep; |
3806 | 466 | return; |
3807 | 466 | } |
3808 | 466 | else { |
3809 | 466 | if (prev->irep->rlen == UINT16_MAX) { |
3810 | 0 | codegen_error(s, "too many nested blocks/methods"); |
3811 | 0 | } |
3812 | 466 | s->irep = irep = mrb_add_irep(s->mrb); |
3813 | 466 | if (prev->irep->rlen == prev->rcapa) { |
3814 | 0 | prev->rcapa *= 2; |
3815 | 0 | prev->reps = (mrb_irep**)codegen_realloc(s, prev->reps, sizeof(mrb_irep*)*prev->rcapa); |
3816 | 0 | } |
3817 | 466 | prev->reps[prev->irep->rlen] = irep; |
3818 | 466 | prev->irep->rlen++; |
3819 | 466 | } |
3820 | 932 | } |
3821 | | |
3822 | | static codegen_scope* |
3823 | | scope_new(mrb_state *mrb, codegen_scope *prev, node *nlv) |
3824 | 1.39k | { |
3825 | 1.39k | static const codegen_scope codegen_scope_zero = { 0 }; |
3826 | 1.39k | mrb_pool *pool = mrb_pool_open(mrb); |
3827 | 1.39k | codegen_scope *s = (codegen_scope*)mrb_pool_alloc(pool, sizeof(codegen_scope)); |
3828 | | |
3829 | 1.39k | if (!s) { |
3830 | 0 | if (prev) |
3831 | 0 | codegen_error(prev, "unexpected scope"); |
3832 | 0 | return NULL; |
3833 | 0 | } |
3834 | 1.39k | *s = codegen_scope_zero; |
3835 | 1.39k | s->mrb = mrb; |
3836 | 1.39k | s->mpool = pool; |
3837 | 1.39k | if (!prev) return s; |
3838 | 932 | s->prev = prev; |
3839 | 932 | s->ainfo = 0; |
3840 | 932 | s->mscope = 0; |
3841 | | |
3842 | 932 | scope_add_irep(s); |
3843 | | |
3844 | 932 | s->rcapa = 8; |
3845 | 932 | s->reps = (mrb_irep**)mrb_malloc(mrb, sizeof(mrb_irep*)*s->rcapa); |
3846 | | |
3847 | 932 | s->icapa = 1024; |
3848 | 932 | s->iseq = (mrb_code*)mrb_malloc(mrb, sizeof(mrb_code)*s->icapa); |
3849 | | |
3850 | 932 | s->pcapa = 32; |
3851 | 932 | s->pool = (mrb_pool_value*)mrb_malloc(mrb, sizeof(mrb_pool_value)*s->pcapa); |
3852 | | |
3853 | 932 | s->scapa = 256; |
3854 | 932 | s->syms = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym)*s->scapa); |
3855 | | |
3856 | 932 | s->lv = nlv; |
3857 | 932 | s->sp += node_len(nlv)+1; /* add self */ |
3858 | 932 | s->nlocals = s->sp; |
3859 | 932 | if (nlv) { |
3860 | 466 | mrb_sym *lv; |
3861 | 466 | node *n = nlv; |
3862 | 466 | size_t i = 0; |
3863 | | |
3864 | 466 | s->irep->lv = lv = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym)*(s->nlocals-1)); |
3865 | 69.7k | for (i=0, n=nlv; n; i++,n=n->cdr) { |
3866 | 69.2k | lv[i] = lv_name(n); |
3867 | 69.2k | } |
3868 | 466 | mrb_assert(i + 1 == s->nlocals); |
3869 | 466 | } |
3870 | 932 | s->ai = mrb_gc_arena_save(mrb); |
3871 | | |
3872 | 932 | s->filename_sym = prev->filename_sym; |
3873 | 932 | if (s->filename_sym) { |
3874 | 0 | s->lines = (uint16_t*)mrb_malloc(mrb, sizeof(short)*s->icapa); |
3875 | 0 | } |
3876 | 932 | s->lineno = prev->lineno; |
3877 | | |
3878 | | /* debug setting */ |
3879 | 932 | s->debug_start_pos = 0; |
3880 | 932 | if (s->filename_sym) { |
3881 | 0 | mrb_debug_info_alloc(mrb, s->irep); |
3882 | 0 | } |
3883 | 932 | else { |
3884 | 932 | s->irep->debug_info = NULL; |
3885 | 932 | } |
3886 | 932 | s->parser = prev->parser; |
3887 | 932 | s->filename_index = prev->filename_index; |
3888 | | |
3889 | 932 | s->rlev = prev->rlev+1; |
3890 | | |
3891 | 932 | return s; |
3892 | 1.39k | } |
3893 | | |
3894 | | static void |
3895 | | scope_finish(codegen_scope *s) |
3896 | 845 | { |
3897 | 845 | mrb_state *mrb = s->mrb; |
3898 | 845 | mrb_irep *irep = s->irep; |
3899 | | |
3900 | 845 | if (s->nlocals > 0xff) { |
3901 | 57 | codegen_error(s, "too many local variables"); |
3902 | 57 | } |
3903 | 845 | irep->flags = 0; |
3904 | 845 | if (s->iseq) { |
3905 | 788 | size_t catchsize = sizeof(struct mrb_irep_catch_handler) * irep->clen; |
3906 | 788 | irep->iseq = (const mrb_code*)codegen_realloc(s, s->iseq, sizeof(mrb_code)*s->pc + catchsize); |
3907 | 788 | irep->ilen = s->pc; |
3908 | 788 | if (irep->clen > 0) { |
3909 | 0 | memcpy((void*)(irep->iseq + irep->ilen), s->catch_table, catchsize); |
3910 | 0 | } |
3911 | 788 | } |
3912 | 57 | else { |
3913 | 57 | irep->clen = 0; |
3914 | 57 | } |
3915 | 845 | mrb_free(s->mrb, s->catch_table); |
3916 | 845 | s->catch_table = NULL; |
3917 | 845 | irep->pool = (const mrb_pool_value*)codegen_realloc(s, s->pool, sizeof(mrb_pool_value)*irep->plen); |
3918 | 845 | irep->syms = (const mrb_sym*)codegen_realloc(s, s->syms, sizeof(mrb_sym)*irep->slen); |
3919 | 845 | irep->reps = (const mrb_irep**)codegen_realloc(s, s->reps, sizeof(mrb_irep*)*irep->rlen); |
3920 | 845 | if (s->filename_sym) { |
3921 | 0 | mrb_sym fname = mrb_parser_get_filename(s->parser, s->filename_index); |
3922 | 0 | const char *filename = mrb_sym_name_len(s->mrb, fname, NULL); |
3923 | |
|
3924 | 0 | mrb_debug_info_append_file(s->mrb, s->irep->debug_info, |
3925 | 0 | filename, s->lines, s->debug_start_pos, s->pc); |
3926 | 0 | } |
3927 | 845 | mrb_free(s->mrb, s->lines); |
3928 | | |
3929 | 845 | irep->nlocals = s->nlocals; |
3930 | 845 | irep->nregs = s->nregs; |
3931 | | |
3932 | 845 | mrb_gc_arena_restore(mrb, s->ai); |
3933 | 845 | mrb_pool_close(s->mpool); |
3934 | 845 | } |
3935 | | |
3936 | | static struct loopinfo* |
3937 | | loop_push(codegen_scope *s, enum looptype t) |
3938 | 0 | { |
3939 | 0 | struct loopinfo *p = (struct loopinfo*)codegen_palloc(s, sizeof(struct loopinfo)); |
3940 | |
|
3941 | 0 | p->type = t; |
3942 | 0 | p->pc0 = p->pc1 = p->pc2 = JMPLINK_START; |
3943 | 0 | p->prev = s->loop; |
3944 | 0 | p->reg = cursp(); |
3945 | 0 | s->loop = p; |
3946 | |
|
3947 | 0 | return p; |
3948 | 0 | } |
3949 | | |
3950 | | static void |
3951 | | loop_break(codegen_scope *s, node *tree) |
3952 | 0 | { |
3953 | 0 | if (!s->loop) { |
3954 | 0 | codegen(s, tree, NOVAL); |
3955 | 0 | raise_error(s, "unexpected break"); |
3956 | 0 | } |
3957 | 0 | else { |
3958 | 0 | struct loopinfo *loop; |
3959 | | |
3960 | |
|
3961 | 0 | loop = s->loop; |
3962 | 0 | if (tree) { |
3963 | 0 | if (loop->reg < 0) { |
3964 | 0 | codegen(s, tree, NOVAL); |
3965 | 0 | } |
3966 | 0 | else { |
3967 | 0 | gen_retval(s, tree); |
3968 | 0 | } |
3969 | 0 | } |
3970 | 0 | while (loop) { |
3971 | 0 | if (loop->type == LOOP_BEGIN) { |
3972 | 0 | loop = loop->prev; |
3973 | 0 | } |
3974 | 0 | else if (loop->type == LOOP_RESCUE) { |
3975 | 0 | loop = loop->prev; |
3976 | 0 | } |
3977 | 0 | else{ |
3978 | 0 | break; |
3979 | 0 | } |
3980 | 0 | } |
3981 | 0 | if (!loop) { |
3982 | 0 | raise_error(s, "unexpected break"); |
3983 | 0 | return; |
3984 | 0 | } |
3985 | | |
3986 | 0 | if (loop->type == LOOP_NORMAL) { |
3987 | 0 | int tmp; |
3988 | |
|
3989 | 0 | if (loop->reg >= 0) { |
3990 | 0 | if (tree) { |
3991 | 0 | gen_move(s, loop->reg, cursp(), 0); |
3992 | 0 | } |
3993 | 0 | else { |
3994 | 0 | genop_1(s, OP_LOADNIL, loop->reg); |
3995 | 0 | } |
3996 | 0 | } |
3997 | 0 | tmp = genjmp(s, OP_JMPUW, loop->pc2); |
3998 | 0 | loop->pc2 = tmp; |
3999 | 0 | } |
4000 | 0 | else { |
4001 | 0 | if (!tree) { |
4002 | 0 | genop_1(s, OP_LOADNIL, cursp()); |
4003 | 0 | } |
4004 | 0 | gen_return(s, OP_BREAK, cursp()); |
4005 | 0 | } |
4006 | 0 | } |
4007 | 0 | } |
4008 | | |
4009 | | static void |
4010 | | loop_pop(codegen_scope *s, int val) |
4011 | 0 | { |
4012 | 0 | if (val) { |
4013 | 0 | genop_1(s, OP_LOADNIL, cursp()); |
4014 | 0 | } |
4015 | 0 | dispatch_linked(s, s->loop->pc2); |
4016 | 0 | s->loop = s->loop->prev; |
4017 | 0 | if (val) push(); |
4018 | 0 | } |
4019 | | |
4020 | | static int |
4021 | | catch_handler_new(codegen_scope *s) |
4022 | 0 | { |
4023 | 0 | size_t newsize = sizeof(struct mrb_irep_catch_handler) * (s->irep->clen + 1); |
4024 | 0 | s->catch_table = (struct mrb_irep_catch_handler*)codegen_realloc(s, (void*)s->catch_table, newsize); |
4025 | 0 | return s->irep->clen++; |
4026 | 0 | } |
4027 | | |
4028 | | static void |
4029 | | catch_handler_set(codegen_scope *s, int ent, enum mrb_catch_type type, uint32_t begin, uint32_t end, uint32_t target) |
4030 | 0 | { |
4031 | 0 | struct mrb_irep_catch_handler *e; |
4032 | |
|
4033 | 0 | mrb_assert(ent >= 0 && ent < s->irep->clen); |
4034 | |
|
4035 | 0 | e = &s->catch_table[ent]; |
4036 | 0 | uint8_to_bin(type, &e->type); |
4037 | 0 | mrb_irep_catch_handler_pack(begin, e->begin); |
4038 | 0 | mrb_irep_catch_handler_pack(end, e->end); |
4039 | 0 | mrb_irep_catch_handler_pack(target, e->target); |
4040 | 0 | } |
4041 | | |
4042 | | static struct RProc* |
4043 | | generate_code(mrb_state *mrb, parser_state *p, int val) |
4044 | 466 | { |
4045 | 466 | codegen_scope *scope = scope_new(mrb, 0, 0); |
4046 | 466 | struct mrb_jmpbuf *prev_jmp = mrb->jmp; |
4047 | 466 | struct mrb_jmpbuf jmpbuf; |
4048 | 466 | struct RProc *proc; |
4049 | | |
4050 | 466 | mrb->jmp = &jmpbuf; |
4051 | | |
4052 | 466 | scope->mrb = mrb; |
4053 | 466 | scope->parser = p; |
4054 | 466 | scope->filename_sym = p->filename_sym; |
4055 | 466 | scope->filename_index = p->current_filename_index; |
4056 | | |
4057 | 466 | MRB_TRY(mrb->jmp) { |
4058 | | /* prepare irep */ |
4059 | 466 | codegen(scope, p->tree, val); |
4060 | 466 | proc = mrb_proc_new(mrb, scope->irep); |
4061 | 466 | mrb_irep_decref(mrb, scope->irep); |
4062 | 466 | mrb_pool_close(scope->mpool); |
4063 | 466 | proc->c = NULL; |
4064 | 466 | if (mrb->c->cibase && mrb->c->cibase->proc == proc->upper) { |
4065 | 394 | proc->upper = NULL; |
4066 | 394 | } |
4067 | 466 | mrb->jmp = prev_jmp; |
4068 | 466 | return proc; |
4069 | 466 | } |
4070 | 466 | MRB_CATCH(mrb->jmp) { |
4071 | 0 | mrb_irep_decref(mrb, scope->irep); |
4072 | 0 | mrb_pool_close(scope->mpool); |
4073 | 0 | mrb->jmp = prev_jmp; |
4074 | 0 | return NULL; |
4075 | 0 | } |
4076 | 0 | MRB_END_EXC(mrb->jmp); |
4077 | 0 | } |
4078 | | |
4079 | | MRB_API struct RProc* |
4080 | | mrb_generate_code(mrb_state *mrb, parser_state *p) |
4081 | 466 | { |
4082 | 466 | return generate_code(mrb, p, VAL); |
4083 | 466 | } |
4084 | | |
4085 | | void |
4086 | | mrb_irep_remove_lv(mrb_state *mrb, mrb_irep *irep) |
4087 | 0 | { |
4088 | 0 | int i; |
4089 | |
|
4090 | 0 | if (irep->flags & MRB_IREP_NO_FREE) return; |
4091 | 0 | if (irep->lv) { |
4092 | 0 | mrb_free(mrb, (void*)irep->lv); |
4093 | 0 | irep->lv = NULL; |
4094 | 0 | } |
4095 | 0 | if (!irep->reps) return; |
4096 | 0 | for (i = 0; i < irep->rlen; i++) { |
4097 | 0 | mrb_irep_remove_lv(mrb, (mrb_irep*)irep->reps[i]); |
4098 | 0 | } |
4099 | 0 | } |