/** * mono_arch_get_throw_corlib_exception: * * Returns a function pointer which can be used to raise * corlib exceptions. The returned function has the following * signature: void (*func) (guint32 ex_token, guint32 offset); * Here, offset is the offset which needs to be substracted from the caller IP * to get the IP of the throw. Passing the offset has the advantage that it * needs no relocations in the caller. */ gpointer mono_arch_get_throw_corlib_exception (MonoTrampInfo **info, gboolean aot) { static guint32 *start; static int inited = 0; guint32 *code; int reg; g_assert (!aot); if (info) *info = NULL; if (inited) return start; inited = 1; code = start = mono_global_codeman_reserve (64 * sizeof (guint32)); #ifdef SPARCV9 reg = sparc_g4; #else reg = sparc_g1; #endif sparc_mov_reg_reg (code, sparc_o7, sparc_o2); sparc_save_imm (code, sparc_sp, -160, sparc_sp); sparc_set (code, MONO_TOKEN_TYPE_DEF, sparc_o7); sparc_add (code, FALSE, sparc_i0, sparc_o7, sparc_o1); sparc_set (code, mono_defaults.exception_class->image, sparc_o0); sparc_set (code, mono_exception_from_token, 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); /* Compute throw ip */ sparc_sll_imm (code, sparc_o1, 2, sparc_o1); sparc_sub (code, 0, sparc_o2, sparc_o1, sparc_o7); sparc_set (code, mono_arch_get_throw_exception (NULL, FALSE), reg); /* Use a jmp instead of a call so o7 is preserved */ sparc_jmpl_imm (code, reg, 0, sparc_g0); sparc_nop (code); g_assert ((code - start) < 32); mono_arch_flush_icache ((guint8*)start, (guint8*)code - (guint8*)start); return start; }
/** * mono_arch_get_throw_exception_by_name: * * Returns a function pointer which can be used to raise * corlib exceptions. The returned function has the following * signature: void (*func) (char *exc_name, gpointer ip); */ gpointer mono_arch_get_throw_exception_by_name (void) { static guint32 *start; static int inited = 0; guint32 *code; int reg; if (inited) return start; inited = 1; code = start = mono_global_codeman_reserve (64 * sizeof (guint32)); #ifdef SPARCV9 reg = sparc_g4; #else reg = sparc_g1; #endif 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 (), reg); /* Use a jmp instead of a call so o7 is preserved */ sparc_jmpl_imm (code, reg, 0, sparc_g0); sparc_nop (code); g_assert ((code - start) < 32); mono_arch_flush_icache ((guint8*)start, (guint8*)code - (guint8*)start); return start; }
static void calculate_sizes (MonoMethodSignature *sig, guint *stack_size, guint *code_size, gboolean string_ctor, gboolean *use_memcpy) { guint i, fr, gr; guint32 simpletype; fr = gr = 0; *stack_size = MINIMAL_STACK_SIZE * SLOT_SIZE; *code_size = (PROLOG_INS + CALL_INS + EPILOG_INS) * 4; /* function arguments */ if (sig->hasthis) add_general (&gr, stack_size, code_size, TRUE); for (i = 0; i < sig->param_count; i++) { if (sig->params[i]->byref) { add_general (&gr, stack_size, code_size, TRUE); continue; } simpletype = sig->params[i]->type; enum_calc_size: switch (simpletype) { case MONO_TYPE_R4: #if SPARCV9 (*code_size) += 4; /* for the fdtos */ #else (*code_size) += 12; (*stack_size) += 4; #endif case MONO_TYPE_BOOLEAN: case MONO_TYPE_CHAR: case MONO_TYPE_I1: case MONO_TYPE_U1: case MONO_TYPE_I2: case MONO_TYPE_U2: case MONO_TYPE_I4: case MONO_TYPE_U4: case MONO_TYPE_I: case MONO_TYPE_U: case MONO_TYPE_PTR: case MONO_TYPE_CLASS: case MONO_TYPE_OBJECT: case MONO_TYPE_STRING: case MONO_TYPE_SZARRAY: add_general (&gr, stack_size, code_size, TRUE); break; case MONO_TYPE_VALUETYPE: { gint size; guint32 align; if (sig->params[i]->data.klass->enumtype) { simpletype = sig->params[i]->data.klass->enum_basetype->type; goto enum_calc_size; } size = mono_class_native_size (sig->params[i]->data.klass, &align); #if SPARCV9 if (size != 4) { #else if (1) { #endif DEBUG(fprintf(stderr, "copy %d byte struct on stack\n", size)); *use_memcpy = TRUE; *code_size += 8*4; *stack_size = (*stack_size + (align - 1)) & (~(align -1)); *stack_size += (size + 3) & (~3); if (gr > OUT_REGS) { *code_size += 4; *stack_size += 4; } } else { add_general (&gr, stack_size, code_size, TRUE); #if SPARCV9 *code_size += 8; #else *code_size += 4; #endif } break; } case MONO_TYPE_I8: case MONO_TYPE_R8: add_general (&gr, stack_size, code_size, FALSE); break; default: g_error ("Can't trampoline 0x%x", sig->params[i]->type); } } /* function return value */ if (sig->ret->byref || string_ctor) { *code_size += 8; } else { simpletype = sig->ret->type; enum_retvalue: switch (simpletype) { case MONO_TYPE_BOOLEAN: case MONO_TYPE_I1: case MONO_TYPE_U1: case MONO_TYPE_I2: case MONO_TYPE_U2: case MONO_TYPE_CHAR: case MONO_TYPE_I4: case MONO_TYPE_U4: case MONO_TYPE_I: case MONO_TYPE_U: case MONO_TYPE_CLASS: case MONO_TYPE_OBJECT: case MONO_TYPE_PTR: case MONO_TYPE_STRING: case MONO_TYPE_R4: case MONO_TYPE_R8: case MONO_TYPE_SZARRAY: case MONO_TYPE_ARRAY: *code_size += 8; break; case MONO_TYPE_I8: *code_size += 12; break; case MONO_TYPE_VALUETYPE: { gint size; if (sig->ret->data.klass->enumtype) { simpletype = sig->ret->data.klass->enum_basetype->type; goto enum_retvalue; } size = mono_class_native_size (sig->ret->data.klass, NULL); #if SPARCV9 if (size <= 32) *code_size += 8 + (size + 7) / 2; else *code_size += 8; #else *code_size += 8; #endif break; } case MONO_TYPE_VOID: break; default: g_error ("Can't handle as return value 0x%x", sig->ret->type); } } if (*use_memcpy) { *stack_size += 8; *code_size += 24; if (sig->hasthis) { *stack_size += SLOT_SIZE; *code_size += 4; } } *stack_size = (*stack_size + (FRAME_ALIGN - 1)) & (~(FRAME_ALIGN -1)); } static inline guint32 * emit_epilog (guint32 *p, MonoMethodSignature *sig, guint stack_size) { int ret_offset = 8; /* * Standard epilog. * 8 may be 12 when returning structures (to skip unimp opcode). */ #if !SPARCV9 if (sig != NULL && !sig->ret->byref && sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->data.klass->enumtype) ret_offset = 12; #endif sparc_jmpl_imm (p, sparc_i7, ret_offset, sparc_zero); sparc_restore (p, sparc_zero, sparc_zero, sparc_zero); return p; }
/* * mono_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) */ gpointer mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot) { static guint32 *start; static int inited = 0; guint32 *code; int i; g_assert (!aot); if (info) *info = NULL; if (inited) return start; code = start = mono_global_codeman_reserve (64 * sizeof (guint32)); /* * There are two frames here: * - the first frame is used by call_filter * - the second frame is used to run the filter code */ /* Create first frame */ sparc_save_imm (code, sparc_sp, -256, sparc_sp); sparc_mov_reg_reg (code, sparc_i1, sparc_o0); sparc_ldi_imm (code, sparc_i0, G_STRUCT_OFFSET (MonoContext, sp), sparc_o1); /* Create second frame */ sparc_save_imm (code, sparc_sp, -256, sparc_sp); sparc_mov_reg_reg (code, sparc_i0, sparc_o0); sparc_mov_reg_reg (code, sparc_i1, sparc_o1); /* * 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. */ sparc_flushw (code); sparc_mov_reg_reg (code, sparc_fp, sparc_o7); /* * 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_ldi_imm (code, sparc_o1, MONO_SPARC_STACK_BIAS + i * sizeof (gpointer), sparc_l0 + i); /* Save %fp to a location reserved in mono_arch_allocate_vars */ sparc_sti_imm (code, sparc_o7, sparc_fp, MONO_SPARC_STACK_BIAS - sizeof (gpointer)); /* Call the filter code, after this returns, %o0 will hold the result */ sparc_call_imm (code, sparc_o0, 0); sparc_nop (code); /* Restore original %fp */ sparc_ldi_imm (code, sparc_fp, MONO_SPARC_STACK_BIAS - sizeof (gpointer), sparc_fp); sparc_mov_reg_reg (code, sparc_o0, sparc_i0); /* 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); mono_arch_flush_icache ((guint8*)start, (guint8*)code - (guint8*)start); inited = 1; return start; }