|
|
@@ -1178,7 +1178,6 @@ mono_arch_create_vars (MonoCompile *cfg)
|
|
|
}
|
|
|
|
|
|
cfg->arch_eh_jit_info = 1;
|
|
|
- cfg->create_lmf_var = 1;
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
@@ -2361,143 +2360,6 @@ emit_load_volatile_arguments (MonoCompile *cfg, guint8 *code)
|
|
|
return code;
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * emit_setup_lmf:
|
|
|
- *
|
|
|
- * Emit code to initialize an LMF structure at LMF_OFFSET.
|
|
|
- */
|
|
|
-static guint8*
|
|
|
-emit_setup_lmf (MonoCompile *cfg, guint8 *code, gint32 lmf_offset, int cfa_offset)
|
|
|
-{
|
|
|
- /* save the current IP */
|
|
|
- if (cfg->compile_aot) {
|
|
|
- /* This pushes the current ip */
|
|
|
- x86_call_imm (code, 0);
|
|
|
- x86_pop_reg (code, X86_EAX);
|
|
|
- } else {
|
|
|
- mono_add_patch_info (cfg, code + 1 - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
|
|
|
- x86_mov_reg_imm (code, X86_EAX, 0);
|
|
|
- }
|
|
|
- x86_mov_membase_reg (code, cfg->frame_reg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, eip), X86_EAX, sizeof (mgreg_t));
|
|
|
-
|
|
|
- /* save all caller saved regs */
|
|
|
- x86_mov_membase_reg (code, cfg->frame_reg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, ebp), X86_EBP, sizeof (mgreg_t));
|
|
|
- x86_mov_membase_reg (code, cfg->frame_reg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, esi), X86_ESI, sizeof (mgreg_t));
|
|
|
- x86_mov_membase_reg (code, cfg->frame_reg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, edi), X86_EDI, sizeof (mgreg_t));
|
|
|
- x86_mov_membase_reg (code, cfg->frame_reg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, ebx), X86_EBX, sizeof (mgreg_t));
|
|
|
-
|
|
|
- mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset + lmf_offset + G_STRUCT_OFFSET (MonoLMF, eip), SLOT_NOREF);
|
|
|
- mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset + lmf_offset + G_STRUCT_OFFSET (MonoLMF, ebp), SLOT_NOREF);
|
|
|
- mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset + lmf_offset + G_STRUCT_OFFSET (MonoLMF, esi), SLOT_NOREF);
|
|
|
- mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset + lmf_offset + G_STRUCT_OFFSET (MonoLMF, edi), SLOT_NOREF);
|
|
|
- mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset + lmf_offset + G_STRUCT_OFFSET (MonoLMF, ebx), SLOT_NOREF);
|
|
|
- mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset + lmf_offset + G_STRUCT_OFFSET (MonoLMF, esp), SLOT_NOREF);
|
|
|
- mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset + lmf_offset + G_STRUCT_OFFSET (MonoLMF, method), SLOT_NOREF);
|
|
|
- mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset + lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr), SLOT_NOREF);
|
|
|
- mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset + lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), SLOT_NOREF);
|
|
|
-
|
|
|
- return code;
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * emit_save_lmf:
|
|
|
- *
|
|
|
- * Emit code to push an LMF structure on the LMF stack.
|
|
|
- */
|
|
|
-static guint8*
|
|
|
-emit_save_lmf (MonoCompile *cfg, guint8 *code, gint32 lmf_offset)
|
|
|
-{
|
|
|
- if ((lmf_tls_offset != -1) && !is_win32 && !optimize_for_xen) {
|
|
|
- /*
|
|
|
- * Optimized version which uses the mono_lmf TLS variable instead of indirection
|
|
|
- * through the mono_lmf_addr TLS variable.
|
|
|
- */
|
|
|
- /* %eax = previous_lmf */
|
|
|
- code = mono_x86_emit_tls_get (code, X86_EAX, lmf_tls_offset);
|
|
|
- /* set previous_lmf */
|
|
|
- x86_mov_membase_reg (code, cfg->frame_reg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), X86_EAX, sizeof (mgreg_t));
|
|
|
- x86_lea_membase (code, X86_EAX, cfg->frame_reg, lmf_offset);
|
|
|
- /* set new LMF */
|
|
|
- code = mono_x86_emit_tls_set (code, X86_EAX, lmf_tls_offset);
|
|
|
- } else {
|
|
|
- /* get the address of lmf for the current thread */
|
|
|
- /*
|
|
|
- * This is performance critical so we try to use some tricks to make
|
|
|
- * it fast.
|
|
|
- */
|
|
|
- if (lmf_addr_tls_offset != -1) {
|
|
|
- /* Load lmf quicky using the GS register */
|
|
|
- code = mono_x86_emit_tls_get (code, X86_EAX, lmf_addr_tls_offset);
|
|
|
-#ifdef TARGET_WIN32
|
|
|
- /* The TLS key actually contains a pointer to the MonoJitTlsData structure */
|
|
|
- /* FIXME: Add a separate key for LMF to avoid this */
|
|
|
- x86_alu_reg_imm (code, X86_ADD, X86_EAX, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
|
|
|
-#endif
|
|
|
- } else {
|
|
|
- if (cfg->compile_aot)
|
|
|
- code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
|
|
|
- code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_get_lmf_addr");
|
|
|
- }
|
|
|
-
|
|
|
- /* save lmf_addr */
|
|
|
- x86_mov_membase_reg (code, cfg->frame_reg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr), X86_EAX, sizeof (mgreg_t));
|
|
|
- /* save previous_lmf */
|
|
|
- x86_mov_reg_membase (code, X86_ECX, X86_EAX, 0, sizeof (mgreg_t));
|
|
|
- x86_mov_membase_reg (code, cfg->frame_reg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), X86_ECX, sizeof (mgreg_t));
|
|
|
- /* set new LMF */
|
|
|
- x86_lea_membase (code, X86_ECX, cfg->frame_reg, lmf_offset);
|
|
|
- x86_mov_membase_reg (code, X86_EAX, 0, X86_ECX, sizeof (mgreg_t));
|
|
|
- }
|
|
|
- return code;
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * emit_restore_lmf:
|
|
|
- *
|
|
|
- * Emit code to pop an LMF structure from the LMF stack.
|
|
|
- * Preserves the return registers.
|
|
|
- */
|
|
|
-static guint8*
|
|
|
-emit_restore_lmf (MonoCompile *cfg, guint8 *code, gint32 lmf_offset)
|
|
|
-{
|
|
|
- MonoMethodSignature *sig = mono_method_signature (cfg->method);
|
|
|
- int prev_lmf_reg;
|
|
|
-
|
|
|
- if ((lmf_tls_offset != -1) && !is_win32 && !optimize_for_xen) {
|
|
|
- /*
|
|
|
- * Optimized version which uses the mono_lmf TLS variable instead of indirection
|
|
|
- * through the mono_lmf_addr TLS variable.
|
|
|
- */
|
|
|
- /* reg = previous_lmf */
|
|
|
- x86_mov_reg_membase (code, X86_ECX, cfg->frame_reg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), 4);
|
|
|
-
|
|
|
- /* lmf = previous_lmf */
|
|
|
- code = mono_x86_emit_tls_set (code, X86_ECX, lmf_tls_offset);
|
|
|
- } else {
|
|
|
- /* Find a spare register */
|
|
|
- switch (mini_type_get_underlying_type (cfg->generic_sharing_context, sig->ret)->type) {
|
|
|
- case MONO_TYPE_I8:
|
|
|
- case MONO_TYPE_U8:
|
|
|
- prev_lmf_reg = X86_EDI;
|
|
|
- cfg->used_int_regs |= (1 << X86_EDI);
|
|
|
- break;
|
|
|
- default:
|
|
|
- prev_lmf_reg = X86_EDX;
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- /* reg = previous_lmf */
|
|
|
- x86_mov_reg_membase (code, prev_lmf_reg, cfg->frame_reg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), 4);
|
|
|
-
|
|
|
- /* ecx = lmf */
|
|
|
- x86_mov_reg_membase (code, X86_ECX, cfg->frame_reg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr), 4);
|
|
|
-
|
|
|
- /* *(lmf) = previous_lmf */
|
|
|
- x86_mov_membase_reg (code, X86_ECX, 0, prev_lmf_reg, 4);
|
|
|
- }
|
|
|
- return code;
|
|
|
-}
|
|
|
-
|
|
|
#define REAL_PRINT_REG(text,reg) \
|
|
|
mono_assert (reg >= 0); \
|
|
|
x86_push_reg (code, X86_EAX); \
|
|
|
@@ -5209,7 +5071,89 @@ mono_arch_emit_prolog (MonoCompile *cfg)
|
|
|
alloc_size = cfg->stack_offset;
|
|
|
pos = 0;
|
|
|
|
|
|
- if (!method->save_lmf) {
|
|
|
+ if (method->save_lmf) {
|
|
|
+ pos += sizeof (MonoLMF);
|
|
|
+
|
|
|
+ /* save the current IP */
|
|
|
+ if (cfg->compile_aot) {
|
|
|
+ /* This pushes the current ip */
|
|
|
+ x86_call_imm (code, 0);
|
|
|
+ } else {
|
|
|
+ mono_add_patch_info (cfg, code + 1 - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
|
|
|
+ x86_push_imm_template (code);
|
|
|
+ }
|
|
|
+ cfa_offset += sizeof (gpointer);
|
|
|
+ mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset, SLOT_NOREF);
|
|
|
+
|
|
|
+ /* save all caller saved regs */
|
|
|
+ x86_push_reg (code, X86_EBP);
|
|
|
+ cfa_offset += sizeof (gpointer);
|
|
|
+ mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset, SLOT_NOREF);
|
|
|
+ x86_push_reg (code, X86_ESI);
|
|
|
+ cfa_offset += sizeof (gpointer);
|
|
|
+ mono_emit_unwind_op_offset (cfg, code, X86_ESI, - cfa_offset);
|
|
|
+ mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset, SLOT_NOREF);
|
|
|
+ x86_push_reg (code, X86_EDI);
|
|
|
+ cfa_offset += sizeof (gpointer);
|
|
|
+ mono_emit_unwind_op_offset (cfg, code, X86_EDI, - cfa_offset);
|
|
|
+ mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset, SLOT_NOREF);
|
|
|
+ x86_push_reg (code, X86_EBX);
|
|
|
+ cfa_offset += sizeof (gpointer);
|
|
|
+ mono_emit_unwind_op_offset (cfg, code, X86_EBX, - cfa_offset);
|
|
|
+ mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset, SLOT_NOREF);
|
|
|
+
|
|
|
+ if ((lmf_tls_offset != -1) && !is_win32 && !optimize_for_xen) {
|
|
|
+ /*
|
|
|
+ * Optimized version which uses the mono_lmf TLS variable instead of indirection
|
|
|
+ * through the mono_lmf_addr TLS variable.
|
|
|
+ */
|
|
|
+ /* %eax = previous_lmf */
|
|
|
+ code = mono_x86_emit_tls_get (code, X86_EAX, lmf_tls_offset);
|
|
|
+ /* skip esp + method_info + lmf */
|
|
|
+ x86_alu_reg_imm (code, X86_SUB, X86_ESP, 12);
|
|
|
+ cfa_offset += 12;
|
|
|
+ mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset, SLOT_NOREF);
|
|
|
+ mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset + 4, SLOT_NOREF);
|
|
|
+ mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset + 8, SLOT_NOREF);
|
|
|
+ /* push previous_lmf */
|
|
|
+ x86_push_reg (code, X86_EAX);
|
|
|
+ cfa_offset += 4;
|
|
|
+ mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset, SLOT_NOREF);
|
|
|
+ /* new lmf = ESP */
|
|
|
+ code = mono_x86_emit_tls_set (code, X86_ESP, lmf_tls_offset);
|
|
|
+ } else {
|
|
|
+ /* get the address of lmf for the current thread */
|
|
|
+ /*
|
|
|
+ * This is performance critical so we try to use some tricks to make
|
|
|
+ * it fast.
|
|
|
+ */
|
|
|
+
|
|
|
+ if (lmf_addr_tls_offset != -1) {
|
|
|
+ /* Load lmf quicky using the GS register */
|
|
|
+ code = mono_x86_emit_tls_get (code, X86_EAX, lmf_addr_tls_offset);
|
|
|
+#ifdef TARGET_WIN32
|
|
|
+ /* The TLS key actually contains a pointer to the MonoJitTlsData structure */
|
|
|
+ /* FIXME: Add a separate key for LMF to avoid this */
|
|
|
+ x86_alu_reg_imm (code, X86_ADD, X86_EAX, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
|
|
|
+#endif
|
|
|
+ } else {
|
|
|
+ if (cfg->compile_aot)
|
|
|
+ code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
|
|
|
+ code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_get_lmf_addr");
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Skip esp + method info */
|
|
|
+ x86_alu_reg_imm (code, X86_SUB, X86_ESP, 8);
|
|
|
+
|
|
|
+ /* push lmf */
|
|
|
+ x86_push_reg (code, X86_EAX);
|
|
|
+ /* push *lfm (previous_lmf) */
|
|
|
+ x86_push_membase (code, X86_EAX, 0);
|
|
|
+ /* *(lmf) = ESP */
|
|
|
+ x86_mov_membase_reg (code, X86_EAX, 0, X86_ESP, 4);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+
|
|
|
if (cfg->used_int_regs & (1 << X86_EBX)) {
|
|
|
x86_push_reg (code, X86_EBX);
|
|
|
pos += 4;
|
|
|
@@ -5357,11 +5301,6 @@ mono_arch_emit_prolog (MonoCompile *cfg)
|
|
|
x86_mov_membase_reg (code, X86_EBP, cfg->rgctx_var->inst_offset, MONO_ARCH_RGCTX_REG, 4);
|
|
|
}
|
|
|
|
|
|
- if (method->save_lmf) {
|
|
|
- code = emit_setup_lmf (cfg, code, cfg->lmf_var->inst_offset, cfa_offset);
|
|
|
- code = emit_save_lmf (cfg, code, cfg->lmf_var->inst_offset);
|
|
|
- }
|
|
|
-
|
|
|
if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
|
|
|
code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
|
|
|
|
|
|
@@ -5417,7 +5356,8 @@ mono_arch_emit_epilog (MonoCompile *cfg)
|
|
|
pos = 0;
|
|
|
|
|
|
if (method->save_lmf) {
|
|
|
- gint32 lmf_offset = cfg->lmf_var->inst_offset;
|
|
|
+ gint32 prev_lmf_reg;
|
|
|
+ gint32 lmf_offset = -sizeof (MonoLMF);
|
|
|
|
|
|
/* check if we need to restore protection of the stack after a stack overflow */
|
|
|
if (mono_get_jit_tls_offset () != -1) {
|
|
|
@@ -5436,19 +5376,49 @@ mono_arch_emit_epilog (MonoCompile *cfg)
|
|
|
} else {
|
|
|
/* FIXME: maybe save the jit tls in the prolog */
|
|
|
}
|
|
|
+ if ((lmf_tls_offset != -1) && !is_win32 && !optimize_for_xen) {
|
|
|
+ /*
|
|
|
+ * Optimized version which uses the mono_lmf TLS variable instead of indirection
|
|
|
+ * through the mono_lmf_addr TLS variable.
|
|
|
+ */
|
|
|
+ /* reg = previous_lmf */
|
|
|
+ x86_mov_reg_membase (code, X86_ECX, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), 4);
|
|
|
+
|
|
|
+ /* lmf = previous_lmf */
|
|
|
+ code = mono_x86_emit_tls_set (code, X86_ECX, lmf_tls_offset);
|
|
|
+ } else {
|
|
|
+ /* Find a spare register */
|
|
|
+ switch (mini_type_get_underlying_type (cfg->generic_sharing_context, sig->ret)->type) {
|
|
|
+ case MONO_TYPE_I8:
|
|
|
+ case MONO_TYPE_U8:
|
|
|
+ prev_lmf_reg = X86_EDI;
|
|
|
+ cfg->used_int_regs |= (1 << X86_EDI);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ prev_lmf_reg = X86_EDX;
|
|
|
+ break;
|
|
|
+ }
|
|
|
|
|
|
- code = emit_restore_lmf (cfg, code, lmf_offset);
|
|
|
+ /* reg = previous_lmf */
|
|
|
+ x86_mov_reg_membase (code, prev_lmf_reg, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), 4);
|
|
|
+
|
|
|
+ /* ecx = lmf */
|
|
|
+ x86_mov_reg_membase (code, X86_ECX, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr), 4);
|
|
|
+
|
|
|
+ /* *(lmf) = previous_lmf */
|
|
|
+ x86_mov_membase_reg (code, X86_ECX, 0, prev_lmf_reg, 4);
|
|
|
+ }
|
|
|
|
|
|
/* restore caller saved regs */
|
|
|
if (cfg->used_int_regs & (1 << X86_EBX)) {
|
|
|
- x86_mov_reg_membase (code, X86_EBX, cfg->frame_reg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, ebx), 4);
|
|
|
+ x86_mov_reg_membase (code, X86_EBX, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, ebx), 4);
|
|
|
}
|
|
|
|
|
|
if (cfg->used_int_regs & (1 << X86_EDI)) {
|
|
|
- x86_mov_reg_membase (code, X86_EDI, cfg->frame_reg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, edi), 4);
|
|
|
+ x86_mov_reg_membase (code, X86_EDI, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, edi), 4);
|
|
|
}
|
|
|
if (cfg->used_int_regs & (1 << X86_ESI)) {
|
|
|
- x86_mov_reg_membase (code, X86_ESI, cfg->frame_reg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, esi), 4);
|
|
|
+ x86_mov_reg_membase (code, X86_ESI, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, esi), 4);
|
|
|
}
|
|
|
|
|
|
/* EBP is restored by LEAVE */
|