[dmd-internals] non-PODs again
Johannes Pfau
johannespfau at googlemail.com
Fri Mar 8 04:40:36 PST 2013
Am 07.03.2013 22:19, schrieb Walter Bright:
> Oops, I missed that. It's a bug in dmd.
>
OK, this explains the inconsistency between normal and varargs functions.
>> nevertheless the non-POD is passed in registers. Add a
>> __traits(isPOD, Date) test to the example, it returns false.
>>>
>>>>
>>>> I also don't understand how a copy ctor could break this.
>>>
>>> Because a copy ctor executes arbitrary code, and this just does not
>>> work in the general case if a value is in a register.
>>
>> Yes, the struct value can't be passed _to the copy constructor_ in a
>> register - but the copy ctor itself is always called with a reference
>> to the value, i.e. it's declared as
>> __copyctor(ref Date this, ref Date b)
>>
>> For all other functions I don't see why it can't be passed in a
>> register.
>>
>
> The copy constructor must have its address. Registers don't have an
> address.
Yes, registers don't have an address. But think of passing in a
registers as a "move", not as a copy and moving the value out of that
register in the callee again:
TDPL, page 249:
"First off, D objects must be relocatable, that is location-independent:
an object can be moved around memory be using raw memory move without
it's integrity being affected. [...] It is illegal to create objects
with internal pointers in D and the compiler and runtime subsystem are
free to assume observance of this rule. [...] The postblit constructor
makes copying equivalent to a move plus an optional user-defined hook
[...]. The compiler is free to not insert the call to this(this)
whenever it can prove the source of the copy will not be used after the
copying process".
So C++ would probably pass a non-POD like this:
;-0x8(%ebp) is the local value
------------
mov -0x8(%ebp),-0x4(%ebp) ;create the
copy for the callee function
lea -0x4(%ebp),%eax ;load
address of copy
call <_D1e4Date8__cpctorMxFKxS1e4DateZv> ;call copy ctor for copy
lea -0x4(%ebp),%eax ;load
address of copy
call <function> ;call function, passing a _reference_ to copy
<function>
(%eax) ;do something with object pointed to by eax
------------
And this is how it can be done when passing by value in a register
;-0x8(%ebp) is the local value
------------
mov -0x8(%ebp),-0x4(%ebp) ;create the
copy for the callee function
lea -0x4(%ebp),%eax ;load
address of copy
call <_D1e4Date8__cpctorMxFKxS1e4DateZv> ;call copy ctor for copy
mov -0x4(%ebp),%eax ;load
_value_ of copy (move copy into eax) *
call <function> ;call function, passing a _value_
<function>
mov %eax,-0x4(%ebp) ;load the
value passed in the register back onto stack
;(move copy from eax to stack) *
-0x4(%ebp) ;do something with object
------------
So why is the second example illegal? In the end in both examples we
have a valid address as the value is moved out of the register again, so
everything which can be done in the first example can be done in the
second example. I only see 2 differences between those two examples:
* The second example has two additional memory moves (or bitblits). But
it never accesses the original value again after a move, so according to
TDPL this is legal and there is no need to call the copy ctor for these
bit blits(moves).
* Because of the moves in the second example the address passed to the
copy ctor call is different from the address <function> sees. This is
why C++ can't do #2, as in C++ the address must be the same. TDPL
explicitly states that moves and changing addresses is allowed in D, so
this is not an issue.
So please explain what's illegal in this concrete example #2.
--
Johannes Pfau
More information about the dmd-internals
mailing list