I couldn’t find an extension which allows you to easily designate state as being protected from UNDO, RESTORE, and RESTART, so I’ve been working on writing one. For word values this is easy, and sufficient for my purposes, but I figured if I’m writing an extension I should support block values too (and tables of varying size). This would require dynamic memory allocation, but if I understand the Glulx spec (and the source code of Glulxe) correctly, using @protect on heap memory is legal. However, two problems arise.
First, since you can only protect one continuous range at a time (aargh!), you can’t protect a heap block without forgetting what its address is (at least without risking protecting memory you don’t want protected). This is not so hard to get around, since you only need a single extra word of protected memory: I’m thinking of stashing the address in the rock of a Glk object or two - disgusting, I know. For RESTORE I could use a file since you’re doing file I/O anyway, but for UNDO and RESTART I’d really rather not (besides, now it’s a challenge to see if I can do it without files…).
More seriously, while protecting some heap block B will keep its data from being modified, this could also corrupt the heap, since in the restored state some other blocks might be located in addresses which used to be part of B. And if the heap doesn’t extend as far as B, then nothing is corrupted but of course you can’t access B without getting a memory access error. The only way I can think of to get around this is the following awful process:
- Compute some bound B on how big the memory map could be after the restore:
[list=a]
[*] For RESTORE, open the save file and parse the memory chunk (sadness). - For UNDO, keep track of the largest the memory map has ever been at a @saveundo point.
- For RESTART, keep track of how big the memory map was in the initial state.
[/:m]
[] Allocate enough memory to force the memory map to expand beyond B by the amount of information you need to protect (say there are L bytes of it).[/:m]
[] Copy the state you want preserved into memory starting at B (this will not cause an error, since Glulx allows writing to anywhere in the memory map even if not part of a heap block), and @protect the range [B, B+L).[/*:m]
[] Somehow stash the values of B and L where they can be recovered after the restore.[/:m]
[] Perform the restore.[/:m]
[] Extract B and L, and allocate enough memory to force the memory map to expand up to B+L (since @malloc does not change the contents of memory, the data will be preserved).[/:m]
[] Read the data starting at B and put it back in its rightful place; release the extra allocated memory.
[/:m][/list:o]
Can anyone think of a better way?