Dynamic array as stack and GC.BlkAttr.APPENDABLE

IgorStepanov via Digitalmars-d digitalmars-d at puremagic.com
Sat Nov 15 14:40:02 PST 2014


On Saturday, 15 November 2014 at 03:41:56 UTC, Steven 
Schveighoffer wrote:
> On 11/14/14 8:56 PM, IgorStepanov wrote:
>> On Friday, 14 November 2014 at 23:49:00 UTC, ketmar via 
>> Digitalmars-d
>> wrote:
>>> On Fri, 14 Nov 2014 23:23:17 +0000
>>> IgorStepanov via Digitalmars-d <digitalmars-d at puremagic.com> 
>>> wrote:
>>>
>>>> What does the NO_INTERIOR flag?
>>> it stops GC to acknowledge pointers inside allocated area as 
>>> anchors.
>>> i.e. if there is no pointer to the head (first address) of 
>>> allocated
>>> memory, it is assumed to be garbage.
>>>
>>> this way we have much less "false pointers", and GC not doing
>>> pointer->block conversions.
>>>
>>> for buckets we certainly has "head pointer" and can't have 
>>> pointers to
>>> bucket elements without "head pointer". so it's safe to tell 
>>> GC that it
>>> shouldn't do unnecessary work.
>>
>> In other words, if buckets array will contain only uint-s 
>> there is no
>> reason to mark buckets with NO_INTERIOR?
>
> In case ketmar's reply doesn't drive it home...
>
> NO_INTERIOR means that the GC should NOT consider pointers to a 
> block as valid references if those pointers don't point to the 
> HEAD of the block. In other words, they point to the interior.
>
> An example
>
> int * x = new int;
> *x = 5;
> byte *b = cast(byte *)x;
> b++; // b is now an interior pointer, yet x is not.
>
> If we had marked x's block as NO_INTERIOR, we are fine as long 
> as x remains. If we set x to null, there is a danger that the 
> block is collected, and now b is dangling.
>
> Now, this isn't a whole lot more efficient, you still have to 
> look up what b points at and see that it has the flag set. BUT, 
> where it DOES help is if you had some size_t somewhere on a 
> stack, that happens to be the same value as b, the GC may think 
> it's a pointer, but correctly not keep the block alive just for 
> that "false pointer". The larger the block, the more helpful 
> NO_INTERIOR is.
>
> -Steve

Thanks for explanations. I undersood that now. However I have got 
a strange bug with NO_INTERIOR.
I have the following function:
static Bucket[] newBuckets(in size_t len) @trusted pure nothrow
{
     Bucket[] ret = new Bucket[len];

     if (!__ctfe)
     {
         GC.setAttr(ret.ptr, GC.BlkAttr.NO_INTERIOR);
     }
     return ret;
}

The Bucket declaration has a two uint fields and one of those has 
a explicit initializer:

private enum uint EmptyBucket = uint.max;

static struct Bucket
{
     uint depth;
     uint index = EmptyBucket;

     @property bool occupied() const
     {
         return index != EmptyBucket;
     }
}

I call this function for creating new bucket array (in init() 
function, at first value inserting and at rehashing).
I don't create a copy, slice, I don't get a array pointer. Before 
array creating and rehashing I use buckets only for access by 
index. However I have got a error, when `index` field initializes 
with some strange value when newBuckets argument is very big. 
(buckets.length is big value). When I comment a 
GC.setAttr(ret.ptr, GC.BlkAttr.NO_INTERIOR); line, code start 
works fine.
Do I any fundamental error in this code?
May be Bucket[] ret = new Bucket[len]; ret.ptr is not base 
pointer?


More information about the Digitalmars-d mailing list