#include <mono/metadata/profiler-private.h>
#include <mono/metadata/tabledefs.h>
-#define OPDEF(a,b,c,d,e,f,g,h,i,j) \
- a = i,
-
-enum {
-#include "mono/cil/opcode.def"
- CEE_LASTOP
-};
-#undef OPDEF
+#include <mono/mini/mini.h>
#include "mintops.h"
+#include "interp-internals.h"
#include "interp.h"
+// TODO: export from marshal.c
+MonoDelegate* mono_ftnptr_to_delegate (MonoClass *klass, gpointer ftn);
+
#define DEBUG 0
typedef struct
goto enum_type;
} else
return MINT_TYPE_VT;
+ case MONO_TYPE_GENERICINST:
+ type = &type->data.generic_class->container_class->byval_arg;
+ goto enum_type;
default:
g_warning ("got type 0x%02x", type->type);
g_assert_not_reached ();
{
int mt;
MonoClass *klass = NULL;
- if (n == 0 && mono_method_signature (td->method)->hasthis) {
- if (td->method->klass->valuetype)
+ MonoType *type;
+
+ gboolean hasthis = mono_method_signature (td->method)->hasthis;
+ if (hasthis && n == 0)
+ type = &td->method->klass->byval_arg;
+ else
+ type = mono_method_signature (td->method)->params [hasthis ? n - 1 : n];
+
+ mt = mint_type (type);
+ if (mt == MINT_TYPE_VT) {
+ gint32 size;
+ klass = mono_class_from_mono_type (type);
+ if (mono_method_signature (td->method)->pinvoke)
+ size = mono_class_native_size (klass, NULL);
+ else
+ size = mono_class_value_size (klass, NULL);
+
+ if (hasthis && n == 0) {
mt = MINT_TYPE_P;
- else {
- mt = MINT_TYPE_O;
- klass = td->method->klass;
+ ADD_CODE (td, MINT_LDARG_P);
+ ADD_CODE (td, td->rtm->arg_offsets [n]); /* FIX for large offset */
+ klass = NULL;
+ } else {
+ PUSH_VT (td, size);
+ ADD_CODE (td, MINT_LDARG_VT);
+ ADD_CODE (td, td->rtm->arg_offsets [n]); /* FIX for large offset */
+ WRITE32 (td, &size);
}
- ADD_CODE(td, MINT_LDTHIS);
} else {
- MonoType *type;
- n -= mono_method_signature (td->method)->hasthis;
- type = mono_method_signature (td->method)->params [n];
- mt = mint_type (type);
- if (mt == MINT_TYPE_VT) {
- gint32 size;
- if (mono_method_signature (td->method)->pinvoke)
- size = mono_class_native_size (type->data.klass, NULL);
- else
- size = mono_class_value_size (type->data.klass, NULL);
- PUSH_VT(td, size);
- ADD_CODE(td, MINT_LDARG_VT);
- ADD_CODE(td, td->rtm->arg_offsets [n]); /* FIX for large offset */
- WRITE32(td, &size);
- klass = type->data.klass;
+ if (hasthis && n == 0) {
+ mt = MINT_TYPE_P;
+ ADD_CODE (td, MINT_LDARG_P);
+ ADD_CODE (td, td->rtm->arg_offsets [n]); /* FIX for large offset */
+ klass = NULL;
} else {
ADD_CODE(td, MINT_LDARG_I1 + (mt - MINT_TYPE_I1));
ADD_CODE(td, td->rtm->arg_offsets [n]); /* FIX for large offset */
{
int mt;
CHECK_STACK (td, 1);
- if (n == 0 && mono_method_signature (td->method)->hasthis)
- ADD_CODE(td, MINT_STTHIS);
- else {
- MonoType *type;
- n -= mono_method_signature (td->method)->hasthis;
- type = mono_method_signature (td->method)->params [n];
- mt = mint_type (type);
- if (mt == MINT_TYPE_VT) {
- gint32 size;
- if (mono_method_signature (td->method)->pinvoke)
- size = mono_class_native_size (type->data.klass, NULL);
- else
- size = mono_class_value_size (type->data.klass, NULL);
- ADD_CODE(td, MINT_STARG_VT);
- ADD_CODE(td, n);
- WRITE32(td, &size);
- if (td->sp [-1].type == STACK_TYPE_VT)
- POP_VT(td, size);
- } else {
- ADD_CODE(td, MINT_STARG_I1 + (mt - MINT_TYPE_I1));
- ADD_CODE(td, td->rtm->arg_offsets [n]);
- }
+ MonoType *type;
+
+ gboolean hasthis = mono_method_signature (td->method)->hasthis;
+ if (hasthis && n == 0)
+ type = &td->method->klass->byval_arg;
+ else
+ type = mono_method_signature (td->method)->params [n - !!hasthis];
+
+ mt = mint_type (type);
+ if (mt == MINT_TYPE_VT) {
+ gint32 size;
+ g_error ("data.klass");
+ if (mono_method_signature (td->method)->pinvoke)
+ size = mono_class_native_size (type->data.klass, NULL);
+ else
+ size = mono_class_value_size (type->data.klass, NULL);
+ ADD_CODE(td, MINT_STARG_VT);
+ ADD_CODE(td, n);
+ WRITE32(td, &size);
+ if (td->sp [-1].type == STACK_TYPE_VT)
+ POP_VT(td, size);
+ } else {
+ ADD_CODE(td, MINT_STARG_I1 + (mt - MINT_TYPE_I1));
+ ADD_CODE(td, td->rtm->arg_offsets [n]);
}
--td->sp;
}
static void
store_inarg(TransformData *td, int n)
{
- MonoType *type = mono_method_signature (td->method)->params [n];
+ MonoType *type;
+ gboolean hasthis = mono_method_signature (td->method)->hasthis;
+ if (hasthis && n == 0)
+ type = &td->method->klass->byval_arg;
+ else
+ type = mono_method_signature (td->method)->params [n - !!hasthis];
+
int mt = mint_type (type);
+ if (hasthis && n == 0) {
+ ADD_CODE (td, MINT_STINARG_P);
+ ADD_CODE (td, n);
+ return;
+ }
if (mt == MINT_TYPE_VT) {
+ MonoClass *klass = mono_class_from_mono_type (type);
gint32 size;
if (mono_method_signature (td->method)->pinvoke)
- size = mono_class_native_size (type->data.klass, NULL);
+ size = mono_class_native_size (klass, NULL);
else
- size = mono_class_value_size (type->data.klass, NULL);
+ size = mono_class_value_size (klass, NULL);
ADD_CODE(td, MINT_STINARG_VT);
ADD_CODE(td, n);
WRITE32(td, &size);
int offset = td->rtm->local_offsets [n];
MonoClass *klass = NULL;
if (mt == MINT_TYPE_VT) {
- gint32 size = mono_class_value_size (type->data.klass, NULL);
+ klass = mono_class_from_mono_type (type);
+ gint32 size = mono_class_value_size (klass, NULL);
PUSH_VT(td, size);
ADD_CODE(td, MINT_LDLOC_VT);
ADD_CODE(td, offset); /*FIX for large offset */
WRITE32(td, &size);
- klass = type->data.klass;
} else {
+ g_assert (mt < MINT_TYPE_VT);
if (mt == MINT_TYPE_I4 && !td->is_bb_start [td->in_start - td->il_code] && td->last_new_ip != NULL &&
td->last_new_ip [0] == MINT_STLOC_I4 && td->last_new_ip [1] == offset) {
td->last_new_ip [0] = MINT_STLOC_NP_I4;
stack_type [mt], td->sp [-1].type);
}
if (mt == MINT_TYPE_VT) {
- gint32 size = mono_class_value_size (type->data.klass, NULL);
+ MonoClass *klass = mono_class_from_mono_type (type);
+ gint32 size = mono_class_value_size (klass, NULL);
ADD_CODE(td, MINT_STLOC_VT);
ADD_CODE(td, offset); /*FIX for large offset */
WRITE32(td, &size);
if (td->sp [-1].type == STACK_TYPE_VT)
POP_VT(td, size);
} else {
+ g_assert (mt < MINT_TYPE_VT);
ADD_CODE(td, MINT_STLOC_I1 + (mt - MINT_TYPE_I1));
ADD_CODE(td, offset); /*FIX for large offset */
}
return index;
}
+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)
+{
+ MonoImage *image = method->klass->image;
+ MonoMethodSignature *csignature;
+ MonoError error;
+ int virtual = *td->ip == CEE_CALLVIRT;
+ int calli = *td->ip == CEE_CALLI || *td->ip == CEE_MONO_CALLI_EXTRA_ARG;
+ int i;
+ guint32 vt_stack_used = 0;
+ guint32 vt_res_size = 0;
+ int op = -1;
+ int native = 0;
+ int is_void = 0;
+
+ guint32 token = read32 (td->ip + 1);
+
+ if (target_method == NULL) {
+ if (calli) {
+ CHECK_STACK(td, 1);
+ native = (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE && td->sp [-1].type == STACK_TYPE_I);
+ --td->sp;
+ if (method->wrapper_type != MONO_WRAPPER_NONE)
+ csignature = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
+ else
+ csignature = mono_metadata_parse_signature (image, token);
+ target_method = NULL;
+ } else {
+ if (method->wrapper_type == MONO_WRAPPER_NONE)
+ target_method = mono_get_method_full (image, token, NULL, generic_context);
+ else
+ target_method = (MonoMethod *)mono_method_get_wrapper_data (method, token);
+ csignature = mono_method_signature (target_method);
+ if (target_method->klass == mono_defaults.string_class) {
+ if (target_method->name [0] == 'g') {
+ if (strcmp (target_method->name, "get_Chars") == 0)
+ op = MINT_GETCHR;
+ else if (strcmp (target_method->name, "get_Length") == 0)
+ op = MINT_STRLEN;
+ }
+ } else if (target_method->klass == mono_defaults.array_class) {
+ if (strcmp (target_method->name, "get_Rank") == 0)
+ op = MINT_ARRAY_RANK;
+ else if (strcmp (target_method->name, "get_Length") == 0)
+ op = MINT_LDLEN;
+ }
+ }
+ } else {
+ csignature = mono_method_signature (target_method);
+ }
+
+ if (constrained_class) {
+ if (constrained_class->enumtype && !strcmp (target_method->name, "GetHashCode")) {
+ /* Use the corresponding method from the base type to avoid boxing */
+ MonoType *base_type = mono_class_enum_basetype (constrained_class);
+ g_assert (base_type);
+ constrained_class = mono_class_from_mono_type (base_type);
+ target_method = mono_class_get_method_from_name (constrained_class, target_method->name, 0);
+ g_assert (target_method);
+ }
+ }
+
+ if (constrained_class) {
+ mono_class_setup_vtable (constrained_class);
+#if DEBUG_INTERP
+ g_print ("CONSTRAINED.CALLVIRT: %s::%s. %s (%p) ->\n", target_method->klass->name, target_method->name, mono_signature_full_name (target_method->signature), target_method);
+#endif
+ target_method = mono_get_method_constrained_with_method (image, target_method, constrained_class, generic_context, &error);
+#if DEBUG_INTERP
+ g_print (" : %s::%s. %s (%p)\n", target_method->klass->name, target_method->name, mono_signature_full_name (target_method->signature), target_method);
+#endif
+ mono_error_cleanup (&error); /* FIXME: don't swallow the error */
+ mono_class_setup_vtable (target_method->klass);
+
+ if (constrained_class->valuetype && (target_method->klass == mono_defaults.object_class || target_method->klass == mono_defaults.enum_class->parent || target_method->klass == mono_defaults.enum_class)) {
+ ADD_CODE (td, MINT_BOX);
+ ADD_CODE (td, get_data_item_index (td, constrained_class));
+ ADD_CODE (td, csignature->param_count);
+ } else if (!constrained_class->valuetype) {
+ /* managed pointer on the stack, we need to deref that puppy */
+ ADD_CODE (td, MINT_LDIND_I);
+ ADD_CODE (td, csignature->param_count);
+ } else {
+ g_assert (target_method->klass->valuetype);
+ virtual = FALSE;
+ }
+ }
+
+ if (target_method)
+ mono_class_init (target_method->klass);
+
+ CHECK_STACK (td, csignature->param_count + csignature->hasthis);
+ if (!calli && (!virtual || (target_method->flags & METHOD_ATTRIBUTE_VIRTUAL) == 0) &&
+ (target_method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) == 0 &&
+ (target_method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) == 0) {
+ int called_inited = mono_class_vtable (domain, target_method->klass)->initialized;
+ MonoMethodHeader *mheader = mono_method_get_header (target_method);
+
+ if (/*mono_metadata_signature_equal (method->signature, target_method->signature) */ method == target_method && *(td->ip + 5) == CEE_RET) {
+ int offset;
+ if (mono_interp_traceopt)
+ g_print ("Optimize tail call of %s.%s\n", target_method->klass->name, target_method->name);
+ for (i = csignature->param_count - 1; i >= 0; --i)
+ store_arg (td, i + csignature->hasthis);
+
+ if (csignature->hasthis) {
+ g_error ("STTHIS removal");
+ // ADD_CODE(td, MINT_STTHIS);
+ --td->sp;
+ }
+ ADD_CODE(td, MINT_BR_S);
+ offset = body_start_offset - ((td->new_ip - 1) - td->new_code);
+ ADD_CODE(td, offset);
+ if (!is_bb_start [td->ip + 5 - td->il_code])
+ ++td->ip; /* gobble the CEE_RET if it isn't branched to */
+ td->ip += 5;
+ return;
+ } else {
+ /* mheader might not exist if this is a delegate invoc, etc */
+ if (mheader && *mheader->code == CEE_RET && called_inited) {
+ if (mono_interp_traceopt)
+ g_print ("Inline (empty) call of %s.%s\n", target_method->klass->name, target_method->name);
+ for (i = 0; i < csignature->param_count; i++)
+ ADD_CODE(td, MINT_POP); /*FIX: vt */
+ if (csignature->hasthis) {
+ if (virtual)
+ ADD_CODE(td, MINT_CKNULL);
+ ADD_CODE(td, MINT_POP);
+ }
+ td->sp -= csignature->param_count + csignature->hasthis;
+ td->ip += 5;
+ return;
+ }
+ }
+ }
+ if (method->wrapper_type == MONO_WRAPPER_NONE && target_method != NULL) {
+ if (target_method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
+ target_method = mono_marshal_get_native_wrapper (target_method, FALSE, FALSE);
+ if (!virtual && target_method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
+ target_method = mono_marshal_get_synchronized_wrapper (target_method);
+ }
+ g_assert (csignature->call_convention == MONO_CALL_DEFAULT || csignature->call_convention == MONO_CALL_C);
+ td->sp -= csignature->param_count + !!csignature->hasthis;
+ for (i = 0; i < csignature->param_count; ++i) {
+ if (td->sp [i + !!csignature->hasthis].type == STACK_TYPE_VT) {
+ gint32 size;
+ MonoClass *klass = mono_class_from_mono_type (csignature->params [i]);
+ if (csignature->pinvoke && method->wrapper_type != MONO_WRAPPER_NONE)
+ size = mono_class_native_size (klass, NULL);
+ else
+ size = mono_class_value_size (klass, NULL);
+ size = (size + 7) & ~7;
+ vt_stack_used += size;
+ }
+ }
+
+ /* need to handle typedbyref ... */
+ if (csignature->ret->type != MONO_TYPE_VOID) {
+ int mt = mint_type(csignature->ret);
+ MonoClass *klass = mono_class_from_mono_type (csignature->ret);
+ if (mt == MINT_TYPE_VT) {
+ if (csignature->pinvoke && method->wrapper_type != MONO_WRAPPER_NONE)
+ vt_res_size = mono_class_native_size (klass, NULL);
+ else
+ vt_res_size = mono_class_value_size (klass, NULL);
+ PUSH_VT(td, vt_res_size);
+ }
+ PUSH_TYPE(td, stack_type[mt], klass);
+ } else
+ is_void = TRUE;
+
+ if (op >= 0) {
+ ADD_CODE(td, op);
+#if SIZEOF_VOID_P == 8
+ if (op == MINT_LDLEN)
+ ADD_CODE(td, MINT_CONV_I4_I8);
+#endif
+ } else {
+ if (calli)
+ ADD_CODE(td, native ? MINT_CALLI_NAT : MINT_CALLI);
+ else if (virtual)
+ ADD_CODE(td, is_void ? MINT_VCALLVIRT : MINT_CALLVIRT);
+ else
+ ADD_CODE(td, is_void ? MINT_VCALL : MINT_CALL);
+
+ if (calli) {
+ ADD_CODE(td, get_data_item_index (td, (void *)csignature));
+ } else {
+ ADD_CODE(td, get_data_item_index (td, (void *)mono_interp_get_runtime_method (domain, target_method, &error)));
+ mono_error_cleanup (&error); /* FIXME: don't swallow the error */
+ }
+ }
+ td->ip += 5;
+ if (vt_stack_used != 0 || vt_res_size != 0) {
+ ADD_CODE(td, MINT_VTRESULT);
+ ADD_CODE(td, vt_res_size);
+ WRITE32(td, &vt_stack_used);
+ td->vt_sp -= vt_stack_used;
+ }
+}
+
static void
generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start)
{
MonoImage *image = method->klass->image;
MonoDomain *domain = mono_domain_get ();
MonoGenericContext *generic_context = NULL;
+ MonoClass *constrained_class = NULL;
MonoError error;
int offset, mt;
int i;
g_free (name);
}
+ if (signature->hasthis)
+ store_inarg (&td, 0);
for (i = 0; i < signature->param_count; i++)
- store_inarg(&td, i);
+ store_inarg (&td, i + !!signature->hasthis);
body_start_offset = td.new_ip - td.new_code;
td.ip += 2;
break;
case CEE_LDARGA_S: {
+ /* NOTE: n includes this */
int n = ((guint8 *)td.ip)[1];
- if (n == 0 && signature->hasthis)
+ if (n == 0 && signature->hasthis) {
+ g_error ("LDTHISA: NOPE");
ADD_CODE(&td, MINT_LDTHISA);
+ }
else {
ADD_CODE(&td, MINT_LDARGA);
- ADD_CODE(&td, td.rtm->arg_offsets [n - signature->hasthis]);
+ ADD_CODE(&td, td.rtm->arg_offsets [n]);
}
PUSH_SIMPLE_TYPE(&td, STACK_TYPE_MP);
td.ip += 2;
case CEE_CALLVIRT: /* Fall through */
case CEE_CALLI: /* Fall through */
case CEE_CALL: {
- MonoMethod *m;
- MonoMethodSignature *csignature;
- int virtual = *td.ip == CEE_CALLVIRT;
- int calli = *td.ip == CEE_CALLI;
- int i;
- guint32 vt_stack_used = 0;
- guint32 vt_res_size = 0;
- int op = -1;
- int native = 0;
- int is_void = 0;
-
- token = read32 (td.ip + 1);
- if (calli) {
- CHECK_STACK(&td, 1);
- native = (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE && td.sp [-1].type == STACK_TYPE_I);
- --td.sp;
- if (method->wrapper_type != MONO_WRAPPER_NONE)
- csignature = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
- else
- csignature = mono_metadata_parse_signature (image, token);
- m = NULL;
- } else {
- if (method->wrapper_type == MONO_WRAPPER_NONE)
- m = mono_get_method_full (image, token, NULL, generic_context);
- else
- m = (MonoMethod *)mono_method_get_wrapper_data (method, token);
- csignature = mono_method_signature (m);
- if (m->klass == mono_defaults.string_class) {
- if (m->name [0] == 'g') {
- if (strcmp (m->name, "get_Chars") == 0)
- op = MINT_GETCHR;
- else if (strcmp (m->name, "get_Length") == 0)
- op = MINT_STRLEN;
- }
- } else if (m->klass == mono_defaults.array_class) {
- if (strcmp (m->name, "get_Rank") == 0)
- op = MINT_ARRAY_RANK;
- else if (strcmp (m->name, "get_Length") == 0)
- op = MINT_LDLEN;
- }
- }
- CHECK_STACK(&td, csignature->param_count + csignature->hasthis);
- if (!calli && (!virtual || (m->flags & METHOD_ATTRIBUTE_VIRTUAL) == 0) &&
- (m->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) == 0 &&
- (m->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) == 0) {
- int called_inited = mono_class_vtable (domain, m->klass)->initialized;
- MonoMethodHeader *mheader = mono_method_get_header (m);
-
- if (/*mono_metadata_signature_equal (method->signature, m->signature) */ method == m && *(td.ip + 5) == CEE_RET) {
- int offset;
- if (mono_interp_traceopt)
- g_print ("Optimize tail call of %s.%s\n", m->klass->name, m->name);
- for (i = csignature->param_count - 1; i >= 0; --i)
- store_arg (&td, i + csignature->hasthis);
-
- if (csignature->hasthis) {
- ADD_CODE(&td, MINT_STTHIS);
- --td.sp;
- }
- ADD_CODE(&td, MINT_BR_S);
- offset = body_start_offset - ((td.new_ip - 1) - td.new_code);
- ADD_CODE(&td, offset);
- if (!is_bb_start [td.ip + 5 - td.il_code])
- ++td.ip; /* gobble the CEE_RET if it isn't branched to */
- td.ip += 5;
- break;
- } else {
- /* mheader might not exist if this is a delegate invoc, etc */
- if (mheader && *mheader->code == CEE_RET && called_inited) {
- if (mono_interp_traceopt)
- g_print ("Inline (empty) call of %s.%s\n", m->klass->name, m->name);
- for (i = 0; i < csignature->param_count; i++)
- ADD_CODE(&td, MINT_POP); /*FIX: vt */
- if (csignature->hasthis) {
- if (virtual)
- ADD_CODE(&td, MINT_CKNULL);
- ADD_CODE(&td, MINT_POP);
- }
- td.sp -= csignature->param_count + csignature->hasthis;
- td.ip += 5;
- break;
- }
- }
- }
- if (method->wrapper_type == MONO_WRAPPER_NONE && m != NULL) {
- if (m->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
- m = mono_marshal_get_native_wrapper (m, FALSE, FALSE);
- if (!virtual && m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
- m = mono_marshal_get_synchronized_wrapper (m);
- }
- g_assert (csignature->call_convention == MONO_CALL_DEFAULT || csignature->call_convention == MONO_CALL_C);
- td.sp -= csignature->param_count + csignature->hasthis;
- for (i = 0; i < csignature->param_count; ++i) {
- if (td.sp [i + csignature->hasthis].type == STACK_TYPE_VT) {
- gint32 size;
- if (csignature->pinvoke && method->wrapper_type != MONO_WRAPPER_NONE)
- size = mono_class_native_size (csignature->params [i]->data.klass, NULL);
- else
- size = mono_class_value_size (csignature->params [i]->data.klass, NULL);
- size = (size + 7) & ~7;
- vt_stack_used += size;
- }
- }
-
- /* need to handle typedbyref ... */
- if (csignature->ret->type != MONO_TYPE_VOID) {
- int mt = mint_type(csignature->ret);
- MonoClass *klass = NULL;
- if (mt == MINT_TYPE_VT) {
- if (csignature->pinvoke && method->wrapper_type != MONO_WRAPPER_NONE)
- vt_res_size = mono_class_native_size (csignature->ret->data.klass, NULL);
- else
- vt_res_size = mono_class_value_size (csignature->ret->data.klass, NULL);
- PUSH_VT(&td, vt_res_size);
- klass = csignature->ret->data.klass;
- } else if (mt == MINT_TYPE_O)
- klass = mono_class_from_mono_type (csignature->ret);
- PUSH_TYPE(&td, stack_type[mt], klass);
- } else
- is_void = TRUE;
-
- if (op >= 0) {
- ADD_CODE(&td, op);
-#if SIZEOF_VOID_P == 8
- if (op == MINT_LDLEN)
- ADD_CODE(&td, MINT_CONV_I4_I8);
-#endif
- } else {
- if (calli)
- ADD_CODE(&td, native ? MINT_CALLI_NAT : MINT_CALLI);
- else if (virtual)
- ADD_CODE(&td, is_void ? MINT_VCALLVIRT : MINT_CALLVIRT);
- else
- ADD_CODE(&td, is_void ? MINT_VCALL : MINT_CALL);
- ADD_CODE(&td, get_data_item_index (&td, calli? (void *)csignature : (void *)mono_interp_get_runtime_method (domain, m, &error)));
- mono_error_cleanup (&error); /* FIXME: don't swallow the error */
- }
- td.ip += 5;
- if (vt_stack_used != 0 || vt_res_size != 0) {
- ADD_CODE(&td, MINT_VTRESULT);
- ADD_CODE(&td, vt_res_size);
- WRITE32(&td, &vt_stack_used);
- td.vt_sp -= vt_stack_used;
- }
+ interp_transform_call (&td, method, NULL, domain, generic_context, is_bb_start, body_start_offset, constrained_class);
+ constrained_class = NULL;
break;
}
case CEE_RET: {
int vt_size = 0;
if (signature->ret->type != MONO_TYPE_VOID) {
--td.sp;
- if (mint_type(signature->ret) == MINT_TYPE_VT) {
- vt_size = mono_class_value_size (signature->ret->data.klass, NULL);
+ MonoClass *klass = mono_class_from_mono_type (signature->ret);
+ if (mint_type (&klass->byval_arg) == MINT_TYPE_VT) {
+ vt_size = mono_class_value_size (klass, NULL);
vt_size = (vt_size + 7) & ~7;
}
}
if (td.sp > td.stack)
g_warning ("%s.%s: CEE_RET: more values on stack: %d", td.method->klass->name, td.method->name, td.sp - td.stack);
if (td.vt_sp != vt_size)
- g_warning ("%s.%s: CEE_RET: value type stack: %d", td.method->klass->name, td.method->name, td.vt_sp);
+ g_error ("%s.%s: CEE_RET: value type stack: %d vs. %d", td.method->klass->name, td.method->name, td.vt_sp, vt_size);
if (vt_size == 0)
SIMPLE_OP(td, signature->ret->type == MONO_TYPE_VOID ? MINT_RET_VOID : MINT_RET);
else {
case CEE_LDIND_I:
CHECK_STACK (&td, 1);
SIMPLE_OP (td, MINT_LDIND_I);
+ ADD_CODE (&td, 0);
SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I);
break;
case CEE_LDIND_R4:
ADD_CODE(&td, MINT_CONV_U4_I8);
#endif
break;
+ case STACK_TYPE_MP:
+ break;
default:
g_assert_not_reached ();
}
ADD_CODE(&td, MINT_LDOBJ);
ADD_CODE(&td, get_data_item_index(&td, klass));
- if (klass->byval_arg.type == MONO_TYPE_VALUETYPE && !klass->byval_arg.data.klass->enumtype) {
+ if (mint_type (&klass->byval_arg) == MINT_TYPE_VT) {
size = mono_class_value_size (klass, NULL);
PUSH_VT(&td, size);
}
ADD_CODE(&td, MINT_NEWOBJ);
ADD_CODE(&td, get_data_item_index (&td, mono_interp_get_runtime_method (domain, m, &error)));
mono_error_cleanup (&error); /* FIXME: don't swallow the error */
- if (klass->byval_arg.type == MONO_TYPE_VALUETYPE) {
+
+ if (mint_type (&klass->byval_arg) == MINT_TYPE_VT) {
vt_res_size = mono_class_value_size (klass, NULL);
- PUSH_VT(&td, vt_res_size);
+ PUSH_VT (&td, vt_res_size);
}
for (i = 0; i < csignature->param_count; ++i) {
int mt = mint_type(csignature->params [i]);
if (mt == MINT_TYPE_VT) {
- gint32 size = mono_class_value_size (csignature->params [i]->data.klass, NULL);
+ MonoClass *k = mono_class_from_mono_type (csignature->params [i]);
+ gint32 size = mono_class_value_size (k, NULL);
size = (size + 7) & ~7;
vt_stack_used += size;
}
WRITE32(&td, &vt_stack_used);
td.vt_sp -= vt_stack_used;
}
- PUSH_TYPE(&td, stack_type [mint_type (&klass->byval_arg)], klass);
+ PUSH_TYPE (&td, stack_type [mint_type (&klass->byval_arg)], klass);
break;
}
case CEE_CASTCLASS:
klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
else
klass = mono_class_get_full (image, token, generic_context);
+
+ if (mono_class_is_nullable (klass)) {
+ g_error ("cee_unbox: implement Nullable");
+ }
ADD_CODE(&td, MINT_UNBOX);
ADD_CODE(&td, get_data_item_index (&td, klass));
SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_MP);
td.ip += 5;
+ break;
+ case CEE_UNBOX_ANY:
+ CHECK_STACK (&td, 1);
+ token = read32 (td.ip + 1);
+
+ g_assert (method->wrapper_type == MONO_WRAPPER_NONE);
+ klass = mono_class_get_full (image, token, generic_context);
+
+ if (mini_type_is_reference (&klass->byval_arg)) {
+ g_error ("unbox_any: generic class is reference type");
+ } else if (mono_class_is_nullable (klass)) {
+ MonoMethod *target_method = mono_class_get_method_from_name (klass, "Unbox", 1);
+ /* td.ip is incremented by interp_transform_call */
+ interp_transform_call (&td, method, target_method, domain, generic_context, is_bb_start, body_start_offset, NULL);
+ } else {
+ int mt = mint_type (&klass->byval_arg);
+ ADD_CODE (&td, MINT_UNBOX);
+ ADD_CODE (&td, get_data_item_index (&td, klass));
+ SET_TYPE (td.sp - 1, stack_type [mt], klass);
+ if (mt == MINT_TYPE_VT) {
+ int size = mono_class_value_size (klass, NULL);
+ PUSH_VT (&td, size);
+ }
+ td.ip += 5;
+ }
+
break;
case CEE_THROW:
CHECK_STACK (&td, 1);
token = read32 (td.ip + 1);
field = mono_field_from_token (image, token, &klass, generic_context);
mono_class_init (klass);
- mt = mint_type(field->type);
+
+ MonoClass *field_klass = mono_class_from_mono_type (field->type);
+ mt = mint_type (&field_klass->byval_arg);
if (klass->marshalbyref) {
ADD_CODE(&td, mt == MINT_TYPE_VT ? MINT_LDRMFLD_VT : MINT_LDRMFLD);
ADD_CODE(&td, get_data_item_index (&td, field));
ADD_CODE(&td, MINT_LDFLD_I1 + mt - MINT_TYPE_I1);
ADD_CODE(&td, klass->valuetype ? field->offset - sizeof(MonoObject) : field->offset);
}
- klass = NULL;
if (mt == MINT_TYPE_VT) {
- int size = mono_class_value_size (field->type->data.klass, NULL);
+ int size = mono_class_value_size (field_klass, NULL);
PUSH_VT(&td, size);
WRITE32(&td, &size);
- klass = field->type->data.klass;
- } else if (mt == MINT_TYPE_O)
- klass = mono_class_from_mono_type (field->type);
+ }
+ if (td.sp [-1].type == STACK_TYPE_VT) {
+ int size = mono_class_value_size (klass, NULL);
+ size = (size + 7) & ~7;
+ td.vt_sp -= size;
+ ADD_CODE (&td, MINT_VTRESULT);
+ ADD_CODE (&td, 0);
+ WRITE32 (&td, &size);
+ }
td.ip += 5;
- SET_TYPE(td.sp - 1, stack_type [mt], klass);
+ SET_TYPE(td.sp - 1, stack_type [mt], field_klass);
break;
}
case CEE_STFLD:
ADD_CODE(&td, klass->valuetype ? field->offset - sizeof(MonoObject) : field->offset);
}
if (mt == MINT_TYPE_VT) {
- int size = mono_class_value_size (field->type->data.klass, NULL);
+ MonoClass *klass = mono_class_from_mono_type (field->type);
+ int size = mono_class_value_size (klass, NULL);
POP_VT(&td, size);
WRITE32(&td, &size);
}
ADD_CODE(&td, get_data_item_index (&td, field));
klass = NULL;
if (mt == MINT_TYPE_VT) {
- int size = mono_class_value_size (field->type->data.klass, NULL);
+ MonoClass *klass = mono_class_from_mono_type (field->type);
+ int size = mono_class_value_size (klass, NULL);
PUSH_VT(&td, size);
WRITE32(&td, &size);
klass = field->type->data.klass;
} else {
if (mt == MINT_TYPE_O)
klass = mono_class_from_mono_type (field->type);
- if (!domain->special_static_fields || !g_hash_table_lookup (domain->special_static_fields, field)) {
- if (mt == MINT_TYPE_O)
- td.new_ip [-2] = MINT_LDSFLD_O;
- else if (mt == MINT_TYPE_I4)
- td.new_ip [-2] = MINT_LDSFLD_I4;
- }
- ADD_CODE(&td, get_data_item_index (&td, mono_class_vtable (domain, field->parent)));
}
td.ip += 5;
PUSH_TYPE(&td, stack_type [mt], klass);
ADD_CODE(&td, mt == MINT_TYPE_VT ? MINT_STSFLD_VT : MINT_STSFLD);
ADD_CODE(&td, get_data_item_index (&td, field));
if (mt == MINT_TYPE_VT) {
- int size = mono_class_value_size (field->type->data.klass, NULL);
- POP_VT(&td, size);
- WRITE32(&td, &size);
+ MonoClass *klass = mono_class_from_mono_type (field->type);
+ int size = mono_class_value_size (klass, NULL);
+ POP_VT (&td, size);
+ WRITE32 (&td, &size);
}
td.ip += 5;
--td.sp;
klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
else
klass = mono_class_get_full (image, token, generic_context);
- g_assert (klass->valuetype);
- if (klass->byval_arg.type == MONO_TYPE_VALUETYPE && !klass->enumtype) {
- size = mono_class_value_size (klass, NULL);
- size = (size + 7) & ~7;
- td.vt_sp -= size;
+
+ if (mono_class_is_nullable (klass)) {
+ MonoMethod *target_method = mono_class_get_method_from_name (klass, "Box", 1);
+ /* td.ip is incremented by interp_transform_call */
+ interp_transform_call (&td, method, target_method, domain, generic_context, is_bb_start, body_start_offset, NULL);
+ } else if (!klass->valuetype) {
+ /* already boxed, do nothing. */
+ td.ip += 5;
+ } else {
+ if (mint_type (&klass->byval_arg) == MINT_TYPE_VT && !klass->enumtype) {
+ size = mono_class_value_size (klass, NULL);
+ size = (size + 7) & ~7;
+ td.vt_sp -= size;
+ }
+ ADD_CODE(&td, MINT_BOX);
+ ADD_CODE(&td, get_data_item_index (&td, klass));
+ ADD_CODE (&td, 0);
+ SET_TYPE(td.sp - 1, STACK_TYPE_O, klass);
+ td.ip += 5;
}
- ADD_CODE(&td, MINT_BOX);
- ADD_CODE(&td, get_data_item_index (&td, klass));
- SET_TYPE(td.sp - 1, STACK_TYPE_O, klass);
- td.ip += 5;
+
break;
}
case CEE_NEWARR:
--td.sp;
SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_O);
break;
+ case CEE_LDELEM:
+ CHECK_STACK (&td, 2);
+ token = read32 (td.ip + 1);
+ klass = mono_class_get_full (image, token, generic_context);
+ switch (mint_type (&klass->byval_arg)) {
+ case MINT_TYPE_I4:
+ ENSURE_I4 (&td, 1);
+ SIMPLE_OP (td, MINT_LDELEM_I4);
+ --td.sp;
+ SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4);
+ break;
+ case MINT_TYPE_VT: {
+ int size = mono_class_value_size (klass, NULL);
+ ENSURE_I4 (&td, 1);
+ SIMPLE_OP (td, MINT_LDELEM_VT);
+ ADD_CODE (&td, get_data_item_index (&td, klass));
+ WRITE32 (&td, &size);
+ --td.sp;
+ SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_VT);
+ PUSH_VT (&td, size);
+ break;
+ }
+ default: {
+ GString *res = g_string_new ("");
+ mono_type_get_desc (res, &klass->byval_arg, TRUE);
+ g_print ("LDELEM: %s -> %d (%s)\n", klass->name, mint_type (&klass->byval_arg), res->str);
+ g_string_free (res, TRUE);
+ g_assert (0);
+ break;
+ }
+ }
+ td.ip += 4;
+ break;
case CEE_STELEM_I:
CHECK_STACK (&td, 3);
ENSURE_I4 (&td, 2);
SIMPLE_OP (td, MINT_STELEM_REF);
td.sp -= 3;
break;
+ case CEE_STELEM:
+ CHECK_STACK (&td, 3);
+ ENSURE_I4 (&td, 2);
+ token = read32 (td.ip + 1);
+ klass = mono_class_get_full (image, token, generic_context);
+ switch (mint_type (&klass->byval_arg)) {
+ case MINT_TYPE_I4:
+ SIMPLE_OP (td, MINT_STELEM_I4);
+ break;
+ case MINT_TYPE_O:
+ SIMPLE_OP (td, MINT_STELEM_REF);
+ break;
+ case MINT_TYPE_VT: {
+ int size = mono_class_value_size (klass, NULL);
+ SIMPLE_OP (td, MINT_STELEM_VT);
+ ADD_CODE (&td, get_data_item_index (&td, klass));
+ WRITE32 (&td, &size);
+ POP_VT (&td, size);
+ break;
+ }
+ default: {
+ GString *res = g_string_new ("");
+ mono_type_get_desc (res, &klass->byval_arg, TRUE);
+ g_print ("STELEM: %s -> %d (%s)\n", klass->name, mint_type (&klass->byval_arg), res->str);
+ g_string_free (res, TRUE);
+ g_assert (0);
+ break;
+ }
+ }
+ td.ip += 4;
+ td.sp -= 3;
+ break;
#if 0
- case CEE_LDELEM:
- case CEE_STELEM:
- case CEE_UNBOX_ANY:
-
case CEE_CONV_OVF_U1:
case CEE_CONV_OVF_I8:
case CEE_UNUSED41:
++td.ip;
switch (*td.ip) {
+ case CEE_MONO_CALLI_EXTRA_ARG:
+ /* Same as CEE_CALLI, llvm specific */
+ interp_transform_call (&td, method, NULL, domain, generic_context, is_bb_start, body_start_offset, NULL);
+ break;
case CEE_MONO_ICALL: {
guint32 token;
gpointer func;
if (MONO_TYPE_IS_VOID (info->sig->ret))
ADD_CODE (&td,MINT_ICALL_V_V);
else
- g_assert_not_reached();
+ ADD_CODE (&td, MINT_ICALL_V_P);
break;
case 1:
if (MONO_TYPE_IS_VOID (info->sig->ret))
default:
g_assert_not_reached ();
}
- g_error ("FIXME: ftnptr to delegate");
-#if 0
- if (func == mono_ftnptr_to_delegate)
+
+ if (func == mono_ftnptr_to_delegate) {
+ g_error ("TODO: ?");
func = mono_interp_ftnptr_to_delegate;
-#endif
+ }
ADD_CODE(&td, get_data_item_index (&td, func));
td.sp -= info->sig->param_count;
case CEE_MONO_NOT_TAKEN:
++td.ip;
break;
+ case CEE_MONO_LDPTR_INT_REQ_FLAG:
+ ADD_CODE (&td, MINT_MONO_LDPTR);
+ ADD_CODE (&td, get_data_item_index (&td, mono_thread_interruption_request_flag ()));
+ PUSH_TYPE (&td, STACK_TYPE_MP, NULL);
+ ++td.ip;
+ break;
default:
g_error ("transform.c: Unimplemented opcode: 0xF0 %02x at 0x%x\n", *td.ip, td.ip-header->code);
}
break;
case CEE_LDARGA: {
int n = read16 (td.ip + 1);
- if (n == 0 && signature->hasthis)
+ if (n == 0 && signature->hasthis) {
+ g_error ("LDTHISA: NOPE");
ADD_CODE(&td, MINT_LDTHISA);
+ }
else {
ADD_CODE(&td, MINT_LDARGA);
- ADD_CODE(&td, td.rtm->arg_offsets [n - signature->hasthis]); /* FIX for large offsets */
+ ADD_CODE(&td, td.rtm->arg_offsets [n]); /* FIX for large offsets */
}
PUSH_SIMPLE_TYPE(&td, STACK_TYPE_MP);
td.ip += 3;
td.sp -= 3;
++td.ip;
break;
-#if 0
- case CEE_CONSTRAINED_: {
- guint32 token;
- /* FIXME: implement */
- ++ip;
- token = read32 (ip);
- ip += 4;
+ case CEE_CONSTRAINED_:
+ token = read32 (td.ip + 1);
+ constrained_class = mono_class_get_full (image, token, generic_context);
+ mono_class_init (constrained_class);
+ td.ip += 5;
break;
- }
-#endif
case CEE_INITBLK:
CHECK_STACK(&td, 3);
ADD_CODE(&td, MINT_INITBLK);
generating_code = 0;
break;
case CEE_SIZEOF: {
- guint32 align;
gint32 size;
token = read32 (td.ip + 1);
td.ip += 5;
if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
+ int align;
MonoType *type = mono_type_create_from_typespec (image, token);
size = mono_type_size (type, &align);
} else {
+ guint32 align;
MonoClass *szclass = mono_class_get_full (image, token, generic_context);
mono_class_init (szclass);
#if 0
}
/* assumes all internal calls with an array this are built in... */
- if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
- (! mono_method_signature (method)->hasthis || method->klass->rank == 0)) {
- runtime_method->code = g_malloc(sizeof(short));
- runtime_method->code[0] = MINT_CALLINT;
- if (((MonoMethodPInvoke*) method)->addr == NULL)
- ((MonoMethodPInvoke*) method)->addr = mono_lookup_internal_call (method);
- g_error ("FIXME: not available?");
-#if 0
- runtime_method->func = mono_arch_create_trampoline (mono_method_signature (method), method->string_ctor);
-#endif
+ if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL && (! mono_method_signature (method)->hasthis || method->klass->rank == 0)) {
+ nm = mono_marshal_get_native_wrapper (method, TRUE, FALSE);
+ signature = mono_method_signature (nm);
} else {
const char *name = method->name;
if (method->klass->parent == mono_defaults.multicastdelegate_class) {
if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
- g_error ("FIXME: no del?");
nm = mono_marshal_get_delegate_invoke (method, NULL);
} else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
nm = mono_marshal_get_delegate_begin_invoke (method);
runtime_method->alloca_size = runtime_method->stack_size;
runtime_method->transformed = TRUE;
mono_os_mutex_unlock(&calc_section);
- g_error ("FIXME: no jinfo?");
mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_OK);
return NULL;
}
// return mono_get_exception_missing_method ();
}
mono_class_init (m->klass);
- if (!(m->klass->flags & TYPE_ATTRIBUTE_INTERFACE))
+ if (!mono_class_is_interface (m->klass))
mono_class_vtable (domain, m->klass);
}
ip += 5;
if (runtime_method->transformed) {
mono_os_mutex_unlock(&calc_section);
g_free (is_bb_start);
- g_error ("FIXME: missing jinfo1");
mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_OK);
return NULL;
}
runtime_method->locals_size = offset;
g_assert (runtime_method->locals_size < 65536);
offset = 0;
- runtime_method->arg_offsets = g_malloc(signature->param_count * sizeof(guint32));
+ runtime_method->arg_offsets = g_malloc ((!!signature->hasthis + signature->param_count) * sizeof(guint32));
+
+ if (signature->hasthis) {
+ g_assert (!signature->pinvoke);
+ size = mono_type_stack_size (&method->klass->byval_arg, &align);
+ offset += align - 1;
+ offset &= ~(align - 1);
+ runtime_method->arg_offsets [0] = offset;
+ offset += size;
+ }
+
for (i = 0; i < signature->param_count; ++i) {
if (signature->pinvoke) {
- size = mono_type_native_stack_size (signature->params [i], &align);
+ guint32 dummy;
+ size = mono_type_native_stack_size (signature->params [i], &dummy);
align = 8;
}
else
size = mono_type_stack_size (signature->params [i], &align);
offset += align - 1;
offset &= ~(align - 1);
- runtime_method->arg_offsets [i] = offset;
+ runtime_method->arg_offsets [i + !!signature->hasthis] = offset;
offset += size;
}
offset = (offset + 7) & ~7;