Thread overview
[D-runtime] Proposed changes to GC interface
Aug 06, 2010
Sean Kelly
Aug 06, 2010
Sean Kelly
Aug 06, 2010
Sean Kelly
Apr 18, 2012
Sean Kelly
Jul 17, 2013
Sean Kelly
August 06, 2010
I've been thinking about how best to address the problem that the GC currently doesn't finalize structs in conjunction with tracking append metadata, precise scanning, etc.  The current pertinent GC interface is roughly as follows:

extern (C) void*   function(size_t, uint) gc_malloc;
extern (C) BlkInfo function(size_t, uint) gc_qalloc;
extern (C) void*   function(size_t, uint) gc_calloc;
extern (C) void*   function(void*, size_t, uint ba) gc_realloc;
extern (C) size_t  function(void*, size_t, size_t) gc_extend;
extern (C) size_t  function(size_t) gc_reserve;
extern (C) void    function(void*) gc_free;

What I'd like to do is this:

extern (C) void*   function(TypeInfo) gc_alloc;
extern (C) void*   function(TypeInfo, size_t) gc_allocn;
extern (C) size_t  function(void*, size_t, size_t) gc_extend;
extern (C) void*   function(size_t, uint) gc_malloc;
extern (C) size_t  function(size_t) gc_reserve;
extern (C) void    function(void*) gc_free;

// reevaluate
extern (C) size_t  function(void*, size_t, size_t) gc_extend;

// deprecate
extern (C) void*   function(void*, size_t, uint ba) gc_realloc;
extern (C) BlkInfo function(size_t, uint) gc_qalloc;

gc_alloc() and gc_allocn() would become the default GC allocator routines and would set any necessary flags based on the supplied type, store the pointer bitmap, initialize the block based on ti.init[], etc.

gc_malloc() will remain as-is because I suspect there will always be a need for using D as a "better C."  If this becomes an array of structs the user would be responsible for supplying the TypeInfo later (or finalizer or whatever).

gc_qalloc() should be rendered largely useless by the addition of gc_alloc() and gc_allocn(), since the need for gc_qalloc() was mostly to efficiently do stuff in lifetime.d that would instead be handled by the GC.  Steve, is this accurate?

gc_realloc() has never seen much use and promises to become increasingly more complicated as TypeInfo is added, etc.  I'd prefer to just drop it and let the user call gc_extend() if he wants to resize memory in place.  This would require allowing gc_extend() to be used on sub-page sized blocks, but this seems reasonable anyway.  If I have a 150 byte array in a 256 byte block I should be allowed to extend it to 256 bytes.  Doing so is basically a no-op, but it frees the user from having to query the block size to determine how to handle an array append operation, for example.

Finally, I really want to change the APPENDABLE bit to NO_APPEND/STATIC/SINGLE/whatever since the default (zero value) behavior should be that an allocated block is not an array.

Thoughts?
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.puremagic.com/pipermail/d-runtime/attachments/20100806/9caed43d/attachment.html>
August 06, 2010
>
>From: Sean Kelly <sean at invisibleduck.org>

[snip]

>
>gc_alloc() and gc_allocn() would become the default GC allocator routines and would set any necessary flags based on the supplied type, store the pointer bitmap, initialize the block based on ti.init[], etc.

OK, but why do we need bitmaps/bits if we can just store that info in the TypeInfo?  I mean, gc_allocn is pretty much the same as lifetime's _d_newArrayT.  It uses the bits set in the typeinfo to determine the NO_SCAN flag.  Why can't the GC use those bits?

I'd think that bits are only useful for small blocks where the cost of storing the TypeInfo pointer is greater than 10% overhead.  But if you need to go from block -> typeinfo, this may be a requirement (see questions below).

In addition to these, if the GC is going to handle appending, then it should handle how the length is stored.  This means, we need functions to get and set the length to support append and the capacity/assumeSafeAppend functions.

