Merge pull request #1603 from iainx/coverage-null-protect
[mono.git] / mono / mini / mini.c
index 604a4142aa8257a8d982c0848274a522fb6a21a1..ca734ad3e2252313216a5d557c906d99b2bd4c7a 100755 (executable)
@@ -12,7 +12,6 @@
 
 #define MONO_LLVM_IN_MINI 1
 #include <config.h>
-#include <signal.h>
 #ifdef HAVE_ALLOCA_H
 #include <alloca.h>
 #endif
@@ -23,6 +22,9 @@
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
 #endif
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
 
 #include <mono/utils/memcheck.h>
 
@@ -53,6 +55,7 @@
 #include <mono/utils/mono-math.h>
 #include <mono/utils/mono-compiler.h>
 #include <mono/utils/mono-counters.h>
+#include <mono/utils/mono-error-internals.h>
 #include <mono/utils/mono-logger-internal.h>
 #include <mono/utils/mono-mmap.h>
 #include <mono/utils/mono-path.h>
@@ -138,9 +141,6 @@ mono_breakpoint_info_index [MONO_BREAKPOINT_ARRAY_SIZE];
 /* Whenever to check for pending exceptions in managed-to-native wrappers */
 gboolean check_for_pending_exc = TRUE;
 
-/* Whenever to disable passing/returning small valuetypes in registers for managed methods */
-gboolean disable_vtypes_in_regs = FALSE;
-
 static GSList *tramp_infos;
 
 static void register_icalls (void);
