123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342 |
- #include "il2cpp-config.h"
- #include "gc/GCHandle.h"
- #include "il2cpp-object-internals.h"
- #include "GarbageCollector.h"
- #include "os/Mutex.h"
- #include "utils/Memory.h"
- #include <memory>
- namespace il2cpp
- {
- namespace gc
- {
- typedef struct
- {
- uint32_t *bitmap;
- void* *entries;
- uint32_t size;
- uint8_t type;
- uint32_t slot_hint : 24;/* starting slot for search */
- /* 2^16 appdomains should be enough for everyone (though I know I'll regret this in 20 years) */
- /* we alloc this only for weak refs, since we can get the domain directly in the other cases */
- uint16_t *domain_ids;
- } HandleData;
- /* weak and weak-track arrays will be allocated in malloc memory
- */
- static HandleData gc_handles[] =
- {
- {NULL, NULL, 0, HANDLE_WEAK, 0},
- {NULL, NULL, 0, HANDLE_WEAK_TRACK, 0},
- {NULL, NULL, 0, HANDLE_NORMAL, 0},
- {NULL, NULL, 0, HANDLE_PINNED, 0}
- };
- static int
- find_first_unset(uint32_t bitmap)
- {
- int i;
- for (i = 0; i < 32; ++i)
- {
- if (!(bitmap & (1 << i)))
- return i;
- }
- return -1;
- }
- static baselib::ReentrantLock g_HandlesMutex;
- #define lock_handles(handles) g_HandlesMutex.Acquire ()
- #define unlock_handles(handles) g_HandlesMutex.Release ()
- static uint32_t
- alloc_handle(HandleData *handles, Il2CppObject *obj, bool track)
- {
- uint32_t slot;
- int i;
- lock_handles(handles);
- if (!handles->size)
- {
- handles->size = 32;
- if (handles->type > HANDLE_WEAK_TRACK)
- {
- handles->entries = (void**)GarbageCollector::AllocateFixed(sizeof(void*) * handles->size, NULL);
- }
- else
- {
- handles->entries = (void**)IL2CPP_MALLOC_ZERO(sizeof(void*) * handles->size);
- handles->domain_ids = (uint16_t*)IL2CPP_MALLOC_ZERO(sizeof(uint16_t) * handles->size);
- }
- handles->bitmap = (uint32_t*)IL2CPP_MALLOC_ZERO(handles->size / 8);
- }
- i = -1;
- for (slot = handles->slot_hint; slot < handles->size / 32; ++slot)
- {
- if (handles->bitmap[slot] != 0xffffffff)
- {
- i = find_first_unset(handles->bitmap[slot]);
- handles->slot_hint = slot;
- break;
- }
- }
- if (i == -1 && handles->slot_hint != 0)
- {
- for (slot = 0; slot < handles->slot_hint; ++slot)
- {
- if (handles->bitmap[slot] != 0xffffffff)
- {
- i = find_first_unset(handles->bitmap[slot]);
- handles->slot_hint = slot;
- break;
- }
- }
- }
- if (i == -1)
- {
- uint32_t *new_bitmap;
- uint32_t new_size = handles->size * 2; /* always double: we memset to 0 based on this below */
- /* resize and copy the bitmap */
- new_bitmap = (uint32_t*)IL2CPP_MALLOC_ZERO(new_size / 8);
- memcpy(new_bitmap, handles->bitmap, handles->size / 8);
- IL2CPP_FREE(handles->bitmap);
- handles->bitmap = new_bitmap;
- /* resize and copy the entries */
- if (handles->type > HANDLE_WEAK_TRACK)
- {
- void* *entries;
- entries = (void**)GarbageCollector::AllocateFixed(sizeof(void*) * new_size, NULL);
- memcpy(entries, handles->entries, sizeof(void*) * handles->size);
- GarbageCollector::SetWriteBarrier(entries, sizeof(void*) * handles->size);
- void** previous_entries = handles->entries;
- handles->entries = entries;
- GarbageCollector::FreeFixed(previous_entries);
- }
- else
- {
- void* *entries;
- uint16_t *domain_ids;
- domain_ids = (uint16_t*)IL2CPP_MALLOC_ZERO(sizeof(uint16_t) * new_size);
- entries = (void**)IL2CPP_MALLOC(sizeof(void*) * new_size);
- /* we disable GC because we could lose some disappearing link updates */
- GarbageCollector::Disable();
- memcpy(entries, handles->entries, sizeof(void*) * handles->size);
- memset(entries + handles->size, 0, sizeof(void*) * handles->size);
- memcpy(domain_ids, handles->domain_ids, sizeof(uint16_t) * handles->size);
- for (i = 0; i < (int32_t)handles->size; ++i)
- {
- Il2CppObject *obj = GarbageCollector::GetWeakLink(&(handles->entries[i]));
- if (handles->entries[i])
- GarbageCollector::RemoveWeakLink(&(handles->entries[i]));
- /*g_print ("reg/unreg entry %d of type %d at %p to object %p (%p), was: %p\n", i, handles->type, &(entries [i]), obj, entries [i], handles->entries [i]);*/
- if (obj)
- {
- GarbageCollector::AddWeakLink(&(entries[i]), obj, track);
- }
- }
- IL2CPP_FREE(handles->entries);
- IL2CPP_FREE(handles->domain_ids);
- handles->entries = entries;
- handles->domain_ids = domain_ids;
- GarbageCollector::Enable();
- }
- /* set i and slot to the next free position */
- i = 0;
- slot = (handles->size + 1) / 32;
- handles->slot_hint = handles->size + 1;
- handles->size = new_size;
- }
- handles->bitmap[slot] |= 1 << i;
- slot = slot * 32 + i;
- handles->entries[slot] = obj;
- GarbageCollector::SetWriteBarrier(handles->entries + slot);
- if (handles->type <= HANDLE_WEAK_TRACK)
- {
- if (obj)
- GarbageCollector::AddWeakLink(&(handles->entries[slot]), obj, track);
- }
- //mono_perfcounters->gc_num_handles++;
- unlock_handles(handles);
- /*g_print ("allocated entry %d of type %d to object %p (in slot: %p)\n", slot, handles->type, obj, handles->entries [slot]);*/
- return (slot << 3) | (handles->type + 1);
- }
- uint32_t GCHandle::New(Il2CppObject *obj, bool pinned)
- {
- return alloc_handle(&gc_handles[pinned ? HANDLE_PINNED : HANDLE_NORMAL], obj, false);
- }
- utils::Expected<uint32_t> GCHandle::NewWeakref(Il2CppObject *obj, bool track_resurrection)
- {
- uint32_t handle = alloc_handle(&gc_handles[track_resurrection ? HANDLE_WEAK_TRACK : HANDLE_WEAK], obj, track_resurrection);
- #ifndef HAVE_SGEN_GC
- if (track_resurrection)
- return utils::Il2CppError(utils::NotSupported, "IL2CPP does not support resurrection for weak references. Pass the trackResurrection with a value of false.");
- #endif
- return handle;
- }
- GCHandleType GCHandle::GetHandleType(uint32_t gchandle)
- {
- return static_cast<GCHandleType>((gchandle & 7) - 1);
- }
- static inline uint32_t GetHandleSlot(uint32_t gchandle)
- {
- return gchandle >> 3;
- }
- Il2CppObject* GCHandle::GetTarget(uint32_t gchandle)
- {
- uint32_t slot = GetHandleSlot(gchandle);
- uint32_t type = GetHandleType(gchandle);
- HandleData *handles = &gc_handles[type];
- Il2CppObject *obj = NULL;
- if (type > 3)
- return NULL;
- lock_handles(handles);
- if (slot < handles->size && (handles->bitmap[slot / 32] & (1 << (slot % 32))))
- {
- if (handles->type <= HANDLE_WEAK_TRACK)
- {
- obj = GarbageCollector::GetWeakLink(&handles->entries[slot]);
- }
- else
- {
- obj = (Il2CppObject*)handles->entries[slot];
- }
- }
- else
- {
- /* print a warning? */
- }
- unlock_handles(handles);
- /*g_print ("get target of entry %d of type %d: %p\n", slot, handles->type, obj);*/
- return obj;
- }
- static void
- il2cpp_gchandle_set_target(uint32_t gchandle, Il2CppObject *obj)
- {
- uint32_t slot = GetHandleSlot(gchandle);
- uint32_t type = GCHandle::GetHandleType(gchandle);
- HandleData *handles = &gc_handles[type];
- Il2CppObject *old_obj = NULL;
- if (type > 3)
- return;
- lock_handles(handles);
- if (slot < handles->size && (handles->bitmap[slot / 32] & (1 << (slot % 32))))
- {
- if (handles->type <= HANDLE_WEAK_TRACK)
- {
- old_obj = (Il2CppObject*)handles->entries[slot];
- if (handles->entries[slot])
- GarbageCollector::RemoveWeakLink(&handles->entries[slot]);
- if (obj)
- GarbageCollector::AddWeakLink(&handles->entries[slot], obj, handles->type == HANDLE_WEAK_TRACK);
- }
- else
- {
- handles->entries[slot] = obj;
- }
- }
- else
- {
- /* print a warning? */
- }
- unlock_handles(handles);
- #ifndef HAVE_SGEN_GC
- if (type == HANDLE_WEAK_TRACK)
- IL2CPP_NOT_IMPLEMENTED(il2cpp_gchandle_set_target);
- #endif
- }
- void GCHandle::Free(uint32_t gchandle)
- {
- uint32_t slot = GetHandleSlot(gchandle);
- uint32_t type = GetHandleType(gchandle);
- HandleData *handles = &gc_handles[type];
- if (type > 3)
- return;
- #ifndef HAVE_SGEN_GC
- if (type == HANDLE_WEAK_TRACK)
- IL2CPP_NOT_IMPLEMENTED(GCHandle::Free);
- #endif
- lock_handles(handles);
- if (slot < handles->size && (handles->bitmap[slot / 32] & (1 << (slot % 32))))
- {
- if (handles->type <= HANDLE_WEAK_TRACK)
- {
- if (handles->entries[slot])
- GarbageCollector::RemoveWeakLink(&handles->entries[slot]);
- }
- else
- {
- handles->entries[slot] = NULL;
- }
- handles->bitmap[slot / 32] &= ~(1 << (slot % 32));
- }
- else
- {
- /* print a warning? */
- }
- //mono_perfcounters->gc_num_handles--;
- /*g_print ("freed entry %d of type %d\n", slot, handles->type);*/
- unlock_handles(handles);
- }
- utils::Expected<uint32_t> GCHandle::GetTargetHandle(Il2CppObject * obj, int32_t handle, int32_t type)
- {
- if (type == -1)
- {
- il2cpp_gchandle_set_target(handle, obj);
- /* the handle doesn't change */
- return handle;
- }
- switch (type)
- {
- case HANDLE_WEAK:
- return NewWeakref(obj, false);
- case HANDLE_WEAK_TRACK:
- return NewWeakref(obj, true);
- case HANDLE_NORMAL:
- return New(obj, false);
- case HANDLE_PINNED:
- return New(obj, true);
- default:
- IL2CPP_ASSERT(0);
- }
- return 0;
- }
- void GCHandle::WalkStrongGCHandleTargets(WalkGCHandleTargetsCallback callback, void* context)
- {
- lock_handles(handles);
- const GCHandleType types[] = { HANDLE_NORMAL, HANDLE_PINNED };
- for (int gcHandleTypeIndex = 0; gcHandleTypeIndex < 2; gcHandleTypeIndex++)
- {
- const HandleData& handles = gc_handles[types[gcHandleTypeIndex]];
- for (uint32_t i = 0; i < handles.size; i++)
- {
- if (handles.entries[i] != NULL)
- callback(static_cast<Il2CppObject*>(handles.entries[i]), context);
- }
- }
- unlock_handles(handles);
- }
- } /* gc */
- } /* il2cpp */
|