Prechádzať zdrojové kódy

2005-11-20 Zoltan Varga <[email protected]>

	* mini-ia64.c exceptions-ia64.c: Simplify the way filters/finally
	handlers are called.

svn path=/trunk/mono/; revision=53292
Zoltan Varga 20 rokov pred
rodič
commit
bbf693c920

+ 3 - 0
mono/mini/ChangeLog

@@ -1,5 +1,8 @@
 2005-11-20  Zoltan Varga  <[email protected]>
 
+	* mini-ia64.c exceptions-ia64.c: Simplify the way filters/finally
+	handlers are called.
+
 	* mini-ia64.c (mono_arch_emit_exceptions): Optimize size of exception
 	throwing code.
 

+ 9 - 20
mono/mini/exceptions-ia64.c

@@ -116,17 +116,18 @@ get_real_call_filter (void)
 	/* int call_filter (guint64 fp, guint64 ip) */
 
 	/*
-	 * We have to create a register+stack frame similar to the frame which contains
-	 * the filter. 
+	 * We have to create a register+stack frame similar to the frame which 
+	 * contains the filter. 
 	 * - setting fp
 	 * - setting up a register stack frame
-	 * These cannot be set up in this function, because the fp register is a stacked
-	 * register which is different in each method. Also, the register stack frame is
-	 * different in each method. So we pass the FP value in a a non-stacked
-	 * register and the code generated by the OP_START_HANDLER opcode will copy it
-	 * to the appropriate register after setting up the register stack frame.
+	 * These cannot be set up in this function, because the fp register is a 
+	 * stacked register which is different in each method. Also, the register 
+	 * stack frame is different in each method. So we pass the FP value in a a 
+	 * non-stacked register and the code generated by the OP_START_HANDLER 
+	 * opcode will copy it to the appropriate register after setting up the 
+	 * register stack frame.
 	 * The stacked registers are not need to be set since variables used in
-	 * handler registers are never allocated to registers.
+	 * handler regions are never allocated to registers.
 	 */
 
 	in0 = 32;
@@ -152,25 +153,13 @@ get_real_call_filter (void)
 	/* Target ip */
 	ia64_mov_to_br (code, IA64_B6, in0 + 1);
 
-	/* Return address */
-	ia64_mov_from_ip (code, GP_SCRATCH_REG);
-	ia64_adds_imm (code, GP_SCRATCH_REG, 3 * 16, GP_SCRATCH_REG);
-
 	/* Call the filter */
 	ia64_br_call_reg (code, IA64_B0, IA64_B6);
 
 	/* R8 contains the result of the filter */
-	/* R9 contains the saved apr_pfs value */
 
 	/* FIXME: Add unwind info for this */
 
-	/* The filter returns using br_cond_reg, so have to do another return */
-	ia64_mov_to_ar_i (code, IA64_PFS, IA64_R9);
-	ia64_mov_from_ip (code, GP_SCRATCH_REG);	
-	ia64_adds_imm (code, GP_SCRATCH_REG, 4 * 16, GP_SCRATCH_REG);
-	ia64_mov_to_br (code, IA64_B0, GP_SCRATCH_REG);
-	ia64_br_ret_reg (code, IA64_B0);
-
 	ia64_begin_bundle (code);
 
 	r_body = mono_ia64_create_unwind_region (&code);

+ 58 - 28
mono/mini/mini-ia64.c

@@ -659,7 +659,8 @@ static void
 mono_ia64_alloc_stacked_registers (MonoCompile *cfg)
 {
 	CallInfo *cinfo;
-	guint32 reserved_regs = 3;
+	guint32 reserved_regs;
+	MonoMethodHeader *header;
 
 	if (cfg->arch.reg_local0 > 0)
 		/* Already done */
@@ -667,8 +668,10 @@ mono_ia64_alloc_stacked_registers (MonoCompile *cfg)
 
 	cinfo = get_call_info (mono_method_signature (cfg->method), FALSE);
 
-	/* Three registers are reserved for use by the prolog/epilog */
-	reserved_regs = 3;
+	header = mono_method_get_header (cfg->method);
+	
+	/* Some registers are reserved for use by the prolog/epilog */
+	reserved_regs = header->num_clauses ? 4 : 3;
 
 	if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
 		(cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)) {
@@ -685,11 +688,20 @@ mono_ia64_alloc_stacked_registers (MonoCompile *cfg)
 
 	cfg->arch.reg_saved_ar_pfs = cfg->arch.reg_local0 - 1;
 	cfg->arch.reg_saved_b0 = cfg->arch.reg_local0 - 2;
-	cfg->arch.reg_saved_sp = cfg->arch.reg_local0 - 3;
+	cfg->arch.reg_fp = cfg->arch.reg_local0 - 3;
+
+	/* 
+	 * Frames without handlers save sp to fp, frames with handlers save it into
+	 * a dedicated register.
+	 */
+	if (header->num_clauses)
+		cfg->arch.reg_saved_sp = cfg->arch.reg_local0 - 4;
+	else
+		cfg->arch.reg_saved_sp = cfg->arch.reg_fp;
 
 	if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
 		(cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)) {
-		cfg->arch.reg_saved_return_val = cfg->arch.reg_local0 - 4;
+		cfg->arch.reg_saved_return_val = cfg->arch.reg_local0 - reserved_regs;
 	}
 
 	/* 
@@ -790,7 +802,7 @@ mono_arch_allocate_vars (MonoCompile *cfg)
 	}
 	else {
 		/* Locals are allocated backwards from %fp */
