1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

Implement invokebuiltin

This commit is contained in:
John Hawthorn 2021-07-08 23:33:55 -07:00 committed by Alan Wu
parent 6055078b24
commit 9951a9a8ec
3 changed files with 60 additions and 1 deletions

View file

@ -1210,6 +1210,18 @@ assert_equal 'foo123', %q{
make_str("foo", 123)
}
# test invokebuiltin as used in struct assignment
assert_equal '123', %q{
def foo(obj)
obj.foo = 123
end
struct = Struct.new(:foo)
obj = struct.new
foo(obj)
foo(obj)
}
# test invokebuiltin_delegate as used inside Dir.open
assert_equal '.', %q{
def foo(path)

View file

@ -310,6 +310,19 @@ class TestYJIT < Test::Unit::TestCase
RUBY
end
def test_invokebuiltin
assert_compiles(<<~RUBY)
def foo(obj)
obj.foo = 123
obj.bar = 123
end
Foo = Struct.new(:foo, :bar)
foo(Foo.new(123))
foo(Foo.new(123))
RUBY
end
def test_super_iseq
assert_compiles(<<~'RUBY', insns: %i[invokesuper opt_plus opt_mult], result: 15)
class A

View file

@ -4136,6 +4136,39 @@ gen_getblockparamproxy(jitstate_t *jit, ctx_t *ctx)
return YJIT_KEEP_COMPILING;
}
static codegen_status_t
gen_invokebuiltin(jitstate_t *jit, ctx_t *ctx)
{
const struct rb_builtin_function *bf = (struct rb_builtin_function *)jit_get_arg(jit, 0);
if (bf->argc + 2 > NUM_C_ARG_REGS) {
return YJIT_CANT_COMPILE;
}
// If the calls don't allocate, do they need up to date PC, SP?
jit_prepare_routine_call(jit, ctx, REG0);
// Call the builtin func (ec, recv, arg1, arg2, ...)
mov(cb, C_ARG_REGS[0], REG_EC);
mov(cb, C_ARG_REGS[1], member_opnd(REG_CFP, rb_control_frame_t, self));
// Copy arguments from locals
for (int32_t i = 0; i < bf->argc; i++) {
x86opnd_t stack_opnd = ctx_stack_opnd(ctx, bf->argc - i - 1);
x86opnd_t c_arg_reg = C_ARG_REGS[2 + i];
mov(cb, c_arg_reg, stack_opnd);
}
call_ptr(cb, REG0, (void *)bf->func_ptr);
// Push the return value
ctx_stack_pop(ctx, bf->argc);
x86opnd_t stack_ret = ctx_stack_push(ctx, TYPE_UNKNOWN);
mov(cb, stack_ret, RAX);
return YJIT_KEEP_COMPILING;
}
// opt_invokebuiltin_delegate calls a builtin function, like
// invokebuiltin does, but instead of taking arguments from the top of the
// stack uses the argument locals (and self) from the current method.
@ -4145,7 +4178,7 @@ gen_opt_invokebuiltin_delegate(jitstate_t *jit, ctx_t *ctx)
const struct rb_builtin_function *bf = (struct rb_builtin_function *)jit_get_arg(jit, 0);
int32_t start_index = (int32_t)jit_get_arg(jit, 1);
if (bf->argc + 2 >= NUM_C_ARG_REGS) {
if (bf->argc + 2 > NUM_C_ARG_REGS) {
return YJIT_CANT_COMPILE;
}
@ -4387,6 +4420,7 @@ yjit_init_codegen(void)
yjit_reg_op(BIN(opt_length), gen_opt_length);
yjit_reg_op(BIN(opt_regexpmatch2), gen_opt_regexpmatch2);
yjit_reg_op(BIN(opt_getinlinecache), gen_opt_getinlinecache);
yjit_reg_op(BIN(invokebuiltin), gen_invokebuiltin);
yjit_reg_op(BIN(opt_invokebuiltin_delegate), gen_opt_invokebuiltin_delegate);
yjit_reg_op(BIN(opt_invokebuiltin_delegate_leave), gen_opt_invokebuiltin_delegate);
yjit_reg_op(BIN(opt_case_dispatch), gen_opt_case_dispatch);