@@ -712,10 +712,11 @@ G_GNUC_UNUSED gboolean
 mono_debug_count (void)
 {
        static int count = 0;
-       count ++;
        static gboolean inited;
        static const char *value;
 
+       count ++;
+
        if (!inited) {
                value = g_getenv ("COUNT");
                inited = TRUE;
@@ -1379,6 +1380,20 @@ mono_compile_make_var_load (MonoCompile *cfg, MonoInst *dest, gssize var_index)
        dest->klass = dest->inst_i0->klass;
 }
 
+MonoInst*
+mini_get_int_to_float_spill_area (MonoCompile *cfg)
+{
+#ifdef TARGET_X86
+       if (!cfg->iconv_raw_var) {
+               cfg->iconv_raw_var = mono_compile_create_var (cfg, &mono_defaults.int32_class->byval_arg, OP_LOCAL);
+               cfg->iconv_raw_var->flags |= MONO_INST_VOLATILE; /*FIXME, use the don't regalloc flag*/
+       }
+       return cfg->iconv_raw_var;
+#else
+       return NULL;
+#endif
+}
+
 #endif
 
 void
@@ -1492,7 +1507,7 @@ mono_add_ins_to_end (MonoBasicBlock *bb, MonoInst *inst)
                                /* Only two instructions */
                                opcode = bb->code->opcode;
 
-                               if ((opcode == OP_COMPARE) || (opcode == OP_COMPARE_IMM) || (opcode == OP_ICOMPARE) || (opcode == OP_ICOMPARE_IMM) || (opcode == OP_FCOMPARE) || (opcode == OP_LCOMPARE) || (opcode == OP_LCOMPARE_IMM)) {
+                               if ((opcode == OP_COMPARE) || (opcode == OP_COMPARE_IMM) || (opcode == OP_ICOMPARE) || (opcode == OP_ICOMPARE_IMM) || (opcode == OP_FCOMPARE) || (opcode == OP_LCOMPARE) || (opcode == OP_LCOMPARE_IMM) || (opcode == OP_RCOMPARE)) {
                                        /* NEW IR */
                                        mono_bblock_insert_before_ins (bb, bb->code, inst);
                                } else {
@@ -1501,7 +1516,7 @@ mono_add_ins_to_end (MonoBasicBlock *bb, MonoInst *inst)
                        } else {
                                opcode = bb->last_ins->prev->opcode;
 
-                               if ((opcode == OP_COMPARE) || (opcode == OP_COMPARE_IMM) || (opcode == OP_ICOMPARE) || (opcode == OP_ICOMPARE_IMM) || (opcode == OP_FCOMPARE) || (opcode == OP_LCOMPARE) || (opcode == OP_LCOMPARE_IMM)) {
+                               if ((opcode == OP_COMPARE) || (opcode == OP_COMPARE_IMM) || (opcode == OP_ICOMPARE) || (opcode == OP_ICOMPARE_IMM) || (opcode == OP_FCOMPARE) || (opcode == OP_LCOMPARE) || (opcode == OP_LCOMPARE_IMM) || (opcode == OP_RCOMPARE)) {
                                        /* NEW IR */
                                        mono_bblock_insert_before_ins (bb, bb->last_ins->prev, inst);
                                } else {
@@ -1705,6 +1720,7 @@ mono_icall_get_wrapper_full (MonoJitICallInfo* callinfo, gboolean do_compile)
        MonoMethod *wrapper;
        gconstpointer trampoline;
        MonoDomain *domain = mono_get_root_domain ();
+       gboolean check_exc = check_for_pending_exc;
        
        if (callinfo->wrapper) {
                return callinfo->wrapper;
@@ -1726,8 +1742,12 @@ mono_icall_get_wrapper_full (MonoJitICallInfo* callinfo, gboolean do_compile)
                return callinfo->trampoline;
        }
 
+       if (!strcmp (callinfo->name, "mono_thread_interruption_checkpoint"))
+               /* This icall is used to check for exceptions, so don't check in the wrapper */
+               check_exc = FALSE;
+
        name = g_strdup_printf ("__icall_wrapper_%s", callinfo->name);
-       wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func, check_for_pending_exc);
+       wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func, check_exc);
        g_free (name);
 
        if (do_compile)
@@ -2397,7 +2417,8 @@ register_opcode_emulation (int opcode, const char *name, const char *sigstr, gpo
        g_assert (!sig->hasthis);
        g_assert (sig->param_count < 3);
 
-       info = mono_register_jit_icall_full (func, name, sig, no_throw, symbol);
+       /* Opcode emulation functions are assumed to don't call mono_raise_exception () */
+       info = mono_register_jit_icall_full (func, name, sig, no_throw, TRUE, symbol);
 
        if (emul_opcode_num >= emul_opcode_alloced) {
                int incr = emul_opcode_alloced? emul_opcode_alloced/2: 16;
@@ -2427,7 +2448,21 @@ register_icall (gpointer func, const char *name, const char *sigstr, gboolean sa
        else
                sig = NULL;
 
-       mono_register_jit_icall_full (func, name, sig, save, save ? name : NULL);
+       mono_register_jit_icall_full (func, name, sig, save, FALSE, save ? name : NULL);
+}
+
+/* Register a jit icall which doesn't throw exceptions through mono_raise_exception () */
+static void
+register_icall_noraise (gpointer func, const char *name, const char *sigstr)
+{
+       MonoMethodSignature *sig;
+
+       if (sigstr)
+               sig = mono_create_icall_signature (sigstr);
+       else
+               sig = NULL;
+
+       mono_register_jit_icall_full (func, name, sig, TRUE, TRUE, name);
 }
 
 static void
@@ -3245,6 +3280,7 @@ mono_patch_info_hash (gconstpointer data)
        case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR:
        case MONO_PATCH_INFO_JIT_TLS_ID:
        case MONO_PATCH_INFO_MONITOR_ENTER:
+       case MONO_PATCH_INFO_MONITOR_ENTER_V4:
        case MONO_PATCH_INFO_MONITOR_EXIT:
        case MONO_PATCH_INFO_GOT_OFFSET:
                return (ji->type << 8);
@@ -3259,6 +3295,8 @@ mono_patch_info_hash (gconstpointer data)
                return g_str_hash (ji->data.target);
        case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
                return (ji->type << 8) | (gsize)ji->data.del_tramp->klass | (gsize)ji->data.del_tramp->method | (gsize)ji->data.del_tramp->virtual;
+       case MONO_PATCH_INFO_LDSTR_LIT:
+               return g_str_hash (ji->data.target);
        default:
                printf ("info type: %d\n", ji->type);
                mono_print_ji (ji); printf ("\n");
@@ -3541,9 +3579,12 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
        case MONO_PATCH_INFO_TYPE_FROM_HANDLE: {
                gpointer handle;
                MonoClass *handle_class;
+               MonoError error;
 
-               handle = mono_ldtoken (patch_info->data.token->image, 
-                                                          patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL);
+               handle = mono_ldtoken_checked (patch_info->data.token->image, 
+                                                          patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, &error);
+               if (!mono_error_ok (&error))
+                       g_error ("Could not patch ldtoken due to %s", mono_error_get_message (&error));
                mono_class_init (handle_class);
                mono_class_init (mono_class_from_mono_type (handle));
 
@@ -3554,9 +3595,12 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
        case MONO_PATCH_INFO_LDTOKEN: {
                gpointer handle;
                MonoClass *handle_class;
+               MonoError error;
                
-               handle = mono_ldtoken (patch_info->data.token->image,
-                                                          patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL);
+               handle = mono_ldtoken_checked (patch_info->data.token->image,
+                                                          patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, &error);
+               if (!mono_error_ok (&error))
+                       g_error ("Could not patch ldtoken due to %s", mono_error_get_message (&error));
                mono_class_init (handle_class);
                
                target = handle;
@@ -3661,6 +3705,9 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
        case MONO_PATCH_INFO_MONITOR_ENTER:
                target = mono_create_monitor_enter_trampoline ();
                break;
+       case MONO_PATCH_INFO_MONITOR_ENTER_V4:
+               target = mono_create_monitor_enter_v4_trampoline ();
+               break;
        case MONO_PATCH_INFO_MONITOR_EXIT:
                target = mono_create_monitor_exit_trampoline ();
                break;
@@ -3710,6 +3757,10 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
                target = NULL;
                break;
        }
+       case MONO_PATCH_INFO_LDSTR_LIT: {
+               target = mono_string_new (domain, patch_info->data.target);
+               break;
+       }
        default:
                g_assert_not_reached ();
        }
@@ -3963,6 +4014,9 @@ mono_codegen (MonoCompile *cfg)
 
                if (cfg->opt & MONO_OPT_PEEPHOLE)
                        mono_arch_peephole_pass_2 (cfg, bb);
+
+               if (cfg->gen_seq_points && !cfg->gen_seq_points_debug_data)
+                       bb_deduplicate_op_il_seq_points (cfg, bb);
        }
 
        if (cfg->prof_options & MONO_PROFILE_COVERAGE)
@@ -3972,6 +4026,8 @@ mono_codegen (MonoCompile *cfg)
 
        cfg->code_len = code - cfg->native_code;
        cfg->prolog_end = cfg->code_len;
+       cfg->cfa_reg = cfg->cur_cfa_reg;
+       cfg->cfa_offset = cfg->cur_cfa_offset;
 
        mono_debug_open_method (cfg);
 
@@ -3986,6 +4042,7 @@ mono_codegen (MonoCompile *cfg)
                if (bb == cfg->bb_exit) {
                        cfg->epilog_begin = cfg->code_len;
                        mono_arch_emit_epilog (cfg);
+                       cfg->epilog_end = cfg->code_len;
                }
        }
 
@@ -4494,7 +4551,7 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile)
 
                        info = mono_jit_info_get_arch_eh_info (jinfo);
                        g_assert (info);
-                       info->epilog_size = cfg->code_size - cfg->epilog_begin;
+                       info->epilog_size = cfg->code_len - cfg->epilog_begin;
                }
                jinfo->unwind_info = unwind_desc;
                g_free (unwind_info);
@@ -4532,7 +4589,7 @@ get_gsharedvt_type (MonoType *t)
                copy = mono_image_alloc0 (image, sizeof (MonoGenericParamFull));
                memcpy (copy, par, sizeof (MonoGenericParamFull));
        } else {
-               copy = g_memdup (par, sizeof (MonoGenericParamFull));
+               copy = g_memdup (par, sizeof (MonoGenericParam));
        }
        copy->owner = NULL;
        // FIXME:
