2010-03-30 Rodrigo Kumpera <rkumpera@novell.com>
authorRodrigo Kumpera <kumpera@gmail.com>
Tue, 30 Mar 2010 21:03:23 +0000 (21:03 -0000)
committerRodrigo Kumpera <kumpera@gmail.com>
Tue, 30 Mar 2010 21:03:23 +0000 (21:03 -0000)
* mini-exceptions.c: Introduce mono_walk_stack_full, which
allows to select if it's new or old context that is passed to
the callback.

* mini-exceptions.c (mono_handle_exception_internal): Handle the
case when executing a guarded handler from the EH machinery.

* mini-exceptions.c (mono_install_handler_block_guard): New function
responsible for checking for handler blocks, installing the guard and
clearing abort state.

* mini-posix.c (sigusr1_signal_handler): Call mono_install_handler_block_guard
to check for handler blocks and skip interruption logic if one was found.

* mini-trampolines.c (mono_handler_block_guard_trampoline): Function called
by the handler block guard trampoline. Resumes interruption by raising the
pending ThreadAbortException.

* mini.c (create_jit_info): Calculate the end address of a finally block.

* mini-x86.c (mono_arch_install_handler_block_guard): Patch the return address
of a finally block to a specified address and return the old one.

* tramp-x86.c (mono_arch_create_handler_block_trampoline): The handler block
trampoline patches the original return address and calls the trampoline function.

svn path=/trunk/mono/; revision=154495

mono/mini/ChangeLog
mono/mini/aot-compiler.c
mono/mini/aot-runtime.c
mono/mini/mini-exceptions.c
mono/mini/mini-posix.c
mono/mini/mini-trampolines.c
mono/mini/mini-x86.c
mono/mini/mini-x86.h
mono/mini/mini.c
mono/mini/mini.h
mono/mini/tramp-x86.c

index 8427a5c67c4c47f5057ca4fb5bf2f5c91793eb45..4c844b0e522e4f69b5e863d965b18778f3e1e202 100755 (executable)
@@ -1,3 +1,31 @@
+2010-03-30 Rodrigo Kumpera  <rkumpera@novell.com>
+
+       * mini-exceptions.c: Introduce mono_walk_stack_full, which
+       allows to select if it's new or old context that is passed to 
+       the callback.
+
+       * mini-exceptions.c (mono_handle_exception_internal): Handle the
+       case when executing a guarded handler from the EH machinery.
+
+       * mini-exceptions.c (mono_install_handler_block_guard): New function
+       responsible for checking for handler blocks, installing the guard and
+       clearing abort state.
+
+       * mini-posix.c (sigusr1_signal_handler): Call mono_install_handler_block_guard
+       to check for handler blocks and skip interruption logic if one was found.
+
+       * mini-trampolines.c (mono_handler_block_guard_trampoline): Function called
+       by the handler block guard trampoline. Resumes interruption by raising the
+       pending ThreadAbortException.
+
+       * mini.c (create_jit_info): Calculate the end address of a finally block.
+
+       * mini-x86.c (mono_arch_install_handler_block_guard): Patch the return address
+       of a finally block to a specified address and return the old one.
+
+       * tramp-x86.c (mono_arch_create_handler_block_trampoline): The handler block
+       trampoline patches the original return address and calls the trampoline function.
+
 2010-03-30  Zoltan Varga  <vargaz@gmail.com>
 
        * mini-trampolines.c (mono_aot_trampoline): Remove some dead code.
index 0afd5ba593f32b784d7f93d424757d18e01bd034..28944ce9843305c2fd6364bf1d4efc01ed15c378 100644 (file)
@@ -3296,7 +3296,7 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
                        encode_value (ei->flags, p, &p);
                        encode_value (ei->exvar_offset, p, &p);
 
