GCHandle.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. #include "il2cpp-config.h"
  2. #include "gc/GCHandle.h"
  3. #include "il2cpp-object-internals.h"
  4. #include "GarbageCollector.h"
  5. #include "os/Mutex.h"
  6. #include "utils/Memory.h"
  7. #include <memory>
  8. namespace il2cpp
  9. {
  10. namespace gc
  11. {
  12. typedef struct
  13. {
  14. uint32_t *bitmap;
  15. void* *entries;
  16. uint32_t size;
  17. uint8_t type;
  18. uint32_t slot_hint : 24;/* starting slot for search */
  19. /* 2^16 appdomains should be enough for everyone (though I know I'll regret this in 20 years) */
  20. /* we alloc this only for weak refs, since we can get the domain directly in the other cases */
  21. uint16_t *domain_ids;
  22. } HandleData;
  23. /* weak and weak-track arrays will be allocated in malloc memory
  24. */
  25. static HandleData gc_handles[] =
  26. {
  27. {NULL, NULL, 0, HANDLE_WEAK, 0},
  28. {NULL, NULL, 0, HANDLE_WEAK_TRACK, 0},
  29. {NULL, NULL, 0, HANDLE_NORMAL, 0},
  30. {NULL, NULL, 0, HANDLE_PINNED, 0}
  31. };
  32. static int
  33. find_first_unset(uint32_t bitmap)
  34. {
  35. int i;
  36. for (i = 0; i < 32; ++i)
  37. {
  38. if (!(bitmap & (1 << i)))
  39. return i;
  40. }
  41. return -1;
  42. }
  43. static baselib::ReentrantLock g_HandlesMutex;
  44. #define lock_handles(handles) g_HandlesMutex.Acquire ()
  45. #define unlock_handles(handles) g_HandlesMutex.Release ()
  46. static uint32_t
  47. alloc_handle(HandleData *handles, Il2CppObject *obj, bool track)
  48. {
  49. uint32_t slot;
  50. int i;
  51. lock_handles(handles);
  52. if (!handles->size)
  53. {
  54. handles->size = 32;
  55. if (handles->type > HANDLE_WEAK_TRACK)
  56. {
  57. handles->entries = (void**)GarbageCollector::AllocateFixed(sizeof(void*) * handles->size, NULL);
  58. }
  59. else
  60. {
  61. handles->entries = (void**)IL2CPP_MALLOC_ZERO(sizeof(void*) * handles->size);
  62. handles->domain_ids = (uint16_t*)IL2CPP_MALLOC_ZERO(sizeof(uint16_t) * handles->size);
  63. }
  64. handles->bitmap = (uint32_t*)IL2CPP_MALLOC_ZERO(handles->size / 8);
  65. }
  66. i = -1;
  67. for (slot = handles->slot_hint; slot < handles->size / 32; ++slot)
  68. {
  69. if (handles->bitmap[slot] != 0xffffffff)
  70. {
  71. i = find_first_unset(handles->bitmap[slot]);
  72. handles->slot_hint = slot;
  73. break;
  74. }
  75. }
  76. if (i == -1 && handles->slot_hint != 0)
  77. {
  78. for (slot = 0; slot < handles->slot_hint; ++slot)
  79. {
  80. if (handles->bitmap[slot] != 0xffffffff)
  81. {
  82. i = find_first_unset(handles->bitmap[slot]);
  83. handles->slot_hint = slot;
  84. break;
  85. }
  86. }
  87. }
  88. if (i == -1)
  89. {
  90. uint32_t *new_bitmap;
  91. uint32_t new_size = handles->size * 2; /* always double: we memset to 0 based on this below */
  92. /* resize and copy the bitmap */
  93. new_bitmap = (uint32_t*)IL2CPP_MALLOC_ZERO(new_size / 8);
  94. memcpy(new_bitmap, handles->bitmap, handles->size / 8);
  95. IL2CPP_FREE(handles->bitmap);
  96. handles->bitmap = new_bitmap;
  97. /* resize and copy the entries */
  98. if (handles->type > HANDLE_WEAK_TRACK)
  99. {
  100. void* *entries;
  101. entries = (void**)GarbageCollector::AllocateFixed(sizeof(void*) * new_size, NULL);
  102. memcpy(entries, handles->entries, sizeof(void*) * handles->size);
  103. GarbageCollector::SetWriteBarrier(entries, sizeof(void*) * handles->size);
  104. void** previous_entries = handles->entries;
  105. handles->entries = entries;
  106. GarbageCollector::FreeFixed(previous_entries);
  107. }
  108. else
  109. {
  110. void* *entries;
  111. uint16_t *domain_ids;
  112. domain_ids = (uint16_t*)IL2CPP_MALLOC_ZERO(sizeof(uint16_t) * new_size);
  113. entries = (void**)IL2CPP_MALLOC(sizeof(void*) * new_size);
  114. /* we disable GC because we could lose some disappearing link updates */
  115. GarbageCollector::Disable();
  116. memcpy(entries, handles->entries, sizeof(void*) * handles->size);
  117. memset(entries + handles->size, 0, sizeof(void*) * handles->size);
  118. memcpy(domain_ids, handles->domain_ids, sizeof(uint16_t) * handles->size);
  119. for (i = 0; i < (int32_t)handles->size; ++i)
  120. {
  121. Il2CppObject *obj = GarbageCollector::GetWeakLink(&(handles->entries[i]));
  122. if (handles->entries[i])
  123. GarbageCollector::RemoveWeakLink(&(handles->entries[i]));
  124. /*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]);*/
  125. if (obj)
  126. {
  127. GarbageCollector::AddWeakLink(&(entries[i]), obj, track);
  128. }
  129. }
  130. IL2CPP_FREE(handles->entries);
  131. IL2CPP_FREE(handles->domain_ids);
  132. handles->entries = entries;
  133. handles->domain_ids = domain_ids;
  134. GarbageCollector::Enable();
  135. }
  136. /* set i and slot to the next free position */
  137. i = 0;
  138. slot = (handles->size + 1) / 32;
  139. handles->slot_hint = handles->size + 1;
  140. handles->size = new_size;
  141. }
  142. handles->bitmap[slot] |= 1 << i;
  143. slot = slot * 32 + i;
  144. handles->entries[slot] = obj;
  145. GarbageCollector::SetWriteBarrier(handles->entries + slot);
  146. if (handles->type <= HANDLE_WEAK_TRACK)
  147. {
  148. if (obj)
  149. GarbageCollector::AddWeakLink(&(handles->entries[slot]), obj, track);
  150. }
  151. //mono_perfcounters->gc_num_handles++;
  152. unlock_handles(handles);
  153. /*g_print ("allocated entry %d of type %d to object %p (in slot: %p)\n", slot, handles->type, obj, handles->entries [slot]);*/
  154. return (slot << 3) | (handles->type + 1);
  155. }
  156. uint32_t GCHandle::New(Il2CppObject *obj, bool pinned)
  157. {
  158. return alloc_handle(&gc_handles[pinned ? HANDLE_PINNED : HANDLE_NORMAL], obj, false);
  159. }
  160. utils::Expected<uint32_t> GCHandle::NewWeakref(Il2CppObject *obj, bool track_resurrection)
  161. {
  162. uint32_t handle = alloc_handle(&gc_handles[track_resurrection ? HANDLE_WEAK_TRACK : HANDLE_WEAK], obj, track_resurrection);
  163. #ifndef HAVE_SGEN_GC
  164. if (track_resurrection)
  165. return utils::Il2CppError(utils::NotSupported, "IL2CPP does not support resurrection for weak references. Pass the trackResurrection with a value of false.");
  166. #endif
  167. return handle;
  168. }
  169. GCHandleType GCHandle::GetHandleType(uint32_t gchandle)
  170. {
  171. return static_cast<GCHandleType>((gchandle & 7) - 1);
  172. }
  173. static inline uint32_t GetHandleSlot(uint32_t gchandle)
  174. {
  175. return gchandle >> 3;
  176. }
  177. Il2CppObject* GCHandle::GetTarget(uint32_t gchandle)
  178. {
  179. uint32_t slot = GetHandleSlot(gchandle);
  180. uint32_t type = GetHandleType(gchandle);
  181. HandleData *handles = &gc_handles[type];
  182. Il2CppObject *obj = NULL;
  183. if (type > 3)
  184. return NULL;
  185. lock_handles(handles);
  186. if (slot < handles->size && (handles->bitmap[slot / 32] & (1 << (slot % 32))))
  187. {
  188. if (handles->type <= HANDLE_WEAK_TRACK)
  189. {
  190. obj = GarbageCollector::GetWeakLink(&handles->entries[slot]);
  191. }
  192. else
  193. {
  194. obj = (Il2CppObject*)handles->entries[slot];
  195. }
  196. }
  197. else
  198. {
  199. /* print a warning? */
  200. }
  201. unlock_handles(handles);
  202. /*g_print ("get target of entry %d of type %d: %p\n", slot, handles->type, obj);*/
  203. return obj;
  204. }
  205. static void
  206. il2cpp_gchandle_set_target(uint32_t gchandle, Il2CppObject *obj)
  207. {
  208. uint32_t slot = GetHandleSlot(gchandle);
  209. uint32_t type = GCHandle::GetHandleType(gchandle);
  210. HandleData *handles = &gc_handles[type];
  211. Il2CppObject *old_obj = NULL;
  212. if (type > 3)
  213. return;
  214. lock_handles(handles);
  215. if (slot < handles->size && (handles->bitmap[slot / 32] & (1 << (slot % 32))))
  216. {
  217. if (handles->type <= HANDLE_WEAK_TRACK)
  218. {
  219. old_obj = (Il2CppObject*)handles->entries[slot];
  220. if (handles->entries[slot])
  221. GarbageCollector::RemoveWeakLink(&handles->entries[slot]);
  222. if (obj)
  223. GarbageCollector::AddWeakLink(&handles->entries[slot], obj, handles->type == HANDLE_WEAK_TRACK);
  224. }
  225. else
  226. {
  227. handles->entries[slot] = obj;
  228. }
  229. }
  230. else
  231. {
  232. /* print a warning? */
  233. }
  234. unlock_handles(handles);
  235. #ifndef HAVE_SGEN_GC
  236. if (type == HANDLE_WEAK_TRACK)
  237. IL2CPP_NOT_IMPLEMENTED(il2cpp_gchandle_set_target);
  238. #endif
  239. }
  240. void GCHandle::Free(uint32_t gchandle)
  241. {
  242. uint32_t slot = GetHandleSlot(gchandle);
  243. uint32_t type = GetHandleType(gchandle);
  244. HandleData *handles = &gc_handles[type];
  245. if (type > 3)
  246. return;
  247. #ifndef HAVE_SGEN_GC
  248. if (type == HANDLE_WEAK_TRACK)
  249. IL2CPP_NOT_IMPLEMENTED(GCHandle::Free);
  250. #endif
  251. lock_handles(handles);
  252. if (slot < handles->size && (handles->bitmap[slot / 32] & (1 << (slot % 32))))
  253. {
  254. if (handles->type <= HANDLE_WEAK_TRACK)
  255. {
  256. if (handles->entries[slot])
  257. GarbageCollector::RemoveWeakLink(&handles->entries[slot]);
  258. }
  259. else
  260. {
  261. handles->entries[slot] = NULL;
  262. }
  263. handles->bitmap[slot / 32] &= ~(1 << (slot % 32));
  264. }
  265. else
  266. {
  267. /* print a warning? */
  268. }
  269. //mono_perfcounters->gc_num_handles--;
  270. /*g_print ("freed entry %d of type %d\n", slot, handles->type);*/
  271. unlock_handles(handles);
  272. }
  273. utils::Expected<uint32_t> GCHandle::GetTargetHandle(Il2CppObject * obj, int32_t handle, int32_t type)
  274. {
  275. if (type == -1)
  276. {
  277. il2cpp_gchandle_set_target(handle, obj);
  278. /* the handle doesn't change */
  279. return handle;
  280. }
  281. switch (type)
  282. {
  283. case HANDLE_WEAK:
  284. return NewWeakref(obj, false);
  285. case HANDLE_WEAK_TRACK:
  286. return NewWeakref(obj, true);
  287. case HANDLE_NORMAL:
  288. return New(obj, false);
  289. case HANDLE_PINNED:
  290. return New(obj, true);
  291. default:
  292. IL2CPP_ASSERT(0);
  293. }
  294. return 0;
  295. }
  296. void GCHandle::WalkStrongGCHandleTargets(WalkGCHandleTargetsCallback callback, void* context)
  297. {
  298. lock_handles(handles);
  299. const GCHandleType types[] = { HANDLE_NORMAL, HANDLE_PINNED };
  300. for (int gcHandleTypeIndex = 0; gcHandleTypeIndex < 2; gcHandleTypeIndex++)
  301. {
  302. const HandleData& handles = gc_handles[types[gcHandleTypeIndex]];
  303. for (uint32_t i = 0; i < handles.size; i++)
  304. {
  305. if (handles.entries[i] != NULL)
  306. callback(static_cast<Il2CppObject*>(handles.entries[i]), context);
  307. }
  308. }
  309. unlock_handles(handles);
  310. }
  311. } /* gc */
  312. } /* il2cpp */