Skip to content

Allow lambdas that don't access self to be made shareable#12567

Open
tenderlove wants to merge 1 commit intoruby:masterfrom
tenderlove:allow-self-in-lambda
Open

Allow lambdas that don't access self to be made shareable#12567
tenderlove wants to merge 1 commit intoruby:masterfrom
tenderlove:allow-self-in-lambda

Conversation

@tenderlove
Copy link
Copy Markdown
Member

@tenderlove tenderlove commented Jan 13, 2025

This commit allows lambdas that don't access self to be "made shareable" regardless of the shareability of self.

For example, the following code used to produce a lambda that was not shareable:

class Foo
  def make_block; lambda { 1234 }; end
end

Ractor.make_shareable(Foo.new.make_block) # exception

This lambda was not allowed to be shareable because it could possibly access self which is an unfrozen instance of Foo. However, we know by looking at the code that it doesn't access the instance of Foo, so I think we should lift this restriction.

Upon calling make_shareable, this change scans the instructions of the block looking for particular instructions that access self. If it sees any of those instructions, then we use the default behavior (checking sharability of self). If we don't see those instructions, then we'll allow the lambda to be shareable.

For example, this is shareable:

def make_block
  foo = 123
  lambda { foo }
end

But these are not shareable:

def make_block
  lambda { @foo }
end
def make_block
  lambda { @foo = 1 }
end
def make_block
  lambda { eval("123") }
end

[Feature #21033]

@tenderlove tenderlove force-pushed the allow-self-in-lambda branch 2 times, most recently from af32eb4 to 5b1d8af Compare January 13, 2025 23:33
This commit allows lambdas that don't access self to be "made shareable"
regardless of the shareability of self.

For example, the following code used to produce a lambda that was not
shareable:

```ruby
class Foo
  def make_block; lambda { 1234 }; end
end

Ractor.make_shareable(Foo.new.make_block) # exception
```

This lambda was not allowed to be shareable because it could possibly
access `self` which is an unfrozen instance of `Foo`.  However, we know
by looking at the code that it doesn't access the instance of `Foo`, so
I think we should lift this restriction.

Upon calling `make_shareable`, this change scans the instructions of the
block looking for particular instructions that access `self`. If it
sees any of those instructions, then we use the default behavior
(checking sharability of `self`). If we don't see those instructions,
then we'll allow the lambda to be shareable.

For example, this is shareable:

```ruby
def make_block
  foo = 123
  lambda { foo }
end
```

But these are not shareable:

```ruby
def make_block
  lambda { @foo }
end
```

```ruby
def make_block
  lambda { @foo = 1 }
end
```

```ruby
def make_block
  lambda { eval("123") }
end
```

[Feature #21033]
@tenderlove tenderlove force-pushed the allow-self-in-lambda branch from 5b1d8af to fd9d359 Compare January 14, 2025 00:21
Comment thread iseq.c

// Returns a boolean indicating whether or not the iseq accesses self.
bool
rb_vm_iseq_reads_self(const rb_iseq_t *iseq)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Doesn't this name look like a predicate very much?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yes, it does. Should I add a _p, or?

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.

2 participants