summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaxime Chevalier-Boisvert <maxime.chevalierboisvert@shopify.com>2022-12-09 17:12:15 -0500
committerGitHub <noreply@github.com>2022-12-09 14:12:15 -0800
commitdaa893db412c6ae814d0291b4ac6fc62a466d394 (patch)
tree055ea7d05c1b94be296bcb31bf03e28f14d5d885
parent1c057cfc2fd84369a2ebff048c4a5fdf5fa08fff (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.rb23
-rw-r--r--vm_insnhelper.c6
-rw-r--r--yjit/src/codegen.rs36
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),