Skip to content

Commit

Permalink
[arm64] Remove the limitation on the number of nullable arguments for…
Browse files Browse the repository at this point in the history
… dyncalls. (mono#11186)

* [arm64] Remove the limitation on the number of nullable arguments for dyncalls.

Fixes xamarin/xamarin-macios#4984.

* [amd64] Remove the limitation on the number of nullable arguments for dyncalls.

* [jit] Add tests for dyncalls with lots of nullable arguments.
  • Loading branch information
vargaz authored and akoeplinger committed Oct 18, 2018
1 parent d16869c commit ab18dea
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 13 deletions.
13 changes: 13 additions & 0 deletions mono/mini/aot-tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,14 @@ public static Nullable<T> Get<T>(T t) where T : struct {
return t;
}

[MethodImplAttribute (MethodImplOptions.NoInlining)]
public static int NullableMany(long? i1, long? i2, long? i3, long? i4, long? i5, long? i6, long? i7, long? i8,
long? i11, long? i12, long? i13, long? i14, long? i15, long? i16, long? i17, long? i18,
long? i21, long? i22, long? i23, long? i24, long? i25, long? i26, long? i27, long? i28,
long? i31, long? i32, long? i33, long? i34, long? i35, long? i36, long? i37, long? i38) {
return (int)((i1 + i8 + i11 + i18 + i21 + i28 + i31 + i38).Value);
}

[MethodImplAttribute (MethodImplOptions.NoInlining)]
public static Nullable<T> GetNull<T>() where T : struct {
return null;
Expand Down Expand Up @@ -424,6 +432,11 @@ public static int test_0_dyncall_nullable () {
res2 = (int?)typeof (NullableMethods).GetMethod ("GetNull").MakeGenericMethod (new Type [] { typeof (int) }).Invoke (null, new object [] { });
if (res2.HasValue)
return 5;

NullableMethods.NullableMany (1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8);
res2 = (int?)typeof (NullableMethods).GetMethod ("NullableMany").Invoke (null, new object [] { 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L });
if (res2 != 36)
return 6;
return 0;
}

Expand Down
51 changes: 45 additions & 6 deletions mono/mini/mini-amd64.c
Original file line number Diff line number Diff line change
Expand Up @@ -2531,7 +2531,7 @@ mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
typedef struct {
MonoMethodSignature *sig;
CallInfo *cinfo;
int nstack_args;
int nstack_args, nullable_area;
} ArchDynCallInfo;

static gboolean
Expand Down Expand Up @@ -2583,7 +2583,7 @@ mono_arch_dyn_call_prepare (MonoMethodSignature *sig)
{
ArchDynCallInfo *info;
CallInfo *cinfo;
int i;
int i, aindex;

cinfo = get_call_info (NULL, sig);

Expand All @@ -2609,6 +2609,34 @@ mono_arch_dyn_call_prepare (MonoMethodSignature *sig)
break;
}
}

for (aindex = 0; aindex < sig->param_count; aindex++) {
MonoType *t = sig->params [aindex];
ArgInfo *ainfo = &cinfo->args [aindex + sig->hasthis];

if (t->byref)
continue;

switch (t->type) {
case MONO_TYPE_GENERICINST:
if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type_internal (t))) {
MonoClass *klass = mono_class_from_mono_type_internal (t);
int size;

if (!(ainfo->storage == ArgValuetypeInReg || ainfo->storage == ArgOnStack)) {
/* Nullables need a temporary buffer, its stored at the end of DynCallArgs.regs after the stack args */
size = mono_class_value_size (klass, NULL);
info->nullable_area += size;
}
}
break;
default:
break;
}
}

info->nullable_area = ALIGN_TO (info->nullable_area, 16);

/* Align to 16 bytes */
if (info->nstack_args & 1)
info->nstack_args ++;
Expand Down Expand Up @@ -2636,7 +2664,7 @@ mono_arch_dyn_call_get_buf_size (MonoDynCallInfo *info)
ArchDynCallInfo *ainfo = (ArchDynCallInfo*)info;

/* Extend the 'regs' field dynamically */
return sizeof (DynCallArgs) + (ainfo->nstack_args * sizeof (mgreg_t));
return sizeof (DynCallArgs) + (ainfo->nstack_args * sizeof (mgreg_t)) + ainfo->nullable_area;
}

