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

Reply via email to