}
/* Read a single constant key/value of a template table. */
-static void bcread_ktabk(LexState *ls, TValue *o)
+static void bcread_ktabk(LexState *ls, TValue *o, GCtab *t)
{
MSize tp = bcread_uleb128(ls);
if (tp >= BCDUMP_KTAB_STR) {
} else if (tp == BCDUMP_KTAB_NUM) {
o->u32.lo = bcread_uleb128(ls);
o->u32.hi = bcread_uleb128(ls);
+ } else if (tp == BCDUMP_KTAB_NIL) { /* Restore nil value marker. */
+ settabV(ls->L, o, t);
} else {
lj_assertLS(tp <= BCDUMP_KTAB_TRUE, "bad constant type %d", tp);
setpriV(o, ~tp);
MSize i;
TValue *o = tvref(t->array);
for (i = 0; i < narray; i++, o++)
- bcread_ktabk(ls, o);
+ bcread_ktabk(ls, o, t);
}
if (nhash) { /* Read hash entries. */
MSize i;
for (i = 0; i < nhash; i++) {
TValue key;
- bcread_ktabk(ls, &key);
+ bcread_ktabk(ls, &key, t);
lj_assertLS(!tvisnil(&key), "nil key");
- bcread_ktabk(ls, lj_tab_set(ls->L, t, &key));
+ bcread_ktabk(ls, lj_tab_set(ls->L, t, &key), t);
}
}
return t;
*p++ = BCDUMP_KTAB_NUM;
p = lj_strfmt_wuleb128(p, o->u32.lo);
p = lj_strfmt_wuleb128(p, o->u32.hi);
+ } else if (tvistab(o)) { /* Write the nil value marker as a nil. */
+ *p++ = BCDUMP_KTAB_NIL;
} else {
lj_assertBCW(tvispri(o), "unhandled type %d", itype(o));
*p++ = BCDUMP_KTAB_NIL+~itype(o);
TValue **heap = ctx->heap;
MSize i = nhash;
for (;; node--) { /* Build heap. */
- if (!tvisnil(&node->key)) {
+ if (!tvisnil(&node->val)) {
bcwrite_ktabk_heap_insert(heap, --i, nhash, &node->key);
if (i == 0) break;
}
MSize i, hmask = t->hmask;
Node *node = noderef(t->node);
for (i = 0; i <= hmask; i++)
- nhash += !tvisnil(&node[i].key);
+ nhash += !tvisnil(&node[i].val);
}
/* Write number of array slots and hash slots. */
p = lj_strfmt_wuleb128(p, narray);
LJFOLDF(fwd_href_tdup)
{
TValue keyv;
+ cTValue *val;
lj_ir_kvalue(J->L, &keyv, fright);
- if (lj_tab_get(J->L, ir_ktab(IR(fleft->op1)), &keyv) == niltvg(J2G(J)) &&
- lj_opt_fwd_href_nokey(J))
+ val = lj_tab_get(J->L, ir_ktab(IR(fleft->op1)), &keyv);
+ /* Check for either nil or the nil value marker in the template table. */
+ if ((tvisnil(val) || tvistab(val)) && lj_opt_fwd_href_nokey(J))
return lj_ir_kkptr(J, niltvg(J2G(J)));
return NEXTFOLD;
}
return lj_ir_knum_u64(J, tv->u64);
else if (tvisint(tv))
return lj_ir_kint(J, intV(tv));
- else if (tvisgcv(tv))
+ else if (tvistab(tv)) /* Template table nil value marker. */
+ return TREF_NIL;
+ else if (tvisstr(tv))
return lj_ir_kstr(J, strV(tv));
}
/* Othwerwise: don't intern as a constant. */
FuncState *fs = ls->fs;
BCLine line = ls->linenumber;
GCtab *t = NULL;
- int vcall = 0, needarr = 0, fixt = 0;
+ int vcall = 0, needarr = 0;
uint32_t narr = 1; /* First array index. */
uint32_t nhash = 0; /* Number of hash entries. */
BCReg freg = fs->freereg;
lj_gc_anybarriert(fs->L, t);
if (expr_isk_nojump(&val)) { /* Add const key/value to template table. */
expr_kvalue(fs, v, &val);
- } else { /* Otherwise create dummy string key (avoids lj_tab_newkey). */
- settabV(fs->L, v, t); /* Preserve key with table itself as value. */
- fixt = 1; /* Fix this later, after all resizes. */
+ /* Mark nil value with table value itself to preserve the key. */
+ if (key.k == VKSTR && tvisnil(v)) settabV(fs->L, v, t);
+ } else { /* Preserve the key for the following non-const store. */
+ settabV(fs->L, v, t);
goto nonconst;
}
} else {
} else {
if (needarr && t->asize < narr)
lj_tab_reasize(fs->L, t, narr-1);
- if (fixt) { /* Fix value for dummy keys in template table. */
- Node *node = noderef(t->node);
- uint32_t i, hmask = t->hmask;
- for (i = 0; i <= hmask; i++) {
- Node *n = &node[i];
- if (tvistab(&n->val)) {
- lj_assertFS(tabV(&n->val) == t, "bad dummy key in template table");
- setnilV(&n->val); /* Turn value into nil. */
- }
- }
- }
lj_gc_check(fs->L);
}
}
Node *next = nextnode(kn);
/* Don't use copyTV here, since it asserts on a copy of a dead key. */
n->val = kn->val; n->key = kn->key;
+ if (tvistab(&n->val)) setnilV(&n->val); /* Replace nil value marker. */
setmref(n->next, next == NULL? next : (Node *)((char *)next + d));
}
}