// File: dragazo[P]cpp-gc/GarbageCollection.cpp
// Function: GC::disjoint_module::collect()
bool GC::disjoint_module::collect()
{
	// -- begin the collection action -- //

	{
		std::lock_guard<std::mutex> internal_lock(internal_mutex);

		// if there are 1 or more ignore sentries acting on this module, do nothing and return true.
		// true is to prevent a deadlock case where we do a blocking collection is made to an ignoring module.
		if (ignore_collect_count > 0) return true;

		// if there's already a collection in progress for this module, we do nothing.
		// if the collector is us, return true - this is to prevent a deadlock case where we do a blocking collection from a router/destructor.
		// otherwise return false - someone else is doing something.
		if (collector_thread != std::thread::id()) return collector_thread == std::this_thread::get_id();

		// otherwise mark the calling thread as the collector thread
		collector_thread = std::this_thread::get_id();

		// begin caching ref count deletion events
		cache_ref_count_del_actions = true;

		// since we just came out of no-collect phase, all the caches should be empty
		assert(objs_add_cache.empty());

		assert(roots_add_cache.empty());
		assert(roots_remove_cache.empty());

		assert(handle_repoint_cache.empty());

		// ref count del cache should also be empty
		assert(ref_count_del_cache.empty());

		// the del list should also be empty
		assert(del_list.empty());
	}

	// -- initialize the collection data -- //

	// we've now started the collection action, so we have lock-free access to collector-only resources.

	// to ensure all unused objects are deleted in one pass, we need to unroot all mutables arcs.
	// this requires going through all the obj list entities, so we might as well clear their marks.

	// for each object we'll examine
	for (info *i = objs.front(); i; i = i->next)
	{
		// clear the marked flag
		i->marked = false;

		// route to mutable arcs and directly unroot from the collector-only root set.
		// this is only safe because we're guaranteed to be the (only) collector at this point.
		i->mutable_route(+[](const smart_handle &arc) { local()->roots.erase(&arc.raw_handle()); });
	}

	// clear the root objs set
	root_objs.clear();

	{
		std::lock_guard<std::mutex> lock(internal_mutex);

		// at this point we've directly unrooted all the mutables in the obj list.
		// however, other threads could have destroyed rooted handles.
		// this means the roots set at this point may contain dangling pointers.
		// thus, we need to apply the cached root/unroot actions.
		// this will ensure there are no dangling pointers that are represented.
		
		// the reason we can't just do the cached unroot actions is because it could exclude live objects.
		// for instance, suppose we have a pre-existing dynamic rooted handle A.
		// now, say a new dynamic rooted handle B is created and initialized to A, then A is destroyed.
		// thus, A was unrooted, but the object it refered to is still reachable through B.
		// this could happen e.g. on a std::vector<GC::ptr<T>> reallocation.
		// this of course could only happen for live objects, so we want to make sure we keep them that way.
		// thus we account for both root and unroot cached actions.

		// for much the same reasons, we need to apply the handle repoint cache.
		// and, because we now have roots that may point to objects in the obj add cache, we need to add those as well.
		// however, we need to clear their marks first.
		// we can't perform the routing step for them because we need the mutex to be locked during this process.
		// but that's not a problem as collect() only guarantees it will collect all objects unreachable prior to invocation.
		// the routing logic is just to ensure this happens in 1 pass and not 2 (uncommon but otherwise possible without this step).

		// so long story short we need to apply all the caches (aside from obj deletion), plus a tiny bit of extra logic.
		// we know this is safe because it's as if we took the graph snapshot later on and just routed to a subset of it for unrooting.

		// apply the obj add cache - also clear their marks (the ones in the obj list are already cleared)
		for (info *i : objs_add_cache)
		{
			i->marked = false;
			objs.add(i);
		}
		objs_add_cache.clear();

		// apply cached root actions
		for (auto i : roots_add_cache) roots.insert(i);
		roots_add_cache.clear();

		// apply cached unroot actions
		for (auto i : roots_remove_cache) roots.erase(i);
		roots_remove_cache.clear();

		// apply handle repoint actions
		for (auto i : handle_repoint_cache) *i.first = i.second;
		handle_repoint_cache.clear();

		// now that that's all done...

		// add the pointed-at objects of all remaining (valid) roots to a set of root objects.
		// we only include the non-null targets for convenience.
		for (auto root : roots)
			if (*root) root_objs.insert(*root);
	}

	// -----------------------------------------------------------

	#if DRAGAZO_GARBAGE_COLLECT_MSG
	std::size_t collect_count = 0; // number of objects that we scheduled for deletion
	#endif

	// -- mark and sweep -- //

	// perform a mark sweep from each root object
	for (info *i : root_objs) i->mark_sweep();

	// -- clean anything not marked -- //

	// for each item in the gc database
	for (info *i = objs.front(), *next; i; i = next)
	{
		next = i->next;

		// if it hasn't been marked, mark it for deletion
		if (!i->marked)
		{
			// mark it for deletion
			objs.remove(i);
			del_list.add(i);

			#if DRAGAZO_GARBAGE_COLLECT_MSG
			++collect_count;
			#endif
		}
	}

	#if DRAGAZO_GARBAGE_COLLECT_MSG
	std::cerr << "collecting - deleting: " << collect_count << '\n';
	#endif

	// -----------------------------------------------------------

	// we've now divided the old obj list into two partitions:
	// the reachable objects are still in the obj list.
	// the unreachable objects are now in the del list.
	// ref count deletion caching is still in effect.

	// destroy unreachable objects
	for (info *i = del_list.front(); i; i = i->next) i->destroy();

	// now we've destroyed the unreachable objects but there may be cached deletions from ref count logic.
	// we'll now resume immediate ref count deletions.
	// we can't resume immediate ref count deletions prior to destroying the unreachable objs because it could double delete.
	// e.g. could drop an unreachable obj ref count to 0 and insta-delete on its own before we get to it.
	// even if we made a check for double delete, it would still deallocate the info object as well and would cause even more headache.
	// we know this usage is safe because there's no way a reachable object could ref count delete an unreachable object.
		
	// resume immediate ref count deletions.
	{
		std::lock_guard<std::mutex> internal_lock(internal_mutex);

		// stop caching ref count deletion actions (i.e. resume immediate ref count deletions)
		cache_ref_count_del_actions = false;

		// if an unreachable object is in the ref count del cache purge it (to avoid the double delete issue for unreachable objs).
		// we know this'll work because the unreachable objects are unreachable from reachable objects (hence the name).
		// thus, since we already called unreachable destructors, there will be no further ref count logic for unreachables.

		// purge unreachable objects from the ref count del cache (to avoid double deletions - see above).
		for (info *i = del_list.front(); i; i = i->next) ref_count_del_cache.erase(i);

		// after the double-deletion purge, remove remaining ref count del cache objects from the obj list.
		// we do this now because enabling immediate ref count del logic means the obj list can be modified by any holder of the mutex.
		for (auto i : ref_count_del_cache) objs.remove(i);
	}

	// we now have lock-free exclusive ownership of the ref count del cache.

	// deallocate memory
	// done after calling ALL unreachable dtors so that the dtors can access the info objects safely.
	// this is because we might be deleting objects whose reference count is not zero.
	// which means they could potentially hold live gc references to other objects in del list and try to refer to their info objects.
	for (info *i = del_list.front(), *next; i; i = next)
	{
		next = i->next; // dealloc() will deallocate the info object as well, so grab the next object now
		i->dealloc();
	}

	// clear the del list (we already deallocated the resources above)
	del_list.unsafe_clear();
	assert(del_list.empty()); // just to make sure

	// remember, we still have lock-free exclusive ownership of the ref count del cache from above.
	// process the cached ref count deletions.
	for (auto i : ref_count_del_cache)
	{
		// we don't need to do all destructors before all deallocators like we did above.
		// this is because we know the ref count for these is zero (because they were cached ref count deletion).
		// this means we don't have the same risks as above (i.e. live references being forcibly severed).

		i->destroy();
		i->dealloc();
	}
	ref_count_del_cache.clear();

	// end the collection action
	// must be after dtors/deallocs to ensure that if they call collect() it'll no-op (otherwise very slow).
	// additionally, must be after those to ensure the caches are fully emptied as the last atomic step.
	// also, if this came before dtors, the reference count system could fall to 0 and result in double dtor.
	{
		std::lock_guard<std::mutex> internal_lock(internal_mutex);

		// mark that there is no longer a collector thread
		collector_thread = std::thread::id();

		// apply all the cached obj add actions that occurred during the collection action
		for (auto i : objs_add_cache) objs.add(i);
		objs_add_cache.clear();

		// apply cached root actions
		for (auto i : roots_add_cache) roots.insert(i);
		roots_add_cache.clear();

		// apply cached unroot actions
		for (auto i : roots_remove_cache) roots.erase(i);
		roots_remove_cache.clear();

		// apply all the cached handle repoint actions
		for (auto i : handle_repoint_cache) *i.first = i.second;
		handle_repoint_cache.clear();
	}

	// return that we did the collection
	return true;
}

