From 929e4b08a4af7c8ef81e66de56d7b03aa1162588 Mon Sep 17 00:00:00 2001 From: Vlad Brezae Date: Mon, 11 Dec 2017 02:56:41 +0200 Subject: [PATCH] [arm64] Rework native entry tramp from interp --- mono/metadata/object-offsets.h | 2 +- mono/mini/interp/interp.c | 10 ++-- mono/mini/mini-arm64.c | 125 ++++++++++++++++++++++++++++++++++++++ mono/mini/mini-arm64.h | 11 ++++ mono/mini/tramp-arm64.c | 133 ++++++++++++++--------------------------- 5 files changed, 185 insertions(+), 96 deletions(-) diff --git a/mono/metadata/object-offsets.h b/mono/metadata/object-offsets.h index 0d8373750a9..965195cddb7 100644 --- a/mono/metadata/object-offsets.h +++ b/mono/metadata/object-offsets.h @@ -287,7 +287,7 @@ DECL_OFFSET(InterpMethodArguments, flen) DECL_OFFSET(InterpMethodArguments, fargs) DECL_OFFSET(InterpMethodArguments, retval) DECL_OFFSET(InterpMethodArguments, is_float_ret) -#if defined(TARGET_AMD64) || defined(TARGET_ARM) +#if defined(TARGET_AMD64) || defined(TARGET_ARM) || defined(TARGET_ARM64) DECL_OFFSET(CallContext, gregs) DECL_OFFSET(CallContext, fregs) DECL_OFFSET(CallContext, stack_size) diff --git a/mono/mini/interp/interp.c b/mono/mini/interp/interp.c index 2ff018a972b..ae1e07223cf 100644 --- a/mono/mini/interp/interp.c +++ b/mono/mini/interp/interp.c @@ -1128,13 +1128,11 @@ static gpointer interp_frame_arg_to_storage (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index) { InterpFrame *iframe = (InterpFrame*)frame; - MonoType *type = sig->ret; - stackval *val = iframe->retval; - g_assert (index == -1); - g_assert (type->type == MONO_TYPE_VALUETYPE); - - return stackval_to_data_addr (type, val); + if (index == -1) + return stackval_to_data_addr (sig->ret, iframe->retval); + else + return stackval_to_data_addr (sig->params [index], &iframe->stack_args [index]); } static void diff --git a/mono/mini/mini-arm64.c b/mono/mini/mini-arm64.c index 092bfd45385..a736c06e325 100644 --- a/mono/mini/mini-arm64.c +++ b/mono/mini/mini-arm64.c @@ -27,6 +27,8 @@ #include #include +#include "interp/interp.h" + /* * Documentation: * @@ -1370,6 +1372,129 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) return cinfo; } +void +mono_arch_set_native_call_context (CallContext *ccontext, gpointer frame, MonoMethodSignature *sig) +{ + CallInfo *cinfo = get_call_info (NULL, sig); + MonoInterpCallbacks *interp_cb = mini_get_interp_callbacks (); + + memset (ccontext, 0, sizeof (CallContext)); + + ccontext->stack_size = ALIGN_TO (cinfo->stack_usage, MONO_ARCH_FRAME_ALIGNMENT); + if (ccontext->stack_size) + ccontext->stack = malloc (ccontext->stack_size); + + if (sig->ret->type != MONO_TYPE_VOID) { + if (cinfo->ret.storage == ArgVtypeByRef) { + gpointer ret_storage = interp_cb->frame_arg_to_storage ((MonoInterpFrameHandle)frame, sig, -1); + ccontext->gregs [cinfo->ret.reg] = (mgreg_t)ret_storage; + } + } + + for (int i = 0; i < sig->param_count + sig->hasthis; i++) { + ArgInfo *ainfo = &cinfo->args [i]; + gpointer storage; + int storage_type = ainfo->storage; + int reg_storage = ainfo->reg; + switch (storage_type) { + case ArgVtypeInIRegs: + case ArgInIReg: { + storage = &ccontext->gregs [reg_storage]; + break; + } + case ArgInFReg: + case ArgInFRegR4: { + storage = &ccontext->fregs [reg_storage]; + break; + } + case ArgHFA: { + if (ainfo->esize == 8) + storage = &ccontext->fregs [reg_storage]; + else + storage = alloca (ainfo->size); + break; + } + case ArgVtypeByRef: { + ccontext->gregs [reg_storage] = (mgreg_t)interp_cb->frame_arg_to_storage ((MonoInterpFrameHandle)frame, sig, i); + /* No copying of value needed, skip to next argument */ + continue; + } + case ArgOnStack: + case ArgOnStackR4: + case ArgOnStackR8: + case ArgVtypeOnStack: { + storage = (char*)ccontext->stack + ainfo->offset; + break; + } + default: + g_error ("Arg storage type not yet supported"); + } + interp_cb->frame_arg_to_data ((MonoInterpFrameHandle)frame, sig, i, storage); + if (storage_type == ArgHFA && ainfo->esize == 4) { + float *storage_float = (float*)storage; + for (int k = 0; k < ainfo->nregs; k++) { + *(float*)&ccontext->fregs [reg_storage + k] = *storage_float; + storage_float++; + } + } + } + + g_free (cinfo); +} + +void +mono_arch_get_native_call_context (CallContext *ccontext, gpointer frame, MonoMethodSignature *sig) +{ + MonoInterpCallbacks *interp_cb = mini_get_interp_callbacks (); + CallInfo *cinfo; + + /* No return value */ + if (sig->ret->type == MONO_TYPE_VOID) + return; + + cinfo = get_call_info (NULL, sig); + + /* The return values were stored directly at address passed in reg */ + if (cinfo->ret.storage == ArgVtypeByRef) + goto done; + + ArgInfo *ainfo = &cinfo->ret; + gpointer storage; + int storage_type = ainfo->storage; + int reg_storage = ainfo->reg; + switch (storage_type) { + case ArgVtypeInIRegs: + case ArgInIReg: { + storage = &ccontext->gregs [reg_storage]; + break; + } + case ArgHFA: { + if (ainfo->esize == 8) { + storage = &ccontext->fregs [reg_storage]; + } else { + storage = alloca (ainfo->size); + float *storage_float = (float*)storage; + for (int k = 0; k < ainfo->nregs; k++) { + *storage_float = *(float*)&ccontext->fregs [reg_storage + k]; + storage_float++; + } + } + break; + } + case ArgInFReg: + case ArgInFRegR4: { + storage = &ccontext->fregs [reg_storage]; + break; + } + default: + g_error ("Arg storage type not yet supported"); + } + interp_cb->data_to_frame_arg ((MonoInterpFrameHandle)frame, sig, -1, storage); + +done: + g_free (cinfo); +} + typedef struct { MonoMethodSignature *sig; CallInfo *cinfo; diff --git a/mono/mini/mini-arm64.h b/mono/mini/mini-arm64.h index 960b3e27250..e2c7dc95373 100644 --- a/mono/mini/mini-arm64.h +++ b/mono/mini/mini-arm64.h @@ -154,6 +154,8 @@ typedef struct { #define MONO_ARCH_HAVE_OPCODE_NEEDS_EMULATION 1 #define MONO_ARCH_HAVE_DECOMPOSE_LONG_OPTS 1 +#define MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP 1 + #ifdef TARGET_IOS #define MONO_ARCH_REDZONE_SIZE 128 @@ -228,6 +230,15 @@ typedef struct { ArgInfo args [1]; } CallInfo; +typedef struct { + /* General registers + ARMREG_R8 for indirect returns */ + mgreg_t gregs [PARAM_REGS + 1]; + /* Floating registers */ + double fregs [FP_PARAM_REGS]; + /* Stack usage, used for passing params on stack */ + guint32 stack_size; + guint8* stack; +} CallContext; guint8* mono_arm_emit_imm64 (guint8 *code, int dreg, gint64 imm); diff --git a/mono/mini/tramp-arm64.c b/mono/mini/tramp-arm64.c index a46b26ae431..6fbfa3d7b76 100644 --- a/mono/mini/tramp-arm64.c +++ b/mono/mini/tramp-arm64.c @@ -620,10 +620,8 @@ gpointer mono_arch_get_enter_icall_trampoline (MonoTrampInfo **info) { #ifndef DISABLE_INTERPRETER - const int gregs_num = INTERP_ICALL_TRAMP_IARGS; - const int fregs_num = INTERP_ICALL_TRAMP_FARGS; - - guint8 *start = NULL, *code, *label_gexits [gregs_num], *label_fexits [fregs_num], *label_leave_tramp [3], *label_is_float_ret; + guint8 *start = NULL, *code; + guint8 *label_start_copy, *label_exit_copy; MonoJumpInfo *ji = NULL; GSList *unwind_ops = NULL; int buf_len, i, framesize = 0, off_methodargs, off_targetaddr; @@ -631,7 +629,7 @@ mono_arch_get_enter_icall_trampoline (MonoTrampInfo **info) buf_len = 512 + 1024; start = code = (guint8 *) mono_global_codeman_reserve (buf_len); - /* save FP and LR */ + /* allocate frame */ framesize += 2 * sizeof (mgreg_t); off_methodargs = framesize; @@ -642,109 +640,66 @@ mono_arch_get_enter_icall_trampoline (MonoTrampInfo **info) framesize = ALIGN_TO (framesize, MONO_ARCH_FRAME_ALIGNMENT); - /* allocate space on stack for argument passing */ - const int stack_space = ALIGN_TO (((gregs_num - ARMREG_R7) * sizeof (mgreg_t)), MONO_ARCH_FRAME_ALIGNMENT); - - arm_subx_imm (code, ARMREG_SP, ARMREG_SP, stack_space + framesize); - arm_stpx (code, ARMREG_FP, ARMREG_LR, ARMREG_SP, stack_space); - arm_addx_imm (code, ARMREG_FP, ARMREG_SP, stack_space); + arm_subx_imm (code, ARMREG_SP, ARMREG_SP, framesize); + arm_stpx (code, ARMREG_FP, ARMREG_LR, ARMREG_SP, 0); + arm_movspx (code, ARMREG_FP, ARMREG_SP); - /* save InterpMethodArguments* onto stack */ + /* save CallContext* onto stack */ arm_strx (code, ARMREG_R1, ARMREG_FP, off_methodargs); /* save target address onto stack */ arm_strx (code, ARMREG_R0, ARMREG_FP, off_targetaddr); - /* load pointer to InterpMethodArguments* into IP0 */ - arm_movx (code, ARMREG_IP0, ARMREG_R1); - - /* move flen into R9 */ - arm_ldrx (code, ARMREG_R9, ARMREG_IP0, MONO_STRUCT_OFFSET (InterpMethodArguments, flen)); - /* load pointer to fargs into R10 */ - arm_ldrx (code, ARMREG_R10, ARMREG_IP0, MONO_STRUCT_OFFSET (InterpMethodArguments, fargs)); - - for (i = 0; i < fregs_num; ++i) { - arm_cmpx_imm (code, ARMREG_R9, 0); - label_fexits [i] = code; - arm_bcc (code, ARMCOND_EQ, 0); + /* allocate the stack space necessary for the call */ + arm_ldrx (code, ARMREG_R0, ARMREG_R1, MONO_STRUCT_OFFSET (CallContext, stack_size)); + arm_movspx (code, ARMREG_IP0, ARMREG_SP); + arm_subx (code, ARMREG_IP0, ARMREG_IP0, ARMREG_R0); + arm_movspx (code, ARMREG_SP, ARMREG_IP0); - g_assert (i <= ARMREG_D7); /* otherwise, need to pass args on stack */ - arm_ldrfpx (code, i, ARMREG_R10, i * sizeof (double)); - arm_subx_imm (code, ARMREG_R9, ARMREG_R9, 1); - } - - for (i = 0; i < fregs_num; i++) - mono_arm_patch (label_fexits [i], code, MONO_R_ARM64_BCC); + /* copy stack from the CallContext, IP0 = dest, IP1 = source */ + arm_movspx (code, ARMREG_IP0, ARMREG_SP); + arm_ldrx (code, ARMREG_IP1, ARMREG_R1, MONO_STRUCT_OFFSET (CallContext, stack)); - /* move ilen into R9 */ - arm_ldrx (code, ARMREG_R9, ARMREG_IP0, MONO_STRUCT_OFFSET (InterpMethodArguments, ilen)); - /* load pointer to iargs into R10 */ - arm_ldrx (code, ARMREG_R10, ARMREG_IP0, MONO_STRUCT_OFFSET (InterpMethodArguments, iargs)); + label_start_copy = code; - int stack_offset = 0; - for (i = 0; i < gregs_num; i++) { - arm_cmpx_imm (code, ARMREG_R9, 0); - label_gexits [i] = code; - arm_bcc (code, ARMCOND_EQ, 0); + arm_cmpx_imm (code, ARMREG_R0, 0); + label_exit_copy = code; + arm_bcc (code, ARMCOND_EQ, 0); + arm_ldrx (code, ARMREG_R2, ARMREG_IP1, 0); + arm_strx (code, ARMREG_R2, ARMREG_IP0, 0); + arm_addx_imm (code, ARMREG_IP0, ARMREG_IP0, sizeof (mgreg_t)); + arm_addx_imm (code, ARMREG_IP1, ARMREG_IP1, sizeof (mgreg_t)); + arm_subx_imm (code, ARMREG_R0, ARMREG_R0, sizeof (mgreg_t)); + arm_b (code, label_start_copy); + mono_arm_patch (label_exit_copy, code, MONO_R_ARM64_BCC); + + /* Load CallContext* into IP0 */ + arm_ldrx (code, ARMREG_IP0, ARMREG_FP, off_methodargs); - if (i <= ARMREG_R7) { - arm_ldrx (code, i, ARMREG_R10, i * sizeof (mgreg_t)); - } else { - arm_ldrx (code, ARMREG_R11, ARMREG_R10, i * sizeof (mgreg_t)); - arm_strx (code, ARMREG_R11, ARMREG_SP, stack_offset); - stack_offset += sizeof (mgreg_t); - } - arm_subx_imm (code, ARMREG_R9, ARMREG_R9, 1); - } + /* set all general purpose registers from CallContext */ + for (i = 0; i < PARAM_REGS + 1; i++) + arm_ldrx (code, i, ARMREG_IP0, MONO_STRUCT_OFFSET (CallContext, gregs) + i * sizeof (mgreg_t)); - for (i = 0; i < gregs_num; i++) - mono_arm_patch (label_gexits [i], code, MONO_R_ARM64_BCC); + /* set all floating registers from CallContext */ + for (i = 0; i < FP_PARAM_REGS; i++) + arm_ldrfpx (code, i, ARMREG_IP0, MONO_STRUCT_OFFSET (CallContext, fregs) + i * sizeof (double)); /* load target addr */ - arm_ldrx (code, ARMREG_R11, ARMREG_FP, off_targetaddr); + arm_ldrx (code, ARMREG_IP0, ARMREG_FP, off_targetaddr); /* call into native function */ - arm_blrx (code, ARMREG_R11); + arm_blrx (code, ARMREG_IP0); - /* load InterpMethodArguments */ + /* load CallContext* */ arm_ldrx (code, ARMREG_IP0, ARMREG_FP, off_methodargs); - /* load is_float_ret */ - arm_ldrx (code, ARMREG_R11, ARMREG_IP0, MONO_STRUCT_OFFSET (InterpMethodArguments, is_float_ret)); - - /* check if a float return value is expected */ - arm_cmpx_imm (code, ARMREG_R11, 0); - label_is_float_ret = code; - arm_bcc (code, ARMCOND_NE, 0); - - /* greg return */ - /* load retval */ - arm_ldrx (code, ARMREG_R11, ARMREG_IP0, MONO_STRUCT_OFFSET (InterpMethodArguments, retval)); - - arm_cmpx_imm (code, ARMREG_R11, 0); - label_leave_tramp [0] = code; - arm_bcc (code, ARMCOND_EQ, 0); - - /* store greg result */ - arm_strx (code, ARMREG_R0, ARMREG_R11, 0); - - label_leave_tramp [1] = code; - arm_bcc (code, ARMCOND_AL, 0); - - /* freg return */ - mono_arm_patch (label_is_float_ret, code, MONO_R_ARM64_BCC); - /* load retval */ - arm_ldrx (code, ARMREG_R11, ARMREG_IP0, MONO_STRUCT_OFFSET (InterpMethodArguments, retval)); - - arm_cmpx_imm (code, ARMREG_R11, 0); - label_leave_tramp [2] = code; - arm_bcc (code, ARMCOND_EQ, 0); - - /* store freg result */ - arm_strfpx (code, ARMREG_D0, ARMREG_R11, 0); + /* set all general purpose registers to CallContext */ + for (i = 0; i < PARAM_REGS; i++) + arm_strx (code, i, ARMREG_IP0, MONO_STRUCT_OFFSET (CallContext, gregs) + i * sizeof (mgreg_t)); - for (i = 0; i < 3; i++) - mono_arm_patch (label_leave_tramp [i], code, MONO_R_ARM64_BCC); + /* set all floating registers to CallContext */ + for (i = 0; i < FP_PARAM_REGS; i++) + arm_strfpx (code, i, ARMREG_IP0, MONO_STRUCT_OFFSET (CallContext, fregs) + i * sizeof (double)); arm_movspx (code, ARMREG_SP, ARMREG_FP); arm_ldpx (code, ARMREG_FP, ARMREG_LR, ARMREG_SP, 0); -- 2.11.4.GIT