diff options
-rw-r--r-- | mono/mini/method-to-ir.c | 16 |
1 files changed, 16 insertions, 0 deletions
diff --git a/mono/mini/method-to-ir.c b/mono/mini/method-to-ir.c index 0b6a75d4aae..f4f9ed33892 100644 --- a/mono/mini/method-to-ir.c +++ b/mono/mini/method-to-ir.c @@ -2401,6 +2401,8 @@ mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSign #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) { + MonoInst *dummy_use; + MONO_EMIT_NULL_CHECK (cfg, this_reg); /* Make a call to delegate->invoke_impl */ @@ -2409,6 +2411,20 @@ mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSign call->inst.inst_offset = G_STRUCT_OFFSET (MonoDelegate, invoke_impl); MONO_ADD_INS (cfg->cbb, (MonoInst*)call); + /* We must emit a dummy use here because the delegate trampoline will + replace the 'this' argument with the delegate target making this activation + no longer a root for the delegate. + This is an issue for delegates that target collectible code such as dynamic + methods of GC'able assemblies. + + For a test case look into #667921. + + FIXME: a dummy use is not the best way to do it as the local register allocator + will put it on a caller save register and spil it around the call. + Ideally, we would either put it on a callee save register or only do the store part. + */ + EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]); + return (MonoInst*)call; } #endif |