diff options
Diffstat (limited to 'src/lj_bcwrite.c')
-rw-r--r-- | src/lj_bcwrite.c | 109 |
1 files changed, 94 insertions, 15 deletions
diff --git a/src/lj_bcwrite.c b/src/lj_bcwrite.c index dd969413..c062dc49 100644 --- a/src/lj_bcwrite.c +++ b/src/lj_bcwrite.c | |||
@@ -27,7 +27,9 @@ typedef struct BCWriteCtx { | |||
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. */ |
32 | #ifdef LUA_USE_ASSERT | 34 | #ifdef LUA_USE_ASSERT |
33 | global_State *g; | 35 | global_State *g; |
@@ -76,6 +78,75 @@ static void bcwrite_ktabk(BCWriteCtx *ctx, cTValue *o, int narrow) | |||
76 | ctx->sb.w = p; | 78 | ctx->sb.w = p; |
77 | } | 79 | } |
78 | 80 | ||
81 | /* Compare two template table keys. */ | ||
82 | static LJ_AINLINE int bcwrite_ktabk_lt(TValue *a, TValue *b) | ||
83 | { | ||
84 | uint32_t at = itype(a), bt = itype(b); | ||
85 | if (at != bt) { /* This also handles false and true keys. */ | ||
86 | return at < bt; | ||
87 | } else if (at == LJ_TSTR) { | ||
88 | return lj_str_cmp(strV(a), strV(b)) < 0; | ||
89 | } else { | ||
90 | return a->u64 < b->u64; /* This works for numbers and integers. */ | ||
91 | } | ||
92 | } | ||
93 | |||
94 | /* Insert key into a sorted heap. */ | ||
95 | static void bcwrite_ktabk_heap_insert(TValue **heap, MSize idx, MSize end, | ||
96 | TValue *key) | ||
97 | { | ||
98 | MSize child; | ||
99 | while ((child = idx * 2 + 1) < end) { | ||
100 | /* Find lower of the two children. */ | ||
101 | TValue *c0 = heap[child]; | ||
102 | if (child + 1 < end) { | ||
103 | TValue *c1 = heap[child + 1]; | ||
104 | if (bcwrite_ktabk_lt(c1, c0)) { | ||
105 | c0 = c1; | ||
106 | child++; | ||
107 | } | ||
108 | } | ||
109 | if (bcwrite_ktabk_lt(key, c0)) break; /* Key lower? Found our position. */ | ||
110 | heap[idx] = c0; /* Move lower child up. */ | ||
111 | idx = child; /* Descend. */ | ||
112 | } | ||
113 | heap[idx] = key; /* Insert key here. */ | ||
114 | } | ||
115 | |||
116 | /* Resize heap, dropping content. */ | ||
117 | static void bcwrite_heap_resize(BCWriteCtx *ctx, uint32_t nsz) | ||
118 | { | ||
119 | lua_State *L = sbufL(&ctx->sb); | ||
120 | if (ctx->heapsz) { | ||
121 | lj_mem_freevec(G(L), ctx->heap, ctx->heapsz, TValue *); | ||
122 | ctx->heapsz = 0; | ||
123 | } | ||
124 | if (nsz) { | ||
125 | ctx->heap = lj_mem_newvec(L, nsz, TValue *); | ||
126 | ctx->heapsz = nsz; | ||
127 | } | ||
128 | } | ||
129 | |||
130 | /* Write hash part of template table in sorted order. */ | ||
131 | static void bcwrite_ktab_sorted_hash(BCWriteCtx *ctx, Node *node, MSize nhash) | ||
132 | { | ||
133 | TValue **heap = ctx->heap; | ||
134 | MSize i = nhash; | ||
135 | for (;; node--) { /* Build heap. */ | ||
136 | if (!tvisnil(&node->val)) { | ||
137 | bcwrite_ktabk_heap_insert(heap, --i, nhash, &node->key); | ||
138 | if (i == 0) break; | ||
139 | } | ||
140 | } | ||
141 | do { /* Drain heap. */ | ||
142 | TValue *key = heap[0]; /* Output lowest key from top. */ | ||
143 | bcwrite_ktabk(ctx, key, 0); | ||
144 | bcwrite_ktabk(ctx, (TValue *)((char *)key - offsetof(Node, key)), 1); | ||
145 | key = heap[--nhash]; /* Remove last key. */ | ||
146 | bcwrite_ktabk_heap_insert(heap, 0, nhash, key); /* Re-insert. */ | ||
147 | } while (nhash); | ||
148 | } | ||
149 | |||
79 | /* Write a template table. */ | 150 | /* Write a template table. */ |
80 | static void bcwrite_ktab(BCWriteCtx *ctx, char *p, const GCtab *t) | 151 | static void bcwrite_ktab(BCWriteCtx *ctx, char *p, const GCtab *t) |
81 | { | 152 | { |
@@ -105,14 +176,20 @@ static void bcwrite_ktab(BCWriteCtx *ctx, char *p, const GCtab *t) | |||
105 | bcwrite_ktabk(ctx, o, 1); | 176 | bcwrite_ktabk(ctx, o, 1); |
106 | } | 177 | } |
107 | if (nhash) { /* Write hash entries. */ | 178 | if (nhash) { /* Write hash entries. */ |
108 | MSize i = nhash; | ||
109 | Node *node = noderef(t->node) + t->hmask; | 179 | Node *node = noderef(t->node) + t->hmask; |
110 | for (;; node--) | 180 | if ((ctx->flags & BCDUMP_F_DETERMINISTIC) && nhash > 1) { |
111 | if (!tvisnil(&node->val)) { | 181 | if (ctx->heapsz < nhash) |
112 | bcwrite_ktabk(ctx, &node->key, 0); | 182 | bcwrite_heap_resize(ctx, t->hmask + 1); |
113 | bcwrite_ktabk(ctx, &node->val, 1); | 183 | bcwrite_ktab_sorted_hash(ctx, node, nhash); |
114 | if (--i == 0) break; | 184 | } else { |
115 | } | 185 | MSize i = nhash; |
186 | for (;; node--) | ||
187 | if (!tvisnil(&node->val)) { | ||
188 | bcwrite_ktabk(ctx, &node->key, 0); | ||
189 | bcwrite_ktabk(ctx, &node->val, 1); | ||
190 | if (--i == 0) break; | ||
191 | } | ||
192 | } | ||
116 | } | 193 | } |
117 | } | 194 | } |
118 | 195 | ||
@@ -269,7 +346,7 @@ static void bcwrite_proto(BCWriteCtx *ctx, GCproto *pt) | |||
269 | p = lj_strfmt_wuleb128(p, pt->sizekgc); | 346 | p = lj_strfmt_wuleb128(p, pt->sizekgc); |
270 | p = lj_strfmt_wuleb128(p, pt->sizekn); | 347 | p = lj_strfmt_wuleb128(p, pt->sizekn); |
271 | p = lj_strfmt_wuleb128(p, pt->sizebc-1); | 348 | p = lj_strfmt_wuleb128(p, pt->sizebc-1); |
272 | if (!ctx->strip) { | 349 | if (!(ctx->flags & BCDUMP_F_STRIP)) { |
273 | if (proto_lineinfo(pt)) | 350 | if (proto_lineinfo(pt)) |
274 | sizedbg = pt->sizept - (MSize)((char *)proto_lineinfo(pt) - (char *)pt); | 351 | sizedbg = pt->sizept - (MSize)((char *)proto_lineinfo(pt) - (char *)pt); |
275 | p = lj_strfmt_wuleb128(p, sizedbg); | 352 | p = lj_strfmt_wuleb128(p, sizedbg); |
@@ -317,11 +394,10 @@ static void bcwrite_header(BCWriteCtx *ctx) | |||
317 | *p++ = BCDUMP_HEAD2; | 394 | *p++ = BCDUMP_HEAD2; |
318 | *p++ = BCDUMP_HEAD3; | 395 | *p++ = BCDUMP_HEAD3; |
319 | *p++ = BCDUMP_VERSION; | 396 | *p++ = BCDUMP_VERSION; |
320 | *p++ = (ctx->strip ? BCDUMP_F_STRIP : 0) + | 397 | *p++ = (ctx->flags & (BCDUMP_F_STRIP | BCDUMP_F_FR2)) + |
321 | LJ_BE*BCDUMP_F_BE + | 398 | LJ_BE*BCDUMP_F_BE + |
322 | ((ctx->pt->flags & PROTO_FFI) ? BCDUMP_F_FFI : 0) + | 399 | ((ctx->pt->flags & PROTO_FFI) ? BCDUMP_F_FFI : 0); |
323 | LJ_FR2*BCDUMP_F_FR2; | 400 | if (!(ctx->flags & BCDUMP_F_STRIP)) { |
324 | if (!ctx->strip) { | ||
325 | p = lj_strfmt_wuleb128(p, len); | 401 | p = lj_strfmt_wuleb128(p, len); |
326 | p = lj_buf_wmem(p, name, len); | 402 | p = lj_buf_wmem(p, name, len); |
327 | } | 403 | } |
@@ -352,14 +428,16 @@ static TValue *cpwriter(lua_State *L, lua_CFunction dummy, void *ud) | |||
352 | 428 | ||
353 | /* Write bytecode for a prototype. */ | 429 | /* Write bytecode for a prototype. */ |
354 | int lj_bcwrite(lua_State *L, GCproto *pt, lua_Writer writer, void *data, | 430 | int lj_bcwrite(lua_State *L, GCproto *pt, lua_Writer writer, void *data, |
355 | int strip) | 431 | uint32_t flags) |
356 | { | 432 | { |
357 | BCWriteCtx ctx; | 433 | BCWriteCtx ctx; |
358 | int status; | 434 | int status; |
359 | ctx.pt = pt; | 435 | ctx.pt = pt; |
360 | ctx.wfunc = writer; | 436 | ctx.wfunc = writer; |
361 | ctx.wdata = data; | 437 | ctx.wdata = data; |
362 | ctx.strip = strip; | 438 | ctx.heapsz = 0; |
439 | if ((bc_op(proto_bc(pt)[0]) != BC_NOT) == LJ_FR2) flags |= BCDUMP_F_FR2; | ||
440 | ctx.flags = flags; | ||
363 | ctx.status = 0; | 441 | ctx.status = 0; |
364 | #ifdef LUA_USE_ASSERT | 442 | #ifdef LUA_USE_ASSERT |
365 | ctx.g = G(L); | 443 | ctx.g = G(L); |
@@ -368,6 +446,7 @@ int lj_bcwrite(lua_State *L, GCproto *pt, lua_Writer writer, void *data, | |||
368 | status = lj_vm_cpcall(L, NULL, &ctx, cpwriter); | 446 | status = lj_vm_cpcall(L, NULL, &ctx, cpwriter); |
369 | if (status == 0) status = ctx.status; | 447 | if (status == 0) status = ctx.status; |
370 | lj_buf_free(G(sbufL(&ctx.sb)), &ctx.sb); | 448 | lj_buf_free(G(sbufL(&ctx.sb)), &ctx.sb); |
449 | bcwrite_heap_resize(&ctx, 0); | ||
371 | return status; | 450 | return status; |
372 | } | 451 | } |
373 | 452 | ||