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