void
mono_interp_error_cleanup (MonoError *error);
+int
+mono_mint_type (MonoType *type);
+
+int
+mono_interp_type_size (MonoType *type, int mt, int *align_p);
+
#if HOST_BROWSER
gboolean
void
mono_jiterp_ld_delegate_method_ptr (gpointer *destination, MonoDelegate **source);
-int
+void
mono_jiterp_stackval_to_data (MonoType *type, stackval *val, void *data);
-int
+void
mono_jiterp_stackval_from_data (MonoType *type, stackval *result, const void *data);
+int
+mono_jiterp_get_arg_offset (InterpMethod *imethod, MonoMethodSignature *sig, int index);
+
gpointer
mono_jiterp_frame_data_allocator_alloc (FrameDataAllocator *stack, InterpFrame *frame, int size);
#endif
-static inline int
-mint_type(MonoType *type)
-{
- if (m_type_is_byref (type))
- return MINT_TYPE_I;
-enum_type:
- switch (type->type) {
- case MONO_TYPE_I1:
- return MINT_TYPE_I1;
- case MONO_TYPE_U1:
- case MONO_TYPE_BOOLEAN:
- return MINT_TYPE_U1;
- case MONO_TYPE_I2:
- return MINT_TYPE_I2;
- case MONO_TYPE_U2:
- case MONO_TYPE_CHAR:
- return MINT_TYPE_U2;
- case MONO_TYPE_I4:
- case MONO_TYPE_U4:
- return MINT_TYPE_I4;
- case MONO_TYPE_I:
- case MONO_TYPE_U:
- case MONO_TYPE_PTR:
- case MONO_TYPE_FNPTR:
- return MINT_TYPE_I;
- case MONO_TYPE_R4:
- return MINT_TYPE_R4;
- case MONO_TYPE_I8:
- case MONO_TYPE_U8:
- return MINT_TYPE_I8;
- case MONO_TYPE_R8:
- return MINT_TYPE_R8;
- case MONO_TYPE_STRING:
- case MONO_TYPE_SZARRAY:
- case MONO_TYPE_CLASS:
- case MONO_TYPE_OBJECT:
- case MONO_TYPE_ARRAY:
- return MINT_TYPE_O;
- case MONO_TYPE_VALUETYPE:
- if (m_class_is_enumtype (type->data.klass)) {
- type = mono_class_enum_basetype_internal (type->data.klass);
- goto enum_type;
- } else
- return MINT_TYPE_VT;
- case MONO_TYPE_TYPEDBYREF:
- return MINT_TYPE_VT;
- case MONO_TYPE_GENERICINST:
- type = m_class_get_byval_arg (type->data.generic_class->container_class);
- goto enum_type;
- case MONO_TYPE_VOID:
- return MINT_TYPE_VOID;
- default:
- g_warning ("got type 0x%02x", type->type);
- g_assert_not_reached ();
- }
- return -1;
-}
-
#endif /* __MONO_MINI_INTERPRETER_INTERNALS_H__ */
frame->state.ip = NULL;
}
+#define STACK_ADD_ALIGNED_BYTES(sp,bytes) ((stackval*)((char*)(sp) + (bytes)))
#define STACK_ADD_BYTES(sp,bytes) ((stackval*)((char*)(sp) + ALIGN_TO(bytes, MINT_STACK_SLOT_SIZE)))
#define STACK_SUB_BYTES(sp,bytes) ((stackval*)((char*)(sp) - ALIGN_TO(bytes, MINT_STACK_SLOT_SIZE)))
}
}
-// Returns the size it uses on the interpreter stack
-static int
-stackval_size (MonoType *type, gboolean pinvoke)
-{
- if (m_type_is_byref (type))
- return MINT_STACK_SLOT_SIZE;
- switch (type->type) {
- case MONO_TYPE_VOID:
- return 0;
- case MONO_TYPE_I1:
- case MONO_TYPE_U1:
- case MONO_TYPE_BOOLEAN:
- case MONO_TYPE_I2:
- case MONO_TYPE_U2:
- case MONO_TYPE_CHAR:
- case MONO_TYPE_I4:
- case MONO_TYPE_U:
- case MONO_TYPE_I:
- case MONO_TYPE_PTR:
- case MONO_TYPE_FNPTR:
- case MONO_TYPE_U4:
- return MINT_STACK_SLOT_SIZE;
- case MONO_TYPE_R4:
- return MINT_STACK_SLOT_SIZE;
- case MONO_TYPE_I8:
- case MONO_TYPE_U8:
- return MINT_STACK_SLOT_SIZE;
- case MONO_TYPE_R8:
- return MINT_STACK_SLOT_SIZE;
- case MONO_TYPE_STRING:
- case MONO_TYPE_SZARRAY:
- case MONO_TYPE_CLASS:
- case MONO_TYPE_OBJECT:
- case MONO_TYPE_ARRAY:
- return MINT_STACK_SLOT_SIZE;
- case MONO_TYPE_VALUETYPE:
- if (m_class_is_enumtype (type->data.klass)) {
- return stackval_size (mono_class_enum_basetype_internal (type->data.klass), pinvoke);
- } else {
- int size;
- if (pinvoke)
- size = mono_class_native_size (type->data.klass, NULL);
- else
- size = mono_class_value_size (type->data.klass, NULL);
- return ALIGN_TO (size, MINT_STACK_SLOT_SIZE);
- }
- case MONO_TYPE_GENERICINST: {
- if (mono_type_generic_inst_is_valuetype (type)) {
- MonoClass *klass = mono_class_from_mono_type_internal (type);
- int size;
- if (pinvoke)
- size = mono_class_native_size (klass, NULL);
- else
- size = mono_class_value_size (klass, NULL);
- return ALIGN_TO (size, MINT_STACK_SLOT_SIZE);
- }
- return stackval_size (m_class_get_byval_arg (type->data.generic_class->container_class), pinvoke);
- }
- default:
- g_error ("got type 0x%02x", type->type);
- }
-}
-
-// Returns the size it uses on the interpreter stack
-static int
+static void
stackval_from_data (MonoType *type, stackval *result, const void *data, gboolean pinvoke)
{
if (m_type_is_byref (type)) {
result->data.p = *(gpointer*)data;
- return MINT_STACK_SLOT_SIZE;
+ return;
}
switch (type->type) {
case MONO_TYPE_VOID:
- return 0;
+ break;;
case MONO_TYPE_I1:
result->data.i = *(gint8*)data;
- return MINT_STACK_SLOT_SIZE;
+ break;
case MONO_TYPE_U1:
case MONO_TYPE_BOOLEAN:
result->data.i = *(guint8*)data;
- return MINT_STACK_SLOT_SIZE;
+ break;
case MONO_TYPE_I2:
result->data.i = *(gint16*)data;
- return MINT_STACK_SLOT_SIZE;
+ break;
case MONO_TYPE_U2:
case MONO_TYPE_CHAR:
result->data.i = *(guint16*)data;
- return MINT_STACK_SLOT_SIZE;
+ break;
case MONO_TYPE_I4:
result->data.i = *(gint32*)data;
- return MINT_STACK_SLOT_SIZE;
+ break;
case MONO_TYPE_U:
case MONO_TYPE_I:
result->data.nati = *(mono_i*)data;
- return MINT_STACK_SLOT_SIZE;
+ break;
case MONO_TYPE_PTR:
case MONO_TYPE_FNPTR:
result->data.p = *(gpointer*)data;
- return MINT_STACK_SLOT_SIZE;
+ break;
case MONO_TYPE_U4:
result->data.i = *(guint32*)data;
- return MINT_STACK_SLOT_SIZE;
+ break;
case MONO_TYPE_R4:
/* memmove handles unaligned case */
memmove (&result->data.f_r4, data, sizeof (float));
- return MINT_STACK_SLOT_SIZE;
+ break;
case MONO_TYPE_I8:
case MONO_TYPE_U8:
memmove (&result->data.l, data, sizeof (gint64));
- return MINT_STACK_SLOT_SIZE;
+ break;
case MONO_TYPE_R8:
memmove (&result->data.f, data, sizeof (double));
- return MINT_STACK_SLOT_SIZE;
+ break;
case MONO_TYPE_STRING:
case MONO_TYPE_SZARRAY:
case MONO_TYPE_CLASS:
case MONO_TYPE_OBJECT:
case MONO_TYPE_ARRAY:
result->data.p = *(gpointer*)data;
- return MINT_STACK_SLOT_SIZE;
+ break;
case MONO_TYPE_VALUETYPE:
if (m_class_is_enumtype (type->data.klass)) {
- return stackval_from_data (mono_class_enum_basetype_internal (type->data.klass), result, data, pinvoke);
+ stackval_from_data (mono_class_enum_basetype_internal (type->data.klass), result, data, pinvoke);
+ break;
} else {
int size;
if (pinvoke)
else
size = mono_class_value_size (type->data.klass, NULL);
memcpy (result, data, size);
- return ALIGN_TO (size, MINT_STACK_SLOT_SIZE);
+ break;
}
case MONO_TYPE_GENERICINST: {
if (mono_type_generic_inst_is_valuetype (type)) {
else
size = mono_class_value_size (klass, NULL);
memcpy (result, data, size);
- return ALIGN_TO (size, MINT_STACK_SLOT_SIZE);
+ break;
}
- return stackval_from_data (m_class_get_byval_arg (type->data.generic_class->container_class), result, data, pinvoke);
+ stackval_from_data (m_class_get_byval_arg (type->data.generic_class->container_class), result, data, pinvoke);
+ break;
}
default:
g_error ("got type 0x%02x", type->type);
/* Does not handle `this` argument */
static guint32
-compute_arg_offset (MonoMethodSignature *sig, int index, int prev_offset)
+compute_arg_offset (MonoMethodSignature *sig, int index)
{
if (index == 0)
return 0;
- if (prev_offset == -1) {
- guint32 offset = 0;
- for (int i = 0; i < index; i++) {
- int size, align;
- MonoType *type = sig->params [i];
- size = mono_type_size (type, &align);
- offset += ALIGN_TO (size, MINT_STACK_SLOT_SIZE);
- }
- return offset;
- } else {
- int size, align;
- MonoType *type = sig->params [index - 1];
- size = mono_type_size (type, &align);
- return prev_offset + ALIGN_TO (size, MINT_STACK_SLOT_SIZE);
+ guint32 offset = 0;
+ int size, align;
+ MonoType *type;
+ for (int i = 0; i < index; i++) {
+ type = sig->params [i];
+ size = mono_interp_type_size (type, mono_mint_type (type), &align);
+
+ offset = ALIGN_TO (offset, align);
+ offset += size;
}
+ type = sig->params [index];
+ mono_interp_type_size (type, mono_mint_type (type), &align);
+
+ offset = ALIGN_TO (offset, align);
+ return offset;
}
static guint32*
if (!sig)
sig = mono_method_signature_internal (imethod->method);
int arg_count = sig->hasthis + sig->param_count;
- g_assert (arg_count);
- guint32 *arg_offsets = (guint32*) g_malloc ((sig->hasthis + sig->param_count) * sizeof (int));
- int index = 0, offset_addend = 0, prev_offset = 0;
+ guint32 *arg_offsets = (guint32*) g_malloc ((arg_count + 1) * sizeof (int));
+ int index = 0, offset = 0;
if (sig->hasthis) {
arg_offsets [index++] = 0;
- offset_addend = MINT_STACK_SLOT_SIZE;
+ offset = MINT_STACK_SLOT_SIZE;
}
for (int i = 0; i < sig->param_count; i++) {
- prev_offset = compute_arg_offset (sig, i, prev_offset);
- arg_offsets [index++] = prev_offset + offset_addend;
+ MonoType *type = sig->params [i];
+ int size, align;
+ size = mono_interp_type_size (type, mono_mint_type (type), &align);
+
+ offset = ALIGN_TO (offset, align);
+ arg_offsets [index++] = offset;
+ offset += size;
}
+ // This index is not associated with an actual argument, we just store the offset
+ // for convenience in order to easily determine the size of the param area used
+ arg_offsets [index] = ALIGN_TO (offset, MINT_STACK_SLOT_SIZE);
mono_memory_write_barrier ();
if (mono_atomic_cas_ptr ((gpointer*)&imethod->arg_offsets, arg_offsets, NULL) != NULL)
return get_arg_offset_fast (imethod, sig, index);
} else {
g_assert (!sig->hasthis);
- return compute_arg_offset (sig, index, -1);
+ return compute_arg_offset (sig, index);
}
}
{
InterpMethod *rmethod;
ThreadContext *context;
- stackval *sp, *sp_args;
+ stackval *sp;
+ int stack_index = 0;
MonoMethod *method;
MonoMethodSignature *sig;
MonoType *type;
orig_domain = mono_threads_attach_coop (mono_domain_get (), &attach_cookie);
context = get_context ();
- sp_args = sp = (stackval*)context->stack_pointer;
+ sp = (stackval*)context->stack_pointer;
method = rmethod->method;
// FIXME: Optimize this
if (sig->hasthis) {
- sp_args->data.p = data->this_arg;
- sp_args++;
+ sp->data.p = data->this_arg;
+ stack_index = 1;
}
gpointer *params;
else
params = data->args;
for (i = 0; i < sig->param_count; ++i) {
- if (m_type_is_byref (sig->params [i])) {
- sp_args->data.p = params [i];
- sp_args++;
- } else {
- int size = stackval_from_data (sig->params [i], sp_args, params [i], FALSE);
- sp_args = STACK_ADD_BYTES (sp_args, size);
- }
+ int arg_offset = get_arg_offset_fast (rmethod, NULL, stack_index + i);
+ stackval *sval = STACK_ADD_ALIGNED_BYTES (sp, arg_offset);
+
+ if (m_type_is_byref (sig->params [i]))
+ sval->data.p = params [i];
+ else
+ stackval_from_data (sig->params [i], sval, params [i], FALSE);
}
- sp_args = (stackval*)ALIGN_TO (sp_args, MINT_STACK_ALIGNMENT);
InterpFrame frame = {0};
frame.imethod = data->rmethod;
frame.stack = sp;
frame.retval = sp;
- context->stack_pointer = (guchar*)sp_args;
+ int params_size = get_arg_offset_fast (rmethod, NULL, stack_index + sig->param_count);
+ context->stack_pointer = (guchar*)ALIGN_TO ((guchar*)sp + params_size, MINT_STACK_ALIGNMENT);
g_assert (context->stack_pointer < context->stack_end);
MONO_ENTER_GC_UNSAFE;
cinfo->wrapper = jit_wrapper;
if (sig->ret->type != MONO_TYPE_VOID) {
- int mt = mint_type (sig->ret);
+ int mt = mono_mint_type (sig->ret);
if (mt == MINT_TYPE_VT) {
MonoClass *klass = mono_class_from_mono_type_internal (sig->ret);
/*
for (guint i = 0; i < rmethod->param_count; ++i) {
MonoType *t = rmethod->param_types [i];
- int mt = mint_type (t);
+ int mt = mono_mint_type (t);
if (m_type_is_byref (sig->params [i])) {
cinfo->arginfo [i] = JIT_ARG_BYVAL;
} else if (mt == MINT_TYPE_O) {
if (cinfo->ret_mt != -1)
args [pindex ++] = ret_sp;
for (guint i = 0; i < rmethod->param_count; ++i) {
- stackval *sval = STACK_ADD_BYTES (sp, get_arg_offset_fast (rmethod, NULL, stack_index + i));
+ stackval *sval = STACK_ADD_ALIGNED_BYTES (sp, get_arg_offset_fast (rmethod, NULL, stack_index + i));
if (cinfo->arginfo [i] == JIT_ARG_BYVAL)
args [pindex ++] = sval->data.p;
else
MonoMethodILState *il_state = (MonoMethodILState*)il_state_ptr;
MonoMethodSignature *sig;
ThreadContext *context = get_context ();
- stackval *orig_sp;
- stackval *sp, *sp_args;
+ stackval *sp;
InterpMethod *imethod;
FrameClauseArgs clause_args;
ERROR_DECL (error);
mono_error_assert_ok (error);
}
- orig_sp = sp_args = sp = (stackval*)context->stack_pointer;
+ sp = (stackval*)context->stack_pointer;
gpointer ret_addr = NULL;
ret_addr = il_state->data [findex];
findex ++;
}
+ int first_param_index = 0;
if (sig->hasthis) {
if (il_state->data [findex])
- sp_args->data.p = *(gpointer*)il_state->data [findex];
- sp_args++;
+ sp->data.p = *(gpointer*)il_state->data [findex];
+ first_param_index = 1;
findex ++;
}
for (int i = 0; i < sig->param_count; ++i) {
if (il_state->data [findex]) {
- int size = stackval_from_data (sig->params [i], sp_args, il_state->data [findex], FALSE);
- sp_args = STACK_ADD_BYTES (sp_args, size);
- } else {
- int size = stackval_size (sig->params [i], FALSE);
- sp_args = STACK_ADD_BYTES (sp_args, size);
+ int arg_offset = get_arg_offset_fast (imethod, NULL, first_param_index + i);
+ stackval *sval = STACK_ADD_ALIGNED_BYTES (sp, arg_offset);
+
+ stackval_from_data (sig->params [i], sval, il_state->data [findex], FALSE);
}
findex ++;
}
- sp_args = (stackval*)ALIGN_TO (sp_args, MINT_STACK_ALIGNMENT);
/* Allocate frame */
InterpFrame frame = {0};
frame.stack = sp;
frame.retval = sp;
- context->stack_pointer = (guchar*)sp_args;
+ int params_size = get_arg_offset_fast (imethod, NULL, first_param_index + sig->param_count);
+ context->stack_pointer = (guchar*)ALIGN_TO ((guchar*)sp + params_size, MINT_STACK_ALIGNMENT);
context->stack_pointer += imethod->alloca_size;
g_assert (context->stack_pointer < context->stack_end);
mono_interp_exec_method (&frame, context, &clause_args);
/* Write back args */
- sp_args = sp;
findex = 0;
if (sig->ret->type != MONO_TYPE_VOID)
findex ++;
if (sig->hasthis) {
// FIXME: This
- sp_args++;
findex ++;
}
for (int i = 0; i < sig->param_count; ++i) {
if (il_state->data [findex]) {
- int size = stackval_to_data (sig->params [i], sp_args, il_state->data [findex], FALSE);
- sp_args = STACK_ADD_BYTES (sp_args, size);
- } else {
- int size = stackval_size (sig->params [i], FALSE);
- sp_args = STACK_ADD_BYTES (sp_args, size);
+ int arg_offset = get_arg_offset_fast (imethod, NULL, first_param_index + i);
+ stackval *sval = STACK_ADD_ALIGNED_BYTES (sp, arg_offset);
+
+ stackval_to_data (sig->params [i], sval, il_state->data [findex], FALSE);
}
findex ++;
}
*filtered = frame.retval->data.i;
}
- memset (orig_sp, 0, (guint8*)context->stack_pointer - (guint8*)orig_sp);
- context->stack_pointer = (guchar*)orig_sp;
+ memset (sp, 0, (guint8*)context->stack_pointer - (guint8*)sp);
+ context->stack_pointer = (guchar*)sp;
check_pending_unwind (context);
}
#ifdef HOST_BROWSER
-EMSCRIPTEN_KEEPALIVE int
+EMSCRIPTEN_KEEPALIVE void
mono_jiterp_stackval_to_data (MonoType *type, stackval *val, void *data)
{
- return stackval_to_data (type, val, data, FALSE);
+ stackval_to_data (type, val, data, FALSE);
}
-EMSCRIPTEN_KEEPALIVE int
+EMSCRIPTEN_KEEPALIVE void
mono_jiterp_stackval_from_data (MonoType *type, stackval *result, const void *data)
{
- return stackval_from_data (type, result, data, FALSE);
+ stackval_from_data (type, result, data, FALSE);
+}
+
+EMSCRIPTEN_KEEPALIVE int
+mono_jiterp_get_arg_offset (InterpMethod *imethod, MonoMethodSignature *sig, int index)
+{
+ return get_arg_offset_fast (imethod, sig, index);
}
EMSCRIPTEN_KEEPALIVE int
// in the correct place and compute the stack offset, then it passes that in to this
// function in order to actually enter the interpreter and process the return value
EMSCRIPTEN_KEEPALIVE void
-mono_jiterp_interp_entry (JiterpEntryData *_data, stackval *sp_args, void *res)
+mono_jiterp_interp_entry (JiterpEntryData *_data, void *res)
{
JiterpEntryDataHeader header;
MonoType *type;
g_assert(header.rmethod);
g_assert(header.rmethod->method);
- g_assert(sp_args);
stackval *sp = (stackval*)header.context->stack_pointer;
frame.stack = sp;
frame.retval = sp;
- header.context->stack_pointer = (guchar*)sp_args;
- g_assert ((guchar*)sp_args < header.context->stack_end);
+ int params_size = get_arg_offset_fast (header.rmethod, NULL, header.params_count);
+ // g_printf ("jiterp_interp_entry: rmethod=%d, params_count=%d, params_size=%d\n", header.rmethod, header.params_count, params_size);
+ header.context->stack_pointer = (guchar*)ALIGN_TO ((guchar*)sp + params_size, MINT_STACK_ALIGNMENT);
+;
+ g_assert (header.context->stack_pointer < header.context->stack_end);
MONO_ENTER_GC_UNSAFE;
mono_interp_exec_method (&frame, header.context, NULL);
#define JITERP_MEMBER_BACKWARD_BRANCH_OFFSETS 10
#define JITERP_MEMBER_BACKWARD_BRANCH_OFFSETS_COUNT 11
#define JITERP_MEMBER_CLAUSE_DATA_OFFSETS 12
+#define JITERP_MEMBER_PARAMS_COUNT 13
// we use these helpers at JIT time to figure out where to do memory loads and stores
EMSCRIPTEN_KEEPALIVE size_t
return offsetof (InterpMethod, clause_data_offsets);
case JITERP_MEMBER_RMETHOD:
return offsetof (JiterpEntryDataHeader, rmethod);
+ case JITERP_MEMBER_PARAMS_COUNT:
+ return offsetof (JiterpEntryDataHeader, params_count);
case JITERP_MEMBER_SPAN_LENGTH:
return offsetof (MonoSpanOfVoid, _length);
case JITERP_MEMBER_SPAN_DATA:
ThreadContext *context;
gpointer orig_domain;
gpointer attach_cookie;
+ int params_count;
} JiterpEntryDataHeader;
// we optimize delegate calls by attempting to cache the delegate invoke
mono_jiterp_do_safepoint (InterpFrame *frame, guint16 *ip);
void
-mono_jiterp_interp_entry (JiterpEntryData *_data, stackval *sp_args, void *res);
+mono_jiterp_interp_entry (JiterpEntryData *_data, void *res);
gpointer
mono_jiterp_imethod_to_ftnptr (InterpMethod *imethod);
td->last_ins->sregs [i] = td->sp [i].local;
g_assert (csignature->ret->type != MONO_TYPE_VOID);
- int ret_mt = mint_type (csignature->ret);
+ int ret_mt = mono_mint_type (csignature->ret);
if (ret_mt == MINT_TYPE_VT) {
// For these intrinsics, if we return a VT then it is a V128
push_type_vt (td, vector_klass, vector_size);
td->last_ins->sregs [i] = td->sp [i].local;
g_assert (csignature->ret->type != MONO_TYPE_VOID);
- int ret_mt = mint_type (csignature->ret);
+ int ret_mt = mono_mint_type (csignature->ret);
if (ret_mt == MINT_TYPE_VT) {
// For these intrinsics, if we return a VT then it is a V128
push_type_vt (td, vector_klass, vector_size);
td->last_ins->sregs [i] = td->sp [i].local;
g_assert (csignature->ret->type != MONO_TYPE_VOID);
- int ret_mt = mint_type (csignature->ret);
+ int ret_mt = mono_mint_type (csignature->ret);
if (ret_mt == MINT_TYPE_VT) {
// For these intrinsics, if we return a VT then it is a V128
push_type_vt (td, vector_klass, vector_size);
}
}
+int
+mono_mint_type (MonoType *type)
+{
+ if (m_type_is_byref (type))
+ return MINT_TYPE_I;
+enum_type:
+ switch (type->type) {
+ case MONO_TYPE_I1:
+ return MINT_TYPE_I1;
+ case MONO_TYPE_U1:
+ case MONO_TYPE_BOOLEAN:
+ return MINT_TYPE_U1;
+ case MONO_TYPE_I2:
+ return MINT_TYPE_I2;
+ case MONO_TYPE_U2:
+ case MONO_TYPE_CHAR:
+ return MINT_TYPE_U2;
+ case MONO_TYPE_I4:
+ case MONO_TYPE_U4:
+ return MINT_TYPE_I4;
+ case MONO_TYPE_I:
+ case MONO_TYPE_U:
+ case MONO_TYPE_PTR:
+ case MONO_TYPE_FNPTR:
+ return MINT_TYPE_I;
+ case MONO_TYPE_R4:
+ return MINT_TYPE_R4;
+ case MONO_TYPE_I8:
+ case MONO_TYPE_U8:
+ return MINT_TYPE_I8;
+ case MONO_TYPE_R8:
+ return MINT_TYPE_R8;
+ case MONO_TYPE_STRING:
+ case MONO_TYPE_SZARRAY:
+ case MONO_TYPE_CLASS:
+ case MONO_TYPE_OBJECT:
+ case MONO_TYPE_ARRAY:
+ return MINT_TYPE_O;
+ case MONO_TYPE_VALUETYPE:
+ if (m_class_is_enumtype (type->data.klass)) {
+ type = mono_class_enum_basetype_internal (type->data.klass);
+ goto enum_type;
+ } else
+ return MINT_TYPE_VT;
+ case MONO_TYPE_TYPEDBYREF:
+ return MINT_TYPE_VT;
+ case MONO_TYPE_GENERICINST:
+ type = m_class_get_byval_arg (type->data.generic_class->container_class);
+ goto enum_type;
+ case MONO_TYPE_VOID:
+ return MINT_TYPE_VOID;
+ default:
+ g_warning ("got type 0x%02x", type->type);
+ g_assert_not_reached ();
+ }
+ return -1;
+}
+
+
/*
* These are additional locals that can be allocated as we transform the code.
* They are allocated past the method locals so they are accessed in the same
td->locals_capacity = 2;
td->locals = (InterpLocal*) g_realloc (td->locals, td->locals_capacity * sizeof (InterpLocal));
}
- int mt = mint_type (type);
+ int mt = mono_mint_type (type);
InterpLocal *local = &td->locals [td->locals_size];
local->type = type;
type = mono_method_signature_internal (td->method)->params [n - !!hasthis];
if (mt)
- *mt = mint_type (type);
+ *mt = mono_mint_type (type);
return type;
}
static void
interp_emit_ldobj (TransformData *td, MonoClass *klass)
{
- int mt = mint_type (m_class_get_byval_arg (klass));
+ int mt = mono_mint_type (m_class_get_byval_arg (klass));
gint32 size = 0;
td->sp--;
static void
interp_emit_stobj (TransformData *td, MonoClass *klass, gboolean reverse_order)
{
- int mt = mint_type (m_class_get_byval_arg (klass));
+ int mt = mono_mint_type (m_class_get_byval_arg (klass));
if (mt == MINT_TYPE_VT) {
if (m_class_has_references (klass)) {
interp_add_ins (td, MINT_CLT_UN_P);
td->sp -= 2;
interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local);
- push_type (td, stack_type [mint_type (m_class_get_byval_arg (k))], k);
+ push_type (td, stack_type [mono_mint_type (m_class_get_byval_arg (k))], k);
interp_ins_set_dreg (td->last_ins, td->sp [-1].local);
td->ip += 5;
return TRUE;
base_klass = mono_class_from_mono_type_internal (base_type);
// Remove the boxing of valuetypes, by replacing them with moves
- prev_prev_ins->opcode = GINT_TO_OPCODE (get_mov_for_type (mint_type (base_type), FALSE));
- td->last_ins->opcode = GINT_TO_OPCODE (get_mov_for_type (mint_type (base_type), FALSE));
+ prev_prev_ins->opcode = GINT_TO_OPCODE (get_mov_for_type (mono_mint_type (base_type), FALSE));
+ td->last_ins->opcode = GINT_TO_OPCODE (get_mov_for_type (mono_mint_type (base_type), FALSE));
intrinsify = TRUE;
} else if (td->last_ins && td->last_ins->opcode == MINT_BOX &&
g_assert (m_class_is_enumtype (constrained_class));
MonoType *base_type = mono_type_get_underlying_type (m_class_get_byval_arg (constrained_class));
base_klass = mono_class_from_mono_type_internal (base_type);
- int mt = mint_type (m_class_get_byval_arg (base_klass));
+ int mt = mono_mint_type (m_class_get_byval_arg (base_klass));
// Remove boxing and load the value of this
td->last_ins->opcode = GINT_TO_OPCODE (get_mov_for_type (mt, FALSE));
static void
interp_constrained_box (TransformData *td, MonoClass *constrained_class, MonoMethodSignature *csignature, MonoError *error)
{
- int mt = mint_type (m_class_get_byval_arg (constrained_class));
+ int mt = mono_mint_type (m_class_get_byval_arg (constrained_class));
StackInfo *sp = td->sp - 1 - csignature->param_count;
if (mono_class_is_nullable (constrained_class)) {
g_assert (mt == MINT_TYPE_VT);
/* need to handle typedbyref ... */
if (csignature->ret->type != MONO_TYPE_VOID) {
- int mt = mint_type(csignature->ret);
+ int mt = mono_mint_type(csignature->ret);
MonoClass *klass = mono_class_from_mono_type_internal (csignature->ret);
if (mt == MINT_TYPE_VT) {
goto exit; \
} while (0)
-static int
-interp_type_size (MonoType *type, int mt, int *align_p)
+int
+mono_interp_type_size (MonoType *type, int mt, int *align_p)
{
int size, align;
if (mt == MINT_TYPE_VT) {
type = m_class_is_valuetype (td->method->klass) ? m_class_get_this_arg (td->method->klass) : m_class_get_byval_arg (td->method->klass);
else
type = mono_method_signature_internal (td->method)->params [i - sig->hasthis];
- int mt = mint_type (type);
+ int mt = mono_mint_type (type);
td->locals [i].type = type;
td->locals [i].flags = INTERP_LOCAL_FLAG_GLOBAL;
td->locals [i].indirects = 0;
td->locals [i].mt = mt;
td->locals [i].def = NULL;
- size = interp_type_size (type, mt, &align);
+ size = mono_interp_type_size (type, mt, &align);
td->locals [i].size = size;
offset = ALIGN_TO (offset, align);
td->locals [i].offset = offset;
td->il_locals_offset = offset;
for (int i = 0; i < num_il_locals; ++i) {
int index = num_args + i;
- size = mono_type_size (header->locals [i], &align);
+ int mt = mono_mint_type (header->locals [i]);
+ size = mono_interp_type_size (header->locals [i], mt, &align);
if (header->locals [i]->type == MONO_TYPE_VALUETYPE) {
if (mono_class_has_failure (header->locals [i]->data.klass)) {
mono_error_set_for_class_failure (error, header->locals [i]->data.klass);
return;
}
}
- int mt = mint_type (header->locals [i]);
- size = interp_type_size (header->locals [i], mt, &align);
offset = ALIGN_TO (offset, align);
imethod->local_offsets [i] = offset;
td->locals [index].type = header->locals [i];
td->locals [index].offset = offset;
td->locals [index].flags = INTERP_LOCAL_FLAG_GLOBAL;
td->locals [index].indirects = 0;
- td->locals [index].mt = mint_type (header->locals [i]);
+ td->locals [index].mt = mono_mint_type (header->locals [i]);
td->locals [index].def = NULL;
td->locals [index].size = size;
// Every local takes a MINT_STACK_SLOT_SIZE so IL locals have same behavior as execution locals
case CEE_RET: {
link_bblocks = FALSE;
MonoType *ult = mini_type_get_underlying_type (signature->ret);
- mt = mint_type (ult);
+ mt = mono_mint_type (ult);
if (mt != MINT_TYPE_VOID) {
// Convert stack contents to return type if necessary
CHECK_STACK (td, 1);
goto_if_nok (error, exit);
if (m_class_is_valuetype (klass)) {
- mt = mint_type (m_class_get_byval_arg (klass));
+ mt = mono_mint_type (m_class_get_byval_arg (klass));
td->sp -= 2;
if (mt == MINT_TYPE_VT && !m_class_has_references (klass)) {
interp_add_ins (td, MINT_CPOBJ_VT_NOREF);
goto_if_nok (error, exit);
}
- int ret_mt = mint_type (m_class_get_byval_arg (klass));
+ int ret_mt = mono_mint_type (m_class_get_byval_arg (klass));
if (klass == mono_defaults.int_class && csignature->param_count == 1) {
#if SIZEOF_VOID_P == 8
if (td->sp [-1].type == STACK_TYPE_I4)
if ((td->last_ins->opcode == MINT_BOX || td->last_ins->opcode == MINT_BOX_VT) &&
(td->sp - 1)->klass == klass && td->last_ins == td->cbb->last_ins) {
interp_clear_ins (td->last_ins);
- mt = mint_type (m_class_get_byval_arg (klass));
+ mt = mono_mint_type (m_class_get_byval_arg (klass));
td->sp--;
// Push back the original value that was boxed. We should handle this in CEE_BOX instead
if (mt == MINT_TYPE_VT)
mono_class_setup_fields (klass);
MonoClass *field_klass = mono_class_from_mono_type_internal (ftype);
- mt = mint_type (ftype);
+ mt = mono_mint_type (ftype);
int field_size = mono_class_value_size (field_klass, NULL);
{
MonoClass *field_klass = mono_class_from_mono_type_internal (ftype);
mono_class_init_internal (klass);
mono_class_setup_fields (klass);
- mt = mint_type (ftype);
+ mt = mono_mint_type (ftype);
BARRIER_IF_VOLATILE (td, MONO_MEMORY_BARRIER_REL);
field = interp_field_from_token (method, token, &klass, generic_context, error);
goto_if_nok (error, exit);
MonoType *ftype = mono_field_get_type_internal (field);
- mt = mint_type (ftype);
+ mt = mono_mint_type (ftype);
klass = mono_class_from_mono_type_internal (ftype);
gboolean in_corlib = m_class_get_image (m_field_get_parent (field)) == mono_defaults.corlib;
field = interp_field_from_token (method, token, &klass, generic_context, error);
goto_if_nok (error, exit);
MonoType *ftype = mono_field_get_type_internal (field);
- mt = mint_type (ftype);
+ mt = mono_mint_type (ftype);
emit_convert (td, td->sp - 1, ftype);
goto exit;
}
- const gboolean vt = mint_type (m_class_get_byval_arg (klass)) == MINT_TYPE_VT;
+ const gboolean vt = mono_mint_type (m_class_get_byval_arg (klass)) == MINT_TYPE_VT;
if (td->sp [-1].type == STACK_TYPE_R8 && m_class_get_byval_arg (klass)->type == MONO_TYPE_R4)
interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_R4, MINT_CONV_R4_R8);
token = read32 (td->ip + 1);
klass = mini_get_class (method, token, generic_context);
CHECK_TYPELOAD (klass);
- switch (mint_type (m_class_get_byval_arg (klass))) {
+ switch (mono_mint_type (m_class_get_byval_arg (klass))) {
case MINT_TYPE_I1:
handle_ldelem (td, MINT_LDELEM_I1, STACK_TYPE_I4);
break;
default: {
GString *res = g_string_new ("");
mono_type_get_desc (res, m_class_get_byval_arg (klass), TRUE);
- g_print ("LDELEM: %s -> %d (%s)\n", m_class_get_name (klass), mint_type (m_class_get_byval_arg (klass)), res->str);
+ g_print ("LDELEM: %s -> %d (%s)\n", m_class_get_name (klass), mono_mint_type (m_class_get_byval_arg (klass)), res->str);
g_string_free (res, TRUE);
g_assert (0);
break;
token = read32 (td->ip + 1);
klass = mini_get_class (method, token, generic_context);
CHECK_TYPELOAD (klass);
- switch (mint_type (m_class_get_byval_arg (klass))) {
+ switch (mono_mint_type (m_class_get_byval_arg (klass))) {
case MINT_TYPE_I1:
handle_stelem (td, MINT_STELEM_I1);
break;
default: {
GString *res = g_string_new ("");
mono_type_get_desc (res, m_class_get_byval_arg (klass), TRUE);
- g_print ("STELEM: %s -> %d (%s)\n", m_class_get_name (klass), mint_type (m_class_get_byval_arg (klass)), res->str);
+ g_print ("STELEM: %s -> %d (%s)\n", m_class_get_name (klass), mono_mint_type (m_class_get_byval_arg (klass)), res->str);
g_string_free (res, TRUE);
g_assert (0);
break;
goto_if_nok (error, exit);
}
mono_class_init_internal (klass);
- mt = mint_type (m_class_get_byval_arg (klass));
+ mt = mono_mint_type (m_class_get_byval_arg (klass));
g_assert (mt == MINT_TYPE_VT);
size = mono_class_value_size (klass, NULL);
g_assert (size == sizeof(gpointer));
int param_offset = get_tos_offset (td);
if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
- mt = mint_type (info->sig->ret);
+ mt = mono_mint_type (info->sig->ret);
push_simple_type (td, stack_type [mt]);
dreg = td->sp [-1].local;
}
td->locals [new_var].call = ins;
td->locals [new_var].flags |= INTERP_LOCAL_FLAG_CALL_ARGS;
- int mt = mint_type (td->locals [var].type);
+ int mt = mono_mint_type (td->locals [var].type);
if (mt != MINT_TYPE_VT && num_pairs < MINT_MOV_PAIRS_MAX && var <= G_MAXUINT16 && new_var <= G_MAXUINT16) {
// We store these in the instruction data slots so we do this optimizations only if they fit
pair_sregs [num_pairs] = (guint16)var;
set_var_live_range (td, pair_dregs [i], ins_index);
}
if (num_pairs == 1) {
- int mt = mint_type (td->locals [pair_sregs [0]].type);
+ int mt = mono_mint_type (td->locals [pair_sregs [0]].type);
int opcode = get_mov_for_type (mt, FALSE);
InterpInst *new_inst = interp_insert_ins_bb (td, bb, ins->prev, opcode);
interp_ins_set_dreg (new_inst, pair_dregs [0]);
[true, "mono_jiterp_get_opcode_value_table_entry", "number", ["number"]],
[true, "mono_jiterp_get_simd_intrinsic", "number", ["number", "number"]],
[true, "mono_jiterp_get_simd_opcode", "number", ["number", "number"]],
+ [true, "mono_jiterp_get_arg_offset", "number", ["number", "number", "number"]],
...legacy_interop_cwraps
];
mono_jiterp_get_opcode_value_table_entry(opcode: number): number;
mono_jiterp_get_simd_intrinsic(arity: number, index: number): VoidPtr;
mono_jiterp_get_simd_opcode(arity: number, index: number): number;
+ mono_jiterp_get_arg_offset (imethod: number, sig: number, index: number): number;
}
const wrapped_c_functions: t_Cwraps = <any>{};
import { NativePointer } from "./types/emscripten";
import { Module } from "./globals";
import {
- getU32_unaligned, _zero_region
+ setI32, getU32_unaligned, _zero_region
} from "./memory";
import { WasmOpcode } from "./jiterpreter-opcodes";
import cwraps from "./cwraps";
ThreadContext *context; // 4
gpointer orig_domain; // 8
gpointer attach_cookie; // 12
+ int params_count; // 16
} JiterpEntryDataHeader;
*/
"interp_entry",
{
"pData": WasmValtype.i32,
- "sp_args": WasmValtype.i32,
"res": WasmValtype.i32,
},
WasmValtype.void, true
"result": WasmValtype.i32,
"value": WasmValtype.i32
},
- WasmValtype.i32, true
+ WasmValtype.void, true
);
} else
builder.clear(constantSlots);
}
function append_stackval_from_data(
- builder: WasmBuilder, type: MonoType, valueName: string
+ builder: WasmBuilder, imethod: number, type: MonoType, valueName: string, argIndex: number
) {
- const stackvalSize = cwraps.mono_jiterp_get_size_of_stackval();
const rawSize = cwraps.mono_jiterp_type_get_raw_value_size(type);
+ const offset = cwraps.mono_jiterp_get_arg_offset(imethod, 0, argIndex);
switch (rawSize) {
case 256: {
builder.local(valueName);
builder.appendU8(WasmOpcode.i32_store);
- builder.appendMemarg(0, 2);
-
- // Fixed stackval size
- builder.i32_const(stackvalSize);
+ builder.appendMemarg(offset, 2);
break;
}
}
builder.appendU8(WasmOpcode.i32_store);
- builder.appendMemarg(0, 2);
-
- // Fixed stackval size
- builder.i32_const(stackvalSize);
+ builder.appendMemarg(offset, 2);
break;
}
default: {
- // Call stackval_from_data to copy the value and get its size
+ // Call stackval_from_data to copy the value
builder.ptr_const(type);
// result
builder.local("sp_args");
+ // apply offset
+ builder.i32_const(offset);
+ builder.appendU8(WasmOpcode.i32_add);
// value
builder.local(valueName);
break;
}
}
-
- // Value size is on the stack, add it to sp_args and update it
- builder.local("sp_args");
- builder.appendU8(WasmOpcode.i32_add);
- builder.local("sp_args", WasmOpcode.set_local);
}
function generate_wasm_body(
const scratchBuffer = <any>Module._malloc(sizeOfJiterpEntryData);
_zero_region(scratchBuffer, sizeOfJiterpEntryData);
+ // Initialize the parameter count in the data blob. This is used to calculate the new value of sp
+ // before entering the interpreter
+ setI32(
+ scratchBuffer + getMemberOffset(JiterpMember.ParamsCount),
+ info.paramTypes.length + (info.hasThisReference ? 1 : 0)
+ );
+
// the this-reference may be a boxed struct that needs to be unboxed, for example calling
// methods like object.ToString on structs will end up with the unbox flag set
// instead of passing an extra 'unbox' argument to every wrapper, though, the flag is hidden
if (info.hasThisReference) {
// null type for raw ptr copy
- append_stackval_from_data(builder, <any>0, "this_arg");
+ append_stackval_from_data(builder, info.imethod, <any>0, "this_arg", 0);
}
/*
for (let i = 0; i < info.paramTypes.length; i++) {
const type = <any>info.paramTypes[i];
- append_stackval_from_data(builder, type, `arg${i}`);
+ append_stackval_from_data(builder, info.imethod, type, `arg${i}`, i + (info.hasThisReference ? 1 : 0));
}
builder.local("scratchBuffer");
- builder.local("sp_args");
if (info.hasReturnValue)
builder.local("res");
else
BackwardBranchOffsets = 10,
BackwardBranchOffsetsCount = 11,
ClauseDataOffsets = 12,
+ ParamsCount = 13,
}
const memberOffsets: { [index: number]: number } = {};