diff --git a/compile.c b/compile.c index 9399b885def351..6f2b812a1e49ba 100644 --- a/compile.c +++ b/compile.c @@ -13035,15 +13035,49 @@ rb_iseq_t * iseq_alloc_for_inlining(const rb_iseq_t *original_iseq); bool rb_simple_iseq_p(const rb_iseq_t *iseq); static bool -inlineable_call(CALL_DATA cd) +contains_method_calls(VALUE *code, size_t size, rb_vm_insns_translator_t * translator) { - unsigned int flags = vm_ci_flag(cd->ci); - if (flags & VM_CALL_ARGS_SIMPLE) { - return true; + int n = 0; + + // Scan the instructions looking for method calls + for (n = 0; n < size;) { + int insn_id = (int)translator((void *)code[n]); + int len = insn_len(insn_id); + + // Any time we find a method call + if (insn_id == BIN(opt_send_without_block)) { + return true; + } + + n += len; } - else { - return false; + + return false; +} + +static bool +inlineable_call(CALL_DATA cd, rb_vm_insns_translator_t * translator) +{ + unsigned int flags = vm_ci_flag(cd->ci); + const struct rb_callable_method_entry_struct * cme = vm_cc_cme(cd->cc); + + if (cme) { + const rb_iseq_t * callee_iseq = cme->def->body.iseq.iseqptr; + VALUE * callee_iseq_code = callee_iseq->body->iseq_encoded; + size_t callee_iseq_size = callee_iseq->body->iseq_size; + bool contain_method_call = contains_method_calls(callee_iseq_code, callee_iseq_size, translator); + + // A leaf method is a method with the builtin inline flag set + // or a method that doesn't contain a method call + bool is_leaf_method = callee_iseq->body->builtin_inline_p || !contain_method_call; + + // Only inline simple and leaf methods + if (flags & VM_CALL_ARGS_SIMPLE && is_leaf_method) { + return true; + } } + + return false; } static int @@ -13070,7 +13104,7 @@ inline_iseqs(VALUE *code, size_t pos, iseq_value_itr_t * func, void *_ctx, rb_vm if (ctx->depth == 0 && insn_id == BIN(opt_send_without_block)) { CALL_DATA cd = (CALL_DATA)code[pos + 1]; - if (inlineable_call(cd)) { + if (inlineable_call(cd, translator)) { const struct rb_callable_method_entry_struct * cme = vm_cc_cme(cd->cc); // Convert the method call in to a linked list of the instructions @@ -13235,7 +13269,7 @@ find_max_local_table(VALUE *code, size_t pos, iseq_value_itr_t * func, void *_ct if (insn_id == BIN(opt_send_without_block)) { CALL_DATA cd = (CALL_DATA)code[pos + 1]; - if (inlineable_call(cd)) { + if (inlineable_call(cd, translator)) { const struct rb_callable_method_entry_struct * cme = vm_cc_cme(cd->cc); // Convert the method call in to a linked list of the instructions