123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292 |
- /* Definitions for the bytecode operations.
- This file is part of khipu.
- khipu is free software: you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Lesser General Public License for more details.
- You should have received a copy of the GNU Lesser General Public License
- along with this program. If not, see <https://www.gnu.org/licenses/>. */
- #include <cstring>
- #include <cstdio>
- #include "bytecode.hpp"
- #include "interp.hpp"
- #include "array.hpp"
- #include "bvector.hpp"
- #include "stream.hpp"
- #include "function.hpp"
- #include "io.hpp"
- KP_DECLS_BEGIN
- static const char OPC_NAMES[] =
- "nop\0dup\0pop\0ret\0is\0not\0cons\0car\0cdr\0cadr\0apply\0tapply\0"
- "loadt\0loadnil\0load0\0load1\0loada0\0loada1\0loadc00\0loadc01\0mkcont\0"
- "closure\0vframe\0tryend\0ldcaller\0clrexc\0symname\0sympkg\0coroval\0"
- "typep\0typep2\0raise\0loadi8\0loadi32\0loadchr8\0loadchr32\0vargc\0"
- "vargc.l\0jmp\0jmp.l\0brt\0brt.l\0brn\0brn.l\0brneq\0brneq.l\0tcall\0"
- "tcall.l\0call\0call.l\0recur\0recur.l\0trecur\0trecur.l\0setc0\0setc0.l\0"
- "setc\0setc.l\0seta\0seta.l\0setg\0setg.l\0setfgs\0setfgs.l\0loadc0\0"
- "loadc0.l\0loadc\0loadc.l\0loada\0loada.l\0loadg\0loadg.l\0loadv\0"
- "loadv.l\0loadx\0loadx.l\0loadfgs\0loadfgs.l\0bind\0bind.l\0trybegin\0"
- "trybegin.l\0setapop\0setapop.l\0irtjmp\0irtjmp.l\0optargs\0optargs.l\0"
- "brbound\0brbound.l\0kwargs\0kwargs.l\0jmpt\0jmpt.l\0jmpn\0jmpn.l\0"
- "box\0box.l\0loadb\0loadb.l\0setb\0setb.l\0skip\0skip.l\0unbind\0unbind.l\0";
- #define BC_CALL_FORM bcode_instr::BC_CALL_FORM
- #define BC_LOAD_FORM bcode_instr::BC_LOAD_FORM
- #define BC_BRANCH_FORM bcode_instr::BC_BRANCH_FORM
- #define BC_LONG_FORM bcode_instr::BC_LONG_FORM
- #define BC_PURE_FORM bcode_instr::BC_PURE_FORM
- static const bcode_instr BCODE_INSTR[] =
- {
- { 0, 0 }, // nop
- { 4, 0 }, // dup
- { 8, 0 }, // pop
- { 12, 0 }, // ret
- { 16, 0 }, // is
- { 19, 0 }, // not
- { 23, 0 }, // cons
- { 28, 0 }, // car
- { 32, 0 }, // cdr
- { 36, 0 }, // cadr
- { 41, 1 | BC_CALL_FORM }, // apply
- { 47, 1 | BC_CALL_FORM }, // tapply
- { 54, 0 | BC_LOAD_FORM | BC_PURE_FORM }, // loadt
- { 60, 0 | BC_LOAD_FORM | BC_PURE_FORM }, // loadnil
- { 68, 0 | BC_LOAD_FORM | BC_PURE_FORM }, // load0
- { 74, 0 | BC_LOAD_FORM | BC_PURE_FORM }, // load1
- { 80, 0 | BC_LOAD_FORM | BC_PURE_FORM }, // loada0
- { 87, 0 | BC_LOAD_FORM | BC_PURE_FORM }, // loada1
- { 94, 0 | BC_LOAD_FORM | BC_PURE_FORM }, // loadc00
- { 102, 0 | BC_LOAD_FORM | BC_PURE_FORM }, // loadc01
- { 110, 1 | BC_LOAD_FORM }, // mkcont
- { 117, 0 }, // closure
- { 125, 0 }, // vframe
- { 132, 0 }, // tryend
- { 139, 0 | BC_LOAD_FORM | BC_PURE_FORM }, // ldcaller
- { 148, 0 }, // clrexc
- { 155, 0 }, // symname
- { 163, 0 }, // sympkg
- { 170, 0 }, // coroval
- { 178, 1 | BC_PURE_FORM }, // typep
- { 184, 2 | BC_PURE_FORM }, // typep2
- { 191, 1 }, // raise
- { 197, 1 | BC_LOAD_FORM | BC_PURE_FORM }, // loadi8
- { 204, 1 | BC_LOAD_FORM | BC_PURE_FORM | BC_LONG_FORM }, // loadi32
- { 212, 1 | BC_LOAD_FORM | BC_PURE_FORM }, // loadchr8
- { 221, 1 | BC_LOAD_FORM | BC_PURE_FORM | BC_LONG_FORM }, // loadchr32
- { 231, 1 }, // vargc
- { 237, 1 | BC_LONG_FORM }, // vargc.l
- { 245, 1 | BC_BRANCH_FORM }, // jmp
- { 249, 1 | BC_BRANCH_FORM | BC_LONG_FORM }, // jmp.l
- { 255, 1 | BC_BRANCH_FORM }, // brt
- { 259, 1 | BC_BRANCH_FORM | BC_LONG_FORM }, // brt.l
- { 265, 1 | BC_BRANCH_FORM }, // brn
- { 269, 1 | BC_BRANCH_FORM | BC_LONG_FORM }, // brn.l
- { 275, 1 | BC_BRANCH_FORM }, // brneq
- { 281, 1 | BC_BRANCH_FORM | BC_LONG_FORM }, // brneq.l
- { 289, 1 | BC_CALL_FORM }, // tcall
- { 295, 1 | BC_CALL_FORM | BC_LONG_FORM }, // tcall.l
- { 303, 1 | BC_CALL_FORM }, // call
- { 308, 1 | BC_CALL_FORM | BC_LONG_FORM }, // call.l
- { 315, 1 | BC_CALL_FORM }, // recur
- { 321, 1 | BC_CALL_FORM | BC_LONG_FORM }, // recur.l
- { 329, 1 | BC_CALL_FORM }, // trecur
- { 336, 1 | BC_CALL_FORM | BC_LONG_FORM }, // trecur.l
- { 345, 1 }, // setc0
- { 351, 1 | BC_LONG_FORM }, // setc0.l
- { 359, 2 }, // setc
- { 364, 2 | BC_LONG_FORM }, // setc.l
- { 371, 1 }, // seta
- { 376, 1 | BC_LONG_FORM }, // seta.l
- { 383, 1 }, // setg
- { 388, 1 | BC_LONG_FORM }, // setg.l
- { 395, 1 }, // setfgs
- { 402, 1 | BC_LONG_FORM }, // setfgs.l
- { 411, 1 | BC_LOAD_FORM | BC_PURE_FORM }, // loadc0
- { 418, 1 | BC_LOAD_FORM | BC_PURE_FORM }, // loadc0.l
- { 427, 2 | BC_LOAD_FORM | BC_PURE_FORM }, // loadc
- { 433, 2 | BC_LOAD_FORM | BC_PURE_FORM | BC_LONG_FORM }, // loadc.l
- { 441, 1 | BC_LOAD_FORM | BC_PURE_FORM }, // loada
- { 447, 1 | BC_LOAD_FORM | BC_PURE_FORM | BC_LONG_FORM }, // loada.l
- { 455, 1 | BC_LOAD_FORM }, // loadg
- { 461, 1 | BC_LOAD_FORM | BC_LONG_FORM }, // loadg.l
- { 469, 1 | BC_LOAD_FORM | BC_PURE_FORM }, // loadv
- { 475, 1 | BC_LOAD_FORM | BC_PURE_FORM | BC_LONG_FORM }, // loadv.l
- { 483, 1 | BC_LOAD_FORM }, // loadx
- { 489, 1 | BC_LOAD_FORM | BC_LONG_FORM }, // loadx.l
- { 497, 1 | BC_LOAD_FORM }, // loadfgs
- { 505, 1 | BC_LOAD_FORM | BC_LONG_FORM }, // loadfgs.l
- { 515, 1 }, // bind
- { 520, 1 | BC_LONG_FORM }, // bind.l
- { 527, 1 | BC_BRANCH_FORM }, // trybegin
- { 536, 1 | BC_BRANCH_FORM | BC_LONG_FORM }, // trybegin.l
- { 547, 1 }, // setapop
- { 555, 1 | BC_LONG_FORM }, // setapop.l
- { 565, 1 | BC_BRANCH_FORM }, // irtjmp
- { 572, 1 | BC_BRANCH_FORM | BC_LONG_FORM }, // irtjmp.l
- { 581, 2 }, // optargs
- { 589, 2 | BC_LONG_FORM }, // optargs.l
- { 599, 1 }, // brbound
- { 607, 1 | BC_LONG_FORM }, // brbound.l
- { 617, 3 }, // kwargs
- { 624, 3 | BC_LONG_FORM }, // kwargs.l
- { 633, 1 | BC_BRANCH_FORM }, // jmpt
- { 638, 1 | BC_BRANCH_FORM | BC_LONG_FORM }, // jmpt.l
- { 645, 1 | BC_BRANCH_FORM }, // jmpn
- { 650, 1 | BC_BRANCH_FORM | BC_LONG_FORM }, // jmpn.l
- { 657, 1 }, // box
- { 661, 1 | BC_LONG_FORM }, // box.l
- { 667, 1 | BC_LOAD_FORM | BC_PURE_FORM }, // loadb
- { 673, 1 | BC_LOAD_FORM | BC_LONG_FORM | BC_PURE_FORM }, // loadb.l
- { 681, 1 }, // setb
- { 686, 1 | BC_LONG_FORM }, // setb.l
- { 693, 1 }, // skip
- { 698, 1 | BC_LONG_FORM }, // skip.l
- { 705, 1 }, // unbind
- { 712, 1 | BC_LONG_FORM }, // unbind.l
- { 0, 0 }
- };
- #undef BC_CALL_FORM
- #undef BC_LOAD_FORM
- #undef BC_BRANCH_FORM
- #undef BC_LONG_FORM
- #undef BC_PURE_FORM
- const bcode_instr* bcode_get (int opc)
- {
- return (&BCODE_INSTR[opc]);
- }
- int bcode_instr::opcode () const
- {
- return ((int)(this - &BCODE_INSTR[0]));
- }
- const char* bcode_instr::name () const
- {
- return (OPC_NAMES + this->name_off);
- }
- static result<void> disasm_aux (interpreter *, object, stream *, int);
- static result<void>
- disasm_print (interpreter *interp, object val, stream *strm, int lv)
- {
- if (fct_p (val))
- KP_VTRY (strm->putb (interp, '\n'),
- disasm_aux (interp, val, strm, lv + 1));
- else
- {
- io_info info;
- info.flags &= ~io_info::FLG_RAW;
- KP_VTRY (strm->putb (interp, ' '),
- xwrite (interp, strm, val, info));
- }
- return (0);
- }
- static result<void>
- disasm_aux (interpreter *interp, object fn, stream *strm, int lv)
- {
- if (native_fct_p (fn))
- {
- const char *nm = fct_sname (fn);
- KP_VTRY (strm->nputb (interp, lv * 2, ' '),
- strm->write (interp, "00: builtin-call ", 17),
- strm->write (interp, nm, strlen (nm)),
- strm->putb (interp, '\n'));
- return (0);
- }
- const bvector *bc = as_bvector (fct_bcode (fn));
- const unsigned char *code = bc->data;
- const array *vals = as_array (fct_vals (fn));
- int sx, width = bc->nbytes < 0xff ? 2 :
- bc->nbytes < 0xffff ? 4 : 8;
- for (uint32_t i = 0; i < bc->nbytes; )
- {
- char buf[64];
- const bcode_instr *instrp = bcode_get (code[i]);
- KP_VTRY (strm->nputb (interp, lv * 2, ' '),
- strm->write (interp, buf, sprintf (buf, "%0*x: %s",
- width, i++,
- instrp->name ())));
- bool done = false;
- switch (instrp->opcode ())
- {
- case OP_LOADV: case OP_LOADVL: case OP_SETG: case OP_SETGL:
- case OP_LOADG: case OP_LOADGL: case OP_LOADX: case OP_LOADXL:
- case OP_BIND: case OP_BINDL:
- sx = instrp->getuarg (&code[i]);
- KP_VTRY (disasm_print (interp, vals->data[sx], strm, lv));
- done = true;
- break;
- case OP_LOADFGS: case OP_LOADFGSL: case OP_SETFGS: case OP_SETFGSL:
- sx = instrp->getuarg (&code[i]);
- KP_VTRY (disasm_print (interp, symbol::fast_global_syms[sx],
- strm, lv));
- done = true;
- default:
- break;
- }
- if (done)
- ;
- else if (instrp->branch_p ())
- KP_VTRY (strm->write (interp, buf,
- sprintf (buf, " %0*x", width,
- i + instrp->getsarg (&code[i]))));
- else
- {
- int nops = 0, nx = i;
- for (; nops < instrp->nops () - 1;
- ++nops, nx += instrp->argsize ())
- KP_VTRY (strm->write (interp, buf,
- sprintf (buf, " %d",
- instrp->getsarg (&code[nx]))));
- if (instrp->nops () > 0)
- KP_VTRY (strm->write (interp, buf,
- sprintf (buf, " %d",
- instrp->getsarg (&code[nx]))));
- }
- i += instrp->nops () * instrp->argsize ();
- KP_VTRY (strm->putb (interp, '\n'));
- }
- return (0);
- }
- result<void> disasm (interpreter *interp, object fn, object out)
- {
- if (!fct_p (fn))
- return (interp->raise ("type-error", "first argument must be a function"));
- else if (!stream_p (out))
- return (interp->raise ("type-error", "second argument must be a stream"));
- return (disasm_aux (interp, fn, as_stream (out), 0));
- }
- KP_DECLS_END
|