[mono] Add support for UnmanagedCallersOnlyAttribute (#38728)
authorAleksey Kliger (λgeek) <alklig@microsoft.com>
Fri, 10 Jul 2020 00:37:36 +0000 (20:37 -0400)
committerGitHub <noreply@github.com>
Fri, 10 Jul 2020 00:37:36 +0000 (20:37 -0400)
* [marshal] Add mono_method_has_unmanaged_callers_only_attribute

* [marshal] Allow calls to mono_marshal_get_managed_wrapped without a delegate class

   In that case, create a wrapper based on the signature of the method itself.

* [aot] Allow decode_method_ref to decode NATIVE_TO_MANAGED wrappers without a delegate class

   Bump the AOT file format

* [interp] ldftn will return a native-to-managed wrapper to UnmanagedCallersOnly methods

* aot: emit byte when we don't expect a class

* jit: create wrapper creation for ldftn in method-to-ir

   Do it at IR generation of the caller, not every time the ldftn is executed

* jit: don't create a jump trampoline for ldftn of a native-to-managed wrapper

   The wrapper might be called from a thread that's not attached to the runtime, and the jump trampoline will look at TLS vars that are not initialized

* interp: transform LDFTN into LDC of a create_method_pointer for UnmanagedCallersOnly method

* marshal: throw invalid program exception for instance and generic methods

* Emit IPE throw instead of aborting JIT or interp compilation for bad UnmanagedCallersOnly methods

   Instead of throwing while JITing (or transforming), throw when the LDFTN is executed.

* disallow delegate constructor calls on UnmanagedCallersOnly methods

* throw IPE if UnmanagedCallersOnly method has non-blittable args

* disallow DllImport and UnmanagedCallersOnly together

   throw NotSupportedException

Co-authored-by: Ryan Lucia <ryan@luciaonline.net>
src/mono/mono/metadata/class-internals.h
src/mono/mono/metadata/jit-icall-reg.h
src/mono/mono/metadata/marshal.c
src/mono/mono/mini/aot-compiler.c
src/mono/mono/mini/aot-runtime.c
src/mono/mono/mini/aot-runtime.h
src/mono/mono/mini/interp/transform.c
src/mono/mono/mini/jit-icalls.c
src/mono/mono/mini/jit-icalls.h
src/mono/mono/mini/method-to-ir.c
src/mono/mono/mini/mini-runtime.c

index 3c271b2..49f5460 100644 (file)
@@ -1553,6 +1553,9 @@ mono_method_is_constructor (MonoMethod *method);
 gboolean
 mono_class_has_default_constructor (MonoClass *klass, gboolean public_only);
 
+gboolean
+mono_method_has_unmanaged_callers_only_attribute (MonoMethod *method);
+
 // There are many ways to do on-demand initialization.
 //   Some allow multiple concurrent initializations. Some do not.
 //   Some allow multiple concurrent writes to the global. Some do not.
index 5b07e4c..3abbdf4 100644 (file)
@@ -308,6 +308,8 @@ MONO_JIT_ICALL (mono_threads_state_poll) \
 MONO_JIT_ICALL (mono_throw_exception) \
 MONO_JIT_ICALL (mono_throw_method_access) \
 MONO_JIT_ICALL (mono_throw_bad_image) \
+MONO_JIT_ICALL (mono_throw_not_supported) \
+MONO_JIT_ICALL (mono_throw_invalid_program) \
 MONO_JIT_ICALL (mono_trace_enter_method) \
 MONO_JIT_ICALL (mono_trace_leave_method) \
 MONO_JIT_ICALL (mono_trace_tail_method) \
index bec2c30..fe74f17 100644 (file)
@@ -113,6 +113,7 @@ static GENERATE_TRY_GET_CLASS_WITH_CACHE (unmanaged_function_pointer_attribute,
 
 #ifdef ENABLE_NETCORE
 static GENERATE_TRY_GET_CLASS_WITH_CACHE (suppress_gc_transition_attribute, "System.Runtime.InteropServices", "SuppressGCTransitionAttribute")
+static GENERATE_TRY_GET_CLASS_WITH_CACHE (unmanaged_callers_only_attribute, "System.Runtime.InteropServices", "UnmanagedCallersOnlyAttribute")
 #endif
 
 static MonoImage*
@@ -3661,6 +3662,23 @@ mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions,
 
        mb->method->save_lmf = 1;
 
+       if (G_UNLIKELY (pinvoke && mono_method_has_unmanaged_callers_only_attribute (method))) {
+               /* emit a wrapper that throws a NotSupportedException */
+               get_marshal_cb ()->mb_emit_exception (mb, "System", "NotSupportedException", "Method canot be marked with both  DllImportAttribute and UnmanagedCallersOnlyAttribute");
+
+               info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_NONE);
+               info->d.managed_to_native.method = method;
+
+               csig = mono_metadata_signature_dup_full (get_method_image (method), sig);
+               csig->pinvoke = 0;
+               res = mono_mb_create_and_cache_full (cache, method, mb, csig,
+                                                                                        csig->param_count + 16, info, NULL);
+               mono_mb_free (mb);
+
+               return res;
+       }
+
+
        /*
         * In AOT mode and embedding scenarios, it is possible that the icall is not
         * registered in the runtime doing the AOT compilation.
@@ -3940,10 +3958,54 @@ emit_managed_wrapper_noilgen (MonoMethodBuilder *mb, MonoMethodSignature *invoke
 }
 #endif
 
+static gboolean
+type_is_blittable (MonoType *type)
+{
+       if (type->byref)
+               return FALSE;
+       type = mono_type_get_underlying_type (type);
+       switch (type->type) {
+       case MONO_TYPE_I1:
+       case MONO_TYPE_U1:
+       case MONO_TYPE_I2:
+       case MONO_TYPE_U2:
+       case MONO_TYPE_I4:
+       case MONO_TYPE_U4:
+       case MONO_TYPE_I8:
+       case MONO_TYPE_U8:
+       case MONO_TYPE_R4:
+       case MONO_TYPE_R8:
+       case MONO_TYPE_I:
+       case MONO_TYPE_U:
+       case MONO_TYPE_PTR:
+       case MONO_TYPE_FNPTR:
+               return TRUE;
+       default:
+               return m_class_is_blittable (mono_class_from_mono_type_internal (type));
+       }
+}
+
+static gboolean
+method_signature_is_blittable (MonoMethodSignature *sig)
+{
+       if (!type_is_blittable (sig->ret))
+               return FALSE;
+
+       for (int i = 0; i < sig->param_count; ++i) {
+               MonoType *type = sig->params [i];
+               if (!type_is_blittable (type))
+                       return FALSE;
+       }
+       return TRUE;
+}
+
 /**
  * mono_marshal_get_managed_wrapper:
  * Generates IL code to call managed methods from unmanaged code 
  * If \p target_handle is \c 0, the wrapper info will be a \c WrapperInfo structure.
+ *
+ * If \p delegate_klass is \c NULL, we're creating a wrapper for a function pointer to a method marked with
+ * UnamangedCallersOnlyAttribute.
  */
 MonoMethod *
 mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, MonoGCHandle target_handle, MonoError *error)
