aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2024-12-28 15:05:01 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2024-12-28 15:05:01 -0300
commitabf8b1cd4a798fada026b4046e9dbc08791963f2 (patch)
tree1a1466ff782cee004c83857554612fbfee38fc2e
parent2a307f898be2716638e7ac30d119f7cd9bbbe096 (diff)
downloadlua-abf8b1cd4a798fada026b4046e9dbc08791963f2.tar.gz
lua-abf8b1cd4a798fada026b4046e9dbc08791963f2.tar.bz2
lua-abf8b1cd4a798fada026b4046e9dbc08791963f2.zip
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}.
-rw-r--r--ltable.c81
1 files changed, 63 insertions, 18 deletions
diff --git a/ltable.c b/ltable.c
index eb5abf9f..f6785367 100644
--- a/ltable.c
+++ b/ltable.c
@@ -981,14 +981,19 @@ lu_byte luaH_getshortstr (Table *t, TString *key, TValue *res) {
981} 981}
982 982
983 983
984static const TValue *Hgetlongstr (Table *t, TString *key) {
985 TValue ko;
986 lua_assert(!strisshr(key));
987 setsvalue(cast(lua_State *, NULL), &ko, key);
988 return getgeneric(t, &ko, 0); /* for long strings, use generic case */
989}
990
991
984static const TValue *Hgetstr (Table *t, TString *key) { 992static const TValue *Hgetstr (Table *t, TString *key) {
985 if (key->tt == LUA_VSHRSTR) 993 if (strisshr(key))
986 return luaH_Hgetshortstr(t, key); 994 return luaH_Hgetshortstr(t, key);
987 else { /* for long strings, use generic case */ 995 else
988 TValue ko; 996 return Hgetlongstr(t, key);
989 setsvalue(cast(lua_State *, NULL), &ko, key);
990 return getgeneric(t, &ko, 0);
991 }
992} 997}
993 998
994 999
@@ -1025,15 +1030,25 @@ lu_byte luaH_get (Table *t, const TValue *key, TValue *res) {
1025} 1030}
1026 1031
1027 1032
1033/*
1034** When a 'pset' cannot be completed, this function returns an encoding
1035** of its result, to be used by 'luaH_finishset'.
1036*/
1037static int retpsetcode (Table *t, const TValue *slot) {
1038 if (isabstkey(slot))
1039 return HNOTFOUND; /* no slot with that key */
1040 else /* return node encoded */
1041 return cast_int((cast(Node*, slot) - t->node)) + HFIRSTNODE;
1042}
1043
1044
1028static int finishnodeset (Table *t, const TValue *slot, TValue *val) { 1045static int finishnodeset (Table *t, const TValue *slot, TValue *val) {
1029 if (!ttisnil(slot)) { 1046 if (!ttisnil(slot)) {
1030 setobj(((lua_State*)NULL), cast(TValue*, slot), val); 1047 setobj(((lua_State*)NULL), cast(TValue*, slot), val);
1031 return HOK; /* success */ 1048 return HOK; /* success */
1032 } 1049 }
1033 else if (isabstkey(slot)) 1050 else
1034 return HNOTFOUND; /* no slot with that key */ 1051 return retpsetcode(t, slot);
1035 else /* return node encoded */
1036 return cast_int((cast(Node*, slot) - t->node)) + HFIRSTNODE;
1037} 1052}
1038 1053
1039 1054
@@ -1060,13 +1075,45 @@ static int psetint (Table *t, lua_Integer key, TValue *val) {
1060} 1075}
1061 1076
1062 1077
1078/*
1079** This function could be just this:
1080** return finishnodeset(t, luaH_Hgetshortstr(t, key), val);
1081** However, it optimizes the common case created by constructors (e.g.,
1082** {x=1, y=2}), which creates a key in a table that has no metatable,
1083** it is not old/black, and it already has space for the key.
1084*/
1085
1063int luaH_psetshortstr (Table *t, TString *key, TValue *val) { 1086int luaH_psetshortstr (Table *t, TString *key, TValue *val) {
1064 return finishnodeset(t, luaH_Hgetshortstr(t, key), val); 1087 const TValue *slot = luaH_Hgetshortstr(t, key);
1088 if (!ttisnil(slot)) { /* key already has a value? (all too common) */
1089 setobj(((lua_State*)NULL), cast(TValue*, slot), val); /* update it */
1090 return HOK; /* done */
1091 }
1092 else if (checknoTM(t->metatable, TM_NEWINDEX)) { /* no metamethod? */
1093 if (ttisnil(val)) /* new value is nil? */
1094 return HOK; /* done (value is already nil/absent) */
1095 if (isabstkey(slot) && /* key is absent? */
1096 !(isblack(t) && iswhite(key))) { /* and don't need barrier? */
1097 TValue tk; /* key as a TValue */
1098 setsvalue(cast(lua_State *, NULL), &tk, key);
1099 if (insertkey(t, &tk, val)) { /* insert key, if there is space */
1100 invalidateTMcache(t);
1101 return HOK;
1102 }
1103 }
1104 }
1105 /* Else, either table has new-index metamethod, or it needs barrier,
1106 or it needs to rehash for the new key. In any of these cases, the
1107 operation cannot be completed here. Return a code for the caller. */
1108 return retpsetcode(t, slot);
1065} 1109}
1066 1110
1067 1111
1068int luaH_psetstr (Table *t, TString *key, TValue *val) { 1112int luaH_psetstr (Table *t, TString *key, TValue *val) {
1069 return finishnodeset(t, Hgetstr(t, key), val); 1113 if (strisshr(key))
1114 return luaH_psetshortstr(t, key, val);
1115 else
1116 return finishnodeset(t, Hgetlongstr(t, key), val);
1070} 1117}
1071 1118
1072 1119
@@ -1087,13 +1134,11 @@ int luaH_pset (Table *t, const TValue *key, TValue *val) {
1087} 1134}
1088 1135
1089/* 1136/*
1090** Finish a raw "set table" operation, where 'slot' is where the value 1137** Finish a raw "set table" operation, where 'hres' encodes where the
1091** should have been (the result of a previous "get table"). 1138** value should have been (the result of a previous 'pset' operation).
1092** Beware: when using this function you probably need to check a GC 1139** Beware: when using this function the caller probably need to check a
1093** barrier and invalidate the TM cache. 1140** GC barrier and invalidate the TM cache.
1094*/ 1141*/
1095
1096
1097void luaH_finishset (lua_State *L, Table *t, const TValue *key, 1142void luaH_finishset (lua_State *L, Table *t, const TValue *key,
1098 TValue *value, int hres) { 1143 TValue *value, int hres) {
1099 lua_assert(hres != HOK); 1144 lua_assert(hres != HOK);