On Wed, 10 Jun 2009, Mindaugas Kavaliauskas wrote:

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.

Yes it is.

> - hb_gc[Un]Lock() is used only by hbregexc.c module. Why this module is so 
> different?

because I made it safe for asynchronous GC activation.
In other modules I used to avoid any memory allocation between hb_gcAlloc()
and attaching the block to well known item. I've seen that you haven't
respected it in some new code but I decided to not talk about it and
generate some noice for other users planing to change GC API.

> - 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.

Yes it is. And if you remember I planed to change current code and
introduce hb_gcAttach() or similar function. Current code it wrong.
hb_gcAlloc() should return locked block or if you prefer more common
terminology block with weak references which should be converted to
normal reference when block is attached to some other container.

> - 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.

No it's not the reason. hb_itemNew() is allocated from GC because it
should be safe to store GC complex items inside even after removing all
.prg references.

> 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.

Yes it is. If we plan to make such big jump in numbering then it's time
to introduce serious modifications which are waiting for long time and
was not added due to backward binary compatibility.
GC should be the 1-st and probably the most important part.

> 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 plan to clean whole GC code then we have to drop backward
compatibility.

> 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).

Yes, but I do not think it's such important in open source projects.
I rather do not believe that we will accept runtime overhead to keep
binary compatibility. Probably we force code recompilation, f.e. by
changing function name. We can define hb_gcAlloc as macro to some
real function like hb_gcAlloc_2 (2 functions in HB_GC_VTBL) and then
simply change it.

>> 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.

Not exactly. Such list can be used only as extension to current code.
Each GC block will have pointer to cyclic GC block list and each GC
block can be relinked from s_pCurrBlock or s_pLockedBlock to other
GC block and then it will be marked automatically when parent GC block
is marked. In such version GC knows about all references between different
blocks and they are not hidden by user mark function. It's possible that
such knowledge will be usable in the future.

> 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.

Of course the unlocked container is necessary for us and we will have
to add function which allocates such container or as I wrote in previous
message document hb_gcUnlock() behavior for grip blocks - it will convert
locked container into unlocked one or in other words remove weak reference.
It's necessary in both versions but it's not enough. We still need
additional mechanism to scan and mark unlocked block which are logically
bound. It can be done by user mark/sweep function (the 1-st version) or
known for GC references chains (the 2-nd version).
Probably the second version gives cleaner final API. F.e. in your example
it will be enough to introduce only one function used to attach to other
container and it will internally automatically remove weak reference (unlock)
the container allocated by hb_itemNew()

best regards,
Przemek
_______________________________________________
Harbour mailing list
[email protected]
http://lists.harbour-project.org/mailman/listinfo/harbour

Reply via email to