Fix crash in mono mini exceptions.exe regression test on win x64.
} catch (Exception ex) {
// FIXME: log it.
Console.WriteLine (ex);
- } finally {
- // unless it is closed by session/call manager, move it back to the loop to receive the next message.
- if (loop && input.State != CommunicationState.Closed)
- ProcessRequestOrInput (input);
}
}
bool _bReEntrant;
int _flavor;
- [NonSerialized]
- bool _locked;
[NonSerialized]
int _lockCount;
{
get
{
- return _locked;
+ return _lockCount > 0;
}
set
{
if (value)
{
- _mutex.WaitOne ();
+ AcquireLock ();
lock (this)
{
- _lockCount++;
if (_lockCount > 1)
ReleaseLock (); // Thread already had the lock
-
- _ownerThread = Thread.CurrentThread;
}
}
else
{
lock (this)
{
- while (_lockCount > 0 && _ownerThread == Thread.CurrentThread)
- {
- _lockCount--;
- _mutex.ReleaseMutex ();
- _ownerThread = null;
+ while (_lockCount > 0 && _ownerThread == Thread.CurrentThread) {
+ ReleaseLock ();
}
}
}
if (_lockCount > 0 && _ownerThread == Thread.CurrentThread) {
_lockCount--;
_mutex.ReleaseMutex ();
- _ownerThread = null;
+ if (_lockCount == 0) {
+ _ownerThread = null;
+ }
}
}
}
Assert.IsFalse (sa.Locked, "Locked");
}
+ [Test]
+ public void SetLocked()
+ {
+ SynchronizationAttribute sa = new SynchronizationAttribute(SynchronizationAttribute.REQUIRES_NEW);
+ sa.Locked = true;
+ Assert.IsTrue(sa.Locked, "Locked");
+ sa.Locked = false;
+ Assert.IsFalse(sa.Locked, "Locked");
+
+ sa.Locked = true;
+ Assert.IsTrue(sa.Locked, "Locked");
+ sa.Locked = true;
+ Assert.IsTrue(sa.Locked, "Locked");
+ sa.Locked = false;
+ Assert.IsFalse(sa.Locked, "Locked");
+ }
+
[Test]
public void SerializationRoundtrip ()
{
public void TestLocked1 ()
{
sincob.Lock (false);
+
Thread tr = new Thread (new ThreadStart (FirstSyncThread));
tr.Start ();
Thread.Sleep (200);
Assert.IsTrue (!otResult, "Concurrency detected in CallbackThread");
}
+ [Test]
+ public void TestSynchronizationReleasedOnMultipleAcquire ()
+ {
+
+ otResult = notreentrant.TestCallback ();
+
+ Thread tr = new Thread (new ThreadStart (CallbackThread));
+ tr.Start();
+
+ bool terminated = tr.Join(2000);
+ Assert.IsTrue(terminated, "Thread didn't get lock of context bound object.");
+
+ Assert.IsTrue (!otResult, "Concurrency detected in CallbackThread");
+ }
+
void CallbackThread ()
{
otResult = notreentrant.TestCallback ();
#define CLI_FLAGS_ILONLY 0x01
#define CLI_FLAGS_32BITREQUIRED 0x02
#define CLI_FLAGS_STRONGNAMESIGNED 0x8
-#define CLI_FLAGS_PREFERRED32BIT 0x10
#define CLI_FLAGS_TRACKDEBUGDATA 0x00010000
+#define CLI_FLAGS_PREFERRED32BIT 0x00020000
guint32 ch_flags;
guint32 ch_entry_point;
*/
}
if (dll_map->func && strcmp (dll_map->func, func) == 0) {
+ *rdll = dll_map->target;
*rfunc = dll_map->target_func;
break;
}
* @dll: The name of the external library, as it would be found in the DllImport declaration. If prefixed with 'i:' the matching of the library name is done without case sensitivity
* @func: if not null, the mapping will only applied to the named function (the value of EntryPoint)
* @tdll: The name of the library to map the specified @dll if it matches.
- * @tfunc: if func is not NULL, the name of the function that replaces the invocation
+ * @tfunc: The name of the function that replaces the invocation. If NULL, it is replaced with a copy of @func.
*
* LOCKING: Acquires the loader lock.
*
entry->dll = dll? g_strdup (dll): NULL;
entry->target = tdll? g_strdup (tdll): NULL;
entry->func = func? g_strdup (func): NULL;
- entry->target_func = tfunc? g_strdup (tfunc): NULL;
+ entry->target_func = tfunc? g_strdup (tfunc): (func? g_strdup (func): NULL);
global_loader_data_lock ();
entry->next = global_dll_map;
entry->dll = dll? mono_image_strdup (assembly, dll): NULL;
entry->target = tdll? mono_image_strdup (assembly, tdll): NULL;
entry->func = func? mono_image_strdup (assembly, func): NULL;
- entry->target_func = tfunc? mono_image_strdup (assembly, tfunc): NULL;
+ entry->target_func = tfunc? mono_image_strdup (assembly, tfunc): (func? mono_image_strdup (assembly, func): NULL);
mono_image_lock (assembly);
entry->next = assembly->dll_map;
* ARGS should contain the this argument too.
* This wrapper serves the same purpose as the runtime-invoke wrappers, but there
* is only one copy of it, which is useful in full-aot.
- * The wrapper info for the wrapper is a WrapperInfo structure.
*/
MonoMethod*
mono_marshal_get_runtime_invoke_dynamic (void)
/*
* generates IL code for the icall wrapper (the generated method
* calls the unmanaged code in func)
- * The wrapper info for the wrapper is a WrapperInfo structure.
*/
MonoMethod *
mono_marshal_get_icall_wrapper (MonoMethodSignature *sig, const char *name, gconstpointer func, gboolean check_exceptions)
*
* generates IL code for the pinvoke wrapper (the generated method
* calls the unmanaged code in piinfo->addr)
- * The wrapper info for the wrapper is a WrapperInfo structure.
*/
MonoMethod *
mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions, gboolean aot)
/*
* This does the equivalent of mono_object_castclass_with_cache.
- * The wrapper info for the wrapper is a WrapperInfo structure.
*/
MonoMethod *
mono_marshal_get_castclass_with_cache (void)
/*
* This does the equivalent of mono_object_isinst_with_cache.
- * The wrapper info for the wrapper is a WrapperInfo structure.
*/
MonoMethod *
mono_marshal_get_isinst_with_cache (void)
* an instance of the given type, icluding the case where the object is a proxy.
* The generated function has the following signature:
* MonoObject* __castclass_wrapper_ (MonoObject *obj)
- * The wrapper info for the wrapper is a WrapperInfo structure.
*/
MonoMethod *
mono_marshal_get_castclass (MonoClass *klass)
* @klass:
*
* generates IL code for StructureToPtr (object structure, IntPtr ptr, bool fDeleteOld)
- * The wrapper info for the wrapper is a WrapperInfo structure.
*/
MonoMethod *
mono_marshal_get_struct_to_ptr (MonoClass *klass)
* @klass:
*
* generates IL code for PtrToStructure (IntPtr src, object structure)
- * The wrapper info for the wrapper is a WrapperInfo structure.
*/
MonoMethod *
mono_marshal_get_ptr_to_struct (MonoClass *klass)
* This is used to avoid infinite recursion since it is hard to determine where to
* replace a method with its synchronized wrapper, and where not.
* The runtime should execute METHOD instead of the wrapper.
- * The wrapper info for the wrapper is a WrapperInfo structure.
*/
MonoMethod *
mono_marshal_get_synchronized_inner_wrapper (MonoMethod *method)
#endif
/*
- * The wrapper info for the wrapper is a WrapperInfo structure.
- *
* TODO:
* - Separate simple interfaces from variant interfaces or mbr types. This way we can avoid the icall for them.
* - Emit a (new) mono bytecode that produces OP_COND_EXC_NE_UN to raise ArrayTypeMismatch
return res;
}
-/*
- * The wrapper info for the wrapper is a WrapperInfo structure.
- */
MonoMethod*
mono_marshal_get_stelemref (void)
{
* mono_marshal_get_gsharedvt_in_wrapper:
*
* This wrapper handles calls from normal code to gsharedvt code.
- *
- * The wrapper info for the wrapper is a WrapperInfo structure.
*/
MonoMethod*
mono_marshal_get_gsharedvt_in_wrapper (void)
* mono_marshal_get_gsharedvt_out_wrapper:
*
* This wrapper handles calls from gsharedvt code to normal code.
- *
- * The wrapper info for the wrapper is a WrapperInfo structure.
*/
MonoMethod*
mono_marshal_get_gsharedvt_out_wrapper (void)
if (!read32 (ptr + 8) || !read32 (ptr + 12))
ADD_ERROR (ctx, g_strdup_printf ("Missing medatata section in the CLI header"));
- if ((read32 (ptr + 16) & ~0x0001000B) != 0)
+ if ((read32 (ptr + 16) & ~0x0003000B) != 0)
ADD_ERROR (ctx, g_strdup_printf ("Invalid CLI header flags"));
ptr += 24;
if (acfg->aot_opts.mtriple && strstr (acfg->aot_opts.mtriple, "darwin")) {
g_string_append (acfg->llc_args, "-mattr=+v6");
} else {
-#ifdef ARM_FPU_VFP
+#if defined(ARM_FPU_VFP_HARD)
+ g_string_append (acfg->llc_args, " -mattr=+vfp2,-neon,+d16 -float-abi=hard");
+ g_string_append (acfg->as_args, " -mfpu=vfp3");
+#elif defined(ARM_FPU_VFP)
g_string_append (acfg->llc_args, " -mattr=+vfp2,-neon,+d16");
g_string_append (acfg->as_args, " -mfpu=vfp3");
#else
msg = g_strdup_printf ("not compiled with --aot=llvmonly");
usable = FALSE;
}
-#ifdef TARGET_ARM
- /* mono_arch_find_imt_method () requires this */
- if ((info->flags & MONO_AOT_FILE_FLAG_WITH_LLVM) && !mono_use_llvm) {
- msg = g_strdup_printf ("compiled against LLVM");
- usable = FALSE;
- }
- if (!(info->flags & MONO_AOT_FILE_FLAG_WITH_LLVM) && mono_use_llvm) {
- msg = g_strdup_printf ("not compiled against LLVM");
- usable = FALSE;
- }
-#endif
if (mini_get_debug_options ()->mdb_optimizations && !(info->flags & MONO_AOT_FILE_FLAG_DEBUG) && !full_aot) {
msg = g_strdup_printf ("not compiled for debugging");
usable = FALSE;
}
[Category ("!FULLAOT")]
+ [Category ("!BITCODE")]
public static int test_0_regress_668095_synchronized_gshared () {
return DoSomething (new DefaultRetriever ());
}
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);
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);
* 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);
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))
inline_costs += 10 * num_calls++;
+ /*
+ * Synchronized wrappers.
+ * Its hard to determine where to replace a method with its synchronized
+ * wrapper without causing an infinite recursion. The current solution is
+ * to add the synchronized wrapper in the trampolines, and to
+ * change the called method to a dummy wrapper, and resolve that wrapper
+ * to the real method in mono_jit_compile_method ().
+ */
+ if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
+ MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
+ if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
+ cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
+ }
+
/*
* Making generic calls out of gsharedvt methods.
* This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
}
}
- /*
- * Synchronized wrappers.
- * Its hard to determine where to replace a method with its synchronized
- * wrapper without causing an infinite recursion. The current solution is
- * to add the synchronized wrapper in the trampolines, and to
- * change the called method to a dummy wrapper, and resolve that wrapper
- * to the real method in mono_jit_compile_method ().
- */
- if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
- MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
- if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
- cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
- }
-
/*
* Virtual calls in llvm-only mode.
*/
MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
+ if (ins_flag & MONO_INST_VOLATILE) {
+ /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
+ emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
+ }
+
if (mini_is_gsharedvt_klass (klass)) {
MonoInst *offset_ins;
MonoMethod *inflated_method;
MonoType *inflated_type = mono_class_inflate_generic_type_checked (&method->klass->byval_arg, context, &error);
mono_error_assert_ok (&error); /* FIXME don't swallow the error */
+ WrapperInfo *winfo = NULL;
MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
MonoJumpInfoGSharedVtCall *res;
mono_class_init (inflated_class);
- g_assert (!method->wrapper_type);
+ if (method->wrapper_type) {
+ winfo = mono_marshal_get_wrapper_info (method);
+
+ g_assert (winfo);
+ g_assert (winfo->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER);
+ method = winfo->d.synchronized_inner.method;
+ }
if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
}
mono_class_init (inflated_method->klass);
g_assert (inflated_method->klass == inflated_class);
+
+ if (winfo) {
+ g_assert (winfo->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER);
+ inflated_method = mono_marshal_get_synchronized_inner_wrapper (inflated_method);
+ }
+
res->method = inflated_method;
return res;
g_assert (method->is_inflated);
+ if (mono_llvm_only && (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED))
+ method = mono_marshal_get_synchronized_wrapper (method);
+
if (!virtual_) {
addr = mono_compile_method_checked (method, error);
return_val_if_nok (error, NULL);
LLVMValueRef
mono_llvm_build_load (LLVMBuilderRef builder, LLVMValueRef PointerVal,
- const char *Name, gboolean is_volatile, BarrierKind barrier)
+ const char *Name, gboolean is_volatile)
{
LoadInst *ins = unwrap(builder)->CreateLoad(unwrap(PointerVal), is_volatile, Name);
+ return wrap(ins);
+}
+
+LLVMValueRef
+mono_llvm_build_atomic_load (LLVMBuilderRef builder, LLVMValueRef PointerVal,
+ const char *Name, gboolean is_volatile, int alignment, BarrierKind barrier)
+{
+ LoadInst *ins = unwrap(builder)->CreateLoad(unwrap(PointerVal), is_volatile, Name);
+
+ ins->setAlignment (alignment);
switch (barrier) {
case LLVM_BARRIER_NONE:
break;
LLVMValueRef
mono_llvm_build_load (LLVMBuilderRef builder, LLVMValueRef PointerVal,
- const char *Name, gboolean is_volatile, BarrierKind barrier);
+ const char *Name, gboolean is_volatile);
LLVMValueRef
+mono_llvm_build_atomic_load (LLVMBuilderRef builder, LLVMValueRef PointerVal,
+ const char *Name, gboolean is_volatile, int alignment, BarrierKind barrier);
+
+LLVMValueRef
mono_llvm_build_aligned_load (LLVMBuilderRef builder, LLVMValueRef PointerVal,
const char *Name, gboolean is_volatile, int alignment);
* LLVM will generate invalid code when encountering a load from a
* NULL address.
*/
- res = mono_llvm_build_load (*builder_ref, addr, name, is_faulting, barrier);
+ if (barrier != LLVM_BARRIER_NONE)
+ res = mono_llvm_build_atomic_load (*builder_ref, addr, name, is_faulting, size, barrier);
+ else
+ res = mono_llvm_build_load (*builder_ref, addr, name, is_faulting);
- /* Mark it with a custom metadata */
- /*
- if (is_faulting)
- set_metadata_flag (res, "mono.faulting.load");
- */
+ /* Mark it with a custom metadata */
+ /*
+ if (is_faulting)
+ set_metadata_flag (res, "mono.faulting.load");
+ */
- return res;
+ return res;
}
}
if (!ctx->imt_rgctx_loc)
ctx->imt_rgctx_loc = build_alloca_llvm_type (ctx, ctx->module->ptr_type, sizeof (gpointer));
LLVMBuildStore (builder, convert (ctx, ctx->values [call->rgctx_arg_reg], ctx->module->ptr_type), ctx->imt_rgctx_loc);
- args [cinfo->rgctx_arg_pindex] = mono_llvm_build_load (builder, ctx->imt_rgctx_loc, "", TRUE, LLVM_BARRIER_NONE);
+ args [cinfo->rgctx_arg_pindex] = mono_llvm_build_load (builder, ctx->imt_rgctx_loc, "", TRUE);
#else
args [cinfo->rgctx_arg_pindex] = convert (ctx, values [call->rgctx_arg_reg], ctx->module->ptr_type);
#endif
if (!ctx->imt_rgctx_loc)
ctx->imt_rgctx_loc = build_alloca_llvm_type (ctx, ctx->module->ptr_type, sizeof (gpointer));
LLVMBuildStore (builder, convert (ctx, ctx->values [call->imt_arg_reg], ctx->module->ptr_type), ctx->imt_rgctx_loc);
- args [cinfo->imt_arg_pindex] = mono_llvm_build_load (builder, ctx->imt_rgctx_loc, "", TRUE, LLVM_BARRIER_NONE);
+ args [cinfo->imt_arg_pindex] = mono_llvm_build_load (builder, ctx->imt_rgctx_loc, "", TRUE);
#else
args [cinfo->imt_arg_pindex] = convert (ctx, values [call->imt_arg_reg], ctx->module->ptr_type);
#endif
case OP_ATOMIC_LOAD_U8:
case OP_ATOMIC_LOAD_R4:
case OP_ATOMIC_LOAD_R8: {
- //#if LLVM_API_VERSION > 100
-#if 0
+#if LLVM_API_VERSION > 100
int size;
gboolean sext, zext;
LLVMTypeRef t;
BarrierKind barrier = (BarrierKind) ins->backend.memory_barrier_kind;
LLVMValueRef index, addr, value, base;
+#if LLVM_API_VERSION < 100
if (!cfg->llvm_only) {
set_failure (ctx, "atomic mono.store intrinsic");
break;
}
+#endif
if (!values [ins->inst_destbasereg]) {
set_failure (ctx, "inst_destbasereg");
* mono_threads_state_poll ();
* FIXME: Use a preserveall wrapper
*/
- val = mono_llvm_build_load (builder, convert (ctx, lhs, LLVMPointerType (IntPtrType (), 0)), "", TRUE, LLVM_BARRIER_NONE);
+ val = mono_llvm_build_load (builder, convert (ctx, lhs, LLVMPointerType (IntPtrType (), 0)), "", TRUE);
cmp = LLVMBuildICmp (builder, LLVMIntEQ, val, LLVMConstNull (LLVMTypeOf (val)), "");
poll_bb = gen_bb (ctx, "POLL_BB");
cont_bb = gen_bb (ctx, "CONT_BB");
while (g_hash_table_iter_next (&iter, (void**)&method, (void**)&callers)) {
LLVMValueRef lmethod;
+ if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
+ continue;
+
lmethod = (LLVMValueRef)g_hash_table_lookup (module->method_to_lmethod, method);
if (lmethod) {
for (l = callers; l; l = l->next) {
mono_error_init (error);
+ if (mono_llvm_only)
+ /* Should be handled by the caller */
+ g_assert (!(method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED));
+
/*
* ICALL wrappers are handled specially, since there is only one copy of them
* shared by all appdomains.
mono_error_init (error);
if (mono_aot_only) {
+ if (mono_llvm_only && method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
+ method = mono_marshal_get_synchronized_wrapper (method);
+
/* Avoid creating trampolines if possible */
gpointer code = mono_jit_find_compiled_method (domain, method);