diff options
| author | Maxime Chevalier-Boisvert <maxime.chevalierboisvert@shopify.com> | 2022-12-09 17:12:15 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-12-09 14:12:15 -0800 |
| commit | daa893db412c6ae814d0291b4ac6fc62a466d394 (patch) | |
| tree | 055ea7d05c1b94be296bcb31bf03e28f14d5d885 | |
| parent | 1c057cfc2fd84369a2ebff048c4a5fdf5fa08fff (diff) | |
YJIT: implement `getconstant` YARV instruction (#6884)
* YJIT: implement getconstant YARV instruction
* Constant id is not a pointer
* Stack operands must be read after jit_prepare_routine_call
Co-authored-by: Takashi Kokubun <takashikkbn@gmail.com>
Notes
Notes:
Merged-By: k0kubun <takashikkbn@gmail.com>
| -rw-r--r-- | test/ruby/test_yjit.rb | 23 | ||||
| -rw-r--r-- | vm_insnhelper.c | 6 | ||||
| -rw-r--r-- | yjit/src/codegen.rs | 36 |
3 files changed, 65 insertions, 0 deletions
diff --git a/test/ruby/test_yjit.rb b/test/ruby/test_yjit.rb index 1020257580..3a5792cab4 100644 --- a/test/ruby/test_yjit.rb +++ b/test/ruby/test_yjit.rb @@ -389,6 +389,29 @@ class TestYJIT < Test::Unit::TestCase assert_compiles("'foo' =~ /(o)./; $2", insns: %i[getspecial], result: nil) end + def test_compile_getconstant + assert_compiles(<<~RUBY, insns: %i[getconstant], result: [], call_threshold: 1) + def get_argv(klass) + klass::ARGV + end + + get_argv(Object) + RUBY + end + + def test_compile_getconstant_with_sp_offset + assert_compiles(<<~RUBY, insns: %i[getconstant], result: 2, call_threshold: 1) + class Foo + Bar = 1 + end + + 2.times do + s = Foo # this opt_getconstant_path needs warmup, so 2.times is needed + Class.new(Foo).const_set(:Bar, s::Bar) + end + RUBY + end + def test_compile_opt_getconstant_path assert_compiles(<<~RUBY, insns: %i[opt_getconstant_path], result: 123, call_threshold: 2) def get_foo diff --git a/vm_insnhelper.c b/vm_insnhelper.c index 265088caac..1eed081fea 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -1070,6 +1070,12 @@ vm_get_ev_const(rb_execution_context_t *ec, VALUE orig_klass, ID id, bool allow_ } } +VALUE +rb_vm_get_ev_const(rb_execution_context_t *ec, VALUE orig_klass, ID id, VALUE allow_nil) +{ + return vm_get_ev_const(ec, orig_klass, id, allow_nil == Qtrue, 0); +} + static inline VALUE vm_get_ev_const_chain(rb_execution_context_t *ec, const ID *segments) { diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs index d890775f2b..6a4026e947 100644 --- a/yjit/src/codegen.rs +++ b/yjit/src/codegen.rs @@ -6590,6 +6590,41 @@ fn gen_setclassvariable( KeepCompiling } +fn gen_getconstant( + jit: &mut JITState, + ctx: &mut Context, + asm: &mut Assembler, + _ocb: &mut OutlinedCb, +) -> CodegenStatus { + + let id = jit_get_arg(jit, 0).as_usize(); + + // vm_get_ev_const can raise exceptions. + jit_prepare_routine_call(jit, ctx, asm); + + let allow_nil_opnd = ctx.stack_pop(1); + let klass_opnd = ctx.stack_pop(1); + + extern "C" { + fn rb_vm_get_ev_const(ec: EcPtr, klass: VALUE, id: ID, allow_nil: VALUE) -> VALUE; + } + + let val_opnd = asm.ccall( + rb_vm_get_ev_const as *const u8, + vec![ + EC, + klass_opnd, + id.into(), + allow_nil_opnd + ], + ); + + let top = ctx.stack_push(Type::Unknown); + asm.mov(top, val_opnd); + + KeepCompiling +} + fn gen_opt_getconstant_path( jit: &mut JITState, ctx: &mut Context, @@ -6993,6 +7028,7 @@ fn get_gen_fn(opcode: VALUE) -> Option<InsnGenFn> { YARVINSN_opt_size => Some(gen_opt_size), YARVINSN_opt_length => Some(gen_opt_length), YARVINSN_opt_regexpmatch2 => Some(gen_opt_regexpmatch2), + YARVINSN_getconstant => Some(gen_getconstant), YARVINSN_opt_getconstant_path => Some(gen_opt_getconstant_path), YARVINSN_invokebuiltin => Some(gen_invokebuiltin), YARVINSN_opt_invokebuiltin_delegate => Some(gen_opt_invokebuiltin_delegate), |
