@@ -417,6 +417,32 @@ static GCRef *gc_sweep(global_State *g, GCRef *p, uint32_t lim)
417417 return p ;
418418}
419419
420+ /* Sweep one string interning table chain. Preserves hashalg bit. */
421+ static void gc_sweepstr (global_State * g , GCRef * chain )
422+ {
423+ /* Mask with other white and LJ_GC_FIXED. Or LJ_GC_SFIXED on shutdown. */
424+ int ow = otherwhite (g );
425+ uintptr_t u = gcrefu (* chain );
426+ GCRef q ;
427+ GCRef * p = & q ;
428+ GCobj * o ;
429+ setgcrefp (q , (u & ~(uintptr_t )1 ));
430+ while ((o = gcref (* p )) != NULL ) {
431+ if (((o -> gch .marked ^ LJ_GC_WHITES ) & ow )) { /* Black or current white? */
432+ lj_assertG (!isdead (g , o ) || (o -> gch .marked & LJ_GC_FIXED ),
433+ "sweep of undead string" );
434+ makewhite (g , o ); /* String is alive, change to the current white. */
435+ p = & o -> gch .nextgc ;
436+ } else { /* Otherwise string is dead, free it. */
437+ lj_assertG (isdead (g , o ) || ow == LJ_GC_SFIXED ,
438+ "sweep of unlive string" );
439+ setgcrefr (* p , o -> gch .nextgc );
440+ lj_str_free (g , gco2str (o ));
441+ }
442+ }
443+ setgcrefp (* chain , (gcrefu (q ) | (u & 1 )));
444+ }
445+
420446/* Check whether we can clear a key or a value slot from a table. */
421447static int gc_mayclear (cTValue * o , int val )
422448{
@@ -571,9 +597,9 @@ void lj_gc_freeall(global_State *g)
571597 /* Free everything, except super-fixed objects (the main thread). */
572598 g -> gc .currentwhite = LJ_GC_WHITES | LJ_GC_SFIXED ;
573599 gc_fullsweep (g , & g -> gc .root );
574- strmask = g -> strmask ;
600+ strmask = g -> str . mask ;
575601 for (i = 0 ; i <= strmask ; i ++ ) /* Free all string hash chains. */
576- gc_fullsweep (g , & g -> strhash [i ]);
602+ gc_sweepstr (g , & g -> str . tab [i ]);
577603}
578604
579605/* -- Collector ----------------------------------------------------------- */
@@ -636,8 +662,8 @@ static size_t gc_onestep(lua_State *L)
636662 return 0 ;
637663 case GCSsweepstring : {
638664 GCSize old = g -> gc .total ;
639- gc_fullsweep (g , & g -> strhash [g -> gc .sweepstr ++ ]); /* Sweep one chain. */
640- if (g -> gc .sweepstr > g -> strmask )
665+ gc_sweepstr (g , & g -> str . tab [g -> gc .sweepstr ++ ]); /* Sweep one chain. */
666+ if (g -> gc .sweepstr > g -> str . mask )
641667 g -> gc .state = GCSsweep ; /* All string hash chains sweeped. */
642668 lj_assertG (old >= g -> gc .total , "sweep increased memory" );
643669 g -> gc .estimate -= old - g -> gc .total ;
@@ -649,8 +675,8 @@ static size_t gc_onestep(lua_State *L)
649675 lj_assertG (old >= g -> gc .total , "sweep increased memory" );
650676 g -> gc .estimate -= old - g -> gc .total ;
651677 if (gcref (* mref (g -> gc .sweep , GCRef )) == NULL ) {
652- if (g -> strnum <= (g -> strmask >> 2 ) && g -> strmask > LJ_MIN_STRTAB * 2 - 1 )
653- lj_str_resize (L , g -> strmask >> 1 ); /* Shrink string table. */
678+ if (g -> str . num <= (g -> str . mask >> 2 ) && g -> str . mask > LJ_MIN_STRTAB * 2 - 1 )
679+ lj_str_resize (L , g -> str . mask >> 1 ); /* Shrink string table. */
654680 if (gcref (g -> gc .mmudata )) { /* Need any finalizations? */
655681 g -> gc .state = GCSfinalize ;
656682#if LJ_HASFFI
0 commit comments