Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Discussion: Pin Ruby values to the stack #101

Open
ekroon opened this issue Feb 9, 2024 · 5 comments
Open

Discussion: Pin Ruby values to the stack #101

ekroon opened this issue Feb 9, 2024 · 5 comments

Comments

@ekroon
Copy link

ekroon commented Feb 9, 2024

I was wondering if you considered stack pinning for arguments as an alternative solution for ensuring Ruby values are not removed from the stack?

I am trying to prototype it a bit and I am not sure this is possible without breaking existing code, but it seems like something that would be helpful?

Maybe you tried / considered and found good reasons to not do this?

@ekroon
Copy link
Author

ekroon commented Feb 12, 2024

@matsadler
Copy link
Owner

I've not thought about this in a while, but I think this is the chain of reasoning I had for not trying this out:

There the Pin type, but only tells you that some data has a stable address, it doesn't tell you if that address is on the stack. There's nothing in the type system that can tell you a value is on the stack. You could do something similar to say NonZeroI64, where there's a runtime check on creating the value, and then from there on you can rely on the type system. I don't know if it's possible to runtime assert a value is on the stack, so that leaves the programmer just promising it is, which is the same situation we're in now, but the code is uglier (Pin<Something> can be self, but if we have to use our own type then we can't use methods) and more complicated. It also might lead people down the path of thinking if they pin the value to the stack just before calling a method on it then they are safe, when in fact the value needs to have been pinned from the moment it was created.

It's possible I missed something, or there's another approach that'd work.


I do have in the back of my mind a way to, behind the scenes, keep values on the stack as part of the automatic type conversion when binding Rust functions to Ruby methods. So that you could bind functions taking &str, and borrow the Ruby string. But I've not gotten as far as prototyping it so I'm not sure if it's even possible.

@ekroon
Copy link
Author

ekroon commented Feb 13, 2024

You could do something similar to say NonZeroI64, where there's a runtime check on creating the value, and then from there on you can rely on the type system. I don't know if it's possible to runtime assert a value is on the stack ...

There are ways to check if a value is on the stack, but that seems more like something that can be provided as a verification step, as I can imagine this would create a decent amount of overhead.

@ianks
Copy link
Contributor

ianks commented Feb 15, 2024

The best I've come up with is to have something like a GcGuardedValue<'a> that calls rb_gc_guard! in the Drop impl.

My memory is a little fuzzy, but when I did this a long time ago this prevented LLVM from optimizing values off of the stack. However, requires that:

  1. The inner Value type is !Copy
  2. Imposes lifetimes on the Value

This kills the ergonomics of the said library, and IMO is not worth the trade-off. Maybe there's another way with Pin but I imagine the above 2 constraints would be necessary. Would be interested to hear if someone comes up with something else.

@yfractal
Copy link

I think we can keep a reference on the Ruby side to avoid this.

Here is an example:


class RubyStore
  def insert(key, val)
    @export_table << key
    @export_table << val
    insert_inner(key, val)
  end
end

The insert_inner inserts the key and val to a Rust struct which is wrapped to the RubyStore object. To avoid GC, the insert inerts the key and val in a local variable.

But this is not enough, as the objects can be moved during GC, so we need to pin those objects. And Fiddle::Pinned can achieve.

But I'm not sure if there is a better solution.

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

No branches or pull requests

5 participants
@matsadler @ekroon @ianks @yfractal and others