[metadata] Lock around special static fields hash access
[mono.git] / mono / mini / jit-icalls.c
index 39abeb285497461e407cb5f3f1bfb3dd0fa96d7b..401ac247e2a0569fb100aa530f9df08cb1682c03 100644 (file)
@@ -1,5 +1,6 @@
-/*
- * jit-icalls.c: internal calls used by the JIT
+/**
+ * \file
+ * internal calls used by the JIT
  *
  * Author:
  *   Dietmar Maurer (dietmar@ximian.com)
@@ -19,6 +20,7 @@
 
 #include "jit-icalls.h"
 #include <mono/utils/mono-error-internals.h>
+#include <mono/metadata/exception-internals.h>
 #include <mono/metadata/threads-types.h>
 #include <mono/metadata/reflection-internals.h>
 
@@ -71,10 +73,10 @@ ldvirtfn_internal (MonoObject *obj, MonoMethod *method, gboolean gshared)
        if (gshared && method->is_inflated && mono_method_get_context (method)->method_inst) {
                MonoGenericContext context = { NULL, NULL };
 
-               if (res->klass->generic_class)
-                       context.class_inst = res->klass->generic_class->context.class_inst;
-               else if (res->klass->generic_container)
-                       context.class_inst = res->klass->generic_container->context.class_inst;
+               if (mono_class_is_ginst (res->klass))
+                       context.class_inst = mono_class_get_generic_class (res->klass)->context.class_inst;
+               else if (mono_class_is_gtd (res->klass))
+                       context.class_inst = mono_class_get_generic_container (res->klass)->context.class_inst;
                context.method_inst = mono_method_get_context (method)->method_inst;
 
                res = mono_class_inflate_generic_method_checked (res, &context, &error);
@@ -886,11 +888,16 @@ mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
 
        //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
 
-       if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
+       if (field->offset == -1) {
+               /* Special static */
+               g_assert (domain->special_static_fields);
+               mono_domain_lock (domain);
+               addr = g_hash_table_lookup (domain->special_static_fields, field);
+               mono_domain_unlock (domain);
                addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
-       else
+       } else {
                addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
-       
+       }
        return addr;
 }
 
@@ -1107,8 +1114,8 @@ mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, gpointe
                return NULL;
        }
        vmethod = mono_object_get_virtual_method (obj, method);
-       g_assert (!vmethod->klass->generic_container);
-       g_assert (!vmethod->klass->generic_class || !vmethod->klass->generic_class->context.class_inst->is_open);
+       g_assert (!mono_class_is_gtd (vmethod->klass));
+       g_assert (!mono_class_is_ginst (vmethod->klass) || !mono_class_get_generic_class (vmethod->klass)->context.class_inst->is_open);
        g_assert (!context->method_inst || !context->method_inst->is_open);
 
        addr = mono_compile_method_checked (vmethod, &error);
@@ -1189,13 +1196,21 @@ mono_create_corlib_exception_0 (guint32 token)
 MonoException *
 mono_create_corlib_exception_1 (guint32 token, MonoString *arg)
 {
-       return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg, NULL);
+       MonoError error;
+       MonoException *ret = mono_exception_from_token_two_strings_checked (
+               mono_defaults.corlib, token, arg, NULL, &error);
+       mono_error_set_pending_exception (&error);
+       return ret;
 }
 
 MonoException *
 mono_create_corlib_exception_2 (guint32 token, MonoString *arg1, MonoString *arg2)
 {
-       return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg1, arg2);
+       MonoError error;
+       MonoException *ret = mono_exception_from_token_two_strings_checked (
+               mono_defaults.corlib, token, arg1, arg2, &error);
+       mono_error_set_pending_exception (&error);
+       return ret;
 }
 
 MonoObject*
@@ -1206,7 +1221,7 @@ mono_object_castclass_unbox (MonoObject *obj, MonoClass *klass)
        MonoClass *oklass;
 
        if (mini_get_debug_options ()->better_cast_details) {
-               jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
+               jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
                jit_tls->class_cast_from = NULL;
        }
 
