+2008-03-04 Mark Probst <mark.probst@gmail.com>
+
+ * domain-internals.h, domain.c: Replaced MonoGenericSharingContext
+ with a new structure, MonoGenericJitInfo, in the MonoJitInfo. It
+ contains the location of "this", used for exception handling.
+
2008-03-04 Zoltan Varga <vargaz@gmail.com>
* class.c (mono_class_layout_fields): Set the min alignment of small structs to
int dummy;
} MonoGenericSharingContext;
+typedef struct
+{
+ MonoGenericSharingContext *generic_sharing_context;
+ gint32 this_offset;
+ guint8 this_reg;
+ gboolean this_in_reg:1;
+} MonoGenericJitInfo;
+
struct _MonoJitInfo {
/* NOTE: These first two elements (method and
next_jit_code_hash) must be in the same order and at the
gboolean cas_method_assert:1;
gboolean cas_method_deny:1;
gboolean cas_method_permitonly:1;
- gboolean has_generic_sharing_context:1;
+ gboolean has_generic_jit_info:1;
MonoJitExceptionInfo clauses [MONO_ZERO_LEN_ARRAY];
- /* There is an optional MonoGenericSharingContext* after the clauses */
+ /* There is an optional MonoGenericJitInfo after the clauses */
};
typedef struct {
void
mono_jit_info_add_aot_module (MonoImage *image, gpointer start, gpointer end) MONO_INTERNAL;
+MonoGenericJitInfo*
+mono_jit_info_get_generic_jit_info (MonoJitInfo *ji) MONO_INTERNAL;
+
MonoGenericSharingContext*
mono_jit_info_get_generic_sharing_context (MonoJitInfo *ji) MONO_INTERNAL;
jit_info_next_value);
}
+MonoGenericJitInfo*
+mono_jit_info_get_generic_jit_info (MonoJitInfo *ji)
+{
+ if (ji->has_generic_jit_info)
+ return (MonoGenericJitInfo*)&ji->clauses [ji->num_clauses];
+ else
+ return NULL;
+}
+
/*
* mono_jit_info_get_generic_sharing_context:
* @ji: a jit info
MonoGenericSharingContext*
mono_jit_info_get_generic_sharing_context (MonoJitInfo *ji)
{
- if (ji->has_generic_sharing_context)
- return *((MonoGenericSharingContext**)&ji->clauses [ji->num_clauses]);
+ MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
+
+ if (gi)
+ return gi->generic_sharing_context;
else
return NULL;
}
void
mono_jit_info_set_generic_sharing_context (MonoJitInfo *ji, MonoGenericSharingContext *gsctx)
{
- g_assert (ji->has_generic_sharing_context);
+ MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
+
+ g_assert (gi);
- *((MonoGenericSharingContext**)&ji->clauses [ji->num_clauses]) = gsctx;
+ gi->generic_sharing_context = gsctx;
}
/**
+2008-03-04 Mark Probst <mark.probst@gmail.com>
+
+ * mini.c: For shared methods of generic classes put the location
+ of "this" into the MonoGenericJitInfo.
+
+ * mini-x86.c, mini-amd64.c, mini.h: Added function for fetching a
+ register out of a MonoContext by register number. Add the generic
+ sharing context as an argument to mono_arch_find_this_argument().
+
+ * mini-alpha.c, mini-arm.c, mini-hppa.c, mini-ia64.c, mini-mips.c,
+ mini-ppc.c, mini-s390.c, mini-s390x.c, mini-sparc.c: Added stub
+ for new arch function.
+
+ * mini-exception.c: Handle open exception clauses in shared
+ generic code.
+
+ * mini-trampolines.c: Supply additional argument to
+ mono_arch_find_this_argument().
+
2008-03-04 Zoltan Varga <vargaz@gmail.com>
* Makefile.am (regtests): Run the bench.exe tests last.
return 3;
}
+gpointer
+mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
+{
+ /* FIXME: implement */
+ g_assert_not_reached ();
+}
}
MonoObject*
-mono_arch_find_this_argument (gpointer *regs, MonoMethod *method)
+mono_arch_find_this_argument (gpointer *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
{
return mono_arch_get_this_arg_from_call (mono_method_signature (method), (gssize*)regs, NULL);
}
ins->inst_offset = thread_tls_offset;
return ins;
}
+
+#define _CTX_REG(ctx,fld,i) ((gpointer)((&ctx->fld)[i]))
+
+gpointer
+mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
+{
+ switch (reg) {
+ case AMD64_RCX: return (gpointer)ctx->rcx;
+ case AMD64_RDX: return (gpointer)ctx->rdx;
+ case AMD64_RBX: return (gpointer)ctx->rbx;
+ case AMD64_RBP: return (gpointer)ctx->rbp;
+ case AMD64_RSP: return (gpointer)ctx->rsp;
+ default:
+ if (reg < 8)
+ return _CTX_REG (ctx, rax, reg);
+ else if (reg >= 12)
+ return _CTX_REG (ctx, r12, reg - 12);
+ else
+ g_assert_not_reached ();
+ }
+}
}
MonoObject*
-mono_arch_find_this_argument (gpointer *regs, MonoMethod *method)
+mono_arch_find_this_argument (gpointer *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
{
return mono_arch_get_this_arg_from_call (mono_method_signature (method), (gssize*)regs, NULL);
}
#endif
-
+gpointer
+mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
+{
+ /* FIXME: implement */
+ g_assert_not_reached ();
+}
#ifndef CUSTOM_EXCEPTION_HANDLING
+static MonoClass*
+get_exception_catch_class (MonoJitExceptionInfo *ei, MonoJitInfo *ji, MonoContext *ctx)
+{
+ MonoClass *catch_class = ei->data.catch_class;
+
+ if (ji->has_generic_jit_info) {
+ MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
+ gpointer info;
+ MonoClass *class;
+ MonoType *inflated_type;
+
+ if (gi->this_in_reg)
+ info = mono_arch_context_get_int_reg (ctx, gi->this_reg);
+ else
+ info = *(gpointer*)((char*)mono_arch_context_get_int_reg (ctx, gi->this_reg) +
+ gi->this_offset);
+
+ if (ji->method->flags & METHOD_ATTRIBUTE_STATIC) {
+ MonoRuntimeGenericContext *rgctx = info;
+
+ class = rgctx->vtable->klass;
+ } else {
+ MonoObject *this = info;
+
+ class = this->vtable->klass;
+ }
+
+ /* FIXME: we shouldn't inflate but instead put the
+ type in the rgctx and fetch it from there. It
+ might be a good idea to do this lazily, i.e. only
+ when the exception is actually thrown, so as not to
+ waste space for exception clauses which might never
+ be encountered. */
+ inflated_type = mono_class_inflate_generic_type (&catch_class->byval_arg,
+ mini_class_get_context (class));
+ catch_class = mono_class_from_mono_type (inflated_type);
+ g_free (inflated_type);
+ }
+
+ return catch_class;
+}
+
/**
* mono_handle_exception_internal:
* @ctx: saved processor state
#endif
MONO_CONTEXT_GET_IP (ctx) <= ei->try_end) {
/* catch block */
+ MonoClass *catch_class = get_exception_catch_class (ei, ji, ctx);
if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE) || (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)) {
/* store the exception object in bp + ei->exvar_offset */
}
if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE &&
- mono_object_isinst (obj, ei->data.catch_class)) || filtered) {
+ mono_object_isinst (obj, catch_class)) || filtered) {
if (test_only) {
if (mono_ex && !initial_trace_ips) {
trace_ips = g_list_reverse (trace_ips);
{
return NULL;
}
+
+gpointer
+mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
+{
+ /* FIXME: implement */
+ g_assert_not_reached ();
+}
}
MonoObject*
-mono_arch_find_this_argument (gpointer *regs, MonoMethod *method)
+mono_arch_find_this_argument (gpointer *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
{
return mono_arch_get_this_arg_from_call (mono_method_signature (method), (gssize*)regs, NULL);
}
ins->inst_offset = thread_tls_offset;
return ins;
}
+
+gpointer
+mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
+{
+ /* FIXME: implement */
+ g_assert_not_reached ();
+}
return ins;
}
+gpointer
+mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
+{
+ /* FIXME: implement */
+ g_assert_not_reached ();
+}
}
MonoObject*
-mono_arch_find_this_argument (gpointer *regs, MonoMethod *method)
+mono_arch_find_this_argument (gpointer *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
{
return mono_arch_get_this_arg_from_call (mono_method_signature (method), (gssize*)regs, NULL);
}
return ins;
}
+gpointer
+mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
+{
+ /* FIXME: implement */
+ g_assert_not_reached ();
+}
}
/*========================= End of Function ========================*/
+
+gpointer
+mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
+{
+ /* FIXME: implement */
+ g_assert_not_reached ();
+}
}
/*========================= End of Function ========================*/
+
+gpointer
+mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
+{
+ /* FIXME: implement */
+ g_assert_not_reached ();
+}
}
MonoObject*
-mono_arch_find_this_argument (gpointer *regs, MonoMethod *method)
+mono_arch_find_this_argument (gpointer *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
{
mono_sparc_flushw ();
{
return NULL;
}
+
+gpointer
+mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
+{
+ /* FIXME: implement */
+ g_assert_not_reached ();
+}
#include "mini.h"
#include "debug-mini.h"
+static MonoGenericSharingContext*
+get_generic_context (guint8 *code)
+{
+ MonoJitInfo *jit_info = mono_jit_info_table_find (mono_domain_get (), (char*)code);
+
+ g_assert (jit_info);
+
+ return mono_jit_info_get_generic_sharing_context (jit_info);
+}
+
#ifdef MONO_ARCH_HAVE_IMT
static gpointer*
mono_convert_imt_slot_to_vtable_slot (gpointer* slot, gpointer *regs, guint8 *code, MonoMethod *method, MonoMethod **impl_method)
{
- MonoObject *this_argument = mono_arch_find_this_argument (regs, method);
+ MonoGenericSharingContext *gsctx = get_generic_context (code);
+ MonoObject *this_argument = mono_arch_find_this_argument (regs, method, gsctx);
MonoVTable *vt = this_argument->vtable;
int displacement = slot - ((gpointer*)vt);
-
+
if (displacement > 0) {
/* slot is in the vtable, not in the IMT */
#if DEBUG_IMT
* For x86 win32, see ???.
*/
static CallInfo*
-get_call_info (MonoCompile *cfg, MonoMemPool *mp, MonoMethodSignature *sig, gboolean is_pinvoke)
+get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSignature *sig, gboolean is_pinvoke)
{
guint32 i, gr, fr;
MonoType *ret_type;
int n = sig->hasthis + sig->param_count;
guint32 stack_size = 0;
CallInfo *cinfo;
- MonoGenericSharingContext *gsctx = cfg ? cfg->generic_sharing_context : NULL;
if (mp)
cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
header = mono_method_get_header (cfg->method);
sig = mono_method_signature (cfg->method);
- cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
+ cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig, FALSE);
cfg->frame_reg = MONO_ARCH_BASEREG;
offset = 0;
sig = mono_method_signature (cfg->method);
- cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
+ cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig, FALSE);
if (cinfo->ret.storage == ArgValuetypeInReg)
cfg->ret_var_is_local = TRUE;
sig = call->signature;
n = sig->param_count + sig->hasthis;
- cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
+ cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig, FALSE);
if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
sentinelpos = sig->sentinelpos + (is_virtual ? 1 : 0);
case OP_VCALL:
case OP_VCALL_REG:
case OP_VCALL_MEMBASE:
- cinfo = get_call_info (cfg, cfg->mempool, ((MonoCallInst*)ins)->signature, FALSE);
+ cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, ((MonoCallInst*)ins)->signature, FALSE);
if (cinfo->ret.storage == ArgValuetypeInReg) {
/* Pop the destination address from the stack */
x86_pop_reg (code, X86_ECX);
sig = mono_method_signature (method);
- cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
+ cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig, FALSE);
/* This is the opposite of the code in emit_prolog */
}
/* Load returned vtypes into registers if needed */
- cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
+ cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig, FALSE);
if (cinfo->ret.storage == ArgValuetypeInReg) {
for (quad = 0; quad < 2; quad ++) {
switch (cinfo->ret.pair_storage [quad]) {
mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
{
MonoCallInst *call = (MonoCallInst*)inst;
- CallInfo *cinfo = get_call_info (cfg, cfg->mempool, inst->signature, FALSE);
+ CallInfo *cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, inst->signature, FALSE);
/* add the this argument */
if (this_reg != -1) {
}
MonoObject*
-mono_arch_find_this_argument (gpointer *regs, MonoMethod *method)
+mono_arch_find_this_argument (gpointer *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
{
MonoMethodSignature *sig = mono_method_signature (method);
- CallInfo *cinfo = get_call_info (NULL, NULL, sig, FALSE);
+ CallInfo *cinfo = get_call_info (gsctx, NULL, sig, FALSE);
int this_argument_offset;
MonoObject *this_argument;
return start;
}
+
+gpointer
+mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
+{
+ switch (reg) {
+ case X86_ECX: return (gpointer)ctx->ecx;
+ case X86_EDX: return (gpointer)ctx->edx;
+ case X86_EBP: return (gpointer)ctx->ebp;
+ case X86_ESP: return (gpointer)ctx->esp;
+ default: return ((gpointer)(&ctx->eax)[reg]);
+ }
+}
for (i = 0; i < header->num_clauses; ++i) {
MonoBasicBlock *try_bb;
MonoExceptionClause *clause = &header->clauses [i];
+
+ /* We can't handle open exception clauses in
+ * static methods yet.
+ */
+ if ((method->flags & METHOD_ATTRIBUTE_STATIC) &&
+ clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
+ clause->data.catch_class &&
+ mono_class_check_context_used (clause->data.catch_class)) {
+ GENERIC_SHARING_FAILURE (CEE_NOP);
+ }
+
GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
try_bb->real_offset = clause->try_offset;
GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
MonoCompile*
mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gboolean run_cctors, gboolean compile_aot, int parts)
{
- MonoMethodHeader *header = mono_method_get_header (method);
+ MonoMethodHeader *header;
guint8 *ip;
MonoCompile *cfg;
MonoJitInfo *jinfo;
gboolean deadce_has_run = FALSE;
gboolean try_generic_shared;
MonoMethod *method_to_compile;
- int gsctx_size;
+ int generic_info_size;
mono_jit_stats.methods_compiled++;
if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)
if (try_generic_shared)
cfg->generic_sharing_context = (MonoGenericSharingContext*)&cfg->generic_sharing_context;
cfg->token_info_hash = g_hash_table_new (NULL, NULL);
+
+ header = mono_method_get_header (method_to_compile);
if (!header) {
cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
}
if (cfg->generic_sharing_context)
- gsctx_size = sizeof (MonoGenericSharingContext*);
+ generic_info_size = sizeof (MonoGenericJitInfo);
else
- gsctx_size = 0;
+ generic_info_size = 0;
if (cfg->method->dynamic) {
jinfo = g_malloc0 (sizeof (MonoJitInfo) + (header->num_clauses * sizeof (MonoJitExceptionInfo)) +
- gsctx_size);
+ generic_info_size);
} else {
/* we access cfg->domain->mp */
mono_domain_lock (cfg->domain);
jinfo = mono_mempool_alloc0 (cfg->domain->mp, sizeof (MonoJitInfo) +
(header->num_clauses * sizeof (MonoJitExceptionInfo)) +
- gsctx_size);
+ generic_info_size);
mono_domain_unlock (cfg->domain);
}
jinfo->cas_inited = FALSE; /* initialization delayed at the first stalk walk using this method */
jinfo->num_clauses = header->num_clauses;
- if (cfg->generic_sharing_context) {
- jinfo->has_generic_sharing_context = 1;
- mono_jit_info_set_generic_sharing_context (jinfo, cfg->generic_sharing_context);
+ if (cfg->generic_sharing_context && !(method_to_compile->flags & METHOD_ATTRIBUTE_STATIC)) {
+ MonoInst *inst;
+ MonoGenericJitInfo *gi;
+
+ jinfo->has_generic_jit_info = 1;
+
+ gi = mono_jit_info_get_generic_jit_info (jinfo);
+ g_assert (gi);
+
+ gi->generic_sharing_context = cfg->generic_sharing_context;
+
+ g_assert (!(method_to_compile->flags & METHOD_ATTRIBUTE_STATIC));
+
+ inst = cfg->varinfo [0];
+
+ if (inst->opcode == OP_REGVAR) {
+ gi->this_in_reg = 1;
+ gi->this_reg = inst->dreg;
+
+ //g_print ("this in reg %d\n", inst->dreg);
+ } else {
+ g_assert (inst->opcode == OP_REGOFFSET);
+#ifdef __i386__
+ g_assert (inst->inst_basereg == X86_EBP);
+#elif defined(__x86_64__)
+ g_assert (inst->inst_basereg == X86_EBP || inst->inst_basereg == X86_ESP);
+#endif
+ g_assert (inst->inst_offset >= G_MININT32 && inst->inst_offset <= G_MAXINT32);
+
+ gi->this_in_reg = 0;
+ gi->this_reg = inst->inst_basereg;
+ gi->this_offset = inst->inst_offset;
+
+ //g_print ("this at offset %d\n", inst->inst_offset);
+ }
}
if (header->num_clauses) {
gpointer mono_arch_ip_from_context (void *sigctx) MONO_INTERNAL;
void mono_arch_sigctx_to_monoctx (void *sigctx, MonoContext *ctx) MONO_INTERNAL;
void mono_arch_monoctx_to_sigctx (MonoContext *mctx, void *ctx) MONO_INTERNAL;
+gpointer mono_arch_context_get_int_reg (MonoContext *ctx, int reg) MONO_INTERNAL;
void mono_arch_flush_register_windows (void) MONO_INTERNAL;
gboolean mono_arch_is_inst_imm (gint64 imm) MONO_INTERNAL;
MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg) MONO_INTERNAL;
gpointer mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain, guint32 *code_len) MONO_INTERNAL;
void mono_arch_emit_imt_argument (MonoCompile *cfg, MonoCallInst *call) MONO_INTERNAL;
MonoMethod* mono_arch_find_imt_method (gpointer *regs, guint8 *code) MONO_INTERNAL;
-MonoObject* mono_arch_find_this_argument (gpointer *regs, MonoMethod *method) MONO_INTERNAL;
+MonoObject* mono_arch_find_this_argument (gpointer *regs, MonoMethod *method, MonoGenericSharingContext *gsctx) MONO_INTERNAL;
gpointer mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count) MONO_INTERNAL;
void mono_arch_notify_pending_exc (void) MONO_INTERNAL;
+2008-03-04 Mark Probst <mark.probst@gmail.com>
+
+ * generics-sharing.2.c: Added test for open catch clauses in
+ shared generic code.
+
2008-02-27 Zoltan Varga <vargaz@gmail.com>
* Makefile.am: Compile and run all tests using the 2.0 profile.
public class ClassB {}
public class ClassC {}
+public class GenExc<T> : Exception {}
+
public class NonGen {
public static int field = 123;
+
+ public static void doThrow () {
+ throw new GenExc<ClassA> ();
+ }
}
public class GenA<T> {
public T cast (Object obj) {
return (T)obj;
}
+
+ public void except () {
+ try {
+ NonGen.doThrow();
+ }
+ catch (GenExc<T>)
+ {
+ //Console.WriteLine("exception thrown");
+ }
+ }
}
public class GenB<T> {
error ("object from " + method + " should have type " + t.ToString () + " but has type " + obj.GetType ().ToString ());
}
- public static void work<T> (T obj) {
+ public static void work<T> (T obj, bool mustCatch) {
EqualityComparer<T> comp = EqualityComparer<T>.Default;
GenA<T> ga = new GenA<T> ();
new GenADeriv<T> ();
+ if (mustCatch) {
+ bool didCatch = false;
+
+ try {
+ ga.except ();
+ } catch (GenExc<ClassA>) {
+ didCatch = true;
+ }
+
+ if (!didCatch)
+ error ("except");
+ } else
+ ga.except ();
+
MyDict<T, ClassB> dtb = new MyDict<T, ClassB> (obj, new ClassB ());
typeCheck ("MyPair", dtb.p, typeof (MyPair<T, ClassB>));
public static int Main ()
{
- work<ClassA> (new ClassA ());
- work<ClassB> (new ClassB ());
- work<ClassC> (new ClassC ());
- work<GenA<ClassA>> (new GenA<ClassA> ());
- work<int[]> (new int[3]);
- work<int> (123);
+ work<ClassA> (new ClassA (), false);
+ work<ClassB> (new ClassB (), true);
+ work<ClassC> (new ClassC (), true);
+ work<GenA<ClassA>> (new GenA<ClassA> (), true);
+ work<int[]> (new int[3], true);
+ work<int> (123, true);
StaticTest<ClassA> sa = new StaticTest<ClassA> (1234);
StaticTest<ClassB> sb = new StaticTest<ClassB> (2345);