-                       if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
+                       if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER || ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
                                encode_value ((gint)((guint8*)ei->data.filter - code), p, &p);
                        else {
                                if (ei->data.catch_class) {
index 89fd3909e7e33c733898fb31461194beddc3c479..327bf27cd9f5b4952c0dfd440287161b634434ac 100644 (file)
@@ -1984,7 +1984,7 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain,
 
                        ei->exvar_offset = decode_value (p, &p);
 
-                       if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
+                       if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER || ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
                                ei->data.filter = code + decode_value (p, &p);
                        else {
                                if (decode_value (p, &p))
index 3ff5faa1306b27d1abeb8d2e5a0743697f7046ec..43d499b36e77aa5460970a17e8a2010a5c6c1ac8 100644 (file)
@@ -63,6 +63,7 @@ static gpointer restore_stack_protection_tramp = NULL;
 
 static void try_more_restore (void);
 static void restore_stack_protection (void);
+static void mono_walk_stack_full (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoContext *start_ctx, MonoStackFrameWalk func, gboolean use_new_ctx, gpointer user_data);
 
 void
 mono_exceptions_init (void)
@@ -658,6 +659,12 @@ ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info
  */
 void
 mono_walk_stack (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoContext *start_ctx, MonoStackFrameWalk func, gpointer user_data)
+{
+       mono_walk_stack_full (domain, jit_tls, start_ctx, func, TRUE, user_data);
+}
+
+static void
+mono_walk_stack_full (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoContext *start_ctx, MonoStackFrameWalk func, gboolean use_new_ctx, gpointer user_data)
 {
        MonoLMF *lmf = mono_get_lmf ();
        MonoJitInfo *ji, rji;
@@ -676,7 +683,7 @@ mono_walk_stack (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoContext *start
                if (!ji || ji == (gpointer)-1)
                        return;
 
-               if (func (domain, &new_ctx, ji, user_data))
+               if (func (domain, use_new_ctx ? &new_ctx : &ctx, ji, user_data))
                        return;
 
                ctx = new_ctx;
@@ -1169,6 +1176,7 @@ mono_handle_exception_internal (MonoContext *ctx, gpointer obj, gpointer origina
        gboolean has_dynamic_methods = FALSE;
        gint32 filter_idx, first_filter_idx;
 
+
        g_assert (ctx != NULL);
        if (!obj) {
                MonoException *ex = mono_get_exception_null_reference ();
@@ -1383,6 +1391,41 @@ mono_handle_exception_internal (MonoContext *ctx, gpointer obj, gpointer origina
 
                                                                return TRUE;
                                                        }
+                                                       /*
+                                                        * This guards against the situation that we abort a thread that is executing a finally clause
+                                                        * that was called by the EH machinery. It won't have a guard trampoline installed, so we must
+                                                        * check for this situation here and resume interruption if we are below the guarded block.
+                                                        */
+                                                       if (G_UNLIKELY (jit_tls->handler_block_return_address)) {
+                                                               gboolean is_outside = FALSE;
+                                                               gpointer prot_bp = MONO_CONTEXT_GET_BP (&jit_tls->ex_ctx);
+                                                               gpointer catch_bp = MONO_CONTEXT_GET_BP (ctx);
+                                                               //FIXME make this stack direction aware
+                                                               if (catch_bp > prot_bp) {
+                                                                       is_outside = TRUE;
+                                                               } else if (catch_bp == prot_bp) {
+                                                                       /* Can be either try { try { } catch {} } finally {} or try { try { } finally {} } catch {}
+                                                                        * So we check if the catch handler_start is protected by the guarded handler protected region
+                                                                        *
+                                                                        * Assumptions:
+                                                                        *      If there is an outstanding guarded_block return address, it means the current thread must be aborted.
+                                                                        *      This is the only way to reach out the guarded block as other cases are handled by the trampoline.
+                                                                        *      There aren't any further finally/fault handler blocks down the stack over this exception.
+                                                                        *   This must be ensured by the code that installs the guard trampoline.
+                                                                        */
+                                                                       g_assert (ji == mini_jit_info_table_find (domain, MONO_CONTEXT_GET_IP (&jit_tls->ex_ctx), NULL));
+
+                                                                       if (!is_address_protected (ji, jit_tls->handler_block, ei->handler_start)) {
+                                                                               is_outside = TRUE;
+                                                                       }
+                                                               }
+                                                               if (is_outside) {
+                                                                       jit_tls->handler_block_return_address = NULL;
+                                                                       jit_tls->handler_block = NULL;
+                                                                       mono_thread_resume_interruption (); /*We ignore the exception here, it will be raised later*/
+                                                               }
+                                                       }
+
                                                        if (mono_trace_is_enabled () && mono_trace_eval (ji->method))
                                                                g_print ("EXCEPTION: catch found at clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
                                                        mono_profiler_exception_clause_handler (ji->method, ei->flags, i);
@@ -2028,3 +2071,111 @@ mono_resume_unwind (void)
 
        restore_context (&ctx);
 }
+
+#ifdef MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD
+
+typedef struct {
+       MonoJitInfo *ji;
+       MonoContext ctx;
+       MonoJitExceptionInfo *ei;
+} FindHandlerBlockData;
+
+static gboolean
+find_last_handler_block (MonoDomain *domain, MonoContext *ctx, MonoJitInfo *ji, gpointer data)
+{
+       int i;
+       gpointer ip;
+       FindHandlerBlockData *pdata = data;
+
+       if (ji->method->wrapper_type)
+               return FALSE;
+
+       ip = MONO_CONTEXT_GET_IP (ctx);
+
+       for (i = 0; i < ji->num_clauses; ++i) {
+               MonoJitExceptionInfo *ei = ji->clauses + i;
+               if (ei->flags != MONO_EXCEPTION_CLAUSE_FINALLY)
+                       continue;
+               /*If ip points to the first instruction it means the handler block didn't start
+                so we can leave its execution to the EH machinery*/
+               if (ei->handler_start < ip && ip < ei->data.handler_end) {
+                       pdata->ji = ji;
+                       pdata->ei = ei;
+                       pdata->ctx = *ctx;
+                       break;
+               }
+       }
+       return FALSE;
+}
+
+
+static gpointer
+install_handler_block_guard (MonoJitInfo *ji, MonoContext *ctx)
+{
+       int i;
+       MonoJitExceptionInfo *clause = NULL;
+       gpointer ip;
+
+       ip = MONO_CONTEXT_GET_IP (ctx);
+
+       for (i = 0; i < ji->num_clauses; ++i) {
+               clause = &ji->clauses [i];
+               if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY)
+                       continue;
+               if (clause->handler_start < ip && clause->data.handler_end > ip)
+                       break;
+       }
+
+       /*no matching finally */
+       if (i == ji->num_clauses)
+               return NULL;
+
+       /*If we stopped on the instruction right before the try, we haven't actually started executing it*/
+       if (ip == clause->handler_start)
+               return NULL;
+
+       return mono_arch_install_handler_block_guard (ji, clause, ctx, mono_create_handler_block_trampoline ());
+}
+
+/*
+ * Finds the bottom handler block running and install a block guard if needed.
+ */
+gboolean
+mono_install_handler_block_guard (MonoInternalThread *thread, MonoContext *ctx)
+{
+       FindHandlerBlockData data = { 0 };
+       MonoDomain *domain = mono_domain_get ();
+       MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
+       gpointer resume_ip;
+
+       if (jit_tls->handler_block_return_address)
+               return FALSE;
+
+       mono_walk_stack_full (domain, jit_tls, ctx, find_last_handler_block, FALSE, &data);
+
+       if (!data.ji)
+               return FALSE;
+
+       memcpy (&jit_tls->ex_ctx, &data.ctx, sizeof (MonoContext));
+
+       resume_ip = install_handler_block_guard (data.ji, &data.ctx);
+       if (resume_ip == NULL)
+               return FALSE;
+
+       jit_tls->handler_block_return_address = resume_ip;
+       jit_tls->handler_block = data.ei;
+       /*Clear current thread from been wapi interrupted otherwise things can go south*/
+       wapi_clear_interruption ();
+
+       return TRUE;
+}
+
+#else
+gboolean
+mono_install_handler_block_guard (MonoInternalThread *thread, MonoContext *ctx)
+{
+       return FALSE;
+}
+
+#endif
+
index 1f04411200e77bde06b024e8ae1004a8184c455e..ddd3251c3c5fae6f20728f3dbf8f19b285004098 100644 (file)
@@ -159,6 +159,7 @@ SIG_HANDLER_SIGNATURE (sigabrt_signal_handler)
 static void
 SIG_HANDLER_SIGNATURE (sigusr1_signal_handler)
 {
+       MonoContext mctx;
        gboolean running_managed;
        MonoException *exc;
        MonoInternalThread *thread = mono_thread_internal_current ();
@@ -195,7 +196,19 @@ SIG_HANDLER_SIGNATURE (sigusr1_signal_handler)
        } else {
                running_managed = FALSE;
        }
-       
+
+       /* We can't do handler block checking from metadata since it requires doing
+        * a stack walk with context.
+        *
+        * FIXME add full-aot support.
+        */
+       if (!mono_aot_only) {
+               mono_arch_sigctx_to_monoctx (ctx, &mctx);
+               if (mono_install_handler_block_guard (thread, &mctx)) {
+                       return;
+               }
+       }
+
        exc = mono_thread_request_interruption (running_managed); 
        if (!exc)
                return;
index 6dcfbdb9245b65bd30049485046bf192e640d612..d4d973bcafc00d9207cc92423f638f6359d720ba 100644 (file)
@@ -966,6 +966,58 @@ mono_delegate_trampoline (mgreg_t *regs, guint8 *code, gpointer *tramp_data, gui
 
 #endif
 
+static gpointer
+mono_handler_block_guard_trampoline (mgreg_t *regs, guint8 *code, gpointer *tramp_data, guint8* tramp)
+{
+       MonoContext ctx;
+       MonoException *exc;
+       MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
+       gpointer resume_ip = jit_tls->handler_block_return_address;
+
+       memcpy (&ctx, &jit_tls->ex_ctx, sizeof (MonoContext));
+       MONO_CONTEXT_SET_IP (&ctx, jit_tls->handler_block_return_address);
+
+       jit_tls->handler_block_return_address = NULL;
+       jit_tls->handler_block = NULL;
+
+       if (!resume_ip) /*this should not happen, but we should avoid crashing */
+               exc = mono_get_exception_execution_engine ("Invalid internal state, resuming abort after handler block but no resume ip found");
+       else
+               exc = mono_thread_resume_interruption ();
+
+       if (exc) {
+               static void (*restore_context) (MonoContext *);
+
+               if (!restore_context)
+                       restore_context = mono_get_restore_context ();
+
+               mono_handle_exception (&ctx, exc, NULL, FALSE);
+               restore_context (&ctx);
+       }
+
+       return resume_ip;
+}
+
+gpointer
+mono_create_handler_block_trampoline (void)
+{
+       static gpointer code;
+
+       if (mono_aot_only) {
+               g_assert (0);
+               return code;
+       }
+
+       mono_trampolines_lock ();
+
+       if (!code)
+               code = mono_arch_create_handler_block_trampoline ();
+
+       mono_trampolines_unlock ();
+
+       return code;
+}
+
 /*
  * mono_get_trampoline_func:
  *
@@ -1006,6 +1058,10 @@ mono_get_trampoline_func (MonoTrampolineType tramp_type)
 #ifdef MONO_ARCH_LLVM_SUPPORTED
        case MONO_TRAMPOLINE_LLVM_VCALL:
                return mono_llvm_vcall_trampoline;
+#endif
+#ifdef MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD
+       case MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD:
+               return mono_handler_block_guard_trampoline;
 #endif
        default:
                g_assert_not_reached ();
@@ -1040,6 +1096,10 @@ mono_trampolines_init (void)
 #ifdef MONO_ARCH_LLVM_SUPPORTED
        mono_trampoline_code [MONO_TRAMPOLINE_LLVM_VCALL] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_LLVM_VCALL);
 #endif
+#ifdef MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD
+       mono_trampoline_code [MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD);
+       mono_create_handler_block_trampoline ();
+#endif
 
        mono_counters_register ("Calls to trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &trampoline_calls);
 }
index e818084c2afae6fcf99627e73d5cfe66d8056e5e..19115016538ced801ab764722e7cff5fe385ab4f 100644 (file)
@@ -5809,6 +5809,50 @@ mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *long_ins)
 #endif /* MONO_ARCH_SIMD_INTRINSICS */
 }
 
+/*MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD*/
+gpointer
+mono_arch_install_handler_block_guard (MonoJitInfo *ji, MonoJitExceptionInfo *clause, MonoContext *ctx, gpointer new_value)
+{
+       int offset;
+       gpointer *sp, old_value;
+       char *bp;
+       const unsigned char *handler;
+
+       /*Decode the first instruction to figure out where did we store the spvar*/
+       /*Our jit MUST generate the following:
+        mov %esp, -?(%ebp)
+        Which is encoded as: 0x89 mod_rm.
+        mod_rm (esp, ebp, imm) which can be: (imm will never be zero)
+               mod (reg + imm8):  01 reg(esp): 100 rm(ebp): 101 -> 01100101 (0x65)
+               mod (reg + imm32): 10 reg(esp): 100 rm(ebp): 101 -> 10100101 (0xA5)
+       */
+       handler = clause->handler_start;
+
+       if (*handler != 0x89)
+               return NULL;
+
+       ++handler;
+
+       if (*handler == 0x65)
+               offset = *(signed char*)(handler + 1);
+       else if (*handler == 0xA5)
+               offset = *(int*)(handler + 1);
+       else
+               return NULL;
+
+       /*Load the spvar*/
+       bp = MONO_CONTEXT_GET_BP (ctx);
+       sp = *(gpointer*)(bp + offset);
+
+       old_value = *sp;
+       if (old_value < ji->code_start || (char*)old_value > ((char*)ji->code_start + ji->code_size))
+               return old_value;
+
+       *sp = new_value;
+
+       return old_value;
+}
+
 #if __APPLE__
 #define DBG_SIGNAL SIGBUS
 #else
index bc7e0dff1a753582babbdd9866ffed3b3accb87e..5af560c7e8a71940ab3c8d55e55eb25d496dcbb0 100644 (file)
@@ -278,6 +278,7 @@ typedef struct {
 #define MONO_ARCH_SOFT_DEBUG_SUPPORTED 1
 #define MONO_ARCH_HAVE_FIND_JIT_INFO_EXT 1
 #define MONO_ARCH_HAVE_EXCEPTIONS_INIT 1
+#define MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD 1
 
 /* Used for optimization, not complete */
 #define MONO_ARCH_IS_OP_MEMBASE(opcode) ((opcode) == OP_X86_PUSH_MEMBASE)
index 9c28c3f99a5743f869da6a14f319dc43fd78c38c..a7751a92375314e117d2fffb6409a6344511cbd5 100644 (file)
@@ -3555,6 +3555,18 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile)
                                        break;
                                }
                        }
+
+                       if (ec->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
+                               int end_offset;
+                               if (ec->handler_offset + ec->handler_len < header->code_size) {
+                                       tblock = cfg->cil_offset_to_bb [ec->handler_offset + ec->handler_len];
+                                       g_assert (tblock);
+                                       end_offset = tblock->native_offset;
+                               } else {
+                                       end_offset = cfg->epilog_begin;
+                               }
+                               ei->data.handler_end = cfg->native_code + end_offset;
+                       }
                }
 
                if (G_UNLIKELY (cfg->verbose_level >= 4)) {
index 6e010292706d8fa2d63c150527549496426c7478..dcf5a49335ad420b4b108a4075970eebcaa203c5 100644 (file)
@@ -817,10 +817,14 @@ typedef struct {
        /* Used to implement --debug=casts */
        MonoClass       *class_cast_from, *class_cast_to;
 
-       /* Stores state needed by mono_resume_unwind () */
+       /* Stores state needed by mono_resume_unwind () and the handler block with a guard */
        MonoContext     ex_ctx;
        /* FIXME: GC */
        gpointer        ex_obj;
+       /* handle block return address */
+       gpointer handler_block_return_address;
+       /* handler block been guarded */
+       MonoJitExceptionInfo *handler_block;
 } MonoJitTlsData;
 
 typedef enum {
@@ -910,6 +914,9 @@ typedef enum {
        MONO_TRAMPOLINE_MONITOR_EXIT,
 #ifdef MONO_ARCH_LLVM_SUPPORTED
        MONO_TRAMPOLINE_LLVM_VCALL,
+#endif
+#ifdef MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD
+       MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD,
 #endif
        MONO_TRAMPOLINE_NUM
 } MonoTrampolineType;
@@ -1801,6 +1808,12 @@ MonoVTable* mono_arch_find_static_call_vtable   (mgreg_t *regs, guint8 *code) MO
 gpointer    mono_arch_build_imt_thunk           (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count, gpointer fail_tramp) MONO_INTERNAL;
 void    mono_arch_notify_pending_exc            (void) MONO_INTERNAL;
 
+/* Handle block guard */
+gpointer mono_arch_install_handler_block_guard (MonoJitInfo *ji, MonoJitExceptionInfo *clause, MonoContext *ctx, gpointer new_value) MONO_INTERNAL;
+gpointer mono_arch_create_handler_block_trampoline (void) MONO_INTERNAL;
+gpointer mono_create_handler_block_trampoline (void) MONO_INTERNAL;
+gboolean mono_install_handler_block_guard (MonoInternalThread *thread, MonoContext *ctx) MONO_INTERNAL;
+
 /* Exception handling */
 
 /* Same as MonoStackWalk, but pass the context/frame type as well */
index 5373ab46a733fe1af530617870ecbd42d7f01fed..3a9095e59271132daf01d8816b77af5ca76bf2b0 100644 (file)
@@ -832,3 +832,41 @@ mono_arch_invalidate_method (MonoJitInfo *ji, void *func, gpointer func_arg)
        x86_push_imm (code, func_arg);
        x86_call_code (code, (guint8*)func);
 }
+
+static void
+handler_block_trampoline_helper (gpointer *ptr)
+{
+       MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
+       *ptr = jit_tls->handler_block_return_address;
+}
+
+gpointer
+mono_arch_create_handler_block_trampoline (void)
+{
+       guint8 *tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD);
+       guint8 *code, *buf;
+       int tramp_size = 64;
+       code = buf = mono_global_codeman_reserve (tramp_size);
+
+       /*
+       This trampoline restore the call chain of the handler block then jumps into the code that deals with it.
+       */
+
+       if (mono_get_jit_tls_offset () != -1) {
+               code = mono_x86_emit_tls_get (code, X86_EAX, mono_get_jit_tls_offset ());
+               x86_mov_reg_membase (code, X86_EAX, X86_EAX, G_STRUCT_OFFSET (MonoJitTlsData, handler_block_return_address), 4);
+               /*simulate a call*/
+               x86_push_reg (code, X86_EAX);
+               x86_jump_code (code, tramp);
+       } else {
+               /*Slow path uses a c helper*/
+               x86_push_reg (code, X86_ESP);
+               x86_push_imm (code, tramp);
+               x86_jump_code (code, handler_block_trampoline_helper);
+       }
+
+       mono_arch_flush_icache (buf, code - buf);
+       g_assert (code - buf <= tramp_size);
+
+       return buf;
+}