Example #1
0
/** \par
 Potion's GC is a generational copying GC. This is why the
 volatile keyword is used so liberally throughout the source
 code. PN types may suddenly move during any collection phase.
 They move from the birth area to the old area.

 Potion actually begins by allocating an old area. This is for
 two reasons. First, the script may be too short to require an
 old area, so we want to avoid allocating two areas to start with.
 And second, since Potion loads its core classes into GC first,
 we save ourselves a severe promotion step by beginning with an
 automatic promotion to second generation. (Oh and this allows
 the core Potion struct pointer to be non-volatile.)

 In short, this first page is never released, since the GC struct
 itself is on that page.

 While this may pay a slight penalty in memory size for long-running
 scripts, perhaps I could add some occassional compaction to solve
 that as well.
 \sa potion_init() which calls GC_PROTECT()
*/
Potion *potion_gc_boot(void *sp) {
  Potion *P;
  int bootsz = POTION_MIN_BIRTH_SIZE;
  void *page1 = pngc_page_new(&bootsz, 0);
  if (page1 == NULL)
    potion_fatal("Not enough memory");
  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);

  // stack must be 16-byte aligned on amd64 SSE or __APPLE__, and 32-byte with AVX instrs.
  // at least amd64 atof() does SSE register return.
#if (PN_SIZE_T == 8) || 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;
}
Example #2
0
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);
}
Example #3
0
//
// Potion's GC is a generational copying GC. This is why the
// volatile keyword is used so liberally throughout the source
// code. PN types may suddenly move during any collection phase.
// They move from the birth area to the old area.
//
// Potion actually begins by allocating an old area. This is for
// two reasons. First, the script may be too short to require an
// old area, so we want to avoid allocating two areas to start with.
// And second, since Potion loads its core classes into GC first,
// we save ourselves a severe promotion step by beginning with an
// automatic promotion to second generation. (Oh and this allows
// the core Potion struct pointer to be non-volatile.)
//
// In short, this first page is never released, since the GC struct
// itself is on that page.
//
// While this may pay a slight penalty in memory size for long-running
// scripts, perhaps I could add some occassional compaction to solve
// that as well.
//
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);

  SET_GEN(birth, page1, bootsz);
  SET_STOREPTR(4);

  M->cstack = sp;
  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;
}