static mps_res_t myscan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit) { int i; INCCOUNT(SCANCALL_COUNT); MPS_SCAN_BEGIN(ss) { while (base < limit) { mycell *obj = base; mps_res_t res; mps_addr_t p; switch (obj->tag) { case MCpadsingle: INCCOUNT(SCANPS_COUNT); base = (mps_addr_t) ((char *) obj + MPS_PF_ALIGN); break; case MCpadmany: INCCOUNT(SCANPM_COUNT); base = (obj->padmulti.next); break; case MCdata: INCCOUNT(SCANOBJ_COUNT); /* actual scanning is done in here */ asserts(obj->data.id != MCerrorid, "scan on error object"); commentif(formatcomments, "scan %li at %p.", obj->data.id, base); for (i=0; i<(obj->data.numrefs); i++) { p = obj->data.ref[i].addr; if (p != NULL) { /* copy ref to p for fixing, to avoid a pun (although the pun would probably work fine almost everywhere) */ commentif(fixcomments, "fix %li[%i] -> %li", obj->data.id, i, obj->data.ref[i].id); res = MPS_FIX(ss, (mps_addr_t *) &p); if (res != MPS_RES_OK) return res; obj->data.ref[i].addr = p; } } base = (mps_addr_t) ((char *) obj + (obj->data.size)); break; case MCheart: INCCOUNT(SCANHEART_COUNT); base = (mps_addr_t) ((char *) obj + (obj->heart.size)); break; default: asserts(0, "scan: bizarre obj tag at %p.", obj); } } } MPS_SCAN_END(ss); return MPS_RES_OK; }
locell *alloclo(mps_ap_t ap, size_t size) { mps_addr_t p; locell *q; size_t bytes; size_t alignment; bytes = offsetof(struct lodata, data) + size; alignment = MPS_PF_ALIGN; /* needed to make it as wide as size_t */ /* twiddle the value of size to make it aligned */ bytes = (bytes+alignment-1) & ~(alignment-1); do { die(mps_reserve(&p, ap, bytes), "Reserve: "); q=p; q->data.tag = LOdata; q->data.id = nextid; q->data.copycount = 0; q->data.size = bytes; } while (!mps_commit(ap, p, bytes)); commentif(alloclocomments, "allocated id %li at %p.", nextid, q); nextid += 1; return q; }
mycell *allocdumb(mps_ap_t ap, size_t size) { mps_addr_t p; mycell *q; size_t bytes; size_t alignment; bytes = offsetof(struct data, ref) + size; alignment = MPS_PF_ALIGN; /* needed to make it as wide as size_t */ /* twiddle the value of size to make it aligned */ bytes = (bytes+alignment-1) & ~(alignment-1); do { die(mps_reserve(&p, ap, bytes), "Reserve: "); INCCOUNT(RESERVE_COUNT); q=p; q->data.tag = MCdata; q->data.id = nextid; q->data.copycount = 0; q->data.numrefs = 0; q->data.checkedflag = 0; q->data.size = bytes; } while (!mps_commit(ap, p, bytes)); INCCOUNT(ALLOC_COUNT); commentif(alloccomments, "allocated id %li at %p.", nextid, q); nextid += 1; return q; }
static void checkloop(mycell *obj, int dir) { mycell *toj; int tid; int i; asserts(obj->tag == MCdata, "checkfrom: non data object in graph at %p.", obj); if (obj->data.checkedflag != dir) { commentif(checkcomments, "checking %p = %li", obj, obj->data.id); checkobjcount += 1; obj->data.checkedflag = dir; for (i=0; i<(obj->data.numrefs); i+=1) { if (obj->data.ref[i].addr != NULL) { toj = (obj->data.ref[i].addr); tid = (obj->data.ref[i].id); asserts(toj->data.id == tid, "checkfrom: corrupt graph at %p, %d.", obj, i); checkloop(toj, dir); } } } }
static void stepper(mps_addr_t addr, mps_fmt_t fmt, mps_pool_t pool, void *V, size_t S) { mycell *a; asserts((mycell *) V == MAGICPOINT, "VII. Void * didn't get passed!"); asserts(S == MAGICSIZE, "VII. Size didn't get passed!"); asserts(fmt == format, "VII. Format didn't get passed!"); a = addr; asserts(((a->tag) & 0x3) == MCdata || ((a->tag) & 0x3) == MCpad, "V. step onto bad object at %p", addr); if (((a->tag) & 0x3) == MCdata) { appcount += 1; asserts(a->data.checkedflag != newstamp, "III/IV. step on object again at %p", a); commentif(a->data.checkedflag != oldstamp, "*. step on unreachable object at %p", a); a->data.checkedflag = newstamp; } else { apppadcount +=1; } }
static void mycopy(mps_addr_t object, mps_addr_t to) { mycell *boj = object; mycell *toj = to; asserts(boj->tag == MCdata, "copy: non-data object"); INCCOUNT(COPY_COUNT); commentif(formatcomments, "copy: %li: %p -> %p\n", boj->data.id, object, to); /* this line would be bad, because the objects might overlap, and then C doesn't guarantee to do the right thing! *toj = *boj; */ memmove(to, object, boj->data.size); if (!freeze) { toj->data.copycount = (toj->data.copycount)+1; if (toj->data.copycount > maxcopy) maxcopy = toj->data.copycount; } }
static void test(void) { mps_arena_t arena; mps_pool_t pool; mps_thr_t thread; mps_root_t root; mps_chain_t chain; mps_fmt_t format; mycell *cells; int h,i,j,k,l; mycell *p[NAPS]; mycell *pobj; size_t bytes; size_t alignment; mps_addr_t q; int nextid = 0x1000000; /* turn on comments about copying and scanning */ formatcomments = BLAH; fixcomments = BLAH; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); cdie(mps_thread_reg(&thread, arena), "register thread"); cdie( mps_root_create_reg(&root, arena, mps_rank_ambig(), 0, thread, mps_stack_scan_ambig, stackpointer, 0), "create root"); cdie( mps_fmt_create_A(&format, arena, &fmtA), "create format"); cdie(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); cdie( mps_pool_create(&pool, arena, mps_class_amc(), format, chain), "create pool"); for (i=0; i<NAPS; i++) { die(mps_ap_create(&ap[i], pool, mps_rank_exact()), "create ap"); ap_state[i] = 0; } cells = allocone(ap[0], NCELLS); /* ap_state can have the following values: 0 before reserve 1 after reverse 2 after init 3 after I=A 0 after commit */ for(h=0; h<100; h++) { comment("%i of 100", h); comment("%i collections", (int) mps_collections(arena)); for(j=0; j<1000; j++) { i = ranint(NAPS); switch (ap_state[i]) { case 0: nrefs[i] = NUMREFS; bytes = offsetof(struct data, ref)+nrefs[i]*sizeof(struct refitem); alignment = MPS_PF_ALIGN; bytes = (bytes+alignment-1)&~(alignment-1); s[i] = bytes; die(mps_reserve(&q, ap[i], s[i]), "reserve: "); p[i] = q; p[i]->data.tag = 0xD033E2A6; p[i]->data.id = nextid; ap_state[i] = 1; commentif(BLAH, "%i: reserve %li at %p", i, nextid, q); nextid +=1; break; case 1: commentif(BLAH, "%i: init %li", i, p[i]->data.id); p[i]->data.tag = MCdata; p[i]->data.numrefs = nrefs[i]; p[i]->data.size = s[i]; ap_state[i] = 2; for (k=0; k<nrefs[i]; k++) { if PNULL { p[i]->data.ref[k].addr = NULL; p[i]->data.ref[k].id = 0; } else { l = ranint(NCELLS); pobj = getref(cells, l); p[i]->data.ref[k].addr = pobj; p[i]->data.ref[k].id = (pobj==NULL ? 0 : pobj->data.id); } commentif(BLAH, " ref %i -> %li", k, p[i]->data.ref[k].id); } break; case 2: commentif(BLAH, "%i: begin commit %li", i, p[i]->data.id); ap[i]->init = ap[i]->alloc; ap_state[i] = 3; break; case 3: case 4: case 5: case 6: case 7: case 8: case 9: ap_state[i]+=1; break; case 10: commentif(BLAH, "%i: end commit %li", i, p[i]->data.id); q=p[i]; if (ap[i]->limit != 0 || mps_ap_trip(ap[i], p[i], s[i])) { l = ranint(NCELLS); setref(cells, l, q); commentif(BLAH, "%i -> %i", i, l); } ap_state[i] = 0; break; } } checkfrom(cells); }
static void test(void *stack_pointer) { mps_arena_t arena; mps_pool_t pool; mps_thr_t thread; mps_root_t root; mps_fmt_t format; mps_chain_t chain; mycell *cells; int h,i,j,k,l; mycell *pobj; mycell *ambig[NAPS]; size_t size0, size1; long mdiff = 0; size_t bytes; size_t alignment; mps_addr_t q; int nextid = 0x1000000; /* turn on comments about copying and scanning */ formatcomments = VERBOSE; fixcomments = VERBOSE; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); die(mps_thread_reg(&thread, arena), "register thread"); cdie(mps_root_create_thread(&root, arena, thread, stack_pointer), "thread root"); die(mps_fmt_create_A(&format, arena, &fmtA), "create format"); cdie(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); die(mmqa_pool_create_chain(&pool, arena, mps_class_amc(), format, chain), "create pool"); for (i = 0; i < NAPS; i++) { die(mps_ap_create(&ap[i], pool, mps_rank_exact()), "create ap"); ap_state[i] = 0; } cells = allocone(ap[0], NCELLS); /* ap_state can have the following values: 0 before reserve 1 after reverse 2 after init 3 after I=A 0 after commit */ for(h=0; h<ITERATIONS; h++) { comment("%i of %i", h, ITERATIONS); for(j=0; j<1000; j++) { if (j == 500) { size0 = mps_arena_committed(arena) - mps_arena_spare_committed(arena); mps_arena_collect(arena); size1 = mps_arena_committed(arena) - mps_arena_spare_committed(arena); asserts(((long) size1)-((long) size0) < 1024*1024, "Collection made arena bigger: %lu -> %lu", (unsigned long) size0, (unsigned long) size1); if (((long) size1)-((long) size0) > mdiff) { mdiff = ((long) size1) - ((long) size0); } } i = ranint(NAPS); switch (ap_state[i]) { case 0: nrefs[i] = NUMREFS; bytes = offsetof(struct data, ref)+nrefs[i]*sizeof(struct refitem); alignment = MPS_PF_ALIGN; bytes = (bytes+alignment-1)&~(alignment-1); s[i] = bytes; die(mps_reserve(&q, ap[i], s[i]), "reserve: "); p[i] = q; p[i]->data.tag = 0xD033E2A6; p[i]->data.id = nextid; ap_state[i] = 1; commentif(VERBOSE, "%i: reserve %li at %p", i, nextid, q); nextid +=1; break; case 1: commentif(VERBOSE, "%i: init %li", i, p[i]->data.id); p[i]->data.tag = MCdata; p[i]->data.numrefs = nrefs[i]; p[i]->data.size = s[i]; ap_state[i] = 2; for (k=0; k<nrefs[i]; k++) { if PNULL { p[i]->data.ref[k].addr = NULL; p[i]->data.ref[k].id = 0; } else { l = ranint(NCELLS); pobj = getref(cells, l); p[i]->data.ref[k].addr = pobj; p[i]->data.ref[k].id = (pobj==NULL ? 0 : pobj->data.id); } commentif(VERBOSE, " ref %i -> %li", k, p[i]->data.ref[k].id); } break; case 2: commentif(VERBOSE, "%i: begin commit %li", i, p[i]->data.id); ambig[i] = p[i]; ap[i]->init = ap[i]->alloc; ap_state[i] = 3; break; case 3: commentif(VERBOSE, "%i: end commit %li", i, p[i]->data.id); q=p[i]; if (ap[i]->limit != 0 || mps_ap_trip(ap[i], p[i], s[i])) { l = ranint(NCELLS); setref(cells, l, q); commentif(VERBOSE, "%i -> %i", i, l); } ap_state[i] = 0; ambig[i] = NULL; break; } } checkfrom(cells); }