bytecode.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. /* Definitions for the bytecode operations.
  2. This file is part of khipu.
  3. khipu is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Lesser General Public License as published by
  5. the Free Software Foundation; either version 3 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public License
  12. along with this program. If not, see <https://www.gnu.org/licenses/>. */
  13. #include <cstring>
  14. #include <cstdio>
  15. #include "bytecode.hpp"
  16. #include "interp.hpp"
  17. #include "array.hpp"
  18. #include "bvector.hpp"
  19. #include "stream.hpp"
  20. #include "function.hpp"
  21. #include "io.hpp"
  22. KP_DECLS_BEGIN
  23. static const char OPC_NAMES[] =
  24. "nop\0dup\0pop\0ret\0is\0not\0cons\0car\0cdr\0cadr\0apply\0tapply\0"
  25. "loadt\0loadnil\0load0\0load1\0loada0\0loada1\0loadc00\0loadc01\0mkcont\0"
  26. "closure\0vframe\0tryend\0ldcaller\0clrexc\0symname\0sympkg\0coroval\0"
  27. "typep\0typep2\0raise\0loadi8\0loadi32\0loadchr8\0loadchr32\0vargc\0"
  28. "vargc.l\0jmp\0jmp.l\0brt\0brt.l\0brn\0brn.l\0brneq\0brneq.l\0tcall\0"
  29. "tcall.l\0call\0call.l\0recur\0recur.l\0trecur\0trecur.l\0setc0\0setc0.l\0"
  30. "setc\0setc.l\0seta\0seta.l\0setg\0setg.l\0setfgs\0setfgs.l\0loadc0\0"
  31. "loadc0.l\0loadc\0loadc.l\0loada\0loada.l\0loadg\0loadg.l\0loadv\0"
  32. "loadv.l\0loadx\0loadx.l\0loadfgs\0loadfgs.l\0bind\0bind.l\0trybegin\0"
  33. "trybegin.l\0setapop\0setapop.l\0irtjmp\0irtjmp.l\0optargs\0optargs.l\0"
  34. "brbound\0brbound.l\0kwargs\0kwargs.l\0jmpt\0jmpt.l\0jmpn\0jmpn.l\0"
  35. "box\0box.l\0loadb\0loadb.l\0setb\0setb.l\0skip\0skip.l\0unbind\0unbind.l\0";
  36. #define BC_CALL_FORM bcode_instr::BC_CALL_FORM
  37. #define BC_LOAD_FORM bcode_instr::BC_LOAD_FORM
  38. #define BC_BRANCH_FORM bcode_instr::BC_BRANCH_FORM
  39. #define BC_LONG_FORM bcode_instr::BC_LONG_FORM
  40. #define BC_PURE_FORM bcode_instr::BC_PURE_FORM
  41. static const bcode_instr BCODE_INSTR[] =
  42. {
  43. { 0, 0 }, // nop
  44. { 4, 0 }, // dup
  45. { 8, 0 }, // pop
  46. { 12, 0 }, // ret
  47. { 16, 0 }, // is
  48. { 19, 0 }, // not
  49. { 23, 0 }, // cons
  50. { 28, 0 }, // car
  51. { 32, 0 }, // cdr
  52. { 36, 0 }, // cadr
  53. { 41, 1 | BC_CALL_FORM }, // apply
  54. { 47, 1 | BC_CALL_FORM }, // tapply
  55. { 54, 0 | BC_LOAD_FORM | BC_PURE_FORM }, // loadt
  56. { 60, 0 | BC_LOAD_FORM | BC_PURE_FORM }, // loadnil
  57. { 68, 0 | BC_LOAD_FORM | BC_PURE_FORM }, // load0
  58. { 74, 0 | BC_LOAD_FORM | BC_PURE_FORM }, // load1
  59. { 80, 0 | BC_LOAD_FORM | BC_PURE_FORM }, // loada0
  60. { 87, 0 | BC_LOAD_FORM | BC_PURE_FORM }, // loada1
  61. { 94, 0 | BC_LOAD_FORM | BC_PURE_FORM }, // loadc00
  62. { 102, 0 | BC_LOAD_FORM | BC_PURE_FORM }, // loadc01
  63. { 110, 1 | BC_LOAD_FORM }, // mkcont
  64. { 117, 0 }, // closure
  65. { 125, 0 }, // vframe
  66. { 132, 0 }, // tryend
  67. { 139, 0 | BC_LOAD_FORM | BC_PURE_FORM }, // ldcaller
  68. { 148, 0 }, // clrexc
  69. { 155, 0 }, // symname
  70. { 163, 0 }, // sympkg
  71. { 170, 0 }, // coroval
  72. { 178, 1 | BC_PURE_FORM }, // typep
  73. { 184, 2 | BC_PURE_FORM }, // typep2
  74. { 191, 1 }, // raise
  75. { 197, 1 | BC_LOAD_FORM | BC_PURE_FORM }, // loadi8
  76. { 204, 1 | BC_LOAD_FORM | BC_PURE_FORM | BC_LONG_FORM }, // loadi32
  77. { 212, 1 | BC_LOAD_FORM | BC_PURE_FORM }, // loadchr8
  78. { 221, 1 | BC_LOAD_FORM | BC_PURE_FORM | BC_LONG_FORM }, // loadchr32
  79. { 231, 1 }, // vargc
  80. { 237, 1 | BC_LONG_FORM }, // vargc.l
  81. { 245, 1 | BC_BRANCH_FORM }, // jmp
  82. { 249, 1 | BC_BRANCH_FORM | BC_LONG_FORM }, // jmp.l
  83. { 255, 1 | BC_BRANCH_FORM }, // brt
  84. { 259, 1 | BC_BRANCH_FORM | BC_LONG_FORM }, // brt.l
  85. { 265, 1 | BC_BRANCH_FORM }, // brn
  86. { 269, 1 | BC_BRANCH_FORM | BC_LONG_FORM }, // brn.l
  87. { 275, 1 | BC_BRANCH_FORM }, // brneq
  88. { 281, 1 | BC_BRANCH_FORM | BC_LONG_FORM }, // brneq.l
  89. { 289, 1 | BC_CALL_FORM }, // tcall
  90. { 295, 1 | BC_CALL_FORM | BC_LONG_FORM }, // tcall.l
  91. { 303, 1 | BC_CALL_FORM }, // call
  92. { 308, 1 | BC_CALL_FORM | BC_LONG_FORM }, // call.l
  93. { 315, 1 | BC_CALL_FORM }, // recur
  94. { 321, 1 | BC_CALL_FORM | BC_LONG_FORM }, // recur.l
  95. { 329, 1 | BC_CALL_FORM }, // trecur
  96. { 336, 1 | BC_CALL_FORM | BC_LONG_FORM }, // trecur.l
  97. { 345, 1 }, // setc0
  98. { 351, 1 | BC_LONG_FORM }, // setc0.l
  99. { 359, 2 }, // setc
  100. { 364, 2 | BC_LONG_FORM }, // setc.l
  101. { 371, 1 }, // seta
  102. { 376, 1 | BC_LONG_FORM }, // seta.l
  103. { 383, 1 }, // setg
  104. { 388, 1 | BC_LONG_FORM }, // setg.l
  105. { 395, 1 }, // setfgs
  106. { 402, 1 | BC_LONG_FORM }, // setfgs.l
  107. { 411, 1 | BC_LOAD_FORM | BC_PURE_FORM }, // loadc0
  108. { 418, 1 | BC_LOAD_FORM | BC_PURE_FORM }, // loadc0.l
  109. { 427, 2 | BC_LOAD_FORM | BC_PURE_FORM }, // loadc
  110. { 433, 2 | BC_LOAD_FORM | BC_PURE_FORM | BC_LONG_FORM }, // loadc.l
  111. { 441, 1 | BC_LOAD_FORM | BC_PURE_FORM }, // loada
  112. { 447, 1 | BC_LOAD_FORM | BC_PURE_FORM | BC_LONG_FORM }, // loada.l
  113. { 455, 1 | BC_LOAD_FORM }, // loadg
  114. { 461, 1 | BC_LOAD_FORM | BC_LONG_FORM }, // loadg.l
  115. { 469, 1 | BC_LOAD_FORM | BC_PURE_FORM }, // loadv
  116. { 475, 1 | BC_LOAD_FORM | BC_PURE_FORM | BC_LONG_FORM }, // loadv.l
  117. { 483, 1 | BC_LOAD_FORM }, // loadx
  118. { 489, 1 | BC_LOAD_FORM | BC_LONG_FORM }, // loadx.l
  119. { 497, 1 | BC_LOAD_FORM }, // loadfgs
  120. { 505, 1 | BC_LOAD_FORM | BC_LONG_FORM }, // loadfgs.l
  121. { 515, 1 }, // bind
  122. { 520, 1 | BC_LONG_FORM }, // bind.l
  123. { 527, 1 | BC_BRANCH_FORM }, // trybegin
  124. { 536, 1 | BC_BRANCH_FORM | BC_LONG_FORM }, // trybegin.l
  125. { 547, 1 }, // setapop
  126. { 555, 1 | BC_LONG_FORM }, // setapop.l
  127. { 565, 1 | BC_BRANCH_FORM }, // irtjmp
  128. { 572, 1 | BC_BRANCH_FORM | BC_LONG_FORM }, // irtjmp.l
  129. { 581, 2 }, // optargs
  130. { 589, 2 | BC_LONG_FORM }, // optargs.l
  131. { 599, 1 }, // brbound
  132. { 607, 1 | BC_LONG_FORM }, // brbound.l
  133. { 617, 3 }, // kwargs
  134. { 624, 3 | BC_LONG_FORM }, // kwargs.l
  135. { 633, 1 | BC_BRANCH_FORM }, // jmpt
  136. { 638, 1 | BC_BRANCH_FORM | BC_LONG_FORM }, // jmpt.l
  137. { 645, 1 | BC_BRANCH_FORM }, // jmpn
  138. { 650, 1 | BC_BRANCH_FORM | BC_LONG_FORM }, // jmpn.l
  139. { 657, 1 }, // box
  140. { 661, 1 | BC_LONG_FORM }, // box.l
  141. { 667, 1 | BC_LOAD_FORM | BC_PURE_FORM }, // loadb
  142. { 673, 1 | BC_LOAD_FORM | BC_LONG_FORM | BC_PURE_FORM }, // loadb.l
  143. { 681, 1 }, // setb
  144. { 686, 1 | BC_LONG_FORM }, // setb.l
  145. { 693, 1 }, // skip
  146. { 698, 1 | BC_LONG_FORM }, // skip.l
  147. { 705, 1 }, // unbind
  148. { 712, 1 | BC_LONG_FORM }, // unbind.l
  149. { 0, 0 }
  150. };
  151. #undef BC_CALL_FORM
  152. #undef BC_LOAD_FORM
  153. #undef BC_BRANCH_FORM
  154. #undef BC_LONG_FORM
  155. #undef BC_PURE_FORM
  156. const bcode_instr* bcode_get (int opc)
  157. {
  158. return (&BCODE_INSTR[opc]);
  159. }
  160. int bcode_instr::opcode () const
  161. {
  162. return ((int)(this - &BCODE_INSTR[0]));
  163. }
  164. const char* bcode_instr::name () const
  165. {
  166. return (OPC_NAMES + this->name_off);
  167. }
  168. static result<void> disasm_aux (interpreter *, object, stream *, int);
  169. static result<void>
  170. disasm_print (interpreter *interp, object val, stream *strm, int lv)
  171. {
  172. if (fct_p (val))
  173. KP_VTRY (strm->putb (interp, '\n'),
  174. disasm_aux (interp, val, strm, lv + 1));
  175. else
  176. {
  177. io_info info;
  178. info.flags &= ~io_info::FLG_RAW;
  179. KP_VTRY (strm->putb (interp, ' '),
  180. xwrite (interp, strm, val, info));
  181. }
  182. return (0);
  183. }
  184. static result<void>
  185. disasm_aux (interpreter *interp, object fn, stream *strm, int lv)
  186. {
  187. if (native_fct_p (fn))
  188. {
  189. const char *nm = fct_sname (fn);
  190. KP_VTRY (strm->nputb (interp, lv * 2, ' '),
  191. strm->write (interp, "00: builtin-call ", 17),
  192. strm->write (interp, nm, strlen (nm)),
  193. strm->putb (interp, '\n'));
  194. return (0);
  195. }
  196. const bvector *bc = as_bvector (fct_bcode (fn));
  197. const unsigned char *code = bc->data;
  198. const array *vals = as_array (fct_vals (fn));
  199. int sx, width = bc->nbytes < 0xff ? 2 :
  200. bc->nbytes < 0xffff ? 4 : 8;
  201. for (uint32_t i = 0; i < bc->nbytes; )
  202. {
  203. char buf[64];
  204. const bcode_instr *instrp = bcode_get (code[i]);
  205. KP_VTRY (strm->nputb (interp, lv * 2, ' '),
  206. strm->write (interp, buf, sprintf (buf, "%0*x: %s",
  207. width, i++,
  208. instrp->name ())));
  209. bool done = false;
  210. switch (instrp->opcode ())
  211. {
  212. case OP_LOADV: case OP_LOADVL: case OP_SETG: case OP_SETGL:
  213. case OP_LOADG: case OP_LOADGL: case OP_LOADX: case OP_LOADXL:
  214. case OP_BIND: case OP_BINDL:
  215. sx = instrp->getuarg (&code[i]);
  216. KP_VTRY (disasm_print (interp, vals->data[sx], strm, lv));
  217. done = true;
  218. break;
  219. case OP_LOADFGS: case OP_LOADFGSL: case OP_SETFGS: case OP_SETFGSL:
  220. sx = instrp->getuarg (&code[i]);
  221. KP_VTRY (disasm_print (interp, symbol::fast_global_syms[sx],
  222. strm, lv));
  223. done = true;
  224. default:
  225. break;
  226. }
  227. if (done)
  228. ;
  229. else if (instrp->branch_p ())
  230. KP_VTRY (strm->write (interp, buf,
  231. sprintf (buf, " %0*x", width,
  232. i + instrp->getsarg (&code[i]))));
  233. else
  234. {
  235. int nops = 0, nx = i;
  236. for (; nops < instrp->nops () - 1;
  237. ++nops, nx += instrp->argsize ())
  238. KP_VTRY (strm->write (interp, buf,
  239. sprintf (buf, " %d",
  240. instrp->getsarg (&code[nx]))));
  241. if (instrp->nops () > 0)
  242. KP_VTRY (strm->write (interp, buf,
  243. sprintf (buf, " %d",
  244. instrp->getsarg (&code[nx]))));
  245. }
  246. i += instrp->nops () * instrp->argsize ();
  247. KP_VTRY (strm->putb (interp, '\n'));
  248. }
  249. return (0);
  250. }
  251. result<void> disasm (interpreter *interp, object fn, object out)
  252. {
  253. if (!fct_p (fn))
  254. return (interp->raise ("type-error", "first argument must be a function"));
  255. else if (!stream_p (out))
  256. return (interp->raise ("type-error", "second argument must be a stream"));
  257. return (disasm_aux (interp, fn, as_stream (out), 0));
  258. }
  259. KP_DECLS_END