In hll_call(), pointers to heap data passed by reference could become
invalid if the heap was reallocated during the call.
The previous implementation attempted to prevent this by calling
heap_guarantee() to pre-allocate heap space. However, this approach
does not work for certain functions in PastelChime2 HLL, which can
perform an unbounded number of heap allocations.
This commit removes heap_guarantee() and replaces it with a more robust
copy-in/copy-out strategy:
- Before the call (Copy-in): For reference arguments, the pointer value
is copied from the heap to a local variable on the stack. A pointer to
this local variable is then passed to the HLL function.
- After the call (Copy-out): The pointer value, which may have been
modified by the HLL function, is written back from the local variable
to its original slot in the heap.
Some classes in Dungeons & Dolls serialize themselves using
`File.Write(this)` in their destructors. Because `File.Write` takes the
argument by value, a copy of `this` is created. If the destructor is
called on the copied `this`, it falls into an an infinite loop.
It is currently only used to populate a field in RSM v9 save file.
As far as I can tell from examining Rance 01's resume save, this
reference does not seem to increment the target's refcount.
Delegates "weakly" reference objects, meaning that referenced objects
can be deleted. Delegate invocations must not invoke on deleted objects.
This is achieved as follows:
* Each heap object has a sequential number.
* Each delegate object is backed by a page storing (object, function,
seq) triples.
* Deleted objects can be detected by comparing the sequential number
stored in the delegate with the sequential number of the object
currently on the heap.
This is consistent with the AliceSoft's implementation (presumed from
the contents of resume save).
This implementation removes dead objects from the delegate in DG_CALL
and DG_NUMOF instructions. (We could do that more often, e.g. when an
object is added to a delegate.)
This breaks existing resume saves that contain delegates. For games that
predate delegate support, this does not affect the save format.
This reverts the following commits:
* 4b1257f "Fix delegate memory management"
* 9bb4665 "Add changes to vm.h" (partial revert)
* 75d6386 "Fix ResumeSave/ResumeLoad bugs with delegates" (partial
revert)
We are going to take a different approach to implementing weak
references in delegates.
Although delegate pages store references to objects on the heap,
adding/removing objects from a delegate does not affect their reference
counts. When an object that is a member of a delegate is deleted, it is
automatically removed from the delegate.
In practice, this means that every object needs to keep a list of
delegates that it belongs to. This increases the size of the page header
on 64 bit systems, but not by much since the additional metadata can be
stored in a union with the array-specific metadata.
1. DG_CALL has to clean up the stack before jumping to the return
address.
2. DG_SET (contrary to its name) is an append operation; it's basically
a combination of DG_NEW_FROM_METHOD and DG_PLUSA.
3. DG_SET and DG_PLUSA need to check for and ignore duplicates.
4. Delegate pages store *references* to structs; the VM should NOT copy
the struct page when copying a delegate page.
This is a serialization interface for a particular struct type. I've
implemented it somewhat generically, only checking that the name of the
struct matches the expected type. The actual structure of the objects
passed in is not checked, and in fact this structure differs between
games.
The serialized data produced by ADVSceneKeeper.Save should be identical
to what's produced by AnteaterADVEngine.dll from Shaman's Sanctuary.
ref types are currently passed to HLL functions as pointers into the
heap. If the HLL function itself needs to allocate memory from the heap,
it can cause the heap to be reallocated, rendering these heap pointers
invalid.
In order to work around this, hll_call now guarantees 64 slots are
available on the heap before calling any HLL function. This is not a
great solution, but it should work to the extent that HLL functions only
allocate a fixed number of heap slots < 64.
This bug could be easily triggered by scrolling up on the message log in
Sengoku Rance.
- Create separate directories for source and header files.
- Build code shared between xsystem4 and aindump as a static library.
- Create header dirs gfx/ system4/ and vm/
- Make CG.c/h usable without a running VM