September 23, 2021

On 9/23/21 3:40 PM, H. S. Teoh wrote:

>

On Thu, Sep 23, 2021 at 03:22:26PM -0400, Steven Schveighoffer via Digitalmars-d wrote:

>

Hm... it cancels all optimizations. No inlining either, or removal of
the empty function. So the penalty is you are going to call the dtor
(with an actual call instruction).

I guess that's better than nothing.
[...]

All of this long discussion begs the question: why not just use
GC.addRoot() and call it a day?

You can. But wouldn't you prefer just pushing something on the stack?

I don't know, it sort of bugs me and fascinates me that there isn't a way to do this easily. The stack is pretty much free to use, adding something to some allocated tree inside the GC (and then later removing it) isn't.

The use cases are exceedingly small though...

-Steve

September 23, 2021

On Thursday, 23 September 2021 at 19:54:56 UTC, Steven Schveighoffer wrote:

>

You can. But wouldn't you prefer just pushing something on the stack?

I don't know, it sort of bugs me and fascinates me that there isn't a way to do this easily. The stack is pretty much free to use, adding something to some allocated tree inside the GC (and then later removing it) isn't.

The use cases are exceedingly small though...

-Steve

I would expect this to work on all platforms and compilers...
scope c = new C;

September 23, 2021

On 9/23/21 4:43 PM, Daniel N wrote:

>

On Thursday, 23 September 2021 at 19:54:56 UTC, Steven Schveighoffer wrote:

>

You can. But wouldn't you prefer just pushing something on the stack?

I don't know, it sort of bugs me and fascinates me that there isn't a way to do this easily. The stack is pretty much free to use, adding something to some allocated tree inside the GC (and then later removing it) isn't.

The use cases are exceedingly small though...

I would expect this to work on all platforms and compilers...
scope c = new C;

This isn't quite the same. This puts c's guts on the stack, which is much less @safe than just putting a reference on the stack.

-Steve

September 23, 2021

On Thursday, 23 September 2021 at 19:54:56 UTC, Steven Schveighoffer wrote:

>

You can. But wouldn't you prefer just pushing something on the stack?

I don't know, it sort of bugs me and fascinates me that there isn't a way to do this easily. The stack is pretty much free to use, adding something to some allocated tree inside the GC (and then later removing it) isn't.

The use cases are exceedingly small though...

-Steve

It doesn't matter where it is, stack or register. What is important is that the pointer value is retained somewhere. KeepAlive should trick the compiler to believe that KeepAlive itself is a user of the resource. How that is done in practice is another question and may vary depending on GC type.

September 24, 2021

On Tuesday, 21 September 2021 at 12:02:05 UTC, Steven Schveighoffer wrote:

>

I just thought of a possible easy and effective way to ensure the thing isn't collected early:

struct Pin(T)
{
   T t;
   @nogc nothrow pure @safe ~this() {}
   alias t this;
}

...
// usage
auto c = Pin!C(new C); // now it needs to be held until the scope ends

Another way:

struct Pin(T)
{
   T t;
   ~this()
   {
      import core.volatile;
      volatileLoad(cast(uint*)&t);
   }
}

// usage
auto c = Pin!C(new C);
September 24, 2021

On 9/23/21 5:34 PM, IGotD- wrote:

>

On Thursday, 23 September 2021 at 19:54:56 UTC, Steven Schveighoffer wrote:

>

You can. But wouldn't you prefer just pushing something on the stack?

I don't know, it sort of bugs me and fascinates me that there isn't a way to do this easily. The stack is pretty much free to use, adding something to some allocated tree inside the GC (and then later removing it) isn't.

The use cases are exceedingly small though...

It doesn't matter where it is, stack or register. What is important is that the pointer value is retained somewhere. KeepAlive should trick the compiler to believe that KeepAlive itself is a user of the resource. How that is done in practice is another question and may vary depending on GC type.

Right, the registers are scanned too. In fact, I'm pretty sure when looking at the code LDC generates when using my latest keepalive lib, it can use a non-temporary register to store the pointer, and then when it comes time to call the destructor, it puts the pointer on the stack (because destructors require a pointer).

And a register is even more performant than the stack!

-Steve

September 24, 2021

On 9/23/21 3:29 PM, Paulo Pinto wrote:

>

It should, that is also what the keep alive from C# and Go that I post earlier do.

Yes, I took a lot of inspiration from that.

>

You are supposed to use keepalive this way:

auto c = new C;
// ... lots of ongoing activities ...
keepAlive(c); // c will survive until keepAlive returns.

If you look into their source code, they then trick to trick the optimizer that keepAlive is relevant and shouldn't be taken away, thus forcing the GC to ensure that the reference isn't collected until function returns.

https://cs.opensource.google/go/go/+/refs/tags/go1.17.1:src/runtime/mfinal.go;l=473

Right, what I'd prefer is something that doesn't actually require a call or code of any kind, but the empty asm seems to require the minimum.

Note that using my keepalive library that way (just calling c.keepAlive at the end of the function) will also work.

-Steve

September 24, 2021

On Thursday, 23 September 2021 at 19:54:56 UTC, Steven Schveighoffer wrote:

>

You can. But wouldn't you prefer just pushing something on the stack?

Not really. If the optimizer can remove dead stack pushes, then program will become 2x slower instantly in addition of consuming more stack memory.

September 24, 2021

On Friday, 24 September 2021 at 15:25:55 UTC, deadalnix wrote:

>

On Thursday, 23 September 2021 at 19:54:56 UTC, Steven Schveighoffer wrote:

>

You can. But wouldn't you prefer just pushing something on the stack?

Not really. If the optimizer can remove dead stack pushes, then program will become 2x slower instantly in addition of consuming more stack memory.

Doubt it would be 2x on a modern CPU. Point stands though. LLVM and GCC both have intrinsics for GC roots so perhaps they could be used here (calling into the GC is going to be very slow anyway so keeping it's return value on the stack wouldn't matter)

September 24, 2021

On 9/24/21 11:25 AM, deadalnix wrote:

>

On Thursday, 23 September 2021 at 19:54:56 UTC, Steven Schveighoffer wrote:

>

You can. But wouldn't you prefer just pushing something on the stack?

Not really. If the optimizer can remove dead stack pushes, then program will become 2x slower instantly in addition of consuming more stack memory.

You think pushing on the stack is going be 2x slower than calling GC.addRoot?

-Steve