Changes in the API of 'luaH_set' and related functions
Functions to set values in a table (luaH_set, luaH_newkey, etc.) receive
the new value, instead of returning a slot where to put the value.
diff --git a/lapi.c b/lapi.c
index 9fffcc1..03e756d 100644
--- a/lapi.c
+++ b/lapi.c
@@ -871,12 +871,10 @@
static void aux_rawset (lua_State *L, int idx, TValue *key, int n) {
Table *t;
- TValue *slot;
lua_lock(L);
api_checknelems(L, n);
t = gettable(L, idx);
- slot = luaH_set(L, t, key);
- setobj2t(L, slot, s2v(L->top - 1));
+ luaH_set(L, t, key, s2v(L->top - 1));
invalidateTMcache(t);
luaC_barrierback(L, obj2gco(t), s2v(L->top - 1));
L->top -= n;
diff --git a/lcode.c b/lcode.c
index 97e427b..d8d353f 100644
--- a/lcode.c
+++ b/lcode.c
@@ -545,11 +545,14 @@
** and try to reuse constants. Because some values should not be used
** as keys (nil cannot be a key, integer keys can collapse with float
** keys), the caller must provide a useful 'key' for indexing the cache.
+** Note that all functions share the same table, so entering or exiting
+** a function can make some indices wrong.
*/
static int addk (FuncState *fs, TValue *key, TValue *v) {
+ TValue val;
lua_State *L = fs->ls->L;
Proto *f = fs->f;
- TValue *idx = luaH_set(L, fs->ls->h, key); /* index scanner table */
+ const TValue *idx = luaH_get(fs->ls->h, key); /* query scanner table */
int k, oldsize;
if (ttisinteger(idx)) { /* is there an index there? */
k = cast_int(ivalue(idx));
@@ -563,7 +566,8 @@
k = fs->nk;
/* numerical value does not need GC barrier;
table has no metatable, so it does not need to invalidate cache */
- setivalue(idx, k);
+ setivalue(&val, k);
+ luaH_finishset(L, fs->ls->h, key, idx, &val);
luaM_growvector(L, f->k, k, f->sizek, TValue, MAXARG_Ax, "constants");
while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]);
setobj(L, &f->k[k], v);
diff --git a/llex.c b/llex.c
index 4b8dec9..e991517 100644
--- a/llex.c
+++ b/llex.c
@@ -122,26 +122,29 @@
/*
-** creates a new string and anchors it in scanner's table so that
-** it will not be collected until the end of the compilation
-** (by that time it should be anchored somewhere)
+** Creates a new string and anchors it in scanner's table so that it
+** will not be collected until the end of the compilation; by that time
+** it should be anchored somewhere. It also internalizes long strings,
+** ensuring there is only one copy of each unique string. The table
+** here is used as a set: the string enters as the key, while its value
+** is irrelevant. We use the string itself as the value only because it
+** is a TValue readly available. Later, the code generation can change
+** this value.
*/
TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
lua_State *L = ls->L;
- TValue *o; /* entry for 'str' */
TString *ts = luaS_newlstr(L, str, l); /* create new string */
- setsvalue2s(L, L->top++, ts); /* temporarily anchor it in stack */
- o = luaH_set(L, ls->h, s2v(L->top - 1));
- if (isempty(o)) { /* not in use yet? */
- /* boolean value does not need GC barrier;
- table is not a metatable, so it does not need to invalidate cache */
- setbtvalue(o); /* t[string] = true */
+ const TValue *o = luaH_getstr(ls->h, ts);
+ if (!ttisnil(o)) /* string already present? */
+ ts = keystrval(nodefromval(o)); /* get saved copy */
+ else { /* not in use yet */
+ TValue *stv = s2v(L->top++); /* reserve stack space for string */
+ setsvalue(L, stv, ts); /* temporarily anchor the string */
+ luaH_finishset(L, ls->h, stv, o, stv); /* t[string] = string */
+ /* table is not a metatable, so it does not need to invalidate cache */
luaC_checkGC(L);
+ L->top--; /* remove string from stack */
}
- else { /* string already present */
- ts = keystrval(nodefromval(o)); /* re-use value previously stored */
- }
- L->top--; /* remove string from stack */
return ts;
}
diff --git a/ltable.c b/ltable.c
index 7e7cbed..e9410f9 100644
--- a/ltable.c
+++ b/ltable.c
@@ -485,7 +485,7 @@
already present in the table */
TValue k;
getnodekey(L, &k, old);
- setobjt2t(L, luaH_set(L, t, &k), gval(old));
+ luaH_set(L, t, &k, gval(old));
}
}
}
@@ -632,7 +632,7 @@
** put new key in its main position; otherwise (colliding node is in its main
** position), new key goes to an empty position.
*/
-TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
+void luaH_newkey (lua_State *L, Table *t, const TValue *key, TValue *value) {
Node *mp;
TValue aux;
if (unlikely(ttisnil(key)))
@@ -654,7 +654,8 @@
if (f == NULL) { /* cannot find a free place? */
rehash(L, t, key); /* grow table */
/* whatever called 'newkey' takes care of TM cache */
- return luaH_set(L, t, key); /* insert key into grown table */
+ luaH_set(L, t, key, value); /* insert key into grown table */
+ return;
}
lua_assert(!isdummy(t));
othern = mainposition(t, keytt(mp), &keyval(mp));
@@ -682,7 +683,7 @@
setnodekey(L, mp, key);
luaC_barrierback(L, obj2gco(t), key);
lua_assert(isempty(gval(mp)));
- return gval(mp);
+ setobj2t(L, gval(mp), value);
}
@@ -770,28 +771,39 @@
/*
+** Finish a raw "set table" operation, where 'slot' is where the value
+** should have been (the result of a previous "get table").
+** Beware: when using this function you probably need to check a GC
+** barrier and invalidate the TM cache.
+*/
+void luaH_finishset (lua_State *L, Table *t, const TValue *key,
+ const TValue *slot, TValue *value) {
+ if (isabstkey(slot))
+ luaH_newkey(L, t, key, value);
+ else
+ setobj2t(L, cast(TValue *, slot), value);
+}
+
+
+/*
** beware: when using this function you probably need to check a GC
** barrier and invalidate the TM cache.
*/
-TValue *luaH_set (lua_State *L, Table *t, const TValue *key) {
- const TValue *p = luaH_get(t, key);
- if (!isabstkey(p))
- return cast(TValue *, p);
- else return luaH_newkey(L, t, key);
+void luaH_set (lua_State *L, Table *t, const TValue *key, TValue *value) {
+ const TValue *slot = luaH_get(t, key);
+ luaH_finishset(L, t, key, slot, value);
}
void luaH_setint (lua_State *L, Table *t, lua_Integer key, TValue *value) {
const TValue *p = luaH_getint(t, key);
- TValue *cell;
- if (!isabstkey(p))
- cell = cast(TValue *, p);
- else {
+ if (isabstkey(p)) {
TValue k;
setivalue(&k, key);
- cell = luaH_newkey(L, t, &k);
+ luaH_newkey(L, t, &k, value);
}
- setobj2t(L, cell, value);
+ else
+ setobj2t(L, cast(TValue *, p), value);
}
diff --git a/ltable.h b/ltable.h
index c0060f4..7bbbcb2 100644
--- a/ltable.h
+++ b/ltable.h
@@ -41,8 +41,12 @@
LUAI_FUNC const TValue *luaH_getshortstr (Table *t, TString *key);
LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key);
LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key);
-LUAI_FUNC TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key);
-LUAI_FUNC TValue *luaH_set (lua_State *L, Table *t, const TValue *key);
+LUAI_FUNC void luaH_newkey (lua_State *L, Table *t, const TValue *key,
+ TValue *value);
+LUAI_FUNC void luaH_set (lua_State *L, Table *t, const TValue *key,
+ TValue *value);
+LUAI_FUNC void luaH_finishset (lua_State *L, Table *t, const TValue *key,
+ const TValue *slot, TValue *value);
LUAI_FUNC Table *luaH_new (lua_State *L);
LUAI_FUNC void luaH_resize (lua_State *L, Table *t, unsigned int nasize,
unsigned int nhsize);
diff --git a/lvm.c b/lvm.c
index aa3b22b..ccebdbe 100644
--- a/lvm.c
+++ b/lvm.c
@@ -337,10 +337,7 @@
lua_assert(isempty(slot)); /* slot must be empty */
tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */
if (tm == NULL) { /* no metamethod? */
- if (isabstkey(slot)) /* no previous entry? */
- slot = luaH_newkey(L, h, key); /* create one */
- /* no metamethod and (now) there is an entry with given key */
- setobj2t(L, cast(TValue *, slot), val); /* set its new value */
+ luaH_finishset(L, h, key, slot, val); /* set new value */
invalidateTMcache(h);
luaC_barrierback(L, obj2gco(h), val);
return;