summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bootstraptest/test_yjit.rb14
-rw-r--r--yjit/src/codegen.rs26
-rw-r--r--yjit/src/core.rs6
3 files changed, 42 insertions, 4 deletions
diff --git a/bootstraptest/test_yjit.rb b/bootstraptest/test_yjit.rb
index ae67c91a76..31bb626690 100644
--- a/bootstraptest/test_yjit.rb
+++ b/bootstraptest/test_yjit.rb
@@ -4830,6 +4830,20 @@ assert_equal "abc", %q{
str
}
+# test --yjit-verify-ctx for arrays with a singleton class
+assert_equal "ok", %q{
+ class Array
+ def foo
+ self.singleton_class.define_method(:first) { :ok }
+ first
+ end
+ end
+
+ def test = [].foo
+
+ test
+}
+
assert_equal '["raised", "Module", "Object"]', %q{
def foo(obj)
obj.superclass.name
diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs
index a5fc3a10a1..000f9fb516 100644
--- a/yjit/src/codegen.rs
+++ b/yjit/src/codegen.rs
@@ -567,14 +567,36 @@ fn verify_ctx(jit: &JITState, ctx: &Context) {
unsafe { CStr::from_ptr(rb_obj_info(val)).to_str().unwrap() }
}
+ // Some types such as CString only assert the class field of the object
+ // when there has never been a singleton class created for objects of that class.
+ // Once there is a singleton class created they become their weaker
+ // `T*` variant, and we more objects should pass the verification.
+ fn relax_type_with_singleton_class_assumption(ty: Type) -> Type {
+ if let Type::CString | Type::CArray | Type::CHash = ty {
+ if has_singleton_class_of(ty.known_class().unwrap()) {
+ match ty {
+ Type::CString => return Type::TString,
+ Type::CArray => return Type::TArray,
+ Type::CHash => return Type::THash,
+ _ => (),
+ }
+ }
+ }
+
+ ty
+ }
+
// Only able to check types when at current insn
assert!(jit.at_current_insn());
let self_val = jit.peek_at_self();
let self_val_type = Type::from(self_val);
+ let learned_self_type = ctx.get_opnd_type(SelfOpnd);
+ let learned_self_type = relax_type_with_singleton_class_assumption(learned_self_type);
+
// Verify self operand type
- if self_val_type.diff(ctx.get_opnd_type(SelfOpnd)) == TypeDiff::Incompatible {
+ if self_val_type.diff(learned_self_type) == TypeDiff::Incompatible {
panic!(
"verify_ctx: ctx self type ({:?}) incompatible with actual value of self {}",
ctx.get_opnd_type(SelfOpnd),
@@ -587,6 +609,7 @@ fn verify_ctx(jit: &JITState, ctx: &Context) {
for i in 0..top_idx {
let learned_mapping = ctx.get_opnd_mapping(StackOpnd(i));
let learned_type = ctx.get_opnd_type(StackOpnd(i));
+ let learned_type = relax_type_with_singleton_class_assumption(learned_type);
let stack_val = jit.peek_at_stack(ctx, i as isize);
let val_type = Type::from(stack_val);
@@ -632,6 +655,7 @@ fn verify_ctx(jit: &JITState, ctx: &Context) {
let top_idx: usize = cmp::min(local_table_size as usize, MAX_TEMP_TYPES);
for i in 0..top_idx {
let learned_type = ctx.get_local_type(i);
+ let learned_type = relax_type_with_singleton_class_assumption(learned_type);
let local_val = jit.peek_at_local(i as i32);
let local_type = Type::from(local_val);
diff --git a/yjit/src/core.rs b/yjit/src/core.rs
index ceba1069e6..0302ecd536 100644
--- a/yjit/src/core.rs
+++ b/yjit/src/core.rs
@@ -53,11 +53,11 @@ pub enum Type {
ImmSymbol,
TString, // An object with the T_STRING flag set, possibly an rb_cString
- CString, // An un-subclassed string of type rb_cString (can have instance vars in some cases)
+ CString, // An object that at one point had its class field equal rb_cString (creating a singleton class changes it)
TArray, // An object with the T_ARRAY flag set, possibly an rb_cArray
- CArray, // An un-subclassed array of type rb_cArray (can have instance vars in some cases)
+ CArray, // An object that at one point had its class field equal rb_cArray (creating a singleton class changes it)
THash, // An object with the T_HASH flag set, possibly an rb_cHash
- CHash, // An un-subclassed hash of type rb_cHash (can have instance vars in some cases)
+ CHash, // An object that at one point had its class field equal rb_cHash (creating a singleton class changes it)
BlockParamProxy, // A special sentinel value indicating the block parameter should be read from
// the current surrounding cfp