Skip to content

Conversation

@anuraaga
Copy link
Contributor

@anuraaga anuraaga commented Jan 30, 2023

In #3336, SetFinalizer was moved to common code out of GC implementations. This prevents custom-gc from trying to implement finalizers (I'd like to). There is a bit of copy-paste among GC implementations because of it, but especially with gc_blocks it's less than it could have been.

At the same time, this reimplements KeepAlive in the same way as Go - while the Go document does make a big deal about finalizers, close reading shows ensures that the object is not freed, which can be important with unsafe code. I don't think KeepAlive has a strong relation to SetFinalizer as is currently documented. In tinygo wasi's case, I believe this specifically means that the shadow stack slot for a variable is not reused by a different one until the call to KeepAlive (for non-wasi, same thing but registers?). However, I need help in knowing whether the The compiler cannot see that alwaysFalse is always false, note is valid for LLVM as well - intuitively for me, just noinline would be enough to ensure the variable is kept alive for the function call.

// The compiler cannot see that alwaysFalse is always false,
// so it emits the test and keeps the call, giving the desired
// escape analysis result. The test is cheaper than the call.
var alwaysFalse bool
Copy link
Contributor Author

@anuraaga anuraaga Jan 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Go, the variable is named cgoAlwaysFalse but I think this was just to reuse the same variable after the fact for something unrelated to cgo.

https://github.com/golang/go/blob/master/src/runtime/mfinal.go#L515

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not convinced the new LTO logic will think alwaysFalse is potentially not always false. I think we need something else here that we can ensure at the compiler level.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about just noinline being enough? If it seems so I could remove this stuff to prevent confusion.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Went ahead and removed down to just adding go:noinline, verifying it actually does keepalive is probably quite tricky but in the meantime it can be attempted along with finalizers in custom GC.

@anuraaga
Copy link
Contributor Author

BTW I could implement SetFinalizer with bdwgc here, in case it helps to see what it may look like.

https://github.com/corazawaf/coraza-proxy-wasm/compare/main...anuraaga:setfinalizer?expand=1

Only limitation is finalizers must be func(interface{}) since I think I would need reflect implemented to be able to support arbitrary funcs.

@anuraaga
Copy link
Contributor Author

anuraaga commented Feb 7, 2023

@dgryski Any other thoughts on this? Thanks!

@dgryski
Copy link
Member

dgryski commented Feb 7, 2023

My only concern is if "no inline" really is enough to convince tinygo/llvm to keep allocations alive. We might need direct compiler support.

/Cc @aykevl

@anuraaga
Copy link
Contributor Author

anuraaga commented Feb 7, 2023

Not sure how hard that is, but assuming this PR doesn't make anything particularly worse, hopefully it's still possible to continue to fix forward. Mainly hoping to be able to implement a full custom GC for 0.27.0 including finalizer :)

Copy link
Member

@dgryski dgryski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough.
LGTM

@anuraaga
Copy link
Contributor Author

anuraaga commented Feb 9, 2023

Saw 0.27.0 update merge to release branch - just curious if this could get in for 0.27.0. Otherwise finalizer would have to wait until 0.28, not the end of the world but figured doesn't hurt to check.

@dgryski
Copy link
Member

dgryski commented Feb 9, 2023

No complaints from my end to get this into 0.27.

@deadprogram
Copy link
Member

@aykevl any other feedback before I squash/merge?

Copy link
Member

@aykevl aykevl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The SetFinalizer parts seem fine by me. But KeepAlive is still unimplemented with this PR, see my comment below.

Comment on lines 91 to 94
//go:noinline
func KeepAlive(x interface{}) {
// Unimplemented. Only required with SetFinalizer().
}

func SetFinalizer(obj interface{}, finalizer interface{}) {
// Unimplemented.
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

//go:noinline doesn't do anything here, except avoid calling a no-op function. Most importantly, this does nothing to keep an object alive: LLVM will happily remove the x parameter because it is not used.

I think the only reliable way to implement this is either by using a volatile operation, or by calling an assembly stub (that simply returns).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the hint, I went ahead and removed the inline and added a TODO based on it. Would like to dig into it in a followup

@aykevl aykevl merged commit f6df276 into tinygo-org:dev Feb 16, 2023
@aykevl
Copy link
Member

aykevl commented Feb 16, 2023

Thank you! I'll take a look at implementing SetFinalizer KeepAlive.
(The Windows build failed but I'm 99% sure that's not because of a bug in this PR so I merged it anyway - also, I can't see why this would fail on Windows only).

@aykevl
Copy link
Member

aykevl commented Feb 17, 2023

Implemented KeepAlive: #3455

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants