# API Migration Guide
This document lists changes to the MMTk-VM API that require changes to be made by the VM bindings.
VM binding developers can use this document as a guide to update their code to maintain
compatibility with the latest release of MMTk.
## View control
Choose how many details you want to read.
{{#include ../../assets/snippets/view-controls.html}}
<div id="api-migration-detail-body">
## 0.33.0
### `GCTriggerPolicy::on_gc_start/on_gc_end` repurposed for GC cycles
```admonish tldr
The old `on_gc_start` and `on_gc_end` (called once per STW pause) are renamed to `on_pause_start`
and `on_pause_end`. `on_pause_start` is now also called after all mutators have stopped, instead of
at the very start of GC scheduling before mutators are asked to stop. The names `on_gc_start` and
`on_gc_end` are reused for a new pair of hooks with different semantics: they are called once per
*GC cycle* rather than once per pause. For stop-the-world GCs, no changes are needed for the delegated
GC trigger; however, for concurrent GCs, the GC trigger needs to differentiate pauses and GC cycles,
and use the correct hooks correspondingly.
```
API changes:
- trait `util::heap::GCTriggerPolicy`
+ `on_gc_start`: Renamed to `on_pause_start`.
* Previously called once for every STW pause, when GC was scheduled and before mutators
were told to stop.
* Now called after all mutators have stopped (i.e. once the world is actually stopped for
the pause). Implementations that only use this hook to record a timestamp or the
reserved-page count for computing GC time/space overhead should still work correctly,
but the recorded time will now reflect the start of the actual pause rather than the
start of GC scheduling (which also includes time spent waiting for mutators to reach a
safepoint).
+ `on_gc_end`: Renamed to `on_pause_end`.
* No change to timing, only the name.
+ `on_gc_start`/`on_gc_end`: New methods that reuse the old names, but with different meaning.
* A GC cycle consists of one or more STW pauses plus any concurrent work in between them.
These new hooks are called once per GC cycle, rather than once per pause.
* For a stop-the-world plan, a GC cycle is exactly one pause, so `on_gc_start`/`on_gc_end`
fire at the same time as `on_pause_start`/`on_pause_end`.
* For a concurrent plan whose cycle spans multiple pauses (e.g. an initial mark pause and
a final mark pause with concurrent marking in between), `on_gc_start` is only called for
the first pause of the cycle, and `on_gc_end` only for the last.
This only affects VM bindings that provide a custom `GCTriggerPolicy` (via
`Collection::create_gc_trigger`).
### Collection enabling/disabling is now managed by MMTk instead of the VM binding
```admonish tldr
`Collection::is_collection_enabled()` is removed. MMTk now tracks whether collection is enabled
itself, via the new, nestable `disable_collection()`/`enable_collection()` API on `MMTK` (and
`memory_manager`).
```
API changes:
- trait `vm::Collection`
+ `is_collection_enabled()`: Removed.
* Previously, the VM binding implemented this method to tell MMTk whether GC is
currently allowed. MMTk now manages this state itself, so the binding no longer needs
to (and no longer can) answer this question.
* If the binding previously disabled collection at certain times (e.g. before some
initialization completed), it should instead call the new `memory_manager::disable_collection()`
at the point where it used to start returning `false`, and `memory_manager::enable_collection()`
at the point where it used to start returning `true` again.
- module `memory_manager`
+ `disable_collection()`: now returns `Result<bool, GcStatus>`. `Ok(true)`
means this call actually switched collection from enabled to disabled; `Ok(false)` means
it only increased the nesting depth of an already-disabled status. `Err(status)` means
collection could not be disabled right now, with `status` naming why (e.g. a GC is in
progress or has been requested); the VM binding should check safepoints, expect a pause,
or wait for the concurrent GC to finish, then call this function again.
* `enable_collection()`: return true if the GC is enabled after the call. Otherwise, the function
returns false.
+ `is_collection_enabled()`: New. Returns whether collection is currently enabled.
See also:
- PR: <https://github.com/mmtk/mmtk-core/pull/1457>
### `Slot` is required to implement `Sync`
```admonish tldr
`vm::slot::Slot` now needs to implement `Sync`.
```
API changes:
- module `vm::slot`
+ `Slot`: Now required to implement `Sync`
* The provided `SimpleSlot` in mmtk-core already implements `Sync`. If the VM binding
uses it, no change is needed.
* If the VM binding's `Slot` implementation does not include raw pointers (`*const T` and
`*mut T`), chance is high that it automatically implements `Sync`. If this is the case,
no change is needed.
* Otherwise, the VM binding should declare `unsafe impl Sync for ...` for the slot type.
### Thread IDs require `Debug` instead of `Display`
```admonish tldr
`mmtk::util::os::OS::ThreadIDType` now needs to implement `Debug` instead of `Display`.
```
API changes:
- module `util::os`
+ `OS::ThreadIDType`: This associated type now requires `Debug` instead of `Display`.
* This allows platforms where the native thread ID type does not implement `Display`,
such as `libc::pthread_t` on musl.
* Bindings that provide an OS implementation should derive or implement `Debug` for
their thread ID type.
### The `<'w>` lifetime in `ObjectTracerContext`
```admonish tldr
Your existing source code probably still works.
```
API changes:
- module `vm::scanning`
+ `ObjectTracerContext::TracerType`: Now has a `<'w>` lifetime parameter
+ `ObjectTracerContext::with_tracer`: Now has a `<'w>` lifetime parameter
* `'w` is the lifetime of the `worker` argument, and is passed to the
`Self::TracerType<'w>` argument of the `func` callback. It basically means the
`ObjectTracer` provided to the `func` callback borrows the `worker` during the callback.
This has always been true, but we now made it explicit through the lifetime parameter.
### Type argument changes in `Finalizable::keep_alive` module
```admonish tldr
`Finalizable::keep_alive` now has the `<OT: ObjectTracer>` type parameter.
```
API changes:
- module `vm::reference_glue`
+ `Finalizable::keep_alive`: Now has the `<OT: ObjectTracer>` type parameter instead of
`<E: ProcessEdgesWork>`. The `trace` parameter is now `&mut OT`. It still has the
`trace_object` method like the old `ProcessEdgesWork` trait, and is supposed to be used the
same way.
### The Cargo feature "is_mmtk_object" is removed
```admonish tldr
The "is_mmtk_object" cargo feature is removed. Anything previously enabled by the "is_mmtk_object"
feature are now enabled by the "vo_bit" feature.
```
API changes: None. If a VM binding uses the "is_mmtk_object" feature, it should now use the
"vo_bit" feature if not already using, and existing code should still compile.
### Side metadata base addresses are no longer constants
```admonish tldr
Side metadata addresses are now chosen at runtime. The old address constants are removed and
replaced with accessor functions that must only be called after MMTk is initialized.
```
API changes:
- module `util::metadata::side_metadata`
+ `GLOBAL_SIDE_METADATA_BASE_ADDRESS`: Removed.
* Use `global_side_metadata_base_address()` instead.
+ `GLOBAL_SIDE_METADATA_VM_BASE_ADDRESS`: Removed.
* Use `global_side_metadata_vm_base_address()` instead.
+ `VO_BIT_SIDE_METADATA_ADDR`: Removed.
* Use `vo_bit_side_metadata_addr()` instead.
- module `util::metadata::vo_bit`
+ `VO_BIT_SIDE_METADATA_ADDR`: Removed.
* Use `vo_bit_side_metadata_addr()` instead.
These addresses are no longer constants because MMTk now chooses the side metadata base address at
boot time. Bindings should fetch them from the accessor functions after MMTk initialization has
completed. Bindings can assume the addresses will not change once they are initialized.
## 0.32.0
### Allocation options changed
```admonish tldr
`AllocationOptions` now has multiple boolean fields instead of one `OnAllocationFail` field. Now
polling cannot be disabled. Instead we can now poll and over-commit in one allocation.
```
API changes:
- module `util::alloc::allocator`
+ `OnAllocationFail`: Removed.
+ `AllocationOptions`: It now has two boolean fields:
* `allow_overcommit`
* `at_safepoint`
* `allow_oom_call`
Variants of the old `enum OnAllocationFail` should be migrated to the new API according to the
following table:
| `RequestGC` | `false` | `true` | `true` |
| `ReturnFailure` | `false` | `false` | `false` |
| `OverCommit` | `true` | `false` | `false` |
Note that MMTk now always polls before trying to get more pages from the page resource, and it may
trigger GC. The old `OnAllocationFail::OverCommit` used to prevent polling, but it is no longer
possible.
See also:
- PR: <https://github.com/mmtk/mmtk-core/pull/1400>
### Removed the notion of "mmap chunk"
```admonish tldr
Constants such as `MMAP_CHUNK_BYTES` were related to the implementation details of the memory
mapper, and should not have been exposed.
```
API changes:
- module `util::conversions`
+ `mmap_chunk_align_down`: Removed.
+ `mmap_chunk_align_up`: Removed.
- module `util::heap::vm_layout`
+ `LOG_MMAP_CHUNK_BYTES`: Removed.
+ `MMAP_CHUNK_BYTES`: Removed.
### `Options` no longer differentiates between environment variables and command line arguments.
```admonish tldr
We replaced both `Options::set_from_command_line` and `Options::set_from_env_var` with
`Options::set_from_string` because all options can now be set via either environment variable or
command line arguments.
```
API changes:
- module `util::options`
+ `Options::set_from_command_line`: Removed.
* Use `Options::set_from_string` instead.
+ `Options::set_from_env_var`: Removed.
* Use `Options::set_from_string` instead.
+ `Options::set_bulk_from_command_line`: Removed.
* Use `Options::set_bulk_from_string` instead.
+ All `<T>` in `MMTKOption<T>` now must implement `FromStr`.
* This means you can parse a string into `T` when setting an `MMTKOption<T>`. For
example, `options.plan.set(user_input.parse()?);`.
### The feature `immix_stress_copying` is removed.
```admonish tldr
The feature `immix_stress_copying` is removed. Bindings can use MMTk options with the following values
to achieve the same behavior as before: `immix_always_defrag=true,immix_defrag_every_block=true,immix_defrag_headroom_percent=50`
```
API changes:
- The feature `immix_stress_copying` is removed.
- module `util::options`
+ `Options` includes `immix_always_defrag`, which defaults to `false`.
+ `Options` includes `immix_defrag_every_block`, which defaults to `false`.
+ `Options` includes `immix_defrag_headroom_percent`, which defaults to `2`.
See also:
- PR: <https://github.com/mmtk/mmtk-core/pull/1324>
## 0.30.0
### `live_bytes_in_last_gc` becomes a runtime option, and returns a map for live bytes in each space
```admonish tldr
`count_live_bytes_in_gc` is now a runtime option instead of a features (build-time), and we collect
live bytes statistics per space. Correspondingly, `memory_manager::live_bytes_in_last_gc` now returns a map for
live bytes in each space.
```
API changes:
- module `util::options`
+ `Options` includes `count_live_bytes_in_gc`, which defaults to `false`. This can be turned on at run-time.
+ The old `count_live_bytes_in_gc` feature is removed.
- module `memory_manager`
+ `live_bytes_in_last_gc` now returns a `HashMap<&'static str, LiveBytesStats>`. The keys are
strings for space names, and the values are statistics for live bytes in the space.
See also:
- PR: <https://github.com/mmtk/mmtk-core/pull/1238>
### mmap-related functions require annotation
```admonish tldr
Memory-mapping functions in `mmtk::util::memory` now take an additional `MmapAnnotation` argument.
```
API changes:
- module `util::memory`
+ The following functions take an additional `MmapAnnotation` argument.
* `dzmmap`
* `dzmmap_noreplace`
* `mmap_noreserve`
## 0.28.0
### `handle_user_collection_request` returns `bool`
```admonish tldr
`memory_manager::handle_user_collection_request` now returns a boolean value to indicate whether a GC
is triggered by the method or not. Bindings may use the return value to do some post-gc cleanup, or
simply ignore the return value.
```
API changes:
- module `memory_manager`
+ `handle_user_collection_request` now returns `bool` to indicate if a GC is triggered by the method.
Bindings may use the value, or simply ignore it.
See also:
- PR: <https://github.com/mmtk/mmtk-core/issues/1205>
- Examples:
+ https://github.com/mmtk/mmtk-julia/pull/177: Ignore return value.
### `ObjectReference` must point inside an object
```admonish tldr
`ObjectReference` is now required to be an address within an object. The concept of "in-object
address" and related methods are removed. Some methods which used to depend on the "in-object
address" no longer need the `<VM>` type argument.
```
API changes:
- struct `ObjectReference`
+ Its "raw address" must be within an object now.
+ The following methods which were used to access the in-object address are removed.
* `from_address`
* `to_address`
* When accessing side metadata, the "raw address" should be used, instead.
+ The following methods no longer have the `<VM>` type argument.
* `get_forwarded_object`
* `is_in_any_space`
* `is_live`
* `is_movable`
* `is_reachable`
- module `memory_manager`
+ `is_mmtk_object`: It now requires the address parameter to be non-zero and word-aligned.
* Otherwise it will not be a legal `ObjectReference` in the first place. The user should
filter out such illegal values.
+ The following functions no longer have the `<VM>` type argument.
* `find_object_from_internal_pointer`
* `is_in_mmtk_space`
* `is_live_object`
* `is_pinned`
* `pin_object`
* `unpin_object`
- struct `Region`
+ The following methods no longer have the `<VM>` type argument.
* `containing`
- trait `ObjectModel`
+ `IN_OBJECT_ADDRESS_OFFSET`: removed because it is no longer needed.
See also:
- PR: <https://github.com/mmtk/mmtk-core/issues/1170>
- Examples:
+ https://github.com/mmtk/mmtk-openjdk/pull/286: a simple case
+ https://github.com/mmtk/mmtk-jikesrvm/issues/178: a VM that needs much change for this
## 0.27.0
### `is_mmtk_object` returns `Option<ObjectReference>`
```admonish tldr
`memory_manager::is_mmtk_object` now returns `Option<ObjectReference>` instead of `bool`.
Bindings can use the returned object reference instead of computing the object reference at the binding side.
```
API changes:
* module `memory_manager`
- `is_mmtk_object` now returns `Option<ObjectReference>`.
See also:
- PR: <https://github.com/mmtk/mmtk-core/pull/1165>
- Example: <https://github.com/mmtk/mmtk-ruby/pull/86>
### Introduce `ObjectModel::IN_OBJECT_ADDRESS_OFFSET`
```admonish tldr
We used to have `ObjectModel::ref_to_address` and `ObjectModel::address_to_ref`, and require
the object reference and the in-object address to have a constant offset. Now, the two methods
are removed, and replaced with a constant `ObjectModel::IN_OBJECT_ADDRESS_OFFSET`.
```
API changes:
* trait `ObjectModel`
- The methods `ref_to_address` and `address_to_ref` are removed.
- Users are required to specify `IN_OBJECT_ADDRESS_OFFSET` instead, which is the offset from the object
reference to the in-object address (the in-object address was the return value for the old `ref_to_address()`).
* type `ObjectReference`
- Add a constant `ALIGNMENT` which equals to the word size. All object references should be at least aligned
to the word size. This is checked in debug builds when an `ObjectReference` is constructed.
See also:
- PR: <https://github.com/mmtk/mmtk-core/pull/1159>
- Example: <https://github.com/mmtk/mmtk-openjdk/pull/283>
## 0.26.0
### Rename "edge" to "slot"
```admonish tldr
The word "edge" **in many identifiers** have been changed to "slot" if it actaully means slot.
Notable items include the traits `Edge`, `EdgeVisitor`, the module `edge_shape`, and member types
and functions in the `Scanning` and `VMBinding` traits. The VM bindings should not only make
changes in response to the changes in MMTk-core, but also make changes to their own identifiers if
they also use "edge" where it should have been "slot". The find/replace tools in text editors and
the refactoring/renaming tools in IDEs should be helpful.
```
API changes:
* module `edge_shape` -> `slot`
* type `RootsWorkFactory`
- `<ES: Edge>` -> `<SL: Slot>`
- `create_process_edge_roots_work` -> `create_process_roots_work`
* type `SimpleEdge` -> `SimpleSlot`
* type `UnimplementedMemorySliceEdgeIterator` -> `UnimplementedMemorySliceSlotIterator`
* trait `Edge` -> `Slot`
* trait `EdgeVisitor` -> `SlotVisitor`
- `<ES: Edge>` -> `<SL: Slot>`
- `visit_edge` -> `visit_slot`
* trait `MemorySlice`
- `Edge` -> `SlotType`
- `EdgeIterator` -> `SlotIterator`
- `iter_edges` -> `iter_slots`
* trait `Scanning`
- `support_edge_enqueuing` -> `support_slot_enqueuing`
- `scan_object`
+ `<EV: EdgeVisitor>` -> `<SV: SlotVisitor>`
- `scan_roots_in_mutator_thread`
+ Type parameter of `factory` changed. See type `RootsWorkFactory`.
- `scan_vm_specific_roots`
+ Same as above.
* trait `VMBinding`
- `VMEdge` -> `VMSlot`
See also:
- PR: <https://github.com/mmtk/mmtk-core/pull/1134>
- Example: <https://github.com/mmtk/mmtk-openjdk/pull/274>
## 0.25.0
### `ObjectReference` is no longer nullable
```admonish tldr
`ObjectReference` can no longer represent a NULL reference. Some methods of `ObjectReference` and
the write barrier functions in `memory_manager` are changed. VM bindings need to re-implement
methods of the `Edge`, `ObjectModel` and `ReferenceGlue` traits.
```
API changes:
* type `ObjectReference`
- It can no longer represent NULL reference.
+ It is now backed by `NonZeroUsize`, and MMTk uses `Option<ObjectReference>` universally
when an `ObjectReference` may or may not exist. It is more idiomatic in Rust.
- The constant `ObjectReference::NULL` is removed.
- `is_null()` is removed.
- `from_raw_address(addr)`
+ The return type is changed to `Option<ObjectReference>`.
+ It returns `None` if `addr` is not zero.
+ If you know `addr` cannot be zero, you can use the new method
`from_raw_address_unchecked(addr)`, instead.
* module `mmtk::memory_manager`
- **Only affects users of write barriers**
- `object_reference_write_pre(mutator, obj, slot, target)`
+ The `target` parameter is now `Option<ObjectReference>`.
+ Pass `None` if the slot was holding a NULL reference or any non-reference value.
- `object_reference_write_post(mutator, obj, slot, target)`
+ Same as above.
- `object_reference_write(mutator, obj, slot, target)`
+ It is labelled as `#[deprecated]` and needs to be redesigned. It cannot handle the case
of storing a non-reference value (such as tagged small integer) into the slot.
+ Before a replacement is available, use `object_reference_write_pre` and
`object_reference_write_post`, instead.
* trait `Edge`
- `load()`
+ The return type is changed to `Option<ObjectReference>`.
+ It returns `None` if the slot is holding a NULL reference or other non-reference
values. MMTk will skip those slots.
* trait `ObjectModel`
- `copy(from, semantics, copy_context)`
+ Previously VM bindings convert the result of `copy_context.alloc_copy()` to
`ObjectReference` using `ObjectReference::from_raw_address()`.
+ Because `CopyContext::alloc_copy()` never returns zero, you can use
`ObjectReference::from_raw_address_unchecked()` to skip the zero check.
- `get_reference_when_copied_to(from, to)`
+ `to` is never zero because MMTk only calls this after the destination is determined.
+ You may skip the zero check, too.
- `address_to_ref(addr)`
+ `addr` is never zero because this method is an inverse operation of
`ref_to_address(objref)` where `objref` is never NULL.
+ You may skip the zero check, too.
* trait `ReferenceGlue`
- *Note: If your VM binding is still using `ReferenceGlue` and the reference processor and
finalization processor in mmtk-core, it is strongly recommended to switch to the
`Scanning::process_weak_refs` method and implement weak reference and finalization
processing on the VM side.*
- `get_referent()`
+ The return type is changed to `Option<ObjectReference>`.
+ It now returns `None` if the referent is cleared.
- `clear_referent()`
+ It now needs to be explicitly implemented because `ObjectReference::NULL` no longer
exists.
+ Note: The `Edge` trait does not have a method for storing NULL to a slot. The VM
binding needs to implement its own method to store NULL to a slot.
Not API change, but worth noting:
* Functions that return `Option<ObjectReference>`
- `memory_manager::get_finalized_object`
- `ObjectReference::get_forwarded_object`
+ The functions listed above did not change, as they still return
`Option<ObjectReference>`. But some VM bindings used to expose them to native programs
by wrapping them into `extern "C"` functions that return `ObjectReference`, and return
`ObjectReference::NULL` for `None`. This is no longer possible since we removed
`ObjectReference::NULL`. The VM bindings should use
`mmtk::util::api_util::NullableObjectReference` for the return type instead.
See also:
- PR: <https://github.com/mmtk/mmtk-core/pull/1064>
- PR: <https://github.com/mmtk/mmtk-core/pull/1130> (for write barriers)
- Example: <https://github.com/mmtk/mmtk-openjdk/pull/265>
- Example: <https://github.com/mmtk/mmtk-openjdk/pull/273> (for write barriers)
### Instance methods of `ObjectReference` changed
```admonish tldr
Some methods of `ObjectReference` now have a type parameter `<VM>`. `ObjectReference::value()` is
removed.
```
API changes:
* type `ObjectReference`
- The following methods now require a generic argument `<VM: VMBinding>`:
- `ObjectReference::is_reachable`
- `ObjectReference::is_live`
- `ObjectReference::is_movable`
- `ObjectReference::get_forwarded_object`
- `ObjectReference::is_in_any_space`
- `ObjectReference::is_sane`
- `ObjectReference::value()` is removed.
+ Use `ObjectReference::to_raw_address()` instead.
See also:
- PR: <https://github.com/mmtk/mmtk-core/pull/1122>
- Example: <https://github.com/mmtk/mmtk-openjdk/pull/272>
### The GC controller (a.k.a. coordinator) is removed
```admonish tldr
The GC controller thread is removed from MMTk core. The VM binding needs to re-implement
`Collection::spawn_gc_thread` and call `GCWorker::run` differently.
```
API changes:
* type `GCWorker`
- `GCWorker::run`
+ It now takes ownership of the `Box<GCWorker>` instance instead of borrowing it.
+ The VM binding can simply call the method `worker.run()` on the worker instance from
`GCThreadContext::Worker(worker)`.
* module `mmtk::memory_manager`
- `start_worker`
+ It is now a simple wrapper of `GCWorker::run` for legacy code. It takes ownership of
the `Box<GCWorker>` instance, too.
* trait `Collection`
- `Collection::spawn_gc_thread`
+ It no longer asks the binding to spawn the controller thread.
+ The VM binding can simply remove the code path related to creating the controller
thread.
+ Note the API change when calling `GCWorker::run` or `start_worker`.
See also:
- PR: <https://github.com/mmtk/mmtk-core/pull/1067>
- Example: <https://github.com/mmtk/mmtk-openjdk/pull/268>
</div>
<script type="text/javascript">
const isApiMigrationGuide = true;
</script>