Module#name shows up as a top C method callee in lobsters so probably
common enough. It's also easy to substitute thanks to rb_mod_name()
already having no GC yield points.

    klass = BasicObject
    50_000_000.times { klass.name }

    Benchmark 1: /.rubies/post/bin/ruby --yjit mod_name.rb
      Time (mean ± σ):      1.433 s ±  0.010 s    [User: 1.410 s, System: 0.010 s]
      Range (min … max):    1.421 s …  1.449 s    10 runs

    Benchmark 2: /.rubies/mstr/bin/ruby --yjit mod_name.rb
      Time (mean ± σ):      1.491 s ±  0.012 s    [User: 1.468 s, System: 0.010 s]
      Range (min … max):    1.470 s …  1.511 s    10 runs

    Summary
      /.rubies/post/bin/ruby --yjit mod_name.rb ran
        1.04 ± 0.01 times faster than /.rubies/mstr/bin/ruby --yjit mod_name.rb
This commit is contained in:
Alan Wu 2024-10-08 11:44:59 -04:00 коммит произвёл GitHub
Родитель cb19dfca2c
Коммит ded078c2c4
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
4 изменённых файлов: 33 добавлений и 0 удалений

Просмотреть файл

@ -97,6 +97,8 @@ rb_namespace_p(VALUE obj)
* to not be anonymous. <code>*permanent</code> is set to 1
* if +classpath+ has no anonymous components. There is no builtin
* Ruby level APIs that can change a permanent +classpath+.
*
* YJIT needs this function to not allocate.
*/
static VALUE
classname(VALUE klass, bool *permanent)
@ -127,6 +129,7 @@ rb_mod_name0(VALUE klass, bool *permanent)
VALUE
rb_mod_name(VALUE mod)
{
// YJIT needs this function to not allocate.
bool permanent;
return classname(mod, &permanent);
}

Просмотреть файл

@ -378,6 +378,7 @@ fn main() {
.allowlist_function("rb_attr_get")
.allowlist_function("rb_ivar_defined")
.allowlist_function("rb_ivar_get")
.allowlist_function("rb_mod_name")
// From internal/vm.h
.allowlist_var("rb_vm_insns_count")

Просмотреть файл

@ -5135,6 +5135,33 @@ fn jit_rb_mod_eqq(
return true;
}
// Substitution for rb_mod_name(). Returns the name of a module/class.
fn jit_rb_mod_name(
_jit: &mut JITState,
asm: &mut Assembler,
_ci: *const rb_callinfo,
_cme: *const rb_callable_method_entry_t,
_block: Option<BlockHandler>,
argc: i32,
_known_recv_class: Option<VALUE>,
) -> bool {
if argc != 0 {
return false;
}
asm_comment!(asm, "Module#name");
// rb_mod_name() never allocates, so no preparation needed.
let name = asm.ccall(rb_mod_name as _, vec![asm.stack_opnd(0)]);
let _ = asm.stack_pop(1); // pop self
// call-seq: mod.name -> string or nil
let ret = asm.stack_push(Type::Unknown);
asm.mov(ret, name);
true
}
// Codegen for rb_obj_equal()
// object identity comparison
fn jit_rb_obj_equal(
@ -10373,6 +10400,7 @@ pub fn yjit_reg_method_codegen_fns() {
yjit_reg_method(rb_mKernel, "eql?", jit_rb_obj_equal);
yjit_reg_method(rb_cModule, "==", jit_rb_obj_equal);
yjit_reg_method(rb_cModule, "===", jit_rb_mod_eqq);
yjit_reg_method(rb_cModule, "name", jit_rb_mod_name);
yjit_reg_method(rb_cSymbol, "==", jit_rb_obj_equal);
yjit_reg_method(rb_cSymbol, "===", jit_rb_obj_equal);
yjit_reg_method(rb_cInteger, "==", jit_rb_int_equal);

Просмотреть файл

@ -1036,6 +1036,7 @@ extern "C" {
pub fn rb_str_buf_append(dst: VALUE, src: VALUE) -> VALUE;
pub fn rb_str_dup(str_: VALUE) -> VALUE;
pub fn rb_str_intern(str_: VALUE) -> VALUE;
pub fn rb_mod_name(mod_: VALUE) -> VALUE;
pub fn rb_ivar_get(obj: VALUE, name: ID) -> VALUE;
pub fn rb_ivar_defined(obj: VALUE, name: ID) -> VALUE;
pub fn rb_attr_get(obj: VALUE, name: ID) -> VALUE;