diff options
Diffstat (limited to 'src/lj_bcwrite.c')
| -rw-r--r-- | src/lj_bcwrite.c | 366 |
1 files changed, 213 insertions, 153 deletions
diff --git a/src/lj_bcwrite.c b/src/lj_bcwrite.c index 1ae2badf..a0230eff 100644 --- a/src/lj_bcwrite.c +++ b/src/lj_bcwrite.c | |||
| @@ -8,7 +8,7 @@ | |||
| 8 | 8 | ||
| 9 | #include "lj_obj.h" | 9 | #include "lj_obj.h" |
| 10 | #include "lj_gc.h" | 10 | #include "lj_gc.h" |
| 11 | #include "lj_str.h" | 11 | #include "lj_buf.h" |
| 12 | #include "lj_bc.h" | 12 | #include "lj_bc.h" |
| 13 | #if LJ_HASFFI | 13 | #if LJ_HASFFI |
| 14 | #include "lj_ctype.h" | 14 | #include "lj_ctype.h" |
| @@ -17,99 +17,140 @@ | |||
| 17 | #include "lj_dispatch.h" | 17 | #include "lj_dispatch.h" |
| 18 | #include "lj_jit.h" | 18 | #include "lj_jit.h" |
| 19 | #endif | 19 | #endif |
| 20 | #include "lj_strfmt.h" | ||
| 20 | #include "lj_bcdump.h" | 21 | #include "lj_bcdump.h" |
| 21 | #include "lj_vm.h" | 22 | #include "lj_vm.h" |
| 22 | 23 | ||
| 23 | /* Context for bytecode writer. */ | 24 | /* Context for bytecode writer. */ |
| 24 | typedef struct BCWriteCtx { | 25 | typedef struct BCWriteCtx { |
| 25 | SBuf sb; /* Output buffer. */ | 26 | SBuf sb; /* Output buffer. */ |
| 26 | lua_State *L; /* Lua state. */ | ||
| 27 | GCproto *pt; /* Root prototype. */ | 27 | GCproto *pt; /* Root prototype. */ |
| 28 | lua_Writer wfunc; /* Writer callback. */ | 28 | lua_Writer wfunc; /* Writer callback. */ |
| 29 | void *wdata; /* Writer callback data. */ | 29 | void *wdata; /* Writer callback data. */ |
| 30 | int strip; /* Strip debug info. */ | 30 | TValue **heap; /* Heap used for deterministic sorting. */ |
| 31 | uint32_t heapsz; /* Size of heap. */ | ||
| 32 | uint32_t flags; /* BCDUMP_F_* flags. */ | ||
| 31 | int status; /* Status from writer callback. */ | 33 | int status; /* Status from writer callback. */ |
| 34 | #ifdef LUA_USE_ASSERT | ||
| 35 | global_State *g; | ||
| 36 | #endif | ||
| 32 | } BCWriteCtx; | 37 | } BCWriteCtx; |
| 33 | 38 | ||
| 34 | /* -- Output buffer handling ---------------------------------------------- */ | 39 | #ifdef LUA_USE_ASSERT |
| 35 | 40 | #define lj_assertBCW(c, ...) lj_assertG_(ctx->g, (c), __VA_ARGS__) | |
| 36 | /* Resize buffer if needed. */ | 41 | #else |
| 37 | static LJ_NOINLINE void bcwrite_resize(BCWriteCtx *ctx, MSize len) | 42 | #define lj_assertBCW(c, ...) ((void)ctx) |
| 38 | { | 43 | #endif |
| 39 | MSize sz = ctx->sb.sz * 2; | ||
| 40 | while (ctx->sb.n + len > sz) sz = sz * 2; | ||
| 41 | lj_str_resizebuf(ctx->L, &ctx->sb, sz); | ||
| 42 | } | ||
| 43 | |||
| 44 | /* Need a certain amount of buffer space. */ | ||
| 45 | static LJ_AINLINE void bcwrite_need(BCWriteCtx *ctx, MSize len) | ||
| 46 | { | ||
| 47 | if (LJ_UNLIKELY(ctx->sb.n + len > ctx->sb.sz)) | ||
| 48 | bcwrite_resize(ctx, len); | ||
| 49 | } | ||
| 50 | |||
| 51 | /* Add memory block to buffer. */ | ||
| 52 | static void bcwrite_block(BCWriteCtx *ctx, const void *p, MSize len) | ||
| 53 | { | ||
| 54 | uint8_t *q = (uint8_t *)(ctx->sb.buf + ctx->sb.n); | ||
| 55 | MSize i; | ||
| 56 | ctx->sb.n += len; | ||
| 57 | for (i = 0; i < len; i++) q[i] = ((uint8_t *)p)[i]; | ||
| 58 | } | ||
| 59 | |||
| 60 | /* Add byte to buffer. */ | ||
| 61 | static LJ_AINLINE void bcwrite_byte(BCWriteCtx *ctx, uint8_t b) | ||
| 62 | { | ||
| 63 | ctx->sb.buf[ctx->sb.n++] = b; | ||
| 64 | } | ||
| 65 | |||
| 66 | /* Add ULEB128 value to buffer. */ | ||
| 67 | static void bcwrite_uleb128(BCWriteCtx *ctx, uint32_t v) | ||
| 68 | { | ||
| 69 | MSize n = ctx->sb.n; | ||
| 70 | uint8_t *p = (uint8_t *)ctx->sb.buf; | ||
| 71 | for (; v >= 0x80; v >>= 7) | ||
| 72 | p[n++] = (uint8_t)((v & 0x7f) | 0x80); | ||
| 73 | p[n++] = (uint8_t)v; | ||
| 74 | ctx->sb.n = n; | ||
| 75 | } | ||
| 76 | 44 | ||
| 77 | /* -- Bytecode writer ----------------------------------------------------- */ | 45 | /* -- Bytecode writer ----------------------------------------------------- */ |
| 78 | 46 | ||
| 79 | /* Write a single constant key/value of a template table. */ | 47 | /* Write a single constant key/value of a template table. */ |
| 80 | static void bcwrite_ktabk(BCWriteCtx *ctx, cTValue *o, int narrow) | 48 | static void bcwrite_ktabk(BCWriteCtx *ctx, cTValue *o, int narrow) |
| 81 | { | 49 | { |
| 82 | bcwrite_need(ctx, 1+10); | 50 | char *p = lj_buf_more(&ctx->sb, 1+10); |
| 83 | if (tvisstr(o)) { | 51 | if (tvisstr(o)) { |
| 84 | const GCstr *str = strV(o); | 52 | const GCstr *str = strV(o); |
| 85 | MSize len = str->len; | 53 | MSize len = str->len; |
| 86 | bcwrite_need(ctx, 5+len); | 54 | p = lj_buf_more(&ctx->sb, 5+len); |
| 87 | bcwrite_uleb128(ctx, BCDUMP_KTAB_STR+len); | 55 | p = lj_strfmt_wuleb128(p, BCDUMP_KTAB_STR+len); |
| 88 | bcwrite_block(ctx, strdata(str), len); | 56 | p = lj_buf_wmem(p, strdata(str), len); |
| 89 | } else if (tvisint(o)) { | 57 | } else if (tvisint(o)) { |
| 90 | bcwrite_byte(ctx, BCDUMP_KTAB_INT); | 58 | *p++ = BCDUMP_KTAB_INT; |
| 91 | bcwrite_uleb128(ctx, intV(o)); | 59 | p = lj_strfmt_wuleb128(p, intV(o)); |
| 92 | } else if (tvisnum(o)) { | 60 | } else if (tvisnum(o)) { |
| 93 | if (!LJ_DUALNUM && narrow) { /* Narrow number constants to integers. */ | 61 | if (!LJ_DUALNUM && narrow) { /* Narrow number constants to integers. */ |
| 94 | lua_Number num = numV(o); | 62 | int64_t i64; |
| 95 | int32_t k = lj_num2int(num); | 63 | int32_t k; |
| 96 | if (num == (lua_Number)k) { /* -0 is never a constant. */ | 64 | if (lj_num2int_check(numV(o), i64, k)) { /* -0 is never a constant. */ |
| 97 | bcwrite_byte(ctx, BCDUMP_KTAB_INT); | 65 | *p++ = BCDUMP_KTAB_INT; |
| 98 | bcwrite_uleb128(ctx, k); | 66 | p = lj_strfmt_wuleb128(p, k); |
| 67 | ctx->sb.w = p; | ||
| 99 | return; | 68 | return; |
| 100 | } | 69 | } |
| 101 | } | 70 | } |
| 102 | bcwrite_byte(ctx, BCDUMP_KTAB_NUM); | 71 | *p++ = BCDUMP_KTAB_NUM; |
| 103 | bcwrite_uleb128(ctx, o->u32.lo); | 72 | p = lj_strfmt_wuleb128(p, o->u32.lo); |
| 104 | bcwrite_uleb128(ctx, o->u32.hi); | 73 | p = lj_strfmt_wuleb128(p, o->u32.hi); |
| 74 | } else if (tvistab(o)) { /* Write the nil value marker as a nil. */ | ||
| 75 | *p++ = BCDUMP_KTAB_NIL; | ||
| 76 | } else { | ||
| 77 | lj_assertBCW(tvispri(o), "unhandled type %d", itype(o)); | ||
| 78 | *p++ = BCDUMP_KTAB_NIL+~itype(o); | ||
| 79 | } | ||
| 80 | ctx->sb.w = p; | ||
| 81 | } | ||
| 82 | |||
| 83 | /* Compare two template table keys. */ | ||
| 84 | static LJ_AINLINE int bcwrite_ktabk_lt(TValue *a, TValue *b) | ||
| 85 | { | ||
| 86 | uint32_t at = itype(a), bt = itype(b); | ||
| 87 | if (at != bt) { /* This also handles false and true keys. */ | ||
| 88 | return at < bt; | ||
| 89 | } else if (at == LJ_TSTR) { | ||
| 90 | return lj_str_cmp(strV(a), strV(b)) < 0; | ||
| 105 | } else { | 91 | } else { |
| 106 | lua_assert(tvispri(o)); | 92 | return a->u64 < b->u64; /* This works for numbers and integers. */ |
| 107 | bcwrite_byte(ctx, BCDUMP_KTAB_NIL+~itype(o)); | ||
| 108 | } | 93 | } |
| 109 | } | 94 | } |
| 110 | 95 | ||
| 96 | /* Insert key into a sorted heap. */ | ||
| 97 | static void bcwrite_ktabk_heap_insert(TValue **heap, MSize idx, MSize end, | ||
| 98 | TValue *key) | ||
| 99 | { | ||
| 100 | MSize child; | ||
| 101 | while ((child = idx * 2 + 1) < end) { | ||
| 102 | /* Find lower of the two children. */ | ||
| 103 | TValue *c0 = heap[child]; | ||
| 104 | if (child + 1 < end) { | ||
| 105 | TValue *c1 = heap[child + 1]; | ||
| 106 | if (bcwrite_ktabk_lt(c1, c0)) { | ||
| 107 | c0 = c1; | ||
| 108 | child++; | ||
| 109 | } | ||
| 110 | } | ||
| 111 | if (bcwrite_ktabk_lt(key, c0)) break; /* Key lower? Found our position. */ | ||
| 112 | heap[idx] = c0; /* Move lower child up. */ | ||
| 113 | idx = child; /* Descend. */ | ||
| 114 | } | ||
| 115 | heap[idx] = key; /* Insert key here. */ | ||
| 116 | } | ||
| 117 | |||
| 118 | /* Resize heap, dropping content. */ | ||
| 119 | static void bcwrite_heap_resize(BCWriteCtx *ctx, uint32_t nsz) | ||
| 120 | { | ||
| 121 | lua_State *L = sbufL(&ctx->sb); | ||
| 122 | if (ctx->heapsz) { | ||
| 123 | lj_mem_freevec(G(L), ctx->heap, ctx->heapsz, TValue *); | ||
| 124 | ctx->heapsz = 0; | ||
| 125 | } | ||
| 126 | if (nsz) { | ||
| 127 | ctx->heap = lj_mem_newvec(L, nsz, TValue *); | ||
| 128 | ctx->heapsz = nsz; | ||
| 129 | } | ||
| 130 | } | ||
| 131 | |||
| 132 | /* Write hash part of template table in sorted order. */ | ||
| 133 | static void bcwrite_ktab_sorted_hash(BCWriteCtx *ctx, Node *node, MSize nhash) | ||
| 134 | { | ||
| 135 | TValue **heap = ctx->heap; | ||
| 136 | MSize i = nhash; | ||
| 137 | for (;; node--) { /* Build heap. */ | ||
| 138 | if (!tvisnil(&node->val)) { | ||
| 139 | bcwrite_ktabk_heap_insert(heap, --i, nhash, &node->key); | ||
| 140 | if (i == 0) break; | ||
| 141 | } | ||
| 142 | } | ||
| 143 | do { /* Drain heap. */ | ||
| 144 | TValue *key = heap[0]; /* Output lowest key from top. */ | ||
| 145 | bcwrite_ktabk(ctx, key, 0); | ||
| 146 | bcwrite_ktabk(ctx, (TValue *)((char *)key - offsetof(Node, key)), 1); | ||
| 147 | key = heap[--nhash]; /* Remove last key. */ | ||
| 148 | bcwrite_ktabk_heap_insert(heap, 0, nhash, key); /* Re-insert. */ | ||
| 149 | } while (nhash); | ||
| 150 | } | ||
| 151 | |||
| 111 | /* Write a template table. */ | 152 | /* Write a template table. */ |
| 112 | static void bcwrite_ktab(BCWriteCtx *ctx, const GCtab *t) | 153 | static void bcwrite_ktab(BCWriteCtx *ctx, char *p, const GCtab *t) |
| 113 | { | 154 | { |
| 114 | MSize narray = 0, nhash = 0; | 155 | MSize narray = 0, nhash = 0; |
| 115 | if (t->asize > 0) { /* Determine max. length of array part. */ | 156 | if (t->asize > 0) { /* Determine max. length of array part. */ |
| @@ -124,11 +165,12 @@ static void bcwrite_ktab(BCWriteCtx *ctx, const GCtab *t) | |||
| 124 | MSize i, hmask = t->hmask; | 165 | MSize i, hmask = t->hmask; |
| 125 | Node *node = noderef(t->node); | 166 | Node *node = noderef(t->node); |
| 126 | for (i = 0; i <= hmask; i++) | 167 | for (i = 0; i <= hmask; i++) |
| 127 | nhash += !tvisnil(&node[i].key); | 168 | nhash += !tvisnil(&node[i].val); |
| 128 | } | 169 | } |
| 129 | /* Write number of array slots and hash slots. */ | 170 | /* Write number of array slots and hash slots. */ |
| 130 | bcwrite_uleb128(ctx, narray); | 171 | p = lj_strfmt_wuleb128(p, narray); |
| 131 | bcwrite_uleb128(ctx, nhash); | 172 | p = lj_strfmt_wuleb128(p, nhash); |
| 173 | ctx->sb.w = p; | ||
| 132 | if (narray) { /* Write array entries (may contain nil). */ | 174 | if (narray) { /* Write array entries (may contain nil). */ |
| 133 | MSize i; | 175 | MSize i; |
| 134 | TValue *o = tvref(t->array); | 176 | TValue *o = tvref(t->array); |
| @@ -136,14 +178,20 @@ static void bcwrite_ktab(BCWriteCtx *ctx, const GCtab *t) | |||
| 136 | bcwrite_ktabk(ctx, o, 1); | 178 | bcwrite_ktabk(ctx, o, 1); |
| 137 | } | 179 | } |
| 138 | if (nhash) { /* Write hash entries. */ | 180 | if (nhash) { /* Write hash entries. */ |
| 139 | MSize i = nhash; | ||
| 140 | Node *node = noderef(t->node) + t->hmask; | 181 | Node *node = noderef(t->node) + t->hmask; |
| 141 | for (;; node--) | 182 | if ((ctx->flags & BCDUMP_F_DETERMINISTIC) && nhash > 1) { |
| 142 | if (!tvisnil(&node->key)) { | 183 | if (ctx->heapsz < nhash) |
| 143 | bcwrite_ktabk(ctx, &node->key, 0); | 184 | bcwrite_heap_resize(ctx, t->hmask + 1); |
| 144 | bcwrite_ktabk(ctx, &node->val, 1); | 185 | bcwrite_ktab_sorted_hash(ctx, node, nhash); |
| 145 | if (--i == 0) break; | 186 | } else { |
| 146 | } | 187 | MSize i = nhash; |
| 188 | for (;; node--) | ||
| 189 | if (!tvisnil(&node->val)) { | ||
| 190 | bcwrite_ktabk(ctx, &node->key, 0); | ||
| 191 | bcwrite_ktabk(ctx, &node->val, 1); | ||
| 192 | if (--i == 0) break; | ||
| 193 | } | ||
| 194 | } | ||
| 147 | } | 195 | } |
| 148 | } | 196 | } |
| 149 | 197 | ||
| @@ -155,12 +203,13 @@ static void bcwrite_kgc(BCWriteCtx *ctx, GCproto *pt) | |||
| 155 | for (i = 0; i < sizekgc; i++, kr++) { | 203 | for (i = 0; i < sizekgc; i++, kr++) { |
| 156 | GCobj *o = gcref(*kr); | 204 | GCobj *o = gcref(*kr); |
| 157 | MSize tp, need = 1; | 205 | MSize tp, need = 1; |
| 206 | char *p; | ||
| 158 | /* Determine constant type and needed size. */ | 207 | /* Determine constant type and needed size. */ |
| 159 | if (o->gch.gct == ~LJ_TSTR) { | 208 | if (o->gch.gct == ~LJ_TSTR) { |
| 160 | tp = BCDUMP_KGC_STR + gco2str(o)->len; | 209 | tp = BCDUMP_KGC_STR + gco2str(o)->len; |
| 161 | need = 5+gco2str(o)->len; | 210 | need = 5+gco2str(o)->len; |
| 162 | } else if (o->gch.gct == ~LJ_TPROTO) { | 211 | } else if (o->gch.gct == ~LJ_TPROTO) { |
| 163 | lua_assert((pt->flags & PROTO_CHILD)); | 212 | lj_assertBCW((pt->flags & PROTO_CHILD), "prototype has unexpected child"); |
| 164 | tp = BCDUMP_KGC_CHILD; | 213 | tp = BCDUMP_KGC_CHILD; |
| 165 | #if LJ_HASFFI | 214 | #if LJ_HASFFI |
| 166 | } else if (o->gch.gct == ~LJ_TCDATA) { | 215 | } else if (o->gch.gct == ~LJ_TCDATA) { |
| @@ -171,34 +220,38 @@ static void bcwrite_kgc(BCWriteCtx *ctx, GCproto *pt) | |||
| 171 | } else if (id == CTID_UINT64) { | 220 | } else if (id == CTID_UINT64) { |
| 172 | tp = BCDUMP_KGC_U64; | 221 | tp = BCDUMP_KGC_U64; |
| 173 | } else { | 222 | } else { |
| 174 | lua_assert(id == CTID_COMPLEX_DOUBLE); | 223 | lj_assertBCW(id == CTID_COMPLEX_DOUBLE, |
| 224 | "bad cdata constant CTID %d", id); | ||
| 175 | tp = BCDUMP_KGC_COMPLEX; | 225 | tp = BCDUMP_KGC_COMPLEX; |
| 176 | } | 226 | } |
| 177 | #endif | 227 | #endif |
| 178 | } else { | 228 | } else { |
| 179 | lua_assert(o->gch.gct == ~LJ_TTAB); | 229 | lj_assertBCW(o->gch.gct == ~LJ_TTAB, |
| 230 | "bad constant GC type %d", o->gch.gct); | ||
| 180 | tp = BCDUMP_KGC_TAB; | 231 | tp = BCDUMP_KGC_TAB; |
| 181 | need = 1+2*5; | 232 | need = 1+2*5; |
| 182 | } | 233 | } |
| 183 | /* Write constant type. */ | 234 | /* Write constant type. */ |
| 184 | bcwrite_need(ctx, need); | 235 | p = lj_buf_more(&ctx->sb, need); |
| 185 | bcwrite_uleb128(ctx, tp); | 236 | p = lj_strfmt_wuleb128(p, tp); |
| 186 | /* Write constant data (if any). */ | 237 | /* Write constant data (if any). */ |
| 187 | if (tp >= BCDUMP_KGC_STR) { | 238 | if (tp >= BCDUMP_KGC_STR) { |
| 188 | bcwrite_block(ctx, strdata(gco2str(o)), gco2str(o)->len); | 239 | p = lj_buf_wmem(p, strdata(gco2str(o)), gco2str(o)->len); |
| 189 | } else if (tp == BCDUMP_KGC_TAB) { | 240 | } else if (tp == BCDUMP_KGC_TAB) { |
| 190 | bcwrite_ktab(ctx, gco2tab(o)); | 241 | bcwrite_ktab(ctx, p, gco2tab(o)); |
| 242 | continue; | ||
| 191 | #if LJ_HASFFI | 243 | #if LJ_HASFFI |
| 192 | } else if (tp != BCDUMP_KGC_CHILD) { | 244 | } else if (tp != BCDUMP_KGC_CHILD) { |
| 193 | cTValue *p = (TValue *)cdataptr(gco2cd(o)); | 245 | cTValue *q = (TValue *)cdataptr(gco2cd(o)); |
| 194 | bcwrite_uleb128(ctx, p[0].u32.lo); | 246 | p = lj_strfmt_wuleb128(p, q[0].u32.lo); |
| 195 | bcwrite_uleb128(ctx, p[0].u32.hi); | 247 | p = lj_strfmt_wuleb128(p, q[0].u32.hi); |
| 196 | if (tp == BCDUMP_KGC_COMPLEX) { | 248 | if (tp == BCDUMP_KGC_COMPLEX) { |
| 197 | bcwrite_uleb128(ctx, p[1].u32.lo); | 249 | p = lj_strfmt_wuleb128(p, q[1].u32.lo); |
| 198 | bcwrite_uleb128(ctx, p[1].u32.hi); | 250 | p = lj_strfmt_wuleb128(p, q[1].u32.hi); |
| 199 | } | 251 | } |
| 200 | #endif | 252 | #endif |
| 201 | } | 253 | } |
| 254 | ctx->sb.w = p; | ||
| 202 | } | 255 | } |
| 203 | } | 256 | } |
| 204 | 257 | ||
| @@ -207,7 +260,7 @@ static void bcwrite_knum(BCWriteCtx *ctx, GCproto *pt) | |||
| 207 | { | 260 | { |
| 208 | MSize i, sizekn = pt->sizekn; | 261 | MSize i, sizekn = pt->sizekn; |
| 209 | cTValue *o = mref(pt->k, TValue); | 262 | cTValue *o = mref(pt->k, TValue); |
| 210 | bcwrite_need(ctx, 10*sizekn); | 263 | char *p = lj_buf_more(&ctx->sb, 10*sizekn); |
| 211 | for (i = 0; i < sizekn; i++, o++) { | 264 | for (i = 0; i < sizekn; i++, o++) { |
| 212 | int32_t k; | 265 | int32_t k; |
| 213 | if (tvisint(o)) { | 266 | if (tvisint(o)) { |
| @@ -215,60 +268,60 @@ static void bcwrite_knum(BCWriteCtx *ctx, GCproto *pt) | |||
| 215 | goto save_int; | 268 | goto save_int; |
| 216 | } else { | 269 | } else { |
| 217 | /* Write a 33 bit ULEB128 for the int (lsb=0) or loword (lsb=1). */ | 270 | /* Write a 33 bit ULEB128 for the int (lsb=0) or loword (lsb=1). */ |
| 218 | if (!LJ_DUALNUM) { /* Narrow number constants to integers. */ | 271 | if (!LJ_DUALNUM && o->u32.hi != LJ_KEYINDEX) { |
| 219 | lua_Number num = numV(o); | 272 | /* Narrow number constants to integers. */ |
| 220 | k = lj_num2int(num); | 273 | int64_t i64; |
| 221 | if (num == (lua_Number)k) { /* -0 is never a constant. */ | 274 | if (lj_num2int_check(numV(o), i64, k)) { /* -0 is never a constant. */ |
| 222 | save_int: | 275 | save_int: |
| 223 | bcwrite_uleb128(ctx, 2*(uint32_t)k | ((uint32_t)k & 0x80000000u)); | 276 | p = lj_strfmt_wuleb128(p, 2*(uint32_t)k | ((uint32_t)k&0x80000000u)); |
| 224 | if (k < 0) { | 277 | if (k < 0) |
| 225 | char *p = &ctx->sb.buf[ctx->sb.n-1]; | 278 | p[-1] = (p[-1] & 7) | ((k>>27) & 0x18); |
| 226 | *p = (*p & 7) | ((k>>27) & 0x18); | ||
| 227 | } | ||
| 228 | continue; | 279 | continue; |
| 229 | } | 280 | } |
| 230 | } | 281 | } |
| 231 | bcwrite_uleb128(ctx, 1+(2*o->u32.lo | (o->u32.lo & 0x80000000u))); | 282 | p = lj_strfmt_wuleb128(p, 1+(2*o->u32.lo | (o->u32.lo & 0x80000000u))); |
| 232 | if (o->u32.lo >= 0x80000000u) { | 283 | if (o->u32.lo >= 0x80000000u) |
| 233 | char *p = &ctx->sb.buf[ctx->sb.n-1]; | 284 | p[-1] = (p[-1] & 7) | ((o->u32.lo>>27) & 0x18); |
| 234 | *p = (*p & 7) | ((o->u32.lo>>27) & 0x18); | 285 | p = lj_strfmt_wuleb128(p, o->u32.hi); |
| 235 | } | ||
| 236 | bcwrite_uleb128(ctx, o->u32.hi); | ||
| 237 | } | 286 | } |
| 238 | } | 287 | } |
| 288 | ctx->sb.w = p; | ||
| 239 | } | 289 | } |
| 240 | 290 | ||
| 241 | /* Write bytecode instructions. */ | 291 | /* Write bytecode instructions. */ |
| 242 | static void bcwrite_bytecode(BCWriteCtx *ctx, GCproto *pt) | 292 | static char *bcwrite_bytecode(BCWriteCtx *ctx, char *p, GCproto *pt) |
| 243 | { | 293 | { |
| 244 | MSize nbc = pt->sizebc-1; /* Omit the [JI]FUNC* header. */ | 294 | MSize nbc = pt->sizebc-1; /* Omit the [JI]FUNC* header. */ |
| 245 | #if LJ_HASJIT | 295 | #if LJ_HASJIT |
| 246 | uint8_t *p = (uint8_t *)&ctx->sb.buf[ctx->sb.n]; | 296 | uint8_t *q = (uint8_t *)p; |
| 247 | #endif | 297 | #endif |
| 248 | bcwrite_block(ctx, proto_bc(pt)+1, nbc*(MSize)sizeof(BCIns)); | 298 | p = lj_buf_wmem(p, proto_bc(pt)+1, nbc*(MSize)sizeof(BCIns)); |
| 299 | UNUSED(ctx); | ||
| 249 | #if LJ_HASJIT | 300 | #if LJ_HASJIT |
| 250 | /* Unpatch modified bytecode containing ILOOP/JLOOP etc. */ | 301 | /* Unpatch modified bytecode containing ILOOP/JLOOP etc. */ |
| 251 | if ((pt->flags & PROTO_ILOOP) || pt->trace) { | 302 | if ((pt->flags & PROTO_ILOOP) || pt->trace) { |
| 252 | jit_State *J = L2J(ctx->L); | 303 | jit_State *J = L2J(sbufL(&ctx->sb)); |
| 253 | MSize i; | 304 | MSize i; |
| 254 | for (i = 0; i < nbc; i++, p += sizeof(BCIns)) { | 305 | for (i = 0; i < nbc; i++, q += sizeof(BCIns)) { |
| 255 | BCOp op = (BCOp)p[LJ_ENDIAN_SELECT(0, 3)]; | 306 | BCOp op = (BCOp)q[LJ_ENDIAN_SELECT(0, 3)]; |
| 256 | if (op == BC_IFORL || op == BC_IITERL || op == BC_ILOOP || | 307 | if (op == BC_IFORL || op == BC_IITERL || op == BC_ILOOP || |
| 257 | op == BC_JFORI) { | 308 | op == BC_JFORI) { |
| 258 | p[LJ_ENDIAN_SELECT(0, 3)] = (uint8_t)(op-BC_IFORL+BC_FORL); | 309 | q[LJ_ENDIAN_SELECT(0, 3)] = (uint8_t)(op-BC_IFORL+BC_FORL); |
| 259 | } else if (op == BC_JFORL || op == BC_JITERL || op == BC_JLOOP) { | 310 | } else if (op == BC_JFORL || op == BC_JITERL || op == BC_JLOOP) { |
| 260 | BCReg rd = p[LJ_ENDIAN_SELECT(2, 1)] + (p[LJ_ENDIAN_SELECT(3, 0)] << 8); | 311 | BCReg rd = q[LJ_ENDIAN_SELECT(2, 1)] + (q[LJ_ENDIAN_SELECT(3, 0)] << 8); |
| 261 | memcpy(p, &traceref(J, rd)->startins, 4); | 312 | memcpy(q, &traceref(J, rd)->startins, 4); |
| 262 | } | 313 | } |
| 263 | } | 314 | } |
| 264 | } | 315 | } |
| 265 | #endif | 316 | #endif |
| 317 | return p; | ||
| 266 | } | 318 | } |
| 267 | 319 | ||
| 268 | /* Write prototype. */ | 320 | /* Write prototype. */ |
| 269 | static void bcwrite_proto(BCWriteCtx *ctx, GCproto *pt) | 321 | static void bcwrite_proto(BCWriteCtx *ctx, GCproto *pt) |
| 270 | { | 322 | { |
| 271 | MSize sizedbg = 0; | 323 | MSize sizedbg = 0; |
| 324 | char *p; | ||
| 272 | 325 | ||
| 273 | /* Recursively write children of prototype. */ | 326 | /* Recursively write children of prototype. */ |
| 274 | if ((pt->flags & PROTO_CHILD)) { | 327 | if ((pt->flags & PROTO_CHILD)) { |
| @@ -282,31 +335,32 @@ static void bcwrite_proto(BCWriteCtx *ctx, GCproto *pt) | |||
| 282 | } | 335 | } |
| 283 | 336 | ||
| 284 | /* Start writing the prototype info to a buffer. */ | 337 | /* Start writing the prototype info to a buffer. */ |
| 285 | lj_str_resetbuf(&ctx->sb); | 338 | p = lj_buf_need(&ctx->sb, |
| 286 | ctx->sb.n = 5; /* Leave room for final size. */ | 339 | 5+4+6*5+(pt->sizebc-1)*(MSize)sizeof(BCIns)+pt->sizeuv*2); |
| 287 | bcwrite_need(ctx, 4+6*5+(pt->sizebc-1)*(MSize)sizeof(BCIns)+pt->sizeuv*2); | 340 | p += 5; /* Leave room for final size. */ |
| 288 | 341 | ||
| 289 | /* Write prototype header. */ | 342 | /* Write prototype header. */ |
| 290 | bcwrite_byte(ctx, (pt->flags & (PROTO_CHILD|PROTO_VARARG|PROTO_FFI))); | 343 | *p++ = (pt->flags & (PROTO_CHILD|PROTO_VARARG|PROTO_FFI)); |
| 291 | bcwrite_byte(ctx, pt->numparams); | 344 | *p++ = pt->numparams; |
| 292 | bcwrite_byte(ctx, pt->framesize); | 345 | *p++ = pt->framesize; |
| 293 | bcwrite_byte(ctx, pt->sizeuv); | 346 | *p++ = pt->sizeuv; |
| 294 | bcwrite_uleb128(ctx, pt->sizekgc); | 347 | p = lj_strfmt_wuleb128(p, pt->sizekgc); |
| 295 | bcwrite_uleb128(ctx, pt->sizekn); | 348 | p = lj_strfmt_wuleb128(p, pt->sizekn); |
| 296 | bcwrite_uleb128(ctx, pt->sizebc-1); | 349 | p = lj_strfmt_wuleb128(p, pt->sizebc-1); |
| 297 | if (!ctx->strip) { | 350 | if (!(ctx->flags & BCDUMP_F_STRIP)) { |
| 298 | if (proto_lineinfo(pt)) | 351 | if (proto_lineinfo(pt)) |
| 299 | sizedbg = pt->sizept - (MSize)((char *)proto_lineinfo(pt) - (char *)pt); | 352 | sizedbg = pt->sizept - (MSize)((char *)proto_lineinfo(pt) - (char *)pt); |
| 300 | bcwrite_uleb128(ctx, sizedbg); | 353 | p = lj_strfmt_wuleb128(p, sizedbg); |
| 301 | if (sizedbg) { | 354 | if (sizedbg) { |
| 302 | bcwrite_uleb128(ctx, pt->firstline); | 355 | p = lj_strfmt_wuleb128(p, pt->firstline); |
| 303 | bcwrite_uleb128(ctx, pt->numline); | 356 | p = lj_strfmt_wuleb128(p, pt->numline); |
| 304 | } | 357 | } |
| 305 | } | 358 | } |
| 306 | 359 | ||
| 307 | /* Write bytecode instructions and upvalue refs. */ | 360 | /* Write bytecode instructions and upvalue refs. */ |
| 308 | bcwrite_bytecode(ctx, pt); | 361 | p = bcwrite_bytecode(ctx, p, pt); |
| 309 | bcwrite_block(ctx, proto_uv(pt), pt->sizeuv*2); | 362 | p = lj_buf_wmem(p, proto_uv(pt), pt->sizeuv*2); |
| 363 | ctx->sb.w = p; | ||
| 310 | 364 | ||
| 311 | /* Write constants. */ | 365 | /* Write constants. */ |
| 312 | bcwrite_kgc(ctx, pt); | 366 | bcwrite_kgc(ctx, pt); |
| @@ -314,18 +368,19 @@ static void bcwrite_proto(BCWriteCtx *ctx, GCproto *pt) | |||
| 314 | 368 | ||
| 315 | /* Write debug info, if not stripped. */ | 369 | /* Write debug info, if not stripped. */ |
| 316 | if (sizedbg) { | 370 | if (sizedbg) { |
| 317 | bcwrite_need(ctx, sizedbg); | 371 | p = lj_buf_more(&ctx->sb, sizedbg); |
| 318 | bcwrite_block(ctx, proto_lineinfo(pt), sizedbg); | 372 | p = lj_buf_wmem(p, proto_lineinfo(pt), sizedbg); |
| 373 | ctx->sb.w = p; | ||
| 319 | } | 374 | } |
| 320 | 375 | ||
| 321 | /* Pass buffer to writer function. */ | 376 | /* Pass buffer to writer function. */ |
| 322 | if (ctx->status == 0) { | 377 | if (ctx->status == 0) { |
| 323 | MSize n = ctx->sb.n - 5; | 378 | MSize n = sbuflen(&ctx->sb) - 5; |
| 324 | MSize nn = (lj_fls(n)+8)*9 >> 6; | 379 | MSize nn = (lj_fls(n)+8)*9 >> 6; |
| 325 | ctx->sb.n = 5 - nn; | 380 | char *q = ctx->sb.b + (5 - nn); |
| 326 | bcwrite_uleb128(ctx, n); /* Fill in final size. */ | 381 | p = lj_strfmt_wuleb128(q, n); /* Fill in final size. */ |
| 327 | lua_assert(ctx->sb.n == 5); | 382 | lj_assertBCW(p == ctx->sb.b + 5, "bad ULEB128 write"); |
| 328 | ctx->status = ctx->wfunc(ctx->L, ctx->sb.buf+5-nn, nn+n, ctx->wdata); | 383 | ctx->status = ctx->wfunc(sbufL(&ctx->sb), q, nn+n, ctx->wdata); |
| 329 | } | 384 | } |
| 330 | } | 385 | } |
| 331 | 386 | ||
| @@ -335,20 +390,20 @@ static void bcwrite_header(BCWriteCtx *ctx) | |||
| 335 | GCstr *chunkname = proto_chunkname(ctx->pt); | 390 | GCstr *chunkname = proto_chunkname(ctx->pt); |
| 336 | const char *name = strdata(chunkname); | 391 | const char *name = strdata(chunkname); |
| 337 | MSize len = chunkname->len; | 392 | MSize len = chunkname->len; |
| 338 | lj_str_resetbuf(&ctx->sb); | 393 | char *p = lj_buf_need(&ctx->sb, 5+5+len); |
| 339 | bcwrite_need(ctx, 5+5+len); | 394 | *p++ = BCDUMP_HEAD1; |
| 340 | bcwrite_byte(ctx, BCDUMP_HEAD1); | 395 | *p++ = BCDUMP_HEAD2; |
| 341 | bcwrite_byte(ctx, BCDUMP_HEAD2); | 396 | *p++ = BCDUMP_HEAD3; |
| 342 | bcwrite_byte(ctx, BCDUMP_HEAD3); | 397 | *p++ = BCDUMP_VERSION; |
| 343 | bcwrite_byte(ctx, BCDUMP_VERSION); | 398 | *p++ = (ctx->flags & (BCDUMP_F_STRIP | BCDUMP_F_FR2)) + |
| 344 | bcwrite_byte(ctx, (ctx->strip ? BCDUMP_F_STRIP : 0) + | 399 | LJ_BE*BCDUMP_F_BE + |
| 345 | (LJ_BE ? BCDUMP_F_BE : 0) + | 400 | ((ctx->pt->flags & PROTO_FFI) ? BCDUMP_F_FFI : 0); |
| 346 | ((ctx->pt->flags & PROTO_FFI) ? BCDUMP_F_FFI : 0)); | 401 | if (!(ctx->flags & BCDUMP_F_STRIP)) { |
| 347 | if (!ctx->strip) { | 402 | p = lj_strfmt_wuleb128(p, len); |
| 348 | bcwrite_uleb128(ctx, len); | 403 | p = lj_buf_wmem(p, name, len); |
| 349 | bcwrite_block(ctx, name, len); | ||
| 350 | } | 404 | } |
| 351 | ctx->status = ctx->wfunc(ctx->L, ctx->sb.buf, ctx->sb.n, ctx->wdata); | 405 | ctx->status = ctx->wfunc(sbufL(&ctx->sb), ctx->sb.b, |
| 406 | (MSize)(p - ctx->sb.b), ctx->wdata); | ||
| 352 | } | 407 | } |
| 353 | 408 | ||
| 354 | /* Write footer of bytecode dump. */ | 409 | /* Write footer of bytecode dump. */ |
| @@ -356,7 +411,7 @@ static void bcwrite_footer(BCWriteCtx *ctx) | |||
| 356 | { | 411 | { |
| 357 | if (ctx->status == 0) { | 412 | if (ctx->status == 0) { |
| 358 | uint8_t zero = 0; | 413 | uint8_t zero = 0; |
| 359 | ctx->status = ctx->wfunc(ctx->L, &zero, 1, ctx->wdata); | 414 | ctx->status = ctx->wfunc(sbufL(&ctx->sb), &zero, 1, ctx->wdata); |
| 360 | } | 415 | } |
| 361 | } | 416 | } |
| 362 | 417 | ||
| @@ -364,8 +419,8 @@ static void bcwrite_footer(BCWriteCtx *ctx) | |||
| 364 | static TValue *cpwriter(lua_State *L, lua_CFunction dummy, void *ud) | 419 | static TValue *cpwriter(lua_State *L, lua_CFunction dummy, void *ud) |
| 365 | { | 420 | { |
| 366 | BCWriteCtx *ctx = (BCWriteCtx *)ud; | 421 | BCWriteCtx *ctx = (BCWriteCtx *)ud; |
| 367 | UNUSED(dummy); | 422 | UNUSED(L); UNUSED(dummy); |
| 368 | lj_str_resizebuf(L, &ctx->sb, 1024); /* Avoids resize for most prototypes. */ | 423 | lj_buf_need(&ctx->sb, 1024); /* Avoids resize for most prototypes. */ |
| 369 | bcwrite_header(ctx); | 424 | bcwrite_header(ctx); |
| 370 | bcwrite_proto(ctx, ctx->pt); | 425 | bcwrite_proto(ctx, ctx->pt); |
| 371 | bcwrite_footer(ctx); | 426 | bcwrite_footer(ctx); |
| @@ -374,20 +429,25 @@ static TValue *cpwriter(lua_State *L, lua_CFunction dummy, void *ud) | |||
| 374 | 429 | ||
| 375 | /* Write bytecode for a prototype. */ | 430 | /* Write bytecode for a prototype. */ |
| 376 | int lj_bcwrite(lua_State *L, GCproto *pt, lua_Writer writer, void *data, | 431 | int lj_bcwrite(lua_State *L, GCproto *pt, lua_Writer writer, void *data, |
| 377 | int strip) | 432 | uint32_t flags) |
| 378 | { | 433 | { |
| 379 | BCWriteCtx ctx; | 434 | BCWriteCtx ctx; |
| 380 | int status; | 435 | int status; |
| 381 | ctx.L = L; | ||
| 382 | ctx.pt = pt; | 436 | ctx.pt = pt; |
| 383 | ctx.wfunc = writer; | 437 | ctx.wfunc = writer; |
| 384 | ctx.wdata = data; | 438 | ctx.wdata = data; |
| 385 | ctx.strip = strip; | 439 | ctx.heapsz = 0; |
| 440 | if ((bc_op(proto_bc(pt)[0]) != BC_NOT) == LJ_FR2) flags |= BCDUMP_F_FR2; | ||
| 441 | ctx.flags = flags; | ||
| 386 | ctx.status = 0; | 442 | ctx.status = 0; |
| 387 | lj_str_initbuf(&ctx.sb); | 443 | #ifdef LUA_USE_ASSERT |
| 444 | ctx.g = G(L); | ||
| 445 | #endif | ||
| 446 | lj_buf_init(L, &ctx.sb); | ||
| 388 | status = lj_vm_cpcall(L, NULL, &ctx, cpwriter); | 447 | status = lj_vm_cpcall(L, NULL, &ctx, cpwriter); |
| 389 | if (status == 0) status = ctx.status; | 448 | if (status == 0) status = ctx.status; |
| 390 | lj_str_freebuf(G(ctx.L), &ctx.sb); | 449 | lj_buf_free(G(sbufL(&ctx.sb)), &ctx.sb); |
| 450 | bcwrite_heap_resize(&ctx, 0); | ||
| 391 | return status; | 451 | return status; |
| 392 | } | 452 | } |
| 393 | 453 | ||
