This source file includes following definitions.
- mytime
- potion_stack_len
- pngc_mark_array
- potion_mark_stack
- pngc_page_new
- pngc_page_delete
- NEW_BIRTH_REGION
- potion_gc_minor
- potion_gc_major
- potion_garbagecollect
- potion_type_size
- potion_gc_copy
- potion_mark_minor
- potion_mark_major
- potion_gc_boot
- potion_gc_release
- potion_gc_actual
- potion_gc_fixed
- potion_gc_reserved
#include <stdio.h>
#include <stdlib.h>
#include "p2.h"
#include "internal.h"
#include "gc.h"
#include "khash.h"
#include "table.h"
#if defined(DEBUG)
#ifdef WIN32
# include <time.h>
#else
# include <sys/time.h>
#endif
#ifdef WIN32
# include <time.h>
#else
# include <sys/time.h>
#endif
static double mytime() {
struct timeval Tp;
struct timezone Tz;
int status;
status = gettimeofday (&Tp, &Tz);
if (status == 0) {
Tp.tv_sec += Tz.tz_minuteswest * 60;
return Tp.tv_sec + (Tp.tv_usec / 1000000.0);
} else {
return -1.0;
}
}
#define DBG_Gv(P,...) \
if (P->flags & DEBUG_GC && P->flags & DEBUG_VERBOSE) { \
printf(__VA_ARGS__); \
}
#define DBG_G(P,...) \
if (P->flags & DEBUG_GC) { \
printf(__VA_ARGS__); \
}
#else
#define DBG_Gv(...)
#define DBG_G(...)
#endif
PN_SIZE potion_stack_len(Potion *P, _PN **p) {
_PN *esp, *c = P->mem->cstack;
POTION_ESP(&esp);
if (p) *p = STACK_UPPER(c, esp);
return esp < c ? c - esp : esp - c + 1;
}
#define HAS_REAL_TYPE(v) (P->vts == NULL || (((struct PNFwd *)v)->fwd == POTION_COPIED || PN_TYPECHECK(PN_VTYPE(v))))
ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS
static PN_SIZE pngc_mark_array(Potion *P, register _PN *x, register long n, int type) {
_PN v;
PN_SIZE i = 0;
struct PNMemory *M = P->mem;
while (n--) {
v = *x;
if (IS_GC_PROTECTED(v) || IN_BIRTH_REGION(v) || IN_OLDER_REGION(v)) {
v = potion_fwd(v);
switch (type) {
case 0:
if (!IS_GC_PROTECTED(v) && IN_BIRTH_REGION(v) && HAS_REAL_TYPE(v)) {
i++;
DBG_Gv(P,"GC mark count only %p %6x\n", x, PN_TYPE(*x));
}
break;
case 1:
if (!IS_GC_PROTECTED(v) && IN_BIRTH_REGION(v) && HAS_REAL_TYPE(v)) {
GC_FORWARD(x, v);
i++;
DBG_Gv(P,"GC mark minor %p -> 0x%lx %6x\n", x, v, PN_TYPE(*x));
}
break;
case 2:
if (!IS_GC_PROTECTED(v) && (IN_BIRTH_REGION(v) || IN_OLDER_REGION(v)) && HAS_REAL_TYPE(v)) {
GC_FORWARD(x, v);
i++;
DBG_Gv(P,"GC mark major %p -> 0x%lx %6x\n", x, v, PN_TYPE(*x));
}
break;
}
}
x++;
}
return i;
}
ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS
PN_SIZE potion_mark_stack(Potion *P, int type) {
long n;
_PN *end, *start = P->mem->cstack;
POTION_ESP(&end);
#if POTION_STACK_DIR > 0
n = end - start;
#else
n = start - end + 1;
start = end;
end = P->mem->cstack;
#endif
DBG_Gv(P,"mark_stack (%p -> %p = %ld, type=%d)\n", start, end, n, type);
if (n <= 0) return 0;
return pngc_mark_array(P, start, n, type);
}
void *pngc_page_new(int *sz, const char exec) {
*sz = PN_ALIGN(*sz, POTION_PAGESIZE);
return potion_mmap(*sz, exec);
}
void pngc_page_delete(void *mem, int sz) {
potion_munmap(mem, PN_ALIGN(sz, POTION_PAGESIZE));
}
static inline int NEW_BIRTH_REGION(struct PNMemory *M, void **wb, int sz) {
int keeps = wb - (void **)M->birth_storeptr;
void *newad = pngc_page_new(&sz, 0);
wb = (void *)(((void **)(newad + sz)) - (keeps + 4));
PN_MEMCPY_N(wb + 1, M->birth_storeptr + 1, void *, keeps);
DEL_BIRTH_REGION();
SET_GEN(birth, newad, sz);
SET_STOREPTR(5 + keeps);
return sz;
}
static int potion_gc_minor(Potion *P, int sz) {
struct PNMemory *M = P->mem;
void *scanptr = 0;
void **storead = 0, **wb = 0;
if (sz < 0)
sz = 0;
else if (sz >= POTION_MAX_BIRTH_SIZE)
return POTION_NO_MEM;
scanptr = (void *) M->old_cur;
DBG_G(P,"running gc_minor "
"(young: %p -> %p = %ld) "
"(old: %p -> %p = %ld) "
"(storeptr len = %ld)\n",
M->birth_lo, M->birth_hi, (long)(M->birth_hi - M->birth_lo),
M->old_lo, M->old_hi, (long)(M->old_hi - M->old_lo),
(long)((void *)M->birth_hi - (void *)M->birth_storeptr));
potion_mark_stack(P, 1);
GC_MINOR_STRINGS();
wb = (void **)M->birth_storeptr;
for (storead = wb; storead < (void **)M->birth_hi; storead++) {
PN v = (PN)*storead;
if (PN_IS_PTR(v))
potion_mark_minor(P, (const struct PNObject *)v);
}
storead = 0;
while ((PN)scanptr < (PN)M->old_cur)
scanptr = potion_mark_minor(P, scanptr);
scanptr = 0;
sz += 2 * POTION_PAGESIZE;
sz = max(sz, potion_birth_suggest(sz, M->old_lo, M->old_cur));
sz = NEW_BIRTH_REGION(M, wb, sz);
M->minors++;
DBG_G(P,"(new young: %p -> %p = %ld)\n", M->birth_lo, M->birth_hi, (long)(M->birth_hi - M->birth_lo));
return POTION_OK;
}
static int potion_gc_major(Potion *P, int siz) {
struct PNMemory *M = P->mem;
void *prevoldlo = 0;
void *prevoldhi = 0;
void *prevoldcur = 0;
void *newold = 0;
void *protptr = (void *)M + PN_ALIGN(sizeof(struct PNMemory), 8);
void *scanptr = 0;
void **wb = 0;
int birthest = 0;
int birthsiz = 0;
int newoldsiz = 0;
int oldsiz = 0;
if (siz < 0)
siz = 0;
else if (siz >= POTION_MAX_BIRTH_SIZE)
return POTION_NO_MEM;
prevoldlo = (void *)M->old_lo;
prevoldhi = (void *)M->old_hi;
prevoldcur = (void *)M->old_cur;
DBG_G(P,"running gc_major "
"(young: %p -> %p = %ld) "
"(old: %p -> %p = %ld)\n",
M->birth_lo, M->birth_hi, (long)(M->birth_hi - M->birth_lo),
M->old_lo, M->old_hi, (long)(M->old_hi - M->old_lo));
birthest = potion_birth_suggest(siz, prevoldlo, prevoldcur);
newoldsiz = (((char *)prevoldcur - (char *)prevoldlo) + siz + birthest +
POTION_GC_THRESHOLD + 16 * POTION_PAGESIZE) + ((char *)M->birth_cur - (char *)M->birth_lo);
newold = pngc_page_new(&newoldsiz, 0);
M->old_cur = scanptr = newold + (sizeof(PN) * 2);
DBG_G(P,"(new old: %p -> %p = %d)\n", newold, (char *)newold + newoldsiz, newoldsiz);
potion_mark_stack(P, 2);
wb = (void **)M->birth_storeptr;
if (M->birth_lo != M) {
while ((PN)protptr < (PN)M->protect)
protptr = potion_mark_major(P, protptr);
}
while ((PN)scanptr < (PN)M->old_cur)
scanptr = potion_mark_major(P, scanptr);
scanptr = 0;
GC_MAJOR_STRINGS();
pngc_page_delete((void *)prevoldlo, (char *)prevoldhi - (char *)prevoldlo);
prevoldlo = 0;
prevoldhi = 0;
prevoldcur = 0;
birthsiz = NEW_BIRTH_REGION(M, wb, siz + birthest);
oldsiz = ((char *)M->old_cur - (char *)newold) +
(birthsiz + 2 * birthest + 4 * POTION_PAGESIZE);
oldsiz = PN_ALIGN(oldsiz, POTION_PAGESIZE);
if (oldsiz < newoldsiz) {
pngc_page_delete((void *)newold + oldsiz, newoldsiz - oldsiz);
newoldsiz = oldsiz;
}
M->old_lo = newold;
M->old_hi = (char *)newold + newoldsiz;
M->majors++;
newold = 0;
return POTION_OK;
}
void potion_garbagecollect(Potion *P, int sz, int full) {
struct PNMemory *M = P->mem;
if (M->collecting) return;
#ifdef DEBUG
double time = mytime();
#endif
M->pass++;
M->collecting = 1;
if (M->old_lo == NULL) {
int gensz = POTION_MIN_BIRTH_SIZE * 4;
if (gensz < sz * 4)
gensz = min(POTION_MAX_BIRTH_SIZE, PN_ALIGN(sz * 4, POTION_PAGESIZE));
void *page = pngc_page_new(&gensz, 0);
SET_GEN(old, page, gensz);
full = 0;
} else if ((char *) M->old_cur + sz + potion_birth_suggest(sz, M->old_lo, M->old_cur) +
((char *) M->birth_hi - (char *) M->birth_lo) > (char *) M->old_hi)
full = 1;
#if POTION_GC_PERIOD>0
else if (M->pass % POTION_GC_PERIOD == POTION_GC_PERIOD)
full = 1;
#endif
if (full)
potion_gc_major(P, sz);
else
potion_gc_minor(P, sz);
#ifdef DEBUG
M->time += mytime() - time;
#endif
M->dirty = 0;
M->collecting = 0;
}
PN_SIZE potion_type_size(Potion *P, const struct PNObject *ptr) {
int sz = 0;
switch (((struct PNFwd *)ptr)->fwd) {
case POTION_COPIED:
case POTION_FWD:
sz = ((struct PNFwd *)ptr)->siz;
goto done;
}
if (ptr->vt > PN_TUSER) {
if (P->vts && PN_VTABLE(ptr->vt) && PN_TYPECHECK(ptr->vt)) {
sz = sizeof(struct PNObject) +
(((struct PNVtable *)PN_VTABLE(ptr->vt))->ivlen * sizeof(PN));
} else {
if (P->flags & (DEBUG_VERBOSE
#ifdef DEBUG
|DEBUG_GC
#endif
))
fprintf(stderr, "** Invalid User Object 0x%lx vt: 0x%lx\n",
(unsigned long)ptr, (unsigned long)ptr->vt);
return 0;
}
goto done;
}
switch (ptr->vt) {
case PN_TNUMBER:
sz = sizeof(struct PNDecimal);
break;
case PN_TSTRING:
sz = sizeof(struct PNString) + PN_STR_LEN(ptr) + 1;
break;
case PN_TCLOSURE:
sz = sizeof(struct PNClosure) + (PN_CLOSURE(ptr)->extra * sizeof(PN));
break;
case PN_TTUPLE:
sz = sizeof(struct PNTuple) + (sizeof(PN) * ((struct PNTuple *)ptr)->alloc);
break;
case PN_TSTATE:
sz = sizeof(Potion);
break;
case PN_TFILE:
sz = sizeof(struct PNFile);
break;
case PN_TVTABLE:
sz = sizeof(struct PNVtable);
break;
case PN_TSOURCE:
sz = sizeof(struct PNSource);
break;
case PN_TBYTES:
sz = sizeof(struct PNBytes) + ((struct PNBytes *)ptr)->siz;
break;
case PN_TPROTO:
sz = sizeof(struct PNProto);
break;
case PN_TTABLE:
sz = sizeof(struct PNTable) + kh_mem(PN, ptr);
break;
case PN_TLICK:
sz = sizeof(struct PNLick);
break;
case PN_TSTRINGS:
sz = sizeof(struct PNTable) + kh_mem(str, ptr);
break;
case PN_TFLEX:
sz = sizeof(PNFlex) + ((PNFlex *)ptr)->siz;
break;
case PN_TCONT:
sz = sizeof(struct PNCont) + (((struct PNCont *)ptr)->len * sizeof(PN));
break;
case PN_TUSER:
sz = sizeof(struct PNData) + ((struct PNData *)ptr)->siz;
break;
}
done:
if (sz < sizeof(struct PNFwd))
sz = sizeof(struct PNFwd);
return PN_ALIGN(sz, 8);
}
void *potion_gc_copy(Potion *P, struct PNObject *ptr) {
void *dst = (void *)P->mem->old_cur;
PN_SIZE sz = potion_type_size(P, (const struct PNObject *)ptr);
if (!sz)
return ptr;
memcpy(dst, ptr, sz);
P->mem->old_cur = (char *)dst + sz;
((struct PNFwd *)ptr)->fwd = POTION_COPIED;
((struct PNFwd *)ptr)->siz = sz;
((struct PNFwd *)ptr)->ptr = (PN)dst;
return dst;
}
void *potion_mark_minor(Potion *P, const struct PNObject *ptr) {
struct PNMemory *M = P->mem;
PN_SIZE i;
PN_SIZE sz = 16;
switch (((struct PNFwd *)ptr)->fwd) {
case POTION_COPIED:
case POTION_FWD:
GC_MINOR_UPDATE(((struct PNFwd *)ptr)->ptr);
goto done;
}
if (ptr->vt > PN_TUSER) {
GC_MINOR_UPDATE(PN_VTABLE(ptr->vt));
int ivars = ((struct PNVtable *)PN_VTABLE(ptr->vt))->ivlen;
for (i = 0; i < ivars; i++)
GC_MINOR_UPDATE(((struct PNObject *)ptr)->ivars[i]);
goto done;
}
switch (ptr->vt) {
case PN_TWEAK:
GC_MINOR_UPDATE(((struct PNWeakRef *)ptr)->data);
break;
case PN_TCLOSURE:
GC_MINOR_UPDATE(((struct PNClosure *)ptr)->sig);
for (i = 0; i < ((struct PNClosure *)ptr)->extra; i++)
GC_MINOR_UPDATE(((struct PNClosure *)ptr)->data[i]);
break;
case PN_TTUPLE: {
struct PNTuple * volatile t = (struct PNTuple *)potion_fwd((PN)ptr);
for (i = 0; i < t->len; i++)
GC_MINOR_UPDATE(t->set[i]);
}
break;
case PN_TSTATE:
DBG_G(P,"GC mark minor Potion_State\n");
GC_MINOR_UPDATE(((Potion *)ptr)->strings);
GC_MINOR_UPDATE(((Potion *)ptr)->lobby);
GC_MINOR_UPDATE(((Potion *)ptr)->vts);
GC_MINOR_UPDATE(((Potion *)ptr)->call);
GC_MINOR_UPDATE(((Potion *)ptr)->callset);
GC_MINOR_UPDATE(((Potion *)ptr)->input);
GC_MINOR_UPDATE(((Potion *)ptr)->source);
GC_MINOR_UPDATE(((Potion *)ptr)->pbuf);
GC_MINOR_UPDATE(((Potion *)ptr)->line);
GC_MINOR_UPDATE(((Potion *)ptr)->unclosed);
break;
case PN_TFILE:
GC_MINOR_UPDATE(((struct PNFile *)ptr)->path);
break;
case PN_TVTABLE:
if (((struct PNVtable *)ptr)->parent)
GC_MINOR_UPDATE(PN_VTABLE(((struct PNVtable *)ptr)->parent));
GC_MINOR_UPDATE(((struct PNVtable *)ptr)->name);
GC_MINOR_UPDATE(((struct PNVtable *)ptr)->ivars);
GC_MINOR_UPDATE(((struct PNVtable *)ptr)->methods);
GC_MINOR_UPDATE(((struct PNVtable *)ptr)->meta);
GC_MINOR_UPDATE(((struct PNVtable *)ptr)->ctor);
GC_MINOR_UPDATE(((struct PNVtable *)ptr)->call);
GC_MINOR_UPDATE(((struct PNVtable *)ptr)->callset);
break;
case PN_TSOURCE:
GC_MINOR_UPDATE(((struct PNSource *)ptr)->a[0]);
GC_MINOR_UPDATE(((struct PNSource *)ptr)->a[1]);
GC_MINOR_UPDATE(((struct PNSource *)ptr)->a[2]);
GC_MINOR_UPDATE(((struct PNSource *)ptr)->line);
break;
case PN_TPROTO:
GC_MINOR_UPDATE(((struct PNProto *)ptr)->source);
GC_MINOR_UPDATE(((struct PNProto *)ptr)->sig);
GC_MINOR_UPDATE(((struct PNProto *)ptr)->stack);
GC_MINOR_UPDATE(((struct PNProto *)ptr)->paths);
GC_MINOR_UPDATE(((struct PNProto *)ptr)->locals);
GC_MINOR_UPDATE(((struct PNProto *)ptr)->upvals);
GC_MINOR_UPDATE(((struct PNProto *)ptr)->values);
GC_MINOR_UPDATE(((struct PNProto *)ptr)->protos);
GC_MINOR_UPDATE(((struct PNProto *)ptr)->debugs);
GC_MINOR_UPDATE(((struct PNProto *)ptr)->tree);
GC_MINOR_UPDATE(((struct PNProto *)ptr)->asmb);
break;
case PN_TTABLE:
GC_MINOR_UPDATE_TABLE(PN, (struct PNTable *)potion_fwd((PN)ptr), 1);
break;
case PN_TLICK:
GC_MINOR_UPDATE(((struct PNLick *)ptr)->name);
GC_MINOR_UPDATE(((struct PNLick *)ptr)->attr);
GC_MINOR_UPDATE(((struct PNLick *)ptr)->inner);
break;
case PN_TFLEX:
for (i = 0; i < PN_FLEX_SIZE(ptr); i++)
GC_MINOR_UPDATE(PN_FLEX_AT(ptr, i));
break;
case PN_TCONT:
GC_KEEP(ptr);
pngc_mark_array(P, (_PN *)((struct PNCont *)ptr)->stack + 3, ((struct PNCont *)ptr)->len - 3, 1);
break;
}
done:
sz = potion_type_size(P, ptr);
return (void *)((char *)ptr + sz);
}
void *potion_mark_major(Potion *P, const struct PNObject *ptr) {
struct PNMemory *M = P->mem;
PN_SIZE i;
PN_SIZE sz = 16;
switch (((struct PNFwd *)ptr)->fwd) {
case POTION_COPIED:
case POTION_FWD:
GC_MAJOR_UPDATE(((struct PNFwd *)ptr)->ptr);
goto done;
}
if (ptr->vt > PN_TUSER) {
GC_MAJOR_UPDATE(PN_VTABLE(ptr->vt));
int ivars = ((struct PNVtable *)PN_VTABLE(ptr->vt))->ivlen;
for (i = 0; i < ivars; i++)
GC_MAJOR_UPDATE(((struct PNObject *)ptr)->ivars[i]);
goto done;
}
switch (ptr->vt) {
case PN_TWEAK:
GC_MAJOR_UPDATE(((struct PNWeakRef *)ptr)->data);
break;
case PN_TCLOSURE:
GC_MAJOR_UPDATE(((struct PNClosure *)ptr)->sig);
for (i = 0; i < ((struct PNClosure *)ptr)->extra; i++)
GC_MAJOR_UPDATE(((struct PNClosure *)ptr)->data[i]);
break;
case PN_TTUPLE: {
struct PNTuple * volatile t = (struct PNTuple *)potion_fwd((PN)ptr);
for (i = 0; i < t->len; i++)
GC_MAJOR_UPDATE(t->set[i]);
}
break;
case PN_TSTATE:
DBG_G(P,"GC mark major Potion_State\n");
GC_MAJOR_UPDATE(((Potion *)ptr)->strings);
GC_MAJOR_UPDATE(((Potion *)ptr)->lobby);
GC_MAJOR_UPDATE(((Potion *)ptr)->vts);
GC_MAJOR_UPDATE(((Potion *)ptr)->call);
GC_MAJOR_UPDATE(((Potion *)ptr)->callset);
GC_MAJOR_UPDATE(((Potion *)ptr)->input);
GC_MAJOR_UPDATE(((Potion *)ptr)->source);
GC_MAJOR_UPDATE(((Potion *)ptr)->pbuf);
GC_MAJOR_UPDATE(((Potion *)ptr)->line);
GC_MAJOR_UPDATE(((Potion *)ptr)->unclosed);
break;
case PN_TFILE:
GC_MAJOR_UPDATE(((struct PNFile *)ptr)->path);
break;
case PN_TVTABLE:
if (((struct PNVtable *)ptr)->parent)
GC_MINOR_UPDATE(PN_VTABLE(((struct PNVtable *)ptr)->parent));
GC_MAJOR_UPDATE(((struct PNVtable *)ptr)->name);
GC_MAJOR_UPDATE(((struct PNVtable *)ptr)->ivars);
GC_MAJOR_UPDATE(((struct PNVtable *)ptr)->methods);
GC_MAJOR_UPDATE(((struct PNVtable *)ptr)->meta);
GC_MAJOR_UPDATE(((struct PNVtable *)ptr)->ctor);
GC_MAJOR_UPDATE(((struct PNVtable *)ptr)->call);
GC_MAJOR_UPDATE(((struct PNVtable *)ptr)->callset);
break;
case PN_TSOURCE:
GC_MAJOR_UPDATE(((struct PNSource *)ptr)->a[0]);
GC_MAJOR_UPDATE(((struct PNSource *)ptr)->a[1]);
GC_MAJOR_UPDATE(((struct PNSource *)ptr)->a[2]);
GC_MINOR_UPDATE(((struct PNSource *)ptr)->line);
break;
case PN_TPROTO:
GC_MAJOR_UPDATE(((struct PNProto *)ptr)->source);
GC_MAJOR_UPDATE(((struct PNProto *)ptr)->sig);
GC_MAJOR_UPDATE(((struct PNProto *)ptr)->stack);
GC_MAJOR_UPDATE(((struct PNProto *)ptr)->paths);
GC_MAJOR_UPDATE(((struct PNProto *)ptr)->locals);
GC_MAJOR_UPDATE(((struct PNProto *)ptr)->upvals);
GC_MAJOR_UPDATE(((struct PNProto *)ptr)->values);
GC_MAJOR_UPDATE(((struct PNProto *)ptr)->protos);
GC_MAJOR_UPDATE(((struct PNProto *)ptr)->debugs);
GC_MAJOR_UPDATE(((struct PNProto *)ptr)->tree);
GC_MAJOR_UPDATE(((struct PNProto *)ptr)->asmb);
break;
case PN_TTABLE:
GC_MAJOR_UPDATE_TABLE(PN, (struct PNTable *)potion_fwd((PN)ptr), 1);
break;
case PN_TLICK:
GC_MAJOR_UPDATE(((struct PNLick *)ptr)->name);
GC_MAJOR_UPDATE(((struct PNLick *)ptr)->attr);
GC_MAJOR_UPDATE(((struct PNLick *)ptr)->inner);
break;
case PN_TFLEX:
for (i = 0; i < PN_FLEX_SIZE(ptr); i++)
GC_MAJOR_UPDATE(PN_FLEX_AT(ptr, i));
break;
case PN_TCONT:
GC_KEEP(ptr);
pngc_mark_array(P, (_PN *)((struct PNCont *)ptr)->stack + 3, ((struct PNCont *)ptr)->len - 3, 2);
break;
}
done:
sz = potion_type_size(P, ptr);
return (void *)((char *)ptr + sz);
}
Potion *potion_gc_boot(void *sp) {
Potion *P;
int bootsz = POTION_MIN_BIRTH_SIZE;
void *page1 = pngc_page_new(&bootsz, 0);
struct PNMemory *M = (struct PNMemory *)page1;
PN_MEMZERO(M, struct PNMemory);
#ifdef DEBUG
M->time = 0.0;
#endif
SET_GEN(birth, page1, bootsz);
SET_STOREPTR(4);
#if (__WORDSIZE == 64) || defined(__APPLE__)
M->cstack = (((_PN)sp & ((1<<5)-1)) == 0 )
? sp : (void *)(_PN)((_PN)sp | ((1<<5)-1) )+1;
#else
M->cstack = sp;
#endif
P = (Potion *)((char *)M + PN_ALIGN(sizeof(struct PNMemory), 8));
PN_MEMZERO(P, Potion);
P->mem = M;
M->birth_cur = (void *)((char *)P + PN_ALIGN(sizeof(Potion), 8));
GC_PROTECT(P);
return P;
}
void potion_gc_release(Potion *P) {
struct PNMemory *M = P->mem;
void *birthlo = (void *)M->birth_lo;
void *birthhi = (void *)M->birth_hi;
void *oldlo = (void *)M->old_lo;
void *oldhi = (void *)M->old_hi;
if (M->birth_lo != M) {
void *protend = (void *)PN_ALIGN((_PN)M->protect, POTION_PAGESIZE);
pngc_page_delete((void *)M, (char *)protend - (char *)M);
}
pngc_page_delete(birthlo, birthhi - birthlo);
if (oldlo != NULL)
pngc_page_delete(oldlo, oldhi - oldlo);
birthlo = 0;
birthhi = 0;
oldlo = 0;
oldhi = 0;
}
PN potion_gc_actual(Potion *P, PN cl, PN self)
{
int total = (char *)P->mem->birth_cur - (char *)P->mem->birth_lo;
if (P->mem != P->mem->birth_lo)
total += (char *)P->mem->protect - (char *)P->mem;
if (P->mem->old_lo != NULL)
total += (char *)P->mem->old_cur - (char *)P->mem->old_lo;
return PN_NUM(total);
}
PN potion_gc_fixed(Potion *P, PN cl, PN self)
{
int total = 0;
if (P->mem->protect != NULL)
total += (char *)P->mem->protect - (char *)P->mem;
return PN_NUM(total);
}
PN potion_gc_reserved(Potion *P, PN cl, PN self)
{
int total = (char *)P->mem->birth_hi - (char *)P->mem->birth_lo;
if (P->mem != P->mem->birth_lo)
total += (char *)P->mem->protect - (char *)P->mem;
if (P->mem->old_lo != NULL)
total += (char *)P->mem->old_hi - (char *)P->mem->old_lo;
return PN_NUM(total);
}