21. Transforms

In a long-running interactive system, it may be desirable to change the format of live objects. In some programming languages (notably Smalltalk), when the programmer edits a class definition, objects belonging to the class must be updated so that they are valid instances of the redefined class. This may involve adding or removing fields from each instance and so changing the size of the allocated objects.

If the object has grown as a result of the redefinition, this redefinition can’t be done in-place, so what actually happens is that for each instance of the old version of the class, a corresponding instance of the new version of the class is created, and all references to the old instance are rewritten to refer to the new instance. Discovering “all references” to an object is a task that falls to the garbage collector.

Transforms are a general mechanism by which the client program

requests the MPS to replace references to one set of objects (the old objects) with references to another (the new objects). The MPS performs this task by carrying out a complete garbage collection, in the course of which all references to old objects are discovered and substituted with references to the corresponding new object.

21.1. Cautions

  1. The arena must be parked (for example, by calling mps_arena_park()) before creating the transform and not unclamped before applying the transform.

  2. A transform cannot be applied if there is an ambiguous reference to any of the old objects. (Because the MPS cannot know whether or not the reference should be updated to point to the new object.)

Warning

The second caution means that transforms may be unsuitable for client programs that treat the registers and control stack as a root, by using mps_root_create_thread() and similar functions, unless the program can guarantee that none of the old references will be referenced by this root.

An alternative and more robust approach is to segregate the formatted objects that need to be updated into a suitable pool, and iterate over them using the function mps_pool_walk().

21.2. Interface

#include "mps.h"
type mps_transform_t

The type of transforms. A transform represents a mapping from old references to new references.

mps_res_t mps_transform_create(mps_transform_t *transform_o, mps_arena_t arena)

Create an empty transform.

transform_o points to a location that will hold the address of the new transform.

arena is the arena in which to create the transform.

mps_transform_create() returns MPS_RES_OK if successful. The MPS may exhaust some resource in the course of mps_transform_create() and will return an appropriate result code if so.

Note

The arena must be parked (for example, by calling mps_arena_park()) before creating a transform, and if mps_transform_apply() is called on a transform, it must be called before the arena is unclamped.

mps_res_t mps_transform_add_oldnew(mps_transform_t transform, mps_addr_t *old_array, mps_addr_t *new_array, size_t count)

Add mappings from an old reference to a new reference to a transform.

transform is the transform to which the mappings will be added.

old_array points to an array of old references, all of which must be to objects in pools whose blocks are automatically managed (see Pool class properties).

new_array points to an array of corresponding new references.

count is the number of references in both arrays.

mps_transform_add_oldnew() returns MPS_RES_OK if successful. The MPS may exhaust some resource in the course of mps_transform_add_oldnew() and will return an appropriate result code if so.

Note

Each old reference must be added at most once to a given transform.

mps_res_t mps_transform_apply(mps_bool_t *applied_o, mps_transform_t transform)

Attempt to apply a transform.

applied_o points to a location that will hold a Boolean indicating whether or not the transform was applied.

transform is the transform to apply.

If the arena is currently incapable of applying the transform, then an appropriate result code is returned, and the location pointed to by applied_o is not updated. Possible causes are:

  • the arena not being in the parked state (in which case the result code is MPS_RES_LIMIT)

  • a collection having taken place since transform was created (in which case the result code is MPS_RES_PARAM).

If the arena is capable of applying the transform, then the MPS carries out a garbage collection, the arena is left in the parked state, mps_transform_apply() returns MPS_RES_OK, and the location pointed to by applied_o is updated.

If in the course of the application, an ambiguous reference was discovered, then the transform is aborted and *applied_o is set to false. In this case, no references to the old objects are updated. (That is, either all of the transform is applied, or none of it.)

The transform can only be applied once, and should be destroyed after use, using mps_transform_destroy().

void mps_transform_destroy(mps_transform_t transform)

Destroy a transform, allowing its resources to be recycled.

transform is the transform to destroy.