From 84205f7cb01644a2e6657eb65effe49386803055 Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Fri, 3 Nov 2023 15:15:46 +0100 Subject: [PATCH 1/2] Draft: opt_new instruction --- compile.c | 13 ++++++++++--- defs/id.def | 1 + insns.def | 35 +++++++++++++++++++++++++++++++++++ internal/object.h | 1 + object.c | 2 +- vm_insnhelper.c | 9 +++++++++ 6 files changed, 57 insertions(+), 4 deletions(-) diff --git a/compile.c b/compile.c index bad3c079fc1422..4080ec4b0dcf92 100644 --- a/compile.c +++ b/compile.c @@ -1442,7 +1442,7 @@ new_insn_body(rb_iseq_t *iseq, const NODE *const line_node, enum ruby_vminsn_typ } static const struct rb_callinfo * -new_callinfo(rb_iseq_t *iseq, ID mid, int argc, unsigned int flag, struct rb_callinfo_kwarg *kw_arg, int has_blockiseq) +new_callinfo(rb_iseq_t *iseq, ID mid, int argc, unsigned int flag, const struct rb_callinfo_kwarg *kw_arg, int has_blockiseq) { VM_ASSERT(argc >= 0); @@ -3930,8 +3930,15 @@ iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj) } if ((vm_ci_flag(ci) & VM_CALL_ARGS_BLOCKARG) == 0 && blockiseq == NULL) { - iobj->insn_id = BIN(opt_send_without_block); - iobj->operand_size = insn_len(iobj->insn_id) - 1; + switch (vm_ci_mid(ci)) { + case idNew: + iobj->insn_id = BIN(opt_new); + iobj->operands[1] = (VALUE)new_callinfo(iseq, idInitialize, vm_ci_argc(ci), vm_ci_flag(ci) | VM_CALL_FCALL, vm_ci_kwarg(ci), FALSE); + break; + default: + iobj->insn_id = BIN(opt_send_without_block); + iobj->operand_size = insn_len(iobj->insn_id) - 1; + } } } #undef SP_INSN diff --git a/defs/id.def b/defs/id.def index 2ddde7be70702a..f9912dd9110d5e 100644 --- a/defs/id.def +++ b/defs/id.def @@ -5,6 +5,7 @@ firstline, predefined = __LINE__+1, %[\ hash freeze nil? + new inspect intern object_id diff --git a/insns.def b/insns.def index b784d7c043599f..fa1f417b8dbfc9 100644 --- a/insns.def +++ b/insns.def @@ -828,6 +828,41 @@ opt_send_without_block } } +/* Invoke constructor */ +DEFINE_INSN +opt_new +(CALL_DATA cd, CALL_DATA cd_initialize) +(...) +(VALUE val) +// attr bool handles_sp = true; +// attr rb_snum_t sp_inc = sp_inc_of_sendish(cd->ci); +// attr rb_snum_t comptime_sp_inc = sp_inc_of_sendish(ci); +{ + VALUE recv = TOPN(vm_ci_argc(cd->ci)); + + val = vm_opt_new_alloc(GET_ISEQ(), recv, cd); + if (val != Qundef) { + TOPN(vm_ci_argc(cd->ci)) = val; + fprintf(stderr, "opt!\n"); + if (vm_sendish(ec, GET_CFP(), cd_initialize, VM_BLOCK_HANDLER_NONE, mexp_search_method) == Qundef) { + val = Qundef; + } + } + + if (val == Qundef) { + fprintf(stderr, "de-opt!\n"); + + VALUE bh = VM_BLOCK_HANDLER_NONE; + val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_method); + JIT_EXEC(ec, val); + + if (val == Qundef) { + RESTORE_REGS(); + NEXT_INSN(); + } + } +} + /* Convert object to string using to_s or equivalent. */ DEFINE_INSN objtostring diff --git a/internal/object.h b/internal/object.h index 58e989562a182e..9f3ed548da08ee 100644 --- a/internal/object.h +++ b/internal/object.h @@ -21,6 +21,7 @@ int rb_bool_expected(VALUE, const char *, int raise); static inline void RBASIC_CLEAR_CLASS(VALUE obj); static inline void RBASIC_SET_CLASS_RAW(VALUE obj, VALUE klass); static inline void RBASIC_SET_CLASS(VALUE obj, VALUE klass); +VALUE rb_class_alloc(VALUE klass); RUBY_SYMBOL_EXPORT_BEGIN /* object.c (export) */ diff --git a/object.c b/object.c index 73fbe78edc5fd8..4c4c08cb9d15c0 100644 --- a/object.c +++ b/object.c @@ -2063,7 +2063,7 @@ rb_class_alloc_m(VALUE klass) return class_call_alloc_func(allocator, klass); } -static VALUE +VALUE rb_class_alloc(VALUE klass) { rb_alloc_func_t allocator = class_get_alloc_func(klass); diff --git a/vm_insnhelper.c b/vm_insnhelper.c index 785dbfedec246b..9d568d924d6629 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -6114,6 +6114,15 @@ vm_opt_mod(VALUE recv, VALUE obj) } } +static VALUE +vm_opt_new_alloc(const rb_iseq_t *iseq, VALUE recv, CALL_DATA cd) +{ + if (RB_TYPE_P(recv, T_CLASS) && vm_method_cfunc_is(iseq, cd, recv, rb_class_new_instance_pass_kw)) { + return rb_class_alloc(recv); + } + return Qundef; +} + static VALUE vm_opt_neq(const rb_iseq_t *iseq, CALL_DATA cd, CALL_DATA cd_eq, VALUE recv, VALUE obj) { From 716c856c98e3a7ccda257afabacc969846a13c01 Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Sat, 4 Nov 2023 11:02:02 +0100 Subject: [PATCH 2/2] WIP --- compile.c | 2 +- insns.def | 38 ++++++++++++++++++++++++-------------- internal/object.h | 2 ++ object.c | 6 +++++- 4 files changed, 32 insertions(+), 16 deletions(-) diff --git a/compile.c b/compile.c index 4080ec4b0dcf92..e743c391799e45 100644 --- a/compile.c +++ b/compile.c @@ -3933,7 +3933,7 @@ iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj) switch (vm_ci_mid(ci)) { case idNew: iobj->insn_id = BIN(opt_new); - iobj->operands[1] = (VALUE)new_callinfo(iseq, idInitialize, vm_ci_argc(ci), vm_ci_flag(ci) | VM_CALL_FCALL, vm_ci_kwarg(ci), FALSE); + iobj->operands[1] = (VALUE)new_callinfo(iseq, idInitialize, vm_ci_argc(ci) - vm_ci_kwarg(ci)->keyword_len, vm_ci_flag(ci) | VM_CALL_FCALL, vm_ci_kwarg(ci), FALSE); break; default: iobj->insn_id = BIN(opt_send_without_block); diff --git a/insns.def b/insns.def index fa1f417b8dbfc9..130fea4d863580 100644 --- a/insns.def +++ b/insns.def @@ -838,22 +838,32 @@ opt_new // attr rb_snum_t sp_inc = sp_inc_of_sendish(cd->ci); // attr rb_snum_t comptime_sp_inc = sp_inc_of_sendish(ci); { - VALUE recv = TOPN(vm_ci_argc(cd->ci)); - - val = vm_opt_new_alloc(GET_ISEQ(), recv, cd); - if (val != Qundef) { - TOPN(vm_ci_argc(cd->ci)) = val; - fprintf(stderr, "opt!\n"); - if (vm_sendish(ec, GET_CFP(), cd_initialize, VM_BLOCK_HANDLER_NONE, mexp_search_method) == Qundef) { - val = Qundef; - } - } + int argc = vm_ci_argc(cd->ci); + VM_ASSERT((int)vm_ci_argc(cd_initialize->ci) == argc); - if (val == Qundef) { - fprintf(stderr, "de-opt!\n"); + VALUE recv = TOPN(argc); + val = Qundef; + + VALUE new_obj = vm_opt_new_alloc(GET_ISEQ(), recv, cd); + if (new_obj != Qundef) { + TOPN(argc) = new_obj; + + val = vm_sendish(ec, GET_CFP(), cd_initialize, VM_BLOCK_HANDLER_NONE, mexp_search_method); + // FIXME: somehow the `initialize` return is what end up being the `.new` return, instead of `new_obj`. + // I don't get why. + + JIT_EXEC(ec, val); - VALUE bh = VM_BLOCK_HANDLER_NONE; - val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_method); + if (val == Qundef) { + RESTORE_REGS(); + NEXT_INSN(); + } + else { + val = new_obj; + } + } + else if (val == Qundef) { + val = vm_sendish(ec, GET_CFP(), cd, VM_BLOCK_HANDLER_NONE, mexp_search_method); JIT_EXEC(ec, val); if (val == Qundef) { diff --git a/internal/object.h b/internal/object.h index 9f3ed548da08ee..02258a207340e4 100644 --- a/internal/object.h +++ b/internal/object.h @@ -22,6 +22,8 @@ static inline void RBASIC_CLEAR_CLASS(VALUE obj); static inline void RBASIC_SET_CLASS_RAW(VALUE obj, VALUE klass); static inline void RBASIC_SET_CLASS(VALUE obj, VALUE klass); VALUE rb_class_alloc(VALUE klass); +VALUE rb_obj_initialize(VALUE _self); + RUBY_SYMBOL_EXPORT_BEGIN /* object.c (export) */ diff --git a/object.c b/object.c index 4c4c08cb9d15c0..95ade0b6a6bb54 100644 --- a/object.c +++ b/object.c @@ -1222,7 +1222,11 @@ rb_class_search_ancestor(VALUE cl, VALUE c) * * Returns a new BasicObject. */ -#define rb_obj_initialize rb_obj_dummy0 +VALUE +rb_obj_initialize(VALUE _self) +{ + return Qnil; +} /* * Not documented