Understanding Static vs Dynamic Memory

I happened upon this line in the Z-Machine specification:

13.1. The dictionary and lexical analysis - Storage

The dictionary table is held in static memory and its byte address is stored in the word at $08 in the header.

and it got me to thinking: Why does the dictionary table have to be in static memory?

I understand that dynamic memory is read/write while static is read-only, but as addresses to dynamic memory are always lower than ones to static memory, it seems to me that there is no technical reason why I couldn’t just put that table in dynamic memory and change the header address to point to it there instead (or alternatively, changing the static memory start address to some point beyond the location of that table), assuming, of course, whatever compiler I might use would allow that. It wouldn’t require any different logic to dereference the pointer, nor would the parsing logic of the table entries have to change in any way, so the mandate that the dictionary table be in static memory feels strangely arbitrary.

Now, I grant that depending on the compiler and the contents of the game, putting that table in dynamic memory may consume all/most of the dynamic memory available so it would have a massive impact on how big your game could be, rendering all but the smallest proof-of-concepts impossible, but I guess I’m trying to wrap my head around some of the prescribed limitations placed on interpreters since that feels like an issue for the game being developed rather than the interpreter itself.

Some things like the existence of high memory for functions and strings and having to use packed addresses to reach them makes intuitive sense. Even the distinction between static and dynamic memory makes sense in terms of access speed and multi-disc handling potentially (although the remarks of 1. The memory map state:

(The original idea behind the high memory mark was that everything below it should be stored in the interpreter’s RAM, while what was above could reasonably be kept in “virtual memory”, i.e., loaded off disc as needed.)

which suggests high memory was intended to facilitate multi-disc handling as opposed to static vs dynamic memory).

But since the specific boundary between dynamic and static memory is determined by the individual game and the actual logic for interpreting the structures in those sections of memory are the same, it seems to me like dictating which specific structures need to be in which half is an odd thing to fix in stone, especially since they still use a dynamic address (codified in the header) to figure out where that is.

Am I missing something obvious, is this distinction something that was very relevant in machine of the era that isn’t really a concept anymore, or is this limitation actually as arbitrary as it feels?

1 Like

If the standard guarantees that the dictionary is in static memory, the interpreter can build an index into the dictionary at game start, for fast access, and it’s guaranteed to not become invalid during program execution.

2 Likes

It’s giving interpreter authors permission to optimize dictionary lookups (which, remember, are handled by the interpreter rather than the game in the Z-machine) by assuming that the dictionary will never change at runtime.

2 Likes

Not really multi-disk handling, but paging / virtual memory, yes.

Disk drives were generally not fast enough to make it viable to swap out dynamic memory to disk, but paging read-only memory was (in some cases barely) fast enough. So an interpreter was expected to keep all of the memory that could change (AKA dynamic memory) in RAM at all times. Then, if there was enough room, it could look at the high-memory mark and consider keeping some or all of the contents under that mark in RAM at all times as well.

Ozmoo for one ignores the high-memory mark completely, and swaps in everything above dynamic memory as needed.

1 Like

Ah, that makes sense. I tend to think of everything from the perspective of the game and the framework by which its capabilities are maximized. I think of the interpreter as being written to execute the games, not the games being written according to the capabilities of the interpreter. Having parts of the standard fixed to make writing the interpreters sane and performant makes perfect sense!

Thanks!

1 Like

After all these years, I never caught that the dictionary is guaranteed to be in static memory. My interpreters don’t cache it.

1 Like

Another aspect is that back when the Z-machine was defined, the usual handling of substantial changes in the object was object-swapping (e.g. placing the broken gizmo in the nowhere/limbo and placing the working gizmo from nowhere in its place), and this obviously allows static dictionary.

The object-swapping handling also allowed the saving of a flag (often a rare resource in early IF engines, a poignant case being the .z3 limit on common proprietes), the checking of the state of the object being merely checking what of the two objects is in the nowhere/limbo, or vice-versa.

Best regards from Italy,
dott. Piergiorgio.

1 Like

I don’t think this is a factor. The list of words that can be used to refer to an object is not stored in the dictionary, but in the object tree, which is stored in dynamic memory.

Changing which words can be used to refer to an object can be done at runtime, both in ZIL and Inform 6. The length of the array can’t be changed though, so you need to make it long enough for all scenarios at compile time.

7 Likes