aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMike Pall <mike>2010-04-21 01:45:58 +0200
committerMike Pall <mike>2010-04-21 01:45:58 +0200
commitab45481199e9c9dd3efec922647bcec122504bcb (patch)
tree0484341edff50a0afe98133ad66fb6a59915996a /src
parentd8cb69ed076c3444258f63314662451c9d117cae (diff)
downloadluajit-ab45481199e9c9dd3efec922647bcec122504bcb.tar.gz
luajit-ab45481199e9c9dd3efec922647bcec122504bcb.tar.bz2
luajit-ab45481199e9c9dd3efec922647bcec122504bcb.zip
No longer let the GC replace dead keys with the LJ_TDEADKEY tag.
Important: this changes the semantics of the write barrier! Carefully read the big comment block in lj_obj.h This helps HREFK key slot specialization and allows safely hoisting HREF/HREFK across GC steps, too (fix for a barely reproducible bug). Dead keys are only removed during a table resize (as before).
Diffstat (limited to 'src')
-rw-r--r--src/lib_base.c2
-rw-r--r--src/lj_api.c7
-rw-r--r--src/lj_gc.c8
-rw-r--r--src/lj_gc.h2
-rw-r--r--src/lj_ir.h2
-rw-r--r--src/lj_lib.c2
-rw-r--r--src/lj_meta.c2
-rw-r--r--src/lj_obj.c14
-rw-r--r--src/lj_obj.h41
-rw-r--r--src/lj_opt_fold.c5
-rw-r--r--src/lj_parse.c6
-rw-r--r--src/lj_record.c9
-rw-r--r--src/lj_tab.c8
13 files changed, 65 insertions, 43 deletions
diff --git a/src/lib_base.c b/src/lib_base.c
index e85b7264..cbfd818a 100644
--- a/src/lib_base.c
+++ b/src/lib_base.c
@@ -54,7 +54,7 @@ LJLIB_PUSH("upval")
54LJLIB_PUSH("thread") 54LJLIB_PUSH("thread")
55LJLIB_PUSH("proto") 55LJLIB_PUSH("proto")
56LJLIB_PUSH("function") 56LJLIB_PUSH("function")
57LJLIB_PUSH("deadkey") 57LJLIB_PUSH("") /* Unused. */
58LJLIB_PUSH("table") 58LJLIB_PUSH("table")
59LJLIB_PUSH(top-8) /* userdata */ 59LJLIB_PUSH(top-8) /* userdata */
60LJLIB_PUSH("number") 60LJLIB_PUSH("number")
diff --git a/src/lj_api.c b/src/lj_api.c
index a19f0b33..aac3b4c9 100644
--- a/src/lj_api.c
+++ b/src/lj_api.c
@@ -196,7 +196,8 @@ LUA_API int lua_type(lua_State *L, int idx)
196 return LUA_TNONE; 196 return LUA_TNONE;
197 } else { /* Magic internal/external tag conversion. ORDER LJ_T */ 197 } else { /* Magic internal/external tag conversion. ORDER LJ_T */
198 int t = ~itype(o); 198 int t = ~itype(o);
199 return (int)(((t < 8 ? 0x98a42110 : 0x75b6) >> 4*(t&7)) & 15u); 199 lua_assert(itype(o) != LJ_TUPVAL);
200 return (int)(((t < 8 ? 0x98042110 : 0x7506) >> 4*(t&7)) & 15u);
200 } 201 }
201} 202}
202 203
@@ -631,7 +632,7 @@ LUALIB_API int luaL_newmetatable(lua_State *L, const char *tname)
631 GCtab *mt = lj_tab_new(L, 0, 1); 632 GCtab *mt = lj_tab_new(L, 0, 1);
632 settabV(L, tv, mt); 633 settabV(L, tv, mt);
633 settabV(L, L->top++, mt); 634 settabV(L, L->top++, mt);
634 lj_gc_objbarriert(L, regt, mt); 635 lj_gc_anybarriert(L, regt);
635 return 1; 636 return 1;
636 } else { 637 } else {
637 copyTV(L, L->top++, tv); 638 copyTV(L, L->top++, tv);
@@ -899,7 +900,7 @@ LUA_API void lua_rawset(lua_State *L, int idx)
899 key = L->top-2; 900 key = L->top-2;
900 dst = lj_tab_set(L, t, key); 901 dst = lj_tab_set(L, t, key);
901 copyTV(L, dst, key+1); 902 copyTV(L, dst, key+1);
902 lj_gc_barriert(L, t, dst); 903 lj_gc_anybarriert(L, t);
903 L->top = key; 904 L->top = key;
904} 905}
905 906
diff --git a/src/lj_gc.c b/src/lj_gc.c
index b97fb955..b457c424 100644
--- a/src/lj_gc.c
+++ b/src/lj_gc.c
@@ -186,13 +186,10 @@ static int gc_traverse_tab(global_State *g, GCtab *t)
186 MSize i, hmask = t->hmask; 186 MSize i, hmask = t->hmask;
187 for (i = 0; i <= hmask; i++) { 187 for (i = 0; i <= hmask; i++) {
188 Node *n = &node[i]; 188 Node *n = &node[i];
189 lua_assert(itype(&n->key) != LJ_TDEADKEY || tvisnil(&n->val));
190 if (!tvisnil(&n->val)) { /* Mark non-empty slot. */ 189 if (!tvisnil(&n->val)) { /* Mark non-empty slot. */
191 lua_assert(!tvisnil(&n->key)); 190 lua_assert(!tvisnil(&n->key));
192 if (!(weak & LJ_GC_WEAKKEY)) gc_marktv(g, &n->key); 191 if (!(weak & LJ_GC_WEAKKEY)) gc_marktv(g, &n->key);
193 if (!(weak & LJ_GC_WEAKVAL)) gc_marktv(g, &n->val); 192 if (!(weak & LJ_GC_WEAKVAL)) gc_marktv(g, &n->val);
194 } else if (tvisgcv(&n->key)) { /* Leave GC key in, but mark as dead. */
195 setitype(&n->key, LJ_TDEADKEY);
196 } 193 }
197 } 194 }
198 } 195 }
@@ -424,11 +421,8 @@ static void gc_clearweak(GCobj *o)
424 Node *n = &node[i]; 421 Node *n = &node[i];
425 /* Clear hash slot when key or value is about to be collected. */ 422 /* Clear hash slot when key or value is about to be collected. */
426 if (!tvisnil(&n->val) && (gc_mayclear(&n->key, 0) || 423 if (!tvisnil(&n->val) && (gc_mayclear(&n->key, 0) ||
427 gc_mayclear(&n->val, 1))) { 424 gc_mayclear(&n->val, 1)))
428 setnilV(&n->val); 425 setnilV(&n->val);
429 if (tvisgcv(&n->key)) /* Leave GC key in, but mark as dead. */
430 setitype(&n->key, LJ_TDEADKEY);
431 }
432 } 426 }
433 } 427 }
434 o = gcref(t->gclist); 428 o = gcref(t->gclist);
diff --git a/src/lj_gc.h b/src/lj_gc.h
index 7279b93c..3d213eb3 100644
--- a/src/lj_gc.h
+++ b/src/lj_gc.h
@@ -69,6 +69,8 @@ LJ_FUNC void lj_gc_barriertrace(global_State *g, void *T);
69#endif 69#endif
70 70
71/* Barrier for stores to table objects. TValue and GCobj variant. */ 71/* Barrier for stores to table objects. TValue and GCobj variant. */
72#define lj_gc_anybarriert(L, t) \
73 { if (isblack(obj2gco(t))) lj_gc_barrierback(G(L), (t)); }
72#define lj_gc_barriert(L, t, tv) \ 74#define lj_gc_barriert(L, t, tv) \
73 { if (tviswhite(tv) && isblack(obj2gco(t))) \ 75 { if (tviswhite(tv) && isblack(obj2gco(t))) \
74 lj_gc_barrierback(G(L), (t)); } 76 lj_gc_barrierback(G(L), (t)); }
diff --git a/src/lj_ir.h b/src/lj_ir.h
index ca871238..14f80ac5 100644
--- a/src/lj_ir.h
+++ b/src/lj_ir.h
@@ -317,7 +317,7 @@ typedef enum {
317 IRT_THREAD, 317 IRT_THREAD,
318 IRT_PROTO, 318 IRT_PROTO,
319 IRT_FUNC, 319 IRT_FUNC,
320 IRT_9, /* LJ_TDEADKEY is never used in the IR. */ 320 IRT_9, /* Never used in the IR. */
321 IRT_TAB, 321 IRT_TAB,
322 IRT_UDATA, 322 IRT_UDATA,
323 /* ... until here. */ 323 /* ... until here. */
diff --git a/src/lj_lib.c b/src/lj_lib.c
index 0ba0ecb1..9540772e 100644
--- a/src/lj_lib.c
+++ b/src/lj_lib.c
@@ -53,7 +53,7 @@ void lj_lib_register(lua_State *L, const char *libname,
53 ptrdiff_t tpos = L->top - L->base; 53 ptrdiff_t tpos = L->top - L->base;
54 54
55 /* Avoid barriers further down. */ 55 /* Avoid barriers further down. */
56 if (isblack(obj2gco(tab))) lj_gc_barrierback(G(L), tab); 56 lj_gc_anybarriert(L, tab);
57 tab->nomm = 0; 57 tab->nomm = 0;
58 58
59 for (;;) { 59 for (;;) {
diff --git a/src/lj_meta.c b/src/lj_meta.c
index c8ac18d6..41124fdc 100644
--- a/src/lj_meta.c
+++ b/src/lj_meta.c
@@ -134,7 +134,7 @@ TValue *lj_meta_tset(lua_State *L, cTValue *o, cTValue *k)
134 TValue *tv = lj_tab_set(L, t, k); 134 TValue *tv = lj_tab_set(L, t, k);
135 if (!tvisnil(tv) || 135 if (!tvisnil(tv) ||
136 !(mo = lj_meta_fast(L, tabref(t->metatable), MM_newindex))) { 136 !(mo = lj_meta_fast(L, tabref(t->metatable), MM_newindex))) {
137 if (isblack(obj2gco(t))) lj_gc_barrierback(G(L), t); 137 lj_gc_anybarriert(L, t);
138 return tv; 138 return tv;
139 } 139 }
140 } else if (tvisnil(mo = lj_meta_lookup(L, o, MM_newindex))) { 140 } else if (tvisnil(mo = lj_meta_lookup(L, o, MM_newindex))) {
diff --git a/src/lj_obj.c b/src/lj_obj.c
index 4363e790..0df51bc4 100644
--- a/src/lj_obj.c
+++ b/src/lj_obj.c
@@ -11,12 +11,12 @@
11/* Object type names. */ 11/* Object type names. */
12LJ_DATADEF const char *const lj_obj_typename[] = { /* ORDER LUA_T */ 12LJ_DATADEF const char *const lj_obj_typename[] = { /* ORDER LUA_T */
13 "no value", "nil", "boolean", "userdata", "number", "string", 13 "no value", "nil", "boolean", "userdata", "number", "string",
14 "table", "function", "userdata", "thread", "proto", "upval" 14 "table", "function", "userdata", "thread", "proto"
15}; 15};
16 16
17LJ_DATADEF const char *const lj_obj_itypename[] = { /* ORDER LJ_T */ 17LJ_DATADEF const char *const lj_obj_itypename[] = { /* ORDER LJ_T */
18 "nil", "boolean", "boolean", "userdata", "string", "upval", "thread", 18 "nil", "boolean", "boolean", "userdata", "string", "upval", "thread",
19 "proto", "function", "deadkey", "table", "userdata", "number" 19 "proto", "function", "" /* Unused */, "table", "userdata", "number"
20}; 20};
21 21
22/* Compare two objects without calling metamethods. */ 22/* Compare two objects without calling metamethods. */
@@ -25,14 +25,8 @@ int lj_obj_equal(cTValue *o1, cTValue *o2)
25 if (itype(o1) == itype(o2)) { 25 if (itype(o1) == itype(o2)) {
26 if (tvispri(o1)) 26 if (tvispri(o1))
27 return 1; 27 return 1;
28 if (!tvisnum(o1)) { 28 if (!tvisnum(o1))
29#if LJ_64 29 return gcrefeq(o1->gcr, o2->gcr);
30 if (tvislightud(o1))
31 return o1->u64 == o2->u64;
32 else
33#endif
34 return gcrefeq(o1->gcr, o2->gcr);
35 }
36 } else if (!tvisnum(o1) || !tvisnum(o2)) { 30 } else if (!tvisnum(o1) || !tvisnum(o2)) {
37 return 0; 31 return 0;
38 } 32 }
diff --git a/src/lj_obj.h b/src/lj_obj.h
index 048a74f9..71146dfc 100644
--- a/src/lj_obj.h
+++ b/src/lj_obj.h
@@ -75,9 +75,37 @@ typedef struct GCRef {
75** a barrier has been omitted are annotated with a NOBARRIER comment. 75** a barrier has been omitted are annotated with a NOBARRIER comment.
76** 76**
77** The same logic applies for stores to table slots (array part or hash 77** The same logic applies for stores to table slots (array part or hash
78** part). ALL uses of lj_tab_set* require a barrier for the stored *value* 78** part). ALL uses of lj_tab_set* require a barrier for the stored value
79** (if it's a GC object). The barrier for the *key* is already handled 79** *and* the stored key, based on the above rules. In practice this means
80** internally by lj_tab_newkey. 80** a barrier is needed if *either* of the key or value are a GC object.
81**
82** It's ok to LEAVE OUT the write barrier in the following special cases:
83** - The stored value is nil. The key doesn't matter because it's either
84** not resurrected or lj_tab_newkey() will take care of the key barrier.
85** - The key doesn't matter if the *previously* stored value is guaranteed
86** to be non-nil (because the key is kept alive in the table).
87** - The key doesn't matter if it's guaranteed not to be part of the table,
88** since lj_tab_newkey() takes care of the key barrier. This applies
89** trivially to new tables, but watch out for resurrected keys. Storing
90** a nil value leaves the key in the table!
91**
92** In case of doubt use lj_gc_anybarriert() as it's rather cheap. It's used
93** by the interpreter for all table stores.
94**
95** Note: In contrast to Lua's GC, LuaJIT's GC does *not* specially mark
96** dead keys in tables. The reference is left in, but it's guaranteed to
97** be never dereferenced as long as the value is nil. It's ok if the key is
98** freed or if any object subsequently gets the same address.
99**
100** Not destroying dead keys helps to keep key hash slots stable. This avoids
101** specialization back-off for HREFK when a value flips between nil and
102** non-nil and the GC gets in the way. It also allows safely hoisting
103** HREF/HREFK across GC steps. Dead keys are only removed if a table is
104** resized (i.e. by NEWREF) and xREF must not be CSEd across a resize.
105**
106** The trade-off is that a write barrier for tables must take the key into
107** account, too. Implicitly resurrecting the key by storing a non-nil value
108** may invalidate the incremental GC invariant.
81*/ 109*/
82 110
83/* -- Common type definitions --------------------------------------------- */ 111/* -- Common type definitions --------------------------------------------- */
@@ -136,10 +164,7 @@ typedef const TValue cTValue;
136 164
137/* More external and GCobj tags for internal objects. */ 165/* More external and GCobj tags for internal objects. */
138#define LAST_TT LUA_TTHREAD 166#define LAST_TT LUA_TTHREAD
139
140#define LUA_TPROTO (LAST_TT+1) 167#define LUA_TPROTO (LAST_TT+1)
141#define LUA_TUPVAL (LAST_TT+2)
142#define LUA_TDEADKEY (LAST_TT+3)
143 168
144/* Internal object tags. 169/* Internal object tags.
145** 170**
@@ -170,7 +195,7 @@ typedef const TValue cTValue;
170#define LJ_TTHREAD (-7) 195#define LJ_TTHREAD (-7)
171#define LJ_TPROTO (-8) 196#define LJ_TPROTO (-8)
172#define LJ_TFUNC (-9) 197#define LJ_TFUNC (-9)
173#define LJ_TDEADKEY (-10) 198/* Unused (-10) */
174#define LJ_TTAB (-11) 199#define LJ_TTAB (-11)
175#define LJ_TUDATA (-12) 200#define LJ_TUDATA (-12)
176/* This is just the canonical number type used in some places. */ 201/* This is just the canonical number type used in some places. */
@@ -689,7 +714,7 @@ static LJ_AINLINE int32_t lj_num2bit(lua_Number n)
689/* -- Miscellaneous object handling --------------------------------------- */ 714/* -- Miscellaneous object handling --------------------------------------- */
690 715
691/* Names and maps for internal and external object tags. */ 716/* Names and maps for internal and external object tags. */
692LJ_DATA const char *const lj_obj_typename[1+LUA_TUPVAL+1]; 717LJ_DATA const char *const lj_obj_typename[1+LUA_TPROTO+1];
693LJ_DATA const char *const lj_obj_itypename[~LJ_TNUMX+1]; 718LJ_DATA const char *const lj_obj_itypename[~LJ_TNUMX+1];
694 719
695#define typename(o) (lj_obj_itypename[itypemap(o)]) 720#define typename(o) (lj_obj_itypename[itypemap(o)])
diff --git a/src/lj_opt_fold.c b/src/lj_opt_fold.c
index c91f3382..69ade882 100644
--- a/src/lj_opt_fold.c
+++ b/src/lj_opt_fold.c
@@ -1351,8 +1351,9 @@ LJFOLDF(fwd_xload)
1351/* Write barriers are amenable to CSE, but not across any incremental 1351/* Write barriers are amenable to CSE, but not across any incremental
1352** GC steps. 1352** GC steps.
1353** 1353**
1354** The same logic applies to open upvalue references, because the stack 1354** The same logic applies to open upvalue references, because a stack
1355** may be resized during a GC step. 1355** may be resized during a GC step (not the current stack, but maybe that
1356** of a coroutine).
1356*/ 1357*/
1357LJFOLD(TBAR any) 1358LJFOLD(TBAR any)
1358LJFOLD(OBAR any any) 1359LJFOLD(OBAR any any)
diff --git a/src/lj_parse.c b/src/lj_parse.c
index 31a70d38..b5bd7baf 100644
--- a/src/lj_parse.c
+++ b/src/lj_parse.c
@@ -189,6 +189,7 @@ static BCReg const_gc(FuncState *fs, GCobj *gc, int itype)
189 lua_State *L = fs->L; 189 lua_State *L = fs->L;
190 TValue o, *val; 190 TValue o, *val;
191 setgcV(L, &o, &gc->gch, itype); 191 setgcV(L, &o, &gc->gch, itype);
192 /* NOBARRIER: the key is new or kept alive. */
192 val = lj_tab_set(L, fs->kt, &o); 193 val = lj_tab_set(L, fs->kt, &o);
193 if (tvisnum(val)) 194 if (tvisnum(val))
194 return val->u32.lo; 195 return val->u32.lo;
@@ -206,6 +207,7 @@ static BCReg const_str(FuncState *fs, ExpDesc *e)
206/* Anchor string constant to avoid GC. */ 207/* Anchor string constant to avoid GC. */
207GCstr *lj_parse_keepstr(LexState *ls, const char *str, size_t len) 208GCstr *lj_parse_keepstr(LexState *ls, const char *str, size_t len)
208{ 209{
210 /* NOBARRIER: the key is new or kept alive. */
209 lua_State *L = ls->L; 211 lua_State *L = ls->L;
210 GCstr *s = lj_str_new(L, str, len); 212 GCstr *s = lj_str_new(L, str, len);
211 TValue *tv = lj_tab_setstr(L, ls->fs->kt, s); 213 TValue *tv = lj_tab_setstr(L, ls->fs->kt, s);
@@ -1202,6 +1204,7 @@ static GCproto *fs_finish(LexState *ls, BCLine line)
1202 lua_assert(ls->fs != NULL || ls->token == TK_eof); 1204 lua_assert(ls->fs != NULL || ls->token == TK_eof);
1203 /* Re-anchor last string token to avoid GC. */ 1205 /* Re-anchor last string token to avoid GC. */
1204 if (ls->token == TK_name || ls->token == TK_string) { 1206 if (ls->token == TK_name || ls->token == TK_string) {
1207 /* NOBARRIER: the key is new or kept alive. */
1205 TValue *tv = lj_tab_setstr(ls->L, ls->fs->kt, strV(&ls->tokenval)); 1208 TValue *tv = lj_tab_setstr(ls->L, ls->fs->kt, strV(&ls->tokenval));
1206 if (tvisnil(tv)) setboolV(tv, 1); 1209 if (tvisnil(tv)) setboolV(tv, 1);
1207 } 1210 }
@@ -1346,8 +1349,7 @@ static void expr_table(LexState *ls, ExpDesc *e)
1346 vcall = 0; 1349 vcall = 0;
1347 expr_kvalue(&k, &key); 1350 expr_kvalue(&k, &key);
1348 expr_kvalue(lj_tab_set(fs->L, t, &k), &val); 1351 expr_kvalue(lj_tab_set(fs->L, t, &k), &val);
1349 if (val.k == VKSTR) 1352 lj_gc_anybarriert(fs->L, t);
1350 lj_gc_objbarriert(fs->L, t, val.u.sval);
1351 } else { 1353 } else {
1352 if (val.k != VCALL) { expr_toanyreg(fs, &val); vcall = 0; } 1354 if (val.k != VCALL) { expr_toanyreg(fs, &val); vcall = 0; }
1353 if (expr_isk(&key)) expr_index(fs, e, &key); 1355 if (expr_isk(&key)) expr_index(fs, e, &key);
diff --git a/src/lj_record.c b/src/lj_record.c
index 206eedca..c13c67fd 100644
--- a/src/lj_record.c
+++ b/src/lj_record.c
@@ -994,6 +994,7 @@ static TRef rec_idx(jit_State *J, RecordIndex *ix)
994 return res; 994 return res;
995 } else { /* Indexed store. */ 995 } else { /* Indexed store. */
996 GCtab *mt = tabref(tabV(&ix->tabv)->metatable); 996 GCtab *mt = tabref(tabV(&ix->tabv)->metatable);
997 int keybarrier = tref_isgcv(ix->key) && !tref_isnil(ix->val);
997 if (tvisnil(oldv)) { /* Previous value was nil? */ 998 if (tvisnil(oldv)) { /* Previous value was nil? */
998 /* Need to duplicate the hasmm check for the early guards. */ 999 /* Need to duplicate the hasmm check for the early guards. */
999 int hasmm = 0; 1000 int hasmm = 0;
@@ -1004,7 +1005,8 @@ static TRef rec_idx(jit_State *J, RecordIndex *ix)
1004 if (hasmm) 1005 if (hasmm)
1005 emitir(IRTG(loadop, IRT_NIL), xref, 0); /* Guard for nil value. */ 1006 emitir(IRTG(loadop, IRT_NIL), xref, 0); /* Guard for nil value. */
1006 else if (xrefop == IR_HREF) 1007 else if (xrefop == IR_HREF)
1007 emitir(IRTG(oldv == niltvg(J2G(J)) ? IR_EQ : IR_NE, IRT_PTR), xref, lj_ir_kptr(J, niltvg(J2G(J)))); 1008 emitir(IRTG(oldv == niltvg(J2G(J)) ? IR_EQ : IR_NE, IRT_PTR),
1009 xref, lj_ir_kptr(J, niltvg(J2G(J))));
1008 if (ix->idxchain && rec_mm_lookup(J, ix, MM_newindex)) { /* Metamethod? */ 1010 if (ix->idxchain && rec_mm_lookup(J, ix, MM_newindex)) { /* Metamethod? */
1009 lua_assert(hasmm); 1011 lua_assert(hasmm);
1010 goto handlemm; 1012 goto handlemm;
@@ -1015,6 +1017,7 @@ static TRef rec_idx(jit_State *J, RecordIndex *ix)
1015 if (tref_isinteger(key)) /* NEWREF needs a TValue as a key. */ 1017 if (tref_isinteger(key)) /* NEWREF needs a TValue as a key. */
1016 key = emitir(IRTN(IR_TONUM), key, 0); 1018 key = emitir(IRTN(IR_TONUM), key, 0);
1017 xref = emitir(IRT(IR_NEWREF, IRT_PTR), ix->tab, key); 1019 xref = emitir(IRT(IR_NEWREF, IRT_PTR), ix->tab, key);
1020 keybarrier = 0; /* NEWREF already takes care of the key barrier. */
1018 } 1021 }
1019 } else if (!lj_opt_fwd_wasnonnil(J, loadop, tref_ref(xref))) { 1022 } else if (!lj_opt_fwd_wasnonnil(J, loadop, tref_ref(xref))) {
1020 /* Cannot derive that the previous value was non-nil, must do checks. */ 1023 /* Cannot derive that the previous value was non-nil, must do checks. */
@@ -1030,11 +1033,13 @@ static TRef rec_idx(jit_State *J, RecordIndex *ix)
1030 emitir(IRTG(loadop, t), xref, 0); /* Guard for non-nil value. */ 1033 emitir(IRTG(loadop, t), xref, 0); /* Guard for non-nil value. */
1031 } 1034 }
1032 } 1035 }
1036 } else {
1037 keybarrier = 0; /* Previous non-nil value kept the key alive. */
1033 } 1038 }
1034 if (tref_isinteger(ix->val)) /* Convert int to number before storing. */ 1039 if (tref_isinteger(ix->val)) /* Convert int to number before storing. */
1035 ix->val = emitir(IRTN(IR_TONUM), ix->val, 0); 1040 ix->val = emitir(IRTN(IR_TONUM), ix->val, 0);
1036 emitir(IRT(loadop+IRDELTA_L2S, tref_type(ix->val)), xref, ix->val); 1041 emitir(IRT(loadop+IRDELTA_L2S, tref_type(ix->val)), xref, ix->val);
1037 if (tref_isgcv(ix->val)) 1042 if (keybarrier || tref_isgcv(ix->val))
1038 emitir(IRT(IR_TBAR, IRT_NIL), ix->tab, 0); 1043 emitir(IRT(IR_TBAR, IRT_NIL), ix->tab, 0);
1039 /* Invalidate neg. metamethod cache for stores with certain string keys. */ 1044 /* Invalidate neg. metamethod cache for stores with certain string keys. */
1040 if (!nommstr(J, ix->key)) { 1045 if (!nommstr(J, ix->key)) {
diff --git a/src/lj_tab.c b/src/lj_tab.c
index d77aa05a..5d68cc54 100644
--- a/src/lj_tab.c
+++ b/src/lj_tab.c
@@ -192,7 +192,7 @@ GCtab * LJ_FASTCALL lj_tab_dup(lua_State *L, const GCtab *kt)
192 Node *kn = &knode[i]; 192 Node *kn = &knode[i];
193 Node *n = &node[i]; 193 Node *n = &node[i];
194 Node *next = nextnode(kn); 194 Node *next = nextnode(kn);
195 /* Don't use copyTV here, since it asserts on a copy of a DEADKEY. */ 195 /* Don't use copyTV here, since it asserts on a copy of a dead key. */
196 n->val = kn->val; n->key = kn->key; 196 n->val = kn->val; n->key = kn->key;
197 setmref(n->next, next == NULL? next : (Node *)((char *)next + d)); 197 setmref(n->next, next == NULL? next : (Node *)((char *)next + d));
198 } 198 }
@@ -448,7 +448,7 @@ TValue *lj_tab_newkey(lua_State *L, GCtab *t, cTValue *key)
448 n->key.u64 = key->u64; 448 n->key.u64 = key->u64;
449 if (LJ_UNLIKELY(tvismzero(&n->key))) 449 if (LJ_UNLIKELY(tvismzero(&n->key)))
450 n->key.u64 = 0; 450 n->key.u64 = 0;
451 lj_gc_barriert(L, t, key); 451 lj_gc_anybarriert(L, t);
452 lua_assert(tvisnil(&n->val)); 452 lua_assert(tvisnil(&n->val));
453 return &n->val; 453 return &n->val;
454} 454}
@@ -517,9 +517,7 @@ static uint32_t keyindex(lua_State *L, GCtab *t, cTValue *key)
517 if (!tvisnil(key)) { 517 if (!tvisnil(key)) {
518 Node *n = hashkey(t, key); 518 Node *n = hashkey(t, key);
519 do { 519 do {
520 if (lj_obj_equal(&n->key, key) || 520 if (lj_obj_equal(&n->key, key))
521 (itype(&n->key) == LJ_TDEADKEY && tvisgcv(key) &&
522 gcV(&n->key) == gcV(key)))
523 return t->asize + (uint32_t)(n - noderef(t->node)); 521 return t->asize + (uint32_t)(n - noderef(t->node));
524 /* Hash key indexes: [t->asize..t->asize+t->nmask] */ 522 /* Hash key indexes: [t->asize..t->asize+t->nmask] */
525 } while ((n = nextnode(n))); 523 } while ((n = nextnode(n)));