@@ -288,10 +288,8 @@ pub fn init() -> Annotations {
288288 annotate_builtin ! ( rb_mKernel, "frozen?" , types:: BoolExact ) ;
289289 annotate_builtin ! ( rb_cSymbol, "name" , types:: StringExact ) ;
290290 annotate_builtin ! ( rb_cSymbol, "to_s" , types:: StringExact ) ;
291- // TOOD(max): Turn this into a load/compare. Will need to side-exit or do the full call if
292- // ENC_CODERANGE_UNKNOWN.
293- annotate_builtin ! ( rb_cString, "ascii_only?" , types:: BoolExact , no_gc, leaf) ;
294- annotate_builtin ! ( rb_cString, "valid_encoding?" , types:: BoolExact , no_gc, leaf) ;
291+ annotate_builtin ! ( rb_cString, "ascii_only?" , inline_string_ascii_only_p, types:: BoolExact , no_gc, leaf) ;
292+ annotate_builtin ! ( rb_cString, "valid_encoding?" , inline_string_valid_encoding_p, types:: BoolExact , no_gc, leaf) ;
295293
296294 // Array iteration builtins (used in with_jit Array#each, map, select, find)
297295 builtin_funcs. insert ( rb_jit_fixnum_inc as * mut c_void , FnProperties { inline : inline_fixnum_inc, return_type : types:: Fixnum , ..Default :: default ( ) } ) ;
@@ -552,6 +550,36 @@ fn inline_string_empty_p(fun: &mut hir::Function, block: hir::BlockId, recv: hir
552550 Some ( result)
553551}
554552
553+ // Load self's cached coderange (flags & MASK), guarding it's been computed
554+ // (UNKNOWN is 0, so side-exit there and let the builtin scan the string).
555+ fn guard_string_coderange ( fun : & mut hir:: Function , block : hir:: BlockId , args : & [ hir:: InsnId ] , state : hir:: InsnId ) -> Option < hir:: InsnId > {
556+ use crate :: hir:: SideExitReason ;
557+ let & [ recv] = args else { return None ; } ;
558+ if !fun. likely_a ( recv, types:: String , state) { return None ; }
559+ let recv = fun. coerce_to ( block, recv, types:: String , state) ;
560+ let flags = fun. load_rbasic_flags ( block, recv) ;
561+ let mask = fun. push_insn ( block, hir:: Insn :: Const { val : hir:: Const :: CUInt64 ( RUBY_ENC_CODERANGE_MASK . into ( ) ) } ) ;
562+ let cr = fun. push_insn ( block, hir:: Insn :: IntAnd { left : flags, right : mask } ) ;
563+ let min_known = fun. push_insn ( block, hir:: Insn :: Const { val : hir:: Const :: CInt64 ( RUBY_ENC_CODERANGE_7BIT . into ( ) ) } ) ;
564+ Some ( fun. push_insn ( block, hir:: Insn :: GuardGreaterEq { left : cr, right : min_known, reason : SideExitReason :: GuardGreaterEq , state } ) )
565+ }
566+
567+ // Inlines String#ascii_only? (rb_str_is_ascii_only_p): coderange == 7BIT.
568+ fn inline_string_ascii_only_p ( fun : & mut hir:: Function , block : hir:: BlockId , _recv : hir:: InsnId , args : & [ hir:: InsnId ] , state : hir:: InsnId ) -> Option < hir:: InsnId > {
569+ let cr = guard_string_coderange ( fun, block, args, state) ?;
570+ let seven_bit = fun. push_insn ( block, hir:: Insn :: Const { val : hir:: Const :: CInt64 ( RUBY_ENC_CODERANGE_7BIT . into ( ) ) } ) ;
571+ let is_7bit = fun. push_insn ( block, hir:: Insn :: IsBitEqual { left : cr, right : seven_bit } ) ;
572+ Some ( fun. push_insn ( block, hir:: Insn :: BoxBool { val : is_7bit } ) )
573+ }
574+
575+ // Inlines String#valid_encoding? (rb_str_valid_encoding_p): coderange != BROKEN.
576+ fn inline_string_valid_encoding_p ( fun : & mut hir:: Function , block : hir:: BlockId , _recv : hir:: InsnId , args : & [ hir:: InsnId ] , state : hir:: InsnId ) -> Option < hir:: InsnId > {
577+ let cr = guard_string_coderange ( fun, block, args, state) ?;
578+ let broken = fun. push_insn ( block, hir:: Insn :: Const { val : hir:: Const :: CInt64 ( RUBY_ENC_CODERANGE_BROKEN . into ( ) ) } ) ;
579+ let is_valid = fun. push_insn ( block, hir:: Insn :: IsBitNotEqual { left : cr, right : broken } ) ;
580+ Some ( fun. push_insn ( block, hir:: Insn :: BoxBool { val : is_valid } ) )
581+ }
582+
555583fn inline_string_append ( fun : & mut hir:: Function , block : hir:: BlockId , recv : hir:: InsnId , args : & [ hir:: InsnId ] , state : hir:: InsnId ) -> Option < hir:: InsnId > {
556584 let & [ other] = args else { return None ; } ;
557585 // Inline only StringExact << String, which matches original type check from
0 commit comments