python-on-a-chip online compiler

Dependencies:   mbed TSI

/media/uploads/va009039/p14p-f446re.png

more info: python-on-a-chip

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?

UserRevisionLine numberNew 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 */