potion  0.2
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
gc.c
Go to the documentation of this file.
1 
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include "potion.h"
13 #include "internal.h"
14 #include "gc.h"
15 #include "khash.h"
16 #include "table.h"
17 
18 #if defined(DEBUG)
19 //mingw32 has struct timeval in sys/time.h
20 //#ifdef WIN32
21 //# include <time.h>
22 //#else
23 #include <sys/time.h>
24 //#endif
25 static double mytime() {
26  struct timeval Tp;
27  struct timezone Tz;
28  int status;
29  status = gettimeofday (&Tp, &Tz);
30  if (status == 0) {
31  Tp.tv_sec += Tz.tz_minuteswest * 60; /* adjust for TZ */
32  return Tp.tv_sec + (Tp.tv_usec / 1000000.0);
33  } else {
34  return -1.0;
35  }
36 }
37 #define DBG_Gv(P,...) \
38  if (P->flags & DEBUG_GC && P->flags & DEBUG_VERBOSE) { \
39  printf(__VA_ARGS__); \
40  }
41 #define DBG_G(P,...) \
42  if (P->flags & DEBUG_GC) { \
43  printf(__VA_ARGS__); \
44  }
45 #else
46 #define DBG_Gv(...)
47 #define DBG_G(...)
48 #endif
49 
51  _PN *esp, *c = P->mem->cstack;
52  POTION_ESP(&esp);
53  if (p) *p = STACK_UPPER(c, esp);
54  return esp < c ? c - esp : esp - c + 1;
55 }
56 
57 #define HAS_REAL_TYPE(v) (P->vts == NULL || (((struct PNFwd *)v)->fwd == POTION_COPIED || PN_TYPECHECK(PN_VTYPE(v))))
58 
60 static PN_SIZE pngc_mark_array(Potion *P, register _PN *x, register long n, int type) {
61  _PN v;
62  PN_SIZE i = 0;
63  struct PNMemory *M = P->mem;
64 
65  while (n--) {
66  v = *x;
67  if (IS_GC_PROTECTED(v) || IN_BIRTH_REGION(v) || IN_OLDER_REGION(v)) {
68  v = potion_fwd(v);
69  switch (type) {
70  case 0: // count only
71  if (!IS_GC_PROTECTED(v) && IN_BIRTH_REGION(v) && HAS_REAL_TYPE(v)) {
72  i++;
73  DBG_Gv(P,"GC mark count only %p %6x\n", x, PN_TYPE(*x));
74  }
75  break;
76  case 1: // minor
77  if (!IS_GC_PROTECTED(v) && IN_BIRTH_REGION(v) && HAS_REAL_TYPE(v)) {
78  GC_FORWARD(x, v);
79  i++;
80  DBG_Gv(P,"GC mark minor %p -> 0x%lx %6x\n", x, v, PN_TYPE(*x));
81  }
82  break;
83  case 2: // major
84  if (!IS_GC_PROTECTED(v) && (IN_BIRTH_REGION(v) || IN_OLDER_REGION(v)) && HAS_REAL_TYPE(v)) {
85  GC_FORWARD(x, v);
86  i++;
87  DBG_Gv(P,"GC mark major %p -> 0x%lx %6x\n", x, v, PN_TYPE(*x));
88  }
89  break;
90  }
91  }
92  x++;
93  }
94  return i;
95 }
96 
99  long n;
100  _PN *end, *start = P->mem->cstack;
101  POTION_ESP(&end);
102 #if POTION_STACK_DIR > 0
103  n = end - start;
104 #else
105  n = start - end + 1;
106  start = end;
107  end = P->mem->cstack;
108 #endif
109  DBG_Gv(P,"mark_stack (%p -> %p = %ld, type=%d)\n", start, end, n, type);
110  if (n <= 0) return 0;
111  return pngc_mark_array(P, start, n, type);
112 }
113 
114 void *pngc_page_new(int *sz, const char exec) {
115  *sz = PN_ALIGN(*sz, POTION_PAGESIZE);
116  return potion_mmap(*sz, exec);
117 }
118 
119 void pngc_page_delete(void *mem, int sz) {
121 }
122 
123 static inline int NEW_BIRTH_REGION(struct PNMemory *M, void **wb, int sz) {
124  int keeps = wb - (void **)M->birth_storeptr;
125  void *newad = pngc_page_new(&sz, 0);
126  if (newad == NULL)
127  potion_fatal("Out of memory");
128  wb = (void *)(((void **)(newad + sz)) - (keeps + 4));
129  PN_MEMCPY_N(wb + 1, M->birth_storeptr + 1, void *, keeps);
131  SET_GEN(birth, newad, sz);
132  SET_STOREPTR(5 + keeps);
133  return sz;
134 }
135 
143 static int potion_gc_minor(Potion *P, int sz) {
144  struct PNMemory *M = P->mem;
145  void *scanptr = 0;
146  void **storead = 0, **wb = 0;
147 
148  if (sz < 0)
149  sz = 0;
150  else if (sz >= POTION_MAX_BIRTH_SIZE)
151  return POTION_NO_MEM;
152 
153  scanptr = (void *) M->old_cur;
154  DBG_Gv(P,"running gc_minor "
155  "(young: %p -> %p = %ld) "
156  "(old: %p -> %p = %ld) "
157  "(storeptr len = %ld)\n",
158  M->birth_lo, M->birth_hi, (long)(M->birth_hi - M->birth_lo),
159  M->old_lo, M->old_hi, (long)(M->old_hi - M->old_lo),
160  (long)((void *)M->birth_hi - (void *)M->birth_storeptr));
161  potion_mark_stack(P, 1);
162 
164 
165  wb = (void **)M->birth_storeptr;
166  for (storead = wb; storead < (void **)M->birth_hi; storead++) {
167  PN v = (PN)*storead;
168  if (PN_IS_PTR(v))
169  potion_mark_minor(P, (const struct PNObject *)v);
170  }
171  storead = 0;
172 
173  while ((PN)scanptr < (PN)M->old_cur)
174  scanptr = potion_mark_minor(P, scanptr);
175  scanptr = 0;
176 
177  sz += 2 * POTION_PAGESIZE;
178  sz = max(sz, potion_birth_suggest(sz, M->old_lo, M->old_cur));
179 
180  sz = NEW_BIRTH_REGION(M, wb, sz);
181  M->minors++;
182 
183  DBG_Gv(P,"(new young: %p -> %p = %ld)\n", M->birth_lo, M->birth_hi, (long)(M->birth_hi - M->birth_lo));
184  return POTION_OK;
185 }
186 
187 static int potion_gc_major(Potion *P, int siz) {
188  struct PNMemory *M = P->mem;
189  void *prevoldlo = 0;
190  void *prevoldhi = 0;
191  void *prevoldcur = 0;
192  void *newold = 0;
193  void *protptr = (void *)M + PN_ALIGN(sizeof(struct PNMemory), 8);
194  void *scanptr = 0;
195  void **wb = 0;
196  int birthest = 0;
197  int birthsiz = 0;
198  int newoldsiz = 0;
199  int oldsiz = 0;
200 
201  if (siz < 0)
202  siz = 0;
203  else if (siz >= POTION_MAX_BIRTH_SIZE) {
204  fprintf(stderr, "** Requesting too much memory: 0x%x > 0x%x\n", siz, POTION_MAX_BIRTH_SIZE);
205  return POTION_NO_MEM;
206  }
207 
208  prevoldlo = (void *)M->old_lo;
209  prevoldhi = (void *)M->old_hi;
210  prevoldcur = (void *)M->old_cur;
211 
212  DBG_G(P,"running gc_major "
213  "(young: %p -> %p = %ld) "
214  "(old: %p -> %p = %ld)\n",
215  M->birth_lo, M->birth_hi, (long)(M->birth_hi - M->birth_lo),
216  M->old_lo, M->old_hi, (long)(M->old_hi - M->old_lo));
217  birthest = potion_birth_suggest(siz, prevoldlo, prevoldcur);
218  newoldsiz = (((char *)prevoldcur - (char *)prevoldlo) + siz + birthest +
219  POTION_GC_THRESHOLD + 16 * POTION_PAGESIZE) + ((char *)M->birth_cur - (char *)M->birth_lo);
220  newold = pngc_page_new(&newoldsiz, 0);
221  if (newold == NULL) {
222  fprintf(stderr, "** Out of memory\n");
223  return POTION_NO_MEM;
224  }
225 
226  M->old_cur = scanptr = newold + (sizeof(PN) * 2);
227  DBG_G(P,"(new old: %p -> %p = %d)\n", newold, (char *)newold + newoldsiz, newoldsiz);
228 
229  potion_mark_stack(P, 2);
230 
231  wb = (void **)M->birth_storeptr;
232  if (M->birth_lo != M) {
233  while ((PN)protptr < (PN)M->protect)
234  protptr = potion_mark_major(P, protptr);
235  }
236 
237  while ((PN)scanptr < (PN)M->old_cur)
238  scanptr = potion_mark_major(P, scanptr);
239  scanptr = 0;
240 
242 
243  pngc_page_delete((void *)prevoldlo, (char *)prevoldhi - (char *)prevoldlo);
244  prevoldlo = 0;
245  prevoldhi = 0;
246  prevoldcur = 0;
247 
248  birthsiz = NEW_BIRTH_REGION(M, wb, siz + birthest);
249  oldsiz = ((char *)M->old_cur - (char *)newold) +
250  (birthsiz + 2 * birthest + 4 * POTION_PAGESIZE);
251  oldsiz = PN_ALIGN(oldsiz, POTION_PAGESIZE);
252  if (oldsiz < newoldsiz) {
253  pngc_page_delete((void *)newold + oldsiz, newoldsiz - oldsiz);
254  newoldsiz = oldsiz;
255  }
256 
257  M->old_lo = newold;
258  M->old_hi = (char *)newold + newoldsiz;
259  M->majors++;
260 
261  newold = 0;
262 
263  return POTION_OK;
264 }
265 
266 void potion_garbagecollect(Potion *P, int sz, int full) {
267  struct PNMemory *M = P->mem;
268  if (M->collecting) return;
269 #ifdef DEBUG
270  double time = mytime();
271 #endif
272  M->pass++;
273  M->collecting = 1;
274 
275  if (M->old_lo == NULL) {
276  int gensz = POTION_MIN_BIRTH_SIZE * 4;
277  if (gensz < sz * 4)
279  void *page = pngc_page_new(&gensz, 0);
280  if (page == NULL) {
281  fprintf(stderr, "** Out of memory\n");
282  return;
283  }
284  SET_GEN(old, page, gensz);
285  full = 0;
286  } else if ((char *) M->old_cur + sz + potion_birth_suggest(sz, M->old_lo, M->old_cur) +
287  ((char *) M->birth_hi - (char *) M->birth_lo) > (char *) M->old_hi)
288  full = 1;
289 #if POTION_GC_PERIOD>0
290  else if (M->pass % POTION_GC_PERIOD == POTION_GC_PERIOD)
291  full = 1;
292 #endif
293 
294  if (full)
295  potion_gc_major(P, sz);
296  else
297  potion_gc_minor(P, sz);
298 
299 #ifdef DEBUG
300  M->time += mytime() - time;
301 #endif
302  M->dirty = 0;
303  M->collecting = 0;
304 }
305 
306 PN_SIZE potion_type_size(Potion *P, const struct PNObject *ptr) {
307  int sz = 0;
308 
309  switch (((struct PNFwd *)ptr)->fwd) {
310  case POTION_COPIED:
311  case POTION_FWD:
312  sz = ((struct PNFwd *)ptr)->siz;
313  goto done_1;
314  }
315 
316  if (ptr->vt < PN_TNIL) goto err;
317  if (ptr->vt > PN_TUSER) {
318  if (P->vts && ptr->vt < PN_TNIL + P->vts->len
319  && PN_VTABLE(ptr->vt) && PN_TYPECHECK(ptr->vt)) {
320  sz = sizeof(struct PNObject) +
321  (((struct PNVtable *)PN_VTABLE(ptr->vt))->ivlen * sizeof(PN));
322  //sz = potion_send((PN)ptr, PN_size); //cannot use bind with POTION_COPIED objs during GC!
323  } else {
324  err:
325  if (P->flags & (DEBUG_VERBOSE
326 #ifdef DEBUG
327  |DEBUG_GC
328 #endif
329  ))
330  fprintf(stderr, "** Invalid User Object 0x%lx vt: 0x%lx\n",
331  (unsigned long)ptr, (unsigned long)ptr->vt);
332  return 0;
333  }
334  goto done_1;
335  }
336 
337  switch (ptr->vt) {
338  case PN_TNUMBER:
339  sz = sizeof(struct PNDouble);
340  break;
341  case PN_TSTRING:
342  sz = sizeof(struct PNString) + PN_STR_LEN(ptr) + 1;
343  break;
344  case PN_TCLOSURE:
345  sz = sizeof(struct PNClosure) + (PN_CLOSURE(ptr)->extra * sizeof(PN));
346  break;
347  case PN_TTUPLE:
348  sz = sizeof(struct PNTuple) + (sizeof(PN) * ((struct PNTuple *)ptr)->alloc);
349  break;
350  case PN_TSTATE:
351  sz = sizeof(Potion);
352  break;
353  case PN_TFILE:
354  sz = sizeof(struct PNFile);
355  break;
356  case PN_TVTABLE:
357  sz = sizeof(struct PNVtable);
358  break;
359  case PN_TSOURCE:
360  sz = sizeof(struct PNSource);
361  break;
362  case PN_TBYTES:
363  sz = sizeof(struct PNBytes) + ((struct PNBytes *)ptr)->siz;
364  break;
365  case PN_TPROTO:
366  sz = sizeof(struct PNProto);
367  break;
368  case PN_TTABLE:
369  sz = sizeof(struct PNTable) + kh_mem(PN, ptr);
370  break;
371  case PN_TLICK:
372  sz = sizeof(struct PNLick);
373  break;
374  case PN_TSTRINGS:
375  sz = sizeof(struct PNTable) + kh_mem(str, ptr);
376  break;
377  case PN_TFLEX:
378  sz = sizeof(PNFlex) + ((PNFlex *)ptr)->siz;
379  break;
380  case PN_TCONT:
381  sz = sizeof(struct PNCont) + (((struct PNCont *)ptr)->len * sizeof(PN));
382  break;
383  case PN_TUSER:
384  sz = sizeof(struct PNData) + ((struct PNData *)ptr)->siz;
385  break;
386  }
387 
388 done_1:
389  if (sz < sizeof(struct PNFwd))
390  sz = sizeof(struct PNFwd);
391  return PN_ALIGN(sz, 8); // force 64-bit alignment
392 }
393 
394 void *potion_gc_copy(Potion *P, struct PNObject *ptr) {
395  void *dst = (void *)P->mem->old_cur;
396  PN_SIZE sz = potion_type_size(P, (const struct PNObject *)ptr);
397  if (!sz) { //external pointer or immediate value
398  DBG_G(P,"GC copy: assuming extern pointer or immediate potion value %p: %ld / 0x%lx\n", ptr, *(long*)ptr, *(long*)ptr);
399  //return ptr;
400  memcpy(dst, ptr, sizeof(void*));
401  return dst;
402  }
403  memcpy(dst, ptr, sz);
404  P->mem->old_cur = (char *)dst + sz;
405 
406  ((struct PNFwd *)ptr)->fwd = POTION_COPIED;
407  ((struct PNFwd *)ptr)->siz = sz;
408  ((struct PNFwd *)ptr)->ptr = (PN)dst;
409 
410  return dst;
411 }
412 
413 void *potion_mark_minor(Potion *P, const struct PNObject *ptr) {
414  struct PNMemory *M = P->mem;
415  PN_SIZE i;
416  PN_SIZE sz = 16;
417 
418  switch (((struct PNFwd *)ptr)->fwd) {
419  case POTION_COPIED:
420  case POTION_FWD:
421  GC_MINOR_UPDATE(((struct PNFwd *)ptr)->ptr);
422  goto done_2;
423  }
424 
425  if (ptr->vt > PN_TUSER) {
426  GC_MINOR_UPDATE(PN_VTABLE(ptr->vt));
427  int ivars = ((struct PNVtable *)PN_VTABLE(ptr->vt))->ivlen;
428  for (i = 0; i < ivars; i++)
429  GC_MINOR_UPDATE(((struct PNObject *)ptr)->ivars[i]);
430  goto done_2;
431  }
432 
433  switch (ptr->vt) {
434  case PN_TWEAK:
435  GC_MINOR_UPDATE(((struct PNWeakRef *)ptr)->data);
436  break;
437  case PN_TCLOSURE:
438  GC_MINOR_UPDATE(((struct PNClosure *)ptr)->sig);
439  for (i = 0; i < ((struct PNClosure *)ptr)->extra; i++)
440  GC_MINOR_UPDATE(((struct PNClosure *)ptr)->data[i]);
441  break;
442  case PN_TTUPLE: {
443  struct PNTuple * volatile t = (struct PNTuple *)potion_fwd((PN)ptr);
444  for (i = 0; i < t->len; i++)
445  GC_MINOR_UPDATE(t->set[i]);
446  }
447  break;
448  case PN_TSTATE:
449  DBG_Gv(P,"GC mark minor Potion_State\n"); // only with threads
450  GC_MINOR_UPDATE(((Potion *)ptr)->strings);
451  GC_MINOR_UPDATE(((Potion *)ptr)->lobby);
452  GC_MINOR_UPDATE(((Potion *)ptr)->vts);
453  GC_MINOR_UPDATE(((Potion *)ptr)->call);
454  GC_MINOR_UPDATE(((Potion *)ptr)->callset);
455  GC_MINOR_UPDATE(((Potion *)ptr)->input);
456  GC_MINOR_UPDATE(((Potion *)ptr)->source);
457  //GC_MINOR_UPDATE(((Potion *)ptr)->pbuf);
458  GC_MINOR_UPDATE(((Potion *)ptr)->line);
459  GC_MINOR_UPDATE(((Potion *)ptr)->unclosed);
460  //GC_MINOR_UPDATE(((Potion *)ptr)->target);
461  GC_MINOR_UPDATE(((Potion *)ptr)->mem);
462  break;
463  case PN_TFILE:
464  GC_MINOR_UPDATE(((struct PNFile *)ptr)->path);
465  break;
466  case PN_TVTABLE:
467  if (((struct PNVtable *)ptr)->parent)
468  GC_MINOR_UPDATE(PN_VTABLE(((struct PNVtable *)ptr)->parent));
469  GC_MINOR_UPDATE(((struct PNVtable *)ptr)->name);
470  GC_MINOR_UPDATE(((struct PNVtable *)ptr)->ivars);
471  GC_MINOR_UPDATE(((struct PNVtable *)ptr)->methods);
472  GC_MINOR_UPDATE(((struct PNVtable *)ptr)->meta);
473  GC_MINOR_UPDATE(((struct PNVtable *)ptr)->ctor);
474  GC_MINOR_UPDATE(((struct PNVtable *)ptr)->call);
475  GC_MINOR_UPDATE(((struct PNVtable *)ptr)->callset);
476  break;
477  case PN_TSOURCE:
478  GC_MINOR_UPDATE(((struct PNSource *)ptr)->a[0]);
479  GC_MINOR_UPDATE(((struct PNSource *)ptr)->a[1]);
480  GC_MINOR_UPDATE(((struct PNSource *)ptr)->a[2]);
481  GC_MINOR_UPDATE(((struct PNSource *)ptr)->line);
482  break;
483  case PN_TPROTO:
484  GC_MINOR_UPDATE(((struct PNProto *)ptr)->source);
485  GC_MINOR_UPDATE(((struct PNProto *)ptr)->sig);
486  GC_MINOR_UPDATE(((struct PNProto *)ptr)->stack);
487  GC_MINOR_UPDATE(((struct PNProto *)ptr)->paths);
488  GC_MINOR_UPDATE(((struct PNProto *)ptr)->locals);
489  GC_MINOR_UPDATE(((struct PNProto *)ptr)->upvals);
490  GC_MINOR_UPDATE(((struct PNProto *)ptr)->values);
491  GC_MINOR_UPDATE(((struct PNProto *)ptr)->protos);
492  GC_MINOR_UPDATE(((struct PNProto *)ptr)->debugs);
493  GC_MINOR_UPDATE(((struct PNProto *)ptr)->tree);
494  GC_MINOR_UPDATE(((struct PNProto *)ptr)->asmb);
495  break;
496  case PN_TTABLE:
497  GC_MINOR_UPDATE_TABLE(PN, (struct PNTable *)potion_fwd((PN)ptr), 1);
498  break;
499  case PN_TLICK:
500  GC_MINOR_UPDATE(((struct PNLick *)ptr)->name);
501  GC_MINOR_UPDATE(((struct PNLick *)ptr)->attr);
502  GC_MINOR_UPDATE(((struct PNLick *)ptr)->inner);
503  break;
504  case PN_TFLEX:
505  for (i = 0; i < PN_FLEX_SIZE(ptr); i++)
506  GC_MINOR_UPDATE(PN_FLEX_AT(ptr, i));
507  break;
508  case PN_TCONT:
509  GC_KEEP(ptr);
510  pngc_mark_array(P, (_PN *)((struct PNCont *)ptr)->stack + 3, ((struct PNCont *)ptr)->len - 3, 1);
511  break;
512  }
513 
514 done_2:
515  sz = potion_type_size(P, ptr);
516  return (void *)((char *)ptr + sz);
517 }
518 
519 void *potion_mark_major(Potion *P, const struct PNObject *ptr) {
520  struct PNMemory *M = P->mem;
521  PN_SIZE i;
522  PN_SIZE sz = 16;
523 
524  switch (((struct PNFwd *)ptr)->fwd) {
525  case POTION_COPIED:
526  case POTION_FWD:
527  GC_MAJOR_UPDATE(((struct PNFwd *)ptr)->ptr);
528  goto done_3;
529  }
530 
531  if (ptr->vt > PN_TUSER) {
532  GC_MAJOR_UPDATE(PN_VTABLE(ptr->vt));
533  int ivars = ((struct PNVtable *)PN_VTABLE(ptr->vt))->ivlen;
534  for (i = 0; i < ivars; i++)
535  GC_MAJOR_UPDATE(((struct PNObject *)ptr)->ivars[i]);
536  goto done_3;
537  }
538 
539  switch (ptr->vt) {
540  case PN_TWEAK:
541  GC_MAJOR_UPDATE(((struct PNWeakRef *)ptr)->data);
542  break;
543  case PN_TCLOSURE:
544  GC_MAJOR_UPDATE(((struct PNClosure *)ptr)->sig);
545  for (i = 0; i < ((struct PNClosure *)ptr)->extra; i++)
546  GC_MAJOR_UPDATE(((struct PNClosure *)ptr)->data[i]);
547  break;
548  case PN_TTUPLE: {
549  struct PNTuple * volatile t = (struct PNTuple *)potion_fwd((PN)ptr);
550  for (i = 0; i < t->len; i++)
551  GC_MAJOR_UPDATE(t->set[i]);
552  }
553  break;
554  case PN_TSTATE:
555  DBG_Gv(P,"GC mark major Potion_State\n"); // only with threads
556  //DBG_G(P," strings\n");
557  GC_MAJOR_UPDATE(((Potion *)ptr)->strings);
558  //DBG_G(P," lobby\n");
559  GC_MAJOR_UPDATE(((Potion *)ptr)->lobby);
560  //DBG_G(P," vts\n");
561  GC_MAJOR_UPDATE(((Potion *)ptr)->vts);
562  //DBG_G(P," call\n");
563  GC_MAJOR_UPDATE(((Potion *)ptr)->call);
564  //DBG_G(P," callset\n");
565  GC_MAJOR_UPDATE(((Potion *)ptr)->callset);
566  //DBG_G(P," input\n");
567  GC_MAJOR_UPDATE(((Potion *)ptr)->input);
568  //DBG_G(P," source\n");
569  GC_MAJOR_UPDATE(((Potion *)ptr)->source);
570  //DBG_G(P," pbuf\n");
571  //GC_MAJOR_UPDATE(((Potion *)ptr)->pbuf);
572  //DBG_G(P," line\n");
573  GC_MAJOR_UPDATE(((Potion *)ptr)->line);
574  //DBG_G(P," unclosed\n");
575  GC_MAJOR_UPDATE(((Potion *)ptr)->unclosed);
576  //GC_MAJOR_UPDATE(((Potion *)ptr)->target);
577  //DBG_G(P," mem\n");
578  GC_MAJOR_UPDATE(((Potion *)ptr)->mem);
579  break;
580  case PN_TFILE:
581  GC_MAJOR_UPDATE(((struct PNFile *)ptr)->path);
582  break;
583  case PN_TVTABLE:
584  if (((struct PNVtable *)ptr)->parent)
585  GC_MAJOR_UPDATE(PN_VTABLE(((struct PNVtable *)ptr)->parent));
586  GC_MAJOR_UPDATE(((struct PNVtable *)ptr)->name);
587  GC_MAJOR_UPDATE(((struct PNVtable *)ptr)->ivars);
588  GC_MAJOR_UPDATE(((struct PNVtable *)ptr)->methods);
589  GC_MAJOR_UPDATE(((struct PNVtable *)ptr)->meta);
590  GC_MAJOR_UPDATE(((struct PNVtable *)ptr)->ctor);
591  GC_MAJOR_UPDATE(((struct PNVtable *)ptr)->call);
592  GC_MAJOR_UPDATE(((struct PNVtable *)ptr)->callset);
593  break;
594  case PN_TSOURCE:
595  GC_MAJOR_UPDATE(((struct PNSource *)ptr)->a[0]);
596  GC_MAJOR_UPDATE(((struct PNSource *)ptr)->a[1]);
597  GC_MAJOR_UPDATE(((struct PNSource *)ptr)->a[2]);
598  GC_MAJOR_UPDATE(((struct PNSource *)ptr)->line);
599  break;
600  case PN_TPROTO:
601  GC_MAJOR_UPDATE(((struct PNProto *)ptr)->source);
602  GC_MAJOR_UPDATE(((struct PNProto *)ptr)->sig);
603  GC_MAJOR_UPDATE(((struct PNProto *)ptr)->stack);
604  GC_MAJOR_UPDATE(((struct PNProto *)ptr)->paths);
605  GC_MAJOR_UPDATE(((struct PNProto *)ptr)->locals);
606  GC_MAJOR_UPDATE(((struct PNProto *)ptr)->upvals);
607  GC_MAJOR_UPDATE(((struct PNProto *)ptr)->values);
608  GC_MAJOR_UPDATE(((struct PNProto *)ptr)->protos);
609  GC_MAJOR_UPDATE(((struct PNProto *)ptr)->debugs);
610  GC_MAJOR_UPDATE(((struct PNProto *)ptr)->tree);
611  GC_MAJOR_UPDATE(((struct PNProto *)ptr)->asmb);
612  break;
613  case PN_TTABLE:
614  GC_MAJOR_UPDATE_TABLE(PN, (struct PNTable *)potion_fwd((PN)ptr), 1);
615  break;
616  case PN_TLICK:
617  GC_MAJOR_UPDATE(((struct PNLick *)ptr)->name);
618  GC_MAJOR_UPDATE(((struct PNLick *)ptr)->attr);
619  GC_MAJOR_UPDATE(((struct PNLick *)ptr)->inner);
620  break;
621  case PN_TFLEX:
622  for (i = 0; i < PN_FLEX_SIZE(ptr); i++)
623  GC_MAJOR_UPDATE(PN_FLEX_AT(ptr, i));
624  break;
625  case PN_TCONT:
626  GC_KEEP(ptr);
627  pngc_mark_array(P, (_PN *)((struct PNCont *)ptr)->stack + 3, ((struct PNCont *)ptr)->len - 3, 2);
628  break;
629  }
630 
631 done_3:
632  sz = potion_type_size(P, ptr);
633  return (void *)((char *)ptr + sz);
634 }
635 
658 Potion *potion_gc_boot(void *sp) {
659  Potion *P;
660  int bootsz = POTION_MIN_BIRTH_SIZE;
661  void *page1 = pngc_page_new(&bootsz, 0);
662  if (page1 == NULL)
663  potion_fatal("Not enough memory");
664  struct PNMemory *M = (struct PNMemory *)page1;
665  PN_MEMZERO(M, struct PNMemory);
666 #ifdef DEBUG
667  M->time = 0.0;
668 #endif
669 
670  SET_GEN(birth, page1, bootsz);
671  SET_STOREPTR(4);
672 
673  // stack must be 16-byte aligned on amd64 SSE or __APPLE__, and 32-byte with AVX instrs.
674  // at least amd64 atof() does SSE register return.
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;
678 #else
679  M->cstack = sp;
680 #endif
681  P = (Potion *)((char *)M + PN_ALIGN(sizeof(struct PNMemory), 8));
682  PN_MEMZERO(P, Potion);
683  P->mem = M;
684 
685  M->birth_cur = (void *)((char *)P + PN_ALIGN(sizeof(Potion), 8));
686  GC_PROTECT(P);
687  return P;
688 }
689 
690 // TODO: release memory allocated by the user
692  struct PNMemory *M = P->mem;
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;
697 
698  if (M->birth_lo != M) {
699  void *protend = (void *)PN_ALIGN((_PN)M->protect, POTION_PAGESIZE);
700  DBG_G(P,"GC page delete: %p - %p\n", M, protend);
701  pngc_page_delete((void *)M, (char *)protend - (char *)M);
702  }
703 
704  pngc_page_delete(birthlo, birthhi - birthlo);
705  if (oldlo != NULL)
706  pngc_page_delete(oldlo, oldhi - oldlo);
707 
708  birthlo = 0;
709  birthhi = 0;
710  oldlo = 0;
711  oldhi = 0;
712 }
713 
715 {
716  int total = (char *)P->mem->birth_cur - (char *)P->mem->birth_lo;
717  if (P->mem != P->mem->birth_lo)
718  total += (char *)P->mem->protect - (char *)P->mem;
719  if (P->mem->old_lo != NULL)
720  total += (char *)P->mem->old_cur - (char *)P->mem->old_lo;
721  return PN_NUM(total);
722 }
723 
725 {
726  int total = 0;
727  if (P->mem->protect != NULL)
728  total += (char *)P->mem->protect - (char *)P->mem;
729  return PN_NUM(total);
730 }
731 
733 {
734  int total = (char *)P->mem->birth_hi - (char *)P->mem->birth_lo;
735  if (P->mem != P->mem->birth_lo)
736  total += (char *)P->mem->protect - (char *)P->mem;
737  if (P->mem->old_lo != NULL)
738  total += (char *)P->mem->old_hi - (char *)P->mem->old_lo;
739  return PN_NUM(total);
740 }
volatile void * old_lo
the old region (TODO: consider making the old region common to all threads)
Definition: potion.h:673
#define DEL_BIRTH_REGION()
Definition: gc.h:40
forwarding pointer (in case of reallocation)
Definition: potion.h:304
static double mytime()
Definition: gc.c:25
byte strings are raw character data, volatile, may be appended/changed.
Definition: potion.h:338
PN potion_gc_actual(Potion *P, PN cl, PN self)
Definition: gc.c:714
void * potion_mark_major(Potion *P, const struct PNObject *ptr)
Definition: gc.c:519
#define min(a, b)
Definition: internal.h:26
#define PN_TSTATE
Definition: potion.h:116
klib hash table library based on double hashing http://en.wikipedia.org/wiki/Double_hashing ...
#define PN_TSTRING
Definition: potion.h:112
a tuple is an array of PNs.
Definition: potion.h:468
#define PN_TCLOSURE
Definition: potion.h:114
#define GC_MAJOR_UPDATE_TABLE(name, kh, is_map)
Definition: gc.h:101
volatile void * birth_hi
Definition: potion.h:669
Potion_Flags flags
vm flags: execution model and debug flags
Definition: potion.h:650
PN ptr
Definition: potion.h:307
unsigned long _PN
Definition: potion.h:78
a closure is an anonymous function, without closed values,
Definition: potion.h:372
the central vtable, see io http://www.piumarta.com/pepsi/objmodel.pdf
Definition: table.h:24
#define PN_TUSER
Definition: potion.h:130
#define max(a, b)
Definition: internal.h:30
static int potion_birth_suggest(int need, volatile void *oldlo, volatile void *oldhi)
Definition: gc.h:147
struct to wrap arbitrary data that we may want to allocate from Potion.
Definition: potion.h:317
#define PN_TLICK
Definition: potion.h:125
static int NEW_BIRTH_REGION(struct PNMemory *M, void **wb, int sz)
Definition: gc.c:123
#define PN_TFILE
Definition: potion.h:117
#define IN_BIRTH_REGION(p)
Definition: gc.h:52
#define PN_TCONT
Definition: potion.h:129
non-API GC internals
#define PN_TNIL
Definition: potion.h:107
#define POTION_MAX_BIRTH_SIZE
Definition: gc.h:17
#define GC_PROTECT(P)
Definition: internal.h:137
static PN potion_fwd(PN)
the potion type is the 't' in the vtable tuple (m,t)
Definition: potion.h:561
PN data[]
PNString.
Definition: potion.h:380
struct PNMemory * mem
allocator/gc
Definition: potion.h:651
a file is wrapper around a file descriptor, non-volatile but mutable.
Definition: potion.h:361
#define DEBUG
Definition: config.h:23
#define POTION_MIN_BIRTH_SIZE
Definition: gc.h:13
#define POTION_OK
internal errors
Definition: potion.h:765
#define PN_TTUPLE
Definition: potion.h:115
#define PN_ALIGN(o, x)
Definition: potion.h:223
#define PN_TYPECHECK(t)
Definition: potion.h:137
a weak ref is used for upvals, it acts as a memory slot, non-volatile but mutable.
Definition: potion.h:479
static int potion_gc_minor(Potion *P, int sz)
Definition: gc.c:143
#define PN_TFLEX
Definition: potion.h:126
#define PN_TBYTES
Definition: potion.h:121
#define PN_NUM(i)
Definition: potion.h:204
volatile void * birth_lo
the birth region
Definition: potion.h:669
void * potion_mmap(size_t length, const char exec)
Definition: contrib.c:89
void * cstack
machine stack start
Definition: potion.h:676
int potion_munmap(void *mem, size_t len)
Definition: contrib.c:101
unsigned int PN_SIZE
Definition: potion.h:79
standard objects act like C structs the fields are defined by the type and it's a fixed size...
Definition: potion.h:295
void * protect
end of protected memory
Definition: potion.h:677
Potion * potion_gc_boot(void *sp)
Definition: gc.c:658
a continuation saves the stack and all stack pointers.
Definition: potion.h:510
#define PN_TVTABLE
Definition: potion.h:119
static ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS PN_SIZE pngc_mark_array(Potion *P, register _PN *x, register long n, int type)
Definition: gc.c:60
PN_SIZE len
Definition: potion.h:470
#define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS
Definition: potion.h:65
#define SET_GEN(t, p, s)
Definition: gc.h:28
#define GC_MINOR_STRINGS()
Definition: gc.h:116
a lick is a unit of generic tree data.
Definition: potion.h:499
#define PN_TSOURCE
Definition: potion.h:120
#define M
Definition: mt19937ar.c:53
the garbage collector
Definition: potion.h:667
#define PN_FLEX_SIZE(N)
Definition: potion.h:231
void * potion_gc_copy(Potion *P, struct PNObject *ptr)
Definition: gc.c:394
void * potion_mark_minor(Potion *P, const struct PNObject *ptr)
Definition: gc.c:413
the table class, based on khash
Definition: table.h:40
#define POTION_NO_MEM
Definition: potion.h:766
volatile void * old_hi
Definition: potion.h:673
#define IN_OLDER_REGION(p)
Definition: gc.h:55
#define HAS_REAL_TYPE(v)
Definition: gc.c:57
struct Potion_State Potion
Definition: potion.h:80
volatile void ** birth_storeptr
Definition: potion.h:670
#define PN_MEMCPY_N(X, Y, T, N)
Definition: internal.h:22
#define PN_TWEAK
Definition: potion.h:113
PN potion_gc_fixed(Potion *P, PN cl, PN self)
Definition: gc.c:724
#define GC_MAJOR_UPDATE(p)
Definition: gc.h:77
strings are immutable UTF-8, the ID is incremental and they may be garbage collected.
Definition: potion.h:328
#define DBG_G(P,...)
Definition: gc.c:41
#define GC_MINOR_UPDATE_TABLE(name, kh, is_map)
Definition: gc.h:86
double time
Definition: potion.h:679
#define POTION_ESP(p)
Definition: internal.h:115
PN_SIZE potion_stack_len(Potion *P, _PN **p)
Definition: gc.c:50
a prototype is compiled source code, a closure block (lambda) non-volatile.
Definition: potion.h:445
void potion_garbagecollect(Potion *P, int sz, int full)
Definition: gc.c:266
non-API internal parts
PNFlex *volatile vts
built in types
Definition: potion.h:649
volatile int pass
Definition: potion.h:675
#define PN_IS_PTR(v)
Definition: potion.h:159
#define PN_FLEX_AT(N, I)
Definition: potion.h:230
#define SET_STOREPTR(n)
Definition: gc.h:34
#define PN_TSTRINGS
Definition: potion.h:127
#define GC_MINOR_UPDATE(p)
Definition: gc.h:69
PN_SIZE potion_type_size(Potion *P, const struct PNObject *ptr)
Definition: gc.c:306
volatile void * old_cur
Definition: potion.h:673
volatile void * birth_cur
Definition: potion.h:669
the global interpreter state P. currently singleton (not threads yet)
Definition: potion.h:644
The potion API.
volatile int majors
Definition: potion.h:675
#define PN_TYPE(x)
Definition: potion.h:133
#define PN_TPROTO
Definition: potion.h:122
#define DBG_Gv(P,...)
Definition: gc.c:37
#define GC_FORWARD(p, v)
Definition: gc.h:61
#define IS_GC_PROTECTED(p)
Definition: gc.h:49
void pngc_page_delete(void *mem, int sz)
Definition: gc.c:119
#define POTION_COPIED
Definition: potion.h:147
void * pngc_page_new(int *sz, const char exec)
Definition: gc.c:114
the central table type, based on core/khash.h
doubles are floating point numbers stored as binary data.
Definition: potion.h:352
#define PN_MEMZERO(X, T)
Definition: internal.h:19
const char * name
Definition: compile.c:30
#define POTION_PAGESIZE
Definition: config.h:36
PN_SIZE alloc
overallocate a bit
Definition: potion.h:471
static int potion_gc_major(Potion *P, int siz)
Definition: gc.c:187
PN potion_gc_reserved(Potion *P, PN cl, PN self)
Definition: gc.c:732
#define GC_MAJOR_STRINGS()
Definition: gc.h:131
int ivlen
PN_TUPLE_LEN(ivars)
Definition: table.h:29
#define PN_TTABLE
Definition: potion.h:124
volatile _PN PN
Definition: potion.h:81
volatile int dirty
Definition: potion.h:675
#define PN_TNUMBER
Definition: potion.h:108
#define POTION_GC_PERIOD
Definition: gc.h:25
#define POTION_FWD
Definition: potion.h:146
ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS PN_SIZE potion_mark_stack(Potion *P, int type)
Definition: gc.c:98
#define GC_KEEP(p)
Definition: gc.h:37
PN set[]
Definition: potion.h:472
void potion_fatal(char *message)
Definition: internal.c:282
volatile int minors
Definition: potion.h:675
PN ivars
PNTuple of all our or the parents inherited vars.
Definition: table.h:30
#define PN_VTABLE(t)
Definition: potion.h:136
void potion_gc_release(Potion *P)
Definition: gc.c:691
volatile int collecting
Definition: potion.h:675
#define POTION_GC_THRESHOLD
Definition: gc.h:24