/src/testdir/build/lua-master/source/lstring.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | ** $Id: lstring.c $ |
3 | | ** String table (keeps all strings handled by Lua) |
4 | | ** See Copyright Notice in lua.h |
5 | | */ |
6 | | |
7 | | #define lstring_c |
8 | | #define LUA_CORE |
9 | | |
10 | | #include "lprefix.h" |
11 | | |
12 | | |
13 | | #include <string.h> |
14 | | |
15 | | #include "lua.h" |
16 | | |
17 | | #include "ldebug.h" |
18 | | #include "ldo.h" |
19 | | #include "lmem.h" |
20 | | #include "lobject.h" |
21 | | #include "lstate.h" |
22 | | #include "lstring.h" |
23 | | |
24 | | |
25 | | /* |
26 | | ** Maximum size for string table. |
27 | | */ |
28 | 41.0k | #define MAXSTRTB cast_int(luaM_limitN(INT_MAX, TString*)) |
29 | | |
30 | | /* |
31 | | ** Initial size for the string table (must be power of 2). |
32 | | ** The Lua core alone registers ~50 strings (reserved words + |
33 | | ** metaevent keys + a few others). Libraries would typically add |
34 | | ** a few dozens more. |
35 | | */ |
36 | | #if !defined(MINSTRTABSIZE) |
37 | 119k | #define MINSTRTABSIZE 128 |
38 | | #endif |
39 | | |
40 | | |
41 | | /* |
42 | | ** equality for long strings |
43 | | */ |
44 | 6.97M | int luaS_eqlngstr (TString *a, TString *b) { |
45 | 6.97M | size_t len = a->u.lnglen; |
46 | 6.97M | lua_assert(a->tt == LUA_VLNGSTR && b->tt == LUA_VLNGSTR); |
47 | 6.97M | return (a == b) || /* same instance or... */ |
48 | 6.97M | ((len == b->u.lnglen) && /* equal length and ... */ |
49 | 3.27M | (memcmp(getlngstr(a), getlngstr(b), len) == 0)); /* equal contents */ |
50 | 6.97M | } |
51 | | |
52 | | |
53 | 267M | unsigned luaS_hash (const char *str, size_t l, unsigned seed) { |
54 | 267M | unsigned int h = seed ^ cast_uint(l); |
55 | 6.41G | for (; l > 0; l--) |
56 | 6.14G | h ^= ((h<<5) + (h>>2) + cast_byte(str[l - 1])); |
57 | 267M | return h; |
58 | 267M | } |
59 | | |
60 | | |
61 | 13.7M | unsigned luaS_hashlongstr (TString *ts) { |
62 | 13.7M | lua_assert(ts->tt == LUA_VLNGSTR); |
63 | 13.7M | if (ts->extra == 0) { /* no hash? */ |
64 | 2.12M | size_t len = ts->u.lnglen; |
65 | 2.12M | ts->hash = luaS_hash(getlngstr(ts), len, ts->hash); |
66 | 0 | ts->extra = 1; /* now it has its hash */ |
67 | 2.12M | } |
68 | 13.7M | return ts->hash; |
69 | 13.7M | } |
70 | | |
71 | | |
72 | 105k | static void tablerehash (TString **vect, int osize, int nsize) { |
73 | 105k | int i; |
74 | 23.7M | for (i = osize; i < nsize; i++) /* clear new elements */ |
75 | 23.6M | vect[i] = NULL; |
76 | 22.8M | for (i = 0; i < osize; i++) { /* rehash old part of the array */ |
77 | 22.7M | TString *p = vect[i]; |
78 | 22.7M | vect[i] = NULL; |
79 | 39.9M | while (p) { /* for each string in the list */ |
80 | 17.2M | TString *hnext = p->u.hnext; /* save next */ |
81 | 17.2M | unsigned int h = lmod(p->hash, nsize); /* new position */ |
82 | 0 | p->u.hnext = vect[h]; /* chain it into array */ |
83 | 17.2M | vect[h] = p; |
84 | 17.2M | p = hnext; |
85 | 17.2M | } |
86 | 22.7M | } |
87 | 105k | } |
88 | | |
89 | | |
90 | | /* |
91 | | ** Resize the string table. If allocation fails, keep the current size. |
92 | | ** (This can degrade performance, but any non-zero size should work |
93 | | ** correctly.) |
94 | | */ |
95 | 46.0k | void luaS_resize (lua_State *L, int nsize) { |
96 | 46.0k | stringtable *tb = &G(L)->strt; |
97 | 46.0k | int osize = tb->size; |
98 | 46.0k | TString **newvect; |
99 | 46.0k | if (nsize < osize) /* shrinking table? */ |
100 | 4.95k | tablerehash(tb->hash, osize, nsize); /* depopulate shrinking part */ |
101 | 46.0k | newvect = luaM_reallocvector(L, tb->hash, osize, nsize, TString*); |
102 | 46.0k | if (l_unlikely(newvect == NULL)) { /* reallocation failed? */ |
103 | 0 | if (nsize < osize) /* was it shrinking table? */ |
104 | 0 | tablerehash(tb->hash, nsize, osize); /* restore to original size */ |
105 | | /* leave table as it was */ |
106 | 0 | } |
107 | 46.0k | else { /* allocation succeeded */ |
108 | 46.0k | tb->hash = newvect; |
109 | 46.0k | tb->size = nsize; |
110 | 46.0k | if (nsize > osize) |
111 | 41.0k | tablerehash(newvect, osize, nsize); /* rehash for new size */ |
112 | 46.0k | } |
113 | 46.0k | } |
114 | | |
115 | | |
116 | | /* |
117 | | ** Clear API string cache. (Entries cannot be empty, so fill them with |
118 | | ** a non-collectable string.) |
119 | | */ |
120 | 1.11M | void luaS_clearcache (global_State *g) { |
121 | 1.11M | int i, j; |
122 | 60.0M | for (i = 0; i < STRCACHE_N; i++) |
123 | 176M | for (j = 0; j < STRCACHE_M; j++) { |
124 | 117M | if (iswhite(g->strcache[i][j])) /* will entry be collected? */ |
125 | 4.25M | g->strcache[i][j] = g->memerrmsg; /* replace it with something fixed */ |
126 | 117M | } |
127 | 1.11M | } |
128 | | |
129 | | |
130 | | /* |
131 | | ** Initialize the string table and the string cache |
132 | | */ |
133 | 59.5k | void luaS_init (lua_State *L) { |
134 | 59.5k | global_State *g = G(L); |
135 | 59.5k | int i, j; |
136 | 59.5k | stringtable *tb = &G(L)->strt; |
137 | 59.5k | tb->hash = luaM_newvector(L, MINSTRTABSIZE, TString*); |
138 | 59.5k | tablerehash(tb->hash, 0, MINSTRTABSIZE); /* clear array */ |
139 | 59.5k | tb->size = MINSTRTABSIZE; |
140 | | /* pre-create memory-error message */ |
141 | 59.5k | g->memerrmsg = luaS_newliteral(L, MEMERRMSG); |
142 | 59.5k | luaC_fix(L, obj2gco(g->memerrmsg)); /* it should never be collected */ |
143 | 3.21M | for (i = 0; i < STRCACHE_N; i++) /* fill cache with valid strings */ |
144 | 9.46M | for (j = 0; j < STRCACHE_M; j++) |
145 | 6.31M | g->strcache[i][j] = g->memerrmsg; |
146 | 59.5k | } |
147 | | |
148 | | |
149 | 94.1M | size_t luaS_sizelngstr (size_t len, int kind) { |
150 | 94.1M | switch (kind) { |
151 | 87.9M | case LSTRREG: /* regular long string */ |
152 | | /* don't need 'falloc'/'ud', but need space for content */ |
153 | 87.9M | return offsetof(TString, falloc) + (len + 1) * sizeof(char); |
154 | 1.17M | case LSTRFIX: /* fixed external long string */ |
155 | | /* don't need 'falloc'/'ud' */ |
156 | 1.17M | return offsetof(TString, falloc); |
157 | 4.96M | default: /* external long string with deallocation */ |
158 | 4.96M | lua_assert(kind == LSTRMEM); |
159 | 4.96M | return sizeof(TString); |
160 | 94.1M | } |
161 | 94.1M | } |
162 | | |
163 | | |
164 | | /* |
165 | | ** creates a new string object |
166 | | */ |
167 | | static TString *createstrobj (lua_State *L, size_t totalsize, lu_byte tag, |
168 | 51.2M | unsigned h) { |
169 | 51.2M | TString *ts; |
170 | 51.2M | GCObject *o; |
171 | 51.2M | o = luaC_newobj(L, tag, totalsize); |
172 | 51.2M | ts = gco2ts(o); |
173 | 0 | ts->hash = h; |
174 | 51.2M | ts->extra = 0; |
175 | 51.2M | return ts; |
176 | 51.2M | } |
177 | | |
178 | | |
179 | 23.8M | TString *luaS_createlngstrobj (lua_State *L, size_t l) { |
180 | 23.8M | size_t totalsize = luaS_sizelngstr(l, LSTRREG); |
181 | 23.8M | TString *ts = createstrobj(L, totalsize, LUA_VLNGSTR, G(L)->seed); |
182 | 23.8M | ts->u.lnglen = l; |
183 | 23.8M | ts->shrlen = LSTRREG; /* signals that it is a regular long string */ |
184 | 23.8M | ts->contents = cast_charp(ts) + offsetof(TString, falloc); |
185 | 23.8M | ts->contents[l] = '\0'; /* ending 0 */ |
186 | 23.8M | return ts; |
187 | 23.8M | } |
188 | | |
189 | | |
190 | 26.3M | void luaS_remove (lua_State *L, TString *ts) { |
191 | 26.3M | stringtable *tb = &G(L)->strt; |
192 | 26.3M | TString **p = &tb->hash[lmod(ts->hash, tb->size)]; |
193 | 29.1M | while (*p != ts) /* find previous element */ |
194 | 2.78M | p = &(*p)->u.hnext; |
195 | 26.3M | *p = (*p)->u.hnext; /* remove element from its list */ |
196 | 26.3M | tb->nuse--; |
197 | 26.3M | } |
198 | | |
199 | | |
200 | 41.0k | static void growstrtab (lua_State *L, stringtable *tb) { |
201 | 41.0k | if (l_unlikely(tb->nuse == INT_MAX)) { /* too many strings? */ |
202 | 0 | luaC_fullgc(L, 1); /* try to free some... */ |
203 | 0 | if (tb->nuse == INT_MAX) /* still too many? */ |
204 | 0 | luaM_error(L); /* cannot even create a message... */ |
205 | 0 | } |
206 | 41.0k | if (tb->size <= MAXSTRTB / 2) /* can grow string table? */ |
207 | 41.0k | luaS_resize(L, tb->size * 2); |
208 | 41.0k | } |
209 | | |
210 | | |
211 | | /* |
212 | | ** Checks whether short string exists and reuses it or creates a new one. |
213 | | */ |
214 | 265M | static TString *internshrstr (lua_State *L, const char *str, size_t l) { |
215 | 265M | TString *ts; |
216 | 265M | global_State *g = G(L); |
217 | 265M | stringtable *tb = &g->strt; |
218 | 265M | unsigned int h = luaS_hash(str, l, g->seed); |
219 | 265M | TString **list = &tb->hash[lmod(h, tb->size)]; |
220 | 265M | lua_assert(str != NULL); /* otherwise 'memcmp'/'memcpy' are undefined */ |
221 | 329M | for (ts = *list; ts != NULL; ts = ts->u.hnext) { |
222 | 303M | if (l == cast_uint(ts->shrlen) && |
223 | 303M | (memcmp(str, getshrstr(ts), l * sizeof(char)) == 0)) { |
224 | | /* found! */ |
225 | 238M | if (isdead(g, ts)) /* dead (but not collected yet)? */ |
226 | 2.41M | changewhite(ts); /* resurrect it */ |
227 | 238M | return ts; |
228 | 238M | } |
229 | 303M | } |
230 | | /* else must create a new string */ |
231 | 26.3M | if (tb->nuse >= tb->size) { /* need to grow string table? */ |
232 | 41.0k | growstrtab(L, tb); |
233 | 41.0k | list = &tb->hash[lmod(h, tb->size)]; /* rehash with new size */ |
234 | 41.0k | } |
235 | 26.3M | ts = createstrobj(L, sizestrshr(l), LUA_VSHRSTR, h); |
236 | 26.3M | ts->shrlen = cast(ls_byte, l); |
237 | 26.3M | getshrstr(ts)[l] = '\0'; /* ending 0 */ |
238 | 26.3M | memcpy(getshrstr(ts), str, l * sizeof(char)); |
239 | 0 | ts->u.hnext = *list; |
240 | 26.3M | *list = ts; |
241 | 26.3M | tb->nuse++; |
242 | 26.3M | return ts; |
243 | 26.3M | } |
244 | | |
245 | | |
246 | | /* |
247 | | ** new string (with explicit length) |
248 | | */ |
249 | 288M | TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { |
250 | 288M | if (l <= LUAI_MAXSHORTLEN) /* short string? */ |
251 | 265M | return internshrstr(L, str, l); |
252 | 22.6M | else { |
253 | 22.6M | TString *ts; |
254 | 22.6M | if (l_unlikely(l * sizeof(char) >= (MAX_SIZE - sizeof(TString)))) |
255 | 0 | luaM_toobig(L); |
256 | 22.6M | ts = luaS_createlngstrobj(L, l); |
257 | 22.6M | memcpy(getlngstr(ts), str, l * sizeof(char)); |
258 | 0 | return ts; |
259 | 22.6M | } |
260 | 288M | } |
261 | | |
262 | | |
263 | | /* |
264 | | ** Create or reuse a zero-terminated string, first checking in the |
265 | | ** cache (using the string address as a key). The cache can contain |
266 | | ** only zero-terminated strings, so it is safe to use 'strcmp' to |
267 | | ** check hits. |
268 | | */ |
269 | 204M | TString *luaS_new (lua_State *L, const char *str) { |
270 | 204M | unsigned int i = point2uint(str) % STRCACHE_N; /* hash */ |
271 | 204M | int j; |
272 | 204M | TString **p = G(L)->strcache[i]; |
273 | 297M | for (j = 0; j < STRCACHE_M; j++) { |
274 | 281M | if (strcmp(str, getstr(p[j])) == 0) /* hit? */ |
275 | 188M | return p[j]; /* that is it */ |
276 | 281M | } |
277 | | /* normal route */ |
278 | 30.7M | for (j = STRCACHE_M - 1; j > 0; j--) |
279 | 15.3M | p[j] = p[j - 1]; /* move out last element */ |
280 | | /* new element is first in the list */ |
281 | 15.3M | p[0] = luaS_newlstr(L, str, strlen(str)); |
282 | 15.3M | return p[0]; |
283 | 204M | } |
284 | | |
285 | | |
286 | 2.96M | Udata *luaS_newudata (lua_State *L, size_t s, unsigned short nuvalue) { |
287 | 2.96M | Udata *u; |
288 | 2.96M | int i; |
289 | 2.96M | GCObject *o; |
290 | 2.96M | if (l_unlikely(s > MAX_SIZE - udatamemoffset(nuvalue))) |
291 | 0 | luaM_toobig(L); |
292 | 2.96M | o = luaC_newobj(L, LUA_VUSERDATA, sizeudata(nuvalue, s)); |
293 | 2.96M | u = gco2u(o); |
294 | 0 | u->len = s; |
295 | 2.96M | u->nuvalue = nuvalue; |
296 | 2.96M | u->metatable = NULL; |
297 | 2.96M | for (i = 0; i < nuvalue; i++) |
298 | 2.96M | setnilvalue(&u->uv[i].uv); |
299 | 2.96M | return u; |
300 | 2.96M | } |
301 | | |
302 | | |
303 | | struct NewExt { |
304 | | ls_byte kind; |
305 | | const char *s; |
306 | | size_t len; |
307 | | TString *ts; /* output */ |
308 | | }; |
309 | | |
310 | | |
311 | 1.05M | static void f_newext (lua_State *L, void *ud) { |
312 | 1.05M | struct NewExt *ne = cast(struct NewExt *, ud); |
313 | 1.05M | size_t size = luaS_sizelngstr(0, ne->kind); |
314 | 1.05M | ne->ts = createstrobj(L, size, LUA_VLNGSTR, G(L)->seed); |
315 | 1.05M | } |
316 | | |
317 | | |
318 | 11 | static void f_pintern (lua_State *L, void *ud) { |
319 | 11 | struct NewExt *ne = cast(struct NewExt *, ud); |
320 | 11 | ne->ts = internshrstr(L, ne->s, ne->len); |
321 | 11 | } |
322 | | |
323 | | |
324 | | TString *luaS_newextlstr (lua_State *L, |
325 | 1.05M | const char *s, size_t len, lua_Alloc falloc, void *ud) { |
326 | 1.05M | struct NewExt ne; |
327 | 1.05M | if (len <= LUAI_MAXSHORTLEN) { /* short string? */ |
328 | 11 | ne.s = s; ne.len = len; |
329 | 11 | if (!falloc) |
330 | 0 | f_pintern(L, &ne); /* just internalize string */ |
331 | 11 | else { |
332 | 11 | TStatus status = luaD_rawrunprotected(L, f_pintern, &ne); |
333 | 11 | (*falloc)(ud, cast_voidp(s), len + 1, 0); /* free external string */ |
334 | 11 | if (status != LUA_OK) /* memory error? */ |
335 | 0 | luaM_error(L); /* re-raise memory error */ |
336 | 11 | } |
337 | 11 | return ne.ts; |
338 | 11 | } |
339 | | /* "normal" case: long strings */ |
340 | 1.05M | if (!falloc) { |
341 | 59.9k | ne.kind = LSTRFIX; |
342 | 59.9k | f_newext(L, &ne); /* just create header */ |
343 | 59.9k | } |
344 | 999k | else { |
345 | 999k | ne.kind = LSTRMEM; |
346 | 999k | if (luaD_rawrunprotected(L, f_newext, &ne) != LUA_OK) { /* mem. error? */ |
347 | 0 | (*falloc)(ud, cast_voidp(s), len + 1, 0); /* free external string */ |
348 | 0 | luaM_error(L); /* re-raise memory error */ |
349 | 0 | } |
350 | 999k | ne.ts->falloc = falloc; |
351 | 999k | ne.ts->ud = ud; |
352 | 999k | } |
353 | 1.05M | ne.ts->shrlen = ne.kind; |
354 | 1.05M | ne.ts->u.lnglen = len; |
355 | 1.05M | ne.ts->contents = cast_charp(s); |
356 | 1.05M | return ne.ts; |
357 | 1.05M | } |
358 | | |
359 | | |