25 static double mytime() {
29 status = gettimeofday (&Tp, &Tz);
31 Tp.tv_sec += Tz.tz_minuteswest * 60;
32 return Tp.tv_sec + (Tp.tv_usec / 1000000.0);
37 #define DBG_Gv(P,...) \
38 if (P->flags & DEBUG_GC && P->flags & DEBUG_VERBOSE) { \
39 printf(__VA_ARGS__); \
41 #define DBG_G(P,...) \
42 if (P->flags & DEBUG_GC) { \
43 printf(__VA_ARGS__); \
53 if (p) *p = STACK_UPPER(c, esp);
54 return esp < c ? c - esp : esp - c + 1;
57 #define HAS_REAL_TYPE(v) (P->vts == NULL || (((struct PNFwd *)v)->fwd == POTION_COPIED || PN_TYPECHECK(PN_VTYPE(v))))
80 DBG_Gv(P,
"GC mark minor %p -> 0x%lx %6x\n", x, v,
PN_TYPE(*x));
87 DBG_Gv(P,
"GC mark major %p -> 0x%lx %6x\n", x, v,
PN_TYPE(*x));
102 #if POTION_STACK_DIR > 0
109 DBG_Gv(P,
"mark_stack (%p -> %p = %ld, type=%d)\n", start, end, n, type);
110 if (n <= 0)
return 0;
128 wb = (
void *)(((
void **)(newad + sz)) - (keeps + 4));
146 void **storead = 0, **wb = 0;
154 DBG_Gv(P,
"running gc_minor "
155 "(young: %p -> %p = %ld) "
156 "(old: %p -> %p = %ld) "
157 "(storeptr len = %ld)\n",
166 for (storead = wb; storead < (
void **)M->
birth_hi; storead++) {
191 void *prevoldcur = 0;
208 prevoldlo = (
void *)M->
old_lo;
209 prevoldhi = (
void *)M->
old_hi;
210 prevoldcur = (
void *)M->
old_cur;
212 DBG_G(P,
"running gc_major "
213 "(young: %p -> %p = %ld) "
214 "(old: %p -> %p = %ld)\n",
218 newoldsiz = (((
char *)prevoldcur - (
char *)prevoldlo) + siz + birthest +
221 if (newold == NULL) {
222 fprintf(stderr,
"** Out of memory\n");
226 M->
old_cur = scanptr = newold + (
sizeof(
PN) * 2);
227 DBG_G(P,
"(new old: %p -> %p = %d)\n", newold, (
char *)newold + newoldsiz, newoldsiz);
249 oldsiz = ((
char *)M->
old_cur - (
char *)newold) +
252 if (oldsiz < newoldsiz) {
258 M->
old_hi = (
char *)newold + newoldsiz;
270 double time = mytime();
281 fprintf(stderr,
"** Out of memory\n");
289 #if POTION_GC_PERIOD>0
300 M->time += mytime() - time;
309 switch (((
struct PNFwd *)ptr)->fwd) {
312 sz = ((
struct PNFwd *)ptr)->siz;
316 if (ptr->vt <
PN_TNIL)
goto err;
321 (((struct PNVtable *)
PN_VTABLE(ptr->vt))->ivlen *
sizeof(
PN));
330 fprintf(stderr,
"** Invalid User Object 0x%lx vt: 0x%lx\n",
331 (
unsigned long)ptr, (
unsigned long)ptr->vt);
342 sz =
sizeof(
struct PNString) + PN_STR_LEN(ptr) + 1;
345 sz =
sizeof(
struct PNClosure) + (PN_CLOSURE(ptr)->extra *
sizeof(
PN));
354 sz =
sizeof(
struct PNFile);
363 sz =
sizeof(
struct PNBytes) + ((struct PNBytes *)ptr)->siz;
369 sz =
sizeof(
struct PNTable) + kh_mem(PN, ptr);
372 sz =
sizeof(
struct PNLick);
375 sz =
sizeof(
struct PNTable) + kh_mem(str, ptr);
378 sz =
sizeof(PNFlex) + ((PNFlex *)ptr)->siz;
381 sz =
sizeof(
struct PNCont) + (((struct PNCont *)ptr)->len *
sizeof(
PN));
384 sz =
sizeof(
struct PNData) + ((struct PNData *)ptr)->siz;
389 if (sz <
sizeof(
struct PNFwd))
390 sz =
sizeof(
struct PNFwd);
398 DBG_G(P,
"GC copy: assuming extern pointer or immediate potion value %p: %ld / 0x%lx\n", ptr, *(
long*)ptr, *(
long*)ptr);
400 memcpy(dst, ptr,
sizeof(
void*));
403 memcpy(dst, ptr, sz);
407 ((
struct PNFwd *)ptr)->siz = sz;
408 ((
struct PNFwd *)ptr)->ptr = (
PN)dst;
418 switch (((
struct PNFwd *)ptr)->fwd) {
428 for (i = 0; i <
ivars; i++)
439 for (i = 0; i < ((
struct PNClosure *)ptr)->extra; i++)
444 for (i = 0; i < t->
len; i++)
449 DBG_Gv(P,
"GC mark minor Potion_State\n");
467 if (((
struct PNVtable *)ptr)->parent)
516 return (
void *)((
char *)ptr + sz);
524 switch (((
struct PNFwd *)ptr)->fwd) {
534 for (i = 0; i <
ivars; i++)
545 for (i = 0; i < ((
struct PNClosure *)ptr)->extra; i++)
550 for (i = 0; i < t->
len; i++)
555 DBG_Gv(P,
"GC mark major Potion_State\n");
584 if (((
struct PNVtable *)ptr)->parent)
633 return (
void *)((
char *)ptr + sz);
675 #if (PN_SIZE_T == 8) || defined(__APPLE__)
676 M->
cstack = (((
_PN)sp & ((1<<5)-1)) == 0 )
677 ? sp : (
void *)(
_PN)((
_PN)sp | ((1<<5)-1) )+1;
693 void *birthlo = (
void *)M->
birth_lo;
694 void *birthhi = (
void *)M->
birth_hi;
695 void *oldlo = (
void *)M->
old_lo;
696 void *oldhi = (
void *)M->
old_hi;
700 DBG_G(P,
"GC page delete: %p - %p\n", M, protend);
volatile void * old_lo
the old region (TODO: consider making the old region common to all threads)
#define DEL_BIRTH_REGION()
forwarding pointer (in case of reallocation)
byte strings are raw character data, volatile, may be appended/changed.
PN potion_gc_actual(Potion *P, PN cl, PN self)
void * potion_mark_major(Potion *P, const struct PNObject *ptr)
klib hash table library based on double hashing http://en.wikipedia.org/wiki/Double_hashing ...
a tuple is an array of PNs.
#define GC_MAJOR_UPDATE_TABLE(name, kh, is_map)
Potion_Flags flags
vm flags: execution model and debug flags
a closure is an anonymous function, without closed values,
the central vtable, see io http://www.piumarta.com/pepsi/objmodel.pdf
static int potion_birth_suggest(int need, volatile void *oldlo, volatile void *oldhi)
struct to wrap arbitrary data that we may want to allocate from Potion.
static int NEW_BIRTH_REGION(struct PNMemory *M, void **wb, int sz)
#define IN_BIRTH_REGION(p)
#define POTION_MAX_BIRTH_SIZE
static PN potion_fwd(PN)
the potion type is the 't' in the vtable tuple (m,t)
struct PNMemory * mem
allocator/gc
a file is wrapper around a file descriptor, non-volatile but mutable.
#define POTION_MIN_BIRTH_SIZE
#define POTION_OK
internal errors
a weak ref is used for upvals, it acts as a memory slot, non-volatile but mutable.
static int potion_gc_minor(Potion *P, int sz)
volatile void * birth_lo
the birth region
void * potion_mmap(size_t length, const char exec)
void * cstack
machine stack start
int potion_munmap(void *mem, size_t len)
standard objects act like C structs the fields are defined by the type and it's a fixed size...
void * protect
end of protected memory
Potion * potion_gc_boot(void *sp)
a continuation saves the stack and all stack pointers.
static ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS PN_SIZE pngc_mark_array(Potion *P, register _PN *x, register long n, int type)
#define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS
#define GC_MINOR_STRINGS()
a lick is a unit of generic tree data.
void * potion_gc_copy(Potion *P, struct PNObject *ptr)
void * potion_mark_minor(Potion *P, const struct PNObject *ptr)
the table class, based on khash
#define IN_OLDER_REGION(p)
struct Potion_State Potion
volatile void ** birth_storeptr
#define PN_MEMCPY_N(X, Y, T, N)
PN potion_gc_fixed(Potion *P, PN cl, PN self)
#define GC_MAJOR_UPDATE(p)
strings are immutable UTF-8, the ID is incremental and they may be garbage collected.
#define GC_MINOR_UPDATE_TABLE(name, kh, is_map)
PN_SIZE potion_stack_len(Potion *P, _PN **p)
a prototype is compiled source code, a closure block (lambda) non-volatile.
void potion_garbagecollect(Potion *P, int sz, int full)
PNFlex *volatile vts
built in types
#define GC_MINOR_UPDATE(p)
PN_SIZE potion_type_size(Potion *P, const struct PNObject *ptr)
volatile void * birth_cur
the global interpreter state P. currently singleton (not threads yet)
#define IS_GC_PROTECTED(p)
void pngc_page_delete(void *mem, int sz)
void * pngc_page_new(int *sz, const char exec)
the central table type, based on core/khash.h
doubles are floating point numbers stored as binary data.
PN_SIZE alloc
overallocate a bit
static int potion_gc_major(Potion *P, int siz)
PN potion_gc_reserved(Potion *P, PN cl, PN self)
#define GC_MAJOR_STRINGS()
int ivlen
PN_TUPLE_LEN(ivars)
ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS PN_SIZE potion_mark_stack(Potion *P, int type)
void potion_fatal(char *message)
PN ivars
PNTuple of all our or the parents inherited vars.
void potion_gc_release(Potion *P)
#define POTION_GC_THRESHOLD