1 /* $NetBSD: lstring.c,v 1.10 2023/04/16 20:46:17 nikita Exp $ */ 2 3 /* 4 ** Id: lstring.c 5 ** String table (keeps all strings handled by Lua) 6 ** See Copyright Notice in lua.h 7 */ 8 9 #define lstring_c 10 #define LUA_CORE 11 12 #include "lprefix.h" 13 14 15 #ifndef _KERNEL 16 #include <string.h> 17 #endif /* _KERNEL */ 18 19 #include "lua.h" 20 21 #include "ldebug.h" 22 #include "ldo.h" 23 #include "lmem.h" 24 #include "lobject.h" 25 #include "lstate.h" 26 #include "lstring.h" 27 28 29 /* 30 ** Maximum size for string table. 31 */ 32 #define MAXSTRTB cast_int(luaM_limitN(MAX_INT, TString*)) 33 34 35 /* 36 ** equality for long strings 37 */ 38 int luaS_eqlngstr (TString *a, TString *b) { 39 size_t len = a->u.lnglen; 40 lua_assert(a->tt == LUA_VLNGSTR && b->tt == LUA_VLNGSTR); 41 return (a == b) || /* same instance or... */ 42 ((len == b->u.lnglen) && /* equal length and ... */ 43 (memcmp(getstr(a), getstr(b), len) == 0)); /* equal contents */ 44 } 45 46 47 unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) { 48 unsigned int h = seed ^ cast_uint(l); 49 for (; l > 0; l--) 50 h ^= ((h<<5) + (h>>2) + cast_byte(str[l - 1])); 51 return h; 52 } 53 54 55 unsigned int luaS_hashlongstr (TString *ts) { 56 lua_assert(ts->tt == LUA_VLNGSTR); 57 if (ts->extra == 0) { /* no hash? */ 58 size_t len = ts->u.lnglen; 59 ts->hash = luaS_hash(getstr(ts), len, ts->hash); 60 ts->extra = 1; /* now it has its hash */ 61 } 62 return ts->hash; 63 } 64 65 66 static void tablerehash (TString **vect, int osize, int nsize) { 67 int i; 68 for (i = osize; i < nsize; i++) /* clear new elements */ 69 vect[i] = NULL; 70 for (i = 0; i < osize; i++) { /* rehash old part of the array */ 71 TString *p = vect[i]; 72 vect[i] = NULL; 73 while (p) { /* for each string in the list */ 74 TString *hnext = p->u.hnext; /* save next */ 75 unsigned int h = lmod(p->hash, nsize); /* new position */ 76 p->u.hnext = vect[h]; /* chain it into array */ 77 vect[h] = p; 78 p = hnext; 79 } 80 } 81 } 82 83 84 /* 85 ** Resize the string table. If allocation fails, keep the current size. 86 ** (This can degrade performance, but any non-zero size should work 87 ** correctly.) 88 */ 89 void luaS_resize (lua_State *L, int nsize) { 90 stringtable *tb = &G(L)->strt; 91 int osize = tb->size; 92 TString **newvect; 93 if (nsize < osize) /* shrinking table? */ 94 tablerehash(tb->hash, osize, nsize); /* depopulate shrinking part */ 95 newvect = luaM_reallocvector(L, tb->hash, osize, nsize, TString*); 96 if (l_unlikely(newvect == NULL)) { /* reallocation failed? */ 97 if (nsize < osize) /* was it shrinking table? */ 98 tablerehash(tb->hash, nsize, osize); /* restore to original size */ 99 /* leave table as it was */ 100 } 101 else { /* allocation succeeded */ 102 tb->hash = newvect; 103 tb->size = nsize; 104 if (nsize > osize) 105 tablerehash(newvect, osize, nsize); /* rehash for new size */ 106 } 107 } 108 109 110 /* 111 ** Clear API string cache. (Entries cannot be empty, so fill them with 112 ** a non-collectable string.) 113 */ 114 void luaS_clearcache (global_State *g) { 115 int i, j; 116 for (i = 0; i < STRCACHE_N; i++) 117 for (j = 0; j < STRCACHE_M; j++) { 118 if (iswhite(g->strcache[i][j])) /* will entry be collected? */ 119 g->strcache[i][j] = g->memerrmsg; /* replace it with something fixed */ 120 } 121 } 122 123 124 /* 125 ** Initialize the string table and the string cache 126 */ 127 void luaS_init (lua_State *L) { 128 global_State *g = G(L); 129 int i, j; 130 stringtable *tb = &G(L)->strt; 131 tb->hash = luaM_newvector(L, MINSTRTABSIZE, TString*); 132 tablerehash(tb->hash, 0, MINSTRTABSIZE); /* clear array */ 133 tb->size = MINSTRTABSIZE; 134 /* pre-create memory-error message */ 135 g->memerrmsg = luaS_newliteral(L, MEMERRMSG); 136 luaC_fix(L, obj2gco(g->memerrmsg)); /* it should never be collected */ 137 for (i = 0; i < STRCACHE_N; i++) /* fill cache with valid strings */ 138 for (j = 0; j < STRCACHE_M; j++) 139 g->strcache[i][j] = g->memerrmsg; 140 } 141 142 143 144 /* 145 ** creates a new string object 146 */ 147 static TString *createstrobj (lua_State *L, size_t l, int tag, unsigned int h) { 148 TString *ts; 149 GCObject *o; 150 size_t totalsize; /* total size of TString object */ 151 totalsize = sizelstring(l); 152 o = luaC_newobj(L, tag, totalsize); 153 ts = gco2ts(o); 154 ts->hash = h; 155 ts->extra = 0; 156 getstr(ts)[l] = '\0'; /* ending 0 */ 157 return ts; 158 } 159 160 161 TString *luaS_createlngstrobj (lua_State *L, size_t l) { 162 TString *ts = createstrobj(L, l, LUA_VLNGSTR, G(L)->seed); 163 ts->u.lnglen = l; 164 return ts; 165 } 166 167 168 void luaS_remove (lua_State *L, TString *ts) { 169 stringtable *tb = &G(L)->strt; 170 TString **p = &tb->hash[lmod(ts->hash, tb->size)]; 171 while (*p != ts) /* find previous element */ 172 p = &(*p)->u.hnext; 173 *p = (*p)->u.hnext; /* remove element from its list */ 174 tb->nuse--; 175 } 176 177 178 static void growstrtab (lua_State *L, stringtable *tb) { 179 if (l_unlikely(tb->nuse == MAX_INT)) { /* too many strings? */ 180 luaC_fullgc(L, 1); /* try to free some... */ 181 if (tb->nuse == MAX_INT) /* still too many? */ 182 luaM_error(L); /* cannot even create a message... */ 183 } 184 if (tb->size <= MAXSTRTB / 2) /* can grow string table? */ 185 luaS_resize(L, tb->size * 2); 186 } 187 188 189 /* 190 ** Checks whether short string exists and reuses it or creates a new one. 191 */ 192 static TString *internshrstr (lua_State *L, const char *str, size_t l) { 193 TString *ts; 194 global_State *g = G(L); 195 stringtable *tb = &g->strt; 196 unsigned int h = luaS_hash(str, l, g->seed); 197 TString **list = &tb->hash[lmod(h, tb->size)]; 198 lua_assert(str != NULL); /* otherwise 'memcmp'/'memcpy' are undefined */ 199 for (ts = *list; ts != NULL; ts = ts->u.hnext) { 200 if (l == ts->shrlen && (memcmp(str, getstr(ts), l * sizeof(char)) == 0)) { 201 /* found! */ 202 if (isdead(g, ts)) /* dead (but not collected yet)? */ 203 changewhite(ts); /* resurrect it */ 204 return ts; 205 } 206 } 207 /* else must create a new string */ 208 if (tb->nuse >= tb->size) { /* need to grow string table? */ 209 growstrtab(L, tb); 210 list = &tb->hash[lmod(h, tb->size)]; /* rehash with new size */ 211 } 212 ts = createstrobj(L, l, LUA_VSHRSTR, h); 213 memcpy(getstr(ts), str, l * sizeof(char)); 214 ts->shrlen = cast_byte(l); 215 ts->u.hnext = *list; 216 *list = ts; 217 tb->nuse++; 218 return ts; 219 } 220 221 222 /* 223 ** new string (with explicit length) 224 */ 225 TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { 226 if (l <= LUAI_MAXSHORTLEN) /* short string? */ 227 return internshrstr(L, str, l); 228 else { 229 TString *ts; 230 if (l_unlikely(l >= (MAX_SIZE - sizeof(TString))/sizeof(char))) 231 luaM_toobig(L); 232 ts = luaS_createlngstrobj(L, l); 233 memcpy(getstr(ts), str, l * sizeof(char)); 234 return ts; 235 } 236 } 237 238 239 /* 240 ** Create or reuse a zero-terminated string, first checking in the 241 ** cache (using the string address as a key). The cache can contain 242 ** only zero-terminated strings, so it is safe to use 'strcmp' to 243 ** check hits. 244 */ 245 TString *luaS_new (lua_State *L, const char *str) { 246 unsigned int i = point2uint(str) % STRCACHE_N; /* hash */ 247 int j; 248 TString **p = G(L)->strcache[i]; 249 for (j = 0; j < STRCACHE_M; j++) { 250 if (strcmp(str, getstr(p[j])) == 0) /* hit? */ 251 return p[j]; /* that is it */ 252 } 253 /* normal route */ 254 for (j = STRCACHE_M - 1; j > 0; j--) 255 p[j] = p[j - 1]; /* move out last element */ 256 /* new element is first in the list */ 257 p[0] = luaS_newlstr(L, str, strlen(str)); 258 return p[0]; 259 } 260 261 262 Udata *luaS_newudata (lua_State *L, size_t s, int nuvalue) { 263 Udata *u; 264 int i; 265 GCObject *o; 266 if (l_unlikely(s > MAX_SIZE - udatamemoffset(nuvalue))) 267 luaM_toobig(L); 268 o = luaC_newobj(L, LUA_VUSERDATA, sizeudata(nuvalue, s)); 269 u = gco2u(o); 270 u->len = s; 271 u->nuvalue = nuvalue; 272 u->metatable = NULL; 273 for (i = 0; i < nuvalue; i++) 274 setnilvalue(&u->uv[i].uv); 275 return u; 276 } 277 278