@@ -3975,11 +4037,33 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass,
        if (!target_handle && (res = mono_marshal_find_in_cache (cache, method)))
                return res;
 
-       invoke = mono_get_delegate_invoke_internal (delegate_klass);
-       invoke_sig = mono_method_signature_internal (invoke);
-
-       mspecs = g_new0 (MonoMarshalSpec*, mono_method_signature_internal (invoke)->param_count + 1);
-       mono_method_get_marshal_info (invoke, mspecs);
+       if (G_UNLIKELY (!delegate_klass)) {
+               /* creating a wrapper for a function pointer with UnmanagedCallersOnlyAttribute */
+               if (mono_method_has_marshal_info (method)) {
+                       mono_error_set_invalid_program (error, "method %s with UnmanadedCallersOnlyAttribute has marshal specs", mono_method_full_name (method, TRUE));
+                       return NULL;
+               }
+               invoke = NULL;
+               invoke_sig = mono_method_signature_internal (method);
+               if (invoke_sig->hasthis) {
+                       mono_error_set_invalid_program (error, "method %s with UnamanagedCallersOnlyAttribute is an instance method", mono_method_full_name (method, TRUE));
+                       return NULL;
+               }
+               if (method->is_generic || method->is_inflated || mono_class_is_ginst (method->klass)) {
+                       mono_error_set_invalid_program (error, "method %s with UnamangedCallersOnlyAttribute is generic", mono_method_full_name (method, TRUE));
+                       return NULL;
+               }
+               if (!method_signature_is_blittable (invoke_sig)) {
+                       mono_error_set_invalid_program (error, "method %s with UnmanagedCallersOnlyAttribute has non-blittable parameters or return type", mono_method_full_name (method, TRUE));
+                       return NULL;
+               }
+               mspecs = g_new0 (MonoMarshalSpec*, invoke_sig->param_count + 1);
+       } else {
+               invoke = mono_get_delegate_invoke_internal (delegate_klass);
+               invoke_sig = mono_method_signature_internal (invoke);
+               mspecs = g_new0 (MonoMarshalSpec*, invoke_sig->param_count + 1);
+               mono_method_get_marshal_info (invoke, mspecs);
+       }
 
        sig = mono_method_signature_internal (method);
 
