[jit] Add support for unlimited size/number of arguments to the dyn call code (#5612)
[mono.git] / mono / mini / mini-arm64.c
index 9edb57aa9ef87da6594dea1b82e87867f7ee5dfe..6192f26b9cf042e653ad287c859bb881aafebca0 100644 (file)
@@ -1381,9 +1381,6 @@ dyn_call_supported (CallInfo *cinfo, MonoMethodSignature *sig)
 {
        int i;
 
-       if (sig->hasthis + sig->param_count > PARAM_REGS + DYN_CALL_STACK_ARGS)
-               return FALSE;
-
        // FIXME: Add more cases
        switch (cinfo->ret.storage) {
        case ArgNone:
@@ -1412,10 +1409,7 @@ dyn_call_supported (CallInfo *cinfo, MonoMethodSignature *sig)
                case ArgInFRegR4:
                case ArgHFA:
                case ArgVtypeByRef:
-                       break;
                case ArgOnStack:
-                       if (ainfo->offset >= DYN_CALL_STACK_ARGS * sizeof (mgreg_t))
-                               return FALSE;
                        break;
                default:
                        return FALSE;
@@ -1473,6 +1467,15 @@ mono_arch_dyn_call_free (MonoDynCallInfo *info)
        g_free (ainfo);
 }
 
+int
+mono_arch_dyn_call_get_buf_size (MonoDynCallInfo *info)
+{
+       ArchDynCallInfo *ainfo = (ArchDynCallInfo*)info;
+
+       g_assert (ainfo->cinfo->stack_usage % MONO_ARCH_FRAME_ALIGNMENT == 0);
+       return sizeof (DynCallArgs) + ainfo->cinfo->stack_usage;
+}
+
 static double
 bitcast_r4_to_r8 (float f)
 {
@@ -1490,7 +1493,7 @@ bitcast_r8_to_r4 (double f)
 }
 
 void
-mono_arch_start_dyn_call (MonoDynCallInfo *info, gpointer **args, guint8 *ret, guint8 *buf, int buf_len)
+mono_arch_start_dyn_call (MonoDynCallInfo *info, gpointer **args, guint8 *ret, guint8 *buf)
 {
        ArchDynCallInfo *dinfo = (ArchDynCallInfo*)info;
        DynCallArgs *p = (DynCallArgs*)buf;
@@ -1499,12 +1502,11 @@ mono_arch_start_dyn_call (MonoDynCallInfo *info, gpointer **args, guint8 *ret, g
        CallInfo *cinfo = dinfo->cinfo;
        int buffer_offset = 0;
 
-       g_assert (buf_len >= sizeof (DynCallArgs));
-
        p->res = 0;
        p->ret = ret;
        p->n_fpargs = dinfo->n_fpargs;
        p->n_fpret = dinfo->n_fpret;
+       p->n_stackargs = cinfo->stack_usage / sizeof (mgreg_t);
 
        arg_index = 0;
        greg = 0;
@@ -4175,14 +4177,35 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                code = emit_ldrfpx (code, ARMREG_D0 + i, ARMREG_LR, MONO_STRUCT_OFFSET (DynCallArgs, fpregs) + (i * 8));
                        arm_patch_rel (labels [0], code, MONO_R_ARM64_BCC);
 
+                       /* Allocate callee area */
+                       code = emit_ldrx (code, ARMREG_R0, ARMREG_LR, MONO_STRUCT_OFFSET (DynCallArgs, n_stackargs));
+                       arm_lslw (code, ARMREG_R0, ARMREG_R0, 3);
+                       arm_movspx (code, ARMREG_R1, ARMREG_SP);
+                       arm_subx (code, ARMREG_R1, ARMREG_R1, ARMREG_R0);
+                       arm_movspx (code, ARMREG_SP, ARMREG_R1);
+
                        /* Set stack args */
-                       for (i = 0; i < DYN_CALL_STACK_ARGS; ++i) {
-                               code = emit_ldrx (code, ARMREG_R0, ARMREG_LR, MONO_STRUCT_OFFSET (DynCallArgs, regs) + ((PARAM_REGS + 1 + i) * sizeof (mgreg_t)));
-                               code = emit_strx (code, ARMREG_R0, ARMREG_SP, i * sizeof (mgreg_t));
-                       }
+                       /* R1 = limit */
+                       code = emit_ldrx (code, ARMREG_R1, ARMREG_LR, MONO_STRUCT_OFFSET (DynCallArgs, n_stackargs));
+                       /* R2 = pointer into 'regs' */
+                       code = emit_imm (code, ARMREG_R2, MONO_STRUCT_OFFSET (DynCallArgs, regs) + ((PARAM_REGS + 1) * sizeof (mgreg_t)));
+                       arm_addx (code, ARMREG_R2, ARMREG_LR, ARMREG_R2);
+                       /* R3 = pointer to stack */
+                       arm_movspx (code, ARMREG_R3, ARMREG_SP);
+                       labels [0] = code;
+                       arm_b (code, code);
+                       labels [1] = code;
+                       code = emit_ldrx (code, ARMREG_R5, ARMREG_R2, 0);
+                       code = emit_strx (code, ARMREG_R5, ARMREG_R3, 0);
+                       code = emit_addx_imm (code, ARMREG_R2, ARMREG_R2, sizeof (mgreg_t));
+                       code = emit_addx_imm (code, ARMREG_R3, ARMREG_R3, sizeof (mgreg_t));
+                       code = emit_subx_imm (code, ARMREG_R1, ARMREG_R1, 1);
+                       arm_patch_rel (labels [0], code, MONO_R_ARM64_B);
+                       arm_cmpw (code, ARMREG_R1, ARMREG_RZR);
+                       arm_bcc (code, ARMCOND_GT, labels [1]);
 
                        /* Set argument registers + r8 */
-                       code = mono_arm_emit_load_regarray (code, 0x1ff, ARMREG_LR, 0);
+                       code = mono_arm_emit_load_regarray (code, 0x1ff, ARMREG_LR, MONO_STRUCT_OFFSET (DynCallArgs, regs));
 
                        /* Make the call */
                        arm_blrx (code, ARMREG_IP1);