1
0
mirror of https://github.com/lua/lua.git synced 2025-02-04 06:13:04 +08:00

Small optimization in 'luaH_psetshortstr'

Do not optimize only for table updates (key already present).
Creation of new short keys in new tables can be quite common in
programs that create lots of small tables, for instance with
constructors like {x=e1,y=e2}.
This commit is contained in:
Roberto Ierusalimschy 2024-12-28 15:05:01 -03:00
parent 2a307f898b
commit abf8b1cd4a

View File

@ -981,14 +981,19 @@ lu_byte luaH_getshortstr (Table *t, TString *key, TValue *res) {
} }
static const TValue *Hgetlongstr (Table *t, TString *key) {
TValue ko;
lua_assert(!strisshr(key));
setsvalue(cast(lua_State *, NULL), &ko, key);
return getgeneric(t, &ko, 0); /* for long strings, use generic case */
}
static const TValue *Hgetstr (Table *t, TString *key) { static const TValue *Hgetstr (Table *t, TString *key) {
if (key->tt == LUA_VSHRSTR) if (strisshr(key))
return luaH_Hgetshortstr(t, key); return luaH_Hgetshortstr(t, key);
else { /* for long strings, use generic case */ else
TValue ko; return Hgetlongstr(t, key);
setsvalue(cast(lua_State *, NULL), &ko, key);
return getgeneric(t, &ko, 0);
}
} }
@ -1025,15 +1030,25 @@ lu_byte luaH_get (Table *t, const TValue *key, TValue *res) {
} }
/*
** When a 'pset' cannot be completed, this function returns an encoding
** of its result, to be used by 'luaH_finishset'.
*/
static int retpsetcode (Table *t, const TValue *slot) {
if (isabstkey(slot))
return HNOTFOUND; /* no slot with that key */
else /* return node encoded */
return cast_int((cast(Node*, slot) - t->node)) + HFIRSTNODE;
}
static int finishnodeset (Table *t, const TValue *slot, TValue *val) { static int finishnodeset (Table *t, const TValue *slot, TValue *val) {
if (!ttisnil(slot)) { if (!ttisnil(slot)) {
setobj(((lua_State*)NULL), cast(TValue*, slot), val); setobj(((lua_State*)NULL), cast(TValue*, slot), val);
return HOK; /* success */ return HOK; /* success */
} }
else if (isabstkey(slot)) else
return HNOTFOUND; /* no slot with that key */ return retpsetcode(t, slot);
else /* return node encoded */
return cast_int((cast(Node*, slot) - t->node)) + HFIRSTNODE;
} }
@ -1060,13 +1075,45 @@ static int psetint (Table *t, lua_Integer key, TValue *val) {
} }
/*
** This function could be just this:
** return finishnodeset(t, luaH_Hgetshortstr(t, key), val);
** However, it optimizes the common case created by constructors (e.g.,
** {x=1, y=2}), which creates a key in a table that has no metatable,
** it is not old/black, and it already has space for the key.
*/
int luaH_psetshortstr (Table *t, TString *key, TValue *val) { int luaH_psetshortstr (Table *t, TString *key, TValue *val) {
return finishnodeset(t, luaH_Hgetshortstr(t, key), val); const TValue *slot = luaH_Hgetshortstr(t, key);
if (!ttisnil(slot)) { /* key already has a value? (all too common) */
setobj(((lua_State*)NULL), cast(TValue*, slot), val); /* update it */
return HOK; /* done */
}
else if (checknoTM(t->metatable, TM_NEWINDEX)) { /* no metamethod? */
if (ttisnil(val)) /* new value is nil? */
return HOK; /* done (value is already nil/absent) */
if (isabstkey(slot) && /* key is absent? */
!(isblack(t) && iswhite(key))) { /* and don't need barrier? */
TValue tk; /* key as a TValue */
setsvalue(cast(lua_State *, NULL), &tk, key);
if (insertkey(t, &tk, val)) { /* insert key, if there is space */
invalidateTMcache(t);
return HOK;
}
}
}
/* Else, either table has new-index metamethod, or it needs barrier,
or it needs to rehash for the new key. In any of these cases, the
operation cannot be completed here. Return a code for the caller. */
return retpsetcode(t, slot);
} }
int luaH_psetstr (Table *t, TString *key, TValue *val) { int luaH_psetstr (Table *t, TString *key, TValue *val) {
return finishnodeset(t, Hgetstr(t, key), val); if (strisshr(key))
return luaH_psetshortstr(t, key, val);
else
return finishnodeset(t, Hgetlongstr(t, key), val);
} }
@ -1087,13 +1134,11 @@ int luaH_pset (Table *t, const TValue *key, TValue *val) {
} }
/* /*
** Finish a raw "set table" operation, where 'slot' is where the value ** Finish a raw "set table" operation, where 'hres' encodes where the
** should have been (the result of a previous "get table"). ** value should have been (the result of a previous 'pset' operation).
** Beware: when using this function you probably need to check a GC ** Beware: when using this function the caller probably need to check a
** barrier and invalidate the TM cache. ** GC barrier and invalidate the TM cache.
*/ */
void luaH_finishset (lua_State *L, Table *t, const TValue *key, void luaH_finishset (lua_State *L, Table *t, const TValue *key,
TValue *value, int hres) { TValue *value, int hres) {
lua_assert(hres != HOK); lua_assert(hres != HOK);