@@ -148,10 +148,9 @@ void luaS_remove (lua_State *L, TString *ts) {
148
148
/*
149
149
** checks whether short string exists and reuses it or creates a new one
150
150
*/
151
- static TString * internshrstr (lua_State * L , const char * str , size_t l ) {
151
+ static TString * queryshrstr (lua_State * L , const char * str , size_t l , unsigned int h ) {
152
152
TString * ts ;
153
153
global_State * g = G (L );
154
- unsigned int h = luaS_hash (str , l , g -> seed );
155
154
TString * * list = & g -> strt .hash [lmod (h , g -> strt .size )];
156
155
for (ts = * list ; ts != NULL ; ts = ts -> u .hnext ) {
157
156
if (l == ts -> shrlen &&
@@ -162,6 +161,13 @@ static TString *internshrstr (lua_State *L, const char *str, size_t l) {
162
161
return ts ;
163
162
}
164
163
}
164
+ return NULL ;
165
+ }
166
+
167
+ static TString * addshrstr (lua_State * L , const char * str , size_t l , unsigned int h ) {
168
+ TString * ts ;
169
+ global_State * g = G (L );
170
+ TString * * list = & g -> strt .hash [lmod (h , g -> strt .size )];
165
171
if (g -> strt .nuse >= g -> strt .size && g -> strt .size <= MAX_INT /2 ) {
166
172
luaS_resize (L , g -> strt .size * 2 );
167
173
list = & g -> strt .hash [lmod (h , g -> strt .size )]; /* recompute with new size */
@@ -174,6 +180,7 @@ static TString *internshrstr (lua_State *L, const char *str, size_t l) {
174
180
return ts ;
175
181
}
176
182
183
+ static TString * internshrstr (lua_State * L , const char * str , size_t l );
177
184
178
185
/*
179
186
** new string (with explicit length)
@@ -224,3 +231,216 @@ Udata *luaS_newudata (lua_State *L, size_t s) {
224
231
return u ;
225
232
}
226
233
234
+ /*
235
+ * global shared table
236
+ */
237
+
238
+ #include "rwlock.h"
239
+ #include "atomic.h"
240
+ #include <stdlib.h>
241
+
242
+ #define SHRSTR_SLOT 0x10000
243
+ #define HASH_NODE (h ) ((h) % SHRSTR_SLOT)
244
+
245
+ struct shrmap_slot {
246
+ struct rwlock lock ;
247
+ TString * str ;
248
+ };
249
+
250
+ struct shrmap {
251
+ struct shrmap_slot h [SHRSTR_SLOT ];
252
+ int n ;
253
+ };
254
+
255
+ static struct shrmap * SSM = NULL ;
256
+
257
+ LUA_API void
258
+ luaS_initshr () {
259
+ struct shrmap * s = malloc (sizeof (* s ));
260
+ memset (s , 0 , sizeof (* s ));
261
+ int i ;
262
+ for (i = 0 ;i < SHRSTR_SLOT ;i ++ ) {
263
+ rwlock_init (& s -> h [i ].lock );
264
+ }
265
+ SSM = s ;
266
+ }
267
+
268
+ LUA_API void
269
+ luaS_exitshr () {
270
+ int i ;
271
+ for (i = 0 ;i < SHRSTR_SLOT ;i ++ ) {
272
+ TString * str = SSM -> h [i ].str ;
273
+ while (str ) {
274
+ TString * next = str -> u .hnext ;
275
+ free (str );
276
+ str = next ;
277
+ }
278
+ }
279
+ free (SSM );
280
+ }
281
+
282
+ static TString *
283
+ query_string (unsigned int h , const char * str , lu_byte l ) {
284
+ struct shrmap_slot * s = & SSM -> h [HASH_NODE (h )];
285
+ rwlock_rlock (& s -> lock );
286
+ TString * ts = s -> str ;
287
+ while (ts ) {
288
+ if (ts -> hash == h &&
289
+ ts -> shrlen == l &&
290
+ memcmp (str , ts + 1 , l ) == 0 ) {
291
+ break ;
292
+ }
293
+ ts = ts -> u .hnext ;
294
+ }
295
+ rwlock_runlock (& s -> lock );
296
+ return ts ;
297
+ }
298
+
299
+ static TString *
300
+ query_ptr (TString * t ) {
301
+ unsigned int h = t -> hash ;
302
+ struct shrmap_slot * s = & SSM -> h [HASH_NODE (h )];
303
+ rwlock_rlock (& s -> lock );
304
+ TString * ts = s -> str ;
305
+ while (ts ) {
306
+ if (ts == t )
307
+ break ;
308
+ ts = ts -> u .hnext ;
309
+ }
310
+ rwlock_runlock (& s -> lock );
311
+ return ts ;
312
+ }
313
+
314
+ static TString *
315
+ new_string (unsigned int h , const char * str , lu_byte l ) {
316
+ size_t sz = sizelstring (l );
317
+ TString * ts = malloc (sz );
318
+ memset (ts , 0 , sz );
319
+ ts -> tt = LUA_TSHRSTR ;
320
+ ts -> hash = h ;
321
+ ts -> shrlen = l ;
322
+ memcpy (ts + 1 , str , l );
323
+ return ts ;
324
+ }
325
+
326
+ static TString *
327
+ add_string (unsigned int h , const char * str , lu_byte l ) {
328
+ TString * tmp = new_string (h , str , l );
329
+ struct shrmap_slot * s = & SSM -> h [HASH_NODE (h )];
330
+ rwlock_wlock (& s -> lock );
331
+ TString * ts = s -> str ;
332
+ while (ts ) {
333
+ if (ts -> hash == h &&
334
+ ts -> shrlen == l &&
335
+ memcmp (str , ts + 1 , l ) == 0 ) {
336
+ break ;
337
+ }
338
+ ts = ts -> u .hnext ;
339
+ }
340
+ if (ts == NULL ) {
341
+ ts = tmp ;
342
+ ts -> u .hnext = s -> str ;
343
+ s -> str = ts ;
344
+ tmp = NULL ;
345
+ }
346
+ rwlock_wunlock (& s -> lock );
347
+ if (tmp ) {
348
+ // string is create by other thread, so free tmp
349
+ free (tmp );
350
+ }
351
+ return ts ;
352
+ }
353
+
354
+ static TString *
355
+ internshrstr (lua_State * L , const char * str , size_t l ) {
356
+ TString * ts ;
357
+ global_State * g = G (L );
358
+ unsigned int h = luaS_hash (str , l , g -> seed );
359
+ unsigned int h0 ;
360
+ // lookup global state of this L first
361
+ ts = queryshrstr (L , str , l , h );
362
+ if (ts )
363
+ return ts ;
364
+ // lookup SSM again
365
+ h0 = luaS_hash (str , l , 0 );
366
+ ts = query_string (h0 , str , l );
367
+ if (ts )
368
+ return ts ;
369
+ // If SSM->n greate than 0, add it to SSM
370
+ if (SSM -> n > 0 ) {
371
+ ATOM_DEC (& SSM -> n );
372
+ return add_string (h0 , str , l );
373
+ }
374
+ // Else add it to global state (local)
375
+ return addshrstr (L , str , l , h );
376
+ }
377
+
378
+ LUA_API void
379
+ luaS_expandshr (int n ) {
380
+ ATOM_ADD (& SSM -> n , n );
381
+ }
382
+
383
+ LUAI_FUNC TString *
384
+ luaS_clonestring (lua_State * L , TString * ts ) {
385
+ unsigned int h ;
386
+ int l ;
387
+ const char * str = getaddrstr (ts );
388
+ global_State * g = G (L );
389
+ TString * result ;
390
+ if (ts -> tt == LUA_TLNGSTR )
391
+ return luaS_newlstr (L , str , ts -> u .lnglen );
392
+ // look up global state of this L first
393
+ l = ts -> shrlen ;
394
+ h = luaS_hash (str , l , g -> seed );
395
+ result = queryshrstr (L , str , l , h );
396
+ if (result )
397
+ return result ;
398
+ // look up SSM by ptr
399
+ result = query_ptr (ts );
400
+ if (result )
401
+ return result ;
402
+ // ts is not in SSM, so recalc hash, and add it to SSM
403
+ h = luaS_hash (str , l , 0 );
404
+ return add_string (h , str , l );
405
+ }
406
+
407
+ struct slotinfo {
408
+ int len ;
409
+ int size ;
410
+ };
411
+
412
+ static void
413
+ getslot (struct shrmap_slot * s , struct slotinfo * info ) {
414
+ memset (info , 0 , sizeof (* info ));
415
+ rwlock_rlock (& s -> lock );
416
+ TString * ts = s -> str ;
417
+ while (ts ) {
418
+ ++ info -> len ;
419
+ info -> size += ts -> shrlen ;
420
+ ts = ts -> u .hnext ;
421
+ }
422
+ rwlock_runlock (& s -> lock );
423
+ }
424
+
425
+ LUA_API int
426
+ luaS_shrinfo (lua_State * L ) {
427
+ struct slotinfo total ;
428
+ struct slotinfo tmp ;
429
+ memset (& total , 0 , sizeof (total ));
430
+ int i ;
431
+ int len = 0 ;
432
+ for (i = 0 ;i < SHRSTR_SLOT ;i ++ ) {
433
+ struct shrmap_slot * s = & SSM -> h [i ];
434
+ getslot (s , & tmp );
435
+ len += tmp .len ;
436
+ if (tmp .len > total .len ) {
437
+ total .len = tmp .len ;
438
+ }
439
+ total .size += tmp .size ;
440
+ }
441
+ lua_pushinteger (L , len );
442
+ lua_pushinteger (L , total .size );
443
+ lua_pushinteger (L , total .len );
444
+ lua_pushinteger (L , SSM -> n );
445
+ return 4 ;
446
+ }
0 commit comments