PageRenderTime 47ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/dna/Heap.c

https://bitbucket.org/cosi2/dotnetanywhere-wb
C | 604 lines | 427 code | 75 blank | 102 comment | 108 complexity | b8fba3a475c293f279d142032d0d05e5 MD5 | raw file
  1. // Copyright (c) 2009 DotNetAnywhere
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining a copy
  4. // of this software and associated documentation files (the "Software"), to deal
  5. // in the Software without restriction, including without limitation the rights
  6. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. // copies of the Software, and to permit persons to whom the Software is
  8. // furnished to do so, subject to the following conditions:
  9. //
  10. // The above copyright notice and this permission notice shall be included in
  11. // all copies or substantial portions of the Software.
  12. //
  13. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  19. // THE SOFTWARE.
  20. #include "Compat.h"
  21. #include "Sys.h"
  22. #include "Heap.h"
  23. #include "MetaData.h"
  24. #include "CLIFile.h"
  25. #include "Type.h"
  26. #include "EvalStack.h"
  27. #include "Finalizer.h"
  28. #include "Thread.h"
  29. #include "System.String.h"
  30. #include "System.Array.h"
  31. #include "System.WeakReference.h"
  32. // Memory roots are:
  33. // All threads, all MethodStates - the ParamLocals memory and the evaluation stack
  34. // All static fields of all types
  35. // Note that the evaluation stack is not typed, so every 4-byte entry is treated as a pointer
  36. typedef struct tSync_ tSync;
  37. typedef struct tHeapEntry_ tHeapEntry;
  38. struct tSync_ {
  39. // The thread that holds this sync block
  40. tThread *pThread;
  41. // The number of times this thread has entered the sync block
  42. U32 count;
  43. // Link to the first weak-ref that targets this object.
  44. // This allows the tracking of all weak-refs that target this object.
  45. HEAP_PTR weakRef;
  46. };
  47. // The memory is kept track of using a balanced binary search tree (ordered by memory address)
  48. // See http://www.eternallyconfuzzled.com/tuts/datastructures/jsw_tut_andersson.aspx for details.
  49. struct tHeapEntry_ {
  50. // Left/right links in the heap binary tree
  51. tHeapEntry *pLink[2];
  52. // The 'level' of this node. Leaf nodes have lowest level
  53. U8 level;
  54. // Used to mark that this node is still in use.
  55. // If this is set to 0xff, then this heap entry is undeletable.
  56. U8 marked;
  57. // Set to 1 if the Finalizer needs to be run.
  58. // Set to 2 if this has been added to the Finalizer queue
  59. // Set to 0 when the Finalizer has been run (or there is no Finalizer in the first place)
  60. // Only set on types that have a Finalizer
  61. U8 needToFinalize;
  62. // unused
  63. U8 padding;
  64. // The type in this heap entry
  65. tMD_TypeDef *pTypeDef;
  66. // Used for locking sync, and tracking WeakReference that point to this object
  67. tSync *pSync;
  68. // The user memory
  69. U8 memory[0];
  70. };
  71. // Get the tHeapEntry pointer when given a HEAP_PTR object
  72. #define GET_HEAPENTRY(heapObj) ((tHeapEntry*)(heapObj - sizeof(tHeapEntry)))
  73. // Forward ref
  74. static void RemoveWeakRefTarget(tHeapEntry *pHeapEntry, U32 removeLongRefs);
  75. static tHeapEntry *pHeapTreeRoot;
  76. static tHeapEntry *nil;
  77. #define MAX_TREE_DEPTH 40
  78. // The total heap memory currently allocated
  79. static U32 trackHeapSize;
  80. // The max heap size allowed before a garbage collection is triggered
  81. static U32 heapSizeMax;
  82. // The number of allocated memory nodes
  83. static U32 numNodes = 0;
  84. // The number of collections done
  85. static U32 numCollections = 0;
  86. #ifdef DIAG_GC
  87. // Track how much time GC's are taking
  88. U64 gcTotalTime = 0;
  89. #endif
  90. #define MIN_HEAP_SIZE 50000
  91. #define MAX_HEAP_EXCESS 200000
  92. void Heap_Init() {
  93. // Initialise vars
  94. trackHeapSize = 0;
  95. heapSizeMax = MIN_HEAP_SIZE;
  96. // Create nil node - for leaf termination
  97. nil = TMALLOCFOREVER(tHeapEntry);
  98. memset(nil, 0, sizeof(tHeapEntry));
  99. nil->pLink[0] = nil->pLink[1] = nil;
  100. // Set the heap tree as empty
  101. pHeapTreeRoot = nil;
  102. }
  103. // Get the size of a heap entry, NOT including the header
  104. // This works by returning the size of the type, unless the type is an array or a string,
  105. // which are the only two types that can have variable sizes
  106. static U32 GetSize(tHeapEntry *pHeapEntry) {
  107. tMD_TypeDef *pType = pHeapEntry->pTypeDef;
  108. if (pType == types[TYPE_SYSTEM_STRING]) {
  109. // If it's a string, return the string length in bytes
  110. return SystemString_GetNumBytes((HEAP_PTR)(pHeapEntry + 1));
  111. }
  112. if (TYPE_ISARRAY(pType)) {
  113. // If it's an array, return the array length * array element size
  114. return SystemArray_GetNumBytes((HEAP_PTR)(pHeapEntry + 1), pType->pArrayElementType);
  115. }
  116. // If it's not string or array, just return the instance memory size
  117. return pType->instanceMemSize;
  118. }
  119. static tHeapEntry* TreeSkew(tHeapEntry *pRoot) {
  120. if (pRoot->pLink[0]->level == pRoot->level && pRoot->level != 0) {
  121. tHeapEntry *pSave = pRoot->pLink[0];
  122. pRoot->pLink[0] = pSave->pLink[1];
  123. pSave->pLink[1] = pRoot;
  124. pRoot = pSave;
  125. }
  126. return pRoot;
  127. }
  128. static tHeapEntry* TreeSplit(tHeapEntry *pRoot) {
  129. if (pRoot->pLink[1]->pLink[1]->level == pRoot->level && pRoot->level != 0) {
  130. tHeapEntry *pSave = pRoot->pLink[1];
  131. pRoot->pLink[1] = pSave->pLink[0];
  132. pSave->pLink[0] = pRoot;
  133. pRoot = pSave;
  134. pRoot->level++;
  135. }
  136. return pRoot;
  137. }
  138. static tHeapEntry* TreeInsert(tHeapEntry *pRoot, tHeapEntry *pEntry) {
  139. if (pRoot == nil) {
  140. pRoot = pEntry;
  141. pRoot->level = 1;
  142. pRoot->pLink[0] = pRoot->pLink[1] = nil;
  143. pRoot->marked = 0;
  144. } else {
  145. tHeapEntry *pNode = pHeapTreeRoot;
  146. tHeapEntry *pUp[MAX_TREE_DEPTH];
  147. I32 top = 0, dir;
  148. // Find leaf position to insert into tree. This first step is unbalanced
  149. for (;;) {
  150. pUp[top++] = pNode;
  151. dir = pNode < pEntry; // 0 for left, 1 for right
  152. if (pNode->pLink[dir] == nil) {
  153. break;
  154. }
  155. pNode = pNode->pLink[dir];
  156. }
  157. // Create new node
  158. pNode->pLink[dir] = pEntry;
  159. pEntry->level = 1;
  160. pEntry->pLink[0] = pEntry->pLink[1] = nil;
  161. pEntry->marked = 0;
  162. // Balance the tree
  163. while (--top >= 0) {
  164. if (top != 0) {
  165. dir = pUp[top-1]->pLink[1] == pUp[top];
  166. }
  167. pUp[top] = TreeSkew(pUp[top]);
  168. pUp[top] = TreeSplit(pUp[top]);
  169. if (top != 0) {
  170. pUp[top-1]->pLink[dir] = pUp[top];
  171. } else {
  172. pRoot = pUp[0];
  173. }
  174. }
  175. }
  176. return pRoot;
  177. }
  178. static tHeapEntry* TreeRemove(tHeapEntry *pRoot, tHeapEntry *pDelete) {
  179. if (pRoot != nil) {
  180. if (pRoot == pDelete) {
  181. if (pRoot->pLink[0] != nil && pRoot->pLink[1] != nil) {
  182. tHeapEntry *pL0;
  183. U8 l;
  184. tHeapEntry *pHeir = pRoot->pLink[0], **ppHeirLink = &pHeir->pLink[0];
  185. while (pHeir->pLink[1] != nil) {
  186. ppHeirLink = &pHeir->pLink[1];
  187. pHeir = pHeir->pLink[1];
  188. }
  189. // Swap the two nodes
  190. pL0 = pHeir->pLink[0];
  191. l = pHeir->level;
  192. // Bring heir to replace root
  193. pHeir->pLink[0] = pRoot->pLink[0];
  194. pHeir->pLink[1] = pRoot->pLink[1];
  195. pHeir->level = pRoot->level;
  196. // Send root to replace heir
  197. *ppHeirLink = pRoot;
  198. pRoot->pLink[0] = pL0;
  199. pRoot->pLink[1] = nil;
  200. pRoot->level = l;
  201. // Set correct return value
  202. pL0 = pRoot;
  203. pRoot = pHeir;
  204. // Delete the node that's been sent down
  205. pRoot->pLink[0] = TreeRemove(pRoot->pLink[0], pL0);
  206. } else {
  207. pRoot = pRoot->pLink[pRoot->pLink[0] == nil];
  208. }
  209. } else {
  210. I32 dir = pRoot < pDelete;
  211. pRoot->pLink[dir] = TreeRemove(pRoot->pLink[dir], pDelete);
  212. }
  213. }
  214. if (pRoot->pLink[0]->level < pRoot->level-1 || pRoot->pLink[1]->level < pRoot->level-1) {
  215. if (pRoot->pLink[1]->level > --pRoot->level) {
  216. pRoot->pLink[1]->level = pRoot->level;
  217. }
  218. pRoot = TreeSkew(pRoot);
  219. pRoot->pLink[1] = TreeSkew(pRoot->pLink[1]);
  220. pRoot->pLink[1]->pLink[1] = TreeSkew(pRoot->pLink[1]->pLink[1]);
  221. pRoot = TreeSplit(pRoot);
  222. pRoot->pLink[1] = TreeSplit(pRoot->pLink[1]);
  223. }
  224. return pRoot;
  225. }
  226. static void GarbageCollect() {
  227. tHeapRoots heapRoots;
  228. tHeapEntry *pNode;
  229. tHeapEntry *pUp[MAX_TREE_DEPTH * 2];
  230. I32 top;
  231. tHeapEntry *pToDelete = NULL;
  232. U32 orgHeapSize = trackHeapSize;
  233. U32 orgNumNodes = numNodes;
  234. #ifdef DIAG_GC
  235. U64 startTime;
  236. #endif
  237. numCollections++;
  238. #ifdef DIAG_GC
  239. startTime = microTime();
  240. #endif
  241. heapRoots.capacity = 64;
  242. heapRoots.num = 0;
  243. heapRoots.pHeapEntries = malloc(heapRoots.capacity * sizeof(tHeapRootEntry));
  244. Thread_GetHeapRoots(&heapRoots);
  245. CLIFile_GetHeapRoots(&heapRoots);
  246. // Mark phase
  247. while (heapRoots.num > 0) {
  248. tHeapRootEntry *pRootsEntry;
  249. U32 i;
  250. U32 moreRootsAdded = 0;
  251. U32 rootsEntryNumPointers;
  252. void **pRootsEntryMem;
  253. // Get a piece of memory off the list of heap memory roots.
  254. pRootsEntry = &heapRoots.pHeapEntries[heapRoots.num - 1];
  255. rootsEntryNumPointers = pRootsEntry->numPointers;
  256. pRootsEntryMem = pRootsEntry->pMem;
  257. // Mark this entry as done
  258. pRootsEntry->numPointers = 0;
  259. pRootsEntry->pMem = NULL;
  260. // Iterate through all pointers in it
  261. for (i=0; i<rootsEntryNumPointers; i++) {
  262. void *pMemRef = pRootsEntryMem[i];
  263. // Quick escape for known non-memory
  264. if (pMemRef == NULL) {
  265. continue;
  266. }
  267. // Find this piece of heap memory in the tracking tree.
  268. // Note that the 2nd memory address comparison MUST be >, not >= as might be expected,
  269. // to allow for a zero-sized memory to be detected (and not garbage collected) properly.
  270. // E.g. The object class has zero memory.
  271. pNode = pHeapTreeRoot;
  272. while (pNode != nil) {
  273. if (pMemRef < (void*)pNode) {
  274. pNode = pNode->pLink[0];
  275. } else if ((char*)pMemRef > ((char*)pNode) + GetSize(pNode) + sizeof(tHeapEntry)) {
  276. pNode = pNode->pLink[1];
  277. } else {
  278. // Found memory. See if it's already been marked.
  279. // If it's already marked, then don't do anything.
  280. // It it's not marked, then add all of its memory to the roots, and mark it.
  281. if (pNode->marked == 0) {
  282. tMD_TypeDef *pType = pNode->pTypeDef;
  283. // Not yet marked, so mark it, and add it to heap roots.
  284. pNode->marked = 1;
  285. // Don't look at the contents of strings, arrays of primitive types, or WeakReferences
  286. if (pType->stackType == EVALSTACK_O ||
  287. pType->stackType == EVALSTACK_VALUETYPE ||
  288. pType->stackType == EVALSTACK_PTR) {
  289. if (pType != types[TYPE_SYSTEM_STRING] &&
  290. (!TYPE_ISARRAY(pType) ||
  291. pType->pArrayElementType->stackType == EVALSTACK_O ||
  292. pType->pArrayElementType->stackType == EVALSTACK_VALUETYPE ||
  293. pType->pArrayElementType->stackType == EVALSTACK_PTR)) {
  294. if (pType != types[TYPE_SYSTEM_WEAKREFERENCE]) {
  295. Heap_SetRoots(&heapRoots,pNode->memory, GetSize(pNode));
  296. moreRootsAdded = 1;
  297. }
  298. }
  299. }
  300. }
  301. break;
  302. }
  303. }
  304. }
  305. if (!moreRootsAdded) {
  306. heapRoots.num--;
  307. }
  308. }
  309. free(heapRoots.pHeapEntries);
  310. // Sweep phase
  311. // Traverse nodes
  312. pUp[0] = pHeapTreeRoot;
  313. top = 1;
  314. while (top != 0) {
  315. // Get this node
  316. pNode = pUp[--top];
  317. // Act on this node
  318. if (pNode->marked) {
  319. if (pNode->marked != 0xff) {
  320. // Still in use (but not marked undeletable), so unmark
  321. pNode->marked = 0;
  322. }
  323. } else {
  324. // Not in use any more, so put in deletion queue if it does not need Finalizing
  325. // If it does need Finalizing, then don't garbage collect, and put in Finalization queue.
  326. if (pNode->needToFinalize) {
  327. if (pNode->needToFinalize == 1) {
  328. AddFinalizer((HEAP_PTR)pNode + sizeof(tHeapEntry));
  329. // Mark it has having been placed in the finalization queue.
  330. // When it has been finalized, then this will be set to 0
  331. pNode->needToFinalize = 2;
  332. // If this object is being targetted by weak-ref(s), handle it
  333. if (pNode->pSync != NULL) {
  334. RemoveWeakRefTarget(pNode, 0);
  335. free(pNode->pSync);
  336. }
  337. }
  338. } else {
  339. // If this object is being targetted by weak-ref(s), handle it
  340. if (pNode->pSync != NULL) {
  341. RemoveWeakRefTarget(pNode, 1);
  342. free(pNode->pSync);
  343. }
  344. // Use pSync to point to next entry in this linked-list.
  345. #ifdef WIN32
  346. (tHeapEntry*)(pNode->pSync) = pToDelete;
  347. #else
  348. pNode->pSync = pToDelete;
  349. #endif
  350. pToDelete = pNode;
  351. }
  352. }
  353. // Get next node(s)
  354. if (pNode->pLink[1] != nil) {
  355. pUp[top++] = pNode->pLink[1];
  356. }
  357. if (pNode->pLink[0] != nil) {
  358. pUp[top++] = pNode->pLink[0];
  359. }
  360. }
  361. // Delete all unused memory nodes.
  362. while (pToDelete != NULL) {
  363. tHeapEntry *pThis = pToDelete;
  364. pToDelete = (tHeapEntry*)(pToDelete->pSync);
  365. pHeapTreeRoot = TreeRemove(pHeapTreeRoot, pThis);
  366. numNodes--;
  367. trackHeapSize -= GetSize(pThis) + sizeof(tHeapEntry);
  368. free(pThis);
  369. }
  370. #ifdef DIAG_GC
  371. gcTotalTime += microTime() - startTime;
  372. #endif
  373. log_f(1, "--- GARBAGE --- [Size: %d -> %d] [Nodes: %d -> %d]\n",
  374. orgHeapSize, trackHeapSize, orgNumNodes, numNodes);
  375. #ifdef DIAG_GC
  376. log_f(1, "GC time = %d ms\n", gcTotalTime / 1000);
  377. #endif
  378. }
  379. void Heap_UnmarkFinalizer(HEAP_PTR heapPtr) {
  380. ((tHeapEntry*)(heapPtr - sizeof(tHeapEntry)))->needToFinalize = 0;
  381. }
  382. void Heap_GarbageCollect() {
  383. GarbageCollect();
  384. }
  385. U32 Heap_NumCollections() {
  386. return numCollections;
  387. }
  388. U32 Heap_GetTotalMemory() {
  389. return trackHeapSize;
  390. }
  391. void Heap_SetRoots(tHeapRoots *pHeapRoots, void *pRoots, U32 sizeInBytes) {
  392. tHeapRootEntry *pRootEntry;
  393. Assert((sizeInBytes & 0x3) == 0);
  394. if (pHeapRoots->num >= pHeapRoots->capacity) {
  395. pHeapRoots->capacity <<= 1;
  396. pHeapRoots->pHeapEntries = (tHeapRootEntry*)realloc(pHeapRoots->pHeapEntries, pHeapRoots->capacity * sizeof(tHeapRootEntry));
  397. }
  398. pRootEntry = &pHeapRoots->pHeapEntries[pHeapRoots->num++];
  399. pRootEntry->numPointers = sizeInBytes >> 2;
  400. pRootEntry->pMem = pRoots;
  401. }
  402. HEAP_PTR Heap_Alloc(tMD_TypeDef *pTypeDef, U32 size) {
  403. tHeapEntry *pHeapEntry;
  404. U32 totalSize;
  405. totalSize = sizeof(tHeapEntry) + size;
  406. // Trigger garbage collection if required.
  407. if (trackHeapSize >= heapSizeMax) {
  408. GarbageCollect();
  409. heapSizeMax = (trackHeapSize + totalSize) << 1;
  410. if (heapSizeMax < trackHeapSize + totalSize + MIN_HEAP_SIZE) {
  411. // Make sure there is always MIN_HEAP_SIZE available to allocate on the heap
  412. heapSizeMax = trackHeapSize + totalSize + MIN_HEAP_SIZE;
  413. }
  414. if (heapSizeMax > trackHeapSize + totalSize + MAX_HEAP_EXCESS) {
  415. // Make sure there is never more that MAX_HEAP_EXCESS space on the heap
  416. heapSizeMax = trackHeapSize + totalSize + MAX_HEAP_EXCESS;
  417. }
  418. }
  419. pHeapEntry = (tHeapEntry*)malloc(totalSize);
  420. pHeapEntry->pTypeDef = pTypeDef;
  421. pHeapEntry->pSync = NULL;
  422. pHeapEntry->needToFinalize = (pTypeDef->pFinalizer != NULL);
  423. memset(pHeapEntry->memory, 0, size);
  424. trackHeapSize += totalSize;
  425. pHeapTreeRoot = TreeInsert(pHeapTreeRoot, pHeapEntry);
  426. numNodes++;
  427. return pHeapEntry->memory;
  428. }
  429. HEAP_PTR Heap_AllocType(tMD_TypeDef *pTypeDef) {
  430. //printf("Heap_AllocType('%s')\n", pTypeDef->name);
  431. return Heap_Alloc(pTypeDef, pTypeDef->instanceMemSize);
  432. }
  433. tMD_TypeDef* Heap_GetType(HEAP_PTR heapEntry) {
  434. tHeapEntry *pHeapEntry = GET_HEAPENTRY(heapEntry);
  435. return pHeapEntry->pTypeDef;
  436. }
  437. void Heap_MakeUndeletable(HEAP_PTR heapEntry) {
  438. tHeapEntry *pHeapEntry = GET_HEAPENTRY(heapEntry);
  439. pHeapEntry->marked = 0xff;
  440. }
  441. void Heap_MakeDeletable(HEAP_PTR heapEntry) {
  442. tHeapEntry *pHeapEntry = GET_HEAPENTRY(heapEntry);
  443. pHeapEntry->marked = 0;
  444. }
  445. HEAP_PTR Heap_Box(tMD_TypeDef *pType, PTR pMem) {
  446. HEAP_PTR boxed;
  447. boxed = Heap_AllocType(pType);
  448. memcpy(boxed, pMem, pType->instanceMemSize);
  449. return boxed;
  450. }
  451. HEAP_PTR Heap_Clone(HEAP_PTR obj) {
  452. tHeapEntry *pObj = GET_HEAPENTRY(obj);
  453. HEAP_PTR clone;
  454. U32 size = GetSize(pObj);
  455. clone = Heap_Alloc(pObj->pTypeDef, size);
  456. memcpy(clone, pObj->memory, size);
  457. return clone;
  458. }
  459. static tSync* EnsureSync(tHeapEntry *pHeapEntry) {
  460. if (pHeapEntry->pSync == NULL) {
  461. tSync *pSync = TMALLOC(tSync);
  462. memset(pSync, 0, sizeof(tSync));
  463. pHeapEntry->pSync = pSync;
  464. }
  465. return pHeapEntry->pSync;
  466. }
  467. static void DeleteSync(tHeapEntry *pHeapEntry) {
  468. if (pHeapEntry->pSync != NULL) {
  469. if (pHeapEntry->pSync->count == 0 && pHeapEntry->pSync->weakRef == NULL) {
  470. free(pHeapEntry->pSync);
  471. pHeapEntry->pSync = NULL;
  472. }
  473. }
  474. }
  475. // Return 1 if lock succesfully got
  476. // Return 0 if couldn't get the lock this time
  477. U32 Heap_SyncTryEnter(HEAP_PTR obj) {
  478. tHeapEntry *pHeapEntry = GET_HEAPENTRY(obj);
  479. tThread *pThread = Thread_GetCurrent();
  480. tSync *pSync;
  481. pSync = EnsureSync(pHeapEntry);
  482. if (pSync->pThread == NULL) {
  483. pSync->pThread = pThread;
  484. pSync->count = 1;
  485. return 1;
  486. }
  487. if (pSync->pThread == pThread) {
  488. pSync->count++;
  489. return 1;
  490. }
  491. return 0;
  492. }
  493. // Returns 1 if all is OK
  494. // Returns 0 if the wrong thread is releasing the sync, or if no thread hold the sync
  495. U32 Heap_SyncExit(HEAP_PTR obj) {
  496. tHeapEntry *pHeapEntry = GET_HEAPENTRY(obj);
  497. tThread *pThread = Thread_GetCurrent();
  498. if (pHeapEntry->pSync == NULL) {
  499. return 0;
  500. }
  501. if (pHeapEntry->pSync->pThread != pThread) {
  502. return 0;
  503. }
  504. if (--pHeapEntry->pSync->count == 0) {
  505. DeleteSync(pHeapEntry);
  506. }
  507. return 1;
  508. }
  509. static void RemoveWeakRefTarget(tHeapEntry *pTarget, U32 removeLongRefs) {
  510. SystemWeakReference_TargetGone(&pTarget->pSync->weakRef, removeLongRefs);
  511. }
  512. // Returns the previous first weak-ref in target targetted by weakref
  513. HEAP_PTR Heap_SetWeakRefTarget(HEAP_PTR target, HEAP_PTR weakRef) {
  514. tHeapEntry *pTarget = GET_HEAPENTRY(target);
  515. tSync *pSync;
  516. HEAP_PTR prevWeakRef;
  517. pSync = EnsureSync(pTarget);
  518. prevWeakRef = pSync->weakRef;
  519. pSync->weakRef = weakRef;
  520. return prevWeakRef;
  521. }
  522. HEAP_PTR* Heap_GetWeakRefAddress(HEAP_PTR target) {
  523. tHeapEntry *pTarget = GET_HEAPENTRY(target);
  524. return &pTarget->pSync->weakRef;
  525. }
  526. void Heap_RemovedWeakRefTarget(HEAP_PTR target) {
  527. tHeapEntry *pTarget = GET_HEAPENTRY(target);
  528. DeleteSync(pTarget);
  529. }