diff options
author | Ludovic Henry <luhenry@microsoft.com> | 2018-03-08 05:48:23 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-03-08 05:48:23 +0300 |
commit | 7f6c3ef15b47f6409e4100355d15f140930f8e93 (patch) | |
tree | 2774090bbc9d834cc245b0bf0d05e4126acebb2c | |
parent | 30441ea0ac8fa090d8fb88ad5ed79b4d84212a3b (diff) |
[2017-10] Only null check target for delegate if method is not static. (#7476)
* Only null check target for delegate if method is not static. Fixes regression introduced by 1cfd52452a4af3fd6eee32f45a8067926af8479e.
* pass first stack arg to transform, so we get the correct delegate wrapper
the wrapper logic detects if the target method of a delegate is a static
method with an argument bound, and handles it properly in the generated
code.
fixes mono/tests/delegate14.cs
-rw-r--r-- | mono/mini/interp/interp-internals.h | 2 | ||||
-rw-r--r-- | mono/mini/interp/interp.c | 4 | ||||
-rw-r--r-- | mono/mini/interp/transform.c | 4 | ||||
-rw-r--r-- | mono/mini/method-to-ir.c | 6 | ||||
-rw-r--r-- | mono/tests/delegate14.cs | 22 |
5 files changed, 31 insertions, 7 deletions
diff --git a/mono/mini/interp/interp-internals.h b/mono/mini/interp/interp-internals.h index 894747e23d0..5cfed578253 100644 --- a/mono/mini/interp/interp-internals.h +++ b/mono/mini/interp/interp-internals.h @@ -137,7 +137,7 @@ extern int mono_interp_traceopt; extern GSList *jit_classes; MonoException * -mono_interp_transform_method (InterpMethod *imethod, ThreadContext *context); +mono_interp_transform_method (InterpMethod *imethod, ThreadContext *context, MonoDelegate *del); void mono_interp_transform_init (void); diff --git a/mono/mini/interp/interp.c b/mono/mini/interp/interp.c index d4a876c2cf6..d742f6539d8 100644 --- a/mono/mini/interp/interp.c +++ b/mono/mini/interp/interp.c @@ -1972,7 +1972,7 @@ do_transform_method (InterpFrame *frame, ThreadContext *context) /* Use the parent frame as the current frame is not complete yet */ interp_push_lmf (&ext, frame->parent); - frame->ex = mono_interp_transform_method (frame->imethod, context); + frame->ex = mono_interp_transform_method (frame->imethod, context, (MonoDelegate *) frame->stack_args [0].data.p); context->managed_code = 1; interp_pop_lmf (&ext); @@ -2456,7 +2456,7 @@ ves_exec_method_with_context (InterpFrame *frame, ThreadContext *context, unsign if (!new_method->transformed) { frame->ip = ip; - frame->ex = mono_interp_transform_method (new_method, context); + frame->ex = mono_interp_transform_method (new_method, context, NULL); if (frame->ex) goto exit_frame; } diff --git a/mono/mini/interp/transform.c b/mono/mini/interp/transform.c index 0bdb1580534..804235194f6 100644 --- a/mono/mini/interp/transform.c +++ b/mono/mini/interp/transform.c @@ -4261,7 +4261,7 @@ mono_interp_transform_init (void) } MonoException * -mono_interp_transform_method (InterpMethod *imethod, ThreadContext *context) +mono_interp_transform_method (InterpMethod *imethod, ThreadContext *context, MonoDelegate *del) { MonoError error; int i, align, size, offset; @@ -4340,7 +4340,7 @@ mono_interp_transform_method (InterpMethod *imethod, ThreadContext *context) char *wrapper_name = g_strdup_printf ("__icall_wrapper_%s", mi->name); nm = mono_marshal_get_icall_wrapper (mi->sig, wrapper_name, mi->func, TRUE); } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) { - nm = mono_marshal_get_delegate_invoke (method, NULL); + nm = mono_marshal_get_delegate_invoke (method, del); } else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) { nm = mono_marshal_get_delegate_begin_invoke (method); } else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) { diff --git a/mono/mini/method-to-ir.c b/mono/mini/method-to-ir.c index 3185a203fe8..f2808cdfd3b 100644 --- a/mono/mini/method-to-ir.c +++ b/mono/mini/method-to-ir.c @@ -3973,8 +3973,10 @@ handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, Mono /* Set target field */ /* Optimize away setting of NULL target */ if (!MONO_INS_IS_PCONST_NULL (target)) { - MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target->dreg, 0); - MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException"); + if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) { + MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target->dreg, 0); + MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException"); + } MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target), target->dreg); if (cfg->gen_write_barriers) { dreg = alloc_preg (cfg); diff --git a/mono/tests/delegate14.cs b/mono/tests/delegate14.cs index 2fd7d62b1fa..36c6f896e8a 100644 --- a/mono/tests/delegate14.cs +++ b/mono/tests/delegate14.cs @@ -6,6 +6,12 @@ public static class Program { public static int Main (string[] args) { + // calling delegate on extension method with null target is allowed + Func<int> func = null; + if (CallFunc(func.CallFuncIfNotNull) != 0) + return 2; + + // constructing delegate on instance method with null target should throw ITest obj = null; try { @@ -23,4 +29,20 @@ public static class Program { void Func (); } + + static int CallFunc(Func<int> func) + { + return func(); + } } + +public static class FuncExtensions +{ + public static int CallFuncIfNotNull(this Func<int> func) + { + if (func != null) + return func(); + + return 0; + } +}
\ No newline at end of file |