2004-03-08 Zoltan Varga <vargaz@freemail.hu>
+ * mini-sparc.h mini-sparc.c inssel-sparc.brg exceptions-sparc.c
+ cpu-sparc.md: Add exception handling support + other fixes.
+
* driver.c: Print --help output to stdout. Fixes #55261. Also fix
typed GC detection in --version.
conv.ovf.u:
add.ovf:
add.ovf.un:
-mul.ovf: dest:i src1:i src2:i len:12
-mul.ovf.un: dest:i src1:i src2:i len:12
+mul.ovf: dest:i src1:i src2:i len:24
+mul.ovf.un: dest:i src1:i src2:i len:20
sub.ovf:
sub.ovf.un:
-# FIXME: May need some work
-endfinally: len:4
+start_handler: len:20
+endfinally: len:20
+endfilter: len:16
leave:
leave.s:
stind.i:
stloc:
localloc: dest:i src1:i len:24
sparc_localloc_imm: dest:i len:16
-endfilter:
unaligned.:
volatile.:
tail.:
lcompare:
local:
arg:
+setfret: dest:f src1:f len:8
# FIXME: Mono-specifc opcodes (OP_) Need to clean these up
outarg: src1:i len:1
outarg_imm: len:5
lcall: dest:l len:16 clob:c
lcall_reg: dest:l src1:i len:16 clob:c
lcall_membase: dest:l src1:b len:20 clob:c
-vcall: len:8 clob:c
-vcall_reg: src1:i len:8 clob:c
-vcall_membase: src1:b len:16 clob:c
+vcall: len:12 clob:c
+vcall_reg: src1:i len:12 clob:c
+vcall_membase: src1:b len:20 clob:c
call_reg: dest:i src1:i len:12 clob:c
call_membase: dest:i src1:b len:16 clob:c
trap:
shl_imm: dest:i src1:i len:12
shr_imm: dest:i src1:i len:12
shr_un_imm: dest:i src1:i len:12
-cond_exc_eq: len:8
-cond_exc_ne_un: len:8
-cond_exc_lt: len:8
-cond_exc_lt_un: len:8
-cond_exc_gt: len:8
-cond_exc_gt_un: len:8
-cond_exc_ge: len:8
-cond_exc_ge_un: len:8
-cond_exc_le: len:8
-cond_exc_le_un: len:8
-cond_exc_ov: len:8
-cond_exc_no: len:8
-cond_exc_c: len:8
-cond_exc_nc: len:8
+cond_exc_eq: len:12
+cond_exc_ne_un: len:12
+cond_exc_lt: len:12
+cond_exc_lt_un: len:12
+cond_exc_gt: len:12
+cond_exc_gt_un: len:12
+cond_exc_ge: len:12
+cond_exc_ge_un: len:12
+cond_exc_le: len:12
+cond_exc_le_un: len:12
+cond_exc_ov: len:12
+cond_exc_no: len:12
+cond_exc_c: len:12
+cond_exc_nc: len:12
long_add:
long_sub:
long_mul:
long_conv_to_u2:
long_conv_to_u1:
long_conv_to_i:
-long_conv_to_ovf_i: dest:i src1:i src2:i len:36
+long_conv_to_ovf_i: dest:i src1:i src2:i len:44
long_conv_to_ovf_u:
long_add_ovf:
long_add_ovf_un:
#include <glib.h>
#include <signal.h>
#include <string.h>
+#include <sys/ucontext.h>
#include <mono/arch/sparc/sparc-codegen.h>
#include <mono/metadata/appdomain.h>
#include <mono/metadata/debug-helpers.h>
#include <mono/metadata/exception.h>
#include <mono/metadata/mono-debug.h>
+#include <mono/metadata/gc-internal.h>
#include "mini.h"
#include "mini-sparc.h"
-#warning NotReady
+typedef struct MonoContext {
+ guint32 ip;
+ guint32 *sp;
+ guint32 *fp;
+} MonoContext;
-typedef struct sigcontext MonoContext;
+gboolean mono_sparc_handle_exception (MonoContext *ctx, gpointer obj, gboolean test_only);
-gboolean mono_arch_handle_exception (MonoContext *ctx, gpointer obj, gboolean test_only);
+#define MONO_CONTEXT_SET_IP(ctx,eip) do { (ctx)->ip = (long)(eip); } while (0);
+#define MONO_CONTEXT_SET_BP(ctx,ebp) do { (ctx)->sp = (long)(ebp); } while (0);
-#define MONO_CONTEXT_SET_IP(ctx,ip) do { (ctx)->SC_EIP = (long)ip; } while (0);
-#define MONO_CONTEXT_SET_BP(ctx,bp) do { (ctx)->SC_EBP = (long)bp; } while (0);
+#define MONO_CONTEXT_GET_IP(ctx) ((gpointer)((ctx)->ip))
+#define MONO_CONTEXT_GET_BP(ctx) ((gpointer)((ctx)->fp))
-#define MONO_CONTEXT_GET_IP(ctx) ((gpointer)((ctx)->SC_EIP))
-#define MONO_CONTEXT_GET_BP(ctx) ((gpointer)((ctx)->SC_EBP))
+#define IS_ON_SIGALTSTACK(jit_tls) FALSE
-#ifdef MONO_USE_EXC_TABLES
+/*
+ * arch_get_restore_context:
+ *
+ * Returns a pointer to a method which restores a previously saved sigcontext.
+ */
+static gpointer
+arch_get_restore_context (void)
+{
+ static guint32 start [32];
+ static int inited = 0;
+ guint32 *code;
+
+ if (inited)
+ return start;
-/*************************************/
-/* STACK UNWINDING STUFF */
-/*************************************/
+ code = start;
-/* These definitions are from unwind-dw2.c in glibc 2.2.5 */
+ sparc_ld_imm (code, sparc_o0, G_STRUCT_OFFSET (MonoContext, ip), sparc_i7);
+ sparc_ld_imm (code, sparc_o0, G_STRUCT_OFFSET (MonoContext, sp), sparc_i6);
-/* For x86 */
-#define DWARF_FRAME_REGISTERS 17
+ sparc_jmpl_imm (code, sparc_i7, 0, sparc_g0);
+ /* FIXME: This does not return to the correct window */
+ sparc_restore_imm (code, sparc_g0, 0, sparc_g0);
+
+ g_assert ((code - start) < 32);
+
+ inited = 1;
+
+ return start;
+}
-typedef struct frame_state
+/*
+ * arch_get_call_filter:
+ *
+ * Returns a pointer to a method which calls an exception filter. We
+ * also use this function to call finally handlers (we pass NULL as
+ * @exc object in this case).
+ *
+ * call_filter (MonoContext *ctx, gpointer ip)
+ */
+static gpointer
+arch_get_call_filter (void)
{
- void *cfa;
- void *eh_ptr;
- long cfa_offset;
- long args_size;
- long reg_or_offset[DWARF_FRAME_REGISTERS+1];
- unsigned short cfa_reg;
- unsigned short retaddr_column;
- char saved[DWARF_FRAME_REGISTERS+1];
-} frame_state;
+ static guint32 start [64];
+ static int inited = 0;
+ guint32 *code;
+ int i;
+ if (inited)
+ return start;
-typedef struct frame_state * (*framesf) (void *, struct frame_state *);
+ code = start;
-static framesf frame_state_for = NULL;
+ /*
+ * There are two frames here:
+ * - the first frame is used by call_filter
+ * - the second frame is used to run the filter code
+ */
-static gboolean inited = FALSE;
+ /* Create first frame */
+ sparc_save_imm (code, sparc_sp, -160, sparc_sp);
-typedef char ** (*get_backtrace_symbols_type) (void *__const *__array, int __size);
+ sparc_mov_reg_reg (code, sparc_i1, sparc_o0);
+ sparc_ld_imm (code, sparc_i0, G_STRUCT_OFFSET (MonoContext, sp), sparc_o1);
-static get_backtrace_symbols_type get_backtrace_symbols = NULL;
+ /* Create second frame */
+ sparc_save_imm (code, sparc_sp, -160, sparc_sp);
-static void
-init_frame_state_for (void)
-{
- GModule *module;
+ sparc_mov_reg_reg (code, sparc_i0, sparc_o0);
+ sparc_mov_reg_reg (code, sparc_i1, sparc_o1);
/*
- * There are two versions of __frame_state_for: one in libgcc.a and the
- * other in glibc.so. We need the version from glibc.
- * For more info, see this:
- * http://gcc.gnu.org/ml/gcc/2002-08/msg00192.html
+ * We need to change %fp to point to the stack frame of the method
+ * containing the filter. But changing %fp also changes the %sp of
+ * the parent frame (the first frame), so if the OS saves the first frame,
+ * it saves it to the stack frame of the method, which is not good.
+ * So flush all register windows to memory before changing %fp.
*/
- if ((module = g_module_open ("libc.so.6", G_MODULE_BIND_LAZY))) {
-
- if (!g_module_symbol (module, "__frame_state_for", (gpointer*)&frame_state_for))
- frame_state_for = NULL;
+ sparc_flushw (code);
- if (!g_module_symbol (module, "backtrace_symbols", (gpointer*)&get_backtrace_symbols)) {
- get_backtrace_symbols = NULL;
- frame_state_for = NULL;
- }
+ sparc_mov_reg_reg (code, sparc_fp, sparc_o7);
- g_module_close (module);
- }
+ /*
+ * Modify the second frame so it is identical to the one used in the
+ * method containing the filter.
+ */
+ for (i = 0; i < 16; ++i)
+ sparc_ld_imm (code, sparc_o1, i * 4, sparc_l0 + i);
- inited = TRUE;
-}
+ /* Save %fp to a location reserved in mono_arch_allocate_vars */
+ sparc_st_imm (code, sparc_o7, sparc_fp, -4);
-/* mono_arch_has_unwind_info:
- *
- * Tests if a function has an DWARF exception table able to restore
- * all caller saved registers.
- */
-gboolean
-mono_arch_has_unwind_info (gconstpointer addr)
-{
- return FALSE;
+ /* Call the filter code, after this returns, %i0 will hold the result */
+ sparc_call_imm (code, sparc_o0, 0);
+ sparc_nop (code);
+
+ /* Restore original %fp */
+ sparc_ld_imm (code, sparc_fp, -4, sparc_fp);
+
+ /* Return to first frame */
+ sparc_restore (code, sparc_g0, sparc_g0, sparc_g0);
+
+ /* FIXME: Save locals to the stack */
+
+ /* Return to caller */
+ sparc_ret (code);
+ /* Return result in delay slot */
+ sparc_restore (code, sparc_o0, sparc_g0, sparc_o0);
+
+ g_assert ((code - start) < 64);
+
+ inited = 1;
+
+ return start;
}
-struct stack_frame
+static void
+throw_exception (MonoObject *ex, guint32 sp, guint32 ip)
{
- void *next;
- void *return_address;
-};
-#endif
+ MonoContext ctx;
+ static void (*restore_context) (MonoContext *);
+
+ if (!restore_context)
+ restore_context = arch_get_restore_context ();
+
+ ctx.sp = (guint32*)sp;
+ ctx.ip = ip;
+ ctx.fp = (guint32*)ctx.sp [sparc_i6 - 16];
+
+ mono_sparc_handle_exception (&ctx, ex, FALSE);
+ restore_context (&ctx);
+ g_assert_not_reached ();
+}
+
+/**
+ * arch_get_throw_exception_by_name:
+ *
+ * Returns a function pointer which can be used to raise exceptions.
+ * The returned function has the following
+ * signature: void (*func) (char *exc_name);
+ */
gpointer
mono_arch_get_throw_exception (void)
{
- return 0xdeadbeef;
+ static guint32 start [32];
+ static int inited = 0;
+ guint32 *code;
+
+ if (inited)
+ return start;
+
+ inited = 1;
+ code = start;
+
+ sparc_save_imm (code, sparc_sp, -160, sparc_sp);
+
+ sparc_flushw (code);
+ sparc_mov_reg_reg (code, sparc_i0, sparc_o0);
+ sparc_mov_reg_reg (code, sparc_fp, sparc_o1);
+ sparc_mov_reg_reg (code, sparc_i7, sparc_o2);
+ sparc_set (code, throw_exception, sparc_o7);
+ sparc_jmpl (code, sparc_o7, sparc_g0, sparc_callsite);
+ sparc_nop (code);
+
+ g_assert ((code - start) < 32);
+
+ return start;
}
/**
*
* Returns a function pointer which can be used to raise
* corlib exceptions. The returned function has the following
- * signature: void (*func) (char *exc_name);
- * For example to raise an arithmetic exception you can use:
- *
- * x86_push_imm (code, "ArithmeticException");
- * x86_call_code (code, arch_get_throw_exception_by_name ());
- *
+ * signature: void (*func) (char *exc_name, gpointer ip);
*/
gpointer
mono_arch_get_throw_exception_by_name (void)
{
- return 0xdecafbad;
+ static guint32 start [32];
+ static int inited = 0;
+ guint32 *code;
+
+ if (inited)
+ return start;
+
+ inited = 1;
+ code = start;
+
+ sparc_save_imm (code, sparc_sp, -160, sparc_sp);
+
+ sparc_mov_reg_reg (code, sparc_i0, sparc_o2);
+ sparc_set (code, mono_defaults.corlib, sparc_o0);
+ sparc_set (code, "System", sparc_o1);
+ sparc_set (code, mono_exception_from_name, sparc_o7);
+ sparc_jmpl (code, sparc_o7, sparc_g0, sparc_callsite);
+ sparc_nop (code);
+
+ /* Return to the caller, so exception handling does not see this frame */
+ sparc_restore (code, sparc_o0, sparc_g0, sparc_o0);
+
+ /* Put original return address into %o7 */
+ sparc_mov_reg_reg (code, sparc_o1, sparc_o7);
+ sparc_set (code, mono_arch_get_throw_exception (), sparc_g1);
+ /* Use a jmp instead of a call so o7 is preserved */
+ sparc_jmpl_imm (code, sparc_g1, 0, sparc_g0);
+ sparc_nop (code);
+
+ g_assert ((code - start) < 32);
+
+ return start;
}
+/* mono_arch_find_jit_info:
+ *
+ * This function is used to gather information from @ctx. It return the
+ * MonoJitInfo of the corresponding function, unwinds one stack frame and
+ * stores the resulting context into @new_ctx. It also stores a string
+ * describing the stack location into @trace (if not NULL), and modifies
+ * the @lmf if necessary. @native_offset return the IP offset from the
+ * start of the function or -1 if that info is not available.
+ */
+static MonoJitInfo *
+mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx,
+ MonoContext *new_ctx, char **trace, MonoLMF **lmf, int *native_offset,
+ gboolean *managed)
+{
+ MonoJitInfo *ji;
+ gpointer ip = MONO_CONTEXT_GET_IP (ctx);
+ guint32 *window;
+
+ /* Avoid costly table lookup during stack overflow */
+ if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size)))
+ ji = prev_ji;
+ else
+ ji = mono_jit_info_table_find (domain, ip);
+
+ if (trace)
+ *trace = NULL;
+
+ if (native_offset)
+ *native_offset = -1;
+
+ if (managed)
+ *managed = FALSE;
+
+ if (ji != NULL) {
+ char *source_location, *tmpaddr, *fname;
+ gint32 address, iloffset;
+
+ *new_ctx = *ctx;
+
+ address = (char *)ip - (char *)ji->code_start;
+
+ if (native_offset)
+ *native_offset = address;
+
+ if (managed)
+ if (!ji->method->wrapper_type)
+ *managed = TRUE;
+
+ if (trace) {
+ source_location = mono_debug_source_location_from_address (ji->method, address, NULL, domain);
+ iloffset = mono_debug_il_offset_from_address (ji->method, address, domain);
+
+ if (iloffset < 0)
+ tmpaddr = g_strdup_printf ("<0x%05x>", address);
+ else
+ tmpaddr = g_strdup_printf ("[0x%05x]", iloffset);
+
+ fname = mono_method_full_name (ji->method, TRUE);
+
+ if (source_location)
+ *trace = g_strdup_printf ("in %s (at %s) %s", tmpaddr, source_location, fname);
+ else
+ *trace = g_strdup_printf ("in %s %s", tmpaddr, fname);
+
+ g_free (fname);
+ g_free (source_location);
+ g_free (tmpaddr);
+ }
+
+ /* FIXME: lmf */
+
+ /* Restore ip and sp from the saved register window */
+ window = (guint32*)ctx->sp;
+ new_ctx->ip = window [sparc_i7 - 16];
+ new_ctx->sp = (guint32*)(window [sparc_i6 - 16]);
+ new_ctx->fp = (guint32*)(new_ctx->sp [sparc_i6 - 16]);
+
+ *res = *ji;
+ return res;
+ }
+ else {
+ if (!(*lmf))
+ return NULL;
+
+ *new_ctx = *ctx;
+
+ if (!(*lmf)->method)
+ return (gpointer)-1;
+
+ if (trace)
+ *trace = g_strdup_printf ("in (unmanaged) %s", mono_method_full_name ((*lmf)->method, TRUE));
+
+ if ((ji = mono_jit_info_table_find (domain, (gpointer)(*lmf)->ip))) {
+ *res = *ji;
+ } else {
+ memset (res, 0, sizeof (MonoJitInfo));
+ res->method = (*lmf)->method;
+ }
+
+ new_ctx->ip = (*lmf)->ip;
+ new_ctx->sp = (*lmf)->sp;
+ new_ctx->fp = (*lmf)->ebp;
+
+ *lmf = (*lmf)->previous_lmf;
+
+ return res;
+ }
+}
+
static MonoArray *
glist_to_array (GList *list)
{
}
/**
- * arch_handle_exception:
+ * mono_sparc_handle_exception:
* @ctx: saved processor state
* @obj: the exception object
* @test_only: only test if the exception is caught, but dont call handlers
*
*/
gboolean
-mono_arch_handle_exception (MonoContext *ctx, gpointer obj, gboolean test_only)
+mono_sparc_handle_exception (MonoContext *ctx, gpointer obj, gboolean test_only)
{
+ MonoDomain *domain = mono_domain_get ();
+ MonoJitInfo *ji, rji;
+ static int (*call_filter) (MonoContext *, gpointer) = NULL;
+ static void (*restore_context) (MonoContext *);
+ MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
+ MonoLMF *lmf = jit_tls->lmf;
+ GList *trace_ips = NULL;
+ MonoException *mono_ex;
+ gboolean stack_overflow = FALSE;
+ MonoContext initial_ctx;
+ int frame_count = 0;
+ gboolean gc_disabled = FALSE;
+
+ /*
+ * This function might execute on an alternate signal stack, and Boehm GC
+ * can't handle that.
+ * Also, since the altstack is small, stack space intensive operations like
+ * JIT compilation should be avoided.
+ */
+ if (IS_ON_SIGALTSTACK (jit_tls)) {
+ /*
+ * FIXME: disabling/enabling GC while already on a signal stack might
+ * not be safe either.
+ */
+ /* Have to reenable it later */
+ gc_disabled = TRUE;
+ mono_gc_disable ();
+ }
+
+ g_assert (ctx != NULL);
+ if (!obj) {
+ MonoException *ex = mono_get_exception_null_reference ();
+ ex->message = mono_string_new (domain, "Object reference not set to an instance of an object");
+ obj = (MonoObject *)ex;
+ }
+
+ if (mono_object_isinst (obj, mono_defaults.exception_class)) {
+ mono_ex = (MonoException*)obj;
+ mono_ex->stack_trace = NULL;
+ } else {
+ mono_ex = NULL;
+ }
+
+ printf ("HANDLING EXCEPTION: %s\n", ((MonoObject*)obj)->vtable->klass->name);
+
+ if (obj == domain->stack_overflow_ex)
+ stack_overflow = TRUE;
+
+ if (!call_filter)
+ call_filter = arch_get_call_filter ();
+
+ if (!restore_context)
+ restore_context = arch_get_restore_context ();
+
+ g_assert (jit_tls->end_of_stack);
+ g_assert (jit_tls->abort_func);
+
+ if (!test_only) {
+ MonoContext ctx_cp = *ctx;
+ if (mono_jit_trace_calls != NULL)
+ g_print ("EXCEPTION handling: %s\n", mono_object_class (obj)->name);
+ if (!mono_sparc_handle_exception (&ctx_cp, obj, TRUE)) {
+ if (mono_break_on_exc)
+ G_BREAKPOINT ();
+ mono_unhandled_exception (obj);
+ }
+ }
+
+ initial_ctx = *ctx;
+ memset (&rji, 0, sizeof (rji));
+
+ while (1) {
+ MonoContext new_ctx;
+ char *trace = NULL;
+ gboolean need_trace = FALSE;
+ guint32 free_stack;
+
+ if (test_only && (frame_count < 1000))
+ need_trace = TRUE;
+
+ ji = mono_arch_find_jit_info (domain, jit_tls, &rji, &rji, ctx, &new_ctx,
+ need_trace ? &trace : NULL, &lmf, NULL, NULL);
+ if (!ji) {
+ g_warning ("Exception inside function without unwind info");
+ g_assert_not_reached ();
+ }
+
+ //printf ("JI: %p IP: %p SP: %p.\n", ji, (gpointer)new_ctx.ip, new_ctx.sp);
+
+ if (ji != (gpointer)-1) {
+ frame_count ++;
+ //printf ("M: %s %p %p %d.\n", mono_method_full_name (ji->method, TRUE), jit_tls->end_of_stack, ctx->ebp, count);
+
+ if (test_only && ji->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE && mono_ex) {
+ char *tmp, *strace;
+
+ /* Avoid giant stack traces */
+ if (frame_count < 1000) {
+ trace_ips = g_list_append (trace_ips, MONO_CONTEXT_GET_IP (ctx));
+
+ if (!mono_ex->stack_trace)
+ strace = g_strdup ("");
+ else
+ strace = mono_string_to_utf8 (mono_ex->stack_trace);
+
+ tmp = g_strdup_printf ("%s%s\n", strace, trace);
+ g_free (strace);
+
+ mono_ex->stack_trace = mono_string_new (domain, tmp);
+
+ g_free (tmp);
+ }
+ }
+
+/*
+ if (stack_overflow)
+ free_stack = (guint8*)(MONO_CONTEXT_GET_BP (ctx)) - (guint8*)(MONO_CONTEXT_GET_BP (&initial_ctx));
+ else
+ free_stack = 0xffffff;
+*/
+ free_stack = 0xffffff;
+
+ /*
+ * During stack overflow, wait till the unwinding frees some stack
+ * space before running handlers/finalizers.
+ */
+ if ((free_stack > (64 * 1024)) && ji->num_clauses) {
+ int i;
+
+ g_assert (ji->clauses);
+
+ for (i = 0; i < ji->num_clauses; i++) {
+ MonoJitExceptionInfo *ei = &ji->clauses [i];
+
+ if (ei->try_start <= MONO_CONTEXT_GET_IP (ctx) &&
+ MONO_CONTEXT_GET_IP (ctx) <= ei->try_end) {
+ /* catch block */
+
+ if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE) || (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)) {
+ /* store the exception object int cfg->excvar */
+ g_assert (ji->exvar_offset);
+ *((gpointer *)((char *)MONO_CONTEXT_GET_BP (ctx) + ji->exvar_offset)) = obj;
+ }
+
+ if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE &&
+ mono_object_isinst (obj, mono_class_get (ji->method->klass->image, ei->data.token))) ||
+ ((ei->flags == MONO_EXCEPTION_CLAUSE_FILTER &&
+ call_filter (ctx, ei->data.filter)))) {
+ if (test_only) {
+ if (mono_ex)
+ mono_ex->trace_ips = glist_to_array (trace_ips);
+ g_list_free (trace_ips);
+ g_free (trace);
+
+ if (gc_disabled)
+ mono_gc_enable ();
+ return TRUE;
+ }
+ if (mono_jit_trace_calls != NULL && mono_trace_eval (ji->method))
+ g_print ("EXCEPTION: catch found at clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
+ MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
+ jit_tls->lmf = lmf;
+ g_free (trace);
+
+ if (gc_disabled)
+ mono_gc_enable ();
+ return 0;
+ }
+ if (!test_only && ei->try_start <= MONO_CONTEXT_GET_IP (ctx) &&
+ MONO_CONTEXT_GET_IP (ctx) < ei->try_end &&
+ (ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
+ if (mono_jit_trace_calls != NULL && mono_trace_eval (ji->method))
+ g_print ("EXCEPTION: finally clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
+ printf ("BEFORE FILTER.\n");
+ call_filter (ctx, ei->handler_start);
+ printf ("AFTER FILTER.\n");
+ }
+
+ }
+ }
+ }
+ }
+
+ g_free (trace);
+
+ *ctx = new_ctx;
+
+ if ((ji == (gpointer)-1) || MONO_CONTEXT_GET_BP (ctx) >= jit_tls->end_of_stack) {
+ if (gc_disabled)
+ mono_gc_enable ();
+
+ if (!test_only) {
+ jit_tls->lmf = lmf;
+
+ if (IS_ON_SIGALTSTACK (jit_tls)) {
+ /* Switch back to normal stack */
+ if (stack_overflow)
+ /* Free up some stack space */
+ initial_ctx.sp += (64 * 1024);
+ initial_ctx.ip = (unsigned int)jit_tls->abort_func;
+ restore_context (&initial_ctx);
+ }
+ else
+ jit_tls->abort_func (obj);
+ g_assert_not_reached ();
+ } else {
+ if (mono_ex)
+ mono_ex->trace_ips = glist_to_array (trace_ips);
+ g_list_free (trace_ips);
+ return FALSE;
+ }
+ }
+ }
+
g_assert_not_reached ();
}
+
+gboolean
+mono_arch_handle_exception (ucontext_t *ctx, gpointer obj, gboolean test_only)
+{
+ MonoContext mctx;
+
+ /*
+ * Access to the machine state using the ucontext_t parameter is somewhat
+ * under documented under solaris. The code below seems to work under
+ * Solaris 9.
+ */
+ g_assert (!ctx->uc_mcontext.gwins);
+
+ mctx.ip = ctx->uc_mcontext.gregs [REG_PC];
+ mctx.sp = ctx->uc_mcontext.gregs [REG_SP];
+ mctx.fp = mctx.sp [sparc_fp - 16];
+
+ mono_sparc_handle_exception (&mctx, obj, test_only);
+
+ /* We can't use restore_context to return from a signal handler */
+ ctx->uc_mcontext.gregs [REG_PC] = mctx.ip;
+ ctx->uc_mcontext.gregs [REG_nPC] = mctx.ip + 4;
+ ctx->uc_mcontext.gregs [REG_SP] = mctx.sp;
+ mctx.sp [sparc_fp - 16] = mctx.fp;
+
+ return TRUE;
+}
mono_bblock_add_inst (s->cbb, tree);
}
+freg: OP_LCONV_TO_R8 (lreg) {
+ /* Dummy rule */
+}
+
freg: OP_LCONV_TO_R4 (lreg) {
tree->sreg1 = state->left->reg1;
tree->dreg = state->reg1;
}
stmt: OP_SETRET (freg) {
- MONO_EMIT_UNALU (s, tree, OP_FMOVE, sparc_f0, state->left->reg1);
+ tree->opcode = OP_SETFRET;
+ tree->sreg1 = state->left->reg1;
+ tree->dreg = sparc_f0;
mono_bblock_add_inst (s->cbb, tree);
}
}
reg: CEE_LDIND_I1 (OP_REGVAR) {
- /* All regs are 32 bit */
- tree->opcode = OP_MOVE;
- tree->sreg1 = state->left->tree->dreg;
- tree->dreg = state->reg1;
- mono_bblock_add_inst (s->cbb, tree);
+ MONO_EMIT_UNALU (s, tree, CEE_CONV_I1, state->reg1, state->left->tree->dreg);
}
reg: CEE_LDIND_I2 (OP_REGVAR) {
- /* All regs are 32 bit */
- tree->opcode = OP_MOVE;
- tree->sreg1 = state->left->tree->dreg;
- tree->dreg = state->reg1;
- mono_bblock_add_inst (s->cbb, tree);
+ MONO_EMIT_UNALU (s, tree, CEE_CONV_I2, state->reg1, state->left->tree->dreg);
}
stmt: CEE_BNE_UN (fpcflags) {
/* nothing to do */
}
+stmt: OP_START_HANDLER {
+ mono_bblock_add_inst (s->cbb, tree);
+}
+
+stmt: CEE_ENDFINALLY {
+ //MonoInst *spvar = mono_find_spvar_for_region (s, s->cbb->region);
+ //MONO_EMIT_NEW_LOAD_MEMBASE (s, sparc_o7, spvar->inst_basereg, spvar->inst_offset);
+ mono_bblock_add_inst (s->cbb, tree);
+}
+
+stmt: OP_ENDFILTER (reg) {
+ //MonoInst *spvar = mono_find_spvar_for_region (s, s->cbb->region);
+ //MONO_EMIT_NEW_LOAD_MEMBASE (s, sparc_o7, spvar->inst_basereg, spvar->inst_offset);
+ tree->sreg1 = state->left->reg1;
+ mono_bblock_add_inst (s->cbb, tree);
+}
+
stmt: OP_START_HANDLER {
}
stmt: CEE_ENDFINALLY {
+ mono_bblock_add_inst (s->cbb, tree);
}
stmt: OP_ENDFILTER (reg) {
+ tree->sreg1 = state->left->reg1;
+ tree->dreg = state->reg1;
+ mono_bblock_add_inst (s->cbb, tree);
}
reg: OP_CEQ (OP_COMPARE (freg, freg)) {
m->frame_reg = sparc_fp;
offset = 0;
+ /*
+ * Reserve a stack slot for holding information used during exception
+ * handling.
+ */
+ if (header->num_clauses)
+ offset += 8;
+
+ if (m->method->save_lmf) {
+ offset += sizeof (MonoLMF);
+ m->arch.lmf_offset = offset;
+ }
+
curinst = m->locals_start;
for (i = curinst; i < m->num_varinfo; ++i) {
inst = m->varinfo [i];
MonoInst *inst;
gint align;
guint32 offset, pad;
- guint32 size = mono_type_stack_size (&in->klass->byval_arg, &align);
+ guint32 size;
+
+ if (sig->pinvoke)
+ size = mono_type_native_stack_size (&in->klass->byval_arg, &align);
+ else
+ size = mono_type_stack_size (&in->klass->byval_arg, &align);
/*
* We use OP_OUTARG_VT to copy the valuetype to a stack location, then
opcode_to_sparc_cond (int opcode)
{
switch (opcode) {
-
case OP_FBGE:
return sparc_fbge;
case OP_FBLE:
return sparc_fbg;
case CEE_BEQ:
case OP_CEQ:
+ case OP_COND_EXC_EQ:
return sparc_be;
case CEE_BNE_UN:
+ case OP_COND_EXC_NE_UN:
return sparc_bne;
case CEE_BLT:
case OP_CLT:
+ case OP_COND_EXC_LT:
return sparc_bl;
case CEE_BLT_UN:
case OP_CLT_UN:
+ case OP_COND_EXC_LT_UN:
return sparc_blu;
case CEE_BGT:
case OP_CGT:
+ case OP_COND_EXC_GT:
return sparc_bg;
case CEE_BGT_UN:
case OP_CGT_UN:
+ case OP_COND_EXC_GT_UN:
return sparc_bgu;
case CEE_BGE:
+ case OP_COND_EXC_GE:
return sparc_bge;
case CEE_BGE_UN:
+ case OP_COND_EXC_GE_UN:
return sparc_beu;
case CEE_BLE:
+ case OP_COND_EXC_LE:
return sparc_ble;
case CEE_BLE_UN:
+ case OP_COND_EXC_LE_UN:
return sparc_bleu;
+ case OP_COND_EXC_OV:
+ return sparc_bvs;
+ case OP_COND_EXC_C:
+ return sparc_bcs;
+
+ case OP_COND_EXC_NO:
+ case OP_COND_EXC_NC:
+ NOT_IMPLEMENTED;
default:
g_assert_not_reached ();
return sparc_be;
#define EMIT_FLOAT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_GENERAL((ins),fbranch,(cond))
+/* emit an exception if condition is fail */
+/*
+ * We put the exception throwing code out-of-line, at the end of the method
+ */
+#define EMIT_COND_SYSTEM_EXCEPTION(ins,cond,sexc_name) do { \
+ mono_add_patch_info (cfg, (guint8*)(code) - (cfg)->native_code, \
+ MONO_PATCH_INFO_EXC, sexc_name); \
+ sparc_branch (code, 1, cond, 0); \
+ sparc_nop (code); \
+ } while (0);
+
#define EMIT_ALU_IMM(ins,op,setcc) do { \
if (sparc_is_imm13 ((ins)->inst_imm)) \
sparc_ ## op ## _imm (code, (setcc), (ins)->sreg1, ins->inst_imm, (ins)->dreg); \
sparc_ ## op ## _imm (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset); \
} while (0);
-
-/* emit an exception if condition is fail */
-#define EMIT_COND_SYSTEM_EXCEPTION(cond,signed,exc_name) \
- do { \
- mono_add_patch_info (cfg, code - cfg->native_code, \
- MONO_PATCH_INFO_EXC, exc_name); \
- x86_branch32 (code, cond, 0, signed); \
- } while (0);
-
-#define EMIT_FPCOMPARE(code) do { \
- x86_fcompp (code); \
- x86_fnstsw (code); \
- x86_alu_reg_imm (code, X86_AND, X86_EAX, 0x4500); \
-} while (0);
-
static void
peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
{
}
static void
-sparc_patch (guint8 *code, guint8 *target)
+sparc_patch (guint8 *code, const guint8 *target)
{
guint32 ins = *(guint32*)code;
guint32 op = ins >> 30;
if (!sparc_is_imm22 (disp))
NOT_IMPLEMENTED;
/* Bicc */
- *(guint32*)code = ((ins >> 22) << 22) | disp;
+ *(guint32*)code = ((ins >> 22) << 22) | (disp & 0x3fffff);
}
else if ((op == 0) && (op2 == 6)) {
if (!sparc_is_imm22 (disp))
NOT_IMPLEMENTED;
/* FBicc */
- *(guint32*)code = ((ins >> 22) << 22) | disp;
+ *(guint32*)code = ((ins >> 22) << 22) | (disp & 0x3fffff);
}
else if ((op == 0) && (op2 == 4)) {
guint32 ins2 = *(guint32*)(code + 4);
/* sethi followed by or */
guint32 *p = (guint32*)code;
sparc_set (p, target, rd);
- while (p < (code + 4))
+ while (p <= (code + 4))
sparc_nop (p);
}
else if ((sparc_inst_op (ins2) == 3) && (sparc_inst_imm (ins2))) {
// g_print ("patched with 0x%08x\n", ins);
}
+static guint32*
+emit_vret_token (MonoInst *ins, guint32 *code)
+{
+ MonoCallInst *call = (MonoCallInst*)ins;
+ guint32 size;
+
+ /*
+ * The sparc ABI requires that calls to functions which return a structure
+ * contain an additional unimpl instruction which is checked by the callee.
+ */
+ if (call->signature->pinvoke && MONO_TYPE_ISSTRUCT(call->signature->ret)) {
+ size = mono_class_native_size (call->signature->ret->data.klass, NULL);
+ sparc_unimp (code, size & 0xfff);
+ }
+
+ return code;
+}
+
static guint32*
emit_move_return_value (MonoInst *ins, guint32 *code)
{
case OP_FCALL_REG:
case OP_FCALL_MEMBASE:
sparc_fmovs (code, sparc_f0, ins->dreg);
- sparc_fmovs (code, sparc_f1, ins->dreg + 1);
+ if (((MonoCallInst*)ins)->signature->ret->type == MONO_TYPE_R4)
+ sparc_fstod (code, ins->dreg, ins->dreg);
+ else
+ sparc_fmovs (code, sparc_f1, ins->dreg + 1);
break;
case OP_VCALL:
case OP_VCALL_REG:
guint last_offset = 0;
int max_len, cpos;
- GC_malloc (240);
-
if (cfg->opt & MONO_OPT_PEEPHOLE)
peephole_pass (cfg, bb);
case CEE_ADD:
sparc_add (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg);
break;
- case OP_ADC:
- sparc_addx (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg);
- break;
case OP_ADD_IMM:
EMIT_ALU_IMM (ins, add, FALSE);
break;
+ case OP_ADC:
+ /* according to inssel-long32.brg, this should set cc */
+ sparc_addx (code, TRUE, ins->sreg1, ins->sreg2, ins->dreg);
+ break;
case OP_ADC_IMM:
- EMIT_ALU_IMM (ins, addx, FALSE);
+ EMIT_ALU_IMM (ins, addx, TRUE);
break;
case OP_SUBCC:
sparc_sub (code, TRUE, ins->sreg1, ins->sreg2, ins->dreg);
case CEE_SUB:
sparc_sub (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg);
break;
- case OP_SBB:
- sparc_subx (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg);
- break;
case OP_SUB_IMM:
// we add the negated value
if (sparc_is_imm13 (- ins->inst_imm))
sparc_add (code, FALSE, ins->sreg1, sparc_o7, ins->dreg);
}
break;
+ case OP_SBB:
+ /* according to inssel-long32.brg, this should set cc */
+ sparc_subx (code, TRUE, ins->sreg1, ins->sreg2, ins->dreg);
+ break;
case OP_SBB_IMM:
- EMIT_ALU_IMM (ins, subx, FALSE);
+ EMIT_ALU_IMM (ins, subx, TRUE);
break;
case CEE_AND:
sparc_and (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg);
EMIT_ALU_IMM (ins, smul, FALSE);
break;
case CEE_MUL_OVF:
- /* FIXME: */
- sparc_smul (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg);
+ sparc_smul (code, TRUE, ins->sreg1, ins->sreg2, ins->dreg);
+ sparc_rdy (code, sparc_g1);
+ sparc_sra_imm (code, ins->dreg, 31, sparc_o7);
+ sparc_cmp (code, sparc_g1, sparc_o7);
+ EMIT_COND_SYSTEM_EXCEPTION (ins, sparc_bne, "OverflowException");
break;
case CEE_MUL_OVF_UN:
- /* FIXME: */
- sparc_umul (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg);
+ sparc_umul (code, TRUE, ins->sreg1, ins->sreg2, ins->dreg);
+ sparc_rdy (code, sparc_o7);
+ sparc_cmp (code, sparc_o7, sparc_g0);
+ EMIT_COND_SYSTEM_EXCEPTION (ins, sparc_bne, "OverflowException");
break;
case OP_ICONST:
case OP_SETREGIMM:
sparc_call_simple (code, 0);
sparc_nop (code);
+ code = emit_vret_token (ins, code);
code = emit_move_return_value (ins, code);
break;
case OP_FCALL_REG:
else
sparc_nop (code);
+ code = emit_vret_token (ins, code);
code = emit_move_return_value (ins, code);
break;
case OP_FCALL_MEMBASE:
else
sparc_nop (code);
+ code = emit_vret_token (ins, code);
code = emit_move_return_value (ins, code);
break;
+ case OP_SETFRET:
+ if (cfg->method->signature->ret->type == MONO_TYPE_R4)
+ sparc_fdtos (code, ins->sreg1, sparc_f0);
+ else {
+ sparc_fmovs (code, ins->sreg1, ins->dreg);
+ sparc_fmovs (code, ins->sreg1 + 1, ins->dreg + 1);
+ }
+ break;
case OP_OUTARG:
g_assert_not_reached ();
break;
/* Keep alignment */
sparc_add_imm (code, FALSE, ins->sreg1, MONO_ARCH_FRAME_ALIGNMENT - 1, ins->dreg);
sparc_set (code, ~(MONO_ARCH_FRAME_ALIGNMENT - 1), sparc_o7);
- sparc_or (code, FALSE, ins->dreg, sparc_o7, ins->dreg);
+ sparc_and (code, FALSE, ins->dreg, sparc_o7, ins->dreg);
sparc_sub (code, FALSE, sparc_sp, ins->dreg, ins->dreg);
/* Keep %sp valid at all times */
sparc_mov_reg_reg (code, ins->dreg, sparc_sp);
+ g_assert (sparc_is_imm13 (cfg->arch.localloc_offset));
+ sparc_add_imm (code, FALSE, ins->dreg, cfg->arch.localloc_offset, ins->dreg);
break;
case OP_SPARC_LOCALLOC_IMM: {
guint32 offset = ins->inst_c0;
sparc_sub (code, FALSE, sparc_sp, sparc_o7, sparc_sp);
}
sparc_mov_reg_reg (code, sparc_sp, ins->dreg);
+ g_assert (sparc_is_imm13 (cfg->arch.localloc_offset));
+ sparc_add_imm (code, FALSE, ins->dreg, cfg->arch.localloc_offset, ins->dreg);
break;
}
case CEE_RET:
/* The return is done in the epilog */
g_assert_not_reached ();
break;
- case CEE_THROW: {
- sparc_unimp (code, 0);
- /* FIXME: */
+ case CEE_THROW:
+ mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_INTERNAL_METHOD,
+ (gpointer)"mono_arch_throw_exception");
+ sparc_call_simple (code, 0);
+ /* Delay slot */
+ sparc_mov_reg_reg (code, ins->sreg1, sparc_o0);
+ break;
+ case OP_START_HANDLER: {
+ /*
+ * The START_HANDLER instruction marks the beginning of a handler
+ * block. It is called using a call instruction, so %o7 contains
+ * the return address. Since the handler executes in the same stack
+ * frame as the method itself, we can't use save/restore to save
+ * the return address. Instead, we save it into a dedicated
+ * variable.
+ */
+ MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
+ if (!sparc_is_imm13 (spvar->inst_offset)) {
+ sparc_set (code, spvar->inst_offset, sparc_g0);
+ sparc_st (code, sparc_o7, spvar->inst_basereg, sparc_g0);
+ }
+ else
+ sparc_st_imm (code, sparc_o7, spvar->inst_basereg, spvar->inst_offset);
break;
}
- case OP_ENDFILTER:
- /* FIXME: */
+ case OP_ENDFILTER: {
+ MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
+ if (!sparc_is_imm13 (spvar->inst_offset)) {
+ sparc_set (code, spvar->inst_offset, sparc_g0);
+ sparc_ld (code, spvar->inst_basereg, sparc_g0, sparc_o7);
+ }
+ else
+ sparc_ld_imm (code, spvar->inst_basereg, spvar->inst_offset, sparc_o7);
+ sparc_jmpl_imm (code, sparc_o7, 8, sparc_g0);
+ /* Delay slot */
+ sparc_mov_reg_reg (code, ins->sreg1, sparc_o0);
break;
- case CEE_ENDFINALLY:
- /* FIXME: */
+ }
+ case CEE_ENDFINALLY: {
+ MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
+ if (!sparc_is_imm13 (spvar->inst_offset)) {
+ sparc_set (code, spvar->inst_offset, sparc_g0);
+ sparc_ld (code, spvar->inst_basereg, sparc_g0, sparc_o7);
+ }
+ else
+ sparc_ld_imm (code, spvar->inst_basereg, spvar->inst_offset, sparc_o7);
+ sparc_jmpl_imm (code, sparc_o7, 8, sparc_g0);
+ sparc_nop (code);
break;
+ }
case OP_CALL_HANDLER:
- /* FIXME: */
+ mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
+ sparc_call_simple (code, 0);
+ sparc_nop (code);
break;
case OP_LABEL:
ins->inst_c0 = (guint8*)code - cfg->native_code;
case OP_COND_EXC_NO:
case OP_COND_EXC_C:
case OP_COND_EXC_NC:
- /* FIXME: */
- //EMIT_COND_SYSTEM_EXCEPTION (branch_cc_table [ins->opcode - OP_COND_EXC_EQ],
- // (ins->opcode < OP_COND_EXC_NE_UN), ins->inst_p1);
+ EMIT_COND_SYSTEM_EXCEPTION (ins, opcode_to_sparc_cond (ins->opcode), ins->inst_p1);
break;
case CEE_BEQ:
case CEE_BNE_UN:
break;
/* floating point opcodes */
- case OP_R8CONST: {
- double d = *(double*)ins->inst_p0;
-
+ case OP_R8CONST:
mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_R8, ins->inst_p0);
sparc_sethi (code, 0, sparc_o7);
sparc_lddf_imm (code, sparc_o7, 0, ins->dreg);
break;
- }
- case OP_R4CONST: {
- float f = *(float*)ins->inst_p0;
-
+ case OP_R4CONST:
mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_R4, ins->inst_p0);
sparc_sethi (code, 0, sparc_o7);
sparc_ldf_imm (code, sparc_o7, 0, ins->dreg);
/* Extend to double */
sparc_fstod (code, ins->dreg, ins->dreg);
break;
- }
case OP_STORER8_MEMBASE_REG:
if (!sparc_is_imm13 (ins->inst_offset + 4)) {
sparc_set (code, ins->inst_offset, sparc_o7);
case OP_FCONV_TO_U8:
NOT_IMPLEMENTED;
break;
+ case CEE_CONV_R_UN:
+ NOT_IMPLEMENTED;
+ break;
case OP_LCONV_TO_R_UN: {
NOT_IMPLEMENTED;
break;
sparc_nop (code);
label [0] = code;
- /* FIXME: throw exception */
+
+ EMIT_COND_SYSTEM_EXCEPTION (ins, sparc_ba, "OverflowException");
/* negative */
sparc_patch (br [0], code);
/* ms word must 0xfffffff */
sparc_cmp_imm (code, ins->sreg2, -1);
- sparc_branch (code, 1, sparc_bne, label [0]);
+ br [2] = code;
+ sparc_branch (code, 1, sparc_bne, 0);
+ sparc_patch (br [2], label [0]);
/* Ok */
sparc_patch (br [1], code);
target = patch_info->data.inst->inst_c0 + code;
break;
case MONO_PATCH_INFO_IP:
- *((gpointer *)(ip)) = ip;
- continue;
+ target = ip;
+ break;
case MONO_PATCH_INFO_METHOD_REL:
- NOT_IMPLEMENTED;
- *((gpointer *)(ip)) = code + patch_info->data.offset;
- continue;
+ target = code + patch_info->data.offset;
+ if (ip == 0xfdec419c)
+ printf ("X: %p %p.\n", ip, target);
+ break;
case MONO_PATCH_INFO_INTERNAL_METHOD: {
MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
if (!mi) {
break;
}
case MONO_PATCH_INFO_EXC_NAME:
- NOT_IMPLEMENTED;
- *((gconstpointer *)(ip + 1)) = patch_info->data.name;
- continue;
+ target = patch_info->data.name;
+ break;
case MONO_PATCH_INFO_LDSTR:
NOT_IMPLEMENTED;
*((gconstpointer *)(ip + 1)) =
/*
* make sure we have enough space for exceptions
- * 16 is the size of two push_imm instructions and a call
*/
- max_epilog_size += exc_count*16;
+ max_epilog_size += exc_count * 24;
return max_epilog_size;
}
offset += cfg->param_area;
/* align the stack size to 8 bytes */
- cfg->stack_offset = ALIGN_TO (offset, MONO_ARCH_FRAME_ALIGNMENT);
+ offset = ALIGN_TO (offset, MONO_ARCH_FRAME_ALIGNMENT);
+
+ /*
+ * localloc'd memory is stored between the local variables (whose
+ * size is given by cfg->stack_offset), and between the space reserved
+ * by the ABI.
+ */
+ cfg->arch.localloc_offset = offset - cfg->stack_offset;
+
+ cfg->stack_offset = offset;
if (!sparc_is_imm13 (- cfg->stack_offset)) {
/* Can't use sparc_o7 here, since we're still in the caller's frame */
else
sparc_save_imm (code, sparc_sp, - cfg->stack_offset, sparc_sp);
+ if (strstr (cfg->method->name, "test_marshal_struct")) {
+ mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_ABS, mono_sparc_break);
+ sparc_call_simple (code, 0);
+ sparc_nop (code);
+ }
+
sig = method->signature;
cinfo = get_call_info (sig, FALSE);
g_free (cinfo);
+ if (cfg->method->save_lmf) {
+ gint32 lmf_offset = - cfg->arch.lmf_offset;
+
+ /* Save ip */
+ mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
+ sparc_set (code, 0xfffffff, sparc_o7);
+ sparc_st_imm (code, sparc_o7, sparc_fp, lmf_offset + G_STRUCT_OFFSET (MonoLMF, ip));
+ /* Save sp */
+ sparc_st_imm (code, sparc_sp, sparc_fp, lmf_offset + G_STRUCT_OFFSET (MonoLMF, sp));
+ /* Save fp */
+ sparc_st_imm (code, sparc_fp, sparc_fp, lmf_offset + G_STRUCT_OFFSET (MonoLMF, ebp));
+ /* Save method */
+ /* FIXME: add a relocation for this */
+ sparc_set (code, cfg->method, sparc_o7);
+ sparc_st_imm (code, sparc_o7, sparc_fp, lmf_offset + G_STRUCT_OFFSET (MonoLMF, method));
+ /* Get the address of lmf for the current thread */
+ mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
+ (gpointer)"mono_get_lmf_addr");
+ sparc_call_simple (code, 0);
+ sparc_nop (code);
+
+ /* Save lmf_addr */
+ sparc_st_imm (code, sparc_o0, sparc_fp, lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr));
+ /* Save previous_lmf */
+ sparc_ld (code, sparc_o0, sparc_g0, sparc_o7);
+ sparc_st_imm (code, sparc_o7, sparc_fp, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf));
+ /* Set new lmf */
+ sparc_add_imm (code, FALSE, sparc_fp, lmf_offset, sparc_o7);
+ sparc_st (code, sparc_o7, sparc_o0, sparc_g0);
+ }
+
if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
- sparc_ret (code);
- sparc_restore_imm (code, sparc_g0, 0, sparc_g0);
-
-#if 0
-
-
- pos = 0;
-
- if (method->save_lmf) {
- pos = -sizeof (MonoLMF);
- }
+ if (cfg->method->save_lmf) {
+ gint32 lmf_offset = - cfg->arch.lmf_offset;
- if (method->save_lmf) {
-#if 0
- /* ebx = previous_lmf */
- x86_pop_reg (code, X86_EBX);
- /* edi = lmf */
- x86_pop_reg (code, X86_EDI);
+ /* Load previous_lmf */
+ sparc_ld_imm (code, sparc_fp, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), sparc_l0);
+ /* Load lmf_addr */
+ sparc_ld_imm (code, sparc_fp, lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr), sparc_l1);
/* *(lmf) = previous_lmf */
- x86_mov_membase_reg (code, X86_EDI, 0, X86_EBX, 4);
-
- /* discard method info */
- x86_pop_reg (code, X86_ESI);
-
- /* restore caller saved regs */
- x86_pop_reg (code, X86_EBP);
- x86_pop_reg (code, X86_ESI);
- x86_pop_reg (code, X86_EDI);
- x86_pop_reg (code, X86_EBX);
-#endif
+ sparc_st (code, sparc_l0, sparc_l1, sparc_g0);
}
- if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
- //ppc_lwz (code, sparc_l0, cfg->stack_usage + 8, cfg->frame_reg);
- //ppc_mtlr (code, sparc_l0);
- }
- //ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
- for (i = 13; i < 32; ++i) {
- if (cfg->used_int_regs & (1 << i)) {
- pos += 4;
- //ppc_lwz (code, i, -pos, cfg->frame_reg);
- }
- }
- //ppc_blr (code);
+ sparc_ret (code);
+ sparc_restore_imm (code, sparc_g0, 0, sparc_g0);
/* add code to raise exceptions */
for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
switch (patch_info->type) {
case MONO_PATCH_INFO_EXC:
- /*x86_patch (patch_info->ip.i + cfg->native_code, code);
- x86_push_imm (code, patch_info->data.target);
- x86_push_imm (code, patch_info->ip.i + cfg->native_code);
+ sparc_patch (cfg->native_code + patch_info->ip.i, code);
+ mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);
+ sparc_set (code, 0xffffff, sparc_o0);
+ mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_METHOD_REL, (gpointer)patch_info->ip.i);
+ sparc_set (code, 0xffffff, sparc_o1);
patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
- patch_info->data.name = "throw_exception_by_name";
+ patch_info->data.name = "mono_arch_throw_exception_by_name";
patch_info->ip.i = code - cfg->native_code;
- x86_jump_code (code, 0);*/
+ sparc_call_simple (code, 0);
+ sparc_nop (code);
break;
default:
/* do nothing */
break;
}
}
-#endif
cfg->code_len = code - cfg->native_code;
#define MONO_ARCH_FRAME_ALIGNMENT 8
-/* Also check this. */
#define MONO_ARCH_CODE_ALIGNMENT 32
-/* BASEREG = Frame pointer
- * RETREG? = Return register (but is it for caller or callee?)
- */
#define MONO_ARCH_BASEREG sparc_fp
#define MONO_ARCH_RETREG1 sparc_i0
gpointer previous_lmf;
gpointer lmf_addr;
MonoMethod *method;
+ guint32 ip;
+ guint32 sp;
guint32 ebp;
- guint32 eip;
};
-#define MONO_ARCH_EMULATE_FCONV_TO_I8 1
-#define MONO_ARCH_EMULATE_LCONV_TO_R8 1
-#define MONO_ARCH_EMULATE_LCONV_TO_R4 1
+typedef struct MonoCompileArch {
+ guint32 lmf_offset;
+ guint32 localloc_offset;
+} MonoCompileArch;
+
+#define MONO_ARCH_USE_SIGACTION 1
+
+#define MONO_ARCH_EMULATE_FCONV_TO_I8 1
+#define MONO_ARCH_EMULATE_LCONV_TO_R8 1
+#define MONO_ARCH_EMULATE_LCONV_TO_R4 1
+#define MONO_ARCH_EMULATE_CONV_R8_UN 1
#define MONO_ARCH_EMULATE_LCONV_TO_R8_UN 1
#define MONO_ARCH_EMULATE_FREM 1