@@ -1240,7 +1255,7 @@ mono_object_castclass_with_cache (MonoObject *obj, MonoClass *klass, gpointer *c
        gpointer cached_vtable, obj_vtable;
 
        if (mini_get_debug_options ()->better_cast_details) {
-               jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
+               jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
                jit_tls->class_cast_from = NULL;
        }
 
@@ -1323,9 +1338,9 @@ constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *k
        MonoMethod *m;
        int vt_slot, iface_offset;
 
-       mono_error_init (error);
+       error_init (error);
 
-       if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
+       if (mono_class_is_interface (klass)) {
                MonoObject *this_obj;
 
                /* Have to use the receiver's type instead of klass, the receiver is a ref type */
@@ -1343,7 +1358,7 @@ constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *k
                mono_class_setup_vtable (klass);
                g_assert (klass->vtable);
                vt_slot = mono_method_get_vtable_slot (cmethod);
-               if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
+               if (mono_class_is_interface (cmethod->klass)) {
                        iface_offset = mono_class_interface_offset (klass, cmethod->klass);
                        g_assert (iface_offset != -1);
                        vt_slot += iface_offset;
@@ -1487,15 +1502,15 @@ mono_fill_method_rgctx (MonoMethodRuntimeGenericContext *mrgctx, int index)
  * out parameter.
  */
 static gpointer
-resolve_iface_call (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg, gboolean caller_gsharedvt)
+resolve_iface_call (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg, gboolean caller_gsharedvt, MonoError *error)
 {
-       MonoError error;
        MonoVTable *vt;
        gpointer *imt, *vtable_slot;
        MonoMethod *impl_method, *generic_virtual = NULL, *variant_iface = NULL;
        gpointer addr, compiled_method, aot_addr;
        gboolean need_rgctx_tramp = FALSE, need_unbox_tramp = FALSE;
 
+       error_init (error);
        if (!this_obj)
                /* The caller will handle it */
                return NULL;
@@ -1503,11 +1518,12 @@ resolve_iface_call (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method,
        vt = this_obj->vtable;
        imt = (gpointer*)vt - MONO_IMT_SIZE;
 
-       vtable_slot = mini_resolve_imt_method (vt, imt + imt_slot, imt_method, &impl_method, &aot_addr, &need_rgctx_tramp, &variant_iface);
+       vtable_slot = mini_resolve_imt_method (vt, imt + imt_slot, imt_method, &impl_method, &aot_addr, &need_rgctx_tramp, &variant_iface, error);
+       return_val_if_nok (error, NULL);
 
        // FIXME: This can throw exceptions
-       addr = compiled_method = mono_compile_method_checked (impl_method, &error);
-       mono_error_assert_ok (&error);
+       addr = compiled_method = mono_compile_method_checked (impl_method, error);
+       mono_error_assert_ok (error);
        g_assert (addr);
 
        if (imt_method->is_inflated && ((MonoMethodInflated*)imt_method)->context.method_inst)
@@ -1537,7 +1553,13 @@ resolve_iface_call (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method,
 gpointer
 mono_resolve_iface_call_gsharedvt (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg)
 {
-       return resolve_iface_call (this_obj, imt_slot, imt_method, out_arg, TRUE);
+       MonoError error;
+       gpointer res = resolve_iface_call (this_obj, imt_slot, imt_method, out_arg, TRUE, &error);
+       if (!is_ok (&error)) {
+               MonoException *ex = mono_error_convert_to_exception (&error);
+               mono_llvm_throw_exception ((MonoObject*)ex);
+       }
+       return res;
 }
 
 static gboolean
@@ -1566,18 +1588,18 @@ is_generic_method_definition (MonoMethod *m)
  * out parameter.
  */
 static gpointer
-resolve_vcall (MonoVTable *vt, int slot, MonoMethod *imt_method, gpointer *out_arg, gboolean gsharedvt)
+resolve_vcall (MonoVTable *vt, int slot, MonoMethod *imt_method, gpointer *out_arg, gboolean gsharedvt, MonoError *error)
 {
-       MonoError error;
        MonoMethod *m, *generic_virtual = NULL;
        gpointer addr, compiled_method;
        gboolean need_unbox_tramp = FALSE;
 
+       error_init (error);
        /* Same as in common_call_trampoline () */
 
        /* Avoid loading metadata or creating a generic vtable if possible */
-       addr = mono_aot_get_method_from_vt_slot (mono_domain_get (), vt, slot, &error);
-       mono_error_raise_exception (&error); // FIXME: Don't raise here
+       addr = mono_aot_get_method_from_vt_slot (mono_domain_get (), vt, slot, error);
+       return_val_if_nok (error, NULL);
        if (addr && !vt->klass->valuetype)
                return mono_create_ftnptr (mono_domain_get (), addr);
 
@@ -1592,18 +1614,18 @@ resolve_vcall (MonoVTable *vt, int slot, MonoMethod *imt_method, gpointer *out_a
                else
                        declaring = m;
 
-               if (m->klass->generic_class)
-                       context.class_inst = m->klass->generic_class->context.class_inst;
+               if (mono_class_is_ginst (m->klass))
+                       context.class_inst = mono_class_get_generic_class (m->klass)->context.class_inst;
                else
-                       g_assert (!m->klass->generic_container);
+                       g_assert (!mono_class_is_gtd (m->klass));
 
                generic_virtual = imt_method;
                g_assert (generic_virtual);
                g_assert (generic_virtual->is_inflated);
                context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
 
-               m = mono_class_inflate_generic_method_checked (declaring, &context, &error);
-               mono_error_assert_ok (&error); /* FIXME don't swallow the error */
+               m = mono_class_inflate_generic_method_checked (declaring, &context, error);
+               mono_error_assert_ok (error); /* FIXME don't swallow the error */
        }
 
        if (generic_virtual) {
@@ -1614,9 +1636,12 @@ resolve_vcall (MonoVTable *vt, int slot, MonoMethod *imt_method, gpointer *out_a
                        need_unbox_tramp = TRUE;
        }
 
+       if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
+               m = mono_marshal_get_synchronized_wrapper (m);
+
        // FIXME: This can throw exceptions
-       addr = compiled_method = mono_compile_method_checked (m, &error);
-       mono_error_assert_ok (&error);
+       addr = compiled_method = mono_compile_method_checked (m, error);
+       mono_error_assert_ok (error);
        g_assert (addr);
 
        addr = mini_add_method_wrappers_llvmonly (m, addr, gsharedvt, need_unbox_tramp, out_arg);
@@ -1638,7 +1663,13 @@ mono_resolve_vcall_gsharedvt (MonoObject *this_obj, int slot, MonoMethod *imt_me
 {
        g_assert (this_obj);
 
-       return resolve_vcall (this_obj->vtable, slot, imt_method, out_arg, TRUE);
+       MonoError error;
+       gpointer result = resolve_vcall (this_obj->vtable, slot, imt_method, out_arg, TRUE, &error);
+       if (!is_ok (&error)) {
+               MonoException *ex = mono_error_convert_to_exception (&error);
+               mono_llvm_throw_exception ((MonoObject*)ex);
+       }
+       return result;
 }
 
 /*
@@ -1667,10 +1698,10 @@ mono_resolve_generic_virtual_call (MonoVTable *vt, int slot, MonoMethod *generic
        else
                declaring = m;
 
-       if (m->klass->generic_class)
-               context.class_inst = m->klass->generic_class->context.class_inst;
+       if (mono_class_is_ginst (m->klass))
+               context.class_inst = mono_class_get_generic_class (m->klass)->context.class_inst;
        else
-               g_assert (!m->klass->generic_container);
+               g_assert (!mono_class_is_gtd (m->klass));
 
        g_assert (generic_virtual->is_inflated);
        context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
@@ -1690,7 +1721,7 @@ mono_resolve_generic_virtual_call (MonoVTable *vt, int slot, MonoMethod *generic
 
        /*
         * This wastes memory but the memory usage is bounded since
-        * mono_method_add_generic_virtual_invocation () eventually builds an imt thunk for
+        * mono_method_add_generic_virtual_invocation () eventually builds an imt trampoline for
         * this vtable slot so we are not called any more for this instantiation.
         */
        MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
@@ -1720,21 +1751,27 @@ mono_resolve_generic_virtual_iface_call (MonoVTable *vt, int imt_slot, MonoMetho
 
        imt = (gpointer*)vt - MONO_IMT_SIZE;
 
-       mini_resolve_imt_method (vt, imt + imt_slot, generic_virtual, &m, &aot_addr, &need_rgctx_tramp, &variant_iface);
+       mini_resolve_imt_method (vt, imt + imt_slot, generic_virtual, &m, &aot_addr, &need_rgctx_tramp, &variant_iface, &error);
+       if (!is_ok (&error)) {
+               MonoException *ex = mono_error_convert_to_exception (&error);
+               mono_llvm_throw_exception ((MonoObject*)ex);
+       }
 
        if (vt->klass->valuetype)
                need_unbox_tramp = TRUE;
 
-       // FIXME: This can throw exceptions
+       if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
+               m = mono_marshal_get_synchronized_wrapper (m);
+
        addr = compiled_method = mono_compile_method_checked (m, &error);
-       mono_error_assert_ok (&error);
+       mono_error_raise_exception (&error);
        g_assert (addr);
 
        addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, &arg);
 
        /*
         * This wastes memory but the memory usage is bounded since
-        * mono_method_add_generic_virtual_invocation () eventually builds an imt thunk for
+        * mono_method_add_generic_virtual_invocation () eventually builds an imt trampoline for
         * this vtable slot so we are not called any more for this instantiation.
         */
        MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
@@ -1754,11 +1791,14 @@ mono_resolve_generic_virtual_iface_call (MonoVTable *vt, int imt_slot, MonoMetho
 gpointer
 mono_init_vtable_slot (MonoVTable *vtable, int slot)
 {
+       MonoError error;
        gpointer arg = NULL;
        gpointer addr;
        gpointer *ftnptr;
 
-       addr = resolve_vcall (vtable, slot, NULL, &arg, FALSE);
+       addr = resolve_vcall (vtable, slot, NULL, &arg, FALSE, &error);
+       if (mono_error_set_pending_exception (&error))
+               return NULL;
        ftnptr = mono_domain_alloc0 (vtable->domain, 2 * sizeof (gpointer));
        ftnptr [0] = addr;
        ftnptr [1] = arg;
@@ -1787,12 +1827,16 @@ mono_llvmonly_init_delegate (MonoDelegate *del)
         * but we don't have a a structure which could own its memory.
         */
        if (G_UNLIKELY (!ftndesc)) {
-               gpointer addr = mono_compile_method_checked (del->method, &error);
+               MonoMethod *m = del->method;
+               if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
+                       m = mono_marshal_get_synchronized_wrapper (m);
+
+               gpointer addr = mono_compile_method_checked (m, &error);
                if (mono_error_set_pending_exception (&error))
                        return;
 
-               if (del->method->klass->valuetype && mono_method_signature (del->method)->hasthis)
-                   addr = mono_aot_get_unbox_trampoline (del->method);
+               if (m->klass->valuetype && mono_method_signature (m)->hasthis)
+                   addr = mono_aot_get_unbox_trampoline (m);
 
                gpointer arg = mini_get_delegate_arg (del->method, addr);
 
@@ -1813,6 +1857,9 @@ mono_llvmonly_init_delegate_virtual (MonoDelegate *del, MonoObject *target, Mono
 
        method = mono_object_get_virtual_method (target, method);
 
+       if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
+               method = mono_marshal_get_synchronized_wrapper (method);
+
        del->method = method;
        del->method_ptr = mono_compile_method_checked (method, &error);
        if (mono_error_set_pending_exception (&error))
@@ -1825,12 +1872,9 @@ mono_llvmonly_init_delegate_virtual (MonoDelegate *del, MonoObject *target, Mono
 MonoObject*
 mono_get_assembly_object (MonoImage *image)
 {
-       MonoError error;
-       MonoObject *result;
-       result = (MonoObject*)mono_assembly_get_object_checked (mono_domain_get (), image->assembly, &error);
-       if (!result)
-               mono_error_set_pending_exception (&error);
-       return result;
+       ICALL_ENTRY();
+       MonoObjectHandle result = MONO_HANDLE_CAST (MonoObject, mono_assembly_get_object_handle (mono_domain_get (), image->assembly, &error));
+       ICALL_RETURN_OBJ (result);
 }
 
 MonoObject*
@@ -1871,15 +1915,20 @@ mono_interruption_checkpoint_from_trampoline (void)
 }
 
 void
-mono_throw_method_access (MonoMethod *callee, MonoMethod *caller)
+mono_throw_method_access (MonoMethod *caller, MonoMethod *callee)
 {
-       char *callee_name = mono_method_full_name (callee, 1);
        char *caller_name = mono_method_full_name (caller, 1);
+       char *callee_name = mono_method_full_name (callee, 1);
        MonoError error;
 
-       mono_error_init (&error);
-       mono_error_set_generic_error (&error, "System", "MethodAccessException", "Method `%s' is inaccessible from method `%s'\n", callee_name, caller_name);
+       error_init (&error);
+       mono_error_set_generic_error (&error, "System", "MethodAccessException", "Method `%s' is inaccessible from method `%s'", callee_name, caller_name);
        mono_error_set_pending_exception (&error);
        g_free (callee_name);
        g_free (caller_name);
 }
+
+void
+mono_dummy_jit_icall (void)
+{
+}