In incremental mode, threads don't need to be visited again once
visited in the atomic phase. In generational mode (where all visits
are in the atomic phase), only old threads need to be kept in the
'grayagain' list for the next cycle.
When entering generational mode, all objects are old. So, the only
objects that need to be in a gray list are threads, which can be
assigned without barriers. Changes in anything else (e.g., weak
tables) will trigger barriers that, if needed, will add the object
to a gray list.
OLD1 objects can be potentially anywhere in the 'allgc' list (up
to 'reallyold'), but frequently they are all after 'old1' (natural
evolution of survivals) or do not exist at all (when all objects die
young). So, instead of 'markold' starts looking for them always
from the start of 'allgc', the collector keeps an extra pointer,
'firstold1', that points to the first OLD1 object in the 'allgc' list,
or is NULL if there are no OLD1 objects in that list.
Instead of adding all tables and userdata back to the 'grayagain' list
to be checked by 'correctgraylist', the collector adds only the objects
that will remain in that list (objects aged TOUCHED1). This commit
also rewrites 'correctgraylist' with a clearer logic.
Small changes to ensure that all objects are kept 'new' in incremental
GC (except for fixed strings, which are always old) and to make that
fact clearer.
Barriers cannot be active during sweep, even in generational mode.
(Although gen. mode is not incremental, it can hit a barrier when
deleting a thread and closing its upvalues.) The colors of objects are
being changed during sweep and, therefore, cannot be trusted.
When an object aged OLD1 is finalized, it is moved from the list
'finobj' to the *beginning* of the list 'allgc'. So, this part of the
list (and not only the survival list) must be visited by 'markold'.
'simplesect' encloses the introductory text of sections with
subsections, so that each section either is all text or is all
subsections. (This commit also corrects a small brace error in the
manual and extra spaces/tabs in some other files.)
When converging marks on ephemeron tables, change the direction the
tables are traversed at each iteration, to try to avoid bad-case
scenarios with linked lists of entries in a table.
Open upvalues are kept alive together with their corresponding
stack. This change makes a simpler and safer fix to the issue in
commit 440a5ee78c, about upvalues in the list of open upvalues
being collected while others are being created. (That previous fix
may not be correct.)
- Several new comments in 'lmem.c'.
- Both 'luaM_growaux_' and 'luaM_shrinkvector_' use 'luaM_saferealloc_'
to check for errors. Moreover, the use of 'luaM_saferealloc_' makes
'luaM_shrinkvector_' try again if shrink fails (which can happen now).
- In 'checkSizes', save old debt only when needed.
The 'GCSenteratomic' is just an auxiliary state for transitioning
to 'GCSatomic'. All GC traversals should be done either on the
'GCSpropagate' state or the 'GCSatomic' state.
- The warning functions get an extra parameter that tells whether
message is to be continued (instead of using end-of-lines as a signal).
- The user data for the warning function is a regular value, instead
of a writable slot inside the Lua state.
After a major bad collection (one that collects too few objects),
next collection will be major again. In that case, avoid switching
back to generational mode (as it will have to switch again to
incremental to do next major collection).
The mechanism of "caching the last closure created for a prototype to
try to reuse it the next time a closure for that prototype is created"
was removed. There are several reasons:
- It is hard to find a natural example where this cache has a measurable
impact on performance.
- Programmers already perceive closure creation as something slow,
so they tend to avoid it inside hot paths. (Any case where the cache
could reuse a closure can be rewritten predefining the closure in some
variable and using that variable.)
- The implementation was somewhat complex, due to a bad interaction
with the generational collector. (Typically, new closures are new,
while prototypes are old. So, the cache breaks the invariant that
old objects should not point to new ones.)
Start of the implementation of "scoped variables" or "to be closed"
variables, local variables whose '__close' (or themselves) are called
when they go out of scope. This commit implements the syntax, the
opcode, and the creation of the corresponding upvalue, but it still
does not call the finalizations when the variable goes out of scope
(the most important part).
Currently, the syntax is 'local scoped name = exp', but that will
probably change.
During generational collection, a userdatum must become gray and
go to a gray list after being traversed (like tables), so that
'correctgraylist' can handle it to its next stage.
This commit also added minimum tests for the generational collector,
including one that would detect this bug.
When Lua is building large long-duration structures, frequent small
minor collections just waste time. Trying to avoid this, the
collector will do a larger pause after a major collection when it
does not collect enough garbage (which is a hint that memory is
being used for long-lasting objects).
if the key is dead, it cannot be given to 'next'. Instead, we now
use a 'table' tag without the collectable bit, which makes it
a unique tag good enough to reserve space.
Some simplifications (not counting bytes, couting only slots visited;
no more 'gcfinnum'); more GC parameters; using vararg in 'lua_gc' to
set parameters in different GC modes
when entering sweep phase ('entersweep'); that may be too
expensive to be done still inside the atomic step. Walking
one single object more often than not will work.