Joeq includes a general framework for memory management. It supports both managed (explicitly allocated and deallocated) and unmanaged (garbage collected) memory. The interface is based on the Java Memory Toolkit (JMTk) for the Jikes RVM. It supports a wide variety of garbage collection techniques such as compacting versus non-compacting, exact versus conservative, generations, concurrency, and reference counting. The specifications of the memory manager are accessible through the GCInterface interface, which includes query methods on whether garbage collection requires safe points and the nature of those safe points, whether objects can move or not, whether the collector supports conservative information, what types of read/write barriers are necessary, and interfaces to the allocator for various types of object allocations.
Specific allocation strategies are handled through the Heap interface. Conceptually, a Heap represents a bundle of memory. Different allocation strategies are implemented as subclasses of the abstract Heap interface. For example, a FreeListHeap allocates memory using a free list allocator, a MallocHeap allocates memory through a system call to malloc(), and a FixedSizeBinHeap allocates memory using fixed size bins. Multiple heaps can be in use at the same time to handle allocations of different types. Entire heaps can be thrown away at once when they are explicitly deallocated or the collector determines that there are no more live references into a heap.
Raw addresses in Joeq are represented by special types: HeapAddress, CodeAddress, and StackAddress refer to addresses that refer to locations on the heap, in the code, or on the stack, respectively. Operations on addresses are implemented as method calls on these types; for example, the peek() method dereferences the given address and returns its contents. Abstracting these types in the Java implementation provides a unified interface to memory, which makes it possible to reuse much of the code for both native execution and hosted execution. In native execution, operations on addresses are directly compiled down to their machine level equivalents. In hosted execution, the different address types are implemented as subclasses to the given address types, and proxy objects are created for addresses in the system. Operations on these proxy objects are reflected back into the system. During bootstrapping, the types on the proxy objects allow the bootstrapper to know the correct relocation to emit for various addresses. Using well-typed addresses also enforces a limited notion of type safety, even when dealing with raw addresses. In addition, it makes the implementation of Joeq independent of the address width, so Joeq could very easily be ported to a 64 bit architecture.
The object layout is also parameterized by an ObjectLayout interface. This interface includes methods to initialize objects and extract various types of metadata, such as object class or lock status. Experimenting with various object layout schemes is as easy as subclassing ObjectLayout and implementing a few essential methods.