DIP 1014:Hooking D's struct move semantics--Community Review Round 1

Shachar Shemesh shachar at weka.io
Thu May 17 12:36:29 UTC 2018


I'm not sure I follow all of your comments.

For the rest my comments, let's assume that the compiler may assume that 
__move_post_blt is a no-op if hasElaborateMove returns false.

On 17/05/18 14:33, kinke wrote:
>> 3. When deciding to move a struct instance, the compiler MUST emit a 
>> call to the struct's __move_post_blt after blitting the instance and 
>> before releasing the memory containing the old instance. 
>> __move_post_blt MUST receive references to both the pre- and post-move 
>> instances.
> 
> This implies that such structs must not be considered PODs, i.e., cannot 
> be passed in registers and must be passed on the stack.

I'm not familiar with passing structs in registers. I am familiar with 
passing pointer to the structs in registers, which should not be 
affected by this.

If actual (I'm assuming short) structs can be passed in registers, then, 
yes, structs with elaborate move are not PoDs.

> It also means 
> that the compiler will have to insert a __move_post_blt call right 
> before the call (as the callee has no idea about the old address),

Again, as far as I know, structs are not copied when passed as 
arguments. They are allocated on the caller's stack and a reference is 
passed to the callee. If that's the case, no move (of any kind) is done.

I might be missing something. Can you write a code snippet to which you 
are referring?

> after 
> blitting the arg to the callee params stack; this may be tricky to 
> implement for LDC, as that last blit is implicit in LLVM IR (LLVM byval 
> attribute).

And yet, C++ clang managed to do it in classes with && constructors.

> As a side note, when passing a postblit-struct lvalue arg by value,

Just to be clear, are we talking about passing by reference an instance 
of a struct that has postblit?

> the 
> compiler first copies the lvalue


> to a temporary on the caller's stack, 
> incl. postblit call, and then moves that copy to the callee. So this 
> requires either a postblit+postmove combo on the caller side before the 
> actual call, or a single postblit call for the final address (callee's 
> param).

Again, that does not align with my familiarity of the ABI. If I do:

struct S {
   ...

   this(this) {
     // some code
   }

   void opPostMove(ref S new, const ref S old) {
     // some code
   }
}

void func1(ref S arg) {
}

void func2(S arg) {
}


As far as I know the ABI, in func1, a pointer to S is passed. In func2, 
a pointer to caller stack allocate instance is passed, and the original 
is copied in. It sounds to me like you are talking about the case of:

S s;

func2(s);

in which case you need to copy s to a temporary, and then pass a pointer 
to that temporary to func2. I don't see where a move enters here.

However, if a move does enter here (and one is necessary if, for 
example, func2's frame needs to be dynamically allocated because an 
escaping delegate references it), then, yes, an opPostMove will also 
need to be called.

Again, if hasElaborateMove returns false, then no change from current 
behavior is needed.

Shachar


More information about the Digitalmars-d mailing list