@@ -4634,6 +4691,7 @@ get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGeneri
 MonoMethod*
 mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gsharedvt)
 {
+       MonoError error;
        MonoGenericContext shared_context;
        MonoMethod *declaring_method, *res;
        gboolean partial = FALSE;
@@ -4685,7 +4743,9 @@ mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gs
                partial = TRUE;
        }
 
-    res = mono_class_inflate_generic_method (declaring_method, &shared_context);
+    res = mono_class_inflate_generic_method_checked (declaring_method, &shared_context, &error);
+       g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
+
        if (!partial) {
                /* The result should be an inflated method whose parent is not inflated */
                g_assert (!res->klass->is_inflated);
@@ -4845,7 +4905,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl
        cfg->full_aot = full_aot;
        cfg->skip_visibility = method->skip_visibility;
        cfg->orig_method = method;
-       cfg->gen_seq_points = TRUE;
+       cfg->gen_seq_points = debug_options.gen_seq_points_compact_data || debug_options.gen_seq_points_debug_data;
        cfg->gen_seq_points_debug_data = debug_options.gen_seq_points_debug_data;
 
        cfg->explicit_null_checks = debug_options.explicit_null_checks;
@@ -4856,8 +4916,14 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl
        cfg->compile_llvm = try_llvm;
        cfg->token_info_hash = g_hash_table_new (NULL, NULL);
 
+       if (!mono_debug_count ())
+               cfg->opt &= ~MONO_OPT_FLOAT32;
+       cfg->r4fp = (cfg->opt & MONO_OPT_FLOAT32) ? 1 : 0;
+       cfg->r4_stack_type = cfg->r4fp ? STACK_R4 : STACK_R8;
+
        if (cfg->gen_seq_points)
                cfg->seq_points = g_ptr_array_new ();
+       mono_error_init (&cfg->error);
 
        if (cfg->compile_aot && !try_generic_shared && (method->is_generic || method->klass->generic_container || method_is_gshared)) {
                cfg->exception_type = MONO_EXCEPTION_GENERIC_SHARING_FAILED;
@@ -5279,7 +5345,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl
        */
 
 //#define DEBUGSSA "logic_run"
-#define DEBUGSSA_CLASS "Tests"
+//#define DEBUGSSA_CLASS "Tests"
 #ifdef DEBUGSSA
 
        if (!cfg->disable_ssa) {
@@ -5948,6 +6014,10 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
        case MONO_EXCEPTION_OUT_OF_MEMORY:
                ex = mono_domain_get ()->out_of_memory_ex;
                break;
+       case MONO_EXCEPTION_MONO_ERROR:
+               g_assert (!mono_error_ok (&cfg->error));
+               ex = mono_error_convert_to_exception (&cfg->error);
+               break;
        default:
                g_assert_not_reached ();
        }
@@ -6119,8 +6189,11 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException
                        if (method->is_inflated)
                                ctx = mono_method_get_context (method);
                        method = info->d.synchronized_inner.method;
-                       if (ctx)
-                               method = mono_class_inflate_generic_method (method, ctx);
+                       if (ctx) {
+                               MonoError error;
+                               method = mono_class_inflate_generic_method_checked (method, ctx, &error);
+                               g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
+                       }
                }
        }
 
