Skip to content

Commit 684e84d

Browse files
XrXrmaximecb
andcommitted
Use rb_ivar_get() for general case of getivar (#17)
* Use rb_ivar_get() for general case of getivar Pretty straight forward. Buys about 1% coverage on railsbench. * Update yjit_codegen.c Co-authored-by: Maxime Chevalier-Boisvert <maximechevalierb@gmail.com>
1 parent 62c1297 commit 684e84d

File tree

2 files changed

+48
-2
lines changed

2 files changed

+48
-2
lines changed

bootstraptest/test_yjit.rb

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,33 @@ def bar(ins)
656656
[bar(ins), bar(oth)]
657657
}
658658

659+
# get ivar on object, then on hash
660+
assert_equal '[42, 100]', %q{
661+
class Hash
662+
attr_accessor :foo
663+
end
664+
665+
class A
666+
attr_reader :foo
667+
668+
def initialize
669+
@foo = 42
670+
end
671+
end
672+
673+
def use(val)
674+
val.foo
675+
end
676+
677+
678+
h = {}
679+
h.foo = 100
680+
obj = A.new
681+
682+
use(obj)
683+
[use(obj), use(h)]
684+
}
685+
659686
# get ivar on String
660687
assert_equal '[nil, nil, 42, 42]', %q{
661688
# @foo to exercise the getinstancevariable instruction

yjit_codegen.c

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -924,8 +924,27 @@ gen_get_ivar(jitstate_t *jit, ctx_t *ctx, const int max_chain_depth, VALUE compt
924924
// Eventually, we can encode whether an object is T_OBJECT or not
925925
// inside object shapes.
926926
if (rb_get_alloc_func(comptime_val_klass) != rb_class_allocate_instance) {
927-
GEN_COUNTER_INC(cb, getivar_not_object);
928-
return YJIT_CANT_COMPILE;
927+
// General case. Call rb_ivar_get(). No need to reconstruct interpreter
928+
// state since the routine never raises exceptions or allocate objects
929+
// visibile to Ruby.
930+
// VALUE rb_ivar_get(VALUE obj, ID id)
931+
ADD_COMMENT(cb, "call rb_ivar_get()");
932+
yjit_save_regs(cb);
933+
mov(cb, C_ARG_REGS[0], REG0);
934+
mov(cb, C_ARG_REGS[1], imm_opnd((int64_t)ivar_name));
935+
call_ptr(cb, REG1, (void *)rb_ivar_get);
936+
yjit_load_regs(cb);
937+
938+
if (!reg0_opnd.is_self) {
939+
(void)ctx_stack_pop(ctx, 1);
940+
}
941+
// Push the ivar on the stack
942+
x86opnd_t out_opnd = ctx_stack_push(ctx, TYPE_UNKNOWN);
943+
mov(cb, out_opnd, RAX);
944+
945+
// Jump to next instruction. This allows guard chains to share the same successor.
946+
jit_jump_to_next_insn(jit, ctx);
947+
return YJIT_END_BLOCK;
929948
}
930949
RUBY_ASSERT(BUILTIN_TYPE(comptime_receiver) == T_OBJECT); // because we checked the allocator
931950

0 commit comments

Comments
 (0)