Przemyslaw Czerpak wrote:
How can we fix it? I see the only solution: collectible pointers should
have not only Destroy method, but also Mark. This is something like a
little move toward method support for collectible pointers.
Yes it is. In the past Ryszard added support for registering mark/sweep
functions (see hb_gcRegisterSweep() and hb_gcUnregisterSweep()) but it's
hard to use them to resolve the problem like in your example due to reverted
mark precedence. For this we need some more general solution. The easiest
way is adding mark sweep function though probably it will be good to join
this modification with some other. F.e. we should clearly define the GC API
and introduce weak references as obligatory for each newly allocated block.
To not increase allocated memory for HB_GARBAGE structure we can make
it using the same trick as for extended references and register in current
pFunc member pointer to static const structure with different functions.
Now 'free' and 'mark'.
If we want to keep backward compatibility then we can add new GC function
and use 1 bit in flags to mark GC blocks with such function table instead
of pure destructor function. And of course we will have to add function
to mark pure GC blocks and document hb_gcUnlock() behavior for grip blocks.
Hi,
I'm a little confused in details of GC:
- gcRegisterSweep() is not used in Harbour code at all. It is slow also
--- gcUnregisterSweep do a linear scan.
- hb_gc[Un]Lock() is used only by hbregexc.c module. Why this module is
so different?
- I thought hb_gcAlloc() returns a locked item and this item is unlocked
after it is put into some item (there was discussion about it some time
ago), but I found a different code.
- I'm surprised, hb_itemNew() container is allocated from GC, but I can
guess the reason: if GC block (array, collectible pointer, etc) is
released, container should be collected also.
Collectible pointers were started to used not long time ago, so I think
it's a good time, to do cleanup and change GC API as necessary.
I do not think we need to play with compatibility bit. I see the code
below as a good solution:
typedef struct {
PHB_GC_FUNC_FREE free;
PHB_GC_FUNC_MARK mark;
} HB_GC_VTBL;
[const] static HB_GC_VTBL hb_sink_vtbl = {
hb_sink_destructor,
hb_sink_mark};
ISink * pSink = ( ISink* ) hb_gcAlloc( sizeof( ISink ), hb_sink_vtbl );
mark function can be left NULL, o assigned to
hb_gc_default_mark_function (to avoid if(...->mark != NULL) check inside
GC collector code), if no action is required for mark.
If we want to be safe for future GC extensions (thought this part
usually does not requires to be changed if it is well constructed in the
beginning), we can add:
typedef struct {
int size;
PHB_GC_FUNC_FREE free;
PHB_GC_FUNC_MARK mark;
} HB_GC_VTBL;
.size should be initialized to sizeof( HB_GC_VTBL ). This will allow to
track incompatible gcAlloc() calls in current code (without GPF, because
size is first 4 bytes of function), and in the future (.size is a kind
of "version number", if we add new methods to GC).
Alternatively we can introduce chains of references which can be bound
with each GC block and add function to register/unregister such references.
Registration grip block in references of some other GC block should
automatically unlock it and make a part of mark sweep processing when the
main block is accessed.
I guess I understand that you mean. It will add additional grip list
insert/delete operations on hb_itemCopy(). I guess it will slow down HVM.
I still thinking about why grips are locked. The PROPER unlocking may
solve the problem. But we need to include grips into the marking
process. Only locked or marked grips should mark their content.
hb_gcItemRef() can be split into hb_grip_mark, hb_array_mark,
hb_hash_mark, etc. grip becoms one of the common GC blocks.
Regards,
Mindaugas
_______________________________________________
Harbour mailing list
[email protected]
http://lists.harbour-project.org/mailman/listinfo/harbour