Просмотр исходного кода

Revert the 'Emit push/pop LMF code as IR' changes, they seem to break make test-sgen on wrench.

Zoltan Varga 12 лет назад
Родитель
Сommit
cd49ed4b02
6 измененных файлов с 134 добавлено и 276 удалено
  1. 0 79
      mono/mini/method-to-ir.c
  2. 13 20
      mono/mini/mini-amd64.c
  3. 1 0
      mono/mini/mini-amd64.h
  4. 119 149
      mono/mini/mini-x86.c
  5. 0 16
      mono/mini/mini.c
  6. 1 12
      mono/mini/mini.h

+ 0 - 79
mono/mini/method-to-ir.c

@@ -1868,77 +1868,6 @@ mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int so
 	}
 }
 
-/*
- * emit_push_lmf:
- *
- *   Emit IR to push the current LMF onto the LMF stack.
- */
-static void
-emit_push_lmf (MonoCompile *cfg)
-{
-	/*
-	 * 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 (!cfg->lmf_ir)
-		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);
-}
-
-/*
- * emit_push_lmf:
- *
- *   Emit IR to pop the current LMF from the LMF stack.
- */
-static void
-emit_pop_lmf (MonoCompile *cfg)
-{
-	int lmf_reg, lmf_addr_reg, prev_lmf_reg;
-	MonoInst *ins;
-
-	if (!cfg->lmf_ir)
-		return;
-
-	/*
-	 * Emit IR to pop the LMF:
-	 * *(lmf->lmf_addr) = lmf->prev_lmf
-	 */
-	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);
-}
-
 static int
 ret_type_to_call_opcode (MonoType *type, int calli, int virt, MonoGenericSharingContext *gsctx)
 {
@@ -8359,9 +8288,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 					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;
 
@@ -11723,11 +11649,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 		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;

+ 13 - 20
mono/mini/mini-amd64.c

@@ -2010,14 +2010,16 @@ mono_arch_create_vars (MonoCompile *cfg)
 	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
-
-	cfg->create_lmf_var = 1;
-#if !defined(TARGET_WIN32) && !defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
-	cfg->lmf_ir = 1;
-#endif
 }
 
 static void
@@ -3734,13 +3736,14 @@ emit_save_lmf (MonoCompile *cfg, guint8 *code, gint32 lmf_offset, gboolean *args
 			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 {
 			/* 
@@ -3761,18 +3764,13 @@ emit_save_lmf (MonoCompile *cfg, guint8 *code, gint32 lmf_offset, gboolean *args
 		/* 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 emit_push_lmf () in method-to-ir.c */
-		/* FIXME: Use this on win32 as well */
-		return code;
-#endif
 	}
 
 	return code;
 }
 
 /*
- * emit_restore_lmf:
+ * emit_save_lmf:
  *
  *   Emit code to pop an LMF structure from the LMF stack.
  */
@@ -3789,15 +3787,10 @@ emit_restore_lmf (MonoCompile *cfg, guint8 *code, gint32 lmf_offset)
 		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;
@@ -4949,7 +4942,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
 			break;
 		}
 		case OP_AMD64_SAVE_SP_TO_LMF: {
-			MonoInst *lmf_var = cfg->lmf_var;
+			MonoInst *lmf_var = cfg->arch.lmf_var;
 			amd64_mov_membase_reg (code, cfg->frame_reg, lmf_var->inst_offset + G_STRUCT_OFFSET (MonoLMF, rsp), AMD64_RSP, 8);
 			break;
 		}
@@ -6568,7 +6561,7 @@ mono_arch_emit_prolog (MonoCompile *cfg)
 	int alloc_size, pos, i, cfa_offset, quad, max_epilog_size;
 	guint8 *code;
 	CallInfo *cinfo;
-	MonoInst *lmf_var = cfg->lmf_var;
+	MonoInst *lmf_var = cfg->arch.lmf_var;
 	gboolean args_clobbered = FALSE;
 	gboolean trace = FALSE;
 #ifdef __native_client_codegen__
@@ -7132,7 +7125,7 @@ mono_arch_emit_epilog (MonoCompile *cfg)
 	guint8 *code;
 	int max_epilog_size;
 	CallInfo *cinfo;
-	gint32 lmf_offset = cfg->lmf_var ? ((MonoInst*)cfg->lmf_var)->inst_offset : -1;
+	gint32 lmf_offset = cfg->arch.lmf_var ? ((MonoInst*)cfg->arch.lmf_var)->inst_offset : -1;
 	
 	max_epilog_size = get_max_epilog_size (cfg);
 

+ 1 - 0
mono/mini/mini-amd64.h

@@ -203,6 +203,7 @@ typedef struct MonoCompileArch {
 #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)

+ 119 - 149
mono/mini/mini-x86.c

@@ -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 */

+ 0 - 16
mono/mini/mini.c

@@ -2870,9 +2870,6 @@ mini_get_tls_offset (MonoJitTlsKey key)
 	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;
@@ -2942,12 +2939,6 @@ mono_get_lmf_intrinsic (MonoCompile* cfg)
 	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)
 {
@@ -3620,13 +3611,6 @@ mono_compile_create_vars (MonoCompile *cfg)
 		g_print ("locals done\n");
 
 	mono_arch_create_vars (cfg);
-
-	if (cfg->method->save_lmf && cfg->create_lmf_var) {
-		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;
-	}
 }
 
 void

+ 1 - 12
mono/mini/mini.h

@@ -1053,8 +1053,7 @@ typedef enum {
 	TLS_KEY_JIT_TLS = 1,
 	/* mono_domain_get () */
 	TLS_KEY_DOMAIN = 2,
-	TLS_KEY_LMF = 3,
-	TLS_KEY_LMF_ADDR = 4
+	TLS_KEY_LMF = 3
 } MonoJitTlsKey;
 
 /*
@@ -1383,9 +1382,6 @@ typedef struct {
 	/* 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 */
@@ -1431,12 +1427,6 @@ typedef struct {
 	guint            disable_vreg_to_lvreg : 1;
 	guint            disable_deadce_vars : 1;
 	guint            disable_out_of_line_bblocks : 1;
-	guint            create_lmf_var : 1;
-	/*
-	 * 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 ().
-	 */
-	guint            lmf_ir : 1;
 	guint            gen_write_barriers : 1;
 	guint            init_ref_vars : 1;
 	guint            extend_live_ranges : 1;
@@ -1976,7 +1966,6 @@ MonoInst* mono_get_jit_tls_intrinsic        (MonoCompile *cfg) MONO_INTERNAL;
 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;