In a bootimage=true build, we create allocate certain objects as
"immortal fixies", which means they will never been deallocated at
runtime and should only be visited if/when they point to objects which
might move during garbage collection. However, there was a bug in the
following case:
1. immortal fixie F is updated to point to a movable object M and
thus F is added to the list of fixies to visit during the next minor
collection (but not the next major one, since all reachable objects
are visited during a major collection, and there's no point in
visiting an unreachable object, whereas during a minor collection we
have to visit F because we don't know if it's reachable or not)
2. a major collection occurs, but F is not reachable and thus is not
visited, whereas M is moved
3. a minor collection occurs, and since F is still in the list, it is
visited, but since it contains a stale pointer to M's old location,
we crash
The solution is to ensure unreachable immortal fixies are removed from
the above list after each major collection, thus guaranteeing they
won't be visited on any subsequent collection.
Previously, I used a shell script to extract modification date ranges
from the Git history, but that was complicated and unreliable, so now
every file just gets the same year range in its copyright header. If
someone needs to know when a specific file was modified and by whom,
they can look at the Git history themselves; no need to include it
redundantly in the header.
Objects which are eligable for finalization must be retained until
after their finalize methods are called. However, the VM must
determine the entire set of such objects before retaining any of them;
otherwise the process of retaining a given object may cause others to
become reachable and thus be considered ineligible for finalization
even though they are only reachable via other finalizable objects.
The end result of this mistake is that only a few of the objects which
are finalizable will be recognized at each GC cycle, so it requires
many such cycles to find them all, and if new objects become
finalizable at a faster rate, the VM will never catch up and
eventually run out of memory.
This patch fixes the above mistake and also includes tuning to
minimize the need for GC in low memory situations.
The original goal was to minimize memory usage by garbage collecting
more frequently and more comprehensively as we got closer to the heap
limit. In practice, though, this just slowed the VM to a crawl as
memory pressure increased. If an app really wants to use a lot of
memory, the VM shouldn't penalize it aside from throwing an
OutOfMemoryError if it exceeds the limit.
This is necessary to avoid name conflicts on various platforms. For
example, iOS has its own util.h, and Windows has a process.h. By
including our version as e.g. "avian/util.h", we avoid confusion with
the system version.