what to do with postblit on the heap?
Steven Schveighoffer
schveiguy at yahoo.com
Tue Jun 21 04:34:24 PDT 2011
On Mon, 20 Jun 2011 21:59:49 -0400, Michel Fortin
<michel.fortin at michelf.com> wrote:
> On 2011-06-20 18:12:11 -0400, "Steven Schveighoffer"
> <schveiguy at yahoo.com> said:
>
>> On Mon, 20 Jun 2011 16:45:44 -0400, Michel Fortin
>> <michel.fortin at michelf.com> wrote:
>>
>>> My feeling is that array appending and array assignment should be
>>> considered a compiler issue first and foremost. The compiler needs to
>>> be fixed, and once that's done the runtime will need to be updated
>>> anyway to match the changes in the compiler. Your proposed fix for
>>> array assignment is a good start for when the compiler will provide
>>> the necessary info to the runtime, but applying it at this time will
>>> just fix some cases by breaking a few others: net improvement zero.
>> BTW, I now feel that your request to make a distinction between move
>> and copy is not required. The compiler currently calls the destructor
>> of temporaries, so it should also call postblit. I don't think it can
>> make the distinction between array appending and simply calling some
>> other function.
>
> Well, if
>
> a ~= S();
>
> does result in a temporary which get copied and then destroyed, why have
> move semantics at all? Move semantics are not just an optimization, they
> actually change the semantics. If you have a struct with a @disabled
> postblit, should it still be appendable?
Good question. I don't even know how the runtime could avoid calling
postblit, there is no flag saying the postblit is disabled in the typeinfo
(that I know of).
But think about it this way, if you have a function foo:
foo(S)(ref S s, S[] arr)
{
arr[0] = s;
}
Isn't this copy semantics? This is exactly how the D runtime gets the
data. The only difference is, the runtime function is allowed to accept a
temporary as a reference (not possible in a normal function).
Now, you could force move semantics, if you know the argument is an
rvalue, but I don't know enough about what postblit is used for in order
to say it's fine to use move semantics to move the struct into the heap.
The reason I say move semantics are an optimization is because:
{
S tmp;
arr ~= tmp;
}
is essentially equivalent to:
arr ~= S();
But the former is copy semantics, the latter can be considered move. It
seems like a smart compiler during optimization could rewrite the former
as the latter, unless the semantics truly are different. Which is why I'm
trying to figure out how postblit can be used ;)
>> If the issue of array assignment is fixed, do you think it's worth
>> putting the change in, and then filing a bug against the GC? I still
>> think the current cases that "work" are fundamentally broken anyways.
>
> That depends. I'm not too sure currently whether the S destructor is
> called for this code:
>
> a ~= S();
It is, I tested it. I ran this code:
struct Test
{
this(this) { writeln("copy done"); }
void opAssign(Test rhs) { writeln("assignment done"); }
~this() { writeln("destructor called"); }
}
void main()
{
Test[] tests = new Test[1];
{
// Test test;
// tests ~= test;
tests ~= Test();
}
writeln("done");
}
and saw "destructor called" in the output, no matter which option was
commented out.
> All in all, I don't think it's important enough to justify we waste
> hours debating in what order we should fix those bugs. Do what you think
> is right. If it becomes a problem or it introduces a bug here or there,
> we'll adjust, at worse that means a revert of your commit.
OK, then I'll push the change. I already filed a bug against _d_arraycopy.
>>> As for the issue that destructors aren't called for arrays on the
>>> heap, it's a serious problem. But it's also a separate problem that
>>> concerns purely the runtime, as far as I am aware of. Is there
>>> someone working on it?
>> I think we need precise scanning to get a complete solution. Another
>> option is to increase the information the array runtime stores in the
>> memory block (currently it only stores the "used" length) and then hook
>> the GC to call the dtors. This might be a quick fix that doesn't
>> require precise scanning, but it also fixes the most common case of
>> allocating a single struct or an array of structs on the heap.
>
> The GC calling the destructor doesn't require precise scanning. Although
> it's true that both problems require adding type information to memory
> blocks, beyond that requirement they're both independent. It'd be really
> nice if struct destructors were called correctly.
Yes, the more I think about it, the more this solution looks attractive.
All that is required is to flag the block as having a finalizer, store the
TypeInfo pointer somewhere, and the GC should call it.
I'll put in a bugzilla enhancement so it's not forgotten.
-Steve
More information about the Digitalmars-d
mailing list