diff --git a/lapi.c b/lapi.c index 9fffcc16..03e756d6 100644 --- a/lapi.c +++ b/lapi.c @@ -871,12 +871,10 @@ LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) { 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 97e427b2..d8d353fe 100644 --- a/lcode.c +++ b/lcode.c @@ -545,11 +545,14 @@ static void freeexps (FuncState *fs, expdesc *e1, expdesc *e2) { ** 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 @@ static int addk (FuncState *fs, TValue *key, TValue *v) { 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 4b8dec99..e9915178 100644 --- a/llex.c +++ b/llex.c @@ -122,26 +122,29 @@ l_noret luaX_syntaxerror (LexState *ls, const char *msg) { /* -** 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 7e7cbed9..e9410f99 100644 --- a/ltable.c +++ b/ltable.c @@ -485,7 +485,7 @@ static void reinsert (lua_State *L, Table *ot, Table *t) { 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 @@ static Node *getfreepos (Table *t) { ** 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 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) { 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 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) { setnodekey(L, mp, key); luaC_barrierback(L, obj2gco(t), key); lua_assert(isempty(gval(mp))); - return gval(mp); + setobj2t(L, gval(mp), value); } @@ -769,29 +770,40 @@ const TValue *luaH_get (Table *t, const TValue *key) { } +/* +** 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 c0060f4b..7bbbcb21 100644 --- a/ltable.h +++ b/ltable.h @@ -41,8 +41,12 @@ LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key, 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 aa3b22bf..ccebdbe0 100644 --- a/lvm.c +++ b/lvm.c @@ -337,10 +337,7 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key, 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;