diff --git a/configure.ac b/configure.ac index bdffc309a6fa..d783e536e82f 100644 --- a/configure.ac +++ b/configure.ac @@ -146,7 +146,7 @@ case "$host" in CFLAGS="$CFLAGS -D_REENTRANT -D_GNU_SOURCE -s WASM=1" CPPFLAGS="$CPPFLAGS -D_REENTRANT -DUSE_MMAP -s WASM=1" libgc_threads=pthreads - platform_wasm=yes + host_wasm=yes # FIXME: RID="osx-x64" COREARCH="wasm32" @@ -410,6 +410,13 @@ case "$host" in host_sunos=yes ;; *-*-darwin*) + # Temporary workaround for Apple Silicon + # config.guess returns arm-apple-darwin20.0.0 + if test $ac_cv_host = arm-apple-darwin20.0.0 -o $ac_cv_target = arm-apple-darwin20.0.0; then + echo "You are running on Apple Silicon, but using an old config.guess, invoke configure like this:" + echo "Run configure using ./configure --host=aarch64-apple-darwin20.0.0 --target=aarch64-apple-darwin20.0.0" + exit 1 + fi parallel_mark="Disabled_Currently_Hangs_On_MacOSX" host_darwin=yes target_mach=yes @@ -451,6 +458,10 @@ case "$host" in platform_ios=yes has_dtrace=no ;; + aarch64*-darwin20*) + # OSX/arm64 + support_boehm=no + ;; aarch64*-darwin*) platform_ios=yes ;; @@ -586,7 +597,7 @@ AM_CONDITIONAL(HOST_SIGPOSIX, test x$use_sigposix = xyes) AM_CONDITIONAL(HOST_ANDROID, test x$platform_android = xyes) AM_CONDITIONAL(HOST_TIZEN, test x$platform_tizen = xyes) AM_CONDITIONAL(HOST_IOS, test x$platform_ios = xyes) -AM_CONDITIONAL(HOST_WASM, test x$platform_wasm = xyes) +AM_CONDITIONAL(HOST_WASM, test x$host_wasm = xyes) AM_CONDITIONAL(HOST_AIX, test x$host_aix = xyes) if test -z "$HOST_DARWIN_TRUE"; then : @@ -952,16 +963,6 @@ if test x$with_core = xonly; then fi AM_CONDITIONAL(ENABLE_NETCORE, test x$with_core = xonly) -if test x$with_core = xonly; then - if test -f $srcdir/mono/eventpipe/ep.h; then - enable_perftracing=yes - fi - if test x$enable_perftracing = xyes; then - AC_DEFINE(ENABLE_PERFTRACING,1,[Enables support for eventpipe library]) - fi -fi -AM_CONDITIONAL(ENABLE_PERFTRACING, test x$enable_perftracing = xyes) - # # A sanity check to catch cases where the package was unpacked # with an ancient tar program (Solaris) @@ -1220,6 +1221,7 @@ if test "x$crash_reporting" != "xyes"; then CFLAGS="$CFLAGS -DDISABLE_CRASH_REPORTING=1" CXXFLAGS="$CXXFLAGS -DDISABLE_CRASH_REPORTING=1" fi +AM_CONDITIONAL(DISABLE_CRASH_REPORTING, test x$crash_reporting != xyes) AC_ARG_ENABLE(monodroid, [ --enable-monodroid Enable runtime support for Monodroid (Xamarin.Android)], enable_monodroid=$enableval, enable_monodroid=no) AM_CONDITIONAL(ENABLE_MONODROID, test x$enable_monodroid = xyes) @@ -1314,6 +1316,12 @@ AC_ARG_WITH(spectre-mitigation, [ --with-spectre-mitigation=yes,no AC_ARG_WITH(spectre-indirect-branch-choice, [ --with-spectre-indirect-branch-choice=keep,thunk,inline,extern Convert indirect branches to the specified kind of thunk (defaults to inline)], [], [with_spectre_indirect_branch_choice=inline]) AC_ARG_WITH(spectre-function-return-choice, [ --with-spectre-function-return-choice=keep,thunk,inline,extern Convert function return instructions to the specified kind of thunk (defaults to inline)], [], [with_spectre_function_return_choice=inline]) +AC_ARG_WITH(static_icu, [ --with-static-icu=yes|no Integrate ICU statically into the runtime (defaults to no)],[ + if test x$with_static_icu = xyes ; then + AC_DEFINE(STATIC_ICU,1,[Integrate ICU statically into the runtime.]) + fi +], [with_static_icu=no]) + dnl dnl Spectre compiler mitigation flag checks dnl @@ -1411,6 +1419,7 @@ if test x$with_runtime_preset = xnetcore; then mono_feature_disable_gac='yes' mono_feature_disable_perfcounters='yes' mono_feature_disable_attach='yes' + mono_feature_disable_cfgdir_config='yes' if test "x$enable_monodroid" = "x" -a "x$enable_monotouch" = "x"; then mono_feature_disable_dllmap='yes' # FIXME: the mobile products use this fi @@ -1701,6 +1710,7 @@ AM_CONDITIONAL(INSTALL_MONOTOUCH, [test "x$with_monotouch" != "xno"]) AM_CONDITIONAL(INSTALL_MONOTOUCH_WATCH, [test "x$with_monotouch_watch" != "xno"]) AM_CONDITIONAL(INSTALL_MONOTOUCH_TV, [test "x$with_monotouch_tv" != "xno"]) AM_CONDITIONAL(BITCODE, test "x$with_bitcode" = "xyes") +AM_CONDITIONAL(STATIC_ICU, test "x$with_static_icu" = "xyes") AM_CONDITIONAL(INSTALL_XAMMAC, [test "x$with_xammac" != "xno"]) AM_CONDITIONAL(INSTALL_TESTING_AOT_FULL_INTERP, [test "x$with_testing_aot_full_interp" != "xno"]) AM_CONDITIONAL(INSTALL_TESTING_AOT_HYBRID, [test "x$with_testing_aot_hybrid" != "xno"]) @@ -1787,9 +1797,7 @@ fi AM_CONDITIONAL(ENABLE_STATIC_GCC_LIBS, test "x$enable_static_gcc_libs" = "xyes") AC_ARG_ENABLE(minimal, [ --enable-minimal=LIST drop support for LIST subsystems. - LIST is a comma-separated list from: aot, profiler, decimal, pinvoke, debug, appdomains, verifier, dllmap, - reflection_emit, reflection_emit_save, large_code, logging, com, ssa, generics, attach, jit, interpreter, simd, soft_debug, perfcounters, normalization, desktop_loader, shared_perfcounters, remoting, - security, lldb, mdb, assert_messages, config, cfgdir_config, cleanup, sgen_marksweep_conc, sgen_split_nursery, sgen_gc_bridge, sgen_debug_helpers, sockets, gac, threads, processes.], + LIST is a comma-separated list from: aot, profiler, decimal, pinvoke, debug, appdomains, verifier, dllmap, reflection_emit, reflection_emit_save, large_code, logging, com, ssa, generics, attach, jit, interpreter, simd, soft_debug, perfcounters, normalization, desktop_loader, shared_perfcounters, remoting, security, lldb, mdb, assert_messages, config, cfgdir_config, cleanup, sgen_marksweep_conc, sgen_split_nursery, sgen_gc_bridge, sgen_toggleref, sgen_debug_helpers, sgen_binary_protocol, sockets, gac, threads, processes, eventpipe.], [ for feature in `echo "$enable_minimal" | sed -e "s/,/ /g"`; do eval "mono_feature_disable_$feature='yes'" @@ -1985,7 +1993,6 @@ if test "x$mono_feature_disable_sgen_marksweep_conc" = "xyes"; then AC_MSG_NOTICE([Disabled concurrent gc support in SGEN.]) fi - if test "x$mono_feature_disable_sgen_split_nursery" = "xyes"; then AC_DEFINE(DISABLE_SGEN_SPLIT_NURSERY, 1, [Disable minor=split support in SGEN.]) AC_MSG_NOTICE([Disabled minor=split support in SGEN.]) @@ -1996,11 +2003,21 @@ if test "x$mono_feature_disable_sgen_gc_bridge" = "xyes"; then AC_MSG_NOTICE([Disabled gc bridge support in SGEN.]) fi +if test "x$mono_feature_disable_sgen_toggleref" = "xyes"; then + AC_DEFINE(DISABLE_SGEN_TOGGLEREF, 1, [Disable toggleref support in SGEN.]) + AC_MSG_NOTICE([Disabled toggleref support in SGEN.]) +fi + if test "x$mono_feature_disable_sgen_debug_helpers" = "xyes"; then AC_DEFINE(DISABLE_SGEN_DEBUG_HELPERS, 1, [Disable debug helpers in SGEN.]) AC_MSG_NOTICE([Disabled debug helpers in SGEN.]) fi +if test "x$mono_feature_disable_sgen_binary_protocol" = "xyes"; then + AC_DEFINE(DISABLE_SGEN_BINARY_PROTOCOL, 1, [Disable binary protocol logging in SGEN.]) + AC_MSG_NOTICE([Disabled binary protocol logging in SGEN.]) +fi + if test "x$mono_feature_disable_sockets" = "xyes"; then AC_DEFINE(DISABLE_SOCKETS, 1, [Disable sockets]) AC_MSG_NOTICE([Disabled sockets]) @@ -2026,6 +2043,22 @@ if test "x$mono_feature_disable_processes" = "xyes"; then AC_MSG_NOTICE([Disabled process support]) fi +if test "x$mono_feature_disable_eventpipe" = "xyes"; then + AC_DEFINE(DISABLE_EVENTPIPE, 1, [Disable EventPipe support]) + AC_MSG_NOTICE([Disabled EventPipe support]) + enable_perftracing=no +fi + +if test x$enable_perftracing = x -a x$with_core = xonly; then + if test -f $srcdir/mono/eventpipe/ep.h; then + enable_perftracing=yes + fi +fi +if test x$enable_perftracing = xyes; then + AC_DEFINE(ENABLE_PERFTRACING,1,[Enables support for eventpipe library]) +fi +AM_CONDITIONAL(ENABLE_PERFTRACING, test x$enable_perftracing = xyes) + AC_ARG_ENABLE(executables, [ --disable-executables disable the build of the runtime executables], enable_executables=$enableval, enable_executables=yes) AM_CONDITIONAL(DISABLE_EXECUTABLES, test x$enable_executables = xno) @@ -2796,7 +2829,7 @@ if test x$host_win32 = xno; then AC_CHECK_HEADERS(pthread_np.h) AC_CHECK_FUNCS(pthread_mutex_timedlock) AC_CHECK_FUNCS(pthread_getattr_np pthread_attr_get_np pthread_getname_np pthread_setname_np pthread_cond_timedwait_relative_np) - AC_CHECK_FUNCS(pthread_kill) + AC_CHECK_FUNCS(pthread_kill pthread_jit_write_protect_np) AC_MSG_CHECKING(for PTHREAD_MUTEX_RECURSIVE) AC_TRY_COMPILE([ #include ], [ pthread_mutexattr_t attr; @@ -4654,7 +4687,7 @@ case "$host" in ACCESS_UNALIGNED="yes" BTLS_SUPPORTED=yes BTLS_PLATFORM=s390x - CFLAGS="$CFLAGS -mbackchain -D__USE_STRING_INLINES" + CFLAGS="$CFLAGS -mbackchain" ;; riscv32-*) TARGET=RISCV32 @@ -4753,6 +4786,12 @@ if test "x$host" != "x$target"; then sizeof_register=8 AC_DEFINE(TARGET_WATCHOS, 1, [...]) ;; + aarch64*darwin*) + TARGET=ARM64 + # Both ios and osx/arm64 have the same aarc64-darwin triple, + # assume ios for now when cross compiling + TARGET_SYS=IOS + ;; aarch64-*) TARGET=ARM64 ;; @@ -4965,7 +5004,7 @@ if test "x$target_mach" = "xyes"; then CPPFLAGS_FOR_LIBGC="$CPPFLAGS_FOR_LIBGC -DTARGET_WATCHOS" CFLAGS_FOR_LIBGC="$CFLAGS_FOR_LIBGC -DTARGET_WATCHOS" BTLS_SUPPORTED=no - elif test "x$TARGET" = "xARM" -o "x$TARGET" = "xARM64" -o "x$TARGET" = "xARM6432"; then + elif test "x$TARGET_SYS" = "xIOS" -o "x$TARGET" = "xARM" -o "x$TARGET" = "xARM6432"; then AC_DEFINE(TARGET_IOS,1,[The JIT/AOT targets iOS]) CPPFLAGS_FOR_LIBGC="$CPPFLAGS_FOR_LIBGC -DTARGET_IOS" CFLAGS_FOR_LIBGC="$CFLAGS_FOR_LIBGC -DTARGET_IOS" @@ -4981,6 +5020,9 @@ if test "x$target_mach" = "xyes"; then CPPFLAGS_FOR_LIBGC="$CPPFLAGS_FOR_LIBGC -DTARGET_OSX" CFLAGS_FOR_LIBGC="$CFLAGS_FOR_LIBGC -DTARGET_OSX" target_osx=yes + if test "x$TARGET" = "xARM64"; then + BTLS_SUPPORTED=no + fi ], [ AC_DEFINE(TARGET_IOS,1,[The JIT/AOT targets iOS]) CPPFLAGS_FOR_LIBGC="$CPPFLAGS_FOR_LIBGC -DTARGET_IOS" @@ -6769,8 +6811,10 @@ AC_SUBST(MONO_NATIVE_PLATFORM_TYPE_UNIFIED) # if test "x$enable_llvm_runtime" = "xyes"; then AC_SUBST(MONO_CXXLD, [$CXX]) + AC_SUBST(MONO_LIBTOOL_TAG, '--tag=CXX') else AC_SUBST(MONO_CXXLD, [$CC]) + AC_SUBST(MONO_LIBTOOL_TAG, '') fi ### Set -Werror options @@ -6841,7 +6885,10 @@ if test x$with_core = xonly; then fi if test x$have_shim_globalization = xyes || test x$cross_compiling = xyes; then ICU_SHIM_PATH=../../../libraries/Native/Unix/System.Globalization.Native - if test x$target_osx = xyes; then + if test x$target_wasm = xyes && test x$with_static_icu = xyes; then + ICU_CFLAGS="-DTARGET_UNIX -DU_DISABLE_RENAMING -DHAVE_UDAT_STANDALONE_SHORTER_WEEKDAYS -DHAVE_SET_MAX_VARIABLE" + have_sys_icu=yes + elif test x$target_osx = xyes; then ORIG_CPPFLAGS=$CPPFLAGS # adding icu path to pkg_config_path PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig:/usr/local/opt/icu4c/lib/pkgconfig @@ -6869,6 +6916,9 @@ if test x$with_core = xonly; then elif test x$host_sunos = xyes; then ICU_CFLAGS="-DPALEXPORT="" -DTARGET_UNIX -Wno-reserved-id-macro -Wno-documentation -Wno-documentation-unknown-command -Wno-switch-enum -Wno-covered-switch-default -Wno-extra-semi-stmt -Wno-unknown-warning-option" have_sys_icu=yes + elif test x$host_wasm = xyes; then + ICU_CFLAGS="-DPALEXPORT="" -DTARGET_UNIX -Wno-reserved-id-macro -Wno-documentation -Wno-documentation-unknown-command -Wno-switch-enum -Wno-covered-switch-default -Wno-covered-switch-default -Wno-extra-semi-stmt -Wno-unknown-warning-option" + have_sys_icu=yes else GLOBALIZATION_SHIM_DEFINES="-DNO_GLOBALIZATION_SHIM" fi diff --git a/docs/README b/docs/README index 862cd45ae0ae..3a4f3b346921 100644 --- a/docs/README +++ b/docs/README @@ -22,7 +22,7 @@ Layout as well as the upcoming Monodoc tools and index creation tools). - The files can contain any ammount of extra information. + The files can contain any amount of extra information. The documentation from the source code is then merged with these files and the header/footer information to produce diff --git a/external/bockbuild b/external/bockbuild index ea787cd31b2b..93607d34adb7 160000 --- a/external/bockbuild +++ b/external/bockbuild @@ -1 +1 @@ -Subproject commit ea787cd31b2b5ecde01d51ff2c6d8ac24808e45a +Subproject commit 93607d34adb7b4561ada0dfad9ebb87f262ca9e6 diff --git a/external/ikvm b/external/ikvm index 8362227c5ba8..26d148421cef 160000 --- a/external/ikvm +++ b/external/ikvm @@ -1 +1 @@ -Subproject commit 8362227c5ba876d9ab3bcd765ca9e1921b2dafa0 +Subproject commit 26d148421cefd47aaeb5b1f408e6fc60e00d981b diff --git a/external/roslyn-binaries b/external/roslyn-binaries index 77eda77b706a..04556aa2c2fb 160000 --- a/external/roslyn-binaries +++ b/external/roslyn-binaries @@ -1 +1 @@ -Subproject commit 77eda77b706a109935a2f56cd4b0800bb95735c7 +Subproject commit 04556aa2c2fb82bf5d2ce3b59f284f97bf20626b diff --git a/mcs/class/System.Transactions/System.Transactions/Transaction.cs b/mcs/class/System.Transactions/System.Transactions/Transaction.cs index e1de05591ce2..462a0f9bf744 100644 --- a/mcs/class/System.Transactions/System.Transactions/Transaction.cs +++ b/mcs/class/System.Transactions/System.Transactions/Transaction.cs @@ -23,6 +23,8 @@ public class Transaction : IDisposable, ISerializable [ThreadStatic] static Transaction ambient; + Transaction internalTransaction; + IsolationLevel level; TransactionInformation info; @@ -83,6 +85,8 @@ internal Transaction (Transaction other) volatiles = other.Volatiles; durables = other.Durables; pspe = other.Pspe; + TransactionCompletedInternal = other.TransactionCompletedInternal; + internalTransaction = other; } [MonoTODO] @@ -92,7 +96,29 @@ void ISerializable.GetObjectData (SerializationInfo info, throw new NotImplementedException (); } - public event TransactionCompletedEventHandler TransactionCompleted; + internal event TransactionCompletedEventHandler TransactionCompletedInternal; + + // Transaction B was cloned from transaction A. Add event handlers to A + // when they are added to B. This will not work when new handlers are added to A + // as A has no reference to B. + public event TransactionCompletedEventHandler TransactionCompleted + { + add + { + if (this.internalTransaction != null) + this.internalTransaction.TransactionCompleted += value; + + TransactionCompletedInternal += value; + } + + remove + { + if (this.internalTransaction != null) + this.internalTransaction.TransactionCompleted -= value; + + TransactionCompletedInternal -= value; + } + } public static Transaction Current { get { @@ -378,7 +404,7 @@ internal void CommitInternal () private void DoCommit () { /* Scope becomes null in TransactionScope.Dispose */ - if (Scope != null) { + if (Scope != null && (!Scope.IsComplete || !Scope.IsDisposed)) { /* See test ExplicitTransaction8 */ Rollback (null, null); CheckAborted (); @@ -529,14 +555,14 @@ void DoSingleCommit (IPromotableSinglePhaseNotification single) void CheckAborted () { - if (aborted) + if (aborted || (Scope != null && Scope.IsAborted)) throw new TransactionAbortedException ("Transaction has aborted", innerException); } void FireCompleted () { - if (TransactionCompleted != null) - TransactionCompleted (this, new TransactionEventArgs(this)); + if (TransactionCompletedInternal != null) + TransactionCompletedInternal (this, new TransactionEventArgs(this)); } static void EnsureIncompleteCurrentScope () @@ -548,4 +574,3 @@ static void EnsureIncompleteCurrentScope () } } } - diff --git a/mcs/class/System.Transactions/System.Transactions/TransactionScope.cs b/mcs/class/System.Transactions/System.Transactions/TransactionScope.cs index 503a4b6b9d9d..9cb38a710bed 100644 --- a/mcs/class/System.Transactions/System.Transactions/TransactionScope.cs +++ b/mcs/class/System.Transactions/System.Transactions/TransactionScope.cs @@ -9,6 +9,7 @@ // (C)2006 Novell Inc, // +using System.Threading; using DTCOption = System.Transactions.EnterpriseServicesInteropOption; @@ -19,6 +20,7 @@ public sealed class TransactionScope : IDisposable static TransactionOptions defaultOptions = new TransactionOptions (0, TransactionManager.DefaultTimeout); + Timer scopeTimer; Transaction transaction; Transaction oldTransaction; TransactionScope parentScope; @@ -29,6 +31,7 @@ public sealed class TransactionScope : IDisposable bool disposed; bool completed; + bool aborted; bool isRoot; bool asyncFlowEnabled; @@ -99,7 +102,7 @@ public TransactionScope (TransactionScopeOption scopeOption, DTCOption interopOption) { Initialize (scopeOption, null, transactionOptions, interopOption, - TransactionManager.DefaultTimeout, TransactionScopeAsyncFlowOption.Suppress); + transactionOptions.Timeout, TransactionScopeAsyncFlowOption.Suppress); } public TransactionScope (Transaction transactionToUse, @@ -143,8 +146,35 @@ void Initialize (TransactionScopeOption scopeOption, transaction.InitScope (this); if (parentScope != null) parentScope.nested ++; + if (timeout != TimeSpan.Zero) + scopeTimer = new Timer (TransactionScope.TimerCallback, this, scopeTimeout, TimeSpan.Zero); } + private static void TimerCallback (object state) + { + TransactionScope scope = state as TransactionScope; + if (null == scope) + { + throw new TransactionException ("TransactionScopeTimerObjectInvalid", null); + } + + scope.TimeoutScope (); + } + + private void TimeoutScope() + { + if (!completed && transaction != null) + { + try + { + this.transaction.Rollback (); + this.aborted = true; + } + catch (ObjectDisposedException ex) { } + catch (TransactionException txEx) { } + } + } + Transaction InitTransaction (Transaction tx, TransactionScopeOption scopeOption, TransactionOptions options) { if (tx != null) @@ -181,6 +211,14 @@ public void Complete () completed = true; } + internal bool IsAborted { + get { return aborted; } + } + + internal bool IsDisposed { + get { return disposed; } + } + internal bool IsComplete { get { return completed; } } @@ -214,6 +252,9 @@ public void Dispose () throw new InvalidOperationException ("Transaction.Current has changed inside of the TransactionScope"); } + if (scopeTimer != null) + scopeTimer.Dispose(); + if (asyncFlowEnabled) { if (oldTransaction != null) oldTransaction.Scope = parentScope; @@ -229,7 +270,10 @@ public void Dispose () transaction.Scope = null; - if (!IsComplete) { + if (IsAborted) { + throw new TransactionAbortedException("Transaction has aborted"); + } + else if (!IsComplete) { transaction.Rollback (); variedTransaction.Rollback(); return; @@ -251,9 +295,11 @@ public void Dispose () /* scope was not in a transaction, (Suppress) */ return; - transaction.Scope = null; - - if (!IsComplete) + if (IsAborted) { + transaction.Scope = null; + throw new TransactionAbortedException("Transaction has aborted"); + } + else if (!IsComplete) { transaction.Rollback(); return; @@ -265,10 +311,10 @@ public void Dispose () transaction.CommitInternal(); + transaction.Scope = null; } } } } - diff --git a/mcs/class/System.Transactions/Test/TransactionScopeTest.cs b/mcs/class/System.Transactions/Test/TransactionScopeTest.cs index a741fcf4775f..34e912c94fef 100644 --- a/mcs/class/System.Transactions/Test/TransactionScopeTest.cs +++ b/mcs/class/System.Transactions/Test/TransactionScopeTest.cs @@ -11,6 +11,7 @@ using System; using NUnit.Framework; using System.Transactions; +using System.Threading; namespace MonoTests.System.Transactions { @@ -1114,6 +1115,18 @@ public void ExplicitIsolationLevel() Assert.AreEqual(IsolationLevel.ReadCommitted, Transaction.Current.IsolationLevel); } } + + [Test] + [ExpectedException(typeof(TransactionAbortedException))] + public void TransactionScopeTimeout() + { + Assert.IsNull(Transaction.Current, "Ambient transaction exists (before)"); + using (var ts = new TransactionScope(TransactionScopeOption.Required, TimeSpan.FromMilliseconds(1))) + { + Thread.Sleep(100); + ts.Complete(); + } + } } } diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/Line.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/Line.cs index 7e0213be860c..c0b5072a9ca8 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/Line.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/Line.cs @@ -719,7 +719,7 @@ internal bool RecalculateLine (Graphics g, Document doc) if (doc.Wrap) { // FIXME: Technically there are multiple no-break spaces, not just the main one. - if ((Char.IsWhiteSpace (c) && c != '\u00A0') || c == '-' || c == '\u2013' || c == '\u2014') { + if (wrap_pos <= pos && ((Char.IsWhiteSpace (c) && c != '\u00A0') || c == '-' || c == '\u2013' || c == '\u2014')) { // Primarily break on dashes or whitespace other than a no-break space. prev_wrap_pos = wrap_pos; if (c == '\t') { @@ -738,11 +738,15 @@ internal bool RecalculateLine (Graphics g, Document doc) if (Char.IsWhiteSpace (c)) { if (wrap_pos > pos) { while (wrap_pos < text.Length && Char.IsWhiteSpace (text [wrap_pos]) && text [wrap_pos] != '\t') { + // Leave whitespace other than tabs on the end of this line. wrap_pos++; } pos++; wrapped = true; - // don't try pulling more into this line, but keep looping to deal with the rest of the widths and tags + // don't try pulling more into this line, but keep looping to deal with the rest of the widths and tags that will be left on the line + } else { + // At the wrap position, so split the line. c is a tab. + split_tag = tag; } } else { if (wrap_pos > pos && pos > 0) { diff --git a/mcs/jay/skeleton.cs b/mcs/jay/skeleton.cs index dda3811bdbe6..eab249ba058b 100644 --- a/mcs/jay/skeleton.cs +++ b/mcs/jay/skeleton.cs @@ -92,7 +92,7 @@ . protected string[] yyExpecting (int state) { . int [] tokens = yyExpectingTokens (state); . string [] result = new string[tokens.Length]; . for (int n = 0; n < tokens.Length; n++) -. result[n++] = yyNames[tokens [n]]; +. result[n] = yyNames[tokens [n]]; . return result; . } . diff --git a/mcs/tools/linker/monodroid-linked-size.csv b/mcs/tools/linker/monodroid-linked-size.csv index 20c3076912c6..0686e50a0941 100644 --- a/mcs/tools/linker/monodroid-linked-size.csv +++ b/mcs/tools/linker/monodroid-linked-size.csv @@ -1,24 +1,24 @@ App,mscorlib.dll,System.dll,System.Core.dll,System.Xml.dll,I18N.CJK.dll,I18N.MidEast.dll,I18N.Other.dll,I18N.Rare.dll,I18N.West.dll,I18N.dll,Microsoft.CSharp.dll,System.ComponentModel.Composition.dll,System.ComponentModel.DataAnnotations.dll,System.Data.DataSetExtensions.dll,System.Data.Services.Client.dll,System.Data.dll,System.IO.Compression.FileSystem.dll,System.IO.Compression.dll,System.IdentityModel.dll,System.Json.dll,System.Net.Http.WinHttpHandler.dll,System.Net.Http.dll,System.Net.dll,System.Numerics.Vectors.dll,System.Numerics.dll,System.Reflection.Context.dll,System.Runtime.CompilerServices.Unsafe.dll,System.Runtime.Serialization.dll,System.Security.dll,System.ServiceModel.Internals.dll,System.ServiceModel.Web.dll,System.ServiceModel.dll,System.Transactions.dll,System.Web.Services.dll,System.Windows.dll,System.Xml.Linq.dll,System.Xml.Serialization.dll -System.Core/test-plinq-01.exe,1564160,12800,63488,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -System.Core/test-queryable-01.exe,1889280,14336,385536,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -System.Core/test-queryable-02.exe,1889280,14336,385536,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -System.Net.Http/test-handler-01.exe,1891328,101376,27136,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10752,0,0,25600,0,0,0,0,0,0,0,0,0,0,0,0 -System/test-security.exe,1885184,71168,27136,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,25600,0,0,0,0,0,0,0,0,0,0,0,0 +System.Core/test-plinq-01.exe,1563648,12800,63488,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +System.Core/test-queryable-01.exe,1888768,14336,385536,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +System.Core/test-queryable-02.exe,1888768,14336,385536,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +System.Net.Http/test-handler-01.exe,1890816,101376,27136,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10752,0,0,25600,0,0,0,0,0,0,0,0,0,0,0,0 +System/test-security.exe,1884672,71168,27136,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,25600,0,0,0,0,0,0,0,0,0,0,0,0 System/test-typeconverter.exe,1589760,81408,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -mscorlib/test-array.exe,1557504,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -mscorlib/test-calendar-01.exe,1557504,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -mscorlib/test-calendar-02.exe,1557504,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +mscorlib/test-array.exe,1556992,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +mscorlib/test-calendar-01.exe,1556992,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +mscorlib/test-calendar-02.exe,1556992,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 mscorlib/test-crypto-01.exe,1747968,13824,24576,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -mscorlib/test-exception-01.exe,1557504,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +mscorlib/test-exception-01.exe,1556992,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 mscorlib/test-locale-01.exe,1559040,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -mscorlib/test-methodimpl-01.exe,1557504,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -mscorlib/test-reflection-01.exe,1557504,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -mscorlib/test-reflection-02.exe,1567232,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +mscorlib/test-methodimpl-01.exe,1556992,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +mscorlib/test-reflection-01.exe,1556992,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +mscorlib/test-reflection-02.exe,1566720,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 mscorlib/test-reflection-03.exe,1558016,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 mscorlib/test-reflection-04.exe,1566720,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -mscorlib/test-reflection.exe,1852928,13824,24576,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -mscorlib/test-remoting.exe,1557504,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -mscorlib/test-string-01.exe,1557504,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -mscorlib/test-string-02.exe,1557504,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +mscorlib/test-reflection.exe,1852416,13824,24576,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +mscorlib/test-remoting.exe,1556992,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +mscorlib/test-string-01.exe,1556992,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +mscorlib/test-string-02.exe,1556992,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 mscorlib/test-string-03.exe,1557504,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 mscorlib/test-task-01.exe,1561088,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 diff --git a/mcs/tools/linker/monotouch-linked-size.csv b/mcs/tools/linker/monotouch-linked-size.csv index c81db2bfd63f..fe94d0b81b79 100644 --- a/mcs/tools/linker/monotouch-linked-size.csv +++ b/mcs/tools/linker/monotouch-linked-size.csv @@ -1,19 +1,19 @@ App,mscorlib.dll,System.dll,System.Core.dll,System.Xml.dll,I18N.CJK.dll,I18N.MidEast.dll,I18N.Other.dll,I18N.Rare.dll,I18N.West.dll,I18N.dll,Microsoft.CSharp.dll,System.ComponentModel.Composition.dll,System.ComponentModel.DataAnnotations.dll,System.Data.DataSetExtensions.dll,System.Data.Services.Client.dll,System.Data.dll,System.IO.Compression.FileSystem.dll,System.IO.Compression.dll,System.IdentityModel.dll,System.Json.dll,System.Net.Http.WinHttpHandler.dll,System.Net.Http.dll,System.Net.dll,System.Numerics.Vectors.dll,System.Numerics.dll,System.Reflection.Context.dll,System.Runtime.CompilerServices.Unsafe.dll,System.Runtime.Serialization.dll,System.Security.dll,System.ServiceModel.Internals.dll,System.ServiceModel.Web.dll,System.ServiceModel.dll,System.Transactions.dll,System.Web.Services.dll,System.Windows.dll,System.Xml.Linq.dll,System.Xml.Serialization.dll -Newtonsoft.Json.Test/bin/iPhoneSimulator/Release/Newtonsoft.Json.Test.exe,1824768,720384,369152,421376,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,35840,0,0,0,0,0,0,0,0,0,0,30720,0 +Newtonsoft.Json.Test/bin/iPhoneSimulator/Release/Newtonsoft.Json.Test.exe,1824256,720384,369152,420864,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,35840,0,0,0,0,0,0,0,0,0,0,30720,0 System.Core/test-plinq-01.exe,942080,13824,60928,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -System.Net.Http/test-handler-01.exe,1392128,86016,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10240,0,0,25600,0,0,0,0,0,0,0,0,0,0,0,0 -System/test-security.exe,1384960,64000,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,25600,0,0,0,0,0,0,0,0,0,0,0,0 +System.Net.Http/test-handler-01.exe,1391616,86016,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10240,0,0,25600,0,0,0,0,0,0,0,0,0,0,0,0 +System/test-security.exe,1384448,64000,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,25600,0,0,0,0,0,0,0,0,0,0,0,0 System/test-typeconverter.exe,1033728,80384,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 mscorlib/test-array.exe,874496,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 mscorlib/test-calendar-01.exe,874496,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 mscorlib/test-calendar-02.exe,874496,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 mscorlib/test-crypto-01.exe,875008,0,4608,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 mscorlib/test-exception-01.exe,874496,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -mscorlib/test-locale-01.exe,878592,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +mscorlib/test-locale-01.exe,878080,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 mscorlib/test-methodimpl-01.exe,874496,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 mscorlib/test-reflection-01.exe,874496,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -mscorlib/test-reflection-02.exe,886784,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -mscorlib/test-reflection-03.exe,997376,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +mscorlib/test-reflection-02.exe,886272,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +mscorlib/test-reflection-03.exe,996864,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 mscorlib/test-reflection-04.exe,886272,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 mscorlib/test-string-01.exe,874496,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 mscorlib/test-string-02.exe,875008,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 diff --git a/mcs/tools/linker/net_4_x-linked-size.csv b/mcs/tools/linker/net_4_x-linked-size.csv index 35301f9a5bd5..176e6b5ce4ad 100644 --- a/mcs/tools/linker/net_4_x-linked-size.csv +++ b/mcs/tools/linker/net_4_x-linked-size.csv @@ -1,23 +1,23 @@ App,mscorlib.dll,System.dll,System.Core.dll,System.Xml.dll,I18N.CJK.dll,I18N.MidEast.dll,I18N.Other.dll,I18N.Rare.dll,I18N.West.dll,I18N.dll,Microsoft.Build.Engine.dll,Microsoft.Build.Framework.dll,Microsoft.Build.Tasks.v4.0.dll,Microsoft.Build.Utilities.v4.0.dll,Microsoft.Build.dll,Microsoft.CSharp.dll,Microsoft.VisualC.dll,Microsoft.Web.Infrastructure.dll,System.ComponentModel.Composition.dll,System.ComponentModel.DataAnnotations.dll,System.Configuration.Install.dll,System.Configuration.dll,System.Data.DataSetExtensions.dll,System.Data.Entity.dll,System.Data.Linq.dll,System.Data.OracleClient.dll,System.Data.Services.Client.dll,System.Data.Services.dll,System.Data.dll,System.Deployment.dll,System.Design.dll,System.DirectoryServices.Protocols.dll,System.DirectoryServices.dll,System.Drawing.Design.dll,System.Drawing.dll,System.Dynamic.dll,System.EnterpriseServices.dll,System.IO.Compression.FileSystem.dll,System.IO.Compression.dll,System.IdentityModel.Selectors.dll,System.IdentityModel.dll,System.Json.Microsoft.dll,System.Json.dll,System.Management.dll,System.Messaging.dll,System.Net.Http.Formatting.dll,System.Net.Http.WebRequest.dll,System.Net.Http.dll,System.Net.dll,System.Numerics.Vectors.dll,System.Numerics.dll,System.Reactive.Core.dll,System.Reactive.Debugger.dll,System.Reactive.Experimental.dll,System.Reactive.Interfaces.dll,System.Reactive.Linq.dll,System.Reactive.Observable.Aliases.dll,System.Reactive.PlatformServices.dll,System.Reactive.Providers.dll,System.Reactive.Runtime.Remoting.dll,System.Reactive.Windows.Forms.dll,System.Reactive.Windows.Threading.dll,System.Reflection.Context.dll,System.Runtime.Caching.dll,System.Runtime.CompilerServices.Unsafe.dll,System.Runtime.DurableInstancing.dll,System.Runtime.Remoting.dll,System.Runtime.Serialization.Formatters.Soap.dll,System.Runtime.Serialization.dll,System.Security.dll,System.ServiceModel.Activation.dll,System.ServiceModel.Discovery.dll,System.ServiceModel.Internals.dll,System.ServiceModel.Routing.dll,System.ServiceModel.Web.dll,System.ServiceModel.dll,System.ServiceProcess.dll,System.Threading.Tasks.Dataflow.dll,System.Transactions.dll,System.Web.Abstractions.dll,System.Web.ApplicationServices.dll,System.Web.DynamicData.dll,System.Web.Extensions.Design.dll,System.Web.Extensions.dll,System.Web.Http.SelfHost.dll,System.Web.Http.WebHost.dll,System.Web.Http.dll,System.Web.Mobile.dll,System.Web.Mvc.dll,System.Web.Razor.dll,System.Web.RegularExpressions.dll,System.Web.Routing.dll,System.Web.Services.dll,System.Web.WebPages.Deployment.dll,System.Web.WebPages.Razor.dll,System.Web.WebPages.dll,System.Web.dll,System.Windows.Forms.DataVisualization.dll,System.Windows.Forms.dll,System.Windows.dll,System.Workflow.Activities.dll,System.Workflow.ComponentModel.dll,System.Workflow.Runtime.dll,System.Xaml.dll,System.Xml.Linq.dll,System.Xml.Serialization.dll -Newtonsoft.Json.Test/bin/Release/Newtonsoft.Json.Test.exe,2366976,1025024,346112,1319424,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,56832,0,0,0,0,0,0,622080,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36864,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6144,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,35840,0 -System.Core/test-plinq-01.exe,1563136,67072,63488,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -System.Core/test-queryable-01.exe,1980416,62464,365056,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -System.Core/test-queryable-02.exe,1980416,62464,365568,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -System/test-security.exe,2152960,842240,7168,694272,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,51712,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,25600,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -System/test-typeconverter.exe,1579008,136704,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -mscorlib/test-array.exe,1556480,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -mscorlib/test-calendar-01.exe,1556480,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -mscorlib/test-calendar-02.exe,1556480,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -mscorlib/test-exception-01.exe,1556480,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +Newtonsoft.Json.Test/bin/Release/Newtonsoft.Json.Test.exe,2366464,1024512,346112,1319424,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,56832,0,0,0,0,0,0,622080,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36864,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6144,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,35840,0 +System.Core/test-plinq-01.exe,1562624,67072,63488,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +System.Core/test-queryable-01.exe,1979904,62464,365056,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +System.Core/test-queryable-02.exe,1979904,62464,365568,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +System/test-security.exe,2152448,841728,7168,694272,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,51712,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,25600,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +System/test-typeconverter.exe,1578496,136704,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +mscorlib/test-array.exe,1555968,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +mscorlib/test-calendar-01.exe,1555968,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +mscorlib/test-calendar-02.exe,1555968,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +mscorlib/test-exception-01.exe,1555968,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 mscorlib/test-locale-01.exe,1558528,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -mscorlib/test-methodimpl-01.exe,1556480,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -mscorlib/test-reflection-01.exe,1556480,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -mscorlib/test-reflection-02.exe,1566208,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -mscorlib/test-reflection-03.exe,1658368,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +mscorlib/test-methodimpl-01.exe,1555968,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +mscorlib/test-reflection-01.exe,1555968,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +mscorlib/test-reflection-02.exe,1565696,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +mscorlib/test-reflection-03.exe,1657856,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 mscorlib/test-reflection-04.exe,1565696,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -mscorlib/test-reflection.exe,1943552,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -mscorlib/test-remoting.exe,1556480,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -mscorlib/test-string-01.exe,1556480,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -mscorlib/test-string-02.exe,1556480,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -mscorlib/test-string-03.exe,1561088,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -mscorlib/test-task-01.exe,1560576,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +mscorlib/test-reflection.exe,1943040,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +mscorlib/test-remoting.exe,1555968,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +mscorlib/test-string-01.exe,1555968,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +mscorlib/test-string-02.exe,1555968,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +mscorlib/test-string-03.exe,1560576,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +mscorlib/test-task-01.exe,1560064,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 diff --git a/mcs/tools/linker/wasm-linked-size.csv b/mcs/tools/linker/wasm-linked-size.csv index 9a7e75c9d83a..676e6ca80773 100644 --- a/mcs/tools/linker/wasm-linked-size.csv +++ b/mcs/tools/linker/wasm-linked-size.csv @@ -1,24 +1,24 @@ App,mscorlib.dll,System.dll,System.Core.dll,System.Xml.dll,I18N.CJK.dll,I18N.MidEast.dll,I18N.Other.dll,I18N.Rare.dll,I18N.West.dll,I18N.dll,Microsoft.CSharp.dll,System.ComponentModel.Composition.dll,System.ComponentModel.DataAnnotations.dll,System.Data.DataSetExtensions.dll,System.Data.dll,System.IO.Compression.FileSystem.dll,System.IO.Compression.dll,System.Net.Http.dll,System.Numerics.Vectors.dll,System.Numerics.dll,System.Runtime.CompilerServices.Unsafe.dll,System.Runtime.Serialization.dll,System.Security.dll,System.ServiceModel.Internals.dll,System.Transactions.dll,System.Xml.Linq.dll -BlazingPizza.Client/bin/Release/netstandard2.0/BlazingPizza.Client.dll,1122304,67072,286208,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8704,0,0,3072,0,0,0,0,0 -HelloWorld/bin/Release/netstandard2.0/dist/_framework/_bin/HelloWorld.dll,1110016,67072,284672,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8704,0,0,0,0,0,0,0,0 -Microsoft.AspNetCore.Blazor.E2EPerformance/bin/Release/netstandard2.0/Microsoft.AspNetCore.Blazor.E2EPerformance.dll,1155584,68608,286208,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8704,0,0,0,0,0,0,0,0 -Newtonsoft/bin/Release/netstandard2.0/dist/_framework/_bin/Newtonsoft.dll,1110016,67072,284672,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8704,0,0,0,0,0,0,0,0 -System.Core/test-plinq-01.exe,535040,12288,60928,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -System.Net.Http/test-handler-01.exe,713216,38400,7168,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6656,0,0,0,0,0,0,0,0 -System/test-security.exe,1039360,60416,26624,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,25600,0,0,0,0,0,0 -System/test-typeconverter.exe,648704,78848,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -mscorlib/test-array.exe,450560,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -mscorlib/test-calendar-01.exe,450560,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -mscorlib/test-calendar-02.exe,450560,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -mscorlib/test-crypto-01.exe,833024,11776,24576,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -mscorlib/test-exception-01.exe,450560,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -mscorlib/test-locale-01.exe,458752,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -mscorlib/test-methodimpl-01.exe,450560,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -mscorlib/test-reflection-01.exe,450560,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -mscorlib/test-reflection-02.exe,462336,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -mscorlib/test-reflection-03.exe,599040,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -mscorlib/test-reflection-04.exe,461824,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -mscorlib/test-string-01.exe,450560,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -mscorlib/test-string-02.exe,450560,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -mscorlib/test-string-03.exe,466944,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -mscorlib/test-task-01.exe,532992,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +BlazingPizza.Client/bin/Release/netstandard2.0/BlazingPizza.Client.dll,1491968,67072,286208,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8704,0,0,3072,0,0,0,0,0 +HelloWorld/bin/Release/netstandard2.0/dist/_framework/_bin/HelloWorld.dll,1479680,67072,284672,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8704,0,0,0,0,0,0,0,0 +Microsoft.AspNetCore.Blazor.E2EPerformance/bin/Release/netstandard2.0/Microsoft.AspNetCore.Blazor.E2EPerformance.dll,1529856,68608,286208,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8704,0,0,0,0,0,0,0,0 +Newtonsoft/bin/Release/netstandard2.0/dist/_framework/_bin/Newtonsoft.dll,1479680,67072,284672,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8704,0,0,0,0,0,0,0,0 +System.Core/test-plinq-01.exe,975360,12288,60928,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +System.Net.Http/test-handler-01.exe,1085440,38400,7168,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6656,0,0,0,0,0,0,0,0 +System/test-security.exe,1414144,60416,26624,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,25600,0,0,0,0,0,0 +System/test-typeconverter.exe,1135104,78848,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +mscorlib/test-array.exe,969216,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +mscorlib/test-calendar-01.exe,969216,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +mscorlib/test-calendar-02.exe,969216,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +mscorlib/test-crypto-01.exe,1210880,11776,24576,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +mscorlib/test-exception-01.exe,969216,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +mscorlib/test-locale-01.exe,971264,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +mscorlib/test-methodimpl-01.exe,969216,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +mscorlib/test-reflection-01.exe,969216,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +mscorlib/test-reflection-02.exe,980480,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +mscorlib/test-reflection-03.exe,990208,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +mscorlib/test-reflection-04.exe,979968,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +mscorlib/test-string-01.exe,969216,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +mscorlib/test-string-02.exe,969216,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +mscorlib/test-string-03.exe,977920,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +mscorlib/test-task-01.exe,972800,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 diff --git a/mcs/tools/wasm-tuner/InterpToNativeGenerator.cs b/mcs/tools/wasm-tuner/InterpToNativeGenerator.cs index e110dd9b27c0..d3381ba8e99d 100644 --- a/mcs/tools/wasm-tuner/InterpToNativeGenerator.cs +++ b/mcs/tools/wasm-tuner/InterpToNativeGenerator.cs @@ -171,6 +171,16 @@ class InterpToNativeGenerator { "VIIIFII", "VIIIFIII", "VIIIIF", + "IFFFFIII", + "IFFIII", + "VIIIIFFII", + "IIILIIII", + "IIILLI", + "IL", + "IFF", + "IFFF", + "IFFFF", + "VLII", }; static string TypeToSigType (char c) { diff --git a/mcs/tools/wasm-tuner/PInvokeTableGenerator.cs b/mcs/tools/wasm-tuner/PInvokeTableGenerator.cs new file mode 100644 index 000000000000..0b46a1716f98 --- /dev/null +++ b/mcs/tools/wasm-tuner/PInvokeTableGenerator.cs @@ -0,0 +1,303 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.IO; +using System.Linq; +using System.Text; +using System.Json; +using System.Collections.Generic; +using Mono.Cecil; + +public class PInvokeTableGenerator +{ + public PInvokeTableGenerator () { + } + + List assemblies; + Dictionary modules; + List pinvokes; + List callbacks; + + public void Run (List assemblies, Dictionary modules) { + this.assemblies = assemblies; + this.modules = modules; + + CollectPInvokes (assemblies, out pinvokes, out callbacks); + + Console.WriteLine ("// GENERATED FILE, DO NOT MODIFY"); + Console.WriteLine (); + + GenPInvokeTable (); + GenNativeToInterp (); + } + + void GenPInvokeTable () { + var decls = new Dictionary (); + foreach (var pinvoke in pinvokes) { + if (modules.ContainsKey (pinvoke.Module)) { + pinvoke.CDecl = GenPinvokeDecl (pinvoke); + if (decls.TryGetValue (pinvoke.EntryPoint, out Pinvoke prev_pinvoke)) { + if (pinvoke.CDecl != prev_pinvoke.CDecl) { + Console.Error.WriteLine ($"Warning: PInvoke method '{pinvoke.EntryPoint}' has incompatible declarations."); + pinvoke.TableEntryPoint = "mono_wasm_pinvoke_vararg_stub"; + prev_pinvoke.TableEntryPoint = "mono_wasm_pinvoke_vararg_stub"; + continue; + } + } + decls [pinvoke.EntryPoint] = pinvoke; + Console.WriteLine (pinvoke.CDecl); + } + } + + foreach (var module in modules.Keys) { + string symbol = module.Replace (".", "_") + "_imports"; + Console.WriteLine ("static PinvokeImport " + symbol + " [] = {"); + foreach (var pinvoke in pinvokes) { + if (pinvoke.Module == module) + Console.WriteLine ("{\"" + pinvoke.EntryPoint + "\", " + pinvoke.TableEntryPoint + "},"); + } + Console.WriteLine ("{NULL, NULL}"); + Console.WriteLine ("};"); + } + Console.Write ("static void *pinvoke_tables[] = { "); + foreach (var module in modules.Keys) { + string symbol = module.Replace (".", "_") + "_imports"; + Console.Write (symbol + ","); + } + Console.WriteLine ("};"); + Console.Write ("static char *pinvoke_names[] = { "); + foreach (var module in modules.Keys) { + Console.Write ("\"" + module + "\"" + ","); + } + Console.WriteLine ("};"); + } + + void GenNativeToInterp () { + // Generate native->interp entry functions + // These are called by native code, so they need to obtain + // the interp entry function/arg from a global array + // They also need to have a signature matching what the + // native code expects, which is the native signature + // of the delegate invoke in the [MonoPInvokeCallback] + // attribute. + // Only blittable parameter/return types are supposed. + int cb_index = 0; + + // Arguments to interp entry functions in the runtime + Console.WriteLine ("InterpFtnDesc wasm_native_to_interp_ftndescs[" + callbacks.Count + "];"); + + foreach (var cb in callbacks) { + var method = cb.Method; + + if (!IsBlittable (method.ReturnType)) + Error ("The return type of pinvoke callback method '" + method.FullName + "' needs to be blittable."); + foreach (var p in method.Parameters) { + if (!IsBlittable (p.ParameterType)) + Error ("Parameter types of pinvoke callback method '" + method.FullName + "' needs to be blittable."); + } + } + + foreach (var cb in callbacks) { + var sb = new StringBuilder (); + var method = cb.Method; + + // The signature of the interp entry function + // This is a gsharedvt_in signature + sb.Append ("typedef void "); + sb.Append (" (*WasmInterpEntrySig_" + cb_index + ") ("); + int pindex = 0; + if (method.ReturnType.Name != "Void") { + sb.Append ("int"); + pindex ++; + } + foreach (var p in method.Parameters) { + if (pindex > 0) + sb.Append (","); + sb.Append ("int"); + pindex ++; + } + if (pindex > 0) + sb.Append (","); + // Extra arg + sb.Append ("int"); + sb.Append (");\n"); + + bool is_void = method.ReturnType.Name == "Void"; + + string module_symbol = method.DeclaringType.Module.Assembly.Name.Name.Replace (".", "_"); + var token = method.MetadataToken.ToUInt32 (); + string entry_name = $"wasm_native_to_interp_{module_symbol}_{token}"; + cb.EntryName = entry_name; + sb.Append (WasmTuner.MapType (method.ReturnType)); + sb.Append ($" {entry_name} ("); + pindex = 0; + foreach (var p in method.Parameters) { + if (pindex > 0) + sb.Append (","); + sb.Append (WasmTuner.MapType (method.Parameters [pindex].ParameterType)); + sb.Append (" arg" + pindex); + pindex ++; + } + sb.Append (") { \n"); + if (!is_void) + sb.Append (WasmTuner.MapType (method.ReturnType) + " res;\n"); + sb.Append ("((WasmInterpEntrySig_" + cb_index + ")wasm_native_to_interp_ftndescs [" + cb_index + "].func) ("); + pindex = 0; + if (!is_void) { + sb.Append ("&res"); + pindex ++; + } + int aindex = 0; + foreach (var p in method.Parameters) { + if (pindex > 0) + sb.Append (", "); + sb.Append ("&arg" + aindex); + pindex ++; + aindex ++; + } + if (pindex > 0) + sb.Append (", "); + sb.Append ($"wasm_native_to_interp_ftndescs [{cb_index}].arg"); + sb.Append (");\n"); + if (!is_void) + sb.Append ("return res;\n"); + sb.Append ("}"); + Console.WriteLine (sb); + cb_index ++; + } + + // Array of function pointers + Console.Write ("static void *wasm_native_to_interp_funcs[] = { "); + foreach (var cb in callbacks) { + Console.Write (cb.EntryName + ","); + } + Console.WriteLine ("};"); + + // Lookup table from method->interp entry + // The key is a string of the form _ + // FIXME: Use a better encoding + Console.Write ("static const char *wasm_native_to_interp_map[] = { "); + foreach (var cb in callbacks) { + var method = cb.Method; + string module_symbol = method.DeclaringType.Module.Assembly.Name.Name.Replace (".", "_"); + var token = method.MetadataToken.ToUInt32 (); + Console.WriteLine ($"\"{module_symbol}_{token}\","); + } + Console.WriteLine ("};"); + } + + static bool IsBlittable (TypeReference type) { + switch (type.MetadataType) { + case MetadataType.Void: + case MetadataType.Char: + case MetadataType.Boolean: + case MetadataType.Byte: + case MetadataType.SByte: + case MetadataType.Int16: + case MetadataType.UInt16: + case MetadataType.Int32: + case MetadataType.UInt32: + case MetadataType.Int64: + case MetadataType.UInt64: + case MetadataType.IntPtr: + case MetadataType.UIntPtr: + case MetadataType.Single: + case MetadataType.Double: + case MetadataType.Pointer: + case MetadataType.ByReference: + return true; + case MetadataType.ValueType: { + var tdef = type.Resolve (); + return tdef != null && tdef.IsEnum; + } + default: + return false; + } + } + + static void Error (string msg) { + Console.Error.WriteLine (msg); + Environment.Exit (1); + } + + public static void CollectPInvokes (List assemblies, out List pinvokes, out List callbacks) { + pinvokes = new List (); + callbacks = new List (); + foreach (var assembly in assemblies) { + foreach (var type in assembly.MainModule.Types) { + ProcessTypeForPinvoke (pinvokes, callbacks, type); + foreach (var nested in type.NestedTypes) + ProcessTypeForPinvoke (pinvokes, callbacks, nested); + } + } + } + + static void ProcessTypeForPinvoke (List pinvokes, List callbacks, TypeDefinition type) { + foreach (var method in type.Methods) { + var info = method.PInvokeInfo; + if (info != null) { + pinvokes.Add (new Pinvoke (info.EntryPoint, info.Module.Name, method)); + } + + foreach (var attr in method.CustomAttributes) { + // The type has no defined namespace + if (attr.Constructor.DeclaringType.Name == "MonoPInvokeCallbackAttribute") { + if (!method.IsStatic) + Error ($"Method '{method.FullName}' decored with [MonoPInvokeCallback] needs to be static."); + var callback_type = attr.ConstructorArguments [0]; + if (callback_type.Type.Name != "Type" || callback_type.Value == null) + Error ("[MonoPInvokeCallback] attribute has invalid format."); + var tref = (TypeReference)callback_type.Value; + callbacks.Add (new PinvokeCallback (method, tref)); + } else if (attr.Constructor.DeclaringType.Name == "UnmanagedCallersOnlyAttribute") { + callbacks.Add (new PinvokeCallback (method, null)); + } + } + } + } + + static string GenPinvokeDecl (Pinvoke pinvoke) { + var sb = new StringBuilder (); + var method = pinvoke.Method; + sb.Append (WasmTuner.MapType (method.ReturnType)); + sb.Append ($" {pinvoke.EntryPoint} ("); + int pindex = 0; + foreach (var p in method.Parameters) { + if (pindex > 0) + sb.Append (","); + sb.Append (WasmTuner.MapType (method.Parameters [pindex].ParameterType)); + pindex ++; + } + sb.Append (");"); + return sb.ToString (); + } +} + +public class Pinvoke +{ + public Pinvoke (string entry_point, string module, MethodReference method) { + EntryPoint = entry_point; + TableEntryPoint = entry_point; + Module = module; + Method = method; + } + + public string EntryPoint; + public string TableEntryPoint; + public string Module; + public MethodReference Method; + public string CDecl; +} + +public class PinvokeCallback +{ + public PinvokeCallback (MethodReference method, TypeReference callback_type) { + Method = method; + CallbackType = callback_type; + } + + public MethodReference Method; + public TypeReference CallbackType; + public string EntryName; +} diff --git a/mcs/tools/wasm-tuner/tuner.cs b/mcs/tools/wasm-tuner/tuner.cs index 3004f35cd669..d6768e7ebbc2 100644 --- a/mcs/tools/wasm-tuner/tuner.cs +++ b/mcs/tools/wasm-tuner/tuner.cs @@ -40,22 +40,6 @@ public IcallClass (string name) { public Dictionary Icalls; } -class Pinvoke -{ - public Pinvoke (string entry_point, string module, MethodReference method) { - EntryPoint = entry_point; - TableEntryPoint = entry_point; - Module = module; - Method = method; - } - - public string EntryPoint; - public string TableEntryPoint; - public string Module; - public MethodReference Method; - public string CDecl; -} - public class WasmTuner { public static int Main (String[] args) { @@ -66,8 +50,6 @@ public static int Main (String[] args) { Dictionary runtime_icalls; - List pinvokes; - // Read the icall table generated by mono --print-icall-table void ReadTable (string filename) { JsonValue json; @@ -128,7 +110,7 @@ int Run (String[] args) { } } - static string MapType (TypeReference t) { + public static string MapType (TypeReference t) { if (t.Name == "Void") return "void"; else if (t.Name == "Double") @@ -143,91 +125,25 @@ static string MapType (TypeReference t) { return "int"; } - static string GenPinvokeDecl (Pinvoke pinvoke) { - var sb = new StringBuilder (); - var method = pinvoke.Method; - sb.Append (MapType (method.ReturnType)); - sb.Append ($" {pinvoke.EntryPoint} ("); - int pindex = 0; - foreach (var p in method.Parameters) { - if (pindex > 0) - sb.Append (","); - sb.Append (MapType (method.Parameters [pindex].ParameterType)); - pindex ++; - } - sb.Append (");"); - return sb.ToString (); - } - int GenPinvokeTable (String[] args) { var modules = new Dictionary (); foreach (var module in args [1].Split (',')) modules [module] = module; args = args.Skip (2).ToArray (); - pinvokes = new List (); - foreach (var fname in args) { - var a = AssemblyDefinition.ReadAssembly (fname); + var assemblies = new List (); + foreach (var fname in args) + assemblies.Add (AssemblyDefinition.ReadAssembly (fname)); - foreach (var type in a.MainModule.Types) { - ProcessTypeForPinvoke (pinvokes, type); - foreach (var nested in type.NestedTypes) - ProcessTypeForPinvoke (pinvokes, nested); - } - } - - Console.WriteLine ("// GENERATED FILE, DO NOT MODIFY"); - Console.WriteLine (); - - var decls = new Dictionary (); - foreach (var pinvoke in pinvokes) { - if (modules.ContainsKey (pinvoke.Module)) { - pinvoke.CDecl = GenPinvokeDecl (pinvoke); - if (decls.TryGetValue (pinvoke.EntryPoint, out Pinvoke prev_pinvoke)) { - if (pinvoke.CDecl != prev_pinvoke.CDecl) { - Console.Error.WriteLine ($"Warning: PInvoke method '{pinvoke.EntryPoint}' has incompatible declarations."); - pinvoke.TableEntryPoint = "mono_wasm_pinvoke_vararg_stub"; - prev_pinvoke.TableEntryPoint = "mono_wasm_pinvoke_vararg_stub"; - continue; - } - } - decls [pinvoke.EntryPoint] = pinvoke; - Console.WriteLine (pinvoke.CDecl); - } - } - - foreach (var module in modules.Keys) { - string symbol = module.Replace (".", "_") + "_imports"; - Console.WriteLine ("static PinvokeImport " + symbol + " [] = {"); - foreach (var pinvoke in pinvokes) { - if (pinvoke.Module == module) - Console.WriteLine ("{\"" + pinvoke.EntryPoint + "\", " + pinvoke.TableEntryPoint + "},"); - } - Console.WriteLine ("{NULL, NULL}"); - Console.WriteLine ("};"); - } - Console.Write ("static void *pinvoke_tables[] = { "); - foreach (var module in modules.Keys) { - string symbol = module.Replace (".", "_") + "_imports"; - Console.Write (symbol + ","); - } - Console.WriteLine ("};"); - Console.Write ("static char *pinvoke_names[] = { "); - foreach (var module in modules.Keys) { - Console.Write ("\"" + module + "\"" + ","); - } - Console.WriteLine ("};"); + var generator = new PInvokeTableGenerator (); + generator.Run (assemblies, modules); return 0; } - void ProcessTypeForPinvoke (List pinvokes, TypeDefinition type) { - foreach (var method in type.Methods) { - var info = method.PInvokeInfo; - if (info == null) - continue; - pinvokes.Add (new Pinvoke (info.EntryPoint, info.Module.Name, method)); - } + void Error (string msg) { + Console.Error.WriteLine (msg); + Environment.Exit (1); } static string GenIcallDecl (Icall icall) { @@ -454,16 +370,14 @@ int GenInterpToNative (String[] args) { string outfileName = args [1]; args = args.Skip (2).ToArray (); - pinvokes = new List (); - foreach (var fname in args) { - var a = AssemblyDefinition.ReadAssembly (fname); + var assemblies = new List (); + foreach (var fname in args) + assemblies.Add (AssemblyDefinition.ReadAssembly (fname)); - foreach (var type in a.MainModule.Types) { - ProcessTypeForPinvoke (pinvokes, type); - foreach (var nested in type.NestedTypes) - ProcessTypeForPinvoke (pinvokes, nested); - } - } + List pinvokes; + List callbacks; + + PInvokeTableGenerator.CollectPInvokes (assemblies, out pinvokes, out callbacks); var gen = new InterpToNativeGenerator (); foreach (var pinvoke in pinvokes) diff --git a/mcs/tools/wasm-tuner/wasm-tuner.csproj b/mcs/tools/wasm-tuner/wasm-tuner.csproj index d61ae501f27e..ec8d1a52d838 100644 --- a/mcs/tools/wasm-tuner/wasm-tuner.csproj +++ b/mcs/tools/wasm-tuner/wasm-tuner.csproj @@ -54,6 +54,7 @@ + genconsts diff --git a/mcs/tools/wasm-tuner/wasm-tuner.exe.sources b/mcs/tools/wasm-tuner/wasm-tuner.exe.sources index dd547f12c6d5..c89615d45afe 100644 --- a/mcs/tools/wasm-tuner/wasm-tuner.exe.sources +++ b/mcs/tools/wasm-tuner/wasm-tuner.exe.sources @@ -1,5 +1,6 @@ tuner.cs InterpToNativeGenerator.cs +PInvokeTableGenerator.cs ../../build/common/Consts.cs ../../build/common/SR.cs ../../class/System.Json/corefx/SR.cs diff --git a/mono/Makefile.am b/mono/Makefile.am index d8b7e4881335..a592773b4abf 100644 --- a/mono/Makefile.am +++ b/mono/Makefile.am @@ -42,4 +42,6 @@ endif endif endif -DIST_SUBDIRS = btls $(culture_dirs) native eglib arch utils cil zlib $(sgen_dirs) metadata mini dis $(managed_unit_test_dirs) $(native_unit_test_dirs) benchmark profiler +DIST_SUBDIRS = btls $(culture_dirs) native eglib eventpipe arch utils cil zlib $(sgen_dirs) metadata mini dis $(managed_unit_test_dirs) $(native_unit_test_dirs) benchmark profiler + +EXTRA_DIST = eventpipe/Makefile diff --git a/mono/arch/arm64/Makefile.am b/mono/arch/arm64/Makefile.am index bdc37622a640..e735d0ed69aa 100644 --- a/mono/arch/arm64/Makefile.am +++ b/mono/arch/arm64/Makefile.am @@ -1,3 +1,9 @@ MAKEFLAGS := $(MAKEFLAGS) --no-builtin-rules EXTRA_DIST = arm64-codegen.h codegen-test.c + +test-codegen: + $(CC) $(CFLAGS) -I../../.. -I../../eglib/ ../../eglib/.libs/libeglib.a -o codegen-test codegen-test.c + ./codegen-test > tmp.s + $(CC) $(CFLAGS) -c -o tmp.o tmp.s + objdump -d --triple=arm64e tmp.o diff --git a/mono/arch/arm64/arm64-codegen.h b/mono/arch/arm64/arm64-codegen.h index 239f4161fd92..d35fda11752f 100644 --- a/mono/arch/arm64/arm64-codegen.h +++ b/mono/arch/arm64/arm64-codegen.h @@ -867,4 +867,40 @@ arm_encode_arith_imm (int imm, guint32 *shift) #define arm_cmpp arm_cmpx #endif +/* ARM v8.3 */ + +/* PACIA */ + +#define arm_format_pacia(p, crm, op2) arm_emit ((p), (0b11010101000000110010000000011111 << 0) | ((crm) << 8) | ((op2) << 5)) +#define arm_paciasp(p) arm_format_pacia ((p), 0b0011, 0b001) + +/* PACIB */ + +#define arm_format_pacib(p, crm, op2) arm_emit ((p), (0b11010101000000110010000000011111 << 0) | ((crm) << 8) | ((op2) << 5)) +#define arm_pacibsp(p) arm_format_pacib ((p), 0b0011, 0b011) + +/* RETA */ +#define arm_format_reta(p,key) arm_emit ((p), 0b11010110010111110000101111111111 + ((key) << 10)) + +#define arm_retaa(p) arm_format_reta ((p),0) +#define arm_retab(p) arm_format_reta ((p),1) + +/* BRA */ + +#define arm_format_bra(p, z, m, rn, rm) arm_emit ((p), (0b1101011000011111000010 << 10) + ((z) << 24) + ((m) << 10) + ((rn) << 5) + ((rm) << 0)) + +#define arm_braaz(p, rn) arm_format_bra ((p), 0, 0, (rn), 0b11111) +#define arm_brabz(p, rn) arm_format_bra ((p), 0, 1, (rn), 0b11111) +#define arm_braa(p, rn, rm) arm_format_bra ((p), 1, 0, (rn), (rm)) +#define arm_brab(p, rn, rm) arm_format_bra ((p), 1, 1, (rn), (rm)) + +/* BLRA */ + +#define arm_format_blra(p, z, m, rn, rm) arm_emit ((p), (0b1101011000111111000010 << 10) + ((z) << 24) + ((m) << 10) + ((rn) << 5) + ((rm) << 0)) + +#define arm_blraaz(p, rn) arm_format_blra ((p), 0, 0, (rn), 0b11111) +#define arm_blraa(p, rn, rm) arm_format_blra ((p), 1, 0, (rn), (rm)) +#define arm_blrabz(p, rn) arm_format_blra ((p), 0, 1, (rn), 0b11111) +#define arm_blrab(p, rn, rm) arm_format_blra ((p), 1, 1, (rn), (rm)) + #endif /* __arm_CODEGEN_H__ */ diff --git a/mono/arch/arm64/codegen-test.c b/mono/arch/arm64/codegen-test.c index bb9d9dcdecd4..efb991e84273 100644 --- a/mono/arch/arm64/codegen-test.c +++ b/mono/arch/arm64/codegen-test.c @@ -416,6 +416,19 @@ main (int argc, char *argv []) arm_stlxrx (code, ARMREG_R0, ARMREG_R1, ARMREG_R2); arm_stlxrw (code, ARMREG_R0, ARMREG_R1, ARMREG_R2); + arm_paciasp (code); + arm_pacibsp (code); + arm_retaa (code); + arm_retab (code); + arm_braaz (code, ARMREG_R1); + arm_brabz (code, ARMREG_R1); + arm_braa (code, ARMREG_R1, ARMREG_R2); + arm_brab (code, ARMREG_R1, ARMREG_R2); + arm_blraaz (code, ARMREG_R1); + arm_blraa (code, ARMREG_R1, ARMREG_R2); + arm_blrabz (code, ARMREG_R1); + arm_blrab (code, ARMREG_R1, ARMREG_R2); + for (i = 0; i < code - buf; ++i) printf (".byte %d\n", buf [i]); printf ("\n"); diff --git a/mono/arch/riscv/riscv-codegen-test.c b/mono/arch/riscv/riscv-codegen-test.c index 722dc0f820e4..fb6338e5a0b2 100644 --- a/mono/arch/riscv/riscv-codegen-test.c +++ b/mono/arch/riscv/riscv-codegen-test.c @@ -1,7 +1,6 @@ /* * Licensed to the .NET Foundation under one or more agreements. * The .NET Foundation licenses this file to you under the MIT license. - * See the LICENSE file in the project root for more information. */ #define MONO_RISCV_CODEGEN_TEST diff --git a/mono/arch/riscv/riscv-codegen.h b/mono/arch/riscv/riscv-codegen.h index 9bd4b4a58223..7ba438aa7915 100644 --- a/mono/arch/riscv/riscv-codegen.h +++ b/mono/arch/riscv/riscv-codegen.h @@ -1,7 +1,6 @@ /* * Licensed to the .NET Foundation under one or more agreements. * The .NET Foundation licenses this file to you under the MIT license. - * See the LICENSE file in the project root for more information. */ #ifndef __MONO_RISCV_CODEGEN_H__ diff --git a/mono/eglib/eglib-remap.h b/mono/eglib/eglib-remap.h index c5e27adae85d..c9751049c3b7 100644 --- a/mono/eglib/eglib-remap.h +++ b/mono/eglib/eglib-remap.h @@ -311,3 +311,6 @@ #define g_set_printerr_handler monoeg_set_printerr_handler #define g_size_to_int monoeg_size_to_int +#define g_ascii_charcmp monoeg_ascii_charcmp +#define g_ascii_charcasecmp monoeg_ascii_charcasecmp +#define g_warning_d monoeg_warning_d diff --git a/mono/eglib/glib.h b/mono/eglib/glib.h index a056e9589898..4272679aeb13 100644 --- a/mono/eglib/glib.h +++ b/mono/eglib/glib.h @@ -779,6 +779,7 @@ GLogLevelFlags g_log_set_fatal_mask (const gchar *log_domain, GLogLevelFlags f void g_logv (const gchar *log_domain, GLogLevelFlags log_level, const gchar *format, va_list args); G_EXTERN_C // Used by MonoPosixHelper or MonoSupportW, at least. void g_log (const gchar *log_domain, GLogLevelFlags log_level, const gchar *format, ...); +void g_log_disabled (const gchar *log_domain, GLogLevelFlags log_level, const char *file, int line); G_EXTERN_C // Used by MonoPosixHelper or MonoSupportW, at least. void g_assertion_message (const gchar *format, ...) G_GNUC_NORETURN; void mono_assertion_message_disabled (const char *file, int line) G_GNUC_NORETURN; @@ -786,6 +787,7 @@ void mono_assertion_message (const char *file, int line, const char * void mono_assertion_message_unreachable (const char *file, int line) G_GNUC_NORETURN; const char * g_get_assertion_message (void); +#ifndef DISABLE_ASSERT_MESSAGES #ifdef HAVE_C99_SUPPORT /* The for (;;) tells gc thats g_error () doesn't return, avoiding warnings */ #define g_error(format, ...) do { g_log (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR, format, __VA_ARGS__); for (;;); } while (0) @@ -800,6 +802,13 @@ const char * g_get_assertion_message (void); #define g_message(...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, __VA_ARGS__) #define g_debug(...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, __VA_ARGS__) #endif /* ndef HAVE_C99_SUPPORT */ +#else +#define g_error(...) do { g_log_disabled (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR, __FILE__, __LINE__); for (;;); } while (0) +#define g_critical(...) g_log_disabled (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, __FILE__, __LINE__) +#define g_warning(...) g_log_disabled (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, __FILE__, __LINE__) +#define g_message(...) g_log_disabled (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, __FILE__, __LINE__) +#define g_debug(...) g_log_disabled (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, __FILE__, __LINE__) +#endif typedef void (*GLogFunc) (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data); typedef void (*GPrintFunc) (const gchar *string); diff --git a/mono/eglib/goutput.c b/mono/eglib/goutput.c index f9da72dfe57d..b54b1e0d8b5b 100644 --- a/mono/eglib/goutput.c +++ b/mono/eglib/goutput.c @@ -183,6 +183,12 @@ g_log (const gchar *log_domain, GLogLevelFlags log_level, const gchar *format, . va_end (args); } +void +g_log_disabled (const gchar *log_domain, GLogLevelFlags log_level, const char *file, int line) +{ + g_log (log_domain, log_level, "%s:%d ", file, line); +} + static char *failure_assertion = NULL; const char * diff --git a/mono/eventpipe/Makefile b/mono/eventpipe/Makefile index b04e6fb04124..df8d79eb40bc 100644 --- a/mono/eventpipe/Makefile +++ b/mono/eventpipe/Makefile @@ -1 +1,6 @@ # empty placeholder for build +dist: + +distdir: + +distclean: diff --git a/mono/metadata/Makefile.am b/mono/metadata/Makefile.am index 8e6f520077df..76fa995d570d 100644 --- a/mono/metadata/Makefile.am +++ b/mono/metadata/Makefile.am @@ -142,24 +142,35 @@ libmonoruntime_support_la_CFLAGS = $(filter-out @CXX_REMOVE_CFLAGS@, @CFLAGS@) @ if ENABLE_NETCORE if HAVE_SYS_ICU + +# symlink ICU sources to a local dir so automake puts intermediates into the target-specific folder +icushim/%.c: @ICU_SHIM_PATH@/%.c + $(LN_S) $^ $@ + shim_libraries = libmonoruntime-shimglobalization.la nodist_libmonoruntime_shimglobalization_la_SOURCES = \ - @ICU_SHIM_PATH@/pal_calendarData.c \ - @ICU_SHIM_PATH@/pal_casing.c \ - @ICU_SHIM_PATH@/pal_collation.c \ - @ICU_SHIM_PATH@/pal_idna.c \ - @ICU_SHIM_PATH@/pal_locale.c \ - @ICU_SHIM_PATH@/pal_localeNumberData.c \ - @ICU_SHIM_PATH@/pal_localeStringData.c \ - @ICU_SHIM_PATH@/pal_normalization.c \ - @ICU_SHIM_PATH@/pal_timeZoneInfo.c \ - @ICU_SHIM_PATH@/pal_icushim.c \ - @ICU_SHIM_PATH@/entrypoints.c + icushim/pal_calendarData.c \ + icushim/pal_casing.c \ + icushim/pal_collation.c \ + icushim/pal_idna.c \ + icushim/pal_locale.c \ + icushim/pal_localeNumberData.c \ + icushim/pal_localeStringData.c \ + icushim/pal_normalization.c \ + icushim/pal_timeZoneInfo.c \ + icushim/entrypoints.c libmonoruntime_shimglobalization_la_CFLAGS = @ICU_CFLAGS@ -I$(top_srcdir)/../libraries/Native/Unix/System.Globalization.Native/ -I$(top_srcdir)/../libraries/Native/Unix/Common/ -endif -endif + +if STATIC_ICU +nodist_libmonoruntime_shimglobalization_la_SOURCES += icushim/pal_icushim_static.c +else +nodist_libmonoruntime_shimglobalization_la_SOURCES += icushim/pal_icushim.c +endif # STATIC_ICU + +endif # HAVE_SYS_ICU +endif # ENABLE_NETCORE if !ENABLE_NETCORE culture_libraries = ../culture/libmono-culture.la @@ -498,7 +509,7 @@ libmonoruntimeinclude_HEADERS = \ sgen-bridge.h \ threads.h \ tokentype.h \ - verify.h + verify.h if !ENABLE_MSVC_ONLY diff --git a/mono/metadata/appdomain.c b/mono/metadata/appdomain.c index ceed387a734a..11d04619eb13 100644 --- a/mono/metadata/appdomain.c +++ b/mono/metadata/appdomain.c @@ -2147,7 +2147,7 @@ mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name) if (!is_ok (error)) goto exit; - found = !!strstr (dir_name, base_dir); + found = strstr (dir_name, base_dir) != 0; if (found) goto exit; diff --git a/mono/metadata/class-init.c b/mono/metadata/class-init.c index dbfae12e0a4b..3c74ee88f895 100644 --- a/mono/metadata/class-init.c +++ b/mono/metadata/class-init.c @@ -1008,8 +1008,6 @@ mono_class_create_bounded_array (MonoClass *eclass, guint32 rank, gboolean bound char *name; MonoImageSet* image_set; - g_assert (rank <= 255); - if (rank > 1) /* bounded only matters for one-dimensional arrays */ bounded = FALSE; @@ -1077,15 +1075,16 @@ mono_class_create_bounded_array (MonoClass *eclass, guint32 rank, gboolean bound klass->class_kind = MONO_CLASS_ARRAY; nsize = strlen (eclass->name); - name = (char *)g_malloc (nsize + 2 + rank + 1); + int maxrank = MIN (rank, 32); + name = (char *)g_malloc (nsize + 2 + maxrank + 1); memcpy (name, eclass->name, nsize); name [nsize] = '['; - if (rank > 1) - memset (name + nsize + 1, ',', rank - 1); + if (maxrank > 1) + memset (name + nsize + 1, ',', maxrank - 1); if (bounded) - name [nsize + rank] = '*'; - name [nsize + rank + bounded] = ']'; - name [nsize + rank + bounded + 1] = 0; + name [nsize + maxrank] = '*'; + name [nsize + maxrank + bounded] = ']'; + name [nsize + maxrank + bounded + 1] = 0; klass->name = image_set ? mono_image_set_strdup (image_set, name) : mono_image_strdup (image, name); g_free (name); @@ -2231,7 +2230,7 @@ mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_ /* Publish the data */ mono_loader_lock (); - if (klass->instance_size && !klass->image->dynamic) { + if (klass->instance_size && !klass->image->dynamic && klass_byval_arg->type != MONO_TYPE_FNPTR) { /* Might be already set using cached info */ if (klass->instance_size != instance_size) { /* Emit info to help debugging */ @@ -3400,7 +3399,8 @@ mono_class_setup_methods (MonoClass *klass) if (methods [i]->flags & METHOD_ATTRIBUTE_VIRTUAL) { if (method_is_reabstracted (methods[i]->flags)) { - methods [i]->is_reabstracted = 1; + if (!methods [i]->is_inflated) + mono_method_set_is_reabstracted (methods [i]); continue; } methods [i]->slot = slot++; diff --git a/mono/metadata/class-internals.h b/mono/metadata/class-internals.h index 05963326b1b5..49f54606eb28 100644 --- a/mono/metadata/class-internals.h +++ b/mono/metadata/class-internals.h @@ -53,6 +53,21 @@ typedef enum { } MonoRemotingTarget; #define MONO_METHOD_PROP_GENERIC_CONTAINER 0 +/* verification success bit, protected by the image lock */ +#define MONO_METHOD_PROP_VERIFICATION_SUCCESS 1 +/* infrequent vtable layout bits protected by the loader lock */ +#define MONO_METHOD_PROP_INFREQUENT_BITS 2 + +/* Infrequently accessed bits of method definitions stored in the image properties. + * The method must not be inflated. + * + * LOCKING: Reading the bits acquires the image lock. Writing the bits assumes + * the loader lock is held. + */ +typedef struct _MonoMethodDefInfrequentBits { + unsigned int is_reabstracted:1; /* whenever this is a reabstraction of another interface */ + unsigned int is_covariant_override_impl:1; /* whether this is an override with a signature different from its declared method */ +} MonoMethodDefInfrequentBits; struct _MonoMethod { guint16 flags; /* method flags */ @@ -73,10 +88,8 @@ struct _MonoMethod { unsigned int is_generic:1; /* whenever this is a generic method definition */ unsigned int is_inflated:1; /* whether we're a MonoMethodInflated */ unsigned int skip_visibility:1; /* whenever to skip JIT visibility checks */ - unsigned int verification_success:1; /* whether this method has been verified successfully.*/ - unsigned int is_reabstracted:1; /* whenever this is a reabstraction of another interface */ - unsigned int is_covariant_override_impl:1; /* whether this is an override with a signature different from its declared method */ - signed int slot : 15; + unsigned int _unused : 2; /* unused */ + signed int slot : 16; /* * If is_generic is TRUE, the generic_container is stored in image->property_hash, @@ -887,6 +900,30 @@ mono_generic_class_get_context (MonoGenericClass *gclass); void mono_method_set_generic_container (MonoMethod *method, MonoGenericContainer* container); +void +mono_method_set_verification_success (MonoMethod *method); + +gboolean +mono_method_get_verification_success (MonoMethod *method); + +const MonoMethodDefInfrequentBits * +mono_method_lookup_infrequent_bits (MonoMethod *methoddef); + +MonoMethodDefInfrequentBits * +mono_method_get_infrequent_bits (MonoMethod *methoddef); + +gboolean +mono_method_get_is_reabstracted (MonoMethod *method); + +void +mono_method_set_is_reabstracted (MonoMethod *methoddef); + +gboolean +mono_method_get_is_covariant_override_impl (MonoMethod *method); + +void +mono_method_set_is_covariant_override_impl (MonoMethod *methoddef); + MonoMethod* mono_class_inflate_generic_method_full_checked (MonoMethod *method, MonoClass *klass_hint, MonoGenericContext *context, MonoError *error); @@ -1516,6 +1553,9 @@ mono_method_is_constructor (MonoMethod *method); gboolean mono_class_has_default_constructor (MonoClass *klass, gboolean public_only); +gboolean +mono_method_has_unmanaged_callers_only_attribute (MonoMethod *method); + // There are many ways to do on-demand initialization. // Some allow multiple concurrent initializations. Some do not. // Some allow multiple concurrent writes to the global. Some do not. diff --git a/mono/metadata/class-setup-vtable.c b/mono/metadata/class-setup-vtable.c index 91f1c5d40453..58ac82f98e35 100644 --- a/mono/metadata/class-setup-vtable.c +++ b/mono/metadata/class-setup-vtable.c @@ -1568,9 +1568,9 @@ check_signature_covariant (MonoClass *klass, MonoMethod *impl, MonoMethod *decl) * \param vtable_size the number of slots in the vtable * * Given a provisional vtable for a class, check that any methods that come from \p klass that have the \c - * MonoMethod:is_covariant_override_impl bit have the most specific signature of any method in that slot in the ancestor - * classes. This checks that if the current class is overriding a method, it is doing so with the most specific - * signature. + * MonoMethodDefInfrequentBits:is_covariant_override_impl bit have the most specific signature of any method in that + * slot in the ancestor classes. This checks that if the current class is overriding a method, it is doing so with the + * most specific signature. * * Because classes can override methods either explicitly using an .override directive or implicitly by matching the * signature of some virtual method of some ancestor class, you could get into a situation where a class incorrectly @@ -1598,7 +1598,7 @@ check_vtable_covariant_override_impls (MonoClass *klass, MonoMethod **vtable, in /* we only need to check the slots that the parent class has, too. Everything else is new. */ for (int slot = 0; slot < parent_class->vtable_size; ++slot) { MonoMethod *impl = vtable[slot]; - if (!impl || !impl->is_covariant_override_impl || impl->klass != klass) + if (!impl || !mono_method_get_is_covariant_override_impl (impl) || impl->klass != klass) continue; MonoMethod *last_checked_prev_override = NULL; for (MonoClass *cur_class = parent_class; cur_class ; cur_class = cur_class->parent) { @@ -1867,7 +1867,7 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o if (im->flags & METHOD_ATTRIBUTE_STATIC) continue; - if (im->is_reabstracted == 1) + if (mono_method_get_is_reabstracted (im)) continue; TRACE_INTERFACE_VTABLE (printf (" [class is not abstract, checking slot %d for interface '%s'.'%s', method %s, slot check is %d]\n", @@ -1914,10 +1914,10 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o goto fail; #ifdef FEATURE_COVARIANT_RETURNS - if (vtable[slot] && vtable[slot]->is_covariant_override_impl) { + if (vtable[slot] && mono_method_get_is_covariant_override_impl (vtable[slot])) { TRACE_INTERFACE_VTABLE (printf (" in class %s, implicit override %s overrides %s in slot %d, which contained %s which had the covariant return bit\n", mono_type_full_name (m_class_get_byval_arg (klass)), mono_method_full_name (cm, 1), mono_method_full_name (m1, 1), slot, mono_method_full_name (vtable[slot], 1))); /* Mark the current method as overriding a covariant return method; after the explicit overloads are applied, if this method is still in its slot in the vtable, we will check that it's the most specific implementation */ - cm->is_covariant_override_impl = TRUE; + mono_method_set_is_covariant_override_impl (cm); } #endif /* FEATURE_COVARIANT_RETURNS */ @@ -2006,9 +2006,9 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o /* Historically, mono didn't do a signature equivalence check for explicit overrides, but we need one for covariant returns */ /* If the previous impl in the slot had the covariant signature bit set, or if the signature of the proposed impl doesn't match the signature of the previous impl, check for covariance */ if (prev_impl != NULL && - (prev_impl->is_covariant_override_impl || + (mono_method_get_is_covariant_override_impl (prev_impl) || !mono_metadata_signature_equal (mono_method_signature_internal (impl), mono_method_signature_internal (prev_impl)))) { - impl->is_covariant_override_impl = TRUE; + mono_method_set_is_covariant_override_impl (impl); } /* if we saw the attribute or if we think we need to check impl sigs, we will need to traverse the class hierarchy. */ @@ -2085,7 +2085,7 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o if (!mono_class_is_abstract (klass)) { for (i = 0; i < cur_slot; ++i) { if (vtable [i] == NULL || (vtable [i]->flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_STATIC))) { - if (vtable [i] != NULL && vtable [i]->is_reabstracted == 1) + if (vtable [i] != NULL && mono_method_get_is_reabstracted (vtable [i])) continue; char *type_name = mono_type_get_full_name (klass); char *method_name = vtable [i] ? mono_method_full_name (vtable [i], TRUE) : g_strdup ("none"); diff --git a/mono/metadata/class.c b/mono/metadata/class.c index a1bd6326c146..bc3b46b7f760 100644 --- a/mono/metadata/class.c +++ b/mono/metadata/class.c @@ -372,8 +372,12 @@ mono_type_get_name_recurse (MonoType *type, GString *str, gboolean is_recursed, g_string_append_c (str, '['); if (rank == 1) g_string_append_c (str, '*'); - for (i = 1; i < rank; i++) - g_string_append_c (str, ','); + else if (rank > 64) + // Only taken in an error path, runtime will not load arrays of more than 32 dimensions + g_string_append_printf (str, "%d", rank); + else + for (i = 1; i < rank; i++) + g_string_append_c (str, ','); g_string_append_c (str, ']'); mono_type_name_check_byref (type, str); @@ -1379,6 +1383,133 @@ mono_method_set_generic_container (MonoMethod *method, MonoGenericContainer* con mono_image_property_insert (mono_method_get_image (method), method, MONO_METHOD_PROP_GENERIC_CONTAINER, container); } +/** + * mono_method_set_verification_success: + * + * Sets a bit indicating that the method has been verified. + * + * LOCKING: acquires the image lock. + */ +void +mono_method_set_verification_success (MonoMethod *method) +{ + g_assert (!method->is_inflated); + + mono_image_property_insert (mono_method_get_image (method), method, MONO_METHOD_PROP_VERIFICATION_SUCCESS, GUINT_TO_POINTER(1)); +} + +/** + * mono_method_get_verification_sucess: + * + * Returns \c TRUE if the method has been verified successfully. + * + * LOCKING: acquires the image lock. + */ +gboolean +mono_method_get_verification_success (MonoMethod *method) +{ + if (method->is_inflated) + method = ((MonoMethodInflated *)method)->declaring; + + gpointer value = mono_image_property_lookup (mono_method_get_image (method), method, MONO_METHOD_PROP_VERIFICATION_SUCCESS); + + return value != NULL; +} + +/** + * mono_method_lookup_infrequent_bits: + * + * Looks for existing \c MonoMethodDefInfrequentBits struct associated with + * this method definition. Unlike \c mono_method_get_infrequent bits, this + * does not allocate a new struct if one doesn't exist. + * + * LOCKING: Acquires the image lock + */ +const MonoMethodDefInfrequentBits* +mono_method_lookup_infrequent_bits (MonoMethod *method) +{ + g_assert (!method->is_inflated); + + return (const MonoMethodDefInfrequentBits*)mono_image_property_lookup (mono_method_get_image (method), method, MONO_METHOD_PROP_INFREQUENT_BITS); +} + +/** + * mono_method_get_infrequent_bits: + * + * Looks for an existing, or allocates a new \c MonoMethodDefInfrequentBits struct for this method definition. + * Method must not be inflated. + * + * Unlike \c mono_method_lookup_infrequent_bits, this will allocate a new + * struct if the method didn't have one. + * + * LOCKING: Acquires the image lock + */ +MonoMethodDefInfrequentBits * +mono_method_get_infrequent_bits (MonoMethod *method) +{ + g_assert (!method->is_inflated); + MonoImage *image = mono_method_get_image (method); + MonoMethodDefInfrequentBits *infrequent_bits = NULL; + mono_image_lock (image); + infrequent_bits = (MonoMethodDefInfrequentBits *)mono_image_property_lookup (image, method, MONO_METHOD_PROP_INFREQUENT_BITS); + if (!infrequent_bits) { + infrequent_bits = (MonoMethodDefInfrequentBits *)mono_image_alloc0 (image, sizeof (MonoMethodDefInfrequentBits)); + mono_image_property_insert (image, method, MONO_METHOD_PROP_INFREQUENT_BITS, infrequent_bits); + } + mono_image_unlock (image); + return infrequent_bits; +} + +gboolean +mono_method_get_is_reabstracted (MonoMethod *method) +{ + if (method->is_inflated) + method = ((MonoMethodInflated*)method)->declaring; + const MonoMethodDefInfrequentBits *infrequent_bits = mono_method_lookup_infrequent_bits (method); + return infrequent_bits != NULL && infrequent_bits->is_reabstracted; +} + +gboolean +mono_method_get_is_covariant_override_impl (MonoMethod *method) +{ + if (method->is_inflated) + method = ((MonoMethodInflated*)method)->declaring; + const MonoMethodDefInfrequentBits *infrequent_bits = mono_method_lookup_infrequent_bits (method); + return infrequent_bits != NULL && infrequent_bits->is_covariant_override_impl; +} + +/** + * mono_method_set_is_reabstracted: + * + * Sets the \c MonoMethodDefInfrequentBits:is_reabstracted bit for this method + * definition. The bit means that the method is a default interface method + * that used to have a default implementation in an ancestor interface, but is + * now abstract once again. + * + * LOCKING: Assumes the loader lock is held + */ +void +mono_method_set_is_reabstracted (MonoMethod *method) +{ + mono_method_get_infrequent_bits (method)->is_reabstracted = 1; +} + +/** + * mono_method_set_is_covariant_override_impl: + * + * Sets the \c MonoMethodDefInfrequentBits:is_covariant_override_impl bit for + * this method definition. The bit means that the method is an override with a + * signature that is not equal to the signature of the method that it is + * overriding. + * + * LOCKING: Assumes the loader lock is held + */ +void +mono_method_set_is_covariant_override_impl (MonoMethod *method) +{ + mono_method_get_infrequent_bits (method)->is_covariant_override_impl = 1; +} + /** * mono_class_find_enum_basetype: * \param class The enum class @@ -3317,7 +3448,7 @@ mono_class_from_name (MonoImage *image, const char* name_space, const char *name * * This function works exactly like mono_class_from_name but it will abort if the class is not found. * This function should be used by the runtime for critical types to which there's no way to recover but crash - * If they are missing. Thing of System.Object or System.String. + * if they are missing. For example, System.Object or System.String. */ MonoClass * mono_class_load_from_name (MonoImage *image, const char* name_space, const char *name) diff --git a/mono/metadata/custom-attrs.c b/mono/metadata/custom-attrs.c index f9297172e6ed..491ae63bfb8f 100644 --- a/mono/metadata/custom-attrs.c +++ b/mono/metadata/custom-attrs.c @@ -489,6 +489,7 @@ MONO_RESTORE_WARNING case MONO_TYPE_SZARRAY: { MonoArray *arr; guint32 i, alen, basetype; + if (!bcheck_blob (p, 3, boundp, error)) return NULL; alen = read32 (p); @@ -497,8 +498,10 @@ MONO_RESTORE_WARNING *end = p; return NULL; } + arr = mono_array_new_checked (mono_domain_get(), tklass, alen, error); return_val_if_nok (error, NULL); + basetype = m_class_get_byval_arg (tklass)->type; if (basetype == MONO_TYPE_VALUETYPE && m_class_is_enumtype (tklass)) basetype = mono_class_enum_basetype_internal (tklass)->type; @@ -569,7 +572,10 @@ MONO_RESTORE_WARNING case MONO_TYPE_CLASS: case MONO_TYPE_OBJECT: case MONO_TYPE_STRING: - case MONO_TYPE_SZARRAY: + case MONO_TYPE_SZARRAY: { + HANDLE_FUNCTION_ENTER (); + MONO_HANDLE_NEW (MonoArray, arr); + for (i = 0; i < alen; i++) { MonoObject *item = NULL; load_cattr_value (image, m_class_get_byval_arg (tklass), &item, p, boundp, &p, error); @@ -577,13 +583,16 @@ MONO_RESTORE_WARNING return NULL; mono_array_setref_internal (arr, i, item); } + HANDLE_FUNCTION_RETURN (); break; + } default: g_error ("Type 0x%02x not handled in custom attr array decoding", basetype); } *end = p; g_assert (out_obj); *out_obj = (MonoObject*)arr; + return NULL; } default: @@ -625,6 +634,8 @@ create_cattr_typed_arg (MonoType *t, MonoObject *val, MonoError *error) error_init (error); + HANDLE_FUNCTION_ENTER (); + MONO_STATIC_POINTER_INIT (MonoMethod, ctor) ctor = mono_class_get_method_from_name_checked (mono_class_get_custom_attribute_typed_argument_class (), ".ctor", 2, 0, error); @@ -634,15 +645,20 @@ create_cattr_typed_arg (MonoType *t, MonoObject *val, MonoError *error) params [0] = mono_type_get_object_checked (mono_domain_get (), t, error); return_val_if_nok (error, NULL); + MONO_HANDLE_PIN ((MonoObject*)params [0]); params [1] = val; retval = mono_object_new_checked (mono_domain_get (), mono_class_get_custom_attribute_typed_argument_class (), error); return_val_if_nok (error, NULL); + MONO_HANDLE_PIN (retval); + unboxed = mono_object_unbox_internal (retval); mono_runtime_invoke_checked (ctor, unboxed, params, error); return_val_if_nok (error, NULL); + HANDLE_FUNCTION_RETURN (); + return retval; } @@ -654,6 +670,8 @@ create_cattr_named_arg (void *minfo, MonoObject *typedarg, MonoError *error) error_init (error); + HANDLE_FUNCTION_ENTER (); + MONO_STATIC_POINTER_INIT (MonoMethod, ctor) ctor = mono_class_get_method_from_name_checked (mono_class_get_custom_attribute_named_argument_class (), ".ctor", 2, 0, error); @@ -665,12 +683,15 @@ create_cattr_named_arg (void *minfo, MonoObject *typedarg, MonoError *error) params [1] = typedarg; retval = mono_object_new_checked (mono_domain_get (), mono_class_get_custom_attribute_named_argument_class (), error); return_val_if_nok (error, NULL); + MONO_HANDLE_PIN (retval); unboxed = mono_object_unbox_internal (retval); mono_runtime_invoke_checked (ctor, unboxed, params, error); return_val_if_nok (error, NULL); + HANDLE_FUNCTION_RETURN (); + return retval; } @@ -1182,7 +1203,7 @@ mono_reflection_create_custom_attr_data_args (MonoImage *image, MonoMethod *meth /* * mono_reflection_create_custom_attr_data_args_noalloc: * - * Same as mono_reflection_create_custom_attr_data_args_noalloc but allocate no managed objects, return values + * Same as mono_reflection_create_custom_attr_data_args but allocate no managed objects, return values * using C arrays. Only usable for cattrs with primitive/type arguments. * TYPED_ARGS, NAMED_ARGS, and NAMED_ARG_INFO should be freed using g_free (). */ @@ -1385,7 +1406,7 @@ ves_icall_System_Reflection_CustomAttributeData_ResolveArgumentsInternal (MonoRe obj = mono_array_get_internal (typed_args, MonoObject*, i); MONO_HANDLE_ASSIGN_RAW (obj_h, obj); - t = mono_method_signature_internal (method)->params [i]; + t = sig->params [i]; if (t->type == MONO_TYPE_OBJECT && obj) t = m_class_get_byval_arg (obj->vtable->klass); typedarg = create_cattr_typed_arg (t, obj, error); diff --git a/mono/metadata/debug-internals.h b/mono/metadata/debug-internals.h index 0743602591b6..4fb12e39eca2 100644 --- a/mono/metadata/debug-internals.h +++ b/mono/metadata/debug-internals.h @@ -53,6 +53,7 @@ typedef struct typedef enum { DEBUG_DIR_ENTRY_CODEVIEW = 2, + DEBUG_DIR_REPRODUCIBLE = 16, DEBUG_DIR_ENTRY_PPDB = 17, DEBUG_DIR_PDB_CHECKSUM = 19 } DebugDirectoryEntryType; diff --git a/mono/metadata/exception.h b/mono/metadata/exception.h index 721dd493ae04..155c23c7e774 100644 --- a/mono/metadata/exception.h +++ b/mono/metadata/exception.h @@ -106,8 +106,7 @@ mono_get_exception_argument_null (const char *arg); MONO_API MonoException * mono_get_exception_argument (const char *arg, const char *msg); -MONO_API MONO_RT_EXTERNAL_ONLY -MonoException * +MONO_API MonoException * mono_get_exception_argument_out_of_range (const char *arg); MONO_API MONO_RT_EXTERNAL_ONLY diff --git a/mono/metadata/handle.h b/mono/metadata/handle.h index 2cedc51bb7ea..6a9ad056deb7 100644 --- a/mono/metadata/handle.h +++ b/mono/metadata/handle.h @@ -516,6 +516,9 @@ TYPED_HANDLE_DECL (MonoObject); TYPED_HANDLE_DECL (MonoException); TYPED_HANDLE_DECL (MonoAppContext); +/* Simpler version of MONO_HANDLE_NEW if the handle is not used */ +#define MONO_HANDLE_PIN(object) MONO_HANDLE_NEW (MonoObject, (object)) + // Structs cannot be cast to structs. // As well, a function is needed because an anonymous struct cannot be initialized in C. static inline MonoObjectHandle diff --git a/mono/metadata/icall-decl.h b/mono/metadata/icall-decl.h index 1bb8ab1cfa67..2c153f8cd6c9 100644 --- a/mono/metadata/icall-decl.h +++ b/mono/metadata/icall-decl.h @@ -159,7 +159,9 @@ ICALL_EXPORT gint64 ves_icall_System_GC_GetTotalMemory (MonoBoolean forceCollect ICALL_EXPORT gint64 ves_icall_System_Threading_Timer_GetTimeMonotonic (void); ICALL_EXPORT gpointer ves_icall_System_GCHandle_GetAddrOfPinnedObject (MonoGCHandle handle); ICALL_EXPORT int ves_icall_Interop_Sys_DoubleToString (double, char*, char*, int); +#if !ENABLE_NETCORE ICALL_EXPORT int ves_icall_System_Environment_get_Platform (void); +#endif ICALL_EXPORT int ves_icall_System_GC_GetCollectionCount (int); ICALL_EXPORT int ves_icall_System_GC_GetMaxGeneration (void); ICALL_EXPORT gint64 ves_icall_System_GC_GetAllocatedBytesForCurrentThread (void); diff --git a/mono/metadata/icall-def-netcore.h b/mono/metadata/icall-def-netcore.h index ee55fbbc7fc2..8e3a61820b65 100644 --- a/mono/metadata/icall-def-netcore.h +++ b/mono/metadata/icall-def-netcore.h @@ -94,11 +94,8 @@ HANDLES(ENV_2, "GetCommandLineArgs", ves_icall_System_Environment_GetCommandLine HANDLES(ENV_3, "GetEnvironmentVariableNames", ves_icall_System_Environment_GetEnvironmentVariableNames, MonoArray, 0, ()) NOHANDLES(ICALL(ENV_4, "GetProcessorCount", ves_icall_System_Environment_get_ProcessorCount)) NOHANDLES(ICALL(ENV_9, "get_ExitCode", mono_environment_exitcode_get)) -HANDLES(ENV_11, "get_MachineName", ves_icall_System_Environment_get_MachineName, MonoString, 0, ()) -NOHANDLES(ICALL(ENV_13, "get_Platform", ves_icall_System_Environment_get_Platform)) NOHANDLES(ICALL(ENV_15, "get_TickCount", ves_icall_System_Environment_get_TickCount)) NOHANDLES(ICALL(ENV_15a, "get_TickCount64", ves_icall_System_Environment_get_TickCount64)) -HANDLES(ENV_16, "get_UserName", ves_icall_System_Environment_get_UserName, MonoString, 0, ()) HANDLES(ENV_17, "internalGetEnvironmentVariable_native", ves_icall_System_Environment_GetEnvironmentVariable_native, MonoString, 1, (const_char_ptr)) NOHANDLES(ICALL(ENV_20, "set_ExitCode", mono_environment_exitcode_set)) diff --git a/mono/metadata/icall-eventpipe.c b/mono/metadata/icall-eventpipe.c index 553aff220a2e..4222ffb72e80 100644 --- a/mono/metadata/icall-eventpipe.c +++ b/mono/metadata/icall-eventpipe.c @@ -5,7 +5,7 @@ #ifdef ENABLE_NETCORE #include -#ifdef ENABLE_PERFTRACING +#if defined(ENABLE_PERFTRACING) && !defined(DISABLE_EVENTPIPE) #include #include #include @@ -172,6 +172,54 @@ mono_eventpipe_fini (void) ep_rt_mono_initialized = FALSE; } +static +void +delegate_callback_data_free_func ( + EventPipeCallback callback_func, + void *callback_data) +{ + if (callback_data) + mono_gchandle_free_internal ((MonoGCHandle)callback_data); +} + +static +void +delegate_callback_func ( + const uint8_t *source_id, + unsigned long is_enabled, + uint8_t level, + uint64_t match_any_keywords, + uint64_t match_all_keywords, + EventFilterDescriptor *filter_data, + void *callback_context) +{ + + /*internal unsafe delegate void EtwEnableCallback( + in Guid sourceId, + int isEnabled, + byte level, + long matchAnyKeywords, + long matchAllKeywords, + EVENT_FILTER_DESCRIPTOR* filterData, + void* callbackContext);*/ + + MonoGCHandle delegate_object_handle = (MonoGCHandle)callback_context; + MonoObject *delegate_object = delegate_object_handle ? mono_gchandle_get_target_internal (delegate_object_handle) : NULL; + if (delegate_object) { + void *params [7]; + params [0] = (void *)source_id; + params [1] = (void *)&is_enabled; + params [2] = (void *)&level; + params [3] = (void *)&match_any_keywords; + params [4] = (void *)&match_all_keywords; + params [5] = (void *)filter_data; + params [6] = NULL; + + ERROR_DECL (error); + mono_runtime_delegate_invoke_checked (delegate_object, params, error); + } +} + gconstpointer ves_icall_System_Diagnostics_Tracing_EventPipeInternal_CreateProvider ( MonoStringHandle provider_name, @@ -179,26 +227,19 @@ ves_icall_System_Diagnostics_Tracing_EventPipeInternal_CreateProvider ( MonoError *error) { EventPipeProvider *provider = NULL; - gpointer delegate_func = NULL; + void *callback_data = NULL; if (MONO_HANDLE_IS_NULL (provider_name)) { mono_error_set_argument_null (error, "providerName", ""); return NULL; } -#ifndef HOST_WASM - if (!MONO_HANDLE_IS_NULL (callback_func)) { - delegate_func = mono_delegate_to_ftnptr_impl (callback_func, error); - if (!is_ok (error) || !delegate_func) { - mono_error_set_argument_null (error, "callback_func", ""); - return NULL; - } - } -#endif + if (!MONO_HANDLE_IS_NULL (callback_func)) + callback_data = (void *)mono_gchandle_new_weakref_internal (MONO_HANDLE_RAW (MONO_HANDLE_CAST (MonoObject, callback_func)), FALSE); char *provider_name_utf8 = mono_string_handle_to_utf8 (provider_name, error); if (is_ok (error) && provider_name_utf8) { - provider = ep_create_provider (provider_name_utf8, (EventPipeCallback)delegate_func, NULL); + provider = ep_create_provider (provider_name_utf8, delegate_callback_func, delegate_callback_data_free_func, callback_data); } g_free (provider_name_utf8); @@ -248,11 +289,13 @@ ves_icall_System_Diagnostics_Tracing_EventPipeInternal_Enable ( { ERROR_DECL (error); EventPipeSessionID session_id = 0; + char *output_file_utf8 = NULL; if (circular_buffer_size_mb == 0 || format > EP_SERIALIZATION_FORMAT_COUNT || providers_len == 0 || providers == NULL) return 0; - char *output_file_utf8 = mono_utf16_to_utf8 (output_file, g_utf16_len (output_file), error); + if (output_file) + output_file_utf8 = mono_utf16_to_utf8 (output_file, g_utf16_len (output_file), error); EventPipeProviderConfigurationNative *native_config_providers = (EventPipeProviderConfigurationNative *)providers; EventPipeProviderConfiguration *config_providers = g_new0 (EventPipeProviderConfiguration, providers_len); diff --git a/mono/metadata/icall.c b/mono/metadata/icall.c index 213227213ce5..948b43f9dec5 100644 --- a/mono/metadata/icall.c +++ b/mono/metadata/icall.c @@ -7523,6 +7523,7 @@ ves_icall_Remoting_RealProxy_InternalGetProxyType (MonoTransparentProxyHandle tp /* System.Environment */ +#ifndef ENABLE_NETCORE MonoStringHandle ves_icall_System_Environment_get_UserName (MonoError *error) { @@ -7606,6 +7607,7 @@ ves_icall_System_Environment_get_Platform (void) { return mono_icall_get_platform (); } +#endif /* !ENABLE_NETCORE */ #ifndef HOST_WIN32 static MonoStringHandle diff --git a/mono/metadata/image.c b/mono/metadata/image.c index d3b2f8ea5d88..d0b6c8b42089 100644 --- a/mono/metadata/image.c +++ b/mono/metadata/image.c @@ -1038,8 +1038,7 @@ mono_has_pdb_checksum (char *raw_data, uint32_t raw_data_len) debug_dir.major_version = read16(data + 8); debug_dir.minor_version = read16(data + 10); debug_dir.type = read32(data + 12); - printf("debug_dir.type - %d\n", debug_dir.type); - if (debug_dir.type == DEBUG_DIR_PDB_CHECKSUM) + if (debug_dir.type == DEBUG_DIR_PDB_CHECKSUM || debug_dir.type == DEBUG_DIR_REPRODUCIBLE) return TRUE; } } diff --git a/mono/metadata/jit-icall-reg.h b/mono/metadata/jit-icall-reg.h index 5b07e4c9e153..3abbdf45da4d 100644 --- a/mono/metadata/jit-icall-reg.h +++ b/mono/metadata/jit-icall-reg.h @@ -308,6 +308,8 @@ MONO_JIT_ICALL (mono_threads_state_poll) \ MONO_JIT_ICALL (mono_throw_exception) \ MONO_JIT_ICALL (mono_throw_method_access) \ MONO_JIT_ICALL (mono_throw_bad_image) \ +MONO_JIT_ICALL (mono_throw_not_supported) \ +MONO_JIT_ICALL (mono_throw_invalid_program) \ MONO_JIT_ICALL (mono_trace_enter_method) \ MONO_JIT_ICALL (mono_trace_leave_method) \ MONO_JIT_ICALL (mono_trace_tail_method) \ diff --git a/mono/metadata/loader.c b/mono/metadata/loader.c index 56db42136dad..1d5405e14bf4 100644 --- a/mono/metadata/loader.c +++ b/mono/metadata/loader.c @@ -2034,7 +2034,7 @@ mono_method_get_header_internal (MonoMethod *method, MonoError *error) // FIXME: for internal callers maybe it makes sense to do this check at the call site, not // here? if (mono_method_has_no_body (method)) { - if (method->is_reabstracted == 1) + if (mono_method_get_is_reabstracted (method)) mono_error_set_generic_error (error, "System", "EntryPointNotFoundException", "%s", method->name); else mono_error_set_bad_image (error, img, "Method has no body"); diff --git a/mono/metadata/marshal.c b/mono/metadata/marshal.c index a2523b51b3c9..3faa290b12c0 100644 --- a/mono/metadata/marshal.c +++ b/mono/metadata/marshal.c @@ -113,6 +113,7 @@ static GENERATE_TRY_GET_CLASS_WITH_CACHE (unmanaged_function_pointer_attribute, #ifdef ENABLE_NETCORE static GENERATE_TRY_GET_CLASS_WITH_CACHE (suppress_gc_transition_attribute, "System.Runtime.InteropServices", "SuppressGCTransitionAttribute") +static GENERATE_TRY_GET_CLASS_WITH_CACHE (unmanaged_callers_only_attribute, "System.Runtime.InteropServices", "UnmanagedCallersOnlyAttribute") #endif static MonoImage* @@ -3661,6 +3662,23 @@ mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions, mb->method->save_lmf = 1; + if (G_UNLIKELY (pinvoke && mono_method_has_unmanaged_callers_only_attribute (method))) { + /* emit a wrapper that throws a NotSupportedException */ + get_marshal_cb ()->mb_emit_exception (mb, "System", "NotSupportedException", "Method canot be marked with both DllImportAttribute and UnmanagedCallersOnlyAttribute"); + + info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_NONE); + info->d.managed_to_native.method = method; + + csig = mono_metadata_signature_dup_full (get_method_image (method), sig); + csig->pinvoke = 0; + res = mono_mb_create_and_cache_full (cache, method, mb, csig, + csig->param_count + 16, info, NULL); + mono_mb_free (mb); + + return res; + } + + /* * In AOT mode and embedding scenarios, it is possible that the icall is not * registered in the runtime doing the AOT compilation. @@ -3940,10 +3958,58 @@ emit_managed_wrapper_noilgen (MonoMethodBuilder *mb, MonoMethodSignature *invoke } #endif +static gboolean +type_is_blittable (MonoType *type) +{ + if (type->byref) + return FALSE; + type = mono_type_get_underlying_type (type); + switch (type->type) { + case MONO_TYPE_I1: + case MONO_TYPE_U1: + case MONO_TYPE_I2: + case MONO_TYPE_U2: + case MONO_TYPE_I4: + case MONO_TYPE_U4: + case MONO_TYPE_I8: + case MONO_TYPE_U8: + case MONO_TYPE_R4: + case MONO_TYPE_R8: + case MONO_TYPE_I: + case MONO_TYPE_U: + case MONO_TYPE_PTR: + case MONO_TYPE_FNPTR: + case MONO_TYPE_VOID: + return TRUE; + default: { + MonoClass *klass = mono_class_from_mono_type_internal (type); + mono_class_init_sizes (klass); + return m_class_is_blittable (klass); + } + } +} + +static gboolean +method_signature_is_blittable (MonoMethodSignature *sig) +{ + if (!type_is_blittable (sig->ret)) + return FALSE; + + for (int i = 0; i < sig->param_count; ++i) { + MonoType *type = sig->params [i]; + if (!type_is_blittable (type)) + return FALSE; + } + return TRUE; +} + /** * mono_marshal_get_managed_wrapper: * Generates IL code to call managed methods from unmanaged code * If \p target_handle is \c 0, the wrapper info will be a \c WrapperInfo structure. + * + * If \p delegate_klass is \c NULL, we're creating a wrapper for a function pointer to a method marked with + * UnamangedCallersOnlyAttribute. */ MonoMethod * mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, MonoGCHandle target_handle, MonoError *error) @@ -3975,11 +4041,33 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, if (!target_handle && (res = mono_marshal_find_in_cache (cache, method))) return res; - invoke = mono_get_delegate_invoke_internal (delegate_klass); - invoke_sig = mono_method_signature_internal (invoke); - - mspecs = g_new0 (MonoMarshalSpec*, mono_method_signature_internal (invoke)->param_count + 1); - mono_method_get_marshal_info (invoke, mspecs); + if (G_UNLIKELY (!delegate_klass)) { + /* creating a wrapper for a function pointer with UnmanagedCallersOnlyAttribute */ + if (mono_method_has_marshal_info (method)) { + mono_error_set_invalid_program (error, "method %s with UnmanadedCallersOnlyAttribute has marshal specs", mono_method_full_name (method, TRUE)); + return NULL; + } + invoke = NULL; + invoke_sig = mono_method_signature_internal (method); + if (invoke_sig->hasthis) { + mono_error_set_invalid_program (error, "method %s with UnamanagedCallersOnlyAttribute is an instance method", mono_method_full_name (method, TRUE)); + return NULL; + } + if (method->is_generic || method->is_inflated || mono_class_is_ginst (method->klass)) { + mono_error_set_invalid_program (error, "method %s with UnamangedCallersOnlyAttribute is generic", mono_method_full_name (method, TRUE)); + return NULL; + } + if (!method_signature_is_blittable (invoke_sig)) { + mono_error_set_invalid_program (error, "method %s with UnmanagedCallersOnlyAttribute has non-blittable parameters or return type", mono_method_full_name (method, TRUE)); + return NULL; + } + mspecs = g_new0 (MonoMarshalSpec*, invoke_sig->param_count + 1); + } else { + invoke = mono_get_delegate_invoke_internal (delegate_klass); + invoke_sig = mono_method_signature_internal (invoke); + mspecs = g_new0 (MonoMarshalSpec*, invoke_sig->param_count + 1); + mono_method_get_marshal_info (invoke, mspecs); + } sig = mono_method_signature_internal (method); @@ -4005,10 +4093,11 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, m.csig = csig; m.image = get_method_image (method); - mono_marshal_set_callconv_from_modopt (invoke, csig, TRUE); + if (invoke) + mono_marshal_set_callconv_from_modopt (invoke, csig, TRUE); /* The attribute is only available in Net 2.0 */ - if (mono_class_try_get_unmanaged_function_pointer_attribute_class ()) { + if (delegate_klass && mono_class_try_get_unmanaged_function_pointer_attribute_class ()) { MonoCustomAttrInfo *cinfo; MonoCustomAttrEntry *attr; @@ -4097,7 +4186,7 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, } mono_mb_free (mb); - for (i = mono_method_signature_internal (invoke)->param_count; i >= 0; i--) + for (i = invoke_sig->param_count; i >= 0; i--) if (mspecs [i]) mono_metadata_free_marshal_spec (mspecs [i]); g_free (mspecs); @@ -6809,3 +6898,33 @@ get_marshal_cb (void) } return &marshal_cb; } + +/** + * mono_method_has_unmanaged_callers_only_attribute: + * + * Returns \c TRUE if \p method has the \c UnmanagedCallersOnlyAttribute + */ +gboolean +mono_method_has_unmanaged_callers_only_attribute (MonoMethod *method) +{ +#ifndef ENABLE_NETCORE + return FALSE; +#else + ERROR_DECL (attr_error); + MonoClass *attr_klass = NULL; + attr_klass = mono_class_try_get_unmanaged_callers_only_attribute_class (); + if (!attr_klass) + return FALSE; + MonoCustomAttrInfo *cinfo; + cinfo = mono_custom_attrs_from_method_checked (method, attr_error); + if (!is_ok (attr_error) || !cinfo) { + mono_error_cleanup (attr_error); + return FALSE; + } + gboolean result; + result = mono_custom_attrs_has_attr (cinfo, attr_klass); + if (!cinfo->cached) + mono_custom_attrs_free (cinfo); + return result; +#endif +} diff --git a/mono/metadata/mono-config.c b/mono/metadata/mono-config.c index f0940187e1fd..df9cf248efe3 100644 --- a/mono/metadata/mono-config.c +++ b/mono/metadata/mono-config.c @@ -666,8 +666,7 @@ mono_config_for_assembly_internal (MonoImage *assembly) MONO_REQ_GC_UNSAFE_MODE; MonoConfigParseState state = {NULL}; - int i; - char *aname, *cfg, *cfg_name; + char *cfg_name; const char *bundled_config; state.assembly = assembly; @@ -684,6 +683,7 @@ mono_config_for_assembly_internal (MonoImage *assembly) #ifndef DISABLE_CFGDIR_CONFIG int got_it = 0; + char *aname, *cfg; cfg_name = g_strdup_printf ("%s.config", mono_image_get_name (assembly)); const char *cfg_dir = mono_get_config_dir (); if (!cfg_dir) { @@ -691,7 +691,7 @@ mono_config_for_assembly_internal (MonoImage *assembly) return; } - for (i = 0; (aname = get_assembly_filename (assembly, i)) != NULL; ++i) { + for (int i = 0; (aname = get_assembly_filename (assembly, i)) != NULL; ++i) { cfg = g_build_filename (cfg_dir, "mono", "assemblies", aname, cfg_name, (const char*)NULL); got_it += mono_config_parse_file_with_context (&state, cfg); g_free (cfg); diff --git a/mono/metadata/native-library.c b/mono/metadata/native-library.c index 02eb5a12e94b..ff2c6cc8d647 100644 --- a/mono/metadata/native-library.c +++ b/mono/metadata/native-library.c @@ -11,28 +11,40 @@ #include "mono/utils/mono-logger-internals.h" #include "mono/utils/mono-path.h" #include "mono/metadata/native-library.h" +#include "mono/metadata/custom-attrs-internals.h" #ifdef ENABLE_NETCORE static int pinvoke_search_directories_count; static char **pinvoke_search_directories; -// In DllImportSearchPath enum, bit 0x2 represents AssemblyDirectory. It is not passed on and is instead handled by the runtime. -#define DLLIMPORTSEARCHPATH_ASSEMBLYDIRECTORY 0x2 +// sync with src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/DllImportSearchPath.cs +typedef enum +{ + DLLIMPORTSEARCHPATH_LEGACY_BEHAVIOR = 0x0, // when no other flags are present, search the application directory and then call LoadLibraryEx with LOAD_WITH_ALTERED_SEARCH_PATH + DLLIMPORTSEARCHPATH_USE_DLL_DIRECTORY_FOR_DEPENDENCIES = 0x100, + DLLIMPORTSEARCHPATH_APPLICATION_DIRECTORY = 0x200, + DLLIMPORTSEARCHPATH_USER_DIRECTORIES = 0x400, + DLLIMPORTSEARCHPATH_SYSTEM32 = 0x800, + DLLIMPORTSEARCHPATH_SAFE_DIRECTORIES = 0x1000, + DLLIMPORTSEARCHPATH_ASSEMBLY_DIRECTORY = 0x2, // search the assembly directory first regardless of platform, not passed on to LoadLibraryEx +} DllImportSearchPath; +//static const int DLLIMPORTSEARCHPATH_LOADLIBRARY_FLAG_MASK = DLLIMPORTSEARCHPATH_USE_DLL_DIRECTORY_FOR_DEPENDENCIES | DLLIMPORTSEARCHPATH_APPLICATION_DIRECTORY | +// DLLIMPORTSEARCHPATH_USER_DIRECTORIES | DLLIMPORTSEARCHPATH_SYSTEM32 | DLLIMPORTSEARCHPATH_SAFE_DIRECTORIES; // This lock may be taken within an ALC lock, and should never be the other way around. static MonoCoopMutex native_library_module_lock; static GHashTable *native_library_module_map; /* - * This blacklist is used as a set for cache invalidation purposes with netcore pinvokes. + * This blocklist is used as a set for cache invalidation purposes with netcore pinvokes. * When pinvokes are resolved with anything other than the last-chance managed event, * the results of that lookup are added to an ALC-level cache. However, if a library is then * unloaded with NativeLibrary.Free(), this cache should be invalidated so that a newly called - * pinvoke will not attempt to use it, hence the blacklist. This design means that if another + * pinvoke will not attempt to use it, hence the blocklist. This design means that if another * library is loaded at the same address, it will function with a perf hit, as the entry will - * repeatedly be added and removed from the cache due to its presence in the blacklist. + * repeatedly be added and removed from the cache due to its presence in the blocklist. * This is a rare scenario and considered a worthwhile tradeoff. */ -static GHashTable *native_library_module_blacklist; +static GHashTable *native_library_module_blocklist; #endif #ifndef DISABLE_DLLMAP @@ -58,6 +70,7 @@ GENERATE_GET_CLASS_WITH_CACHE (appdomain_unloaded_exception, "System", "AppDomai GENERATE_TRY_GET_CLASS_WITH_CACHE (appdomain_unloaded_exception, "System", "AppDomainUnloadedException") #ifdef ENABLE_NETCORE GENERATE_GET_CLASS_WITH_CACHE (native_library, "System.Runtime.InteropServices", "NativeLibrary"); +static GENERATE_TRY_GET_CLASS_WITH_CACHE (dllimportsearchpath_attribute, "System.Runtime.InteropServices", "DefaultDllImportSearchPathsAttribute"); #endif #ifndef DISABLE_DLLMAP @@ -319,8 +332,8 @@ mono_global_loader_cache_init (void) #ifdef ENABLE_NETCORE if (!native_library_module_map) native_library_module_map = g_hash_table_new (g_direct_hash, g_direct_equal); - if (!native_library_module_blacklist) - native_library_module_blacklist = g_hash_table_new (g_direct_hash, g_direct_equal); + if (!native_library_module_blocklist) + native_library_module_blocklist = g_hash_table_new (g_direct_hash, g_direct_equal); mono_coop_mutex_init (&native_library_module_lock); #endif } @@ -472,9 +485,9 @@ netcore_handle_lookup (gpointer handle) // LOCKING: expects you to hold native_library_module_lock static gboolean -netcore_check_blacklist (MonoDl *module) +netcore_check_blocklist (MonoDl *module) { - return g_hash_table_contains (native_library_module_blacklist, module); + return g_hash_table_contains (native_library_module_blocklist, module); } static MonoDl * @@ -504,7 +517,6 @@ static MonoDl * netcore_probe_for_module (MonoImage *image, const char *file_name, int flags) { MonoDl *module = NULL; - gboolean search_assembly_dir = flags & DLLIMPORTSEARCHPATH_ASSEMBLYDIRECTORY; // Try without any path additions module = netcore_probe_for_module_variations (NULL, file_name); @@ -514,13 +526,15 @@ netcore_probe_for_module (MonoImage *image, const char *file_name, int flags) module = netcore_probe_for_module_variations (pinvoke_search_directories[i], file_name); // Check the assembly directory if the search flag is set and the image exists - if (search_assembly_dir && image != NULL && module == NULL) { + if (flags & DLLIMPORTSEARCHPATH_ASSEMBLY_DIRECTORY && image != NULL && module == NULL) { char *mdirname = g_path_get_dirname (image->filename); if (mdirname) module = netcore_probe_for_module_variations (mdirname, file_name); g_free (mdirname); } + // TODO: Pass remaining flags on to LoadLibraryEx on Windows where appropriate, see https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.dllimportsearchpath?view=netcore-3.1 + return module; } @@ -720,13 +734,13 @@ netcore_check_alc_cache (MonoAssemblyLoadContext *alc, const char *scope) result = (MonoDl *)g_hash_table_lookup (alc->pinvoke_scopes, scope); if (result) { - gboolean blacklisted; + gboolean blocklisted; native_library_lock (); - blacklisted = netcore_check_blacklist (result); + blocklisted = netcore_check_blocklist (result); native_library_unlock (); - if (blacklisted) { + if (blocklisted) { g_hash_table_remove (alc->pinvoke_scopes, scope); result = NULL; } @@ -835,6 +849,50 @@ netcore_lookup_native_library (MonoAssemblyLoadContext *alc, MonoImage *image, c return module; } +static int +get_dllimportsearchpath_flags (MonoCustomAttrInfo *cinfo) +{ + ERROR_DECL (error); + MonoCustomAttrEntry *attr = NULL; + MonoClass *dllimportsearchpath = mono_class_try_get_dllimportsearchpath_attribute_class (); + int idx; + int flags; + + if (!dllimportsearchpath) + return -1; + if (!cinfo) + return -2; + + for (idx = 0; idx < cinfo->num_attrs; ++idx) { + MonoClass *ctor_class = cinfo->attrs [idx].ctor->klass; + if (ctor_class == dllimportsearchpath) { + attr = &cinfo->attrs [idx]; + break; + } + } + if (!attr) + return -3; + + gpointer *typed_args, *named_args; + CattrNamedArg *arginfo; + int num_named_args; + + mono_reflection_create_custom_attr_data_args_noalloc (m_class_get_image (attr->ctor->klass), attr->ctor, attr->data, attr->data_size, + &typed_args, &named_args, &num_named_args, &arginfo, error); + if (!is_ok (error)) { + mono_error_cleanup (error); + return -4; + } + + flags = *(gint32*)typed_args [0]; + g_free (typed_args [0]); + g_free (typed_args); + g_free (named_args); + g_free (arginfo); + + return flags; +} + #else // ENABLE_NETCORE static MonoDl * @@ -1174,6 +1232,8 @@ lookup_pinvoke_call_impl (MonoMethod *method, MonoLookupPInvokeStatus *status_ou MonoImage *image = m_class_get_image (method->klass); #ifdef ENABLE_NETCORE MonoAssemblyLoadContext *alc = mono_image_get_alc (image); + MonoCustomAttrInfo *cinfo; + int flags; #endif MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)method; MonoTableInfo *tables = image->tables; @@ -1240,8 +1300,26 @@ lookup_pinvoke_call_impl (MonoMethod *method, MonoLookupPInvokeStatus *status_ou #ifndef HOST_WIN32 retry_with_libcoreclr: #endif - // FIXME: these flags are not getting passed correctly - module = netcore_lookup_native_library (alc, image, new_scope, 0); + { + ERROR_DECL (local_error); + cinfo = mono_custom_attrs_from_method_checked (method, local_error); + mono_error_cleanup (local_error); + } + flags = get_dllimportsearchpath_flags (cinfo); + if (cinfo && !cinfo->cached) + mono_custom_attrs_free (cinfo); + + if (flags < 0) { + ERROR_DECL (local_error); + cinfo = mono_custom_attrs_from_assembly_checked (m_class_get_image (method->klass)->assembly, TRUE, local_error); + mono_error_cleanup (local_error); + flags = get_dllimportsearchpath_flags (cinfo); + if (cinfo && !cinfo->cached) + mono_custom_attrs_free (cinfo); + } + if (flags < 0) + flags = 0; + module = netcore_lookup_native_library (alc, image, new_scope, flags); #else module = legacy_lookup_native_library (image, new_scope); #endif @@ -1420,7 +1498,7 @@ ves_icall_System_Runtime_InteropServices_NativeLibrary_FreeLib (gpointer lib, Mo goto leave; g_hash_table_remove (native_library_module_map, module->handle); - g_hash_table_add (native_library_module_blacklist, module); + g_hash_table_add (native_library_module_blocklist, module); mono_dl_close (module); leave: @@ -1496,7 +1574,7 @@ ves_icall_System_Runtime_InteropServices_NativeLibrary_LoadByName (MonoStringHan goto_if_nok (error, leave); // FIXME: implement search flag defaults properly - module = netcore_probe_for_module (image, lib_name, has_search_flag ? search_flag : 0x2); + module = netcore_probe_for_module (image, lib_name, has_search_flag ? search_flag : DLLIMPORTSEARCHPATH_ASSEMBLY_DIRECTORY); if (!module) mono_error_set_generic_error (error, "System", "DllNotFoundException", "%s", lib_name); goto_if_nok (error, leave); @@ -1601,4 +1679,3 @@ mono_loader_save_bundled_library (int fd, uint64_t offset, uint64_t size, const g_free (buffer); } - diff --git a/mono/metadata/object-offsets.h b/mono/metadata/object-offsets.h index 82f901714646..f11bbf58e82b 100644 --- a/mono/metadata/object-offsets.h +++ b/mono/metadata/object-offsets.h @@ -167,11 +167,13 @@ DECL_OFFSET(MonoJitTlsData, stack_restore_ctx) DECL_OFFSET(MonoGSharedVtMethodRuntimeInfo, locals_size) DECL_OFFSET(MonoGSharedVtMethodRuntimeInfo, entries) //XXX more to fix here +#if !defined(ENABLE_NETCORE) DECL_OFFSET(MonoContinuation, stack_used_size) DECL_OFFSET(MonoContinuation, saved_stack) DECL_OFFSET(MonoContinuation, return_sp) DECL_OFFSET(MonoContinuation, lmf) DECL_OFFSET(MonoContinuation, return_ip) +#endif DECL_OFFSET(MonoDelegateTrampInfo, method) DECL_OFFSET(MonoDelegateTrampInfo, invoke_impl) @@ -249,6 +251,9 @@ DECL_OFFSET(MonoLMF, ebp) DECL_OFFSET(MonoLMF, eip) DECL_OFFSET(MonoLMF, gregs) DECL_OFFSET(MonoLMF, fregs) +#elif defined(TARGET_RISCV) +DECL_OFFSET(MonoContext, gregs) +DECL_OFFSET(MonoContext, fregs) #endif // Shared architecture offfsets diff --git a/mono/metadata/object.c b/mono/metadata/object.c index f19fd0a8b726..140c91e9de62 100644 --- a/mono/metadata/object.c +++ b/mono/metadata/object.c @@ -5779,8 +5779,13 @@ mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params, mono_error_assert_ok (error); MONO_STATIC_POINTER_INIT_END (MonoMethod, box_method) - g_assert (res->vtable->klass == mono_defaults.int_class); - box_args [0] = ((MonoIntPtr*)res)->m_value; + if (res) { + g_assert (res->vtable->klass == mono_defaults.int_class); + box_args [0] = ((MonoIntPtr*)res)->m_value; + } else { + g_assert (sig->ret->byref); + box_args [0] = NULL; + } if (sig->ret->byref) { // byref is already unboxed by the invoke code MonoType *tmpret = mono_metadata_type_dup (NULL, sig->ret); diff --git a/mono/metadata/profiler-events.h b/mono/metadata/profiler-events.h index 941348013d41..c7ab3f66d516 100644 --- a/mono/metadata/profiler-events.h +++ b/mono/metadata/profiler-events.h @@ -1,7 +1,6 @@ /* * Licensed to the .NET Foundation under one or more agreements. * The .NET Foundation licenses this file to you under the MIT license. - * See the LICENSE file in the project root for more information. */ /* diff --git a/mono/metadata/profiler-legacy.h b/mono/metadata/profiler-legacy.h index 964b198508d9..ec6a8490ad05 100644 --- a/mono/metadata/profiler-legacy.h +++ b/mono/metadata/profiler-legacy.h @@ -1,7 +1,6 @@ /* * Licensed to the .NET Foundation under one or more agreements. * The .NET Foundation licenses this file to you under the MIT license. - * See the LICENSE file in the project root for more information. */ #ifndef __MONO_PROFILER_LEGACY_H__ diff --git a/mono/metadata/profiler-private.h b/mono/metadata/profiler-private.h index 6fe72490d53a..1042711498fd 100644 --- a/mono/metadata/profiler-private.h +++ b/mono/metadata/profiler-private.h @@ -1,7 +1,6 @@ /* * Licensed to the .NET Foundation under one or more agreements. * The .NET Foundation licenses this file to you under the MIT license. - * See the LICENSE file in the project root for more information. */ #ifndef __MONO_PROFILER_PRIVATE_H__ diff --git a/mono/metadata/profiler.c b/mono/metadata/profiler.c index 1435981ea700..8fe24a7869db 100644 --- a/mono/metadata/profiler.c +++ b/mono/metadata/profiler.c @@ -1,7 +1,6 @@ /* * Licensed to the .NET Foundation under one or more agreements. * The .NET Foundation licenses this file to you under the MIT license. - * See the LICENSE file in the project root for more information. */ #include diff --git a/mono/metadata/profiler.h b/mono/metadata/profiler.h index bc603978bfd8..2fd2d840f82a 100644 --- a/mono/metadata/profiler.h +++ b/mono/metadata/profiler.h @@ -1,7 +1,6 @@ /* * Licensed to the .NET Foundation under one or more agreements. * The .NET Foundation licenses this file to you under the MIT license. - * See the LICENSE file in the project root for more information. */ #ifndef __MONO_PROFILER_H__ diff --git a/mono/metadata/sgen-toggleref.c b/mono/metadata/sgen-toggleref.c index 831d0aaccfc1..9a5d98e29339 100644 --- a/mono/metadata/sgen-toggleref.c +++ b/mono/metadata/sgen-toggleref.c @@ -19,6 +19,7 @@ #include "sgen-toggleref.h" #include "sgen/sgen-client.h" +#ifndef DISABLE_SGEN_TOGGLEREF /*only one of the two can be non null at a given time*/ typedef struct { @@ -234,4 +235,18 @@ sgen_register_test_toggleref_callback (void) toggleref_callback = test_toggleref_callback; } +#else + +void +mono_gc_toggleref_register_callback (MonoToggleRefStatus (*proccess_toggleref) (MonoObject *obj)) +{ +} + +void +mono_gc_toggleref_add (MonoObject *object, mono_bool strong_ref) +{ +} + +#endif + #endif diff --git a/mono/mini/Makefile.am.in b/mono/mini/Makefile.am.in index 7d7a6a2515be..2bf98c88cfc5 100755 --- a/mono/mini/Makefile.am.in +++ b/mono/mini/Makefile.am.in @@ -428,6 +428,8 @@ interp_sources = \ interp/interp.h \ interp/interp-internals.h \ interp/interp.c \ + interp/interp-intrins.h \ + interp/interp-intrins.c \ interp/mintops.h \ interp/mintops.def \ interp/mintops.c \ @@ -767,6 +769,7 @@ libmonosgen_2_0_la_CFLAGS = $(mono_sgen_CFLAGS) @CXX_ADD_CFLAGS@ libmonosgen_2_0_la_LIBADD = libmini.la $(interp_libs_with_mini) $(dbg_libs_with_mini) $(sgen_libs) $(LIBMONO_DTRACE_OBJECT) $(LLVMMONOF) libmonosgen_2_0_la_LDFLAGS = $(libmonoldflags) $(monobin_platform_ldflags) $(CCLDFLAGS) +libmonosgen_2_0_la_LIBTOOLFLAGS = $(MONO_LIBTOOL_TAG) noinst_LIBRARIES += libmaintest.a diff --git a/mono/mini/aot-compiler.c b/mono/mini/aot-compiler.c index adb9cab48538..5e8d1d3ab734 100644 --- a/mono/mini/aot-compiler.c +++ b/mono/mini/aot-compiler.c @@ -3761,7 +3761,13 @@ encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, guint8 *buf, guint8 case MONO_WRAPPER_NATIVE_TO_MANAGED: { g_assert (info); encode_method_ref (acfg, info->d.native_to_managed.method, p, &p); - encode_klass_ref (acfg, info->d.native_to_managed.klass, p, &p); + MonoClass *klass = info->d.native_to_managed.klass; + if (!klass) { + encode_value (0, p, &p); + } else { + encode_value (1, p, &p); + encode_klass_ref (acfg, klass, p, &p); + } break; } default: @@ -12290,6 +12296,9 @@ compile_asm (MonoAotCompile *acfg) #elif defined(TARGET_AMD64) && defined(TARGET_MACH) #define LD_NAME "clang" #define LD_OPTIONS "--shared" +#elif defined(TARGET_ARM64) && defined(TARGET_OSX) +#define LD_NAME "clang" +#define LD_OPTIONS "--shared" #elif defined(TARGET_WIN32_MSVC) #define LD_NAME "link.exe" #define LD_OPTIONS "/DLL /MACHINE:X64 /NOLOGO /INCREMENTAL:NO" diff --git a/mono/mini/aot-runtime-wasm.c b/mono/mini/aot-runtime-wasm.c index e928cb3f221f..f2d70e4e8bbd 100644 --- a/mono/mini/aot-runtime-wasm.c +++ b/mono/mini/aot-runtime-wasm.c @@ -8,6 +8,7 @@ #include #include "mini.h" +#include "mono-private-unstable.h" #include "interp/interp.h" #ifdef TARGET_WASM @@ -114,6 +115,23 @@ mono_wasm_get_interp_to_native_trampoline (MonoMethodSignature *sig) return interp_to_native_invokes [idx]; } +static MonoWasmGetNativeToInterpTramp get_native_to_interp_tramp_cb; + +MONO_API void +mono_wasm_install_get_native_to_interp_tramp (MonoWasmGetNativeToInterpTramp cb) +{ + get_native_to_interp_tramp_cb = cb; +} + +gpointer +mono_wasm_get_native_to_interp_trampoline (MonoMethod *method, gpointer extra_arg) +{ + if (get_native_to_interp_tramp_cb) + return get_native_to_interp_tramp_cb (method, extra_arg); + else + return NULL; +} + #else /* TARGET_WASM */ MONO_EMPTY_SOURCE_FILE (aot_runtime_wasm); diff --git a/mono/mini/aot-runtime.c b/mono/mini/aot-runtime.c index 209279d894d6..b42c76efba75 100644 --- a/mono/mini/aot-runtime.c +++ b/mono/mini/aot-runtime.c @@ -1312,9 +1312,13 @@ decode_method_ref_with_target (MonoAotModule *module, MethodRef *ref, MonoMethod m = decode_resolve_method_ref (module, p, &p, error); if (!m) return FALSE; - klass = decode_klass_ref (module, p, &p, error); - if (!klass) - return FALSE; + gboolean has_class = decode_value (p, &p); + if (has_class) { + klass = decode_klass_ref (module, p, &p, error); + if (!klass) + return FALSE; + } else + klass = NULL; ref->method = mono_marshal_get_managed_wrapper (m, klass, 0, error); if (!is_ok (error)) return FALSE; diff --git a/mono/mini/aot-runtime.h b/mono/mini/aot-runtime.h index c4171fab12a3..79b9b6d8356b 100644 --- a/mono/mini/aot-runtime.h +++ b/mono/mini/aot-runtime.h @@ -11,7 +11,7 @@ #include "mini.h" /* Version number of the AOT file format */ -#define MONO_AOT_FILE_VERSION 178 +#define MONO_AOT_FILE_VERSION 179 #define MONO_AOT_TRAMP_PAGE_SIZE 16384 diff --git a/mono/mini/cpu-riscv32.md b/mono/mini/cpu-riscv32.md index 65b602cc5301..dcac804bd820 100644 --- a/mono/mini/cpu-riscv32.md +++ b/mono/mini/cpu-riscv32.md @@ -1,6 +1,5 @@ # Licensed to the .NET Foundation under one or more agreements. # The .NET Foundation licenses this file to you under the MIT license. -# See the LICENSE file in the project root for more information. # # RISC-V RV32 Machine Description # diff --git a/mono/mini/cpu-riscv64.md b/mono/mini/cpu-riscv64.md index e8c29d3824cf..0a4863df5313 100644 --- a/mono/mini/cpu-riscv64.md +++ b/mono/mini/cpu-riscv64.md @@ -1,6 +1,5 @@ # Licensed to the .NET Foundation under one or more agreements. # The .NET Foundation licenses this file to you under the MIT license. -# See the LICENSE file in the project root for more information. # # RISC-V RV64 Machine Description # diff --git a/mono/mini/debugger-agent.c b/mono/mini/debugger-agent.c index f76e887e6db8..5b6d729a3390 100644 --- a/mono/mini/debugger-agent.c +++ b/mono/mini/debugger-agent.c @@ -1085,18 +1085,18 @@ finish_agent_init (gboolean on_startup) // FIXME: Generated address // FIXME: Races with transport_connect () - char *argv [ ] = { - agent_config.launch, - agent_config.transport, - agent_config.address, - NULL - }; #ifdef G_OS_WIN32 // Nothing. FIXME? g_spawn_async_with_pipes is easy enough to provide for Windows if needed. #elif !HAVE_G_SPAWN g_printerr ("g_spawn_async_with_pipes not supported on this platform\n"); exit (1); #else + char *argv [ ] = { + agent_config.launch, + agent_config.transport, + agent_config.address, + NULL + }; int res = g_spawn_async_with_pipes (NULL, argv, NULL, (GSpawnFlags)0, NULL, NULL, NULL, NULL, NULL, NULL, NULL); if (!res) { g_printerr ("Failed to execute '%s'.\n", agent_config.launch); @@ -3598,6 +3598,10 @@ dbg_path_get_basename (const char *filename) return g_strdup (&r[1]); } +static GENERATE_TRY_GET_CLASS_WITH_CACHE(hidden_klass, "System.Diagnostics", "DebuggerHiddenAttribute") +static GENERATE_TRY_GET_CLASS_WITH_CACHE(step_through_klass, "System.Diagnostics", "DebuggerStepThroughAttribute") +static GENERATE_TRY_GET_CLASS_WITH_CACHE(non_user_klass, "System.Diagnostics", "DebuggerNonUserCodeAttribute") + static void init_jit_info_dbg_attrs (MonoJitInfo *ji) { @@ -3607,27 +3611,19 @@ init_jit_info_dbg_attrs (MonoJitInfo *ji) if (ji->dbg_attrs_inited) return; - MONO_STATIC_POINTER_INIT (MonoClass, hidden_klass) - hidden_klass = mono_class_load_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggerHiddenAttribute"); - MONO_STATIC_POINTER_INIT_END (MonoClass, hidden_klass) - - - MONO_STATIC_POINTER_INIT (MonoClass, step_through_klass) - step_through_klass = mono_class_load_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggerStepThroughAttribute"); - MONO_STATIC_POINTER_INIT_END (MonoClass, step_through_klass) - - MONO_STATIC_POINTER_INIT (MonoClass, non_user_klass) - non_user_klass = mono_class_load_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggerNonUserCodeAttribute"); - MONO_STATIC_POINTER_INIT_END (MonoClass, non_user_klass) + // NOTE: The following Debugger attributes may not exist if they are trimmed away by the ILLinker + MonoClass *hidden_klass = mono_class_try_get_hidden_klass_class (); + MonoClass *step_through_klass = mono_class_try_get_step_through_klass_class (); + MonoClass *non_user_klass = mono_class_try_get_non_user_klass_class (); ainfo = mono_custom_attrs_from_method_checked (jinfo_get_method (ji), error); mono_error_cleanup (error); /* FIXME don't swallow the error? */ if (ainfo) { - if (mono_custom_attrs_has_attr (ainfo, hidden_klass)) + if (hidden_klass && mono_custom_attrs_has_attr (ainfo, hidden_klass)) ji->dbg_hidden = TRUE; - if (mono_custom_attrs_has_attr (ainfo, step_through_klass)) + if (step_through_klass && mono_custom_attrs_has_attr (ainfo, step_through_klass)) ji->dbg_step_through = TRUE; - if (mono_custom_attrs_has_attr (ainfo, non_user_klass)) + if (non_user_klass && mono_custom_attrs_has_attr (ainfo, non_user_klass)) ji->dbg_non_user_code = TRUE; mono_custom_attrs_free (ainfo); } @@ -3635,9 +3631,9 @@ init_jit_info_dbg_attrs (MonoJitInfo *ji) ainfo = mono_custom_attrs_from_class_checked (jinfo_get_method (ji)->klass, error); mono_error_cleanup (error); /* FIXME don't swallow the error? */ if (ainfo) { - if (mono_custom_attrs_has_attr (ainfo, step_through_klass)) + if (step_through_klass && mono_custom_attrs_has_attr (ainfo, step_through_klass)) ji->dbg_step_through = TRUE; - if (mono_custom_attrs_has_attr (ainfo, non_user_klass)) + if (non_user_klass && mono_custom_attrs_has_attr (ainfo, non_user_klass)) ji->dbg_non_user_code = TRUE; mono_custom_attrs_free (ainfo); } diff --git a/mono/mini/driver.c b/mono/mini/driver.c index 8646f92d47c7..f2876328b7a7 100644 --- a/mono/mini/driver.c +++ b/mono/mini/driver.c @@ -2011,10 +2011,6 @@ apply_root_domain_configuration_file_bindings (MonoDomain *domain, char *root_do static void mono_check_interp_supported (void) { -#ifdef DISABLE_INTERPRETER - g_error ("Mono IL interpreter support is missing\n"); -#endif - #ifdef MONO_CROSS_COMPILE g_error ("--interpreter on cross-compile runtimes not supported\n"); #endif @@ -3004,7 +3000,7 @@ mono_runtime_set_execution_mode_full (int mode, gboolean override) mono_llvm_only = TRUE; break; - case MONO_EE_MODE_INTERP: + case MONO_AOT_MODE_INTERP_ONLY: mono_check_interp_supported (); mono_use_interpreter = TRUE; diff --git a/mono/mini/ee.h b/mono/mini/ee.h index 55efe5390fa9..70c2d47bcb72 100644 --- a/mono/mini/ee.h +++ b/mono/mini/ee.h @@ -1,7 +1,6 @@ /* * Licensed to the .NET Foundation under one or more agreements. * The .NET Foundation licenses this file to you under the MIT license. - * See the LICENSE file in the project root for more information. */ #include diff --git a/mono/mini/exceptions-amd64.c b/mono/mini/exceptions-amd64.c index f795a06b1eca..8be488d1309e 100644 --- a/mono/mini/exceptions-amd64.c +++ b/mono/mini/exceptions-amd64.c @@ -1905,7 +1905,7 @@ void mono_arch_code_chunk_destroy (void *chunk) } #endif /* MONO_ARCH_HAVE_UNWIND_TABLE */ -#if MONO_SUPPORT_TASKLETS && !defined(DISABLE_JIT) +#if MONO_SUPPORT_TASKLETS && !defined(DISABLE_JIT) && !defined(ENABLE_NETCORE) MonoContinuationRestore mono_tasklets_arch_restore (void) { @@ -1956,7 +1956,7 @@ mono_tasklets_arch_restore (void) saved = start; return (MonoContinuationRestore)saved; } -#endif /* MONO_SUPPORT_TASKLETS && !defined(DISABLE_JIT) */ +#endif /* MONO_SUPPORT_TASKLETS && !defined(DISABLE_JIT) && !defined(ENABLE_NETCORE) */ /* * mono_arch_setup_resume_sighandler_ctx: @@ -1975,14 +1975,14 @@ mono_arch_setup_resume_sighandler_ctx (MonoContext *ctx, gpointer func) MONO_CONTEXT_SET_IP (ctx, func); } -#if !MONO_SUPPORT_TASKLETS || defined(DISABLE_JIT) +#if (!MONO_SUPPORT_TASKLETS || defined(DISABLE_JIT)) && !defined(ENABLE_NETCORE) MonoContinuationRestore mono_tasklets_arch_restore (void) { g_assert_not_reached (); return NULL; } -#endif /* !MONO_SUPPORT_TASKLETS || defined(DISABLE_JIT) */ +#endif /* (!MONO_SUPPORT_TASKLETS || defined(DISABLE_JIT)) && !defined(ENABLE_NETCORE) */ void mono_arch_undo_ip_adjustment (MonoContext *ctx) diff --git a/mono/mini/exceptions-arm64.c b/mono/mini/exceptions-arm64.c index 11cb6ccdd9d3..3c06a2ac070d 100644 --- a/mono/mini/exceptions-arm64.c +++ b/mono/mini/exceptions-arm64.c @@ -36,6 +36,8 @@ mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot) size = 256; code = start = mono_global_codeman_reserve (size); + MINI_BEGIN_CODEGEN (); + arm_movx (code, ARMREG_IP0, ARMREG_R0); ctx_reg = ARMREG_IP0; @@ -63,8 +65,8 @@ mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot) arm_brk (code, 0); g_assert ((code - start) < size); - mono_arch_flush_icache (start, code - start); - MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL)); + + MINI_END_CODEGEN (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL); if (info) *info = mono_tramp_info_create ("restore_context", start, code - start, ji, unwind_ops); @@ -106,6 +108,8 @@ mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot) * returning the value returned by the call. */ + MINI_BEGIN_CODEGEN (); + /* Setup a frame */ arm_stpx_pre (code, ARMREG_FP, ARMREG_LR, ARMREG_SP, -frame_size); arm_movspx (code, ARMREG_FP, ARMREG_SP); @@ -152,8 +156,8 @@ mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot) arm_retx (code, ARMREG_LR); g_assert ((code - start) < size); - mono_arch_flush_icache (start, code - start); - MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL)); + + MINI_END_CODEGEN (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL); if (info) *info = mono_tramp_info_create ("call_filter", start, code - start, ji, unwind_ops); @@ -186,6 +190,8 @@ get_throw_trampoline (int size, gboolean corlib, gboolean rethrow, gboolean llvm offset += num_fregs * 8; frame_size = ALIGN_TO (offset, MONO_ARCH_FRAME_ALIGNMENT); + MINI_BEGIN_CODEGEN (); + /* Setup a frame */ arm_stpx_pre (code, ARMREG_FP, ARMREG_LR, ARMREG_SP, -frame_size); arm_movspx (code, ARMREG_FP, ARMREG_SP); @@ -254,8 +260,8 @@ get_throw_trampoline (int size, gboolean corlib, gboolean rethrow, gboolean llvm arm_brk (code, 0x0); g_assert ((code - start) < size); - mono_arch_flush_icache (start, code - start); - MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL)); + + MINI_END_CODEGEN (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL); if (info) *info = mono_tramp_info_create (tramp_name, start, code - start, ji, unwind_ops); @@ -329,9 +335,6 @@ mono_arch_exceptions_init (void) GSList *tramps, *l; if (mono_aot_only) { - - // FIXME Macroize. - tramp = mono_aot_get_trampoline ("llvm_throw_corlib_exception_trampoline"); mono_register_jit_icall_info (&mono_get_jit_icall_info ()->mono_llvm_throw_corlib_exception_trampoline, tramp, "llvm_throw_corlib_exception_trampoline", NULL, TRUE, NULL); @@ -340,7 +343,6 @@ mono_arch_exceptions_init (void) tramp = mono_aot_get_trampoline ("llvm_resume_unwind_trampoline"); mono_register_jit_icall_info (&mono_get_jit_icall_info ()->mono_llvm_resume_unwind_trampoline, tramp, "llvm_resume_unwind_trampoline", NULL, TRUE, NULL); - } else { tramps = mono_arm_get_exception_trampolines (FALSE); for (l = tramps; l; l = l->next) { diff --git a/mono/mini/exceptions-riscv.c b/mono/mini/exceptions-riscv.c index 23f2f4499ca8..5c8983f801b5 100644 --- a/mono/mini/exceptions-riscv.c +++ b/mono/mini/exceptions-riscv.c @@ -1,7 +1,6 @@ /* * Licensed to the .NET Foundation under one or more agreements. * The .NET Foundation licenses this file to you under the MIT license. - * See the LICENSE file in the project root for more information. */ #include "mini-runtime.h" @@ -13,14 +12,15 @@ #ifndef DISABLE_JIT static gpointer -nop_stub (void) +nop_stub (unsigned int pattern) { guint8 *code, *start; start = code = mono_global_codeman_reserve (0x50); - /* nop */ - riscv_addi (code, RISCV_X0, RISCV_X0, 0); + /* hang in debugger */ + riscv_addi (code, RISCV_X0, RISCV_X0, pattern); + riscv_ebreak (code); mono_arch_flush_icache (start, code - start); @@ -30,43 +30,76 @@ nop_stub (void) gpointer mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot) { - *info = NULL; - return nop_stub (); + guint8 *start, *code; + MonoJumpInfo *ji = NULL; + GSList *unwind_ops = NULL; + int i, ctx_reg, size; + + size = 512; + code = start = mono_global_codeman_reserve (size); + + riscv_addi (code, RISCV_T0, RISCV_A0, 0); + ctx_reg = RISCV_T0; + + /* Restore fregs */ + for (i = 0; i < RISCV_N_FREGS; ++i) + riscv_flw (code, i, ctx_reg, MONO_STRUCT_OFFSET (MonoContext, fregs) + (i * sizeof (double))); + + /* Restore gregs */ + for (i = 0; i < RISCV_N_FREGS; ++i) { + if (i == ctx_reg) + continue; + riscv_ld (code, i, ctx_reg, MONO_STRUCT_OFFSET (MonoContext, gregs) + (i * sizeof (double))); + } + + riscv_ld (code, ctx_reg, ctx_reg, MONO_STRUCT_OFFSET (MonoContext, gregs) + (RISCV_ZERO * sizeof (double))); + riscv_jalr (code, RISCV_ZERO, ctx_reg, 0); + /* Not reached */ + riscv_ebreak (code); + + g_assert ((code - start) < size); + mono_arch_flush_icache (start, code - start); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL)); + + if (info) + *info = mono_tramp_info_create ("restore_context", start, code - start, ji, unwind_ops); + + return start; } gpointer mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot) { *info = NULL; - return nop_stub (); + return nop_stub (0x37); } gpointer mono_arch_get_throw_exception (MonoTrampInfo **info, gboolean aot) { *info = NULL; - return nop_stub (); + return nop_stub (0x77); } gpointer mono_arch_get_rethrow_exception (MonoTrampInfo **info, gboolean aot) { *info = NULL; - return nop_stub (); + return nop_stub (0x88); } gpointer mono_arch_get_rethrow_preserve_exception (MonoTrampInfo **info, gboolean aot) { *info = NULL; - return nop_stub (); + return nop_stub (0x99); } gpointer mono_arch_get_throw_corlib_exception (MonoTrampInfo **info, gboolean aot) { *info = NULL; - return nop_stub (); + return nop_stub (0xaa); } #else @@ -126,7 +159,63 @@ mono_arch_unwind_frame (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo MonoContext *ctx, MonoContext *new_ctx, MonoLMF **lmf, host_mgreg_t **save_locations, StackFrameInfo *frame) { - NOT_IMPLEMENTED; + gpointer ip = MONO_CONTEXT_GET_IP (ctx); + + memset (frame, 0, sizeof (StackFrameInfo)); + frame->ji = ji; + + *new_ctx = *ctx; + + if (ji != NULL) { + NOT_IMPLEMENTED; + host_mgreg_t regs [MONO_MAX_IREGS + 12 + 1]; + guint8 *cfa; + guint32 unwind_info_len; + guint8 *unwind_info; + + + if (ji->is_trampoline) + frame->type = FRAME_TYPE_TRAMPOLINE; + else + frame->type = FRAME_TYPE_MANAGED; + + unwind_info = mono_jinfo_get_unwind_info (ji, &unwind_info_len); + + memcpy (regs, &new_ctx->gregs, sizeof (host_mgreg_t) * 32); + + /* f8..f9 & f18..f27 are callee saved */ + for (int i = 0; i < 2; i++) + (regs + MONO_MAX_IREGS) [i] = *((host_mgreg_t*)&new_ctx->fregs [RISCV_F8 + i]); + for (int i = 0; i < 10; i++) + (regs + MONO_MAX_IREGS) [i] = *((host_mgreg_t*)&new_ctx->fregs [RISCV_F18 + i]); + + gboolean success = mono_unwind_frame (unwind_info, unwind_info_len, (guint8*)ji->code_start, + (guint8*)ji->code_start + ji->code_size, + (guint8*)ip, NULL, regs, MONO_MAX_IREGS + 8, + save_locations, MONO_MAX_IREGS, (guint8**)&cfa); + + if (!success) + return FALSE; + + memcpy (&new_ctx->gregs, regs, sizeof (host_mgreg_t) * 32); + for (int i = 0; i < 2; i++) + *((host_mgreg_t*)&new_ctx->fregs [RISCV_F8 + i]) = (regs + MONO_MAX_IREGS) [i]; + for (int i = 0; i < 10; i++) + *((host_mgreg_t*)&new_ctx->fregs [RISCV_F18 + i]) = (regs + MONO_MAX_IREGS) [i]; + + new_ctx->gregs [RISCV_SP] = (host_mgreg_t)(gsize)cfa; + + if (*lmf) + NOT_IMPLEMENTED; + + /* we substract 1, so that the IP points into the call instruction */ + new_ctx->gregs [RISCV_ZERO]--; + + return TRUE; + } else if (*lmf) { + NOT_IMPLEMENTED; + } + return FALSE; } @@ -178,11 +267,11 @@ mono_arch_setup_resume_sighandler_ctx (MonoContext *ctx, gpointer func) void mono_arch_undo_ip_adjustment (MonoContext *context) { - NOT_IMPLEMENTED; + context->gregs[RISCV_ZERO]++; } void mono_arch_do_ip_adjustment (MonoContext *context) { - g_assert_not_reached (); + context->gregs[RISCV_ZERO]--; } diff --git a/mono/mini/exceptions-x86.c b/mono/mini/exceptions-x86.c index a0f79a71426c..ef9927577e6a 100644 --- a/mono/mini/exceptions-x86.c +++ b/mono/mini/exceptions-x86.c @@ -1175,7 +1175,7 @@ mono_arch_handle_altstack_exception (void *sigctx, MONO_SIG_HANDLER_INFO_TYPE *s #endif } -#if MONO_SUPPORT_TASKLETS +#if MONO_SUPPORT_TASKLETS && !defined(ENABLE_NETCORE) MonoContinuationRestore mono_tasklets_arch_restore (void) { diff --git a/mono/mini/helpers.c b/mono/mini/helpers.c index daffe1f52e17..eddfe646d78f 100644 --- a/mono/mini/helpers.c +++ b/mono/mini/helpers.c @@ -268,7 +268,7 @@ mono_disassemble_code (MonoCompile *cfg, guint8 *code, int size, char *id) fflush (stdout); -#if defined(__arm__) || defined(__aarch64__) +#if (defined(__arm__) || defined(__aarch64__)) && !defined(TARGET_OSX) /* * The arm assembler inserts ELF directives instructing objdump to display * everything as data. diff --git a/mono/mini/interp/interp-internals.h b/mono/mini/interp/interp-internals.h index 895311b569b8..e3f3e04c8c9e 100644 --- a/mono/mini/interp/interp-internals.h +++ b/mono/mini/interp/interp-internals.h @@ -129,6 +129,8 @@ typedef enum { IMETHOD_CODE_UNKNOWN } InterpMethodCodeType; +#define PROFILE_INTERP 0 + /* * Structure representing a method transformed for the interpreter * This is domain specific @@ -158,7 +160,6 @@ struct InterpMethod { MonoJitInfo *jinfo; MonoDomain *domain; - guint32 locals_size; guint32 total_locals_size; guint32 stack_size; guint32 vt_stack_size; @@ -175,6 +176,10 @@ struct InterpMethod { unsigned int init_locals : 1; unsigned int vararg : 1; unsigned int needs_thread_attach : 1; +#if PROFILE_INTERP + long calls; + long opcounts; +#endif }; /* Used for localloc memory allocation */ @@ -223,7 +228,6 @@ typedef struct { struct InterpFrame { InterpFrame *parent; /* parent */ InterpMethod *imethod; /* parent */ - stackval *stack_args; /* parent */ stackval *retval; /* parent */ stackval *stack; InterpFrame *next_free; diff --git a/mono/mini/interp/interp-intrins.c b/mono/mini/interp/interp-intrins.c new file mode 100644 index 000000000000..b4093225dd28 --- /dev/null +++ b/mono/mini/interp/interp-intrins.c @@ -0,0 +1,140 @@ +/* + * Intrinsics for libraries methods that are heavily used in interpreter relevant + * scenarios and where compiling these methods with the interpreter would have + * heavy performance impact. + */ + +#include "interp-intrins.h" + +#include +#include + +static guint32 +rotate_left (guint32 value, int offset) +{ + return (value << offset) | (value >> (32 - offset)); +} + +void +interp_intrins_marvin_block (guint32 *pp0, guint32 *pp1) +{ + // Marvin.Block + guint32 p0 = *pp0; + guint32 p1 = *pp1; + + p1 ^= p0; + p0 = rotate_left (p0, 20); + + p0 += p1; + p1 = rotate_left (p1, 9); + + p1 ^= p0; + p0 = rotate_left (p0, 27); + + p0 += p1; + p1 = rotate_left (p1, 19); + + *pp0 = p0; + *pp1 = p1; +} + +guint32 +interp_intrins_ascii_chars_to_uppercase (guint32 value) +{ + // Utf16Utility.ConvertAllAsciiCharsInUInt32ToUppercase + guint32 lowerIndicator = value + 0x00800080 - 0x00610061; + guint32 upperIndicator = value + 0x00800080 - 0x007B007B; + guint32 combinedIndicator = (lowerIndicator ^ upperIndicator); + guint32 mask = (combinedIndicator & 0x00800080) >> 2; + + return value ^ mask; +} + +int +interp_intrins_ordinal_ignore_case_ascii (guint32 valueA, guint32 valueB) +{ + // Utf16Utility.UInt32OrdinalIgnoreCaseAscii + guint32 differentBits = valueA ^ valueB; + guint32 lowerIndicator = valueA + 0x01000100 - 0x00410041; + guint32 upperIndicator = (valueA | 0x00200020u) + 0x00800080 - 0x007B007B; + guint32 combinedIndicator = lowerIndicator | upperIndicator; + return (((combinedIndicator >> 2) | ~0x00200020) & differentBits) == 0; +} + +int +interp_intrins_64ordinal_ignore_case_ascii (guint64 valueA, guint64 valueB) +{ + // Utf16Utility.UInt64OrdinalIgnoreCaseAscii + guint64 lowerIndicator = valueA + 0x0080008000800080l - 0x0041004100410041l; + guint64 upperIndicator = (valueA | 0x0020002000200020l) + 0x0100010001000100l - 0x007B007B007B007Bl; + guint64 combinedIndicator = (0x0080008000800080l & lowerIndicator & upperIndicator) >> 2; + return (valueA | combinedIndicator) == (valueB | combinedIndicator); +} + +static int +interp_intrins_count_digits (guint32 value) +{ + int digits = 1; + if (value >= 100000) { + value /= 100000; + digits += 5; + } + if (value < 10) { + // no-op + } else if (value < 100) { + digits++; + } else if (value < 1000) { + digits += 2; + } else if (value < 10000) { + digits += 3; + } else { + digits += 4; + } + return digits; +} + +static guint32 +interp_intrins_math_divrem (guint32 a, guint32 b, guint32 *result) +{ + guint32 div = a / b; + *result = a - (div * b); + return div; +} + +MonoString* +interp_intrins_u32_to_decstr (guint32 value, MonoArray *cache, MonoVTable *vtable) +{ + // Number.UInt32ToDecStr + int bufferLength = interp_intrins_count_digits (value); + + if (bufferLength == 1) + return mono_array_get_fast (cache, MonoString*, value); + + int size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)bufferLength + 1) * 2)); + MonoString* result = mono_gc_alloc_string (vtable, size, bufferLength); + mono_unichar2 *buffer = &result->chars [0]; + mono_unichar2 *p = buffer + bufferLength; + do { + guint32 remainder; + value = interp_intrins_math_divrem (value, 10, &remainder); + *(--p) = (mono_unichar2)(remainder + '0'); + } while (value != 0); + return result; +} + +mono_u +interp_intrins_widen_ascii_to_utf16 (guint8 *pAsciiBuffer, mono_unichar2 *pUtf16Buffer, mono_u elementCount) +{ + // ASCIIUtility.WidenAsciiToUtf16 + mono_u currentOffset = 0; + + while (currentOffset < elementCount) { + guint16 asciiData = pAsciiBuffer [currentOffset]; + if ((asciiData & 0x80) != 0) + return currentOffset; + + pUtf16Buffer [currentOffset] = (mono_unichar2)asciiData; + currentOffset++; + } + return currentOffset; +} diff --git a/mono/mini/interp/interp-intrins.h b/mono/mini/interp/interp-intrins.h new file mode 100644 index 000000000000..2be852f33152 --- /dev/null +++ b/mono/mini/interp/interp-intrins.h @@ -0,0 +1,27 @@ +#ifndef __MONO_MINI_INTERP_INTRINSICS_H__ +#define __MONO_MINI_INTERP_INTRINSICS_H__ + +#include +#include + +#include "interp-internals.h" + +void +interp_intrins_marvin_block (guint32 *pp0, guint32 *pp1); + +guint32 +interp_intrins_ascii_chars_to_uppercase (guint32 val); + +int +interp_intrins_ordinal_ignore_case_ascii (guint32 valueA, guint32 valueB); + +int +interp_intrins_64ordinal_ignore_case_ascii (guint64 valueA, guint64 valueB); + +MonoString* +interp_intrins_u32_to_decstr (guint32 value, MonoArray *cache, MonoVTable *vtable); + +mono_u +interp_intrins_widen_ascii_to_utf16 (guint8 *pAsciiBuffer, mono_unichar2 *pUtf16Buffer, mono_u elementCount); + +#endif /* __MONO_MINI_INTERP_INTRINSICS_H__ */ diff --git a/mono/mini/interp/interp.c b/mono/mini/interp/interp.c index ea7dbc2ddb94..53d20e1997c8 100644 --- a/mono/mini/interp/interp.c +++ b/mono/mini/interp/interp.c @@ -63,6 +63,7 @@ #include "interp.h" #include "interp-internals.h" #include "mintops.h" +#include "interp-intrins.h" #include #include @@ -95,8 +96,6 @@ struct FrameClauseArgs { MonoException *filter_exception; /* Frame that is executing this clause */ InterpFrame *exec_frame; - /* If set, exec_frame is a duplicate separate frame of this frame */ - InterpFrame *base_frame; }; /* @@ -222,12 +221,11 @@ frame_data_allocator_pop (FrameDataAllocator *stack, InterpFrame *frame) * Reinitialize a frame. */ static void -reinit_frame (InterpFrame *frame, InterpFrame *parent, InterpMethod *imethod, stackval *stack_args) +reinit_frame (InterpFrame *frame, InterpFrame *parent, InterpMethod *imethod, stackval *sp) { frame->parent = parent; frame->imethod = imethod; - frame->stack_args = stack_args; - frame->stack = NULL; + frame->stack = sp; frame->state.ip = NULL; } @@ -246,6 +244,8 @@ static gboolean interp_init_done = FALSE; static void interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs *clause_args); +static MonoException* do_transform_method (InterpFrame *frame, ThreadContext *context); + static InterpMethod* lookup_method_pointer (gpointer addr); typedef void (*ICallMethod) (InterpFrame *frame); @@ -329,7 +329,7 @@ int mono_interp_traceopt = 0; #endif -#if defined(__GNUC__) && !defined(TARGET_WASM) && !COUNT_OPS && !DEBUG_INTERP && !ENABLE_CHECKED_BUILD +#if defined(__GNUC__) && !defined(TARGET_WASM) && !COUNT_OPS && !DEBUG_INTERP && !ENABLE_CHECKED_BUILD && !PROFILE_INTERP #define USE_COMPUTED_GOTO 1 #endif @@ -445,7 +445,7 @@ ves_real_abort (int line, MonoMethod *mh, #define ves_abort() \ do {\ ves_real_abort(__LINE__, frame->imethod->method, ip, frame->stack, sp); \ - goto abort_label; \ + THROW_EX (mono_get_exception_execution_engine (NULL), ip); \ } while (0); static InterpMethod* @@ -1090,7 +1090,7 @@ interp_throw (ThreadContext *context, MonoException *ex, InterpFrame *frame, con #define NULL_CHECK(o) do { \ if (G_UNLIKELY (!(o))) \ - goto null_label; \ + THROW_EX (mono_get_exception_null_reference (), ip); \ } while (0) #define EXCEPTION_CHECKPOINT \ @@ -1284,8 +1284,9 @@ static InterpMethodArguments* build_args_from_sig (MonoMethodSignature *sig, Int size_t int_f = 0; if (sig->hasthis) { - margs->iargs [0] = frame->stack_args->data.p; + margs->iargs [0] = frame->stack [0].data.p; int_i++; + g_error ("FIXME if hasthis, we incorrectly access the args below"); } for (int i = 0; i < sig->param_count; i++) { @@ -1312,7 +1313,7 @@ static InterpMethodArguments* build_args_from_sig (MonoMethodSignature *sig, Int case MONO_TYPE_I8: case MONO_TYPE_U8: #endif - margs->iargs [int_i] = frame->stack_args [i].data.p; + margs->iargs [int_i] = frame->stack [i].data.p; #if DEBUG_INTERP g_print ("build_args_from_sig: margs->iargs [%d]: %p (frame @ %d)\n", int_i, margs->iargs [int_i], i); #endif @@ -1321,7 +1322,7 @@ static InterpMethodArguments* build_args_from_sig (MonoMethodSignature *sig, Int #if SIZEOF_VOID_P == 4 case MONO_TYPE_I8: case MONO_TYPE_U8: { - stackval *sarg = &frame->stack_args [i]; + stackval *sarg = &frame->stack [i]; #ifdef TARGET_ARM /* pairs begin at even registers */ if (i8_align == 8 && int_i & 1) @@ -1340,9 +1341,9 @@ static InterpMethodArguments* build_args_from_sig (MonoMethodSignature *sig, Int case MONO_TYPE_R4: case MONO_TYPE_R8: if (ptype == MONO_TYPE_R4) - * (float *) &(margs->fargs [int_f]) = frame->stack_args [i].data.f_r4; + * (float *) &(margs->fargs [int_f]) = frame->stack [i].data.f_r4; else - margs->fargs [int_f] = frame->stack_args [i].data.f; + margs->fargs [int_f] = frame->stack [i].data.f; #if DEBUG_INTERP g_print ("build_args_from_sig: margs->fargs [%d]: %p (%f) (frame @ %d)\n", int_f, margs->fargs [int_f], margs->fargs [int_f], i); #endif @@ -1400,7 +1401,7 @@ interp_frame_arg_to_data (MonoInterpFrameHandle frame, MonoMethodSignature *sig, if (index == -1) stackval_to_data (sig->ret, iframe->retval, data, sig->pinvoke); else - stackval_to_data (sig->params [index], &iframe->stack_args [index], data, sig->pinvoke); + stackval_to_data (sig->params [index], &iframe->stack [index], data, sig->pinvoke); } static void @@ -1411,9 +1412,9 @@ interp_data_to_frame_arg (MonoInterpFrameHandle frame, MonoMethodSignature *sig, if (index == -1) stackval_from_data (sig->ret, iframe->retval, data, sig->pinvoke); else if (sig->hasthis && index == 0) - iframe->stack_args [index].data.p = *(gpointer*)data; + iframe->stack [index].data.p = *(gpointer*)data; else - stackval_from_data (sig->params [index - sig->hasthis], &iframe->stack_args [index], data, sig->pinvoke); + stackval_from_data (sig->params [index - sig->hasthis], &iframe->stack [index], data, sig->pinvoke); } static gpointer @@ -1424,14 +1425,14 @@ interp_frame_arg_to_storage (MonoInterpFrameHandle frame, MonoMethodSignature *s if (index == -1) return stackval_to_data_addr (sig->ret, iframe->retval); else - return stackval_to_data_addr (sig->params [index], &iframe->stack_args [index]); + return stackval_to_data_addr (sig->params [index], &iframe->stack [index]); } static void interp_frame_arg_set_storage (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gpointer storage) { InterpFrame *iframe = (InterpFrame*)frame; - stackval *val = (index == -1) ? iframe->retval : &iframe->stack_args [index]; + stackval *val = (index == -1) ? iframe->retval : &iframe->stack [index]; MonoType *type = (index == -1) ? sig->ret : sig->params [index]; switch (type->type) { @@ -1486,7 +1487,10 @@ ves_pinvoke_method ( gpointer *cache, stackval *sp) { - InterpFrame frame = {parent_frame, NULL, sp, retval}; + InterpFrame frame = {0}; + frame.parent = parent_frame; + frame.stack = sp; + frame.retval = retval; MonoLMFExt ext; gpointer args; @@ -1776,11 +1780,11 @@ dump_args (InterpFrame *inv) if (signature->hasthis) { MonoMethod *method = inv->imethod->method; - dump_stackval (str, inv->stack_args, m_class_get_byval_arg (method->klass)); + dump_stackval (str, inv->stack, m_class_get_byval_arg (method->klass)); } for (i = 0; i < signature->param_count; ++i) - dump_stackval (str, inv->stack_args + (!!signature->hasthis) + i, signature->params [i]); + dump_stackval (str, inv->stack + (!!signature->hasthis) + i, signature->params [i]); return g_string_free (str, FALSE); } @@ -1865,6 +1869,7 @@ interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject MonoMethodSignature *sig = mono_method_signature_internal (method); MonoClass *klass = mono_class_from_mono_type_internal (sig->ret); stackval result; + stackval *sp = (stackval*)context->stack_pointer; MonoMethod *target_method = method; error_init (error); @@ -1880,30 +1885,38 @@ interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject //* MonoObject *runtime_invoke (MonoObject *this_obj, void **params, MonoObject **exc, void* method) result.data.vt = alloca (mono_class_instance_size (klass)); - stackval args [4]; - if (sig->hasthis) - args [0].data.p = obj; + sp [0].data.p = obj; else - args [0].data.p = NULL; - args [1].data.p = params; - args [2].data.p = exc; - args [3].data.p = target_method; + sp [0].data.p = NULL; + sp [1].data.p = params; + sp [2].data.p = exc; + sp [3].data.p = target_method; InterpMethod *imethod = mono_interp_get_imethod (domain, invoke_wrapper, error); mono_error_assert_ok (error); - InterpFrame frame = {NULL, imethod, args, &result}; + InterpFrame frame = {0}; + frame.imethod = imethod; + frame.stack = sp; + frame.retval = &result; + + // The method to execute might not be transformed yet, so we don't know how much stack + // it uses. We bump the stack_pointer here so any code triggered by method compilation + // will not attempt to use the space that we used to push the args for this method. + // The real top of stack for this method will be set in interp_exec_method once the + // method is transformed. + context->stack_pointer = (guchar*)(sp + 4); interp_exec_method (&frame, context, NULL); + context->stack_pointer = (guchar*)sp; + if (context->has_resume_state) { - // This can happen on wasm !? - MonoException *thrown_exc = (MonoException*) mono_gchandle_get_target_internal (context->exc_gchandle); - if (exc) - *exc = (MonoObject*)thrown_exc; - else - mono_error_set_exception_instance (error, thrown_exc); + /* + * This can happen on wasm where native frames cannot be skipped during EH. + * EH processing will continue when control returns to the interpreter. + */ return NULL; } return (MonoObject*)result.data.p; @@ -1924,8 +1937,8 @@ interp_entry (InterpEntryData *data) { InterpMethod *rmethod; ThreadContext *context; + stackval *sp; stackval result; - stackval *args; MonoMethod *method; MonoMethodSignature *sig; MonoType *type; @@ -1943,17 +1956,15 @@ interp_entry (InterpEntryData *data) orig_domain = mono_threads_attach_coop (mono_domain_get (), &attach_cookie); context = get_context (); + sp = (stackval*)context->stack_pointer; method = rmethod->method; sig = mono_method_signature_internal (method); // FIXME: Optimize this - //printf ("%s\n", mono_method_full_name (method, 1)); - - args = g_newa (stackval, sig->param_count + (sig->hasthis ? 1 : 0)); if (sig->hasthis) - args [0].data.p = data->this_arg; + sp [0].data.p = data->this_arg; gpointer *params; if (data->many_args) @@ -1963,29 +1974,32 @@ interp_entry (InterpEntryData *data) for (i = 0; i < sig->param_count; ++i) { int a_index = i + (sig->hasthis ? 1 : 0); if (sig->params [i]->byref) { - args [a_index].data.p = params [i]; + sp [a_index].data.p = params [i]; continue; } type = rmethod->param_types [i]; switch (type->type) { case MONO_TYPE_VALUETYPE: - args [a_index].data.p = params [i]; + sp [a_index].data.p = params [i]; break; case MONO_TYPE_GENERICINST: if (MONO_TYPE_IS_REFERENCE (type)) - args [a_index].data.p = *(gpointer*)params [i]; + sp [a_index].data.p = *(gpointer*)params [i]; else - args [a_index].data.vt = params [i]; + sp [a_index].data.vt = params [i]; break; default: - stackval_from_data (type, &args [a_index], params [i], FALSE); + stackval_from_data (type, &sp [a_index], params [i], FALSE); break; } } memset (&result, 0, sizeof (result)); - InterpFrame frame = {NULL, data->rmethod, args, &result}; + InterpFrame frame = {0}; + frame.imethod = data->rmethod; + frame.stack = sp; + frame.retval = &result; type = rmethod->rtype; switch (type->type) { @@ -2000,8 +2014,12 @@ interp_entry (InterpEntryData *data) break; } + context->stack_pointer = (guchar*)(sp + sig->hasthis + sig->param_count); + interp_exec_method (&frame, context, NULL); + context->stack_pointer = (guchar*)sp; + g_assert (!context->has_resume_state); if (rmethod->needs_thread_attach) @@ -2367,7 +2385,6 @@ init_jit_call_info (InterpMethod *rmethod, MonoError *error) static MONO_NEVER_INLINE void do_jit_call (stackval *sp, unsigned char *vt_sp, InterpFrame *frame, InterpMethod *rmethod, MonoError *error) { - MonoMethodSignature *sig; guint8 res_buf [256]; MonoLMFExt ext; JitCallInfo *cinfo; @@ -2384,8 +2401,6 @@ do_jit_call (stackval *sp, unsigned char *vt_sp, InterpFrame *frame, InterpMetho } cinfo = (JitCallInfo*)rmethod->jit_call_info; - sig = cinfo->sig; - /* * Convert the arguments on the interpeter stack to the format expected by the gsharedvt_out wrapper. */ @@ -2495,6 +2510,12 @@ do_transform_method (InterpFrame *frame, ThreadContext *context) gboolean push_lmf = frame->parent != NULL; ERROR_DECL (error); +#if DEBUG_INTERP + char *mn = mono_method_full_name (frame->imethod->method, TRUE); + g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn); + g_free (mn); +#endif + /* Use the parent frame as the current frame is not complete yet */ if (push_lmf) interp_push_lmf (&ext, frame->parent); @@ -2705,8 +2726,8 @@ static MONO_NEVER_INLINE void interp_entry_from_trampoline (gpointer ccontext_untyped, gpointer rmethod_untyped) { ThreadContext *context; + stackval *sp; stackval result; - stackval *args; MonoMethod *method; MonoMethodSignature *sig; CallContext *ccontext = (CallContext*) ccontext_untyped; @@ -2718,6 +2739,7 @@ interp_entry_from_trampoline (gpointer ccontext_untyped, gpointer rmethod_untype orig_domain = mono_threads_attach_coop (mono_domain_get (), &attach_cookie); context = get_context (); + sp = (stackval*)context->stack_pointer; method = rmethod->method; sig = mono_method_signature_internal (method); @@ -2728,24 +2750,28 @@ interp_entry_from_trampoline (gpointer ccontext_untyped, gpointer rmethod_untype sig = newsig; } - args = (stackval*)alloca (sizeof (stackval) * (sig->param_count + (sig->hasthis ? 1 : 0))); - /* Allocate storage for value types */ for (i = 0; i < sig->param_count; i++) { MonoType *type = sig->params [i]; - alloc_storage_for_stackval (&args [i + sig->hasthis], type, sig->pinvoke); + alloc_storage_for_stackval (&sp [i + sig->hasthis], type, sig->pinvoke); } if (sig->ret->type != MONO_TYPE_VOID) alloc_storage_for_stackval (&result, sig->ret, sig->pinvoke); - InterpFrame frame = {NULL, rmethod, args, &result}; + InterpFrame frame = {0}; + frame.imethod = rmethod; + frame.stack = sp; + frame.retval = &result; /* Copy the args saved in the trampoline to the frame stack */ mono_arch_get_native_call_context_args (ccontext, &frame, sig); + context->stack_pointer = (guchar*)(sp + sig->hasthis + sig->param_count); + interp_exec_method (&frame, context, NULL); + context->stack_pointer = (guchar*)sp; g_assert (!context->has_resume_state); if (rmethod->needs_thread_attach) @@ -2890,19 +2916,11 @@ interp_create_method_pointer_llvmonly (MonoMethod *method, gboolean unbox, MonoE static gpointer interp_create_method_pointer (MonoMethod *method, gboolean compile, MonoError *error) { -#ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED - if (mono_llvm_only) - return (gpointer)no_llvmonly_interp_method_pointer; - return (gpointer)interp_no_native_to_managed; -#else gpointer addr, entry_func, entry_wrapper = NULL; MonoDomain *domain = mono_domain_get (); MonoJitDomainInfo *info; InterpMethod *imethod = mono_interp_get_imethod (domain, method, error); - if (mono_llvm_only) - return (gpointer)no_llvmonly_interp_method_pointer; - if (imethod->jit_entry) return imethod->jit_entry; @@ -2920,9 +2938,59 @@ interp_create_method_pointer (MonoMethod *method, gboolean compile, MonoError *e sig = newsig; } - if (mono_llvm_only) + if (sig->param_count > MAX_INTERP_ENTRY_ARGS) { + entry_func = (gpointer)interp_entry_general; + } else if (sig->hasthis) { + if (sig->ret->type == MONO_TYPE_VOID) + entry_func = entry_funcs_instance [sig->param_count]; + else + entry_func = entry_funcs_instance_ret [sig->param_count]; + } else { + if (sig->ret->type == MONO_TYPE_VOID) + entry_func = entry_funcs_static [sig->param_count]; + else + entry_func = entry_funcs_static_ret [sig->param_count]; + } + +#ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED +#ifdef HOST_WASM + if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) { + WrapperInfo *info = mono_marshal_get_wrapper_info (method); + MonoMethod *orig_method = info->d.native_to_managed.method; + + /* + * These are called from native code. Ask the host app for a trampoline. + */ + MonoFtnDesc *ftndesc = g_new0 (MonoFtnDesc, 1); + ftndesc->addr = entry_func; + ftndesc->arg = imethod; + + addr = mono_wasm_get_native_to_interp_trampoline (orig_method, ftndesc); + if (addr) { + mono_memory_barrier (); + imethod->jit_entry = addr; + return addr; + } + +#ifdef ENABLE_NETCORE + /* + * The runtime expects a function pointer unique to method and + * the native caller expects a function pointer with the + * right signature, so fail right away. + */ + mono_error_set_platform_not_supported (error, "No native to managed transitions on this platform."); + return NULL; +#endif + } +#endif + return (gpointer)interp_no_native_to_managed; +#endif + + if (mono_llvm_only) { /* The caller should call interp_create_method_pointer_llvmonly */ - g_assert_not_reached (); + //g_assert_not_reached (); + return (gpointer)no_llvmonly_interp_method_pointer; + } if (method->wrapper_type && method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) return imethod; @@ -2939,21 +3007,7 @@ interp_create_method_pointer (MonoMethod *method, gboolean compile, MonoError *e entry_wrapper = mono_jit_compile_method_jit_only (wrapper, error); #endif - if (entry_wrapper) { - if (sig->param_count > MAX_INTERP_ENTRY_ARGS) { - entry_func = (gpointer)interp_entry_general; - } else if (sig->hasthis) { - if (sig->ret->type == MONO_TYPE_VOID) - entry_func = entry_funcs_instance [sig->param_count]; - else - entry_func = entry_funcs_instance_ret [sig->param_count]; - } else { - if (sig->ret->type == MONO_TYPE_VOID) - entry_func = entry_funcs_static [sig->param_count]; - else - entry_func = entry_funcs_static_ret [sig->param_count]; - } - } else { + if (!entry_wrapper) { #ifndef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE g_assertion_message ("couldn't compile wrapper \"%s\" for \"%s\"", mono_method_get_name_full (wrapper, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL), @@ -3010,7 +3064,6 @@ interp_create_method_pointer (MonoMethod *method, gboolean compile, MonoError *e imethod->jit_entry = addr; return addr; -#endif } static void @@ -3059,7 +3112,7 @@ static long opcode_counts[MINT_LASTOP]; if (G_UNLIKELY (!(vtable)->initialized)) { \ mono_runtime_class_init_full ((vtable), error); \ if (!is_ok (error)) \ - goto throw_error_label; \ + THROW_EX (mono_error_convert_to_exception (error), ip); \ } \ } while (0); @@ -3281,7 +3334,7 @@ g_warning_d (const char *format, int d) #if !USE_COMPUTED_GOTO static void -g_error_xsx (const char *format, int x1, const char *s, int x2) +interp_error_xsx (const char *format, int x1, const char *s, int x2) { g_error (format, x1, s, x2); } @@ -3292,22 +3345,20 @@ method_entry (ThreadContext *context, InterpFrame *frame, #if DEBUG_INTERP int *out_tracing, #endif - MonoException **out_ex, FrameClauseArgs *clause_args) + MonoException **out_ex) { gboolean slow = FALSE; #if DEBUG_INTERP debug_enter (frame, out_tracing); #endif +#if PROFILE_INTERP + frame->imethod->calls++; +#endif *out_ex = NULL; if (!G_UNLIKELY (frame->imethod->transformed)) { slow = TRUE; -#if DEBUG_INTERP - char *mn = mono_method_full_name (frame->imethod->method, TRUE); - g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn); - g_free (mn); -#endif MonoException *ex = do_transform_method (frame, context); if (ex) { *out_ex = ex; @@ -3320,13 +3371,6 @@ method_entry (ThreadContext *context, InterpFrame *frame, } } - if (!clause_args || clause_args->base_frame) { - frame->stack = (stackval*)context->stack_pointer; - context->stack_pointer += frame->imethod->alloca_size; - /* Make sure the stack pointer is bumped before we store any references on the stack */ - mono_compiler_barrier (); - } - return slow; } @@ -3357,6 +3401,10 @@ method_entry (ThreadContext *context, InterpFrame *frame, finally_ips = NULL; \ } while (0) +#if PROFILE_INTERP +static long total_executed_opcodes; +#endif + /* * If CLAUSE_ARGS is non-null, start executing from it. * The ERROR argument is used to avoid declaring an error object for every interp frame, its not used @@ -3392,14 +3440,17 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs #if DEBUG_INTERP &tracing, #endif - &ex, clause_args)) { + &ex)) { if (ex) THROW_EX (ex, NULL); EXCEPTION_CHECKPOINT; } - if (clause_args && clause_args->base_frame) - memcpy (frame->stack, clause_args->base_frame->stack, frame->imethod->alloca_size); + if (!clause_args) { + context->stack_pointer = (guchar*)frame->stack + frame->imethod->alloca_size; + /* Make sure the stack pointer is bumped before we store any references on the stack */ + mono_compiler_barrier (); + } INIT_INTERP_STATE (frame, clause_args); @@ -3426,6 +3477,10 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs * but it may be useful for debug */ while (1) { +#if PROFILE_INTERP + frame->imethod->opcounts++; + total_executed_opcodes++; +#endif MintOpcode opcode; #ifdef ENABLE_CHECKED_BUILD guchar *vt_start = (guchar*)frame->stack + frame->imethod->total_locals_size; @@ -3440,8 +3495,8 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs DUMP_INSTR(); MINT_IN_SWITCH (*ip) { MINT_IN_CASE(MINT_INITLOCALS) - memset (locals, 0, frame->imethod->locals_size); - ++ip; + memset (locals + ip [1], 0, ip [2]); + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_NOP) MINT_IN_CASE(MINT_NIY) @@ -3914,12 +3969,16 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs #if DEBUG_INTERP &tracing, #endif - &ex, NULL)) { + &ex)) { if (ex) THROW_EX (ex, NULL); EXCEPTION_CHECKPOINT; } + context->stack_pointer = (guchar*)sp + cmethod->alloca_size; + /* Make sure the stack pointer is bumped before we store any references on the stack */ + mono_compiler_barrier (); + INIT_INTERP_STATE (frame, NULL); MINT_IN_BREAK; @@ -4012,19 +4071,20 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs g_assert_checked (sp == (stackval*)(locals + frame->imethod->total_locals_size + frame->imethod->vt_stack_size)); goto exit_frame; MINT_IN_CASE(MINT_RET_VT) { - gpointer dest_vt; int const i32 = READ32 (ip + 1); --sp; if (frame->parent) { - dest_vt = frame->parent->state.vt_sp; - /* Push the valuetype in the parent frame */ + gpointer dest_vt = frame->parent->state.vt_sp; + // Push the valuetype in the parent frame. parent->state.sp [0] can be inside + // vt to be returned, so we need to copy it before updating sp [0]. + memcpy (dest_vt, sp->data.p, i32); frame->parent->state.sp [0].data.p = dest_vt; frame->parent->state.sp++; frame->parent->state.vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT); } else { - dest_vt = frame->retval->data.p; + gpointer dest_vt = frame->retval->data.p; + memcpy (dest_vt, sp->data.p, i32); } - memcpy (dest_vt, sp->data.p, i32); g_assert_checked (sp == (stackval*)(locals + frame->imethod->total_locals_size + frame->imethod->vt_stack_size)); goto exit_frame; } @@ -4045,19 +4105,18 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs g_assert_checked (sp == (stackval*)(locals + frame->imethod->total_locals_size + frame->imethod->vt_stack_size)); goto exit_frame; MINT_IN_CASE(MINT_RET_VT_LOCALLOC) { - gpointer dest_vt; int const i32 = READ32 (ip + 1); --sp; if (frame->parent) { - dest_vt = frame->parent->state.vt_sp; + gpointer dest_vt = frame->parent->state.vt_sp; /* Push the valuetype in the parent frame */ + memcpy (dest_vt, sp->data.p, i32); frame->parent->state.sp [0].data.p = dest_vt; frame->parent->state.sp++; frame->parent->state.vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT); } else { - dest_vt = frame->retval->data.p; + memcpy (frame->retval->data.p, sp->data.p, i32); } - memcpy (dest_vt, sp->data.p, i32); frame_data_allocator_pop (&context->data_stack, frame); g_assert_checked (sp == (stackval*)(locals + frame->imethod->total_locals_size + frame->imethod->vt_stack_size)); goto exit_frame; @@ -4530,31 +4589,37 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs MINT_IN_BREAK; } MINT_IN_CASE(MINT_STIND_REF) + NULL_CHECK (sp [-2].data.p); ++ip; sp -= 2; mono_gc_wbarrier_generic_store_internal (sp->data.p, sp [1].data.o); MINT_IN_BREAK; MINT_IN_CASE(MINT_STIND_I1) + NULL_CHECK (sp [-2].data.p); ++ip; sp -= 2; * (gint8 *) sp->data.p = (gint8)sp[1].data.i; MINT_IN_BREAK; MINT_IN_CASE(MINT_STIND_I2) + NULL_CHECK (sp [-2].data.p); ++ip; sp -= 2; * (gint16 *) sp->data.p = (gint16)sp[1].data.i; MINT_IN_BREAK; MINT_IN_CASE(MINT_STIND_I4) + NULL_CHECK (sp [-2].data.p); ++ip; sp -= 2; * (gint32 *) sp->data.p = sp[1].data.i; MINT_IN_BREAK; MINT_IN_CASE(MINT_STIND_I) + NULL_CHECK (sp [-2].data.p); ++ip; sp -= 2; * (mono_i *) sp->data.p = (mono_i)sp[1].data.p; MINT_IN_BREAK; MINT_IN_CASE(MINT_STIND_I8) + NULL_CHECK (sp [-2].data.p); ++ip; sp -= 2; #ifdef NO_UNALIGNED_ACCESS @@ -4565,11 +4630,13 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs * (gint64 *) sp->data.p = sp[1].data.l; MINT_IN_BREAK; MINT_IN_CASE(MINT_STIND_R4) + NULL_CHECK (sp [-2].data.p); ++ip; sp -= 2; * (float *) sp->data.p = sp[1].data.f_r4; MINT_IN_BREAK; MINT_IN_CASE(MINT_STIND_R8) + NULL_CHECK (sp [-2].data.p); ++ip; sp -= 2; #ifdef NO_UNALIGNED_ACCESS @@ -4659,9 +4726,9 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs gint32 l1 = sp [-1].data.i; gint32 l2 = sp [-2].data.i; if (l1 == 0) - goto div_zero_label; + THROW_EX (mono_get_exception_divide_by_zero (), ip); if (l1 == (-1) && l2 == G_MININT32) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); BINOP(i, /); MINT_IN_BREAK; } @@ -4669,9 +4736,9 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs gint64 l1 = sp [-1].data.l; gint64 l2 = sp [-2].data.l; if (l1 == 0) - goto div_zero_label; + THROW_EX (mono_get_exception_divide_by_zero (), ip); if (l1 == (-1) && l2 == G_MININT64) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); BINOP(l, /); MINT_IN_BREAK; } @@ -4688,21 +4755,21 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs ++ip; MINT_IN_CASE(MINT_DIV_UN_I4) if (sp [-1].data.i == 0) - goto div_zero_label; + THROW_EX (mono_get_exception_divide_by_zero (), ip); BINOP_CAST(i, /, guint32); MINT_IN_BREAK; MINT_IN_CASE(MINT_DIV_UN_I8) if (sp [-1].data.l == 0) - goto div_zero_label; + THROW_EX (mono_get_exception_divide_by_zero (), ip); BINOP_CAST(l, /, guint64); MINT_IN_BREAK; MINT_IN_CASE(MINT_REM_I4) { int i1 = sp [-1].data.i; int i2 = sp [-2].data.i; if (i1 == 0) - goto div_zero_label; + THROW_EX (mono_get_exception_divide_by_zero (), ip); if (i1 == (-1) && i2 == G_MININT32) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); BINOP(i, %); MINT_IN_BREAK; } @@ -4710,9 +4777,9 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs gint64 l1 = sp [-1].data.l; gint64 l2 = sp [-2].data.l; if (l1 == 0) - goto div_zero_label; + THROW_EX (mono_get_exception_divide_by_zero (), ip); if (l1 == (-1) && l2 == G_MININT64) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); BINOP(l, %); MINT_IN_BREAK; } @@ -4730,12 +4797,12 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs MINT_IN_BREAK; MINT_IN_CASE(MINT_REM_UN_I4) if (sp [-1].data.i == 0) - goto div_zero_label; + THROW_EX (mono_get_exception_divide_by_zero (), ip); BINOP_CAST(i, %, guint32); MINT_IN_BREAK; MINT_IN_CASE(MINT_REM_UN_I8) if (sp [-1].data.l == 0) - goto div_zero_label; + THROW_EX (mono_get_exception_divide_by_zero (), ip); BINOP_CAST(l, %, guint64); MINT_IN_BREAK; MINT_IN_CASE(MINT_AND_I4) @@ -5033,7 +5100,7 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs sp -= param_count; sp->data.o = ves_array_create (frame->imethod->domain, newobj_class, param_count, sp, error); if (!is_ok (error)) - goto throw_error_label; + THROW_EX (mono_error_convert_to_exception (error), ip); ++sp; ip += 3; @@ -5073,7 +5140,7 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs OBJREF (o) = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass)); if (G_UNLIKELY (!o)) { mono_error_set_out_of_memory (error, "Could not allocate %i bytes", m_class_get_instance_size (vtable->klass)); - goto throw_error_label; + THROW_EX (mono_error_convert_to_exception (error), ip); } // Store o next to and before the parameters on the stack so GC will see it, @@ -5207,6 +5274,23 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs ip++; MINT_IN_BREAK; } + MINT_IN_CASE(MINT_INTRINS_SPAN_CTOR) { + gpointer ptr = sp [-2].data.p; + int len = sp [-1].data.i; + if (len < 0) + THROW_EX (mono_get_exception_argument_out_of_range ("length"), ip); + *(gpointer*)vt_sp = ptr; + *(gint32*)((gpointer*)vt_sp + 1) = len; + sp [-2].data.p = vt_sp; +#if SIZEOF_VOID_P == 8 + vt_sp += ALIGN_TO (12, MINT_VT_ALIGNMENT); +#else + vt_sp += ALIGN_TO (8, MINT_VT_ALIGNMENT); +#endif + sp--; + ip++; + MINT_IN_BREAK; + } MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_GET_VALUE) { gpointer *byreference_this = (gpointer*)sp [-1].data.p; sp [-1].data.p = *byreference_this; @@ -5228,6 +5312,49 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs ++ip; MINT_IN_BREAK; } + MINT_IN_CASE(MINT_INTRINS_MARVIN_BLOCK) { + sp -= 2; + interp_intrins_marvin_block ((guint32*)sp [0].data.p, (guint32*)sp [1].data.p); + ++ip; + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_INTRINS_ASCII_CHARS_TO_UPPERCASE) { + sp [-1].data.i = interp_intrins_ascii_chars_to_uppercase ((guint32)sp [-1].data.i); + ++ip; + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_INTRINS_MEMORYMARSHAL_GETARRAYDATAREF) { + MonoObject* const o = sp [-1].data.o; + NULL_CHECK (o); + sp[-1].data.p = (guint8*)o + MONO_STRUCT_OFFSET (MonoArray, vector); + ++ip; + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_INTRINS_ORDINAL_IGNORE_CASE_ASCII) { + sp--; + sp [-1].data.i = interp_intrins_ordinal_ignore_case_ascii ((guint32)sp [-1].data.i, (guint32)sp [0].data.i); + ++ip; + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_INTRINS_64ORDINAL_IGNORE_CASE_ASCII) { + sp--; + sp [-1].data.i = interp_intrins_64ordinal_ignore_case_ascii ((guint64)sp [-1].data.l, (guint64)sp [0].data.l); + ++ip; + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_INTRINS_U32_TO_DECSTR) { + MonoArray **cache_addr = (MonoArray**)frame->imethod->data_items [ip [1]]; + MonoVTable *string_vtable = (MonoVTable*)frame->imethod->data_items [ip [2]]; + sp [-1].data.o = (MonoObject*)interp_intrins_u32_to_decstr ((guint32)sp [-1].data.i, *cache_addr, string_vtable); + ip += 3; + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_INTRINS_WIDEN_ASCII_TO_UTF16) { + sp -= 2; + sp [-1].data.nati = interp_intrins_widen_ascii_to_utf16 ((guint8*)sp [-1].data.p, (mono_unichar2*)sp [0].data.p, sp [1].data.nati); + ip++; + MINT_IN_BREAK; + } MINT_IN_CASE(MINT_INTRINS_UNSAFE_BYTE_OFFSET) { sp -= 2; sp [0].data.nati = (guint8*)sp [1].data.p - (guint8*)sp [0].data.p; @@ -5261,7 +5388,7 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs if (isinst_instr) sp [-1].data.p = NULL; else - goto invalid_cast_label; + THROW_EX (mono_get_exception_invalid_cast (), ip); } } ip += 2; @@ -5279,7 +5406,7 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs if (isinst_instr) sp [-1].data.p = NULL; else - goto invalid_cast_label; + THROW_EX (mono_get_exception_invalid_cast (), ip); } } ip += 2; @@ -5295,7 +5422,7 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs if (isinst_instr) sp [-1].data.p = NULL; else - goto invalid_cast_label; + THROW_EX (mono_get_exception_invalid_cast (), ip); } } ip += 2; @@ -5315,7 +5442,7 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs MonoClass* const c = (MonoClass*)frame->imethod->data_items[ip [1]]; if (!(m_class_get_rank (o->vtable->klass) == 0 && m_class_get_element_class (o->vtable->klass) == m_class_get_element_class (c))) - goto invalid_cast_label; + THROW_EX (mono_get_exception_invalid_cast (), ip); sp [-1].data.p = mono_object_unbox_internal (o); ip += 2; @@ -5447,24 +5574,6 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs MINT_IN_BREAK; } - -#define LDARGFLD(datamem, fieldtype) do { \ - MonoObject *o = frame->stack_args [ip [1]].data.o; \ - NULL_CHECK (o); \ - sp [0].data.datamem = *(fieldtype *)((char *)o + ip [2]) ; \ - sp++; \ - ip += 3; \ -} while (0) - MINT_IN_CASE(MINT_LDARGFLD_I1) LDARGFLD(i, gint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDARGFLD_U1) LDARGFLD(i, guint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDARGFLD_I2) LDARGFLD(i, gint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDARGFLD_U2) LDARGFLD(i, guint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDARGFLD_I4) LDARGFLD(i, gint32); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDARGFLD_I8) LDARGFLD(l, gint64); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDARGFLD_R4) LDARGFLD(f_r4, float); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDARGFLD_R8) LDARGFLD(f, double); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDARGFLD_O) LDARGFLD(p, gpointer); MINT_IN_BREAK; - #define LDLOCFLD(datamem, fieldtype) do { \ MonoObject *o = *(MonoObject**)(locals + ip [1]); \ NULL_CHECK (o); \ @@ -5573,30 +5682,6 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs sp -= 2; MINT_IN_BREAK; -#define STARGFLD(datamem, fieldtype) do { \ - MonoObject *o = frame->stack_args [ip [1]].data.o; \ - NULL_CHECK (o); \ - sp--; \ - * (fieldtype *)((char *)o + ip [2]) = sp [0].data.datamem; \ - ip += 3; \ -} while (0) - MINT_IN_CASE(MINT_STARGFLD_I1) STARGFLD(i, gint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STARGFLD_U1) STARGFLD(i, guint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STARGFLD_I2) STARGFLD(i, gint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STARGFLD_U2) STARGFLD(i, guint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STARGFLD_I4) STARGFLD(i, gint32); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STARGFLD_I8) STARGFLD(l, gint64); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STARGFLD_R4) STARGFLD(f_r4, float); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STARGFLD_R8) STARGFLD(f, double); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STARGFLD_O) { - MonoObject *o = frame->stack_args [ip [1]].data.o; - NULL_CHECK (o); - sp--; - mono_gc_wbarrier_set_field_internal (o, (char *) o + ip [2], sp [0].data.o); - ip += 3; - MINT_IN_BREAK; - } - #define STLOCFLD(datamem, fieldtype) do { \ MonoObject *o = *(MonoObject**)(locals + ip [1]); \ NULL_CHECK (o); \ @@ -5792,30 +5877,30 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs } MINT_IN_CASE(MINT_CONV_OVF_I4_UN_R8) if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT32) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); sp [-1].data.i = (gint32)sp [-1].data.f; ++ip; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_U8_I4) if (sp [-1].data.i < 0) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); sp [-1].data.l = sp [-1].data.i; ++ip; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_U8_I8) if (sp [-1].data.l < 0) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); ++ip; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_I8_U8) if ((guint64) sp [-1].data.l > G_MAXINT64) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); ++ip; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_U8_R4) { guint64 res = (guint64)sp [-1].data.f_r4; if (mono_isnan (sp [-1].data.f_r4) || mono_trunc (sp [-1].data.f_r4) != res) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); sp [-1].data.l = res; ++ip; MINT_IN_BREAK; @@ -5823,7 +5908,7 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs MINT_IN_CASE(MINT_CONV_OVF_U8_R8) { guint64 res = (guint64)sp [-1].data.f; if (mono_isnan (sp [-1].data.f) || mono_trunc (sp [-1].data.f) != res) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); sp [-1].data.l = res; ++ip; MINT_IN_BREAK; @@ -5831,7 +5916,7 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R8) { gint64 res = (gint64)sp [-1].data.f; if (res < 0 || mono_isnan (sp [-1].data.f) || mono_trunc (sp [-1].data.f) != res) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); sp [-1].data.l = res; ++ip; MINT_IN_BREAK; @@ -5839,7 +5924,7 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R4) { gint64 res = (gint64)sp [-1].data.f_r4; if (res < 0 || mono_isnan (sp [-1].data.f_r4) || mono_trunc (sp [-1].data.f_r4) != res) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); sp [-1].data.l = res; ++ip; MINT_IN_BREAK; @@ -5847,7 +5932,7 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs MINT_IN_CASE(MINT_CONV_OVF_I8_R4) { gint64 res = (gint64)sp [-1].data.f_r4; if (mono_isnan (sp [-1].data.f_r4) || mono_trunc (sp [-1].data.f_r4) != res) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); sp [-1].data.l = res; ++ip; MINT_IN_BREAK; @@ -5855,7 +5940,7 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs MINT_IN_CASE(MINT_CONV_OVF_I8_R8) { gint64 res = (gint64)sp [-1].data.f; if (mono_isnan (sp [-1].data.f) || mono_trunc (sp [-1].data.f) != res) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); sp [-1].data.l = res; ++ip; MINT_IN_BREAK; @@ -5879,7 +5964,7 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs MonoVTable *vtable = (MonoVTable*)frame->imethod->data_items[ip [1]]; sp [-1].data.o = (MonoObject*) mono_array_new_specific_checked (vtable, sp [-1].data.i, error); if (!is_ok (error)) { - goto throw_error_label; + THROW_EX (mono_error_convert_to_exception (error), ip); } ip += 2; /*if (profiling_classes) { @@ -6115,195 +6200,195 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs } MINT_IN_CASE(MINT_CONV_OVF_I4_U4) if (sp [-1].data.i < 0) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); ++ip; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_I4_I8) if (sp [-1].data.l < G_MININT32 || sp [-1].data.l > G_MAXINT32) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); sp [-1].data.i = (gint32) sp [-1].data.l; ++ip; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_I4_U8) if ((guint64)sp [-1].data.l > G_MAXINT32) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); sp [-1].data.i = (gint32) sp [-1].data.l; ++ip; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_I4_R4) { gint32 res = (gint32)sp [-1].data.f_r4; if (mono_isnan (sp [-1].data.f_r4) || mono_trunc (sp [-1].data.f_r4) != res) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); sp [-1].data.i = res; ++ip; MINT_IN_BREAK; } MINT_IN_CASE(MINT_CONV_OVF_I4_R8) if (sp [-1].data.f < G_MININT32 || sp [-1].data.f > G_MAXINT32 || isnan (sp [-1].data.f)) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); sp [-1].data.i = (gint32) sp [-1].data.f; ++ip; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_U4_I4) if (sp [-1].data.i < 0) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); ++ip; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_U4_I8) if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT32) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); sp [-1].data.i = (guint32) sp [-1].data.l; ++ip; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_U4_R4) { guint32 res = (guint32)sp [-1].data.f_r4; if (mono_isnan (sp [-1].data.f_r4) || mono_trunc (sp [-1].data.f_r4) != res) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); sp [-1].data.i = res; ++ip; MINT_IN_BREAK; } MINT_IN_CASE(MINT_CONV_OVF_U4_R8) if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT32 || isnan (sp [-1].data.f)) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); sp [-1].data.i = (guint32) sp [-1].data.f; ++ip; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_I2_I4) if (sp [-1].data.i < G_MININT16 || sp [-1].data.i > G_MAXINT16) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); ++ip; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_I2_U4) if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXINT16) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); ++ip; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_I2_I8) if (sp [-1].data.l < G_MININT16 || sp [-1].data.l > G_MAXINT16) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); sp [-1].data.i = (gint16) sp [-1].data.l; ++ip; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_I2_U8) if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT16) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); sp [-1].data.i = (gint16) sp [-1].data.l; ++ip; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_I2_R4) if (sp [-1].data.f_r4 < G_MININT16 || sp [-1].data.f_r4 > G_MAXINT16 || isnan (sp [-1].data.f_r4)) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); sp [-1].data.i = (gint16) sp [-1].data.f_r4; ++ip; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_I2_R8) if (sp [-1].data.f < G_MININT16 || sp [-1].data.f > G_MAXINT16 || isnan (sp [-1].data.f)) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); sp [-1].data.i = (gint16) sp [-1].data.f; ++ip; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_I2_UN_R4) if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXINT16 || isnan (sp [-1].data.f_r4)) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); sp [-1].data.i = (gint16) sp [-1].data.f_r4; ++ip; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_I2_UN_R8) if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT16 || isnan (sp [-1].data.f)) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); sp [-1].data.i = (gint16) sp [-1].data.f; ++ip; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_U2_I4) if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXUINT16) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); ++ip; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_U2_I8) if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT16) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); sp [-1].data.i = (guint16) sp [-1].data.l; ++ip; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_U2_R4) if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXUINT16 || isnan (sp [-1].data.f_r4)) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); sp [-1].data.i = (guint16) sp [-1].data.f_r4; ++ip; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_U2_R8) if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT16 || isnan (sp [-1].data.f)) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); sp [-1].data.i = (guint16) sp [-1].data.f; ++ip; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_I1_I4) if (sp [-1].data.i < G_MININT8 || sp [-1].data.i > G_MAXINT8) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); ++ip; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_I1_U4) if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXINT8) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); ++ip; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_I1_I8) if (sp [-1].data.l < G_MININT8 || sp [-1].data.l > G_MAXINT8) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); sp [-1].data.i = (gint8) sp [-1].data.l; ++ip; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_I1_U8) if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT8) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); sp [-1].data.i = (gint8) sp [-1].data.l; ++ip; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_I1_R4) if (sp [-1].data.f_r4 < G_MININT8 || sp [-1].data.f_r4 > G_MAXINT8 || isnan (sp [-1].data.f_r4)) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); sp [-1].data.i = (gint8) sp [-1].data.f_r4; ++ip; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_I1_R8) if (sp [-1].data.f < G_MININT8 || sp [-1].data.f > G_MAXINT8 || isnan (sp [-1].data.f)) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); sp [-1].data.i = (gint8) sp [-1].data.f; ++ip; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_I1_UN_R4) if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXINT8 || isnan (sp [-1].data.f_r4)) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); sp [-1].data.i = (gint8) sp [-1].data.f_r4; ++ip; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_I1_UN_R8) if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT8 || isnan (sp [-1].data.f)) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); sp [-1].data.i = (gint8) sp [-1].data.f; ++ip; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_U1_I4) if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXUINT8) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); ++ip; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_U1_I8) if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT8) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); sp [-1].data.i = (guint8) sp [-1].data.l; ++ip; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_U1_R4) if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXUINT8 || isnan (sp [-1].data.f_r4)) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); sp [-1].data.i = (guint8) sp [-1].data.f_r4; ++ip; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_U1_R8) if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT8 || isnan (sp [-1].data.f)) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); sp [-1].data.i = (guint8) sp [-1].data.f; ++ip; MINT_IN_BREAK; @@ -6346,7 +6431,7 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs MonoClass* const c = (MonoClass*)frame->imethod->data_items [ip [1]]; if (c != tref->klass) - goto invalid_cast_label; + THROW_EX (mono_get_exception_invalid_cast (), ip); vt_sp -= ALIGN_TO (sizeof (MonoTypedRef), MINT_VT_ALIGNMENT); @@ -6363,62 +6448,62 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs MINT_IN_BREAK; MINT_IN_CASE(MINT_ADD_OVF_I4) if (CHECK_ADD_OVERFLOW (sp [-2].data.i, sp [-1].data.i)) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); BINOP(i, +); MINT_IN_BREAK; MINT_IN_CASE(MINT_ADD_OVF_I8) if (CHECK_ADD_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l)) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); BINOP(l, +); MINT_IN_BREAK; MINT_IN_CASE(MINT_ADD_OVF_UN_I4) if (CHECK_ADD_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i)) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); BINOP_CAST(i, +, guint32); MINT_IN_BREAK; MINT_IN_CASE(MINT_ADD_OVF_UN_I8) if (CHECK_ADD_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l)) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); BINOP_CAST(l, +, guint64); MINT_IN_BREAK; MINT_IN_CASE(MINT_MUL_OVF_I4) if (CHECK_MUL_OVERFLOW (sp [-2].data.i, sp [-1].data.i)) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); BINOP(i, *); MINT_IN_BREAK; MINT_IN_CASE(MINT_MUL_OVF_I8) if (CHECK_MUL_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l)) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); BINOP(l, *); MINT_IN_BREAK; MINT_IN_CASE(MINT_MUL_OVF_UN_I4) if (CHECK_MUL_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i)) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); BINOP_CAST(i, *, guint32); MINT_IN_BREAK; MINT_IN_CASE(MINT_MUL_OVF_UN_I8) if (CHECK_MUL_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l)) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); BINOP_CAST(l, *, guint64); MINT_IN_BREAK; MINT_IN_CASE(MINT_SUB_OVF_I4) if (CHECK_SUB_OVERFLOW (sp [-2].data.i, sp [-1].data.i)) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); BINOP(i, -); MINT_IN_BREAK; MINT_IN_CASE(MINT_SUB_OVF_I8) if (CHECK_SUB_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l)) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); BINOP(l, -); MINT_IN_BREAK; MINT_IN_CASE(MINT_SUB_OVF_UN_I4) if (CHECK_SUB_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i)) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); BINOP_CAST(i, -, guint32); MINT_IN_BREAK; MINT_IN_CASE(MINT_SUB_OVF_UN_I8) if (CHECK_SUB_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l)) - goto overflow_label; + THROW_EX (mono_get_exception_overflow (), ip); BINOP_CAST(l, -, guint64); MINT_IN_BREAK; MINT_IN_CASE(MINT_START_ABORT_PROT) @@ -6786,57 +6871,20 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs MINT_IN_BREAK; } -#define LDARG(datamem, argtype) \ - sp->data.datamem = (argtype) frame->stack_args [ip [1]].data.datamem; \ - ip += 2; \ - ++sp; - -#define LDARGn(datamem, argtype, n) \ - sp->data.datamem = (argtype) frame->stack_args [n].data.datamem; \ - ++ip; \ - ++sp; - - MINT_IN_CASE(MINT_LDARG_I1) LDARG(i, gint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDARG_U1) LDARG(i, guint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDARG_I2) LDARG(i, gint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDARG_U2) LDARG(i, guint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDARG_I4) LDARG(i, gint32); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDARG_I8) LDARG(l, gint64); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDARG_R4) LDARG(f_r4, float); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDARG_R8) LDARG(f, double); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDARG_O) LDARG(p, gpointer); MINT_IN_BREAK; - - MINT_IN_CASE(MINT_LDARG_P0) LDARGn(p, gpointer, 0); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDARG_VT) { sp->data.p = vt_sp; int const i32 = READ32 (ip + 2); - memcpy(sp->data.p, frame->stack_args [ip [1]].data.p, i32); + memcpy(sp->data.p, frame->stack [ip [1]].data.p, i32); vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT); ip += 4; ++sp; MINT_IN_BREAK; } -#define STARG(datamem, argtype) \ - --sp; \ - frame->stack_args [ip [1]].data.datamem = (argtype) sp->data.datamem; \ - ip += 2; \ - - MINT_IN_CASE(MINT_STARG_I1) STARG(i, gint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STARG_U1) STARG(i, guint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STARG_I2) STARG(i, gint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STARG_U2) STARG(i, guint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STARG_I4) STARG(i, gint32); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STARG_I8) STARG(l, gint64); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STARG_R4) STARG(f_r4, float); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STARG_R8) STARG(f, double); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STARG_O) STARG(p, gpointer); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STARG_VT) { int const i32 = READ32 (ip + 2); --sp; - memcpy(frame->stack_args [ip [1]].data.p, sp->data.p, i32); + memcpy(frame->stack [ip [1]].data.p, sp->data.p, i32); vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT); ip += 4; MINT_IN_BREAK; @@ -6869,18 +6917,17 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs int const i32 = READ32 (ip + 2); if (i32 == -1) { } else if (i32) { - gpointer dest_vt; sp--; if (frame->parent) { - dest_vt = frame->parent->state.vt_sp; + gpointer dest_vt = frame->parent->state.vt_sp; /* Push the valuetype in the parent frame */ + memcpy (dest_vt, sp->data.p, i32); frame->parent->state.sp [0].data.p = dest_vt; frame->parent->state.sp++; frame->parent->state.vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT); } else { - dest_vt = frame->retval->data.p; + memcpy (frame->retval->data.p, sp->data.p, i32); } - memcpy (dest_vt, sp->data.p, i32); } else { sp--; if (frame->parent) { @@ -6930,14 +6977,8 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs MINT_IN_BREAK; } - MINT_IN_CASE(MINT_LDARGA) - sp->data.p = &frame->stack_args [ip [1]]; - ip += 2; - ++sp; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDARGA_VT) - sp->data.p = frame->stack_args [ip [1]].data.p; + sp->data.p = frame->stack [ip [1]].data.p; ip += 2; ++sp; MINT_IN_BREAK; @@ -7025,7 +7066,7 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs MINT_IN_CASE(MINT_LOCALLOC) { stackval *sp_start = (stackval*)(locals + frame->imethod->total_locals_size + frame->imethod->vt_stack_size); if (sp != sp_start + 1) /*FIX?*/ - goto abort_label; + THROW_EX (mono_get_exception_execution_engine (NULL), ip); int len = sp [-1].data.i; // FIXME we need a separate allocator for localloc sections @@ -7269,25 +7310,13 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs #if !USE_COMPUTED_GOTO default: - g_error_xsx ("Unimplemented opcode: %04x %s at 0x%x\n", *ip, mono_interp_opname (*ip), ip - frame->imethod->code); + interp_error_xsx ("Unimplemented opcode: %04x %s at 0x%x\n", *ip, mono_interp_opname (*ip), ip - frame->imethod->code); #endif } } g_assert_not_reached (); -abort_label: - THROW_EX (mono_get_exception_execution_engine (NULL), ip); -null_label: - THROW_EX (mono_get_exception_null_reference (), ip); -div_zero_label: - THROW_EX (mono_get_exception_divide_by_zero (), ip); -overflow_label: - THROW_EX (mono_get_exception_overflow (), ip); -throw_error_label: - THROW_EX (mono_error_convert_to_exception (error), ip); -invalid_cast_label: - THROW_EX (mono_get_exception_invalid_cast (), ip); resume: g_assert (context->has_resume_state); g_assert (frame->imethod); @@ -7335,8 +7364,12 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs /* Return to the main loop after a non-recursive interpreter call */ //printf ("R: %s -> %s %p\n", mono_method_get_full_name (frame->imethod->method), mono_method_get_full_name (frame->parent->imethod->method), frame->parent->state.ip); g_assert_checked (frame->stack); - context->stack_pointer = (guchar*)frame->stack; frame = frame->parent; + /* + * FIXME We should be able to avoid dereferencing imethod here, if we will have + * a param_area and all calls would inherit the same sp, or if we are full coop. + */ + context->stack_pointer = (guchar*)frame->stack + frame->imethod->alloca_size; LOAD_INTERP_STATE (frame); CHECK_RESUME_STATE (context); @@ -7344,18 +7377,8 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs goto main_loop; } exit_clause: - if (clause_args) { - if (clause_args->base_frame) { - // We finished executing a filter. The execution stack of the base frame - // should remain unmodified, but we need to update the local space. - char *locals_base = (char*)clause_args->base_frame->stack; - - memcpy (locals_base, locals, frame->imethod->locals_size); - context->stack_pointer = (guchar*)frame->stack; - } - } else { + if (!clause_args) context->stack_pointer = (guchar*)frame->stack; - } DEBUG_LEAVE (); } @@ -7484,17 +7507,29 @@ interp_run_filter (StackFrameInfo *frame, MonoException *ex, int clause_index, g * Have to run the clause in a new frame which is a copy of IFRAME, since * during debugging, there are two copies of the frame on the stack. */ - InterpFrame child_frame = {iframe, iframe->imethod, iframe->stack_args, &retval}; + InterpFrame child_frame = {0}; + child_frame.parent = iframe; + child_frame.imethod = iframe->imethod; + child_frame.stack = (stackval*)context->stack_pointer; + child_frame.retval = &retval; + + /* Copy the stack frame of the original method */ + memcpy (child_frame.stack, iframe->stack, iframe->imethod->total_locals_size); + context->stack_pointer += iframe->imethod->alloca_size; memset (&clause_args, 0, sizeof (FrameClauseArgs)); clause_args.start_with_ip = (const guint16*)handler_ip; clause_args.end_at_ip = (const guint16*)handler_ip_end; clause_args.filter_exception = ex; - clause_args.base_frame = iframe; clause_args.exec_frame = &child_frame; interp_exec_method (&child_frame, context, &clause_args); + /* Copy back the updated frame */ + memcpy (iframe->stack, child_frame.stack, iframe->imethod->total_locals_size); + + context->stack_pointer = (guchar*)child_frame.stack; + /* ENDFILTER stores the result into child_frame->retval */ return retval.data.i ? TRUE : FALSE; } @@ -7618,7 +7653,7 @@ interp_frame_get_arg (MonoInterpFrameHandle frame, int pos) g_assert (iframe->imethod); sig = mono_method_signature_internal (iframe->imethod->method); - return stackval_to_data_addr (sig->params [pos], &iframe->stack_args [pos + !!iframe->imethod->hasthis]); + return stackval_to_data_addr (sig->params [pos], &iframe->stack [pos + !!iframe->imethod->hasthis]); } static gpointer @@ -7638,7 +7673,7 @@ interp_frame_get_this (MonoInterpFrameHandle frame) g_assert (iframe->imethod); g_assert (iframe->imethod->hasthis); - return &iframe->stack_args [0].data.p; + return &iframe->stack [0].data.p; } static MonoInterpFrameHandle @@ -7759,6 +7794,48 @@ interp_print_op_count (void) } #endif +#if PROFILE_INTERP + +static InterpMethod **imethods; +static int num_methods; +const int opcount_threshold = 100000; + +static void +interp_add_imethod (gpointer method) +{ + InterpMethod *imethod = (InterpMethod*) method; + if (imethod->opcounts > opcount_threshold) + imethods [num_methods++] = imethod; +} + +static int +imethod_opcount_comparer (gconstpointer m1, gconstpointer m2) +{ + return (*(InterpMethod**)m2)->opcounts - (*(InterpMethod**)m1)->opcounts; +} + +static void +interp_print_method_counts (void) +{ + MonoDomain *domain = mono_get_root_domain (); + MonoJitDomainInfo *info = domain_jit_info (domain); + + mono_domain_jit_code_hash_lock (domain); + imethods = (InterpMethod**) malloc (info->interp_code_hash.num_entries * sizeof (InterpMethod*)); + mono_internal_hash_table_apply (&info->interp_code_hash, interp_add_imethod); + mono_domain_jit_code_hash_unlock (domain); + + qsort (imethods, num_methods, sizeof (InterpMethod*), imethod_opcount_comparer); + + printf ("Total executed opcodes %ld\n", total_executed_opcodes); + long cumulative_executed_opcodes = 0; + for (int i = 0; i < num_methods; i++) { + cumulative_executed_opcodes += imethods [i]->opcounts; + printf ("%d%% Opcounts %ld, calls %ld, Method %s, imethod ptr %p\n", (int)(cumulative_executed_opcodes * 100 / total_executed_opcodes), imethods [i]->opcounts, imethods [i]->calls, mono_method_full_name (imethods [i]->method, TRUE), imethods [i]); + } +} +#endif + static void interp_set_optimizations (guint32 opts) { @@ -7787,6 +7864,9 @@ interp_cleanup (void) #if COUNT_OPS interp_print_op_count (); #endif +#if PROFILE_INTERP + interp_print_method_counts (); +#endif } static void diff --git a/mono/mini/interp/interp.h b/mono/mini/interp/interp.h index 756f381c8aee..e6a3454dec1a 100644 --- a/mono/mini/interp/interp.h +++ b/mono/mini/interp/interp.h @@ -49,6 +49,9 @@ MONO_API void mono_ee_interp_init (const char *); gpointer mono_wasm_get_interp_to_native_trampoline (MonoMethodSignature *sig); +gpointer +mono_wasm_get_native_to_interp_trampoline (MonoMethod *method, gpointer extra_arg); + #endif #endif /* __MONO_MINI_INTERPRETER_H__ */ diff --git a/mono/mini/interp/mintops.def b/mono/mini/interp/mintops.def index 3ba07ec600c8..6e4d90fab787 100644 --- a/mono/mini/interp/mintops.def +++ b/mono/mini/interp/mintops.def @@ -50,30 +50,8 @@ OPDEF(MINT_LDC_R8, "ldc.r8", 5, Pop0, Push1, MintOpDouble) OPDEF(MINT_ARGLIST, "arglist", 1, Pop0, Push1, MintOpNoArgs) -OPDEF(MINT_LDARG_I1, "ldarg.i1", 2, Pop0, Push1, MintOpUShortInt) -OPDEF(MINT_LDARG_U1, "ldarg.u1", 2, Pop0, Push1, MintOpUShortInt) -OPDEF(MINT_LDARG_I2, "ldarg.i2", 2, Pop0, Push1, MintOpUShortInt) -OPDEF(MINT_LDARG_U2, "ldarg.u2", 2, Pop0, Push1, MintOpUShortInt) -OPDEF(MINT_LDARG_I4, "ldarg.i4", 2, Pop0, Push1, MintOpUShortInt) -OPDEF(MINT_LDARG_I8, "ldarg.i8", 2, Pop0, Push1, MintOpUShortInt) -OPDEF(MINT_LDARG_R4, "ldarg.r4", 2, Pop0, Push1, MintOpUShortInt) -OPDEF(MINT_LDARG_R8, "ldarg.r8", 2, Pop0, Push1, MintOpUShortInt) -OPDEF(MINT_LDARG_O, "ldarg.o", 2, Pop0, Push1, MintOpUShortInt) -OPDEF(MINT_LDARG_P0, "ldarg.p0", 1, Pop0, Push1, MintOpNoArgs) OPDEF(MINT_LDARG_VT, "ldarg.vt", 4, Pop0, Push1, MintOpShortAndInt) - -OPDEF(MINT_STARG_I1, "starg.i1", 2, Pop1, Push0, MintOpUShortInt) -OPDEF(MINT_STARG_U1, "starg.u1", 2, Pop1, Push0, MintOpUShortInt) -OPDEF(MINT_STARG_I2, "starg.i2", 2, Pop1, Push0, MintOpUShortInt) -OPDEF(MINT_STARG_U2, "starg.u2", 2, Pop1, Push0, MintOpUShortInt) -OPDEF(MINT_STARG_I4, "starg.i4", 2, Pop1, Push0, MintOpUShortInt) -OPDEF(MINT_STARG_I8, "starg.i8", 2, Pop1, Push0, MintOpUShortInt) -OPDEF(MINT_STARG_R4, "starg.r4", 2, Pop1, Push0, MintOpUShortInt) -OPDEF(MINT_STARG_R8, "starg.r8", 2, Pop1, Push0, MintOpUShortInt) -OPDEF(MINT_STARG_O, "starg.o", 2, Pop1, Push0, MintOpUShortInt) OPDEF(MINT_STARG_VT, "starg.vt", 4, Pop1, Push0, MintOpShortAndInt) - -OPDEF(MINT_LDARGA, "ldarga", 2, Pop0, Push1, MintOpUShortInt) OPDEF(MINT_LDARGA_VT, "ldarga.vt", 2, Pop0, Push1, MintOpUShortInt) OPDEF(MINT_LDFLD_VT_I1, "ldfld.vt.i1", 3, Pop1, Push1, MintOpTwoShorts) @@ -108,16 +86,6 @@ OPDEF(MINT_LDRMFLD_VT, "ldrmfld.vt", 2, Pop1, Push1, MintOpUShortInt) OPDEF(MINT_LDFLDA, "ldflda", 2, Pop1, Push1, MintOpUShortInt) OPDEF(MINT_LDFLDA_UNSAFE, "ldflda.unsafe", 2, Pop1, Push1, MintOpUShortInt) -OPDEF(MINT_LDARGFLD_I1, "ldargfld.i1", 3, Pop0, Push1, MintOpTwoShorts) -OPDEF(MINT_LDARGFLD_U1, "ldargfld.u1", 3, Pop0, Push1, MintOpTwoShorts) -OPDEF(MINT_LDARGFLD_I2, "ldargfld.i2", 3, Pop0, Push1, MintOpTwoShorts) -OPDEF(MINT_LDARGFLD_U2, "ldargfld.u2", 3, Pop0, Push1, MintOpTwoShorts) -OPDEF(MINT_LDARGFLD_I4, "ldargfld.i4", 3, Pop0, Push1, MintOpTwoShorts) -OPDEF(MINT_LDARGFLD_I8, "ldargfld.i8", 3, Pop0, Push1, MintOpTwoShorts) -OPDEF(MINT_LDARGFLD_R4, "ldargfld.r4", 3, Pop0, Push1, MintOpTwoShorts) -OPDEF(MINT_LDARGFLD_R8, "ldargfld.r8", 3, Pop0, Push1, MintOpTwoShorts) -OPDEF(MINT_LDARGFLD_O, "ldargfld.o", 3, Pop0, Push1, MintOpTwoShorts) - OPDEF(MINT_LDLOCFLD_I1, "ldlocfld.i1", 3, Pop0, Push1, MintOpTwoShorts) OPDEF(MINT_LDLOCFLD_U1, "ldlocfld.u1", 3, Pop0, Push1, MintOpTwoShorts) OPDEF(MINT_LDLOCFLD_I2, "ldlocfld.i2", 3, Pop0, Push1, MintOpTwoShorts) @@ -145,16 +113,6 @@ OPDEF(MINT_STFLD_R8_UNALIGNED, "stfld.r8.unaligned", 2, Pop2, Push0, MintOpUShor OPDEF(MINT_STRMFLD, "strmfld", 2, Pop2, Push0, MintOpFieldToken) OPDEF(MINT_STRMFLD_VT, "strmfld.vt", 2, Pop2, Push0, MintOpUShortInt) -OPDEF(MINT_STARGFLD_I1, "stargfld.i1", 3, Pop1, Push0, MintOpTwoShorts) -OPDEF(MINT_STARGFLD_U1, "stargfld.u1", 3, Pop1, Push0, MintOpTwoShorts) -OPDEF(MINT_STARGFLD_I2, "stargfld.i2", 3, Pop1, Push0, MintOpTwoShorts) -OPDEF(MINT_STARGFLD_U2, "stargfld.u2", 3, Pop1, Push0, MintOpTwoShorts) -OPDEF(MINT_STARGFLD_I4, "stargfld.i4", 3, Pop1, Push0, MintOpTwoShorts) -OPDEF(MINT_STARGFLD_I8, "stargfld.i8", 3, Pop1, Push0, MintOpTwoShorts) -OPDEF(MINT_STARGFLD_R4, "stargfld.r4", 3, Pop1, Push0, MintOpTwoShorts) -OPDEF(MINT_STARGFLD_R8, "stargfld.r8", 3, Pop1, Push0, MintOpTwoShorts) -OPDEF(MINT_STARGFLD_O, "stargfld.o", 3, Pop1, Push0, MintOpTwoShorts) - OPDEF(MINT_STLOCFLD_I1, "stlocfld.i1", 3, Pop1, Push0, MintOpTwoShorts) OPDEF(MINT_STLOCFLD_U1, "stlocfld.u1", 3, Pop1, Push0, MintOpTwoShorts) OPDEF(MINT_STLOCFLD_I2, "stlocfld.i2", 3, Pop1, Push0, MintOpTwoShorts) @@ -426,7 +384,7 @@ OPDEF(MINT_STOBJ_VT, "stobj.vt", 2, Pop2, Push0, MintOpClassToken) OPDEF(MINT_CPBLK, "cpblk", 1, Pop3, Push0, MintOpNoArgs) OPDEF(MINT_INITBLK, "initblk", 1, Pop3, Push0, MintOpNoArgs) OPDEF(MINT_LOCALLOC, "localloc", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_INITLOCALS, "initlocals", 1, Pop0, Push0, MintOpNoArgs) +OPDEF(MINT_INITLOCALS, "initlocals", 3, Pop0, Push0, MintOpTwoShorts) OPDEF(MINT_LDELEM_I, "ldelem.i", 1, Pop2, Push1, MintOpNoArgs) OPDEF(MINT_LDELEM_I1, "ldelem.i1", 1, Pop2, Push1, MintOpNoArgs) @@ -828,9 +786,17 @@ OPDEF(MINT_PROF_COVERAGE_STORE, "prof_coverage_store", 5, Pop0, Push0, MintOpLon OPDEF(MINT_INTRINS_ENUM_HASFLAG, "intrins_enum_hasflag", 2, Pop2, Push1, MintOpClassToken) OPDEF(MINT_INTRINS_GET_HASHCODE, "intrins_get_hashcode", 1, Pop1, Push1, MintOpNoArgs) OPDEF(MINT_INTRINS_GET_TYPE, "intrins_get_type", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_INTRINS_BYREFERENCE_CTOR, "intrins_byreference_ctor", 1, Pop1, Push1, MintOpClassToken) +OPDEF(MINT_INTRINS_BYREFERENCE_CTOR, "intrins_byreference_ctor", 1, Pop1, Push1, MintOpNoArgs) +OPDEF(MINT_INTRINS_SPAN_CTOR, "intrins_span_ctor", 1, Pop2, Push1, MintOpNoArgs) OPDEF(MINT_INTRINS_BYREFERENCE_GET_VALUE, "intrins_byreference_get_value", 1, Pop1, Push1, MintOpNoArgs) OPDEF(MINT_INTRINS_UNSAFE_ADD_BYTE_OFFSET, "intrins_unsafe_add_byte_offset", 1, Pop2, Push1, MintOpNoArgs) OPDEF(MINT_INTRINS_UNSAFE_BYTE_OFFSET, "intrins_unsafe_byte_offset", 1, Pop2, Push1, MintOpNoArgs) OPDEF(MINT_INTRINS_RUNTIMEHELPERS_OBJECT_HAS_COMPONENT_SIZE, "intrins_runtimehelpers_object_has_component_size", 1, Pop1, Push1, MintOpNoArgs) OPDEF(MINT_INTRINS_CLEAR_WITH_REFERENCES, "intrin_clear_with_references", 1, Pop2, Push0, MintOpNoArgs) +OPDEF(MINT_INTRINS_MARVIN_BLOCK, "intrins_marvin_block", 1, Pop2, Push0, MintOpNoArgs) +OPDEF(MINT_INTRINS_ASCII_CHARS_TO_UPPERCASE, "intrins_ascii_chars_to_uppercase", 1, Pop1, Push1, MintOpNoArgs) +OPDEF(MINT_INTRINS_MEMORYMARSHAL_GETARRAYDATAREF, "intrins_memorymarshal_getarraydataref", 1, Pop1, Push1, MintOpNoArgs) +OPDEF(MINT_INTRINS_ORDINAL_IGNORE_CASE_ASCII, "intrins_ordinal_ignore_case_ascii", 1, Pop2, Push1, MintOpNoArgs) +OPDEF(MINT_INTRINS_64ORDINAL_IGNORE_CASE_ASCII, "intrins_64ordinal_ignore_case_ascii", 1, Pop2, Push1, MintOpNoArgs) +OPDEF(MINT_INTRINS_U32_TO_DECSTR, "intrins_u32_to_decstr", 3, Pop1, Push1, MintOpNoArgs) +OPDEF(MINT_INTRINS_WIDEN_ASCII_TO_UTF16, "intrins_widen_ascii_to_utf16", 1, Pop3, Push1, MintOpNoArgs) diff --git a/mono/mini/interp/mintops.h b/mono/mini/interp/mintops.h index 7b4cb507d370..4a6f760f3b50 100644 --- a/mono/mini/interp/mintops.h +++ b/mono/mini/interp/mintops.h @@ -58,8 +58,6 @@ typedef enum { #define MINT_IS_STLOC(op) ((op) >= MINT_STLOC_I1 && (op) <= MINT_STLOC_VT) #define MINT_IS_MOVLOC(op) ((op) >= MINT_MOVLOC_1 && (op) <= MINT_MOVLOC_VT) #define MINT_IS_STLOC_NP(op) ((op) >= MINT_STLOC_NP_I4 && (op) <= MINT_STLOC_NP_O) -#define MINT_IS_LDARG(op) ((op) >= MINT_LDARG_I1 && (op) <= MINT_LDARG_VT) -#define MINT_IS_STARG(op) ((op) >= MINT_STARG_I1 && (op) <= MINT_STARG_VT) #define MINT_IS_CONDITIONAL_BRANCH(op) ((op) >= MINT_BRFALSE_I4 && (op) <= MINT_BLT_UN_R8_S) #define MINT_IS_CALL(op) ((op) >= MINT_CALL && (op) <= MINT_JIT_CALL) #define MINT_IS_PATCHABLE_CALL(op) ((op) >= MINT_CALL && (op) <= MINT_VCALL) diff --git a/mono/mini/interp/transform.c b/mono/mini/interp/transform.c index af28de5ddd1f..1fd13dd4bec3 100644 --- a/mono/mini/interp/transform.c +++ b/mono/mini/interp/transform.c @@ -594,7 +594,8 @@ load_arg(TransformData *td, int n) if (hasthis && n == 0) { mt = MINT_TYPE_I; - interp_add_ins (td, MINT_LDARG_P0); + interp_add_ins (td, MINT_LDLOC_O); + td->last_ins->data [0] = 0; klass = NULL; } else { PUSH_VT (td, size); @@ -607,9 +608,10 @@ load_arg(TransformData *td, int n) // Special case loading of the first ptr sized argument if (mt != MINT_TYPE_O) mt = MINT_TYPE_I; - interp_add_ins (td, MINT_LDARG_P0); + interp_add_ins (td, MINT_LDLOC_O); + td->last_ins->data [0] = 0; } else { - interp_add_ins (td, MINT_LDARG_I1 + (mt - MINT_TYPE_I1)); + interp_add_ins (td, MINT_LDLOC_I1 + (mt - MINT_TYPE_I1)); td->last_ins->data [0] = n; if (mt == MINT_TYPE_O) klass = mono_class_from_mono_type_internal (type); @@ -640,7 +642,7 @@ store_arg(TransformData *td, int n) if (td->sp [-1].type == STACK_TYPE_VT) POP_VT(td, size); } else { - interp_add_ins (td, MINT_STARG_I1 + (mt - MINT_TYPE_I1)); + interp_add_ins (td, MINT_STLOC_I1 + (mt - MINT_TYPE_I1)); td->last_ins->data [0] = n; } --td->sp; @@ -839,6 +841,32 @@ interp_generate_bie_throw (TransformData *td) td->last_ins->data [0] = get_data_item_index (td, (gpointer)info->func); } +static void +interp_generate_not_supported_throw (TransformData *td) +{ + MonoJitICallInfo *info = &mono_get_jit_icall_info ()->mono_throw_not_supported; + + interp_add_ins (td, MINT_ICALL_V_V); + td->last_ins->data [0] = get_data_item_index (td, (gpointer)info->func); +} + +static void +interp_generate_ipe_throw_with_msg (TransformData *td, MonoError *error_msg) +{ + MonoJitICallInfo *info = &mono_get_jit_icall_info ()->mono_throw_invalid_program; + + char *msg = mono_mempool_strdup (td->rtm->domain->mp, mono_error_get_message (error_msg)); + + interp_add_ins (td, MINT_MONO_LDPTR); + td->last_ins->data [0] = get_data_item_index (td, msg); + PUSH_SIMPLE_TYPE (td, STACK_TYPE_I); + + interp_add_ins (td, MINT_ICALL_P_V); + td->last_ins->data [0] = get_data_item_index (td, (gpointer)info->func); + + td->sp -= 1; +} + /* * These are additional locals that can be allocated as we transform the code. * They are allocated past the method locals so they are accessed in the same @@ -1348,20 +1376,15 @@ interp_handle_magic_type_intrinsics (TransformData *td, MonoMethod *target_metho /* emit call to managed conversion method */ return FALSE; } else if (!strcmp (".cctor", tm)) { - /* white list */ return FALSE; } else if (!strcmp ("Parse", tm)) { - /* white list */ return FALSE; } else if (!strcmp ("ToString", tm)) { - /* white list */ return FALSE; } else if (!strcmp ("GetHashCode", tm)) { - /* white list */ return FALSE; } else if (!strcmp ("IsNaN", tm) || !strcmp ("IsInfinity", tm) || !strcmp ("IsNegativeInfinity", tm) || !strcmp ("IsPositiveInfinity", tm)) { g_assert (type_index == 2); // nfloat only - /* white list */ return FALSE; } @@ -1479,6 +1502,43 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas } else if (in_corlib && !strcmp (klass_name_space, "System") && !strcmp (klass_name, "ByReference`1")) { g_assert (!strcmp (tm, "get_Value")); *op = MINT_INTRINS_BYREFERENCE_GET_VALUE; + } else if (in_corlib && !strcmp (klass_name_space, "System") && !strcmp (klass_name, "Marvin")) { + if (!strcmp (tm, "Block")) + *op = MINT_INTRINS_MARVIN_BLOCK; + } else if (in_corlib && !strcmp (klass_name_space, "System.Runtime.InteropServices") && !strcmp (klass_name, "MemoryMarshal")) { + if (!strcmp (tm, "GetArrayDataReference")) + *op = MINT_INTRINS_MEMORYMARSHAL_GETARRAYDATAREF; + } else if (in_corlib && !strcmp (klass_name_space, "System.Text.Unicode") && !strcmp (klass_name, "Utf16Utility")) { + if (!strcmp (tm, "ConvertAllAsciiCharsInUInt32ToUppercase")) + *op = MINT_INTRINS_ASCII_CHARS_TO_UPPERCASE; + else if (!strcmp (tm, "UInt32OrdinalIgnoreCaseAscii")) + *op = MINT_INTRINS_ORDINAL_IGNORE_CASE_ASCII; + else if (!strcmp (tm, "UInt64OrdinalIgnoreCaseAscii")) + *op = MINT_INTRINS_64ORDINAL_IGNORE_CASE_ASCII; + } else if (in_corlib && !strcmp (klass_name_space, "System.Text") && !strcmp (klass_name, "ASCIIUtility")) { + if (!strcmp (tm, "WidenAsciiToUtf16")) + *op = MINT_INTRINS_WIDEN_ASCII_TO_UTF16; + } else if (in_corlib && !strcmp (klass_name_space, "System") && !strcmp (klass_name, "Number")) { + if (!strcmp (tm, "UInt32ToDecStr") && csignature->param_count == 1) { + ERROR_DECL(error); + MonoVTable *vtable = mono_class_vtable_checked (td->rtm->domain, target_method->klass, error); + if (!is_ok (error)) { + mono_error_cleanup (error); + return FALSE; + } + /* Don't use intrinsic if cctor not yet run */ + if (!vtable->initialized) + return FALSE; + /* The cache is the first static field. Update this if bcl code changes */ + MonoClassField *field = m_class_get_fields (target_method->klass); + g_assert (!strcmp (field->name, "s_singleDigitStringCache")); + interp_add_ins (td, MINT_INTRINS_U32_TO_DECSTR); + td->last_ins->data [0] = get_data_item_index (td, (char*)mono_vtable_get_static_field_data (vtable) + field->offset); + td->last_ins->data [1] = get_data_item_index (td, mono_class_vtable_checked (td->rtm->domain, mono_defaults.string_class, error)); + SET_TYPE (td->sp - 1, STACK_TYPE_O, mono_defaults.string_class); + td->ip += 5; + return TRUE; + } } else if (in_corlib && !strcmp (klass_name_space, "System") && (!strcmp (klass_name, "Math") || !strcmp (klass_name, "MathF"))) { gboolean is_float = strcmp (klass_name, "MathF") == 0; @@ -1844,7 +1904,7 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas static MonoMethod* interp_transform_internal_calls (MonoMethod *method, MonoMethod *target_method, MonoMethodSignature *csignature, gboolean is_virtual) { - if (method->wrapper_type == MONO_WRAPPER_NONE && target_method != NULL) { + if (((method->wrapper_type == MONO_WRAPPER_NONE) || (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)) && target_method != NULL) { if (target_method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) target_method = mono_marshal_get_native_wrapper (target_method, FALSE, FALSE); if (!is_virtual && target_method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) @@ -2930,16 +2990,43 @@ interp_emit_memory_barrier (TransformData *td, int kind) } while (0) static void -interp_method_compute_offsets (TransformData *td, InterpMethod *imethod, MonoMethodSignature *signature, MonoMethodHeader *header, MonoError *error) +interp_method_compute_offsets (TransformData *td, InterpMethod *imethod, MonoMethodSignature *sig, MonoMethodHeader *header, MonoError *error) { int i, offset, size, align; + int num_args = sig->hasthis + sig->param_count; + int num_il_locals = header->num_locals; + int num_locals = num_args + num_il_locals; - imethod->local_offsets = (guint32*)g_malloc (header->num_locals * sizeof(guint32)); - td->locals = (InterpLocal*)g_malloc (header->num_locals * sizeof (InterpLocal)); - td->locals_size = header->num_locals; + imethod->local_offsets = (guint32*)g_malloc (num_il_locals * sizeof(guint32)); + td->locals = (InterpLocal*)g_malloc (num_locals * sizeof (InterpLocal)); + td->locals_size = num_locals; td->locals_capacity = td->locals_size; offset = 0; - for (i = 0; i < header->num_locals; ++i) { + + g_assert (sizeof (stackval) == MINT_VT_ALIGNMENT); + + /* + * We will load arguments as if they are locals. Unlike normal locals, every argument + * is stored in a stackval sized slot and valuetypes have special semantics since we + * receive a pointer to the valuetype data rather than the data itself. + */ + for (i = 0; i < num_args; i++) { + MonoType *type; + if (sig->hasthis && i == 0) + type = m_class_get_byval_arg (td->method->klass); + else + type = mono_method_signature_internal (td->method)->params [i - sig->hasthis]; + td->locals [i].offset = offset; + td->locals [i].flags = 0; + td->locals [i].indirects = 0; + td->locals [i].type = type; + td->locals [i].mt = mint_type (type); + offset += sizeof (stackval); + } + + td->il_locals_offset = offset; + for (i = 0; i < num_il_locals; ++i) { + int index = num_args + i; size = mono_type_size (header->locals [i], &align); if (header->locals [i]->type == MONO_TYPE_VALUETYPE) { if (mono_class_has_failure (header->locals [i]->data.klass)) { @@ -2950,24 +3037,24 @@ interp_method_compute_offsets (TransformData *td, InterpMethod *imethod, MonoMet offset += align - 1; offset &= ~(align - 1); imethod->local_offsets [i] = offset; - td->locals [i].offset = offset; - td->locals [i].flags = 0; - td->locals [i].indirects = 0; - td->locals [i].type = header->locals [i]; - td->locals [i].mt = mint_type (header->locals [i]); + td->locals [index].offset = offset; + td->locals [index].flags = 0; + td->locals [index].indirects = 0; + td->locals [index].type = header->locals [i]; + td->locals [index].mt = mint_type (header->locals [i]); offset += size; } - offset = (offset + 7) & ~7; + offset = ALIGN_TO (offset, MINT_VT_ALIGNMENT); + td->il_locals_size = offset - td->il_locals_offset; imethod->exvar_offsets = (guint32*)g_malloc (header->num_clauses * sizeof (guint32)); for (i = 0; i < header->num_clauses; i++) { imethod->exvar_offsets [i] = offset; offset += sizeof (MonoObject*); } - offset = (offset + 7) & ~7; + offset = ALIGN_TO (offset, MINT_VT_ALIGNMENT); - imethod->locals_size = offset; - g_assert (imethod->locals_size < 65536); + g_assert (offset < G_MAXUINT16); td->total_locals_size = offset; } @@ -2978,6 +3065,20 @@ mono_test_interp_method_compute_offsets (TransformData *td, InterpMethod *imetho interp_method_compute_offsets (td, imethod, signature, header, error); } +static gboolean +type_has_references (MonoType *type) +{ + if (MONO_TYPE_IS_REFERENCE (type)) + return TRUE; + if (MONO_TYPE_ISSTRUCT (type)) { + MonoClass *klass = mono_class_from_mono_type_internal (type); + if (!m_class_is_inited (klass)) + mono_class_init_internal (klass); + return m_class_has_references (klass); + } + return FALSE; +} + /* Return false is failure to init basic blocks due to being in inline method */ static gboolean init_bb_start (TransformData *td, MonoMethodHeader *header, gboolean inlining) @@ -3308,6 +3409,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm = td->rtm; MonoDomain *domain = rtm->domain; MonoMethodSignature *signature = mono_method_signature_internal (method); + int num_args = signature->hasthis + signature->param_count; gboolean ret = TRUE; gboolean emitted_funccall_seq_point = FALSE; guint32 *arg_locals = NULL; @@ -3428,8 +3530,11 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, * before use. We also don't need this instruction if the init locals flag * is not set and there are no locals holding references. */ - if (header->num_locals) + if (header->num_locals) { interp_add_ins (td, MINT_INITLOCALS); + td->last_ins->data [0] = td->il_locals_offset; + td->last_ins->data [1] = td->il_locals_size; + } guint16 enter_profiling = 0; if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) @@ -3588,7 +3693,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, case CEE_LDLOC_3: { int loc_n = *td->ip - CEE_LDLOC_0; if (!inlining) - load_local (td, loc_n); + load_local (td, num_args + loc_n); else load_local (td, local_locals [loc_n]); ++td->ip; @@ -3600,7 +3705,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, case CEE_STLOC_3: { int loc_n = *td->ip - CEE_STLOC_0; if (!inlining) - store_local (td, loc_n); + store_local (td, num_args + loc_n); else store_local (td, local_locals [loc_n]); ++td->ip; @@ -3621,7 +3726,12 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, if (!inlining) { get_arg_type_exact (td, n, &mt); - interp_add_ins (td, mt == MINT_TYPE_VT ? MINT_LDARGA_VT : MINT_LDARGA); + if (mt == MINT_TYPE_VT) { + interp_add_ins (td, MINT_LDARGA_VT); + } else { + interp_add_ins (td, MINT_LDLOCA_S); + td->locals [n].indirects++; + } td->last_ins->data [0] = n; } else { int loc_n = arg_locals [n]; @@ -3645,7 +3755,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, case CEE_LDLOC_S: { int loc_n = ((guint8 *)td->ip)[1]; if (!inlining) - load_local (td, loc_n); + load_local (td, num_args + loc_n); else load_local (td, local_locals [loc_n]); td->ip += 2; @@ -3654,7 +3764,9 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, case CEE_LDLOCA_S: { int loc_n = ((guint8 *)td->ip)[1]; interp_add_ins (td, MINT_LDLOCA_S); - if (inlining) + if (!inlining) + loc_n += num_args; + else loc_n = local_locals [loc_n]; td->last_ins->data [0] = loc_n; td->locals [loc_n].indirects++; @@ -3665,7 +3777,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, case CEE_STLOC_S: { int loc_n = ((guint8 *)td->ip)[1]; if (!inlining) - store_local (td, loc_n); + store_local (td, num_args + loc_n); else store_local (td, local_locals [loc_n]); td->ip += 2; @@ -4634,6 +4746,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, PUSH_TYPE (td, stack_type [mint_type (m_class_get_byval_arg (klass))], klass); } else { + gboolean can_inline = TRUE; if (m_class_get_parent (klass) == mono_defaults.array_class) { interp_add_ins (td, MINT_NEWOBJ_ARRAY); td->last_ins->data [0] = get_data_item_index (td, m->klass); @@ -4648,6 +4761,14 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, /* public ByReference(ref T value) */ g_assert (csignature->hasthis && csignature->param_count == 1); interp_add_ins (td, MINT_INTRINS_BYREFERENCE_CTOR); + } else if (m_class_get_image (klass) == mono_defaults.corlib && + (!strcmp (m_class_get_name (m->klass), "Span`1") || + !strcmp (m_class_get_name (m->klass), "ReadOnlySpan`1")) && + csignature->param_count == 2 && + csignature->params [0]->type == MONO_TYPE_PTR && + !type_has_references (mono_method_get_context (m)->class_inst->type_argv [0])) { + /* ctor frequently used with ReadOnlySpan over static arrays */ + interp_add_ins (td, MINT_INTRINS_SPAN_CTOR); } else if (klass != mono_defaults.string_class && !mono_class_is_marshalbyref (klass) && !mono_class_has_finalizer (klass) && @@ -4705,6 +4826,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, move_stack (td, (td->sp - td->stack) - csignature->param_count, -2); // Set the method to be executed as part of newobj instruction newobj_fast->data [0] = get_data_item_index (td, mono_interp_get_imethod (domain, m, error)); + can_inline = FALSE; } else { // Runtime (interp_exec_method_full in interp.c) inserts // extra stack to hold this and return value, before call. @@ -4714,8 +4836,10 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, td->last_ins->data [0] = get_data_item_index (td, mono_interp_get_imethod (domain, m, error)); } goto_if_nok (error, exit); - /* The constructor was not inlined, abort inlining of current method */ - INLINE_FAILURE; + if (!can_inline) { + /* The constructor was not inlined, abort inlining of current method */ + INLINE_FAILURE; + } td->sp -= csignature->param_count; if (mint_type (m_class_get_byval_arg (klass)) == MINT_TYPE_VT) { @@ -4732,7 +4856,8 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, } } if ((vt_stack_used != 0 || vt_res_size != 0) && - td->last_ins->opcode != MINT_INTRINS_BYREFERENCE_CTOR) { + td->last_ins->opcode != MINT_INTRINS_BYREFERENCE_CTOR && + td->last_ins->opcode != MINT_INTRINS_SPAN_CTOR) { /* FIXME Remove this once vtsp and sp are unified */ interp_add_ins (td, MINT_VTRESULT); td->last_ins->data [0] = vt_res_size; @@ -4915,7 +5040,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, obj_size = ALIGN_TO (obj_size, MINT_VT_ALIGNMENT); #ifndef DISABLE_REMOTING - if ((m_class_get_marshalbyref (klass) && !(signature->hasthis && td->last_ins->opcode == MINT_LDARG_P0)) || + if ((m_class_get_marshalbyref (klass) && !(signature->hasthis && td->last_ins->opcode == MINT_LDLOC_O && td->last_ins->data [0] == 0)) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) { g_assert (!is_static); @@ -6168,6 +6293,61 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, if (method->wrapper_type == MONO_WRAPPER_NONE && m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) m = mono_marshal_get_synchronized_wrapper (m); + if (G_UNLIKELY (*td->ip == CEE_LDFTN && + m->wrapper_type == MONO_WRAPPER_NONE && + mono_method_has_unmanaged_callers_only_attribute (m))) { + + if (m->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) { + interp_generate_not_supported_throw (td); + interp_add_ins (td, MINT_LDNULL); + td->ip += 5; + PUSH_SIMPLE_TYPE (td, STACK_TYPE_MP); + break; + } + + MonoMethod *ctor_method; + + const unsigned char *next_ip = td->ip + 5; + /* check for + * ldftn method_sig + * newobj Delegate::.ctor + */ + if (next_ip < end && + *next_ip == CEE_NEWOBJ && + ((ctor_method = interp_get_method (method, read32 (next_ip + 1), image, generic_context, error))) && + is_ok (error) && + m_class_get_parent (ctor_method->klass) == mono_defaults.multicastdelegate_class && + !strcmp (ctor_method->name, ".ctor")) { + mono_error_set_not_supported (error, "Cannot create delegate from method with UnmanagedCallersOnlyAttribute"); + goto exit; + } + + MonoClass *delegate_klass = NULL; + MonoGCHandle target_handle = 0; + ERROR_DECL (wrapper_error); + m = mono_marshal_get_managed_wrapper (m, delegate_klass, target_handle, wrapper_error); + if (!is_ok (wrapper_error)) { + /* Generate a call that will throw an exception if the + * UnmanagedCallersOnly attribute is used incorrectly */ + interp_generate_ipe_throw_with_msg (td, wrapper_error); + mono_error_cleanup (wrapper_error); + interp_add_ins (td, MINT_LDNULL); + } else { + /* push a pointer to a trampoline that calls m */ + gpointer entry = mini_get_interp_callbacks ()->create_method_pointer (m, TRUE, error); +#if SIZEOF_VOID_P == 8 + interp_add_ins (td, MINT_LDC_I8); + WRITE64_INS (td->last_ins, 0, &entry); +#else + interp_add_ins (td, MINT_LDC_I4); + WRITE32_INS (td->last_ins, 0, &entry); +#endif + } + td->ip += 5; + PUSH_SIMPLE_TYPE (td, STACK_TYPE_MP); + break; + } + interp_add_ins (td, *td->ip == CEE_LDFTN ? MINT_LDFTN : MINT_LDVIRTFTN); td->last_ins->data [0] = get_data_item_index (td, mono_interp_get_imethod (domain, m, error)); goto_if_nok (error, exit); @@ -6189,7 +6369,12 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, if (!inlining) { get_arg_type_exact (td, n, &mt); - interp_add_ins (td, mt == MINT_TYPE_VT ? MINT_LDARGA_VT : MINT_LDARGA); + if (mt == MINT_TYPE_VT) { + interp_add_ins (td, MINT_LDARGA_VT); + } else { + interp_add_ins (td, MINT_LDLOCA_S); + td->locals [n].indirects++; + } td->last_ins->data [0] = n; } else { int loc_n = arg_locals [n]; @@ -6213,7 +6398,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, case CEE_LDLOC: { int loc_n = read16 (td->ip + 1); if (!inlining) - load_local (td, loc_n); + load_local (td, num_args + loc_n); else load_local (td, local_locals [loc_n]); td->ip += 3; @@ -6222,7 +6407,9 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, case CEE_LDLOCA: { int loc_n = read16 (td->ip + 1); interp_add_ins (td, MINT_LDLOCA_S); - if (inlining) + if (!inlining) + loc_n += num_args; + else loc_n = local_locals [loc_n]; td->last_ins->data [0] = loc_n; td->locals [loc_n].indirects++; @@ -6233,7 +6420,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, case CEE_STLOC: { int loc_n = read16 (td->ip + 1); if (!inlining) - store_local (td, loc_n); + store_local (td, num_args + loc_n); else store_local (td, local_locals [loc_n]); td->ip += 3; @@ -6755,18 +6942,6 @@ clear_stack_content_info_for_local (StackContentInfo *start, StackContentInfo *e } } -// The value of argument has changed. This means the contents of the stack where the -// argument was loaded, no longer contain the value of the argument. Clear them. -static void -clear_stack_content_info_for_argument (StackContentInfo *start, StackContentInfo *end, int argument) -{ - StackContentInfo *si; - for (si = start; si < end; si++) { - if (si->val.type == STACK_VALUE_ARG && si->val.arg == argument) - si->val.type = STACK_VALUE_NONE; - } -} - // The value of local has changed. This means we can no longer assume that any other local // is a copy of this local. static void @@ -7279,7 +7454,7 @@ interp_cprop (TransformData *td) } else { locals [dest_local].type = STACK_VALUE_NONE; } - } else if (sp->val.type == STACK_VALUE_NONE || sp->val.type == STACK_VALUE_ARG) { + } else if (sp->val.type == STACK_VALUE_NONE) { locals [dest_local].type = STACK_VALUE_NONE; } else { g_assert (sp->val.type == STACK_VALUE_I4 || sp->val.type == STACK_VALUE_I8); @@ -7348,15 +7523,6 @@ interp_cprop (TransformData *td) // propagated instruction, so we remove the top of stack dependency sp [-1].ins = NULL; sp++; - } else if (MINT_IS_LDARG (ins->opcode)) { - sp->ins = ins; - sp->val.type = STACK_VALUE_ARG; - sp->val.arg = ins->opcode == MINT_LDARG_P0 ? 0 : ins->data [0]; - sp++; - } else if (MINT_IS_STARG (ins->opcode)) { - int dest_arg = ins->data [0]; - sp--; - clear_stack_content_info_for_argument (stack, sp, dest_arg); } else if (ins->opcode >= MINT_BOX && ins->opcode <= MINT_BOX_NULLABLE) { int offset = ins->data [1]; // Clear the stack slot that is boxed @@ -7465,17 +7631,6 @@ interp_cprop (TransformData *td) interp_clear_ins (td, src->ins); mono_interp_stats.super_instructions++; mono_interp_stats.killed_instructions++; - } else if (src->val.type == STACK_VALUE_ARG && (mono_interp_opt & INTERP_OPT_SUPER_INSTRUCTIONS)) { - int arg_index = src->val.arg; - int fld_offset = ins->data [0]; - int mt = ins->opcode - MINT_STFLD_I1; - ins = interp_insert_ins (td, ins, MINT_STARGFLD_I1 + mt); - ins->data [0] = arg_index; - ins->data [1] = fld_offset; - interp_clear_ins (td, ins->prev); - interp_clear_ins (td, src->ins); - mono_interp_stats.super_instructions++; - mono_interp_stats.killed_instructions++; } } sp -= 2; @@ -7544,20 +7699,6 @@ interp_super_instructions (TransformData *td) prev1_ins = NULL; mono_interp_stats.super_instructions++; mono_interp_stats.killed_instructions++; - } else if (prev1_ins->opcode == MINT_LDARG_O || prev1_ins->opcode == MINT_LDARG_P0) { - int arg_index = 0; - int fld_offset = ins->data [0]; - int mt = ins->opcode - MINT_LDFLD_I1; - if (prev1_ins->opcode == MINT_LDARG_O) - arg_index = prev1_ins->data [0]; - ins = interp_insert_ins (td, ins, MINT_LDARGFLD_I1 + mt); - ins->data [0] = arg_index; - ins->data [1] = fld_offset; - interp_clear_ins (td, ins->prev); - interp_clear_ins (td, prev1_ins); - prev1_ins = NULL; - mono_interp_stats.super_instructions++; - mono_interp_stats.killed_instructions++; } } else if (MINT_IS_STLOC (ins->opcode) && prev1_ins && prev2_ins) { if (prev1_ins->opcode == MINT_ADD1_I4 || prev1_ins->opcode == MINT_ADD1_I8 || diff --git a/mono/mini/interp/transform.h b/mono/mini/interp/transform.h index a814859d39af..aa662fe75951 100644 --- a/mono/mini/interp/transform.h +++ b/mono/mini/interp/transform.h @@ -23,9 +23,8 @@ typedef struct #define STACK_VALUE_NONE 0 #define STACK_VALUE_LOCAL 1 -#define STACK_VALUE_ARG 2 -#define STACK_VALUE_I4 3 -#define STACK_VALUE_I8 4 +#define STACK_VALUE_I4 2 +#define STACK_VALUE_I8 3 // StackValue contains data to construct an InterpInst that is equivalent with the contents // of the stack slot / local / argument. @@ -122,6 +121,8 @@ typedef struct unsigned int max_vt_sp; unsigned int total_locals_size; InterpLocal *locals; + unsigned int il_locals_offset; + unsigned int il_locals_size; unsigned int locals_size; unsigned int locals_capacity; int n_data_items; diff --git a/mono/mini/intrinsics.c b/mono/mini/intrinsics.c index 6f6d93bbe407..cf8bcc936aaa 100644 --- a/mono/mini/intrinsics.c +++ b/mono/mini/intrinsics.c @@ -1948,6 +1948,34 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign } } + if (in_corlib && + !strcmp ("System", cmethod_klass_name_space) && + !strcmp ("ThrowHelper", cmethod_klass_name) && + !strcmp ("ThrowForUnsupportedVectorBaseType", cmethod->name)) { + /* The mono JIT can't optimize the body of this method away */ + MonoGenericContext *ctx = mono_method_get_context (cmethod); + g_assert (ctx); + g_assert (ctx->method_inst); + + MonoType *t = ctx->method_inst->type_argv [0]; + switch (t->type) { + case MONO_TYPE_I1: + case MONO_TYPE_U1: + case MONO_TYPE_I2: + case MONO_TYPE_U2: + case MONO_TYPE_I4: + case MONO_TYPE_U4: + case MONO_TYPE_I8: + case MONO_TYPE_U8: + case MONO_TYPE_R4: + case MONO_TYPE_R8: + MONO_INST_NEW (cfg, ins, OP_NOP); + MONO_ADD_INS (cfg->cbb, ins); + return ins; + default: + break; + } + } #endif ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args); diff --git a/mono/mini/jit-icalls.c b/mono/mini/jit-icalls.c index 0cdc7a544c26..d4116aafa8a9 100644 --- a/mono/mini/jit-icalls.c +++ b/mono/mini/jit-icalls.c @@ -54,7 +54,12 @@ mono_ldftn (MonoMethod *method) return addr; } - addr = mono_create_jump_trampoline (mono_domain_get (), method, FALSE, error); + /* if we need the address of a native-to-managed wrapper, just compile it now, trampoline needs thread local + * variables that won't be there if we run on a thread that's not attached yet. */ + if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) + addr = mono_compile_method_checked (method, error); + else + addr = mono_create_jump_trampoline (mono_domain_get (), method, FALSE, error); if (!is_ok (error)) { mono_error_set_pending_exception (error); return NULL; @@ -1590,6 +1595,22 @@ mono_throw_bad_image () mono_error_set_pending_exception (error); } +void +mono_throw_not_supported () +{ + ERROR_DECL (error); + mono_error_set_generic_error (error, "System", "NotSupportedException", ""); + mono_error_set_pending_exception (error); +} + +void +mono_throw_invalid_program (const char *msg) +{ + ERROR_DECL (error); + mono_error_set_invalid_program (error, "Invalid IL due to: %s", msg); + mono_error_set_pending_exception (error); +} + void mono_dummy_jit_icall (void) { diff --git a/mono/mini/jit-icalls.h b/mono/mini/jit-icalls.h index 41ebae89ceee..7de1133c0e47 100644 --- a/mono/mini/jit-icalls.h +++ b/mono/mini/jit-icalls.h @@ -223,6 +223,10 @@ ICALL_EXTERN_C void mono_throw_method_access (MonoMethod *caller, MonoMethod *ca ICALL_EXTERN_C void mono_throw_bad_image (void); +ICALL_EXTERN_C void mono_throw_not_supported (void); + +ICALL_EXTERN_C void mono_throw_invalid_program (const char *msg); + ICALL_EXTERN_C void mono_dummy_jit_icall (void); #endif /* __MONO_JIT_ICALLS_H__ */ diff --git a/mono/mini/jit.h b/mono/mini/jit.h index 011792c346b4..02639c95122d 100644 --- a/mono/mini/jit.h +++ b/mono/mini/jit.h @@ -65,6 +65,8 @@ typedef enum { MONO_AOT_MODE_INTERP_LLVMONLY, /* Use only llvm compiled code, fall back to the interpeter */ MONO_AOT_MODE_LLVMONLY_INTERP, + /* Same as --interp */ + MONO_AOT_MODE_INTERP_ONLY, /* Sentinel value used internally by the runtime. We use a large number to avoid clashing with some internal values. */ MONO_AOT_MODE_LAST = 1000, } MonoAotMode; diff --git a/mono/mini/llvm-jit.cpp b/mono/mini/llvm-jit.cpp index bd31c13dd31c..8307990a4e25 100644 --- a/mono/mini/llvm-jit.cpp +++ b/mono/mini/llvm-jit.cpp @@ -247,7 +247,7 @@ struct MonoLLVMJIT { void *sym = nullptr; auto err = mono_dl_symbol (current, name, &sym); if (!sym) { - outs () << "R: " << namestr << "\n"; + outs () << "R: " << namestr << " " << err << "\n"; } assert (sym); return JITSymbol{(uint64_t)(gssize)sym, flags}; @@ -457,7 +457,7 @@ init_passes_and_options () // FIXME: find optimal mono specific order of passes // see https://llvm.org/docs/Frontend/PerformanceTips.html#pass-ordering // the following order is based on a stripped version of "OPT -O2" - const char *default_opts = " -simplifycfg -sroa -lower-expect -instcombine -jump-threading -loop-rotate -licm -simplifycfg -lcssa -loop-idiom -indvars -loop-deletion -gvn -memcpyopt -sccp -bdce -instcombine -dse -simplifycfg -enable-implicit-null-checks -sroa -instcombine" NO_CALL_FRAME_OPT; + const char *default_opts = " -simplifycfg -sroa -lower-expect -instcombine -sroa -jump-threading -loop-rotate -licm -simplifycfg -lcssa -loop-idiom -indvars -loop-deletion -gvn -memcpyopt -sccp -bdce -instcombine -dse -simplifycfg -enable-implicit-null-checks -sroa -instcombine" NO_CALL_FRAME_OPT; const char *opts = g_getenv ("MONO_LLVM_OPT"); if (opts == NULL) opts = default_opts; diff --git a/mono/mini/method-to-ir.c b/mono/mini/method-to-ir.c index b6a8bab7421b..ead3c2e63b2d 100644 --- a/mono/mini/method-to-ir.c +++ b/mono/mini/method-to-ir.c @@ -2311,6 +2311,25 @@ emit_bad_image_failure (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee mono_emit_jit_icall (cfg, mono_throw_bad_image, NULL); } +static void +emit_not_supported_failure (MonoCompile *cfg) +{ + mono_emit_jit_icall (cfg, mono_throw_not_supported, NULL); +} + +static void +emit_invalid_program_with_msg (MonoCompile *cfg, MonoError *error_msg, MonoMethod *caller, MonoMethod *callee) +{ + g_assert (!is_ok (error_msg)); + char *str = mono_mempool_strdup (cfg->domain->mp, mono_error_get_message (error_msg)); + MonoInst *iargs[1]; + if (cfg->compile_aot) + EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str); + else + EMIT_NEW_PCONST (cfg, iargs [0], str); + mono_emit_jit_icall (cfg, mono_throw_invalid_program, iargs); +} + // FIXME Consolidate the multiple functions named get_method_nofail. static MonoMethod* get_method_nofail (MonoClass *klass, const char *method_name, int num_params, int flags) @@ -5482,9 +5501,9 @@ is_supported_tailcall (MonoCompile *cfg, const guint8 *ip, MonoMethod *method, M // http://www.mono-project.com/docs/advanced/runtime/docs/generic-sharing/ // // 1. Non-generic non-static methods of reference types have access to the - // RGCTX via the “this” argument (this->vtable->rgctx). + // RGCTX via the "this" argument (this->vtable->rgctx). // 2. a Non-generic static methods of reference types and b. non-generic methods - // of value types need to be passed a pointer to the caller’s class’s VTable in the MONO_ARCH_RGCTX_REG register. + // of value types need to be passed a pointer to the caller's class's VTable in the MONO_ARCH_RGCTX_REG register. // 3. Generic methods need to be passed a pointer to the MRGCTX in the MONO_ARCH_RGCTX_REG register // // That is what vtable_arg is here (always?). @@ -7218,8 +7237,17 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b } else if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && direct_icalls_enabled (cfg, cmethod)) { direct_icall = TRUE; } else if (fsig->pinvoke) { - MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot); - fsig = mono_method_signature_internal (wrapper); + if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) { + /* + * Avoid calling mono_marshal_get_native_wrapper () too early, it might call managed + * callbacks on netcore. + */ + fsig = mono_metadata_signature_dup_mempool (cfg->mempool, fsig); + fsig->pinvoke = FALSE; + } else { + MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot); + fsig = mono_method_signature_internal (wrapper); + } } else if (constrained_class) { } else { fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, cfg->error); @@ -7382,8 +7410,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b int costs; gboolean always = FALSE; - if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || - (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) { + if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) { /* Prevent inlining of methods that call wrappers */ INLINE_FAILURE ("wrapper call"); // FIXME? Does this write to cmethod impact tailcall_supported? Probably not. @@ -11084,6 +11111,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b if (mono_security_core_clr_enabled ()) ensure_method_is_allowed_to_call_method (cfg, method, cmethod); + const gboolean has_unmanaged_callers_only = + cmethod->wrapper_type == MONO_WRAPPER_NONE && + mono_method_has_unmanaged_callers_only_attribute (cmethod); + /* * Optimize the common case of ldftn+delegate creation */ @@ -11094,6 +11125,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b MonoMethod *invoke; int invoke_context_used; + if (G_UNLIKELY (has_unmanaged_callers_only)) { + mono_error_set_not_supported (cfg->error, "Cannot create delegate from method with UnmanagedCallersOnlyAttribute"); + CHECK_CFG_ERROR; + } + invoke = mono_get_delegate_invoke_internal (ctor_method->klass); if (!invoke || !mono_method_signature_internal (invoke)) LOAD_ERROR; @@ -11131,6 +11167,38 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b } } + /* UnmanagedCallersOnlyAttribute means ldftn should return a method callable from native */ + if (G_UNLIKELY (has_unmanaged_callers_only)) { + if (G_UNLIKELY (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) { + // Follow CoreCLR, disallow [UnmanagedCallersOnly] and [DllImport] to be used + // together + emit_not_supported_failure (cfg); + EMIT_NEW_PCONST (cfg, ins, NULL); + *sp++ = ins; + inline_costs += CALL_COST * MIN(10, num_calls++); + break; + } + MonoClass *delegate_klass = NULL; + MonoGCHandle target_handle = 0; + ERROR_DECL (wrapper_error); + MonoMethod *wrapped_cmethod; + wrapped_cmethod = mono_marshal_get_managed_wrapper (cmethod, delegate_klass, target_handle, wrapper_error); + if (!is_ok (wrapper_error)) { + /* if we couldn't create a wrapper because cmethod isn't supposed to have an + UnmanagedCallersOnly attribute, follow CoreCLR behavior and throw when the + method with the ldftn is executing, not when it is being compiled. */ + emit_invalid_program_with_msg (cfg, wrapper_error, method, cmethod); + mono_error_cleanup (wrapper_error); + EMIT_NEW_PCONST (cfg, ins, NULL); + *sp++ = ins; + + inline_costs += CALL_COST * MIN(10, num_calls++); + break; + } else { + cmethod = wrapped_cmethod; + } + } + argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD); ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst); *sp++ = ins; diff --git a/mono/mini/mini-arm64.c b/mono/mini/mini-arm64.c index 7907193b5e0f..30992b6cd881 100644 --- a/mono/mini/mini-arm64.c +++ b/mono/mini/mini-arm64.c @@ -114,6 +114,8 @@ get_delegate_invoke_impl (gboolean has_target, gboolean param_count, guint32 *co { guint8 *code, *start; + MINI_BEGIN_CODEGEN (); + if (has_target) { start = code = mono_global_codeman_reserve (12); @@ -123,9 +125,6 @@ get_delegate_invoke_impl (gboolean has_target, gboolean param_count, guint32 *co arm_brx (code, ARMREG_IP0); g_assert ((code - start) <= 12); - - mono_arch_flush_icache (start, 12); - MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL)); } else { int size, i; @@ -139,10 +138,8 @@ get_delegate_invoke_impl (gboolean has_target, gboolean param_count, guint32 *co arm_brx (code, ARMREG_IP0); g_assert ((code - start) <= size); - - mono_arch_flush_icache (start, size); - MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL)); } + MINI_END_CODEGEN (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL); if (code_size) *code_size = code - start; @@ -255,7 +252,7 @@ mono_arch_init (void) mono_arm_gsharedvt_init (); -#if defined(TARGET_IOS) || defined(TARGET_WATCHOS) +#if defined(TARGET_IOS) || defined(TARGET_WATCHOS) || defined(TARGET_OSX) ios_abi = TRUE; #endif } @@ -1076,7 +1073,11 @@ add_general (CallInfo *cinfo, ArgInfo *ainfo, int size, gboolean sign) { if (cinfo->gr >= PARAM_REGS) { ainfo->storage = ArgOnStack; - if (ios_abi) { + /* + * FIXME: The vararg argument handling code in ves_icall_System_ArgIterator_IntGetNextArg + * assumes every argument is allocated to a separate full size stack slot. + */ + if (ios_abi && !cinfo->vararg) { /* Assume size == align */ } else { /* Put arguments into 8 byte aligned stack slots */ @@ -1344,6 +1345,10 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) cinfo->nargs = n; cinfo->pinvoke = sig->pinvoke; + // Constrain this to OSX only for now +#ifdef TARGET_OSX + cinfo->vararg = sig->call_convention == MONO_CALL_VARARG; +#endif /* Return value */ add_param (cinfo, &cinfo->ret, sig->ret); @@ -5350,6 +5355,8 @@ mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTC buf = mono_domain_code_reserve (domain, buf_len); code = buf; + MINI_BEGIN_CODEGEN (); + /* * We are called by JITted code, which passes in the IMT argument in * MONO_ARCH_RGCTX_REG (r27). We need to preserve all caller saved regs @@ -5419,8 +5426,7 @@ mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTC g_assert ((code - buf) <= buf_len); - mono_arch_flush_icache (buf, code - buf); - MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_IMT_TRAMPOLINE, NULL)); + MINI_END_CODEGEN (buf, code - buf, MONO_PROFILER_CODE_BUFFER_IMT_TRAMPOLINE, NULL); return buf; } @@ -5460,7 +5466,9 @@ mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip) } else { /* ip points to an ldrx */ code += 4; + mono_codeman_enable_write (); arm_blrx (code, ARMREG_IP0); + mono_codeman_disable_write (); mono_arch_flush_icache (ip, code - ip); } } @@ -5479,7 +5487,9 @@ mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip) } else { /* ip points to an ldrx */ code += 4; + mono_codeman_enable_write (); arm_nop (code); + mono_codeman_disable_write (); mono_arch_flush_icache (ip, code - ip); } } diff --git a/mono/mini/mini-arm64.h b/mono/mini/mini-arm64.h index 41590fb0e87f..4074aa8b43f2 100644 --- a/mono/mini/mini-arm64.h +++ b/mono/mini/mini-arm64.h @@ -177,6 +177,9 @@ typedef struct { #define MONO_ARCH_FLOAT32_SUPPORTED 1 #define MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP 1 #define MONO_ARCH_LLVM_TARGET_LAYOUT "e-i64:64-i128:128-n32:64-S128" +#ifdef TARGET_OSX +#define MONO_ARCH_FORCE_FLOAT32 1 +#endif // Does the ABI have a volatile non-parameter register, so tailcall // can pass context to generics or interfaces? @@ -250,7 +253,7 @@ typedef struct { struct CallInfo { int nargs; int gr, fr, stack_usage; - gboolean pinvoke; + gboolean pinvoke, vararg; ArgInfo ret; ArgInfo sig_cookie; ArgInfo args [1]; diff --git a/mono/mini/mini-exceptions.c b/mono/mini/mini-exceptions.c index 0ddb5b0d7c34..e75267929377 100644 --- a/mono/mini/mini-exceptions.c +++ b/mono/mini/mini-exceptions.c @@ -1446,9 +1446,9 @@ fill_frame_managed_info (MonoFrameSummary *frame, MonoMethod * method) typedef struct { char *suffix; char *exported_name; -} MonoLibWhitelistEntry; +} MonoLibAllowlistEntry; -static GList *native_library_whitelist; +static GList *native_library_allowlist; static gboolean allow_all_native_libraries = FALSE; static void @@ -1457,10 +1457,10 @@ mono_crash_reporting_register_native_library (const char *module_path, const cha // Examples: libsystem_pthread.dylib -> "pthread" // Examples: libsystem_platform.dylib -> "platform" // Examples: mono-sgen -> "mono" from above line - MonoLibWhitelistEntry *entry = g_new0 (MonoLibWhitelistEntry, 1); + MonoLibAllowlistEntry*entry = g_new0 (MonoLibAllowlistEntry, 1); entry->suffix = g_strdup (module_path); entry->exported_name = g_strdup (module_name); - native_library_whitelist = g_list_append (native_library_whitelist, entry); + native_library_allowlist = g_list_append (native_library_allowlist, entry); } static void @@ -1470,7 +1470,7 @@ mono_crash_reporting_allow_all_native_libraries () } static gboolean -check_whitelisted_module (const char *in_name, const char **out_module) +check_allowlisted_module (const char *in_name, const char **out_module) { #ifndef MONO_PRIVATE_CRASHES return TRUE; @@ -1498,8 +1498,8 @@ check_whitelisted_module (const char *in_name, const char **out_module) return TRUE; } - for (GList *cursor = native_library_whitelist; cursor; cursor = cursor->next) { - MonoLibWhitelistEntry *iter = (MonoLibWhitelistEntry *) cursor->data; + for (GList *cursor = native_library_allowlist; cursor; cursor = cursor->next) { + MonoLibAllowlistEntry*iter = (MonoLibAllowlistEntry*) cursor->data; if (!g_str_has_suffix (in_name, iter->suffix)) continue; if (out_module) @@ -1538,7 +1538,7 @@ mono_get_portable_ip (intptr_t in_ip, intptr_t *out_ip, gint32 *out_offset, cons if (!success) return FALSE; - if (!check_whitelisted_module (fname, out_module)) + if (!check_allowlisted_module (fname, out_module)) return FALSE; *out_ip = mono_make_portable_ip ((intptr_t) saddr, (intptr_t) fbase); diff --git a/mono/mini/mini-generic-sharing.c b/mono/mini/mini-generic-sharing.c index 8c042132af15..5fb8bbb39c96 100644 --- a/mono/mini/mini-generic-sharing.c +++ b/mono/mini/mini-generic-sharing.c @@ -1170,6 +1170,8 @@ get_wrapper_shared_vtype (MonoType *t) if ((mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK) != TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT) return NULL; mono_class_setup_fields (klass); + if (mono_class_has_failure (klass)) + return NULL; int num_fields = mono_class_get_field_count (klass); MonoClassField *klass_fields = m_class_get_fields (klass); diff --git a/mono/mini/mini-llvm-cpp.cpp b/mono/mini/mini-llvm-cpp.cpp index e9ef87822229..dd9138ef6c28 100644 --- a/mono/mini/mini-llvm-cpp.cpp +++ b/mono/mini/mini-llvm-cpp.cpp @@ -520,7 +520,9 @@ mono_llvm_di_create_function (void *di_builder, void *cu, LLVMValueRef func, con di_file = builder->createFile (file, dir); type = builder->createSubroutineType (builder->getOrCreateTypeArray (ArrayRef ())); #if LLVM_API_VERSION >= 900 - di_func = builder->createFunction (di_file, name, mangled_name, di_file, line, type, 0); + di_func = builder->createFunction ( + di_file, name, mangled_name, di_file, line, type, 0, + DINode::FlagZero, DISubprogram::SPFlagDefinition | DISubprogram::SPFlagLocalToUnit); #else di_func = builder->createFunction (di_file, name, mangled_name, di_file, line, type, true, true, 0); #endif diff --git a/mono/mini/mini-llvm.c b/mono/mini/mini-llvm.c index c400e94f8164..4ac4e72eece2 100644 --- a/mono/mini/mini-llvm.c +++ b/mono/mini/mini-llvm.c @@ -11675,8 +11675,10 @@ llvm_jit_finalize_method (EmitContext *ctx) while (g_hash_table_iter_next (&iter, NULL, (void**)&var)) callee_vars [i ++] = var; + mono_codeman_enable_write (); cfg->native_code = (guint8*)mono_llvm_compile_method (ctx->module->mono_ee, cfg, ctx->lmethod, nvars, callee_vars, callee_addrs, &eh_frame); mono_llvm_remove_gc_safepoint_poll (ctx->lmodule); + mono_codeman_disable_write (); if (cfg->verbose_level > 1) { g_print ("\n*** Optimized LLVM IR for %s ***\n", mono_method_full_name (cfg->method, TRUE)); if (cfg->compile_aot) { diff --git a/mono/mini/mini-profiler.c b/mono/mini/mini-profiler.c index 46240cae89af..63b4fa8df7c5 100644 --- a/mono/mini/mini-profiler.c +++ b/mono/mini/mini-profiler.c @@ -1,7 +1,6 @@ /* * Licensed to the .NET Foundation under one or more agreements. * The .NET Foundation licenses this file to you under the MIT license. - * See the LICENSE file in the project root for more information. */ #include diff --git a/mono/mini/mini-riscv.c b/mono/mini/mini-riscv.c index 6d46c884f8c8..f12b699a5ef4 100644 --- a/mono/mini/mini-riscv.c +++ b/mono/mini/mini-riscv.c @@ -1,7 +1,6 @@ /* * Licensed to the .NET Foundation under one or more agreements. * The .NET Foundation licenses this file to you under the MIT license. - * See the LICENSE file in the project root for more information. */ #include @@ -233,6 +232,16 @@ mono_arch_find_static_call_vtable (host_mgreg_t *regs, guint8 *code) return (MonoVTable *) regs [MONO_ARCH_VTABLE_REG]; } +GSList* +mono_arch_get_cie_program (void) +{ + GSList *l = NULL; + + mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, RISCV_SP, 0); + + return l; +} + host_mgreg_t mono_arch_context_get_int_reg (MonoContext *ctx, int reg) { diff --git a/mono/mini/mini-riscv.h b/mono/mini/mini-riscv.h index fe0bf9e58030..9b7624b037f4 100644 --- a/mono/mini/mini-riscv.h +++ b/mono/mini/mini-riscv.h @@ -1,7 +1,6 @@ /* * Licensed to the .NET Foundation under one or more agreements. * The .NET Foundation licenses this file to you under the MIT license. - * See the LICENSE file in the project root for more information. */ #ifndef __MONO_MINI_RISCV_H__ diff --git a/mono/mini/mini-runtime.c b/mono/mini/mini-runtime.c index 37ef936aa13d..caf65d40e88a 100644 --- a/mono/mini/mini-runtime.c +++ b/mono/mini/mini-runtime.c @@ -133,7 +133,7 @@ gboolean mono_use_llvm = FALSE; gboolean mono_use_fast_math = FALSE; -// Lists of whitelisted and blacklisted CPU features +// Lists of allowlisted and blocklisted CPU features MonoCPUFeatures mono_cpu_features_enabled = (MonoCPUFeatures)0; #ifdef DISABLE_SIMD @@ -1460,9 +1460,11 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, } } + mono_codeman_enable_write (); for (i = 0; i < patch_info->data.table->table_size; i++) { jump_table [i] = code + GPOINTER_TO_INT (patch_info->data.table->table [i]); } + mono_codeman_disable_write (); target = jump_table; break; @@ -1754,6 +1756,8 @@ mini_patch_jump_sites (MonoDomain *domain, MonoMethod *method, gpointer addr) patch_info.type = MONO_PATCH_INFO_METHOD_JUMP; patch_info.data.method = method; + mono_codeman_enable_write (); + #ifdef MONO_ARCH_HAVE_PATCH_CODE_NEW for (tmp = jlist->list; tmp; tmp = tmp->next) mono_arch_patch_code_new (NULL, domain, (guint8 *)tmp->data, &patch_info, addr); @@ -1766,6 +1770,8 @@ mini_patch_jump_sites (MonoDomain *domain, MonoMethod *method, gpointer addr) mono_error_assert_ok (error); } #endif + + mono_codeman_disable_write (); } } @@ -1957,6 +1963,8 @@ enum { ELF_MACHINE = EM_PPC64, #elif HOST_S390X ELF_MACHINE = EM_S390, +#elif HOST_RISCV + ELF_MACHINE = EM_RISCV, #endif JIT_CODE_LOAD = 0 }; @@ -2014,7 +2022,7 @@ mono_enable_jit_dump (void) add_file_header_info (&header); if (perf_dump_file) { fwrite (&header, sizeof (header), 1, perf_dump_file); - //This informs perf of the presence of the jitdump file and support for the feature.​ + //This informs perf of the presence of the jitdump file and support for the feature. perf_dump_mmap_addr = mmap (NULL, sizeof (header), PROT_READ | PROT_EXEC, MAP_PRIVATE, fileno (perf_dump_file), 0); } @@ -4540,7 +4548,7 @@ mini_init (const char *filename, const char *runtime_version) else domain = mono_init_from_assembly (filename, filename); -#ifdef ENABLE_PERFTRACING +#if defined(ENABLE_PERFTRACING) && !defined(DISABLE_EVENTPIPE) ep_init (); #endif @@ -4588,7 +4596,9 @@ mini_init (const char *filename, const char *runtime_version) mono_simd_intrinsics_init (); #endif +#ifndef ENABLE_NETCORE mono_tasklets_init (); +#endif register_trampolines (domain); @@ -4887,6 +4897,8 @@ register_icalls (void) register_icall (mono_get_method_object, mono_icall_sig_object_ptr, TRUE); register_icall (mono_throw_method_access, mono_icall_sig_void_ptr_ptr, FALSE); register_icall (mono_throw_bad_image, mono_icall_sig_void, FALSE); + register_icall (mono_throw_not_supported, mono_icall_sig_void, FALSE); + register_icall (mono_throw_invalid_program, mono_icall_sig_void_ptr, FALSE); register_icall_no_wrapper (mono_dummy_jit_icall, mono_icall_sig_void); register_icall_with_wrapper (mono_monitor_enter_internal, mono_icall_sig_int32_obj); @@ -4984,7 +4996,8 @@ mini_cleanup (MonoDomain *domain) mono_runtime_print_stats (); jit_stats_cleanup (); mono_jit_dump_cleanup (); -#ifdef ENABLE_PERFTRACING + mini_get_interp_callbacks ()->cleanup (); +#if defined(ENABLE_PERFTRACING) && !defined(DISABLE_EVENTPIPE) ep_shutdown (); #endif } diff --git a/mono/mini/mini-runtime.h b/mono/mini/mini-runtime.h index 971d9a59c675..9eea434e05e7 100644 --- a/mono/mini/mini-runtime.h +++ b/mono/mini/mini-runtime.h @@ -411,11 +411,9 @@ extern MonoEEFeatures mono_ee_features; //XXX this enum *MUST extend MonoAotMode as they are consumed together. typedef enum { - /* Always execute with interp, will use JIT to produce trampolines */ - MONO_EE_MODE_INTERP = MONO_AOT_MODE_LAST, + MONO_EE_MODE_INTERP = MONO_AOT_MODE_INTERP_ONLY, } MonoEEMode; - static inline MonoMethod* jinfo_get_method (MonoJitInfo *ji) { @@ -613,5 +611,16 @@ gboolean MONO_SIG_HANDLER_SIGNATURE (mono_chain_signal); void mini_register_sigterm_handler (void); +#define MINI_BEGIN_CODEGEN() do { \ + mono_codeman_enable_write (); \ + } while (0) + +#define MINI_END_CODEGEN(buf,size,type,arg) do { \ + mono_codeman_disable_write (); \ + mono_arch_flush_icache ((buf), (size)); \ + if ((int)type != -1) \ + MONO_PROFILER_RAISE (jit_code_buffer, ((buf), (size), (type), (arg))); \ + } while (0) + #endif /* __MONO_MINI_RUNTIME_H__ */ diff --git a/mono/mini/mini-s390x.h b/mono/mini/mini-s390x.h index 2efcafbd456b..bb358e235ab0 100644 --- a/mono/mini/mini-s390x.h +++ b/mono/mini/mini-s390x.h @@ -158,7 +158,7 @@ struct SeqPointInfo { #define MONO_INIT_CONTEXT_FROM_FUNC(ctx,func) do { \ MonoS390StackFrame *sframe; \ - __asm__ volatile("lgr %0,15" : "=r" (sframe)); \ + __asm__ volatile("lgr %0,%%r15" : "=r" (sframe)); \ MONO_CONTEXT_SET_BP ((ctx), sframe->prev); \ MONO_CONTEXT_SET_SP ((ctx), sframe->prev); \ MONO_CONTEXT_SET_IP ((ctx), func); \ diff --git a/mono/mini/mini-wasm-debugger.c b/mono/mini/mini-wasm-debugger.c index 603b331d1f0b..dc1f5d38f3d2 100644 --- a/mono/mini/mini-wasm-debugger.c +++ b/mono/mini/mini-wasm-debugger.c @@ -38,6 +38,7 @@ EMSCRIPTEN_KEEPALIVE void mono_wasm_get_object_properties (int object_id, gboole EMSCRIPTEN_KEEPALIVE void mono_wasm_get_array_values (int object_id); EMSCRIPTEN_KEEPALIVE void mono_wasm_get_array_value_expanded (int object_id, int idx); EMSCRIPTEN_KEEPALIVE void mono_wasm_invoke_getter_on_object (int object_id, const char* name); +EMSCRIPTEN_KEEPALIVE void mono_wasm_get_deref_ptr_value (void *value_addr, MonoClass *klass); //JS functions imported that we use extern void mono_wasm_add_frame (int il_offset, int method_token, const char *assembly_name, const char *method_name); @@ -808,11 +809,13 @@ static gboolean describe_value(MonoType * type, gpointer addr, gboolean expandVa case MONO_TYPE_FNPTR: { char *class_name = mono_type_full_name (type); const void *val = *(const void **)addr; - char *val_str = g_strdup_printf ("(%s) %p", class_name, val); + char *descr = g_strdup_printf ("(%s) %p", class_name, val); - mono_wasm_add_typed_value ("pointer", val_str, (guint32)val); + EM_ASM ({ + MONO.mono_wasm_add_typed_value ('pointer', $0, { ptr_addr: $1, klass_addr: $2 }); + }, descr, val ? addr : 0, val ? mono_class_from_mono_type_internal (type) : 0); - g_free (val_str); + g_free (descr); g_free (class_name); break; } @@ -1281,6 +1284,19 @@ describe_variables_on_frame (MonoStackFrameInfo *info, MonoContext *ctx, gpointe return TRUE; } +EMSCRIPTEN_KEEPALIVE void +mono_wasm_get_deref_ptr_value (void *value_addr, MonoClass *klass) +{ + MonoType *type = m_class_get_byval_arg (klass); + if (type->type != MONO_TYPE_PTR && type->type != MONO_TYPE_FNPTR) { + DEBUG_PRINTF (2, "BUG: mono_wasm_get_deref_ptr_value: Expected to get a ptr type, but got 0x%x\n", type->type); + return; + } + + mono_wasm_add_properties_var ("deref", -1); + describe_value (type->data.type, value_addr, TRUE); +} + //FIXME this doesn't support getting the return value pseudo-var EMSCRIPTEN_KEEPALIVE void mono_wasm_get_var_info (int scope, int* pos, int len) diff --git a/mono/mini/mini-wasm.c b/mono/mini/mini-wasm.c index 3b914a03fddf..e60d77f49250 100644 --- a/mono/mini/mini-wasm.c +++ b/mono/mini/mini-wasm.c @@ -604,13 +604,13 @@ tp_cb (void) mono_runtime_try_invoke (method, NULL, NULL, &exc, error); if (!is_ok (error)) { - printf ("tp callback failed due to %s\n", mono_error_get_message (error)); + printf ("ThreadPool Callback failed due to error: %s\n", mono_error_get_message (error)); mono_error_cleanup (error); } if (exc) { char *type_name = mono_type_get_full_name (mono_object_class (exc)); - printf ("tp callback threw a %s\n", type_name); + printf ("ThreadPool Callback threw an unhandled exception of type %s\n", type_name); g_free (type_name); } } diff --git a/mono/mini/mini.c b/mono/mini/mini.c index 2c9a2e96f5e1..3cad9644f67a 100644 --- a/mono/mini/mini.c +++ b/mono/mini/mini.c @@ -972,7 +972,7 @@ mini_method_verify (MonoCompile *cfg, MonoMethod *method, gboolean fail_compile) GSList *tmp, *res; gboolean is_fulltrust; - if (method->verification_success) + if (mono_method_get_verification_success (method)) return FALSE; if (!mono_verifier_is_enabled_for_method (method)) @@ -1022,7 +1022,7 @@ mini_method_verify (MonoCompile *cfg, MonoMethod *method, gboolean fail_compile) } mono_free_verify_list (res); } - method->verification_success = 1; + mono_method_set_verification_success (method); return FALSE; } @@ -2252,6 +2252,8 @@ mono_codegen (MonoCompile *cfg) code = (guint8 *)mono_domain_code_reserve (code_domain, cfg->code_size + cfg->thunk_area + unwindlen); } + mono_codeman_enable_write (); + if (cfg->thunk_area) { cfg->thunks_offset = cfg->code_size + unwindlen; cfg->thunks = code + cfg->thunks_offset; @@ -2343,6 +2345,9 @@ mono_codegen (MonoCompile *cfg) } else { mono_domain_code_commit (code_domain, cfg->native_code, cfg->code_size, cfg->code_len); } + + mono_codeman_disable_write (); + MONO_PROFILER_RAISE (jit_code_buffer, (cfg->native_code, cfg->code_len, MONO_PROFILER_CODE_BUFFER_METHOD, cfg->method)); mono_arch_flush_icache (cfg->native_code, cfg->code_len); @@ -3048,6 +3053,9 @@ init_backend (MonoBackend *backend) #ifdef MONO_ARCH_HAVE_OPTIMIZED_DIV backend->optimized_div = 1; #endif +#ifdef MONO_ARCH_FORCE_FLOAT32 + backend->force_float32 = 1; +#endif } static gboolean @@ -3150,6 +3158,9 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl #ifndef MONO_ARCH_FLOAT32_SUPPORTED opts &= ~MONO_OPT_FLOAT32; #endif + if (current_backend->force_float32) + /* Force float32 mode on newer platforms */ + opts |= MONO_OPT_FLOAT32; restart_compile: if (method_is_gshared) { diff --git a/mono/mini/mini.h b/mono/mini/mini.h index e782440c7e18..58eb136d3181 100644 --- a/mono/mini/mini.h +++ b/mono/mini/mini.h @@ -1193,7 +1193,7 @@ typedef struct { guint have_generalized_imt_trampoline : 1; gboolean have_op_tailcall_membase : 1; gboolean have_op_tailcall_reg : 1; - gboolean have_volatile_non_param_register : 1; + gboolean have_volatile_non_param_register : 1; guint gshared_supported : 1; guint use_fpstack : 1; guint ilp32 : 1; @@ -1203,6 +1203,7 @@ typedef struct { guint disable_div_with_mul : 1; guint explicit_null_checks : 1; guint optimized_div : 1; + guint force_float32 : 1; int monitor_enter_adjustment; int dyn_call_param_area; } MonoBackend; diff --git a/mono/mini/mono-private-unstable.h b/mono/mini/mono-private-unstable.h index 04fb0a045de6..4d746dd00e25 100644 --- a/mono/mini/mono-private-unstable.h +++ b/mono/mini/mono-private-unstable.h @@ -29,4 +29,11 @@ mono_install_load_aot_data_hook (MonoLoadAotDataFunc load_func, MonoFreeAotDataF MONO_API int monovm_initialize (int propertyCount, const char **propertyKeys, const char **propertyValues); +//#ifdef HOST_WASM +typedef void* (*MonoWasmGetNativeToInterpTramp) (MonoMethod *method, void *extra_arg); + +MONO_API void +mono_wasm_install_get_native_to_interp_tramp (MonoWasmGetNativeToInterpTramp cb); +//#endif + #endif /*__MONO_JIT_MONO_PRIVATE_UNSTABLE_H__*/ diff --git a/mono/mini/simd-intrinsics-netcore.c b/mono/mini/simd-intrinsics-netcore.c index 688c3620af0d..a93b334fe4ab 100644 --- a/mono/mini/simd-intrinsics-netcore.c +++ b/mono/mini/simd-intrinsics-netcore.c @@ -373,9 +373,10 @@ static guint16 vector_t_methods [] = { SN_LessThanOrEqual, SN_Max, SN_Min, - SN_get_AllOnes, + SN_get_AllBitsSet, SN_get_Count, SN_get_Item, + SN_get_One, SN_get_Zero, SN_op_Addition, SN_op_BitwiseAnd, @@ -398,6 +399,9 @@ emit_sys_numerics_vector_t (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSig int size, len, id; gboolean is_unsigned; + static const float r4_one = 1.0f; + static const double r8_one = 1.0; + id = lookup_intrins (vector_t_methods, sizeof (vector_t_methods), cmethod); if (id == -1) return NULL; @@ -427,7 +431,33 @@ emit_sys_numerics_vector_t (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSig case SN_get_Zero: g_assert (fsig->param_count == 0 && mono_metadata_type_equal (fsig->ret, type)); return emit_simd_ins (cfg, klass, OP_XZERO, -1, -1); - case SN_get_AllOnes: { + case SN_get_One: { + g_assert (fsig->param_count == 0 && mono_metadata_type_equal (fsig->ret, type)); + MonoInst *one = NULL; + int expand_opcode = type_to_expand_op (etype); + MONO_INST_NEW (cfg, one, -1); + switch (expand_opcode) { + case OP_EXPAND_R4: + one->opcode = OP_R4CONST; + one->type = STACK_R4; + one->inst_p0 = (void *) &r4_one; + break; + case OP_EXPAND_R8: + one->opcode = OP_R8CONST; + one->type = STACK_R8; + one->inst_p0 = (void *) &r8_one; + break; + default: + one->opcode = OP_ICONST; + one->type = STACK_I4; + one->inst_c0 = 1; + break; + } + one->dreg = alloc_dreg (cfg, one->type); + MONO_ADD_INS (cfg->cbb, one); + return emit_simd_ins (cfg, klass, expand_opcode, one->dreg, -1); + } + case SN_get_AllBitsSet: { /* Compare a zero vector with itself */ ins = emit_simd_ins (cfg, klass, OP_XZERO, -1, -1); return emit_xcompare (cfg, klass, etype->type, ins, ins); diff --git a/mono/mini/simd-methods-netcore.h b/mono/mini/simd-methods-netcore.h index fceba001c083..6ea5b9c4a217 100644 --- a/mono/mini/simd-methods-netcore.h +++ b/mono/mini/simd-methods-netcore.h @@ -14,7 +14,7 @@ METHOD(LeadingZeroCount) METHOD(get_Count) METHOD(get_IsHardwareAccelerated) METHOD(get_IsSupported) -METHOD(get_AllOnes) +METHOD(get_AllBitsSet) METHOD(get_Item) METHOD(get_One) METHOD(get_Zero) diff --git a/mono/mini/tasklets.c b/mono/mini/tasklets.c index 361b3f02353f..402a3a981c23 100644 --- a/mono/mini/tasklets.c +++ b/mono/mini/tasklets.c @@ -12,6 +12,7 @@ #include "mono/metadata/loader-internals.h" #include "mono/utils/mono-tls-inline.h" +#if !defined(ENABLE_NETCORE) #if defined(MONO_SUPPORT_TASKLETS) #include "mono/metadata/loader-internals.h" @@ -213,5 +214,7 @@ mono_tasklets_init(void) mono_add_internal_call_internal ("Mono.Tasklets.Continuation::restore", continuation_restore); } -#endif +#endif /* MONO_SUPPORT_TASKLETS */ + +#endif /* ENABLE_NETCORE */ diff --git a/mono/mini/tasklets.h b/mono/mini/tasklets.h index fc6f0b8178a9..dd8750f3f2f2 100644 --- a/mono/mini/tasklets.h +++ b/mono/mini/tasklets.h @@ -7,6 +7,7 @@ #include "mini.h" +#if !defined(ENABLE_NETCORE) typedef struct { MonoLMF *lmf; gpointer top_sp; @@ -31,5 +32,7 @@ void mono_tasklets_cleanup (void); MonoContinuationRestore mono_tasklets_arch_restore (void); +#endif /* ENABLE_NETCORE */ + #endif /* __MONO_TASKLETS_H__ */ diff --git a/mono/mini/trace.c b/mono/mini/trace.c index bea1a6085874..c6ace8c9ae5d 100644 --- a/mono/mini/trace.c +++ b/mono/mini/trace.c @@ -31,7 +31,7 @@ #pragma warning(disable:4312) // FIXME pointer cast to different size #endif -#if defined (HOST_ANDROID) || (defined (TARGET_IOS) && defined (TARGET_IOS)) +#if defined (HOST_ANDROID) || defined (TARGET_IOS) # undef printf # define printf(...) g_log("mono", G_LOG_LEVEL_MESSAGE, __VA_ARGS__) # undef fprintf diff --git a/mono/mini/tramp-arm64-gsharedvt.c b/mono/mini/tramp-arm64-gsharedvt.c index c1038511d67f..269624c259da 100644 --- a/mono/mini/tramp-arm64-gsharedvt.c +++ b/mono/mini/tramp-arm64-gsharedvt.c @@ -13,6 +13,7 @@ #include "mini.h" #include "mini-arm64.h" #include "mini-arm64-gsharedvt.h" +#include "mini-runtime.h" /* * GSHAREDVT @@ -36,13 +37,16 @@ mono_arch_get_gsharedvt_arg_trampoline (MonoDomain *domain, gpointer arg, gpoint */ buf = code = mono_global_codeman_reserve (buf_len); + MINI_BEGIN_CODEGEN (); + code = mono_arm_emit_imm64 (code, ARMREG_IP1, (guint64)arg); code = mono_arm_emit_imm64 (code, ARMREG_IP0, (guint64)addr); arm_brx (code, ARMREG_IP0); g_assert ((code - buf) < buf_len); - mono_arch_flush_icache (buf, code - buf); + + MINI_END_CODEGEN (buf, code - buf, -1, NULL); return buf; } @@ -248,6 +252,8 @@ mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot) cfa_offset = offset; + MINI_BEGIN_CODEGEN (); + /* Setup frame */ arm_stpx_pre (code, ARMREG_FP, ARMREG_LR, ARMREG_SP, -cfa_offset); mono_add_unwind_op_def_cfa (unwind_ops, code, buf, ARMREG_SP, cfa_offset); @@ -547,7 +553,8 @@ mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot) if (info) *info = mono_tramp_info_create ("gsharedvt_trampoline", buf, code - buf, ji, unwind_ops); - mono_arch_flush_icache (buf, code - buf); + MINI_END_CODEGEN (buf, code - buf, -1, NULL); + return buf; } diff --git a/mono/mini/tramp-arm64.c b/mono/mini/tramp-arm64.c index 04eda906c469..7b889a3ffde4 100644 --- a/mono/mini/tramp-arm64.c +++ b/mono/mini/tramp-arm64.c @@ -30,8 +30,9 @@ void mono_arch_patch_callsite (guint8 *method_start, guint8 *code_ptr, guint8 *addr) { + MINI_BEGIN_CODEGEN (); mono_arm_patch (code_ptr - 4, addr, MONO_R_ARM64_BL); - mono_arch_flush_icache (code_ptr - 4, 4); + MINI_END_CODEGEN (code_ptr - 4, 4, -1, NULL); } void @@ -133,6 +134,8 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf //offset += 22 * 8; frame_size = ALIGN_TO (offset, MONO_ARCH_FRAME_ALIGNMENT); + MINI_BEGIN_CODEGEN (); + /* Setup stack frame */ imm = frame_size; mono_add_unwind_op_def_cfa (unwind_ops, code, buf, ARMREG_SP, 0); @@ -303,8 +306,8 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf arm_brx (code, ARMREG_IP0); g_assert ((code - buf) < buf_len); - mono_arch_flush_icache (buf, code - buf); - MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL)); + + MINI_END_CODEGEN (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL); if (info) { tramp_name = mono_get_generic_trampoline_name (tramp_type); @@ -328,14 +331,16 @@ mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_ty buf = code = mono_domain_code_reserve (domain, buf_len); + MINI_BEGIN_CODEGEN (); + code = mono_arm_emit_imm64 (code, ARMREG_IP1, (guint64)arg1); code = mono_arm_emit_imm64 (code, ARMREG_IP0, (guint64)tramp); arm_brx (code, ARMREG_IP0); g_assert ((code - buf) < buf_len); - mono_arch_flush_icache (buf, code - buf); - MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE, mono_get_generic_trampoline_simple_name (tramp_type))); + + MINI_END_CODEGEN (buf, code - buf, MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE, mono_get_generic_trampoline_simple_name (tramp_type)); if (code_len) *code_len = code - buf; @@ -351,13 +356,17 @@ mono_arch_get_unbox_trampoline (MonoMethod *m, gpointer addr) MonoDomain *domain = mono_domain_get (); start = code = mono_domain_code_reserve (domain, size); + + MINI_BEGIN_CODEGEN (); + code = mono_arm_emit_imm64 (code, ARMREG_IP0, (guint64)addr); arm_addx_imm (code, ARMREG_R0, ARMREG_R0, MONO_ABI_SIZEOF (MonoObject)); arm_brx (code, ARMREG_IP0); g_assert ((code - start) <= size); - mono_arch_flush_icache (start, code - start); - MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_UNBOX_TRAMPOLINE, m)); + + MINI_END_CODEGEN (start, code - start, MONO_PROFILER_CODE_BUFFER_UNBOX_TRAMPOLINE, m); + return start; } @@ -369,14 +378,16 @@ mono_arch_get_static_rgctx_trampoline (gpointer arg, gpointer addr) MonoDomain *domain = mono_domain_get (); start = code = mono_domain_code_reserve (domain, buf_len); + + MINI_BEGIN_CODEGEN (); + code = mono_arm_emit_imm64 (code, MONO_ARCH_RGCTX_REG, (guint64)arg); code = mono_arm_emit_imm64 (code, ARMREG_IP0, (guint64)addr); arm_brx (code, ARMREG_IP0); - g_assert ((code - start) <= buf_len); + MINI_END_CODEGEN (start, code - start, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL); - mono_arch_flush_icache (start, code - start); - MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL)); + g_assert ((code - start) <= buf_len); return start; } @@ -415,6 +426,8 @@ mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 slot, MonoTrampInfo **info /* The vtable/mrgtx is in R0 */ g_assert (MONO_ARCH_VTABLE_REG == ARMREG_R0); + MINI_BEGIN_CODEGEN (); + if (is_mrgctx) { /* get mrgctx ptr */ arm_movx (code, ARMREG_IP1, ARMREG_R0); @@ -468,11 +481,10 @@ mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 slot, MonoTrampInfo **info } arm_brx (code, ARMREG_IP0); - mono_arch_flush_icache (buf, code - buf); - MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL)); - g_assert (code - buf <= buf_size); + MINI_END_CODEGEN (buf, code - buf, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL); + if (info) { char *name = mono_get_rgctx_fetch_trampoline_name (slot); *info = mono_tramp_info_create (name, buf, code - buf, ji, unwind_ops); @@ -498,6 +510,8 @@ mono_arch_create_general_rgctx_lazy_fetch_trampoline (MonoTrampInfo **info, gboo mono_add_unwind_op_def_cfa (unwind_ops, code, buf, ARMREG_SP, 0); + MINI_BEGIN_CODEGEN (); + // FIXME: Currently, we always go to the slow path. /* Load trampoline addr */ arm_ldrx (code, ARMREG_IP0, MONO_ARCH_RGCTX_REG, 8); @@ -505,11 +519,10 @@ mono_arch_create_general_rgctx_lazy_fetch_trampoline (MonoTrampInfo **info, gboo g_assert (MONO_ARCH_VTABLE_REG == ARMREG_R0); arm_brx (code, ARMREG_IP0); - mono_arch_flush_icache (buf, code - buf); - MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL)); - g_assert (code - buf <= tramp_size); + MINI_END_CODEGEN (buf, code - buf, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL); + if (info) *info = mono_tramp_info_create ("rgctx_fetch_trampoline_general", buf, code - buf, ji, unwind_ops); @@ -547,6 +560,8 @@ mono_arch_create_sdb_trampoline (gboolean single_step, MonoTrampInfo **info, gbo // FIXME: Unwind info + MINI_BEGIN_CODEGEN (); + /* Setup stack frame */ imm = frame_size; while (imm > 256) { @@ -605,10 +620,10 @@ mono_arch_create_sdb_trampoline (gboolean single_step, MonoTrampInfo **info, gbo arm_retx (code, ARMREG_LR); - mono_arch_flush_icache (code, code - buf); - MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL)); g_assert (code - buf <= tramp_size); + MINI_END_CODEGEN (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL); + const char *tramp_name = single_step ? "sdb_single_step_trampoline" : "sdb_breakpoint_trampoline"; *info = mono_tramp_info_create (tramp_name, buf, code - buf, ji, unwind_ops); @@ -644,6 +659,8 @@ mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) framesize = ALIGN_TO (framesize, MONO_ARCH_FRAME_ALIGNMENT); + MINI_BEGIN_CODEGEN (); + arm_subx_imm (code, ARMREG_SP, ARMREG_SP, framesize); arm_stpx (code, ARMREG_FP, ARMREG_LR, ARMREG_SP, 0); arm_movspx (code, ARMREG_FP, ARMREG_SP); @@ -712,8 +729,7 @@ mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) g_assert (code - start < buf_len); - mono_arch_flush_icache (start, code - start); - MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_HELPER, NULL)); + MINI_END_CODEGEN (start, code - start, MONO_PROFILER_CODE_BUFFER_HELPER, NULL); if (info) *info = mono_tramp_info_create ("interp_to_native_trampoline", start, code - start, ji, unwind_ops); @@ -744,6 +760,8 @@ mono_arch_get_native_to_interp_trampoline (MonoTrampInfo **info) offset += sizeof (CallContext); framesize = ALIGN_TO (offset, MONO_ARCH_FRAME_ALIGNMENT); + MINI_BEGIN_CODEGEN (); + mono_add_unwind_op_def_cfa (unwind_ops, code, start, ARMREG_SP, 0); arm_subx_imm (code, ARMREG_SP, ARMREG_SP, framesize); @@ -788,8 +806,7 @@ mono_arch_get_native_to_interp_trampoline (MonoTrampInfo **info) g_assert (code - start < buf_len); - mono_arch_flush_icache (start, code - start); - MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL)); + MINI_END_CODEGEN (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL); if (info) *info = mono_tramp_info_create ("native_to_interp_trampoline", start, code - start, ji, unwind_ops); diff --git a/mono/mini/tramp-riscv.c b/mono/mini/tramp-riscv.c index 7ab932005738..d58d8e46f198 100644 --- a/mono/mini/tramp-riscv.c +++ b/mono/mini/tramp-riscv.c @@ -1,7 +1,6 @@ /* * Licensed to the .NET Foundation under one or more agreements. * The .NET Foundation licenses this file to you under the MIT license. - * See the LICENSE file in the project root for more information. */ #include "mini-runtime.h" diff --git a/mono/mini/wasm_m2n_invoke.g.h b/mono/mini/wasm_m2n_invoke.g.h index 9ff51af01d8c..715070c03fd2 100644 --- a/mono/mini/wasm_m2n_invoke.g.h +++ b/mono/mini/wasm_m2n_invoke.g.h @@ -1527,6 +1527,104 @@ wasm_invoke_viiiif (void *target_func, InterpMethodArguments *margs) } +static void +wasm_invoke_iffffiii (void *target_func, InterpMethodArguments *margs) +{ + typedef int (*T)(float arg_0, float arg_1, float arg_2, float arg_3, int arg_4, int arg_5, int arg_6); + T func = (T)target_func; + int res = func (*(float*)&margs->fargs [FIDX (0)], *(float*)&margs->fargs [FIDX (1)], *(float*)&margs->fargs [FIDX (2)], *(float*)&margs->fargs [FIDX (3)], (int)(gssize)margs->iargs [0], (int)(gssize)margs->iargs [1], (int)(gssize)margs->iargs [2]); + *(int*)margs->retval = res; + +} + +static void +wasm_invoke_iffiii (void *target_func, InterpMethodArguments *margs) +{ + typedef int (*T)(float arg_0, float arg_1, int arg_2, int arg_3, int arg_4); + T func = (T)target_func; + int res = func (*(float*)&margs->fargs [FIDX (0)], *(float*)&margs->fargs [FIDX (1)], (int)(gssize)margs->iargs [0], (int)(gssize)margs->iargs [1], (int)(gssize)margs->iargs [2]); + *(int*)margs->retval = res; + +} + +static void +wasm_invoke_viiiiffii (void *target_func, InterpMethodArguments *margs) +{ + typedef void (*T)(int arg_0, int arg_1, int arg_2, int arg_3, float arg_4, float arg_5, int arg_6, int arg_7); + T func = (T)target_func; + func ((int)(gssize)margs->iargs [0], (int)(gssize)margs->iargs [1], (int)(gssize)margs->iargs [2], (int)(gssize)margs->iargs [3], *(float*)&margs->fargs [FIDX (0)], *(float*)&margs->fargs [FIDX (1)], (int)(gssize)margs->iargs [4], (int)(gssize)margs->iargs [5]); + +} + +static void +wasm_invoke_iiiliiii (void *target_func, InterpMethodArguments *margs) +{ + typedef int (*T)(int arg_0, int arg_1, gint64 arg_2, int arg_3, int arg_4, int arg_5, int arg_6); + T func = (T)target_func; + int res = func ((int)(gssize)margs->iargs [0], (int)(gssize)margs->iargs [1], get_long_arg (margs, 2), (int)(gssize)margs->iargs [4], (int)(gssize)margs->iargs [5], (int)(gssize)margs->iargs [6], (int)(gssize)margs->iargs [7]); + *(int*)margs->retval = res; + +} + +static void +wasm_invoke_iiilli (void *target_func, InterpMethodArguments *margs) +{ + typedef int (*T)(int arg_0, int arg_1, gint64 arg_2, gint64 arg_3, int arg_4); + T func = (T)target_func; + int res = func ((int)(gssize)margs->iargs [0], (int)(gssize)margs->iargs [1], get_long_arg (margs, 2), get_long_arg (margs, 4), (int)(gssize)margs->iargs [6]); + *(int*)margs->retval = res; + +} + +static void +wasm_invoke_il (void *target_func, InterpMethodArguments *margs) +{ + typedef int (*T)(gint64 arg_0); + T func = (T)target_func; + int res = func (get_long_arg (margs, 0)); + *(int*)margs->retval = res; + +} + +static void +wasm_invoke_iff (void *target_func, InterpMethodArguments *margs) +{ + typedef int (*T)(float arg_0, float arg_1); + T func = (T)target_func; + int res = func (*(float*)&margs->fargs [FIDX (0)], *(float*)&margs->fargs [FIDX (1)]); + *(int*)margs->retval = res; + +} + +static void +wasm_invoke_ifff (void *target_func, InterpMethodArguments *margs) +{ + typedef int (*T)(float arg_0, float arg_1, float arg_2); + T func = (T)target_func; + int res = func (*(float*)&margs->fargs [FIDX (0)], *(float*)&margs->fargs [FIDX (1)], *(float*)&margs->fargs [FIDX (2)]); + *(int*)margs->retval = res; + +} + +static void +wasm_invoke_iffff (void *target_func, InterpMethodArguments *margs) +{ + typedef int (*T)(float arg_0, float arg_1, float arg_2, float arg_3); + T func = (T)target_func; + int res = func (*(float*)&margs->fargs [FIDX (0)], *(float*)&margs->fargs [FIDX (1)], *(float*)&margs->fargs [FIDX (2)], *(float*)&margs->fargs [FIDX (3)]); + *(int*)margs->retval = res; + +} + +static void +wasm_invoke_vlii (void *target_func, InterpMethodArguments *margs) +{ + typedef void (*T)(gint64 arg_0, int arg_1, int arg_2); + T func = (T)target_func; + func (get_long_arg (margs, 0), (int)(gssize)margs->iargs [2], (int)(gssize)margs->iargs [3]); + +} + static const char* interp_to_native_signatures [] = { "DD", "DDD", @@ -1550,12 +1648,17 @@ static const char* interp_to_native_signatures [] = { "ID", "IDIII", "IF", +"IFF", +"IFFF", +"IFFFF", "IFFFFFFI", +"IFFFFIII", "IFFFFIIII", "IFFI", "IFFIF", "IFFIFI", "IFFII", +"IFFIII", "IFI", "IFIII", "II", @@ -1616,12 +1719,15 @@ static const char* interp_to_native_signatures [] = { "IIIIIIIIIIIII", "IIIIIIIIIIIIII", "IIIL", +"IIILIIII", +"IIILLI", "IIL", "IILI", "IILIIII", "IILIIIL", "IILLI", "IILLLI", +"IL", "ILI", "L", "LI", @@ -1671,6 +1777,7 @@ static const char* interp_to_native_signatures [] = { "VIIIFIII", "VIIII", "VIIIIF", +"VIIIIFFII", "VIIIII", "VIIIIII", "VIIIIIII", @@ -1686,6 +1793,7 @@ static const char* interp_to_native_signatures [] = { "VIL", "VILLI", "VL", +"VLII", }; static void* interp_to_native_invokes [] = { wasm_invoke_dd, @@ -1710,12 +1818,17 @@ wasm_invoke_i, wasm_invoke_id, wasm_invoke_idiii, wasm_invoke_if, +wasm_invoke_iff, +wasm_invoke_ifff, +wasm_invoke_iffff, wasm_invoke_iffffffi, +wasm_invoke_iffffiii, wasm_invoke_iffffiiii, wasm_invoke_iffi, wasm_invoke_iffif, wasm_invoke_iffifi, wasm_invoke_iffii, +wasm_invoke_iffiii, wasm_invoke_ifi, wasm_invoke_ifiii, wasm_invoke_ii, @@ -1776,12 +1889,15 @@ wasm_invoke_iiiiiiiiiiii, wasm_invoke_iiiiiiiiiiiii, wasm_invoke_iiiiiiiiiiiiii, wasm_invoke_iiil, +wasm_invoke_iiiliiii, +wasm_invoke_iiilli, wasm_invoke_iil, wasm_invoke_iili, wasm_invoke_iiliiii, wasm_invoke_iiliiil, wasm_invoke_iilli, wasm_invoke_iillli, +wasm_invoke_il, wasm_invoke_ili, wasm_invoke_l, wasm_invoke_li, @@ -1831,6 +1947,7 @@ wasm_invoke_viiifii, wasm_invoke_viiifiii, wasm_invoke_viiii, wasm_invoke_viiiif, +wasm_invoke_viiiiffii, wasm_invoke_viiiii, wasm_invoke_viiiiii, wasm_invoke_viiiiiii, @@ -1846,4 +1963,5 @@ wasm_invoke_viil, wasm_invoke_vil, wasm_invoke_villi, wasm_invoke_vl, +wasm_invoke_vlii, }; diff --git a/mono/sgen/sgen-client.h b/mono/sgen/sgen-client.h index 53a1a43f45de..7eb78f75fad5 100644 --- a/mono/sgen/sgen-client.h +++ b/mono/sgen/sgen-client.h @@ -207,12 +207,19 @@ void sgen_client_bridge_processing_finish (int generation); gboolean sgen_client_bridge_is_bridge_object (GCObject *obj); void sgen_client_bridge_register_finalized_object (GCObject *object); +#ifndef DISABLE_SGEN_TOGGLEREF /* * No action is necessary. */ void sgen_client_mark_togglerefs (char *start, char *end, ScanCopyContext ctx); void sgen_client_clear_togglerefs (char *start, char *end, ScanCopyContext ctx); void sgen_foreach_toggleref_root (void (*callback)(MonoObject*, gpointer), gpointer data); +#else +static inline void sgen_client_mark_togglerefs (char *start, char *end, ScanCopyContext ctx) { } +static inline void sgen_client_clear_togglerefs (char *start, char *end, ScanCopyContext ctx) { } +static inline void sgen_foreach_toggleref_root (void (*callback)(MonoObject*, gpointer), gpointer data) { } +#endif + /* * Called to handle `MONO_GC_PARAMS` and `MONO_GC_DEBUG` options. The `handle` functions diff --git a/mono/sgen/sgen-conf.h b/mono/sgen/sgen-conf.h index a955a46ab53e..fc6ee088dbf5 100644 --- a/mono/sgen/sgen-conf.h +++ b/mono/sgen/sgen-conf.h @@ -130,7 +130,12 @@ typedef target_mword SgenDescriptor; * Making this a constant enables us to put logging in a lot of places and * not pay its cost on release builds. */ +#ifndef DISABLE_SGEN_DEBUG_HELPERS #define SGEN_MAX_DEBUG_LEVEL 2 +#else +/* No logging support */ +#define SGEN_MAX_DEBUG_LEVEL (-1) +#endif /* * Maximum level of asserts to enable on this build. diff --git a/mono/sgen/sgen-gc.c b/mono/sgen/sgen-gc.c index 9071837fbc5a..e6719fae0585 100644 --- a/mono/sgen/sgen-gc.c +++ b/mono/sgen/sgen-gc.c @@ -106,7 +106,7 @@ happened. This might make for a good first implementation to get some data on performance. - *) Some sort of blacklist support? Blacklists is a concept from the + *) Some sort of blocklist support? Blocklists is a concept from the Boehm GC: if during a conservative scan we find pointers to an area which we might use as heap, we mark that area as unusable, so pointer retention by random pinning pointers is reduced. @@ -235,7 +235,12 @@ static gboolean disable_minor_collections = FALSE; static gboolean disable_major_collections = FALSE; static gboolean do_verify_nursery = FALSE; static gboolean do_dump_nursery_content = FALSE; + +#ifndef DISABLE_SGEN_DEBUG_HELPERS static gboolean enable_nursery_canaries = FALSE; +#else +static const gboolean enable_nursery_canaries = FALSE; +#endif static gboolean precleaning_enabled = TRUE; static gboolean dynamic_nursery = FALSE; @@ -378,7 +383,9 @@ static volatile mword highest_heap_address = 0; MonoCoopMutex sgen_interruption_mutex; int sgen_current_collection_generation = -1; +#ifndef DISABLE_SGEN_MAJOR_MARKSWEEP_CONC volatile gboolean sgen_concurrent_collection_in_progress = FALSE; +#endif /* objects that are ready to be finalized */ static SgenPointerQueue fin_ready_queue = SGEN_POINTER_QUEUE_INIT (INTERNAL_MEM_FINALIZE_READY); @@ -1359,6 +1366,7 @@ sgen_set_pinned_from_failed_allocation (mword objsize) bytes_pinned_from_failed_allocation += objsize; } +#ifndef DISABLE_SGEN_MAJOR_MARKSWEEP_CONC gboolean sgen_collection_is_concurrent (void) { @@ -1378,6 +1386,7 @@ sgen_get_concurrent_collection_in_progress (void) { return sgen_concurrent_collection_in_progress; } +#endif typedef struct { SgenThreadPoolJob job; @@ -2176,10 +2185,12 @@ major_start_collection (SgenGrayQueue *gc_thread_gray_queue, const char *reason, { SgenObjectOperations *object_ops_nopar, *object_ops_par = NULL; +#ifndef DISABLE_SGEN_MAJOR_MARKSWEEP_CONC if (concurrent) { g_assert (sgen_major_collector.is_concurrent); sgen_concurrent_collection_in_progress = TRUE; } +#endif sgen_binary_protocol_collection_begin (mono_atomic_load_i32 (&mono_gc_stats.major_gc_count), GENERATION_OLD); @@ -2366,8 +2377,10 @@ major_finish_collection (SgenGrayQueue *gc_thread_gray_queue, const char *reason sgen_binary_protocol_collection_end (mono_atomic_load_i32 (&mono_gc_stats.major_gc_count) - 1, GENERATION_OLD, counts.num_scanned_objects, counts.num_unique_scanned_objects); +#ifndef DISABLE_SGEN_MAJOR_MARKSWEEP_CONC if (sgen_concurrent_collection_in_progress) sgen_concurrent_collection_in_progress = FALSE; +#endif } static gboolean @@ -3729,7 +3742,11 @@ sgen_gc_init (void) sgen_binary_protocol_init (filename, (gint64)limit); } else if (!strcmp (opt, "nursery-canaries")) { do_verify_nursery = TRUE; +#ifndef DISABLE_SGEN_DEBUG_HELPERS enable_nursery_canaries = TRUE; +#else + g_error ("Sgen was built with canaries disabled"); +#endif /* If aot code is used, allocation from there won't expect the layout with canaries enabled */ sgen_set_use_managed_allocator (FALSE); } else if (!sgen_client_handle_gc_debug (opt)) { diff --git a/mono/sgen/sgen-gc.h b/mono/sgen/sgen-gc.h index 2478a0be511b..900ed5b1f809 100644 --- a/mono/sgen/sgen-gc.h +++ b/mono/sgen/sgen-gc.h @@ -476,20 +476,37 @@ void sgen_free_internal (void *addr, int type); void* sgen_alloc_internal_dynamic (size_t size, int type, gboolean assert_on_failure); void sgen_free_internal_dynamic (void *addr, size_t size, int type); +#ifndef DISABLE_SGEN_DEBUG_HELPERS void sgen_pin_stats_enable (void); void sgen_pin_stats_register_object (GCObject *obj, int generation); void sgen_pin_stats_register_global_remset (GCObject *obj); void sgen_pin_stats_report (void); +#else +static inline void sgen_pin_stats_enable (void) { } +static inline void sgen_pin_stats_register_object (GCObject *obj, int generation) { } +static inline void sgen_pin_stats_register_global_remset (GCObject *obj) { } +static inline void sgen_pin_stats_report (void) { } +#endif +#ifndef DISABLE_SGEN_DEBUG_HELPERS void sgen_gchandle_stats_enable (void); void sgen_gchandle_stats_report (void); +#else +static inline void sgen_gchandle_stats_enable (void) { } +static inline void sgen_gchandle_stats_report (void) { } +#endif void sgen_sort_addresses (void **array, size_t size); void sgen_add_to_global_remset (gpointer ptr, GCObject *obj); int sgen_get_current_collection_generation (void); +#ifndef DISABLE_SGEN_MAJOR_MARKSWEEP_CONC gboolean sgen_collection_is_concurrent (void); gboolean sgen_get_concurrent_collection_in_progress (void); +#else +#define sgen_collection_is_concurrent() FALSE +#define sgen_get_concurrent_collection_in_progress() FALSE +#endif void sgen_set_bytes_allocated_attached (guint64 bytes); void sgen_increment_bytes_allocated_detached (guint64 bytes); @@ -837,8 +854,14 @@ void sgen_register_obj_with_weak_fields (GCObject *obj); void sgen_mark_togglerefs (char *start, char *end, ScanCopyContext ctx); void sgen_clear_togglerefs (char *start, char *end, ScanCopyContext ctx); +#ifndef DISABLE_SGEN_TOGGLEREF void sgen_process_togglerefs (void); void sgen_register_test_toggleref_callback (void); +#else +static inline void sgen_process_togglerefs (void) { } +static inline void sgen_register_test_toggleref_callback (void) { } +#endif + void sgen_mark_bridge_object (GCObject *obj) MONO_PERMIT (need (sgen_gc_locked)); @@ -1074,7 +1097,11 @@ extern mword sgen_total_promoted_size; extern mword sgen_total_allocated_major; extern volatile gboolean sgen_suspend_finalizers; extern MonoCoopMutex sgen_gc_mutex; +#ifndef DISABLE_SGEN_MAJOR_MARKSWEEP_CONC extern volatile gboolean sgen_concurrent_collection_in_progress; +#else +static const gboolean sgen_concurrent_collection_in_progress = FALSE; +#endif /* Nursery helpers. */ diff --git a/mono/sgen/sgen-gchandles.c b/mono/sgen/sgen-gchandles.c index 1ca10685a8c1..b802c439db6d 100644 --- a/mono/sgen/sgen-gchandles.c +++ b/mono/sgen/sgen-gchandles.c @@ -523,6 +523,7 @@ sgen_register_obj_with_weak_fields (GCObject *obj) alloc_handle (gc_handles_for_type (HANDLE_WEAK_FIELDS), obj, FALSE); } +#ifndef DISABLE_SGEN_DEBUG_HELPERS void sgen_gchandle_stats_enable (void) { @@ -596,6 +597,7 @@ sgen_gchandle_stats_report (void) mono_gc_printf (sgen_gc_debug_file, "\n"); } SGEN_HASH_TABLE_FOREACH_END; } +#endif void sgen_init_gchandles (void) diff --git a/mono/sgen/sgen-marksweep.c b/mono/sgen/sgen-marksweep.c index 5fbd780144f4..7634caa5e21f 100644 --- a/mono/sgen/sgen-marksweep.c +++ b/mono/sgen/sgen-marksweep.c @@ -197,7 +197,11 @@ typedef enum { static volatile int sweep_state = SWEEP_STATE_SWEPT; static gboolean concurrent_mark; +#ifndef DISABLE_SGEN_MAJOR_MARKSWEEP_CONC static gboolean concurrent_sweep = DEFAULT_SWEEP_MODE; +#else +static const gboolean concurrent_sweep = SGEN_SWEEP_SERIAL; +#endif static int sweep_pool_context = -1; @@ -908,6 +912,9 @@ static SgenThreadPoolJob * volatile sweep_blocks_job; static void major_finish_sweep_checking (void) { + if (!concurrent_sweep) + return; + guint32 block_index; SgenThreadPoolJob *job; @@ -2399,10 +2406,16 @@ major_handle_gc_param (const char *opt) lazy_sweep = FALSE; return TRUE; } else if (!strcmp (opt, "concurrent-sweep")) { +#ifndef DISABLE_SGEN_MAJOR_MARKSWEEP_CONC concurrent_sweep = TRUE; +#else + g_error ("Sgen was built with concurrent collector disabled"); +#endif return TRUE; } else if (!strcmp (opt, "no-concurrent-sweep")) { +#ifndef DISABLE_SGEN_MAJOR_MARKSWEEP_CONC concurrent_sweep = FALSE; +#endif return TRUE; } @@ -2884,7 +2897,9 @@ sgen_marksweep_init_internal (SgenMajorCollector *collector, gboolean is_concurr collector->alloc_degraded = major_alloc_degraded; collector->alloc_object = major_alloc_object; +#ifndef DISABLE_SGEN_MAJOR_MARKSWEEP_CONC collector->alloc_object_par = major_alloc_object_par; +#endif collector->free_pinned_object = free_pinned_object; collector->iterate_objects = major_iterate_objects; collector->free_non_pinned_object = major_free_non_pinned_object; @@ -2921,7 +2936,9 @@ sgen_marksweep_init_internal (SgenMajorCollector *collector, gboolean is_concurr collector->post_param_init = post_param_init; collector->is_valid_object = major_is_valid_object; collector->describe_pointer = major_describe_pointer; +#ifndef DISABLE_SGEN_BINARY_PROTOCOL collector->count_cards = major_count_cards; +#endif collector->init_block_free_lists = sgen_init_block_free_lists; collector->major_ops_serial.copy_or_mark_object = major_copy_or_mark_object_canonical; diff --git a/mono/sgen/sgen-pinning-stats.c b/mono/sgen/sgen-pinning-stats.c index f3e8631e9912..c8f0e0e22c29 100644 --- a/mono/sgen/sgen-pinning-stats.c +++ b/mono/sgen/sgen-pinning-stats.c @@ -10,6 +10,8 @@ #include "config.h" #ifdef HAVE_SGEN_GC +#ifndef DISABLE_SGEN_DEBUG_HELPERS + #include #include "mono/sgen/sgen-gc.h" @@ -247,4 +249,6 @@ sgen_pin_stats_get_object_list (void) return &pinned_objects; } +#endif + #endif /* HAVE_SGEN_GC */ diff --git a/mono/sgen/sgen-pinning.h b/mono/sgen/sgen-pinning.h index 797e12b2614b..d445b2b34860 100644 --- a/mono/sgen/sgen-pinning.h +++ b/mono/sgen/sgen-pinning.h @@ -42,10 +42,17 @@ void sgen_pin_objects_in_section (GCMemSection *section, ScanCopyContext ctx); /* Pinning stats */ +#ifndef DISABLE_SGEN_DEBUG_HELPERS void sgen_pin_stats_register_address (char *addr, int pin_type); size_t sgen_pin_stats_get_pinned_byte_count (int pin_type); SgenPointerQueue *sgen_pin_stats_get_object_list (void); void sgen_pin_stats_reset (void); +#else +static inline void sgen_pin_stats_register_address (char *addr, int pin_type) { } +static inline size_t sgen_pin_stats_get_pinned_byte_count (int pin_type) { return 0; } +static inline SgenPointerQueue *sgen_pin_stats_get_object_list (void) { return NULL; } +static inline void sgen_pin_stats_reset (void) { } +#endif /* Perpetual pinning, aka cementing */ diff --git a/mono/sgen/sgen-protocol.c b/mono/sgen/sgen-protocol.c index 4afaf87e20d6..5fc013d6b57f 100644 --- a/mono/sgen/sgen-protocol.c +++ b/mono/sgen/sgen-protocol.c @@ -30,6 +30,8 @@ #include #endif +#ifndef DISABLE_SGEN_BINARY_PROTOCOL + #if defined(HOST_WIN32) static const HANDLE invalid_file_value = INVALID_HANDLE_VALUE; /* If valid, dump binary protocol to this file */ @@ -488,4 +490,6 @@ protocol_entry (unsigned char type, gpointer data, int size) #undef TYPE_POINTER #undef TYPE_BOOL +#endif + #endif /* HAVE_SGEN_GC */ diff --git a/mono/sgen/sgen-protocol.h b/mono/sgen/sgen-protocol.h index a29eb7d3e3d3..eff42b3206bd 100644 --- a/mono/sgen/sgen-protocol.h +++ b/mono/sgen/sgen-protocol.h @@ -14,6 +14,8 @@ #include "sgen-gc.h" +#ifndef DISABLE_SGEN_BINARY_PROTOCOL + #define PROTOCOL_HEADER_CHECK 0xde7ec7ab1ec0de /* * The version needs to be bumped every time we introduce breaking changes (like @@ -244,4 +246,70 @@ gboolean sgen_binary_protocol_flush_buffers (gboolean force); #undef TYPE_POINTER #undef TYPE_BOOL +#else + +#ifndef TYPE_INT +#define TYPE_INT int +#endif +#ifndef TYPE_LONGLONG +#define TYPE_LONGLONG long long +#endif +#ifndef TYPE_SIZE +#define TYPE_SIZE size_t +#endif +#ifndef TYPE_POINTER +#define TYPE_POINTER gpointer +#endif +#ifndef TYPE_BOOL +#define TYPE_BOOL gboolean +#endif + +#define BEGIN_PROTOCOL_ENTRY0(method) \ + static inline void sgen_ ## method (void) {} +#define BEGIN_PROTOCOL_ENTRY1(method,t1,f1) \ + static inline void sgen_ ## method (t1 f1) {} +#define BEGIN_PROTOCOL_ENTRY2(method,t1,f1,t2,f2) \ + static inline void sgen_ ## method (t1 f1, t2 f2) {} +#define BEGIN_PROTOCOL_ENTRY3(method,t1,f1,t2,f2,t3,f3) \ + static inline void sgen_ ## method (t1 f1, t2 f2, t3 f3) {} +#define BEGIN_PROTOCOL_ENTRY4(method,t1,f1,t2,f2,t3,f3,t4,f4) \ + static inline void sgen_ ## method (t1 f1, t2 f2, t3 f3, t4 f4) {} +#define BEGIN_PROTOCOL_ENTRY5(method,t1,f1,t2,f2,t3,f3,t4,f4,t5,f5) \ + static inline void sgen_ ## method (t1 f1, t2 f2, t3 f3, t4 f4, t5 f5) {} +#define BEGIN_PROTOCOL_ENTRY6(method,t1,f1,t2,f2,t3,f3,t4,f4,t5,f5,t6,f6) \ + static inline void sgen_ ## method (t1 f1, t2 f2, t3 f3, t4 f4, t5 f5, t6 f6) {} +#define BEGIN_PROTOCOL_ENTRY_HEAVY0(method) \ + static inline void sgen_ ## method (void) {} +#define BEGIN_PROTOCOL_ENTRY_HEAVY1(method,t1,f1) \ + static inline void sgen_ ## method (t1 f1) {} +#define BEGIN_PROTOCOL_ENTRY_HEAVY2(method,t1,f1,t2,f2) \ + static inline void sgen_ ## method (t1 f1, t2 f2) {} +#define BEGIN_PROTOCOL_ENTRY_HEAVY3(method,t1,f1,t2,f2,t3,f3) \ + static inline void sgen_ ## method (t1 f1, t2 f2, t3 f3) {} +#define BEGIN_PROTOCOL_ENTRY_HEAVY4(method,t1,f1,t2,f2,t3,f3,t4,f4) \ + static inline void sgen_ ## method (t1 f1, t2 f2, t3 f3, t4 f4) {} +#define BEGIN_PROTOCOL_ENTRY_HEAVY5(method,t1,f1,t2,f2,t3,f3,t4,f4,t5,f5) \ + static inline void sgen_ ## method (t1 f1, t2 f2, t3 f3, t4 f4, t5 f5) {} +#define BEGIN_PROTOCOL_ENTRY_HEAVY6(method,t1,f1,t2,f2,t3,f3,t4,f4,t5,f5,t6,f6) \ + static inline void sgen_ ## method (t1 f1, t2 f2, t3 f3, t4 f4, t5 f5, t6 f6) {} +#define DEFAULT_PRINT() +#define CUSTOM_PRINT(_) + +#define IS_ALWAYS_MATCH(_) +#define MATCH_INDEX(_) +#define IS_VTABLE_MATCH(_) + +#define END_PROTOCOL_ENTRY +#define END_PROTOCOL_ENTRY_FLUSH +#define END_PROTOCOL_ENTRY_HEAVY + +#include "sgen-protocol-def.h" + +static inline void sgen_binary_protocol_init (const char *filename, long long limit) {} +static inline gboolean sgen_binary_protocol_is_enabled (void) { return FALSE; } +static inline gboolean sgen_binary_protocol_flush_buffers (gboolean force) { return FALSE; } +static inline gboolean sgen_binary_protocol_is_heavy_enabled () { return FALSE; } + +#endif + #endif diff --git a/mono/sgen/sgen-thread-pool.c b/mono/sgen/sgen-thread-pool.c index 656e56185679..2cb408f7cbfe 100644 --- a/mono/sgen/sgen-thread-pool.c +++ b/mono/sgen/sgen-thread-pool.c @@ -15,6 +15,8 @@ #include "mono/sgen/sgen-client.h" #include "mono/utils/mono-os-mutex.h" + +#ifndef DISABLE_SGEN_MAJOR_MARKSWEEP_CONC static mono_mutex_t lock; static mono_cond_t work_cond; static mono_cond_t done_cond; @@ -402,5 +404,71 @@ sgen_thread_pool_is_thread_pool_thread (MonoNativeThreadId some_thread) return 0; } +#else + +int +sgen_thread_pool_create_context (int num_threads, SgenThreadPoolThreadInitFunc init_func, SgenThreadPoolIdleJobFunc idle_func, SgenThreadPoolContinueIdleJobFunc continue_idle_func, SgenThreadPoolShouldWorkFunc should_work_func, void **thread_datas) +{ + return 0; +} + +void +sgen_thread_pool_start (void) +{ +} + +void +sgen_thread_pool_shutdown (void) +{ +} + +SgenThreadPoolJob* +sgen_thread_pool_job_alloc (const char *name, SgenThreadPoolJobFunc func, size_t size) +{ + SgenThreadPoolJob *job = (SgenThreadPoolJob *)sgen_alloc_internal_dynamic (size, INTERNAL_MEM_THREAD_POOL_JOB, TRUE); + job->name = name; + job->size = size; + job->func = func; + return job; +} + +void +sgen_thread_pool_job_free (SgenThreadPoolJob *job) +{ + sgen_free_internal_dynamic (job, job->size, INTERNAL_MEM_THREAD_POOL_JOB); +} + +void +sgen_thread_pool_job_enqueue (int context_id, SgenThreadPoolJob *job) +{ +} + +void +sgen_thread_pool_job_wait (int context_id, SgenThreadPoolJob *job) +{ +} + +void +sgen_thread_pool_idle_signal (int context_id) +{ +} + +void +sgen_thread_pool_idle_wait (int context_id, SgenThreadPoolContinueIdleWaitFunc continue_wait) +{ +} + +void +sgen_thread_pool_wait_for_all_jobs (int context_id) +{ +} + +int +sgen_thread_pool_is_thread_pool_thread (MonoNativeThreadId some_thread) +{ + return 0; +} + +#endif #endif diff --git a/mono/sgen/sgen-workers.c b/mono/sgen/sgen-workers.c index a8897d93dbb5..16e93d69a0f0 100644 --- a/mono/sgen/sgen-workers.c +++ b/mono/sgen/sgen-workers.c @@ -639,11 +639,6 @@ sgen_workers_assert_gray_queue_is_empty (int generation) { } -void -sgen_workers_foreach (int generation, SgenWorkerCallback callback) -{ -} - SgenObjectOperations* sgen_workers_get_idle_func_object_ops (WorkerData *worker) { @@ -685,11 +680,6 @@ sgen_workers_set_num_active_workers (int generation, int num_workers) { } -void -sgen_workers_start_all_workers (int generation, SgenObjectOperations *object_ops_nopar, SgenObjectOperations *object_ops_par, SgenWorkersFinishCallback callback) -{ -} - void sgen_workers_stop_all_workers (int generation) { diff --git a/mono/sgen/sgen-workers.h b/mono/sgen/sgen-workers.h index 14e68c93e2ae..dce2364857be 100644 --- a/mono/sgen/sgen-workers.h +++ b/mono/sgen/sgen-workers.h @@ -78,7 +78,11 @@ struct _WorkerContext { void sgen_workers_create_context (int generation, int num_workers); void sgen_workers_stop_all_workers (int generation); void sgen_workers_set_num_active_workers (int generation, int num_workers); +#ifndef DISABLE_SGEN_MAJOR_MARKSWEEP_CONC void sgen_workers_start_all_workers (int generation, SgenObjectOperations *object_ops_nopar, SgenObjectOperations *object_ops_par, SgenWorkersFinishCallback finish_job); +#else +#define sgen_workers_start_all_workers(...) +#endif void sgen_workers_enqueue_job (int generation, SgenThreadPoolJob *job, gboolean enqueue); void sgen_workers_join (int generation); gboolean sgen_workers_have_idle_work (int generation); @@ -88,7 +92,11 @@ void sgen_workers_take_from_queue (int generation, SgenGrayQueue *queue); SgenObjectOperations* sgen_workers_get_idle_func_object_ops (WorkerData *worker); int sgen_workers_get_job_split_count (int generation); int sgen_workers_get_active_worker_count (int generation); +#ifndef DISABLE_SGEN_MAJOR_MARKSWEEP_CONC void sgen_workers_foreach (int generation, SgenWorkerCallback callback); +#else +#define sgen_workers_foreach(...) +#endif gboolean sgen_workers_is_worker_thread (MonoNativeThreadId id); #endif diff --git a/mono/tests/Makefile.am b/mono/tests/Makefile.am index fc2a7661882d..6a3af788dfe4 100755 --- a/mono/tests/Makefile.am +++ b/mono/tests/Makefile.am @@ -1121,7 +1121,9 @@ endif endif - +if DISABLE_CRASH_REPORTING +PLATFORM_DISABLED_TESTS += merp-json-valid.exe merp-crash-test.exe +endif if HOST_DARWIN diff --git a/mono/tests/dim-constrained3.il b/mono/tests/dim-constrained3.il index a3f653af2fc7..f570952e91fd 100644 --- a/mono/tests/dim-constrained3.il +++ b/mono/tests/dim-constrained3.il @@ -1,6 +1,5 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. .assembly extern mscorlib { } .assembly constrained3 { } diff --git a/mono/tests/dim-constrained3_gm.il b/mono/tests/dim-constrained3_gm.il index 9245f4872425..1ac69236039d 100644 --- a/mono/tests/dim-constrained3_gm.il +++ b/mono/tests/dim-constrained3_gm.il @@ -1,6 +1,5 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. .assembly extern mscorlib { } .assembly constrained3_gm { } diff --git a/mono/tests/dim-constrainedcall.il b/mono/tests/dim-constrainedcall.il index 6db938f806c2..5708c9cadde4 100644 --- a/mono/tests/dim-constrainedcall.il +++ b/mono/tests/dim-constrainedcall.il @@ -1,6 +1,5 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. .assembly extern mscorlib { } .assembly constrainedcall { } diff --git a/mono/tests/pinvoke-utf8.cs b/mono/tests/pinvoke-utf8.cs index fd58ad42a1ba..d9162d6711c5 100644 --- a/mono/tests/pinvoke-utf8.cs +++ b/mono/tests/pinvoke-utf8.cs @@ -1,6 +1,5 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. using System; using System.Runtime.InteropServices; diff --git a/mono/tests/twopassvariance.il b/mono/tests/twopassvariance.il index 1bc29f421b05..d4267bef4af9 100644 --- a/mono/tests/twopassvariance.il +++ b/mono/tests/twopassvariance.il @@ -1,6 +1,5 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. .assembly extern mscorlib { } diff --git a/mono/utils/freebsd-elf_common.h b/mono/utils/freebsd-elf_common.h index 7aef2d49667e..658119fdbc51 100644 --- a/mono/utils/freebsd-elf_common.h +++ b/mono/utils/freebsd-elf_common.h @@ -169,6 +169,7 @@ typedef struct { #define EM_TINYJ 61 /* Advanced Logic Corp. TinyJ processor. */ #define EM_X86_64 62 /* Advanced Micro Devices x86-64 */ #define EM_AMD64 EM_X86_64 /* Advanced Micro Devices x86-64 (compat) */ +#define EM_RISCV 243 /* RISC-V. */ /* Non-standard or deprecated. */ #define EM_486 6 /* Intel i486. */ diff --git a/mono/utils/mono-codeman.c b/mono/utils/mono-codeman.c index a69f25bb43ec..24c90a3e6dd4 100644 --- a/mono/utils/mono-codeman.c +++ b/mono/utils/mono-codeman.c @@ -27,7 +27,7 @@ static void* mono_code_manager_heap; #endif #include - +#include static uintptr_t code_memory_used = 0; static size_t dynamic_code_alloc_count; @@ -102,6 +102,7 @@ struct _MonoCodeManager { static mono_mutex_t valloc_mutex; static GHashTable *valloc_freelists; +static MonoNativeTlsKey write_level_tls_id; static void* codechunk_valloc (void *preferred, guint32 size) @@ -121,7 +122,9 @@ codechunk_valloc (void *preferred, guint32 size) freelist = (GSList *) g_hash_table_lookup (valloc_freelists, GUINT_TO_POINTER (size)); if (freelist) { ptr = freelist->data; + mono_codeman_enable_write (); memset (ptr, 0, size); + mono_codeman_disable_write (); freelist = g_slist_delete_link (freelist, freelist); g_hash_table_insert (valloc_freelists, GUINT_TO_POINTER (size), freelist); } else { @@ -176,6 +179,8 @@ mono_code_manager_init (void) mono_counters_register ("Dynamic code allocs", MONO_COUNTER_JIT | MONO_COUNTER_ULONG, &dynamic_code_alloc_count); mono_counters_register ("Dynamic code bytes", MONO_COUNTER_JIT | MONO_COUNTER_ULONG, &dynamic_code_bytes_count); mono_counters_register ("Dynamic code frees", MONO_COUNTER_JIT | MONO_COUNTER_ULONG, &dynamic_code_frees_count); + + mono_native_tls_alloc (&write_level_tls_id, NULL); } void @@ -271,7 +276,10 @@ mono_codeman_malloc (gsize n) g_assert (heap); return HeapAlloc (heap, 0, n); #else - return dlmemalign (MIN_ALIGN, n); + mono_codeman_enable_write (); + gpointer res = dlmemalign (MIN_ALIGN, n); + mono_codeman_disable_write (); + return res; #endif } @@ -285,7 +293,9 @@ mono_codeman_free (gpointer p) g_assert (heap); HeapFree (heap, 0, p); #else + mono_codeman_enable_write (); dlfree (p); + mono_codeman_disable_write (); #endif } @@ -476,7 +486,9 @@ new_codechunk (MonoCodeManager *cman, int size) #ifdef BIND_ROOM if (flags == CODE_FLAG_MALLOC) { /* Make sure the thunks area is zeroed */ + mono_codeman_enable_write (); memset (ptr, 0, bsize); + mono_codeman_disable_write (); } #endif @@ -639,3 +651,43 @@ mono_code_manager_size (MonoCodeManager *cman, int *used_size) *used_size = used; return size; } + +/* + * mono_codeman_enable_write (): + * + * Enable writing to code memory on the current thread on platforms that need it. + * Calls can be nested. + */ +void +mono_codeman_enable_write (void) +{ +#ifdef HAVE_PTHREAD_JIT_WRITE_PROTECT_NP + if (__builtin_available (macOS 11, *)) { + int level = GPOINTER_TO_INT (mono_native_tls_get_value (write_level_tls_id)); + level ++; + mono_native_tls_set_value (write_level_tls_id, GINT_TO_POINTER (level)); + pthread_jit_write_protect_np (0); + } +#endif +} + +/* + * mono_codeman_disable_write (): + * + * Disable writing to code memory on the current thread on platforms that need it. + * Calls can be nested. + */ +void +mono_codeman_disable_write (void) +{ +#ifdef HAVE_PTHREAD_JIT_WRITE_PROTECT_NP + if (__builtin_available (macOS 11, *)) { + int level = GPOINTER_TO_INT (mono_native_tls_get_value (write_level_tls_id)); + g_assert (level); + level --; + mono_native_tls_set_value (write_level_tls_id, GINT_TO_POINTER (level)); + if (level == 0) + pthread_jit_write_protect_np (1); + } +#endif +} diff --git a/mono/utils/mono-codeman.h b/mono/utils/mono-codeman.h index 4cf447f6e086..fbe2a2f2d4f4 100644 --- a/mono/utils/mono-codeman.h +++ b/mono/utils/mono-codeman.h @@ -41,5 +41,8 @@ void mono_code_manager_install_callbacks (const MonoCodeManagerCallb typedef int (*MonoCodeManagerFunc) (void *data, int csize, int size, void *user_data); void mono_code_manager_foreach (MonoCodeManager *cman, MonoCodeManagerFunc func, void *user_data); +void mono_codeman_enable_write (void); +void mono_codeman_disable_write (void); + #endif /* __MONO_CODEMAN_H__ */ diff --git a/mono/utils/mono-context.h b/mono/utils/mono-context.h index 7647d4eadb7a..2dbf043ba13f 100644 --- a/mono/utils/mono-context.h +++ b/mono/utils/mono-context.h @@ -918,8 +918,8 @@ typedef struct ucontext MonoContext; "std %%f13,104(%1)\n" \ "std %%f14,112(%1)\n" \ "std %%f15,120(%1)\n" \ - : : "r" (&(ctx).uc_mcontext.gregs[0]), \ - "r" (&(ctx).uc_mcontext.fpregs.fprs[0]) \ + : : "a" (&(ctx).uc_mcontext.gregs[0]), \ + "a" (&(ctx).uc_mcontext.fpregs.fprs[0]) \ : "memory" \ ) diff --git a/mono/utils/mono-hwcap-riscv.c b/mono/utils/mono-hwcap-riscv.c index b2f5dbcfe401..26561e0545d4 100644 --- a/mono/utils/mono-hwcap-riscv.c +++ b/mono/utils/mono-hwcap-riscv.c @@ -1,7 +1,6 @@ /* * Licensed to the .NET Foundation under one or more agreements. * The .NET Foundation licenses this file to you under the MIT license. - * See the LICENSE file in the project root for more information. */ #include diff --git a/mono/utils/mono-hwcap-s390x.c b/mono/utils/mono-hwcap-s390x.c index 5c24a15e5e1b..fcfaf9cae7a2 100644 --- a/mono/utils/mono-hwcap-s390x.c +++ b/mono/utils/mono-hwcap-s390x.c @@ -148,7 +148,7 @@ mono_hwcap_arch_init (void) int lFacs = sizeof (facs) / 8; __asm__ __volatile__ ( - "lgfr\t0,%1\n\t" + "lgfr\t%%r0,%1\n\t" ".insn\ts,0xb2b00000,%0\n\t" : "=m" (facs) : "r" (lFacs) diff --git a/mono/utils/mono-tls.c b/mono/utils/mono-tls.c index 00be95ee3e84..f2b11c852044 100644 --- a/mono/utils/mono-tls.c +++ b/mono/utils/mono-tls.c @@ -70,11 +70,11 @@ # endif # else # define MONO_THREAD_VAR_OFFSET(var,offset) do { guint64 foo; \ - __asm__ ("basr %%r1,0\n\t" \ + __asm__ ("larl %%r1,0f\n\t" \ "j 0f\n\t" \ - ".quad " #var "@NTPOFF\n" \ - "0:\n\t" \ - "lg %0,4(%%r1)\n\t" \ + "0:.quad " #var "@NTPOFF\n" \ + "1:\n\t" \ + "lg %0,0(%%r1)\n\t" \ : "=r" (foo) : : "1"); \ offset = foo; } while (0) # endif diff --git a/mono/utils/valgrind.h b/mono/utils/valgrind.h index 343d301821e6..0829ac748b7c 100644 --- a/mono/utils/valgrind.h +++ b/mono/utils/valgrind.h @@ -831,15 +831,15 @@ typedef * (e.g. VEX/priv/guest_s390_decoder.c). */ #define __SPECIAL_INSTRUCTION_PREAMBLE \ - "lr 15,15\n\t" \ - "lr 1,1\n\t" \ - "lr 2,2\n\t" \ - "lr 3,3\n\t" + "lr %%r15,%%r15\n\t" \ + "lr %%r1,%%r1\n\t" \ + "lr %%r2,%%r2\n\t" \ + "lr %%r3,%%r3\n\t" -#define __CLIENT_REQUEST_CODE "lr 2,2\n\t" -#define __GET_NR_CONTEXT_CODE "lr 3,3\n\t" -#define __CALL_NO_REDIR_CODE "lr 4,4\n\t" -#define __VEX_INJECT_IR_CODE "lr 5,5\n\t" +#define __CLIENT_REQUEST_CODE "lr %%r2,%%r2\n\t" +#define __GET_NR_CONTEXT_CODE "lr %%r3,%%r3\n\t" +#define __CALL_NO_REDIR_CODE "lr %%r4,%%r4\n\t" +#define __VEX_INJECT_IR_CODE "lr %%r5,%%r5\n\t" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ @@ -854,15 +854,15 @@ typedef _zzq_args[4] = (unsigned long long int)(_zzq_arg4); \ _zzq_args[5] = (unsigned long long int)(_zzq_arg5); \ __asm__ volatile(/* r2 = args */ \ - "lgr 2,%1\n\t" \ + "lgr %%r2,%1\n\t" \ /* r3 = default */ \ - "lgr 3,%2\n\t" \ + "lgr %%r3,%2\n\t" \ __SPECIAL_INSTRUCTION_PREAMBLE \ __CLIENT_REQUEST_CODE \ /* results = r3 */ \ - "lgr %0, 3\n\t" \ + "lgr %0,%%r3\n\t" \ : "=d" (_zzq_result) \ - : "a" (&_zzq_args[0]), "0" (_zzq_default) \ + : "a" (&_zzq_args[0]), "r" (_zzq_default) \ : "cc", "2", "3", "memory" \ ); \ _zzq_result; \ @@ -873,7 +873,7 @@ typedef volatile unsigned long long int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ __GET_NR_CONTEXT_CODE \ - "lgr %0, 3\n\t" \ + "lgr %0,%%r3\n\t" \ : "=a" (__addr) \ : \ : "cc", "3", "memory" \ @@ -4652,17 +4652,17 @@ typedef ,"d"(__builtin_dwarf_cfa()) # define VALGRIND_CFI_PROLOGUE \ ".cfi_remember_state\n\t" \ - "lgr 1,%1\n\t" /* copy the argvec pointer in r1 */ \ - "lgr 7,11\n\t" \ - "lgr 11,%2\n\t" \ + "lgr %%r1,%1\n\t" /* copy the argvec pointer in r1 */ \ + "lgr %%r7,%%r11\n\t" \ + "lgr %%r11,%2\n\t" \ ".cfi_def_cfa r11, 0\n\t" # define VALGRIND_CFI_EPILOGUE \ - "lgr 11, 7\n\t" \ + "lgr %%r11,%%r7\n\t" \ ".cfi_restore_state\n\t" #else # define __FRAME_POINTER # define VALGRIND_CFI_PROLOGUE \ - "lgr 1,%1\n\t" + "lgr %%r1,%1\n\t" # define VALGRIND_CFI_EPILOGUE #endif @@ -4695,11 +4695,11 @@ typedef _argvec[0] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ - "aghi 15,-160\n\t" \ - "lg 1, 0(1)\n\t" /* target->r1 */ \ + "aghi %%r15,-160\n\t" \ + "lg %%r1,0(%%r1)\n\t" /* target->r1 */ \ VALGRIND_CALL_NOREDIR_R1 \ - "lgr %0, 2\n\t" \ - "aghi 15,160\n\t" \ + "lgr %0,%%r2\n\t" \ + "aghi %%r15,160\n\t" \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=d" (_res) \ : /*in*/ "d" (&_argvec[0]) __FRAME_POINTER \ @@ -4718,12 +4718,12 @@ typedef _argvec[1] = (unsigned long)arg1; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ - "aghi 15,-160\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 1, 0(1)\n\t" \ + "aghi %%r15,-160\n\t" \ + "lg %%r2,8(%%r1)\n\t" \ + "lg %%r1,0(%%r1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ - "lgr %0, 2\n\t" \ - "aghi 15,160\n\t" \ + "lgr %0,%%r2\n\t" \ + "aghi %%r15,160\n\t" \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ @@ -4742,13 +4742,13 @@ typedef _argvec[2] = (unsigned long)arg2; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ - "aghi 15,-160\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 3,16(1)\n\t" \ - "lg 1, 0(1)\n\t" \ + "aghi %%r15,-160\n\t" \ + "lg %%r2,8(%%r1)\n\t" \ + "lg %%r3,16(%%r1)\n\t" \ + "lg %%r1,0(%%r1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ - "lgr %0, 2\n\t" \ - "aghi 15,160\n\t" \ + "lgr %0,%%r2\n\t" \ + "aghi %%r15,160\n\t" \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ @@ -4768,14 +4768,14 @@ typedef _argvec[3] = (unsigned long)arg3; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ - "aghi 15,-160\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 3,16(1)\n\t" \ - "lg 4,24(1)\n\t" \ - "lg 1, 0(1)\n\t" \ + "aghi %%r15,-160\n\t" \ + "lg %%r2,8(%%r1)\n\t" \ + "lg %%r3,16(%%r1)\n\t" \ + "lg %%r4,24(%%r1)\n\t" \ + "lg %%r1,0(%%r1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ - "lgr %0, 2\n\t" \ - "aghi 15,160\n\t" \ + "lgr %0,%%r2\n\t" \ + "aghi %%r15,160\n\t" \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ @@ -4796,15 +4796,15 @@ typedef _argvec[4] = (unsigned long)arg4; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ - "aghi 15,-160\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 3,16(1)\n\t" \ - "lg 4,24(1)\n\t" \ - "lg 5,32(1)\n\t" \ - "lg 1, 0(1)\n\t" \ + "aghi %%r15,-160\n\t" \ + "lg %%r2,8(%%r1)\n\t" \ + "lg %%r3,16(%%r1)\n\t" \ + "lg %%r4,24(%%r1)\n\t" \ + "lg %%r5,32(%%r1)\n\t" \ + "lg %%r1,0(%%r1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ - "lgr %0, 2\n\t" \ - "aghi 15,160\n\t" \ + "lgr %0,%%r2\n\t" \ + "aghi %%r15,160\n\t" \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ @@ -4826,16 +4826,16 @@ typedef _argvec[5] = (unsigned long)arg5; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ - "aghi 15,-160\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 3,16(1)\n\t" \ - "lg 4,24(1)\n\t" \ - "lg 5,32(1)\n\t" \ - "lg 6,40(1)\n\t" \ - "lg 1, 0(1)\n\t" \ + "aghi %%r15,-160\n\t" \ + "lg %%r2,8(%%r1)\n\t" \ + "lg %%r3,16(%%r1)\n\t" \ + "lg %%r4,24(%%r1)\n\t" \ + "lg %%r5,32(%%r1)\n\t" \ + "lg %%r6,40(%%r1)\n\t" \ + "lg %%r1,0(%%r1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ - "lgr %0, 2\n\t" \ - "aghi 15,160\n\t" \ + "lgr %0,%%r2\n\t" \ + "aghi %%r15,160\n\t" \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ @@ -4859,17 +4859,17 @@ typedef _argvec[6] = (unsigned long)arg6; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ - "aghi 15,-168\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 3,16(1)\n\t" \ - "lg 4,24(1)\n\t" \ - "lg 5,32(1)\n\t" \ - "lg 6,40(1)\n\t" \ - "mvc 160(8,15), 48(1)\n\t" \ - "lg 1, 0(1)\n\t" \ + "aghi %%r15,-168\n\t" \ + "lg %%r2,8(%%r1)\n\t" \ + "lg %%r3,16(%%r1)\n\t" \ + "lg %%r4,24(%%r1)\n\t" \ + "lg %%r5,32(%%r1)\n\t" \ + "lg %%r6,40(%%r1)\n\t" \ + "mvc 160(8,%%r15),48(%%r1)\n\t" \ + "lg %%r1,0(%%r1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ - "lgr %0, 2\n\t" \ - "aghi 15,168\n\t" \ + "lgr %0,%%r2\n\t" \ + "aghi %%r15,168\n\t" \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ @@ -4894,18 +4894,18 @@ typedef _argvec[7] = (unsigned long)arg7; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ - "aghi 15,-176\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 3,16(1)\n\t" \ - "lg 4,24(1)\n\t" \ - "lg 5,32(1)\n\t" \ - "lg 6,40(1)\n\t" \ - "mvc 160(8,15), 48(1)\n\t" \ - "mvc 168(8,15), 56(1)\n\t" \ - "lg 1, 0(1)\n\t" \ + "aghi %%r15,-176\n\t" \ + "lg %%r2,8(%%r1)\n\t" \ + "lg %%r3,16(%%r1)\n\t" \ + "lg %%r4,24(%%r1)\n\t" \ + "lg %%r5,32(%%r1)\n\t" \ + "lg %%r6,40(%%r1)\n\t" \ + "mvc 160(8,%%r15),48(%%r1)\n\t" \ + "mvc 168(8,%%r15),56(%%r1)\n\t" \ + "lg %%r1,0(%%r1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ - "lgr %0, 2\n\t" \ - "aghi 15,176\n\t" \ + "lgr %0,%%r2\n\t" \ + "aghi %%r15,176\n\t" \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ @@ -4931,19 +4931,19 @@ typedef _argvec[8] = (unsigned long)arg8; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ - "aghi 15,-184\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 3,16(1)\n\t" \ - "lg 4,24(1)\n\t" \ - "lg 5,32(1)\n\t" \ - "lg 6,40(1)\n\t" \ - "mvc 160(8,15), 48(1)\n\t" \ - "mvc 168(8,15), 56(1)\n\t" \ - "mvc 176(8,15), 64(1)\n\t" \ - "lg 1, 0(1)\n\t" \ + "aghi %%r15,-184\n\t" \ + "lg %%r2,8(%%r1)\n\t" \ + "lg %%r3,16(%%r1)\n\t" \ + "lg %%r4,24(%%r1)\n\t" \ + "lg %%r5,32(%%r1)\n\t" \ + "lg %%r6,40(%%r1)\n\t" \ + "mvc 160(8,%%r15),48(%%r1)\n\t" \ + "mvc 168(8,%%r15),56(%%r1)\n\t" \ + "mvc 176(8,%%r15),64(%%r1)\n\t" \ + "lg %%r1,0(%%r1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ - "lgr %0, 2\n\t" \ - "aghi 15,184\n\t" \ + "lgr %0,%%r2\n\t" \ + "aghi %%r15,184\n\t" \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ @@ -4970,20 +4970,20 @@ typedef _argvec[9] = (unsigned long)arg9; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ - "aghi 15,-192\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 3,16(1)\n\t" \ - "lg 4,24(1)\n\t" \ - "lg 5,32(1)\n\t" \ - "lg 6,40(1)\n\t" \ - "mvc 160(8,15), 48(1)\n\t" \ - "mvc 168(8,15), 56(1)\n\t" \ - "mvc 176(8,15), 64(1)\n\t" \ - "mvc 184(8,15), 72(1)\n\t" \ - "lg 1, 0(1)\n\t" \ + "aghi %%r15,-192\n\t" \ + "lg %%r2,8(%%r1)\n\t" \ + "lg %%r3,16(%%r1)\n\t" \ + "lg %%r4,24(%%r1)\n\t" \ + "lg %%r5,32(%%r1)\n\t" \ + "lg %%r6,40(%%r1)\n\t" \ + "mvc 160(8,%%r15),48(%%r1)\n\t" \ + "mvc 168(8,%%r15),56(%%r1)\n\t" \ + "mvc 176(8,%%r15),64(%%r1)\n\t" \ + "mvc 184(8,%%r15),72(%%r1)\n\t" \ + "lg %%r1,0(%%r1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ - "lgr %0, 2\n\t" \ - "aghi 15,192\n\t" \ + "lgr %0,%%r2\n\t" \ + "aghi %%r15,192\n\t" \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ @@ -5011,21 +5011,21 @@ typedef _argvec[10] = (unsigned long)arg10; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ - "aghi 15,-200\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 3,16(1)\n\t" \ - "lg 4,24(1)\n\t" \ - "lg 5,32(1)\n\t" \ - "lg 6,40(1)\n\t" \ - "mvc 160(8,15), 48(1)\n\t" \ - "mvc 168(8,15), 56(1)\n\t" \ - "mvc 176(8,15), 64(1)\n\t" \ - "mvc 184(8,15), 72(1)\n\t" \ - "mvc 192(8,15), 80(1)\n\t" \ - "lg 1, 0(1)\n\t" \ + "aghi %%r15,-200\n\t" \ + "lg %%r2,8(%%r1)\n\t" \ + "lg %%r3,16(%%r1)\n\t" \ + "lg %%r4,24(%%r1)\n\t" \ + "lg %%r5,32(%%r1)\n\t" \ + "lg %%r6,40(%%r1)\n\t" \ + "mvc 160(8,%%r15),48(%%r1)\n\t" \ + "mvc 168(8,%%r15),56(%%r1)\n\t" \ + "mvc 176(8,%%r15),64(%%r1)\n\t" \ + "mvc 184(8,%%r15),72(%%r1)\n\t" \ + "mvc 192(8,%%r15),80(%%r1)\n\t" \ + "lg %%r1,0(%%r1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ - "lgr %0, 2\n\t" \ - "aghi 15,200\n\t" \ + "lgr %0,%%r2\n\t" \ + "aghi %%r15,200\n\t" \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ @@ -5054,22 +5054,22 @@ typedef _argvec[11] = (unsigned long)arg11; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ - "aghi 15,-208\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 3,16(1)\n\t" \ - "lg 4,24(1)\n\t" \ - "lg 5,32(1)\n\t" \ - "lg 6,40(1)\n\t" \ - "mvc 160(8,15), 48(1)\n\t" \ - "mvc 168(8,15), 56(1)\n\t" \ - "mvc 176(8,15), 64(1)\n\t" \ - "mvc 184(8,15), 72(1)\n\t" \ - "mvc 192(8,15), 80(1)\n\t" \ - "mvc 200(8,15), 88(1)\n\t" \ - "lg 1, 0(1)\n\t" \ + "aghi %%r15,-208\n\t" \ + "lg %%r2,8(%%r1)\n\t" \ + "lg %%r3,16(%%r1)\n\t" \ + "lg %%r4,24(%%r1)\n\t" \ + "lg %%r5,32(%%r1)\n\t" \ + "lg %%r6,40(%%r1)\n\t" \ + "mvc 160(8,%%r15),48(%%r1)\n\t" \ + "mvc 168(8,%%r15),56(%%r1)\n\t" \ + "mvc 176(8,%%r15),64(%%r1)\n\t" \ + "mvc 184(8,%%r15),72(%%r1)\n\t" \ + "mvc 192(8,%%r15),80(%%r1)\n\t" \ + "mvc 200(8,%%r15),88(%%r1)\n\t" \ + "lg %%r1,0(%%r1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ - "lgr %0, 2\n\t" \ - "aghi 15,208\n\t" \ + "lgr %0,%%r2\n\t" \ + "aghi %%r15,208\n\t" \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ @@ -5099,23 +5099,23 @@ typedef _argvec[12] = (unsigned long)arg12; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ - "aghi 15,-216\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 3,16(1)\n\t" \ - "lg 4,24(1)\n\t" \ - "lg 5,32(1)\n\t" \ - "lg 6,40(1)\n\t" \ - "mvc 160(8,15), 48(1)\n\t" \ - "mvc 168(8,15), 56(1)\n\t" \ - "mvc 176(8,15), 64(1)\n\t" \ - "mvc 184(8,15), 72(1)\n\t" \ - "mvc 192(8,15), 80(1)\n\t" \ - "mvc 200(8,15), 88(1)\n\t" \ - "mvc 208(8,15), 96(1)\n\t" \ - "lg 1, 0(1)\n\t" \ + "aghi %%r15,-216\n\t" \ + "lg %%r2,8(%%r1)\n\t" \ + "lg %%r3,16(%%r1)\n\t" \ + "lg %%r4,24(%%r1)\n\t" \ + "lg %%r5,32(%%r1)\n\t" \ + "lg %%r6,40(%%r1)\n\t" \ + "mvc 160(8,%%r15),48(%%r1)\n\t" \ + "mvc 168(8,%%r15),56(%%r1)\n\t" \ + "mvc 176(8,%%r15),64(%%r1)\n\t" \ + "mvc 184(8,%%r15),72(%%r1)\n\t" \ + "mvc 192(8,%%r15),80(%%r1)\n\t" \ + "mvc 200(8,%%r15),88(%%r1)\n\t" \ + "mvc 208(8,%%r15),96(%%r1)\n\t" \ + "lg %%r1,0(%%r1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ - "lgr %0, 2\n\t" \ - "aghi 15,216\n\t" \ + "lgr %0,%%r2\n\t" \ + "aghi %%r15,216\n\t" \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ diff --git a/msvc/libmini-interp.targets b/msvc/libmini-interp.targets index 31ef8c03a231..0bfddcb1809b 100644 --- a/msvc/libmini-interp.targets +++ b/msvc/libmini-interp.targets @@ -8,6 +8,8 @@ + + diff --git a/msvc/libmini-interp.targets.filters b/msvc/libmini-interp.targets.filters index 267a6baaaf91..09114683ecea 100644 --- a/msvc/libmini-interp.targets.filters +++ b/msvc/libmini-interp.targets.filters @@ -13,6 +13,12 @@ Source Files$(MonoMiniFilterSubFolder)\interp + + Header Files$(MonoMiniFilterSubFolder)\interp + + + Source Files$(MonoMiniFilterSubFolder)\interp + Header Files$(MonoMiniFilterSubFolder)\interp diff --git a/packaging/MacSDK/msbuild.py b/packaging/MacSDK/msbuild.py index 0d3a3a0bcaea..81f25dbe627b 100644 --- a/packaging/MacSDK/msbuild.py +++ b/packaging/MacSDK/msbuild.py @@ -3,7 +3,7 @@ class MSBuild (GitHubPackage): def __init__ (self): GitHubPackage.__init__ (self, 'mono', 'msbuild', '15', # note: fix scripts/ci/run-test-mac-sdk.sh when bumping the version number - revision = '6efa434765e1c0a6982db1ac60e06f013b77c276') + revision = 'f048f95f8c67b4316d72f362ff2fa3dac67f58d4') def build (self): try: diff --git a/sdks/builds/wasm.mk b/sdks/builds/wasm.mk index 5a4b168a6ec3..5aaf58041890 100644 --- a/sdks/builds/wasm.mk +++ b/sdks/builds/wasm.mk @@ -1,7 +1,7 @@ #emcc has lots of bash'isms SHELL:=/bin/bash -EMSCRIPTEN_VERSION=1.39.18 +EMSCRIPTEN_VERSION=1.40.0 EMSCRIPTEN_LOCAL_SDK_DIR=$(TOP)/sdks/builds/toolchains/emsdk EMSCRIPTEN_SDK_DIR ?= $(EMSCRIPTEN_LOCAL_SDK_DIR) diff --git a/sdks/wasm/DebuggerTestSuite/CallFunctionOnTests.cs b/sdks/wasm/DebuggerTestSuite/CallFunctionOnTests.cs index 7a7ca7b4e663..f51be601225e 100644 --- a/sdks/wasm/DebuggerTestSuite/CallFunctionOnTests.cs +++ b/sdks/wasm/DebuggerTestSuite/CallFunctionOnTests.cs @@ -445,11 +445,17 @@ await insp.Ready (async (cli, token) => { }); } + public static TheoryData SilentErrorsTestData (bool? silent) + => new TheoryData { + { "invoke_static_method ('[debugger-test] DebuggerTests.CallFunctionOnTest:LocalsTest', 10);", "dotnet://debugger-test.dll/debugger-cfo-test.cs", 19, 3, silent }, + { "big_array_js_test (10);", "/other.js", 5, 1, silent } + }; + [Theory] - [InlineData (null)] - [InlineData (false)] - [InlineData (true)] - public async Task CheckErrorsWithSilent (bool? silent) + [MemberData (nameof (SilentErrorsTestData), null)] + [MemberData (nameof (SilentErrorsTestData), false)] + [MemberData (nameof (SilentErrorsTestData), true)] + public async Task CFOWithSilentReturnsErrors (string eval_fn, string bp_loc, int line, int col, bool? silent) { var insp = new Inspector (); //Collect events @@ -458,25 +464,35 @@ public async Task CheckErrorsWithSilent (bool? silent) await Ready(); await insp.Ready (async (cli, token) => { ctx = new DebugTestContext (cli, insp, token, scripts); - await SetBreakpoint ("dotnet://debugger-test.dll/debugger-cfo-test.cs", 19, 3); + await SetBreakpoint (bp_loc, line, col); // callFunctionOn - var eval_expr = "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.CallFunctionOnTest:LocalsTest', 10); }, 1);"; + var eval_expr = "window.setTimeout(function() { " + eval_fn + " }, 1);"; var result = await ctx.cli.SendCommand ("Runtime.evaluate", JObject.FromObject (new { expression = eval_expr }), ctx.token); var pause_location = await ctx.insp.WaitFor (Inspector.PAUSE); + var frame_locals = await GetProperties (pause_location ["callFrames"][0]["scopeChain"][0]["object"]["objectId"].Value ()); + var obj = GetAndAssertObjectWithName (frame_locals, "big"); + var big_obj_id = obj ["value"]["objectId"].Value (); + var error_msg = "#This is an error message#"; + // Check the object at the bp var cfo_args = JObject.FromObject (new { - functionDeclaration = "function () { throw Error ('test error'); }", - objectId = "dotnet:object:xyasd", + functionDeclaration = $"function () {{ throw Error ('{error_msg}'); }}", + objectId = big_obj_id }); if (silent.HasValue) cfo_args ["silent"] = silent; - // callFunctionOn + // callFunctionOn, Silent does not change the result, except that the error + // doesn't get reported, and the execution is NOT paused even with setPauseOnException=true result = await ctx.cli.SendCommand ("Runtime.callFunctionOn", cfo_args, ctx.token); - Assert.True ((silent ?? false) == result.IsOk); + Assert.False (result.IsOk, "result.IsOk"); + Assert.True (result.IsErr, "result.IsErr"); + + var hasErrorMessage = result.Error ["exceptionDetails"]?["exception"]?["description"]?.Value ()?.Contains (error_msg); + Assert.True ((hasErrorMessage ?? false), "Exception message not found"); }); } diff --git a/sdks/wasm/DebuggerTestSuite/PointerTests.cs b/sdks/wasm/DebuggerTestSuite/PointerTests.cs new file mode 100644 index 000000000000..932f02a0c802 --- /dev/null +++ b/sdks/wasm/DebuggerTestSuite/PointerTests.cs @@ -0,0 +1,520 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using Newtonsoft.Json.Linq; +using Xunit; +using WebAssembly.Net.Debugging; + +namespace DebuggerTests +{ + + public class PointerTests : DebuggerTestBase { + + public static TheoryData PointersTestData => + new TheoryData { + {$"invoke_static_method ('[debugger-test] DebuggerTests.PointerTests:LocalPointers');", "DebuggerTests.PointerTests", "LocalPointers", 32, "LocalPointers", false}, + {$"invoke_static_method ('[debugger-test] DebuggerTests.PointerTests:LocalPointers');", "DebuggerTests.PointerTests", "LocalPointers", 32, "LocalPointers", true}, + {$"invoke_static_method_async ('[debugger-test] DebuggerTests.PointerTests:LocalPointersAsync');", "DebuggerTests.PointerTests", "LocalPointersAsync", 32, "MoveNext", false}, + {$"invoke_static_method_async ('[debugger-test] DebuggerTests.PointerTests:LocalPointersAsync');", "DebuggerTests.PointerTests", "LocalPointersAsync", 32, "MoveNext", true} + }; + + [Theory] + [MemberDataAttribute (nameof (PointersTestData))] + public async Task InspectLocalPointersToPrimitiveTypes (string eval_fn, string type, string method, int line_offset, string bp_function_name, bool use_cfo) + => await CheckInspectLocalsAtBreakpointSite ( + type, method, line_offset, bp_function_name, + "window.setTimeout(function() { " + eval_fn + " })", + use_cfo: use_cfo, + wait_for_event_fn: async (pause_location) => { + var locals = await GetProperties (pause_location ["callFrames"][0]["callFrameId"].Value()); + + var dt = new DateTime (5, 6, 7, 8, 9, 10); + await CheckProps (locals, new { + ip = TPointer ("int*"), + ip_null = TPointer ("int*", is_null: true), + ipp = TPointer ("int**"), + ipp_null = TPointer ("int**"), + + cvalue0 = TSymbol ("113 'q'"), + cp = TPointer ("char*"), + + vp = TPointer ("void*"), + vp_null = TPointer ("void*", is_null: true), + }, "locals", num_fields: 26); + + var props = await GetObjectOnLocals (locals, "ip"); + await CheckPointerValue (props, "*ip", TNumber (5), "locals"); + + { + var ipp_props = await GetObjectOnLocals (locals, "ipp"); + await CheckPointerValue (ipp_props, "*ipp", TPointer ("int*")); + + ipp_props = await GetObjectOnLocals (ipp_props, "*ipp"); + await CheckPointerValue (ipp_props, "**ipp", TNumber (5)); + } + + { + var ipp_props = await GetObjectOnLocals (locals, "ipp_null"); + await CheckPointerValue (ipp_props, "*ipp_null", TPointer ("int*", is_null: true)); + } + + // *cp + props = await GetObjectOnLocals (locals, "cp"); + await CheckPointerValue (props, "*cp", TSymbol ("113 'q'")); + }); + + [Theory] + [MemberDataAttribute (nameof (PointersTestData))] + public async Task InspectLocalPointerArrays (string eval_fn, string type, string method, int line_offset, string bp_function_name, bool use_cfo) + => await CheckInspectLocalsAtBreakpointSite ( + type, method, line_offset, bp_function_name, + "window.setTimeout(function() { " + eval_fn + " })", + use_cfo: use_cfo, + wait_for_event_fn: async (pause_location) => { + var locals = await GetProperties (pause_location ["callFrames"][0]["callFrameId"].Value()); + + var dt = new DateTime (5, 6, 7, 8, 9, 10); + await CheckProps (locals, new { + ipa = TArray ("int*[]", 3) + }, "locals", num_fields: 26); + + var ipa_elems = await CompareObjectPropertiesFor (locals, "ipa", new [] { + TPointer ("int*"), + TPointer ("int*"), + TPointer ("int*", is_null: true) + }); + + await CheckArrayElements (ipa_elems, new [] { + TNumber (5), + TNumber (10), + null + }); + }); + + [Theory] + [MemberDataAttribute (nameof (PointersTestData))] + public async Task InspectLocalDoublePointerToPrimitiveTypeArrays (string eval_fn, string type, string method, int line_offset, string bp_function_name, bool use_cfo) + => await CheckInspectLocalsAtBreakpointSite ( + type, method, line_offset, bp_function_name, + "window.setTimeout(function() { " + eval_fn + " })", + use_cfo: use_cfo, + wait_for_event_fn: async (pause_location) => { + var locals = await GetProperties (pause_location ["callFrames"][0]["callFrameId"].Value()); + + var dt = new DateTime (5, 6, 7, 8, 9, 10); + await CheckProps (locals, new { + ippa = TArray ("int**[]", 5) + }, "locals", num_fields: 26); + + var ippa_elems = await CompareObjectPropertiesFor (locals, "ippa", new [] { + TPointer ("int**"), + TPointer ("int**"), + TPointer ("int**"), + TPointer ("int**"), + TPointer ("int**", is_null: true) + }); + + { + var actual_elems = await CheckArrayElements (ippa_elems, new [] { + TPointer ("int*"), + TPointer ("int*", is_null: true), + TPointer ("int*"), + TPointer ("int*", is_null: true), + null + }); + + var val = await GetObjectOnLocals (actual_elems [0], "*[0]"); + await CheckPointerValue (val, "**[0]", TNumber (5)); + + val = await GetObjectOnLocals (actual_elems [2], "*[2]"); + await CheckPointerValue (val, "**[2]", TNumber (5)); + } + }); + + [Theory] + [MemberDataAttribute (nameof (PointersTestData))] + public async Task InspectLocalPointersToValueTypes (string eval_fn, string type, string method, int line_offset, string bp_function_name, bool use_cfo) + => await CheckInspectLocalsAtBreakpointSite ( + type, method, line_offset, bp_function_name, + "window.setTimeout(function() { " + eval_fn + " })", + use_cfo: use_cfo, + wait_for_event_fn: async (pause_location) => { + var locals = await GetProperties (pause_location ["callFrames"][0]["callFrameId"].Value()); + + var dt = new DateTime (5, 6, 7, 8, 9, 10); + await CheckProps (locals, new { + dt = TValueType ("System.DateTime", dt.ToString ()), + dtp = TPointer ("System.DateTime*"), + dtp_null = TPointer ("System.DateTime*", is_null: true), + + gsp = TPointer ("DebuggerTests.GenericStructWithUnmanagedT*"), + gsp_null = TPointer ("DebuggerTests.GenericStructWithUnmanagedT*") + }, "locals", num_fields: 26); + + await CheckDateTime (locals, "dt", dt); + + // *dtp + var props = await GetObjectOnLocals (locals, "dtp"); + await CheckDateTime (props, "*dtp", dt); + + var gsp_props = await GetObjectOnLocals (locals, "gsp"); + await CheckPointerValue (gsp_props, "*gsp", TValueType ("DebuggerTests.GenericStructWithUnmanagedT"), "locals#gsp"); + + { + var gs_dt = new DateTime (1, 2, 3, 4, 5, 6); + + var gsp_deref_props = await GetObjectOnLocals (gsp_props, "*gsp"); + await CheckProps (gsp_deref_props, new { + Value = TValueType ("System.DateTime", gs_dt.ToString ()), + IntField = TNumber (4), + DTPP = TPointer ("System.DateTime**") + }, "locals#gsp#deref"); + { + var dtpp_props = await GetObjectOnLocals (gsp_deref_props, "DTPP"); + await CheckPointerValue (dtpp_props, "*DTPP", TPointer ("System.DateTime*"), "locals#*gsp"); + + var dtpp_deref_props = await GetObjectOnLocals (dtpp_props, "*DTPP"); + await CheckDateTime (dtpp_deref_props, "**DTPP", dt); + } + } + + // gsp_null + var gsp_w_n_props = await GetObjectOnLocals (locals, "gsp_null"); + await CheckPointerValue (gsp_w_n_props, "*gsp_null", TValueType ("DebuggerTests.GenericStructWithUnmanagedT"), "locals#gsp"); + + { + var gs_dt = new DateTime (1, 2, 3, 4, 5, 6); + + var gsp_deref_props = await GetObjectOnLocals (gsp_w_n_props, "*gsp_null"); + await CheckProps (gsp_deref_props, new { + Value = TValueType ("System.DateTime", gs_dt.ToString ()), + IntField = TNumber (4), + DTPP = TPointer ("System.DateTime**") + }, "locals#gsp#deref"); + { + var dtpp_props = await GetObjectOnLocals (gsp_deref_props, "DTPP"); + await CheckPointerValue (dtpp_props, "*DTPP", TPointer ("System.DateTime*", is_null: true), "locals#*gsp"); + } + } + }); + + [Theory] + [MemberDataAttribute (nameof (PointersTestData))] + public async Task InspectLocalPointersToValueTypeArrays (string eval_fn, string type, string method, int line_offset, string bp_function_name, bool use_cfo) + => await CheckInspectLocalsAtBreakpointSite ( + type, method, line_offset, bp_function_name, + "window.setTimeout(function() { " + eval_fn + " })", + use_cfo: use_cfo, + wait_for_event_fn: async (pause_location) => { + var locals = await GetProperties (pause_location ["callFrames"][0]["callFrameId"].Value()); + + var dt = new DateTime (5, 6, 7, 8, 9, 10); + await CheckProps (locals, new { + dtpa = TArray ("System.DateTime*[]", 2) + }, "locals", num_fields: 26); + + // dtpa + var dtpa_elems = (await CompareObjectPropertiesFor (locals, "dtpa", new [] { + TPointer ("System.DateTime*"), + TPointer ("System.DateTime*", is_null: true) + })); + { + var actual_elems = await CheckArrayElements (dtpa_elems, new [] { + TValueType ("System.DateTime", dt.ToString ()), + null + }); + + await CheckDateTime (actual_elems [0], "*[0]", dt); + } + }); + + [Theory] + [MemberDataAttribute (nameof (PointersTestData))] + public async Task InspectLocalPointersToGenericValueTypeArrays (string eval_fn, string type, string method, int line_offset, string bp_function_name, bool use_cfo) + => await CheckInspectLocalsAtBreakpointSite ( + type, method, line_offset, bp_function_name, + "window.setTimeout(function() { " + eval_fn + " })", + use_cfo: use_cfo, + wait_for_event_fn: async (pause_location) => { + var locals = await GetProperties (pause_location ["callFrames"][0]["callFrameId"].Value()); + + var dt = new DateTime (5, 6, 7, 8, 9, 10); + await CheckProps (locals, new { + gspa = TArray ("DebuggerTests.GenericStructWithUnmanagedT*[]", 3), + }, "locals", num_fields: 26); + + // dtpa + var gspa_elems = await CompareObjectPropertiesFor (locals, "gspa", new [] { + TPointer ("DebuggerTests.GenericStructWithUnmanagedT*", is_null: true), + TPointer ("DebuggerTests.GenericStructWithUnmanagedT*"), + TPointer ("DebuggerTests.GenericStructWithUnmanagedT*"), + }); + { + var gs_dt = new DateTime (1, 2, 3, 4, 5, 6); + var actual_elems = await CheckArrayElements (gspa_elems, new [] { + null, + TValueType ("DebuggerTests.GenericStructWithUnmanagedT"), + TValueType ("DebuggerTests.GenericStructWithUnmanagedT") + }); + + // *[1] + { + var gsp_deref_props = await GetObjectOnLocals (actual_elems [1], "*[1]"); + await CheckProps (gsp_deref_props, new { + Value = TValueType ("System.DateTime", gs_dt.ToString ()), + IntField = TNumber (4), + DTPP = TPointer ("System.DateTime**") + }, "locals#gsp#deref"); + { + var dtpp_props = await GetObjectOnLocals (gsp_deref_props, "DTPP"); + await CheckPointerValue (dtpp_props, "*DTPP", TPointer ("System.DateTime*"), "locals#*gsp"); + + dtpp_props = await GetObjectOnLocals (dtpp_props, "*DTPP"); + await CheckDateTime (dtpp_props, "**DTPP", dt); + } + } + + // *[2] + { + var gsp_deref_props = await GetObjectOnLocals (actual_elems [2], "*[2]"); + await CheckProps (gsp_deref_props, new { + Value = TValueType ("System.DateTime", gs_dt.ToString ()), + IntField = TNumber (4), + DTPP = TPointer ("System.DateTime**") + }, "locals#gsp#deref"); + { + var dtpp_props = await GetObjectOnLocals (gsp_deref_props, "DTPP"); + await CheckPointerValue (dtpp_props, "*DTPP", TPointer ("System.DateTime*", is_null: true), "locals#*gsp"); + } + } + } + }); + + [Theory] + [MemberDataAttribute (nameof (PointersTestData))] + public async Task InspectLocalDoublePointersToValueTypeArrays (string eval_fn, string type, string method, int line_offset, string bp_function_name, bool use_cfo) + => await CheckInspectLocalsAtBreakpointSite ( + type, method, line_offset, bp_function_name, + "window.setTimeout(function() { " + eval_fn + " })", + use_cfo: use_cfo, + wait_for_event_fn: async (pause_location) => { + var locals = await GetProperties (pause_location ["callFrames"][0]["callFrameId"].Value()); + + var dt = new DateTime (5, 6, 7, 8, 9, 10); + await CheckProps (locals, new { + dtppa = TArray ("System.DateTime**[]", 3), + }, "locals", num_fields: 26); + + // DateTime**[] dtppa = new DateTime**[] { &dtp, &dtp_null, null }; + var dtppa_elems = (await CompareObjectPropertiesFor (locals, "dtppa", new [] { + TPointer ("System.DateTime**"), + TPointer ("System.DateTime**"), + TPointer ("System.DateTime**", is_null: true) + })); + + var exp_elems = new [] { + TPointer ("System.DateTime*"), + TPointer ("System.DateTime*", is_null: true), + null + }; + + var actual_elems = new JToken [exp_elems.Length]; + for (int i = 0; i < exp_elems.Length; i ++) { + if (exp_elems [i] != null) { + actual_elems [i] = await GetObjectOnLocals (dtppa_elems, i.ToString ()); + await CheckPointerValue (actual_elems [i], $"*[{i}]", exp_elems [i], $"dtppa->"); + } + } + }); + + [Theory] + [MemberDataAttribute (nameof (PointersTestData))] + public async Task InspectLocalPointersInClasses (string eval_fn, string type, string method, int line_offset, string bp_function_name, bool use_cfo) + => await CheckInspectLocalsAtBreakpointSite ( + type, method, line_offset, bp_function_name, + "window.setTimeout(function() { " + eval_fn + " })", + use_cfo: use_cfo, + wait_for_event_fn: async (pause_location) => { + var locals = await GetProperties (pause_location ["callFrames"][0]["callFrameId"].Value()); + + var dt = new DateTime (5, 6, 7, 8, 9, 10); + await CheckProps (locals, new { + cwp = TObject ("DebuggerTests.GenericClassWithPointers"), + cwp_null = TObject ("DebuggerTests.GenericClassWithPointers") + }, "locals", num_fields: 26); + + var cwp_props = await GetObjectOnLocals (locals, "cwp"); + var ptr_props = await GetObjectOnLocals (cwp_props, "Ptr"); + await CheckDateTime (ptr_props, "*Ptr", dt); + }); + + public static TheoryData PointersAsMethodArgsTestData => + new TheoryData { + {$"invoke_static_method ('[debugger-test] DebuggerTests.PointerTests:LocalPointers');", "DebuggerTests.PointerTests", "PointersAsArgsTest", 2, "PointersAsArgsTest", false}, + {$"invoke_static_method ('[debugger-test] DebuggerTests.PointerTests:LocalPointers');", "DebuggerTests.PointerTests", "PointersAsArgsTest", 2, "PointersAsArgsTest", true}, + }; + + [Theory] + [MemberDataAttribute (nameof (PointersAsMethodArgsTestData))] + public async Task InspectPrimitiveTypePointersAsMethodArgs (string eval_fn, string type, string method, int line_offset, string bp_function_name, bool use_cfo) + => await CheckInspectLocalsAtBreakpointSite ( + type, method, line_offset, bp_function_name, + "window.setTimeout(function() { " + eval_fn + " })", + use_cfo: use_cfo, + wait_for_event_fn: async (pause_location) => { + var locals = await GetProperties (pause_location ["callFrames"][0]["callFrameId"].Value()); + + var dt = new DateTime (5, 6, 7, 8, 9, 10); + await CheckProps (locals, new { + ip = TPointer ("int*"), + ipp = TPointer ("int**"), + ipa = TArray ("int*[]", 3), + ippa = TArray ("int**[]", 5) + }, "locals", num_fields: 8); + + // ip + var props = await GetObjectOnLocals (locals, "ip"); + await CheckPointerValue (props, "*ip", TNumber (5), "locals"); + + // ipp + var ipp_props = await GetObjectOnLocals (locals, "ipp"); + await CheckPointerValue (ipp_props, "*ipp", TPointer ("int*")); + + ipp_props = await GetObjectOnLocals (ipp_props, "*ipp"); + await CheckPointerValue (ipp_props, "**ipp", TNumber (5)); + + // ipa + var ipa_elems = await CompareObjectPropertiesFor (locals, "ipa", new [] { + TPointer ("int*"), + TPointer ("int*"), + TPointer ("int*", is_null: true) + }); + + await CheckArrayElements (ipa_elems, new [] { + TNumber (5), + TNumber (10), + null + }); + + // ippa + var ippa_elems = await CompareObjectPropertiesFor (locals, "ippa", new [] { + TPointer ("int**"), + TPointer ("int**"), + TPointer ("int**"), + TPointer ("int**"), + TPointer ("int**", is_null: true) + }); + + { + var actual_elems = await CheckArrayElements (ippa_elems, new [] { + TPointer ("int*"), + TPointer ("int*", is_null: true), + TPointer ("int*"), + TPointer ("int*", is_null: true), + null + }); + + var val = await GetObjectOnLocals (actual_elems [0], "*[0]"); + await CheckPointerValue (val, "**[0]", TNumber (5)); + + val = await GetObjectOnLocals (actual_elems [2], "*[2]"); + await CheckPointerValue (val, "**[2]", TNumber (5)); + } + }); + + [Theory] + [MemberDataAttribute (nameof (PointersAsMethodArgsTestData))] + public async Task InspectValueTypePointersAsMethodArgs (string eval_fn, string type, string method, int line_offset, string bp_function_name, bool use_cfo) + => await CheckInspectLocalsAtBreakpointSite ( + type, method, line_offset, bp_function_name, + "window.setTimeout(function() { " + eval_fn + " })", + use_cfo: use_cfo, + wait_for_event_fn: async (pause_location) => { + var locals = await GetProperties (pause_location ["callFrames"][0]["callFrameId"].Value()); + + var dt = new DateTime (5, 6, 7, 8, 9, 10); + await CheckProps (locals, new { + dtp = TPointer ("System.DateTime*"), + dtpp = TPointer ("System.DateTime**"), + dtpa = TArray ("System.DateTime*[]", 2), + dtppa = TArray ("System.DateTime**[]", 3) + }, "locals", num_fields: 8); + + // *dtp + var dtp_props = await GetObjectOnLocals (locals, "dtp"); + await CheckDateTime (dtp_props, "*dtp", dt); + + // *dtpp + var dtpp_props = await GetObjectOnLocals (locals, "dtpp"); + await CheckPointerValue (dtpp_props, "*dtpp", TPointer ("System.DateTime*"), "locals"); + + dtpp_props = await GetObjectOnLocals (dtpp_props, "*dtpp"); + await CheckDateTime (dtpp_props, "**dtpp", dt); + + // dtpa + var dtpa_elems = (await CompareObjectPropertiesFor (locals, "dtpa", new [] { + TPointer ("System.DateTime*"), + TPointer ("System.DateTime*", is_null: true) + })); + { + var actual_elems = await CheckArrayElements (dtpa_elems, new [] { + TValueType ("System.DateTime", dt.ToString ()), + null + }); + + await CheckDateTime (actual_elems [0], "*[0]", dt); + } + + // dtppa = new DateTime**[] { &dtp, &dtp_null, null }; + var dtppa_elems = (await CompareObjectPropertiesFor (locals, "dtppa", new [] { + TPointer ("System.DateTime**"), + TPointer ("System.DateTime**"), + TPointer ("System.DateTime**", is_null: true) + })); + + var exp_elems = new [] { + TPointer ("System.DateTime*"), + TPointer ("System.DateTime*", is_null: true), + null + }; + + await CheckArrayElements (dtppa_elems, exp_elems); + }); + + [Theory] + [InlineData ("invoke_static_method ('[debugger-test] Math:UseComplex', 0, 0);", "Math", "UseComplex", 3, "UseComplex", false)] + [InlineData ("invoke_static_method ('[debugger-test] Math:UseComplex', 0, 0);", "Math", "UseComplex", 3, "UseComplex", true)] + public async Task DerefNonPointerObject (string eval_fn, string type, string method, int line_offset, string bp_function_name, bool use_cfo) + => await CheckInspectLocalsAtBreakpointSite ( + type, method, line_offset, bp_function_name, + "window.setTimeout(function() { " + eval_fn + " })", + use_cfo: use_cfo, + wait_for_event_fn: async (pause_location) => { + + // this will generate the object ids + var locals = await GetProperties (pause_location ["callFrames"][0]["callFrameId"].Value()); + var complex = GetAndAssertObjectWithName (locals, "complex"); + + // try to deref the non-pointer object, as a pointer + var props = await GetProperties (complex ["value"]["objectId"].Value ().Replace (":object:", ":pointer:")); + Assert.Empty (props.Values ()); + + // try to deref an invalid pointer id + props = await GetProperties ("dotnet:pointer:123897"); + Assert.Empty (props.Values ()); + }); + + async Task CheckArrayElements (JToken array, JToken[] exp_elems) + { + var actual_elems = new JToken [exp_elems.Length]; + for (int i = 0; i < exp_elems.Length; i ++) { + if (exp_elems [i] != null) { + actual_elems [i] = await GetObjectOnLocals (array, i.ToString ()); + await CheckPointerValue (actual_elems [i], $"*[{i}]", exp_elems [i], $"dtppa->"); + } + } + + return actual_elems; + } + } +} \ No newline at end of file diff --git a/sdks/wasm/DebuggerTestSuite/Support.cs b/sdks/wasm/DebuggerTestSuite/Support.cs index 56db77df5162..efa161090877 100644 --- a/sdks/wasm/DebuggerTestSuite/Support.cs +++ b/sdks/wasm/DebuggerTestSuite/Support.cs @@ -214,6 +214,50 @@ await EvaluateAndCheck ( }); } + // sets breakpoint by method name and line offset + internal async Task CheckInspectLocalsAtBreakpointSite (string type, string method, int line_offset, string bp_function_name, string eval_expression, + Action locals_fn = null, Func wait_for_event_fn = null, bool use_cfo = false, string assembly="debugger-test.dll", int col = 0) + { + var insp = new Inspector (); + //Collect events + var scripts = SubscribeToScripts(insp); + + await Ready (); + await insp.Ready (async (cli, token) => { + ctx = new DebugTestContext (cli, insp, token, scripts); + ctx.UseCallFunctionOnBeforeGetProperties = use_cfo; + + var bp = await SetBreakpointInMethod (assembly, type, method, line_offset, col); + + var args = JObject.FromObject (new { expression = eval_expression }); + var res = await ctx.cli.SendCommand ("Runtime.evaluate", args, ctx.token); + if (!res.IsOk) { + Console.WriteLine ($"Failed to run command {method} with args: {args?.ToString ()}\nresult: {res.Error.ToString ()}"); + Assert.True (false, $"SendCommand for {method} failed with {res.Error.ToString ()}"); + } + + var pause_location = await ctx.insp.WaitFor (Inspector.PAUSE); + + if (bp_function_name != null) + Assert.Equal (bp_function_name, pause_location ["callFrames"]?[0]?["functionName"]?.Value ()); + + Assert.Equal (bp.Value ["breakpointId"]?.ToString (), pause_location ["hitBreakpoints"]?[0]?.Value ()); + + var top_frame = pause_location ["callFrames"][0]; + + var scope = top_frame ["scopeChain"][0]; + Assert.Equal ("dotnet:scope:0", scope ["object"]["objectId"]); + + if (wait_for_event_fn != null) + await wait_for_event_fn (pause_location); + + if (locals_fn != null) { + var locals = await GetProperties (pause_location ["callFrames"][0]["callFrameId"].Value ()); + locals_fn (locals); + } + }); + } + internal void CheckLocation (string script_loc, int line, int column, Dictionary scripts, JToken location) { var loc_str = $"{ scripts[location["scriptId"].Value()] }" @@ -277,6 +321,13 @@ internal JToken CheckObject (JToken locals, string name, string class_name, stri return l; } + internal async Task CheckPointerValue (JToken locals, string name, JToken expected, string label = null) + { + var l = GetAndAssertObjectWithName (locals, name); + await CheckValue (l ["value"], expected, $"{label ?? String.Empty}-{name}"); + return l; + } + internal async Task CheckDateTime (JToken locals, string name, DateTime expected) { var obj = GetAndAssertObjectWithName(locals, name); @@ -486,9 +537,8 @@ void CheckDelegateTarget(string actual_target, string exp_target) } } - internal async Task CheckCustomType (JToken actual, JToken exp_val, string label) + internal async Task CheckCustomType (JToken actual_val, JToken exp_val, string label) { - var actual_val = actual ["value"]; var ctype = exp_val["__custom_type"].Value(); switch (ctype) { case "delegate": @@ -496,23 +546,35 @@ internal async Task CheckCustomType (JToken actual, JToken exp_val, string label break; case "pointer": { - AssertEqual ("symbol", actual_val ["type"]?.Value(), $"{label}-type"); - if (exp_val ["is_null"]?.Value() == false) { + if (exp_val ["is_null"]?.Value() == true) { + AssertEqual ("symbol", actual_val ["type"]?.Value(), $"{label}-type"); + + var exp_val_str = $"({exp_val ["type_name"]?.Value()}) 0"; + AssertEqual (exp_val_str, actual_val ["value"]?.Value (), $"{label}-value"); + AssertEqual (exp_val_str, actual_val ["description"]?.Value (), $"{label}-description"); + } else if (exp_val ["is_void"]?.Value () == true) { + AssertEqual ("symbol", actual_val ["type"]?.Value(), $"{label}-type"); + + var exp_val_str = $"({exp_val ["type_name"]?.Value()})"; + AssertStartsWith (exp_val_str, actual_val ["value"]?.Value (), $"{label}-value"); + AssertStartsWith (exp_val_str, actual_val ["description"]?.Value (), $"{label}-description"); + } else { + AssertEqual ("object", actual_val ["type"]?.Value(), $"{label}-type"); + var exp_prefix = $"({exp_val ["type_name"]?.Value()})"; - AssertStartsWith (exp_prefix, actual_val ["value"]?.Value (), $"{label}-value"); + AssertStartsWith (exp_prefix, actual_val ["className"]?.Value (), $"{label}-className"); AssertStartsWith (exp_prefix, actual_val ["description"]?.Value (), $"{label}-description"); - } else { - var exp_prefix = $"({exp_val ["type_name"]?.Value()}) 0"; - AssertEqual (exp_prefix, actual_val ["value"]?.Value (), $"{label}-value"); - AssertEqual (exp_prefix, actual_val ["description"]?.Value (), $"{label}-description"); + Assert.False (actual_val ["className"]?.Value () == $"{exp_prefix} 0", $"[{label}] Expected a non-null value, but got {actual_val}"); } break; } case "getter": { - var get = actual ["get"]; - Assert.True (get != null, $"[{label}] No `get` found"); + // For getter, `actual_val` is not `.value`, instead it's the container object + // which has a `.get` instead of a `.value` + var get = actual_val ["get"]; + Assert.True (get != null, $"[{label}] No `get` found. {(actual_val != null ? "Make sure to pass the container object for testing getters, and not the ['value']": String.Empty)}"); AssertEqual ("Function", get ["className"]?.Value (), $"{label}-className"); AssertStartsWith ($"get {exp_val ["type_name"]?.Value ()} ()", get ["description"]?.Value (), $"{label}-description"); @@ -546,12 +608,8 @@ internal async Task CheckProps (JToken actual, object exp_o, string label, int n var act_i = actual_arr [i]; AssertEqual (i.ToString (), act_i ["name"]?.Value (), $"{label}-[{i}].name"); - - if (exp_i ["__custom_type"] != null) { - await CheckCustomType (act_i, exp_i, $"{label}-{i}th value"); - } else { + if (exp_i != null) await CheckValue (act_i["value"], exp_i, $"{label}-{i}th value"); - } } return; @@ -580,7 +638,8 @@ internal async Task CheckProps (JToken actual, object exp_o, string label, int n if (exp_val.Type == JTokenType.Array) { var actual_props = await GetProperties(actual_val["objectId"]?.Value()); await CheckProps (actual_props, exp_val, $"{label}-{exp_name}"); - } else if (exp_val ["__custom_type"] != null) { + } else if (exp_val ["__custom_type"] != null && exp_val ["__custom_type"]?.Value () == "getter") { + // hack: for getters, actual won't have a .value await CheckCustomType (actual_obj, exp_val, $"{label}#{exp_name}"); } else { await CheckValue (actual_val, exp_val, $"{label}#{exp_name}"); @@ -820,7 +879,7 @@ internal static JObject TDelegate(string className, string target) }); internal static JObject TPointer (string type_name, bool is_null = false) - => JObject.FromObject (new { __custom_type = "pointer", type_name = type_name, is_null = is_null }); + => JObject.FromObject (new { __custom_type = "pointer", type_name = type_name, is_null = is_null, is_void = type_name.StartsWith ("void*") }); internal static JObject TIgnore () => JObject.FromObject (new { __custom_type = "ignore_me" }); diff --git a/sdks/wasm/DebuggerTestSuite/Tests.cs b/sdks/wasm/DebuggerTestSuite/Tests.cs index fdd97c017db6..af0ed7219166 100644 --- a/sdks/wasm/DebuggerTestSuite/Tests.cs +++ b/sdks/wasm/DebuggerTestSuite/Tests.cs @@ -1308,38 +1308,6 @@ await insp.Ready (async (cli, token) => { }); } - [Theory] - [InlineData (false)] - [InlineData (true)] - public async Task InspectLocalsWithPointers (bool use_cfo) - => await CheckInspectLocalsAtBreakpointSite ( - "dotnet://debugger-test.dll/debugger-test.cs", 294, 2, - "PointersTest", - "window.setTimeout(function() { invoke_static_method_async ('[debugger-test] Math:PointersTest'); })", - use_cfo: use_cfo, - wait_for_event_fn: async (pause_location) => { - var locals = await GetProperties (pause_location ["callFrames"][0]["callFrameId"].Value()); - - var dt = new DateTime (5, 6, 7, 8, 9, 10); - await CheckProps (locals, new { - ivalue0 = TNumber (5), - ivalue1 = TNumber (10), - ip = TPointer ("int*"), - ip_null = TPointer ("int*", is_null: true), - ipp = TPointer ("int**"), - - ipa = TArray ("int*[]", 3), - cvalue0 = TSymbol ("113 'q'"), - cp = TPointer ("char*"), - dt = TValueType ("System.DateTime", dt.ToString ()), - vp = TPointer ("void*"), - vp_null = TPointer ("void*", is_null: true), - dtp = TPointer ("System.DateTime*"), - dtp_null = TPointer ("System.DateTime*", is_null: true) - }, "locals"); - - }); - [Theory] [InlineData (false)] [InlineData (true)] @@ -1376,8 +1344,35 @@ await CompareObjectPropertiesFor (frame_locals, "this", label: "this#0"); }); - // + + [Fact] + public async Task SteppingIntoMscorlib () { + var insp = new Inspector (); + //Collect events + var scripts = SubscribeToScripts(insp); + + await Ready (); + await insp.Ready (async (cli, token) => { + ctx = new DebugTestContext (cli, insp, token, scripts); + + var bp = await SetBreakpoint ("dotnet://debugger-test.dll/debugger-test.cs", 74, 2); + var pause_location = await EvaluateAndCheck ( + "window.setTimeout(function() { invoke_static_method ('[debugger-test] Math:OuterMethod'); }, 1);", + "dotnet://debugger-test.dll/debugger-test.cs", 74, 2, + "OuterMethod"); + + //make sure we're on the right bp + Assert.Equal (bp.Value ["breakpointId"]?.ToString (), pause_location ["hitBreakpoints"]?[0]?.Value ()); + + pause_location = await SendCommandAndCheck (null, $"Debugger.stepInto", null, -1, -1, null); + var top_frame = pause_location ["callFrames"][0]; + + AssertEqual ("WriteLine", top_frame ["functionName"]?.Value (), "Expected to be in WriteLine method"); + var script_id = top_frame ["functionLocation"]["scriptId"].Value (); + AssertEqual ("dotnet://mscorlib.dll/Console.cs", scripts [script_id], "Expected to stopped in System.Console.WriteLine"); + }); + } + //TODO add tests covering basic stepping behavior as step in/out/over } - } diff --git a/sdks/wasm/Makefile b/sdks/wasm/Makefile index cee014cb8681..29553fcd7b2a 100644 --- a/sdks/wasm/Makefile +++ b/sdks/wasm/Makefile @@ -132,7 +132,7 @@ provision-emsdk: # emsdk_env.sh calls emsdk construct_env which is a bit slow so make a copy emsdk_env.sh: | provision-emsdk - cd $(EMSCRIPTEN_SDK_DIR) && ./emsdk construct_env $(CURDIR)/emsdk_env.sh + cd $(EMSCRIPTEN_SDK_DIR) && ./emsdk construct_env > $(CURDIR)/emsdk_env.sh # These builds overwrite their installed files # forcing everything to be rebuilt so use a stamp file @@ -156,6 +156,10 @@ bcl: $(MAKE) -C ../builds package-wasm-bcl touch .stamp-bcl +tuner: + $(MAKE) -C ../../mcs/tools/wasm-tuner PROFILE=wasm_tools + cp ../../mcs/class/lib/wasm_tools/wasm-tuner.* ../out/wasm-bcl/wasm_tools/ + MONO_LIBS = $(TOP)/sdks/out/wasm-runtime-release/lib/{libmono-ee-interp.a,libmono-native.a,libmono-icall-table.a,libmonosgen-2.0.a,libmono-ilgen.a} MONO_THREADS_LIBS = $(TOP)/sdks/out/wasm-runtime-threads-release/lib/{libmono-ee-interp.a,libmono-native.a,libmono-icall-table.a,libmonosgen-2.0.a,libmono-ilgen.a} MONO_DYNAMIC_LIBS = $(TOP)/sdks/out/wasm-runtime-dynamic-release/lib/{libmono-ee-interp.a,libmono-native.a,libmono-icall-table.a,libmonosgen-2.0.a,libmono-ilgen.a} diff --git a/sdks/wasm/Mono.WebAssembly.DebuggerProxy/DebugStore.cs b/sdks/wasm/Mono.WebAssembly.DebuggerProxy/DebugStore.cs index be349392ab68..f633fe786d59 100644 --- a/sdks/wasm/Mono.WebAssembly.DebuggerProxy/DebugStore.cs +++ b/sdks/wasm/Mono.WebAssembly.DebuggerProxy/DebugStore.cs @@ -502,6 +502,7 @@ private Uri GetSourceLinkUrl (string document) public IEnumerable Sources => this.sources; + public Dictionary TypesByName => this.typesByName; public int Id => id; public string Name => image.Name; diff --git a/sdks/wasm/Mono.WebAssembly.DebuggerProxy/DevToolsHelper.cs b/sdks/wasm/Mono.WebAssembly.DebuggerProxy/DevToolsHelper.cs index 08cebf1b1b77..a615540e4502 100644 --- a/sdks/wasm/Mono.WebAssembly.DebuggerProxy/DevToolsHelper.cs +++ b/sdks/wasm/Mono.WebAssembly.DebuggerProxy/DevToolsHelper.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using System.Threading.Tasks; +using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System.Threading; @@ -190,8 +191,11 @@ public static MonoCommands ClearAllBreakpoints () public static MonoCommands GetDetails (DotnetObjectId objectId, JToken args = null) => new MonoCommands ($"MONO.mono_wasm_get_details ('{objectId}', {(args ?? "{}")})"); - public static MonoCommands GetScopeVariables (int scopeId, params int[] vars) - => new MonoCommands ($"MONO.mono_wasm_get_variables({scopeId}, [ {string.Join (",", vars)} ])"); + public static MonoCommands GetScopeVariables (int scopeId, params VarInfo[] vars) + { + var var_ids = vars.Select (v => new { index = v.Index, name = v.Name }).ToArray (); + return new MonoCommands ($"MONO.mono_wasm_get_variables({scopeId}, {JsonConvert.SerializeObject (var_ids)})"); + } public static MonoCommands SetBreakpoint (string assemblyName, uint methodToken, int ilOffset) => new MonoCommands ($"MONO.mono_wasm_set_breakpoint (\"{assemblyName}\", {methodToken}, {ilOffset})"); diff --git a/sdks/wasm/Mono.WebAssembly.DebuggerProxy/MonoProxy.cs b/sdks/wasm/Mono.WebAssembly.DebuggerProxy/MonoProxy.cs index e0e6c3e528fc..5169d1ccfff3 100644 --- a/sdks/wasm/Mono.WebAssembly.DebuggerProxy/MonoProxy.cs +++ b/sdks/wasm/Mono.WebAssembly.DebuggerProxy/MonoProxy.cs @@ -318,6 +318,14 @@ protected override async Task AcceptCommand (MessageId id, string method, } var methodInfo = type.Methods.FirstOrDefault (m => m.Name == methodName); + if (methodInfo == null) { + // Maybe this is an async method, in which case the debug info is attached + // to the async method implementation, in class named: + // `{type_name}/::MoveNext` + methodInfo = assembly.TypesByName.Values.SingleOrDefault (t => t.FullName.StartsWith ($"{typeName}/<{methodName}>")) + ?.Methods.FirstOrDefault (mi => mi.Name == "MoveNext"); + } + if (methodInfo == null) { SendResponse (id, Result.Err ($"Method '{typeName}:{methodName}' not found."), token); return true; @@ -334,11 +342,11 @@ protected override async Task AcceptCommand (MessageId id, string method, if (!DotnetObjectId.TryParse (args ["objectId"], out var objectId)) return false; - var silent = args ["silent"]?.Value () ?? false; if (objectId.Scheme == "scope") { - var fail = silent ? Result.OkFromObject (new { result = new { } }) : Result.Exception (new ArgumentException ($"Runtime.callFunctionOn not supported with scope ({objectId}).")); - - SendResponse (id, fail, token); + SendResponse (id, + Result.Exception (new ArgumentException ( + $"Runtime.callFunctionOn not supported with scope ({objectId}).")), + token); return true; } @@ -347,8 +355,6 @@ protected override async Task AcceptCommand (MessageId id, string method, if (res.IsOk && res_value_type == JTokenType.Object || res_value_type == JTokenType.Object) res = Result.OkFromObject (new { result = res.Value ["result"]["value"] }); - else if (res.IsErr && silent) - res = Result.OkFromObject (new { result = new { } }); SendResponse (id, res, token); return true; @@ -372,7 +378,7 @@ async Task RuntimeGetProperties (MessageId id, DotnetObjectId objectId, var value_json_str = res.Value ["result"]?["value"]?["__value_as_json_string__"]?.Value (); if (value_json_str != null) { res = Result.OkFromObject (new { - result = JArray.Parse (value_json_str.Replace (@"\""", "\"")) + result = JArray.Parse (value_json_str) }); } else { res = Result.OkFromObject (new { result = new {} }); @@ -582,7 +588,7 @@ internal async Task TryGetVariableValue (MessageId msg_id, int scope_id, var scope = context.CallStack.FirstOrDefault (s => s.Id == scope_id); var live_vars = scope.Method.GetLiveVarsAt (scope.Location.CliLocation.Offset); //get_this - var res = await SendMonoCommand (msg_id, MonoCommands.GetScopeVariables (scope.Id, live_vars.Select (lv => lv.Index).ToArray ()), token); + var res = await SendMonoCommand (msg_id, MonoCommands.GetScopeVariables (scope.Id, live_vars), token); var scope_values = res.Value? ["result"]? ["value"]?.Values ()?.ToArray (); thisValue = scope_values?.FirstOrDefault (v => v ["name"]?.Value () == "this"); @@ -650,9 +656,7 @@ async Task GetScopeProperties (MessageId msg_id, int scope_id, Cancellat if (scope == null) return Result.Err (JObject.FromObject (new { message = $"Could not find scope with id #{scope_id}" })); - var vars = scope.Method.GetLiveVarsAt (scope.Location.CliLocation.Offset); - - var var_ids = vars.Select (v => v.Index).ToArray (); + var var_ids = scope.Method.GetLiveVarsAt (scope.Location.CliLocation.Offset); var res = await SendMonoCommand (msg_id, MonoCommands.GetScopeVariables (scope.Id, var_ids), token); //if we fail we just buble that to the IDE (and let it panic over it) @@ -661,27 +665,13 @@ async Task GetScopeProperties (MessageId msg_id, int scope_id, Cancellat var values = res.Value? ["result"]? ["value"]?.Values ().ToArray (); - if(values == null) + if(values == null || values.Length == 0) return Result.OkFromObject (new { result = Array.Empty () }); - var var_list = new List (); - int i = 0; - for (; i < vars.Length && i < values.Length; i ++) { - // For async methods, we get locals with names, unlike non-async methods - // and the order may not match the var_ids, so, use the names that they - // come with - if (values [i]["name"] != null) - continue; - - ctx.LocalsCache[vars [i].Name] = values [i]; - var_list.Add (new { name = vars [i].Name, value = values [i]["value"] }); - } - for (; i < values.Length; i ++) { - ctx.LocalsCache[values [i]["name"].ToString()] = values [i]; - var_list.Add (values [i]); - } + foreach (var value in values) + ctx.LocalsCache [value ["name"]?.Value ()] = value; - return Result.OkFromObject (new { result = var_list }); + return Result.OkFromObject (new { result = values }); } catch (Exception exception) { Log ("verbose", $"Error resolving scope properties {exception.Message}"); return Result.Exception (exception); diff --git a/sdks/wasm/packager.cs b/sdks/wasm/packager.cs index ff6f68e22183..ede46f44f6a8 100644 --- a/sdks/wasm/packager.cs +++ b/sdks/wasm/packager.cs @@ -923,7 +923,7 @@ int Run (string[] args) { ninja.WriteLine (" restat = true"); ninja.WriteLine (" description = [CPIFDIFF] $in -> $out"); ninja.WriteLine ("rule create-emsdk-env"); - ninja.WriteLine (" command = $emscripten_sdkdir/emsdk construct_env $out"); + ninja.WriteLine (" command = $emscripten_sdkdir/emsdk construct_env > $out"); ninja.WriteLine ("rule emcc"); ninja.WriteLine (" command = bash -c '$emcc $emcc_flags $flags -c -o $out $in'"); ninja.WriteLine (" description = [EMCC] $in -> $out"); diff --git a/sdks/wasm/src/driver.c b/sdks/wasm/src/driver.c index 7aca18f48a4f..5812bfb81e42 100644 --- a/sdks/wasm/src/driver.c +++ b/sdks/wasm/src/driver.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "pinvoke.h" @@ -157,7 +158,7 @@ mono_wasm_add_assembly (const char *name, const unsigned char *data, unsigned in entry->next = assemblies; assemblies = entry; ++assembly_count; - return mono_has_pdb_checksum (data, size); + return mono_has_pdb_checksum ((char*)data, size); } EMSCRIPTEN_KEEPALIVE void @@ -304,6 +305,31 @@ icall_table_lookup_symbol (void *func) #endif +/* + * get_native_to_interp: + * + * Return a pointer to a wasm function which can be used to enter the interpreter to + * execute METHOD from native code. + * EXTRA_ARG is the argument passed to the interp entry functions in the runtime. + */ +void* +get_native_to_interp (MonoMethod *method, void *extra_arg) +{ + uint32_t token = mono_method_get_token (method); + MonoClass *klass = mono_method_get_class (method); + MonoImage *image = mono_class_get_image (klass); + MonoAssembly *assembly = mono_image_get_assembly (image); + MonoAssemblyName *aname = mono_assembly_get_name (assembly); + const char *name = mono_assembly_name_get_name (aname); + char key [128]; + + assert (strlen (name) < 100); + sprintf (key, "%s_%d", name, token); + + void *addr = wasm_dl_get_native_to_interp (key, extra_arg); + return addr; +} + void mono_initialize_internals () { mono_add_internal_call ("WebAssembly.Runtime::InvokeJS", mono_wasm_invoke_js); @@ -316,7 +342,6 @@ void mono_initialize_internals () #ifdef CORE_BINDINGS core_initialize_internals(); #endif - } EMSCRIPTEN_KEEPALIVE void @@ -333,6 +358,7 @@ mono_wasm_load_runtime (const char *managed_path, int enable_debugging) mini_parse_debug_option ("top-runtime-invoke-unhandled"); mono_dl_fallback_register (wasm_dl_load, wasm_dl_symbol, NULL, NULL); + mono_wasm_install_get_native_to_interp_tramp (get_native_to_interp); #ifdef ENABLE_AOT // Defined in driver-gen.c @@ -343,7 +369,7 @@ mono_wasm_load_runtime (const char *managed_path, int enable_debugging) mono_jit_set_aot_mode (MONO_AOT_MODE_LLVMONLY); #endif #else - mono_jit_set_aot_mode (MONO_AOT_MODE_INTERP_LLVMONLY); + mono_jit_set_aot_mode (MONO_AOT_MODE_INTERP_ONLY); if (enable_debugging) { // Disable optimizations which interfere with debugging interp_opts = "-all"; diff --git a/sdks/wasm/src/library_mono.js b/sdks/wasm/src/library_mono.js index 92960f45479e..6569fd985d05 100644 --- a/sdks/wasm/src/library_mono.js +++ b/sdks/wasm/src/library_mono.js @@ -141,6 +141,27 @@ var MonoSupportLib = { return final_var_list; }, + // code from https://stackoverflow.com/a/5582308 + // + // Given `dotnet:object:foo:bar`, + // returns [ 'dotnet', 'object', 'foo:bar'] + _split_object_id: function (id, delim = ':', count = 3) { + if (id === undefined || id == "") + return []; + + if (delim === undefined) delim = ':'; + if (count === undefined) count = 3; + + var arr = id.split (delim); + var result = arr.splice (0, count - 1); + + if (arr.length > 0) + result.push (arr.join (delim)); + return result; + }, + + // + // @var_list: [ { index: , name: }, .. ] mono_wasm_get_variables: function(scope, var_list) { if (!this.mono_wasm_get_var_info) this.mono_wasm_get_var_info = Module.cwrap ("mono_wasm_get_var_info", null, [ 'number', 'number', 'number']); @@ -150,7 +171,7 @@ var MonoSupportLib = { var ptr = Module._malloc(numBytes); var heapBytes = new Int32Array(Module.HEAP32.buffer, ptr, numBytes); for (let i=0; i') > 0) - res [i].name = name.substring (1, name.indexOf ('>')); - } + var res_name = res [i].name; + + var value = res[i].value; + if (this._async_method_objectId != 0) { + //Async methods are special in the way that local variables can be lifted to generated class fields + //value of "this" comes here either + if (res_name !== undefined && res_name.indexOf ('>') > 0) { + // For async methods, we get the names too, so use that + // ALTHOUGH, the name wouldn't have `<>` for method args + res [i].name = res_name.substring (1, res_name.indexOf ('>')); + } - if (this._async_method_objectId != 0) { - for (let i in res) { - if (res [i].value.isValueType != undefined && res [i].value.isValueType) - res [i].value.objectId = `dotnet:valuetype:${this._async_method_objectId}:${res [i].fieldOffset}`; + if (value.isValueType) + value.objectId = `dotnet:valuetype:${this._async_method_objectId}:${res [i].fieldOffset}`; + } else if (res_name === undefined && var_list [i] !== undefined) { + // For non-async methods, we just have the var id, but we have the name + // from the caller + res [i].name = var_list [i].name; } } @@ -208,8 +236,14 @@ var MonoSupportLib = { var res = MONO._fixup_name_value_objects (this.var_info); for (var i = 0; i < res.length; i++) { - if (res [i].value.isValueType != undefined && res [i].value.isValueType) + var prop_value = res [i].value; + if (prop_value.isValueType) { res [i].value.objectId = `dotnet:array:${objId}:${i}`; + } else if (prop_value.objectId !== undefined && prop_value.objectId.startsWith("dotnet:pointer")) { + prop_value.objectId = this._get_updated_ptr_id (prop_value.objectId, { + varName: `[${i}]` + }); + } } this.var_info = []; @@ -254,12 +288,26 @@ var MonoSupportLib = { for (let i in var_list) { var value = var_list [i].value; - if (value == undefined || value.type != "object") + if (value === undefined) continue; - if (value.isValueType != true || value.expanded != true) // undefined would also give us false + if (value.objectId !== undefined && value.objectId.startsWith ("dotnet:pointer:")) { + var ptr_args = this._get_ptr_args (value.objectId); + if (ptr_args.varName === undefined) { + // It might have been already set in some cases, like arrays + // where the name would be `0`, but we want `[0]` for pointers, + // so the deref would look like `*[0]` + value.objectId = this._get_updated_ptr_id (value.objectId, { + varName: var_list [i].name + }); + } + } + + if (value.type != "object" || value.isValueType != true || value.expanded != true) // undefined would also give us false continue; + // Generate objectId for expanded valuetypes + var objectId = value.objectId; if (objectId == undefined) objectId = `dotnet:valuetype:${this._next_value_type_id ()}`; @@ -366,6 +414,46 @@ var MonoSupportLib = { return { __value_as_json_string__: JSON.stringify (res_details) }; }, + _get_ptr_args: function (objectId) { + var parts = this._split_object_id (objectId); + if (parts.length != 3) + throw new Error (`Bug: Unexpected objectId format for a pointer, expected 3 parts: ${objectId}`); + return JSON.parse (parts [2]); + }, + + _get_updated_ptr_id: function (objectId, new_args) { + var old_args = {}; + if (typeof (objectId) === 'string' && objectId.length) + old_args = this._get_ptr_args (objectId); + + return `dotnet:pointer:${JSON.stringify ( Object.assign (old_args, new_args) )}`; + }, + + _get_deref_ptr_value: function (objectId) { + if (!this.mono_wasm_get_deref_ptr_value_info) + this.mono_wasm_get_deref_ptr_value_info = Module.cwrap("mono_wasm_get_deref_ptr_value", null, ['number', 'number']); + + var ptr_args = this._get_ptr_args (objectId); + if (ptr_args.ptr_addr == 0 || ptr_args.klass_addr == 0) + throw new Error (`Both ptr_addr and klass_addr need to be non-zero, to dereference a pointer. objectId: ${objectId}`); + + this.var_info = []; + var value_addr = new DataView (Module.HEAPU8.buffer).getUint32 (ptr_args.ptr_addr, /* littleEndian */ true); + this.mono_wasm_get_deref_ptr_value_info (value_addr, ptr_args.klass_addr); + + var res = MONO._fixup_name_value_objects(this.var_info); + if (res.length > 0) { + if (ptr_args.varName === undefined) + throw new Error (`Bug: no varName found for the pointer. objectId: ${objectId}`); + + res [0].name = `*${ptr_args.varName}`; + } + + res = this._post_process_details (res); + this.var_info = []; + return res; + }, + mono_wasm_get_details: function (objectId, args) { var parts = objectId.split(":"); if (parts[0] != "dotnet") @@ -394,6 +482,10 @@ var MonoSupportLib = { case "cfo_res": return this._get_cfo_res_details (objectId, args); + case "pointer": { + return this._get_deref_ptr_value (objectId); + } + default: throw new Error(`Unknown object id format: ${objectId}`); } @@ -835,13 +927,26 @@ var MonoSupportLib = { break; case "pointer": { - MONO.var_info.push ({ - value: { - type: "symbol", - value: str_value, - description: str_value - } - }); + var fixed_value_str = MONO._mono_csharp_fixup_class_name (str_value); + if (value.klass_addr == 0 || value.ptr_addr == 0 || fixed_value_str.startsWith ('(void*')) { + // null or void*, which we can't deref + MONO.var_info.push({ + value: { + type: "symbol", + value: fixed_value_str, + description: fixed_value_str + } + }); + } else { + MONO.var_info.push({ + value: { + type: "object", + className: fixed_value_str, + description: fixed_value_str, + objectId: this._get_updated_ptr_id ('', value) + } + }); + } } break; diff --git a/sdks/wasm/src/pinvoke.c b/sdks/wasm/src/pinvoke.c index ce014ed72294..3804005cb5ad 100644 --- a/sdks/wasm/src/pinvoke.c +++ b/sdks/wasm/src/pinvoke.c @@ -42,3 +42,20 @@ wasm_dl_is_pinvoke_table (void *handle) } return 0; } + +void* +wasm_dl_get_native_to_interp (const char *key, void *extra_arg) +{ +#ifdef GEN_PINVOKE + for (int i = 0; i < sizeof (wasm_native_to_interp_map) / sizeof (void*); ++i) { + if (!strcmp (wasm_native_to_interp_map [i], key)) { + void *addr = wasm_native_to_interp_funcs [i]; + wasm_native_to_interp_ftndescs [i] = *(InterpFtnDesc*)extra_arg; + return addr; + } + } + return NULL; +#else + return NULL; +#endif +} diff --git a/sdks/wasm/src/pinvoke.h b/sdks/wasm/src/pinvoke.h index 927dcee1fb3f..03c5ce4ed6da 100644 --- a/sdks/wasm/src/pinvoke.h +++ b/sdks/wasm/src/pinvoke.h @@ -6,12 +6,20 @@ typedef struct { void *func; } PinvokeImport; +typedef struct { + void *func; + void *arg; +} InterpFtnDesc; + void* wasm_dl_lookup_pinvoke_table (const char *name); int wasm_dl_is_pinvoke_table (void *handle); +void* +wasm_dl_get_native_to_interp (const char *key, void *extra_arg); + void mono_wasm_pinvoke_vararg_stub (void); diff --git a/sdks/wasm/tests/debugger/debugger-pointers-test.cs b/sdks/wasm/tests/debugger/debugger-pointers-test.cs new file mode 100644 index 000000000000..6cca499566ea --- /dev/null +++ b/sdks/wasm/tests/debugger/debugger-pointers-test.cs @@ -0,0 +1,109 @@ +using System; +using System.Threading.Tasks; + +namespace DebuggerTests +{ + public class PointerTests + { + + public static unsafe void LocalPointers () + { + int ivalue0 = 5; + int ivalue1 = 10; + + int* ip = &ivalue0; + int* ip_null = null; + int** ipp = &ip; + int** ipp_null = &ip_null; + int*[] ipa = new int*[] { &ivalue0, &ivalue1, null }; + int**[] ippa = new int**[] { &ip, &ip_null, ipp, ipp_null, null }; + char cvalue0 = 'q'; + char* cp = &cvalue0; + + DateTime dt = new DateTime(5, 6, 7, 8, 9, 10); + void* vp = &dt; + void* vp_null = null; + void** vpp = &vp; + void** vpp_null = &vp_null; + + DateTime* dtp = &dt; + DateTime* dtp_null = null; + DateTime*[] dtpa = new DateTime*[] { dtp, dtp_null }; + DateTime**[] dtppa = new DateTime**[] { &dtp, &dtp_null, null }; + Console.WriteLine($"-- break here: ip_null==null: {ip_null == null}, ipp_null: {ipp_null == null}, *ipp_null==ip_null: {*ipp_null == ip_null}, *ipp_null==null: {*ipp_null == null}"); + + var gs = new GenericStructWithUnmanagedT { Value = new DateTime(1, 2, 3, 4, 5, 6), IntField = 4, DTPP = &dtp }; + var gs_null = new GenericStructWithUnmanagedT { Value = new DateTime(1, 2, 3, 4, 5, 6), IntField = 4, DTPP = &dtp_null }; + var gsp = &gs; + var gsp_null = &gs_null; + var gspa = new GenericStructWithUnmanagedT*[] { null, gsp, gsp_null }; + + var cwp = new GenericClassWithPointers { Ptr = dtp }; + var cwp_null = new GenericClassWithPointers(); + Console.WriteLine($"{(int)*ip}, {(int)**ipp}, {ipp_null == null}, {ip_null == null}, {ippa == null}, {ipa}, {(char)*cp}, {(vp == null ? "null" : "not null")}, {dtp->Second}, {gsp->IntField}, {cwp}, {cwp_null}, {gs_null}"); + + PointersAsArgsTest (ip, ipp, ipa, ippa, &dt, &dtp, dtpa, dtppa); + } + + static unsafe void PointersAsArgsTest(int* ip, int** ipp, int*[] ipa, int**[] ippa, + DateTime* dtp, DateTime** dtpp, DateTime*[] dtpa, DateTime**[] dtppa) + { + Console.WriteLine($"break here!"); + if (ip == null) + Console.WriteLine($"ip is null"); + Console.WriteLine($"done!"); + } + + public static unsafe async Task LocalPointersAsync () + { + int ivalue0 = 5; + int ivalue1 = 10; + + int* ip = &ivalue0; + int* ip_null = null; + int** ipp = &ip; + int** ipp_null = &ip_null; + int*[] ipa = new int*[] { &ivalue0, &ivalue1, null }; + int**[] ippa = new int**[] { &ip, &ip_null, ipp, ipp_null, null }; + char cvalue0 = 'q'; + char* cp = &cvalue0; + + DateTime dt = new DateTime(5, 6, 7, 8, 9, 10); + void* vp = &dt; + void* vp_null = null; + void** vpp = &vp; + void** vpp_null = &vp_null; + + DateTime* dtp = &dt; + DateTime* dtp_null = null; + DateTime*[] dtpa = new DateTime*[] { dtp, dtp_null }; + DateTime**[] dtppa = new DateTime**[] { &dtp, &dtp_null, null }; + Console.WriteLine($"-- break here: ip_null==null: {ip_null == null}, ipp_null: {ipp_null == null}, *ipp_null==ip_null: {*ipp_null == ip_null}, *ipp_null==null: {*ipp_null == null}"); + + var gs = new GenericStructWithUnmanagedT { Value = new DateTime(1, 2, 3, 4, 5, 6), IntField = 4, DTPP = &dtp }; + var gs_null = new GenericStructWithUnmanagedT { Value = new DateTime(1, 2, 3, 4, 5, 6), IntField = 4, DTPP = &dtp_null }; + var gsp = &gs; + var gsp_null = &gs_null; + var gspa = new GenericStructWithUnmanagedT*[] { null, gsp, gsp_null }; + + var cwp = new GenericClassWithPointers { Ptr = dtp }; + var cwp_null = new GenericClassWithPointers(); + Console.WriteLine($"{(int)*ip}, {(int)**ipp}, {ipp_null == null}, {ip_null == null}, {ippa == null}, {ipa}, {(char)*cp}, {(vp == null ? "null" : "not null")}, {dtp->Second}, {gsp->IntField}, {cwp}, {cwp_null}, {gs_null}"); + } + + // async methods cannot have unsafe params, so no test for that + } + + public unsafe struct GenericStructWithUnmanagedT where T : unmanaged + { + public T Value; + public int IntField; + + public DateTime** DTPP; + } + + public unsafe class GenericClassWithPointers where T : unmanaged + { + public unsafe T* Ptr; + } +} \ No newline at end of file diff --git a/sdks/wasm/tests/debugger/debugger-test.cs b/sdks/wasm/tests/debugger/debugger-test.cs index bd38e5edd8f1..84e3bcfe0a74 100644 --- a/sdks/wasm/tests/debugger/debugger-test.cs +++ b/sdks/wasm/tests/debugger/debugger-test.cs @@ -272,29 +272,6 @@ public static void DelegateTargetWithVoidReturn (GenericStruct gs) { } delegate GenericStruct DelegateForSignatureTest (Math m, GenericStruct> gs); static bool DelegateTargetForNestedFunc(T arg) => true; - public static unsafe void PointersTest () - { - int ivalue0 = 5; - int ivalue1 = 10; - - int* ip = &ivalue0; - int* ip_null = null; - int** ipp = &ip; - - int*[] ipa = new int*[] { &ivalue0, &ivalue1, null }; - - char cvalue0 = 'q'; - char* cp = &cvalue0; - - DateTime dt = new DateTime(5, 6, 7, 8, 9, 10); - void* vp = &dt; - void* vp_null = null; - - DateTime* dtp = &dt; - DateTime* dtp_null = null; - Console.WriteLine ($"-- break here"); - } - public struct SimpleStruct { public DateTime dt; diff --git a/tools/locale-builder/Makefile.am b/tools/locale-builder/Makefile.am index 909fbc1d42f2..0de636b516e6 100644 --- a/tools/locale-builder/Makefile.am +++ b/tools/locale-builder/Makefile.am @@ -47,5 +47,5 @@ locale-data: fi install-culture-table: culture-info-tables.h - cp -f culture-info-tables.h ../../mono/metadata/. + cp -f culture-info-tables.h ../../mono/culture/. diff --git a/winconfig.h b/winconfig.h index f062d0a69595..7d429a86e8a9 100644 --- a/winconfig.h +++ b/winconfig.h @@ -67,6 +67,9 @@ #ifndef DISABLE_DLLMAP #define DISABLE_DLLMAP 1 #endif +#ifndef DISABLE_CFGDIR_CONFIG +#define DISABLE_CFGDIR_CONFIG 1 +#endif #endif /* Disable runtime state dumping */