diff options
author | Zoltan Varga <vargaz@gmail.com> | 2017-10-18 20:29:02 +0300 |
---|---|---|
committer | Ludovic Henry <luhenry@microsoft.com> | 2017-10-25 17:35:58 +0300 |
commit | e66d9abbb271c3d08589c09afce4afc80de2d3b6 (patch) | |
tree | 8ebb9bf18640624a8c2db85ff46b2e72a1e65f70 | |
parent | 1f4613aa1acacbea90a8aa82daeea4a449cf4df7 (diff) |
[llvm] Fix the returning of vtypes using a hidden argument in bitcode, in some cases, we forgot to generate the code to return the value, causing random data to be returned. Fixes #59956. (#5786)mono-5.4.1.72017-06
-rw-r--r-- | mono/mini/gshared.cs | 46 | ||||
-rw-r--r-- | mono/mini/mini-llvm.c | 15 |
2 files changed, 61 insertions, 0 deletions
diff --git a/mono/mini/gshared.cs b/mono/mini/gshared.cs index 61402f7a4ec..910a6df73f5 100644 --- a/mono/mini/gshared.cs +++ b/mono/mini/gshared.cs @@ -1996,6 +1996,23 @@ public class Tests Console.WriteLine ("X: " + iface.is_ref<AStruct3<string, int, int>> ()); return 0; } + + interface IFace59956 { + int foo<T> (); + } + + class Impl59956 : IFace59956 { + public int foo<T> () { + var builder = new SparseArrayBuilder<T>(true); + + return builder.Markers._count; + } + } + + public static int test_1_59956_regress () { + IFace59956 iface = new Impl59956 (); + return iface.foo<int> (); + } } // #13191 @@ -2013,6 +2030,35 @@ public class MobileServiceCollection<TTable, TCol> } } +// #59956 +internal struct Marker +{ + public Marker(int count, int index) { + } +} + +public struct ArrayBuilder<T> +{ + private T[] _array; + public int _count; + + public ArrayBuilder(int capacity) { + _array = new T[capacity]; + _count = 1; + } +} + +internal struct SparseArrayBuilder<T> +{ + private ArrayBuilder<Marker> _markers; + + public SparseArrayBuilder(bool initialize) : this () { + _markers = new ArrayBuilder<Marker> (10); + } + + public ArrayBuilder<Marker> Markers => _markers; +} + #if !__MOBILE__ public class GSharedTests : Tests { } diff --git a/mono/mini/mini-llvm.c b/mono/mini/mini-llvm.c index 694189a96ac..79b0c8585ae 100644 --- a/mono/mini/mini-llvm.c +++ b/mono/mini/mini-llvm.c @@ -7492,7 +7492,22 @@ mono_llvm_create_vars (MonoCompile *cfg) sig = mono_method_signature (cfg->method); if (cfg->gsharedvt && cfg->llvm_only) { + gboolean vretaddr = FALSE; + if (mini_is_gsharedvt_variable_signature (sig) && sig->ret->type != MONO_TYPE_VOID) { + vretaddr = TRUE; + } else { + MonoMethodSignature *sig = mono_method_signature (cfg->method); + LLVMCallInfo *linfo; + + linfo = get_llvm_call_info (cfg, sig); + vretaddr = (linfo->ret.storage == LLVMArgVtypeRetAddr || linfo->ret.storage == LLVMArgVtypeByRef || linfo->ret.storage == LLVMArgGsharedvtFixed || linfo->ret.storage == LLVMArgGsharedvtVariable || linfo->ret.storage == LLVMArgGsharedvtFixedVtype); + } + if (vretaddr) { + /* + * Creating vret_addr forces CEE_SETRET to store the result into it, + * so we don't have to generate any code in our OP_SETRET case. + */ cfg->vret_addr = mono_compile_create_var (cfg, &mono_get_intptr_class ()->byval_arg, OP_ARG); if (G_UNLIKELY (cfg->verbose_level > 1)) { printf ("vret_addr = "); |