From: Rodrigo Kumpera Date: Sat, 27 May 2017 19:27:37 +0000 (-0700) Subject: Merge pull request #4928 from kumpera/ptr_to_struct_intrinsic X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=commitdiff_plain;h=992525a6df9b644412d4eaf271825128aa5defd5;hp=ed0b9b227bff804ebd25b7bdfd7958c9b861aa20;p=mono.git Merge pull request #4928 from kumpera/ptr_to_struct_intrinsic [mini] Intrinsify Marshal.PtrToStructure --- diff --git a/configure.ac b/configure.ac index 86a2354b389..c5c7ba58b9e 100644 --- a/configure.ac +++ b/configure.ac @@ -40,7 +40,7 @@ MONO_VERSION_BUILD=`echo $VERSION | cut -d . -f 3` # This can be reset to 0 when Mono's version number is bumped # since it's part of the corlib version (the prefix '1' in the full # version number is to ensure the number isn't treated as octal in C) -MONO_CORLIB_COUNTER=1 +MONO_CORLIB_COUNTER=2 MONO_CORLIB_VERSION=`printf "1%02d%02d%02d%03d" $MONO_VERSION_MAJOR $MONO_VERSION_MINOR $MONO_VERSION_BUILD $MONO_CORLIB_COUNTER` AC_DEFINE_UNQUOTED(MONO_CORLIB_VERSION,$MONO_CORLIB_VERSION,[Version of the corlib-runtime interface]) diff --git a/external/bockbuild b/external/bockbuild index c783777342f..7dba4865168 160000 --- a/external/bockbuild +++ b/external/bockbuild @@ -1 +1 @@ -Subproject commit c783777342f4d39b58f3c2e6a1659eedf504ac87 +Subproject commit 7dba4865168e7719aacf21bec5497ae99f8a86e4 diff --git a/mcs/class/Mono.Posix/Assembly/AssemblyInfo.cs b/mcs/class/Mono.Posix/Assembly/AssemblyInfo.cs index e26c50b01cd..ce6b749678d 100644 --- a/mcs/class/Mono.Posix/Assembly/AssemblyInfo.cs +++ b/mcs/class/Mono.Posix/Assembly/AssemblyInfo.cs @@ -34,9 +34,16 @@ using System.Reflection; using System.Runtime.InteropServices; using System.Security.Permissions; -[assembly: AssemblyVersion (Consts.FxVersion)] + +#if MONO_POSIX_NETSTANDARD_BUILD +[assembly: AssemblyVersion ("1.0.0.0")] +[assembly: AssemblyTitle("Mono.Posix.NETStandard.dll")] +#else +[assembly: AssemblyVersion (Consts.FxVersion)] [assembly: AssemblyTitle("Mono.Posix.dll")] +#endif + [assembly: AssemblyDescription("Unix Integration Classes")] [assembly: CLSCompliant (true)] @@ -48,9 +55,11 @@ using System.Security.Permissions; */ +#if !MONO_POSIX_NETSTANDARD_BUILD +// We are using ../Open.snk for MONO_POSIX_NETSTANDARD_BUILD [assembly: AssemblyDelaySign (true)] [assembly: AssemblyKeyFile ("../mono.pub")] - +#endif /* * TODO: * diff --git a/mcs/class/Mono.Posix/Mono.Posix.NETStandard-netstandard_2_0.csproj b/mcs/class/Mono.Posix/Mono.Posix.NETStandard-netstandard_2_0.csproj new file mode 100644 index 00000000000..85635867d3e --- /dev/null +++ b/mcs/class/Mono.Posix/Mono.Posix.NETStandard-netstandard_2_0.csproj @@ -0,0 +1,35 @@ + + + + netstandard2.0 + true + Mono.Posix.NETStandard + false + false + false + false + true + true + ..\Open.snk + + + + + $(DefineConstants);MONO_POSIX_NETSTANDARD_BUILD + + + + $(DefineConstants);FORCE_USE_LIBC_NOT_MSVC + + + + + + + + + + + + diff --git a/mcs/class/Mono.Posix/Mono.Unix.Native/Stdlib.cs b/mcs/class/Mono.Posix/Mono.Unix.Native/Stdlib.cs index dbabb29c7f1..59b66ca26fb 100644 --- a/mcs/class/Mono.Posix/Mono.Unix.Native/Stdlib.cs +++ b/mcs/class/Mono.Posix/Mono.Unix.Native/Stdlib.cs @@ -309,6 +309,7 @@ namespace Mono.Unix.Native { public delegate void SignalHandler (int signal); +#if !NETSTANDARD2_0 internal class XPrintfFunctions { internal delegate object XPrintf (object[] parameters); @@ -335,6 +336,7 @@ namespace Mono.Unix.Native { syslog = new XPrintf (_syslog.Invoke); } } +#endif // // Convention: Functions that are part of the C standard library go here. @@ -378,7 +380,11 @@ namespace Mono.Unix.Native { // public class Stdlib { +#if FORCE_USE_LIBC_NOT_MSVC + internal const string LIBC = "c"; +#else internal const string LIBC = "msvcrt"; +#endif internal const string MPH = "MonoPosixHelper"; // It is possible for Mono.Posix and MonoPosixHelper to get out of sync, @@ -771,6 +777,7 @@ namespace Mono.Unix.Native { return sys_fprintf (stream, "%s", message); } +#if !NETSTANDARD2_0 [Obsolete ("Not necessarily portable due to cdecl restrictions.\n" + "Use fprintf (IntPtr, string) instead.")] public static int fprintf (IntPtr stream, string format, params object[] parameters) @@ -781,6 +788,7 @@ namespace Mono.Unix.Native { Array.Copy (parameters, 0, _parameters, 2, parameters.Length); return (int) XPrintfFunctions.fprintf (_parameters); } +#endif /* SKIP: fscanf(3) */ @@ -793,6 +801,7 @@ namespace Mono.Unix.Native { return sys_printf ("%s", message); } +#if !NETSTANDARD2_0 [Obsolete ("Not necessarily portable due to cdecl restrictions.\n" + "Use printf (string) instead.")] public static int printf (string format, params object[] parameters) @@ -802,6 +811,7 @@ namespace Mono.Unix.Native { Array.Copy (parameters, 0, _parameters, 1, parameters.Length); return (int) XPrintfFunctions.printf (_parameters); } +#endif /* SKIP: scanf(3) */ @@ -823,6 +833,7 @@ namespace Mono.Unix.Native { return sys_snprintf (s, (ulong) s.Capacity, "%s", message); } +#if !NETSTANDARD2_0 [CLSCompliant (false)] [Obsolete ("Not necessarily portable due to cdecl restrictions.\n" + "Use snprintf (StringBuilder, string) instead.")] @@ -853,6 +864,7 @@ namespace Mono.Unix.Native { Array.Copy (parameters, 0, _parameters, 3, parameters.Length); return (int) XPrintfFunctions.snprintf (_parameters); } +#endif /* * SKIP: diff --git a/mcs/class/Mono.Posix/Mono.Unix.Native/Syscall.cs b/mcs/class/Mono.Posix/Mono.Unix.Native/Syscall.cs index 4ae330d5b46..c750e5fa86b 100644 --- a/mcs/class/Mono.Posix/Mono.Unix.Native/Syscall.cs +++ b/mcs/class/Mono.Posix/Mono.Unix.Native/Syscall.cs @@ -4387,6 +4387,7 @@ namespace Mono.Unix.Native { return UnixMarshal.EscapeFormatString (message, new char[]{'m'}); } +#if !NETSTANDARD2_0 [Obsolete ("Not necessarily portable due to cdecl restrictions.\n" + "Use syslog(SyslogFacility, SyslogLevel, string) instead.")] public static int syslog (SyslogFacility facility, SyslogLevel level, @@ -4415,6 +4416,7 @@ namespace Mono.Unix.Native { Array.Copy (parameters, 0, _parameters, 2, parameters.Length); return (int) XPrintfFunctions.syslog (_parameters); } +#endif [DllImport (MPH, SetLastError=true, EntryPoint="Mono_Posix_Syscall_closelog")] diff --git a/mcs/class/Mono.Posix/Test/Mono.Unix.Native/StdlibTest.cs b/mcs/class/Mono.Posix/Test/Mono.Unix.Native/StdlibTest.cs index aa0c06b76c6..e429af7f726 100644 --- a/mcs/class/Mono.Posix/Test/Mono.Unix.Native/StdlibTest.cs +++ b/mcs/class/Mono.Posix/Test/Mono.Unix.Native/StdlibTest.cs @@ -56,7 +56,7 @@ namespace MonoTests.Mono.Unix.Native { Assert.IsFalse (NativeConvert.ToSignum (st.signalReceived) == Signum.SIGURG, "#IH: Signal Handler invoked when it should have been removed!"); } - +#if !NETCOREAPP2_0 [Test] // MSVCRT.DLL doesn't export snprintf(3). [Category ("NotDotNet")] @@ -92,6 +92,7 @@ namespace MonoTests.Mono.Unix.Native { Assert.AreEqual (s.ToString(), expected, "#SNPF: printf of many builtin types failed"); } +#endif } } diff --git a/mcs/class/corlib/Mono/RuntimeStructs.cs b/mcs/class/corlib/Mono/RuntimeStructs.cs index f70ee556ac6..92884a2591d 100644 --- a/mcs/class/corlib/Mono/RuntimeStructs.cs +++ b/mcs/class/corlib/Mono/RuntimeStructs.cs @@ -51,7 +51,7 @@ namespace Mono { // handle.h HandleStackMark struct HandleStackMark { - int size; + int size, interior_size; IntPtr chunk; } diff --git a/mcs/class/corlib/System.IO/FileStream.cs b/mcs/class/corlib/System.IO/FileStream.cs index 664d9305745..f6b752d1784 100644 --- a/mcs/class/corlib/System.IO/FileStream.cs +++ b/mcs/class/corlib/System.IO/FileStream.cs @@ -224,14 +224,6 @@ namespace System.IO } } - if (access == FileAccess.Read && mode != FileMode.Create && mode != FileMode.OpenOrCreate && - mode != FileMode.CreateNew && !File.Exists (path)) { - // don't leak the path information for isolated storage - string msg = Locale.GetText ("Could not find file \"{0}\"."); - string fname = GetSecureFileName (path); - throw new FileNotFoundException (String.Format (msg, fname), fname); - } - // IsolatedStorage needs to keep the Name property to the default "[Unknown]" if (!anonymous) this.name = path; diff --git a/mcs/class/corlib/System/TimeZoneInfo.cs b/mcs/class/corlib/System/TimeZoneInfo.cs index 5c812b6f592..1c5cdd3ae82 100644 --- a/mcs/class/corlib/System/TimeZoneInfo.cs +++ b/mcs/class/corlib/System/TimeZoneInfo.cs @@ -574,11 +574,17 @@ namespace System #if LIBC private static TimeZoneInfo FindSystemTimeZoneByFileName (string id, string filepath) { - if (!File.Exists (filepath)) - throw new TimeZoneNotFoundException (); - - using (FileStream stream = File.OpenRead (filepath)) { + FileStream stream = null; + try { + stream = File.OpenRead (filepath); + } catch (Exception ex) { + throw new TimeZoneNotFoundException ("Couldn't read time zone file " + filepath, ex); + } + try { return BuildFromStream (id, stream); + } finally { + if (stream != null) + stream.Dispose(); } } #endif diff --git a/mcs/class/corlib/Test/System.IO/FileTest.cs b/mcs/class/corlib/Test/System.IO/FileTest.cs index cf95e49fa3a..4fc95243fe0 100644 --- a/mcs/class/corlib/Test/System.IO/FileTest.cs +++ b/mcs/class/corlib/Test/System.IO/FileTest.cs @@ -14,6 +14,8 @@ using System; using System.IO; using System.Globalization; using System.Threading; +using System.Runtime.InteropServices; + using NUnit.Framework; @@ -2680,5 +2682,53 @@ namespace MonoTests.System.IO MoveTest (FileAccess.ReadWrite, FileShare.Write | FileShare.Delete, true); MoveTest (FileAccess.ReadWrite, FileShare.ReadWrite | FileShare.Delete, true); } + + + [DllImport ("libc", SetLastError=true)] + public static extern int symlink (string oldpath, string newpath); + + [Test] + public void SymLinkLoop () + { + if (!RunningOnUnix) + Assert.Ignore ("Symlink are hard on windows"); + + var name1 = Path.GetRandomFileName (); + var name2 = Path.GetRandomFileName (); + + var path1 = Path.Combine (Path.GetTempPath (), name1); + var path2 = Path.Combine (Path.GetTempPath (), name2); + + File.Delete (path1); + File.Delete (path2); + + try { + symlink (path1, path2); + symlink (path2, path1); + + Assert.IsTrue (File.Exists (path1), "File.Exists must return true for path1 symlink loop"); + Assert.IsTrue (File.Exists (path2), "File.Exists must return true for path2 symlink loop"); + + try { + using (var f = File.Open (path1, FileMode.Open, FileAccess.Read)) { + Assert.Fail ("File.Open must throw for symlink loops"); + } + } catch (IOException ex) { + Assert.AreEqual (0x80070781u, (uint)ex.HResult, "Ensure HRESULT is correct"); + } + + File.Delete (path1); //Delete must not throw and must work + Assert.IsFalse (File.Exists (path1), "File.Delete must delete symlink loops"); + + } finally { + try { + File.Delete (path1); + File.Delete (path2); + } catch (IOException) { + //Don't double fault any exception from the tests. + } + + } + } } } diff --git a/mcs/class/corlib/Test/System/DecimalTest-Microsoft.cs b/mcs/class/corlib/Test/System/DecimalTest-Microsoft.cs index 261e9b56925..c168a31e426 100644 --- a/mcs/class/corlib/Test/System/DecimalTest-Microsoft.cs +++ b/mcs/class/corlib/Test/System/DecimalTest-Microsoft.cs @@ -14,6 +14,8 @@ using System.Runtime.CompilerServices; using System.Threading; using System.Collections.Generic; +#pragma warning disable CS1718 + namespace MonoTests.System { [TestFixture] diff --git a/mcs/class/corlib/corert/Debug.cs b/mcs/class/corlib/corert/Debug.cs index eda79f7927d..31959c17398 100644 --- a/mcs/class/corlib/corert/Debug.cs +++ b/mcs/class/corlib/corert/Debug.cs @@ -2,8 +2,6 @@ namespace System.Diagnostics.Private { static partial class Debug { - static readonly string NewLine = Environment.NewLine; - static void ShowAssertDialog (string stackTrace, string message, string detailMessage) { // FIXME should we g_error in this case? diff --git a/mcs/class/referencesource/mscorlib/system/io/filesystemenumerable.cs b/mcs/class/referencesource/mscorlib/system/io/filesystemenumerable.cs index 145bbb5424b..c9fca00b3e4 100644 --- a/mcs/class/referencesource/mscorlib/system/io/filesystemenumerable.cs +++ b/mcs/class/referencesource/mscorlib/system/io/filesystemenumerable.cs @@ -783,9 +783,10 @@ namespace System.IO internal override DirectoryInfo CreateObject(SearchResult result) { String name = result.FullPath; - String permissionName = name + "\\."; #if MONO_FEATURE_CAS + String permissionName = name + "\\."; + #if FEATURE_CORECLR FileSecurityState state = new FileSecurityState(FileSecurityStateAccess.Read, String.Empty, permissionName); state.EnsureState(); @@ -821,9 +822,10 @@ namespace System.IO if (isDir) { String name = result.FullPath; - String permissionName = name + "\\."; #if MONO_FEATURE_CAS + String permissionName = name + "\\."; + #if FEATURE_CORECLR FileSecurityState state = new FileSecurityState(FileSecurityStateAccess.Read, String.Empty, permissionName); state.EnsureState(); diff --git a/mcs/errors/cs1031-3.cs b/mcs/errors/cs1031-3.cs new file mode 100644 index 00000000000..3126dfaa48b --- /dev/null +++ b/mcs/errors/cs1031-3.cs @@ -0,0 +1,18 @@ +// CS1031: Type expected +// Line: 16 + +public class B where Y: B +{ +} + +public class A: B> +{ +} + +public class Repro +{ + public static void Main (string[] args) + { + var h = typeof (B>); + } +} \ No newline at end of file diff --git a/mcs/mcs/cs-tokenizer.cs b/mcs/mcs/cs-tokenizer.cs index e6a95fe8163..d6314ff005a 100644 --- a/mcs/mcs/cs-tokenizer.cs +++ b/mcs/mcs/cs-tokenizer.cs @@ -1267,7 +1267,8 @@ namespace Mono.CSharp else if (the_token == Token.INTERR_NULLABLE || the_token == Token.STAR) goto again; else if (the_token == Token.OP_GENERICS_LT) { - if (!parse_less_than (ref genericDimension)) + int unused = 0; + if (!parse_less_than (ref unused)) return false; goto again; } else if (the_token == Token.OPEN_BRACKET) { diff --git a/mcs/mcs/expression.cs b/mcs/mcs/expression.cs index c054330db20..9042dcdabad 100644 --- a/mcs/mcs/expression.cs +++ b/mcs/mcs/expression.cs @@ -7570,14 +7570,21 @@ namespace Mono.CSharp bool is_value_type = type.IsStructOrEnum; VariableReference vr = target as VariableReference; + bool prepare_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments?.ContainsEmitWithAwait () == true; + if (target != null && is_value_type && (vr != null || method == null)) { + if (prepare_await) { + arguments = arguments.Emit (ec, false, true); + prepare_await = false; + } + target.AddressOf (ec, AddressOp.Store); } else if (vr != null && vr.IsRef) { vr.EmitLoad (ec); } if (arguments != null) { - if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.Count > (this is NewInitialize ? 0 : 1)) && arguments.ContainsEmitWithAwait ()) + if (prepare_await) arguments = arguments.Emit (ec, false, true); arguments.Emit (ec); diff --git a/mcs/tests/test-async-92.cs b/mcs/tests/test-async-92.cs new file mode 100644 index 00000000000..e41ac00a531 --- /dev/null +++ b/mcs/tests/test-async-92.cs @@ -0,0 +1,22 @@ +using System.Threading.Tasks; + +public class A +{ + public async Task Test1 (int input2) + { + return new ValueType (await Task.FromResult (12345)); + } + + public static void Main () + { + var a = new A (); + a.Test1 (1).Wait (); + } +} + +public struct ValueType +{ + public ValueType (int field2) + { + } +} diff --git a/mcs/tests/ver-il-net_4_x.xml b/mcs/tests/ver-il-net_4_x.xml index 4882b788602..b06aba48fd5 100644 --- a/mcs/tests/ver-il-net_4_x.xml +++ b/mcs/tests/ver-il-net_4_x.xml @@ -52705,6 +52705,24 @@ + + + + 14 + + + 8 + + + + + 44 + + + 7 + + + @@ -66729,6 +66747,32 @@ + + + + 33 + + + 20 + + + 7 + + + + + 2 + + + + + 174 + + + 13 + + + diff --git a/mcs/tools/mkbundle/mkbundle.cs b/mcs/tools/mkbundle/mkbundle.cs index a76e9f88c92..ab13accc034 100755 --- a/mcs/tools/mkbundle/mkbundle.cs +++ b/mcs/tools/mkbundle/mkbundle.cs @@ -1110,6 +1110,14 @@ void mono_register_config_for_assembly (const char* assembly_name, cons } if (error != null) { + Console.Error.WriteLine ("Failure to load i18n assemblies, the following directories were searched for the assemblies:"); + foreach (var path in link_paths){ + Console.Error.WriteLine (" Path: " + path); + } + if (custom_mode){ + Console.WriteLine ("In Custom mode, you need to provide the directory to lookup assemblies from using -L"); + } + Error ("Couldn't load one or more of the i18n assemblies: " + error); Environment.Exit (1); } @@ -1183,7 +1191,12 @@ void mono_register_config_for_assembly (const char* assembly_name, cons Assembly a = null; try { + if (!quiet) + Console.WriteLine ("Attempting to load assembly: {0}", assembly); a = universe.LoadFile (assembly); + if (!quiet) + Console.WriteLine ("Assembly {0} loaded successfully.", assembly); + } catch (FileNotFoundException){ Error ($"Cannot find assembly `{assembly}'"); } catch (IKVM.Reflection.BadImageFormatException f) { @@ -1206,6 +1219,8 @@ void mono_register_config_for_assembly (const char* assembly_name, cons string total_log = ""; foreach (string dir in link_paths){ string full_path = Path.Combine (dir, assembly); + if (!quiet) + Console.WriteLine ("Attempting to load assembly from: " + full_path); if (!assembly.EndsWith (".dll") && !assembly.EndsWith (".exe")) full_path += ".dll"; diff --git a/mono/dis/Makefile.am b/mono/dis/Makefile.am index 14090d8c3ec..06085362c54 100644 --- a/mono/dis/Makefile.am +++ b/mono/dis/Makefile.am @@ -8,7 +8,7 @@ if SUPPORT_SGEN metadata_lib=$(top_builddir)/mono/metadata/libmonoruntimesgen-static.la gc_lib=$(top_builddir)/mono/sgen/libmonosgen-static.la else -metadata_lib=$(top_builddir)/mono/metadata/libmonoruntime-static.a +metadata_lib=$(top_builddir)/mono/metadata/libmonoruntime-static.la gc_lib=$(LIBGC_STATIC_LIBS) endif diff --git a/mono/metadata/appdomain.c b/mono/metadata/appdomain.c index f8de9e2d23e..7bcd8fa7a75 100644 --- a/mono/metadata/appdomain.c +++ b/mono/metadata/appdomain.c @@ -1148,6 +1148,7 @@ leave: MonoAssembly* mono_try_assembly_resolve_handle (MonoDomain *domain, MonoStringHandle fname, MonoAssembly *requesting, gboolean refonly, MonoError *error) { + HANDLE_FUNCTION_ENTER (); MonoAssembly *ret = NULL; MonoMethod *method; MonoBoolean isrefonly; @@ -1156,7 +1157,7 @@ mono_try_assembly_resolve_handle (MonoDomain *domain, MonoStringHandle fname, Mo error_init (error); if (mono_runtime_get_no_exec ()) - return ret; + goto leave; g_assert (domain != NULL && !MONO_HANDLE_IS_NULL (fname)); @@ -1167,14 +1168,16 @@ mono_try_assembly_resolve_handle (MonoDomain *domain, MonoStringHandle fname, Mo MonoReflectionAssemblyHandle requesting_handle; if (requesting) { requesting_handle = mono_assembly_get_object_handle (domain, requesting, error); - return_val_if_nok (error, ret); + if (!is_ok (error)) + goto leave; } params [0] = MONO_HANDLE_RAW (fname); params[1] = requesting ? MONO_HANDLE_RAW (requesting_handle) : NULL; params [2] = &isrefonly; MonoReflectionAssemblyHandle result = MONO_HANDLE_NEW (MonoReflectionAssembly, mono_runtime_invoke_checked (method, domain->domain, params, error)); ret = !MONO_HANDLE_IS_NULL (result) ? MONO_HANDLE_GETVAL (result, assembly) : NULL; - return ret; +leave: + HANDLE_FUNCTION_RETURN_VAL (ret); } MonoAssembly * @@ -1243,6 +1246,7 @@ add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht) static void mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data) { + HANDLE_FUNCTION_ENTER (); static MonoClassField *assembly_load_field; static MonoMethod *assembly_load_method; MonoError error; @@ -1253,7 +1257,7 @@ mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data) if (!domain->domain) /* This can happen during startup */ - return; + goto leave; #ifdef ASSEMBLY_LOAD_DEBUG fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name); #endif @@ -1271,7 +1275,7 @@ mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data) mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value); if (load_value == NULL) { /* No events waiting to be triggered */ - return; + goto leave; } MonoReflectionAssemblyHandle ref_assembly = mono_assembly_get_object_handle (domain, assembly, &error); @@ -1286,6 +1290,8 @@ mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data) mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error); mono_error_cleanup (&error); +leave: + HANDLE_FUNCTION_RETURN (); } /* diff --git a/mono/metadata/class.c b/mono/metadata/class.c index ee0695ceccf..4ed4f39da3d 100644 --- a/mono/metadata/class.c +++ b/mono/metadata/class.c @@ -9106,10 +9106,25 @@ mono_class_get_methods (MonoClass* klass, gpointer *iter) static MonoMethod* mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter) { - MonoMethod** method; + gboolean static_iter = FALSE; + if (!iter) return NULL; - if (klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass)) { + + /* + * If the lowest bit of the iterator is 1, this is an iterator for static metadata, + * and the upper bits contain an index. Otherwise, the iterator is a pointer into + * klass->methods. + */ + if ((gsize)(*iter) & 1) + static_iter = TRUE; + /* Use the static metadata only if klass->methods is not yet initialized */ + if (!static_iter && !(klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass))) + static_iter = TRUE; + + if (!static_iter) { + MonoMethod** methodptr; + if (!*iter) { mono_class_setup_methods (klass); /* @@ -9119,20 +9134,22 @@ mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter) if (!klass->methods) return NULL; /* start from the first */ - method = &klass->methods [0]; + methodptr = &klass->methods [0]; } else { - method = (MonoMethod **)*iter; - method++; + methodptr = (MonoMethod **)*iter; + methodptr++; } + if (*iter) + g_assert ((guint64)(*iter) > 0x100); int mcount = mono_class_get_method_count (klass); - while (method < &klass->methods [mcount]) { - if (*method && ((*method)->flags & METHOD_ATTRIBUTE_VIRTUAL)) + while (methodptr < &klass->methods [mcount]) { + if (*methodptr && ((*methodptr)->flags & METHOD_ATTRIBUTE_VIRTUAL)) break; - method ++; + methodptr ++; } - if (method < &klass->methods [mcount]) { - *iter = method; - return *method; + if (methodptr < &klass->methods [mcount]) { + *iter = methodptr; + return *methodptr; } else { return NULL; } @@ -9144,7 +9161,7 @@ mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter) if (!*iter) { start_index = 0; } else { - start_index = GPOINTER_TO_UINT (*iter); + start_index = GPOINTER_TO_UINT (*iter) >> 1; } int first_idx = mono_class_get_first_method_idx (klass); @@ -9165,7 +9182,7 @@ mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter) mono_error_cleanup (&error); /* FIXME don't swallow the error */ /* Add 1 here so the if (*iter) check fails */ - *iter = GUINT_TO_POINTER (i + 1); + *iter = GUINT_TO_POINTER (((i + 1) << 1) | 1); return res; } else { return NULL; diff --git a/mono/metadata/cominterop.c b/mono/metadata/cominterop.c index 86309ef2023..d522657b62f 100644 --- a/mono/metadata/cominterop.c +++ b/mono/metadata/cominterop.c @@ -1090,7 +1090,7 @@ mono_cominterop_get_invoke (MonoMethod *method) for (i = 1; i <= sig->param_count; i++) mono_mb_emit_ldarg (mb, i); - if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) { + if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || mono_class_is_interface (method->klass)) { MonoMethod * native_wrapper = mono_cominterop_get_native_wrapper(method); mono_mb_emit_managed_call (mb, native_wrapper, NULL); } diff --git a/mono/metadata/domain-internals.h b/mono/metadata/domain-internals.h index c9fb4add3dd..6efe5f5a656 100644 --- a/mono/metadata/domain-internals.h +++ b/mono/metadata/domain-internals.h @@ -241,6 +241,8 @@ struct _MonoJitInfo { * d.tramp_info contains additional data in this case. */ gboolean is_trampoline:1; + /* Whenever this jit info refers to an interpreter method */ + gboolean is_interp:1; /* FIXME: Embed this after the structure later*/ gpointer gc_info; /* Currently only used by SGen */ diff --git a/mono/metadata/handle.c b/mono/metadata/handle.c index 00a11e67319..bdb1c773593 100644 --- a/mono/metadata/handle.c +++ b/mono/metadata/handle.c @@ -73,66 +73,12 @@ const MonoObjectHandle mono_null_value_handle = NULL; #define THIS_IS_AN_OK_NUMBER_OF_HANDLES 100 -enum { - HANDLE_CHUNK_PTR_OBJ = 0x0, /* chunk element points to beginning of a managed object */ - HANDLE_CHUNK_PTR_INTERIOR = 0x1, /* chunk element points into the middle of a managed object */ - HANDLE_CHUNK_PTR_MASK = 0x1 -}; - -/* number of bits in each word of the interior pointer bitmap */ -#define INTERIOR_HANDLE_BITMAP_BITS_PER_WORD (sizeof(guint32) << 3) - -static gboolean -bitset_bits_test (guint32 *bitmaps, int idx) -{ - int w = idx / INTERIOR_HANDLE_BITMAP_BITS_PER_WORD; - int b = idx % INTERIOR_HANDLE_BITMAP_BITS_PER_WORD; - guint32 bitmap = bitmaps [w]; - guint32 mask = 1u << b; - return ((bitmap & mask) != 0); -} - -static void -bitset_bits_set (guint32 *bitmaps, int idx) -{ - int w = idx / INTERIOR_HANDLE_BITMAP_BITS_PER_WORD; - int b = idx % INTERIOR_HANDLE_BITMAP_BITS_PER_WORD; - guint32 *bitmap = &bitmaps [w]; - guint32 mask = 1u << b; - *bitmap |= mask; -} -static void -bitset_bits_clear (guint32 *bitmaps, int idx) -{ - int w = idx / INTERIOR_HANDLE_BITMAP_BITS_PER_WORD; - int b = idx % INTERIOR_HANDLE_BITMAP_BITS_PER_WORD; - guint32 *bitmap = &bitmaps [w]; - guint32 mask = ~(1u << b); - *bitmap &= mask; -} - -static gpointer* -chunk_element_objslot_init (HandleChunk *chunk, int idx, gboolean interior) -{ - if (interior) - bitset_bits_set (chunk->interior_bitmap, idx); - else - bitset_bits_clear (chunk->interior_bitmap, idx); - return &chunk->elems [idx].o; -} - static HandleChunkElem* chunk_element (HandleChunk *chunk, int idx) { return &chunk->elems[idx]; } -static guint -chunk_element_kind (HandleChunk *chunk, int idx) -{ - return bitset_bits_test (chunk->interior_bitmap, idx) ? HANDLE_CHUNK_PTR_INTERIOR : HANDLE_CHUNK_PTR_OBJ; -} - static HandleChunkElem* handle_to_chunk_element (MonoObjectHandle o) { @@ -207,25 +153,12 @@ mono_handle_chunk_leak_check (HandleStack *handles) { } #endif -MonoRawHandle -#ifndef MONO_HANDLE_TRACK_OWNER -mono_handle_new (MonoObject *object) -#else -mono_handle_new (MonoObject *object, const char *owner) -#endif -{ -#ifndef MONO_HANDLE_TRACK_OWNER - return mono_handle_new_full (object, FALSE); -#else - return mono_handle_new_full (object, FALSE, owner); -#endif -} /* Actual handles implementation */ MonoRawHandle #ifndef MONO_HANDLE_TRACK_OWNER -mono_handle_new_full (gpointer rawptr, gboolean interior) +mono_handle_new (MonoObject *obj) #else -mono_handle_new_full (gpointer rawptr, gboolean interior, const char *owner) +mono_handle_new (MonoObject *obj, const char *owner) #endif { MonoThreadInfo *info = mono_thread_info_current (); @@ -238,7 +171,7 @@ mono_handle_new_full (gpointer rawptr, gboolean interior, const char *owner) retry: if (G_LIKELY (top->size < OBJECTS_PER_HANDLES_CHUNK)) { int idx = top->size; - gpointer* objslot = chunk_element_objslot_init (top, idx, interior); + gpointer* objslot = &top->elems [idx].o; /* can be interrupted anywhere here, so: * 1. make sure the new slot is null * 2. make the new slot scannable (increment size) @@ -251,7 +184,7 @@ retry: mono_memory_write_barrier (); top->size++; mono_memory_write_barrier (); - *objslot = rawptr; + *objslot = obj; SET_OWNER (top,idx); SET_SP (handles, top, idx); return objslot; @@ -266,7 +199,6 @@ retry: } HandleChunk *new_chunk = g_new (HandleChunk, 1); new_chunk->size = 0; - memset (new_chunk->interior_bitmap, 0, INTERIOR_HANDLE_BITMAP_WORDS); new_chunk->prev = top; new_chunk->next = NULL; /* make sure size == 0 before new chunk is visible */ @@ -276,20 +208,51 @@ retry: goto retry; } +MonoRawHandle +#ifndef MONO_HANDLE_TRACK_OWNER +mono_handle_new_interior (gpointer rawptr) +#else +mono_handle_new_interior (gpointer rawptr, const char *owner) +#endif +{ + MonoThreadInfo *info = mono_thread_info_current (); + HandleStack *handles = (HandleStack *)info->handle_stack; + HandleChunk *top = handles->interior; +#ifdef MONO_HANDLE_TRACK_SP + mono_handle_chunk_leak_check (handles); +#endif + + g_assert (top); + /* + * Don't extend the chunk now, interior handles are + * only used for icall arguments, they shouldn't + * overflow. + */ + g_assert (top->size < OBJECTS_PER_HANDLES_CHUNK); + int idx = top->size; + gpointer *objslot = &top->elems [idx].o; + *objslot = NULL; + mono_memory_write_barrier (); + top->size++; + mono_memory_write_barrier (); + *objslot = rawptr; + SET_OWNER (top,idx); + SET_SP (handles, top, idx); + return objslot; +} HandleStack* mono_handle_stack_alloc (void) { - HandleStack *stack = g_new (HandleStack, 1); - HandleChunk *chunk = g_new (HandleChunk, 1); + HandleStack *stack = g_new0 (HandleStack, 1); + HandleChunk *chunk = g_new0 (HandleChunk, 1); + HandleChunk *interior = g_new0 (HandleChunk, 1); - chunk->size = 0; - memset (chunk->interior_bitmap, 0, INTERIOR_HANDLE_BITMAP_WORDS); - chunk->prev = chunk->next = NULL; mono_memory_write_barrier (); stack->top = stack->bottom = chunk; -#ifdef MONO_HANDLE_TRACK_OWNER + stack->interior = interior; +#ifdef MONO_HANDLE_TRACK_SP stack->stackmark_sp = NULL; #endif return stack; @@ -309,9 +272,44 @@ mono_handle_stack_free (HandleStack *stack) c = next; } g_free (c); + g_free (stack->interior); g_free (stack); } +void +mono_handle_stack_free_domain (HandleStack *stack, MonoDomain *domain) +{ + /* Called by the GC while clearing out objects of the given domain from the heap. */ + /* If there are no handles-related bugs, there is nothing to do: if a + * thread accessed objects from the domain it was aborted, so any + * threads left alive cannot have any handles that point into the + * unloading domain. However if there is a handle leak, the handle stack is not */ + if (!stack) + return; + /* Root domain only unloaded when mono is shutting down, don't need to check anything */ + if (domain == mono_get_root_domain () || mono_runtime_is_shutting_down ()) + return; + HandleChunk *cur = stack->bottom; + HandleChunk *last = stack->top; + if (!cur) + return; + while (cur) { + for (int idx = 0; idx < cur->size; ++idx) { + HandleChunkElem *elem = &cur->elems[idx]; + if (!elem->o) + continue; + g_assert (mono_object_domain (elem->o) != domain); + } + if (cur == last) + break; + cur = cur->next; + } + /* We don't examine the interior pointers here because the GC treats + * them conservatively and anyway we don't have enough information here to + * find the object's vtable. + */ +} + static void check_handle_stack_monotonic (HandleStack *stack) { @@ -362,46 +360,32 @@ mono_handle_stack_scan (HandleStack *stack, GcScanFunc func, gpointer gc_data, g Note that if we're running, we know the world is stopped. */ - HandleChunk *cur = stack->bottom; - HandleChunk *last = stack->top; - - if (!cur) - return; + if (precise) { + HandleChunk *cur = stack->bottom; + HandleChunk *last = stack->top; - while (cur) { - /* assume that object pointers will be much more common than interior pointers. - * scan the object pointers by iterating over the chunk elements. - * scan the interior pointers by iterating over the bitmap bits. - */ - if (precise) { + while (cur) { for (int i = 0; i < cur->size; ++i) { HandleChunkElem* elem = chunk_element (cur, i); - int kind = chunk_element_kind (cur, i); gpointer* obj_slot = &elem->o; - if (kind == HANDLE_CHUNK_PTR_OBJ && *obj_slot != NULL) + if (*obj_slot != NULL) func (obj_slot, gc_data); } - } else { - int elem_idx = 0; - for (int i = 0; i < INTERIOR_HANDLE_BITMAP_WORDS; ++i) { - elem_idx = i * INTERIOR_HANDLE_BITMAP_BITS_PER_WORD; - if (elem_idx >= cur->size) - break; - /* no interior pointers in the range */ - if (cur->interior_bitmap [i] == 0) - continue; - for (int j = 0; j < INTERIOR_HANDLE_BITMAP_BITS_PER_WORD && elem_idx < cur->size; ++j,++elem_idx) { - HandleChunkElem *elem = chunk_element (cur, elem_idx); - int kind = chunk_element_kind (cur, elem_idx); - gpointer *ptr_slot = &elem->o; - if (kind == HANDLE_CHUNK_PTR_INTERIOR && *ptr_slot != NULL) - func (ptr_slot, gc_data); - } - } + if (cur == last) + break; + cur = cur->next; + } + } else { + HandleChunk *cur = stack->interior; + + if (!cur) + return; + for (int i = 0; i < cur->size; ++i) { + HandleChunkElem* elem = chunk_element (cur, i); + gpointer* ptr_slot = &elem->o; + if (*ptr_slot != NULL) + func (ptr_slot, gc_data); } - if (cur == last) - break; - cur = cur->next; } } @@ -488,7 +472,6 @@ mono_gchandle_from_handle (MonoObjectHandle handle, mono_bool pinned) HandleChunk *chunk = chunk_element_to_chunk_idx (stack, elem, &elem_idx); /* gchandles cannot deal with interior pointers */ g_assert (chunk != NULL); - g_assert (chunk_element_kind (chunk, elem_idx) != HANDLE_CHUNK_PTR_INTERIOR); return mono_gchandle_new (MONO_HANDLE_RAW (handle), pinned); } diff --git a/mono/metadata/handle.h b/mono/metadata/handle.h index fd6d0cfffee..5a8e3356268 100644 --- a/mono/metadata/handle.h +++ b/mono/metadata/handle.h @@ -25,7 +25,6 @@ G_BEGIN_DECLS - /* Handle stack. @@ -73,13 +72,8 @@ typedef struct { #endif } HandleChunkElem; -/* number of guint32's needed to store the interior pointers bitmap */ -#define INTERIOR_HANDLE_BITMAP_WORDS ((OBJECTS_PER_HANDLES_CHUNK + 31) / 32) - struct _HandleChunk { int size; //number of handles - /* bits in the range 0..size-1 of interior_bitmap are valid; rest are ignored. */ - guint32 interior_bitmap [INTERIOR_HANDLE_BITMAP_WORDS]; HandleChunk *prev, *next; HandleChunkElem elems [OBJECTS_PER_HANDLES_CHUNK]; }; @@ -90,10 +84,13 @@ typedef struct { #ifdef MONO_HANDLE_TRACK_SP gpointer stackmark_sp; // C stack pointer top when from most recent mono_stack_mark_init #endif + /* Chunk for storing interior pointers. Not extended right now */ + HandleChunk *interior; } HandleStack; +// Keep this in sync with RuntimeStructs.cs typedef struct { - int size; + int size, interior_size; HandleChunk *chunk; #ifdef MONO_HANDLE_TRACK_SP gpointer prev_sp; // C stack pointer from prior mono_stack_mark_init @@ -108,18 +105,20 @@ typedef void (*GcScanFunc) (gpointer*, gpointer); #ifndef MONO_HANDLE_TRACK_OWNER MonoRawHandle mono_handle_new (MonoObject *object); MonoRawHandle mono_handle_new_full (gpointer rawptr, gboolean interior); +MonoRawHandle mono_handle_new_interior (gpointer rawptr); #else MonoRawHandle mono_handle_new (MonoObject *object, const char* owner); MonoRawHandle mono_handle_new_full (gpointer rawptr, gboolean interior, const char *owner); +MonoRawHandle mono_handle_new_interior (gpointer rawptr, const char *owner); #endif - void mono_handle_stack_scan (HandleStack *stack, GcScanFunc func, gpointer gc_data, gboolean precise); gboolean mono_handle_stack_is_empty (HandleStack *stack); HandleStack* mono_handle_stack_alloc (void); void mono_handle_stack_free (HandleStack *handlestack); MonoRawHandle mono_stack_mark_pop_value (MonoThreadInfo *info, HandleStackMark *stackmark, MonoRawHandle value); void mono_stack_mark_record_size (MonoThreadInfo *info, HandleStackMark *stackmark, const char *func_name); +void mono_handle_stack_free_domain (HandleStack *stack, MonoDomain *domain); #ifdef MONO_HANDLE_TRACK_SP void mono_handle_chunk_leak_check (HandleStack *handles); @@ -134,6 +133,7 @@ mono_stack_mark_init (MonoThreadInfo *info, HandleStackMark *stackmark) HandleStack *handles = (HandleStack *)info->handle_stack; stackmark->size = handles->top->size; stackmark->chunk = handles->top; + stackmark->interior_size = handles->interior->size; #ifdef MONO_HANDLE_TRACK_SP stackmark->prev_sp = handles->stackmark_sp; handles->stackmark_sp = sptop; @@ -148,6 +148,7 @@ mono_stack_mark_pop (MonoThreadInfo *info, HandleStackMark *stackmark) old_top->size = stackmark->size; mono_memory_write_barrier (); handles->top = old_top; + handles->interior->size = stackmark->interior_size; #ifdef MONO_HANDLE_TRACK_SP mono_memory_write_barrier (); /* write to top before prev_sp */ handles->stackmark_sp = stackmark->prev_sp; @@ -403,20 +404,6 @@ This is why we evaluate index and value before any call to MONO_HANDLE_RAW or ot mono_handle_array_getref (MONO_HANDLE_CAST(MonoObject, (DEST)), (HANDLE), (IDX)); \ } while (0) -/* Handles into the interior of objects. - * - * Typically when working with value types, we pass them by reference. In the case where the value type - * is a field in a managed class, the reference will be a pointer into the middle of a managed object. - * We need to identify such pointers in order for SGen to scan them correctly. - */ - -#ifndef MONO_HANDLE_TRACK_OWNER -#define MONO_HANDLE_NEW_GET_VALPTR(HANDLE,TYPE,FIELD) (TYPE_VALUE_HANDLE_NAME(TYPE))(mono_handle_new_full (&(HANDLE)->__raw->FIELD), TRUE)) -#else -#define MONO_HANDLE_NEW_GET_VALPTR(HANDLE,TYPE,FIELD) (TYPE_VALUE_HANDLE_NAME(TYPE))(mono_handle_new_full (&(HANDLE)->__raw->FIELD), TRUE, HANDLE_OWNER_STRINGIFY(__FILE__, __LINE__)) -#endif - - #define MONO_HANDLE_ASSIGN(DESTH, SRCH) \ mono_handle_assign (MONO_HANDLE_CAST (MonoObject, (DESTH)), MONO_HANDLE_CAST(MonoObject, (SRCH))) diff --git a/mono/metadata/icall-def.h b/mono/metadata/icall-def.h index b8d6b81b1e7..51b333dce30 100644 --- a/mono/metadata/icall-def.h +++ b/mono/metadata/icall-def.h @@ -207,9 +207,9 @@ ICALL(DECIMAL_13, "ToSingle", mono_decimal_to_float) #endif ICALL_TYPE(DELEGATE, "System.Delegate", DELEGATE_1) -ICALL(DELEGATE_1, "AllocDelegateLike_internal", ves_icall_System_Delegate_AllocDelegateLike_internal) -ICALL(DELEGATE_2, "CreateDelegate_internal", ves_icall_System_Delegate_CreateDelegate_internal) -ICALL(DELEGATE_3, "GetVirtualMethod_internal", ves_icall_System_Delegate_GetVirtualMethod_internal) +HANDLES(ICALL(DELEGATE_1, "AllocDelegateLike_internal", ves_icall_System_Delegate_AllocDelegateLike_internal)) +HANDLES(ICALL(DELEGATE_2, "CreateDelegate_internal", ves_icall_System_Delegate_CreateDelegate_internal)) +HANDLES(ICALL(DELEGATE_3, "GetVirtualMethod_internal", ves_icall_System_Delegate_GetVirtualMethod_internal)) ICALL_TYPE(DEBUGR, "System.Diagnostics.Debugger", DEBUGR_1) ICALL(DEBUGR_1, "IsAttached_internal", ves_icall_System_Diagnostics_Debugger_IsAttached_internal) @@ -683,8 +683,8 @@ ICALL(MARSHAL_7, "FreeHGlobal", ves_icall_System_Runtime_InteropServices_Marshal ICALL(MARSHAL_44, "GetCCW", ves_icall_System_Runtime_InteropServices_Marshal_GetCCW) ICALL(MARSHAL_8, "GetComSlotForMethodInfoInternal", ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal) #endif -ICALL(MARSHAL_9, "GetDelegateForFunctionPointerInternal", ves_icall_System_Runtime_InteropServices_Marshal_GetDelegateForFunctionPointerInternal) -ICALL(MARSHAL_10, "GetFunctionPointerForDelegateInternal", ves_icall_System_Runtime_InteropServices_Marshal_GetFunctionPointerForDelegateInternal) +HANDLES(ICALL(MARSHAL_9, "GetDelegateForFunctionPointerInternal", ves_icall_System_Runtime_InteropServices_Marshal_GetDelegateForFunctionPointerInternal)) +HANDLES(ICALL(MARSHAL_10, "GetFunctionPointerForDelegateInternal", ves_icall_System_Runtime_InteropServices_Marshal_GetFunctionPointerForDelegateInternal)) #ifndef DISABLE_COM ICALL(MARSHAL_52, "GetHRForException_WinRT", ves_icall_System_Runtime_InteropServices_Marshal_GetHRForException_WinRT) ICALL(MARSHAL_45, "GetIDispatchForObjectInternal", ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal) @@ -697,9 +697,9 @@ ICALL(MARSHAL_47, "GetObjectForCCW", ves_icall_System_Runtime_InteropServices_Ma ICALL(MARSHAL_54, "GetRawIUnknownForComObjectNoAddRef", ves_icall_System_Runtime_InteropServices_Marshal_GetRawIUnknownForComObjectNoAddRef) ICALL(MARSHAL_48, "IsComObject", ves_icall_System_Runtime_InteropServices_Marshal_IsComObject) #endif -ICALL(MARSHAL_12, "OffsetOf", ves_icall_System_Runtime_InteropServices_Marshal_OffsetOf) -ICALL(MARSHAL_13, "Prelink", ves_icall_System_Runtime_InteropServices_Marshal_Prelink) -ICALL(MARSHAL_14, "PrelinkAll", ves_icall_System_Runtime_InteropServices_Marshal_PrelinkAll) +HANDLES(ICALL(MARSHAL_12, "OffsetOf", ves_icall_System_Runtime_InteropServices_Marshal_OffsetOf)) +HANDLES(ICALL(MARSHAL_13, "Prelink", ves_icall_System_Runtime_InteropServices_Marshal_Prelink)) +HANDLES(ICALL(MARSHAL_14, "PrelinkAll", ves_icall_System_Runtime_InteropServices_Marshal_PrelinkAll)) HANDLES(ICALL(MARSHAL_15, "PtrToStringAnsi(intptr)", ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi)) ICALL(MARSHAL_16, "PtrToStringAnsi(intptr,int)", ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi_len) ICALL(MARSHAL_17, "PtrToStringBSTR", ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR) @@ -716,7 +716,7 @@ ICALL(MARSHAL_23, "ReAllocHGlobal", ves_icall_System_Runtime_InteropServices_Mar ICALL(MARSHAL_49, "ReleaseComObjectInternal", ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal) ICALL(MARSHAL_29, "ReleaseInternal", ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal) #endif -ICALL(MARSHAL_30, "SizeOf", ves_icall_System_Runtime_InteropServices_Marshal_SizeOf) +HANDLES(ICALL(MARSHAL_30, "SizeOf", ves_icall_System_Runtime_InteropServices_Marshal_SizeOf)) ICALL(MARSHAL_31, "StringToBSTR", ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR) ICALL(MARSHAL_32, "StringToHGlobalAnsi", ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalAnsi) ICALL(MARSHAL_33, "StringToHGlobalUni", ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalUni) diff --git a/mono/metadata/icall.c b/mono/metadata/icall.c index 67acdcb5210..79329f93538 100644 --- a/mono/metadata/icall.c +++ b/mono/metadata/icall.c @@ -6170,99 +6170,92 @@ ves_icall_RuntimeType_MakePointerType (MonoReflectionTypeHandle ref_type, MonoEr return mono_type_get_object_handle (domain, &pklass->byval_arg, error); } -ICALL_EXPORT MonoObject * -ves_icall_System_Delegate_CreateDelegate_internal (MonoReflectionType *type, MonoObject *target, - MonoReflectionMethod *info, MonoBoolean throwOnBindFailure) +ICALL_EXPORT MonoObjectHandle +ves_icall_System_Delegate_CreateDelegate_internal (MonoReflectionTypeHandle ref_type, MonoObjectHandle target, + MonoReflectionMethodHandle info, MonoBoolean throwOnBindFailure, MonoError *error) { - MonoError error; - MonoClass *delegate_class = mono_class_from_mono_type (type->type); - MonoObject *delegate; + MonoType *type = MONO_HANDLE_GETVAL (ref_type, type); + MonoClass *delegate_class = mono_class_from_mono_type (type); gpointer func; - MonoMethod *method = info->method; + MonoMethod *method = MONO_HANDLE_GETVAL (info, method); MonoMethodSignature *sig = mono_method_signature(method); - mono_class_init_checked (delegate_class, &error); - if (mono_error_set_pending_exception (&error)) - return NULL; + mono_class_init_checked (delegate_class, error); + return_val_if_nok (error, NULL_HANDLE); if (!(delegate_class->parent == mono_defaults.multicastdelegate_class)) { /* FIXME improve this exception message */ - mono_error_set_execution_engine (&error, "file %s: line %d (%s): assertion failed: (%s)", __FILE__, __LINE__, + mono_error_set_execution_engine (error, "file %s: line %d (%s): assertion failed: (%s)", __FILE__, __LINE__, __func__, "delegate_class->parent == mono_defaults.multicastdelegate_class"); - mono_error_set_pending_exception (&error); - return NULL; + return NULL_HANDLE; } if (mono_security_core_clr_enabled ()) { - if (!mono_security_core_clr_ensure_delegate_creation (method, &error)) { + MonoError security_error; + if (!mono_security_core_clr_ensure_delegate_creation (method, &security_error)) { if (throwOnBindFailure) - mono_error_set_pending_exception (&error); + mono_error_move (error, &security_error); else - mono_error_cleanup (&error); - return NULL; + mono_error_cleanup (&security_error); + return NULL_HANDLE; } } if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) { if (!method->is_inflated) { - mono_set_pending_exception(mono_get_exception_argument("method", " Cannot bind to the target method because its signature differs from that of the delegate type")); - return NULL; + mono_error_set_argument (error, "method", " Cannot bind to the target method because its signature differs from that of the delegate type"); + return NULL_HANDLE; } } - delegate = mono_object_new_checked (mono_object_domain (type), delegate_class, &error); - if (mono_error_set_pending_exception (&error)) - return NULL; + MonoObjectHandle delegate = MONO_HANDLE_NEW (MonoObject, mono_object_new_checked (MONO_HANDLE_DOMAIN (ref_type), delegate_class, error)); + return_val_if_nok (error, NULL_HANDLE); if (method_is_dynamic (method)) { /* Creating a trampoline would leak memory */ - func = mono_compile_method_checked (method, &error); - if (mono_error_set_pending_exception (&error)) - return NULL; + func = mono_compile_method_checked (method, error); + return_val_if_nok (error, NULL_HANDLE); } else { - if (target && method->flags & METHOD_ATTRIBUTE_VIRTUAL && method->klass != mono_object_class (target)) - method = mono_object_get_virtual_method (target, method); - gpointer trampoline = mono_runtime_create_jump_trampoline (mono_domain_get (), method, TRUE, &error); - if (mono_error_set_pending_exception (&error)) - return NULL; + if (!MONO_HANDLE_IS_NULL (target) && method->flags & METHOD_ATTRIBUTE_VIRTUAL && method->klass != mono_handle_class (target)) { + method = mono_object_handle_get_virtual_method (target, method, error); + return_val_if_nok (error, NULL_HANDLE); + } + gpointer trampoline = mono_runtime_create_jump_trampoline (mono_domain_get (), method, TRUE, error); + return_val_if_nok (error, NULL_HANDLE); func = mono_create_ftnptr (mono_domain_get (), trampoline); } - mono_delegate_ctor_with_method (delegate, target, func, method, &error); - if (mono_error_set_pending_exception (&error)) - return NULL; + mono_delegate_ctor_with_method (delegate, target, func, method, error); + return_val_if_nok (error, NULL_HANDLE); return delegate; } -ICALL_EXPORT MonoMulticastDelegate * -ves_icall_System_Delegate_AllocDelegateLike_internal (MonoDelegate *delegate) +ICALL_EXPORT MonoMulticastDelegateHandle +ves_icall_System_Delegate_AllocDelegateLike_internal (MonoDelegateHandle delegate, MonoError *error) { - MonoError error; - MonoMulticastDelegate *ret; + error_init (error); - g_assert (mono_class_has_parent (mono_object_class (delegate), mono_defaults.multicastdelegate_class)); + MonoClass *klass = mono_handle_class (delegate); + g_assert (mono_class_has_parent (klass, mono_defaults.multicastdelegate_class)); - ret = (MonoMulticastDelegate*) mono_object_new_checked (mono_object_domain (delegate), mono_object_class (delegate), &error); - if (mono_error_set_pending_exception (&error)) - return NULL; + MonoMulticastDelegateHandle ret = MONO_HANDLE_NEW (MonoMulticastDelegate, mono_object_new_checked (MONO_HANDLE_DOMAIN (delegate), klass, error)); + return_val_if_nok (error, MONO_HANDLE_CAST (MonoMulticastDelegate, NULL_HANDLE)); - ret->delegate.invoke_impl = mono_runtime_create_delegate_trampoline (mono_object_class (delegate)); + MONO_HANDLE_SETVAL (MONO_HANDLE_CAST (MonoDelegate, ret), invoke_impl, gpointer, mono_runtime_create_delegate_trampoline (klass)); return ret; } -ICALL_EXPORT MonoReflectionMethod* -ves_icall_System_Delegate_GetVirtualMethod_internal (MonoDelegate *delegate) +ICALL_EXPORT MonoReflectionMethodHandle +ves_icall_System_Delegate_GetVirtualMethod_internal (MonoDelegateHandle delegate, MonoError *error) { - MonoReflectionMethod *ret = NULL; - MonoError error; - MonoMethod *m; + error_init (error); - m = mono_object_get_virtual_method (delegate->target, delegate->method); - ret = mono_method_get_object_checked (mono_domain_get (), m, m->klass, &error); - mono_error_set_pending_exception (&error); - return ret; + MonoObjectHandle delegate_target = MONO_HANDLE_NEW_GET (MonoObject, delegate, target); + MonoMethod *m = mono_object_handle_get_virtual_method (delegate_target, MONO_HANDLE_GETVAL (delegate, method), error); + return_val_if_nok (error, MONO_HANDLE_CAST (MonoReflectionMethod, NULL_HANDLE)); + return mono_method_get_object_handle (mono_domain_get (), m, m->klass, error); } /* System.Buffer */ @@ -7508,38 +7501,34 @@ prelink_method (MonoMethod *method, MonoError *error) return; mono_lookup_pinvoke_call (method, &exc_class, &exc_arg); if (exc_class) { - mono_error_set_exception_instance (error, - mono_exception_from_name_msg (mono_defaults.corlib, "System", exc_class, exc_arg)); + mono_error_set_generic_error (error, "System", exc_class, "%s", exc_arg); return; } /* create the wrapper, too? */ } ICALL_EXPORT void -ves_icall_System_Runtime_InteropServices_Marshal_Prelink (MonoReflectionMethod *method) +ves_icall_System_Runtime_InteropServices_Marshal_Prelink (MonoReflectionMethodHandle method, MonoError *error) { - MonoError error; + error_init (error); - prelink_method (method->method, &error); - mono_error_set_pending_exception (&error); + prelink_method (MONO_HANDLE_GETVAL (method, method), error); } ICALL_EXPORT void -ves_icall_System_Runtime_InteropServices_Marshal_PrelinkAll (MonoReflectionType *type) +ves_icall_System_Runtime_InteropServices_Marshal_PrelinkAll (MonoReflectionTypeHandle type, MonoError *error) { - MonoError error; - MonoClass *klass = mono_class_from_mono_type (type->type); + error_init (error); + MonoClass *klass = mono_class_from_mono_type (MONO_HANDLE_GETVAL (type, type)); MonoMethod* m; gpointer iter = NULL; - mono_class_init_checked (klass, &error); - if (mono_error_set_pending_exception (&error)) - return; + mono_class_init_checked (klass, error); + return_if_nok (error); while ((m = mono_class_get_methods (klass, &iter))) { - prelink_method (m, &error); - if (mono_error_set_pending_exception (&error)) - return; + prelink_method (m, error); + return_if_nok (error); } } diff --git a/mono/metadata/marshal.c b/mono/metadata/marshal.c index b82e49d8ea5..f60de81c46b 100644 --- a/mono/metadata/marshal.c +++ b/mono/metadata/marshal.c @@ -89,7 +89,7 @@ static void ftnptr_eh_callback_default (guint32 gchandle); static MonoFtnPtrEHCallback ftnptr_eh_callback = ftnptr_eh_callback_default; static void -delegate_hash_table_add (MonoDelegate *d); +delegate_hash_table_add (MonoDelegateHandle d); static void delegate_hash_table_remove (MonoDelegate *d); @@ -179,9 +179,15 @@ mono_string_to_byvalwstr (gpointer dst, MonoString *src, int size); gpointer mono_delegate_to_ftnptr (MonoDelegate *delegate); +gpointer +mono_delegate_handle_to_ftnptr (MonoDelegateHandle delegate, MonoError *error); + MonoDelegate* mono_ftnptr_to_delegate (MonoClass *klass, gpointer ftn); +MonoDelegateHandle +mono_ftnptr_to_delegate_handle (MonoClass *klass, gpointer ftn, MonoError *error); + gpointer mono_array_to_savearray (MonoArray *array); @@ -431,25 +437,44 @@ mono_marshal_unlock_internal (void) /* This is a JIT icall, it sets the pending exception and return NULL on error */ gpointer -mono_delegate_to_ftnptr (MonoDelegate *delegate) +mono_delegate_to_ftnptr (MonoDelegate *delegate_raw) { + HANDLE_FUNCTION_ENTER (); MonoError error; + MONO_HANDLE_DCL (MonoDelegate, delegate); + gpointer result = mono_delegate_handle_to_ftnptr (delegate, &error); + mono_error_set_pending_exception (&error); + HANDLE_FUNCTION_RETURN_VAL (result); +} + +gpointer +mono_delegate_handle_to_ftnptr (MonoDelegateHandle delegate, MonoError *error) +{ + HANDLE_FUNCTION_ENTER (); + gpointer result = NULL; + error_init (error); MonoMethod *method, *wrapper; MonoClass *klass; uint32_t target_handle = 0; - if (!delegate) - return NULL; + if (MONO_HANDLE_IS_NULL (delegate)) + goto leave; - if (delegate->delegate_trampoline) - return delegate->delegate_trampoline; + if (MONO_HANDLE_GETVAL (delegate, delegate_trampoline)) { + result = MONO_HANDLE_GETVAL (delegate, delegate_trampoline); + goto leave; + } - klass = ((MonoObject *)delegate)->vtable->klass; + klass = mono_handle_class (delegate); g_assert (klass->delegate); - method = delegate->method; - if (delegate->method_is_virtual) - method = mono_object_get_virtual_method (delegate->target, method); + method = MONO_HANDLE_GETVAL (delegate, method); + if (MONO_HANDLE_GETVAL (delegate, method_is_virtual)) { + MonoObjectHandle delegate_target = MONO_HANDLE_NEW_GET (MonoObject, delegate, target); + method = mono_object_handle_get_virtual_method (delegate_target, method, error); + if (!is_ok (error)) + goto leave; + } if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) { const char *exc_class, *exc_arg; @@ -458,38 +483,39 @@ mono_delegate_to_ftnptr (MonoDelegate *delegate) ftnptr = mono_lookup_pinvoke_call (method, &exc_class, &exc_arg); if (!ftnptr) { g_assert (exc_class); - mono_set_pending_exception (mono_exception_from_name_msg (mono_defaults.corlib, "System", exc_class, exc_arg)); - return NULL; + mono_error_set_generic_error (error, "System", exc_class, "%s", exc_arg); + goto leave; } - return ftnptr; + result = ftnptr; + goto leave; } - if (delegate->target) { + MonoObjectHandle delegate_target = MONO_HANDLE_NEW_GET (MonoObject, delegate, target); + if (!MONO_HANDLE_IS_NULL (delegate_target)) { /* Produce a location which can be embedded in JITted code */ - target_handle = mono_gchandle_new_weakref (delegate->target, FALSE); + target_handle = mono_gchandle_new_weakref (MONO_HANDLE_RAW (delegate_target), FALSE); /* FIXME: a version of mono_gchandle_new_weakref that takes a coop handle */ } - wrapper = mono_marshal_get_managed_wrapper (method, klass, target_handle, &error); - if (!is_ok (&error)) - goto fail; + wrapper = mono_marshal_get_managed_wrapper (method, klass, target_handle, error); + if (!is_ok (error)) + goto leave; - delegate->delegate_trampoline = mono_compile_method_checked (wrapper, &error); - if (!is_ok (&error)) - goto fail; + MONO_HANDLE_SETVAL (delegate, delegate_trampoline, gpointer, mono_compile_method_checked (wrapper, error)); + if (!is_ok (error)) + goto leave; // Add the delegate to the delegate hash table delegate_hash_table_add (delegate); /* when the object is collected, collect the dynamic method, too */ - mono_object_register_finalizer ((MonoObject*)delegate); + mono_object_register_finalizer ((MonoObject*) MONO_HANDLE_RAW (delegate)); - return delegate->delegate_trampoline; + result = MONO_HANDLE_GETVAL (delegate, delegate_trampoline); -fail: - if (target_handle != 0) +leave: + if (!is_ok (error) && target_handle != 0) mono_gchandle_free (target_handle); - mono_error_set_pending_exception (&error); - return NULL; + HANDLE_FUNCTION_RETURN_VAL (result); } /* @@ -521,7 +547,7 @@ delegate_hash_table_remove (MonoDelegate *d) } static void -delegate_hash_table_add (MonoDelegate *d) +delegate_hash_table_add (MonoDelegateHandle d) { guint32 gchandle; guint32 old_gchandle; @@ -529,14 +555,15 @@ delegate_hash_table_add (MonoDelegate *d) mono_marshal_lock (); if (delegate_hash_table == NULL) delegate_hash_table = delegate_hash_table_new (); + gpointer delegate_trampoline = MONO_HANDLE_GETVAL (d, delegate_trampoline); if (mono_gc_is_moving ()) { - gchandle = mono_gchandle_new_weakref ((MonoObject*)d, FALSE); - old_gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (delegate_hash_table, d->delegate_trampoline)); - g_hash_table_insert (delegate_hash_table, d->delegate_trampoline, GUINT_TO_POINTER (gchandle)); + gchandle = mono_gchandle_new_weakref ((MonoObject*) MONO_HANDLE_RAW (d), FALSE); + old_gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (delegate_hash_table, delegate_trampoline)); + g_hash_table_insert (delegate_hash_table, delegate_trampoline, GUINT_TO_POINTER (gchandle)); if (old_gchandle) mono_gchandle_free (old_gchandle); } else { - g_hash_table_insert (delegate_hash_table, d->delegate_trampoline, d); + g_hash_table_insert (delegate_hash_table, delegate_trampoline, MONO_HANDLE_RAW (d)); } mono_marshal_unlock (); } @@ -590,12 +617,23 @@ parse_unmanaged_function_pointer_attr (MonoClass *klass, MonoMethodPInvoke *piin MonoDelegate* mono_ftnptr_to_delegate (MonoClass *klass, gpointer ftn) { + HANDLE_FUNCTION_ENTER (); MonoError error; + MonoDelegateHandle result = mono_ftnptr_to_delegate_handle (klass, ftn, &error); + mono_error_set_pending_exception (&error); + HANDLE_FUNCTION_RETURN_OBJ (result); +} + +MonoDelegateHandle +mono_ftnptr_to_delegate_handle (MonoClass *klass, gpointer ftn, MonoError *error) +{ + HANDLE_FUNCTION_ENTER (); + error_init (error); guint32 gchandle; - MonoDelegate *d; + MonoDelegateHandle d = MONO_HANDLE_NEW (MonoDelegate, NULL); if (ftn == NULL) - return NULL; + goto leave; mono_marshal_lock (); if (delegate_hash_table == NULL) @@ -605,30 +643,26 @@ mono_ftnptr_to_delegate (MonoClass *klass, gpointer ftn) gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (delegate_hash_table, ftn)); mono_marshal_unlock (); if (gchandle) - d = (MonoDelegate*)mono_gchandle_get_target (gchandle); - else - d = NULL; + MONO_HANDLE_ASSIGN (d, MONO_HANDLE_CAST (MonoDelegate, mono_gchandle_get_target_handle (gchandle))); } else { - d = (MonoDelegate *)g_hash_table_lookup (delegate_hash_table, ftn); + MONO_HANDLE_ASSIGN (d, MONO_HANDLE_NEW (MonoDelegate, g_hash_table_lookup (delegate_hash_table, ftn))); mono_marshal_unlock (); } - if (d == NULL) { + if (MONO_HANDLE_IS_NULL (d)) { /* This is a native function, so construct a delegate for it */ MonoMethodSignature *sig; MonoMethod *wrapper; MonoMarshalSpec **mspecs; MonoMethod *invoke = mono_get_delegate_invoke (klass); MonoMethodPInvoke piinfo; - MonoObject *this_obj; + MonoObjectHandle this_obj; int i; if (use_aot_wrappers) { wrapper = mono_marshal_get_native_func_wrapper_aot (klass); - this_obj = mono_value_box_checked (mono_domain_get (), mono_defaults.int_class, &ftn, &error); - if (!is_ok (&error)) { - mono_error_set_pending_exception (&error); - return NULL; - } + this_obj = MONO_HANDLE_NEW (MonoObject, mono_value_box_checked (mono_domain_get (), mono_defaults.int_class, &ftn, error)); + if (!is_ok (error)) + goto leave; } else { memset (&piinfo, 0, sizeof (piinfo)); parse_unmanaged_function_pointer_attr (klass, &piinfo); @@ -640,7 +674,7 @@ mono_ftnptr_to_delegate (MonoClass *klass, gpointer ftn) sig->hasthis = 0; wrapper = mono_marshal_get_native_func_wrapper (klass->image, sig, &piinfo, mspecs, ftn); - this_obj = NULL; + this_obj = MONO_HANDLE_NEW (MonoObject, NULL); for (i = mono_method_signature (invoke)->param_count; i >= 0; i--) if (mspecs [i]) @@ -649,25 +683,24 @@ mono_ftnptr_to_delegate (MonoClass *klass, gpointer ftn) g_free (sig); } - d = (MonoDelegate*)mono_object_new_checked (mono_domain_get (), klass, &error); - if (!mono_error_ok (&error)) { - mono_error_set_pending_exception (&error); - return NULL; - } - gpointer compiled_ptr = mono_compile_method_checked (wrapper, &error); - if (mono_error_set_pending_exception (&error)) - return NULL; - mono_delegate_ctor_with_method ((MonoObject*)d, this_obj, compiled_ptr, wrapper, &error); - if (mono_error_set_pending_exception (&error)) - return NULL; - } + MONO_HANDLE_ASSIGN (d, MONO_HANDLE_NEW (MonoDelegate, mono_object_new_checked (mono_domain_get (), klass, error))); + if (!is_ok (error)) + goto leave; + gpointer compiled_ptr = mono_compile_method_checked (wrapper, error); + if (!is_ok (error)) + goto leave; - if (d->object.vtable->domain != mono_domain_get ()) { - mono_set_pending_exception (mono_get_exception_not_supported ("Delegates cannot be marshalled from native code into a domain other than their home domain")); - return NULL; + mono_delegate_ctor_with_method (MONO_HANDLE_CAST (MonoObject, d), this_obj, compiled_ptr, wrapper, error); + if (!is_ok (error)) + goto leave; } - return d; + g_assert (!MONO_HANDLE_IS_NULL (d)); + if (MONO_HANDLE_DOMAIN (d) != mono_domain_get ()) + mono_error_set_not_supported (error, "Delegates cannot be marshalled from native code into a domain other than their home domain"); + +leave: + HANDLE_FUNCTION_RETURN_REF (MonoDelegate, d); } void @@ -11025,18 +11058,23 @@ ves_icall_System_Runtime_InteropServices_Marshal_GetLastWin32Error (void) } guint32 -ves_icall_System_Runtime_InteropServices_Marshal_SizeOf (MonoReflectionType *rtype) +ves_icall_System_Runtime_InteropServices_Marshal_SizeOf (MonoReflectionTypeHandle rtype, MonoError *error) { MonoClass *klass; MonoType *type; guint32 layout; - MONO_CHECK_ARG_NULL (rtype, 0); + error_init (error); + + if (MONO_HANDLE_IS_NULL (rtype)) { + mono_error_set_argument_null (error, "type", ""); + return 0; + } - type = rtype->type; + type = MONO_HANDLE_GETVAL (rtype, type); klass = mono_class_from_mono_type (type); if (!mono_class_init (klass)) { - mono_set_pending_exception (mono_class_get_exception_for_failure (klass)); + mono_error_set_for_class_failure (error, klass); return 0; } @@ -11045,13 +11083,7 @@ ves_icall_System_Runtime_InteropServices_Marshal_SizeOf (MonoReflectionType *rty if (type->type == MONO_TYPE_PTR || type->type == MONO_TYPE_FNPTR) { return sizeof (gpointer); } else if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT) { - gchar *msg; - MonoException *exc; - - msg = g_strdup_printf ("Type %s cannot be marshaled as an unmanaged structure.", klass->name); - exc = mono_get_exception_argument ("t", msg); - g_free (msg); - mono_set_pending_exception (exc); + mono_error_set_argument (error, "t", "Type %s cannot be marshaled as an unmanaged structure.", klass->name); return 0; } @@ -11157,26 +11189,29 @@ ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure_type (gpointer s } int -ves_icall_System_Runtime_InteropServices_Marshal_OffsetOf (MonoReflectionType *type, MonoString *field_name) +ves_icall_System_Runtime_InteropServices_Marshal_OffsetOf (MonoReflectionTypeHandle ref_type, MonoStringHandle field_name, MonoError *error) { - MonoError error; - MonoMarshalType *info; - MonoClass *klass; - char *fname; - int match_index = -1; - - MONO_CHECK_ARG_NULL (type, 0); - MONO_CHECK_ARG_NULL (field_name, 0); - - fname = mono_string_to_utf8_checked (field_name, &error); - if (mono_error_set_pending_exception (&error)) + error_init (error); + if (MONO_HANDLE_IS_NULL (ref_type)) { + mono_error_set_argument_null (error, "type", ""); return 0; - klass = mono_class_from_mono_type (type->type); + } + if (MONO_HANDLE_IS_NULL (field_name)) { + mono_error_set_argument_null (error, "fieldName", ""); + return 0; + } + + char *fname = mono_string_handle_to_utf8 (field_name, error); + return_val_if_nok (error, 0); + + MonoType *type = MONO_HANDLE_GETVAL (ref_type, type); + MonoClass *klass = mono_class_from_mono_type (type); if (!mono_class_init (klass)) { - mono_set_pending_exception (mono_class_get_exception_for_failure (klass)); + mono_error_set_for_class_failure (error, klass); return 0; } + int match_index = -1; while (klass && match_index == -1) { MonoClassField* field; int i = 0; @@ -11198,21 +11233,14 @@ ves_icall_System_Runtime_InteropServices_Marshal_OffsetOf (MonoReflectionType *t g_free (fname); if(match_index == -1) { - MonoException* exc; - gchar *tmp; - /* Get back original class instance */ - klass = mono_class_from_mono_type (type->type); + klass = mono_class_from_mono_type (type); - tmp = g_strdup_printf ("Field passed in is not a marshaled member of the type %s", klass->name); - exc = mono_get_exception_argument ("fieldName", tmp); - g_free (tmp); - - mono_set_pending_exception ((MonoException*)exc); + mono_error_set_argument (error, "fieldName", "Field passed in is not a marshaled member of the type %s", klass->name); return 0; } - info = mono_marshal_load_type_info (klass); + MonoMarshalType *info = mono_marshal_load_type_info (klass); return info->fields [match_index].offset; } @@ -11438,22 +11466,24 @@ ves_icall_System_Runtime_InteropServices_Marshal_UnsafeAddrOfPinnedArrayElement return mono_array_addr_with_size_fast (arrayobj, mono_array_element_size (arrayobj->obj.vtable->klass), index); } -MonoDelegate* -ves_icall_System_Runtime_InteropServices_Marshal_GetDelegateForFunctionPointerInternal (void *ftn, MonoReflectionType *type) +MonoDelegateHandle +ves_icall_System_Runtime_InteropServices_Marshal_GetDelegateForFunctionPointerInternal (void *ftn, MonoReflectionTypeHandle type, MonoError *error) { - MonoClass *klass = mono_type_get_class (type->type); + error_init (error); + MonoClass *klass = mono_type_get_class (MONO_HANDLE_GETVAL (type, type)); if (!mono_class_init (klass)) { - mono_set_pending_exception (mono_class_get_exception_for_failure (klass)); + mono_error_set_for_class_failure (error, klass); return NULL; } - return mono_ftnptr_to_delegate (klass, ftn); + return mono_ftnptr_to_delegate_handle (klass, ftn, error); } gpointer -ves_icall_System_Runtime_InteropServices_Marshal_GetFunctionPointerForDelegateInternal (MonoDelegate *delegate) +ves_icall_System_Runtime_InteropServices_Marshal_GetFunctionPointerForDelegateInternal (MonoDelegateHandle delegate, MonoError *error) { - return mono_delegate_to_ftnptr (delegate); + error_init (error); + return mono_delegate_handle_to_ftnptr (delegate, error); } /** @@ -12337,9 +12367,9 @@ static MonoObjectHandle mono_icall_handle_new (gpointer rawobj) { #ifdef MONO_HANDLE_TRACK_OWNER - return mono_handle_new_full (rawobj, FALSE, ""); + return mono_handle_new (rawobj, ""); #else - return mono_handle_new_full (rawobj, FALSE); + return mono_handle_new (rawobj); #endif } @@ -12347,8 +12377,8 @@ static MonoObjectHandle mono_icall_handle_new_interior (gpointer rawobj) { #ifdef MONO_HANDLE_TRACK_OWNER - return mono_handle_new_full (rawobj, TRUE, ""); + return mono_handle_new_interior (rawobj, ""); #else - return mono_handle_new_full (rawobj, TRUE); + return mono_handle_new_interior (rawobj); #endif } diff --git a/mono/metadata/marshal.h b/mono/metadata/marshal.h index 57018b828d4..65719385906 100644 --- a/mono/metadata/marshal.h +++ b/mono/metadata/marshal.h @@ -458,7 +458,7 @@ guint32 ves_icall_System_Runtime_InteropServices_Marshal_GetLastWin32Error (void); guint32 -ves_icall_System_Runtime_InteropServices_Marshal_SizeOf (MonoReflectionType *rtype); +ves_icall_System_Runtime_InteropServices_Marshal_SizeOf (MonoReflectionTypeHandle rtype, MonoError *error); void ves_icall_System_Runtime_InteropServices_Marshal_StructureToPtr (MonoObject *obj, gpointer dst, MonoBoolean delete_old); @@ -470,7 +470,7 @@ MonoObject * ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure_type (gpointer src, MonoReflectionType *type); int -ves_icall_System_Runtime_InteropServices_Marshal_OffsetOf (MonoReflectionType *type, MonoString *field_name); +ves_icall_System_Runtime_InteropServices_Marshal_OffsetOf (MonoReflectionTypeHandle type, MonoStringHandle field_name, MonoError *error); gpointer ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString *string); @@ -514,11 +514,11 @@ ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (void *ptr); void* ves_icall_System_Runtime_InteropServices_Marshal_UnsafeAddrOfPinnedArrayElement (MonoArray *arrayobj, int index); -MonoDelegate* -ves_icall_System_Runtime_InteropServices_Marshal_GetDelegateForFunctionPointerInternal (void *ftn, MonoReflectionType *type); +MonoDelegateHandle +ves_icall_System_Runtime_InteropServices_Marshal_GetDelegateForFunctionPointerInternal (void *ftn, MonoReflectionTypeHandle type, MonoError *error); gpointer -ves_icall_System_Runtime_InteropServices_Marshal_GetFunctionPointerForDelegateInternal (MonoDelegate *delegate); +ves_icall_System_Runtime_InteropServices_Marshal_GetFunctionPointerForDelegateInternal (MonoDelegateHandle delegate, MonoError *error); int ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk); diff --git a/mono/metadata/mempool-internals.h b/mono/metadata/mempool-internals.h index d2cf14781b0..3458232139c 100644 --- a/mono/metadata/mempool-internals.h +++ b/mono/metadata/mempool-internals.h @@ -61,6 +61,20 @@ g_slist_append_mempool (MonoMemPool *mp, GSList *list, gpointer data) return new_list; } +static inline GList* +g_list_append_mempool (MonoMemPool *mp, GList *list, gpointer data) +{ + GList *new_list; + + new_list = (GList *) mono_mempool_alloc0 (mp, sizeof (GList)); + new_list->data = data; + new_list->prev = g_list_last (list); + if (new_list->prev) + new_list->prev->next = new_list; + + return list ? list : new_list; +} + char* mono_mempool_strdup_vprintf (MonoMemPool *pool, const char *format, va_list args); diff --git a/mono/metadata/object-internals.h b/mono/metadata/object-internals.h index 59b1cc55899..7af56df2a72 100644 --- a/mono/metadata/object-internals.h +++ b/mono/metadata/object-internals.h @@ -655,10 +655,10 @@ void mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error); gboolean -mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method, MonoError *error); +mono_delegate_ctor_with_method (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoMethod *method, MonoError *error); gboolean -mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoError *error); +mono_delegate_ctor (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoError *error); void* mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words); @@ -768,12 +768,18 @@ struct _MonoDelegate { MonoBoolean method_is_virtual; }; +/* Safely access System.Delegate from native code */ +TYPED_HANDLE_DECL (MonoDelegate); + typedef struct _MonoMulticastDelegate MonoMulticastDelegate; struct _MonoMulticastDelegate { MonoDelegate delegate; MonoArray *delegates; }; +/* Safely access System.MulticastDelegate from native code */ +TYPED_HANDLE_DECL (MonoMulticastDelegate); + struct _MonoReflectionField { MonoObject object; MonoClass *klass; diff --git a/mono/metadata/object.c b/mono/metadata/object.c index 92aa723f20a..d30f0413ac2 100644 --- a/mono/metadata/object.c +++ b/mono/metadata/object.c @@ -7817,43 +7817,44 @@ mono_print_unhandled_exception (MonoObject *exc) * On failure returns FALSE and sets \p error. */ gboolean -mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method, MonoError *error) +mono_delegate_ctor_with_method (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoMethod *method, MonoError *error) { MONO_REQ_GC_UNSAFE_MODE; error_init (error); - MonoDelegate *delegate = (MonoDelegate *)this_obj; + MonoDelegateHandle delegate = MONO_HANDLE_CAST (MonoDelegate, this_obj); - g_assert (this_obj); + g_assert (!MONO_HANDLE_IS_NULL (this_obj)); g_assert (addr); - g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class)); + MonoClass *klass = mono_handle_class (this_obj); + g_assert (mono_class_has_parent (klass, mono_defaults.multicastdelegate_class)); if (method) - delegate->method = method; + MONO_HANDLE_SETVAL (delegate, method, MonoMethod*, method); mono_stats.delegate_creations++; #ifndef DISABLE_REMOTING - if (target && mono_object_is_transparent_proxy (target)) { + if (!MONO_HANDLE_IS_NULL (target) && mono_class_is_transparent_proxy (mono_handle_class (target))) { g_assert (method); method = mono_marshal_get_remoting_invoke (method); #ifdef ENABLE_INTERPRETER //g_error ("need RuntimeMethod in method_ptr when using interpreter"); #endif - delegate->method_ptr = mono_compile_method_checked (method, error); + MONO_HANDLE_SETVAL (delegate, method_ptr, gpointer, mono_compile_method_checked (method, error)); return_val_if_nok (error, FALSE); - MONO_OBJECT_SETREF (delegate, target, target); + MONO_HANDLE_SET (delegate, target, target); } else #endif { - delegate->method_ptr = addr; - MONO_OBJECT_SETREF (delegate, target, target); + MONO_HANDLE_SETVAL (delegate, method_ptr, gpointer, addr); + MONO_HANDLE_SET (delegate, target, target); } - delegate->invoke_impl = callbacks.create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass); + MONO_HANDLE_SETVAL (delegate, invoke_impl, gpointer, callbacks.create_delegate_trampoline (MONO_HANDLE_DOMAIN (delegate), mono_handle_class (delegate))); if (callbacks.init_delegate) - callbacks.init_delegate (delegate); + callbacks.init_delegate (MONO_HANDLE_RAW (delegate)); /* FIXME: update init_delegate callback to take a MonoDelegateHandle */ return TRUE; } @@ -7867,7 +7868,7 @@ mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpoint * On failure returns FALSE and sets \p error. */ gboolean -mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoError *error) +mono_delegate_ctor (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoError *error) { MONO_REQ_GC_UNSAFE_MODE; diff --git a/mono/metadata/sgen-mono.c b/mono/metadata/sgen-mono.c index 44adebbc003..7cb7f291259 100644 --- a/mono/metadata/sgen-mono.c +++ b/mono/metadata/sgen-mono.c @@ -893,6 +893,10 @@ mono_gc_clear_domain (MonoDomain * domain) sgen_clear_nursery_fragments (); + FOREACH_THREAD (info) { + mono_handle_stack_free_domain ((HandleStack*)info->client_info.info.handle_stack, domain); + } FOREACH_THREAD_END + if (sgen_mono_xdomain_checks && domain != mono_get_root_domain ()) { sgen_scan_for_registered_roots_in_domain (domain, ROOT_TYPE_NORMAL); sgen_scan_for_registered_roots_in_domain (domain, ROOT_TYPE_WBARRIER); diff --git a/mono/metadata/w32error-unix.c b/mono/metadata/w32error-unix.c index dbbc43bc6f8..df41473dfe8 100644 --- a/mono/metadata/w32error-unix.c +++ b/mono/metadata/w32error-unix.c @@ -65,7 +65,7 @@ mono_w32error_unix_to_win32 (guint32 error) case EIO: return ERROR_INVALID_HANDLE; case EINTR: return ERROR_IO_PENDING; /* best match I could find */ case EPIPE: return ERROR_WRITE_FAULT; - case ELOOP: return ERROR_ACCESS_DENIED; /* Empirically found by testing desktop dotnet. */ + case ELOOP: return ERROR_CANT_RESOLVE_FILENAME; default: g_error ("%s: unknown error (%d) \"%s\"", __FILE__, error, g_strerror (error)); diff --git a/mono/metadata/w32error.h b/mono/metadata/w32error.h index c8fb1717a52..439bdd81a2a 100644 --- a/mono/metadata/w32error.h +++ b/mono/metadata/w32error.h @@ -42,6 +42,7 @@ #define ERROR_FILENAME_EXCED_RANGE 206 #define ERROR_DIRECTORY 267 #define ERROR_IO_PENDING 997 +#define ERROR_CANT_RESOLVE_FILENAME 1921 #define ERROR_ENCRYPTION_FAILED 6000 #define WSAEINTR 10004 #define WSAEBADF 10009 diff --git a/mono/metadata/w32file-unix.c b/mono/metadata/w32file-unix.c index f6e4d2df513..6fcb0f691f1 100644 --- a/mono/metadata/w32file-unix.c +++ b/mono/metadata/w32file-unix.c @@ -2518,7 +2518,6 @@ gboolean mono_w32file_delete(const gunichar2 *name) gchar *filename; gint retval; gboolean ret = FALSE; - guint32 attrs; #if 0 struct stat statbuf; FileShare *shareinfo; @@ -2539,14 +2538,6 @@ gboolean mono_w32file_delete(const gunichar2 *name) return(FALSE); } - attrs = mono_w32file_get_attributes (name); - if (attrs == INVALID_FILE_ATTRIBUTES) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: file attributes error", __func__); - /* Error set by mono_w32file_get_attributes() */ - g_free (filename); - return(FALSE); - } - #if 0 /* Check to make sure sharing allows us to open the file for * writing. See bug 323389. @@ -3748,7 +3739,7 @@ mono_w32file_get_attributes (const gunichar2 *name) } result = _wapi_stat (utf8_name, &buf); - if (result == -1 && errno == ENOENT) { + if (result == -1 && (errno == ENOENT || errno == ELOOP)) { /* Might be a dangling symlink... */ result = _wapi_lstat (utf8_name, &buf); } diff --git a/mono/metadata/w32socket-unix.c b/mono/metadata/w32socket-unix.c index 70b36ed2fa3..75d90df2ed9 100644 --- a/mono/metadata/w32socket-unix.c +++ b/mono/metadata/w32socket-unix.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #ifdef HAVE_SYS_IOCTL_H #include @@ -27,7 +28,6 @@ #endif #include #include -#include #ifdef HAVE_SYS_UIO_H #include #endif diff --git a/mono/mini/Makefile.am.in b/mono/mini/Makefile.am.in index e0db07a52b4..a08d93b4137 100755 --- a/mono/mini/Makefile.am.in +++ b/mono/mini/Makefile.am.in @@ -401,6 +401,9 @@ interp_sources = \ interp/mintops.def \ interp/mintops.c \ interp/transform.c +else +interp_sources = \ + interp/interp-stubs.c endif if ENABLE_LLVM @@ -502,6 +505,8 @@ test_sources = \ aot-tests.cs \ gc-test.cs \ gshared.cs \ + unaligned.cs \ + MemoryIntrinsics.il \ mixed.cs if NACL_CODEGEN @@ -521,6 +526,7 @@ regtests_UNIVERSAL = \ devirtualization.exe \ generics.exe \ basic-simd.exe \ + unaligned.exe \ basic-vectors.exe if NACL_CODEGEN @@ -654,6 +660,9 @@ nacl.exe: nacl.cs TestDriver.dll generics.exe: generics.cs TestDriver.dll generics-variant-types.dll $(MCS) -out:$@ $(CSFLAGS) $< -r:TestDriver.dll -r:generics-variant-types.dll -r:$(CLASS)/System.Core.dll +unaligned.exe: unaligned.cs TestDriver.dll MemoryIntrinsics.dll + $(MCS) -out:$@ $(CSFLAGS) $< -r:TestDriver.dll -r:MemoryIntrinsics.dll + %.exe: %.cs TestDriver.dll $(MCS) -out:$@ $(CSFLAGS) $< -r:TestDriver.dll @@ -666,6 +675,9 @@ TestDriver.dll: $(srcdir)/TestDriver.cs $(srcdir)/TestHelpers.cs generics-variant-types.dll: generics-variant-types.il $(ILASM) -dll -output=$@ $< +MemoryIntrinsics.dll: MemoryIntrinsics.il + $(ILASM) -dll -output=$@ $< + if NACL_CODEGEN GENMDESC_OPTS=--nacl else !NACL_CODEGEN @@ -770,6 +782,7 @@ gsharedvtcheck: $(MAKE) fullaotcheck GSHAREDVT=1 fullaot_regtests = $(regtests) aot-tests.exe $(if $(GSHAREDVT),gshared.exe) +fullaot_testing_deps = generics-variant-types.dll TestDriver.dll MemoryIntrinsics.dll FULLAOT_LIBS_UNIVERSAL = \ mscorlib.dll \ @@ -795,17 +808,18 @@ FULLAOT_LIBS_DISABLED += \ System.Configuration.dll endif + FULLAOT_LIBS = $(filter-out $(FULLAOT_LIBS_DISABLED),$(FULLAOT_LIBS_UNIVERSAL)) FULLAOT_TMP_DIR=$(top_builddir)/mono/mini/fullaot-tmp # This currently only works on amd64/arm -fullaotcheck: $(mono) $(fullaot_regtests) +fullaotcheck: $(mono) $(fullaot_regtests) $(fullaot_testing_deps) rm -rf $(FULLAOT_TMP_DIR) mkdir $(FULLAOT_TMP_DIR) $(MAKE) fullaot-libs AOT_FLAGS="full,$(MONO_FULLAOT_ADDITIONAL_ARGS)$(INVARIANT_AOT_OPTIONS)" GSHAREDVT=$(GSHAREDVT) - cp $(regtests) $(fullaot_regtests) generics-variant-types.dll TestDriver.dll $(FULLAOT_TMP_DIR)/ - MONO_PATH=$(FULLAOT_TMP_DIR) $(top_builddir)/runtime/mono-wrapper $(MOBILE_RUNTIME_ARG) $(LLVM_AOT_RUNTIME_OPTS) $(GSHAREDVT_RUNTIME_OPTS) --aot="full,$(MONO_FULLAOT_ADDITIONAL_ARGS)$(INVARIANT_AOT_OPTIONS)" $(FULLAOT_TMP_DIR)/{generics-variant-types.dll,TestDriver.dll,*.exe} || exit 1 + cp $(regtests) $(fullaot_regtests) $(fullaot_testing_deps) $(FULLAOT_TMP_DIR)/ + MONO_PATH=$(FULLAOT_TMP_DIR) $(top_builddir)/runtime/mono-wrapper $(MOBILE_RUNTIME_ARG) $(LLVM_AOT_RUNTIME_OPTS) $(GSHAREDVT_RUNTIME_OPTS) --aot="full,$(MONO_FULLAOT_ADDITIONAL_ARGS)$(INVARIANT_AOT_OPTIONS)" $(FULLAOT_TMP_DIR)/{*.dll,*.exe} || exit 1 ln -s $(if $(MONO_EXECUTABLE),$(MONO_EXECUTABLE),$$PWD/mono) $(FULLAOT_TMP_DIR)/ for i in $(fullaot_regtests); do echo $$i; MONO_PATH=$(FULLAOT_TMP_DIR) $(top_builddir)/runtime/mono-wrapper $(MOBILE_RUNTIME_ARG) --full-aot $(FULLAOT_TMP_DIR)/$$i --exclude '!FULLAOT' $(ARCH_FULLAOT_EXCLUDE) || exit 1; done @@ -827,8 +841,8 @@ llvmonlycheck: mono $(llvmonly_regtests) rm -rf fullaot-tmp mkdir fullaot-tmp $(MAKE) fullaot-libs AOT_FLAGS="llvmonly,$(MONO_FULLAOT_ADDITIONAL_ARGS)$(INVARIANT_AOT_OPTIONS)" - cp $(llvmonly_regtests) generics-variant-types.dll TestDriver.dll fullaot-tmp/ - MONO_PATH=fullaot-tmp $(top_builddir)/runtime/mono-wrapper $(MOBILE_RUNTIME_ARG) --aot=llvmonly fullaot-tmp/{generics-variant-types.dll,TestDriver.dll,*.exe} || exit 1 + cp $(llvmonly_regtests) $(fullaot_testing_deps) fullaot-tmp/ + MONO_PATH=fullaot-tmp $(top_builddir)/runtime/mono-wrapper $(MOBILE_RUNTIME_ARG) --aot=llvmonly fullaot-tmp/{*.dll,*.exe} || exit 1 ln -s $$PWD/mono fullaot-tmp/ for i in $(llvmonly_regtests); do echo $$i; MONO_PATH=fullaot-tmp $(top_builddir)/runtime/mono-wrapper $(MOBILE_RUNTIME_ARG) --llvmonly fullaot-tmp/$$i --exclude '!BITCODE' || exit 1; done diff --git a/mono/mini/MemoryIntrinsics.il b/mono/mini/MemoryIntrinsics.il new file mode 100644 index 00000000000..dd4c9b5d47e --- /dev/null +++ b/mono/mini/MemoryIntrinsics.il @@ -0,0 +1,180 @@ +.assembly extern mscorlib +{ + .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) + .ver 4:0:0:0 +} + +.assembly 'MemoryIntrinsics' +{ + .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) + .hash algorithm 0x00008004 + .ver 0:0:0:0 +} +.module 'instrics-lib.dll' +.imagebase 0x00400000 +.file alignment 0x00000200 +.stackreserve 0x00100000 +.subsystem 0x0003 +.corflags 0x00000001 + +.namespace Mono { + .class public abstract auto ansi sealed beforefieldinit Intrinsics extends [mscorlib]System.Object + { + .method public hidebysig static void Cpobj(void* 'to', void* from) cil managed + { + ldarg.0 + ldarg.1 + cpobj !!T + ret + } + + .method public hidebysig static !!T Ldobj(void* 'from') cil managed + { + ldarg.0 + ldobj !!T + ret + } + + .method public hidebysig static void Stobj(void* 'to', !!T 'value') cil managed + { + ldarg.0 + ldarg.1 + stobj !!T + ret + } + + .method public hidebysig static void LdobjStObjPair(void* 'to', void* 'from') cil managed + { + ldarg.0 + ldarg.1 + ldobj !!T + stobj !!T + ret + } + + .method public hidebysig static void Cpblk(void* 'to', void* 'from', int32 size) cil managed + { + ldarg.0 + ldarg.1 + ldarg.2 + cpblk + ret + } + + .method public hidebysig static void Initblk(void* 'to', int32 'value', int32 'size') cil managed + { + ldarg.0 + ldarg.1 + ldarg.2 + initblk + ret + } + + //Unaligned intrinsics + .method public hidebysig static void UnalignedCpobj(void* 'to', void* from) cil managed + { + ldarg.0 + ldarg.1 + unaligned. 1 + cpobj !!T + ret + } + + .method public hidebysig static !!T UnalignedLdobj(void* 'from') cil managed + { + ldarg.0 + unaligned. 1 + ldobj !!T + ret + } + + .method public hidebysig static void UnalignedStobj(void* 'to', !!T 'value') cil managed + { + ldarg.0 + ldarg.1 + unaligned. 1 + stobj !!T + ret + } + + .method public hidebysig static void UnalignedLdobjStObjPair(void* 'to', void* 'from') cil managed + { + ldarg.0 + ldarg.1 + unaligned. 1 + ldobj !!T + stobj !!T + ret + } + + .method public hidebysig static void UnalignedCpblk(void* 'to', void* 'from', int32 size) cil managed + { + ldarg.0 + ldarg.1 + ldarg.2 + unaligned. 1 + cpblk + ret + } + + .method public hidebysig static void UnalignedInit(void* 'to', int32 'value', int32 'size') cil managed + { + ldarg.0 + ldarg.1 + ldarg.2 + unaligned. 1 + initblk + ret + } + + //Unaligned ldind + .method public hidebysig static int16 UnalignedLdInd2(void* 'from') cil managed + { + ldarg.0 + unaligned. 1 + ldind.i2 + ret + } + + .method public hidebysig static int32 UnalignedLdInd4(void* 'from') cil managed + { + ldarg.0 + unaligned. 1 + ldind.i4 + ret + } + + .method public hidebysig static int64 UnalignedLdInd8(void* 'from') cil managed + { + ldarg.0 + unaligned. 1 + ldind.i8 + ret + } + + .method public hidebysig static float32 UnalignedLdIndR4(void* 'from') cil managed + { + ldarg.0 + unaligned. 1 + ldind.r4 + ret + } + + .method public hidebysig static float64 UnalignedLdIndR8(void* 'from') cil managed + { + ldarg.0 + unaligned. 1 + ldind.r8 + ret + } + + .method public hidebysig static native int UnalignedLdIndI(void* 'from') cil managed + { + ldarg.0 + unaligned. 1 + ldind.i + ret + } + + } +} diff --git a/mono/mini/aot-runtime.c b/mono/mini/aot-runtime.c index 782106c45e1..30ef9a64ad7 100644 --- a/mono/mini/aot-runtime.c +++ b/mono/mini/aot-runtime.c @@ -3941,9 +3941,11 @@ load_method (MonoDomain *domain, MonoAotModule *amodule, MonoImage *image, MonoM if (!method) return NULL; } - full_name = mono_method_full_name (method, TRUE); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT: NOT FOUND: %s.", full_name); - g_free (full_name); + if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)) { + full_name = mono_method_full_name (method, TRUE); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT: NOT FOUND: %s.", full_name); + g_free (full_name); + } } return NULL; } diff --git a/mono/mini/debugger-agent.c b/mono/mini/debugger-agent.c index c639fa9e756..bfdddb37547 100644 --- a/mono/mini/debugger-agent.c +++ b/mono/mini/debugger-agent.c @@ -72,10 +72,11 @@ #include #include #include +#include #include "debugger-agent.h" #include "mini.h" #include "seq-points.h" -#include +#include "interp/interp.h" /* * On iOS we can't use System.Environment.Exit () as it will do the wrong @@ -137,6 +138,7 @@ typedef struct MonoContext ctx; MonoDebugMethodJitInfo *jit; MonoJitInfo *ji; + MonoInterpFrameHandle interp_frame; int flags; mgreg_t *reg_locations [MONO_MAX_IREGS]; /* @@ -2480,6 +2482,35 @@ static void invoke_method (void); * SUSPEND/RESUME */ +static MonoJitInfo* +get_top_method_ji (gpointer ip, MonoDomain **domain, gpointer *out_ip) +{ + MonoJitInfo *ji; + + if (out_ip) + *out_ip = ip; + + ji = mini_jit_info_table_find (mono_domain_get (), (char*)ip, domain); + if (!ji) { + /* Could be an interpreter method */ + + MonoLMF *lmf = mono_get_lmf (); + MonoInterpFrameHandle *frame; + + g_assert (((guint64)lmf->previous_lmf) & 2); + MonoLMFExt *ext = (MonoLMFExt*)lmf; + + g_assert (ext->interp_exit); + frame = ext->interp_exit_data; + ji = mono_interp_frame_get_jit_info (frame); + if (domain) + *domain = mono_domain_get (); + if (out_ip) + *out_ip = mono_interp_frame_get_ip (frame); + } + return ji; +} + /* * save_thread_context: * @@ -2619,13 +2650,23 @@ thread_interrupt (DebuggerTlsData *tls, MonoThreadInfo *info, MonoJitInfo *ji) * suspended when it returns to managed code, so the parent's ctx should * remain valid. */ + MonoThreadUnwindState *state = mono_thread_info_get_suspend_state (info); + data.last_frame_set = FALSE; - mono_get_eh_callbacks ()->mono_walk_stack_with_state (get_last_frame, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &data); + mono_get_eh_callbacks ()->mono_walk_stack_with_state (get_last_frame, state, MONO_UNWIND_SIGNAL_SAFE, &data); if (data.last_frame_set) { gpointer jit_tls = ((MonoThreadInfo*)tls->thread->thread_info)->jit_data; memcpy (&tls->async_last_frame, &data.last_frame, sizeof (StackFrameInfo)); + if (data.last_frame.type == FRAME_TYPE_INTERP_TO_MANAGED) { + /* + * Store the current lmf instead of the parent one, since that + * contains the interp exit data. + */ + data.lmf = state->unwind_data [MONO_UNWIND_DATA_LMF]; + } + copy_unwind_state_from_frame_data (&tls->async_state, &data, jit_tls); copy_unwind_state_from_frame_data (&tls->context, &data, jit_tls); } else { @@ -2751,8 +2792,8 @@ process_suspend (DebuggerTlsData *tls, MonoContext *ctx) return; } - ji = mini_jit_info_table_find (mono_domain_get (), (char*)ip, NULL); - + ji = get_top_method_ji (ip, NULL, NULL); + g_assert (ji); /* Can't suspend in these methods */ method = jinfo_get_method (ji); if (method->klass == mono_defaults.string_class && (!strcmp (method->name, "memset") || strstr (method->name, "memcpy"))) @@ -3051,7 +3092,7 @@ process_frame (StackFrameInfo *info, MonoContext *ctx, gpointer user_data) SeqPoint sp; int flags = 0; - if (info->type != FRAME_TYPE_MANAGED) { + if (info->type != FRAME_TYPE_MANAGED && info->type != FRAME_TYPE_INTERP) { if (info->type == FRAME_TYPE_DEBUGGER_INVOKE) { /* Mark the last frame as an invoke frame */ if (ud->frames) @@ -3104,6 +3145,7 @@ process_frame (StackFrameInfo *info, MonoContext *ctx, gpointer user_data) frame->native_offset = info->native_offset; frame->flags = flags; frame->ji = info->ji; + frame->interp_frame = info->interp_frame; if (info->reg_locations) memcpy (frame->reg_locations, info->reg_locations, MONO_MAX_IREGS * sizeof (mgreg_t*)); if (ctx) { @@ -4096,7 +4138,7 @@ jit_end (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo, int result) send_type_load (method->klass); - if (!result) + if (!result && jinfo) add_pending_breakpoints (method, jinfo); } @@ -4229,11 +4271,15 @@ insert_breakpoint (MonoSeqPointInfo *seq_points, MonoDomain *domain, MonoJitInfo if (it.seq_point.native_offset == SEQ_POINT_NATIVE_OFFSET_DEAD_CODE) { DEBUG_PRINTF (1, "[dbg] Attempting to insert seq point at dead IL offset %d, ignoring.\n", (int)bp->il_offset); } else if (count == 0) { + if (ji->is_interp) { + mono_interp_set_breakpoint (ji, inst->ip); + } else { #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED - mono_arch_set_breakpoint (ji, inst->ip); + mono_arch_set_breakpoint (ji, inst->ip); #else - NOT_IMPLEMENTED; + NOT_IMPLEMENTED; #endif + } } DEBUG_PRINTF (1, "[dbg] Inserted breakpoint at %s:[il=0x%x,native=0x%x] [%p](%d).\n", mono_method_full_name (jinfo_get_method (ji), TRUE), (int)it.seq_point.il_offset, (int)it.seq_point.native_offset, inst->ip, count); @@ -4255,7 +4301,10 @@ remove_breakpoint (BreakpointInstance *inst) g_assert (count > 0); if (count == 1 && inst->native_offset != SEQ_POINT_NATIVE_OFFSET_DEAD_CODE) { - mono_arch_clear_breakpoint (ji, ip); + if (ji->is_interp) + mono_interp_clear_breakpoint (ji, ip); + else + mono_arch_clear_breakpoint (ji, ip); DEBUG_PRINTF (1, "[dbg] Clear breakpoint at %s [%p].\n", mono_method_full_name (jinfo_get_method (ji), TRUE), ip); } #else @@ -4372,12 +4421,15 @@ set_bp_in_method (MonoDomain *domain, MonoMethod *method, MonoSeqPointInfo *seq_ /* Might be AOTed code */ mono_class_init (method->klass); code = mono_aot_get_method_checked (domain, method, &oerror); - g_assert (code); - mono_error_assert_ok (&oerror); - ji = mono_jit_info_table_find (domain, (char *)code); + if (code) { + mono_error_assert_ok (&oerror); + ji = mono_jit_info_table_find (domain, (char *)code); + } else { + /* Might be interpreted */ + ji = mono_interp_find_jit_info (domain, method); + } g_assert (ji); } - g_assert (code); insert_breakpoint (seq_points, domain, ji, bp, error); } @@ -4636,16 +4688,15 @@ ss_update (SingleStepReq *req, MonoJitInfo *ji, SeqPoint *sp, DebuggerTlsData *t } } - MonoDebugMethodAsyncInfo* asyncMethod = mono_debug_lookup_method_async_debug_info (method); - if (asyncMethod) { - for (int i = 0; i < asyncMethod->num_awaits; i++) - { - if (asyncMethod->yield_offsets[i] == sp->il_offset || asyncMethod->resume_offsets[i] == sp->il_offset) { - mono_debug_free_method_async_debug_info (asyncMethod); + MonoDebugMethodAsyncInfo* async_method = mono_debug_lookup_method_async_debug_info (method); + if (async_method) { + for (int i = 0; i < async_method->num_awaits; i++) { + if (async_method->yield_offsets[i] == sp->il_offset || async_method->resume_offsets[i] == sp->il_offset) { + mono_debug_free_method_async_debug_info (async_method); return FALSE; } } - mono_debug_free_method_async_debug_info (asyncMethod); + mono_debug_free_method_async_debug_info (async_method); } if (req->size != STEP_SIZE_LINE) @@ -4756,7 +4807,7 @@ get_notify_debugger_of_wait_completion_method () } static void -process_breakpoint_inner (DebuggerTlsData *tls, gboolean from_signal) +process_breakpoint (DebuggerTlsData *tls, gboolean from_signal) { MonoJitInfo *ji; guint8 *ip; @@ -4777,11 +4828,27 @@ process_breakpoint_inner (DebuggerTlsData *tls, gboolean from_signal) ip = (guint8 *)MONO_CONTEXT_GET_IP (ctx); ji = mini_jit_info_table_find (mono_domain_get (), (char*)ip, NULL); + + if (!ji) { + /* Interpreter */ + // FIXME: Pass a flag instead to detect this + MonoLMF *lmf = mono_get_lmf (); + MonoInterpFrameHandle *frame; + + g_assert (((guint64)lmf->previous_lmf) & 2); + MonoLMFExt *ext = (MonoLMFExt*)lmf; + + g_assert (ext->interp_exit); + frame = ext->interp_exit_data; + ji = mono_interp_frame_get_jit_info (frame); + ip = mono_interp_frame_get_ip (frame); + } + g_assert (ji && !ji->is_trampoline); method = jinfo_get_method (ji); /* Compute the native offset of the breakpoint from the ip */ - native_offset = ip - (guint8*)ji->code_start; + native_offset = ip - (guint8*)ji->code_start; /* * Skip the instruction causing the breakpoint signal. @@ -4936,9 +5003,9 @@ process_signal_event (void (*func) (DebuggerTlsData*, gboolean)) } static void -process_breakpoint (void) +process_breakpoint_from_signal (void) { - process_signal_event (process_breakpoint_inner); + process_signal_event (process_breakpoint); } static void @@ -4980,19 +5047,30 @@ mono_debugger_agent_breakpoint_hit (void *sigctx) * problems, like the original signal is disabled, libgc can't handle altstack, etc. * So set up the signal context to return to the real breakpoint handler function. */ - resume_from_signal_handler (sigctx, process_breakpoint); + resume_from_signal_handler (sigctx, process_breakpoint_from_signal); } +typedef struct { + gboolean found; + MonoContext *ctx; +} UserBreakCbData; + static gboolean -user_break_cb (StackFrameInfo *frame, MonoContext *ctx, gpointer data) +user_break_cb (StackFrameInfo *frame, MonoContext *ctx, gpointer user_data) { + UserBreakCbData *data = user_data; + + if (frame->type == FRAME_TYPE_INTERP_TO_MANAGED) { + data->found = TRUE; + return TRUE; + } if (frame->managed) { - *(MonoContext*)data = *ctx; + data->found = TRUE; + *data->ctx = *ctx; return TRUE; - } else { - return FALSE; } + return FALSE; } /* @@ -5005,11 +5083,15 @@ mono_debugger_agent_user_break (void) MonoContext ctx; int suspend_policy; GSList *events; + UserBreakCbData data; + + memset (&data, 0, sizeof (UserBreakCbData)); + data.ctx = &ctx; /* Obtain a context */ MONO_CONTEXT_SET_IP (&ctx, NULL); - mono_walk_stack_with_ctx (user_break_cb, NULL, (MonoUnwindOptions)0, &ctx); - g_assert (MONO_CONTEXT_GET_IP (&ctx) != NULL); + mono_walk_stack_with_ctx (user_break_cb, NULL, (MonoUnwindOptions)0, &data); + g_assert (data.found); mono_loader_lock (); events = create_event_list (EVENT_KIND_USER_BREAK, NULL, NULL, NULL, &suspend_policy); @@ -5051,8 +5133,6 @@ process_single_step_inner (DebuggerTlsData *tls, gboolean from_signal) SeqPoint sp; MonoSeqPointInfo *info; - ip = (guint8 *)MONO_CONTEXT_GET_IP (ctx); - /* Skip the instruction causing the single step */ if (from_signal) mono_arch_skip_single_step (ctx); @@ -5072,14 +5152,15 @@ process_single_step_inner (DebuggerTlsData *tls, gboolean from_signal) if (mono_thread_internal_current () != ss_req->thread) return; - if (log_level > 0) { - ji = mini_jit_info_table_find (mono_domain_get (), (char*)ip, &domain); + ip = (guint8 *)MONO_CONTEXT_GET_IP (ctx); + + ji = get_top_method_ji (ip, &domain, (gpointer*)&ip); + g_assert (ji && !ji->is_trampoline); + if (log_level > 0) { DEBUG_PRINTF (1, "[%p] Single step event (depth=%s) at %s (%p)[0x%x], sp %p, last sp %p\n", (gpointer) (gsize) mono_native_thread_id_get (), ss_depth_to_string (ss_req->depth), mono_method_full_name (jinfo_get_method (ji), TRUE), MONO_CONTEXT_GET_IP (ctx), (int)((guint8*)MONO_CONTEXT_GET_IP (ctx) - (guint8*)ji->code_start), MONO_CONTEXT_GET_SP (ctx), ss_req->last_sp); } - ji = mini_jit_info_table_find (mono_domain_get (), (char*)ip, &domain); - g_assert (ji && !ji->is_trampoline); method = jinfo_get_method (ji); g_assert (method); @@ -5114,8 +5195,10 @@ process_single_step_inner (DebuggerTlsData *tls, gboolean from_signal) * The ip points to the instruction causing the single step event, which is before * the offset recorded in the seq point map, so find the next seq point after ip. */ - if (!mono_find_next_seq_point_for_native_offset (domain, method, (guint8*)ip - (guint8*)ji->code_start, &info, &sp)) + if (!mono_find_next_seq_point_for_native_offset (domain, method, (guint8*)ip - (guint8*)ji->code_start, &info, &sp)) { + g_assert_not_reached (); return; + } il_offset = sp.il_offset; @@ -5230,7 +5313,7 @@ debugger_agent_breakpoint_from_context (MonoContext *ctx) mono_thread_state_init_from_monoctx (&tls->restore_state, ctx); memcpy (&tls->handler_ctx, ctx, sizeof (MonoContext)); - process_breakpoint_inner (tls, FALSE); + process_breakpoint (tls, FALSE); memcpy (ctx, &tls->restore_state.ctx, sizeof (MonoContext)); memcpy (&tls->restore_state, &orig_restore_state, sizeof (MonoThreadUnwindState)); @@ -5250,8 +5333,10 @@ start_single_stepping (void) #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED int val = InterlockedIncrement (&ss_count); - if (val == 1) + if (val == 1) { mono_arch_start_single_stepping (); + mono_interp_start_single_stepping (); + } #else g_assert_not_reached (); #endif @@ -5263,8 +5348,10 @@ stop_single_stepping (void) #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED int val = InterlockedDecrement (&ss_count); - if (val == 0) + if (val == 0) { mono_arch_stop_single_stepping (); + mono_interp_stop_single_stepping (); + } #else g_assert_not_reached (); #endif @@ -6707,6 +6794,24 @@ set_var (MonoType *t, MonoDebugVarInfo *var, MonoContext *ctx, MonoDomain *domai } } +static void +set_interp_var (MonoType *t, gpointer addr, guint8 *val_buf) +{ + int size; + + if (t->byref) { + addr = *(gpointer*)addr; + g_assert (addr); + } + + if (MONO_TYPE_IS_REFERENCE (t)) + size = sizeof (gpointer); + else + size = mono_class_value_size (mono_class_from_mono_type (t), NULL); + + memcpy (addr, val_buf, size); +} + static void clear_event_request (int req_id, int etype) { @@ -9376,7 +9481,13 @@ thread_commands (int command, guint8 *p, guint8 *end, Buffer *buf) // FIXME: Check that the ip change is safe DEBUG_PRINTF (1, "[dbg] Setting IP to %s:0x%0x(0x%0x)\n", tls->frames [0]->actual_method->name, (int)sp.il_offset, (int)sp.native_offset); - MONO_CONTEXT_SET_IP (&tls->restore_state.ctx, (guint8*)tls->frames [0]->ji->code_start + sp.native_offset); + + if (tls->frames [0]->ji->is_interp) { + MonoJitTlsData *jit_data = ((MonoThreadInfo*)thread->thread_info)->jit_data; + mono_interp_set_resume_state (jit_data, NULL, tls->frames [0]->interp_frame, (guint8*)tls->frames [0]->ji->code_start + sp.native_offset); + } else { + MONO_CONTEXT_SET_IP (&tls->restore_state.ctx, (guint8*)tls->frames [0]->ji->code_start + sp.native_offset); + } break; } default: @@ -9442,7 +9553,7 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf) sig = mono_method_signature (frame->actual_method); - if (!jit->has_var_info || !mono_get_seq_points (frame->domain, frame->actual_method)) + if (!(jit->has_var_info || frame->ji->is_interp) || !mono_get_seq_points (frame->domain, frame->actual_method)) /* * The method is probably from an aot image compiled without soft-debug, variables might be dead, etc. */ @@ -9463,9 +9574,17 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf) DEBUG_PRINTF (4, "[dbg] send arg %d.\n", pos); - g_assert (pos >= 0 && pos < jit->num_params); + if (frame->ji->is_interp) { + guint8 *addr; + + addr = mono_interp_frame_get_arg (frame->interp_frame, pos); + + buffer_add_value_full (buf, sig->params [pos], addr, frame->domain, FALSE, NULL); + } else { + g_assert (pos >= 0 && pos < jit->num_params); - add_var (buf, jit, sig->params [pos], &jit->params [pos], &frame->ctx, frame->domain, FALSE); + add_var (buf, jit, sig->params [pos], &jit->params [pos], &frame->ctx, frame->domain, FALSE); + } } else { MonoDebugLocalsInfo *locals; @@ -9475,30 +9594,57 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf) pos = locals->locals [pos].index; mono_debug_free_locals (locals); } - g_assert (pos >= 0 && pos < jit->num_locals); DEBUG_PRINTF (4, "[dbg] send local %d.\n", pos); - add_var (buf, jit, header->locals [pos], &jit->locals [pos], &frame->ctx, frame->domain, FALSE); + if (frame->ji->is_interp) { + guint8 *addr; + + addr = mono_interp_frame_get_local (frame->interp_frame, pos); + + buffer_add_value_full (buf, header->locals [pos], addr, frame->domain, FALSE, NULL); + } else { + g_assert (pos >= 0 && pos < jit->num_locals); + + add_var (buf, jit, header->locals [pos], &jit->locals [pos], &frame->ctx, frame->domain, FALSE); + } } } mono_metadata_free_mh (header); break; } case CMD_STACK_FRAME_GET_THIS: { + if (frame->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) + return ERR_ABSENT_INFORMATION; if (frame->api_method->klass->valuetype) { if (!sig->hasthis) { MonoObject *p = NULL; buffer_add_value (buf, &mono_defaults.object_class->byval_arg, &p, frame->domain); } else { - add_var (buf, jit, &frame->actual_method->klass->this_arg, jit->this_var, &frame->ctx, frame->domain, TRUE); + if (frame->ji->is_interp) { + guint8 *addr; + + addr = mono_interp_frame_get_this (frame->interp_frame); + + buffer_add_value_full (buf, &frame->actual_method->klass->this_arg, addr, frame->domain, FALSE, NULL); + } else { + add_var (buf, jit, &frame->actual_method->klass->this_arg, jit->this_var, &frame->ctx, frame->domain, TRUE); + } } } else { if (!sig->hasthis) { MonoObject *p = NULL; buffer_add_value (buf, &frame->actual_method->klass->byval_arg, &p, frame->domain); } else { - add_var (buf, jit, &frame->api_method->klass->byval_arg, jit->this_var, &frame->ctx, frame->domain, TRUE); + if (frame->ji->is_interp) { + guint8 *addr; + + addr = mono_interp_frame_get_this (frame->interp_frame); + + buffer_add_value_full (buf, &frame->api_method->klass->byval_arg, addr, frame->domain, FALSE, NULL); + } else { + add_var (buf, jit, &frame->api_method->klass->byval_arg, jit->this_var, &frame->ctx, frame->domain, TRUE); + } } } break; @@ -9507,7 +9653,8 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf) MonoError error; guint8 *val_buf; MonoType *t; - MonoDebugVarInfo *var; + MonoDebugVarInfo *var = NULL; + gboolean is_arg = FALSE; len = decode_int (p, &p, end); header = mono_method_get_header_checked (frame->actual_method, &error); @@ -9523,6 +9670,7 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf) t = sig->params [pos]; var = &jit->params [pos]; + is_arg = TRUE; } else { MonoDebugLocalsInfo *locals; @@ -9546,7 +9694,17 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf) if (err != ERR_NONE) return err; - set_var (t, var, &frame->ctx, frame->domain, val_buf, frame->reg_locations, &tls->restore_state.ctx); + if (frame->ji->is_interp) { + guint8 *addr; + + if (is_arg) + addr = mono_interp_frame_get_arg (frame->interp_frame, pos); + else + addr = mono_interp_frame_get_local (frame->interp_frame, pos); + set_interp_var (t, addr, val_buf); + } else { + set_var (t, var, &frame->ctx, frame->domain, val_buf, frame->reg_locations, &tls->restore_state.ctx); + } } mono_metadata_free_mh (header); break; @@ -9564,15 +9722,23 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf) t = &frame->actual_method->klass->byval_arg; /* Checked by the sender */ g_assert (MONO_TYPE_ISSTRUCT (t)); - var = jit->this_var; - g_assert (var); val_buf = (guint8 *)g_alloca (mono_class_instance_size (mono_class_from_mono_type (t))); err = decode_value (t, frame->domain, val_buf, p, &p, end); if (err != ERR_NONE) return err; - set_var (&frame->actual_method->klass->this_arg, var, &frame->ctx, frame->domain, val_buf, frame->reg_locations, &tls->restore_state.ctx); + if (frame->ji->is_interp) { + guint8 *addr; + + addr = mono_interp_frame_get_this (frame->interp_frame); + set_interp_var (&frame->actual_method->klass->this_arg, addr, val_buf); + } else { + var = jit->this_var; + g_assert (var); + + set_var (&frame->actual_method->klass->this_arg, var, &frame->ctx, frame->domain, val_buf, frame->reg_locations, &tls->restore_state.ctx); + } break; } default: diff --git a/mono/mini/decompose.c b/mono/mini/decompose.c index 1c3060f1624..93668ac8524 100644 --- a/mono/mini/decompose.c +++ b/mono/mini/decompose.c @@ -1227,8 +1227,8 @@ mono_decompose_vtype_opts (MonoCompile *cfg) EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype); EMIT_NEW_VARLOADA ((cfg), (dest), dest_var, dest_var->inst_vtype); + mini_emit_memory_copy (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke, 0); - mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke); break; } case OP_VZERO: @@ -1273,7 +1273,7 @@ mono_decompose_vtype_opts (MonoCompile *cfg) dreg = alloc_preg (cfg); EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset); - mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke); + mini_emit_memory_copy (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke, 0); break; } case OP_LOADV_MEMBASE: { @@ -1290,7 +1290,7 @@ mono_decompose_vtype_opts (MonoCompile *cfg) dreg = alloc_preg (cfg); EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset); EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype); - mini_emit_stobj (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke); + mini_emit_memory_copy (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke, 0); break; } case OP_OUTARG_VT: { diff --git a/mono/mini/interp/interp-internals.h b/mono/mini/interp/interp-internals.h index cc4cd237c67..3b19a6d1bda 100644 --- a/mono/mini/interp/interp-internals.h +++ b/mono/mini/interp/interp-internals.h @@ -105,6 +105,7 @@ struct _MonoInvocation { stackval *stack_args; /* parent */ stackval *stack; stackval *sp; /* For GC stack marking */ + unsigned char *locals; /* exception info */ unsigned char invoke_trap; const unsigned short *ip; diff --git a/mono/mini/interp/interp-stubs.c b/mono/mini/interp/interp-stubs.c new file mode 100644 index 00000000000..176e45b6080 --- /dev/null +++ b/mono/mini/interp/interp-stubs.c @@ -0,0 +1,98 @@ +#include + +#ifndef ENABLE_INTERPRETER + +#include "interp.h" + +/* Dummy versions of interpreter functions to avoid ifdefs at call sites */ + +MonoJitInfo* +mono_interp_find_jit_info (MonoDomain *domain, MonoMethod *method) +{ + return NULL; +} + +void +mono_interp_set_breakpoint (MonoJitInfo *jinfo, gpointer ip) +{ + g_assert_not_reached (); +} + +void +mono_interp_clear_breakpoint (MonoJitInfo *jinfo, gpointer ip) +{ + g_assert_not_reached (); +} + +MonoJitInfo* +mono_interp_frame_get_jit_info (MonoInterpFrameHandle frame) +{ + g_assert_not_reached (); + return NULL; +} + +gpointer +mono_interp_frame_get_ip (MonoInterpFrameHandle frame) +{ + g_assert_not_reached (); + return NULL; +} + +gpointer +mono_interp_frame_get_arg (MonoInterpFrameHandle frame, int pos) +{ + g_assert_not_reached (); + return NULL; +} + +gpointer +mono_interp_frame_get_local (MonoInterpFrameHandle frame, int pos) +{ + g_assert_not_reached (); + return NULL; +} + +gpointer +mono_interp_frame_get_this (MonoInterpFrameHandle frame) +{ + g_assert_not_reached (); + return NULL; +} + +void +mono_interp_start_single_stepping (void) +{ +} + +void +mono_interp_stop_single_stepping (void) +{ +} + +void +mono_interp_set_resume_state (MonoJitTlsData *jit_tls, MonoException *ex, MonoInterpFrameHandle interp_frame, gpointer handler_ip) +{ + g_assert_not_reached (); +} + +void +mono_interp_run_finally (StackFrameInfo *frame, int clause_index, gpointer handler_ip) +{ + g_assert_not_reached (); +} + +void +mono_interp_frame_iter_init (MonoInterpStackIter *iter, gpointer interp_exit_data) +{ + g_assert_not_reached (); +} + +gboolean +mono_interp_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame) +{ + g_assert_not_reached (); + return FALSE; +} + +#endif + diff --git a/mono/mini/interp/interp.c b/mono/mini/interp/interp.c index 68d3b3998a4..0b530d8330a 100644 --- a/mono/mini/interp/interp.c +++ b/mono/mini/interp/interp.c @@ -66,6 +66,7 @@ #include #include +#include #ifdef TARGET_ARM #include @@ -104,6 +105,8 @@ init_frame (MonoInvocation *frame, MonoInvocation *parent_frame, RuntimeMethod * * Used for testing. */ GSList *jit_classes; +/* If TRUE, interpreted code will be interrupted at function entry/backward branches */ +static gboolean ss_enabled; void ves_exec_method (MonoInvocation *frame); @@ -204,14 +207,27 @@ static void debug_enter (MonoInvocation *frame, int *tracing) /* Set the current execution state to the resume state in context */ #define SET_RESUME_STATE(context) do { \ ip = (context)->handler_ip; \ + if (frame->ex) { \ sp->data.p = frame->ex; \ ++sp; \ + } \ frame->ex = NULL; \ (context)->has_resume_state = 0; \ (context)->handler_frame = NULL; \ goto main_loop; \ } while (0) +static void +set_context (ThreadContext *context) +{ + MonoJitTlsData *jit_tls; + + mono_native_tls_set_value (thread_context_id, context); + jit_tls = mono_tls_get_jit_tls (); + if (jit_tls) + jit_tls->interp_context = context; +} + static void ves_real_abort (int line, MonoMethod *mh, const unsigned short *ip, stackval *stack, stackval *sp) @@ -234,6 +250,19 @@ ves_real_abort (int line, MonoMethod *mh, THROW_EX (mono_get_exception_execution_engine (NULL), ip); \ } while (0); +static RuntimeMethod* +lookup_runtime_method (MonoDomain *domain, MonoMethod *method) +{ + RuntimeMethod *rtm; + MonoJitDomainInfo *info; + + info = domain_jit_info (domain); + mono_domain_jit_code_hash_lock (domain); + rtm = mono_internal_hash_table_lookup (&info->interp_code_hash, method); + mono_domain_jit_code_hash_unlock (domain); + return rtm; +} + RuntimeMethod* mono_interp_get_runtime_method (MonoDomain *domain, MonoMethod *method, MonoError *error) { @@ -278,6 +307,30 @@ mono_interp_create_trampoline (MonoDomain *domain, MonoMethod *method, MonoError return mono_interp_get_runtime_method (domain, method, error); } +/* + * interp_push_lmf: + * + * Push an LMF frame on the LMF stack + * to mark the transition to native code. + * This is needed for the native code to + * be able to do stack walks. + */ +static void +interp_push_lmf (MonoLMFExt *ext, MonoInvocation *frame) +{ + memset (ext, 0, sizeof (MonoLMFExt)); + ext->interp_exit = TRUE; + ext->interp_exit_data = frame; + + mono_push_lmf (ext); +} + +static void +interp_pop_lmf (MonoLMFExt *ext) +{ + mono_pop_lmf (&ext->lmf); +} + static inline RuntimeMethod* get_virtual_method (MonoDomain *domain, RuntimeMethod *runtime_method, MonoObject *obj) { @@ -943,19 +996,11 @@ ves_pinvoke_method (MonoInvocation *frame, MonoMethodSignature *sig, MonoFuncV a context->current_frame = frame; context->managed_code = 0; - /* - * Push an LMF frame on the LMF stack - * to mark the transition to native code. - */ - memset (&ext, 0, sizeof (ext)); - ext.interp_exit = TRUE; - ext.interp_exit_data = frame; - - mono_push_lmf (&ext); + interp_push_lmf (&ext, frame); mono_interp_enter_icall_trampoline (addr, margs); - mono_pop_lmf (&ext.lmf); + interp_pop_lmf (&ext); context->managed_code = 1; /* domain can only be changed by native code */ @@ -1307,7 +1352,7 @@ mono_interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoOb int i, type, isobject = 0; void *ret = NULL; stackval result; - stackval *args = alloca (sizeof (stackval) * (sig->param_count + !!sig->hasthis)); + stackval *args; ThreadContext context_struct; MonoInvocation *old_frame = NULL; jmp_buf env; @@ -1323,8 +1368,8 @@ mono_interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoOb context->domain = mono_domain_get (); context->current_frame = old_frame; context->managed_code = 0; - } else - mono_native_tls_set_value (thread_context_id, NULL); + } else + set_context (NULL); if (exc != NULL) *exc = (MonoObject *)frame.ex; return retval; @@ -1336,7 +1381,7 @@ mono_interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoOb context_struct.base_frame = &frame; context_struct.env_frame = &frame; context_struct.current_env = &env; - mono_native_tls_set_value (thread_context_id, context); + set_context (context); } else old_frame = context->current_frame; @@ -1384,6 +1429,7 @@ mono_interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoOb break; } + args = alloca (sizeof (stackval) * (sig->param_count + !!sig->hasthis)); if (sig->hasthis) args [0].data.p = obj; @@ -1453,13 +1499,14 @@ handle_enum: if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) method = mono_marshal_get_native_wrapper (method, FALSE, FALSE); INIT_FRAME (&frame,context->current_frame,args,&result,mono_get_root_domain (),method,error); + if (exc) frame.invoke_trap = 1; context->managed_code = 1; ves_exec_method_with_context (&frame, context, NULL, NULL, -1); context->managed_code = 0; if (context == &context_struct) - mono_native_tls_set_value (thread_context_id, NULL); + set_context (NULL); else context->current_frame = old_frame; if (frame.ex != NULL) { @@ -1519,10 +1566,10 @@ interp_entry (InterpEntryData *data) memset (context, 0, sizeof (ThreadContext)); context_struct.base_frame = &frame; context_struct.env_frame = &frame; - mono_native_tls_set_value (thread_context_id, context); - } - else + set_context (context); + } else { old_frame = context->current_frame; + } context->domain = mono_domain_get (); args = alloca (sizeof (stackval) * (sig->param_count + (sig->hasthis ? 1 : 0))); @@ -1615,7 +1662,7 @@ interp_entry (InterpEntryData *data) ves_exec_method_with_context (&frame, context, NULL, NULL, -1); context->managed_code = 0; if (context == &context_struct) - mono_native_tls_set_value (thread_context_id, NULL); + set_context (NULL); else context->current_frame = old_frame; @@ -2088,8 +2135,17 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context, uns g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn); g_free (mn); #endif + + MonoLMFExt ext; + + /* 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->runtime_method, context); context->managed_code = 1; + + interp_pop_lmf (&ext); + if (frame->ex) { rtm = NULL; ip = NULL; @@ -2112,6 +2168,7 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context, uns vtalloc = vt_sp; #endif locals = (unsigned char *) vt_sp + rtm->vt_stack_size; + frame->locals = locals; child_frame.parent = frame; if (filter_exception) { @@ -2136,10 +2193,18 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context, uns MINT_IN_CASE(MINT_NOP) ++ip; MINT_IN_BREAK; - MINT_IN_CASE(MINT_BREAK) + MINT_IN_CASE(MINT_BREAK) { ++ip; - G_BREAKPOINT (); /* this is not portable... */ + + MonoLMFExt ext; + + interp_push_lmf (&ext, frame); + + mono_debugger_agent_user_break (); + + interp_pop_lmf (&ext); MINT_IN_BREAK; + } MINT_IN_CASE(MINT_LDNULL) sp->data.p = NULL; ++ip; @@ -2257,6 +2322,7 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context, uns vtalloc = vt_sp; #endif locals = vt_sp + rtm->vt_stack_size; + frame->locals = locals; ip = rtm->new_body_start; /* bypass storing input args from callers frame */ MINT_IN_BREAK; } @@ -2567,15 +2633,7 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context, uns } } - /* - * Push an LMF frame on the LMF stack - * to mark the transition to compiled code. - */ - memset (&ext, 0, sizeof (ext)); - ext.interp_exit = TRUE; - ext.interp_exit_data = frame; - - mono_push_lmf (&ext); + interp_push_lmf (&ext, frame); switch (pindex) { case 0: { @@ -2631,7 +2689,7 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context, uns break; } - mono_pop_lmf (&ext.lmf); + interp_pop_lmf (&ext); if (context->has_resume_state) { /* @@ -2819,7 +2877,7 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context, uns goto exit_frame; MINT_IN_CASE(MINT_RET_VOID) if (sp > frame->stack) - g_warning ("ret.void: more values on stack: %d", sp-frame->stack); + g_warning ("ret.void: more values on stack: %d %s", sp-frame->stack, mono_method_full_name (frame->runtime_method->method, TRUE)); goto exit_frame; MINT_IN_CASE(MINT_RET_VT) i32 = READ32(ip + 1); @@ -3110,7 +3168,7 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context, uns gint offset; ip += 2 * (guint32)sp->data.i; offset = READ32 (ip); - ip = st + offset; + ip = ip + offset; } else { ip = st; } @@ -3486,10 +3544,13 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context, uns MINT_IN_BREAK; MINT_IN_CASE(MINT_CPOBJ) { c = rtm->data_items[* (guint16 *)(ip + 1)]; - g_assert (c->byval_arg.type == MONO_TYPE_VALUETYPE); + g_assert (c->valuetype); /* if this assertion fails, we need to add a write barrier */ g_assert (!MONO_TYPE_IS_REFERENCE (&c->byval_arg)); - stackval_from_data (&c->byval_arg, &sp [-2], sp [-1].data.p, FALSE); + if (c->byval_arg.type == MONO_TYPE_VALUETYPE) + stackval_from_data (&c->byval_arg, &sp [-2], sp [-1].data.p, FALSE); + else + stackval_from_data (&c->byval_arg, sp [-2].data.p, sp [-1].data.p, FALSE); ip += 2; sp -= 2; MINT_IN_BREAK; @@ -3661,6 +3722,7 @@ array_constructed: frame->ex_handler = NULL; if (!sp->data.p) sp->data.p = mono_get_exception_null_reference (); + THROW_EX ((MonoException *)sp->data.p, ip); MINT_IN_BREAK; MINT_IN_CASE(MINT_LDFLDA_UNSAFE) @@ -4513,6 +4575,72 @@ array_constructed: ++ip; mono_jit_set_domain (context->original_domain); MINT_IN_BREAK; + MINT_IN_CASE(MINT_SDB_INTR_LOC) + if (G_UNLIKELY (ss_enabled)) { + MonoLMFExt ext; + static void (*ss_tramp) (void); + + if (!ss_tramp) { + void *tramp = mini_get_single_step_trampoline (); + mono_memory_barrier (); + ss_tramp = tramp; + } + + /* + * Make this point to the MINT_SDB_SEQ_POINT instruction which follows this since + * the address of that instruction is stored as the seq point address. + */ + frame->ip = ip + 1; + + interp_push_lmf (&ext, frame); + /* + * Use the same trampoline as the JIT. This ensures that + * the debugger has the context for the last interpreter + * native frame. + */ + ss_tramp (); + interp_pop_lmf (&ext); + + if (context->has_resume_state) { + if (frame == context->handler_frame) + SET_RESUME_STATE (context); + else + goto exit_frame; + } + } + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_SDB_SEQ_POINT) + /* Just a placeholder for a breakpoint */ + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_SDB_BREAKPOINT) { + MonoLMFExt ext; + + static void (*bp_tramp) (void); + if (!bp_tramp) { + void *tramp = mini_get_breakpoint_trampoline (); + mono_memory_barrier (); + bp_tramp = tramp; + } + + frame->ip = ip; + + interp_push_lmf (&ext, frame); + /* Use the same trampoline as the JIT */ + bp_tramp (); + interp_pop_lmf (&ext); + + if (context->has_resume_state) { + if (frame == context->handler_frame) + SET_RESUME_STATE (context); + else + goto exit_frame; + } + + ++ip; + MINT_IN_BREAK; + } #define RELOP(datamem, op) \ --sp; \ @@ -5058,7 +5186,7 @@ ves_exec_method (MonoInvocation *frame) context_struct.current_env = &env; context_struct.search_for_handler = 0; context_struct.managed_code = 0; - mono_native_tls_set_value (thread_context_id, context); + set_context (context); } frame->ip = NULL; frame->parent = context->current_frame; @@ -5076,7 +5204,7 @@ ves_exec_method (MonoInvocation *frame) mono_unhandled_exception ((MonoObject*)frame->ex); } if (context->base_frame == frame) - mono_native_tls_set_value (thread_context_id, NULL); + set_context (NULL); else context->current_frame = frame->parent; } @@ -5099,7 +5227,7 @@ void mono_interp_init () { mono_native_tls_alloc (&thread_context_id, NULL); - mono_native_tls_set_value (thread_context_id, NULL); + set_context (NULL); mono_interp_transform_init (); } @@ -5275,12 +5403,16 @@ mono_interp_regression_list (int verbose, int count, char *images []) * Set the state the interpeter will continue to execute from after execution returns to the interpreter. */ void -mono_interp_set_resume_state (MonoException *ex, StackFrameInfo *frame, gpointer handler_ip) +mono_interp_set_resume_state (MonoJitTlsData *jit_tls, MonoException *ex, MonoInterpFrameHandle interp_frame, gpointer handler_ip) { - ThreadContext *context = mono_native_tls_get_value (thread_context_id); + ThreadContext *context; + + g_assert (jit_tls); + context = jit_tls->interp_context; + g_assert (context); context->has_resume_state = TRUE; - context->handler_frame = frame->interp_frame; + context->handler_frame = interp_frame; /* This is on the stack, so it doesn't need a wbarrier */ context->handler_frame->ex = ex; context->handler_ip = handler_ip; @@ -5326,20 +5458,115 @@ mono_interp_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame) memset (frame, 0, sizeof (StackFrameInfo)); /* pinvoke frames doesn't have runtime_method set */ - while (iframe && !iframe->runtime_method) + while (iframe && !(iframe->runtime_method && iframe->runtime_method->code)) iframe = iframe->parent; if (!iframe) return FALSE; frame->type = FRAME_TYPE_INTERP; + // FIXME: + frame->domain = mono_domain_get (); frame->interp_frame = iframe; frame->method = iframe->runtime_method->method; frame->actual_method = frame->method; /* This is the offset in the interpreter IR */ - frame->native_offset = iframe->ip - iframe->runtime_method->code; + frame->native_offset = (guint8*)iframe->ip - (guint8*)iframe->runtime_method->code; frame->ji = iframe->runtime_method->jinfo; stack_iter->current = iframe->parent; return TRUE; } + +MonoJitInfo* +mono_interp_find_jit_info (MonoDomain *domain, MonoMethod *method) +{ + RuntimeMethod* rtm; + + rtm = lookup_runtime_method (domain, method); + if (rtm) + return rtm->jinfo; + else + return NULL; +} + +void +mono_interp_set_breakpoint (MonoJitInfo *jinfo, gpointer ip) +{ + guint16 *code = (guint16*)ip; + g_assert (*code == MINT_SDB_SEQ_POINT); + *code = MINT_SDB_BREAKPOINT; +} + +void +mono_interp_clear_breakpoint (MonoJitInfo *jinfo, gpointer ip) +{ + guint16 *code = (guint16*)ip; + g_assert (*code == MINT_SDB_BREAKPOINT); + *code = MINT_SDB_SEQ_POINT; +} + +MonoJitInfo* +mono_interp_frame_get_jit_info (MonoInterpFrameHandle frame) +{ + MonoInvocation *iframe = (MonoInvocation*)frame; + + g_assert (iframe->runtime_method); + return iframe->runtime_method->jinfo; +} + +gpointer +mono_interp_frame_get_ip (MonoInterpFrameHandle frame) +{ + MonoInvocation *iframe = (MonoInvocation*)frame; + + g_assert (iframe->runtime_method); + return (gpointer)iframe->ip; +} + +gpointer +mono_interp_frame_get_arg (MonoInterpFrameHandle frame, int pos) +{ + MonoInvocation *iframe = (MonoInvocation*)frame; + + g_assert (iframe->runtime_method); + + int arg_offset = iframe->runtime_method->arg_offsets [pos + (iframe->runtime_method->hasthis ? 1 : 0)]; + + return iframe->args + arg_offset; +} + +gpointer +mono_interp_frame_get_local (MonoInterpFrameHandle frame, int pos) +{ + MonoInvocation *iframe = (MonoInvocation*)frame; + + g_assert (iframe->runtime_method); + + return iframe->locals + iframe->runtime_method->local_offsets [pos]; +} + +gpointer +mono_interp_frame_get_this (MonoInterpFrameHandle frame) +{ + MonoInvocation *iframe = (MonoInvocation*)frame; + + g_assert (iframe->runtime_method); + g_assert (iframe->runtime_method->hasthis); + + int arg_offset = iframe->runtime_method->arg_offsets [0]; + + return iframe->args + arg_offset; +} + +void +mono_interp_start_single_stepping (void) +{ + ss_enabled = TRUE; +} + +void +mono_interp_stop_single_stepping (void) +{ + ss_enabled = FALSE; +} diff --git a/mono/mini/interp/interp.h b/mono/mini/interp/interp.h index cf922507500..6abf93a6f0a 100644 --- a/mono/mini/interp/interp.h +++ b/mono/mini/interp/interp.h @@ -28,6 +28,8 @@ struct _MonoInterpStackIter { gpointer dummy [8]; }; +typedef gpointer MonoInterpFrameHandle; + int mono_interp_regression_list (int verbose, int count, char *images []); @@ -53,7 +55,7 @@ void interp_walk_stack_with_ctx (MonoInternalStackWalk func, MonoContext *ctx, MonoUnwindOptions options, void *user_data); void -mono_interp_set_resume_state (MonoException *ex, StackFrameInfo *frame, gpointer handler_ip); +mono_interp_set_resume_state (MonoJitTlsData *jit_tls, MonoException *ex, MonoInterpFrameHandle interp_frame, gpointer handler_ip); void mono_interp_run_finally (StackFrameInfo *frame, int clause_index, gpointer handler_ip); @@ -64,4 +66,34 @@ mono_interp_frame_iter_init (MonoInterpStackIter *iter, gpointer interp_exit_dat gboolean mono_interp_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame); +MonoJitInfo* +mono_interp_find_jit_info (MonoDomain *domain, MonoMethod *method); + +void +mono_interp_set_breakpoint (MonoJitInfo *jinfo, gpointer ip); + +void +mono_interp_clear_breakpoint (MonoJitInfo *jinfo, gpointer ip); + +MonoJitInfo* +mono_interp_frame_get_jit_info (MonoInterpFrameHandle frame); + +gpointer +mono_interp_frame_get_ip (MonoInterpFrameHandle frame); + +gpointer +mono_interp_frame_get_arg (MonoInterpFrameHandle frame, int pos); + +gpointer +mono_interp_frame_get_local (MonoInterpFrameHandle frame, int pos); + +gpointer +mono_interp_frame_get_this (MonoInterpFrameHandle frame); + +void +mono_interp_start_single_stepping (void); + +void +mono_interp_stop_single_stepping (void); + #endif /* __MONO_MINI_INTERPRETER_H__ */ diff --git a/mono/mini/interp/mintops.c b/mono/mini/interp/mintops.c index e1c58ecf7a9..b0fa6358c89 100644 --- a/mono/mini/interp/mintops.c +++ b/mono/mini/interp/mintops.c @@ -106,7 +106,7 @@ mono_interp_dis_mintop(const guint16 *base, const guint16 *ip) if (i > 0) g_print (", "); offset = (gint32)READ32 (p); - g_print ("IL_%04x", ip - base + 3 + 2 * sval + offset); + g_print ("IL_%04x", p + offset); p += 2; } g_print (")"); diff --git a/mono/mini/interp/mintops.def b/mono/mini/interp/mintops.def index 190c6647d08..647e5838607 100644 --- a/mono/mini/interp/mintops.def +++ b/mono/mini/interp/mintops.def @@ -521,3 +521,6 @@ OPDEF(MINT_MONO_JIT_DETACH, "mono_jit_detach", 1, MintOpNoArgs) // FIXME: MintOp OPDEF(MINT_JIT_CALL, "mono_jit_call", 2, MintOpNoArgs) +OPDEF(MINT_SDB_INTR_LOC, "sdb_intr_loc", 1, MintOpNoArgs) +OPDEF(MINT_SDB_SEQ_POINT, "sdb_seq_point", 1, MintOpNoArgs) +OPDEF(MINT_SDB_BREAKPOINT, "sdb_breakpoint", 1, MintOpNoArgs) diff --git a/mono/mini/interp/transform.c b/mono/mini/interp/transform.c index 9354aa8737c..a309a4a9fab 100644 --- a/mono/mini/interp/transform.c +++ b/mono/mini/interp/transform.c @@ -15,6 +15,7 @@ #include #include #include +#include #include @@ -34,6 +35,31 @@ typedef struct unsigned char flags; } StackInfo; +typedef struct { + guint8 *ip; + GSList *preds; + GSList *seq_points; + SeqPoint *last_seq_point; + + // This will hold a list of last sequence points of incoming basic blocks + SeqPoint **pred_seq_points; + guint num_pred_seq_points; +} InterpBasicBlock; + +typedef enum { + RELOC_SHORT_BRANCH, + RELOC_LONG_BRANCH, + RELOC_SWITCH +} RelocType; + +typedef struct { + RelocType type; + /* In the interpreter IR */ + int offset; + /* In the IL code */ + int target; +} Reloc; + typedef struct { MonoMethod *method; @@ -45,7 +71,6 @@ typedef struct const unsigned char *in_start; int code_size; int *in_offsets; - int *forward_refs; StackInfo **stack_state; int *stack_height; int *vt_stack_size; @@ -65,6 +90,14 @@ typedef struct void **data_items; GHashTable *data_hash; int *clause_indexes; + gboolean gen_sdb_seq_points; + GPtrArray *seq_points; + InterpBasicBlock **offset_to_bb; + InterpBasicBlock *entry_bb; + MonoMemPool *mempool; + GList *basic_blocks; + GPtrArray *relocs; + gboolean verbose_level; } TransformData; #define MINT_TYPE_I1 0 @@ -150,7 +183,7 @@ grow_code (TransformData *td) } while (0) static void -handle_branch(TransformData *td, int short_op, int long_op, int offset) +handle_branch (TransformData *td, int short_op, int long_op, int offset) { int shorten_branch = 0; int target = td->ip + offset - td->il_code; @@ -168,12 +201,18 @@ handle_branch(TransformData *td, int short_op, int long_op, int offset) shorten_branch = 1; } } else { - int prev = td->forward_refs [target]; - td->forward_refs [td->ip - td->il_code] = prev; - td->forward_refs [target] = td->ip - td->il_code; - offset = 0; + offset = 0xffff; if (td->header->code_size <= 25000) /* FIX to be precise somehow? */ shorten_branch = 1; + + Reloc *reloc = mono_mempool_alloc0 (td->mempool, sizeof (Reloc)); + if (shorten_branch) + reloc->type = RELOC_SHORT_BRANCH; + else + reloc->type = RELOC_LONG_BRANCH; + reloc->offset = td->new_ip - td->new_code; + reloc->target = target; + g_ptr_array_add (td->relocs, reloc); } if (shorten_branch) { ADD_CODE(td, short_op); @@ -554,11 +593,13 @@ load_local(TransformData *td, int n) WRITE32(td, &size); } else { g_assert (mt < MINT_TYPE_VT); - if (mt == MINT_TYPE_I4 && !td->is_bb_start [td->in_start - td->il_code] && td->last_new_ip != NULL && + if (!td->gen_sdb_seq_points && + mt == MINT_TYPE_I4 && !td->is_bb_start [td->in_start - td->il_code] && td->last_new_ip != NULL && td->last_new_ip [0] == MINT_STLOC_I4 && td->last_new_ip [1] == offset) { td->last_new_ip [0] = MINT_STLOC_NP_I4; - } else if (mt == MINT_TYPE_O && !td->is_bb_start [td->in_start - td->il_code] && td->last_new_ip != NULL && - td->last_new_ip [0] == MINT_STLOC_O && td->last_new_ip [1] == offset) { + } else if (!td->gen_sdb_seq_points && + mt == MINT_TYPE_O && !td->is_bb_start [td->in_start - td->il_code] && td->last_new_ip != NULL && + td->last_new_ip [0] == MINT_STLOC_O && td->last_new_ip [1] == offset) { td->last_new_ip [0] = MINT_STLOC_NP_O; } else { ADD_CODE(td, MINT_LDLOC_I1 + (mt - MINT_TYPE_I1)); @@ -696,22 +737,8 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target else target_method = (MonoMethod *)mono_method_get_wrapper_data (method, token); csignature = mono_method_signature (target_method); - if (target_method->klass == mono_defaults.string_class) { - if (target_method->name [0] == 'g') { - if (strcmp (target_method->name, "get_Chars") == 0) - op = MINT_GETCHR; - else if (strcmp (target_method->name, "get_Length") == 0) - op = MINT_STRLEN; - } - } else if (mono_class_is_subclass_of (target_method->klass, mono_defaults.array_class, FALSE)) { - if (!strcmp (target_method->name, "get_Rank")) { - op = MINT_ARRAY_RANK; - } else if (!strcmp (target_method->name, "get_Length")) { - op = MINT_LDLEN; - } else if (!strcmp (target_method->name, "Address")) { - op = readonly ? MINT_LDELEMA : MINT_LDELEMA_TC; - } - } else if (target_method && generic_context) { + + if (generic_context) { csignature = mono_inflate_generic_signature (csignature, generic_context, &error); mono_error_cleanup (&error); /* FIXME: don't swallow the error */ target_method = mono_class_inflate_generic_method_checked (target_method, generic_context, &error); @@ -722,6 +749,33 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target csignature = mono_method_signature (target_method); } + /* Intrinsics */ + if (target_method) { + if (target_method->klass == mono_defaults.string_class) { + if (target_method->name [0] == 'g') { + if (strcmp (target_method->name, "get_Chars") == 0) + op = MINT_GETCHR; + else if (strcmp (target_method->name, "get_Length") == 0) + op = MINT_STRLEN; + } + } else if (mono_class_is_subclass_of (target_method->klass, mono_defaults.array_class, FALSE)) { + if (!strcmp (target_method->name, "get_Rank")) { + op = MINT_ARRAY_RANK; + } else if (!strcmp (target_method->name, "get_Length")) { + op = MINT_LDLEN; + } else if (!strcmp (target_method->name, "Address")) { + op = readonly ? MINT_LDELEMA : MINT_LDELEMA_TC; + } + } else if (target_method->klass->image == mono_defaults.corlib && + (strcmp (target_method->klass->name_space, "System.Diagnostics") == 0) && + (strcmp (target_method->klass->name, "Debugger") == 0)) { + if (!strcmp (target_method->name, "Break") && csignature->param_count == 0) { + if (mini_should_insert_breakpoint (method)) + op = MINT_BREAK; + } + } + } + if (constrained_class) { if (constrained_class->enumtype && !strcmp (target_method->name, "GetHashCode")) { /* Use the corresponding method from the base type to avoid boxing */ @@ -793,7 +847,7 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target mono_class_init (target_method->klass); CHECK_STACK (td, csignature->param_count + csignature->hasthis); - if (!calli && (!virtual || (target_method->flags & METHOD_ATTRIBUTE_VIRTUAL) == 0) && + if (!calli && op == -1 && (!virtual || (target_method->flags & METHOD_ATTRIBUTE_VIRTUAL) == 0) && (target_method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) == 0 && (target_method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) == 0 && !(target_method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING)) { @@ -802,7 +856,7 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target if (/*mono_metadata_signature_equal (method->signature, target_method->signature) */ method == target_method && *(td->ip + 5) == CEE_RET) { int offset; - if (mono_interp_traceopt) + if (td->verbose_level) g_print ("Optimize tail call of %s.%s\n", target_method->klass->name, target_method->name); for (i = csignature->param_count - 1 + !!csignature->hasthis; i >= 0; --i) @@ -818,7 +872,7 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target } else { /* mheader might not exist if this is a delegate invoc, etc */ if (mheader && *mheader->code == CEE_RET && called_inited) { - if (mono_interp_traceopt) + if (td->verbose_level) g_print ("Inline (empty) call of %s.%s\n", target_method->klass->name, target_method->name); for (i = 0; i < csignature->param_count; i++) { ADD_CODE (td, MINT_POP); /*FIX: vt */ @@ -926,6 +980,109 @@ interp_field_from_token (MonoMethod *method, guint32 token, MonoClass **klass, M return field; } +static InterpBasicBlock* +get_bb (TransformData *td, InterpBasicBlock *cbb, unsigned char *ip) +{ + int offset = ip - td->il_code; + InterpBasicBlock *bb = td->offset_to_bb [offset]; + + if (!bb) { + bb = mono_mempool_alloc0 (td->mempool, sizeof (InterpBasicBlock)); + bb->ip = ip; + td->offset_to_bb [offset] = bb; + + td->basic_blocks = g_list_append_mempool (td->mempool, td->basic_blocks, bb); + } + + if (cbb) + bb->preds = g_slist_prepend_mempool (td->mempool, bb->preds, cbb); + return bb; +} + +/* + * get_basic_blocks: + * + * Compute the set of IL level basic blocks. + */ +static void +get_basic_blocks (TransformData *td) +{ + guint8 *start = (guint8*)td->il_code; + guint8 *end = (guint8*)td->il_code + td->code_size; + guint8 *ip = start; + unsigned char *target; + int i; + guint cli_addr; + const MonoOpcode *opcode; + InterpBasicBlock *cbb; + + td->offset_to_bb = mono_mempool_alloc0 (td->mempool, sizeof (InterpBasicBlock*) * (end - start + 1)); + td->entry_bb = cbb = get_bb (td, NULL, start); + + while (ip < end) { + cli_addr = ip - start; + td->offset_to_bb [cli_addr] = cbb; + i = mono_opcode_value ((const guint8 **)&ip, end); + opcode = &mono_opcodes [i]; + switch (opcode->argument) { + case MonoInlineNone: + ip++; + break; + case MonoInlineString: + case MonoInlineType: + case MonoInlineField: + case MonoInlineMethod: + case MonoInlineTok: + case MonoInlineSig: + case MonoShortInlineR: + case MonoInlineI: + ip += 5; + break; + case MonoInlineVar: + ip += 3; + break; + case MonoShortInlineVar: + case MonoShortInlineI: + ip += 2; + break; + case MonoShortInlineBrTarget: + target = start + cli_addr + 2 + (signed char)ip [1]; + get_bb (td, cbb, target); + ip += 2; + cbb = get_bb (td, cbb, ip); + break; + case MonoInlineBrTarget: + target = start + cli_addr + 5 + (gint32)read32 (ip + 1); + get_bb (td, cbb, target); + ip += 5; + cbb = get_bb (td, cbb, ip); + break; + case MonoInlineSwitch: { + guint32 n = read32 (ip + 1); + guint32 j; + ip += 5; + cli_addr += 5 + 4 * n; + target = start + cli_addr; + get_bb (td, cbb, target); + + for (j = 0; j < n; ++j) { + target = start + cli_addr + (gint32)read32 (ip); + get_bb (td, cbb, target); + ip += 4; + } + cbb = get_bb (td, cbb, ip); + break; + } + case MonoInlineR: + case MonoInlineI8: + ip += 9; + break; + default: + g_assert_not_reached (); + } + } +} + static void interp_save_debug_info (RuntimeMethod *rtm, MonoMethodHeader *header, TransformData *td, GArray *line_numbers) { @@ -940,14 +1097,26 @@ interp_save_debug_info (RuntimeMethod *rtm, MonoMethodHeader *header, TransformD */ dinfo = g_new0 (MonoDebugMethodJitInfo, 1); + dinfo->num_params = rtm->param_count; + dinfo->params = g_new0 (MonoDebugVarInfo, dinfo->num_params); dinfo->num_locals = header->num_locals; dinfo->locals = g_new0 (MonoDebugVarInfo, header->num_locals); dinfo->code_start = (guint8*)rtm->code; dinfo->code_size = td->new_ip - td->new_code; dinfo->epilogue_begin = 0; - dinfo->has_var_info = FALSE; + dinfo->has_var_info = TRUE; dinfo->num_line_numbers = line_numbers->len; dinfo->line_numbers = g_new0 (MonoDebugLineNumberEntry, dinfo->num_line_numbers); + + for (i = 0; i < dinfo->num_params; i++) { + MonoDebugVarInfo *var = &dinfo->params [i]; + var->type = rtm->param_types [i]; + } + for (i = 0; i < dinfo->num_locals; i++) { + MonoDebugVarInfo *var = &dinfo->locals [i]; + var->type = header->locals [i]; + } + for (i = 0; i < dinfo->num_line_numbers; i++) dinfo->line_numbers [i] = g_array_index (line_numbers, MonoDebugLineNumberEntry, i); mono_debug_add_method (rtm->method, dinfo, mono_domain_get ()); @@ -955,6 +1124,201 @@ interp_save_debug_info (RuntimeMethod *rtm, MonoMethodHeader *header, TransformD mono_debug_free_method_jit_info (dinfo); } +/* Same as the code in seq-points.c */ +static void +insert_pred_seq_point (SeqPoint *last_sp, SeqPoint *sp, GSList **next) +{ + GSList *l; + int src_index = last_sp->next_offset; + int dst_index = sp->next_offset; + + /* bb->in_bb might contain duplicates */ + for (l = next [src_index]; l; l = l->next) + if (GPOINTER_TO_UINT (l->data) == dst_index) + break; + if (!l) + next [src_index] = g_slist_append (next [src_index], GUINT_TO_POINTER (dst_index)); +} + +static void +recursively_make_pred_seq_points (TransformData *td, InterpBasicBlock *bb) +{ + const gpointer MONO_SEQ_SEEN_LOOP = GINT_TO_POINTER(-1); + GSList *l; + + GArray *predecessors = g_array_new (FALSE, TRUE, sizeof (gpointer)); + GHashTable *seen = g_hash_table_new_full (g_direct_hash, NULL, NULL, NULL); + + // Insert/remove sentinel into the memoize table to detect loops containing bb + bb->pred_seq_points = MONO_SEQ_SEEN_LOOP; + + for (l = bb->preds; l; l = l->next) { + InterpBasicBlock *in_bb = l->data; + + // This bb has the last seq point, append it and continue + if (in_bb->last_seq_point != NULL) { + predecessors = g_array_append_val (predecessors, in_bb->last_seq_point); + continue; + } + + // We've looped or handled this before, exit early. + // No last sequence points to find. + if (in_bb->pred_seq_points == MONO_SEQ_SEEN_LOOP) + continue; + + // Take sequence points from incoming basic blocks + + if (in_bb == td->entry_bb) + continue; + + if (in_bb->pred_seq_points == NULL) + recursively_make_pred_seq_points (td, in_bb); + + // Union sequence points with incoming bb's + for (int i=0; i < in_bb->num_pred_seq_points; i++) { + if (!g_hash_table_lookup (seen, in_bb->pred_seq_points [i])) { + g_array_append_val (predecessors, in_bb->pred_seq_points [i]); + g_hash_table_insert (seen, in_bb->pred_seq_points [i], (gpointer)&MONO_SEQ_SEEN_LOOP); + } + } + // predecessors = g_array_append_vals (predecessors, in_bb->pred_seq_points, in_bb->num_pred_seq_points); + } + + g_hash_table_destroy (seen); + + if (predecessors->len != 0) { + bb->pred_seq_points = mono_mempool_alloc0 (td->mempool, sizeof (SeqPoint *) * predecessors->len); + bb->num_pred_seq_points = predecessors->len; + + for (int newer = 0; newer < bb->num_pred_seq_points; newer++) { + bb->pred_seq_points [newer] = g_array_index (predecessors, gpointer, newer); + } + } + + g_array_free (predecessors, TRUE); +} + +static void +collect_pred_seq_points (TransformData *td, InterpBasicBlock *bb, SeqPoint *seqp, GSList **next) +{ + // Doesn't have a last sequence point, must find from incoming basic blocks + if (bb->pred_seq_points == NULL && bb != td->entry_bb) + recursively_make_pred_seq_points (td, bb); + + for (int i = 0; i < bb->num_pred_seq_points; i++) + insert_pred_seq_point (bb->pred_seq_points [i], seqp, next); + + return; +} + +static void +save_seq_points (TransformData *td) +{ + RuntimeMethod *rtm = td->rtm; + GByteArray *array; + int i, seq_info_size; + MonoSeqPointInfo *info; + MonoDomain *domain = mono_domain_get (); + GSList **next = NULL; + GList *bblist; + + if (!td->gen_sdb_seq_points) + return; + + /* + * For each sequence point, compute the list of sequence points immediately + * following it, this is needed to implement 'step over' in the debugger agent. + * Similar to the code in mono_save_seq_point_info (). + */ + for (i = 0; i < td->seq_points->len; ++i) { + SeqPoint *sp = g_ptr_array_index (td->seq_points, i); + + /* Store the seq point index here temporarily */ + sp->next_offset = i; + } + next = mono_mempool_alloc0 (td->mempool, sizeof (GList*) * td->seq_points->len); + for (bblist = td->basic_blocks; bblist; bblist = bblist->next) { + InterpBasicBlock *bb = bblist->data; + + GSList *bb_seq_points = g_slist_reverse (bb->seq_points); + SeqPoint *last = NULL; + for (GSList *l = bb_seq_points; l; l = l->next) { + SeqPoint *sp = l->data; + + if (sp->il_offset == METHOD_ENTRY_IL_OFFSET || sp->il_offset == METHOD_EXIT_IL_OFFSET) + /* Used to implement method entry/exit events */ + continue; + + if (last != NULL) { + /* Link with the previous seq point in the same bb */ + next [last->next_offset] = g_slist_append_mempool (td->mempool, next [last->next_offset], GINT_TO_POINTER (sp->next_offset)); + } else { + /* Link with the last bb in the previous bblocks */ + collect_pred_seq_points (td, bb, sp, next); + } + last = sp; + } + } + + /* Serialize the seq points into a byte array */ + array = g_byte_array_new (); + SeqPoint zero_seq_point = {0}; + SeqPoint* last_seq_point = &zero_seq_point; + for (i = 0; i < td->seq_points->len; ++i) { + SeqPoint *sp = (SeqPoint*)g_ptr_array_index (td->seq_points, i); + + sp->next_offset = 0; + if (mono_seq_point_info_add_seq_point (array, sp, last_seq_point, next [i], TRUE)) + last_seq_point = sp; + } + + if (td->verbose_level) { + g_print ("\nSEQ POINT MAP FOR %s: \n", td->method->name); + + for (i = 0; i < td->seq_points->len; ++i) { + SeqPoint *sp = (SeqPoint*)g_ptr_array_index (td->seq_points, i); + GSList *l; + + if (!next [i]) + continue; + + g_print ("\tIL0x%x[0x%0x] ->", sp->il_offset, sp->native_offset); + for (l = next [i]; l; l = l->next) { + int next_index = GPOINTER_TO_UINT (l->data); + g_print (" IL0x%x", ((SeqPoint*)g_ptr_array_index (td->seq_points, next_index))->il_offset); + } + g_print ("\n"); + } + } + + info = mono_seq_point_info_new (array->len, TRUE, array->data, TRUE, &seq_info_size); + mono_jit_stats.allocated_seq_points_size += seq_info_size; + + g_byte_array_free (array, TRUE); + + mono_domain_lock (domain); + g_hash_table_insert (domain_jit_info (domain)->seq_points, rtm->method, info); + mono_domain_unlock (domain); +} + +static void +emit_seq_point (TransformData *td, int il_offset, InterpBasicBlock *cbb, gboolean nonempty_stack) +{ + SeqPoint *seqp; + + seqp = mono_mempool_alloc0 (td->mempool, sizeof (SeqPoint)); + seqp->il_offset = il_offset; + seqp->native_offset = (guint8*)td->new_ip - (guint8*)td->new_code; + if (nonempty_stack) + seqp->flags |= MONO_SEQ_POINT_FLAG_NONEMPTY_STACK; + + ADD_CODE (td, MINT_SDB_SEQ_POINT); + g_ptr_array_add (td->seq_points, seqp); + + cbb->seq_points = g_slist_prepend_mempool (td->mempool, cbb->seq_points, seqp); + cbb->last_seq_point = seqp; +} + static void generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, MonoGenericContext *generic_context) { @@ -976,8 +1340,20 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo TransformData td; int generating_code = 1; GArray *line_numbers; + MonoDebugMethodInfo *minfo; + MonoBitSet *seq_point_locs = NULL; + MonoBitSet *seq_point_set_locs = NULL; + gboolean sym_seq_points = FALSE; + InterpBasicBlock *bb_exit = NULL; + static gboolean verbose_method_inited; + static char* verbose_method_name; + + if (!verbose_method_inited) { + verbose_method_name = getenv ("MONO_VERBOSE_METHOD"); + verbose_method_inited = TRUE; + } - memset(&td, 0, sizeof(td)); + memset (&td, 0, sizeof(td)); td.method = method; td.rtm = rtm; td.is_bb_start = is_bb_start; @@ -987,8 +1363,8 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo td.max_code_size = td.code_size; td.new_code = (unsigned short *)g_malloc(td.max_code_size * sizeof(gushort)); td.new_code_end = td.new_code + td.max_code_size; + td.mempool = mono_mempool_new (); td.in_offsets = g_malloc0(header->code_size * sizeof(int)); - td.forward_refs = g_malloc(header->code_size * sizeof(int)); td.stack_state = g_malloc0(header->code_size * sizeof(StackInfo *)); td.stack_height = g_malloc(header->code_size * sizeof(int)); td.vt_stack_size = g_malloc(header->code_size * sizeof(int)); @@ -997,12 +1373,61 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo td.data_items = NULL; td.data_hash = g_hash_table_new (NULL, NULL); td.clause_indexes = g_malloc (header->code_size * sizeof (int)); + td.gen_sdb_seq_points = debug_options.gen_sdb_seq_points; + td.seq_points = g_ptr_array_new (); + td.relocs = g_ptr_array_new (); + td.verbose_level = mono_interp_traceopt; rtm->data_items = td.data_items; for (i = 0; i < header->code_size; i++) { - td.forward_refs [i] = -1; td.stack_height [i] = -1; td.clause_indexes [i] = -1; } + + if (verbose_method_name) { + const char *name = verbose_method_name; + + if ((strchr (name, '.') > name) || strchr (name, ':')) { + MonoMethodDesc *desc; + + desc = mono_method_desc_new (name, TRUE); + if (mono_method_desc_full_match (desc, method)) { + td.verbose_level = 4; + } + mono_method_desc_free (desc); + } else { + if (strcmp (method->name, name) == 0) + td.verbose_level = 4; + } + } + + if (td.gen_sdb_seq_points) { + get_basic_blocks (&td); + + minfo = mono_debug_lookup_method (method); + + if (minfo) { + MonoSymSeqPoint *sps; + int i, n_il_offsets; + + mono_debug_get_seq_points (minfo, NULL, NULL, NULL, &sps, &n_il_offsets); + // FIXME: Free + seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (td.mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0); + seq_point_set_locs = mono_bitset_mem_new (mono_mempool_alloc0 (td.mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0); + sym_seq_points = TRUE; + + for (i = 0; i < n_il_offsets; ++i) { + if (sps [i].il_offset < header->code_size) + mono_bitset_set_fast (seq_point_locs, sps [i].il_offset); + } + g_free (sps); + } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) { + /* Methods without line number info like auto-generated property accessors */ + seq_point_locs = mono_bitset_new (header->code_size, 0); + seq_point_set_locs = mono_bitset_new (header->code_size, 0); + sym_seq_points = TRUE; + } + } + td.new_ip = td.new_code; td.last_new_ip = NULL; @@ -1045,7 +1470,7 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo td.ip = header->code; end = td.ip + header->code_size; - if (mono_interp_traceopt) { + if (td.verbose_level) { char *tmp = mono_disasm_code (NULL, method, td.ip, end); char *name = mono_method_full_name (method, TRUE); g_print ("Method %s, original code:\n", name); @@ -1069,6 +1494,12 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo } } + if (sym_seq_points) { + InterpBasicBlock *cbb = td.offset_to_bb [0]; + g_assert (cbb); + emit_seq_point (&td, METHOD_ENTRY_IL_OFFSET, cbb, FALSE); + } + while (td.ip < end) { int in_offset; @@ -1080,38 +1511,10 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo td.in_start = td.ip; MonoDebugLineNumberEntry lne; - lne.native_offset = td.new_ip - td.new_code; - lne.il_offset = td.ip - header->code; + lne.native_offset = (guint8*)td.new_ip - (guint8*)td.new_code; + lne.il_offset = in_offset; g_array_append_val (line_numbers, lne); - while (td.forward_refs [in_offset] >= 0) { - int j = td.forward_refs [in_offset]; - int slot; - td.forward_refs [in_offset] = td.forward_refs [j]; - if (td.in_offsets [j] < 0) { - int old_switch_offset = -td.in_offsets [j]; - int new_switch_offset = td.in_offsets [old_switch_offset]; - int switch_case = (j - old_switch_offset - 5) / 4; - int n_cases = read32 (header->code + old_switch_offset + 1); - offset = (td.new_ip - td.new_code) - (new_switch_offset + 2 * n_cases + 3); - slot = new_switch_offset + 3 + 2 * switch_case; - td.new_code [slot] = * (unsigned short *)(&offset); - td.new_code [slot + 1] = * ((unsigned short *)&offset + 1); - } else { - int op = td.new_code [td.in_offsets [j]]; - if (mono_interp_opargtype [op] == MintOpShortBranch) { - offset = (td.new_ip - td.new_code) - td.in_offsets [j]; - g_assert (offset <= 32767); - slot = td.in_offsets [j] + 1; - td.new_code [slot] = offset; - } else { - offset = (td.new_ip - td.new_code) - td.in_offsets [j]; - slot = td.in_offsets [j] + 1; - td.new_code [slot] = * (unsigned short *)(&offset); - td.new_code [slot + 1] = * ((unsigned short *)&offset + 1); - } - } - } if (td.stack_height [in_offset] >= 0) { g_assert (is_bb_start [in_offset]); if (td.stack_height [in_offset] > 0) @@ -1127,7 +1530,7 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo ++td.ip; continue; } - if (mono_interp_traceopt > 1) { + if (td.verbose_level > 1) { printf("IL_%04lx %s %-10s -> IL_%04lx, sp %ld, %s %-12s vt_sp %u (max %u)\n", td.ip - td.il_code, td.is_bb_start [td.ip - td.il_code] == 3 ? "<>" : @@ -1138,6 +1541,26 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo (td.sp > td.stack && (td.sp [-1].type == STACK_TYPE_O || td.sp [-1].type == STACK_TYPE_VT)) ? (td.sp [-1].klass == NULL ? "?" : td.sp [-1].klass->name) : "", td.vt_sp, td.max_vt_sp); } + + if (sym_seq_points && mono_bitset_test_fast (seq_point_locs, td.ip - header->code)) { + InterpBasicBlock *cbb = td.offset_to_bb [td.ip - header->code]; + g_assert (cbb); + + /* + * Make methods interruptable at the beginning, and at the targets of + * backward branches. + */ + if (in_offset == 0 || g_slist_length (cbb->preds) > 1) + ADD_CODE (&td, MINT_SDB_INTR_LOC); + + emit_seq_point (&td, in_offset, cbb, FALSE); + + mono_bitset_set_fast (seq_point_set_locs, td.ip - header->code); + } + + if (sym_seq_points) + bb_exit = td.offset_to_bb [td.ip - header->code]; + switch (*td.ip) { case CEE_NOP: /* lose it */ @@ -1318,7 +1741,20 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo case CEE_CALLVIRT: /* Fall through */ case CEE_CALLI: /* Fall through */ case CEE_CALL: { + gboolean need_seq_point = FALSE; + + if (sym_seq_points && !mono_bitset_test_fast (seq_point_locs, td.ip + 5 - header->code)) + need_seq_point = TRUE; + interp_transform_call (&td, method, NULL, domain, generic_context, is_bb_start, body_start_offset, constrained_class, readonly); + + if (need_seq_point) { + InterpBasicBlock *cbb = td.offset_to_bb [td.ip - header->code]; + g_assert (cbb); + + emit_seq_point (&td, td.ip - header->code, cbb, TRUE); + } + constrained_class = NULL; readonly = FALSE; break; @@ -1337,6 +1773,13 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo g_warning ("%s.%s: CEE_RET: more values on stack: %d", td.method->klass->name, td.method->name, td.sp - td.stack); if (td.vt_sp != vt_size) g_error ("%s.%s: CEE_RET: value type stack: %d vs. %d", td.method->klass->name, td.method->name, td.vt_sp, vt_size); + + if (sym_seq_points) { + InterpBasicBlock *cbb = td.offset_to_bb [td.ip - header->code]; + g_assert (cbb); + emit_seq_point (&td, METHOD_EXIT_IL_OFFSET, bb_exit, FALSE); + } + if (vt_size == 0) SIMPLE_OP(td, signature->ret->type == MONO_TYPE_VOID ? MINT_RET_VOID : MINT_RET); else { @@ -1456,15 +1899,12 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo case CEE_SWITCH: { guint32 n; const unsigned char *next_ip; - const unsigned char *base_ip = td.ip; - unsigned short *next_new_ip; ++td.ip; n = read32 (td.ip); ADD_CODE (&td, MINT_SWITCH); WRITE32 (&td, &n); td.ip += 4; next_ip = td.ip + n * 4; - next_new_ip = td.new_ip + n * 2; --td.sp; int stack_height = td.sp - td.stack; for (i = 0; i < n; i++) { @@ -1475,16 +1915,19 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo if (stack_height > 0 && stack_height != td.stack_height [target]) g_warning ("SWITCH with back branch and non-empty stack"); #endif - target = td.in_offsets [target] - (next_new_ip - td.new_code); + target = td.in_offsets [target] - (td.new_ip - td.new_code); } else { td.stack_height [target] = stack_height; td.vt_stack_size [target] = td.vt_sp; if (stack_height > 0) td.stack_state [target] = g_memdup (td.stack, stack_height * sizeof (td.stack [0])); - int prev = td.forward_refs [target]; - td.forward_refs [td.ip - td.il_code] = prev; - td.forward_refs [target] = td.ip - td.il_code; - td.in_offsets [td.ip - td.il_code] = - (base_ip - td.il_code); + + Reloc *reloc = mono_mempool_alloc0 (td.mempool, sizeof (Reloc)); + reloc->type = RELOC_SWITCH; + reloc->offset = td.new_ip - td.new_code; + reloc->target = target; + g_ptr_array_add (td.relocs, reloc); + target = 0xffff; } WRITE32 (&td, &target); td.ip += 4; @@ -1942,12 +2385,13 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo MonoString *s; token = mono_metadata_token_index (read32 (td.ip + 1)); td.ip += 5; - if (method->wrapper_type != MONO_WRAPPER_NONE) { - s = mono_string_new_wrapper( - mono_method_get_wrapper_data (method, token)); - } - else + if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) { + s = mono_method_get_wrapper_data (method, token); + } else if (method->wrapper_type != MONO_WRAPPER_NONE) { + s = mono_string_new_wrapper (mono_method_get_wrapper_data (method, token)); + } else { s = mono_ldstr (domain, image, token); + } ADD_CODE(&td, MINT_LDSTR); ADD_CODE(&td, get_data_item_index (&td, s)); PUSH_TYPE(&td, STACK_TYPE_O, mono_defaults.string_class); @@ -3237,8 +3681,7 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo ++td.ip; break; case CEE_UNALIGNED_: - ++td.ip; - /* FIX: should do something? */; + td.ip += 2; break; case CEE_VOLATILE_: ++td.ip; @@ -3342,9 +3785,35 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo td.last_ip = td.in_start; } - if (mono_interp_traceopt) { + /* Handle relocations */ + for (int i = 0; i < td.relocs->len; ++i) { + Reloc *reloc = g_ptr_array_index (td.relocs, i); + + int offset = td.in_offsets [reloc->target] - reloc->offset; + + switch (reloc->type) { + case RELOC_SHORT_BRANCH: + g_assert (td.new_code [reloc->offset + 1] == 0xffff); + td.new_code [reloc->offset + 1] = offset; + break; + case RELOC_LONG_BRANCH: + g_assert_not_reached (); + break; + case RELOC_SWITCH: { + guint16 *v = (guint16*)&offset; + td.new_code [reloc->offset] = *(guint16*)v; + td.new_code [reloc->offset + 1] = *(guint16*)(v + 1); + break; + } + default: + g_assert_not_reached (); + break; + } + } + + if (td.verbose_level) { const guint16 *p = td.new_code; - printf("Runtime method: %p, VT stack size: %d\n", rtm, td.max_vt_sp); + printf("Runtime method: %s %p, VT stack size: %d\n", mono_method_full_name (method, TRUE), rtm, td.max_vt_sp); printf("Calculated stack size: %d, stated size: %d\n", td.max_stack_height, header->max_stack); while (p < td.new_ip) { p = mono_interp_dis_mintop(td.new_code, p); @@ -3384,6 +3853,7 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo /* Create a MonoJitInfo for the interpreted method by creating the interpreter IR as the native code. */ int jinfo_len = mono_jit_info_size (0, header->num_clauses, 0); MonoJitInfo *jinfo = (MonoJitInfo *)mono_domain_alloc0 (domain, jinfo_len); + jinfo->is_interp = 1; rtm->jinfo = jinfo; mono_jit_info_init (jinfo, method, (guint8*)rtm->code, code_len, 0, header->num_clauses, 0); for (i = 0; i < jinfo->num_clauses; ++i) { @@ -3391,17 +3861,18 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo MonoExceptionClause *c = rtm->clauses + i; ei->flags = c->flags; - ei->try_start = rtm->code + c->try_offset; - ei->try_end = rtm->code + c->try_offset + c->try_len; - ei->handler_start = rtm->code + c->handler_offset; + ei->try_start = (guint8*)(rtm->code + c->try_offset); + ei->try_end = (guint8*)(rtm->code + c->try_offset + c->try_len); + ei->handler_start = (guint8*)(rtm->code + c->handler_offset); if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER || ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY) { } else { ei->data.catch_class = c->data.catch_class; } } + save_seq_points (&td); + g_free (td.in_offsets); - g_free (td.forward_refs); for (i = 0; i < header->code_size; ++i) g_free (td.stack_state [i]); g_free (td.stack_state); @@ -3411,7 +3882,10 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo g_free (td.stack); g_hash_table_destroy (td.data_hash); g_free (td.clause_indexes); + g_ptr_array_free (td.seq_points, TRUE); g_array_free (line_numbers, TRUE); + g_ptr_array_free (td.relocs, TRUE); + mono_mempool_destroy (td.mempool); } static mono_mutex_t calc_section; @@ -3482,7 +3956,7 @@ mono_interp_transform_method (RuntimeMethod *runtime_method, ThreadContext *cont mono_os_mutex_lock(&calc_section); if (runtime_method->transformed) { mono_os_mutex_unlock(&calc_section); - mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_OK); + mono_profiler_method_end_jit (method, runtime_method->jinfo, MONO_PROFILE_OK); return NULL; } @@ -3657,7 +4131,7 @@ mono_interp_transform_method (RuntimeMethod *runtime_method, ThreadContext *cont if (runtime_method->transformed) { mono_os_mutex_unlock(&calc_section); g_free (is_bb_start); - mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_OK); + mono_profiler_method_end_jit (method, runtime_method->jinfo, MONO_PROFILE_OK); return NULL; } @@ -3708,7 +4182,8 @@ mono_interp_transform_method (RuntimeMethod *runtime_method, ThreadContext *cont g_free (is_bb_start); - mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_OK); + // FIXME: Add a different callback ? + mono_profiler_method_end_jit (method, runtime_method->jinfo, MONO_PROFILE_OK); runtime_method->transformed = TRUE; mono_os_mutex_unlock(&calc_section); diff --git a/mono/mini/jit-icalls.c b/mono/mini/jit-icalls.c index 401ac247e2a..648e69cf18c 100644 --- a/mono/mini/jit-icalls.c +++ b/mono/mini/jit-icalls.c @@ -1458,11 +1458,15 @@ mono_generic_class_init (MonoVTable *vtable) } void -ves_icall_mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr) +ves_icall_mono_delegate_ctor (MonoObject *this_obj_raw, MonoObject *target_raw, gpointer addr) { + HANDLE_FUNCTION_ENTER (); MonoError error; + MONO_HANDLE_DCL (MonoObject, this_obj); + MONO_HANDLE_DCL (MonoObject, target); mono_delegate_ctor (this_obj, target, addr, &error); mono_error_set_pending_exception (&error); + HANDLE_FUNCTION_RETURN (); } gpointer diff --git a/mono/mini/memory-access.c b/mono/mini/memory-access.c index f20d6790eea..6a6e11006cc 100644 --- a/mono/mini/memory-access.c +++ b/mono/mini/memory-access.c @@ -8,22 +8,25 @@ #ifndef DISABLE_JIT +#include #include #include "mini.h" #include "ir-emit.h" +#include "jit-icalls.h" #define MAX_INLINE_COPIES 10 +#define MAX_INLINE_COPY_SIZE 10000 void mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align) { int val_reg; + /*FIXME arbitrary hack to avoid unbound code expansion.*/ + g_assert (size < MAX_INLINE_COPY_SIZE); g_assert (val == 0); - - if (align == 0) - align = 4; + g_assert (align > 0); if ((size <= SIZEOF_REGISTER) && (size <= align)) { switch (size) { @@ -51,39 +54,51 @@ mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, else MONO_EMIT_NEW_ICONST (cfg, val_reg, val); - if (align < 4) { - /* This could be optimized further if neccesary */ - while (size >= 1) { - MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg); - offset += 1; - size -= 1; - } - return; - } - - if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) { - if (offset % 8) { - MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg); - offset += 4; - size -= 4; - } + if (align < SIZEOF_VOID_P) { + if (align % 2 == 1) + goto set_1; + if (align % 4 == 2) + goto set_2; + if (SIZEOF_VOID_P == 8 && align % 8 == 4) + goto set_4; + } + + //Unaligned offsets don't naturaly happen in the runtime, so it's ok to be conservative in how we copy + //We assume that input src and dest are be aligned to `align` so offset just worsen it + int offsets_mask = offset & 0x7; //we only care about the misalignment part + if (offsets_mask) { + if (offsets_mask % 2 == 1) + goto set_1; + if (offsets_mask % 4 == 2) + goto set_2; + if (SIZEOF_VOID_P == 8 && offsets_mask % 8 == 4) + goto set_4; + } + + if (SIZEOF_REGISTER == 8) { while (size >= 8) { MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg); offset += 8; size -= 8; } - } + } +set_4: while (size >= 4) { MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg); offset += 4; size -= 4; } + + +set_2: while (size >= 2) { MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg); offset += 2; size -= 2; } + +set_1: while (size >= 1) { MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg); offset += 1; @@ -96,25 +111,32 @@ mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int so { int cur_reg; - if (align == 0) - align = 4; - /*FIXME arbitrary hack to avoid unbound code expansion.*/ - g_assert (size < 10000); + g_assert (size < MAX_INLINE_COPY_SIZE); + g_assert (align > 0); + + if (align < SIZEOF_VOID_P) { + if (align == 4) + goto copy_4; + if (align == 2) + goto copy_2; + goto copy_1; + } - if (align < 4) { - /* This could be optimized further if neccesary */ - while (size >= 1) { - cur_reg = alloc_preg (cfg); - MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset); - MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg); - doffset += 1; - soffset += 1; - size -= 1; - } + //Unaligned offsets don't naturaly happen in the runtime, so it's ok to be conservative in how we copy + //We assume that input src and dest are be aligned to `align` so offset just worsen it + int offsets_mask = (doffset | soffset) & 0x7; //we only care about the misalignment part + if (offsets_mask) { + if (offsets_mask % 2 == 1) + goto copy_1; + if (offsets_mask % 4 == 2) + goto copy_2; + if (SIZEOF_VOID_P == 8 && offsets_mask % 8 == 4) + goto copy_4; } - if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) { + + if (SIZEOF_REGISTER == 8) { while (size >= 8) { cur_reg = alloc_preg (cfg); MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset); @@ -123,8 +145,9 @@ mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int so soffset += 8; size -= 8; } - } + } +copy_4: while (size >= 4) { cur_reg = alloc_preg (cfg); MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset); @@ -133,6 +156,8 @@ mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int so soffset += 4; size -= 4; } + +copy_2: while (size >= 2) { cur_reg = alloc_preg (cfg); MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset); @@ -141,6 +166,8 @@ mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int so soffset += 2; size -= 2; } + +copy_1: while (size >= 1) { cur_reg = alloc_preg (cfg); MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset); @@ -157,7 +184,7 @@ mini_emit_memcpy_internal (MonoCompile *cfg, MonoInst *dest, MonoInst *src, Mono /* FIXME: Optimize the case when src/dest is OP_LDADDR */ /* We can't do copies at a smaller granule than the provided alignment */ - if (size_ins || ((size / align > MAX_INLINE_COPIES) && !(cfg->opt & MONO_OPT_INTRINS))) { + if (size_ins || (size / align > MAX_INLINE_COPIES) || !(cfg->opt & MONO_OPT_INTRINS)) { MonoInst *iargs [3]; iargs [0] = dest; iargs [1] = src; @@ -177,7 +204,7 @@ mini_emit_memset_internal (MonoCompile *cfg, MonoInst *dest, MonoInst *value_ins /* FIXME: Optimize the case when dest is OP_LDADDR */ /* We can't do copies at a smaller granule than the provided alignment */ - if (value_ins || size_ins || value != 0 || ((size / align > MAX_INLINE_COPIES) && !(cfg->opt & MONO_OPT_INTRINS))) { + if (value_ins || size_ins || value != 0 || (size / align > MAX_INLINE_COPIES) || !(cfg->opt & MONO_OPT_INTRINS)) { MonoInst *iargs [3]; iargs [0] = dest; @@ -207,12 +234,232 @@ mini_emit_memset_const_size (MonoCompile *cfg, MonoInst *dest, int value, int si mini_emit_memset_internal (cfg, dest, NULL, value, NULL, size, align); } + +static void +create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset) +{ + MonoClassField *field; + gpointer iter = NULL; + + while ((field = mono_class_get_fields (klass, &iter))) { + int foffset; + + if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) + continue; + foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset; + if (mini_type_is_reference (mono_field_get_type (field))) { + g_assert ((foffset % SIZEOF_VOID_P) == 0); + *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P); + } else { + MonoClass *field_class = mono_class_from_mono_type (field->type); + if (field_class->has_references) + create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset); + } + } +} + +static gboolean +mini_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align) +{ + int dest_ptr_reg, tmp_reg, destreg, srcreg, offset; + unsigned need_wb = 0; + + if (align == 0) + align = 4; + + /*types with references can't have alignment smaller than sizeof(void*) */ + if (align < SIZEOF_VOID_P) + return FALSE; + + if (size > 5 * SIZEOF_VOID_P) + return FALSE; + + create_write_barrier_bitmap (cfg, klass, &need_wb, 0); + + destreg = iargs [0]->dreg; + srcreg = iargs [1]->dreg; + offset = 0; + + dest_ptr_reg = alloc_preg (cfg); + tmp_reg = alloc_preg (cfg); + + /*tmp = dreg*/ + EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg); + + while (size >= SIZEOF_VOID_P) { + MonoInst *load_inst; + MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE); + load_inst->dreg = tmp_reg; + load_inst->inst_basereg = srcreg; + load_inst->inst_offset = offset; + MONO_ADD_INS (cfg->cbb, load_inst); + + MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg); + + if (need_wb & 0x1) + mini_emit_write_barrier (cfg, iargs [0], load_inst); + + offset += SIZEOF_VOID_P; + size -= SIZEOF_VOID_P; + need_wb >>= 1; + + /*tmp += sizeof (void*)*/ + if (size >= SIZEOF_VOID_P) { + NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P); + MONO_ADD_INS (cfg->cbb, iargs [0]); + } + } + + /* Those cannot be references since size < sizeof (void*) */ + while (size >= 4) { + MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset); + MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg); + offset += 4; + size -= 4; + } + + while (size >= 2) { + MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset); + MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg); + offset += 2; + size -= 2; + } + + while (size >= 1) { + MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset); + MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg); + offset += 1; + size -= 1; + } + + return TRUE; +} + +static void +mini_emit_memory_copy_internal (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, int explicit_align, gboolean native) +{ + MonoInst *iargs [4]; + int size; + guint32 align = 0; + MonoInst *size_ins = NULL; + MonoInst *memcpy_ins = NULL; + + g_assert (klass); + /* + Fun fact about @native. It's false that @klass will have no ref when @native is true. + This happens in pinvoke2. What goes is that marshal.c uses CEE_MONO_LDOBJNATIVE and pass klass. + The actual stuff being copied will have no refs, but @klass might. + This means we can't assert !(klass->has_references && native). + */ + + if (cfg->gshared) + klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg)); + + /* + * This check breaks with spilled vars... need to handle it during verification anyway. + * g_assert (klass && klass == src->klass && klass == dest->klass); + */ + + if (mini_is_gsharedvt_klass (klass)) { + g_assert (!native); + size_ins = mini_emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE); + memcpy_ins = mini_emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY); + } + + if (native) + size = mono_class_native_size (klass, &align); + else + size = mono_class_value_size (klass, &align); + + if (!align) + align = SIZEOF_VOID_P; + if (explicit_align) + align = explicit_align; + + if (mini_type_is_reference (&klass->byval_arg)) { // Refs *MUST* be naturally aligned + MonoInst *store, *load; + int dreg = alloc_ireg_ref (cfg); + + NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, src->dreg, 0); + MONO_ADD_INS (cfg->cbb, load); + + NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, dest->dreg, 0, dreg); + MONO_ADD_INS (cfg->cbb, store); + + mini_emit_write_barrier (cfg, dest, src); + } else if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) { /* if native is true there should be no references in the struct */ + /* Avoid barriers when storing to the stack */ + if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) || + (dest->opcode == OP_LDADDR))) { + int context_used; + + iargs [0] = dest; + iargs [1] = src; + + context_used = mini_class_check_context_used (cfg, klass); + + /* It's ok to intrinsify under gsharing since shared code types are layout stable. */ + if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mini_emit_wb_aware_memcpy (cfg, klass, iargs, size, align)) { + } else if (size_ins || align < SIZEOF_VOID_P) { + if (context_used) { + iargs [2] = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS); + } else { + iargs [2] = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass); + if (!cfg->compile_aot) + mono_class_compute_gc_descriptor (klass); + } + if (size_ins) + mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs); + else + mono_emit_jit_icall (cfg, mono_value_copy, iargs); + } else { + /* We don't unroll more than 5 stores to avoid code bloat. */ + /*This is harmless and simplify mono_gc_get_range_copy_func */ + size += (SIZEOF_VOID_P - 1); + size &= ~(SIZEOF_VOID_P - 1); + + EMIT_NEW_ICONST (cfg, iargs [2], size); + mono_emit_jit_icall (cfg, mono_gc_get_range_copy_func (), iargs); + } + return; + } + } + + if (size_ins) { + iargs [0] = dest; + iargs [1] = src; + iargs [2] = size_ins; + mini_emit_calli (cfg, mono_method_signature (mini_get_memcpy_method ()), iargs, memcpy_ins, NULL, NULL); + } else { + mini_emit_memcpy_const_size (cfg, dest, src, size, align); + } +} + MonoInst* mini_emit_memory_load (MonoCompile *cfg, MonoType *type, MonoInst *src, int offset, int ins_flag) { MonoInst *ins; - EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, type, src->dreg, offset); + if (ins_flag & MONO_INST_UNALIGNED) { + MonoInst *addr, *tmp_var; + int align; + int size = mono_type_size (type, &align); + + if (offset) { + MonoInst *add_offset; + NEW_BIALU_IMM (cfg, add_offset, OP_PADD_IMM, alloc_preg (cfg), src->dreg, offset); + MONO_ADD_INS (cfg->cbb, add_offset); + src = add_offset; + } + + tmp_var = mono_compile_create_var (cfg, type, OP_LOCAL); + EMIT_NEW_VARLOADA (cfg, addr, tmp_var, tmp_var->inst_vtype); + + mini_emit_memcpy_const_size (cfg, addr, src, size, 1); + EMIT_NEW_TEMPLOAD (cfg, ins, tmp_var->inst_c0); + } else { + EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, type, src->dreg, offset); + } ins->flags |= ins_flag; if (ins_flag & MONO_INST_VOLATILE) { @@ -233,6 +480,16 @@ mini_emit_memory_store (MonoCompile *cfg, MonoType *type, MonoInst *dest, MonoIn /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */ mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL); } + + if (ins_flag & MONO_INST_UNALIGNED) { + MonoInst *addr, *mov, *tmp_var; + + tmp_var = mono_compile_create_var (cfg, type, OP_LOCAL); + EMIT_NEW_TEMPSTORE (cfg, mov, tmp_var->inst_c0, value); + EMIT_NEW_VARLOADA (cfg, addr, tmp_var, tmp_var->inst_vtype); + mini_emit_memory_copy_internal (cfg, dest, addr, mono_class_from_mono_type (type), 1, FALSE); + } + /* FIXME: should check item at sp [1] is compatible with the type of the store. */ EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, type, dest->dreg, 0, value->dreg); @@ -247,7 +504,7 @@ mini_emit_memory_store (MonoCompile *cfg, MonoType *type, MonoInst *dest, MonoIn void mini_emit_memory_copy_bytes (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoInst *size, int ins_flag) { - int align = SIZEOF_VOID_P; + int align = (ins_flag & MONO_INST_UNALIGNED) ? 1 : SIZEOF_VOID_P; /* * FIXME: It's unclear whether we should be emitting both the acquire @@ -262,11 +519,9 @@ mini_emit_memory_copy_bytes (MonoCompile *cfg, MonoInst *dest, MonoInst *src, Mo mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ); } - if ((cfg->opt & MONO_OPT_INTRINS) && (size->opcode == OP_ICONST) && size->inst_c0 < 10000) { + if ((cfg->opt & MONO_OPT_INTRINS) && (size->opcode == OP_ICONST)) { mini_emit_memcpy_const_size (cfg, dest, src, size->inst_c0, align); } else { - if (cfg->verbose_level > 3) - printf ("EMITING REGULAR COPY\n"); mini_emit_memcpy_internal (cfg, dest, src, size, 0, align); } @@ -279,7 +534,7 @@ mini_emit_memory_copy_bytes (MonoCompile *cfg, MonoInst *dest, MonoInst *src, Mo void mini_emit_memory_init_bytes (MonoCompile *cfg, MonoInst *dest, MonoInst *value, MonoInst *size, int ins_flag) { - int align = SIZEOF_VOID_P; + int align = (ins_flag & MONO_INST_UNALIGNED) ? 1 : SIZEOF_VOID_P; if (ins_flag & MONO_INST_VOLATILE) { /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */ @@ -295,4 +550,37 @@ mini_emit_memory_init_bytes (MonoCompile *cfg, MonoInst *dest, MonoInst *value, } +/* + * If @klass is a valuetype, emit code to copy a value with source address in @src and destination address in @dest. + * If @klass is a ref type, copy a pointer instead. + */ + +void +mini_emit_memory_copy (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native, int ins_flag) +{ + int explicit_align = 0; + if (ins_flag & MONO_INST_UNALIGNED) + explicit_align = 1; + + /* + * FIXME: It's unclear whether we should be emitting both the acquire + * and release barriers for cpblk. It is technically both a load and + * store operation, so it seems like that's the sensible thing to do. + * + * FIXME: We emit full barriers on both sides of the operation for + * simplicity. We should have a separate atomic memcpy method instead. + */ + if (ins_flag & MONO_INST_VOLATILE) { + /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */ + mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ); + } + + mini_emit_memory_copy_internal (cfg, dest, src, klass, explicit_align, native); + + if (ins_flag & MONO_INST_VOLATILE) { + /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */ + mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ); + } +} + #endif diff --git a/mono/mini/method-to-ir.c b/mono/mini/method-to-ir.c index 72cf3442291..3817d2809f9 100644 --- a/mono/mini/method-to-ir.c +++ b/mono/mini/method-to-ir.c @@ -2827,29 +2827,6 @@ mini_get_memcpy_method (void) return memcpy_method; } -static void -create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset) -{ - MonoClassField *field; - gpointer iter = NULL; - - while ((field = mono_class_get_fields (klass, &iter))) { - int foffset; - - if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) - continue; - foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset; - if (mini_type_is_reference (mono_field_get_type (field))) { - g_assert ((foffset % SIZEOF_VOID_P) == 0); - *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P); - } else { - MonoClass *field_class = mono_class_from_mono_type (field->type); - if (field_class->has_references) - create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset); - } - } -} - void mini_emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value) { @@ -2863,6 +2840,8 @@ mini_emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value) if (!cfg->gen_write_barriers) return; + //method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !MONO_INS_IS_PCONST_NULL (sp [1]) + card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask); mono_gc_get_nursery (&nursery_shift_bits, &nursery_size); @@ -2906,177 +2885,6 @@ mini_emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value) EMIT_NEW_DUMMY_USE (cfg, dummy_use, value); } -gboolean -mini_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align) -{ - int dest_ptr_reg, tmp_reg, destreg, srcreg, offset; - unsigned need_wb = 0; - - if (align == 0) - align = 4; - - /*types with references can't have alignment smaller than sizeof(void*) */ - if (align < SIZEOF_VOID_P) - return FALSE; - - if (size > 5 * SIZEOF_VOID_P) - return FALSE; - - create_write_barrier_bitmap (cfg, klass, &need_wb, 0); - - destreg = iargs [0]->dreg; - srcreg = iargs [1]->dreg; - offset = 0; - - dest_ptr_reg = alloc_preg (cfg); - tmp_reg = alloc_preg (cfg); - - /*tmp = dreg*/ - EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg); - - while (size >= SIZEOF_VOID_P) { - MonoInst *load_inst; - MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE); - load_inst->dreg = tmp_reg; - load_inst->inst_basereg = srcreg; - load_inst->inst_offset = offset; - MONO_ADD_INS (cfg->cbb, load_inst); - - MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg); - - if (need_wb & 0x1) - mini_emit_write_barrier (cfg, iargs [0], load_inst); - - offset += SIZEOF_VOID_P; - size -= SIZEOF_VOID_P; - need_wb >>= 1; - - /*tmp += sizeof (void*)*/ - if (size >= SIZEOF_VOID_P) { - NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P); - MONO_ADD_INS (cfg->cbb, iargs [0]); - } - } - - /* Those cannot be references since size < sizeof (void*) */ - while (size >= 4) { - MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset); - MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg); - offset += 4; - size -= 4; - } - - while (size >= 2) { - MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset); - MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg); - offset += 2; - size -= 2; - } - - while (size >= 1) { - MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset); - MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg); - offset += 1; - size -= 1; - } - - return TRUE; -} - -/* - * Emit code to copy a valuetype of type @klass whose address is stored in - * @src->dreg to memory whose address is stored at @dest->dreg. - */ -void -mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native) -{ - MonoInst *iargs [4]; - int n; - guint32 align = 0; - MonoMethod *memcpy_method; - MonoInst *size_ins = NULL; - MonoInst *memcpy_ins = NULL; - - g_assert (klass); - if (cfg->gshared) - klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg)); - - /* - * This check breaks with spilled vars... need to handle it during verification anyway. - * g_assert (klass && klass == src->klass && klass == dest->klass); - */ - - if (mini_is_gsharedvt_klass (klass)) { - g_assert (!native); - size_ins = mini_emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE); - memcpy_ins = mini_emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY); - } - - if (native) - n = mono_class_native_size (klass, &align); - else - n = mono_class_value_size (klass, &align); - - if (!align) - align = SIZEOF_VOID_P; - /* if native is true there should be no references in the struct */ - if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) { - /* Avoid barriers when storing to the stack */ - if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) || - (dest->opcode == OP_LDADDR))) { - int context_used; - - iargs [0] = dest; - iargs [1] = src; - - context_used = mini_class_check_context_used (cfg, klass); - - /* It's ok to intrinsify under gsharing since shared code types are layout stable. */ - if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mini_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) { - return; - } else if (size_ins || align < SIZEOF_VOID_P) { - if (context_used) { - iargs [2] = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS); - } else { - iargs [2] = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass); - if (!cfg->compile_aot) - mono_class_compute_gc_descriptor (klass); - } - if (size_ins) - mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs); - else - mono_emit_jit_icall (cfg, mono_value_copy, iargs); - } else { - /* We don't unroll more than 5 stores to avoid code bloat. */ - /*This is harmless and simplify mono_gc_get_range_copy_func */ - n += (SIZEOF_VOID_P - 1); - n &= ~(SIZEOF_VOID_P - 1); - - EMIT_NEW_ICONST (cfg, iargs [2], n); - mono_emit_jit_icall (cfg, mono_gc_get_range_copy_func (), iargs); - } - } - } - - if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 8) { - /* FIXME: Optimize the case when src/dest is OP_LDADDR */ - mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align); - } else { - iargs [0] = dest; - iargs [1] = src; - if (size_ins) - iargs [2] = size_ins; - else - EMIT_NEW_ICONST (cfg, iargs [2], n); - - memcpy_method = mini_get_memcpy_method (); - if (memcpy_ins) - mini_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL); - else - mono_emit_method_call (cfg, memcpy_method, iargs, NULL); - } -} - MonoMethod* mini_get_memset_method (void) { @@ -4763,54 +4571,6 @@ mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, uns return addr; } -static MonoBreakPolicy -always_insert_breakpoint (MonoMethod *method) -{ - return MONO_BREAK_POLICY_ALWAYS; -} - -static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint; - -/** - * mono_set_break_policy: - * \param policy_callback the new callback function - * - * Allow embedders to decide wherther to actually obey breakpoint instructions - * (both break IL instructions and \c Debugger.Break method calls), for example - * to not allow an app to be aborted by a perfectly valid IL opcode when executing - * untrusted or semi-trusted code. - * - * \p policy_callback will be called every time a break point instruction needs to - * be inserted with the method argument being the method that calls \c Debugger.Break - * or has the IL \c break instruction. The callback should return \c MONO_BREAK_POLICY_NEVER - * if it wants the breakpoint to not be effective in the given method. - * \c MONO_BREAK_POLICY_ALWAYS is the default. - */ -void -mono_set_break_policy (MonoBreakPolicyFunc policy_callback) -{ - if (policy_callback) - break_policy_func = policy_callback; - else - break_policy_func = always_insert_breakpoint; -} - -static gboolean -should_insert_brekpoint (MonoMethod *method) { - switch (break_policy_func (method)) { - case MONO_BREAK_POLICY_ALWAYS: - return TRUE; - case MONO_BREAK_POLICY_NEVER: - return FALSE; - case MONO_BREAK_POLICY_ON_DBG: - g_warning ("mdb no longer supported"); - return FALSE; - default: - g_warning ("Incorrect value returned from break policy callback"); - return FALSE; - } -} - /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */ static MonoInst* emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set) @@ -5955,7 +5715,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign (strcmp (cmethod->klass->name_space, "System.Diagnostics") == 0) && (strcmp (cmethod->klass->name, "Debugger") == 0)) { if (!strcmp (cmethod->name, "Break") && fsig->param_count == 0) { - if (should_insert_brekpoint (cfg->method)) { + if (mini_should_insert_breakpoint (cfg->method)) { ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL); } else { MONO_INST_NEW (cfg, ins, OP_NOP); @@ -7997,7 +7757,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b MONO_ADD_INS (cfg->cbb, ins); break; case CEE_BREAK: - if (should_insert_brekpoint (cfg->method)) { + if (mini_should_insert_breakpoint (cfg->method)) { ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL); } else { MONO_INST_NEW (cfg, ins, OP_NOP); @@ -9892,23 +9652,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b klass = mini_get_class (method, token, generic_context); CHECK_TYPELOAD (klass); sp -= 2; - if (generic_class_is_reference_type (cfg, klass)) { - MonoInst *store, *load; - int dreg = alloc_ireg_ref (cfg); - - NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0); - load->flags |= ins_flag; - MONO_ADD_INS (cfg->cbb, load); - - NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg); - store->flags |= ins_flag; - MONO_ADD_INS (cfg->cbb, store); - - if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER) - mini_emit_write_barrier (cfg, sp [0], sp [1]); - } else { - mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE); - } + mini_emit_memory_copy (cfg, sp [0], sp [1], klass, FALSE, ins_flag); ins_flag = 0; ip += 5; break; @@ -9957,14 +9701,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b } /* Optimize the ldobj+stobj combination */ - /* The reference case ends up being a load+store anyway */ - /* Skip this if the operation is volatile. */ - if (((ip [5] == CEE_STOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 5) && read32 (ip + 6) == token) && !generic_class_is_reference_type (cfg, klass) && !(ins_flag & MONO_INST_VOLATILE)) { + if (((ip [5] == CEE_STOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 5) && read32 (ip + 6) == token)) { CHECK_STACK (1); sp --; - mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE); + mini_emit_memory_copy (cfg, sp [0], sp [1], klass, FALSE, ins_flag); ip += 5 + 5; ins_flag = 0; @@ -10635,7 +10377,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b dreg = alloc_ireg_mp (cfg); EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg); wbarrier_ptr_ins = ins; - /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */ + /* The decomposition will call mini_emit_memory_copy () which will emit a wbarrier if needed */ EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg); } else { EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg); @@ -11896,7 +11638,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL); temp->backend.is_pinvoke = 1; EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0); - mini_emit_stobj (cfg, dest, src, klass, TRUE); + mini_emit_memory_copy (cfg, dest, src, klass, TRUE, 0); EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0); dest->type = STACK_VTYPE; @@ -11927,7 +11669,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b } else { EMIT_NEW_RETLOADA (cfg, ins); } - mini_emit_stobj (cfg, ins, sp [0], klass, TRUE); + mini_emit_memory_copy (cfg, ins, sp [0], klass, TRUE, 0); if (sp != stack_start) UNVERIFIED; @@ -14445,11 +14187,4 @@ NOTES the values on the stack before emitting the last instruction of the bb. */ -#else /* !DISABLE_JIT */ - -void -mono_set_break_policy (MonoBreakPolicyFunc policy_callback) -{ -} - #endif /* !DISABLE_JIT */ diff --git a/mono/mini/mini-arm.c b/mono/mini/mini-arm.c index 96c7d3a6adf..10a9daa20ef 100644 --- a/mono/mini/mini-arm.c +++ b/mono/mini/mini-arm.c @@ -323,7 +323,7 @@ mono_arm_patchable_bl (guint8 *code, int cond) return code; } -#if defined(__ARM_EABI__) && defined(__linux__) && !defined(PLATFORM_ANDROID) && !defined(__native_client__) +#if defined(__ARM_EABI__) && defined(__linux__) && !defined(PLATFORM_ANDROID) && !defined(__native_client__) && !defined(MONO_CROSS_COMPILE) #define HAVE_AEABI_READ_TP 1 #endif @@ -337,7 +337,6 @@ mono_arch_have_fast_tls (void) #ifdef HAVE_AEABI_READ_TP static gboolean have_fast_tls = FALSE; static gboolean inited = FALSE; - gpointer tp1, tp2; if (mini_get_debug_options ()->use_fallback_tls) return FALSE; @@ -345,10 +344,14 @@ mono_arch_have_fast_tls (void) if (inited) return have_fast_tls; - tp1 = __aeabi_read_tp (); - asm volatile("mrc p15, 0, %0, c13, c0, 3" : "=r" (tp2)); + if (v7_supported) { + gpointer tp1, tp2; - have_fast_tls = tp1 && tp1 == tp2; + tp1 = __aeabi_read_tp (); + asm volatile("mrc p15, 0, %0, c13, c0, 3" : "=r" (tp2)); + + have_fast_tls = tp1 && tp1 == tp2; + } inited = TRUE; return have_fast_tls; #else @@ -359,6 +362,7 @@ mono_arch_have_fast_tls (void) static guint8* emit_tls_get (guint8 *code, int dreg, int tls_offset) { + g_assert (v7_supported); ARM_MRC (code, 15, 0, dreg, 13, 0, 3); ARM_LDR_IMM (code, dreg, dreg, tls_offset); return code; @@ -368,6 +372,7 @@ static guint8* emit_tls_set (guint8 *code, int sreg, int tls_offset) { int tp_reg = (sreg != ARMREG_R0) ? ARMREG_R0 : ARMREG_R1; + g_assert (v7_supported); ARM_MRC (code, 15, 0, tp_reg, 13, 0, 3); ARM_STR_IMM (code, sreg, tp_reg, tls_offset); return code; diff --git a/mono/mini/mini-exceptions.c b/mono/mini/mini-exceptions.c index b6b1d813399..7878372c10c 100644 --- a/mono/mini/mini-exceptions.c +++ b/mono/mini/mini-exceptions.c @@ -1070,6 +1070,7 @@ mono_walk_stack_full (MonoJitStackWalk func, MonoContext *start_ctx, MonoDomain mgreg_t *new_reg_locations [MONO_MAX_IREGS]; gboolean get_reg_locations = unwind_options & MONO_UNWIND_REG_LOCATIONS; gboolean async = mono_thread_info_is_async_context (); + Unwinder unwinder; if (mono_llvm_only) { GSList *l, *ips; @@ -1114,9 +1115,11 @@ mono_walk_stack_full (MonoJitStackWalk func, MonoContext *start_ctx, MonoDomain memcpy (&ctx, start_ctx, sizeof (MonoContext)); memset (reg_locations, 0, sizeof (reg_locations)); + unwinder_init (&unwinder); + while (MONO_CONTEXT_GET_SP (&ctx) < jit_tls->end_of_stack) { frame.lmf = lmf; - res = mono_find_jit_info_ext (domain, jit_tls, NULL, &ctx, &new_ctx, NULL, &lmf, get_reg_locations ? new_reg_locations : NULL, &frame); + res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, &ctx, &new_ctx, NULL, &lmf, get_reg_locations ? new_reg_locations : NULL, &frame); if (!res) return; @@ -1633,7 +1636,7 @@ mono_handle_exception_internal_first_pass (MonoContext *ctx, MonoObject *obj, gi gpointer ip; if (in_interp) - ip = (guint16*)ji->code_start + frame.native_offset; + ip = (guint8*)ji->code_start + frame.native_offset; else ip = MONO_CONTEXT_GET_IP (ctx); @@ -2009,7 +2012,7 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu } if (in_interp) - ip = (guint16*)ji->code_start + frame.native_offset; + ip = (guint8*)ji->code_start + frame.native_offset; else ip = MONO_CONTEXT_GET_IP (ctx); @@ -2131,7 +2134,7 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu * like the call which transitioned to JITted code has succeeded, but the * return value register etc. is not set, so we have to be careful. */ - mono_interp_set_resume_state (mono_ex, &frame, ei->handler_start); + mono_interp_set_resume_state (jit_tls, mono_ex, frame.interp_frame, ei->handler_start); /* Undo the IP adjustment done by mono_arch_unwind_frame () */ #if defined(TARGET_AMD64) ctx->gregs [AMD64_RIP] ++; @@ -2260,6 +2263,9 @@ mono_debugger_run_finally (MonoContext *start_ctx) * mono_handle_exception: * \param ctx saved processor state * \param obj the exception object + * + * Handle the exception OBJ starting from the state CTX. Modify CTX to point to the handler clause if the exception is caught, and + * return TRUE. */ gboolean mono_handle_exception (MonoContext *ctx, MonoObject *obj) @@ -3407,31 +3413,3 @@ mono_debug_personality (void) g_assert_not_reached (); } #endif - -#ifndef ENABLE_INTERPRETER -/* Stubs of interpreter functions */ -void -mono_interp_set_resume_state (MonoException *ex, StackFrameInfo *frame, gpointer handler_ip) -{ - g_assert_not_reached (); -} - -void -mono_interp_run_finally (StackFrameInfo *frame, int clause_index, gpointer handler_ip) -{ - g_assert_not_reached (); -} - -void -mono_interp_frame_iter_init (MonoInterpStackIter *iter, gpointer interp_exit_data) -{ - g_assert_not_reached (); -} - -gboolean -mono_interp_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame) -{ - g_assert_not_reached (); - return FALSE; -} -#endif diff --git a/mono/mini/mini-runtime.c b/mono/mini/mini-runtime.c index b5d79629a54..7d427a915ee 100644 --- a/mono/mini/mini-runtime.c +++ b/mono/mini/mini-runtime.c @@ -583,23 +583,23 @@ break_count (void) G_GNUC_UNUSED gboolean mono_debug_count (void) { - static int count = 0; + static int count = 0, int_val = 0; static gboolean inited; - static char *value; count ++; if (!inited) { - value = g_getenv ("COUNT"); + char *value = g_getenv ("COUNT"); + if (value) { + int_val = atoi (value); + g_free (value); + } inited = TRUE; } - if (!value) + if (!int_val) return TRUE; - int int_val = atoi (value); - g_free (value); - if (count == int_val) break_count (); @@ -4547,6 +4547,56 @@ mono_personality (void) g_assert_not_reached (); } + +static MonoBreakPolicy +always_insert_breakpoint (MonoMethod *method) +{ + return MONO_BREAK_POLICY_ALWAYS; +} + +static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint; + +/** + * mono_set_break_policy: + * \param policy_callback the new callback function + * + * Allow embedders to decide whether to actually obey breakpoint instructions + * (both break IL instructions and \c Debugger.Break method calls), for example + * to not allow an app to be aborted by a perfectly valid IL opcode when executing + * untrusted or semi-trusted code. + * + * \p policy_callback will be called every time a break point instruction needs to + * be inserted with the method argument being the method that calls \c Debugger.Break + * or has the IL \c break instruction. The callback should return \c MONO_BREAK_POLICY_NEVER + * if it wants the breakpoint to not be effective in the given method. + * \c MONO_BREAK_POLICY_ALWAYS is the default. + */ +void +mono_set_break_policy (MonoBreakPolicyFunc policy_callback) +{ + if (policy_callback) + break_policy_func = policy_callback; + else + break_policy_func = always_insert_breakpoint; +} + +gboolean +mini_should_insert_breakpoint (MonoMethod *method) +{ + switch (break_policy_func (method)) { + case MONO_BREAK_POLICY_ALWAYS: + return TRUE; + case MONO_BREAK_POLICY_NEVER: + return FALSE; + case MONO_BREAK_POLICY_ON_DBG: + g_warning ("mdb no longer supported"); + return FALSE; + default: + g_warning ("Incorrect value returned from break policy callback"); + return FALSE; + } +} + // Custom handlers currently only implemented by Windows. #ifndef HOST_WIN32 gboolean diff --git a/mono/mini/mini.h b/mono/mini/mini.h index 6eb32809205..ed10d8f9379 100644 --- a/mono/mini/mini.h +++ b/mono/mini/mini.h @@ -1217,11 +1217,12 @@ typedef struct { */ gpointer abort_exc_stack_threshold; - /* * List of methods being JIT'd in the current thread. */ int active_jit_methods; + + gpointer interp_context; } MonoJitTlsData; /* @@ -2481,6 +2482,7 @@ MonoInst* mono_emit_jit_icall_by_info (MonoCompile *cfg, int il_offset, MonoJitI MonoInst* mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this_ins); void mono_create_helper_signatures (void); MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args); +gboolean mini_should_insert_breakpoint (MonoMethod *method); gboolean mini_class_is_system_array (MonoClass *klass); MonoMethodSignature *mono_get_element_address_signature (int arity); @@ -2652,11 +2654,11 @@ MonoInst* mini_emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClas MonoInst* mini_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg); MonoInst* mini_emit_memory_barrier (MonoCompile *cfg, int kind); void mini_emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value); -gboolean mini_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align); MonoInst* mini_emit_memory_load (MonoCompile *cfg, MonoType *type, MonoInst *src, int offset, int ins_flag); void mini_emit_memory_store (MonoCompile *cfg, MonoType *type, MonoInst *dest, MonoInst *value, int ins_flag); void mini_emit_memory_copy_bytes (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoInst *size, int ins_flag); void mini_emit_memory_init_bytes (MonoCompile *cfg, MonoInst *dest, MonoInst *value, MonoInst *size, int ins_flag); +void mini_emit_memory_copy (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native, int ins_flag); MonoMethod* mini_get_memcpy_method (void); MonoMethod* mini_get_memset_method (void); diff --git a/mono/mini/tramp-arm.c b/mono/mini/tramp-arm.c index 51c0cac6de6..723238f4e94 100644 --- a/mono/mini/tramp-arm.c +++ b/mono/mini/tramp-arm.c @@ -847,26 +847,31 @@ mono_arch_get_enter_icall_trampoline (MonoTrampInfo **info) guint8 *start = NULL, *code, *label_gexits [gregs_num], *label_fexits [fregs_num], *label_leave_tramp [3], *label_is_float_ret; MonoJumpInfo *ji = NULL; GSList *unwind_ops = NULL; - int buf_len, i, framesize = 0, off_methodargs, off_targetaddr; + int buf_len, i, framesize, off_methodargs, off_targetaddr; const int fp_reg = ARMREG_R7; buf_len = 512 + 1024; start = code = (guint8 *) mono_global_codeman_reserve (buf_len); - off_methodargs = framesize; + framesize = 5 * sizeof (mgreg_t); /* lr, r4, r8, r6 and plus one */ + + off_methodargs = -framesize; framesize += sizeof (mgreg_t); - off_targetaddr = framesize; + off_targetaddr = -framesize; framesize += sizeof (mgreg_t); - framesize = ALIGN_TO (framesize, MONO_ARCH_FRAME_ALIGNMENT); + framesize = ALIGN_TO (framesize + 4 * sizeof (mgreg_t), MONO_ARCH_FRAME_ALIGNMENT); /* allocate space on stack for argument passing */ const int stack_space = ALIGN_TO (((gregs_num - ARMREG_R3) * sizeof (mgreg_t)), MONO_ARCH_FRAME_ALIGNMENT); - /* use r4, r5 and r6 as scratch registers */ - ARM_PUSH (code, (1 << fp_reg) | (1 << ARMREG_LR) | (1 << ARMREG_R4) | (1 << ARMREG_R5) | (1 << ARMREG_R6)); + /* iOS ABI */ + ARM_PUSH (code, (1 << fp_reg) | (1 << ARMREG_LR)); ARM_MOV_REG_REG (code, fp_reg, ARMREG_SP); + + /* use r4, r8 and r6 as scratch registers */ + ARM_PUSH (code, (1 << ARMREG_R4) | (1 << ARMREG_R8) | (1 << ARMREG_R6)); ARM_SUB_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, stack_space + framesize); /* save InterpMethodArguments* onto stack */ @@ -878,32 +883,32 @@ mono_arch_get_enter_icall_trampoline (MonoTrampInfo **info) /* load pointer to InterpMethodArguments* into r4 */ ARM_MOV_REG_REG (code, ARMREG_R4, ARMREG_R1); - /* move flen into r5 */ - ARM_LDR_IMM (code, ARMREG_R5, ARMREG_R4, MONO_STRUCT_OFFSET (InterpMethodArguments, flen)); + /* move flen into r8 */ + ARM_LDR_IMM (code, ARMREG_R8, ARMREG_R4, MONO_STRUCT_OFFSET (InterpMethodArguments, flen)); /* load pointer to fargs into r6 */ ARM_LDR_IMM (code, ARMREG_R6, ARMREG_R4, MONO_STRUCT_OFFSET (InterpMethodArguments, fargs)); for (i = 0; i < fregs_num; ++i) { - ARM_CMP_REG_IMM (code, ARMREG_R5, 0, 0); + ARM_CMP_REG_IMM (code, ARMREG_R8, 0, 0); label_fexits [i] = code; ARM_B_COND (code, ARMCOND_EQ, 0); g_assert (i <= ARM_VFP_D7); /* otherwise, need to pass args on stack */ ARM_FLDD (code, i, ARMREG_R6, i * sizeof (double)); - ARM_SUB_REG_IMM8 (code, ARMREG_R5, ARMREG_R5, 1); + ARM_SUB_REG_IMM8 (code, ARMREG_R8, ARMREG_R8, 1); } for (i = 0; i < fregs_num; i++) arm_patch (label_fexits [i], code); - /* move ilen into r5 */ - ARM_LDR_IMM (code, ARMREG_R5, ARMREG_R4, MONO_STRUCT_OFFSET (InterpMethodArguments, ilen)); + /* move ilen into r8 */ + ARM_LDR_IMM (code, ARMREG_R8, ARMREG_R4, MONO_STRUCT_OFFSET (InterpMethodArguments, ilen)); /* load pointer to iargs into r6 */ ARM_LDR_IMM (code, ARMREG_R6, ARMREG_R4, MONO_STRUCT_OFFSET (InterpMethodArguments, iargs)); int stack_offset = 0; for (i = 0; i < gregs_num; i++) { - ARM_CMP_REG_IMM (code, ARMREG_R5, 0, 0); + ARM_CMP_REG_IMM (code, ARMREG_R8, 0, 0); label_gexits [i] = code; ARM_B_COND (code, ARMCOND_EQ, 0); @@ -914,7 +919,7 @@ mono_arch_get_enter_icall_trampoline (MonoTrampInfo **info) ARM_STR_IMM (code, ARMREG_R4, ARMREG_SP, stack_offset); stack_offset += sizeof (mgreg_t); } - ARM_SUB_REG_IMM8 (code, ARMREG_R5, ARMREG_R5, 1); + ARM_SUB_REG_IMM8 (code, ARMREG_R8, ARMREG_R8, 1); } for (i = 0; i < gregs_num; i++) @@ -930,24 +935,24 @@ mono_arch_get_enter_icall_trampoline (MonoTrampInfo **info) ARM_LDR_IMM (code, ARMREG_R4, fp_reg, off_methodargs); /* load is_float_ret */ - ARM_LDR_IMM (code, ARMREG_R5, ARMREG_R4, MONO_STRUCT_OFFSET (InterpMethodArguments, is_float_ret)); + ARM_LDR_IMM (code, ARMREG_R8, ARMREG_R4, MONO_STRUCT_OFFSET (InterpMethodArguments, is_float_ret)); /* check if a float return value is expected */ - ARM_CMP_REG_IMM (code, ARMREG_R5, 0, 0); + ARM_CMP_REG_IMM (code, ARMREG_R8, 0, 0); label_is_float_ret = code; ARM_B_COND (code, ARMCOND_NE, 0); /* greg return */ /* load retval */ - ARM_LDR_IMM (code, ARMREG_R5, ARMREG_R4, MONO_STRUCT_OFFSET (InterpMethodArguments, retval)); + ARM_LDR_IMM (code, ARMREG_R8, ARMREG_R4, MONO_STRUCT_OFFSET (InterpMethodArguments, retval)); - ARM_CMP_REG_IMM (code, ARMREG_R5, 0, 0); + ARM_CMP_REG_IMM (code, ARMREG_R8, 0, 0); label_leave_tramp [0] = code; ARM_B_COND (code, ARMCOND_EQ, 0); /* store greg result, always write back 64bit */ - ARM_STR_IMM (code, ARMREG_R0, ARMREG_R5, 0); - ARM_STR_IMM (code, ARMREG_R1, ARMREG_R5, 4); + ARM_STR_IMM (code, ARMREG_R0, ARMREG_R8, 0); + ARM_STR_IMM (code, ARMREG_R1, ARMREG_R8, 4); label_leave_tramp [1] = code; ARM_B_COND (code, ARMCOND_AL, 0); @@ -955,20 +960,22 @@ mono_arch_get_enter_icall_trampoline (MonoTrampInfo **info) /* freg return */ arm_patch (label_is_float_ret, code); /* load retval */ - ARM_LDR_IMM (code, ARMREG_R5, ARMREG_R4, MONO_STRUCT_OFFSET (InterpMethodArguments, retval)); + ARM_LDR_IMM (code, ARMREG_R8, ARMREG_R4, MONO_STRUCT_OFFSET (InterpMethodArguments, retval)); - ARM_CMP_REG_IMM (code, ARMREG_R5, 0, 0); + ARM_CMP_REG_IMM (code, ARMREG_R8, 0, 0); label_leave_tramp [2] = code; ARM_B_COND (code, ARMCOND_EQ, 0); /* store freg result */ - ARM_FSTD (code, ARM_VFP_F0, ARMREG_R5, 0); + ARM_FSTD (code, ARM_VFP_F0, ARMREG_R8, 0); for (i = 0; i < 3; i++) arm_patch (label_leave_tramp [i], code); + ARM_ADD_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, stack_space + framesize); + ARM_POP (code, (1 << ARMREG_R4) | (1 << ARMREG_R8) | (1 << ARMREG_R6)); ARM_MOV_REG_REG (code, ARMREG_SP, fp_reg); - ARM_POP (code, (1 << fp_reg) | (1 << ARMREG_PC) | (1 << ARMREG_R4) | (1 << ARMREG_R5) | (1 << ARMREG_R6)); + ARM_POP (code, (1 << fp_reg) | (1 << ARMREG_PC)); g_assert (code - start < buf_len); diff --git a/mono/mini/unaligned.cs b/mono/mini/unaligned.cs new file mode 100644 index 00000000000..397fbbb92ec --- /dev/null +++ b/mono/mini/unaligned.cs @@ -0,0 +1,307 @@ +using System; +using System.Runtime.CompilerServices; +using Mono; + +/* + * Regression tests for the mono JIT. + * + * Each test needs to be of the form: + * + * static int test__ (); + * + * where is an integer (the value that needs to be returned by + * the method to make it pass. + * is a user-displayed name used to identify the test. + * + * The tests can be driven in two ways: + * *) running the program directly: Main() uses reflection to find and invoke + * the test methods (this is useful mostly to check that the tests are correct) + * *) with the --regression switch of the jit (this is the preferred way since + * all the tests will be run with optimizations on and off) + * + * The reflection logic could be moved to a .dll since we need at least another + * regression test file written in IL code to have better control on how + * the IL code looks. + */ + +#if __MOBILE__ +namespace UnalignedTests +{ +#endif + + +class Tests { + +#if !__MOBILE__ + public static int Main (string[] args) { + return TestDriver.RunTests (typeof (Tests), args); + } +#endif + + + public static unsafe int test_0_ldobj_r4 () + { + byte *ptr = stackalloc byte [32]; + float f = (float)123.44f; + *(float*)ptr = (float)f; + + int expected = *(int*)ptr; + + Intrinsics.UnalignedStobj (ptr + 1, expected); + if (Intrinsics.UnalignedLdobj (ptr + 1) != f) + return 1; + + return 0; + } + + public static unsafe int test_0_ldobj_r8 () + { + byte *ptr = stackalloc byte [32]; + double f = 34423.44f; + *(double*)ptr = (double)f; + + long expected = *(long*)ptr; + + Intrinsics.UnalignedStobj (ptr + 3, expected); + if (Intrinsics.UnalignedLdobj (ptr + 3) != f) + return 1; + + return 0; + } + + public static unsafe int test_0_ldobj () + { + byte *ptr = stackalloc byte [20]; + for (int i = 0; i < 20; ++i) + ptr [i] = (byte)i; + + + if (Intrinsics.UnalignedLdobj (ptr + 0) != 0x0100) + return 1; + + if (Intrinsics.UnalignedLdobj (ptr + 1) != 0x0201) + return 2; + + if (Intrinsics.UnalignedLdobj (ptr + 2) != 0x0302) + return 3; + + if (Intrinsics.UnalignedLdobj (ptr + 1) != 0x04030201) + return 4; + + if (Intrinsics.UnalignedLdobj (ptr + 2) != 0x05040302) + return 5; + + if (Intrinsics.UnalignedLdobj (ptr + 1) != 0x0807060504030201) + return 6; + + if (Intrinsics.UnalignedLdobj (ptr + 6) != 0xD0C0B0A09080706) + return 7; + + return 0; + } + + public static unsafe int test_0_ldind () + { + byte *ptr = stackalloc byte [20]; + for (int i = 0; i < 20; ++i) + ptr [i] = (byte)i; + + + if (Intrinsics.UnalignedLdInd2 (ptr + 0) != 0x0100) + return 1; + + if (Intrinsics.UnalignedLdInd2 (ptr + 1) != 0x0201) + return 2; + + if (Intrinsics.UnalignedLdInd2 (ptr + 2) != 0x0302) + return 3; + + if (Intrinsics.UnalignedLdInd4 (ptr + 1) != 0x04030201) + return 4; + + if (Intrinsics.UnalignedLdInd4 (ptr + 2) != 0x05040302) + return 5; + + if (Intrinsics.UnalignedLdInd8 (ptr + 1) != 0x0807060504030201) + return 6; + + if (Intrinsics.UnalignedLdInd8 (ptr + 6) != 0xD0C0B0A09080706) + return 7; + + return 0; + } + public static unsafe int test_0_cpobj () + { + byte *dest = stackalloc byte [20]; + byte *src = stackalloc byte [20]; + for (int i = 0; i < 20; ++i) + src [i] = (byte)i; + + Intrinsics.UnalignedCpobj (dest + 0, src + 0); + if (dest [0] != src [0] || dest [1] != src [1]) + return 1; + + Intrinsics.UnalignedCpobj (dest + 1, src + 0); + if (dest [1] != src [0] || dest [2] != src [1]) + return 2; + + Intrinsics.UnalignedCpobj (dest + 0, src + 1); + if (dest [0] != src [1] || dest [1] != src [2]) + return 3; + + Intrinsics.UnalignedCpobj (dest + 1, src + 1); + if (dest [1] != src [1] || dest [2] != src [2]) + return 3; + + Intrinsics.UnalignedCpobj (dest + 3, src); + for (int i = 0; i < 4; ++i) { + if (dest [i + 3] != src [i]) + return 4; + } + + Intrinsics.UnalignedCpobj (dest + 1, src + 2); + for (int i = 0; i < 4; ++i) { + if (dest [i + 1] != src [i + 2]) + return 5; + } + + Intrinsics.UnalignedCpobj (dest + 1, src + 2); + for (int i = 0; i < 8; ++i) { + if (dest [i + 1] != src [i + 2]) + return 6; + } + + Intrinsics.UnalignedCpobj (dest + 7, src + 2); + for (int i = 0; i < 8; ++i) { + if (dest [i + 7] != src [i + 2]) + return 7; + } + + return 0; + } + + public static unsafe int test_0_stobj () + { + byte *ptr = stackalloc byte [20]; + + Intrinsics.UnalignedStobj (ptr + 0, 0x6688); + if (ptr [0] != 0x88 || ptr [1] != 0x66) + return 1; + + Intrinsics.UnalignedStobj (ptr + 1, 0x6589); + if (ptr [1] != 0x89 || ptr [2] != 0x65) + return 2; + + Intrinsics.UnalignedStobj (ptr + 1, 0x60708090); + if (ptr [1] != 0x90 || ptr [2] != 0x80 || ptr [3] != 0x70 || ptr [4] != 0x60) + return 3; + + Intrinsics.UnalignedStobj (ptr + 1, 0x405060708090); + if (ptr [1] != 0x90 || ptr [2] != 0x80 || ptr [3] != 0x70 || ptr [4] != 0x60 || ptr [5] != 0x50 || ptr [6] != 0x40) + return 4; + + return 0; + } + + public static unsafe int test_0_ldobj_stobj () + { + byte *dest = stackalloc byte [20]; + byte *src = stackalloc byte [20]; + + for (int i = 0; i < 20; ++i) + src [i] = (byte)i; + + Intrinsics.UnalignedLdobjStObjPair (dest + 0, src + 0); + if (dest [0] != src [0] || dest [1] != src [1]) + return 1; + + Intrinsics.UnalignedLdobjStObjPair (dest + 1, src + 0); + if (dest [1] != src [0] || dest [2] != src [1]) + return 2; + + Intrinsics.UnalignedLdobjStObjPair (dest + 0, src + 1); + if (dest [0] != src [1] || dest [1] != src [2]) + return 3; + + Intrinsics.UnalignedLdobjStObjPair (dest + 1, src + 1); + if (dest [1] != src [1] || dest [2] != src [2]) + return 3; + + Intrinsics.UnalignedLdobjStObjPair (dest + 1, src + 1); + if (dest [1] != src [1] || dest [2] != src [2]) + return 4; + + Intrinsics.UnalignedLdobjStObjPair (dest + 1, src + 1); + if (dest [1] != src [1] || dest [2] != src [2]) + return 5; + + + return 0; + } + + + public static unsafe int test_0_cpblk () + { + byte *dest = stackalloc byte [20]; + byte *src = stackalloc byte [20]; + for (int i = 0; i < 20; ++i) + src [i] = (byte)i; + + + Intrinsics.UnalignedCpblk (dest + 0, src + 0, 2); + if (dest [0] != src [0] || dest [1] != src [1]) + return 1; + + Intrinsics.UnalignedCpblk (dest + 1, src + 0, 2); + if (dest [1] != src [0] || dest [2] != src [1]) + return 2; + + Intrinsics.UnalignedCpblk (dest + 0, src + 1, 2); + if (dest [0] != src [1] || dest [1] != src [2]) + return 3; + + Intrinsics.UnalignedCpblk (dest + 1, src + 1, 2); + if (dest [1] != src [1] || dest [2] != src [2]) + return 3; + + Intrinsics.UnalignedCpblk (dest + 1, src + 1, 4); + for (int i = 0; i < 4; ++i) { + if (dest [i + 1] != src [i + 1]) + return 4; + } + + Intrinsics.UnalignedCpblk (dest + 1, src + 1, 8); + for (int i = 0; i < 8; ++i) { + if (dest [i + 1] != src [i + 1]) + return 5; + } + + return 0; + } + + + public static unsafe int test_0_initblk () + { + byte *ptr = stackalloc byte [20]; + + for (int i = 0; i < 20; ++i) + ptr [i] = (byte)i; + + Intrinsics.UnalignedInit (ptr, 30, 2); + if (ptr [0] != 30 || ptr [1] != 30) + return 1; + + Intrinsics.UnalignedInit (ptr + 1, 31, 2); + if (ptr[0] != 30 || ptr [1] != 31 || ptr [2] != 31) + return 2; + + return 0; + } +} + +#if __MOBILE__ +} +#endif + + + diff --git a/mono/tests/Makefile.am b/mono/tests/Makefile.am index 58b826ef15a..f4182ec0e34 100755 --- a/mono/tests/Makefile.am +++ b/mono/tests/Makefile.am @@ -463,6 +463,7 @@ TESTS_CS_SRC= \ assemblyresolve_event2.2.cs \ appdomain-unload-callback.cs \ appdomain-unload-doesnot-raise-pending-events.cs \ + appdomain-unload-asmload.cs \ unload-appdomain-on-shutdown.cs \ bug-47295.cs \ loader.cs \ diff --git a/mono/tests/appdomain-unload-asmload.cs b/mono/tests/appdomain-unload-asmload.cs new file mode 100644 index 00000000000..5f79890ca53 --- /dev/null +++ b/mono/tests/appdomain-unload-asmload.cs @@ -0,0 +1,57 @@ +using System; +using System.Threading.Tasks; + +/* This is a regression test that checks that after an AssemblyLoad event fires + * in a domain, the domain can be unloaded. In bug # 56694, a + * System.Reflection.Assembly object from the unloaded domain was kept alive + * and crashed the GC. */ +namespace AppDomainUnloadAsmLoad +{ + class Program + { + static void Main(string[] args) + { + // Need some threads in play + new Program().Run().Wait(); + } + + private async Task Run() + { + var appDomain = AppDomain.CreateDomain("Test subdomain", null, AppDomain.CurrentDomain.SetupInformation); + try + { + var driver = (AppDomainTestDriver)appDomain.CreateInstanceAndUnwrap(typeof(AppDomainTestDriver).Assembly.FullName, + typeof(AppDomainTestDriver).FullName); + driver.Test(); + } + finally + { + AppDomain.Unload(appDomain); + } + } + } + + class AppDomainTestDriver : MarshalByRefObject + { + static AppDomainTestDriver() + { + // Needs a callback so that the runtime fires the + // AssembyLoad event for this domain and materializes a System.Reflection.Assembly + AppDomain.CurrentDomain.AssemblyLoad += CurrentDomain_AssemblyLoad; + } + + private static void CurrentDomain_AssemblyLoad(object sender, AssemblyLoadEventArgs args) + { + } + + internal void Test() + { + /* this can be any class from any assembly that hasn't + * already been loaded into the test domain. + * System.Xml.dll is good because all the tests link + * against it, but it's not otherwise used by this + * domain. */ + var foo = default(System.Xml.XmlException); + } + } +} diff --git a/mono/tests/cominterop.cs b/mono/tests/cominterop.cs index cc86c7387d0..aecae40401d 100644 --- a/mono/tests/cominterop.cs +++ b/mono/tests/cominterop.cs @@ -533,6 +533,9 @@ public class Tests if (TestITestDelegate (itest) != 0) return 174; + if (TestIfaceNoIcall (itest as ITestPresSig) != 0) + return 201; + itest = new TestClass (); if (TestITest (itest) != 0) @@ -543,6 +546,7 @@ public class Tests if (TestITest (itest) != 0) return 176; + #endif #endregion // Runtime Callable Wrapper Tests @@ -775,6 +779,7 @@ public class Tests void ITestIn ([MarshalAs (UnmanagedType.Interface)]ITest val); [MethodImplAttribute (MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] void ITestOut ([MarshalAs (UnmanagedType.Interface)]out ITest val); + int Return22NoICall(); } [ComImport ()] @@ -826,6 +831,8 @@ public class Tests [MethodImplAttribute (MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] [PreserveSig ()] int ITestOut ([MarshalAs (UnmanagedType.Interface)]out ITestPresSig val); + [PreserveSig ()] + int Return22NoICall(); } [System.Runtime.InteropServices.GuidAttribute ("00000000-0000-0000-0000-000000000002")] @@ -865,6 +872,9 @@ public class Tests public virtual extern void ITestIn ([MarshalAs (UnmanagedType.Interface)]ITest val); [MethodImplAttribute (MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] public virtual extern void ITestOut ([MarshalAs (UnmanagedType.Interface)]out ITest val); + + [MethodImplAttribute (MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern int Return22NoICall(); } [System.Runtime.InteropServices.GuidAttribute ("00000000-0000-0000-0000-000000000002")] @@ -1004,6 +1014,11 @@ public class Tests val = new ManagedTestPresSig (); return 0; } + + public int Return22NoICall() + { + return 88; + } } public class ManagedTest : ITest @@ -1093,6 +1108,11 @@ public class Tests return new ManagedTest (); } } + + public int Return22NoICall() + { + return 99; + } } public static int mono_test_marshal_variant_in_callback (VarEnum vt, object obj) @@ -1306,6 +1326,10 @@ public class Tests } return 0; } + + public static int TestIfaceNoIcall (ITestPresSig itest) { + return itest.Return22NoICall () == 22 ? 0 : 1; + } } public class TestVisible diff --git a/mono/tests/libtest.c b/mono/tests/libtest.c index 4517eda2f74..b94b29d52fd 100644 --- a/mono/tests/libtest.c +++ b/mono/tests/libtest.c @@ -3337,6 +3337,7 @@ typedef struct int (STDCALL *DoubleIn)(MonoComObject* pUnk, double a); int (STDCALL *ITestIn)(MonoComObject* pUnk, MonoComObject* pUnk2); int (STDCALL *ITestOut)(MonoComObject* pUnk, MonoComObject* *ppUnk); + int (STDCALL *Return22NoICall)(MonoComObject* pUnk); } MonoIUnknown; struct MonoComObject @@ -3453,6 +3454,13 @@ ITestOut(MonoComObject* pUnk, MonoComObject* *ppUnk) return S_OK; } +LIBTEST_API int STDCALL +Return22NoICall(MonoComObject* pUnk) +{ + return 22; +} + + static void create_com_object (MonoComObject** pOut); LIBTEST_API int STDCALL @@ -3484,6 +3492,7 @@ static void create_com_object (MonoComObject** pOut) (*pOut)->vtbl->ITestIn = ITestIn; (*pOut)->vtbl->ITestOut = ITestOut; (*pOut)->vtbl->get_ITest = get_ITest; + (*pOut)->vtbl->Return22NoICall = Return22NoICall; } static MonoComObject* same_object = NULL; diff --git a/mono/unit-tests/Makefile.am b/mono/unit-tests/Makefile.am index b2c969ba0bd..ec04c4d1c5f 100644 --- a/mono/unit-tests/Makefile.am +++ b/mono/unit-tests/Makefile.am @@ -10,6 +10,7 @@ endif if !CROSS_COMPILE if !HOST_WIN32 if SUPPORT_BOEHM +if SUPPORT_SGEN noinst_LTLIBRARIES = libtestlib.la libtestlib_la_SOURCES = @@ -54,6 +55,7 @@ check-local: echo "" >> TestResult-unit-tests.xml; \ fi; +endif SUPPORT_SGEN endif SUPPORT_BOEHM endif !HOST_WIN32 endif !CROSS_COMPILE diff --git a/mono/utils/mono-proclib.c b/mono/utils/mono-proclib.c index f733896a6d7..5c5b891d607 100644 --- a/mono/utils/mono-proclib.c +++ b/mono/utils/mono-proclib.c @@ -131,11 +131,11 @@ mono_process_list (int *size) mib [2] = KERN_PROC_ALL; mib [3] = 0; - res = sysctl (mib, 4, NULL, &data_len, NULL, 0); + res = sysctl (mib, 3, NULL, &data_len, NULL, 0); if (res) return NULL; processes = (struct kinfo_proc *) g_malloc (data_len); - res = sysctl (mib, 4, processes, &data_len, NULL, 0); + res = sysctl (mib, 3, processes, &data_len, NULL, 0); if (res < 0) { g_free (processes); if (errno != ENOMEM) diff --git a/msvc/libmono-static.vcxproj b/msvc/libmono-static.vcxproj index f5449aa086c..70dc4b0554c 100644 --- a/msvc/libmono-static.vcxproj +++ b/msvc/libmono-static.vcxproj @@ -137,6 +137,7 @@ + {CB0D9E92-293C-439C-9AC7-C5F59B6E0772} @@ -334,4 +335,4 @@ - \ No newline at end of file + diff --git a/msvc/libmono-static.vcxproj.filters b/msvc/libmono-static.vcxproj.filters index 3ff24065214..029b9d162c1 100644 --- a/msvc/libmono-static.vcxproj.filters +++ b/msvc/libmono-static.vcxproj.filters @@ -157,6 +157,9 @@ Source Files + + Source Files + @@ -257,4 +260,4 @@ Resource Files - \ No newline at end of file +