00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #undef __FILE_ID__
00017 #define __FILE_ID__ 0x06
00018
00019
00030 #include "pm.h"
00031
00032
00034 #ifndef PM_HEAP_SIZE
00035 #warning PM_HEAP_SIZE not defined in src/platform/<yourplatform>/pmfeatures.h
00036 #elif PM_HEAP_SIZE & 3
00037 #error PM_HEAP_SIZE is not a multiple of four
00038 #endif
00039
00040
00042 #define HEAP_NUM_TEMP_ROOTS 24
00043
00050 #define HEAP_MAX_LIVE_CHUNK_SIZE 2044
00051
00058 #define HEAP_MAX_FREE_CHUNK_SIZE 65532
00059
00061 #define HEAP_MIN_CHUNK_SIZE ((sizeof(PmHeapDesc_t) + 3) & ~3)
00062
00063
00068 #define OBJ_GET_GCVAL(pobj) ((((pPmObj_t)pobj)->od >> OD_MARK_SHIFT) & 1)
00069
00074 #ifdef HAVE_GC
00075 #define OBJ_SET_GCVAL(pobj, gcval) \
00076 do \
00077 { \
00078 ((pPmObj_t)pobj)->od = (gcval) ? ((pPmObj_t)pobj)->od | OD_MARK_BIT \
00079 : ((pPmObj_t)pobj)->od & ~OD_MARK_BIT;\
00080 } \
00081 while (0)
00082 #else
00083 #define OBJ_SET_GCVAL(pobj, gcval)
00084 #endif
00085
00086
00108 typedef struct PmHeapDesc_s
00109 {
00111 uint16_t hd;
00112
00114 struct PmHeapDesc_s *prev;
00115
00117 struct PmHeapDesc_s *next;
00118 } PmHeapDesc_t,
00119 *pPmHeapDesc_t;
00120
00121 typedef struct PmHeap_s
00122 {
00123
00124
00125
00126
00127
00129 uint8_t base[PM_HEAP_SIZE];
00130
00132 pPmHeapDesc_t pfreelist;
00133
00135 #if PM_HEAP_SIZE > 65535
00136 uint32_t avail;
00137 #else
00138 uint16_t avail;
00139 #endif
00140
00141 #ifdef HAVE_GC
00142
00143 uint8_t gcval;
00144
00146 uint8_t auto_gc;
00147
00148
00150 pPmObj_t temp_roots[HEAP_NUM_TEMP_ROOTS];
00151
00152 uint8_t temp_root_index;
00153 #endif
00154
00155 } PmHeap_t,
00156 *pPmHeap_t;
00157
00158
00160 static PmHeap_t pmHeap PM_PLAT_HEAP_ATTR;
00161
00162
00163 #if 0
00164 static void
00165 heap_gcPrintFreelist(void)
00166 {
00167 pPmHeapDesc_t pchunk = pmHeap.pfreelist;
00168
00169 printf("DEBUG: pmHeap.avail = %d\n", pmHeap.avail);
00170 printf("DEBUG: freelist:\n");
00171 while (pchunk != C_NULL)
00172 {
00173 printf("DEBUG: free chunk (%d bytes) @ 0x%0x\n",
00174 OBJ_GET_SIZE(pchunk), (int)pchunk);
00175 pchunk = pchunk->next;
00176 }
00177 }
00178 #endif
00179
00180
00181 #if 0
00182
00183 static void
00184 heap_dump(void)
00185 {
00186 static int n = 0;
00187 uint16_t s;
00188 uint32_t i;
00189 void *b;
00190 char filename[32];
00191 FILE *fp;
00192
00193 snprintf(filename, 32, "pmheapdump%02d.bin", n++);
00194 fp = fopen(filename, "wb");
00195
00196
00197 fwrite(&"PM", 1, 2, fp);
00198 s = 0x5544;
00199 fwrite(&s, sizeof(uint16_t), 1, fp);
00200 fwrite(&"MP", 1, 2, fp);
00201
00202
00203 s = sizeof(intptr_t);
00204 fwrite(&s, sizeof(uint16_t), 1, fp);
00205
00206
00207 s = 1;
00208 fwrite(&s, sizeof(uint16_t), 1, fp);
00209
00210
00211 s = 0;
00212 #ifdef USE_STRING_CACHE
00213 s |= 1<<0;
00214 #endif
00215 #ifdef HAVE_DEFAULTARGS
00216 s |= 1<<1;
00217 #endif
00218 #ifdef HAVE_CLOSURES
00219 s |= 1<<2;
00220 #endif
00221 #ifdef HAVE_CLASSES
00222 s |= 1<<3;
00223 #endif
00224 fwrite(&s, sizeof(uint16_t), 1, fp);
00225
00226
00227 i = PM_HEAP_SIZE;
00228 fwrite(&i, sizeof(uint32_t), 1, fp);
00229
00230
00231 b=&pmHeap.base;
00232 fwrite((void*)(&b), sizeof(intptr_t), 1, fp);
00233
00234
00235 fwrite(&pmHeap.base, 1, PM_HEAP_SIZE, fp);
00236
00237
00238 i = 10;
00239 fwrite(&i, sizeof(uint32_t), 1, fp);
00240
00241
00242 fwrite((void *)&gVmGlobal.pnone, sizeof(intptr_t), 1, fp);
00243 fwrite((void *)&gVmGlobal.pfalse, sizeof(intptr_t), 1, fp);
00244 fwrite((void *)&gVmGlobal.ptrue, sizeof(intptr_t), 1, fp);
00245 fwrite((void *)&gVmGlobal.pzero, sizeof(intptr_t), 1, fp);
00246 fwrite((void *)&gVmGlobal.pone, sizeof(intptr_t), 1, fp);
00247 fwrite((void *)&gVmGlobal.pnegone, sizeof(intptr_t), 1, fp);
00248 fwrite((void *)&gVmGlobal.pcodeStr, sizeof(intptr_t), 1, fp);
00249 fwrite((void *)&gVmGlobal.builtins, sizeof(intptr_t), 1, fp);
00250 fwrite((void *)&gVmGlobal.nativeframe, sizeof(intptr_t), 1, fp);
00251 fwrite((void *)&gVmGlobal.threadList, sizeof(intptr_t), 1, fp);
00252 fclose(fp);
00253 }
00254 #endif
00255
00256
00257
00258 static PmReturn_t
00259 heap_unlinkFromFreelist(pPmHeapDesc_t pchunk)
00260 {
00261 C_ASSERT(pchunk != C_NULL);
00262
00263 pmHeap.avail -= OBJ_GET_SIZE(pchunk);
00264
00265 if (pchunk->next != C_NULL)
00266 {
00267 pchunk->next->prev = pchunk->prev;
00268 }
00269
00270
00271 if (pchunk->prev == C_NULL)
00272 {
00273 pmHeap.pfreelist = pchunk->next;
00274 }
00275 else
00276 {
00277 pchunk->prev->next = pchunk->next;
00278 }
00279
00280 return PM_RET_OK;
00281 }
00282
00283
00284
00285 static PmReturn_t
00286 heap_linkToFreelist(pPmHeapDesc_t pchunk)
00287 {
00288 uint16_t size;
00289 pPmHeapDesc_t pscan;
00290
00291
00292 C_ASSERT(OBJ_GET_FREE(pchunk) != 0);
00293
00294 pmHeap.avail += OBJ_GET_SIZE(pchunk);
00295
00296
00297 if (pmHeap.pfreelist == C_NULL)
00298 {
00299 pmHeap.pfreelist = pchunk;
00300 pchunk->next = C_NULL;
00301 pchunk->prev = C_NULL;
00302
00303 return PM_RET_OK;
00304 }
00305
00306
00307 pscan = pmHeap.pfreelist;
00308 size = OBJ_GET_SIZE(pchunk);
00309 while ((OBJ_GET_SIZE(pscan) < size) && (pscan->next != C_NULL))
00310 {
00311 pscan = pscan->next;
00312 }
00313
00314
00315
00316
00317
00318
00319 if (size > OBJ_GET_SIZE(pscan))
00320 {
00321 pchunk->next = pscan->next;
00322 pscan->next = pchunk;
00323 pchunk->prev = pscan;
00324 }
00325
00326
00327 else
00328 {
00329 pchunk->next = pscan;
00330 pchunk->prev = pscan->prev;
00331
00332
00333 if (pscan->prev == C_NULL)
00334 {
00335 pmHeap.pfreelist = pchunk;
00336 }
00337 else
00338 {
00339 pscan->prev->next = pchunk;
00340 }
00341 pscan->prev = pchunk;
00342 }
00343
00344 return PM_RET_OK;
00345 }
00346
00347
00348
00349
00350
00351 PmReturn_t
00352 heap_init(void)
00353 {
00354 pPmHeapDesc_t pchunk;
00355
00356 #if PM_HEAP_SIZE > 65535
00357 uint32_t hs;
00358 #else
00359 uint16_t hs;
00360 #endif
00361
00362 #if __DEBUG__
00363
00364 sli_memset(pmHeap.base, 0xAA, sizeof(pmHeap.base));
00365 #endif
00366
00367
00368 pmHeap.pfreelist = C_NULL;
00369 pmHeap.avail = 0;
00370 #ifdef HAVE_GC
00371 pmHeap.gcval = (uint8_t)0;
00372 pmHeap.temp_root_index = (uint8_t)0;
00373 heap_gcSetAuto(C_TRUE);
00374 #endif
00375
00376
00377 for (pchunk = (pPmHeapDesc_t)pmHeap.base, hs = PM_HEAP_SIZE;
00378 hs >= HEAP_MAX_FREE_CHUNK_SIZE; hs -= HEAP_MAX_FREE_CHUNK_SIZE)
00379 {
00380 OBJ_SET_FREE(pchunk, 1);
00381 OBJ_SET_SIZE(pchunk, HEAP_MAX_FREE_CHUNK_SIZE);
00382 heap_linkToFreelist(pchunk);
00383 pchunk =
00384 (pPmHeapDesc_t)((uint8_t *)pchunk + HEAP_MAX_FREE_CHUNK_SIZE);
00385 }
00386
00387
00388 if (hs >= HEAP_MIN_CHUNK_SIZE)
00389 {
00390
00391 hs = hs & ~3;
00392 OBJ_SET_FREE(pchunk, 1);
00393 OBJ_SET_SIZE(pchunk, hs);
00394 heap_linkToFreelist(pchunk);
00395 }
00396
00397 C_DEBUG_PRINT(VERBOSITY_LOW, "heap_init(), id=%p, s=%d\n",
00398 pmHeap.base, pmHeap.avail);
00399
00400 string_cacheInit();
00401
00402 return PM_RET_OK;
00403 }
00404
00405
00418 static PmReturn_t
00419 heap_getChunkImpl(uint16_t size, uint8_t **r_pchunk)
00420 {
00421 PmReturn_t retval;
00422 pPmHeapDesc_t pchunk;
00423 pPmHeapDesc_t premainderChunk;
00424
00425 C_ASSERT(r_pchunk != C_NULL);
00426
00427
00428 pchunk = pmHeap.pfreelist;
00429 while ((pchunk != C_NULL) && (OBJ_GET_SIZE(pchunk) < size))
00430 {
00431 pchunk = pchunk->next;
00432 }
00433
00434
00435 if (pchunk == C_NULL)
00436 {
00437 *r_pchunk = C_NULL;
00438 PM_RAISE(retval, PM_RET_EX_MEM);
00439 return retval;
00440 }
00441
00442
00443 retval = heap_unlinkFromFreelist(pchunk);
00444 PM_RETURN_IF_ERROR(retval);
00445
00446
00447 if (OBJ_GET_SIZE(pchunk) - size >= HEAP_MIN_CHUNK_SIZE)
00448 {
00449
00450 premainderChunk = (pPmHeapDesc_t)((uint8_t *)pchunk + size);
00451 OBJ_SET_FREE(premainderChunk, 1);
00452 OBJ_SET_SIZE(premainderChunk, OBJ_GET_SIZE(pchunk) - size);
00453
00454
00455 retval = heap_linkToFreelist(premainderChunk);
00456 PM_RETURN_IF_ERROR(retval);
00457
00458
00459 OBJ_SET_SIZE(pchunk, 0);
00460 OBJ_SET_FREE(pchunk, 0);
00461 OBJ_SET_SIZE(pchunk, size);
00462
00463 C_DEBUG_PRINT(VERBOSITY_HIGH,
00464 "heap_getChunkImpl()carved, id=%p, s=%d\n", pchunk,
00465 size);
00466 }
00467 else
00468 {
00469
00470 OBJ_SET_TYPE((pPmObj_t)pchunk, OBJ_TYPE_NON);
00471 OBJ_SET_FREE(pchunk, 0);
00472
00473 C_DEBUG_PRINT(VERBOSITY_HIGH,
00474 "heap_getChunkImpl()exact, id=%p, s=%d\n", pchunk,
00475 OBJ_GET_SIZE(pchunk));
00476 }
00477
00478
00479
00480
00481
00482 OBJ_SET_GCVAL(pchunk, pmHeap.gcval);
00483
00484
00485 *r_pchunk = (uint8_t *)pchunk;
00486
00487 return retval;
00488 }
00489
00490
00491
00492
00493
00494
00495
00496
00497 PmReturn_t
00498 heap_getChunk(uint16_t requestedsize, uint8_t **r_pchunk)
00499 {
00500 PmReturn_t retval;
00501 uint16_t adjustedsize;
00502
00503
00504 if (requestedsize > HEAP_MAX_LIVE_CHUNK_SIZE)
00505 {
00506 PM_RAISE(retval, PM_RET_EX_MEM);
00507 return retval;
00508 }
00509
00510 else if (requestedsize < HEAP_MIN_CHUNK_SIZE)
00511 {
00512 requestedsize = HEAP_MIN_CHUNK_SIZE;
00513 }
00514
00515
00516
00517
00518
00519 adjustedsize = ((requestedsize + 3) & ~3);
00520
00521
00522 retval = heap_getChunkImpl(adjustedsize, r_pchunk);
00523
00524 #ifdef HAVE_GC
00525
00526 if ((retval == PM_RET_EX_MEM) && (pmHeap.auto_gc == C_TRUE)
00527 && (gVmGlobal.nativeframe.nf_active == C_FALSE))
00528 {
00529 retval = heap_gcRun();
00530 PM_RETURN_IF_ERROR(retval);
00531
00532
00533 retval = heap_getChunkImpl(adjustedsize, r_pchunk);
00534 }
00535 #endif
00536
00537
00538 if (retval == PM_RET_OK)
00539 {
00540 C_ASSERT(((intptr_t)*r_pchunk & 3) == 0);
00541 }
00542
00543 return retval;
00544 }
00545
00546
00547
00548 PmReturn_t
00549 heap_freeChunk(pPmObj_t ptr)
00550 {
00551 PmReturn_t retval;
00552
00553 C_DEBUG_PRINT(VERBOSITY_HIGH, "heap_freeChunk(), id=%p, s=%d\n",
00554 ptr, OBJ_GET_SIZE(ptr));
00555
00556
00557 C_ASSERT(((uint8_t *)ptr >= pmHeap.base)
00558 && ((uint8_t *)ptr < pmHeap.base + PM_HEAP_SIZE));
00559
00560
00561 OBJ_SET_FREE(ptr, 1);
00562
00563
00564 OBJ_SET_TYPE(ptr, 0);
00565 retval = heap_linkToFreelist((pPmHeapDesc_t)ptr);
00566 PM_RETURN_IF_ERROR(retval);
00567
00568 return retval;
00569 }
00570
00571
00572
00573 #if PM_HEAP_SIZE > 65535
00574 uint32_t
00575 #else
00576 uint16_t
00577 #endif
00578 heap_getAvail(void)
00579 {
00580 return pmHeap.avail;
00581 }
00582
00583
00584 #ifdef HAVE_GC
00585
00586
00587
00588
00589
00590
00591 static PmReturn_t
00592 heap_gcMarkObj(pPmObj_t pobj)
00593 {
00594 PmReturn_t retval = PM_RET_OK;
00595 int16_t i = 0;
00596 int16_t n;
00597 PmType_t type;
00598
00599
00600 if (pobj == C_NULL)
00601 {
00602 return retval;
00603 }
00604 if (OBJ_GET_GCVAL(pobj) == pmHeap.gcval)
00605 {
00606 return retval;
00607 }
00608
00609
00610 C_ASSERT((((uint8_t *)pobj >= &pmHeap.base[0])
00611 && ((uint8_t *)pobj <= &pmHeap.base[PM_HEAP_SIZE]))
00612 || ((uint8_t *)pobj == (uint8_t *)&gVmGlobal.nativeframe));
00613
00614
00615 C_ASSERT(OBJ_GET_FREE(pobj) == 0);
00616
00617 type = (PmType_t)OBJ_GET_TYPE(pobj);
00618 switch (type)
00619 {
00620
00621 case OBJ_TYPE_NON:
00622 case OBJ_TYPE_INT:
00623 case OBJ_TYPE_FLT:
00624 case OBJ_TYPE_STR:
00625 case OBJ_TYPE_NOB:
00626 case OBJ_TYPE_BOOL:
00627 case OBJ_TYPE_CIO:
00628 OBJ_SET_GCVAL(pobj, pmHeap.gcval);
00629 break;
00630
00631 case OBJ_TYPE_TUP:
00632 i = ((pPmTuple_t)pobj)->length;
00633
00634
00635 OBJ_SET_GCVAL(pobj, pmHeap.gcval);
00636
00637
00638 while (--i >= 0)
00639 {
00640 retval = heap_gcMarkObj(((pPmTuple_t)pobj)->val[i]);
00641 PM_RETURN_IF_ERROR(retval);
00642 }
00643 break;
00644
00645 case OBJ_TYPE_LST:
00646
00647
00648 OBJ_SET_GCVAL(pobj, pmHeap.gcval);
00649
00650
00651 retval = heap_gcMarkObj((pPmObj_t)((pPmList_t)pobj)->val);
00652 break;
00653
00654 case OBJ_TYPE_DIC:
00655
00656 OBJ_SET_GCVAL(pobj, pmHeap.gcval);
00657
00658
00659 retval = heap_gcMarkObj((pPmObj_t)((pPmDict_t)pobj)->d_keys);
00660 PM_RETURN_IF_ERROR(retval);
00661
00662
00663 retval = heap_gcMarkObj((pPmObj_t)((pPmDict_t)pobj)->d_vals);
00664 break;
00665
00666 case OBJ_TYPE_COB:
00667
00668 OBJ_SET_GCVAL(pobj, pmHeap.gcval);
00669
00670
00671 retval = heap_gcMarkObj((pPmObj_t)((pPmCo_t)pobj)->co_names);
00672 PM_RETURN_IF_ERROR(retval);
00673
00674
00675 retval = heap_gcMarkObj((pPmObj_t)((pPmCo_t)pobj)->co_consts);
00676 PM_RETURN_IF_ERROR(retval);
00677
00678
00679 if (((pPmCo_t)pobj)->co_memspace == MEMSPACE_RAM)
00680 {
00681 retval = heap_gcMarkObj((pPmObj_t)
00682 (((pPmCo_t)pobj)->co_codeimgaddr));
00683 PM_RETURN_IF_ERROR(retval);
00684 }
00685
00686 #ifdef HAVE_CLOSURES
00687
00688
00689 retval = heap_gcMarkObj((pPmObj_t)((pPmCo_t)pobj)->co_cellvars);
00690 #endif
00691 break;
00692
00693 case OBJ_TYPE_MOD:
00694 case OBJ_TYPE_FXN:
00695
00696
00697 OBJ_SET_GCVAL(pobj, pmHeap.gcval);
00698
00699
00700 retval = heap_gcMarkObj((pPmObj_t)((pPmFunc_t)pobj)->f_co);
00701 PM_RETURN_IF_ERROR(retval);
00702
00703
00704 retval = heap_gcMarkObj((pPmObj_t)((pPmFunc_t)pobj)->f_attrs);
00705 PM_RETURN_IF_ERROR(retval);
00706
00707
00708 retval = heap_gcMarkObj((pPmObj_t)((pPmFunc_t)pobj)->f_globals);
00709 PM_RETURN_IF_ERROR(retval);
00710
00711 #ifdef HAVE_DEFAULTARGS
00712
00713 retval = heap_gcMarkObj((pPmObj_t)((pPmFunc_t)pobj)->f_defaultargs);
00714 PM_RETURN_IF_ERROR(retval);
00715 #endif
00716
00717 #ifdef HAVE_CLOSURES
00718
00719 retval = heap_gcMarkObj((pPmObj_t)((pPmFunc_t)pobj)->f_closure);
00720 #endif
00721 break;
00722
00723 #ifdef HAVE_CLASSES
00724 case OBJ_TYPE_CLI:
00725
00726 OBJ_SET_GCVAL(pobj, pmHeap.gcval);
00727
00728
00729 retval = heap_gcMarkObj((pPmObj_t)((pPmInstance_t)pobj)->cli_class);
00730 PM_RETURN_IF_ERROR(retval);
00731
00732
00733 retval = heap_gcMarkObj((pPmObj_t)((pPmInstance_t)pobj)->cli_attrs);
00734 break;
00735
00736 case OBJ_TYPE_MTH:
00737
00738 OBJ_SET_GCVAL(pobj, pmHeap.gcval);
00739
00740
00741 retval = heap_gcMarkObj((pPmObj_t)((pPmMethod_t)pobj)->m_instance);
00742 PM_RETURN_IF_ERROR(retval);
00743
00744
00745 retval = heap_gcMarkObj((pPmObj_t)((pPmMethod_t)pobj)->m_func);
00746 PM_RETURN_IF_ERROR(retval);
00747
00748
00749 retval = heap_gcMarkObj((pPmObj_t)((pPmMethod_t)pobj)->m_attrs);
00750 break;
00751
00752 case OBJ_TYPE_CLO:
00753
00754 OBJ_SET_GCVAL(pobj, pmHeap.gcval);
00755
00756
00757 retval = heap_gcMarkObj((pPmObj_t)((pPmClass_t)pobj)->cl_attrs);
00758 PM_RETURN_IF_ERROR(retval);
00759
00760
00761 retval = heap_gcMarkObj((pPmObj_t)((pPmClass_t)pobj)->cl_bases);
00762 break;
00763 #endif
00764
00765
00766
00767
00768
00769 case OBJ_TYPE_CIM:
00770 case OBJ_TYPE_NIM:
00771 PM_RAISE(retval, PM_RET_EX_SYS);
00772 return retval;
00773
00774 case OBJ_TYPE_FRM:
00775 {
00776 pPmObj_t *ppobj2 = C_NULL;
00777
00778
00779 OBJ_SET_GCVAL(pobj, pmHeap.gcval);
00780
00781
00782
00783 if ((((pPmFrame_t)pobj)->fo_func->f_co->co_flags & CO_GENERATOR) == 0)
00784 {
00785 retval = heap_gcMarkObj((pPmObj_t)((pPmFrame_t)pobj)->fo_back);
00786 PM_RETURN_IF_ERROR(retval);
00787 }
00788
00789
00790 retval = heap_gcMarkObj((pPmObj_t)((pPmFrame_t)pobj)->fo_func);
00791 PM_RETURN_IF_ERROR(retval);
00792
00793
00794 retval = heap_gcMarkObj((pPmObj_t)
00795 ((pPmFrame_t)pobj)->fo_blockstack);
00796 PM_RETURN_IF_ERROR(retval);
00797
00798
00799 retval = heap_gcMarkObj((pPmObj_t)((pPmFrame_t)pobj)->fo_attrs);
00800 PM_RETURN_IF_ERROR(retval);
00801
00802
00803 retval = heap_gcMarkObj((pPmObj_t)((pPmFrame_t)pobj)->fo_globals);
00804 PM_RETURN_IF_ERROR(retval);
00805
00806
00807 ppobj2 = ((pPmFrame_t)pobj)->fo_locals;
00808 while (ppobj2 < ((pPmFrame_t)pobj)->fo_sp)
00809 {
00810 retval = heap_gcMarkObj(*ppobj2);
00811 PM_RETURN_IF_ERROR(retval);
00812 ppobj2++;
00813 }
00814 break;
00815 }
00816
00817 case OBJ_TYPE_BLK:
00818
00819 OBJ_SET_GCVAL(pobj, pmHeap.gcval);
00820
00821
00822 retval = heap_gcMarkObj((pPmObj_t)((pPmBlock_t)pobj)->next);
00823 break;
00824
00825 case OBJ_TYPE_SGL:
00826
00827 OBJ_SET_GCVAL(pobj, pmHeap.gcval);
00828
00829
00830 n = ((pSeglist_t)pobj)->sl_length;
00831 pobj = (pPmObj_t)((pSeglist_t)pobj)->sl_rootseg;
00832 for (i = 0; i < n; i++)
00833 {
00834
00835 retval = heap_gcMarkObj(((pSegment_t)pobj)->s_val[i % SEGLIST_OBJS_PER_SEG]);
00836 PM_RETURN_IF_ERROR(retval);
00837
00838
00839 if ((i % SEGLIST_OBJS_PER_SEG) == 0)
00840 {
00841 OBJ_SET_GCVAL(pobj, pmHeap.gcval);
00842 }
00843
00844
00845 else
00846 if ((i % SEGLIST_OBJS_PER_SEG) == (SEGLIST_OBJS_PER_SEG - 1))
00847 {
00848 pobj = (pPmObj_t)((pSegment_t)pobj)->next;
00849 if (pobj == C_NULL)
00850 {
00851 break;
00852 }
00853 }
00854 }
00855 break;
00856
00857 case OBJ_TYPE_SQI:
00858
00859 OBJ_SET_GCVAL(pobj, pmHeap.gcval);
00860
00861
00862 retval = heap_gcMarkObj(((pPmSeqIter_t)pobj)->si_sequence);
00863 break;
00864
00865 case OBJ_TYPE_THR:
00866
00867 OBJ_SET_GCVAL(pobj, pmHeap.gcval);
00868
00869
00870 retval = heap_gcMarkObj((pPmObj_t)((pPmThread_t)pobj)->pframe);
00871 break;
00872
00873 case OBJ_TYPE_NFM:
00874
00875
00876
00877
00878
00879 OBJ_SET_GCVAL(pobj, pmHeap.gcval);
00880
00881
00882 if (gVmGlobal.nativeframe.nf_active)
00883 {
00884
00885 retval = heap_gcMarkObj((pPmObj_t)
00886 gVmGlobal.nativeframe.nf_back);
00887 PM_RETURN_IF_ERROR(retval);
00888
00889
00890 retval = heap_gcMarkObj((pPmObj_t)
00891 gVmGlobal.nativeframe.nf_func);
00892 PM_RETURN_IF_ERROR(retval);
00893
00894
00895 retval = heap_gcMarkObj(gVmGlobal.nativeframe.nf_stack);
00896 PM_RETURN_IF_ERROR(retval);
00897
00898
00899 for (i = 0; i < NATIVE_GET_NUM_ARGS(); i++)
00900 {
00901 retval =
00902 heap_gcMarkObj(gVmGlobal.nativeframe.nf_locals[i]);
00903 PM_RETURN_IF_ERROR(retval);
00904 }
00905 }
00906 break;
00907
00908 #ifdef HAVE_BYTEARRAY
00909 case OBJ_TYPE_BYA:
00910 OBJ_SET_GCVAL(pobj, pmHeap.gcval);
00911
00912 retval = heap_gcMarkObj((pPmObj_t)((pPmBytearray_t)pobj)->val);
00913 break;
00914
00915 case OBJ_TYPE_BYS:
00916 OBJ_SET_GCVAL(pobj, pmHeap.gcval);
00917 break;
00918 #endif
00919
00920 default:
00921
00922 PM_RAISE(retval, PM_RET_EX_SYS);
00923 break;
00924 }
00925 return retval;
00926 }
00927
00928
00929
00930
00931
00932
00933 static PmReturn_t
00934 heap_gcMarkRoots(void)
00935 {
00936 PmReturn_t retval;
00937 uint8_t i;
00938
00939
00940 pmHeap.gcval ^= 1;
00941
00942
00943 retval = heap_gcMarkObj(PM_NONE);
00944 PM_RETURN_IF_ERROR(retval);
00945 retval = heap_gcMarkObj(PM_FALSE);
00946 PM_RETURN_IF_ERROR(retval);
00947 retval = heap_gcMarkObj(PM_TRUE);
00948 PM_RETURN_IF_ERROR(retval);
00949 retval = heap_gcMarkObj(PM_ZERO);
00950 PM_RETURN_IF_ERROR(retval);
00951 retval = heap_gcMarkObj(PM_ONE);
00952 PM_RETURN_IF_ERROR(retval);
00953 retval = heap_gcMarkObj(PM_NEGONE);
00954 PM_RETURN_IF_ERROR(retval);
00955 retval = heap_gcMarkObj(PM_CODE_STR);
00956 PM_RETURN_IF_ERROR(retval);
00957
00958
00959 retval = heap_gcMarkObj(PM_PBUILTINS);
00960 PM_RETURN_IF_ERROR(retval);
00961
00962
00963 retval = heap_gcMarkObj((pPmObj_t)&gVmGlobal.nativeframe);
00964 PM_RETURN_IF_ERROR(retval);
00965
00966
00967 retval = heap_gcMarkObj((pPmObj_t)gVmGlobal.threadList);
00968 PM_RETURN_IF_ERROR(retval);
00969
00970
00971 for (i = 0; i < pmHeap.temp_root_index; i++)
00972 {
00973 retval = heap_gcMarkObj(pmHeap.temp_roots[i]);
00974 PM_RETURN_IF_ERROR(retval);
00975 }
00976
00977 return retval;
00978 }
00979
00980
00981 #if USE_STRING_CACHE
00982
00992 static PmReturn_t
00993 heap_purgeStringCache(uint8_t gcval)
00994 {
00995 PmReturn_t retval;
00996 pPmString_t *ppstrcache;
00997 pPmString_t pstr;
00998
00999
01000 retval = string_getCache(&ppstrcache);
01001 if (ppstrcache == C_NULL)
01002 {
01003 return retval;
01004 }
01005 while ((*ppstrcache != C_NULL) && (OBJ_GET_GCVAL(*ppstrcache) != gcval))
01006 {
01007 *ppstrcache = (*ppstrcache)->next;
01008 }
01009 if (*ppstrcache == C_NULL)
01010 {
01011 return retval;
01012 }
01013
01014
01015 for (pstr = *ppstrcache; pstr->next != C_NULL;)
01016 {
01017
01018 while ((pstr->next != C_NULL) && (OBJ_GET_GCVAL(pstr->next) != gcval))
01019 {
01020 pstr->next = pstr->next->next;
01021 }
01022
01023
01024 if (pstr->next != C_NULL)
01025 {
01026 pstr = pstr->next;
01027 }
01028 }
01029
01030 return retval;
01031 }
01032 #endif
01033
01034
01035
01036
01037
01038
01039 static PmReturn_t
01040 heap_gcSweep(void)
01041 {
01042 PmReturn_t retval;
01043 pPmObj_t pobj;
01044 pPmHeapDesc_t pchunk;
01045 uint16_t totalchunksize;
01046
01047 #if USE_STRING_CACHE
01048 retval = heap_purgeStringCache(pmHeap.gcval);
01049 #endif
01050
01051
01052 pobj = (pPmObj_t)pmHeap.base;
01053 while ((uint8_t *)pobj < &pmHeap.base[PM_HEAP_SIZE])
01054 {
01055
01056 while (!OBJ_GET_FREE(pobj)
01057 && (OBJ_GET_GCVAL(pobj) == pmHeap.gcval)
01058 && ((uint8_t *)pobj < &pmHeap.base[PM_HEAP_SIZE]))
01059 {
01060 pobj = (pPmObj_t)((uint8_t *)pobj + OBJ_GET_SIZE(pobj));
01061 }
01062
01063
01064 if ((uint8_t *)pobj >= &pmHeap.base[PM_HEAP_SIZE])
01065 {
01066 break;
01067 }
01068
01069
01070 totalchunksize = 0;
01071
01072
01073 pchunk = (pPmHeapDesc_t)pobj;
01074 while (OBJ_GET_FREE(pchunk)
01075 || (!OBJ_GET_FREE(pchunk)
01076 && (OBJ_GET_GCVAL(pchunk) != pmHeap.gcval)))
01077 {
01078 if ((totalchunksize + OBJ_GET_SIZE(pchunk))
01079 > HEAP_MAX_FREE_CHUNK_SIZE)
01080 {
01081 break;
01082 }
01083 totalchunksize = totalchunksize + OBJ_GET_SIZE(pchunk);
01084
01085
01086
01087
01088
01089 if (OBJ_GET_FREE(pchunk))
01090 {
01091 retval = heap_unlinkFromFreelist(pchunk);
01092 PM_RETURN_IF_ERROR(retval);
01093 }
01094
01095
01096 else
01097 {
01098 OBJ_SET_TYPE(pchunk, 0);
01099 OBJ_SET_FREE(pchunk, 1);
01100 }
01101
01102 C_DEBUG_PRINT(VERBOSITY_HIGH, "heap_gcSweep(), id=%p, s=%d\n",
01103 pchunk, OBJ_GET_SIZE(pchunk));
01104
01105
01106 pchunk = (pPmHeapDesc_t)
01107 ((uint8_t *)pchunk + OBJ_GET_SIZE(pchunk));
01108
01109
01110 if ((uint8_t *)pchunk >= &pmHeap.base[PM_HEAP_SIZE])
01111 {
01112 break;
01113 }
01114 }
01115
01116
01117 OBJ_SET_FREE(pobj, 1);
01118 OBJ_SET_SIZE(pobj, totalchunksize);
01119
01120
01121 retval = heap_linkToFreelist((pPmHeapDesc_t)pobj);
01122 PM_RETURN_IF_ERROR(retval);
01123
01124
01125 pobj = (pPmObj_t)pchunk;
01126 }
01127
01128 return PM_RET_OK;
01129 }
01130
01131
01132
01133 PmReturn_t
01134 heap_gcRun(void)
01135 {
01136 PmReturn_t retval;
01137
01138
01139
01140
01141
01142 C_ASSERT(pmHeap.temp_root_index < HEAP_NUM_TEMP_ROOTS);
01143
01144 C_DEBUG_PRINT(VERBOSITY_LOW, "heap_gcRun()\n");
01145
01146
01147 retval = heap_gcMarkRoots();
01148 PM_RETURN_IF_ERROR(retval);
01149
01150 retval = heap_gcSweep();
01151
01152 return retval;
01153 }
01154
01155
01156
01157 PmReturn_t
01158 heap_gcSetAuto(uint8_t auto_gc)
01159 {
01160 pmHeap.auto_gc = auto_gc;
01161 return PM_RET_OK;
01162 }
01163
01164 void heap_gcPushTempRoot(pPmObj_t pobj, uint8_t *r_objid)
01165 {
01166 if (pmHeap.temp_root_index < HEAP_NUM_TEMP_ROOTS)
01167 {
01168 *r_objid = pmHeap.temp_root_index;
01169 pmHeap.temp_roots[pmHeap.temp_root_index] = pobj;
01170 pmHeap.temp_root_index++;
01171 }
01172 return;
01173 }
01174
01175
01176 void heap_gcPopTempRoot(uint8_t objid)
01177 {
01178 pmHeap.temp_root_index = objid;
01179 }
01180
01181 #else
01182
01183 void heap_gcPushTempRoot(pPmObj_t pobj, uint8_t *r_objid) {}
01184 void heap_gcPopTempRoot(uint8_t objid) {}
01185
01186 #endif