}
}
- if (!tvisnil(&node->val)) {
+/* Insert key into a sorted heap. */
+static void bcwrite_ktabk_heap_insert(TValue **heap, MSize idx, MSize end,
+ TValue *key)
+{
+ MSize child;
+ while ((child = idx * 2 + 1) < end) {
+ /* Find lower of the two children. */
+ TValue *c0 = heap[child];
+ if (child + 1 < end) {
+ TValue *c1 = heap[child + 1];
+ if (bcwrite_ktabk_lt(c1, c0)) {
+ c0 = c1;
+ child++;
+ }
+ }
+ if (bcwrite_ktabk_lt(key, c0)) break; /* Key lower? Found our position. */
+ heap[idx] = c0; /* Move lower child up. */
+ idx = child; /* Descend. */
+ }
+ heap[idx] = key; /* Insert key here. */
+}
+
+/* Resize heap, dropping content. */
+static void bcwrite_heap_resize(BCWriteCtx *ctx, uint32_t nsz)
+{
+ lua_State *L = sbufL(&ctx->sb);
+ if (ctx->heapsz) {
+ lj_mem_freevec(G(L), ctx->heap, ctx->heapsz, TValue *);
+ ctx->heapsz = 0;
+ }
+ if (nsz) {
+ ctx->heap = lj_mem_newvec(L, nsz, TValue *);
+ ctx->heapsz = nsz;
+ }
+}
+
+/* Write hash part of template table in sorted order. */
+static void bcwrite_ktab_sorted_hash(BCWriteCtx *ctx, Node *node, MSize nhash)
+{
+ TValue **heap = ctx->heap;
+ MSize i = nhash;
+ for (;; node--) { /* Build heap. */
++ if (!tvisnil(&node->key)) {
+ bcwrite_ktabk_heap_insert(heap, --i, nhash, &node->key);
+ if (i == 0) break;
+ }
+ }
+ do { /* Drain heap. */
+ TValue *key = heap[0]; /* Output lowest key from top. */
+ bcwrite_ktabk(ctx, key, 0);
+ bcwrite_ktabk(ctx, (TValue *)((char *)key - offsetof(Node, key)), 1);
+ key = heap[--nhash]; /* Remove last key. */
+ bcwrite_ktabk_heap_insert(heap, 0, nhash, key); /* Re-insert. */
+ } while (nhash);
+}
+
/* Write a template table. */
-static void bcwrite_ktab(BCWriteCtx *ctx, const GCtab *t)
+static void bcwrite_ktab(BCWriteCtx *ctx, char *p, const GCtab *t)
{
MSize narray = 0, nhash = 0;
if (t->asize > 0) { /* Determine max. length of array part. */
MSize i, hmask = t->hmask;
Node *node = noderef(t->node);
for (i = 0; i <= hmask; i++)
- nhash += !tvisnil(&node[i].val);
+ nhash += !tvisnil(&node[i].key);
}
/* Write number of array slots and hash slots. */
- bcwrite_uleb128(ctx, narray);
- bcwrite_uleb128(ctx, nhash);
+ p = lj_strfmt_wuleb128(p, narray);
+ p = lj_strfmt_wuleb128(p, nhash);
+ ctx->sb.w = p;
if (narray) { /* Write array entries (may contain nil). */
MSize i;
TValue *o = tvref(t->array);
bcwrite_ktabk(ctx, o, 1);
}
if (nhash) { /* Write hash entries. */
- MSize i = nhash;
Node *node = noderef(t->node) + t->hmask;
- for (;; node--)
- if (!tvisnil(&node->key)) {
- bcwrite_ktabk(ctx, &node->key, 0);
- bcwrite_ktabk(ctx, &node->val, 1);
- if (--i == 0) break;
- }
+ if ((ctx->flags & BCDUMP_F_DETERMINISTIC) && nhash > 1) {
+ if (ctx->heapsz < nhash)
+ bcwrite_heap_resize(ctx, t->hmask + 1);
+ bcwrite_ktab_sorted_hash(ctx, node, nhash);
+ } else {
+ MSize i = nhash;
+ for (;; node--)
- if (!tvisnil(&node->val)) {
++ if (!tvisnil(&node->key)) {
+ bcwrite_ktabk(ctx, &node->key, 0);
+ bcwrite_ktabk(ctx, &node->val, 1);
+ if (--i == 0) break;
+ }
+ }
}
}