Memory manipulation Isis software documentation

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:

c-byte c-char c-short c-int c-long c-longlong c-uchar c-ushort c-uint c-ulong c-ulonglong c-float c-double c-pointer
int8 int16 int32 int64 uint8 uint16 uint32 uint64 real32 real64
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:

-> (sizeof c-pointer) 8 -> (sizeof c-byte) 1 -> (sizeof c-float) 4 -> (sizeof c-double) 8 -> (sizeof c-short) 2 -> (sizeof int64) 8 -> (sizeof real32) 4


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.
-> (set onek (allocate-memory 1024)) 0x140264a00 -> (set intarray (allocate-memory (* 10 (sizeof c-int)))) 0x140118830 -> (set realarray (allocate-memory (* 10 (sizeof c-float)))) 0x140118860 -> (free-memory onek realarray intarray) Null


Retrieving and storing raw data in memory

The Isis core syntax provides the following optimized memory manipulation operators:

Memory retrieval

( address memtype )
( address [ memtype len ] )
( address [ memtype len offset ] )

Memory storage

( address memtype val )
( address [ memtype len ] val )
( address [ memtype len offset ] val )
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.

Here are some examples:

-> (set oneint (allocate-memory (sizeof c-int))) 0x140008da0 -> (oneint c-int 424242) 424242 -> (oneint c-int) 424242 -> (oneint c-int 53.23) 53.23 -> (oneint c-int) 53 -> (free-memory oneint) Null -> (set onebyte (allocate-memory 1)) 0x140008d80 -> (onebyte c-byte 42) 42 -> (onebyte c-byte) 42 -> (onebyte c-byte 1001) # This will overflow the byte 1001 -> (onebyte c-byte) 233 -> (free-memory onebyte) Null -> (set array1 (allocate-memory (* 3 (sizeof c-int)))) 0x140008de0 -> (array1 c-int [1 2 3]) [ 1 2 3 ] -> (array1 [c-int 3]) [ 1 2 3 ] -> (array1 [c-int 10]) # Peeking past the end of the allocated area [ 1 2 3 0 0 0 14 0 1076136672 1 ] -> (array1 c-int [4.4 5.3 6.7]) [ 4.4 5.3 6.7 ] -> (array1 [c-int 3]) [ 4 5 6 ] -> (free-memory array1) Null -> (set array2 (allocate-memory (* 5 (sizeof c-int)))) 0x140008de0 -> (array2 [c-int 5] [1 2 3 4 5 6 7]) 0x140008de0 -> (array2 [c-int 0 (* 3 (sizeof c-int)) ] 42) 42 -> (array2 [c-int 5]) [ 1 2 3 42 5 ] -> (free-memory array2) Null

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.

-> (set b1 (allocate-memory 16)) 0x14014cc40 -> (set b2 (allocate-memory 16)) 0x14014cc60 -> (set-memory 16 42 b1) 0x14014cc40 -> (b1 [c-byte 16]) [ 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 ] -> (compare-memory 16 b1 b2) False -> (copy-memory 16 b1 b2) 0x14014cc60 -> (compare-memory 16 b1 b2) True -> ((+ b2 6) c-byte 57) 57 -> (set b3 (search-memory 16 57 b2)) 0x14014cc66 -> (set index (integer (- b3 b2))) 6 -> (search-memory 16 88 b2) Null -> (b1 c-byte [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16]) 0x14014cc60 -> (reverse-bytes 4 4 b1 b2) 0x14014cc60 -> (b2 [c-byte 16]) [ 4 3 2 1 8 7 6 5 12 11 10 9 16 15 14 13 ]