@@ -4005,10 +4089,11 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass,
        m.csig = csig;
        m.image = get_method_image (method);
 
-       mono_marshal_set_callconv_from_modopt (invoke, csig, TRUE);
+       if (invoke)
+               mono_marshal_set_callconv_from_modopt (invoke, csig, TRUE);
 
        /* The attribute is only available in Net 2.0 */
-       if (mono_class_try_get_unmanaged_function_pointer_attribute_class ()) {
+       if (delegate_klass && mono_class_try_get_unmanaged_function_pointer_attribute_class ()) {
                MonoCustomAttrInfo *cinfo;
                MonoCustomAttrEntry *attr;
 
@@ -4097,7 +4182,7 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass,
        }
        mono_mb_free (mb);
 
-       for (i = mono_method_signature_internal (invoke)->param_count; i >= 0; i--)
+       for (i = invoke_sig->param_count; i >= 0; i--)
                if (mspecs [i])
                        mono_metadata_free_marshal_spec (mspecs [i]);
        g_free (mspecs);
@@ -6755,3 +6840,33 @@ get_marshal_cb (void)
        }
        return &marshal_cb;
 }
+
+/**
+ * mono_method_has_unmanaged_callers_only_attribute:
+ *
+ * Returns \c TRUE if \p method has the \c UnmanagedCallersOnlyAttribute
+ */
+gboolean
+mono_method_has_unmanaged_callers_only_attribute (MonoMethod *method)
+{
+#ifndef ENABLE_NETCORE
+       return FALSE;
+#else
+       ERROR_DECL (attr_error);
+       MonoClass *attr_klass = NULL;
+       attr_klass = mono_class_try_get_unmanaged_callers_only_attribute_class ();
+       if (!attr_klass)
+               return FALSE;
+       MonoCustomAttrInfo *cinfo;
+       cinfo = mono_custom_attrs_from_method_checked (method, attr_error);
+       if (!is_ok (attr_error) || !cinfo) {
+               mono_error_cleanup (attr_error);
+               return FALSE;
+       }
+       gboolean result;
+       result = mono_custom_attrs_has_attr (cinfo, attr_klass);
+       if (!cinfo->cached)
+               mono_custom_attrs_free (cinfo);
+       return result;
+#endif
+}
index adb9cab..7c76e4c 100644 (file)
@@ -3761,7 +3761,13 @@ encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, guint8 *buf, guint8
                case MONO_WRAPPER_NATIVE_TO_MANAGED: {
                        g_assert (info);
                        encode_method_ref (acfg, info->d.native_to_managed.method, p, &p);
-                       encode_klass_ref (acfg, info->d.native_to_managed.klass, p, &p);
+                       MonoClass *klass = info->d.native_to_managed.klass;
+                       if (!klass) {
+                               encode_value (0, p, &p);
+                       } else {
+                               encode_value (1, p, &p);
+                               encode_klass_ref (acfg, klass, p, &p);
+                       }
                        break;
                }
                default:
