diff --git a/compile.c b/compile.c index bad3c079fc1422..e743c391799e45 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_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); + 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..130fea4d863580 100644 --- a/insns.def +++ b/insns.def @@ -828,6 +828,51 @@ 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); +{ + int argc = vm_ci_argc(cd->ci); + VM_ASSERT((int)vm_ci_argc(cd_initialize->ci) == argc); + + 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); + + 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) { + 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..02258a207340e4 100644 --- a/internal/object.h +++ b/internal/object.h @@ -21,6 +21,9 @@ 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); +VALUE rb_obj_initialize(VALUE _self); + RUBY_SYMBOL_EXPORT_BEGIN /* object.c (export) */ diff --git a/object.c b/object.c index 73fbe78edc5fd8..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 @@ -2063,7 +2067,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) {