@@ -6542,8 +6615,8 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
                gpointer *args;
                static RuntimeInvokeDynamicFunction dyn_runtime_invoke;
                int i, pindex;
-               guint8 buf [128];
-               guint8 retval [128];
+               guint8 buf [256];
+               guint8 retval [256];
 
                if (!dyn_runtime_invoke) {
                        invoke = mono_marshal_get_runtime_invoke_dynamic ();
@@ -6589,7 +6662,7 @@ MONO_SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler)
 {
        MonoException *exc = NULL;
        MonoJitInfo *ji;
-       void *info = MONO_SIG_HANDLER_GET_INFO ();
+       MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
        MONO_SIG_HANDLER_GET_CONTEXT;
 
        ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context (ctx));
@@ -6611,7 +6684,7 @@ MONO_SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler)
                if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
                        return;
 
-               mono_handle_native_sigsegv (SIGSEGV, ctx);
+               mono_handle_native_sigsegv (SIGSEGV, ctx, info);
                if (mono_do_crash_chaining) {
                        mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
                        return;
@@ -6642,6 +6715,8 @@ MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
        gpointer fault_addr = NULL;
 #ifdef HAVE_SIG_INFO
        MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
+#else
+       void *info = NULL;
 #endif
        MONO_SIG_HANDLER_GET_CONTEXT;
 
@@ -6655,7 +6730,8 @@ MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
        }
 #endif
 
-#if !defined(HOST_WIN32) && defined(HAVE_SIG_INFO)
+#if defined(HAVE_SIG_INFO)
+#if !defined(HOST_WIN32)
        fault_addr = info->si_addr;
        if (mono_aot_is_pagefault (info->si_addr)) {
                mono_aot_handle_pagefault (info->si_addr);
@@ -6667,17 +6743,18 @@ MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
        if (!mono_domain_get () || !jit_tls) {
                if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
                        return;
-               mono_handle_native_sigsegv (SIGSEGV, ctx);
+               mono_handle_native_sigsegv (SIGSEGV, ctx, info);
                if (mono_do_crash_chaining) {
                        mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
                        return;
                }
        }
+#endif
 
        ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context (ctx));
 
 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
-       if (mono_handle_soft_stack_ovf (jit_tls, ji, ctx, (guint8*)info->si_addr))
+       if (mono_handle_soft_stack_ovf (jit_tls, ji, ctx, info, (guint8*)info->si_addr))
                return;
 
 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
@@ -6705,7 +6782,7 @@ MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
                if (!ji && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
                        return;
 
-               mono_arch_handle_altstack_exception (ctx, info->si_addr, FALSE);
+               mono_arch_handle_altstack_exception (ctx, info, info->si_addr, FALSE);
        }
 #else
 
