}
}
+/*
+ * emit_push_lmf:
+ *
+ * Emit IR to push the current LMF onto the LMF stack.
+ */
+static void
+emit_push_lmf (MonoCompile *cfg)
+{
+#if defined(MONO_ARCH_ENABLE_LMF_IR)
+ /*
+ * Emit IR to push the LMF:
+ * lmf_addr = <lmf_addr from tls>
+ * lmf->lmf_addr = lmf_addr
+ * lmf->prev_lmf = *lmf_addr
+ * *lmf_addr = lmf
+ */
+ int lmf_reg, lmf_addr_reg, prev_lmf_reg;
+ MonoInst *ins, *lmf_ins;
+
+ if (!mono_arch_enable_lmf_ir (cfg))
+ return;
+
+ lmf_ins = mono_get_lmf_addr_intrinsic (cfg);
+ if (lmf_ins)
+ MONO_ADD_INS (cfg->cbb, lmf_ins);
+ else
+ lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
+ lmf_addr_reg = lmf_ins->dreg;
+
+ EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
+ lmf_reg = ins->dreg;
+ /* Save lmf_addr */
+ if (!cfg->lmf_addr_var)
+ cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
+ EMIT_NEW_UNALU (cfg, ins, OP_MOVE, cfg->lmf_addr_var->dreg, lmf_ins->dreg);
+ prev_lmf_reg = alloc_preg (cfg);
+ /* Save previous_lmf */
+ EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_addr_reg, 0);
+ EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, G_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
+ /* Set new lmf */
+ EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, lmf_reg);
+#endif
+}
+
+/*
+ * emit_push_lmf:
+ *
+ * Emit IR to pop the current LMF from the LMF stack.
+ */
+static void
+emit_pop_lmf (MonoCompile *cfg)
+{
+#if defined(MONO_ARCH_ENABLE_LMF_IR)
+ int lmf_reg, lmf_addr_reg, prev_lmf_reg;
+ MonoInst *ins;
+
+ if (!mono_arch_enable_lmf_ir (cfg))
+ return;
+
+ /*
+ * Emit IR to pop the LMF:
+ * *(lmf->lmf_addr) = lmf->prev_lmf
+ */
+ cfg->cbb = cfg->bb_exit;
+ EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
+ lmf_reg = ins->dreg;
+ /* This could be called before emit_push_lmf () */
+ if (!cfg->lmf_addr_var)
+ cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
+ lmf_addr_reg = cfg->lmf_addr_var->dreg;
+ prev_lmf_reg = alloc_preg (cfg);
+ EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
+ EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
+#endif
+}
+
static int
ret_type_to_call_opcode (MonoType *type, int calli, int virt, MonoGenericSharingContext *gsctx)
{
cfg->ret_var_set = TRUE;
}
} else {
+ if (cfg->lmf_var && cfg->cbb->in_count)
+ emit_pop_lmf (cfg);
+
if (cfg->ret) {
MonoType *ret_type = mono_method_signature (method)->ret;
bblock->next_bb = end_bblock;
}
+ if (cfg->lmf_var) {
+ cfg->cbb = init_localsbb;
+ emit_push_lmf (cfg);
+ }
+
if (cfg->method == method && cfg->domainvar) {
MonoInst *store;
MonoInst *get_domain;
cfg->arch.no_pushes = TRUE;
#endif
- if (cfg->method->save_lmf) {
- MonoInst *lmf_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
- lmf_var->flags |= MONO_INST_VOLATILE;
- lmf_var->flags |= MONO_INST_LMF;
- cfg->arch.lmf_var = lmf_var;
- }
-
#ifndef MONO_AMD64_NO_PUSHES
cfg->arch_eh_jit_info = 1;
#endif
amd64_mov_mem_reg (code, lmf_tls_offset, AMD64_R11, 8);
}
} else {
+#ifdef HOST_WIN32
if (lmf_addr_tls_offset != -1) {
/* Load lmf quicky using the FS register */
code = mono_amd64_emit_tls_get (code, AMD64_RAX, lmf_addr_tls_offset);
-#ifdef HOST_WIN32
/* The TLS key actually contains a pointer to the MonoJitTlsData structure */
/* FIXME: Add a separate key for LMF to avoid this */
amd64_alu_reg_imm (code, X86_ADD, AMD64_RAX, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
-#endif
}
else {
/*
/* Set new lmf */
amd64_lea_membase (code, AMD64_R11, cfg->frame_reg, lmf_offset);
amd64_mov_membase_reg (code, AMD64_RAX, 0, AMD64_R11, sizeof(gpointer));
+#else
+ /* Already handled by the MONO_ARCH_ENABLE_LMF_IR code in method-to-ir.c */
+ /* FIXME: Use this on win32 as well */
+ return code;
+#endif
}
return code;
}
/*
- * emit_save_lmf:
+ * emit_restore_lmf:
*
* Emit code to pop an LMF structure from the LMF stack.
*/
x86_prefix (code, X86_FS_PREFIX);
amd64_mov_mem_reg (code, lmf_tls_offset, AMD64_R11, 8);
} else {
+#ifdef HOST_WIN32
/* Restore previous lmf */
amd64_mov_reg_membase (code, AMD64_RCX, cfg->frame_reg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), sizeof(gpointer));
amd64_mov_reg_membase (code, AMD64_R11, cfg->frame_reg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr), sizeof(gpointer));
amd64_mov_membase_reg (code, AMD64_R11, 0, AMD64_RCX, sizeof(gpointer));
+#else
+ /* Already done in IR */
+ return code;
+#endif
}
return code;
}
+gboolean
+mono_arch_enable_lmf_ir (MonoCompile *cfg)
+{
+#if !defined(TARGET_WIN32) && !defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
+ return TRUE;
+#else
+ return FALSE;
+#endif
+}
+
#define REAL_PRINT_REG(text,reg) \
mono_assert (reg >= 0); \
amd64_push_reg (code, AMD64_RAX); \
break;
}
case OP_AMD64_SAVE_SP_TO_LMF: {
- MonoInst *lmf_var = cfg->arch.lmf_var;
+ MonoInst *lmf_var = cfg->lmf_var;
amd64_mov_membase_reg (code, cfg->frame_reg, lmf_var->inst_offset + G_STRUCT_OFFSET (MonoLMF, rsp), AMD64_RSP, 8);
break;
}
int alloc_size, pos, i, cfa_offset, quad, max_epilog_size;
guint8 *code;
CallInfo *cinfo;
- MonoInst *lmf_var = cfg->arch.lmf_var;
+ MonoInst *lmf_var = cfg->lmf_var;
gboolean args_clobbered = FALSE;
gboolean trace = FALSE;
#ifdef __native_client_codegen__
guint8 *code;
int max_epilog_size;
CallInfo *cinfo;
- gint32 lmf_offset = cfg->arch.lmf_var ? ((MonoInst*)cfg->arch.lmf_var)->inst_offset : -1;
+ gint32 lmf_offset = cfg->lmf_var ? ((MonoInst*)cfg->lmf_var)->inst_offset : -1;
max_epilog_size = get_max_epilog_size (cfg);
#endif
gpointer seq_point_info_var;
gpointer ss_trigger_page_var;
- gpointer lmf_var;
} MonoCompileArch;
#define MONO_CONTEXT_SET_LLVM_EXC_REG(ctx, exc) do { (ctx)->rax = (gsize)exc; } while (0)
#define MONO_ARCH_HAVE_CONTEXT_SET_INT_REG 1
#define MONO_ARCH_HAVE_SETUP_ASYNC_CALLBACK 1
#define MONO_ARCH_HAVE_CREATE_LLVM_NATIVE_THUNK 1
+#define MONO_ARCH_ENABLE_LMF_IR 1
#ifdef TARGET_OSX
#define MONO_ARCH_HAVE_TLS_GET_REG 1
case TLS_KEY_LMF:
offset = mono_get_lmf_tls_offset ();
break;
+ case TLS_KEY_LMF_ADDR:
+ offset = mono_get_lmf_addr_tls_offset ();
+ break;
default:
g_assert_not_reached ();
offset = -1;
return mono_create_tls_get (cfg, TLS_KEY_LMF);
}
+MonoInst*
+mono_get_lmf_addr_intrinsic (MonoCompile* cfg)
+{
+ return mono_create_tls_get (cfg, TLS_KEY_LMF_ADDR);
+}
+
void
mono_add_patch_info (MonoCompile *cfg, int ip, MonoJumpInfoType type, gconstpointer target)
{
if (cfg->verbose_level > 2)
g_print ("locals done\n");
+ if (cfg->method->save_lmf && ARCH_ENABLE_LMF_IR) {
+ MonoInst *lmf_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
+ lmf_var->flags |= MONO_INST_VOLATILE;
+ lmf_var->flags |= MONO_INST_LMF;
+ cfg->lmf_var = lmf_var;
+ }
+
mono_arch_create_vars (cfg);
}
TLS_KEY_JIT_TLS = 1,
/* mono_domain_get () */
TLS_KEY_DOMAIN = 2,
- TLS_KEY_LMF = 3
+ TLS_KEY_LMF = 3,
+ TLS_KEY_LMF_ADDR = 4
} MonoJitTlsKey;
/*
/* For native-to-managed wrappers, the saved old domain */
MonoInst *orig_domain_var;
+ MonoInst *lmf_var;
+ MonoInst *lmf_addr_var;
+
unsigned char *cil_start;
#ifdef __native_client_codegen__
/* this alloc is not aligned, native_code */
MonoInst* mono_get_domain_intrinsic (MonoCompile* cfg) MONO_INTERNAL;
MonoInst* mono_get_thread_intrinsic (MonoCompile* cfg) MONO_INTERNAL;
MonoInst* mono_get_lmf_intrinsic (MonoCompile* cfg) MONO_INTERNAL;
+MonoInst* mono_get_lmf_addr_intrinsic (MonoCompile* cfg) MONO_INTERNAL;
GList *mono_varlist_insert_sorted (MonoCompile *cfg, GList *list, MonoMethodVar *mv, int sort_type) MONO_INTERNAL;
GList *mono_varlist_sort (MonoCompile *cfg, GList *list, int sort_type) MONO_INTERNAL;
void mono_analyze_liveness (MonoCompile *cfg) MONO_INTERNAL;
gpointer mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot) MONO_INTERNAL;
gpointer mono_arch_get_gsharedvt_call_info (gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, MonoGenericSharingContext *gsctx, gboolean gsharedvt_in, gint32 vcall_offset, gboolean calli) MONO_INTERNAL;
gboolean mono_arch_opcode_needs_emulation (MonoCompile *cfg, int opcode) MONO_INTERNAL;
+gboolean mono_arch_enable_lmf_ir (MonoCompile *cfg) MONO_INTERNAL;
#ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
gboolean mono_arch_is_soft_float (void) MONO_INTERNAL;
#define ARCH_HAVE_TLS_GET_REG 0
#endif
+/*
+ * When this is set, the code to push/pop the LMF from the LMF stack is generated as IR
+ * instead of being generated in emit_prolog ()/emit_epilog ().
+ */
+#ifdef MONO_ARCH_ENABLE_LMF_IR
+#define ARCH_ENABLE_LMF_IR 1
+#else
+#define ARCH_ENABLE_LMF_IR 0
+#endif
+
#endif /* __MONO_MINI_H__ */