index 209279d..b42c76e 100644 (file)
@@ -1312,9 +1312,13 @@ decode_method_ref_with_target (MonoAotModule *module, MethodRef *ref, MonoMethod
                        m = decode_resolve_method_ref (module, p, &p, error);
                        if (!m)
                                return FALSE;
-                       klass = decode_klass_ref (module, p, &p, error);
-                       if (!klass)
-                               return FALSE;
+                       gboolean has_class = decode_value (p, &p);
+                       if (has_class) {
+                               klass = decode_klass_ref (module, p, &p, error);
+                               if (!klass)
+                                       return FALSE;
+                       } else
+                               klass = NULL;
                        ref->method = mono_marshal_get_managed_wrapper (m, klass, 0, error);
                        if (!is_ok (error))
                                return FALSE;
index c4171fa..79b9b6d 100644 (file)
@@ -11,7 +11,7 @@
 #include "mini.h"
 
 /* Version number of the AOT file format */
-#define MONO_AOT_FILE_VERSION 178
+#define MONO_AOT_FILE_VERSION 179
 
 #define MONO_AOT_TRAMP_PAGE_SIZE 16384
 
index ad2e654..351812f 100644 (file)
@@ -841,6 +841,32 @@ interp_generate_bie_throw (TransformData *td)
        td->last_ins->data [0] = get_data_item_index (td, (gpointer)info->func);
 }
 
+static void
+interp_generate_not_supported_throw (TransformData *td)
+{
+       MonoJitICallInfo *info = &mono_get_jit_icall_info ()->mono_throw_not_supported;
+
+       interp_add_ins (td, MINT_ICALL_V_V);
+       td->last_ins->data [0] = get_data_item_index (td, (gpointer)info->func);
+}
+
+static void
+interp_generate_ipe_throw_with_msg (TransformData *td, MonoError *error_msg)
+{
+       MonoJitICallInfo *info = &mono_get_jit_icall_info ()->mono_throw_invalid_program;
+
+       char *msg = mono_mempool_strdup (td->rtm->domain->mp, mono_error_get_message (error_msg));
+
+       interp_add_ins (td, MINT_MONO_LDPTR);
+       td->last_ins->data [0] = get_data_item_index (td, msg);
+       PUSH_SIMPLE_TYPE (td, STACK_TYPE_I);
+
+       interp_add_ins (td, MINT_ICALL_P_V);
+       td->last_ins->data [0] = get_data_item_index (td, (gpointer)info->func);
+
+       td->sp -= 1;
+}
+
 /*
  * These are additional locals that can be allocated as we transform the code.
  * They are allocated past the method locals so they are accessed in the same
@@ -6203,6 +6229,61 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header,
                                if (method->wrapper_type == MONO_WRAPPER_NONE && m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
                                        m = mono_marshal_get_synchronized_wrapper (m);
 
+                               if (G_UNLIKELY (*td->ip == CEE_LDFTN &&
+                                               m->wrapper_type == MONO_WRAPPER_NONE &&
+                                               mono_method_has_unmanaged_callers_only_attribute (m))) {
+
+                                       if (m->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
+                                               interp_generate_not_supported_throw (td);
+                                               interp_add_ins (td, MINT_LDNULL);
+                                               td->ip += 5;
+                                               PUSH_SIMPLE_TYPE (td, STACK_TYPE_MP);
+                                               break;
+                                       }
+
+                                       MonoMethod *ctor_method;
+
+                                       const unsigned char *next_ip = td->ip + 5;
+                                       /* check for
+                                        *    ldftn method_sig
+                                        *    newobj Delegate::.ctor
+                                        */
+                                       if (next_ip < end &&
+                                           *next_ip == CEE_NEWOBJ &&
+                                           ((ctor_method = interp_get_method (method, read32 (next_ip + 1), image, generic_context, error))) &&
+                                           is_ok (error) &&
+                                           m_class_get_parent (ctor_method->klass) == mono_defaults.multicastdelegate_class &&
+                                           !strcmp (ctor_method->name, ".ctor")) {
+                                               mono_error_set_not_supported (error, "Cannot create delegate from method with UnmanagedCallersOnlyAttribute");
+                                               goto exit;
+                                       }
+
+                                       MonoClass *delegate_klass = NULL;
+                                       MonoGCHandle target_handle = 0;
+                                       ERROR_DECL (wrapper_error);
+                                       m = mono_marshal_get_managed_wrapper (m, delegate_klass, target_handle, wrapper_error);
+                                       if (!is_ok (wrapper_error)) {
+                                               /* Generate a call that will throw an exception if the
+                                                * UnmanagedCallersOnly attribute is used incorrectly */
+                                               interp_generate_ipe_throw_with_msg (td, wrapper_error);
+                                               mono_error_cleanup (wrapper_error);
+                                               interp_add_ins (td, MINT_LDNULL);
+                                       } else {
+                                               /* push a pointer to a trampoline that calls m */
+                                               gpointer entry = mini_get_interp_callbacks ()->create_method_pointer (m, TRUE, error);
+#if SIZEOF_VOID_P == 8
+                                               interp_add_ins (td, MINT_LDC_I8);
+                                               WRITE64_INS (td->last_ins, 0, &entry);
+#else
+                                               interp_add_ins (td, MINT_LDC_I4);
+                                               WRITE32_INS (td->last_ins, 0, &entry);
+#endif
+                                       }
+                                       td->ip += 5;
+                                       PUSH_SIMPLE_TYPE (td, STACK_TYPE_MP);
+                                       break;
+                               }
+
                                interp_add_ins (td, *td->ip == CEE_LDFTN ? MINT_LDFTN : MINT_LDVIRTFTN);
                                td->last_ins->data [0] = get_data_item_index (td, mono_interp_get_imethod (domain, m, error));
                                goto_if_nok (error, exit);
