mirror of
https://github.com/ruby/ruby.git
synced 2025-08-23 13:04:13 +02:00

Fixing 4bcd5981e8/mjit.c (L338)
should be the right solution for this. We may not be able to free the cc immediately.
Plus, we're not copying cc but just holding references to be marked. cc
should be GC-ed once jit_unit is freed.
111 lines
6.1 KiB
Text
111 lines
6.1 KiB
Text
% # -*- C -*-
|
|
% # Copyright (c) 2018 Takashi Kokubun. All rights reserved.
|
|
% #
|
|
% # This file is a part of the programming language Ruby. Permission is hereby
|
|
% # granted, to either redistribute and/or modify this file, provided that the
|
|
% # conditions mentioned in the file COPYING are met. Consult the file for
|
|
% # details.
|
|
%
|
|
% # Optimized case of send / opt_send_without_block instructions.
|
|
{
|
|
MAYBE_UNUSED(int pc_moved_p) = FALSE;
|
|
% # compiler: Prepare operands which may be used by `insn.call_attribute`
|
|
% insn.opes.each_with_index do |ope, i|
|
|
MAYBE_UNUSED(<%= ope.fetch(:decl) %>) = (<%= ope.fetch(:type) %>)operands[<%= i %>];
|
|
% end
|
|
% # compiler: Use copied cc to avoid race condition
|
|
const struct rb_callcache *captured_cc = status->cc_entries[call_data_index(cd, body)];
|
|
%
|
|
if (!status->compile_info->disable_send_cache && has_valid_method_type(captured_cc)) {
|
|
const rb_iseq_t *iseq;
|
|
const CALL_INFO ci = cd->ci;
|
|
unsigned int argc = vm_ci_argc(ci); // this `argc` variable is for calculating a value's position on stack considering `blockarg`.
|
|
% if insn.name == 'send'
|
|
argc += ((vm_ci_flag(ci) & VM_CALL_ARGS_BLOCKARG) ? 1 : 0); // simulate `vm_caller_setup_arg_block`'s `--reg_cfp->sp`
|
|
% end
|
|
|
|
if (!(vm_ci_flag(ci) & VM_CALL_TAILCALL) // inlining non-tailcall path
|
|
&& vm_cc_cme(captured_cc)->def->type == VM_METHOD_TYPE_ISEQ
|
|
&& fastpath_applied_iseq_p(ci, captured_cc, iseq = def_iseq_ptr(vm_cc_cme(captured_cc)->def))) {
|
|
// CC_SET_FASTPATH in vm_callee_setup_arg
|
|
|
|
int param_size = iseq->body->param.size;
|
|
|
|
fprintf(f, "{\n");
|
|
% # JIT: Declare stack_size to be used in some macro of _mjit_compile_insn_body.erb
|
|
if (status->local_stack_p) {
|
|
fprintf(f, " MAYBE_UNUSED(unsigned int) stack_size = %u;\n", b->stack_size);
|
|
}
|
|
|
|
% # JIT: Invalidate call cache if it requires vm_search_method. This allows to inline some of following things.
|
|
fprintf(f, " const struct rb_call_data *cd = (const struct rb_callcache *)0x%"PRIxVALUE";\n", (VALUE)cd);
|
|
fprintf(f, " const struct rb_callcache *cc = (const struct rb_callcache *)0x%"PRIxVALUE";\n", (VALUE)captured_cc);
|
|
fprintf(f, " if (UNLIKELY(cd->cc != cc || !vm_cc_valid_p(cc, CLASS_OF(stack[%d])))) {\n", b->stack_size - 1 - argc);
|
|
fprintf(f, " reg_cfp->pc = original_body_iseq + %d;\n", pos);
|
|
fprintf(f, " reg_cfp->sp = vm_base_ptr(reg_cfp) + %d;\n", b->stack_size);
|
|
fprintf(f, " goto send_cancel;\n");
|
|
fprintf(f, " }\n");
|
|
|
|
% # JIT: move sp and pc if necessary
|
|
<%= render 'mjit_compile_pc_and_sp', locals: { insn: insn } -%>
|
|
|
|
% # JIT: If ISeq is inlinable, call the inlined method without pushing a frame.
|
|
if (status->inlined_iseqs != NULL && status->inlined_iseqs[pos] == iseq->body) {
|
|
fprintf(f, " {\n");
|
|
fprintf(f, " VALUE orig_self = reg_cfp->self;\n");
|
|
fprintf(f, " reg_cfp->self = stack[%d];\n", b->stack_size - argc - 1);
|
|
fprintf(f, " stack[%d] = _mjit_inlined_%d(ec, reg_cfp, orig_self, original_iseq);\n", b->stack_size - argc - 1, pos);
|
|
fprintf(f, " reg_cfp->self = orig_self;\n");
|
|
fprintf(f, " }\n");
|
|
}
|
|
else {
|
|
% # JIT: Print insn body in insns.def
|
|
fprintf(f, " {\n");
|
|
fprintf(f, " struct rb_calling_info calling;\n");
|
|
% if insn.name == 'send'
|
|
fprintf(f, " calling.block_handler = vm_caller_setup_arg_block(ec, reg_cfp, cd->ci, (rb_iseq_t *)0x%"PRIxVALUE", FALSE);\n", (VALUE)blockiseq);
|
|
% else
|
|
fprintf(f, " calling.block_handler = VM_BLOCK_HANDLER_NONE;\n");
|
|
% end
|
|
fprintf(f, " calling.argc = %d;\n", vm_ci_argc(ci));
|
|
fprintf(f, " calling.recv = stack[%d];\n", b->stack_size - 1 - argc);
|
|
|
|
% # JIT: Special CALL_METHOD. Bypass captured_cc->call and inline vm_call_iseq_setup_normal for vm_call_iseq_setup_func FASTPATH.
|
|
fprintf(f, " {\n");
|
|
fprintf(f, " VALUE v;\n");
|
|
fprintf(f, " vm_call_iseq_setup_normal(ec, reg_cfp, &calling, vm_cc_cme(cc), 0, %d, %d);\n",
|
|
param_size, iseq->body->local_table_size); // fastpath_applied_iseq_p checks rb_simple_iseq_p, which ensures has_opt == FALSE
|
|
if (iseq->body->catch_except_p) {
|
|
fprintf(f, " VM_ENV_FLAGS_SET(ec->cfp->ep, VM_FRAME_FLAG_FINISH);\n");
|
|
fprintf(f, " v = vm_exec(ec, TRUE);\n");
|
|
}
|
|
else {
|
|
fprintf(f, " if ((v = mjit_exec(ec)) == Qundef) {\n");
|
|
fprintf(f, " VM_ENV_FLAGS_SET(ec->cfp->ep, VM_FRAME_FLAG_FINISH);\n"); // This is vm_call0_body's code after vm_call_iseq_setup
|
|
fprintf(f, " v = vm_exec(ec, FALSE);\n");
|
|
fprintf(f, " }\n");
|
|
}
|
|
fprintf(f, " stack[%d] = v;\n", b->stack_size - argc - 1);
|
|
fprintf(f, " }\n");
|
|
|
|
fprintf(f, " }\n");
|
|
|
|
% # JIT: We should evaluate ISeq modified for TracePoint if it's enabled. Note: This is slow.
|
|
fprintf(f, " if (UNLIKELY(!mjit_call_p)) {\n");
|
|
fprintf(f, " reg_cfp->sp = vm_base_ptr(reg_cfp) + %d;\n", b->stack_size + (int)<%= insn.call_attribute('sp_inc') %>);
|
|
if (!pc_moved_p) {
|
|
fprintf(f, " reg_cfp->pc = original_body_iseq + %d;\n", next_pos);
|
|
}
|
|
fprintf(f, " RB_DEBUG_COUNTER_INC(mjit_cancel_invalidate_all);\n");
|
|
fprintf(f, " goto cancel;\n");
|
|
fprintf(f, " }\n");
|
|
}
|
|
|
|
% # compiler: Move JIT compiler's internal stack pointer
|
|
b->stack_size += <%= insn.call_attribute('sp_inc') %>;
|
|
|
|
fprintf(f, "}\n");
|
|
break;
|
|
}
|
|
}
|
|
}
|