Feature #21033 ยป 0001-Allow-lambdas-that-don-t-access-self-to-be-made-shar.patch
| 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);
|
||