2004-03-08 Zoltan Varga <vargaz@freemail.hu>
authorZoltan Varga <vargaz@gmail.com>
Mon, 8 Mar 2004 17:19:52 +0000 (17:19 -0000)
committerZoltan Varga <vargaz@gmail.com>
Mon, 8 Mar 2004 17:19:52 +0000 (17:19 -0000)
* mini-sparc.h mini-sparc.c inssel-sparc.brg exceptions-sparc.c
cpu-sparc.md: Add exception handling support + other fixes.

svn path=/trunk/mono/; revision=23808

mono/mini/ChangeLog
mono/mini/cpu-sparc.md
mono/mini/exceptions-sparc.c
mono/mini/inssel-sparc.brg
mono/mini/mini-sparc.c
mono/mini/mini-sparc.h

index 9e57830759404b082778704d44e76f9a2aa67814..2bd0b81b97ae51a274efbeec7f065b6777920964 100644 (file)
@@ -1,5 +1,8 @@
 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.
 
index 67f0d9ace1174e746c2978308c069b692a98ff5a..e848d78aec735b3ab39c444bf475dad22e4d5521 100644 (file)
@@ -224,12 +224,13 @@ conv.ovf.i:
 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:
@@ -258,7 +259,6 @@ ldloca:
 stloc:
 localloc: dest:i src1:i len:24
 sparc_localloc_imm: dest:i len:16
-endfilter:
 unaligned.:
 volatile.:
 tail.:
@@ -290,6 +290,7 @@ fcompare: src1:f src2:f len:12
 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
@@ -309,9 +310,9 @@ fcall_membase: dest:f src1:b len:20 clob:c
 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:
@@ -360,20 +361,20 @@ xor_imm: dest:i src1:i len:12
 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:
@@ -400,7 +401,7 @@ long_conv_to_u8:
 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:
index e57994493630ab3eb345faedaa7bcba0ecd5a988..b096fbedfe6ffb50895b18837fd697dabbbb3b3f 100644 (file)
@@ -12,6 +12,7 @@
 #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;
 }
 
 /**
@@ -126,19 +217,154 @@ mono_arch_get_throw_exception (void)
  *
  * 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) 
 {
@@ -178,7 +404,7 @@ ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
 }
 
 /**
- * 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
@@ -186,7 +412,248 @@ ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
  *
  */
 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;
+}
index d9ee752769357d391eba4cb1a91e1ef6eb6be039..8a3f4b2e7bbd3d5fd88a3727decfe735c2546170 100644 (file)
@@ -31,6 +31,10 @@ freg: OP_LCONV_TO_R8 (lreg) {
        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;
@@ -98,7 +102,9 @@ stmt: OP_SETRET (lreg) {
 }
 
 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);
 }
 
@@ -249,19 +255,11 @@ stmt: CEE_STIND_R8 (OP_REGVAR, freg) {
 }
 
 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) {
@@ -318,13 +316,34 @@ stmt: CEE_POP (freg) "0" {
        /* 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)) {        
index afb8edbcf4779cc10fc72a607df1664d5d074758..7d20acfb144a402342b4baccd55f05e824899a21 100644 (file)
@@ -479,6 +479,18 @@ mono_arch_allocate_vars (MonoCompile *m)
        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];
@@ -653,7 +665,12 @@ mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call,
                                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
@@ -747,7 +764,6 @@ static inline SparcCond
 opcode_to_sparc_cond (int opcode)
 {
        switch (opcode) {
-
        case OP_FBGE:
                return sparc_fbge;
        case OP_FBLE:
@@ -765,29 +781,47 @@ opcode_to_sparc_cond (int opcode)
                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;
@@ -821,6 +855,17 @@ if (ins->flags & MONO_INST_BRLABEL) { \
 
 #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); \
@@ -865,21 +910,6 @@ if (ins->flags & MONO_INST_BRLABEL) { \
                                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)
 {
@@ -1835,7 +1865,7 @@ mono_emit_stack_alloc (guchar *code, MonoInst* tree)
 }
 
 static void
-sparc_patch (guint8 *code, guint8 *target)
+sparc_patch (guint8 *code, const guint8 *target)
 {
        guint32 ins = *(guint32*)code;
        guint32 op = ins >> 30;
@@ -1849,13 +1879,13 @@ sparc_patch (guint8 *code, guint8 *target)
                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);
@@ -1864,7 +1894,7 @@ sparc_patch (guint8 *code, guint8 *target)
                        /* 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))) {
@@ -1892,6 +1922,24 @@ sparc_patch (guint8 *code, guint8 *target)
 //     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)
 {
@@ -1921,7 +1969,10 @@ 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:
@@ -1981,8 +2032,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
        guint last_offset = 0;
        int max_len, cpos;
 
-       GC_malloc (240);
-
        if (cfg->opt & MONO_OPT_PEEPHOLE)
                peephole_pass (cfg, bb);
 
@@ -2107,14 +2156,15 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *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);
@@ -2122,9 +2172,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                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))
@@ -2134,8 +2181,12 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                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);
@@ -2248,12 +2299,17 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        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:
@@ -2287,6 +2343,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        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:
@@ -2306,6 +2363,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        else
                                sparc_nop (code);
 
+                       code = emit_vret_token (ins, code);
                        code = emit_move_return_value (ins, code);
                        break;
                case OP_FCALL_MEMBASE:
@@ -2323,8 +2381,17 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        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;
@@ -2332,10 +2399,12 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        /* 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;
@@ -2347,25 +2416,68 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                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;
@@ -2423,9 +2535,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                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:
@@ -2441,17 +2551,12 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        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);
@@ -2459,7 +2564,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        /* 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);
@@ -2543,6 +2647,9 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                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;
@@ -2566,14 +2673,17 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        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);
@@ -2729,12 +2839,13 @@ mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, Mono
                        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) {
@@ -2823,9 +2934,8 @@ mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, Mono
                        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)) = 
@@ -3032,9 +3142,8 @@ mono_arch_max_epilog_size (MonoCompile *cfg)
 
        /* 
         * 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;
 }
@@ -3068,7 +3177,16 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                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 */
@@ -3078,6 +3196,12 @@ mono_arch_emit_prolog (MonoCompile *cfg)
        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);
@@ -3170,6 +3294,37 @@ mono_arch_emit_prolog (MonoCompile *cfg)
 
        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);
 
@@ -3193,69 +3348,40 @@ mono_arch_emit_epilog (MonoCompile *cfg)
        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;
 
index 8d9265db5c52c54da96b135bf77a8dd0fb3ddf84..3c24678580325171c1fbd0801d2162c54db73382 100644 (file)
@@ -8,12 +8,8 @@
 
 #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
 
@@ -21,13 +17,22 @@ struct MonoLMF {
        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