diff --git a/mono/mini/interp/interp.c b/mono/mini/interp/interp.c index 1acc4f7ffdf2..a56e0057ce00 100644 --- a/mono/mini/interp/interp.c +++ b/mono/mini/interp/interp.c @@ -1758,7 +1758,7 @@ interp_entry (InterpEntryData *data) } static MONO_NEVER_INLINE stackval * -do_icall (ThreadContext *context, int op, stackval *sp, gpointer ptr) +do_icall (ThreadContext *context, MonoMethodSignature *sig, int op, stackval *sp, gpointer ptr) { MonoLMFExt ext; interp_push_lmf (&ext, context->current_frame); @@ -1792,52 +1792,68 @@ do_icall (ThreadContext *context, int op, stackval *sp, gpointer ptr) func (sp [0].data.p, sp [1].data.p); break; } - case MINT_ICALL_PI_V: { - void (*func)(gpointer,int) = ptr; - sp -= 2; - func (sp [0].data.p, sp [1].data.i); - break; - } case MINT_ICALL_PP_P: { gpointer (*func)(gpointer,gpointer) = ptr; --sp; sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p); break; } - case MINT_ICALL_PI_P: { - gpointer (*func)(gpointer,int) = ptr; - --sp; - sp [-1].data.p = func (sp [-1].data.p, sp [0].data.i); - break; - } case MINT_ICALL_PPP_V: { void (*func)(gpointer,gpointer,gpointer) = ptr; sp -= 3; func (sp [0].data.p, sp [1].data.p, sp [2].data.p); break; } - case MINT_ICALL_PPI_V: { - void (*func)(gpointer,gpointer,int) = ptr; + case MINT_ICALL_PPP_P: { + gpointer (*func)(gpointer,gpointer,gpointer) = ptr; + sp -= 2; + sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p, sp [1].data.p); + break; + } + case MINT_ICALL_PPPP_V: { + void (*func)(gpointer,gpointer,gpointer,gpointer) = ptr; + sp -= 4; + func (sp [0].data.p, sp [1].data.p, sp [2].data.p, sp [3].data.p); + break; + } + case MINT_ICALL_PPPP_P: { + gpointer (*func)(gpointer,gpointer,gpointer,gpointer) = ptr; sp -= 3; - func (sp [0].data.p, sp [1].data.p, sp [2].data.i); + sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p, sp [1].data.p, sp [2].data.p); break; } - case MINT_ICALL_PII_P: { - gpointer (*func)(gpointer,int,int) = ptr; - sp -= 2; - sp [-1].data.p = func (sp [-1].data.p, sp [0].data.i, sp [1].data.i); + case MINT_ICALL_PPPPP_V: { + void (*func)(gpointer,gpointer,gpointer,gpointer,gpointer) = ptr; + sp -= 5; + func (sp [0].data.p, sp [1].data.p, sp [2].data.p, sp [3].data.p, sp [4].data.p); break; } - case MINT_ICALL_PPII_V: { - gpointer (*func)(gpointer,gpointer,int,int) = ptr; + case MINT_ICALL_PPPPP_P: { + gpointer (*func)(gpointer,gpointer,gpointer,gpointer,gpointer) = ptr; sp -= 4; - func (sp [0].data.p, sp [1].data.p, sp [2].data.i, sp [3].data.i); + sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p, sp [1].data.p, sp [2].data.p, sp [3].data.p); + break; + } + case MINT_ICALL_PPPPPP_V: { + void (*func)(gpointer,gpointer,gpointer,gpointer,gpointer,gpointer) = ptr; + sp -= 6; + func (sp [0].data.p, sp [1].data.p, sp [2].data.p, sp [3].data.p, sp [4].data.p, sp [5].data.p); + break; + } + case MINT_ICALL_PPPPPP_P: { + gpointer (*func)(gpointer,gpointer,gpointer,gpointer,gpointer,gpointer) = ptr; + sp -= 5; + sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p, sp [1].data.p, sp [2].data.p, sp [3].data.p, sp [4].data.p); break; } default: g_assert_not_reached (); } + /* convert the native representation to the stackval representation */ + if (sig) + stackval_from_data (sig->ret, &sp [-1], (char*) &sp [-1].data.p, sig->pinvoke); + interp_pop_lmf (&ext); return sp; } @@ -2833,6 +2849,25 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st } MINT_IN_BREAK; } + MINT_IN_CASE(MINT_CALLI_NAT_FAST) { + gpointer target_ip = sp [-1].data.p; + MonoMethodSignature *csignature = rtm->data_items [* (guint16 *)(ip + 1)]; + int opcode = *(guint16 *)(ip + 2); + + sp--; + frame->ip = ip; + + sp = do_icall (context, csignature, opcode, sp, target_ip); + EXCEPTION_CHECKPOINT; + if (context->has_resume_state) { + if (frame == context->handler_frame) + SET_RESUME_STATE (context); + else + goto exit_frame; + } + ip += 3; + MINT_IN_BREAK; + } MINT_IN_CASE(MINT_CALLI_NAT) { MonoMethodSignature *csignature; stackval *endsp = sp; @@ -4859,7 +4894,7 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st * dummy frame that is stored in the lmf and serves as the transition frame */ context->current_frame = &child_frame; - do_icall (context, MINT_ICALL_V_P, &tmp_sp, mono_thread_get_undeniable_exception); + do_icall (context, NULL, MINT_ICALL_V_P, &tmp_sp, mono_thread_get_undeniable_exception); context->current_frame = frame; MonoException *abort_exc = (MonoException*)tmp_sp.data.p; @@ -4880,15 +4915,17 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st MINT_IN_CASE(MINT_ICALL_P_V) MINT_IN_CASE(MINT_ICALL_P_P) MINT_IN_CASE(MINT_ICALL_PP_V) - MINT_IN_CASE(MINT_ICALL_PI_V) MINT_IN_CASE(MINT_ICALL_PP_P) - MINT_IN_CASE(MINT_ICALL_PI_P) MINT_IN_CASE(MINT_ICALL_PPP_V) - MINT_IN_CASE(MINT_ICALL_PPI_V) - MINT_IN_CASE(MINT_ICALL_PII_P) - MINT_IN_CASE(MINT_ICALL_PPII_V) + MINT_IN_CASE(MINT_ICALL_PPP_P) + MINT_IN_CASE(MINT_ICALL_PPPP_V) + MINT_IN_CASE(MINT_ICALL_PPPP_P) + MINT_IN_CASE(MINT_ICALL_PPPPP_V) + MINT_IN_CASE(MINT_ICALL_PPPPP_P) + MINT_IN_CASE(MINT_ICALL_PPPPPP_V) + MINT_IN_CASE(MINT_ICALL_PPPPPP_P) frame->ip = ip; - sp = do_icall (context, *ip, sp, rtm->data_items [*(guint16 *)(ip + 1)]); + sp = do_icall (context, NULL, *ip, sp, rtm->data_items [*(guint16 *)(ip + 1)]); EXCEPTION_CHECKPOINT; if (context->has_resume_state) { if (frame == context->handler_frame) diff --git a/mono/mini/interp/mintops.def b/mono/mini/interp/mintops.def index 0d7f9c4bd397..35199327d066 100644 --- a/mono/mini/interp/mintops.def +++ b/mono/mini/interp/mintops.def @@ -269,7 +269,8 @@ OPDEF(MINT_VCALL, "vcall", 2, MintOpMethodToken) OPDEF(MINT_CALLVIRT, "callvirt", 2, MintOpMethodToken) OPDEF(MINT_VCALLVIRT, "vcallvirt", 2, MintOpMethodToken) OPDEF(MINT_CALLI, "calli", 2, MintOpMethodToken) -OPDEF(MINT_CALLI_NAT, "calli.nat", 2, MintOpMethodToken) +OPDEF(MINT_CALLI_NAT, "calli.nat", 3, MintOpMethodToken) +OPDEF(MINT_CALLI_NAT_FAST, "calli.nat", 2, MintOpMethodToken) OPDEF(MINT_JMP, "jmp", 2, MintOpMethodToken) OPDEF(MINT_CALLRUN, "callrun", 3, MintOpNoArgs) @@ -539,13 +540,15 @@ OPDEF(MINT_ICALL_V_P, "mono_icall_v_p", 2, MintOpClassToken) OPDEF(MINT_ICALL_P_V, "mono_icall_p_v", 2, MintOpClassToken) OPDEF(MINT_ICALL_P_P, "mono_icall_p_p", 2, MintOpClassToken) OPDEF(MINT_ICALL_PP_V, "mono_icall_pp_v", 2, MintOpClassToken) -OPDEF(MINT_ICALL_PI_V, "mono_icall_pi_v", 2, MintOpClassToken) OPDEF(MINT_ICALL_PP_P, "mono_icall_pp_p", 2, MintOpClassToken) -OPDEF(MINT_ICALL_PI_P, "mono_icall_pi_p", 2, MintOpClassToken) OPDEF(MINT_ICALL_PPP_V, "mono_icall_ppp_v", 2, MintOpClassToken) -OPDEF(MINT_ICALL_PPI_V, "mono_icall_ppi_v", 2, MintOpClassToken) -OPDEF(MINT_ICALL_PII_P, "mono_icall_pii_p", 2, MintOpClassToken) -OPDEF(MINT_ICALL_PPII_V, "mono_icall_ppii_v", 2, MintOpClassToken) +OPDEF(MINT_ICALL_PPP_P, "mono_icall_ppp_p", 2, MintOpClassToken) +OPDEF(MINT_ICALL_PPPP_V, "mono_icall_pppp_v", 2, MintOpClassToken) +OPDEF(MINT_ICALL_PPPP_P, "mono_icall_pppp_p", 2, MintOpClassToken) +OPDEF(MINT_ICALL_PPPPP_V, "mono_icall_ppppp_v", 2, MintOpClassToken) +OPDEF(MINT_ICALL_PPPPP_P, "mono_icall_ppppp_p", 2, MintOpClassToken) +OPDEF(MINT_ICALL_PPPPPP_V, "mono_icall_pppppp_v", 2, MintOpClassToken) +OPDEF(MINT_ICALL_PPPPPP_P, "mono_icall_pppppp_p", 2, MintOpClassToken) OPDEF(MINT_MONO_LDPTR, "mono_ldptr", 2, MintOpClassToken) OPDEF(MINT_MONO_TLS, "mono_tls", 3, MintOpInt) OPDEF(MINT_MONO_NEWOBJ, "mono_newobj", 2, MintOpClassToken) diff --git a/mono/mini/interp/transform.c b/mono/mini/interp/transform.c index 4c265f3b8feb..d9698ebca6bb 100644 --- a/mono/mini/interp/transform.c +++ b/mono/mini/interp/transform.c @@ -1063,6 +1063,129 @@ interp_transform_internal_calls (MonoMethod *method, MonoMethod *target_method, return target_method; } +static gboolean +interp_type_as_ptr (MonoType *tp) +{ + if (MONO_TYPE_IS_POINTER (tp)) + return TRUE; + if (MONO_TYPE_IS_REFERENCE (tp)) + return TRUE; + if ((tp)->type == MONO_TYPE_I4) + return TRUE; +#if SIZEOF_VOID_P == 8 + if ((tp)->type == MONO_TYPE_I8) + return TRUE; +#endif + if ((tp)->type == MONO_TYPE_BOOLEAN) + return TRUE; + if ((tp)->type == MONO_TYPE_CHAR) + return TRUE; + if ((tp)->type == MONO_TYPE_VALUETYPE && m_class_is_enumtype (tp->data.klass)) + return TRUE; + return FALSE; +} + +#define INTERP_TYPE_AS_PTR(tp) interp_type_as_ptr (tp) + +static int +interp_icall_op_for_sig (MonoMethodSignature *sig) +{ + int op = -1; + switch (sig->param_count) { + case 0: + if (MONO_TYPE_IS_VOID (sig->ret)) + op = MINT_ICALL_V_V; + else if (INTERP_TYPE_AS_PTR (sig->ret)) + op = MINT_ICALL_V_P; + break; + case 1: + if (MONO_TYPE_IS_VOID (sig->ret)) { + if (INTERP_TYPE_AS_PTR (sig->params [0])) + op = MINT_ICALL_P_V; + } else if (INTERP_TYPE_AS_PTR (sig->ret)) { + if (INTERP_TYPE_AS_PTR (sig->params [0])) + op = MINT_ICALL_P_P; + } + break; + case 2: + if (MONO_TYPE_IS_VOID (sig->ret)) { + if (INTERP_TYPE_AS_PTR (sig->params [0]) && + INTERP_TYPE_AS_PTR (sig->params [1])) + op = MINT_ICALL_PP_V; + } else if (INTERP_TYPE_AS_PTR (sig->ret)) { + if (INTERP_TYPE_AS_PTR (sig->params [0]) && + INTERP_TYPE_AS_PTR (sig->params [1])) + op = MINT_ICALL_PP_P; + } + break; + case 3: + if (MONO_TYPE_IS_VOID (sig->ret)) { + if (INTERP_TYPE_AS_PTR (sig->params [0]) && + INTERP_TYPE_AS_PTR (sig->params [1]) && + INTERP_TYPE_AS_PTR (sig->params [2])) + op = MINT_ICALL_PPP_V; + } else if (INTERP_TYPE_AS_PTR (sig->ret)) { + if (INTERP_TYPE_AS_PTR (sig->params [0]) && + INTERP_TYPE_AS_PTR (sig->params [1]) && + INTERP_TYPE_AS_PTR (sig->params [2])) + op = MINT_ICALL_PPP_P; + } + break; + case 4: + if (MONO_TYPE_IS_VOID (sig->ret)) { + if (INTERP_TYPE_AS_PTR (sig->params [0]) && + INTERP_TYPE_AS_PTR (sig->params [1]) && + INTERP_TYPE_AS_PTR (sig->params [2]) && + INTERP_TYPE_AS_PTR (sig->params [3])) + op = MINT_ICALL_PPPP_V; + } else if (INTERP_TYPE_AS_PTR (sig->ret)) { + if (INTERP_TYPE_AS_PTR (sig->params [0]) && + INTERP_TYPE_AS_PTR (sig->params [1]) && + INTERP_TYPE_AS_PTR (sig->params [2]) && + INTERP_TYPE_AS_PTR (sig->params [3])) + op = MINT_ICALL_PPPP_P; + } + break; + case 5: + if (MONO_TYPE_IS_VOID (sig->ret)) { + if (INTERP_TYPE_AS_PTR (sig->params [0]) && + INTERP_TYPE_AS_PTR (sig->params [1]) && + INTERP_TYPE_AS_PTR (sig->params [2]) && + INTERP_TYPE_AS_PTR (sig->params [3]) && + INTERP_TYPE_AS_PTR (sig->params [4])) + op = MINT_ICALL_PPPPP_V; + } else if (INTERP_TYPE_AS_PTR (sig->ret)) { + if (INTERP_TYPE_AS_PTR (sig->params [0]) && + INTERP_TYPE_AS_PTR (sig->params [1]) && + INTERP_TYPE_AS_PTR (sig->params [2]) && + INTERP_TYPE_AS_PTR (sig->params [3]) && + INTERP_TYPE_AS_PTR (sig->params [4])) + op = MINT_ICALL_PPPPP_P; + } + break; + case 6: + if (MONO_TYPE_IS_VOID (sig->ret)) { + if (INTERP_TYPE_AS_PTR (sig->params [0]) && + INTERP_TYPE_AS_PTR (sig->params [1]) && + INTERP_TYPE_AS_PTR (sig->params [2]) && + INTERP_TYPE_AS_PTR (sig->params [3]) && + INTERP_TYPE_AS_PTR (sig->params [4]) && + INTERP_TYPE_AS_PTR (sig->params [5])) + op = MINT_ICALL_PPPPPP_V; + } else if (INTERP_TYPE_AS_PTR (sig->ret)) { + if (INTERP_TYPE_AS_PTR (sig->params [0]) && + INTERP_TYPE_AS_PTR (sig->params [1]) && + INTERP_TYPE_AS_PTR (sig->params [2]) && + INTERP_TYPE_AS_PTR (sig->params [3]) && + INTERP_TYPE_AS_PTR (sig->params [4]) && + INTERP_TYPE_AS_PTR (sig->params [5])) + op = MINT_ICALL_PPPPPP_P; + } + break; + } + return op; +} + static void interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target_method, MonoDomain *domain, MonoGenericContext *generic_context, unsigned char *is_bb_start, int body_start_offset, MonoClass *constrained_class, gboolean readonly, MonoError *error, gboolean check_visibility) { @@ -1369,8 +1492,11 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target ADD_CODE(td, get_data_item_index (td, (void *)mono_interp_get_imethod (domain, target_method, error))); mono_error_assert_ok (error); } else { + /* Try using fast icall path for simple signatures */ + if (native && !method->dynamic) + op = interp_icall_op_for_sig (csignature); if (calli) - ADD_CODE(td, native ? MINT_CALLI_NAT : MINT_CALLI); + ADD_CODE(td, native ? ((op != -1) ? MINT_CALLI_NAT_FAST : MINT_CALLI_NAT) : MINT_CALLI); else if (is_virtual) ADD_CODE(td, is_void ? MINT_VCALLVIRT : MINT_CALLVIRT); else @@ -1378,6 +1504,8 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target if (calli) { ADD_CODE(td, get_data_item_index (td, (void *)csignature)); + if (op != -1) + ADD_CODE (td, op); } else { ADD_CODE(td, get_data_item_index (td, (void *)mono_interp_get_imethod (domain, target_method, error))); return_if_nok (error); @@ -4143,6 +4271,7 @@ generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, unsig guint32 token; gpointer func; MonoJitICallInfo *info; + int icall_op; token = read32 (td->ip + 1); td->ip += 5; @@ -4151,52 +4280,10 @@ generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, unsig g_assert (info); CHECK_STACK (td, info->sig->param_count); - switch (info->sig->param_count) { - case 0: - if (MONO_TYPE_IS_VOID (info->sig->ret)) - ADD_CODE (td,MINT_ICALL_V_V); - else - ADD_CODE (td, MINT_ICALL_V_P); - break; - case 1: - if (MONO_TYPE_IS_VOID (info->sig->ret)) - ADD_CODE (td,MINT_ICALL_P_V); - else - ADD_CODE (td,MINT_ICALL_P_P); - break; - case 2: - if (MONO_TYPE_IS_VOID (info->sig->ret)) { - if (info->sig->params [1]->type == MONO_TYPE_I4) - ADD_CODE (td,MINT_ICALL_PI_V); - else - ADD_CODE (td,MINT_ICALL_PP_V); - } else { - if (info->sig->params [1]->type == MONO_TYPE_I4) - ADD_CODE (td,MINT_ICALL_PI_P); - else - ADD_CODE (td,MINT_ICALL_PP_P); - } - break; - case 3: - if (MONO_TYPE_IS_VOID (info->sig->ret)) { - if (info->sig->params [2]->type == MONO_TYPE_I4) - ADD_CODE (td,MINT_ICALL_PPI_V); - else - ADD_CODE (td,MINT_ICALL_PPP_V); - } else { - g_assert (info->sig->params [1]->type == MONO_TYPE_I4 && info->sig->params [2]->type == MONO_TYPE_I4); - ADD_CODE (td, MINT_ICALL_PII_P); - } - break; - case 4: - g_assert (MONO_TYPE_IS_VOID (info->sig->ret)); - g_assert (info->sig->params [2]->type == MONO_TYPE_I4 && info->sig->params [3]->type == MONO_TYPE_I4); - ADD_CODE (td, MINT_ICALL_PPII_V); - break; - default: - g_assert_not_reached (); - } + icall_op = interp_icall_op_for_sig (info->sig); + g_assert (icall_op != -1); + ADD_CODE(td, icall_op); ADD_CODE(td, get_data_item_index (td, func)); td->sp -= info->sig->param_count;