2222typedef struct ReachableContext
2323{
2424 std::queue<GCObject*> queue;
25- std::unordered_set<GCObject *> visited;
25+ std::unordered_set<void *> visited;
2626} ReachableContext;
2727
2828static void enqueueobj (ReachableContext* ctx, GCObject* obj)
@@ -372,11 +372,18 @@ static size_t calcgcosize(GCObject *obj)
372372void luaC_enumreachableuserallocs (
373373 lua_State* L,
374374 void * context,
375- void (*node)(void * context, GCObject* ptr, uint8_t tt, uint8_t memcat, size_t size)
375+ void (*node)(void * context, GCObject* ptr, uint8_t tt, uint8_t memcat, size_t size),
376+ const lua_OpaqueGCObjectSet* free_objects
376377)
377378{
378379 ReachableContext ctx;
379380
381+ // Pre-populate visited set with free objects if provided
382+ if (free_objects)
383+ {
384+ ctx.visited = *free_objects;
385+ }
386+
380387 ctx.queue .push (obj2gco (L));
381388 ctx.visited .insert (obj2gco (L));
382389
@@ -390,8 +397,30 @@ void luaC_enumreachableuserallocs(
390397 node (context, current, current->gch .tt , current->gch .memcat , calcgcosize (current));
391398
392399 // Take any new references the current node has and add them to the queue
393- // Even if we don't want to include their size in the calculation, we may still want
394- // to traverse them.
395400 traverseobj (&ctx, current);
396401 }
397402}
403+
404+ lua_OpaqueGCObjectSet luaC_collectfreeobjects (lua_State* L)
405+ {
406+ lua_OpaqueGCObjectSet free_objects;
407+ ReachableContext ctx;
408+
409+ ctx.queue .push (obj2gco (L));
410+ ctx.visited .insert (obj2gco (L));
411+
412+ while (!ctx.queue .empty ())
413+ {
414+ GCObject* current = ctx.queue .front ();
415+ ctx.queue .pop ();
416+
417+ // Collect memcat 2+ objects into the set
418+ if (current->gch .memcat >= 2 )
419+ free_objects.insert (current);
420+
421+ // Traverse child references
422+ traverseobj (&ctx, current);
423+ }
424+
425+ return free_objects;
426+ }
0 commit comments