First set of licensing changes
[mono.git] / mono / mini / mini-trampolines.c
index 174d6f694ad1b5b92adf5ab4ecef810dc061b6c7..c464a0033a77c727829ba44f5e6acea3bba0e84c 100644 (file)
@@ -2,6 +2,7 @@
  * (C) 2003 Ximian, Inc.
  * (C) 2003-2011 Novell, Inc.
  * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
  */
 #include <config.h>
 #include <glib.h>
@@ -182,7 +183,8 @@ mini_resolve_imt_method (MonoVTable *vt, gpointer *vtable_slot, MonoMethod *imt_
        /* We can only use the AOT compiled code if we don't require further processing */
        lookup_aot = !generic_virtual & !variant_iface;
 
-       mono_vtable_build_imt_slot (vt, mono_method_get_imt_slot (imt_method));
+       if (!mono_llvm_only)
+               mono_vtable_build_imt_slot (vt, mono_method_get_imt_slot (imt_method));
 
        if (imt_method->is_inflated && ((MonoMethodInflated*)imt_method)->context.method_inst) {
                MonoError error;
@@ -386,17 +388,14 @@ mini_add_method_trampoline (MonoMethod *m, gpointer compiled_method, gboolean ad
  * - generic sharing (ARG is the rgctx)
  * - gsharedvt signature wrappers (ARG is a function descriptor)
  */
-gpointer
-mini_create_llvmonly_ftndesc (gpointer addr, gpointer arg)
+MonoFtnDesc*
+mini_create_llvmonly_ftndesc (MonoDomain *domain, gpointer addr, gpointer arg)
 {
-       gpointer *res;
-
-       // FIXME: Memory management
-       res = g_malloc0 (2 * sizeof (gpointer));
-       res [0] = addr;
-       res [1] = arg;
+       MonoFtnDesc *ftndesc = (MonoFtnDesc*)mono_domain_alloc0 (mono_domain_get (), 2 * sizeof (gpointer));
+       ftndesc->addr = addr;
+       ftndesc->arg = arg;
 
-       return res;
+       return ftndesc;
 }
 
 /**
@@ -408,7 +407,7 @@ mini_create_llvmonly_ftndesc (gpointer addr, gpointer arg)
 gpointer
 mini_add_method_wrappers_llvmonly (MonoMethod *m, gpointer compiled_method, gboolean caller_gsharedvt, gboolean add_unbox_tramp, gpointer *out_arg)
 {
-       gpointer addr = compiled_method;
+       gpointer addr;
        gboolean callee_gsharedvt, callee_array_helper;
        MonoMethod *jmethod = NULL;
        MonoJitInfo *ji;
@@ -461,8 +460,13 @@ mini_add_method_wrappers_llvmonly (MonoMethod *m, gpointer compiled_method, gboo
 
        if (ji && !ji->is_trampoline)
                jmethod = jinfo_get_method (ji);
-       if (callee_gsharedvt && mini_is_gsharedvt_variable_signature (mono_method_signature (jmethod))) {
+
+       if (callee_gsharedvt)
+               callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jmethod));
+
+       if (!caller_gsharedvt && callee_gsharedvt) {
                MonoMethodSignature *sig, *gsig;
+               gpointer wrapper_addr;
 
                /* Here m is a generic instance, while ji->method is the gsharedvt method implementing it */
 
@@ -470,26 +474,25 @@ mini_add_method_wrappers_llvmonly (MonoMethod *m, gpointer compiled_method, gboo
                sig = mono_method_signature (m);
                gsig = mono_method_signature (jmethod);
 
-               addr = mini_get_gsharedvt_wrapper (TRUE, addr, sig, gsig, -1, FALSE);
+               wrapper_addr = mini_get_gsharedvt_wrapper (TRUE, addr, sig, gsig, -1, FALSE);
 
                /*
                 * This is a gsharedvt in wrapper, it gets passed a ftndesc for the gsharedvt method as an argument.
                 */
-               *out_arg = mini_create_llvmonly_ftndesc (compiled_method, mini_method_get_rgctx (m));
+               *out_arg = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, mini_method_get_rgctx (m));
+               addr = wrapper_addr;
                //printf ("IN: %s\n", mono_method_full_name (m, TRUE));
        }
 
        if (!(*out_arg) && mono_method_needs_static_rgctx_invoke (m, FALSE))
                *out_arg = mini_method_get_rgctx (m);
 
-       if (caller_gsharedvt) {
+       if (caller_gsharedvt && !callee_gsharedvt) {
                /*
                 * The callee uses the gsharedvt calling convention, have to add an out wrapper.
                 */
                gpointer out_wrapper = mini_get_gsharedvt_wrapper (FALSE, NULL, mono_method_signature (m), NULL, -1, FALSE);
-               gpointer *out_wrapper_arg = g_malloc0 (2 * sizeof (gpointer));
-               out_wrapper_arg [0] = addr;
-               out_wrapper_arg [1] = *out_arg;
+               MonoFtnDesc *out_wrapper_arg = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, *out_arg);
 
                addr = out_wrapper;
                *out_arg = out_wrapper_arg;
@@ -499,13 +502,13 @@ mini_add_method_wrappers_llvmonly (MonoMethod *m, gpointer compiled_method, gboo
 }
 
 /**
- * common_call_trampoline:
+ * common_call_trampoline_inner:
  *
  *   The code to handle normal, virtual, and interface method calls and jumps, both
  * from JITted and LLVM compiled code.
  */
 static gpointer
-common_call_trampoline_inner (mgreg_t *regs, guint8 *code, MonoMethod *m, MonoVTable *vt, gpointer *vtable_slot)
+common_call_trampoline_inner (mgreg_t *regs, guint8 *code, MonoMethod *m, MonoVTable *vt, gpointer *vtable_slot, MonoError *error)
 {
        gpointer addr, compiled_method;
        gboolean generic_shared = FALSE;
@@ -518,6 +521,8 @@ common_call_trampoline_inner (mgreg_t *regs, guint8 *code, MonoMethod *m, MonoVT
        gpointer *orig_vtable_slot, *vtable_slot_to_patch = NULL;
        MonoJitInfo *ji = NULL;
 
+       mono_error_init (error);
+
        virtual_ = vt && (gpointer)vtable_slot > (gpointer)vt;
        imt_call = vt && (gpointer)vtable_slot < (gpointer)vt;
 
@@ -689,8 +694,9 @@ common_call_trampoline_inner (mgreg_t *regs, guint8 *code, MonoMethod *m, MonoVT
        if (!code && mono_method_needs_static_rgctx_invoke (m, FALSE))
                need_rgctx_tramp = TRUE;
 
-       addr = compiled_method = mono_compile_method (m);
-       g_assert (addr);
+       addr = compiled_method = mono_jit_compile_method (m, error);
+       if (!addr)
+               return NULL;
 
        if (generic_virtual || variant_iface) {
                if (vt->klass->valuetype) /*FIXME is this required variant iface?*/
@@ -799,11 +805,11 @@ common_call_trampoline_inner (mgreg_t *regs, guint8 *code, MonoMethod *m, MonoVT
 }
 
 static gpointer
-common_call_trampoline (mgreg_t *regs, guint8 *code, MonoMethod *m, MonoVTable *vt, gpointer *vtable_slot)
+common_call_trampoline (mgreg_t *regs, guint8 *code, MonoMethod *m, MonoVTable *vt, gpointer *vtable_slot, MonoError *error)
 {
        gpointer res;
        MONO_PREPARE_RESET_BLOCKING;
-       res = common_call_trampoline_inner (regs, code, m, vt, vtable_slot);
+       res = common_call_trampoline_inner (regs, code, m, vt, vtable_slot, error);
        MONO_FINISH_RESET_BLOCKING;
        return res;
 }
@@ -816,9 +822,17 @@ common_call_trampoline (mgreg_t *regs, guint8 *code, MonoMethod *m, MonoVTable *
 gpointer
 mono_magic_trampoline (mgreg_t *regs, guint8 *code, gpointer arg, guint8* tramp)
 {
+       MonoError error;
+       gpointer res;
+
        trampoline_calls ++;
 
-       return common_call_trampoline (regs, code, (MonoMethod *)arg, NULL, NULL);
+       res = common_call_trampoline (regs, code, (MonoMethod *)arg, NULL, NULL, &error);
+       if (!mono_error_ok (&error)) {
+               mono_error_set_pending_exception (&error);
+               return NULL;
+       }
+       return res;
 }
 
 /**
@@ -833,7 +847,8 @@ mono_vcall_trampoline (mgreg_t *regs, guint8 *code, int slot, guint8 *tramp)
        MonoVTable *vt;
        gpointer *vtable_slot;
        MonoMethod *m;
-       gpointer addr;
+       MonoError error;
+       gpointer addr, res;
 
        trampoline_calls ++;
 
@@ -887,7 +902,12 @@ mono_vcall_trampoline (mgreg_t *regs, guint8 *code, int slot, guint8 *tramp)
                m = NULL;
        }
 
-       return common_call_trampoline (regs, code, m, vt, vtable_slot);
+       res = common_call_trampoline (regs, code, m, vt, vtable_slot, &error);
+       if (!mono_error_ok (&error)) {
+               mono_error_set_pending_exception (&error);
+               return NULL;
+       }
+       return res;
 }
 
 #ifndef DISABLE_REMOTING
@@ -920,7 +940,11 @@ mono_generic_virtual_remoting_trampoline (mgreg_t *regs, guint8 *code, MonoMetho
        g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */;
        m = mono_marshal_get_remoting_invoke_with_check (m);
 
-       addr = mono_compile_method (m);
+       addr = mono_jit_compile_method (m, &error);
+       if (!mono_error_ok (&error)) {
+               mono_error_set_pending_exception (&error);
+               return NULL;
+       }
        g_assert (addr);
 
        return addr;
@@ -952,8 +976,10 @@ mono_aot_trampoline (mgreg_t *regs, guint8 *code, guint8 *token_info,
 
        addr = mono_aot_get_method_from_token (mono_domain_get (), image, token);
        if (!addr) {
-               method = mono_get_method (image, token, NULL);
-               g_assert (method);
+               MonoError error;
+               method = mono_get_method_checked (image, token, NULL, NULL, &error);
+               if (!method)
+                       g_error ("Could not load AOT trampoline due to %s", mono_error_get_message (&error));
 
                /* Use the generic code */
                return mono_magic_trampoline (regs, code, method, tramp);
@@ -981,13 +1007,16 @@ mono_aot_plt_trampoline (mgreg_t *regs, guint8 *code, guint8 *aot_module,
 {
        guint32 plt_info_offset = mono_aot_get_plt_info_offset (regs, code);
        gpointer res;
+       MonoError error;
 
        trampoline_calls ++;
 
-       res = mono_aot_plt_resolve (aot_module, plt_info_offset, code);
+       res = mono_aot_plt_resolve (aot_module, plt_info_offset, code, &error);
        if (!res) {
-               if (mono_loader_get_last_error ())
-                       mono_raise_exception (mono_loader_error_prepare_exception (mono_loader_get_last_error ()));
+               if (!mono_error_ok (&error)) {
+                       mono_error_set_pending_exception (&error);
+                       return NULL;
+               }
                // FIXME: Error handling (how ?)
                g_assert (res);
        }
@@ -1006,6 +1035,8 @@ mono_rgctx_lazy_fetch_trampoline (mgreg_t *regs, guint8 *code, gpointer data, gu
        gpointer arg = (gpointer)(gssize)r [MONO_ARCH_VTABLE_REG];
        guint32 index = MONO_RGCTX_SLOT_INDEX (slot);
        gboolean mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
+       MonoError error;
+       gpointer res;
 
        trampoline_calls ++;
 
@@ -1017,39 +1048,14 @@ mono_rgctx_lazy_fetch_trampoline (mgreg_t *regs, guint8 *code, gpointer data, gu
        num_lookups++;
 
        if (mrgctx)
-               return mono_method_fill_runtime_generic_context ((MonoMethodRuntimeGenericContext *)arg, index);
+               res = mono_method_fill_runtime_generic_context ((MonoMethodRuntimeGenericContext *)arg, index, &error);
        else
-               return mono_class_fill_runtime_generic_context ((MonoVTable *)arg, index);
-}
-
-/*
- * Precompute data to speed up mono_delegate_trampoline ().
- * METHOD might be NULL.
- */
-static MonoDelegateTrampInfo*
-create_delegate_trampoline_data (MonoDomain *domain, MonoClass *klass, MonoMethod *method)
-{
-       MonoDelegateTrampInfo *tramp_data;
-       MonoMethod *invoke;
-       MonoError err;
-
-       // Precompute the delegate invoke impl and pass it to the delegate trampoline
-       invoke = mono_get_delegate_invoke (klass);
-       g_assert (invoke);
-
-       tramp_data = (MonoDelegateTrampInfo *)mono_domain_alloc0 (domain, sizeof (MonoDelegateTrampInfo));
-       tramp_data->invoke = invoke;
-       tramp_data->invoke_sig = mono_method_signature (invoke);
-       tramp_data->impl_this = mono_arch_get_delegate_invoke_impl (mono_method_signature (invoke), TRUE);
-       tramp_data->impl_nothis = mono_arch_get_delegate_invoke_impl (mono_method_signature (invoke), FALSE);
-       tramp_data->method = method;
-       if (method) {
-               mono_error_init (&err);
-               tramp_data->sig = mono_method_signature_checked (method, &err);
-               tramp_data->need_rgctx_tramp = mono_method_needs_static_rgctx_invoke (method, FALSE);
+               res = mono_class_fill_runtime_generic_context ((MonoVTable *)arg, index, &error);
+       if (!mono_error_ok (&error)) {
+               mono_error_set_pending_exception (&error);
+               return NULL;
        }
-
-       return tramp_data;
+       return res;
 }
 
 /**
@@ -1066,6 +1072,7 @@ mono_delegate_trampoline (mgreg_t *regs, guint8 *code, gpointer *arg, guint8* tr
        MonoJitInfo *ji;
        MonoMethod *m;
        MonoMethod *method = NULL;
+       MonoError error;
        gboolean multicast, callvirt = FALSE, closed_over_null = FALSE;
        gboolean need_rgctx_tramp = FALSE;
        gboolean need_unbox_tramp = FALSE;
@@ -1110,8 +1117,10 @@ mono_delegate_trampoline (mgreg_t *regs, guint8 *code, gpointer *arg, guint8* tr
                        if (!(sig && method == tramp_info->method)) {
                                mono_error_init (&err);
                                sig = mono_method_signature_checked (method, &err);
-                               if (!sig)
-                                       mono_error_raise_exception (&err);
+                               if (!sig) {
+                                       mono_error_set_pending_exception (&err);
+                                       return NULL;
+                               }
                        }
 
                        if (sig->hasthis && method->klass->valuetype) {
@@ -1142,8 +1151,10 @@ mono_delegate_trampoline (mgreg_t *regs, guint8 *code, gpointer *arg, guint8* tr
                if (!(sig && method == tramp_info->method)) {
                        mono_error_init (&err);
                        sig = mono_method_signature_checked (method, &err);
-                       if (!sig)
-                               mono_error_raise_exception (&err);
+                       if (!sig) {
+                               mono_error_set_pending_exception (&err);
+                               return NULL;
+                       }
                }
 
                callvirt = !delegate->target && sig->hasthis;
@@ -1192,7 +1203,11 @@ mono_delegate_trampoline (mgreg_t *regs, guint8 *code, gpointer *arg, guint8* tr
                if (enable_caching && delegate->method_code && *delegate->method_code) {
                        delegate->method_ptr = *delegate->method_code;
                } else {
-                       compiled_method = addr = mono_compile_method (method);
+                       compiled_method = addr = mono_jit_compile_method (method, &error);
+                       if (!mono_error_ok (&error)) {
+                               mono_error_set_pending_exception (&error);
+                               return NULL;
+                       }
                        addr = mini_add_method_trampoline (method, compiled_method, need_rgctx_tramp, need_unbox_tramp);
                        delegate->method_ptr = addr;
                        if (enable_caching && delegate->method_code)
@@ -1218,7 +1233,11 @@ mono_delegate_trampoline (mgreg_t *regs, guint8 *code, gpointer *arg, guint8* tr
        if (!code) {
                /* The general, unoptimized case */
                m = mono_marshal_get_delegate_invoke (invoke, delegate);
-               code = (guint8 *)mono_compile_method (m);
+               code = (guint8 *)mono_jit_compile_method (m, &error);
+               if (!mono_error_ok (&error)) {
+                       mono_error_set_pending_exception (&error);
+                       return NULL;
+               }
                code = (guint8 *)mini_add_method_trampoline (m, code, mono_method_needs_static_rgctx_invoke (m, FALSE), FALSE);
        }
 
@@ -1401,12 +1420,14 @@ mono_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_type, M
 }
 
 gpointer
-mono_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
+mono_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error)
 {
        MonoJitInfo *ji;
        gpointer code;
        guint32 code_size = 0;
 
+       mono_error_init (error);
+
        code = mono_jit_find_compiled_method_with_jit_info (domain, method, &ji);
        /*
         * We cannot recover the correct type of a shared generic
@@ -1417,8 +1438,12 @@ mono_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean ad
        if (code && !ji->has_generic_jit_info && !(method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED))
                return code;
 
-       if (mono_llvm_only)
-               return mono_jit_compile_method (method);
+       if (mono_llvm_only) {
+               code = mono_jit_compile_method (method, error);
+               if (!mono_error_ok (error))
+                       return NULL;
+               return code;
+       }
 
        mono_domain_lock (domain);
        code = g_hash_table_lookup (domain_jit_info (domain)->jump_trampoline_hash, method);
@@ -1455,10 +1480,12 @@ method_not_found (void)
 }
 
 gpointer
-mono_create_jit_trampoline_in_domain (MonoDomain *domain, MonoMethod *method)
+mono_create_jit_trampoline (MonoDomain *domain, MonoMethod *method, MonoError *error)
 {
        gpointer tramp;
 
+       mono_error_init (error);
+
        if (mono_aot_only) {
                /* Avoid creating trampolines if possible */
                gpointer code = mono_jit_find_compiled_method (domain, method);
@@ -1471,7 +1498,10 @@ mono_create_jit_trampoline_in_domain (MonoDomain *domain, MonoMethod *method)
                                /* These wrappers are not generated */
                                return method_not_found;
                        /* Methods are lazily initialized on first call, so this can't lead recursion */
-                       return mono_compile_method (method);
+                       code = mono_jit_compile_method (method, error);
+                       if (!mono_error_ok (error))
+                               return NULL;
+                       return code;
                }
        }
 
@@ -1492,12 +1522,6 @@ mono_create_jit_trampoline_in_domain (MonoDomain *domain, MonoMethod *method)
        return tramp;
 }      
 
-gpointer
-mono_create_jit_trampoline (MonoMethod *method)
-{
-       return mono_create_jit_trampoline_in_domain (mono_domain_get (), method);
-}
-
 gpointer
 mono_create_jit_trampoline_from_token (MonoImage *image, guint32 token)
 {
@@ -1523,11 +1547,13 @@ mono_create_jit_trampoline_from_token (MonoImage *image, guint32 token)
 /*
  * mono_create_delegate_trampoline_info:
  *
- *   Create a delegate trampoline for the KLASS+METHOD pair.
+ *  Create a trampoline info structure for the KLASS+METHOD pair.
  */
 MonoDelegateTrampInfo*
 mono_create_delegate_trampoline_info (MonoDomain *domain, MonoClass *klass, MonoMethod *method)
 {
+       MonoMethod *invoke;
+       MonoError error;
        MonoDelegateTrampInfo *tramp_info;
        MonoClassMethodPair pair, *dpair;
        guint32 code_size = 0;
@@ -1540,8 +1566,20 @@ mono_create_delegate_trampoline_info (MonoDomain *domain, MonoClass *klass, Mono
        if (tramp_info)
                return tramp_info;
 
-       tramp_info = create_delegate_trampoline_data (domain, klass, method);
+       invoke = mono_get_delegate_invoke (klass);
+       g_assert (invoke);
 
+       tramp_info = (MonoDelegateTrampInfo *)mono_domain_alloc0 (domain, sizeof (MonoDelegateTrampInfo));
+       tramp_info->invoke = invoke;
+       tramp_info->invoke_sig = mono_method_signature (invoke);
+       tramp_info->impl_this = mono_arch_get_delegate_invoke_impl (mono_method_signature (invoke), TRUE);
+       tramp_info->impl_nothis = mono_arch_get_delegate_invoke_impl (mono_method_signature (invoke), FALSE);
+       tramp_info->method = method;
+       if (method) {
+               mono_error_init (&error);
+               tramp_info->sig = mono_method_signature_checked (method, &error);
+               tramp_info->need_rgctx_tramp = mono_method_needs_static_rgctx_invoke (method, FALSE);
+       }
        tramp_info->invoke_impl = mono_create_specific_trampoline (tramp_info, MONO_TRAMPOLINE_DELEGATE, domain, &code_size);
        g_assert (code_size);