index 0cdc7a5..d4116aa 100644 (file)
@@ -54,7 +54,12 @@ mono_ldftn (MonoMethod *method)
                return addr;
        }
 
-       addr = mono_create_jump_trampoline (mono_domain_get (), method, FALSE, error);
+       /* if we need the address of a native-to-managed wrapper, just compile it now, trampoline needs thread local
+        * variables that won't be there if we run on a thread that's not attached yet. */
+       if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
+               addr = mono_compile_method_checked (method, error);
+       else
+               addr = mono_create_jump_trampoline (mono_domain_get (), method, FALSE, error);
        if (!is_ok (error)) {
                mono_error_set_pending_exception (error);
                return NULL;
@@ -1591,6 +1596,22 @@ mono_throw_bad_image ()
 }
 
 void
+mono_throw_not_supported ()
+{
+       ERROR_DECL (error);
+       mono_error_set_generic_error (error, "System", "NotSupportedException", "");
+       mono_error_set_pending_exception (error);
+}
+
+void
+mono_throw_invalid_program (const char *msg)
+{
+       ERROR_DECL (error);
+       mono_error_set_invalid_program (error, "Invalid IL due to: %s", msg);
+       mono_error_set_pending_exception (error);
+}
+
+void
 mono_dummy_jit_icall (void)
 {
 }
