sclass PersistentManagedObjects_v1 { replace Addr with int. replace BoxedAddr with Int. ManagedIntObjects_v1 mem; IF2 makeUserObject; // user needs to fill this Root root; final static int TYPE_STRING = -1, TYPE_INTARRAY = -2, TYPE_ROOT = -3; class Root extends AbstractManagedObject { final static int ofs_type = 0, ofs_version = 1, ofs_freeListPtr = 2, ofs_userDataPtr = 3; final static int objectSize = ofs_userDataPtr+1; ManagedIntObjects_v1 mem() { ret PersistentManagedObjects_v1.this.mem; } // initialize as wrapper for existing object // or create new when addr == 0 *(Addr addr) { super(PersistentManagedObjects_v1.this.mem); if (addr != 0) setAddr(addr); else create(); } // initialize as new object *() { super(PersistentManagedObjects_v1.this.mem); create(); } void create { setAddr(mem.alloc(objectSize)); init(); } void init { type(TYPE_ROOT); version(1); } // getters + setters int type() { ret mem.get(addr+ofs_type); } void type(int x) { mem.set(addr+ofs_type, x); } int version() { ret mem.get(addr+ofs_version); } void version(int x) { mem.set(addr+ofs_version, x); } Addr freeListPtr() { ret mem.get(addr+ofs_freeListPtr); } void freeListPtr(Addr x) { mem.set(addr+ofs_freeListPtr, x); print("Free list moved to " + x + " (length=" + (x == 0 ? 0 : mem.get(x)) + ")"); } Addr userDataPtr() { ret mem.get(addr+ofs_userDataPtr); } void userDataPtr(Addr x) { mem.set(addr+ofs_userDataPtr, x); } A userData() { ret makeUserObject.get(mem, userDataPtr()); } void userData(A userData) { userDataPtr(userData == null ? 0 : userData.addr()); } public void setAddr(Addr newAddr) { addr = newAddr; mem.setRootField(addr); } // GC handling public void scanForCollection(IManagedObjectCollector gc) { deb()?.printVars("scanForCollection", +this, +addr, +objectSize); gc.noteObject(0, 1, null); gc.noteRootPointer(0); gc.noteObject(addr, objectSize, lambda1 setAddr); //print("note freeList"); //gc.notePointer(addr+ofs_freeListPtr); //gc.noteIntArray(freeListPtr()); // we're dropping it anyway (it's a compaction) print("note userDataPtr"); gc.notePointer(addr+ofs_userDataPtr); var userData = userData(); deb()?.printVars("note", +userData); userData?.scanForCollection(gc); } } // makes a new int[] based storage *(IF2 makeUserObject) { this(new ManagedIntObjects_v1, makeUserObject); } *(ManagedIntObjects_v1 *mem, IF2 *makeUserObject) { Addr rootPtr = mem.getRootField(); print(+rootPtr); root = new Root(rootPtr); mem.freeList = FreeList.fromIntArray(mem.readIntArray(root.freeListPtr())); } void flush { if (mem.freeList.changed) saveFreeList(); } void saveFreeList { print("Freeing old free list at " + root.freeListPtr()); mem.freeIntArray(root.freeListPtr()); int arraySize = (mem.freeList.size()+1)*2; // reserve space for one more entry made in the upcoming freeIntArray() call int sizeNeeded = 1+arraySize; deb()?.printVars(+arraySize, +sizeNeeded); Addr ptr = mem.alloc(sizeNeeded); deb()?.printVars(+ptr); mem.set(ptr, arraySize); // set length // now all the allocs and frees are done and we can persist // the FreeList int[] data = mem.freeList.toIntArray(); mem.freeList.changed = false; for i to arraySize: mem.set(ptr+1+i, i < data.length ? data[i] : 0); // pad with zeros root.freeListPtr(ptr); print("Made new free list at " + root.freeListPtr() + " (l=" + mem.read(root.freeListPtr()) + ")"); } A get aka getUserData() { ret root.userData(); } void set aka setUserData(A userData) { root.userData(userData); } PersistentManagedObjects_v1 rotate() { flush(); ret new PersistentManagedObjects_v1(mem.rotate(), makeUserObject); } void collectAndCompact { ManagedIntObjects_v1_Collector collector = new(mem); collector.startAddress = 0; mem.collectAndCompact(root, collector); print("Resetting freeListPtr"); root.freeListPtr(0); } }