-		cfg->frame_reg = cfg->arch.reg_saved_sp;
+		cfg->frame_reg = cfg->arch.reg_fp;
 		offset = 0;
 	}
 
@@ -3087,19 +3099,32 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
 			MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
 
 			/* 
-			 * We might be called by call_filter, in which case the
-			 * the register stack is not set up correctly. So do it now.
-			 * Allocate a stack frame and set the fp register from the value 
-			 * passed in by the caller.
-			 * R15 is used since it is writable using libunwind.
+			 * R15 determines our caller. It is used since it is writable using
+			 * libunwind.
 			 * R15 == 0 means we are called by OP_CALL_HANDLER or via resume_context ()
+			 * R15 != 0 means we are called by call_filter ().
 			 */
 			ia64_codegen_set_one_ins_per_bundle (code, TRUE);
 			ia64_cmp_eq (code, 6, 7, IA64_R15, IA64_R0);
-			/* Alloc is not predictable so we have to use a branch */
-			ia64_br_cond_pred (code, 6, 3);
+
+			ia64_br_cond_pred (code, 6, 6);
+
+			/*
+			 * Called by call_filter:
+			 * Allocate a new stack frame, and set the fp register from the 
+			 * value passed in by the caller.
+			 * We allocate a similar frame as is done by the prolog, so
+			 * if an exception is thrown while executing the filter, the
+			 * unwinder can unwind through the filter frame using the unwind
+			 * info for the prolog. 
+			 */
 			ia64_alloc (code, cfg->arch.reg_saved_ar_pfs, cfg->arch.reg_local0 - cfg->arch.reg_in0, cfg->arch.reg_out0 - cfg->arch.reg_local0, cfg->arch.n_out_regs, 0);
+			ia64_mov_from_br (code, cfg->arch.reg_saved_b0, IA64_B0);
+			ia64_mov (code, cfg->arch.reg_saved_sp, IA64_SP);
 			ia64_mov (code, cfg->frame_reg, IA64_R15);
+			/* Signal to endfilter that we are called by call_filter */
+			ia64_mov (code, GP_SCRATCH_REG, IA64_R0);
+
 			/* Save the return address */
 			ia64_adds_imm (code, GP_SCRATCH_REG2, spvar->inst_offset, cfg->frame_reg);
 			ia64_st8_hint (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 0);
@@ -3107,23 +3132,26 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
 
 			break;
 		}
-		case CEE_ENDFINALLY: {
-			MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
-			/* Return the saved arp_pfs value to call_filter */
-			ia64_mov (code, IA64_R9, cfg->arch.reg_saved_ar_pfs);
-			ia64_adds_imm (code, GP_SCRATCH_REG, spvar->inst_offset, cfg->frame_reg);
-			ia64_ld8_hint (code, GP_SCRATCH_REG, GP_SCRATCH_REG, 0);
-			ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
-			ia64_br_cond_reg (code, IA64_B6);
-			break;
-		}
+		case CEE_ENDFINALLY:
 		case OP_ENDFILTER: {
-			/* FIXME: Return the value */
+			/* FIXME: Return the value in ENDFILTER */
 			MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
-			/* Return the saved arp_pfs value to call_filter */
-			ia64_mov (code, IA64_R9, cfg->arch.reg_saved_ar_pfs);
+
+			/* Load the return address */
 			ia64_adds_imm (code, GP_SCRATCH_REG, spvar->inst_offset, cfg->frame_reg);
 			ia64_ld8_hint (code, GP_SCRATCH_REG, GP_SCRATCH_REG, 0);
+
+			/* Test caller */
+			ia64_cmp_eq (code, 6, 7, GP_SCRATCH_REG, IA64_R0);
+			ia64_br_cond_pred (code, 7, 4);
+
+			/* Called by call_filter */
+			/* Pop frame */
+			ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
+			ia64_mov_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
+			ia64_br_ret_reg (code, IA64_B0);			
+
+			/* Called by CALL_HANDLER */
 			ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
 			ia64_br_cond_reg (code, IA64_B6);
 			break;
@@ -3894,8 +3922,10 @@ mono_arch_emit_prolog (MonoCompile *cfg)
 	ia64_mov_from_br (code, cfg->arch.reg_saved_b0, IA64_B0);
 
 	if ((alloc_size || cinfo->stack_usage) && !cfg->arch.omit_fp) {
-		ia64_unw_save_reg (code, UNW_IA64_SP, UNW_IA64_GR + cfg->frame_reg);
-		ia64_mov (code, cfg->frame_reg, IA64_SP);
+		ia64_unw_save_reg (code, UNW_IA64_SP, UNW_IA64_GR + cfg->arch.reg_saved_sp);
+		ia64_mov (code, cfg->arch.reg_saved_sp, IA64_SP);
+		if (cfg->frame_reg != cfg->arch.reg_saved_sp)
+			ia64_mov (code, cfg->frame_reg, IA64_SP);
 	}
 
 	if (alloc_size) {

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

@@ -64,6 +64,7 @@ typedef struct MonoCompileArch {
 	gint32 reg_saved_ar_pfs;
 	gint32 reg_saved_b0;
 	gint32 reg_saved_sp;
+	gint32 reg_fp;
 	gint32 reg_saved_return_val;
 	guint32 prolog_end_offset, epilog_begin_offset, epilog_end_offset;
 	void *ret_var_addr_local;