YJIT: Avoid identity-based known-class guards for IO objects (#7911)
`IO#reopen` is very special in that it is able to change the class and singleton class of IO instances. In its presence, it is not correct to assume that IO instances has a stable class/singleton class and guard by comparing identity.
This commit is contained in:
parent
7577c101ed
commit
2b54c135ff
Notes:
git
2023-06-06 14:21:49 +00:00
Merged-By: maximecb <maximecb@ruby-lang.org>
@ -1277,6 +1277,18 @@ class TestYJIT < Test::Unit::TestCase
|
|||||||
RUBY
|
RUBY
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_io_reopen_clobbering_singleton_class
|
||||||
|
assert_compiles(<<~RUBY, result: [:ok, :ok])
|
||||||
|
def $stderr.to_i = :i
|
||||||
|
|
||||||
|
def test = $stderr.to_i
|
||||||
|
|
||||||
|
[test, test]
|
||||||
|
$stderr.reopen($stderr.dup)
|
||||||
|
[test, test].map { :ok unless _1 == :i }
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def code_gc_helpers
|
def code_gc_helpers
|
||||||
|
@ -165,6 +165,7 @@ fn main() {
|
|||||||
.allowlist_var("rb_cTrueClass")
|
.allowlist_var("rb_cTrueClass")
|
||||||
.allowlist_var("rb_cFalseClass")
|
.allowlist_var("rb_cFalseClass")
|
||||||
.allowlist_var("rb_cInteger")
|
.allowlist_var("rb_cInteger")
|
||||||
|
.allowlist_var("rb_cIO")
|
||||||
.allowlist_var("rb_cSymbol")
|
.allowlist_var("rb_cSymbol")
|
||||||
.allowlist_var("rb_cFloat")
|
.allowlist_var("rb_cFloat")
|
||||||
.allowlist_var("rb_cString")
|
.allowlist_var("rb_cString")
|
||||||
|
@ -3871,6 +3871,7 @@ fn jit_guard_known_klass(
|
|||||||
} else if unsafe {
|
} else if unsafe {
|
||||||
FL_TEST(known_klass, VALUE(RUBY_FL_SINGLETON as usize)) != VALUE(0)
|
FL_TEST(known_klass, VALUE(RUBY_FL_SINGLETON as usize)) != VALUE(0)
|
||||||
&& sample_instance == rb_class_attached_object(known_klass)
|
&& sample_instance == rb_class_attached_object(known_klass)
|
||||||
|
&& !rb_obj_is_kind_of(sample_instance, rb_cIO).test()
|
||||||
} {
|
} {
|
||||||
// Singleton classes are attached to one specific object, so we can
|
// Singleton classes are attached to one specific object, so we can
|
||||||
// avoid one memory access (and potentially the is_heap check) by
|
// avoid one memory access (and potentially the is_heap check) by
|
||||||
@ -3882,6 +3883,8 @@ fn jit_guard_known_klass(
|
|||||||
// that its singleton class is empty, so we can't avoid the memory
|
// that its singleton class is empty, so we can't avoid the memory
|
||||||
// access. As an example, `Object.new.singleton_class` is an object in
|
// access. As an example, `Object.new.singleton_class` is an object in
|
||||||
// this situation.
|
// this situation.
|
||||||
|
// Also, guarding by identity is incorrect for IO objects because
|
||||||
|
// IO#reopen can be used to change the class and singleton class of IO objects!
|
||||||
asm.comment("guard known object with singleton class");
|
asm.comment("guard known object with singleton class");
|
||||||
asm.cmp(obj_opnd, sample_instance.into());
|
asm.cmp(obj_opnd, sample_instance.into());
|
||||||
jit_chain_guard(JCC_JNE, jit, asm, ocb, max_chain_depth, counter);
|
jit_chain_guard(JCC_JNE, jit, asm, ocb, max_chain_depth, counter);
|
||||||
|
@ -1083,6 +1083,7 @@ extern "C" {
|
|||||||
pub static mut rb_cFalseClass: VALUE;
|
pub static mut rb_cFalseClass: VALUE;
|
||||||
pub static mut rb_cFloat: VALUE;
|
pub static mut rb_cFloat: VALUE;
|
||||||
pub static mut rb_cHash: VALUE;
|
pub static mut rb_cHash: VALUE;
|
||||||
|
pub static mut rb_cIO: VALUE;
|
||||||
pub static mut rb_cInteger: VALUE;
|
pub static mut rb_cInteger: VALUE;
|
||||||
pub static mut rb_cModule: VALUE;
|
pub static mut rb_cModule: VALUE;
|
||||||
pub static mut rb_cNilClass: VALUE;
|
pub static mut rb_cNilClass: VALUE;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user