@@ -6713,7 +6790,7 @@ MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
                if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
                        return;
 
-               mono_handle_native_sigsegv (SIGSEGV, ctx);
+               mono_handle_native_sigsegv (SIGSEGV, ctx, info);
 
                if (mono_do_crash_chaining) {
                        mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
@@ -6906,6 +6983,8 @@ mini_parse_debug_options (void)
                        debug_options.explicit_null_checks = TRUE;
                else if (!strcmp (arg, "gen-seq-points"))
                        debug_options.gen_seq_points_debug_data = TRUE;
+               else if (!strcmp (arg, "gen-compact-seq-points"))
+                       debug_options.gen_seq_points_compact_data = TRUE;
                else if (!strcmp (arg, "init-stacks"))
                        debug_options.init_stacks = TRUE;
                else if (!strcmp (arg, "casts"))
@@ -6935,10 +7014,9 @@ mini_get_debug_options (void)
 static gpointer
 mini_create_ftnptr (MonoDomain *domain, gpointer addr)
 {
-#if !defined(__ia64__) && !defined(__ppc64__) && !defined(__powerpc64__)
+#if !defined(__ia64__) && (!defined(__ppc64__) && !defined(__powerpc64__) || _CALL_ELF == 2)
        return addr;
 #else
-
        gpointer* desc = NULL;
 
        if ((desc = g_hash_table_lookup (domain->ftnptrs_hash, addr)))
@@ -6964,7 +7042,7 @@ mini_create_ftnptr (MonoDomain *domain, gpointer addr)
 static gpointer
 mini_get_addr_from_ftnptr (gpointer descr)
 {
-#if defined(__ia64__) || defined(__ppc64__) || defined(__powerpc64__)
+#if defined(__ia64__) || ((defined(__ppc64__) || defined(__powerpc64__)) && _CALL_ELF != 2)
        return *(gpointer*)descr;
 #else
        return descr;
@@ -7208,6 +7286,8 @@ mini_init (const char *filename, const char *runtime_version)
        ticallbacks.thread_state_init_from_sigctx = mono_thread_state_init_from_sigctx;
        ticallbacks.thread_state_init_from_handle = mono_thread_state_init_from_handle;
 
+       mono_counters_init ();
+
        mono_threads_runtime_init (&ticallbacks);
 
        if (g_getenv ("MONO_DEBUG") != NULL)
@@ -7413,7 +7493,8 @@ register_icalls (void)
        register_dyn_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE);
        register_dyn_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", "void ptr", TRUE);
        register_icall (mono_thread_get_undeniable_exception, "mono_thread_get_undeniable_exception", "object", FALSE);
-       register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", "void", FALSE);
+       register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", "object", FALSE);
+       register_icall (mono_thread_force_interruption_checkpoint_noraise, "mono_thread_force_interruption_checkpoint_noraise", "object", FALSE);
        register_icall (mono_thread_force_interruption_checkpoint, "mono_thread_force_interruption_checkpoint", "void", FALSE);
 #ifndef DISABLE_REMOTING
        register_icall (mono_load_remote_field_new, "mono_load_remote_field_new", "object object ptr ptr", FALSE);
@@ -7472,9 +7553,12 @@ register_icalls (void)
        register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", "uint32 double", mono_fconv_u4, "mono_fconv_u4", FALSE);
        register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", "long double", mono_fconv_ovf_i8, "mono_fconv_ovf_i8", FALSE);
        register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", "ulong double", mono_fconv_ovf_u8, "mono_fconv_ovf_u8", FALSE);
+       register_opcode_emulation (OP_RCONV_TO_OVF_I8, "__emul_rconv_to_ovf_i8", "long float", mono_rconv_ovf_i8, "mono_rconv_ovf_i8", FALSE);
+       register_opcode_emulation (OP_RCONV_TO_OVF_U8, "__emul_rconv_to_ovf_u8", "ulong float", mono_rconv_ovf_u8, "mono_rconv_ovf_u8", FALSE);
 
 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
        register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", "long double", mono_fconv_i8, "mono_fconv_i8", FALSE);
+       register_opcode_emulation (OP_RCONV_TO_I8, "__emul_rconv_to_i8", "long float", mono_rconv_i8, "mono_rconv_i8", FALSE);
 #endif
 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
        register_opcode_emulation (OP_ICONV_TO_R_UN, "__emul_iconv_to_r_un", "double int32", mono_conv_to_r8_un, "mono_conv_to_r8_un", FALSE);