Browse Source

Change handling of nil value markers in template tables.

Reported by Bernhard M. Wiedemann. #1348 #1155
Fixes from Peter Cawley, Christian Clason, Lewis Russell.
Mike Pall 7 months ago
parent
commit
538a82133a
6 changed files with 24 additions and 25 deletions
  1. 6 4
      src/lj_bcread.c
  2. 5 3
      src/lj_bcwrite.c
  3. 4 2
      src/lj_opt_fold.c
  4. 3 1
      src/lj_opt_mem.c
  5. 5 15
      src/lj_parse.c
  6. 1 0
      src/lj_tab.c

+ 6 - 4
src/lj_bcread.c

@@ -179,7 +179,7 @@ static const void *bcread_varinfo(GCproto *pt)
 }
 }
 
 
 /* Read a single constant key/value of a template table. */
 /* 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);
   MSize tp = bcread_uleb128(ls);
   if (tp >= BCDUMP_KTAB_STR) {
   if (tp >= BCDUMP_KTAB_STR) {
@@ -191,6 +191,8 @@ static void bcread_ktabk(LexState *ls, TValue *o)
   } else if (tp == BCDUMP_KTAB_NUM) {
   } else if (tp == BCDUMP_KTAB_NUM) {
     o->u32.lo = bcread_uleb128(ls);
     o->u32.lo = bcread_uleb128(ls);
     o->u32.hi = bcread_uleb128(ls);
     o->u32.hi = bcread_uleb128(ls);
+  } else if (t && tp == BCDUMP_KTAB_NIL) { /* Restore nil value marker. */
+    settabV(ls->L, o, t);
   } else {
   } else {
     lj_assertLS(tp <= BCDUMP_KTAB_TRUE, "bad constant type %d", tp);
     lj_assertLS(tp <= BCDUMP_KTAB_TRUE, "bad constant type %d", tp);
     setpriV(o, ~tp);
     setpriV(o, ~tp);
@@ -207,15 +209,15 @@ static GCtab *bcread_ktab(LexState *ls)
     MSize i;
     MSize i;
     TValue *o = tvref(t->array);
     TValue *o = tvref(t->array);
     for (i = 0; i < narray; i++, o++)
     for (i = 0; i < narray; i++, o++)
-      bcread_ktabk(ls, o);
+      bcread_ktabk(ls, o, NULL);
   }
   }
   if (nhash) {  /* Read hash entries. */
   if (nhash) {  /* Read hash entries. */
     MSize i;
     MSize i;
     for (i = 0; i < nhash; i++) {
     for (i = 0; i < nhash; i++) {
       TValue key;
       TValue key;
-      bcread_ktabk(ls, &key);
+      bcread_ktabk(ls, &key, NULL);
       lj_assertLS(!tvisnil(&key), "nil key");
       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;
   return t;

+ 5 - 3
src/lj_bcwrite.c

@@ -71,6 +71,8 @@ static void bcwrite_ktabk(BCWriteCtx *ctx, cTValue *o, int narrow)
     *p++ = BCDUMP_KTAB_NUM;
     *p++ = BCDUMP_KTAB_NUM;
     p = lj_strfmt_wuleb128(p, o->u32.lo);
     p = lj_strfmt_wuleb128(p, o->u32.lo);
     p = lj_strfmt_wuleb128(p, o->u32.hi);
     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 {
   } else {
     lj_assertBCW(tvispri(o), "unhandled type %d", itype(o));
     lj_assertBCW(tvispri(o), "unhandled type %d", itype(o));
     *p++ = BCDUMP_KTAB_NIL+~itype(o);
     *p++ = BCDUMP_KTAB_NIL+~itype(o);
@@ -133,7 +135,7 @@ static void bcwrite_ktab_sorted_hash(BCWriteCtx *ctx, Node *node, MSize nhash)
   TValue **heap = ctx->heap;
   TValue **heap = ctx->heap;
   MSize i = nhash;
   MSize i = nhash;
   for (;; node--) {  /* Build heap. */
   for (;; node--) {  /* Build heap. */
-    if (!tvisnil(&node->key)) {
+    if (!tvisnil(&node->val)) {
       bcwrite_ktabk_heap_insert(heap, --i, nhash, &node->key);
       bcwrite_ktabk_heap_insert(heap, --i, nhash, &node->key);
       if (i == 0) break;
       if (i == 0) break;
     }
     }
@@ -163,7 +165,7 @@ static void bcwrite_ktab(BCWriteCtx *ctx, char *p, const GCtab *t)
     MSize i, hmask = t->hmask;
     MSize i, hmask = t->hmask;
     Node *node = noderef(t->node);
     Node *node = noderef(t->node);
     for (i = 0; i <= hmask; i++)
     for (i = 0; i <= hmask; i++)
-      nhash += !tvisnil(&node[i].key);
+      nhash += !tvisnil(&node[i].val);
   }
   }
   /* Write number of array slots and hash slots. */
   /* Write number of array slots and hash slots. */
   p = lj_strfmt_wuleb128(p, narray);
   p = lj_strfmt_wuleb128(p, narray);
@@ -184,7 +186,7 @@ static void bcwrite_ktab(BCWriteCtx *ctx, char *p, const GCtab *t)
     } else {
     } else {
       MSize i = nhash;
       MSize i = nhash;
       for (;; node--)
       for (;; node--)
-	if (!tvisnil(&node->key)) {
+	if (!tvisnil(&node->val)) {
 	  bcwrite_ktabk(ctx, &node->key, 0);
 	  bcwrite_ktabk(ctx, &node->key, 0);
 	  bcwrite_ktabk(ctx, &node->val, 1);
 	  bcwrite_ktabk(ctx, &node->val, 1);
 	  if (--i == 0) break;
 	  if (--i == 0) break;

+ 4 - 2
src/lj_opt_fold.c

@@ -2217,9 +2217,11 @@ LJFOLD(HREF TDUP KNUM)
 LJFOLDF(fwd_href_tdup)
 LJFOLDF(fwd_href_tdup)
 {
 {
   TValue keyv;
   TValue keyv;
+  cTValue *val;
   lj_ir_kvalue(J->L, &keyv, fright);
   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 lj_ir_kkptr(J, niltvg(J2G(J)));
   return NEXTFOLD;
   return NEXTFOLD;
 }
 }

+ 3 - 1
src/lj_opt_mem.c

@@ -233,7 +233,9 @@ static TRef fwd_ahload(jit_State *J, IRRef xref)
 	  return lj_ir_knum_u64(J, tv->u64);
 	  return lj_ir_knum_u64(J, tv->u64);
 	else if (tvisint(tv))
 	else if (tvisint(tv))
 	  return lj_ir_kint(J, intV(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));
 	  return lj_ir_kstr(J, strV(tv));
       }
       }
       /* Othwerwise: don't intern as a constant. */
       /* Othwerwise: don't intern as a constant. */

+ 5 - 15
src/lj_parse.c

@@ -1725,7 +1725,7 @@ static void expr_table(LexState *ls, ExpDesc *e)
   FuncState *fs = ls->fs;
   FuncState *fs = ls->fs;
   BCLine line = ls->linenumber;
   BCLine line = ls->linenumber;
   GCtab *t = NULL;
   GCtab *t = NULL;
-  int vcall = 0, needarr = 0, fixt = 0;
+  int vcall = 0, needarr = 0;
   uint32_t narr = 1;  /* First array index. */
   uint32_t narr = 1;  /* First array index. */
   uint32_t nhash = 0;  /* Number of hash entries. */
   uint32_t nhash = 0;  /* Number of hash entries. */
   BCReg freg = fs->freereg;
   BCReg freg = fs->freereg;
@@ -1769,9 +1769,10 @@ static void expr_table(LexState *ls, ExpDesc *e)
       lj_gc_anybarriert(fs->L, t);
       lj_gc_anybarriert(fs->L, t);
       if (expr_isk_nojump(&val)) {  /* Add const key/value to template table. */
       if (expr_isk_nojump(&val)) {  /* Add const key/value to template table. */
 	expr_kvalue(fs, v, &val);
 	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;
 	goto nonconst;
       }
       }
     } else {
     } else {
@@ -1813,17 +1814,6 @@ static void expr_table(LexState *ls, ExpDesc *e)
   } else {
   } else {
     if (needarr && t->asize < narr)
     if (needarr && t->asize < narr)
       lj_tab_reasize(fs->L, t, narr-1);
       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);
     lj_gc_check(fs->L);
   }
   }
 }
 }

+ 1 - 0
src/lj_tab.c

@@ -194,6 +194,7 @@ GCtab * LJ_FASTCALL lj_tab_dup(lua_State *L, const GCtab *kt)
       Node *next = nextnode(kn);
       Node *next = nextnode(kn);
       /* Don't use copyTV here, since it asserts on a copy of a dead key. */
       /* Don't use copyTV here, since it asserts on a copy of a dead key. */
       n->val = kn->val; n->key = kn->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));
       setmref(n->next, next == NULL? next : (Node *)((char *)next + d));
     }
     }
   }
   }