Note that dmd currently allocates classes via _d_newClass, but allocates individual structs via _d_newArrayT.  This is a major change that needs to be made on the compiler side (it's sort of overdue anyways).

>gc_malloc() will remain as-is because I suspect there will always be a need for

>using D as a "better C."  If this becomes an array of structs the user would be

>responsible for supplying the TypeInfo later (or finalizer or whatever).

Yes, any special handling of the block on delete needs to be handled by the user.  There should be functions to attach handlers for collection on that block.

>gc_qalloc() should be rendered largely useless by the addition of gc_alloc() and
>
>gc_allocn(), since the need for gc_qalloc() was mostly to efficiently do stuff in lifetime.d that would instead be handled by the GC.  Steve, is this
accurate?

I'd say yes, but I'd strongly suggest then that we expose the out parameter for gc_malloc that returns the *actual* block size allocated that I added to support qalloc.  Anyone whose doing direct gc allocations will certainly like to have that bit of info especially since it costs nothing to provide it.  In reality, I didn't care about the entire BlkInfo, I only cared about the allocated length. Using BlkInfo was easy, especially since I needed the bits to be stored (in fact, if you look at qalloc, it simply copies the input parameter bits to the result).

>gc_realloc() has never seen much use and promises to become increasingly more complicated as TypeInfo is added, etc.  I'd prefer to just drop it and let the user call gc_extend() if he wants to resize memory in place.  This would require
>
>allowing gc_extend() to be used on sub-page sized blocks, but this seems reasonable anyway.  If I have a 150 byte array in a 256 byte block I should be allowed to extend it to 256 bytes.  Doing so is basically a no-op, but it frees

>the user from having to query the block size to determine how to handle an array
>
>append operation, for example.

I don't think gc_extend's semantics should be changed.  If one wants to extend into the block, one should just get the capacity and use the block.  This of course is only on blocks that are allocated via gc_malloc.  Blocks allocated via gc_alloc[n] should only be extendable via the runtime functions to keep the TypeInfo sane.

>Finally, I really want to change the APPENDABLE bit to NO_APPEND/STATIC/SINGLE/whatever since the default (zero value) behavior should

>be that an allocated block is not an array.

I think there is a misunderstanding here.  a 0 APPENDABLE bit means it's not appendable (i.e. not an array).  Isn't that what you want?

Overall I think this is a good idea.  I think actually it's probably necessary to integrate the precise scanning and array append stuff together.

Some things to think about, while they're fresh in my mind:
If someone appends to an array with a different typeinfo than it was originally
allocated with, what happens?
What happens when you do a new array of void[]?
Should you be able to retrieve the typeinfo a block was allocated with?
Dare I say it, but this is going to once again separate Tango from phobos, since
Tango does not use druntime even though Tango uses an old version of druntime.
Should we care?  I say no, I strongly believe Tango is stuck on D1 forever.

-Steve




August 06, 2010
On Aug 6, 2010, at 12:34 PM, Steve Schveighoffer wrote:

>> 
>> From: Sean Kelly <sean at invisibleduck.org>
> 
> [snip]
> 
>> 
>> gc_alloc() and gc_allocn() would become the default GC allocator routines and would set any necessary flags based on the supplied type, store the pointer bitmap, initialize the block based on ti.init[], etc.
> 
> OK, but why do we need bitmaps/bits if we can just store that info in the TypeInfo?  I mean, gc_allocn is pretty much the same as lifetime's _d_newArrayT.  It uses the bits set in the typeinfo to determine the NO_SCAN flag.  Why can't the GC use those bits?

It can.  I mostly wasn't sure if we wanted to store a full pointer for all applicable blocks (to reference TypeInfo) or if we should mix bitfields and TypeInfo as needed.

> I'd think that bits are only useful for small blocks where the cost of storing the TypeInfo pointer is greater than 10% overhead.  But if you need to go from block -> typeinfo, this may be a requirement (see questions below).
> 
> In addition to these, if the GC is going to handle appending, then it should handle how the length is stored.  This means, we need functions to get and set the length to support append and the capacity/assumeSafeAppend functions.

gc_allocn() would handle the initial allocation for array types (I tried to wedge both behaviors into one function call and couldn't sort it out to my satisfaction), but you're right that there would need to be an additional call in there.  Maybe gc_extend() could be rewritten to use element counts instead of byte counts, assuming we expect to always have TypeInfo available for arrays?

>> gc_realloc() has never seen much use and promises to become increasingly more complicated as TypeInfo is added, etc.  I'd prefer to just drop it and let the user call gc_extend() if he wants to resize memory in place.  This would require
>> 
>> allowing gc_extend() to be used on sub-page sized blocks, but this seems reasonable anyway.  If I have a 150 byte array in a 256 byte block I should be allowed to extend it to 256 bytes.  Doing so is basically a no-op, but it frees
> 
>> the user from having to query the block size to determine how to handle an array
>> 
>> append operation, for example.
> 
> I don't think gc_extend's semantics should be changed.  If one wants to extend into the block, one should just get the capacity and use the block.  This of course is only on blocks that are allocated via gc_malloc.  Blocks allocated via gc_alloc[n] should only be extendable via the runtime functions to keep the TypeInfo sane.

But the runtime functions would in turn call gc_extend(), right?  One of the things I was thinking of was that gc_extend() currently takes two arguments, a required and a desired size.  But as far as I know the same value is always passed to both.  If this is true, why not just eliminate one?

>> Finally, I really want to change the APPENDABLE bit to NO_APPEND/STATIC/SINGLE/whatever since the default (zero value) behavior should
> 
>> be that an allocated block is not an array.
> 
> I think there is a misunderstanding here.  a 0 APPENDABLE bit means it's not appendable (i.e. not an array).  Isn't that what you want?

Oops, you're right.

> Overall I think this is a good idea.  I think actually it's probably necessary to integrate the precise scanning and array append stuff together.
> 
> Some things to think about, while they're fresh in my mind:
> If someone appends to an array with a different typeinfo than it was originally
> allocated with, what happens?

This shouldn't be allowed.  It's why I don't think gc_extend() should accept typeinfo, etc.

> What happens when you do a new array of void[]?

Same as now I'd think.

> Should you be able to retrieve the typeinfo a block was allocated with?

Seems reasonable to expect so.

> Dare I say it, but this is going to once again separate Tango from phobos, since Tango does not use druntime even though Tango uses an old version of druntime. Should we care?  I say no, I strongly believe Tango is stuck on D1 forever.

I no longer care about retaining compatibility with Tango for exactly the same reason.  I do still think there's value in having a separate runtime and standard library however, because druntime encapsulates the minimum support code necessary for a fully functional D application.  With the all-in-one approach it's just too easy for half the standard library to be pulled into every app simply because some low-level routine wants to do some string formatting or whatever, and I think we'd lose a chunk of potential C/C++ converts if this were the case.
August 06, 2010



----- Original Message ----
> From: Sean Kelly <sean at invisibleduck.org>
> To: D's runtime library developers list <d-runtime at puremagic.com>
> Sent: Fri, August 6, 2010 4:17:43 PM
> Subject: Re: [D-runtime] Proposed changes to GC interface
> 
> On Aug 6, 2010, at 12:34 PM, Steve Schveighoffer wrote:
> 
> >> 
> >> From: Sean Kelly <sean at invisibleduck.org>
> > 
> > [snip]
> > 
> >> 
> >> gc_alloc() and gc_allocn()  would become the default GC allocator routines
>and
>
> >> would set any  necessary flags based on the supplied type, store the pointer
>
> >>  bitmap, initialize the block based on ti.init[], etc.
> > 
> > OK, but  why do we need bitmaps/bits if we can just store that info in the
> >  TypeInfo?  I mean, gc_allocn is pretty much the same as lifetime's
> >  _d_newArrayT.  It uses the bits set in the typeinfo to determine the
>NO_SCAN
>
> > flag.  Why can't the GC use those bits?
> 
> It  can.  I mostly wasn't sure if we wanted to store a full pointer for all
>applicable blocks (to reference TypeInfo) or if we should mix bitfields and TypeInfo as needed.

This poses problems for some of the other things you said.  For example, if you want to append to a block that doesn't point to a typeinfo, but you don't want to pass in a typeinfo, how do you populate the typeinfo for the larger block?

I think perhaps we may need two types of small blocks, ones with typeinfo and ones with just bits.  The ones with just bits could not be used as arrays (i.e. could only be single elements).

> 
> > I'd think that bits are only useful for small  blocks where the cost of
>storing
>
> > the TypeInfo pointer is greater than  10% overhead.  But if you need to go
>from
>
> > block -> typeinfo,  this may be a requirement (see questions below).
> > 
> > In addition to  these, if the GC is going to handle appending, then it should
>
> > handle  how the length is stored.  This means, we need functions to get and
>set
>
> > the length to support append and the capacity/assumeSafeAppend  functions.
> 
> gc_allocn() would handle the initial allocation for array  types (I tried to
>wedge both behaviors into one function call and couldn't sort  it out to my satisfaction), but you're right that there would need to be an  additional call in there.  Maybe gc_extend() could be rewritten to use  element counts instead of byte counts, assuming we expect to always have  TypeInfo available for arrays?

We definitely need to support capacity, which can be used to tune an append, or determine whether an append is going to decouple an array from its original. This helps to write deterministic code.

But I see how you are going with gc_extend, it's like an abstraction of appending that the runtime currently handles.  I think the gc should present a consistent interface.  So if we're dealing in terms of elements on allocation, we should deal with elements on extension also.

> 
> >> gc_realloc() has never seen much  use and promises to become increasingly
>more
>
> >> complicated as  TypeInfo is added, etc.  I'd prefer to just drop it and let
>the
>
> >> user call gc_extend() if he wants to resize memory in place.   This would
>require
>
> >> 
> >> allowing gc_extend() to be used on  sub-page sized blocks, but this seems reasonable anyway.  If I  have a 150 byte array in a 256 byte block I should
>be
>
> >> allowed to  extend it to 256 bytes.  Doing so is basically a no-op, but it
>frees
>
> > 
> >> the user from having to query the block size to determine  how to handle an
>array
>
> >> 
> >> append operation, for  example.
> > 
> > I don't think gc_extend's semantics should be  changed.  If one wants to
>extend
>
> > into the block, one should just  get the capacity and use the block.  This of
>
> > course is only on  blocks that are allocated via gc_malloc.  Blocks allocated
>via
>
> >  gc_alloc[n] should only be extendable via the runtime functions to keep the

> > TypeInfo sane.
> 
> But the runtime functions would in turn call  gc_extend(), right?  One of the
>things I was thinking of was that  gc_extend() currently takes two arguments, a required and a desired size.   But as far as I know the same value is always passed to both.  If this is  true, why not just eliminate one?

Heh, in my last update to druntime, I started trying to use the min and desired sizes.  What I found was that the runtime would give up too early when trying to fulfill the desired size.  So I fixed it to obey the desired size when possible :)

I think an extend function that properly supports min and desired would be very important.

The algorithm would be something like:

if I can extend at least the minimum because the block supports it (without
stomping), do that, as much as possible less than the desired size.
else if I can attach more pages, attach as many as possible to try and get to
desired size,
else reallocate the block as the desired size.

I do believe the algorithm to logarithmically grow an array size should be left outside the GC.  The GC shouldn't make any assumptions it is not told.

But to answer your original point, gc_extend is currently used to add more pages to a block *in place* without reallocating.  For those gc_malloc zealots, we need to support this somehow.  Even if we rename it to something else and commandeer gc_extend to be array appending.

> > Overall I think this is a good idea.  I think  actually it's probably
>necessary
>
> > to integrate the precise scanning and  array append stuff together.
> > 
> > Some things to think about, while  they're fresh in my mind:
> > If someone appends to an array with a  different typeinfo than it was
>originally
>
> > allocated with, what  happens?
> 
> This shouldn't be allowed.  It's why I don't think  gc_extend() should accept
>typeinfo, etc.

Well, it's not illegal to do this:

auto arr = new U[50];
cast(T[]) arr;

arr ~= T(1,2,3);

So we have to either handle this, or reject it, but it has to be done at runtime.  I think the *wrong* approach is to assume the append is trying to add more U's.  So at the very least, gc_extend needs to verify the typeinfo matches.  The compiler already passes the typeinfo to the function, so let's utilize that info.

Come to think of it, should we provide a function to "retype" a block?

> 
> > What happens when you do a  new array of void[]?
> 
> Same as now I'd think.

I'd rethink this.  Since we're storing the typeinfo with a block, why should void[] be typed as containing pointers?  You can always do void*[]...

In fact, you could actually statically disallow new void[x] and probably not lose much (one can always call gc_malloc).

> 
> > Should you be  able to retrieve the typeinfo a block was allocated with?
> 
> Seems  reasonable to expect so.

What about blocks that are tiny where the TypeInfo pointer would be 33% overhead?  If we're only going to store bits.

Again, consider the suggestion that when allocating *arrays* we may always need TypeInfo, but when allocating single elements, we may just want to store bits.

-Steve




August 06, 2010
On Aug 6, 2010, at 1:52 PM, Steve Schveighoffer wrote:
> 
>> 
>>> Should you be  able to retrieve the typeinfo a block was allocated with?
>> 
>> Seems  reasonable to expect so.
> 
> What about blocks that are tiny where the TypeInfo pointer would be 33% overhead?  If we're only going to store bits.
> 
> Again, consider the suggestion that when allocating *arrays* we may always need TypeInfo, but when allocating single elements, we may just want to store bits.

But in this case, perhaps the TypeInfo request would just return null?  I was thinking along the same lines.  Basically, have TypeInfo storage be a parallel array allocated on demand, like some of the bitarrays are.  Pages containing small blocks probably wouldn't need TypeInfo since they aren't likely to contain arrays, and I don't imagine people dynamically allocate structs very often (even though structs are what inspired all of this to begin with).
April 18, 2012
Resurrecting this discussion in light of precise scanning.  There was some discussion following this message which may be worth reviewing.  Also please note that the user-visible interface may use templates, so the actual implementation may be something like:

struct GC
{
    void* alloc(T)()
    {
        // get pointer map for T
        // call gc_alloc() with pointer map, etc.
    }
}

There's also no reason the compiler runtime couldn't call the GC via this interface rather than how it currently calls the C routines directly.  That convention is a bit outdated and simply hasn't been changed because the current approach works.

On Aug 6, 2010, at 11:59 AM, Sean Kelly wrote:

> I've been thinking about how best to address the problem that the GC currently doesn't finalize structs in conjunction with tracking append metadata, precise scanning, etc.  The current pertinent GC interface is roughly as follows:
> 
> extern (C) void*   function(size_t, uint) gc_malloc;
> extern (C) BlkInfo function(size_t, uint) gc_qalloc;
> extern (C) void*   function(size_t, uint) gc_calloc;
> extern (C) void*   function(void*, size_t, uint ba) gc_realloc;
> extern (C) size_t  function(void*, size_t, size_t) gc_extend;
> extern (C) size_t  function(size_t) gc_reserve;
> extern (C) void    function(void*) gc_free;
> 
> What I'd like to do is this:
> 
> extern (C) void*   function(TypeInfo) gc_alloc;
> extern (C) void*   function(TypeInfo, size_t) gc_allocn;
> extern (C) size_t  function(void*, size_t, size_t) gc_extend;
> extern (C) void*   function(size_t, uint) gc_malloc;
> extern (C) size_t  function(size_t) gc_reserve;
> extern (C) void    function(void*) gc_free;
> 
> // reevaluate
> extern (C) size_t  function(void*, size_t, size_t) gc_extend;
> 
> // deprecate
> extern (C) void*   function(void*, size_t, uint ba) gc_realloc;
> extern (C) BlkInfo function(size_t, uint) gc_qalloc;
> 
> gc_alloc() and gc_allocn() would become the default GC allocator routines and would set any necessary flags based on the supplied type, store the pointer bitmap, initialize the block based on ti.init[], etc.
> 
> gc_malloc() will remain as-is because I suspect there will always be a need for using D as a "better C."  If this becomes an array of structs the user would be responsible for supplying the TypeInfo later (or finalizer or whatever).
> 
> gc_qalloc() should be rendered largely useless by the addition of gc_alloc() and gc_allocn(), since the need for gc_qalloc() was mostly to efficiently do stuff in lifetime.d that would instead be handled by the GC.  Steve, is this accurate?
> 
> gc_realloc() has never seen much use and promises to become increasingly more complicated as TypeInfo is added, etc.  I'd prefer to just drop it and let the user call gc_extend() if he wants to resize memory in place.  This would require allowing gc_extend() to be used on sub-page sized blocks, but this seems reasonable anyway.  If I have a 150 byte array in a 256 byte block I should be allowed to extend it to 256 bytes.  Doing so is basically a no-op, but it frees the user from having to query the block size to determine how to handle an array append operation, for example.
> 
> Finally, I really want to change the APPENDABLE bit to NO_APPEND/STATIC/SINGLE/whatever since the default (zero value) behavior should be that an allocated block is not an array.
> 
> Thoughts?
> _______________________________________________
> D-runtime mailing list
> D-runtime@puremagic.com
> http://lists.puremagic.com/mailman/listinfo/d-runtime

_______________________________________________
D-runtime mailing list
D-runtime@puremagic.com
http://lists.puremagic.com/mailman/listinfo/d-runtime

July 17, 2013
Seems time to resurrect this discussion again.  I know the proposal below is dated, but it's a start.  Thoughts?

On Apr 18, 2012, at 11:51 AM, Sean Kelly <sean@invisibleduck.org> wrote:

> Resurrecting this discussion in light of precise scanning.  There was some discussion following this message which may be worth reviewing.  Also please note that the user-visible interface may use templates, so the actual implementation may be something like:
> 
> struct GC
> {
>    void* alloc(T)()
>    {
>        // get pointer map for T
>        // call gc_alloc() with pointer map, etc.
>    }
> }
> 
> There's also no reason the compiler runtime couldn't call the GC via this interface rather than how it currently calls the C routines directly.  That convention is a bit outdated and simply hasn't been changed because the current approach works.
> 
> On Aug 6, 2010, at 11:59 AM, Sean Kelly wrote:
> 
>> I've been thinking about how best to address the problem that the GC currently doesn't finalize structs in conjunction with tracking append metadata, precise scanning, etc.  The current pertinent GC interface is roughly as follows:
>> 
>> extern (C) void*   function(size_t, uint) gc_malloc;
>> extern (C) BlkInfo function(size_t, uint) gc_qalloc;
>> extern (C) void*   function(size_t, uint) gc_calloc;
>> extern (C) void*   function(void*, size_t, uint ba) gc_realloc;
>> extern (C) size_t  function(void*, size_t, size_t) gc_extend;
>> extern (C) size_t  function(size_t) gc_reserve;
>> extern (C) void    function(void*) gc_free;
>> 
>> What I'd like to do is this:
>> 
>> extern (C) void*   function(TypeInfo) gc_alloc;
>> extern (C) void*   function(TypeInfo, size_t) gc_allocn;
>> extern (C) size_t  function(void*, size_t, size_t) gc_extend;
>> extern (C) void*   function(size_t, uint) gc_malloc;
>> extern (C) size_t  function(size_t) gc_reserve;
>> extern (C) void    function(void*) gc_free;
>> 
>> // reevaluate
>> extern (C) size_t  function(void*, size_t, size_t) gc_extend;
>> 
>> // deprecate
>> extern (C) void*   function(void*, size_t, uint ba) gc_realloc;
>> extern (C) BlkInfo function(size_t, uint) gc_qalloc;
>> 
>> gc_alloc() and gc_allocn() would become the default GC allocator routines and would set any necessary flags based on the supplied type, store the pointer bitmap, initialize the block based on ti.init[], etc.
>> 
>> gc_malloc() will remain as-is because I suspect there will always be a need for using D as a "better C."  If this becomes an array of structs the user would be responsible for supplying the TypeInfo later (or finalizer or whatever).
>> 
>> gc_qalloc() should be rendered largely useless by the addition of gc_alloc() and gc_allocn(), since the need for gc_qalloc() was mostly to efficiently do stuff in lifetime.d that would instead be handled by the GC.  Steve, is this accurate?
>> 
>> gc_realloc() has never seen much use and promises to become increasingly more complicated as TypeInfo is added, etc.  I'd prefer to just drop it and let the user call gc_extend() if he wants to resize memory in place.  This would require allowing gc_extend() to be used on sub-page sized blocks, but this seems reasonable anyway.  If I have a 150 byte array in a 256 byte block I should be allowed to extend it to 256 bytes.  Doing so is basically a no-op, but it frees the user from having to query the block size to determine how to handle an array append operation, for example.
>> 
>> Finally, I really want to change the APPENDABLE bit to NO_APPEND/STATIC/SINGLE/whatever since the default (zero value) behavior should be that an allocated block is not an array.
>> 
>> Thoughts?
>> _______________________________________________
>> D-runtime mailing list
>> D-runtime@puremagic.com
>> http://lists.puremagic.com/mailman/listinfo/d-runtime
> 
> _______________________________________________
> D-runtime mailing list
> D-runtime@puremagic.com
> http://lists.puremagic.com/mailman/listinfo/d-runtime

_______________________________________________
D-runtime mailing list
D-runtime@puremagic.com
http://lists.puremagic.com/mailman/listinfo/d-runtime

July 17, 2013
I think you should throw it in a DIP.

Andrei

On 7/17/13 1:13 PM, Sean Kelly wrote:
> Seems time to resurrect this discussion again.  I know the proposal below is dated, but it's a start.  Thoughts?
>
> On Apr 18, 2012, at 11:51 AM, Sean Kelly<sean@invisibleduck.org>  wrote:
>
>> Resurrecting this discussion in light of precise scanning.  There was some discussion following this message which may be worth reviewing.  Also please note that the user-visible interface may use templates, so the actual implementation may be something like:
>>
>> struct GC
>> {
>>     void* alloc(T)()
>>     {
>>         // get pointer map for T
>>         // call gc_alloc() with pointer map, etc.
>>     }
>> }
>>
>> There's also no reason the compiler runtime couldn't call the GC via this interface rather than how it currently calls the C routines directly.  That convention is a bit outdated and simply hasn't been changed because the current approach works.
>>
>> On Aug 6, 2010, at 11:59 AM, Sean Kelly wrote:
>>
>>> I've been thinking about how best to address the problem that the GC currently doesn't finalize structs in conjunction with tracking append metadata, precise scanning, etc.  The current pertinent GC interface is roughly as follows:
>>>
>>> extern (C) void*   function(size_t, uint) gc_malloc;
>>> extern (C) BlkInfo function(size_t, uint) gc_qalloc;
>>> extern (C) void*   function(size_t, uint) gc_calloc;
>>> extern (C) void*   function(void*, size_t, uint ba) gc_realloc;
>>> extern (C) size_t  function(void*, size_t, size_t) gc_extend;
>>> extern (C) size_t  function(size_t) gc_reserve;
>>> extern (C) void    function(void*) gc_free;
>>>
>>> What I'd like to do is this:
>>>
>>> extern (C) void*   function(TypeInfo) gc_alloc;
>>> extern (C) void*   function(TypeInfo, size_t) gc_allocn;
>>> extern (C) size_t  function(void*, size_t, size_t) gc_extend;
>>> extern (C) void*   function(size_t, uint) gc_malloc;
>>> extern (C) size_t  function(size_t) gc_reserve;
>>> extern (C) void    function(void*) gc_free;
>>>
>>> // reevaluate
>>> extern (C) size_t  function(void*, size_t, size_t) gc_extend;
>>>
>>> // deprecate
>>> extern (C) void*   function(void*, size_t, uint ba) gc_realloc;
>>> extern (C) BlkInfo function(size_t, uint) gc_qalloc;
>>>
>>> gc_alloc() and gc_allocn() would become the default GC allocator routines and would set any necessary flags based on the supplied type, store the pointer bitmap, initialize the block based on ti.init[], etc.
>>>
>>> gc_malloc() will remain as-is because I suspect there will always be a need for using D as a "better C."  If this becomes an array of structs the user would be responsible for supplying the TypeInfo later (or finalizer or whatever).
>>>
>>> gc_qalloc() should be rendered largely useless by the addition of gc_alloc() and gc_allocn(), since the need for gc_qalloc() was mostly to efficiently do stuff in lifetime.d that would instead be handled by the GC.  Steve, is this accurate?
>>>
>>> gc_realloc() has never seen much use and promises to become increasingly more complicated as TypeInfo is added, etc.  I'd prefer to just drop it and let the user call gc_extend() if he wants to resize memory in place.  This would require allowing gc_extend() to be used on sub-page sized blocks, but this seems reasonable anyway.  If I have a 150 byte array in a 256 byte block I should be allowed to extend it to 256 bytes.  Doing so is basically a no-op, but it frees the user from having to query the block size to determine how to handle an array append operation, for example.
>>>
>>> Finally, I really want to change the APPENDABLE bit to NO_APPEND/STATIC/SINGLE/whatever since the default (zero value) behavior should be that an allocated block is not an array.
>>>
>>> Thoughts?
>>> _______________________________________________
>>> D-runtime mailing list
>>> D-runtime@puremagic.com
>>> http://lists.puremagic.com/mailman/listinfo/d-runtime
>>
>> _______________________________________________
>> D-runtime mailing list
>> D-runtime@puremagic.com
>> http://lists.puremagic.com/mailman/listinfo/d-runtime
>
> _______________________________________________
> D-runtime mailing list
> D-runtime@puremagic.com
> http://lists.puremagic.com/mailman/listinfo/d-runtime
_______________________________________________
D-runtime mailing list
D-runtime@puremagic.com
http://lists.puremagic.com/mailman/listinfo/d-runtime