1 #include <mruby.h>
2 #include <mruby/irep.h>
3 #include <mruby/debug.h>
4 #include <mruby/opcode.h>
5 #include <mruby/string.h>
6 #include <mruby/proc.h>
7 
8 #ifndef MRB_DISABLE_STDIO
9 static void
print_r(mrb_state * mrb,mrb_irep * irep,size_t n)10 print_r(mrb_state *mrb, mrb_irep *irep, size_t n)
11 {
12   size_t i;
13 
14   if (n == 0) return;
15 
16   for (i=0; i+1<irep->nlocals; i++) {
17     if (irep->lv[i].r == n) {
18       mrb_sym sym = irep->lv[i].name;
19       printf(" R%d:%s", (int)n, mrb_sym2name(mrb, sym));
20       break;
21     }
22   }
23 }
24 
25 static void
print_lv_a(mrb_state * mrb,mrb_irep * irep,uint16_t a)26 print_lv_a(mrb_state *mrb, mrb_irep *irep, uint16_t a)
27 {
28   if (!irep->lv || a >= irep->nlocals || a == 0) {
29     printf("\n");
30     return;
31   }
32   printf("\t;");
33   print_r(mrb, irep, a);
34   printf("\n");
35 }
36 
37 static void
print_lv_ab(mrb_state * mrb,mrb_irep * irep,uint16_t a,uint16_t b)38 print_lv_ab(mrb_state *mrb, mrb_irep *irep, uint16_t a, uint16_t b)
39 {
40   if (!irep->lv || (a >= irep->nlocals && b >= irep->nlocals) || a+b == 0) {
41     printf("\n");
42     return;
43   }
44   printf("\t;");
45   if (a > 0) print_r(mrb, irep, a);
46   if (b > 0) print_r(mrb, irep, b);
47   printf("\n");
48 }
49 
50 static void
print_header(mrb_state * mrb,mrb_irep * irep,ptrdiff_t i)51 print_header(mrb_state *mrb, mrb_irep *irep, ptrdiff_t i)
52 {
53   int32_t line;
54 
55   line = mrb_debug_get_line(mrb, irep, i);
56   if (line < 0) {
57     printf("      ");
58   }
59   else {
60     printf("%5d ", line);
61   }
62 
63   printf("%03d ", (int)i);
64 }
65 
66 #define CASE(insn,ops) case insn: FETCH_ ## ops (); L_ ## insn
67 
68 static void
codedump(mrb_state * mrb,mrb_irep * irep)69 codedump(mrb_state *mrb, mrb_irep *irep)
70 {
71   int ai;
72   mrb_code *pc, *pcend;
73   mrb_code ins;
74   const char *file = NULL, *next_file;
75 
76   if (!irep) return;
77   printf("irep %p nregs=%d nlocals=%d pools=%d syms=%d reps=%d iseq=%d\n", (void*)irep,
78          irep->nregs, irep->nlocals, (int)irep->plen, (int)irep->slen, (int)irep->rlen, (int)irep->ilen);
79 
80   if (irep->lv) {
81     int i;
82 
83     printf("local variable names:\n");
84     for (i = 1; i < irep->nlocals; ++i) {
85       char const *s = mrb_sym2name(mrb, irep->lv[i - 1].name);
86       int n = irep->lv[i - 1].r ? irep->lv[i - 1].r : i;
87       printf("  R%d:%s\n", n, s ? s : "");
88     }
89   }
90 
91   pc = irep->iseq;
92   pcend = pc + irep->ilen;
93   while (pc < pcend) {
94     ptrdiff_t i;
95     uint32_t a;
96     uint16_t b;
97     uint8_t c;
98 
99     ai = mrb_gc_arena_save(mrb);
100 
101     i = pc - irep->iseq;
102     next_file = mrb_debug_get_filename(mrb, irep, i);
103     if (next_file && file != next_file) {
104       printf("file: %s\n", next_file);
105       file = next_file;
106     }
107     print_header(mrb, irep, i);
108     ins = READ_B();
109     switch (ins) {
110     CASE(OP_NOP, Z):
111       printf("OP_NOP\n");
112       break;
113     CASE(OP_MOVE, BB):
114       printf("OP_MOVE\tR%d\tR%d\t", a, b);
115       print_lv_ab(mrb, irep, a, b);
116       break;
117     CASE(OP_LOADL, BB):
118       {
119         mrb_value v = irep->pool[b];
120         mrb_value s = mrb_inspect(mrb, v);
121         printf("OP_LOADL\tR%d\tL(%d)\t; %s", a, b, RSTRING_PTR(s));
122       }
123       print_lv_a(mrb, irep, a);
124       break;
125     CASE(OP_LOADI, BB):
126       printf("OP_LOADI\tR%d\t%d\t", a, b);
127       print_lv_a(mrb, irep, a);
128       break;
129     CASE(OP_LOADINEG, BB):
130       printf("OP_LOADI\tR%d\t-%d\t", a, b);
131       print_lv_a(mrb, irep, a);
132       break;
133     CASE(OP_LOADI__1, B):
134       printf("OP_LOADI__1\tR%d\t\t", a);
135       print_lv_a(mrb, irep, a);
136       break;
137     CASE(OP_LOADI_0, B): goto L_LOADI;
138     CASE(OP_LOADI_1, B): goto L_LOADI;
139     CASE(OP_LOADI_2, B): goto L_LOADI;
140     CASE(OP_LOADI_3, B): goto L_LOADI;
141     CASE(OP_LOADI_4, B): goto L_LOADI;
142     CASE(OP_LOADI_5, B): goto L_LOADI;
143     CASE(OP_LOADI_6, B): goto L_LOADI;
144     CASE(OP_LOADI_7, B):
145     L_LOADI:
146       printf("OP_LOADI_%d\tR%d\t\t", ins-(int)OP_LOADI_0, a);
147       print_lv_a(mrb, irep, a);
148       break;
149     CASE(OP_LOADSYM, BB):
150       printf("OP_LOADSYM\tR%d\t:%s\t", a, mrb_sym2name(mrb, irep->syms[b]));
151       print_lv_a(mrb, irep, a);
152       break;
153     CASE(OP_LOADNIL, B):
154       printf("OP_LOADNIL\tR%d\t\t", a);
155       print_lv_a(mrb, irep, a);
156       break;
157     CASE(OP_LOADSELF, B):
158       printf("OP_LOADSELF\tR%d\t\t", a);
159       print_lv_a(mrb, irep, a);
160       break;
161     CASE(OP_LOADT, B):
162       printf("OP_LOADT\tR%d\t\t", a);
163       print_lv_a(mrb, irep, a);
164       break;
165     CASE(OP_LOADF, B):
166       printf("OP_LOADF\tR%d\t\t", a);
167       print_lv_a(mrb, irep, a);
168       break;
169     CASE(OP_GETGV, BB):
170       printf("OP_GETGV\tR%d\t:%s", a, mrb_sym2name(mrb, irep->syms[b]));
171       print_lv_a(mrb, irep, a);
172       break;
173     CASE(OP_SETGV, BB):
174       printf("OP_SETGV\t:%s\tR%d", mrb_sym2name(mrb, irep->syms[b]), a);
175       print_lv_a(mrb, irep, a);
176       break;
177     CASE(OP_GETSV, BB):
178       printf("OP_GETSV\tR%d\t:%s", a, mrb_sym2name(mrb, irep->syms[b]));
179       print_lv_a(mrb, irep, a);
180       break;
181     CASE(OP_SETSV, BB):
182       printf("OP_SETSV\t:%s\tR%d", mrb_sym2name(mrb, irep->syms[b]), a);
183       print_lv_a(mrb, irep, a);
184       break;
185     CASE(OP_GETCONST, BB):
186       printf("OP_GETCONST\tR%d\t:%s", a, mrb_sym2name(mrb, irep->syms[b]));
187       print_lv_a(mrb, irep, a);
188       break;
189     CASE(OP_SETCONST, BB):
190       printf("OP_SETCONST\t:%s\tR%d", mrb_sym2name(mrb, irep->syms[b]), a);
191       print_lv_a(mrb, irep, a);
192       break;
193     CASE(OP_GETMCNST, BB):
194       printf("OP_GETMCNST\tR%d\tR%d::%s", a, a, mrb_sym2name(mrb, irep->syms[b]));
195       print_lv_a(mrb, irep, a);
196       break;
197     CASE(OP_SETMCNST, BB):
198       printf("OP_SETMCNST\tR%d::%s\tR%d", a+1, mrb_sym2name(mrb, irep->syms[b]), a);
199       print_lv_a(mrb, irep, a);
200       break;
201     CASE(OP_GETIV, BB):
202       printf("OP_GETIV\tR%d\t%s", a, mrb_sym2name(mrb, irep->syms[b]));
203       print_lv_a(mrb, irep, a);
204       break;
205     CASE(OP_SETIV, BB):
206       printf("OP_SETIV\t%s\tR%d", mrb_sym2name(mrb, irep->syms[b]), a);
207       print_lv_a(mrb, irep, a);
208       break;
209     CASE(OP_GETUPVAR, BBB):
210       printf("OP_GETUPVAR\tR%d\t%d\t%d", a, b, c);
211       print_lv_a(mrb, irep, a);
212       break;
213     CASE(OP_SETUPVAR, BBB):
214       printf("OP_SETUPVAR\tR%d\t%d\t%d", a, b, c);
215       print_lv_a(mrb, irep, a);
216       break;
217     CASE(OP_GETCV, BB):
218       printf("OP_GETCV\tR%d\t%s", a, mrb_sym2name(mrb, irep->syms[b]));
219       print_lv_a(mrb, irep, a);
220       break;
221     CASE(OP_SETCV, BB):
222       printf("OP_SETCV\t%s\tR%d", mrb_sym2name(mrb, irep->syms[b]), a);
223       print_lv_a(mrb, irep, a);
224       break;
225     CASE(OP_JMP, S):
226       printf("OP_JMP\t\t%03d\n", a);
227       break;
228     CASE(OP_JMPIF, BS):
229       printf("OP_JMPIF\tR%d\t%03d\t", a, b);
230       print_lv_a(mrb, irep, a);
231       break;
232     CASE(OP_JMPNOT, BS):
233       printf("OP_JMPNOT\tR%d\t%03d\t", a, b);
234       print_lv_a(mrb, irep, a);
235       break;
236     CASE(OP_JMPNIL, BS):
237       printf("OP_JMPNIL\tR%d\t%03d\t", a, b);
238       print_lv_a(mrb, irep, a);
239       break;
240     CASE(OP_SENDV, BB):
241       printf("OP_SENDV\tR%d\t:%s\n", a, mrb_sym2name(mrb, irep->syms[b]));
242       break;
243     CASE(OP_SENDVB, BB):
244       printf("OP_SENDVB\tR%d\t:%s\n", a, mrb_sym2name(mrb, irep->syms[b]));
245       break;
246     CASE(OP_SEND, BBB):
247       printf("OP_SEND\tR%d\t:%s\t%d\n", a, mrb_sym2name(mrb, irep->syms[b]), c);
248       break;
249     CASE(OP_SENDB, BBB):
250       printf("OP_SENDB\tR%d\t:%s\t%d\n", a, mrb_sym2name(mrb, irep->syms[b]), c);
251       break;
252     CASE(OP_CALL, Z):
253       printf("OP_CALL\n");
254       break;
255     CASE(OP_SUPER, BB):
256       printf("OP_SUPER\tR%d\t%d\n", a, b);
257       break;
258     CASE(OP_ARGARY, BS):
259       printf("OP_ARGARY\tR%d\t%d:%d:%d:%d (%d)", a,
260              (b>>11)&0x3f,
261              (b>>10)&0x1,
262              (b>>5)&0x1f,
263              (b>>4)&0x1,
264              (b>>0)&0xf);
265       print_lv_a(mrb, irep, a);
266       break;
267     CASE(OP_ENTER, W):
268       printf("OP_ENTER\t%d:%d:%d:%d:%d:%d:%d\n",
269              (a>>18)&0x1f,
270              (a>>13)&0x1f,
271              (a>>12)&0x1,
272              (a>>7)&0x1f,
273              (a>>2)&0x1f,
274              (a>>1)&0x1,
275              a & 0x1);
276       break;
277     CASE(OP_KEY_P, BB):
278       printf("OP_KEY_P\tR%d\t:%s\t", a, mrb_sym2name(mrb, irep->syms[b]));
279       print_lv_a(mrb, irep, a);
280       break;
281     CASE(OP_KEYEND, Z):
282       printf("OP_KEYEND\n");
283       break;
284     CASE(OP_KARG, BB):
285       printf("OP_KARG\tR%d\t:%s\t", a, mrb_sym2name(mrb, irep->syms[b]));
286       print_lv_a(mrb, irep, a);
287       break;
288     CASE(OP_RETURN, B):
289       printf("OP_RETURN\tR%d\t\t", a);
290       print_lv_a(mrb, irep, a);
291       break;
292     CASE(OP_RETURN_BLK, B):
293       printf("OP_RETURN_BLK\tR%d\t\t", a);
294       print_lv_a(mrb, irep, a);
295       break;
296     CASE(OP_BREAK, B):
297       printf("OP_BREAK\tR%d\t\t", a);
298       print_lv_a(mrb, irep, a);
299       break;
300     CASE(OP_BLKPUSH, BS):
301       printf("OP_BLKPUSH\tR%d\t%d:%d:%d:%d (%d)", a,
302              (b>>11)&0x3f,
303              (b>>10)&0x1,
304              (b>>5)&0x1f,
305              (b>>4)&0x1,
306              (b>>0)&0xf);
307       print_lv_a(mrb, irep, a);
308       break;
309     CASE(OP_LAMBDA, BB):
310       printf("OP_LAMBDA\tR%d\tI(%d:%p)\n", a, b, irep->reps[b]);
311       break;
312     CASE(OP_BLOCK, BB):
313       printf("OP_BLOCK\tR%d\tI(%d:%p)\n", a, b, irep->reps[b]);
314       break;
315     CASE(OP_METHOD, BB):
316       printf("OP_METHOD\tR%d\tI(%d:%p)\n", a, b, irep->reps[b]);
317       break;
318     CASE(OP_RANGE_INC, B):
319       printf("OP_RANGE_INC\tR%d\n", a);
320       break;
321     CASE(OP_RANGE_EXC, B):
322       printf("OP_RANGE_EXC\tR%d\n", a);
323       break;
324     CASE(OP_DEF, BB):
325       printf("OP_DEF\tR%d\t:%s\n", a, mrb_sym2name(mrb, irep->syms[b]));
326       break;
327     CASE(OP_UNDEF, B):
328       printf("OP_UNDEF\t:%s\n", mrb_sym2name(mrb, irep->syms[a]));
329       break;
330     CASE(OP_ALIAS, BB):
331       printf("OP_ALIAS\t:%s\t%s\n", mrb_sym2name(mrb, irep->syms[a]), mrb_sym2name(mrb, irep->syms[b]));
332       break;
333     CASE(OP_ADD, B):
334       printf("OP_ADD\tR%d\t\n", a);
335       break;
336     CASE(OP_ADDI, BB):
337       printf("OP_ADDI\tR%d\t%d\n", a, b);
338       break;
339     CASE(OP_SUB, B):
340       printf("OP_SUB\tR%d\t\n", a);
341       break;
342     CASE(OP_SUBI, BB):
343       printf("OP_SUBI\tR%d\t%d\n", a, b);
344       break;
345     CASE(OP_MUL, B):
346       printf("OP_MUL\tR%d\t\n", a);
347       break;
348     CASE(OP_DIV, B):
349       printf("OP_DIV\tR%d\t\n", a);
350       break;
351     CASE(OP_LT, B):
352       printf("OP_LT\t\tR%d\t\n", a);
353       break;
354     CASE(OP_LE, B):
355       printf("OP_LE\t\tR%d\t\n", a);
356       break;
357     CASE(OP_GT, B):
358       printf("OP_GT\t\tR%d\t\n", a);
359       break;
360     CASE(OP_GE, B):
361       printf("OP_GE\t\tR%d\t\n", a);
362       break;
363     CASE(OP_EQ, B):
364       printf("OP_EQ\t\tR%d\t\n", a);
365       break;
366     CASE(OP_ARRAY, BB):
367       printf("OP_ARRAY\tR%d\t%d\t", a, b);
368       print_lv_a(mrb, irep, a);
369       break;
370     CASE(OP_ARRAY2, BBB):
371       printf("OP_ARRAY\tR%d\tR%d\t%d\t", a, b, c);
372       print_lv_ab(mrb, irep, a, b);
373       break;
374     CASE(OP_ARYCAT, B):
375       printf("OP_ARYCAT\tR%d\t", a);
376       print_lv_a(mrb, irep, a);
377       break;
378     CASE(OP_ARYPUSH, B):
379       printf("OP_ARYPUSH\tR%d\t", a);
380       print_lv_a(mrb, irep, a);
381       break;
382     CASE(OP_ARYDUP, B):
383       printf("OP_ARYDUP\tR%d\t", a);
384       print_lv_a(mrb, irep, a);
385       break;
386     CASE(OP_AREF, BBB):
387       printf("OP_AREF\tR%d\tR%d\t%d", a, b, c);
388       print_lv_ab(mrb, irep, a, b);
389       break;
390     CASE(OP_ASET, BBB):
391       printf("OP_ASET\tR%d\tR%d\t%d", a, b, c);
392       print_lv_ab(mrb, irep, a, b);
393       break;
394     CASE(OP_APOST, BBB):
395       printf("OP_APOST\tR%d\t%d\t%d", a, b, c);
396       print_lv_a(mrb, irep, a);
397       break;
398     CASE(OP_INTERN, B):
399       printf("OP_INTERN\tR%d", a);
400       print_lv_a(mrb, irep, a);
401       break;
402     CASE(OP_STRING, BB):
403       {
404         mrb_value v = irep->pool[b];
405         mrb_value s = mrb_str_dump(mrb, mrb_str_new(mrb, RSTRING_PTR(v), RSTRING_LEN(v)));
406         printf("OP_STRING\tR%d\tL(%d)\t; %s", a, b, RSTRING_PTR(s));
407       }
408       print_lv_a(mrb, irep, a);
409       break;
410     CASE(OP_STRCAT, B):
411       printf("OP_STRCAT\tR%d\t", a);
412       print_lv_a(mrb, irep, a);
413       break;
414     CASE(OP_HASH, BB):
415       printf("OP_HASH\tR%d\t%d\t", a, b);
416       print_lv_a(mrb, irep, a);
417       break;
418     CASE(OP_HASHADD, BB):
419       printf("OP_HASHADD\tR%d\t%d\t", a, b);
420       print_lv_a(mrb, irep, a);
421       break;
422     CASE(OP_HASHCAT, B):
423       printf("OP_HASHCAT\tR%d\t", a);
424       print_lv_a(mrb, irep, a);
425       break;
426 
427     CASE(OP_OCLASS, B):
428       printf("OP_OCLASS\tR%d\t\t", a);
429       print_lv_a(mrb, irep, a);
430       break;
431     CASE(OP_CLASS, BB):
432       printf("OP_CLASS\tR%d\t:%s", a, mrb_sym2name(mrb, irep->syms[b]));
433       print_lv_a(mrb, irep, a);
434       break;
435     CASE(OP_MODULE, BB):
436       printf("OP_MODULE\tR%d\t:%s", a, mrb_sym2name(mrb, irep->syms[b]));
437       print_lv_a(mrb, irep, a);
438       break;
439     CASE(OP_EXEC, BB):
440       printf("OP_EXEC\tR%d\tI(%d:%p)", a, b, irep->reps[b]);
441       print_lv_a(mrb, irep, a);
442       break;
443     CASE(OP_SCLASS, B):
444       printf("OP_SCLASS\tR%d\t", a);
445       print_lv_a(mrb, irep, a);
446       break;
447     CASE(OP_TCLASS, B):
448       printf("OP_TCLASS\tR%d\t\t", a);
449       print_lv_a(mrb, irep, a);
450       break;
451     CASE(OP_ERR, B):
452       {
453         mrb_value v = irep->pool[a];
454         mrb_value s = mrb_str_dump(mrb, mrb_str_new(mrb, RSTRING_PTR(v), RSTRING_LEN(v)));
455         printf("OP_ERR\t%s\n", RSTRING_PTR(s));
456       }
457       break;
458     CASE(OP_EPUSH, B):
459       printf("OP_EPUSH\t\t:I(%d:%p)\n", a, irep->reps[a]);
460       break;
461     CASE(OP_ONERR, S):
462       printf("OP_ONERR\t%03d\n", a);
463       break;
464     CASE(OP_EXCEPT, B):
465       printf("OP_EXCEPT\tR%d\t\t", a);
466       print_lv_a(mrb, irep, a);
467       break;
468     CASE(OP_RESCUE, BB):
469       printf("OP_RESCUE\tR%d\tR%d", a, b);
470       print_lv_ab(mrb, irep, a, b);
471       break;
472     CASE(OP_RAISE, B):
473       printf("OP_RAISE\tR%d\t\t", a);
474       print_lv_a(mrb, irep, a);
475       break;
476     CASE(OP_POPERR, B):
477       printf("OP_POPERR\t%d\t\t\n", a);
478       break;
479     CASE(OP_EPOP, B):
480       printf("OP_EPOP\t%d\n", a);
481       break;
482 
483     CASE(OP_DEBUG, BBB):
484       printf("OP_DEBUG\t%d\t%d\t%d\n", a, b, c);
485       break;
486 
487     CASE(OP_STOP, Z):
488       printf("OP_STOP\n");
489       break;
490 
491     CASE(OP_EXT1, Z):
492       ins = READ_B();
493       printf("OP_EXT1\n");
494       print_header(mrb, irep, pc-irep->iseq-2);
495       switch (ins) {
496 #define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _1 (); goto L_OP_ ## i;
497 #include "mruby/ops.h"
498 #undef OPCODE
499       }
500       break;
501     CASE(OP_EXT2, Z):
502       ins = READ_B();
503       printf("OP_EXT2\n");
504       print_header(mrb, irep, pc-irep->iseq-2);
505       switch (ins) {
506 #define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _2 (); goto L_OP_ ## i;
507 #include "mruby/ops.h"
508 #undef OPCODE
509       }
510       break;
511     CASE(OP_EXT3, Z):
512       ins = READ_B();
513       printf("OP_EXT3\n");
514       print_header(mrb, irep, pc-irep->iseq-2);
515       switch (ins) {
516 #define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _3 (); goto L_OP_ ## i;
517 #include "mruby/ops.h"
518 #undef OPCODE
519       }
520       break;
521 
522     default:
523       printf("OP_unknown (0x%x)\n", ins);
524       break;
525     }
526     mrb_gc_arena_restore(mrb, ai);
527   }
528   printf("\n");
529 }
530 
531 static void
codedump_recur(mrb_state * mrb,mrb_irep * irep)532 codedump_recur(mrb_state *mrb, mrb_irep *irep)
533 {
534   int i;
535 
536   codedump(mrb, irep);
537   for (i=0; i<irep->rlen; i++) {
538     codedump_recur(mrb, irep->reps[i]);
539   }
540 }
541 #endif
542 
543 void
mrb_codedump_all(mrb_state * mrb,struct RProc * proc)544 mrb_codedump_all(mrb_state *mrb, struct RProc *proc)
545 {
546 #ifndef MRB_DISABLE_STDIO
547   codedump_recur(mrb, proc->body.irep);
548 #endif
549 }
550