Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of pymite by
vm/heap.c@0:65f1469d6bfb, 2013-03-02 (annotated)
- Committer:
- va009039
- Date:
- Sat Mar 02 11:54:20 2013 +0000
- Revision:
- 0:65f1469d6bfb
first commit
Who changed what in which revision?
| User | Revision | Line number | New contents of line |
|---|---|---|---|
| va009039 | 0:65f1469d6bfb | 1 | /* |
| va009039 | 0:65f1469d6bfb | 2 | # This file is Copyright 2002 Dean Hall. |
| va009039 | 0:65f1469d6bfb | 3 | # This file is part of the PyMite VM. |
| va009039 | 0:65f1469d6bfb | 4 | # This file is licensed under the MIT License. |
| va009039 | 0:65f1469d6bfb | 5 | # See the LICENSE file for details. |
| va009039 | 0:65f1469d6bfb | 6 | */ |
| va009039 | 0:65f1469d6bfb | 7 | |
| va009039 | 0:65f1469d6bfb | 8 | |
| va009039 | 0:65f1469d6bfb | 9 | #undef __FILE_ID__ |
| va009039 | 0:65f1469d6bfb | 10 | #define __FILE_ID__ 0x06 |
| va009039 | 0:65f1469d6bfb | 11 | |
| va009039 | 0:65f1469d6bfb | 12 | |
| va009039 | 0:65f1469d6bfb | 13 | /** |
| va009039 | 0:65f1469d6bfb | 14 | * \file |
| va009039 | 0:65f1469d6bfb | 15 | * \brief VM Heap |
| va009039 | 0:65f1469d6bfb | 16 | * |
| va009039 | 0:65f1469d6bfb | 17 | * VM heap operations. |
| va009039 | 0:65f1469d6bfb | 18 | * All of PyMite's dynamic memory is obtained from this heap. |
| va009039 | 0:65f1469d6bfb | 19 | * The heap provides dynamic memory on demand. |
| va009039 | 0:65f1469d6bfb | 20 | */ |
| va009039 | 0:65f1469d6bfb | 21 | |
| va009039 | 0:65f1469d6bfb | 22 | |
| va009039 | 0:65f1469d6bfb | 23 | #include "pm.h" |
| va009039 | 0:65f1469d6bfb | 24 | |
| va009039 | 0:65f1469d6bfb | 25 | |
| va009039 | 0:65f1469d6bfb | 26 | /** The size of the temporary roots stack */ |
| va009039 | 0:65f1469d6bfb | 27 | #define HEAP_NUM_TEMP_ROOTS 24 |
| va009039 | 0:65f1469d6bfb | 28 | |
| va009039 | 0:65f1469d6bfb | 29 | /** |
| va009039 | 0:65f1469d6bfb | 30 | * The maximum size a live chunk can be (a live chunk is one that is in use). |
| va009039 | 0:65f1469d6bfb | 31 | * The live chunk size is determined by the size field in the *object* |
| va009039 | 0:65f1469d6bfb | 32 | * descriptor. That field is nine bits with two assumed lsbs (zeros): |
| va009039 | 0:65f1469d6bfb | 33 | * (0x1FF << 2) == 2044 |
| va009039 | 0:65f1469d6bfb | 34 | */ |
| va009039 | 0:65f1469d6bfb | 35 | #ifdef PM_PLAT_POINTER_SIZE |
| va009039 | 0:65f1469d6bfb | 36 | #if PM_PLAT_POINTER_SIZE == 8 |
| va009039 | 0:65f1469d6bfb | 37 | #define HEAP_MAX_LIVE_CHUNK_SIZE 2040 |
| va009039 | 0:65f1469d6bfb | 38 | #else |
| va009039 | 0:65f1469d6bfb | 39 | #define HEAP_MAX_LIVE_CHUNK_SIZE 2044 |
| va009039 | 0:65f1469d6bfb | 40 | #endif |
| va009039 | 0:65f1469d6bfb | 41 | #endif |
| va009039 | 0:65f1469d6bfb | 42 | |
| va009039 | 0:65f1469d6bfb | 43 | /** |
| va009039 | 0:65f1469d6bfb | 44 | * The maximum size a free chunk can be (a free chunk is one that is not in use). |
| va009039 | 0:65f1469d6bfb | 45 | * The free chunk size is limited by the size field in the *heap* descriptor. |
| va009039 | 0:65f1469d6bfb | 46 | * That field is fourteen bits with two assumed least significant bits (zeros): |
| va009039 | 0:65f1469d6bfb | 47 | * (0x3FFF << 2) == 65532 |
| va009039 | 0:65f1469d6bfb | 48 | * For 64-bit platforms, the value is 4 bytes less so that a max-sized chunk is |
| va009039 | 0:65f1469d6bfb | 49 | * a multiple of 8, so that max-sized chunks created during heap_init() have a |
| va009039 | 0:65f1469d6bfb | 50 | * good boundary value. |
| va009039 | 0:65f1469d6bfb | 51 | */ |
| va009039 | 0:65f1469d6bfb | 52 | #ifdef PM_PLAT_POINTER_SIZE |
| va009039 | 0:65f1469d6bfb | 53 | #if PM_PLAT_POINTER_SIZE == 8 |
| va009039 | 0:65f1469d6bfb | 54 | #define HEAP_MAX_FREE_CHUNK_SIZE 65528 |
| va009039 | 0:65f1469d6bfb | 55 | #else |
| va009039 | 0:65f1469d6bfb | 56 | #define HEAP_MAX_FREE_CHUNK_SIZE 65532 |
| va009039 | 0:65f1469d6bfb | 57 | #endif |
| va009039 | 0:65f1469d6bfb | 58 | #endif |
| va009039 | 0:65f1469d6bfb | 59 | |
| va009039 | 0:65f1469d6bfb | 60 | /** The minimum size a chunk can be |
| va009039 | 0:65f1469d6bfb | 61 | * (rounded up to a multiple of platform-pointer-size) */ |
| va009039 | 0:65f1469d6bfb | 62 | #ifdef PM_PLAT_POINTER_SIZE |
| va009039 | 0:65f1469d6bfb | 63 | #if PM_PLAT_POINTER_SIZE == 8 |
| va009039 | 0:65f1469d6bfb | 64 | #define HEAP_MIN_CHUNK_SIZE ((sizeof(PmHeapDesc_t) + 7) & ~7) |
| va009039 | 0:65f1469d6bfb | 65 | #else |
| va009039 | 0:65f1469d6bfb | 66 | #define HEAP_MIN_CHUNK_SIZE ((sizeof(PmHeapDesc_t) + 3) & ~3) |
| va009039 | 0:65f1469d6bfb | 67 | #endif |
| va009039 | 0:65f1469d6bfb | 68 | #endif |
| va009039 | 0:65f1469d6bfb | 69 | |
| va009039 | 0:65f1469d6bfb | 70 | |
| va009039 | 0:65f1469d6bfb | 71 | |
| va009039 | 0:65f1469d6bfb | 72 | /** |
| va009039 | 0:65f1469d6bfb | 73 | * Gets the GC's mark bit for the object. |
| va009039 | 0:65f1469d6bfb | 74 | * This MUST NOT be called on objects that are free. |
| va009039 | 0:65f1469d6bfb | 75 | */ |
| va009039 | 0:65f1469d6bfb | 76 | #define OBJ_GET_GCVAL(pobj) (((pPmObj_t)pobj)->od & OD_MARK_MASK) |
| va009039 | 0:65f1469d6bfb | 77 | |
| va009039 | 0:65f1469d6bfb | 78 | /** |
| va009039 | 0:65f1469d6bfb | 79 | * Sets the GC's mark bit for the object |
| va009039 | 0:65f1469d6bfb | 80 | * This MUST NOT be called on objects that are free. |
| va009039 | 0:65f1469d6bfb | 81 | */ |
| va009039 | 0:65f1469d6bfb | 82 | #ifdef HAVE_GC |
| va009039 | 0:65f1469d6bfb | 83 | #define OBJ_SET_GCVAL(pobj, gcval) \ |
| va009039 | 0:65f1469d6bfb | 84 | do \ |
| va009039 | 0:65f1469d6bfb | 85 | { \ |
| va009039 | 0:65f1469d6bfb | 86 | ((pPmObj_t)pobj)->od = (gcval) ? ((pPmObj_t)pobj)->od | OD_MARK_MASK \ |
| va009039 | 0:65f1469d6bfb | 87 | : ((pPmObj_t)pobj)->od & ~OD_MARK_MASK;\ |
| va009039 | 0:65f1469d6bfb | 88 | } \ |
| va009039 | 0:65f1469d6bfb | 89 | while (0) |
| va009039 | 0:65f1469d6bfb | 90 | #else |
| va009039 | 0:65f1469d6bfb | 91 | #define OBJ_SET_GCVAL(pobj, gcval) |
| va009039 | 0:65f1469d6bfb | 92 | #endif /* HAVE_GC */ |
| va009039 | 0:65f1469d6bfb | 93 | |
| va009039 | 0:65f1469d6bfb | 94 | #define CHUNK_GET_SIZE(pchunk) (((pPmHeapDesc_t)pchunk)->hd & HD_SIZE_MASK) |
| va009039 | 0:65f1469d6bfb | 95 | |
| va009039 | 0:65f1469d6bfb | 96 | /** Sets the size of the chunk in bytes. */ |
| va009039 | 0:65f1469d6bfb | 97 | #define CHUNK_SET_SIZE(pchunk, size) \ |
| va009039 | 0:65f1469d6bfb | 98 | do \ |
| va009039 | 0:65f1469d6bfb | 99 | { \ |
| va009039 | 0:65f1469d6bfb | 100 | ((pPmHeapDesc_t)(pchunk))->hd &= ~HD_SIZE_MASK; \ |
| va009039 | 0:65f1469d6bfb | 101 | ((pPmHeapDesc_t)(pchunk))->hd |= ((size) & HD_SIZE_MASK); \ |
| va009039 | 0:65f1469d6bfb | 102 | } \ |
| va009039 | 0:65f1469d6bfb | 103 | while (0) |
| va009039 | 0:65f1469d6bfb | 104 | |
| va009039 | 0:65f1469d6bfb | 105 | #define OBJ_SET_SIZE(pobj, size) \ |
| va009039 | 0:65f1469d6bfb | 106 | do \ |
| va009039 | 0:65f1469d6bfb | 107 | { \ |
| va009039 | 0:65f1469d6bfb | 108 | ((pPmObj_t)pobj)->od &= ~OD_SIZE_MASK; \ |
| va009039 | 0:65f1469d6bfb | 109 | ((pPmObj_t)pobj)->od |= ((size) & OD_SIZE_MASK); \ |
| va009039 | 0:65f1469d6bfb | 110 | } \ |
| va009039 | 0:65f1469d6bfb | 111 | while (0) |
| va009039 | 0:65f1469d6bfb | 112 | |
| va009039 | 0:65f1469d6bfb | 113 | |
| va009039 | 0:65f1469d6bfb | 114 | /** |
| va009039 | 0:65f1469d6bfb | 115 | * The following is a diagram of the heap descriptor at the head of the chunk: |
| va009039 | 0:65f1469d6bfb | 116 | * @verbatim |
| va009039 | 0:65f1469d6bfb | 117 | * MSb LSb |
| va009039 | 0:65f1469d6bfb | 118 | * 7 6 5 4 3 2 1 0 |
| va009039 | 0:65f1469d6bfb | 119 | * pchunk-> +-+-+-+-+-+-+-+-+ S := Size of the chunk (2 LSbs dropped) |
| va009039 | 0:65f1469d6bfb | 120 | * | S |F|R| F := Chunk free bit (not in use) |
| va009039 | 0:65f1469d6bfb | 121 | * +-----------+-+-+ R := Bit reserved for future use |
| va009039 | 0:65f1469d6bfb | 122 | * | S | |
| va009039 | 0:65f1469d6bfb | 123 | * +---------------+ |
| va009039 | 0:65f1469d6bfb | 124 | * | P(L) | P := hd_prev: Pointer to previous node |
| va009039 | 0:65f1469d6bfb | 125 | * | P(H) | N := hd_next: Pointer to next node |
| va009039 | 0:65f1469d6bfb | 126 | * | N(L) | |
| va009039 | 0:65f1469d6bfb | 127 | * | N(H) | |
| va009039 | 0:65f1469d6bfb | 128 | * +---------------+ |
| va009039 | 0:65f1469d6bfb | 129 | * | unused space | |
| va009039 | 0:65f1469d6bfb | 130 | * ... ... |
| va009039 | 0:65f1469d6bfb | 131 | * | end chunk | |
| va009039 | 0:65f1469d6bfb | 132 | * +---------------+ |
| va009039 | 0:65f1469d6bfb | 133 | * @endverbatim |
| va009039 | 0:65f1469d6bfb | 134 | * |
| va009039 | 0:65f1469d6bfb | 135 | * On an 8-bit MCU with 16-bit addresses, the theoretical minimum size of the |
| va009039 | 0:65f1469d6bfb | 136 | * heap descriptor is 6 bytes. The effective size (due to pointer alignment) |
| va009039 | 0:65f1469d6bfb | 137 | * is usually 8 bytes. On an MCU with 32-bit addresses, the heap descriptor's |
| va009039 | 0:65f1469d6bfb | 138 | * size is 12 bytes. |
| va009039 | 0:65f1469d6bfb | 139 | */ |
| va009039 | 0:65f1469d6bfb | 140 | typedef struct PmHeapDesc_s |
| va009039 | 0:65f1469d6bfb | 141 | { |
| va009039 | 0:65f1469d6bfb | 142 | /** Heap descriptor */ |
| va009039 | 0:65f1469d6bfb | 143 | uint16_t hd; |
| va009039 | 0:65f1469d6bfb | 144 | |
| va009039 | 0:65f1469d6bfb | 145 | /** Ptr to prev heap chunk */ |
| va009039 | 0:65f1469d6bfb | 146 | struct PmHeapDesc_s *prev; |
| va009039 | 0:65f1469d6bfb | 147 | |
| va009039 | 0:65f1469d6bfb | 148 | /** Ptr to next heap chunk */ |
| va009039 | 0:65f1469d6bfb | 149 | struct PmHeapDesc_s *next; |
| va009039 | 0:65f1469d6bfb | 150 | } PmHeapDesc_t, |
| va009039 | 0:65f1469d6bfb | 151 | *pPmHeapDesc_t; |
| va009039 | 0:65f1469d6bfb | 152 | |
| va009039 | 0:65f1469d6bfb | 153 | typedef struct PmHeap_s |
| va009039 | 0:65f1469d6bfb | 154 | { |
| va009039 | 0:65f1469d6bfb | 155 | /** Pointer to base of heap. Set at initialization of VM */ |
| va009039 | 0:65f1469d6bfb | 156 | uint8_t *base; |
| va009039 | 0:65f1469d6bfb | 157 | |
| va009039 | 0:65f1469d6bfb | 158 | /** Size of the heap. Set at initialization of VM */ |
| va009039 | 0:65f1469d6bfb | 159 | uint32_t size; |
| va009039 | 0:65f1469d6bfb | 160 | |
| va009039 | 0:65f1469d6bfb | 161 | /** Ptr to list of free chunks; sorted smallest to largest. */ |
| va009039 | 0:65f1469d6bfb | 162 | pPmHeapDesc_t pfreelist; |
| va009039 | 0:65f1469d6bfb | 163 | |
| va009039 | 0:65f1469d6bfb | 164 | /** The amount of heap space available in free list */ |
| va009039 | 0:65f1469d6bfb | 165 | uint32_t avail; |
| va009039 | 0:65f1469d6bfb | 166 | |
| va009039 | 0:65f1469d6bfb | 167 | #ifdef HAVE_GC |
| va009039 | 0:65f1469d6bfb | 168 | /** Garbage collection mark value */ |
| va009039 | 0:65f1469d6bfb | 169 | uint8_t gcval; |
| va009039 | 0:65f1469d6bfb | 170 | |
| va009039 | 0:65f1469d6bfb | 171 | /** Boolean to indicate if GC should run automatically */ |
| va009039 | 0:65f1469d6bfb | 172 | uint8_t auto_gc; |
| va009039 | 0:65f1469d6bfb | 173 | |
| va009039 | 0:65f1469d6bfb | 174 | /* #239: Fix GC when 2+ unlinked allocs occur */ |
| va009039 | 0:65f1469d6bfb | 175 | /** Stack of objects to be held as temporary roots */ |
| va009039 | 0:65f1469d6bfb | 176 | pPmObj_t temp_roots[HEAP_NUM_TEMP_ROOTS]; |
| va009039 | 0:65f1469d6bfb | 177 | |
| va009039 | 0:65f1469d6bfb | 178 | uint8_t temp_root_index; |
| va009039 | 0:65f1469d6bfb | 179 | #endif /* HAVE_GC */ |
| va009039 | 0:65f1469d6bfb | 180 | |
| va009039 | 0:65f1469d6bfb | 181 | } PmHeap_t, |
| va009039 | 0:65f1469d6bfb | 182 | *pPmHeap_t; |
| va009039 | 0:65f1469d6bfb | 183 | |
| va009039 | 0:65f1469d6bfb | 184 | |
| va009039 | 0:65f1469d6bfb | 185 | /** The PyMite heap */ |
| va009039 | 0:65f1469d6bfb | 186 | static PmHeap_t pmHeap PM_PLAT_HEAP_ATTR; |
| va009039 | 0:65f1469d6bfb | 187 | |
| va009039 | 0:65f1469d6bfb | 188 | |
| va009039 | 0:65f1469d6bfb | 189 | #if 0 |
| va009039 | 0:65f1469d6bfb | 190 | static void |
| va009039 | 0:65f1469d6bfb | 191 | heap_gcPrintFreelist(void) |
| va009039 | 0:65f1469d6bfb | 192 | { |
| va009039 | 0:65f1469d6bfb | 193 | pPmHeapDesc_t pchunk = pmHeap.pfreelist; |
| va009039 | 0:65f1469d6bfb | 194 | |
| va009039 | 0:65f1469d6bfb | 195 | printf("DEBUG: pmHeap.avail = %d\n", pmHeap.avail); |
| va009039 | 0:65f1469d6bfb | 196 | printf("DEBUG: freelist:\n"); |
| va009039 | 0:65f1469d6bfb | 197 | while (pchunk != C_NULL) |
| va009039 | 0:65f1469d6bfb | 198 | { |
| va009039 | 0:65f1469d6bfb | 199 | printf("DEBUG: free chunk (%d bytes) @ 0x%0x\n", |
| va009039 | 0:65f1469d6bfb | 200 | CHUNK_GET_SIZE(pchunk), (int)pchunk); |
| va009039 | 0:65f1469d6bfb | 201 | pchunk = pchunk->next; |
| va009039 | 0:65f1469d6bfb | 202 | } |
| va009039 | 0:65f1469d6bfb | 203 | } |
| va009039 | 0:65f1469d6bfb | 204 | #endif |
| va009039 | 0:65f1469d6bfb | 205 | |
| va009039 | 0:65f1469d6bfb | 206 | |
| va009039 | 0:65f1469d6bfb | 207 | #if 0 |
| va009039 | 0:65f1469d6bfb | 208 | /** DEBUG: dumps the heap and roots list to a file */ |
| va009039 | 0:65f1469d6bfb | 209 | static void |
| va009039 | 0:65f1469d6bfb | 210 | heap_dump(void) |
| va009039 | 0:65f1469d6bfb | 211 | { |
| va009039 | 0:65f1469d6bfb | 212 | static int n = 0; |
| va009039 | 0:65f1469d6bfb | 213 | uint16_t s; |
| va009039 | 0:65f1469d6bfb | 214 | uint32_t i; |
| va009039 | 0:65f1469d6bfb | 215 | char filename[17] = "pmheapdump0N.bin\0"; |
| va009039 | 0:65f1469d6bfb | 216 | FILE *fp; |
| va009039 | 0:65f1469d6bfb | 217 | |
| va009039 | 0:65f1469d6bfb | 218 | filename[11] = '0' + n++; |
| va009039 | 0:65f1469d6bfb | 219 | fp = fopen(filename, "wb"); |
| va009039 | 0:65f1469d6bfb | 220 | |
| va009039 | 0:65f1469d6bfb | 221 | /* magic : PMDUMP for little endian or PMUDMP for big endian */ |
| va009039 | 0:65f1469d6bfb | 222 | fwrite(&"PM", 1, 2, fp); |
| va009039 | 0:65f1469d6bfb | 223 | s = 0x5544; |
| va009039 | 0:65f1469d6bfb | 224 | fwrite(&s, sizeof(uint16_t), 1, fp); |
| va009039 | 0:65f1469d6bfb | 225 | fwrite(&"MP", 1, 2, fp); |
| va009039 | 0:65f1469d6bfb | 226 | |
| va009039 | 0:65f1469d6bfb | 227 | /* pointer size */ |
| va009039 | 0:65f1469d6bfb | 228 | s = sizeof(intptr_t); |
| va009039 | 0:65f1469d6bfb | 229 | fwrite(&s, sizeof(uint16_t), 1, fp); |
| va009039 | 0:65f1469d6bfb | 230 | |
| va009039 | 0:65f1469d6bfb | 231 | /* dump version */ |
| va009039 | 0:65f1469d6bfb | 232 | s = 1; |
| va009039 | 0:65f1469d6bfb | 233 | fwrite(&s, sizeof(uint16_t), 1, fp); |
| va009039 | 0:65f1469d6bfb | 234 | |
| va009039 | 0:65f1469d6bfb | 235 | /* pmfeatures */ |
| va009039 | 0:65f1469d6bfb | 236 | s = 0; |
| va009039 | 0:65f1469d6bfb | 237 | #ifdef USE_STRING_CACHE |
| va009039 | 0:65f1469d6bfb | 238 | s |= 1<<0; |
| va009039 | 0:65f1469d6bfb | 239 | #endif |
| va009039 | 0:65f1469d6bfb | 240 | #ifdef HAVE_DEFAULTARGS |
| va009039 | 0:65f1469d6bfb | 241 | s |= 1<<1; |
| va009039 | 0:65f1469d6bfb | 242 | #endif |
| va009039 | 0:65f1469d6bfb | 243 | #ifdef HAVE_CLOSURES |
| va009039 | 0:65f1469d6bfb | 244 | s |= 1<<2; |
| va009039 | 0:65f1469d6bfb | 245 | #endif |
| va009039 | 0:65f1469d6bfb | 246 | #ifdef HAVE_CLASSES |
| va009039 | 0:65f1469d6bfb | 247 | s |= 1<<3; |
| va009039 | 0:65f1469d6bfb | 248 | #endif |
| va009039 | 0:65f1469d6bfb | 249 | fwrite(&s, sizeof(uint16_t), 1, fp); |
| va009039 | 0:65f1469d6bfb | 250 | |
| va009039 | 0:65f1469d6bfb | 251 | /* Size of heap */ |
| va009039 | 0:65f1469d6bfb | 252 | fwrite(&pmHeap.size, sizeof(uint32_t), 1, fp); |
| va009039 | 0:65f1469d6bfb | 253 | |
| va009039 | 0:65f1469d6bfb | 254 | /* Write base address of heap */ |
| va009039 | 0:65f1469d6bfb | 255 | fwrite((void*)&pmHeap.base, sizeof(intptr_t), 1, fp); |
| va009039 | 0:65f1469d6bfb | 256 | |
| va009039 | 0:65f1469d6bfb | 257 | /* Write contents of heap */ |
| va009039 | 0:65f1469d6bfb | 258 | fwrite(pmHeap.base, 1, pmHeap.size, fp); |
| va009039 | 0:65f1469d6bfb | 259 | |
| va009039 | 0:65f1469d6bfb | 260 | /* Write num roots*/ |
| va009039 | 0:65f1469d6bfb | 261 | i = 10; |
| va009039 | 0:65f1469d6bfb | 262 | fwrite(&i, sizeof(uint32_t), 1, fp); |
| va009039 | 0:65f1469d6bfb | 263 | |
| va009039 | 0:65f1469d6bfb | 264 | /* Write heap root ptrs */ |
| va009039 | 0:65f1469d6bfb | 265 | fwrite((void *)&gVmGlobal.pnone, sizeof(intptr_t), 1, fp); |
| va009039 | 0:65f1469d6bfb | 266 | fwrite((void *)&gVmGlobal.pfalse, sizeof(intptr_t), 1, fp); |
| va009039 | 0:65f1469d6bfb | 267 | fwrite((void *)&gVmGlobal.ptrue, sizeof(intptr_t), 1, fp); |
| va009039 | 0:65f1469d6bfb | 268 | fwrite((void *)&gVmGlobal.pzero, sizeof(intptr_t), 1, fp); |
| va009039 | 0:65f1469d6bfb | 269 | fwrite((void *)&gVmGlobal.pone, sizeof(intptr_t), 1, fp); |
| va009039 | 0:65f1469d6bfb | 270 | fwrite((void *)&gVmGlobal.pnegone, sizeof(intptr_t), 1, fp); |
| va009039 | 0:65f1469d6bfb | 271 | fwrite((void *)&gVmGlobal.pcodeStr, sizeof(intptr_t), 1, fp); |
| va009039 | 0:65f1469d6bfb | 272 | fwrite((void *)&gVmGlobal.builtins, sizeof(intptr_t), 1, fp); |
| va009039 | 0:65f1469d6bfb | 273 | fwrite((void *)&gVmGlobal.nativeframe, sizeof(intptr_t), 1, fp); |
| va009039 | 0:65f1469d6bfb | 274 | fwrite((void *)&gVmGlobal.threadList, sizeof(intptr_t), 1, fp); |
| va009039 | 0:65f1469d6bfb | 275 | fclose(fp); |
| va009039 | 0:65f1469d6bfb | 276 | } |
| va009039 | 0:65f1469d6bfb | 277 | #endif |
| va009039 | 0:65f1469d6bfb | 278 | |
| va009039 | 0:65f1469d6bfb | 279 | |
| va009039 | 0:65f1469d6bfb | 280 | /* Removes the given chunk from the free list; leaves list in sorted order */ |
| va009039 | 0:65f1469d6bfb | 281 | static PmReturn_t |
| va009039 | 0:65f1469d6bfb | 282 | heap_unlinkFromFreelist(pPmHeapDesc_t pchunk) |
| va009039 | 0:65f1469d6bfb | 283 | { |
| va009039 | 0:65f1469d6bfb | 284 | C_ASSERT(pchunk != C_NULL); |
| va009039 | 0:65f1469d6bfb | 285 | |
| va009039 | 0:65f1469d6bfb | 286 | pmHeap.avail -= CHUNK_GET_SIZE(pchunk); |
| va009039 | 0:65f1469d6bfb | 287 | |
| va009039 | 0:65f1469d6bfb | 288 | if (pchunk->next != C_NULL) |
| va009039 | 0:65f1469d6bfb | 289 | { |
| va009039 | 0:65f1469d6bfb | 290 | pchunk->next->prev = pchunk->prev; |
| va009039 | 0:65f1469d6bfb | 291 | } |
| va009039 | 0:65f1469d6bfb | 292 | |
| va009039 | 0:65f1469d6bfb | 293 | /* If pchunk was the first chunk in the free list, update the heap ptr */ |
| va009039 | 0:65f1469d6bfb | 294 | if (pchunk->prev == C_NULL) |
| va009039 | 0:65f1469d6bfb | 295 | { |
| va009039 | 0:65f1469d6bfb | 296 | pmHeap.pfreelist = pchunk->next; |
| va009039 | 0:65f1469d6bfb | 297 | } |
| va009039 | 0:65f1469d6bfb | 298 | else |
| va009039 | 0:65f1469d6bfb | 299 | { |
| va009039 | 0:65f1469d6bfb | 300 | pchunk->prev->next = pchunk->next; |
| va009039 | 0:65f1469d6bfb | 301 | } |
| va009039 | 0:65f1469d6bfb | 302 | |
| va009039 | 0:65f1469d6bfb | 303 | return PM_RET_OK; |
| va009039 | 0:65f1469d6bfb | 304 | } |
| va009039 | 0:65f1469d6bfb | 305 | |
| va009039 | 0:65f1469d6bfb | 306 | |
| va009039 | 0:65f1469d6bfb | 307 | /* Inserts in order a chunk into the free list. Caller adjusts heap state */ |
| va009039 | 0:65f1469d6bfb | 308 | static PmReturn_t |
| va009039 | 0:65f1469d6bfb | 309 | heap_linkToFreelist(pPmHeapDesc_t pchunk) |
| va009039 | 0:65f1469d6bfb | 310 | { |
| va009039 | 0:65f1469d6bfb | 311 | uint16_t size; |
| va009039 | 0:65f1469d6bfb | 312 | pPmHeapDesc_t pscan; |
| va009039 | 0:65f1469d6bfb | 313 | |
| va009039 | 0:65f1469d6bfb | 314 | /* Ensure the object is already free */ |
| va009039 | 0:65f1469d6bfb | 315 | C_ASSERT(OBJ_GET_FREE(pchunk) != 0); |
| va009039 | 0:65f1469d6bfb | 316 | |
| va009039 | 0:65f1469d6bfb | 317 | pmHeap.avail += CHUNK_GET_SIZE(pchunk); |
| va009039 | 0:65f1469d6bfb | 318 | |
| va009039 | 0:65f1469d6bfb | 319 | /* If free list is empty, add to head of list */ |
| va009039 | 0:65f1469d6bfb | 320 | if (pmHeap.pfreelist == C_NULL) |
| va009039 | 0:65f1469d6bfb | 321 | { |
| va009039 | 0:65f1469d6bfb | 322 | pmHeap.pfreelist = pchunk; |
| va009039 | 0:65f1469d6bfb | 323 | pchunk->next = C_NULL; |
| va009039 | 0:65f1469d6bfb | 324 | pchunk->prev = C_NULL; |
| va009039 | 0:65f1469d6bfb | 325 | |
| va009039 | 0:65f1469d6bfb | 326 | return PM_RET_OK; |
| va009039 | 0:65f1469d6bfb | 327 | } |
| va009039 | 0:65f1469d6bfb | 328 | |
| va009039 | 0:65f1469d6bfb | 329 | /* Scan free list for insertion point */ |
| va009039 | 0:65f1469d6bfb | 330 | pscan = pmHeap.pfreelist; |
| va009039 | 0:65f1469d6bfb | 331 | size = CHUNK_GET_SIZE(pchunk); |
| va009039 | 0:65f1469d6bfb | 332 | while ((CHUNK_GET_SIZE(pscan) < size) && (pscan->next != C_NULL)) |
| va009039 | 0:65f1469d6bfb | 333 | { |
| va009039 | 0:65f1469d6bfb | 334 | pscan = pscan->next; |
| va009039 | 0:65f1469d6bfb | 335 | } |
| va009039 | 0:65f1469d6bfb | 336 | |
| va009039 | 0:65f1469d6bfb | 337 | /* |
| va009039 | 0:65f1469d6bfb | 338 | * Insert chunk after the scan chunk (next is NULL). |
| va009039 | 0:65f1469d6bfb | 339 | * This is a slightly rare case where the last chunk in the free list |
| va009039 | 0:65f1469d6bfb | 340 | * is smaller than the chunk being freed. |
| va009039 | 0:65f1469d6bfb | 341 | */ |
| va009039 | 0:65f1469d6bfb | 342 | if (size > CHUNK_GET_SIZE(pscan)) |
| va009039 | 0:65f1469d6bfb | 343 | { |
| va009039 | 0:65f1469d6bfb | 344 | pchunk->next = pscan->next; |
| va009039 | 0:65f1469d6bfb | 345 | pscan->next = pchunk; |
| va009039 | 0:65f1469d6bfb | 346 | pchunk->prev = pscan; |
| va009039 | 0:65f1469d6bfb | 347 | } |
| va009039 | 0:65f1469d6bfb | 348 | |
| va009039 | 0:65f1469d6bfb | 349 | /* Insert chunk before the scan chunk */ |
| va009039 | 0:65f1469d6bfb | 350 | else |
| va009039 | 0:65f1469d6bfb | 351 | { |
| va009039 | 0:65f1469d6bfb | 352 | pchunk->next = pscan; |
| va009039 | 0:65f1469d6bfb | 353 | pchunk->prev = pscan->prev; |
| va009039 | 0:65f1469d6bfb | 354 | |
| va009039 | 0:65f1469d6bfb | 355 | /* If chunk will be first item in free list */ |
| va009039 | 0:65f1469d6bfb | 356 | if (pscan->prev == C_NULL) |
| va009039 | 0:65f1469d6bfb | 357 | { |
| va009039 | 0:65f1469d6bfb | 358 | pmHeap.pfreelist = pchunk; |
| va009039 | 0:65f1469d6bfb | 359 | } |
| va009039 | 0:65f1469d6bfb | 360 | else |
| va009039 | 0:65f1469d6bfb | 361 | { |
| va009039 | 0:65f1469d6bfb | 362 | pscan->prev->next = pchunk; |
| va009039 | 0:65f1469d6bfb | 363 | } |
| va009039 | 0:65f1469d6bfb | 364 | pscan->prev = pchunk; |
| va009039 | 0:65f1469d6bfb | 365 | } |
| va009039 | 0:65f1469d6bfb | 366 | |
| va009039 | 0:65f1469d6bfb | 367 | return PM_RET_OK; |
| va009039 | 0:65f1469d6bfb | 368 | } |
| va009039 | 0:65f1469d6bfb | 369 | |
| va009039 | 0:65f1469d6bfb | 370 | |
| va009039 | 0:65f1469d6bfb | 371 | PmReturn_t |
| va009039 | 0:65f1469d6bfb | 372 | heap_init(uint8_t *base, uint32_t size) |
| va009039 | 0:65f1469d6bfb | 373 | { |
| va009039 | 0:65f1469d6bfb | 374 | pPmHeapDesc_t pchunk; |
| va009039 | 0:65f1469d6bfb | 375 | uint32_t hs; |
| va009039 | 0:65f1469d6bfb | 376 | uint8_t *adjbase; |
| va009039 | 0:65f1469d6bfb | 377 | |
| va009039 | 0:65f1469d6bfb | 378 | /* Round-up Heap base by the size of the platform pointer */ |
| va009039 | 0:65f1469d6bfb | 379 | adjbase = base + ((sizeof(intptr_t) - 1) & ~(sizeof(intptr_t) - 1)); |
| va009039 | 0:65f1469d6bfb | 380 | pmHeap.base = adjbase; |
| va009039 | 0:65f1469d6bfb | 381 | pmHeap.size = size - (adjbase - base); |
| va009039 | 0:65f1469d6bfb | 382 | |
| va009039 | 0:65f1469d6bfb | 383 | #if __DEBUG__ |
| va009039 | 0:65f1469d6bfb | 384 | /* Fill the heap with a non-NULL value to bring out any heap bugs. */ |
| va009039 | 0:65f1469d6bfb | 385 | sli_memset(pmHeap.base, 0xAA, pmHeap.size); |
| va009039 | 0:65f1469d6bfb | 386 | #endif |
| va009039 | 0:65f1469d6bfb | 387 | |
| va009039 | 0:65f1469d6bfb | 388 | /* Init heap globals */ |
| va009039 | 0:65f1469d6bfb | 389 | pmHeap.pfreelist = C_NULL; |
| va009039 | 0:65f1469d6bfb | 390 | pmHeap.avail = 0; |
| va009039 | 0:65f1469d6bfb | 391 | #ifdef HAVE_GC |
| va009039 | 0:65f1469d6bfb | 392 | pmHeap.gcval = (uint8_t)0; |
| va009039 | 0:65f1469d6bfb | 393 | pmHeap.temp_root_index = (uint8_t)0; |
| va009039 | 0:65f1469d6bfb | 394 | heap_gcSetAuto(C_TRUE); |
| va009039 | 0:65f1469d6bfb | 395 | #endif /* HAVE_GC */ |
| va009039 | 0:65f1469d6bfb | 396 | |
| va009039 | 0:65f1469d6bfb | 397 | pchunk = (pPmHeapDesc_t)pmHeap.base; |
| va009039 | 0:65f1469d6bfb | 398 | hs = pmHeap.size; |
| va009039 | 0:65f1469d6bfb | 399 | |
| va009039 | 0:65f1469d6bfb | 400 | /* #180 Proactively link memory previously lost/neglected at tail of heap */ |
| va009039 | 0:65f1469d6bfb | 401 | if ((hs % HEAP_MAX_FREE_CHUNK_SIZE) < HEAP_MIN_CHUNK_SIZE) |
| va009039 | 0:65f1469d6bfb | 402 | { |
| va009039 | 0:65f1469d6bfb | 403 | OBJ_SET_FREE(pchunk, 1); |
| va009039 | 0:65f1469d6bfb | 404 | CHUNK_SET_SIZE(pchunk, HEAP_MIN_CHUNK_SIZE); |
| va009039 | 0:65f1469d6bfb | 405 | heap_linkToFreelist(pchunk); |
| va009039 | 0:65f1469d6bfb | 406 | hs -= HEAP_MIN_CHUNK_SIZE; |
| va009039 | 0:65f1469d6bfb | 407 | pchunk = (pPmHeapDesc_t)((uint8_t *)pchunk + HEAP_MIN_CHUNK_SIZE); |
| va009039 | 0:65f1469d6bfb | 408 | } |
| va009039 | 0:65f1469d6bfb | 409 | |
| va009039 | 0:65f1469d6bfb | 410 | /* Create as many max-sized chunks as possible in the freelist */ |
| va009039 | 0:65f1469d6bfb | 411 | for (; |
| va009039 | 0:65f1469d6bfb | 412 | hs >= HEAP_MAX_FREE_CHUNK_SIZE; hs -= HEAP_MAX_FREE_CHUNK_SIZE) |
| va009039 | 0:65f1469d6bfb | 413 | { |
| va009039 | 0:65f1469d6bfb | 414 | OBJ_SET_FREE(pchunk, 1); |
| va009039 | 0:65f1469d6bfb | 415 | CHUNK_SET_SIZE(pchunk, HEAP_MAX_FREE_CHUNK_SIZE); |
| va009039 | 0:65f1469d6bfb | 416 | heap_linkToFreelist(pchunk); |
| va009039 | 0:65f1469d6bfb | 417 | pchunk = (pPmHeapDesc_t)((uint8_t *)pchunk + HEAP_MAX_FREE_CHUNK_SIZE); |
| va009039 | 0:65f1469d6bfb | 418 | } |
| va009039 | 0:65f1469d6bfb | 419 | |
| va009039 | 0:65f1469d6bfb | 420 | /* Add any leftover memory to the freelist */ |
| va009039 | 0:65f1469d6bfb | 421 | if (hs >= HEAP_MIN_CHUNK_SIZE) |
| va009039 | 0:65f1469d6bfb | 422 | { |
| va009039 | 0:65f1469d6bfb | 423 | /* Round down to a multiple of four */ |
| va009039 | 0:65f1469d6bfb | 424 | hs = hs & ~3; |
| va009039 | 0:65f1469d6bfb | 425 | OBJ_SET_FREE(pchunk, 1); |
| va009039 | 0:65f1469d6bfb | 426 | CHUNK_SET_SIZE(pchunk, hs); |
| va009039 | 0:65f1469d6bfb | 427 | heap_linkToFreelist(pchunk); |
| va009039 | 0:65f1469d6bfb | 428 | } |
| va009039 | 0:65f1469d6bfb | 429 | |
| va009039 | 0:65f1469d6bfb | 430 | C_DEBUG_PRINT(VERBOSITY_LOW, "heap_init(), id=%p, s=%u\n", |
| va009039 | 0:65f1469d6bfb | 431 | pmHeap.base, (unsigned int)pmHeap.avail); |
| va009039 | 0:65f1469d6bfb | 432 | |
| va009039 | 0:65f1469d6bfb | 433 | #if USE_STRING_CACHE |
| va009039 | 0:65f1469d6bfb | 434 | string_cacheInit(); |
| va009039 | 0:65f1469d6bfb | 435 | #endif |
| va009039 | 0:65f1469d6bfb | 436 | |
| va009039 | 0:65f1469d6bfb | 437 | return PM_RET_OK; |
| va009039 | 0:65f1469d6bfb | 438 | } |
| va009039 | 0:65f1469d6bfb | 439 | |
| va009039 | 0:65f1469d6bfb | 440 | |
| va009039 | 0:65f1469d6bfb | 441 | /** |
| va009039 | 0:65f1469d6bfb | 442 | * Obtains a chunk of memory from the free list |
| va009039 | 0:65f1469d6bfb | 443 | * |
| va009039 | 0:65f1469d6bfb | 444 | * Performs the Best Fit algorithm. |
| va009039 | 0:65f1469d6bfb | 445 | * Iterates through the freelist to see if a chunk of suitable size exists. |
| va009039 | 0:65f1469d6bfb | 446 | * Shaves a chunk to perfect size iff the remainder is greater than |
| va009039 | 0:65f1469d6bfb | 447 | * the minimum chunk size. |
| va009039 | 0:65f1469d6bfb | 448 | * |
| va009039 | 0:65f1469d6bfb | 449 | * @param size Requested chunk size |
| va009039 | 0:65f1469d6bfb | 450 | * @param r_pchunk Return ptr to chunk |
| va009039 | 0:65f1469d6bfb | 451 | * @return Return status |
| va009039 | 0:65f1469d6bfb | 452 | */ |
| va009039 | 0:65f1469d6bfb | 453 | static PmReturn_t |
| va009039 | 0:65f1469d6bfb | 454 | heap_getChunkImpl(uint16_t size, uint8_t **r_pchunk) |
| va009039 | 0:65f1469d6bfb | 455 | { |
| va009039 | 0:65f1469d6bfb | 456 | PmReturn_t retval; |
| va009039 | 0:65f1469d6bfb | 457 | pPmHeapDesc_t pchunk; |
| va009039 | 0:65f1469d6bfb | 458 | pPmHeapDesc_t premainderChunk; |
| va009039 | 0:65f1469d6bfb | 459 | |
| va009039 | 0:65f1469d6bfb | 460 | C_ASSERT(r_pchunk != C_NULL); |
| va009039 | 0:65f1469d6bfb | 461 | |
| va009039 | 0:65f1469d6bfb | 462 | /* Skip to the first chunk that can hold the requested size */ |
| va009039 | 0:65f1469d6bfb | 463 | pchunk = pmHeap.pfreelist; |
| va009039 | 0:65f1469d6bfb | 464 | while ((pchunk != C_NULL) && (CHUNK_GET_SIZE(pchunk) < size)) |
| va009039 | 0:65f1469d6bfb | 465 | { |
| va009039 | 0:65f1469d6bfb | 466 | pchunk = pchunk->next; |
| va009039 | 0:65f1469d6bfb | 467 | } |
| va009039 | 0:65f1469d6bfb | 468 | |
| va009039 | 0:65f1469d6bfb | 469 | /* No chunk of appropriate size was found, raise OutOfMemory exception */ |
| va009039 | 0:65f1469d6bfb | 470 | if (pchunk == C_NULL) |
| va009039 | 0:65f1469d6bfb | 471 | { |
| va009039 | 0:65f1469d6bfb | 472 | *r_pchunk = C_NULL; |
| va009039 | 0:65f1469d6bfb | 473 | PM_RAISE(retval, PM_RET_EX_MEM); |
| va009039 | 0:65f1469d6bfb | 474 | return retval; |
| va009039 | 0:65f1469d6bfb | 475 | } |
| va009039 | 0:65f1469d6bfb | 476 | |
| va009039 | 0:65f1469d6bfb | 477 | /* Remove the chunk from the free list */ |
| va009039 | 0:65f1469d6bfb | 478 | retval = heap_unlinkFromFreelist(pchunk); |
| va009039 | 0:65f1469d6bfb | 479 | PM_RETURN_IF_ERROR(retval); |
| va009039 | 0:65f1469d6bfb | 480 | |
| va009039 | 0:65f1469d6bfb | 481 | /* Check if a chunk should be carved from what is available */ |
| va009039 | 0:65f1469d6bfb | 482 | if (CHUNK_GET_SIZE(pchunk) - size >= HEAP_MIN_CHUNK_SIZE) |
| va009039 | 0:65f1469d6bfb | 483 | { |
| va009039 | 0:65f1469d6bfb | 484 | /* Create the heap descriptor for the remainder chunk */ |
| va009039 | 0:65f1469d6bfb | 485 | premainderChunk = (pPmHeapDesc_t)((uint8_t *)pchunk + size); |
| va009039 | 0:65f1469d6bfb | 486 | OBJ_SET_FREE(premainderChunk, 1); |
| va009039 | 0:65f1469d6bfb | 487 | CHUNK_SET_SIZE(premainderChunk, CHUNK_GET_SIZE(pchunk) - size); |
| va009039 | 0:65f1469d6bfb | 488 | |
| va009039 | 0:65f1469d6bfb | 489 | /* Put the remainder chunk back in the free list */ |
| va009039 | 0:65f1469d6bfb | 490 | retval = heap_linkToFreelist(premainderChunk); |
| va009039 | 0:65f1469d6bfb | 491 | PM_RETURN_IF_ERROR(retval); |
| va009039 | 0:65f1469d6bfb | 492 | |
| va009039 | 0:65f1469d6bfb | 493 | /* Convert the chunk from a heap descriptor to an object descriptor */ |
| va009039 | 0:65f1469d6bfb | 494 | OBJ_SET_SIZE(pchunk, 0); |
| va009039 | 0:65f1469d6bfb | 495 | OBJ_SET_FREE(pchunk, 0); |
| va009039 | 0:65f1469d6bfb | 496 | OBJ_SET_SIZE(pchunk, size); |
| va009039 | 0:65f1469d6bfb | 497 | |
| va009039 | 0:65f1469d6bfb | 498 | C_DEBUG_PRINT(VERBOSITY_HIGH, |
| va009039 | 0:65f1469d6bfb | 499 | "heap_getChunkImpl()carved, id=%p, s=%d\n", pchunk, |
| va009039 | 0:65f1469d6bfb | 500 | size); |
| va009039 | 0:65f1469d6bfb | 501 | } |
| va009039 | 0:65f1469d6bfb | 502 | else |
| va009039 | 0:65f1469d6bfb | 503 | { |
| va009039 | 0:65f1469d6bfb | 504 | /* Set chunk's type to none (overwrites size field's high byte) */ |
| va009039 | 0:65f1469d6bfb | 505 | OBJ_SET_TYPE((pPmObj_t)pchunk, OBJ_TYPE_NON); |
| va009039 | 0:65f1469d6bfb | 506 | OBJ_SET_FREE(pchunk, 0); |
| va009039 | 0:65f1469d6bfb | 507 | |
| va009039 | 0:65f1469d6bfb | 508 | C_DEBUG_PRINT(VERBOSITY_HIGH, |
| va009039 | 0:65f1469d6bfb | 509 | "heap_getChunkImpl()exact, id=%p, s=%d\n", pchunk, |
| va009039 | 0:65f1469d6bfb | 510 | PM_OBJ_GET_SIZE(pchunk)); |
| va009039 | 0:65f1469d6bfb | 511 | } |
| va009039 | 0:65f1469d6bfb | 512 | |
| va009039 | 0:65f1469d6bfb | 513 | /* |
| va009039 | 0:65f1469d6bfb | 514 | * Set the chunk's GC mark so it will be collected during the next GC cycle |
| va009039 | 0:65f1469d6bfb | 515 | * if it is not reachable |
| va009039 | 0:65f1469d6bfb | 516 | */ |
| va009039 | 0:65f1469d6bfb | 517 | OBJ_SET_GCVAL(pchunk, pmHeap.gcval); |
| va009039 | 0:65f1469d6bfb | 518 | |
| va009039 | 0:65f1469d6bfb | 519 | /* Return the chunk */ |
| va009039 | 0:65f1469d6bfb | 520 | *r_pchunk = (uint8_t *)pchunk; |
| va009039 | 0:65f1469d6bfb | 521 | |
| va009039 | 0:65f1469d6bfb | 522 | return retval; |
| va009039 | 0:65f1469d6bfb | 523 | } |
| va009039 | 0:65f1469d6bfb | 524 | |
| va009039 | 0:65f1469d6bfb | 525 | |
| va009039 | 0:65f1469d6bfb | 526 | /* |
| va009039 | 0:65f1469d6bfb | 527 | * Allocates chunk of memory. |
| va009039 | 0:65f1469d6bfb | 528 | * Filters out invalid sizes. |
| va009039 | 0:65f1469d6bfb | 529 | * Rounds the size up to the next multiple of the platform pointer size. |
| va009039 | 0:65f1469d6bfb | 530 | * Obtains a chunk of at least the desired size. |
| va009039 | 0:65f1469d6bfb | 531 | */ |
| va009039 | 0:65f1469d6bfb | 532 | PmReturn_t |
| va009039 | 0:65f1469d6bfb | 533 | heap_getChunk(uint16_t requestedsize, uint8_t **r_pchunk) |
| va009039 | 0:65f1469d6bfb | 534 | { |
| va009039 | 0:65f1469d6bfb | 535 | PmReturn_t retval; |
| va009039 | 0:65f1469d6bfb | 536 | uint16_t adjustedsize; |
| va009039 | 0:65f1469d6bfb | 537 | |
| va009039 | 0:65f1469d6bfb | 538 | /* Ensure size request is valid */ |
| va009039 | 0:65f1469d6bfb | 539 | if (requestedsize > HEAP_MAX_LIVE_CHUNK_SIZE) |
| va009039 | 0:65f1469d6bfb | 540 | { |
| va009039 | 0:65f1469d6bfb | 541 | PM_RAISE(retval, PM_RET_EX_MEM); |
| va009039 | 0:65f1469d6bfb | 542 | return retval; |
| va009039 | 0:65f1469d6bfb | 543 | } |
| va009039 | 0:65f1469d6bfb | 544 | |
| va009039 | 0:65f1469d6bfb | 545 | else if (requestedsize < HEAP_MIN_CHUNK_SIZE) |
| va009039 | 0:65f1469d6bfb | 546 | { |
| va009039 | 0:65f1469d6bfb | 547 | requestedsize = HEAP_MIN_CHUNK_SIZE; |
| va009039 | 0:65f1469d6bfb | 548 | } |
| va009039 | 0:65f1469d6bfb | 549 | |
| va009039 | 0:65f1469d6bfb | 550 | /* |
| va009039 | 0:65f1469d6bfb | 551 | * Round up the size to a multiple of N bytes, |
| va009039 | 0:65f1469d6bfb | 552 | * where N is 8 for 64-bit platforms and 4 for all else. |
| va009039 | 0:65f1469d6bfb | 553 | * This maintains pointer alignment in the heap (required). |
| va009039 | 0:65f1469d6bfb | 554 | */ |
| va009039 | 0:65f1469d6bfb | 555 | #ifdef PM_PLAT_POINTER_SIZE |
| va009039 | 0:65f1469d6bfb | 556 | #if PM_PLAT_POINTER_SIZE == 8 |
| va009039 | 0:65f1469d6bfb | 557 | adjustedsize = ((requestedsize + 7) & ~7); |
| va009039 | 0:65f1469d6bfb | 558 | #else |
| va009039 | 0:65f1469d6bfb | 559 | adjustedsize = ((requestedsize + 3) & ~3); |
| va009039 | 0:65f1469d6bfb | 560 | #endif /* PM_PLAT_POINTER_SIZE */ |
| va009039 | 0:65f1469d6bfb | 561 | #else |
| va009039 | 0:65f1469d6bfb | 562 | adjustedsize = ((requestedsize + 3) & ~3); |
| va009039 | 0:65f1469d6bfb | 563 | #endif /* PM_PLAT_POINTER_SIZE */ |
| va009039 | 0:65f1469d6bfb | 564 | |
| va009039 | 0:65f1469d6bfb | 565 | /* Attempt to get a chunk */ |
| va009039 | 0:65f1469d6bfb | 566 | retval = heap_getChunkImpl(adjustedsize, r_pchunk); |
| va009039 | 0:65f1469d6bfb | 567 | |
| va009039 | 0:65f1469d6bfb | 568 | #ifdef HAVE_GC |
| va009039 | 0:65f1469d6bfb | 569 | /* Perform GC if out of memory, gc is enabled and not in native session */ |
| va009039 | 0:65f1469d6bfb | 570 | if ((retval == PM_RET_EX_MEM) && (pmHeap.auto_gc == C_TRUE) |
| va009039 | 0:65f1469d6bfb | 571 | && (gVmGlobal.nativeframe.nf_active == C_FALSE)) |
| va009039 | 0:65f1469d6bfb | 572 | { |
| va009039 | 0:65f1469d6bfb | 573 | retval = heap_gcRun(); |
| va009039 | 0:65f1469d6bfb | 574 | PM_RETURN_IF_ERROR(retval); |
| va009039 | 0:65f1469d6bfb | 575 | |
| va009039 | 0:65f1469d6bfb | 576 | /* Attempt to get a chunk */ |
| va009039 | 0:65f1469d6bfb | 577 | retval = heap_getChunkImpl(adjustedsize, r_pchunk); |
| va009039 | 0:65f1469d6bfb | 578 | } |
| va009039 | 0:65f1469d6bfb | 579 | #endif /* HAVE_GC */ |
| va009039 | 0:65f1469d6bfb | 580 | |
| va009039 | 0:65f1469d6bfb | 581 | /* Ensure that the pointer is N-byte aligned */ |
| va009039 | 0:65f1469d6bfb | 582 | if (retval == PM_RET_OK) |
| va009039 | 0:65f1469d6bfb | 583 | { |
| va009039 | 0:65f1469d6bfb | 584 | #ifdef PM_PLAT_POINTER_SIZE |
| va009039 | 0:65f1469d6bfb | 585 | #if PM_PLAT_POINTER_SIZE == 8 |
| va009039 | 0:65f1469d6bfb | 586 | C_ASSERT(((intptr_t)*r_pchunk & 7) == 0); |
| va009039 | 0:65f1469d6bfb | 587 | #else |
| va009039 | 0:65f1469d6bfb | 588 | C_ASSERT(((intptr_t)*r_pchunk & 3) == 0); |
| va009039 | 0:65f1469d6bfb | 589 | #endif /* PM_PLAT_POINTER_SIZE */ |
| va009039 | 0:65f1469d6bfb | 590 | #else |
| va009039 | 0:65f1469d6bfb | 591 | C_ASSERT(((intptr_t)*r_pchunk & 3) == 0); |
| va009039 | 0:65f1469d6bfb | 592 | #endif /* PM_PLAT_POINTER_SIZE */ |
| va009039 | 0:65f1469d6bfb | 593 | } |
| va009039 | 0:65f1469d6bfb | 594 | |
| va009039 | 0:65f1469d6bfb | 595 | return retval; |
| va009039 | 0:65f1469d6bfb | 596 | } |
| va009039 | 0:65f1469d6bfb | 597 | |
| va009039 | 0:65f1469d6bfb | 598 | |
| va009039 | 0:65f1469d6bfb | 599 | /* Releases chunk to the free list */ |
| va009039 | 0:65f1469d6bfb | 600 | PmReturn_t |
| va009039 | 0:65f1469d6bfb | 601 | heap_freeChunk(pPmObj_t ptr) |
| va009039 | 0:65f1469d6bfb | 602 | { |
| va009039 | 0:65f1469d6bfb | 603 | PmReturn_t retval; |
| va009039 | 0:65f1469d6bfb | 604 | |
| va009039 | 0:65f1469d6bfb | 605 | C_DEBUG_PRINT(VERBOSITY_HIGH, "heap_freeChunk(), id=%p, s=%d\n", |
| va009039 | 0:65f1469d6bfb | 606 | ptr, PM_OBJ_GET_SIZE(ptr)); |
| va009039 | 0:65f1469d6bfb | 607 | |
| va009039 | 0:65f1469d6bfb | 608 | /* Ensure the chunk falls within the heap */ |
| va009039 | 0:65f1469d6bfb | 609 | C_ASSERT(((uint8_t *)ptr >= &pmHeap.base[0]) |
| va009039 | 0:65f1469d6bfb | 610 | && ((uint8_t *)ptr <= &pmHeap.base[pmHeap.size])); |
| va009039 | 0:65f1469d6bfb | 611 | |
| va009039 | 0:65f1469d6bfb | 612 | /* Insert the chunk into the freelist */ |
| va009039 | 0:65f1469d6bfb | 613 | OBJ_SET_FREE(ptr, 1); |
| va009039 | 0:65f1469d6bfb | 614 | |
| va009039 | 0:65f1469d6bfb | 615 | /* Clear type so that heap descriptor's size's upper byte is zero */ |
| va009039 | 0:65f1469d6bfb | 616 | OBJ_SET_TYPE(ptr, 0); |
| va009039 | 0:65f1469d6bfb | 617 | retval = heap_linkToFreelist((pPmHeapDesc_t)ptr); |
| va009039 | 0:65f1469d6bfb | 618 | PM_RETURN_IF_ERROR(retval); |
| va009039 | 0:65f1469d6bfb | 619 | |
| va009039 | 0:65f1469d6bfb | 620 | return retval; |
| va009039 | 0:65f1469d6bfb | 621 | } |
| va009039 | 0:65f1469d6bfb | 622 | |
| va009039 | 0:65f1469d6bfb | 623 | |
| va009039 | 0:65f1469d6bfb | 624 | uint32_t |
| va009039 | 0:65f1469d6bfb | 625 | heap_getAvail(void) |
| va009039 | 0:65f1469d6bfb | 626 | { |
| va009039 | 0:65f1469d6bfb | 627 | return pmHeap.avail; |
| va009039 | 0:65f1469d6bfb | 628 | } |
| va009039 | 0:65f1469d6bfb | 629 | |
| va009039 | 0:65f1469d6bfb | 630 | |
| va009039 | 0:65f1469d6bfb | 631 | uint32_t |
| va009039 | 0:65f1469d6bfb | 632 | heap_getSize(void) |
| va009039 | 0:65f1469d6bfb | 633 | { |
| va009039 | 0:65f1469d6bfb | 634 | return pmHeap.size; |
| va009039 | 0:65f1469d6bfb | 635 | } |
| va009039 | 0:65f1469d6bfb | 636 | |
| va009039 | 0:65f1469d6bfb | 637 | |
| va009039 | 0:65f1469d6bfb | 638 | #ifdef HAVE_GC |
| va009039 | 0:65f1469d6bfb | 639 | /* |
| va009039 | 0:65f1469d6bfb | 640 | * Marks the given object and the objects it references. |
| va009039 | 0:65f1469d6bfb | 641 | * |
| va009039 | 0:65f1469d6bfb | 642 | * @param pobj Any non-free heap object |
| va009039 | 0:65f1469d6bfb | 643 | * @return Return code |
| va009039 | 0:65f1469d6bfb | 644 | */ |
| va009039 | 0:65f1469d6bfb | 645 | static PmReturn_t |
| va009039 | 0:65f1469d6bfb | 646 | heap_gcMarkObj(pPmObj_t pobj) |
| va009039 | 0:65f1469d6bfb | 647 | { |
| va009039 | 0:65f1469d6bfb | 648 | PmReturn_t retval = PM_RET_OK; |
| va009039 | 0:65f1469d6bfb | 649 | int16_t i = 0; |
| va009039 | 0:65f1469d6bfb | 650 | int16_t n; |
| va009039 | 0:65f1469d6bfb | 651 | PmType_t type; |
| va009039 | 0:65f1469d6bfb | 652 | |
| va009039 | 0:65f1469d6bfb | 653 | /* Return if ptr is null or object is already marked */ |
| va009039 | 0:65f1469d6bfb | 654 | if (pobj == C_NULL) |
| va009039 | 0:65f1469d6bfb | 655 | { |
| va009039 | 0:65f1469d6bfb | 656 | return retval; |
| va009039 | 0:65f1469d6bfb | 657 | } |
| va009039 | 0:65f1469d6bfb | 658 | if (OBJ_GET_GCVAL(pobj) == pmHeap.gcval) |
| va009039 | 0:65f1469d6bfb | 659 | { |
| va009039 | 0:65f1469d6bfb | 660 | return retval; |
| va009039 | 0:65f1469d6bfb | 661 | } |
| va009039 | 0:65f1469d6bfb | 662 | |
| va009039 | 0:65f1469d6bfb | 663 | /* The pointer must be within the heap (native frame is special case) */ |
| va009039 | 0:65f1469d6bfb | 664 | C_ASSERT((((uint8_t *)pobj >= &pmHeap.base[0]) |
| va009039 | 0:65f1469d6bfb | 665 | && ((uint8_t *)pobj <= &pmHeap.base[pmHeap.size])) |
| va009039 | 0:65f1469d6bfb | 666 | || ((uint8_t *)pobj == (uint8_t *)&gVmGlobal.nativeframe)); |
| va009039 | 0:65f1469d6bfb | 667 | |
| va009039 | 0:65f1469d6bfb | 668 | /* The object must not already be free */ |
| va009039 | 0:65f1469d6bfb | 669 | C_ASSERT(OBJ_GET_FREE(pobj) == 0); |
| va009039 | 0:65f1469d6bfb | 670 | |
| va009039 | 0:65f1469d6bfb | 671 | type = (PmType_t)OBJ_GET_TYPE(pobj); |
| va009039 | 0:65f1469d6bfb | 672 | switch (type) |
| va009039 | 0:65f1469d6bfb | 673 | { |
| va009039 | 0:65f1469d6bfb | 674 | /* Objects with no references to other objects */ |
| va009039 | 0:65f1469d6bfb | 675 | case OBJ_TYPE_NON: |
| va009039 | 0:65f1469d6bfb | 676 | case OBJ_TYPE_INT: |
| va009039 | 0:65f1469d6bfb | 677 | case OBJ_TYPE_FLT: |
| va009039 | 0:65f1469d6bfb | 678 | case OBJ_TYPE_STR: |
| va009039 | 0:65f1469d6bfb | 679 | case OBJ_TYPE_NOB: |
| va009039 | 0:65f1469d6bfb | 680 | case OBJ_TYPE_BOOL: |
| va009039 | 0:65f1469d6bfb | 681 | case OBJ_TYPE_CIO: |
| va009039 | 0:65f1469d6bfb | 682 | OBJ_SET_GCVAL(pobj, pmHeap.gcval); |
| va009039 | 0:65f1469d6bfb | 683 | break; |
| va009039 | 0:65f1469d6bfb | 684 | |
| va009039 | 0:65f1469d6bfb | 685 | case OBJ_TYPE_TUP: |
| va009039 | 0:65f1469d6bfb | 686 | i = ((pPmTuple_t)pobj)->length; |
| va009039 | 0:65f1469d6bfb | 687 | |
| va009039 | 0:65f1469d6bfb | 688 | /* Mark tuple head */ |
| va009039 | 0:65f1469d6bfb | 689 | OBJ_SET_GCVAL(pobj, pmHeap.gcval); |
| va009039 | 0:65f1469d6bfb | 690 | |
| va009039 | 0:65f1469d6bfb | 691 | /* Mark each obj in tuple */ |
| va009039 | 0:65f1469d6bfb | 692 | while (--i >= 0) |
| va009039 | 0:65f1469d6bfb | 693 | { |
| va009039 | 0:65f1469d6bfb | 694 | retval = heap_gcMarkObj(((pPmTuple_t)pobj)->val[i]); |
| va009039 | 0:65f1469d6bfb | 695 | PM_RETURN_IF_ERROR(retval); |
| va009039 | 0:65f1469d6bfb | 696 | } |
| va009039 | 0:65f1469d6bfb | 697 | break; |
| va009039 | 0:65f1469d6bfb | 698 | |
| va009039 | 0:65f1469d6bfb | 699 | case OBJ_TYPE_LST: |
| va009039 | 0:65f1469d6bfb | 700 | |
| va009039 | 0:65f1469d6bfb | 701 | /* Mark the list */ |
| va009039 | 0:65f1469d6bfb | 702 | OBJ_SET_GCVAL(pobj, pmHeap.gcval); |
| va009039 | 0:65f1469d6bfb | 703 | |
| va009039 | 0:65f1469d6bfb | 704 | /* Mark the seglist */ |
| va009039 | 0:65f1469d6bfb | 705 | retval = heap_gcMarkObj((pPmObj_t)((pPmList_t)pobj)->val); |
| va009039 | 0:65f1469d6bfb | 706 | break; |
| va009039 | 0:65f1469d6bfb | 707 | |
| va009039 | 0:65f1469d6bfb | 708 | case OBJ_TYPE_DIC: |
| va009039 | 0:65f1469d6bfb | 709 | /* Mark the dict head */ |
| va009039 | 0:65f1469d6bfb | 710 | OBJ_SET_GCVAL(pobj, pmHeap.gcval); |
| va009039 | 0:65f1469d6bfb | 711 | |
| va009039 | 0:65f1469d6bfb | 712 | /* Mark the keys seglist */ |
| va009039 | 0:65f1469d6bfb | 713 | retval = heap_gcMarkObj((pPmObj_t)((pPmDict_t)pobj)->d_keys); |
| va009039 | 0:65f1469d6bfb | 714 | PM_RETURN_IF_ERROR(retval); |
| va009039 | 0:65f1469d6bfb | 715 | |
| va009039 | 0:65f1469d6bfb | 716 | /* Mark the vals seglist */ |
| va009039 | 0:65f1469d6bfb | 717 | retval = heap_gcMarkObj((pPmObj_t)((pPmDict_t)pobj)->d_vals); |
| va009039 | 0:65f1469d6bfb | 718 | break; |
| va009039 | 0:65f1469d6bfb | 719 | |
| va009039 | 0:65f1469d6bfb | 720 | case OBJ_TYPE_COB: |
| va009039 | 0:65f1469d6bfb | 721 | /* Mark the code obj head */ |
| va009039 | 0:65f1469d6bfb | 722 | OBJ_SET_GCVAL(pobj, pmHeap.gcval); |
| va009039 | 0:65f1469d6bfb | 723 | |
| va009039 | 0:65f1469d6bfb | 724 | /* Mark the names tuple */ |
| va009039 | 0:65f1469d6bfb | 725 | retval = heap_gcMarkObj((pPmObj_t)((pPmCo_t)pobj)->co_names); |
| va009039 | 0:65f1469d6bfb | 726 | PM_RETURN_IF_ERROR(retval); |
| va009039 | 0:65f1469d6bfb | 727 | |
| va009039 | 0:65f1469d6bfb | 728 | /* Mark the consts tuple */ |
| va009039 | 0:65f1469d6bfb | 729 | retval = heap_gcMarkObj((pPmObj_t)((pPmCo_t)pobj)->co_consts); |
| va009039 | 0:65f1469d6bfb | 730 | PM_RETURN_IF_ERROR(retval); |
| va009039 | 0:65f1469d6bfb | 731 | |
| va009039 | 0:65f1469d6bfb | 732 | /* #122: Mark the code image if it is in RAM */ |
| va009039 | 0:65f1469d6bfb | 733 | if (((pPmCo_t)pobj)->co_memspace == MEMSPACE_RAM) |
| va009039 | 0:65f1469d6bfb | 734 | { |
| va009039 | 0:65f1469d6bfb | 735 | retval = heap_gcMarkObj((pPmObj_t) |
| va009039 | 0:65f1469d6bfb | 736 | (((pPmCo_t)pobj)->co_codeimgaddr)); |
| va009039 | 0:65f1469d6bfb | 737 | PM_RETURN_IF_ERROR(retval); |
| va009039 | 0:65f1469d6bfb | 738 | } |
| va009039 | 0:65f1469d6bfb | 739 | |
| va009039 | 0:65f1469d6bfb | 740 | #ifdef HAVE_CLOSURES |
| va009039 | 0:65f1469d6bfb | 741 | /* #256: Add support for closures */ |
| va009039 | 0:65f1469d6bfb | 742 | /* Mark the cellvars tuple */ |
| va009039 | 0:65f1469d6bfb | 743 | retval = heap_gcMarkObj((pPmObj_t)((pPmCo_t)pobj)->co_cellvars); |
| va009039 | 0:65f1469d6bfb | 744 | #endif /* HAVE_CLOSURES */ |
| va009039 | 0:65f1469d6bfb | 745 | break; |
| va009039 | 0:65f1469d6bfb | 746 | |
| va009039 | 0:65f1469d6bfb | 747 | case OBJ_TYPE_MOD: |
| va009039 | 0:65f1469d6bfb | 748 | case OBJ_TYPE_FXN: |
| va009039 | 0:65f1469d6bfb | 749 | /* Module and Func objs are implemented via the PmFunc_t */ |
| va009039 | 0:65f1469d6bfb | 750 | /* Mark the func obj head */ |
| va009039 | 0:65f1469d6bfb | 751 | OBJ_SET_GCVAL(pobj, pmHeap.gcval); |
| va009039 | 0:65f1469d6bfb | 752 | |
| va009039 | 0:65f1469d6bfb | 753 | /* Mark the code obj */ |
| va009039 | 0:65f1469d6bfb | 754 | retval = heap_gcMarkObj((pPmObj_t)((pPmFunc_t)pobj)->f_co); |
| va009039 | 0:65f1469d6bfb | 755 | PM_RETURN_IF_ERROR(retval); |
| va009039 | 0:65f1469d6bfb | 756 | |
| va009039 | 0:65f1469d6bfb | 757 | /* Mark the attr dict */ |
| va009039 | 0:65f1469d6bfb | 758 | retval = heap_gcMarkObj((pPmObj_t)((pPmFunc_t)pobj)->f_attrs); |
| va009039 | 0:65f1469d6bfb | 759 | PM_RETURN_IF_ERROR(retval); |
| va009039 | 0:65f1469d6bfb | 760 | |
| va009039 | 0:65f1469d6bfb | 761 | /* Mark the globals dict */ |
| va009039 | 0:65f1469d6bfb | 762 | retval = heap_gcMarkObj((pPmObj_t)((pPmFunc_t)pobj)->f_globals); |
| va009039 | 0:65f1469d6bfb | 763 | PM_RETURN_IF_ERROR(retval); |
| va009039 | 0:65f1469d6bfb | 764 | |
| va009039 | 0:65f1469d6bfb | 765 | #ifdef HAVE_DEFAULTARGS |
| va009039 | 0:65f1469d6bfb | 766 | /* Mark the default args tuple */ |
| va009039 | 0:65f1469d6bfb | 767 | retval = heap_gcMarkObj((pPmObj_t)((pPmFunc_t)pobj)->f_defaultargs); |
| va009039 | 0:65f1469d6bfb | 768 | PM_RETURN_IF_ERROR(retval); |
| va009039 | 0:65f1469d6bfb | 769 | #endif /* HAVE_DEFAULTARGS */ |
| va009039 | 0:65f1469d6bfb | 770 | |
| va009039 | 0:65f1469d6bfb | 771 | #ifdef HAVE_CLOSURES |
| va009039 | 0:65f1469d6bfb | 772 | /* #256: Mark the closure tuple */ |
| va009039 | 0:65f1469d6bfb | 773 | retval = heap_gcMarkObj((pPmObj_t)((pPmFunc_t)pobj)->f_closure); |
| va009039 | 0:65f1469d6bfb | 774 | #endif /* HAVE_CLOSURES */ |
| va009039 | 0:65f1469d6bfb | 775 | break; |
| va009039 | 0:65f1469d6bfb | 776 | |
| va009039 | 0:65f1469d6bfb | 777 | #ifdef HAVE_CLASSES |
| va009039 | 0:65f1469d6bfb | 778 | case OBJ_TYPE_CLI: |
| va009039 | 0:65f1469d6bfb | 779 | /* Mark the obj head */ |
| va009039 | 0:65f1469d6bfb | 780 | OBJ_SET_GCVAL(pobj, pmHeap.gcval); |
| va009039 | 0:65f1469d6bfb | 781 | |
| va009039 | 0:65f1469d6bfb | 782 | /* Mark the class */ |
| va009039 | 0:65f1469d6bfb | 783 | retval = heap_gcMarkObj((pPmObj_t)((pPmInstance_t)pobj)->cli_class); |
| va009039 | 0:65f1469d6bfb | 784 | PM_RETURN_IF_ERROR(retval); |
| va009039 | 0:65f1469d6bfb | 785 | |
| va009039 | 0:65f1469d6bfb | 786 | /* Mark the attrs dict */ |
| va009039 | 0:65f1469d6bfb | 787 | retval = heap_gcMarkObj((pPmObj_t)((pPmInstance_t)pobj)->cli_attrs); |
| va009039 | 0:65f1469d6bfb | 788 | break; |
| va009039 | 0:65f1469d6bfb | 789 | |
| va009039 | 0:65f1469d6bfb | 790 | case OBJ_TYPE_MTH: |
| va009039 | 0:65f1469d6bfb | 791 | /* Mark the obj head */ |
| va009039 | 0:65f1469d6bfb | 792 | OBJ_SET_GCVAL(pobj, pmHeap.gcval); |
| va009039 | 0:65f1469d6bfb | 793 | |
| va009039 | 0:65f1469d6bfb | 794 | /* Mark the instance */ |
| va009039 | 0:65f1469d6bfb | 795 | retval = heap_gcMarkObj((pPmObj_t)((pPmMethod_t)pobj)->m_instance); |
| va009039 | 0:65f1469d6bfb | 796 | PM_RETURN_IF_ERROR(retval); |
| va009039 | 0:65f1469d6bfb | 797 | |
| va009039 | 0:65f1469d6bfb | 798 | /* Mark the func */ |
| va009039 | 0:65f1469d6bfb | 799 | retval = heap_gcMarkObj((pPmObj_t)((pPmMethod_t)pobj)->m_func); |
| va009039 | 0:65f1469d6bfb | 800 | PM_RETURN_IF_ERROR(retval); |
| va009039 | 0:65f1469d6bfb | 801 | |
| va009039 | 0:65f1469d6bfb | 802 | /* Mark the attrs dict */ |
| va009039 | 0:65f1469d6bfb | 803 | retval = heap_gcMarkObj((pPmObj_t)((pPmMethod_t)pobj)->m_attrs); |
| va009039 | 0:65f1469d6bfb | 804 | break; |
| va009039 | 0:65f1469d6bfb | 805 | |
| va009039 | 0:65f1469d6bfb | 806 | case OBJ_TYPE_CLO: |
| va009039 | 0:65f1469d6bfb | 807 | /* Mark the obj head */ |
| va009039 | 0:65f1469d6bfb | 808 | OBJ_SET_GCVAL(pobj, pmHeap.gcval); |
| va009039 | 0:65f1469d6bfb | 809 | |
| va009039 | 0:65f1469d6bfb | 810 | /* Mark the attrs dict */ |
| va009039 | 0:65f1469d6bfb | 811 | retval = heap_gcMarkObj((pPmObj_t)((pPmClass_t)pobj)->cl_attrs); |
| va009039 | 0:65f1469d6bfb | 812 | PM_RETURN_IF_ERROR(retval); |
| va009039 | 0:65f1469d6bfb | 813 | |
| va009039 | 0:65f1469d6bfb | 814 | /* Mark the base tuple */ |
| va009039 | 0:65f1469d6bfb | 815 | retval = heap_gcMarkObj((pPmObj_t)((pPmClass_t)pobj)->cl_bases); |
| va009039 | 0:65f1469d6bfb | 816 | break; |
| va009039 | 0:65f1469d6bfb | 817 | #endif /* HAVE_CLASSES */ |
| va009039 | 0:65f1469d6bfb | 818 | |
| va009039 | 0:65f1469d6bfb | 819 | /* |
| va009039 | 0:65f1469d6bfb | 820 | * An obj in ram should not be of these types. |
| va009039 | 0:65f1469d6bfb | 821 | * Images arrive in RAM as string objects (image is array of bytes) |
| va009039 | 0:65f1469d6bfb | 822 | */ |
| va009039 | 0:65f1469d6bfb | 823 | case OBJ_TYPE_CIM: |
| va009039 | 0:65f1469d6bfb | 824 | case OBJ_TYPE_NIM: |
| va009039 | 0:65f1469d6bfb | 825 | PM_RAISE(retval, PM_RET_EX_SYS); |
| va009039 | 0:65f1469d6bfb | 826 | return retval; |
| va009039 | 0:65f1469d6bfb | 827 | |
| va009039 | 0:65f1469d6bfb | 828 | case OBJ_TYPE_FRM: |
| va009039 | 0:65f1469d6bfb | 829 | { |
| va009039 | 0:65f1469d6bfb | 830 | pPmObj_t *ppobj2 = C_NULL; |
| va009039 | 0:65f1469d6bfb | 831 | |
| va009039 | 0:65f1469d6bfb | 832 | /* Mark the frame obj head */ |
| va009039 | 0:65f1469d6bfb | 833 | OBJ_SET_GCVAL(pobj, pmHeap.gcval); |
| va009039 | 0:65f1469d6bfb | 834 | |
| va009039 | 0:65f1469d6bfb | 835 | /* Mark the previous frame, if this isn't a generator's frame */ |
| va009039 | 0:65f1469d6bfb | 836 | /* Issue #129: Fix iterator losing its object */ |
| va009039 | 0:65f1469d6bfb | 837 | if ((((pPmFrame_t)pobj)->fo_func->f_co->co_flags & CO_GENERATOR) == 0) |
| va009039 | 0:65f1469d6bfb | 838 | { |
| va009039 | 0:65f1469d6bfb | 839 | retval = heap_gcMarkObj((pPmObj_t)((pPmFrame_t)pobj)->fo_back); |
| va009039 | 0:65f1469d6bfb | 840 | PM_RETURN_IF_ERROR(retval); |
| va009039 | 0:65f1469d6bfb | 841 | } |
| va009039 | 0:65f1469d6bfb | 842 | |
| va009039 | 0:65f1469d6bfb | 843 | /* Mark the fxn obj */ |
| va009039 | 0:65f1469d6bfb | 844 | retval = heap_gcMarkObj((pPmObj_t)((pPmFrame_t)pobj)->fo_func); |
| va009039 | 0:65f1469d6bfb | 845 | PM_RETURN_IF_ERROR(retval); |
| va009039 | 0:65f1469d6bfb | 846 | |
| va009039 | 0:65f1469d6bfb | 847 | /* Mark the blockstack */ |
| va009039 | 0:65f1469d6bfb | 848 | retval = heap_gcMarkObj((pPmObj_t) |
| va009039 | 0:65f1469d6bfb | 849 | ((pPmFrame_t)pobj)->fo_blockstack); |
| va009039 | 0:65f1469d6bfb | 850 | PM_RETURN_IF_ERROR(retval); |
| va009039 | 0:65f1469d6bfb | 851 | |
| va009039 | 0:65f1469d6bfb | 852 | /* Mark the attrs dict */ |
| va009039 | 0:65f1469d6bfb | 853 | retval = heap_gcMarkObj((pPmObj_t)((pPmFrame_t)pobj)->fo_attrs); |
| va009039 | 0:65f1469d6bfb | 854 | PM_RETURN_IF_ERROR(retval); |
| va009039 | 0:65f1469d6bfb | 855 | |
| va009039 | 0:65f1469d6bfb | 856 | /* Mark the globals dict */ |
| va009039 | 0:65f1469d6bfb | 857 | retval = heap_gcMarkObj((pPmObj_t)((pPmFrame_t)pobj)->fo_globals); |
| va009039 | 0:65f1469d6bfb | 858 | PM_RETURN_IF_ERROR(retval); |
| va009039 | 0:65f1469d6bfb | 859 | |
| va009039 | 0:65f1469d6bfb | 860 | /* Mark each obj in the locals list and the stack */ |
| va009039 | 0:65f1469d6bfb | 861 | ppobj2 = ((pPmFrame_t)pobj)->fo_locals; |
| va009039 | 0:65f1469d6bfb | 862 | while (ppobj2 < ((pPmFrame_t)pobj)->fo_sp) |
| va009039 | 0:65f1469d6bfb | 863 | { |
| va009039 | 0:65f1469d6bfb | 864 | retval = heap_gcMarkObj(*ppobj2); |
| va009039 | 0:65f1469d6bfb | 865 | PM_RETURN_IF_ERROR(retval); |
| va009039 | 0:65f1469d6bfb | 866 | ppobj2++; |
| va009039 | 0:65f1469d6bfb | 867 | } |
| va009039 | 0:65f1469d6bfb | 868 | break; |
| va009039 | 0:65f1469d6bfb | 869 | } |
| va009039 | 0:65f1469d6bfb | 870 | |
| va009039 | 0:65f1469d6bfb | 871 | case OBJ_TYPE_BLK: |
| va009039 | 0:65f1469d6bfb | 872 | /* Mark the block obj head */ |
| va009039 | 0:65f1469d6bfb | 873 | OBJ_SET_GCVAL(pobj, pmHeap.gcval); |
| va009039 | 0:65f1469d6bfb | 874 | |
| va009039 | 0:65f1469d6bfb | 875 | /* Mark the next block in the stack */ |
| va009039 | 0:65f1469d6bfb | 876 | retval = heap_gcMarkObj((pPmObj_t)((pPmBlock_t)pobj)->next); |
| va009039 | 0:65f1469d6bfb | 877 | break; |
| va009039 | 0:65f1469d6bfb | 878 | |
| va009039 | 0:65f1469d6bfb | 879 | case OBJ_TYPE_SGL: |
| va009039 | 0:65f1469d6bfb | 880 | /* Mark the seglist obj head */ |
| va009039 | 0:65f1469d6bfb | 881 | OBJ_SET_GCVAL(pobj, pmHeap.gcval); |
| va009039 | 0:65f1469d6bfb | 882 | |
| va009039 | 0:65f1469d6bfb | 883 | /* Mark the seglist's segments */ |
| va009039 | 0:65f1469d6bfb | 884 | n = ((pSeglist_t)pobj)->sl_length; |
| va009039 | 0:65f1469d6bfb | 885 | pobj = (pPmObj_t)((pSeglist_t)pobj)->sl_rootseg; |
| va009039 | 0:65f1469d6bfb | 886 | for (i = 0; i < n; i++) |
| va009039 | 0:65f1469d6bfb | 887 | { |
| va009039 | 0:65f1469d6bfb | 888 | /* Mark the segment item */ |
| va009039 | 0:65f1469d6bfb | 889 | retval = heap_gcMarkObj(((pSegment_t)pobj)->s_val[i % SEGLIST_OBJS_PER_SEG]); |
| va009039 | 0:65f1469d6bfb | 890 | PM_RETURN_IF_ERROR(retval); |
| va009039 | 0:65f1469d6bfb | 891 | |
| va009039 | 0:65f1469d6bfb | 892 | /* Mark the segment obj head */ |
| va009039 | 0:65f1469d6bfb | 893 | if ((i % SEGLIST_OBJS_PER_SEG) == 0) |
| va009039 | 0:65f1469d6bfb | 894 | { |
| va009039 | 0:65f1469d6bfb | 895 | OBJ_SET_GCVAL(pobj, pmHeap.gcval); |
| va009039 | 0:65f1469d6bfb | 896 | } |
| va009039 | 0:65f1469d6bfb | 897 | |
| va009039 | 0:65f1469d6bfb | 898 | /* Point to the next segment */ |
| va009039 | 0:65f1469d6bfb | 899 | else |
| va009039 | 0:65f1469d6bfb | 900 | if ((i % SEGLIST_OBJS_PER_SEG) == (SEGLIST_OBJS_PER_SEG - 1)) |
| va009039 | 0:65f1469d6bfb | 901 | { |
| va009039 | 0:65f1469d6bfb | 902 | pobj = (pPmObj_t)((pSegment_t)pobj)->next; |
| va009039 | 0:65f1469d6bfb | 903 | if (pobj == C_NULL) |
| va009039 | 0:65f1469d6bfb | 904 | { |
| va009039 | 0:65f1469d6bfb | 905 | break; |
| va009039 | 0:65f1469d6bfb | 906 | } |
| va009039 | 0:65f1469d6bfb | 907 | } |
| va009039 | 0:65f1469d6bfb | 908 | } |
| va009039 | 0:65f1469d6bfb | 909 | break; |
| va009039 | 0:65f1469d6bfb | 910 | |
| va009039 | 0:65f1469d6bfb | 911 | case OBJ_TYPE_SQI: |
| va009039 | 0:65f1469d6bfb | 912 | /* Mark the sequence iterator obj head */ |
| va009039 | 0:65f1469d6bfb | 913 | OBJ_SET_GCVAL(pobj, pmHeap.gcval); |
| va009039 | 0:65f1469d6bfb | 914 | |
| va009039 | 0:65f1469d6bfb | 915 | /* Mark the sequence */ |
| va009039 | 0:65f1469d6bfb | 916 | retval = heap_gcMarkObj(((pPmSeqIter_t)pobj)->si_sequence); |
| va009039 | 0:65f1469d6bfb | 917 | break; |
| va009039 | 0:65f1469d6bfb | 918 | |
| va009039 | 0:65f1469d6bfb | 919 | case OBJ_TYPE_THR: |
| va009039 | 0:65f1469d6bfb | 920 | /* Mark the thread obj head */ |
| va009039 | 0:65f1469d6bfb | 921 | OBJ_SET_GCVAL(pobj, pmHeap.gcval); |
| va009039 | 0:65f1469d6bfb | 922 | |
| va009039 | 0:65f1469d6bfb | 923 | /* Mark the current frame */ |
| va009039 | 0:65f1469d6bfb | 924 | retval = heap_gcMarkObj((pPmObj_t)((pPmThread_t)pobj)->pframe); |
| va009039 | 0:65f1469d6bfb | 925 | break; |
| va009039 | 0:65f1469d6bfb | 926 | |
| va009039 | 0:65f1469d6bfb | 927 | case OBJ_TYPE_NFM: |
| va009039 | 0:65f1469d6bfb | 928 | /* |
| va009039 | 0:65f1469d6bfb | 929 | * Mark the obj desc. This doesn't really do much since the |
| va009039 | 0:65f1469d6bfb | 930 | * native frame is declared static (not from the heap), but this |
| va009039 | 0:65f1469d6bfb | 931 | * is here in case that ever changes |
| va009039 | 0:65f1469d6bfb | 932 | */ |
| va009039 | 0:65f1469d6bfb | 933 | OBJ_SET_GCVAL(pobj, pmHeap.gcval); |
| va009039 | 0:65f1469d6bfb | 934 | |
| va009039 | 0:65f1469d6bfb | 935 | /* Mark the native frame's remaining fields if active */ |
| va009039 | 0:65f1469d6bfb | 936 | if (gVmGlobal.nativeframe.nf_active) |
| va009039 | 0:65f1469d6bfb | 937 | { |
| va009039 | 0:65f1469d6bfb | 938 | /* Mark the frame stack */ |
| va009039 | 0:65f1469d6bfb | 939 | retval = heap_gcMarkObj((pPmObj_t) |
| va009039 | 0:65f1469d6bfb | 940 | gVmGlobal.nativeframe.nf_back); |
| va009039 | 0:65f1469d6bfb | 941 | PM_RETURN_IF_ERROR(retval); |
| va009039 | 0:65f1469d6bfb | 942 | |
| va009039 | 0:65f1469d6bfb | 943 | /* Mark the function object */ |
| va009039 | 0:65f1469d6bfb | 944 | retval = heap_gcMarkObj((pPmObj_t) |
| va009039 | 0:65f1469d6bfb | 945 | gVmGlobal.nativeframe.nf_func); |
| va009039 | 0:65f1469d6bfb | 946 | PM_RETURN_IF_ERROR(retval); |
| va009039 | 0:65f1469d6bfb | 947 | |
| va009039 | 0:65f1469d6bfb | 948 | /* Mark the stack object */ |
| va009039 | 0:65f1469d6bfb | 949 | retval = heap_gcMarkObj(gVmGlobal.nativeframe.nf_stack); |
| va009039 | 0:65f1469d6bfb | 950 | PM_RETURN_IF_ERROR(retval); |
| va009039 | 0:65f1469d6bfb | 951 | |
| va009039 | 0:65f1469d6bfb | 952 | /* Mark the args to the native func */ |
| va009039 | 0:65f1469d6bfb | 953 | for (i = 0; i < NATIVE_GET_NUM_ARGS(); i++) |
| va009039 | 0:65f1469d6bfb | 954 | { |
| va009039 | 0:65f1469d6bfb | 955 | retval = |
| va009039 | 0:65f1469d6bfb | 956 | heap_gcMarkObj(gVmGlobal.nativeframe.nf_locals[i]); |
| va009039 | 0:65f1469d6bfb | 957 | PM_RETURN_IF_ERROR(retval); |
| va009039 | 0:65f1469d6bfb | 958 | } |
| va009039 | 0:65f1469d6bfb | 959 | } |
| va009039 | 0:65f1469d6bfb | 960 | break; |
| va009039 | 0:65f1469d6bfb | 961 | |
| va009039 | 0:65f1469d6bfb | 962 | #ifdef HAVE_BYTEARRAY |
| va009039 | 0:65f1469d6bfb | 963 | case OBJ_TYPE_BYA: |
| va009039 | 0:65f1469d6bfb | 964 | OBJ_SET_GCVAL(pobj, pmHeap.gcval); |
| va009039 | 0:65f1469d6bfb | 965 | |
| va009039 | 0:65f1469d6bfb | 966 | retval = heap_gcMarkObj((pPmObj_t)((pPmBytearray_t)pobj)->val); |
| va009039 | 0:65f1469d6bfb | 967 | break; |
| va009039 | 0:65f1469d6bfb | 968 | |
| va009039 | 0:65f1469d6bfb | 969 | case OBJ_TYPE_BYS: |
| va009039 | 0:65f1469d6bfb | 970 | OBJ_SET_GCVAL(pobj, pmHeap.gcval); |
| va009039 | 0:65f1469d6bfb | 971 | break; |
| va009039 | 0:65f1469d6bfb | 972 | #endif /* HAVE_BYTEARRAY */ |
| va009039 | 0:65f1469d6bfb | 973 | |
| va009039 | 0:65f1469d6bfb | 974 | default: |
| va009039 | 0:65f1469d6bfb | 975 | /* There should be no invalid types */ |
| va009039 | 0:65f1469d6bfb | 976 | PM_RAISE(retval, PM_RET_EX_SYS); |
| va009039 | 0:65f1469d6bfb | 977 | break; |
| va009039 | 0:65f1469d6bfb | 978 | } |
| va009039 | 0:65f1469d6bfb | 979 | return retval; |
| va009039 | 0:65f1469d6bfb | 980 | } |
| va009039 | 0:65f1469d6bfb | 981 | |
| va009039 | 0:65f1469d6bfb | 982 | |
| va009039 | 0:65f1469d6bfb | 983 | /* |
| va009039 | 0:65f1469d6bfb | 984 | * Marks the root objects so they won't be collected during the sweep phase. |
| va009039 | 0:65f1469d6bfb | 985 | * Recursively marks all objects reachable from the roots. |
| va009039 | 0:65f1469d6bfb | 986 | */ |
| va009039 | 0:65f1469d6bfb | 987 | static PmReturn_t |
| va009039 | 0:65f1469d6bfb | 988 | heap_gcMarkRoots(void) |
| va009039 | 0:65f1469d6bfb | 989 | { |
| va009039 | 0:65f1469d6bfb | 990 | PmReturn_t retval; |
| va009039 | 0:65f1469d6bfb | 991 | uint8_t i; |
| va009039 | 0:65f1469d6bfb | 992 | |
| va009039 | 0:65f1469d6bfb | 993 | /* Toggle the GC marking value so it differs from the last run */ |
| va009039 | 0:65f1469d6bfb | 994 | pmHeap.gcval ^= 1; |
| va009039 | 0:65f1469d6bfb | 995 | |
| va009039 | 0:65f1469d6bfb | 996 | /* Mark the constant objects */ |
| va009039 | 0:65f1469d6bfb | 997 | retval = heap_gcMarkObj(PM_NONE); |
| va009039 | 0:65f1469d6bfb | 998 | PM_RETURN_IF_ERROR(retval); |
| va009039 | 0:65f1469d6bfb | 999 | retval = heap_gcMarkObj(PM_FALSE); |
| va009039 | 0:65f1469d6bfb | 1000 | PM_RETURN_IF_ERROR(retval); |
| va009039 | 0:65f1469d6bfb | 1001 | retval = heap_gcMarkObj(PM_TRUE); |
| va009039 | 0:65f1469d6bfb | 1002 | PM_RETURN_IF_ERROR(retval); |
| va009039 | 0:65f1469d6bfb | 1003 | retval = heap_gcMarkObj(PM_ZERO); |
| va009039 | 0:65f1469d6bfb | 1004 | PM_RETURN_IF_ERROR(retval); |
| va009039 | 0:65f1469d6bfb | 1005 | retval = heap_gcMarkObj(PM_ONE); |
| va009039 | 0:65f1469d6bfb | 1006 | PM_RETURN_IF_ERROR(retval); |
| va009039 | 0:65f1469d6bfb | 1007 | retval = heap_gcMarkObj(PM_NEGONE); |
| va009039 | 0:65f1469d6bfb | 1008 | PM_RETURN_IF_ERROR(retval); |
| va009039 | 0:65f1469d6bfb | 1009 | retval = heap_gcMarkObj(PM_CODE_STR); |
| va009039 | 0:65f1469d6bfb | 1010 | PM_RETURN_IF_ERROR(retval); |
| va009039 | 0:65f1469d6bfb | 1011 | |
| va009039 | 0:65f1469d6bfb | 1012 | /* Mark the builtins dict */ |
| va009039 | 0:65f1469d6bfb | 1013 | retval = heap_gcMarkObj(PM_PBUILTINS); |
| va009039 | 0:65f1469d6bfb | 1014 | PM_RETURN_IF_ERROR(retval); |
| va009039 | 0:65f1469d6bfb | 1015 | |
| va009039 | 0:65f1469d6bfb | 1016 | /* Mark the native frame if it is active */ |
| va009039 | 0:65f1469d6bfb | 1017 | retval = heap_gcMarkObj((pPmObj_t)&gVmGlobal.nativeframe); |
| va009039 | 0:65f1469d6bfb | 1018 | PM_RETURN_IF_ERROR(retval); |
| va009039 | 0:65f1469d6bfb | 1019 | |
| va009039 | 0:65f1469d6bfb | 1020 | /* Mark the thread list */ |
| va009039 | 0:65f1469d6bfb | 1021 | retval = heap_gcMarkObj((pPmObj_t)gVmGlobal.threadList); |
| va009039 | 0:65f1469d6bfb | 1022 | PM_RETURN_IF_ERROR(retval); |
| va009039 | 0:65f1469d6bfb | 1023 | |
| va009039 | 0:65f1469d6bfb | 1024 | /* Mark the temporary roots */ |
| va009039 | 0:65f1469d6bfb | 1025 | for (i = 0; i < pmHeap.temp_root_index; i++) |
| va009039 | 0:65f1469d6bfb | 1026 | { |
| va009039 | 0:65f1469d6bfb | 1027 | retval = heap_gcMarkObj(pmHeap.temp_roots[i]); |
| va009039 | 0:65f1469d6bfb | 1028 | PM_RETURN_IF_ERROR(retval); |
| va009039 | 0:65f1469d6bfb | 1029 | } |
| va009039 | 0:65f1469d6bfb | 1030 | |
| va009039 | 0:65f1469d6bfb | 1031 | return retval; |
| va009039 | 0:65f1469d6bfb | 1032 | } |
| va009039 | 0:65f1469d6bfb | 1033 | |
| va009039 | 0:65f1469d6bfb | 1034 | |
| va009039 | 0:65f1469d6bfb | 1035 | #if USE_STRING_CACHE |
| va009039 | 0:65f1469d6bfb | 1036 | /** |
| va009039 | 0:65f1469d6bfb | 1037 | * Unlinks free objects from the string cache. |
| va009039 | 0:65f1469d6bfb | 1038 | * This function must only be called by the GC after the heap has been marked |
| va009039 | 0:65f1469d6bfb | 1039 | * and before the heap has been swept. |
| va009039 | 0:65f1469d6bfb | 1040 | * |
| va009039 | 0:65f1469d6bfb | 1041 | * This solves the problem where a string object would be collected |
| va009039 | 0:65f1469d6bfb | 1042 | * but its chunk was still linked into the free list |
| va009039 | 0:65f1469d6bfb | 1043 | * |
| va009039 | 0:65f1469d6bfb | 1044 | * @param gcval The current value for chunks marked by the GC |
| va009039 | 0:65f1469d6bfb | 1045 | */ |
| va009039 | 0:65f1469d6bfb | 1046 | static PmReturn_t |
| va009039 | 0:65f1469d6bfb | 1047 | heap_purgeStringCache(uint8_t gcval) |
| va009039 | 0:65f1469d6bfb | 1048 | { |
| va009039 | 0:65f1469d6bfb | 1049 | PmReturn_t retval; |
| va009039 | 0:65f1469d6bfb | 1050 | pPmString_t *ppstrcache; |
| va009039 | 0:65f1469d6bfb | 1051 | pPmString_t pstr; |
| va009039 | 0:65f1469d6bfb | 1052 | |
| va009039 | 0:65f1469d6bfb | 1053 | /* Update string cache pointer if the first string objs are not marked */ |
| va009039 | 0:65f1469d6bfb | 1054 | retval = string_getCache(&ppstrcache); |
| va009039 | 0:65f1469d6bfb | 1055 | if (ppstrcache == C_NULL) |
| va009039 | 0:65f1469d6bfb | 1056 | { |
| va009039 | 0:65f1469d6bfb | 1057 | return retval; |
| va009039 | 0:65f1469d6bfb | 1058 | } |
| va009039 | 0:65f1469d6bfb | 1059 | while ((*ppstrcache != C_NULL) && (OBJ_GET_GCVAL(*ppstrcache) != gcval)) |
| va009039 | 0:65f1469d6bfb | 1060 | { |
| va009039 | 0:65f1469d6bfb | 1061 | *ppstrcache = (*ppstrcache)->next; |
| va009039 | 0:65f1469d6bfb | 1062 | } |
| va009039 | 0:65f1469d6bfb | 1063 | if (*ppstrcache == C_NULL) |
| va009039 | 0:65f1469d6bfb | 1064 | { |
| va009039 | 0:65f1469d6bfb | 1065 | return retval; |
| va009039 | 0:65f1469d6bfb | 1066 | } |
| va009039 | 0:65f1469d6bfb | 1067 | |
| va009039 | 0:65f1469d6bfb | 1068 | /* Unlink remaining strings that are not marked */ |
| va009039 | 0:65f1469d6bfb | 1069 | for (pstr = *ppstrcache; pstr->next != C_NULL;) |
| va009039 | 0:65f1469d6bfb | 1070 | { |
| va009039 | 0:65f1469d6bfb | 1071 | /* Unlink consecutive non-marked strings */ |
| va009039 | 0:65f1469d6bfb | 1072 | while ((pstr->next != C_NULL) && (OBJ_GET_GCVAL(pstr->next) != gcval)) |
| va009039 | 0:65f1469d6bfb | 1073 | { |
| va009039 | 0:65f1469d6bfb | 1074 | pstr->next = pstr->next->next; |
| va009039 | 0:65f1469d6bfb | 1075 | } |
| va009039 | 0:65f1469d6bfb | 1076 | |
| va009039 | 0:65f1469d6bfb | 1077 | /* If not at end of cache, string must be marked, skip it */ |
| va009039 | 0:65f1469d6bfb | 1078 | if (pstr->next != C_NULL) |
| va009039 | 0:65f1469d6bfb | 1079 | { |
| va009039 | 0:65f1469d6bfb | 1080 | pstr = pstr->next; |
| va009039 | 0:65f1469d6bfb | 1081 | } |
| va009039 | 0:65f1469d6bfb | 1082 | } |
| va009039 | 0:65f1469d6bfb | 1083 | |
| va009039 | 0:65f1469d6bfb | 1084 | return retval; |
| va009039 | 0:65f1469d6bfb | 1085 | } |
| va009039 | 0:65f1469d6bfb | 1086 | #endif |
| va009039 | 0:65f1469d6bfb | 1087 | |
| va009039 | 0:65f1469d6bfb | 1088 | |
| va009039 | 0:65f1469d6bfb | 1089 | /* |
| va009039 | 0:65f1469d6bfb | 1090 | * Reclaims any object that does not have a current mark. |
| va009039 | 0:65f1469d6bfb | 1091 | * Puts it in the free list. Coalesces all contiguous free chunks. |
| va009039 | 0:65f1469d6bfb | 1092 | */ |
| va009039 | 0:65f1469d6bfb | 1093 | static PmReturn_t |
| va009039 | 0:65f1469d6bfb | 1094 | heap_gcSweep(void) |
| va009039 | 0:65f1469d6bfb | 1095 | { |
| va009039 | 0:65f1469d6bfb | 1096 | PmReturn_t retval; |
| va009039 | 0:65f1469d6bfb | 1097 | pPmObj_t pobj; |
| va009039 | 0:65f1469d6bfb | 1098 | pPmHeapDesc_t pchunk; |
| va009039 | 0:65f1469d6bfb | 1099 | uint16_t totalchunksize; |
| va009039 | 0:65f1469d6bfb | 1100 | |
| va009039 | 0:65f1469d6bfb | 1101 | #if USE_STRING_CACHE |
| va009039 | 0:65f1469d6bfb | 1102 | retval = heap_purgeStringCache(pmHeap.gcval); |
| va009039 | 0:65f1469d6bfb | 1103 | #endif |
| va009039 | 0:65f1469d6bfb | 1104 | |
| va009039 | 0:65f1469d6bfb | 1105 | /* Start at the base of the heap */ |
| va009039 | 0:65f1469d6bfb | 1106 | pobj = (pPmObj_t)pmHeap.base; |
| va009039 | 0:65f1469d6bfb | 1107 | while ((uint8_t *)pobj < &pmHeap.base[pmHeap.size]) |
| va009039 | 0:65f1469d6bfb | 1108 | { |
| va009039 | 0:65f1469d6bfb | 1109 | /* Skip to the next unmarked or free chunk within the heap */ |
| va009039 | 0:65f1469d6bfb | 1110 | while (!OBJ_GET_FREE(pobj) |
| va009039 | 0:65f1469d6bfb | 1111 | && (OBJ_GET_GCVAL(pobj) == pmHeap.gcval) |
| va009039 | 0:65f1469d6bfb | 1112 | && ((uint8_t *)pobj < &pmHeap.base[pmHeap.size])) |
| va009039 | 0:65f1469d6bfb | 1113 | { |
| va009039 | 0:65f1469d6bfb | 1114 | pobj = (pPmObj_t)((uint8_t *)pobj + PM_OBJ_GET_SIZE(pobj)); |
| va009039 | 0:65f1469d6bfb | 1115 | } |
| va009039 | 0:65f1469d6bfb | 1116 | |
| va009039 | 0:65f1469d6bfb | 1117 | /* Stop if reached the end of the heap */ |
| va009039 | 0:65f1469d6bfb | 1118 | if ((uint8_t *)pobj >= &pmHeap.base[pmHeap.size]) |
| va009039 | 0:65f1469d6bfb | 1119 | { |
| va009039 | 0:65f1469d6bfb | 1120 | break; |
| va009039 | 0:65f1469d6bfb | 1121 | } |
| va009039 | 0:65f1469d6bfb | 1122 | |
| va009039 | 0:65f1469d6bfb | 1123 | /* Accumulate the sizes of all consecutive unmarked or free chunks */ |
| va009039 | 0:65f1469d6bfb | 1124 | totalchunksize = 0; |
| va009039 | 0:65f1469d6bfb | 1125 | |
| va009039 | 0:65f1469d6bfb | 1126 | /* Coalesce all contiguous free chunks */ |
| va009039 | 0:65f1469d6bfb | 1127 | pchunk = (pPmHeapDesc_t)pobj; |
| va009039 | 0:65f1469d6bfb | 1128 | while (OBJ_GET_FREE(pchunk) |
| va009039 | 0:65f1469d6bfb | 1129 | || (!OBJ_GET_FREE(pchunk) |
| va009039 | 0:65f1469d6bfb | 1130 | && (OBJ_GET_GCVAL(pchunk) != pmHeap.gcval))) |
| va009039 | 0:65f1469d6bfb | 1131 | { |
| va009039 | 0:65f1469d6bfb | 1132 | /* |
| va009039 | 0:65f1469d6bfb | 1133 | * If the chunk is already free, unlink it because its size |
| va009039 | 0:65f1469d6bfb | 1134 | * is about to change |
| va009039 | 0:65f1469d6bfb | 1135 | */ |
| va009039 | 0:65f1469d6bfb | 1136 | if (OBJ_GET_FREE(pchunk)) |
| va009039 | 0:65f1469d6bfb | 1137 | { |
| va009039 | 0:65f1469d6bfb | 1138 | if ((totalchunksize + CHUNK_GET_SIZE(pchunk)) |
| va009039 | 0:65f1469d6bfb | 1139 | > HEAP_MAX_FREE_CHUNK_SIZE) |
| va009039 | 0:65f1469d6bfb | 1140 | { |
| va009039 | 0:65f1469d6bfb | 1141 | break; |
| va009039 | 0:65f1469d6bfb | 1142 | } |
| va009039 | 0:65f1469d6bfb | 1143 | retval = heap_unlinkFromFreelist(pchunk); |
| va009039 | 0:65f1469d6bfb | 1144 | PM_RETURN_IF_ERROR(retval); |
| va009039 | 0:65f1469d6bfb | 1145 | } |
| va009039 | 0:65f1469d6bfb | 1146 | |
| va009039 | 0:65f1469d6bfb | 1147 | /* Otherwise free and reclaim the unmarked chunk */ |
| va009039 | 0:65f1469d6bfb | 1148 | else |
| va009039 | 0:65f1469d6bfb | 1149 | { |
| va009039 | 0:65f1469d6bfb | 1150 | if ((totalchunksize + PM_OBJ_GET_SIZE(pchunk)) |
| va009039 | 0:65f1469d6bfb | 1151 | > HEAP_MAX_FREE_CHUNK_SIZE) |
| va009039 | 0:65f1469d6bfb | 1152 | { |
| va009039 | 0:65f1469d6bfb | 1153 | break; |
| va009039 | 0:65f1469d6bfb | 1154 | } |
| va009039 | 0:65f1469d6bfb | 1155 | OBJ_SET_TYPE(pchunk, 0); |
| va009039 | 0:65f1469d6bfb | 1156 | OBJ_SET_FREE(pchunk, 1); |
| va009039 | 0:65f1469d6bfb | 1157 | } |
| va009039 | 0:65f1469d6bfb | 1158 | totalchunksize = totalchunksize + CHUNK_GET_SIZE(pchunk); |
| va009039 | 0:65f1469d6bfb | 1159 | |
| va009039 | 0:65f1469d6bfb | 1160 | C_DEBUG_PRINT(VERBOSITY_HIGH, "heap_gcSweep(), id=%p, s=%d\n", |
| va009039 | 0:65f1469d6bfb | 1161 | pchunk, CHUNK_GET_SIZE(pchunk)); |
| va009039 | 0:65f1469d6bfb | 1162 | |
| va009039 | 0:65f1469d6bfb | 1163 | /* Proceed to the next chunk */ |
| va009039 | 0:65f1469d6bfb | 1164 | pchunk = (pPmHeapDesc_t) |
| va009039 | 0:65f1469d6bfb | 1165 | ((uint8_t *)pchunk + CHUNK_GET_SIZE(pchunk)); |
| va009039 | 0:65f1469d6bfb | 1166 | |
| va009039 | 0:65f1469d6bfb | 1167 | /* Stop if it's past the end of the heap */ |
| va009039 | 0:65f1469d6bfb | 1168 | if ((uint8_t *)pchunk >= &pmHeap.base[pmHeap.size]) |
| va009039 | 0:65f1469d6bfb | 1169 | { |
| va009039 | 0:65f1469d6bfb | 1170 | break; |
| va009039 | 0:65f1469d6bfb | 1171 | } |
| va009039 | 0:65f1469d6bfb | 1172 | } |
| va009039 | 0:65f1469d6bfb | 1173 | |
| va009039 | 0:65f1469d6bfb | 1174 | /* Set the heap descriptor data */ |
| va009039 | 0:65f1469d6bfb | 1175 | OBJ_SET_FREE(pobj, 1); |
| va009039 | 0:65f1469d6bfb | 1176 | CHUNK_SET_SIZE(pobj, totalchunksize); |
| va009039 | 0:65f1469d6bfb | 1177 | |
| va009039 | 0:65f1469d6bfb | 1178 | /* Insert chunk into free list */ |
| va009039 | 0:65f1469d6bfb | 1179 | retval = heap_linkToFreelist((pPmHeapDesc_t)pobj); |
| va009039 | 0:65f1469d6bfb | 1180 | PM_RETURN_IF_ERROR(retval); |
| va009039 | 0:65f1469d6bfb | 1181 | |
| va009039 | 0:65f1469d6bfb | 1182 | /* Continue to the next chunk */ |
| va009039 | 0:65f1469d6bfb | 1183 | pobj = (pPmObj_t)pchunk; |
| va009039 | 0:65f1469d6bfb | 1184 | } |
| va009039 | 0:65f1469d6bfb | 1185 | |
| va009039 | 0:65f1469d6bfb | 1186 | return PM_RET_OK; |
| va009039 | 0:65f1469d6bfb | 1187 | } |
| va009039 | 0:65f1469d6bfb | 1188 | |
| va009039 | 0:65f1469d6bfb | 1189 | |
| va009039 | 0:65f1469d6bfb | 1190 | /* Runs the mark-sweep garbage collector */ |
| va009039 | 0:65f1469d6bfb | 1191 | PmReturn_t |
| va009039 | 0:65f1469d6bfb | 1192 | heap_gcRun(void) |
| va009039 | 0:65f1469d6bfb | 1193 | { |
| va009039 | 0:65f1469d6bfb | 1194 | PmReturn_t retval; |
| va009039 | 0:65f1469d6bfb | 1195 | |
| va009039 | 0:65f1469d6bfb | 1196 | /* #239: Fix GC when 2+ unlinked allocs occur */ |
| va009039 | 0:65f1469d6bfb | 1197 | /* This assertion fails when there are too many objects on the temporary |
| va009039 | 0:65f1469d6bfb | 1198 | * root stack and a GC occurs; consider increasing PM_HEAP_NUM_TEMP_ROOTS |
| va009039 | 0:65f1469d6bfb | 1199 | */ |
| va009039 | 0:65f1469d6bfb | 1200 | C_ASSERT(pmHeap.temp_root_index < HEAP_NUM_TEMP_ROOTS); |
| va009039 | 0:65f1469d6bfb | 1201 | |
| va009039 | 0:65f1469d6bfb | 1202 | C_DEBUG_PRINT(VERBOSITY_LOW, "heap_gcRun()\n"); |
| va009039 | 0:65f1469d6bfb | 1203 | |
| va009039 | 0:65f1469d6bfb | 1204 | retval = heap_gcMarkRoots(); |
| va009039 | 0:65f1469d6bfb | 1205 | PM_RETURN_IF_ERROR(retval); |
| va009039 | 0:65f1469d6bfb | 1206 | |
| va009039 | 0:65f1469d6bfb | 1207 | /*heap_dump();*/ |
| va009039 | 0:65f1469d6bfb | 1208 | retval = heap_gcSweep(); |
| va009039 | 0:65f1469d6bfb | 1209 | /*heap_dump();*/ |
| va009039 | 0:65f1469d6bfb | 1210 | return retval; |
| va009039 | 0:65f1469d6bfb | 1211 | } |
| va009039 | 0:65f1469d6bfb | 1212 | |
| va009039 | 0:65f1469d6bfb | 1213 | |
| va009039 | 0:65f1469d6bfb | 1214 | /* Enables or disables automatic garbage collection */ |
| va009039 | 0:65f1469d6bfb | 1215 | PmReturn_t |
| va009039 | 0:65f1469d6bfb | 1216 | heap_gcSetAuto(uint8_t auto_gc) |
| va009039 | 0:65f1469d6bfb | 1217 | { |
| va009039 | 0:65f1469d6bfb | 1218 | pmHeap.auto_gc = auto_gc; |
| va009039 | 0:65f1469d6bfb | 1219 | return PM_RET_OK; |
| va009039 | 0:65f1469d6bfb | 1220 | } |
| va009039 | 0:65f1469d6bfb | 1221 | |
| va009039 | 0:65f1469d6bfb | 1222 | void heap_gcPushTempRoot(pPmObj_t pobj, uint8_t *r_objid) |
| va009039 | 0:65f1469d6bfb | 1223 | { |
| va009039 | 0:65f1469d6bfb | 1224 | if (pmHeap.temp_root_index < HEAP_NUM_TEMP_ROOTS) |
| va009039 | 0:65f1469d6bfb | 1225 | { |
| va009039 | 0:65f1469d6bfb | 1226 | *r_objid = pmHeap.temp_root_index; |
| va009039 | 0:65f1469d6bfb | 1227 | pmHeap.temp_roots[pmHeap.temp_root_index] = pobj; |
| va009039 | 0:65f1469d6bfb | 1228 | pmHeap.temp_root_index++; |
| va009039 | 0:65f1469d6bfb | 1229 | } |
| va009039 | 0:65f1469d6bfb | 1230 | return; |
| va009039 | 0:65f1469d6bfb | 1231 | } |
| va009039 | 0:65f1469d6bfb | 1232 | |
| va009039 | 0:65f1469d6bfb | 1233 | |
| va009039 | 0:65f1469d6bfb | 1234 | void heap_gcPopTempRoot(uint8_t objid) |
| va009039 | 0:65f1469d6bfb | 1235 | { |
| va009039 | 0:65f1469d6bfb | 1236 | pmHeap.temp_root_index = objid; |
| va009039 | 0:65f1469d6bfb | 1237 | } |
| va009039 | 0:65f1469d6bfb | 1238 | |
| va009039 | 0:65f1469d6bfb | 1239 | #else |
| va009039 | 0:65f1469d6bfb | 1240 | |
| va009039 | 0:65f1469d6bfb | 1241 | void heap_gcPushTempRoot(pPmObj_t pobj, uint8_t *r_objid) {} |
| va009039 | 0:65f1469d6bfb | 1242 | void heap_gcPopTempRoot(uint8_t objid) {} |
| va009039 | 0:65f1469d6bfb | 1243 | |
| va009039 | 0:65f1469d6bfb | 1244 | #endif /* HAVE_GC */ |
