userspace/kp_bcwrite.c - ktap

Global variables defined

Data types defined

Functions defined

Macros defined

Source code

  1. /*
  2. * Bytecode writer
  3. *
  4. * This file is part of ktap by Jovi Zhangwei.
  5. *
  6. * Copyright (C) 2012-2013 Jovi Zhangwei <jovi.zhangwei@gmail.com>.
  7. *
  8. * Copyright (C) 1994-2013 Lua.org, PUC-Rio.
  9. *  - The part of code in this file is copied from lua initially.
  10. *  - lua's MIT license is compatible with GPL.
  11. *
  12. * ktap is free software; you can redistribute it and/or modify it
  13. * under the terms and conditions of the GNU General Public License,
  14. * version 2, as published by the Free Software Foundation.
  15. *
  16. * ktap is distributed in the hope it will be useful, but WITHOUT
  17. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  18. * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  19. * more details.
  20. *
  21. * You should have received a copy of the GNU General Public License along with
  22. * this program; if not, write to the Free Software Foundation, Inc.,
  23. * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
  24. */

  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>

  28. #include "../include/ktap_types.h"
  29. #include "cparser.h"
  30. #include "kp_util.h"

  31. /* Context for bytecode writer. */
  32. typedef struct BCWriteCtx {
  33.     SBuf sb;        /* Output buffer. */
  34.     ktap_proto_t *pt;    /* Root prototype. */
  35.     ktap_writer wfunc;    /* Writer callback. */
  36.     void *wdata;        /* Writer callback data. */
  37.     int strip;        /* Strip debug info. */
  38.     int status;        /* Status from writer callback. */
  39. } BCWriteCtx;


  40. static char *bcwrite_uint32(char *p, uint32_t v)
  41. {
  42.     memcpy(p, &v, sizeof(uint32_t));
  43.     p += sizeof(uint32_t);
  44.     return p;
  45. }

  46. /* -- Bytecode writer ----------------------------------------------------- */

  47. /* Write a single constant key/value of a template table. */
  48. static void bcwrite_ktabk(BCWriteCtx *ctx, const ktap_val_t *o, int narrow)
  49. {
  50.     char *p = kp_buf_more(&ctx->sb, 1+10);
  51.     if (is_string(o)) {
  52.         const ktap_str_t *str = rawtsvalue(o);
  53.         int len = str->len;
  54.         p = kp_buf_more(&ctx->sb, 5+len);
  55.         p = bcwrite_uint32(p, BCDUMP_KTAB_STR+len);
  56.         p = kp_buf_wmem(p, getstr(str), len);
  57.     } else if (is_number(o)) {
  58.         p = bcwrite_uint32(p, BCDUMP_KTAB_NUM);
  59.         p = kp_buf_wmem(p, &nvalue(o), sizeof(ktap_number));
  60.     } else {
  61.         kp_assert(tvispri(o));
  62.         p = bcwrite_uint32(p, BCDUMP_KTAB_NIL+~itype(o));
  63.     }
  64.     setsbufP(&ctx->sb, p);
  65. }

  66. /* Write a template table. */
  67. static void bcwrite_ktab(BCWriteCtx *ctx, char *p, const ktap_tab_t *t)
  68. {
  69.     int narray = 0, nhash = 0;
  70.     if (t->asize > 0) {  /* Determine max. length of array part. */
  71.         ptrdiff_t i;
  72.         ktap_val_t *array = t->array;
  73.         for (i = (ptrdiff_t)t->asize-1; i >= 0; i--)
  74.             if (!is_nil(&array[i]))
  75.                 break;
  76.             narray = (int)(i+1);
  77.     }
  78.     if (t->hmask > 0) {  /* Count number of used hash slots. */
  79.         int i, hmask = t->hmask;
  80.         ktap_node_t *node = t->node;
  81.         for (i = 0; i <= hmask; i++)
  82.             nhash += !is_nil(&node[i].val);
  83.     }
  84.     /* Write number of array slots and hash slots. */
  85.     p = bcwrite_uint32(p, narray);
  86.     p = bcwrite_uint32(p, nhash);
  87.     setsbufP(&ctx->sb, p);
  88.     if (narray) {  /* Write array entries (may contain nil). */
  89.         int i;
  90.         ktap_val_t *o = t->array;
  91.         for (i = 0; i < narray; i++, o++)
  92.             bcwrite_ktabk(ctx, o, 1);
  93.     }
  94.     if (nhash) {  /* Write hash entries. */
  95.         int i = nhash;
  96.         ktap_node_t *node = t->node + t->hmask;
  97.         for (;; node--)
  98.             if (!is_nil(&node->val)) {
  99.                 bcwrite_ktabk(ctx, &node->key, 0);
  100.                 bcwrite_ktabk(ctx, &node->val, 1);
  101.                 if (--i == 0)
  102.                     break;
  103.             }
  104.     }
  105. }

  106. /* Write GC constants of a prototype. */
  107. static void bcwrite_kgc(BCWriteCtx *ctx, ktap_proto_t *pt)
  108. {
  109.     int i, sizekgc = pt->sizekgc;
  110.     ktap_obj_t **kr = (ktap_obj_t **)pt->k - (ptrdiff_t)sizekgc;

  111.     for (i = 0; i < sizekgc; i++, kr++) {
  112.         ktap_obj_t *o = *kr;
  113.         int tp, need = 1;
  114.         char *p;

  115.         /* Determine constant type and needed size. */
  116.         if (o->gch.gct == ~KTAP_TSTR) {
  117.             tp = BCDUMP_KGC_STR + ((ktap_str_t *)o)->len;
  118.             need = 5 + ((ktap_str_t *)o)->len;
  119.         } else if (o->gch.gct == ~KTAP_TPROTO) {
  120.             kp_assert((pt->flags & PROTO_CHILD));
  121.             tp = BCDUMP_KGC_CHILD;
  122.         } else {
  123.             kp_assert(o->gch.gct == ~KTAP_TTAB);
  124.             tp = BCDUMP_KGC_TAB;
  125.             need = 1+2*5;
  126.         }

  127.         /* Write constant type. */
  128.         p = kp_buf_more(&ctx->sb, need);
  129.         p = bcwrite_uint32(p, tp);
  130.         /* Write constant data (if any). */
  131.         if (tp >= BCDUMP_KGC_STR) {
  132.             p = kp_buf_wmem(p, getstr((ktap_str_t *)o),
  133.                     ((ktap_str_t *)o)->len);
  134.         } else if (tp == BCDUMP_KGC_TAB) {
  135.             bcwrite_ktab(ctx, p, (ktap_tab_t *)o);
  136.             continue;
  137.         }
  138.         setsbufP(&ctx->sb, p);
  139.     }
  140. }

  141. /* Write number constants of a prototype. */
  142. static void bcwrite_knum(BCWriteCtx *ctx, ktap_proto_t *pt)
  143. {
  144.     int i, sizekn = pt->sizekn;
  145.     const ktap_val_t *o = (ktap_val_t *)pt->k;
  146.     char *p = kp_buf_more(&ctx->sb, 10*sizekn);

  147.     for (i = 0; i < sizekn; i++, o++) {
  148.         if (is_number(o))
  149.             p = kp_buf_wmem(p, &nvalue(o), sizeof(ktap_number));
  150.     }
  151.     setsbufP(&ctx->sb, p);
  152. }

  153. /* Write bytecode instructions. */
  154. static char *bcwrite_bytecode(BCWriteCtx *ctx, char *p, ktap_proto_t *pt)
  155. {
  156.     int nbc = pt->sizebc-1/* Omit the [JI]FUNC* header. */

  157.     p = kp_buf_wmem(p, proto_bc(pt)+1, nbc*(int)sizeof(BCIns));
  158.     return p;
  159. }

  160. /* Write prototype. */
  161. static void bcwrite_proto(BCWriteCtx *ctx, ktap_proto_t *pt)
  162. {
  163.     int sizedbg = 0;
  164.     char *p;

  165.     /* Recursively write children of prototype. */
  166.     if (pt->flags & PROTO_CHILD) {
  167.         ptrdiff_t i, n = pt->sizekgc;
  168.         ktap_obj_t **kr = (ktap_obj_t **)pt->k - 1;
  169.         for (i = 0; i < n; i++, kr--) {
  170.             ktap_obj_t *o = *kr;
  171.             if (o->gch.gct == ~KTAP_TPROTO)
  172.                 bcwrite_proto(ctx, (ktap_proto_t *)o);
  173.         }
  174.     }

  175.     /* Start writing the prototype info to a buffer. */
  176.     p = kp_buf_need(&ctx->sb,
  177.         5+4+6*5+(pt->sizebc-1)*(int)sizeof(BCIns)+pt->sizeuv*2);
  178.     p += 4/* Leave room for final size. */

  179.     /* Write prototype header. */
  180.     *p++ = (pt->flags & (PROTO_CHILD|PROTO_VARARG|PROTO_FFI));
  181.     *p++ = pt->numparams;
  182.     *p++ = pt->framesize;
  183.     *p++ = pt->sizeuv;
  184.     p = bcwrite_uint32(p, pt->sizekgc);
  185.     p = bcwrite_uint32(p, pt->sizekn);
  186.     p = bcwrite_uint32(p, pt->sizebc-1);
  187.     if (!ctx->strip) {
  188.         if (proto_lineinfo(pt))
  189.             sizedbg = pt->sizept -
  190.                 (int)((char *)proto_lineinfo(pt) - (char *)pt);
  191.         p = bcwrite_uint32(p, sizedbg);
  192.         if (sizedbg) {
  193.             p = bcwrite_uint32(p, pt->firstline);
  194.             p = bcwrite_uint32(p, pt->numline);
  195.         }
  196.     }

  197.     /* Write bytecode instructions and upvalue refs. */
  198.     p = bcwrite_bytecode(ctx, p, pt);
  199.     p = kp_buf_wmem(p, proto_uv(pt), pt->sizeuv*2);
  200.     setsbufP(&ctx->sb, p);

  201.     /* Write constants. */
  202.     bcwrite_kgc(ctx, pt);
  203.     bcwrite_knum(ctx, pt);

  204.     /* Write debug info, if not stripped. */
  205.     if (sizedbg) {
  206.         p = kp_buf_more(&ctx->sb, sizedbg);
  207.         p = kp_buf_wmem(p, proto_lineinfo(pt), sizedbg);
  208.         setsbufP(&ctx->sb, p);
  209.     }

  210.     /* Pass buffer to writer function. */
  211.     if (ctx->status == 0) {
  212.         int n = sbuflen(&ctx->sb) - 4;
  213.         char *q = sbufB(&ctx->sb);
  214.         p = bcwrite_uint32(q, n);  /* Fill in final size. */
  215.         kp_assert(p == sbufB(&ctx->sb) + 4);
  216.         ctx->status = ctx->wfunc(q, n + 4, ctx->wdata);
  217.     }
  218. }

  219. /* Write header of bytecode dump. */
  220. static void bcwrite_header(BCWriteCtx *ctx)
  221. {
  222.     ktap_str_t *chunkname = proto_chunkname(ctx->pt);
  223.     const char *name = getstr(chunkname);
  224.     int len = chunkname->len;
  225.     char *p = kp_buf_need(&ctx->sb, 5+5+len);
  226.     *p++ = BCDUMP_HEAD1;
  227.     *p++ = BCDUMP_HEAD2;
  228.     *p++ = BCDUMP_HEAD3;
  229.     *p++ = BCDUMP_VERSION;
  230.     *p++ = (ctx->strip ? BCDUMP_F_STRIP : 0) + (KP_BE ? BCDUMP_F_BE : 0);

  231.     if (!ctx->strip) {
  232.         p = bcwrite_uint32(p, len);
  233.         p = kp_buf_wmem(p, name, len);
  234.     }
  235.     ctx->status = ctx->wfunc(sbufB(&ctx->sb),
  236.         (int)(p - sbufB(&ctx->sb)), ctx->wdata);
  237. }

  238. /* Write footer of bytecode dump. */
  239. static void bcwrite_footer(BCWriteCtx *ctx)
  240. {
  241.     if (ctx->status == 0) {
  242.         uint8_t zero = 0;
  243.         ctx->status = ctx->wfunc(&zero, 1, ctx->wdata);
  244.     }
  245. }

  246. /* Write bytecode for a prototype. */
  247. int kp_bcwrite(ktap_proto_t *pt, ktap_writer writer, void *data, int strip)
  248. {
  249.     BCWriteCtx ctx;

  250.     ctx.pt = pt;
  251.     ctx.wfunc = writer;
  252.     ctx.wdata = data;
  253.     ctx.strip = strip;
  254.     ctx.status = 0;

  255.     kp_buf_init(&ctx.sb);
  256.     kp_buf_need(&ctx.sb, 1024);  /* Avoids resize for most prototypes. */
  257.     bcwrite_header(&ctx);
  258.     bcwrite_proto(&ctx, ctx.pt);
  259.     bcwrite_footer(&ctx);

  260.     kp_buf_free(&ctx.sb);
  261.     return ctx.status;
  262. }

  263. /* -- Bytecode dump ----------------------------------------------------- */

  264. static const char * const bc_names[] = {
  265. #define BCNAME(name, ma, mb, mc, mt)       #name,
  266.     BCDEF(BCNAME)
  267. #undef BCNAME
  268.   NULL
  269. };

  270. static const uint16_t bc_mode[] = {
  271.     BCDEF(BCMODE)
  272. };

  273. static void dump_bytecode(ktap_proto_t *pt)
  274. {
  275.     int nbc = pt->sizebc - 1; /* Omit the FUNC* header. */
  276.     BCIns *ins = proto_bc(pt) + 1;
  277.     ktap_obj_t **kbase = pt->k;
  278.     int i;

  279.     printf("-- BYTECODE -- %s:%d-%d\n", getstr(pt->chunkname),
  280.         pt->firstline, pt->firstline + pt->numline);

  281.     for (i = 0; i < nbc; i++, ins++) {
  282.         int op = bc_op(*ins);

  283.         printf("%04d\t%s", i + 1, bc_names[op]);

  284.         printf("\t%d", bc_a(*ins));
  285.         if (bcmode_b(op) != BCMnone)
  286.             printf("\t%d", bc_b(*ins));

  287.         if (bcmode_hasd(op))
  288.             printf("\t%d", bc_d(*ins));
  289.         else
  290.             printf("\t%d", bc_c(*ins));

  291.         if (bcmode_b(op) == BCMstr || bcmode_c(op) == BCMstr) {
  292.             printf("\t  ; ");
  293.             if (bcmode_d(op) == BCMstr) {
  294.                 int idx = ~bc_d(*ins);
  295.                 printf("\"%s\"", getstr((ktap_str_t *)kbase[idx]));
  296.             }
  297.         }
  298.         printf("\n");
  299.     }
  300. }

  301. static int function_nr = 0;

  302. void kp_dump_proto(ktap_proto_t *pt)
  303. {
  304.     printf("\n----------------------------------------------------\n");
  305.     printf("function proto %d:\n", function_nr++);
  306.     printf("numparams: %d\n", pt->numparams);
  307.     printf("framesize: %d\n", pt->framesize);
  308.     printf("sizebc: %d\n", pt->sizebc);
  309.     printf("sizekgc: %d\n", pt->sizekgc);
  310.     printf("sizekn: %d\n", pt->sizekn);
  311.     printf("sizept: %d\n", pt->sizept);
  312.     printf("sizeuv: %d\n", pt->sizeuv);
  313.     printf("firstline: %d\n", pt->firstline);
  314.     printf("numline: %d\n", pt->numline);

  315.     printf("has child proto: %d\n", pt->flags & PROTO_CHILD);
  316.     printf("has vararg: %d\n", pt->flags & PROTO_VARARG);
  317.     printf("has ILOOP: %d\n", pt->flags & PROTO_ILOOP);

  318.     dump_bytecode(pt);

  319.     /* Recursively dump children of prototype. */
  320.     if (pt->flags & PROTO_CHILD) {
  321.         ptrdiff_t i, n = pt->sizekgc;
  322.         ktap_obj_t **kr = (ktap_obj_t **)pt->k - 1;
  323.         for (i = 0; i < n; i++, kr--) {
  324.             ktap_obj_t *o = *kr;
  325.             if (o->gch.gct == ~KTAP_TPROTO)
  326.                 kp_dump_proto((ktap_proto_t *)o);
  327.         }
  328.     }
  329. }