diff --git a/src/code/ia32.c b/src/code/ia32.c
index 3493d17874306e7e1c05ef72c1eccfa9e8b60f57..0e7e095e8a4c94e7630fe0324ef45b3251efb93c 100644
--- a/src/code/ia32.c
+++ b/src/code/ia32.c
@@ -390,6 +390,36 @@ static int alloc_regs = 0, valid_regs = 0;
     ((INT32)(X)) - (INT32)(p_->program + p_->num_program);              \
 }while(0)
 
+#ifdef INS_ENTRY
+void ia32_ins_entry(void)
+{
+#ifdef REGISTER_DEBUG
+  /* All registers are valid here... */
+  valid_regs = 0xff;
+#endif
+  /* Push all registers that the ABI requires to be preserved.
+   *
+   * cf Sys V ABI Intel386 Architecture Supplement 4th ed 3-11:
+   *   "Registers %ebp, %ebx, %edi, %esi, and %esp ``belong'' to the cal-
+   *    ling function."
+   *
+   * also cf Fig 3-16.
+   */
+  PUSH_REG(REG_EBP);
+  MOV_REG_TO_REG(REG_ESP, REG_EBP);
+  /* FIXME: Add local storage here if needed. */
+  PUSH_REG(REG_EDI);
+  PUSH_REG(REG_ESI);
+  PUSH_REG(REG_EBX);
+  /* Funcall arguments (4 * 4 bytes). */
+  ADD_VAL_TO_REG(-0x10, REG_ESP);
+
+#ifdef REGISTER_DEBUG
+  valid_regs = 0;
+#endif
+}
+#endif
+
 static void update_arg1(INT32 value)
 {
   MOV_VAL_TO_RELSTACK (value, 0);
@@ -793,6 +823,7 @@ static void ins_debug_instr_prologue (PIKE_INSTR_T instr, INT32 arg1, INT32 arg2
 void ins_f_byte(unsigned int b)
 {
   void *addr;
+  INT32 rel_addr = 0;
 
   b-=F_OFFSET;
 #ifdef PIKE_DEBUG
@@ -859,16 +890,84 @@ void ins_f_byte(unsigned int b)
 	addr = (void *)f_get_iterator;
       }
       break;
+
+#ifdef OPCODE_INLINE_RETURN
+  case F_CATCH - F_OFFSET:
+    {
+      /* Special argument for the F_CATCH instruction. */
+      addr = inter_return_opcode_F_CATCH;
+      /* FIXME: Is there really no easier way to get at EIP? */
+      add_to_program(0xe8);
+      PUSH_INT(0);
+      POP_REG(REG_EAX);	/* EIP ==> EAX */
+      ADD_VAL_TO_REG(0x7fffffff, REG_EAX);
+      rel_addr = PIKE_PC;
+      MOV_REG_TO_RELSTACK(REG_EAX, 0);
+    }
+    break;
+#endif
   }
 #endif /* !DEBUG_MALLOC */
 
   ia32_call_c_function(addr);
 
+#ifdef INS_ENTRY
+  if (instrs[b].flags & I_RETURN) {
+    INT32 skip;
+#ifdef REGISTER_DEBUG
+    INT32 orig_valid_regs = valid_regs;
+    valid_regs = 0xff;
+#endif
+    if ((b + F_OFFSET) == F_RETURN_IF_TRUE) {
+      /* Kludge. We must check if the ret addr is
+       * orig_addr + JUMP_EPILOGUE_SIZE. */
+      /* There's no easy way to get at EIP directly,
+       * so we assume that the function we called
+       * above exited with a RET, in which case EIP
+       * is at ESP[-4]...
+       */
+      MOV_RELSTACK_TO_REG(-4, REG_ESI);
+      ADD_VAL_TO_REG(JUMP_EPILOGUE_SIZE, REG_ESI);
+    }
+    CMP_REG_IMM32(REG_EAX, -1);
+    JNE(0);
+    skip = (INT32)PIKE_PC;
+    ADD_VAL_TO_REG(0x10, REG_ESP);	/* Funcall arguments (4 * 4 bytes). */
+    POP_REG(REG_EBX);
+    POP_REG(REG_ESI);
+    POP_REG(REG_EDI);
+    POP_REG(REG_EBP);
+    RET();
+    Pike_compiler->new_program->program[skip-1] = ((INT32)PIKE_PC) - skip;
+    if ((b + F_OFFSET) == F_RETURN_IF_TRUE) {
+      /* Kludge. We must check if the ret addr is
+       * orig_addr + JUMP_EPILOGUE_SIZE. */
+      CMP_REG_REG(REG_EAX, REG_ESI);
+      JE(0x02);
+      add_to_program (0xff);	/* jmp *%eax */
+      add_to_program (0xe0);
+#ifdef REGISTER_DEBUG
+      valid_regs = orig_valid_regs;
+#endif
+      return;
+    }
+#ifdef REGISTER_DEBUG
+    valid_regs = orig_valid_regs;
+#endif
+  }
+#endif
+
 #ifdef OPCODE_RETURN_JUMPADDR
   if (instrs[b].flags & I_JUMP) {
     /* This is the code that JUMP_EPILOGUE_SIZE compensates for. */
     add_to_program (0xff);	/* jmp *%eax */
     add_to_program (0xe0);
+
+#ifdef OPCODE_INLINE_RETURN
+    if (b + F_OFFSET == F_CATCH) {
+      upd_pointer(rel_addr - 4, PIKE_PC + 6 - rel_addr);
+    }
+#endif
   }
 #endif
 }
