Norimasa Okamoto
/
pymite
python-on-a-chip online compiler
- http://pymbed.appspot.com/
- https://code.google.com/p/python-on-a-chip/
- http://www.youtube.com/watch?v=Oyqc2bFRW9I
- https://bitbucket.org/va009039/pymbed/
more info: python-on-a-chip
vm/heap.c@15:94ca5c8003e5, 2016-04-14 (annotated)
- Committer:
- va009039
- Date:
- Thu Apr 14 22:32:57 2016 +0000
- Revision:
- 15:94ca5c8003e5
- Parent:
- 0:65f1469d6bfb
update Nucleo-F401RE.
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 */ |