index 41ebae8..7de1133 100644 (file)
@@ -223,6 +223,10 @@ ICALL_EXTERN_C void mono_throw_method_access (MonoMethod *caller, MonoMethod *ca
 
 ICALL_EXTERN_C void mono_throw_bad_image (void);
 
+ICALL_EXTERN_C void mono_throw_not_supported (void);
+
+ICALL_EXTERN_C void mono_throw_invalid_program (const char *msg);
+
 ICALL_EXTERN_C void mono_dummy_jit_icall (void);
 
 #endif /* __MONO_JIT_ICALLS_H__ */
index 032d519..efcecb8 100644 (file)
@@ -2307,6 +2307,25 @@ emit_bad_image_failure (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee
        mono_emit_jit_icall (cfg, mono_throw_bad_image, NULL);
 }
 
+static void
+emit_not_supported_failure (MonoCompile *cfg)
+{
+       mono_emit_jit_icall (cfg, mono_throw_not_supported, NULL);
+}
+
+static void
+emit_invalid_program_with_msg (MonoCompile *cfg, MonoError *error_msg, MonoMethod *caller, MonoMethod *callee)
+{
+       g_assert (!is_ok (error_msg));
+       char *str = mono_mempool_strdup (cfg->domain->mp, mono_error_get_message (error_msg));
+       MonoInst *iargs[1];
+       if (cfg->compile_aot)
+               EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
+       else
+               EMIT_NEW_PCONST (cfg, iargs [0], str);
+       mono_emit_jit_icall (cfg, mono_throw_invalid_program, iargs);
+}
+
 // FIXME Consolidate the multiple functions named get_method_nofail.
 static MonoMethod*
 get_method_nofail (MonoClass *klass, const char *method_name, int num_params, int flags)
@@ -11059,6 +11078,10 @@ mono_ldptr:
                        if (mono_security_core_clr_enabled ())
                                ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
 
+                       const gboolean has_unmanaged_callers_only =
+                               cmethod->wrapper_type == MONO_WRAPPER_NONE &&
+                               mono_method_has_unmanaged_callers_only_attribute (cmethod);
+
                        /*
                         * Optimize the common case of ldftn+delegate creation
                         */
@@ -11069,6 +11092,11 @@ mono_ldptr:
                                        MonoMethod *invoke;
                                        int invoke_context_used;
 
+                                       if (G_UNLIKELY (has_unmanaged_callers_only)) {
+                                               mono_error_set_not_supported (cfg->error, "Cannot create delegate from method with UnmanagedCallersOnlyAttribute");
+                                               CHECK_CFG_ERROR;
+                                       }
+
                                        invoke = mono_get_delegate_invoke_internal (ctor_method->klass);
                                        if (!invoke || !mono_method_signature_internal (invoke))
                                                LOAD_ERROR;
@@ -11106,6 +11134,38 @@ mono_ldptr:
                                }
                        }
 
+                       /* UnmanagedCallersOnlyAttribute means ldftn should return a method callable from native */
+                       if (G_UNLIKELY (has_unmanaged_callers_only)) {
+                               if (G_UNLIKELY (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
+                                       // Follow CoreCLR, disallow [UnmanagedCallersOnly] and [DllImport] to be used
+                                       // together
+                                       emit_not_supported_failure (cfg);
+                                       EMIT_NEW_PCONST (cfg, ins, NULL);
+                                       *sp++ = ins;
+                                       inline_costs += CALL_COST * MIN(10, num_calls++);
+                                       break;
+                               }
+                               MonoClass *delegate_klass = NULL;
+                               MonoGCHandle target_handle = 0;
+                               ERROR_DECL (wrapper_error);
+                               MonoMethod *wrapped_cmethod;
+                               wrapped_cmethod = mono_marshal_get_managed_wrapper (cmethod, delegate_klass, target_handle, wrapper_error);
+                               if (!is_ok (wrapper_error)) {
+                                       /* if we couldn't create a wrapper because cmethod isn't supposed to have an
+                                       UnmanagedCallersOnly attribute, follow CoreCLR behavior and throw when the
+                                       method with the ldftn is executing, not when it is being compiled. */
+                                       emit_invalid_program_with_msg (cfg, wrapper_error, method, cmethod);
+                                       mono_error_cleanup (wrapper_error);
+                                       EMIT_NEW_PCONST (cfg, ins, NULL);
+                                       *sp++ = ins;
+
+                                       inline_costs += CALL_COST * MIN(10, num_calls++);
+                                       break;
+                               } else {
+                                       cmethod = wrapped_cmethod;
+                               }
+                       }
+
                        argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
                        ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
                        *sp++ = ins;
index 9d0adce..a1e1187 100644 (file)
@@ -4887,6 +4887,8 @@ register_icalls (void)
        register_icall (mono_get_method_object, mono_icall_sig_object_ptr, TRUE);
        register_icall (mono_throw_method_access, mono_icall_sig_void_ptr_ptr, FALSE);
        register_icall (mono_throw_bad_image, mono_icall_sig_void, FALSE);
+       register_icall (mono_throw_not_supported, mono_icall_sig_void, FALSE);
+       register_icall (mono_throw_invalid_program, mono_icall_sig_void_ptr, FALSE);
        register_icall_no_wrapper (mono_dummy_jit_icall, mono_icall_sig_void);
 
        register_icall_with_wrapper (mono_monitor_enter_internal, mono_icall_sig_int32_obj);