зеркало из https://github.com/github/ruby.git
YJIT: Fastpath for Module#name (#11819)
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:
Родитель
cb19dfca2c
Коммит
ded078c2c4
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче