@ -413,13 +413,13 @@ static void traverseweakvalue (global_State *g, Table *h) {
* * ( in the atomic phase ) . In generational mode , it ( like all visited
* * tables ) must be kept in some gray list for post - processing .
*/
static int traverseephemeron ( global_State * g , Table * h ) {
static int traverseephemeron ( global_State * g , Table * h , int inv ) {
int marked = 0 ; /* true if an object is marked in this traversal */
int hasclears = 0 ; /* true if table has white keys */
int hasww = 0 ; /* true if table has entry "white-key -> white-value" */
Node * n , * limit = gnodelast ( h ) ;
unsigned int i ;
unsigned int asize = luaH_realasize ( h ) ;
unsigned int nsize = sizenode ( h ) ;
/* traverse array part */
for ( i = 0 ; i < asize ; i + + ) {
if ( valiswhite ( & h - > array [ i ] ) ) {
@ -427,8 +427,10 @@ static int traverseephemeron (global_State *g, Table *h) {
reallymarkobject ( g , gcvalue ( & h - > array [ i ] ) ) ;
}
}
/* traverse hash part */
for ( n = gnode ( h , 0 ) ; n < limit ; n + + ) {
/* traverse hash part; if 'inv', traverse descending
( see ' convergeephemerons ' ) */
for ( i = 0 ; i < nsize ; i + + ) {
Node * n = inv ? gnode ( h , nsize - 1 - i ) : gnode ( h , i ) ;
if ( isempty ( gval ( n ) ) ) /* entry is empty? */
clearkey ( n ) ; /* clear its key */
else if ( iscleared ( g , gckeyN ( n ) ) ) { /* key is not marked (yet)? */
@ -490,7 +492,7 @@ static lu_mem traversetable (global_State *g, Table *h) {
if ( ! weakkey ) /* strong keys? */
traverseweakvalue ( g , h ) ;
else if ( ! weakvalue ) /* strong values? */
traverseephemeron ( g , h ) ;
traverseephemeron ( g , h , 0 ) ;
else /* all weak */
linkgclist ( h , g - > allweak ) ; /* nothing to traverse now */
}
@ -620,21 +622,30 @@ static lu_mem propagateall (global_State *g) {
}
/*
* * Traverse all ephemeron tables propagating marks from keys to values .
* * Repeat until it converges , that is , nothing new is marked . ' dir '
* * inverts the direction of the traversals , trying to speed up
* * convergence on chains in the same table .
* *
*/
static void convergeephemerons ( global_State * g ) {
int changed ;
int dir = 0 ;
do {
GCObject * w ;
GCObject * next = g - > ephemeron ; /* get ephemeron list */
g - > ephemeron = NULL ; /* tables may return to this list when traversed */
changed = 0 ;
while ( ( w = next ) ! = NULL ) {
next = gco2t ( w ) - > gclist ;
if ( traverseephemeron ( g , gco2t ( w ) ) ) { /* traverse marked some value? */
while ( ( w = next ) ! = NULL ) { /* for each ephemeron table */
next = gco2t ( w ) - > gclist ; /* list is rebuilt during loop */
if ( traverseephemeron ( g , gco2t ( w ) , dir ) ) { /* marked some value? */
propagateall ( g ) ; /* propagate changes */
changed = 1 ; /* will have to revisit all ephemeron tables */
}
}
} while ( changed ) ;
dir = ! dir ; /* invert direction next time */
} while ( changed ) ; /* repeat until no more changes */
}
/* }====================================================== */