Memory manipulation

This document explains the primitives and syntax constructs for
manipulating memory in Isis, including mechanisms for allocating and
deallocating memory, and retrieving and modifying elements or arrays
of data in memory. There are also optimized utilities for copying,
comparing, searching, and filling memory regions.

Memory types

Several pre-defined constants, each corresponding to a particular type
supported by your machine, are used in calls the memory manipulation
operators described later:

The constants on the left above each correspond to a standard C type,
the sizes of which may vary from machine to machine. The constants on
the right refer to types that will be the same size on any machine,
but not all of them may be available on every machine. Constants
named with a 'u' refer to unsigned types.

Sizes of memory types

A single element of each memory type defined above has a particular
size in bytes. The types prefixed with c- above may vary in
size from machine to machine, so knowing their sizes will be important
when allocating or traversing memory that contains data elements that
are larger than one byte.

The way to find out the size of a memory type is to look it up in the
predefined list sizeof using the constants defined above as
indices, like this:

Allocating and deallocating memory

(allocate-memory numbytes) # allocate memory, return Null if not available
(free-memory address ...) # free memory, always returns Null
(malloc numbytes) # same as allocate-memory
(free numbytes) # same as free-memory
allocate-memory allocates the specified number of bytes and returns the address of
that memory. free-memory deallocates previously allocated memory at the specifed
addresses (you may pass as many as you wish). Isis will NOT automatically free memory when an
address is no longer used. Therefore, when you no longer need a piece of memory that you
allocated with allocate-memory, you MUST call free-memory on it.

Memory retrieval

Memory storage

In each of the above constructs, address should evaluate to a memory address where the
operation is to occur, and memtype should evaluate to one of the memory type constants
defined above, specifying what format of data you wish to retrieve or store there. len
should evaluate to an integer, specifying the length of an array to read or write in memory.
If an integer offset is given, it is added to the address in order to determine where
the memory operation will occur.

The first memory retrieval construct reads a single element of memory of the given type from
the given address and returns it, converted to the most appropriate Isis type. The second
retrieves an array of data from memory, returned as a list of values, unless len is
zero, in which case a single (non-list) value is returned (as in the first form). The last
form works the same way, but adds an offset to the address to determine where to retrieve the
value.

The memory storage operators work in an analogous fashion. In each case val is
converted to the specified memory type and stored at the specified location. If val is
a list, an array is written into memory, up to a maximum number of elements specified by
len if given. Otherwise, only a single value is stored into memory, even if len
is non-zero. All of the storage operators return the same val that was passed to them.

Certain Isis types may not be compatible with certain memory types, in which case an error
message will be printed and Null returned. For example, you cannot store Isis
procedures as any type, and you cannot store Isis addresses as any type other than
c-pointer. An error will also be printed if you try to store a list containing
elements of different types.

Other memory utilities

(copy-memory numbytes srcaddr destaddr) # copy bytes, no overlap allowed
(move-memory numbytes srcaddr destaddr) # same as copy but works if overlap
(compare-memory numbytes addr1 addr2) # compare bytes, return True if same
(search-memory numbytes value addr) # look for byte, return addr or Null
(set-memory numbytes value addr) # fill a byte into memory
(reverse-bytes wordsize numwords inbuf outbuf) # reverse byte order of buffer
copy-memory copies bytes from a source region to a destination region that do not
overlap. move-memory is the same as copy-memory except it will work if the
regions do overlap. compare-memory compares the specified number of bytes in two
regions and returns True if they are identical, False if not.
search-memory searches for a particular byte value in a memory region (up to the
specified number of bytes) and returns its address if found, or Null if not found.
set-memory fills a memory region with the specified byte value.

reverse-bytes reverses the byte order of elements in a buffer. It accepts word sizes
of 2, 4, or 8 bytes. The output buffer address is returned, or Null if an invalid
word size was specified.