#define PTR_TO_GREG(ptr) (mgreg_t)(ptr)
Expand Down Expand Up @@ -2664,6 +2692,7 @@ mono_arch_start_dyn_call (MonoDynCallInfo *info, gpointer **args, guint8 *ret, g
int arg_index, greg, i, pindex;
MonoMethodSignature *sig = dinfo->sig;
int buffer_offset = 0;
guint8 *nullable_buffer;
static int general_param_reg_to_index[MONO_MAX_IREGS];
static int float_param_reg_to_index[MONO_MAX_FREGS];

Expand All @@ -2688,6 +2717,12 @@ mono_arch_start_dyn_call (MonoDynCallInfo *info, gpointer **args, guint8 *ret, g
greg = 0;
pindex = 0;

/* Stored after the stack arguments */
nullable_buffer = (guint8*)&(p->regs [PARAM_REGS + (dinfo->nstack_args * sizeof (mgreg_t))]);

if (dinfo->nullable_area)
printf ("%d\n", dinfo->nullable_area);

if (sig->hasthis || dinfo->cinfo->vret_arg_index == 1) {
p->regs [greg ++] = PTR_TO_GREG(*(args [arg_index ++]));
if (!sig->hasthis)
Expand Down Expand Up @@ -2784,9 +2819,13 @@ mono_arch_start_dyn_call (MonoDynCallInfo *info, gpointer **args, guint8 *ret, g
int size;

size = mono_class_value_size (klass, NULL);
nullable_buf = p->buffer + buffer_offset;
buffer_offset += size;
g_assert (buffer_offset <= 256);
if (ainfo->storage == ArgValuetypeInReg || ainfo->storage == ArgOnStack) {
nullable_buf = g_alloca (size);
} else {
nullable_buf = nullable_buffer + buffer_offset;
buffer_offset += size;
g_assert (buffer_offset <= dinfo->nullable_area);
}

/* The argument pointed to by arg is either a boxed vtype or null */
mono_nullable_init (nullable_buf, (MonoObject*)arg, klass);
Expand Down
1 change: 0 additions & 1 deletion mono/mini/mini-amd64.h
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,6 @@ typedef struct {
double fregs [8];
mgreg_t has_fp;
mgreg_t nstack_args;
guint8 buffer [256];
/* This should come last as the structure is dynamically extended */
mgreg_t regs [PARAM_REGS];
} DynCallArgs;
Expand Down
36 changes: 31 additions & 5 deletions mono/mini/mini-arm64.c
Original file line number Diff line number Diff line change
Expand Up @@ -1581,7 +1581,7 @@ typedef struct {
CallInfo *cinfo;
MonoType *rtype;
MonoType **param_types;
int n_fpargs, n_fpret;
int n_fpargs, n_fpret, nullable_area;
} ArchDynCallInfo;

static gboolean
Expand Down Expand Up @@ -1634,7 +1634,7 @@ mono_arch_dyn_call_prepare (MonoMethodSignature *sig)
{
ArchDynCallInfo *info;
CallInfo *cinfo;
int i;
int i, aindex;

cinfo = get_call_info (NULL, sig);

Expand Down Expand Up @@ -1663,6 +1663,28 @@ mono_arch_dyn_call_prepare (MonoMethodSignature *sig)
default:
break;
}

for (aindex = 0; aindex < sig->param_count; aindex++) {
MonoType *t = info->param_types [aindex];

if (t->byref)
continue;

switch (t->type) {
case MONO_TYPE_GENERICINST:
if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type_internal (t))) {
MonoClass *klass = mono_class_from_mono_type_internal (t);
int size;

/* Nullables need a temporary buffer, its stored at the end of DynCallArgs.regs after the stack args */
size = mono_class_value_size (klass, NULL);
info->nullable_area += size;
}
break;
default:
break;
}
}

return (MonoDynCallInfo*)info;
}
Expand All @@ -1683,7 +1705,7 @@ 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;
return sizeof (DynCallArgs) + ainfo->cinfo->stack_usage + ainfo->nullable_area;
}

static double
Expand Down Expand Up @@ -1711,6 +1733,7 @@ mono_arch_start_dyn_call (MonoDynCallInfo *info, gpointer **args, guint8 *ret, g
MonoMethodSignature *sig = dinfo->sig;
CallInfo *cinfo = dinfo->cinfo;
int buffer_offset = 0;
guint8 *nullable_buffer;

p->res = 0;
p->ret = ret;
Expand All @@ -1722,6 +1745,9 @@ mono_arch_start_dyn_call (MonoDynCallInfo *info, gpointer **args, guint8 *ret, g
greg = 0;
pindex = 0;

/* Stored after the stack arguments */
nullable_buffer = (guint8*)&(p->regs [PARAM_REGS + 1 + (cinfo->stack_usage / sizeof (mgreg_t))]);

if (sig->hasthis)
p->regs [greg ++] = (mgreg_t)*(args [arg_index ++]);

Expand Down Expand Up @@ -1827,9 +1853,9 @@ mono_arch_start_dyn_call (MonoDynCallInfo *info, gpointer **args, guint8 *ret, g
* if the nullable param is passed by ref.
*/
size = mono_class_value_size (klass, NULL);
nullable_buf = p->buffer + buffer_offset;
nullable_buf = nullable_buffer + buffer_offset;
buffer_offset += size;
g_assert (buffer_offset <= 256);
g_assert (buffer_offset <= dinfo->nullable_area);

/* The argument pointed to by arg is either a boxed vtype or null */
mono_nullable_init (nullable_buf, (MonoObject*)arg, klass);
Expand Down
1 change: 0 additions & 1 deletion mono/mini/mini-arm64.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@ typedef struct {
guint8 *ret;
double fpregs [FP_PARAM_REGS];
int n_fpargs, n_fpret, n_stackargs;
guint8 buffer [256];
/* This should come last as the structure is dynamically extended */
/* The +1 is for r8 */
mgreg_t regs [PARAM_REGS + 1];
Expand Down

0 comments on commit ab18dea

Please sign in to comment.