Project

General

Profile

Feature #21033 ยป 0001-Allow-lambdas-that-don-t-access-self-to-be-made-shar.patch

tenderlovemaking (Aaron Patterson), 01/14/2025 12:01 AM

View differences:

bootstraptest/test_ractor.rb
Ractor.shareable?(pr)
}
# Ractor.make_shareable(a_proc) that doesn't access self
assert_equal 'true', %q{
class Foo
def make_block; lambda { 123 }; end
end
pr = Foo.new.make_block
Ractor.make_shareable(pr)
Ractor.shareable?(pr)
}
# Ractor.make_shareable(a_proc) should fail when accessing self
assert_equal 'true', %q{
class Foo
def make_block; lambda { self }; end
end
pr = Foo.new.make_block
begin
Ractor.make_shareable(pr)
rescue Ractor::IsolationError
true
end
}
# Ractor.make_shareable(a_proc) should fail when accessing self via method
assert_equal 'true', %q{
class Foo
def hi; end
def make_block; lambda { hi }; end
end
pr = Foo.new.make_block
begin
Ractor.make_shareable(pr)
rescue Ractor::IsolationError
true
end
}
# Ractor.make_shareable(a_proc) should fail when accessing self via eval (also a method call)
assert_equal 'true', %q{
class Foo
def make_block; lambda { eval("123") }; end
end
pr = Foo.new.make_block
begin
Ractor.make_shareable(pr)
rescue Ractor::IsolationError
true
end
}
# Ractor.make_shareable(a_proc) should fail when accessing self via local
assert_equal 'true', %q{
class Foo
def make_block
x = self
lambda { x }
end
end
pr = Foo.new.make_block
begin
Ractor.make_shareable(pr)
rescue Ractor::IsolationError
true
end
}
# Ractor.make_shareable(a_proc) should fail when accessing self via ivar get
assert_equal 'true', %q{
class Foo
def initialize; @x = 1; end
def make_block
lambda { @x }
end
end
pr = Foo.new.make_block
begin
Ractor.make_shareable(pr)
rescue Ractor::IsolationError
true
end
}
# Ractor.make_shareable(a_proc) should fail when accessing self via ivar set
assert_equal 'true', %q{
class Foo
def initialize; @x = 1; end
def make_block
lambda { @x = 456 }
end
end
pr = Foo.new.make_block
begin
Ractor.make_shareable(pr)
rescue Ractor::IsolationError
true
end
}
# Ractor.make_shareable(a_proc) should fail with a circular lambda
assert_equal 'true', %q{
class Foo
def make_block
x = lambda { x }
x
end
end
pr = Foo.new.make_block
begin
Ractor.make_shareable(pr)
rescue Ractor::IsolationError
true
end
}
# Ractor.make_shareable(a_proc) should fail with `defined?(@iv)`
assert_equal 'true', %q{
class Foo
def make_block
lambda { defined?(@foo) }
end
end
pr = Foo.new.make_block
begin
Ractor.make_shareable(pr)
rescue Ractor::IsolationError
true
end
}
# Ractor.shareable?(recursive_objects)
assert_equal '[false, false]', %q{
y = []
iseq.c
return insn;
}
// Returns a boolean indicating whether or not the iseq accesses self.
bool
rb_vm_iseq_reads_self(const rb_iseq_t *iseq)
{
unsigned int pos = 0;
while (pos < ISEQ_BODY(iseq)->iseq_size) {
int opcode = rb_vm_insn_decode(ISEQ_BODY(iseq)->iseq_encoded[pos]);
unsigned int next_pos = pos + insn_len(opcode);
if (opcode == BIN(putself) ||
opcode == BIN(getinstancevariable) ||
opcode == BIN(setinstancevariable) ||
opcode == BIN(definedivar)) {
return true;
}
pos = next_pos;
}
return false;
}
static inline int
encoded_iseq_trace_instrument(VALUE *iseq_encoded_insn, rb_event_flag_t turnon, bool remain_current_trace)
{
iseq.h
/* vm.c */
VALUE rb_iseq_local_variables(const rb_iseq_t *iseq);
bool rb_vm_iseq_reads_self(const rb_iseq_t *iseq);
attr_index_t rb_estimate_iv_count(VALUE klass, const rb_iseq_t * initialize_iseq);
vm.c
rb_proc_t *proc = (rb_proc_t *)RTYPEDDATA_DATA(self);
if (proc->block.type != block_type_iseq) rb_raise(rb_eRuntimeError, "not supported yet");
if (!rb_ractor_shareable_p(vm_block_self(&proc->block))) {
if (rb_vm_iseq_reads_self(iseq) && !rb_ractor_shareable_p(vm_block_self(&proc->block))) {
rb_raise(rb_eRactorIsolationError,
"Proc's self is not shareable: %" PRIsVALUE,
self);
    (1-1/1)