void potion_test_allocated(CuTest *T) { struct PNMemory *M = P->mem; void *prev = NULL; void *scanptr = (void *)((char *)M->birth_lo + PN_ALIGN(sizeof(struct PNMemory), 8)); while ((PN)scanptr < (PN)M->birth_cur) { if (((struct PNFwd *)scanptr)->fwd != POTION_FWD && ((struct PNFwd *)scanptr)->fwd != POTION_COPIED) { if (((struct PNObject *)scanptr)->vt > PN_TUSER) { vPN(Object) o = (struct PNObject *)scanptr; fprintf(stderr, "error: scanning heap from %p to %p\n", M->birth_lo, M->birth_cur); fprintf(stderr, "%p in %s region\n", scanptr, IS_GC_PROTECTED(scanptr) ? "protected" : IN_BIRTH_REGION(scanptr) ? "birth" : IN_OLDER_REGION(scanptr) ? "older" : "gc"); fprintf(stderr, "%p { uniq:0x%08x vt:0x%08x ivars[0]:0x%08lx type:0x%x}\n", scanptr, o->uniq, o->vt, o->ivars[0], potion_type((PN)scanptr)); fprintf(stderr, "prev %p: size=%d, type:0x%x (%s)\n", prev, potion_type_size(P, prev), potion_type((PN)prev), AS_STR(PN_VTABLE(PN_TYPE((PN)prev)))); #ifdef DEBUG //potion_dump_stack(P); #endif } CuAssert(T, "wrong type for allocated object", ((struct PNObject *)scanptr)->vt <= PN_TUSER); } prev = scanptr; scanptr = (void *)((char *)scanptr + potion_type_size(P, scanptr)); CuAssert(T, "allocated object goes beyond GC pointer", (PN)scanptr <= (PN)M->birth_cur); } }
void potion_dump(Potion *P, PN data) { PN pd = potion_send(data, PN_string); PN pt = potion_send(PN_VTABLE(PN_TYPE(data)), PN_string); char *d = pd ? PN_STR_PTR(pd) : "nil"; char *t = pt ? PN_STR_PTR(pt) : "NilKind"; printf("%s (%s)\n", d, t); }
/**\memberof PNFile \c "write" a binary representation of obj to the file handle. \param obj PNString, PNBytes, PNInteger (long or double), PNBoolean (char 0 or 1) \return PNInteger written bytes or PN_NIL */ PN potion_file_write(Potion *P, PN cl, pn_file self, PN obj) { long len = 0; char *ptr = NULL; union { double d; long l; char c; } tmp; //TODO: maybe extract ptr+len to seperate function if (!PN_IS_PTR(obj)) { if (!obj) return PN_NIL; //silent else if (PN_IS_INT(obj)) { tmp.l = PN_NUM(obj); len = sizeof(tmp); ptr = (char *)&tmp.l; } else if (PN_IS_BOOL(obj)) { tmp.c = (obj == PN_TRUE) ? 1 : 0; len = 1; ptr = (char *)&tmp.c; } else { assert(0 && "Invalid primitive type"); } } else { switch (PN_TYPE(obj)) { case PN_TSTRING: len = PN_STR_LEN(obj); ptr = PN_STR_PTR(obj); break; case PN_TBYTES: len = potion_send(obj, PN_STR("length")); ptr = PN_STR_PTR(obj); break; case PN_TNUMBER: { tmp.d = PN_DBL(obj); len = sizeof(tmp); ptr = (char *)&tmp.d; break; } default: return potion_type_error(P, obj); } } int r = write(self->fd, ptr, len); if (r == -1) return potion_io_error(P, "write"); return PN_NUM(r); }
static inline char *potion_type_name(Potion *P, PN obj) { obj = potion_fwd(obj); return PN_IS_PTR(obj) ? AS_STR(potion_send(PN_VTABLE(PN_TYPE(obj)), PN_string)) : PN_IS_NIL(obj) ? "nil" : PN_IS_NUM(obj) ? "Number" : "Boolean"; }
void potion_dump_stack(Potion *P) { long n; PN *end, *ebp, *start = P->mem->cstack; struct PNMemory *M = P->mem; POTION_ESP(&end); POTION_EBP(&ebp); #if POTION_STACK_DIR > 0 n = end - start; #else n = start - end + 1; start = end; end = M->cstack; #endif printf("-- dumping %ld stack from %p to %p --\n", n, start, end); printf(" ebp = %p, *ebp = %lx\n", ebp, *ebp); while (n--) { vPN(Object) o = (struct PNObject*)*start; printf(" stack(%ld) = %p: %lx", n, start, *start); if (IS_GC_PROTECTED(*start)) printf(" vt=%x gc", PN_TYPE(o)); else if (IN_BIRTH_REGION(*start)) printf(" vt=%x gc(0)", PN_TYPE(o)); else if (IN_OLDER_REGION(*start)) printf(" vt=%x gc(1)", PN_TYPE(o)); if (*start == 0) printf(" nil\n"); else if (*start & 1) printf(" %ld INT\n", PN_INT(*start)); else if (*start & 2) printf(" %s BOOL\n", *start == 2 ? "false" : "true"); else printf(" \n"); start++; } }
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: // count only 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: // minor 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: // major 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; }
void potion_test_double(CuTest *T) { PN dec = potion_strtod(P, "14466", 5); CuAssert(T, "double not a number", PN_TYPE(dec) == PN_TNUMBER); }
void potion_test_bool(CuTest *T) { CuAssert(T, "true isn't a bool type", PN_TYPE(PN_TRUE) == PN_TBOOLEAN); CuAssert(T, "true is a ref", !PN_IS_PTR(PN_TRUE)); CuAssert(T, "false isn't a bool type", PN_TYPE(PN_FALSE) == PN_TBOOLEAN); CuAssert(T, "false is a ref", !PN_IS_PTR(PN_FALSE)); }
void potion_test_nil(CuTest *T) { CuAssert(T, "nil isn't a nil type", PN_TYPE(PN_NIL) == PN_TNIL); CuAssert(T, "nil is a ref", !PN_IS_PTR(PN_NIL)); CuAssert(T, "nil nil? is false", PN_TRUE == potion_send(PN_NIL, potion_str(P, "nil?"))); }
static void potion_cmd_compile ( char *filename, int exec, int verbose, void *sp ) { PN buf, code; int fd = -1; struct stat stats; Potion *P = potion_create(sp); if (stat(filename, &stats) == -1) { potion_warn("** %s does not exist.\n", filename); goto done; } fd = open(filename, O_RDONLY | O_BINARY); if (fd == -1) { potion_warn("** could not open %s. check permissions.\n", filename); goto done; } buf = potion_bytes(P, stats.st_size); if (read(fd, PN_STR_PTR(buf), stats.st_size) == stats.st_size) { PN_STR_PTR(buf)[stats.st_size] = '\0'; code = potion_source_load(P, PN_NIL, buf); if (PN_IS_PROTO(code)) { if (verbose > 1) printf("\n\n-- loaded --\n"); } else { code = potion_parse(P, buf); if (PN_TYPE(code) == PN_TERROR) { potion_send(potion_send(code, PN_string), PN_print); goto done; } if (verbose > 1) { printf("\n-- parsed --\n"); potion_send(potion_send(code, PN_string), PN_print); printf("\n"); } code = potion_send(code, PN_compile, potion_str(P, filename), PN_NIL); if (verbose > 1) printf("\n-- compiled --\n"); } if (verbose > 1) { potion_send(potion_send(code, PN_string), PN_print); printf("\n"); } if (exec == 1) { code = potion_vm(P, code, P->lobby, PN_NIL, 0, NULL ); if (verbose > 1) printf( "\n-- vm returned %p (fixed=%ld, actual=%ld, reserved=%ld) --\n", (void *) code, PN_INT(potion_gc_fixed(P, 0, 0)), PN_INT(potion_gc_actual(P, 0, 0)), PN_INT(potion_gc_reserved(P, 0, 0))); if (verbose) { potion_send(potion_send(code, PN_string), PN_print); printf("\n"); } } else if (exec == 2) { #if POTION_JIT == 1 PN val; PN cl = potion_closure_new(P, (PN_F)potion_jit_proto(P, code, POTION_JIT_TARGET), PN_NIL, 1); PN_CLOSURE(cl)->data[0] = code; val = PN_PROTO(code)->jit(P, cl, P->lobby); if (verbose > 1) printf("\n-- jit returned %p (fixed=%ld, actual=%ld, reserved=%ld) --\n", PN_PROTO(code)->jit, PN_INT(potion_gc_fixed(P, 0, 0)), PN_INT(potion_gc_actual(P, 0, 0)), PN_INT(potion_gc_reserved(P, 0, 0))); if (verbose) { potion_send(potion_send(val, PN_string), PN_print); printf("\n"); } #else potion_warn("** potion built without JIT support\n"); #endif } else { char pnbpath[255]; FILE *pnb; sprintf(pnbpath, "%sb", filename); pnb = fopen(pnbpath, "wb"); if (!pnb) { potion_warn("** could not open %s for writing. check permissions.\n",pnbpath); goto done; } code = potion_source_dump(P, PN_NIL, code); if (fwrite(PN_STR_PTR(code), 1, PN_STR_LEN(code), pnb) == PN_STR_LEN(code)) { potion_notice("** compiled code saved to %s\n", pnbpath); potion_notice("** run it with: potion %s\n", pnbpath); fclose(pnb); } else { potion_warn("** could not write all bytecode.\n"); } } #if 0 void *scanptr = (void *)((char *)P->mem->old_lo + (sizeof(PN) * 2)); while ((PN)scanptr < (PN)P->mem->old_cur) { printf("%p.vt = %lx (%u)\n", scanptr, ((struct PNObject *)scanptr)->vt, potion_type_size(P, scanptr)); if (((struct PNFwd *)scanptr)->fwd != POTION_FWD && ((struct PNFwd *)scanptr)->fwd != POTION_COPIED) { if (((struct PNObject *)scanptr)->vt < 0 || ((struct PNObject *)scanptr)->vt > PN_TUSER) { printf("wrong type for allocated object: %p.vt = %lx\n", scanptr, ((struct PNObject *)scanptr)->vt); break; } } scanptr = (void *)((char *)scanptr + potion_type_size(P, scanptr)); if ((PN)scanptr > (PN)P->mem->old_cur) { printf("allocated object goes beyond GC pointer\n"); break; } } #endif } else { potion_warn("** could not read entire file."); } done: if (fd != -1) close(fd); if (P != NULL ) potion_destroy(P); }