aboutsummaryrefslogtreecommitdiff
path: root/src/lj_bcwrite.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lj_bcwrite.c')
-rw-r--r--src/lj_bcwrite.c366
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. */
24typedef struct BCWriteCtx { 25typedef 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
37static 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. */
45static 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. */
52static 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. */
61static 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. */
67static 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. */
80static void bcwrite_ktabk(BCWriteCtx *ctx, cTValue *o, int narrow) 48static 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. */
84static 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. */
97static 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. */
119static 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. */
133static 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. */
112static void bcwrite_ktab(BCWriteCtx *ctx, const GCtab *t) 153static 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. */
242static void bcwrite_bytecode(BCWriteCtx *ctx, GCproto *pt) 292static 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. */
269static void bcwrite_proto(BCWriteCtx *ctx, GCproto *pt) 321static 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)
364static TValue *cpwriter(lua_State *L, lua_CFunction dummy, void *ud) 419static 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. */
376int lj_bcwrite(lua_State *L, GCproto *pt, lua_Writer writer, void *data, 431int 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