!include once #1027304 // Eclipse Collections // Note: Pointers can't point _inside_ of objects sclass ManagedIntObjects_v1_Collector implements IManagedObjectCollector { ManagedIntObjects_v1 mem; CompactTreeSet objects = new(intRangeComparatorByStart()); new IntHashSet pointers; new LongHashSet pointerRanges; // IntRanges as longs new IntIntHashMap relocationMap; int[] newMem; int startAddress; // 1 normally, 0 for PersistentManagedObjects_v1 // if object at key moves, send new address to the callbacks new MultiMap> relocationCallbacks; bool discardFreeListEarly; // saves memory, but ironically makes original memory unusable when compacting fails because of OOM bool verbose = true; *(ManagedIntObjects_v1 *mem) {} // notify collector that there is an object in a location public void noteObject(int start, int size, IVF1 updateAddress default null) { deb()?.printVars("noteObject", +start, +size); objects.add(intRange(start, start+size)); if (updateAddress != null) relocationCallbacks.put(start, updateAddress); } // notify collector that there is a pointer in a location public void notePointer(int addr, IVF1 updateAddress) { if (addr != 0) { pointers.add(addr); int target = mem.get(addr); if (target != 0 && updateAddress != null) relocationCallbacks.put(target, updateAddress); } } public void noteRootPointer(int addr) { deb()?.printVars("noteRootPointer", +addr, pointingTo := mem.get(addr)); pointers.add(addr); } // notify collector that there is a pointer array in a location public void notePointerArray(int start) { if (start == 0) ret; int n = mem.get(start); noteObject(start, n+1); notePointerRange(IntRange(start+1, start+1+n)); } // notify collector that there is an int array in a location public void noteIntArray(int start) { if (start == 0) ret; int n = mem.get(start); noteObject(start, n+1); } void notePointerRange(IntRange r) { pointerRanges.add(intRangeToLong(r)); } int sizeNeeded() { ret mem.reservedSpaceAtBeginning()+totalIntRangesLength_int(objects); } void collectAndCompact() { int sizeNeeded = sizeNeeded(); if (mem.size() == sizeNeeded) ret; if (discardFreeListEarly) mem.freeList.clear(); // reserve new memory print("Reserving " + toM(sizeNeeded*(long) mem.wordSizeInBytes()) + " MB"); newMem = new int[sizeNeeded]; // copy all the objects, fill relocationMap print("Copying " + nObjects(objects) + " (" + n2(l(relocationCallbacks), "callback") + ")"); int freePtr = startAddress; for (IntRange r : objects) { int oldObjectStart = r.start, newObjectStart = freePtr; if (oldObjectStart != newObjectStart) { relocationMap.put(oldObjectStart, newObjectStart); L> callbacks = relocationCallbacks.get(oldObjectStart); deb()?.printVars("Moving object", +r, +oldObjectStart, +newObjectStart, +callbacks); callFAll(callbacks, newObjectStart); } else { //printVars("Keeping object", +r); } arraycopy(mem.mem, oldObjectStart, newMem, newObjectStart, r.length()); freePtr += r.length(); } relocationCallbacks.clear(); // update the pointers print("Updating " + n2(pointers.size(), "pointer")); IntIterator itPointers = pointers.intIterator(); while (itPointers.hasNext()) movePointer(itPointers.next()); print("Updating " + n2(pointerRanges.size(), "pointer range")); var itPointerRanges = pointerRanges.longIterator(); while (itPointerRanges.hasNext()) { IntRange r = longToIntRange(itPointerRanges.next()); for (int i = r.start; i < r.end; i++) movePointer(i); } print("Managed GC done"); mem.mem = newMem; if (!discardFreeListEarly) mem.freeList.clear(); } // call after collectAndCompact to get new location of objects public int getNewLocation(int addr) { ret relocationMap.getIfAbsent(addr, addr); } void movePointer(int pointerAddr) { // find enclosing object IntRange obj = objects.floor(IntRange(pointerAddr, pointerAddr)); if (obj == null) ret with print("Pointer without object: " + pointerAddr); int newObjAddr = relocationMap.getIfAbsent(obj.start, obj.start); int newPointerAddr = newObjAddr-obj.start+pointerAddr; // find target, update pointer int target = mem.get(pointerAddr); deb()?.printVars("movePointer", +pointerAddr, +obj, +newObjAddr, +newPointerAddr, +target); if (target == 0) ret; int newTarget = relocationMap.getIfAbsent(target, -1); deb()?.printVars("movePointer", +newTarget); if (newTarget >= 0) newMem[newPointerAddr] = newTarget; } public void noteString(int addr, IVF1 updateAddress default null) { if (addr == 0) ret; int n = ((mem.get(addr)^0x80000000)+3)/4; noteObject(addr, n+1, updateAddress); } }