// Assembly:
subq $0x2c8, %rsp            # imm = 0x2C8
movq %rdi, 0x2b8(%rsp)
movq 0x2b8(%rsp), %rsi
movq %rsi, 0x40(%rsp)
leaq 0x2b0(%rsp), %rdi
callq 0x95b0
movq 0x40(%rsp), %rax
cmpq $0x0, 0x30(%rax)
jbe 0x5e9d
movb $0x1, 0x2c7(%rsp)
movl $0x1, 0x2ac(%rsp)
jmp 0x609d
movq 0x40(%rsp), %rax
movq 0x28(%rax), %rax
movq %rax, 0x2a0(%rsp)
leaq 0x298(%rsp), %rdi
callq 0x9620
movq 0x2a0(%rsp), %rdi
movq 0x298(%rsp), %rsi
callq 0x95e0
testb $0x1, %al
jne 0x5ed6
jmp 0x5f22
movq 0x40(%rsp), %rax
movq 0x28(%rax), %rax
movq %rax, 0x290(%rsp)
callq 0x9660
movq %rax, 0x288(%rsp)
movq 0x290(%rsp), %rdi
movq 0x288(%rsp), %rsi
callq 0x9640
andb $0x1, %al
movb %al, 0x2c7(%rsp)
movl $0x1, 0x2ac(%rsp)
jmp 0x609d
callq 0x9660
movq 0x40(%rsp), %rdi
movq %rax, 0x280(%rsp)
movq 0x280(%rsp), %rax
movq %rax, 0x28(%rdi)
movb $0x1, 0xc8(%rdi)
addq $0x108, %rdi            # imm = 0x108
callq 0x9690
testb $0x1, %al
jne 0x5f59
jmp 0x5f5b
jmp 0x5f7a
leaq 0x5e1e4(%rip), %rdi     # 0x64146
leaq 0x5e1f4(%rip), %rsi     # 0x6415d
movl $0xd9, %edx
leaq 0x5e1fe(%rip), %rcx     # 0x64173
callq 0x51e0
movq 0x40(%rsp), %rdi
addq $0x140, %rdi            # imm = 0x140
callq 0x94b0
testb $0x1, %al
jne 0x5f91
jmp 0x5f93
jmp 0x5fb2
leaq 0x5e1fd(%rip), %rdi     # 0x64197
leaq 0x5e1bc(%rip), %rsi     # 0x6415d
movl $0xdb, %edx
leaq 0x5e1c6(%rip), %rcx     # 0x64173
callq 0x51e0
movq 0x40(%rsp), %rdi
addq $0x178, %rdi            # imm = 0x178
callq 0x94b0
testb $0x1, %al
jne 0x5fc9
jmp 0x5fcb
jmp 0x5fea
leaq 0x5e1dd(%rip), %rdi     # 0x641af
leaq 0x5e184(%rip), %rsi     # 0x6415d
movl $0xdc, %edx
leaq 0x5e18e(%rip), %rcx     # 0x64173
callq 0x51e0
movq 0x40(%rsp), %rdi
addq $0x1b0, %rdi            # imm = 0x1B0
callq 0x96b0
testb $0x1, %al
jne 0x6001
jmp 0x6003
jmp 0x6022
leaq 0x5e1c0(%rip), %rdi     # 0x641ca
leaq 0x5e14c(%rip), %rsi     # 0x6415d
movl $0xde, %edx
leaq 0x5e156(%rip), %rcx     # 0x64173
callq 0x51e0
movq 0x40(%rsp), %rdi
addq $0xd0, %rdi
callq 0x9690
testb $0x1, %al
jne 0x6039
jmp 0x603b
jmp 0x605a
leaq 0x5e1a5(%rip), %rdi     # 0x641e7
leaq 0x5e114(%rip), %rsi     # 0x6415d
movl $0xe1, %edx
leaq 0x5e11e(%rip), %rcx     # 0x64173
callq 0x51e0
movq 0x40(%rsp), %rdi
addq $0xb8, %rdi
callq 0x9460
testb $0x1, %al
jne 0x6071
jmp 0x6073
jmp 0x6092
leaq 0x5e189(%rip), %rdi     # 0x64203
leaq 0x5e0dc(%rip), %rsi     # 0x6415d
movl $0xe4, %edx
leaq 0x5e0e6(%rip), %rcx     # 0x64173
callq 0x51e0
movl $0x0, 0x2ac(%rsp)
leaq 0x2b0(%rsp), %rdi
callq 0x96d0
movl 0x2ac(%rsp), %eax
testl %eax, %eax
je 0x60bc
jmp 0x60b7
jmp 0x6c16
movq 0x40(%rsp), %rdi
addq $0x38, %rdi
callq 0x9490
movq %rax, 0x278(%rsp)
cmpq $0x0, 0x278(%rsp)
je 0x613b
movq 0x278(%rsp), %rax
movb $0x0, 0x28(%rax)
movq 0x278(%rsp), %rax
movq %rax, 0x38(%rsp)
leaq 0x26f(%rsp), %rdi
callq 0x6c40
movq %rax, %rsi
leaq 0x270(%rsp), %rdi
callq 0x9720
movq 0x38(%rsp), %rdi
movq 0x270(%rsp), %rsi
callq 0x96f0
movq 0x278(%rsp), %rax
movq 0x38(%rax), %rax
movq %rax, 0x278(%rsp)
jmp 0x60d2
movq 0x40(%rsp), %rdi
addq $0x80, %rdi
callq 0x9750
movq 0x40(%rsp), %rsi
leaq 0x260(%rsp), %rdi
callq 0x95b0
movq 0x40(%rsp), %rax
addq $0x108, %rax            # imm = 0x108
movq %rax, 0x258(%rsp)
movq 0x258(%rsp), %rdi
callq 0x9760
movq %rax, 0x250(%rsp)
movq 0x258(%rsp), %rdi
callq 0x9790
movq %rax, 0x248(%rsp)
leaq 0x250(%rsp), %rdi
leaq 0x248(%rsp), %rsi
callq 0x97c0
testb $0x1, %al
jne 0x61b6
jmp 0x61ff
leaq 0x250(%rsp), %rdi
callq 0x97e0
movq 0x40(%rsp), %rdi
movq (%rax), %rax
movq %rax, 0x240(%rsp)
movq 0x240(%rsp), %rax
movb $0x0, 0x28(%rax)
addq $0x38, %rdi
movq 0x240(%rsp), %rsi
callq 0x5990
leaq 0x250(%rsp), %rdi
callq 0x9800
jmp 0x619b
movq 0x40(%rsp), %rdi
addq $0x108, %rdi            # imm = 0x108
callq 0x9750
movq 0x40(%rsp), %rax
addq $0x140, %rax            # imm = 0x140
movq %rax, 0x238(%rsp)
movq 0x238(%rsp), %rdi
callq 0x94d0
movq %rax, 0x230(%rsp)
movq 0x238(%rsp), %rdi
callq 0x9830
movq %rax, 0x228(%rsp)
leaq 0x230(%rsp), %rdi
leaq 0x228(%rsp), %rsi
callq 0x9860
testb $0x1, %al
jne 0x626b
jmp 0x62f1
leaq 0x230(%rsp), %rdi
callq 0x9500
movq 0x40(%rsp), %rdi
movq (%rax), %rax
movq %rax, 0x220(%rsp)
addq $0x48, %rdi
leaq 0x220(%rsp), %rsi
callq 0x9880
movb %dl, 0x2f(%rsp)
movq %rax, 0x30(%rsp)
jmp 0x62a4
movb 0x2f(%rsp), %al
movq 0x30(%rsp), %rcx
movq %rcx, 0x200(%rsp)
movb %al, 0x208(%rsp)
leaq 0x230(%rsp), %rdi
callq 0x98d0
jmp 0x624d
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x218(%rsp)
movl %eax, 0x214(%rsp)
leaq 0x260(%rsp), %rdi
callq 0x96d0
jmp 0x6c27
movq 0x40(%rsp), %rdi
addq $0x140, %rdi            # imm = 0x140
callq 0x9900
movq 0x40(%rsp), %rax
addq $0x178, %rax            # imm = 0x178
movq %rax, 0x1f8(%rsp)
movq 0x1f8(%rsp), %rdi
callq 0x94d0
movq %rax, 0x1f0(%rsp)
movq 0x1f8(%rsp), %rdi
callq 0x9830
movq %rax, 0x1e8(%rsp)
leaq 0x1f0(%rsp), %rdi
leaq 0x1e8(%rsp), %rsi
callq 0x9860
testb $0x1, %al
jne 0x635a
jmp 0x639b
leaq 0x1f0(%rsp), %rdi
callq 0x9500
movq 0x40(%rsp), %rdi
movq (%rax), %rax
movq %rax, 0x1e0(%rsp)
addq $0x48, %rdi
leaq 0x1e0(%rsp), %rsi
callq 0x9910
jmp 0x638a
jmp 0x638c
leaq 0x1f0(%rsp), %rdi
callq 0x98d0
jmp 0x633f
movq 0x40(%rsp), %rdi
addq $0x178, %rdi            # imm = 0x178
callq 0x9900
movq 0x40(%rsp), %rax
addq $0x1b0, %rax            # imm = 0x1B0
movq %rax, 0x1d8(%rsp)
movq 0x1d8(%rsp), %rdi
callq 0x9940
movq %rax, 0x1d0(%rsp)
movq 0x1d8(%rsp), %rdi
callq 0x9970
movq %rax, 0x1c8(%rsp)
leaq 0x1d0(%rsp), %rdi
leaq 0x1c8(%rsp), %rsi
callq 0x99a0
testb $0x1, %al
jne 0x6404
jmp 0x644a
leaq 0x1d0(%rsp), %rdi
callq 0x99c0
movq (%rax), %rcx
movq %rcx, 0x1b8(%rsp)
movq 0x8(%rax), %rax
movq %rax, 0x1c0(%rsp)
movq 0x1c0(%rsp), %rcx
movq 0x1b8(%rsp), %rax
movq %rcx, (%rax)
leaq 0x1d0(%rsp), %rdi
callq 0x99e0
jmp 0x63e9
movq 0x40(%rsp), %rdi
addq $0x1b0, %rdi            # imm = 0x1B0
callq 0x9a10
movq 0x40(%rsp), %rax
addq $0x48, %rax
movq %rax, 0x1b0(%rsp)
movq 0x1b0(%rsp), %rdi
callq 0x94d0
movq %rax, 0x1a8(%rsp)
movq 0x1b0(%rsp), %rdi
callq 0x9830
movq %rax, 0x1a0(%rsp)
leaq 0x1a8(%rsp), %rdi
leaq 0x1a0(%rsp), %rsi
callq 0x9860
testb $0x1, %al
jne 0x64b1
jmp 0x6524
leaq 0x1a8(%rsp), %rdi
callq 0x9500
movq (%rax), %rax
movq %rax, 0x198(%rsp)
movq 0x198(%rsp), %rax
cmpq $0x0, (%rax)
je 0x6510
movq 0x40(%rsp), %rdi
subq $-0x80, %rdi
movq 0x198(%rsp), %rsi
callq 0x9a20
movb %dl, 0x1f(%rsp)
movq %rax, 0x20(%rsp)
jmp 0x64f8
movb 0x1f(%rsp), %al
movq 0x20(%rsp), %rcx
movq %rcx, 0x188(%rsp)
movb %al, 0x190(%rsp)
jmp 0x6512
leaq 0x1a8(%rsp), %rdi
callq 0x98d0
jmp 0x6496
leaq 0x260(%rsp), %rdi
callq 0x96d0
movq 0x40(%rsp), %rax
addq $0x80, %rax
movq %rax, 0x180(%rsp)
movq 0x180(%rsp), %rdi
callq 0x9760
movq %rax, 0x178(%rsp)
movq 0x180(%rsp), %rdi
callq 0x9790
movq %rax, 0x170(%rsp)
leaq 0x178(%rsp), %rdi
leaq 0x170(%rsp), %rsi
callq 0x97c0
testb $0x1, %al
jne 0x6589
jmp 0x65bd
leaq 0x178(%rsp), %rdi
callq 0x97e0
movq (%rax), %rax
movq %rax, 0x168(%rsp)
movq 0x168(%rsp), %rdi
callq 0x5df0
leaq 0x178(%rsp), %rdi
callq 0x9800
jmp 0x656e
movq 0x40(%rsp), %rdi
addq $0x38, %rdi
callq 0x9490
movq %rax, 0x160(%rsp)
cmpq $0x0, 0x160(%rsp)
je 0x6643
movq 0x160(%rsp), %rax
movq 0x38(%rax), %rax
movq %rax, 0x158(%rsp)
movq 0x160(%rsp), %rax
testb $0x1, 0x28(%rax)
jne 0x662f
movq 0x40(%rsp), %rdi
addq $0x38, %rdi
movq 0x160(%rsp), %rsi
callq 0x59f0
movq 0x40(%rsp), %rdi
addq $0xb8, %rdi
movq 0x160(%rsp), %rsi
callq 0x5990
jmp 0x6631
movq 0x158(%rsp), %rax
movq %rax, 0x160(%rsp)
jmp 0x65d3
movq 0x40(%rsp), %rdi
addq $0xb8, %rdi
callq 0x9490
movq %rax, 0x150(%rsp)
cmpq $0x0, 0x150(%rsp)
je 0x668a
movq 0x150(%rsp), %rdi
callq 0x9a70
movq 0x150(%rsp), %rax
movq 0x38(%rax), %rax
movq %rax, 0x150(%rsp)
jmp 0x665c
movq 0x40(%rsp), %rsi
leaq 0x148(%rsp), %rdi
callq 0x95b0
movq 0x40(%rsp), %rdi
movb $0x0, 0xc8(%rdi)
addq $0xb8, %rdi
callq 0x9490
movq %rax, 0x10(%rsp)
jmp 0x66bb
movq 0x10(%rsp), %rax
movq %rax, 0x140(%rsp)
cmpq $0x0, 0x140(%rsp)
je 0x672c
movq 0x40(%rsp), %rdi
addq $0xd0, %rdi
leaq 0x140(%rsp), %rsi
callq 0x9a90
jmp 0x66ee
jmp 0x66f0
movq 0x140(%rsp), %rax
movq 0x38(%rax), %rax
movq %rax, 0x140(%rsp)
jmp 0x66c8
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x218(%rsp)
movl %eax, 0x214(%rsp)
leaq 0x148(%rsp), %rdi
callq 0x96d0
jmp 0x6c27
movq 0x40(%rsp), %rax
addq $0xd0, %rax
movq %rax, 0x138(%rsp)
movq 0x138(%rsp), %rdi
callq 0x9760
movq %rax, 0x130(%rsp)
movq 0x138(%rsp), %rdi
callq 0x9790
movq %rax, 0x128(%rsp)
leaq 0x130(%rsp), %rdi
leaq 0x128(%rsp), %rsi
callq 0x97c0
testb $0x1, %al
jne 0x6784
jmp 0x67c1
leaq 0x130(%rsp), %rdi
callq 0x97e0
movq 0x40(%rsp), %rdi
movq (%rax), %rax
movq %rax, 0x120(%rsp)
addq $0x38, %rdi
movq 0x120(%rsp), %rsi
callq 0x59f0
leaq 0x130(%rsp), %rdi
callq 0x9800
jmp 0x6769
leaq 0x148(%rsp), %rdi
callq 0x96d0
movq 0x40(%rsp), %rdi
addq $0xb8, %rdi
callq 0x9490
movq %rax, 0x118(%rsp)
cmpq $0x0, 0x118(%rsp)
je 0x6825
movq 0x118(%rsp), %rax
movq 0x38(%rax), %rax
movq %rax, 0x110(%rsp)
movq 0x118(%rsp), %rdi
callq 0x9ac0
movq 0x110(%rsp), %rax
movq %rax, 0x118(%rsp)
jmp 0x67e7
movq 0x40(%rsp), %rdi
addq $0xb8, %rdi
callq 0x9ae0
movq 0x40(%rsp), %rdi
addq $0xb8, %rdi
callq 0x9460
testb $0x1, %al
jne 0x684d
jmp 0x684f
jmp 0x686e
leaq 0x5d9ad(%rip), %rdi     # 0x64203
leaq 0x5d900(%rip), %rsi     # 0x6415d
movl $0x188, %edx            # imm = 0x188
leaq 0x5d90a(%rip), %rcx     # 0x64173
callq 0x51e0
movq 0x40(%rsp), %rax
addq $0xd0, %rax
movq %rax, 0x108(%rsp)
movq 0x108(%rsp), %rdi
callq 0x9760
movq %rax, 0x100(%rsp)
movq 0x108(%rsp), %rdi
callq 0x9790
movq %rax, 0xf8(%rsp)
leaq 0x100(%rsp), %rdi
leaq 0xf8(%rsp), %rsi
callq 0x97c0
testb $0x1, %al
jne 0x68c6
jmp 0x6907
leaq 0x100(%rsp), %rdi
callq 0x97e0
movq (%rax), %rax
movq %rax, 0xf0(%rsp)
movq 0xf0(%rsp), %rdi
callq 0x9a70
movq 0xf0(%rsp), %rdi
callq 0x9ac0
leaq 0x100(%rsp), %rdi
callq 0x9800
jmp 0x68ab
movq 0x40(%rsp), %rdi
addq $0xd0, %rdi
callq 0x9750
movq 0x40(%rsp), %rsi
leaq 0xe8(%rsp), %rdi
callq 0x95b0
leaq 0xe0(%rsp), %rdi
callq 0x9620
movq 0x40(%rsp), %rax
movq 0xe0(%rsp), %rcx
movq %rcx, 0x28(%rax)
addq $0x108, %rax            # imm = 0x108
movq %rax, 0xd8(%rsp)
movq 0xd8(%rsp), %rdi
callq 0x9760
movq %rax, 0xd0(%rsp)
movq 0xd8(%rsp), %rdi
callq 0x9790
movq %rax, 0xc8(%rsp)
leaq 0xd0(%rsp), %rdi
leaq 0xc8(%rsp), %rsi
callq 0x97c0
testb $0x1, %al
jne 0x699b
jmp 0x69d8
leaq 0xd0(%rsp), %rdi
callq 0x97e0
movq 0x40(%rsp), %rdi
movq (%rax), %rax
movq %rax, 0xc0(%rsp)
addq $0x38, %rdi
movq 0xc0(%rsp), %rsi
callq 0x5990
leaq 0xd0(%rsp), %rdi
callq 0x9800
jmp 0x6980
movq 0x40(%rsp), %rdi
addq $0x108, %rdi            # imm = 0x108
callq 0x9750
movq 0x40(%rsp), %rax
addq $0x140, %rax            # imm = 0x140
movq %rax, 0xb8(%rsp)
movq 0xb8(%rsp), %rdi
callq 0x94d0
movq %rax, 0xb0(%rsp)
movq 0xb8(%rsp), %rdi
callq 0x9830
movq %rax, 0xa8(%rsp)
leaq 0xb0(%rsp), %rdi
leaq 0xa8(%rsp), %rsi
callq 0x9860
testb $0x1, %al
jne 0x6a44
jmp 0x6aca
leaq 0xb0(%rsp), %rdi
callq 0x9500
movq 0x40(%rsp), %rdi
movq (%rax), %rax
movq %rax, 0xa0(%rsp)
addq $0x48, %rdi
leaq 0xa0(%rsp), %rsi
callq 0x9880
movb %dl, 0x7(%rsp)
movq %rax, 0x8(%rsp)
jmp 0x6a7d
movb 0x7(%rsp), %al
movq 0x8(%rsp), %rcx
movq %rcx, 0x90(%rsp)
movb %al, 0x98(%rsp)
leaq 0xb0(%rsp), %rdi
callq 0x98d0
jmp 0x6a26
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x218(%rsp)
movl %eax, 0x214(%rsp)
leaq 0xe8(%rsp), %rdi
callq 0x96d0
jmp 0x6c27
movq 0x40(%rsp), %rdi
addq $0x140, %rdi            # imm = 0x140
callq 0x9900
movq 0x40(%rsp), %rax
addq $0x178, %rax            # imm = 0x178
movq %rax, 0x88(%rsp)
movq 0x88(%rsp), %rdi
callq 0x94d0
movq %rax, 0x80(%rsp)
movq 0x88(%rsp), %rdi
callq 0x9830
movq %rax, 0x78(%rsp)
leaq 0x80(%rsp), %rdi
leaq 0x78(%rsp), %rsi
callq 0x9860
testb $0x1, %al
jne 0x6b2d
jmp 0x6b68
leaq 0x80(%rsp), %rdi
callq 0x9500
movq 0x40(%rsp), %rdi
movq (%rax), %rax
movq %rax, 0x70(%rsp)
addq $0x48, %rdi
leaq 0x70(%rsp), %rsi
callq 0x9910
jmp 0x6b57
jmp 0x6b59
leaq 0x80(%rsp), %rdi
callq 0x98d0
jmp 0x6b15
movq 0x40(%rsp), %rdi
addq $0x178, %rdi            # imm = 0x178
callq 0x9900
movq 0x40(%rsp), %rax
addq $0x1b0, %rax            # imm = 0x1B0
movq %rax, 0x68(%rsp)
movq 0x68(%rsp), %rdi
callq 0x9940
movq %rax, 0x60(%rsp)
movq 0x68(%rsp), %rdi
callq 0x9970
movq %rax, 0x58(%rsp)
leaq 0x60(%rsp), %rdi
leaq 0x58(%rsp), %rsi
callq 0x99a0
testb $0x1, %al
jne 0x6bbc
jmp 0x6bf0
leaq 0x60(%rsp), %rdi
callq 0x99c0
movq (%rax), %rcx
movq %rcx, 0x48(%rsp)
movq 0x8(%rax), %rax
movq %rax, 0x50(%rsp)
movq 0x50(%rsp), %rcx
movq 0x48(%rsp), %rax
movq %rcx, (%rax)
leaq 0x60(%rsp), %rdi
callq 0x99e0
jmp 0x6ba7
movq 0x40(%rsp), %rdi
addq $0x1b0, %rdi            # imm = 0x1B0
callq 0x9a10
leaq 0xe8(%rsp), %rdi
callq 0x96d0
movb $0x1, 0x2c7(%rsp)
movb 0x2c7(%rsp), %al
andb $0x1, %al
addq $0x2c8, %rsp            # imm = 0x2C8
retq
movq 0x218(%rsp), %rdi
callq 0x5510
nopw %cs:(%rax,%rax)