@@ -1204,4 +1303,8 @@ void ia32_init_interpreter_state(void)
       ia32_clflush_size = cpu_info.clflush_size * 8;
     }
   }
+
+#ifdef OPCODE_INLINE_RETURN
+  instrs[F_CATCH - F_OFFSET].address = inter_return_opcode_F_CATCH;
+#endif
 }
diff --git a/src/code/ia32.h b/src/code/ia32.h
index 6887c1084e1ee9fb3628f3a44f0593110a7a3ae1..25f1944853aa797530690cafcf8f603dd36ed01e 100644
--- a/src/code/ia32.h
+++ b/src/code/ia32.h
@@ -23,6 +23,12 @@
 
 #else  /* GCC_IA32_ASM_STYLE */
 
+#define OPCODE_INLINE_RETURN
+void ia32_ins_entry(void);
+#define INS_ENTRY()	ia32_ins_entry()
+/* Size of the prologue added by INS_ENTRY() (in PIKE_OPCODE_T's). */
+#define ENTRY_PROLOGUE_SIZE	0x09
+
 #ifdef OPCODE_RETURN_JUMPADDR
 /* Don't need an lvalue in this case. */
 #define PROG_COUNTER ((unsigned char *)__builtin_return_address(0))
@@ -133,6 +139,19 @@ void ia32_flush_instruction_cache(void *addr, size_t len);
 void ia32_init_interpreter_state(void);
 #define INIT_INTERPRETER_STATE	ia32_init_interpreter_state
 
+#ifdef INS_ENTRY
+
+#define CALL_MACHINE_CODE(pc)                                           \
+  do {                                                                  \
+    /* The test is needed to get the labels to work... */               \
+    if (pc) {                                                           \
+      ((int (*)(void))(pc)) ();						\
+      goto inter_return_label;                                          \
+    }                                                                   \
+  } while(0)
+
+#else /* !INS_ENTRY */
+
 #ifdef CL_IA32_ASM_STYLE
 
 #define CALL_MACHINE_CODE(pc)                                   \
@@ -160,4 +179,6 @@ void ia32_init_interpreter_state(void);
 #define EXIT_MACHINE_CODE()						\
   __asm__ __volatile__( "add $16,%%esp\n" : : )
 
+#endif /* INS_ENTRY */
+
 #endif /* GCC_IA32_ASM_STYLE */