Fixes process names trimmed to 15 chars.
parallel_mark=yes
ikvm_native=yes
-case "$host" in
- powerpc*-*-linux*)
- # https://bugzilla.novell.com/show_bug.cgi?id=504411
- disable_munmap=yes
- ;;
-esac
-
host_win32=no
target_win32=no
platform_android=no
-platform_darwin=no
+host_darwin=no
case "$host" in
*-mingw*|*-*-cygwin*)
AC_DEFINE(DISABLE_PORTABILITY,1,[Disable the io-portability layer])
libgc_configure_args="$libgc_configure_args --enable-win32-dllmain=yes"
;;
*-*-*netbsd*)
- host_win32=no
CPPFLAGS="$CPPFLAGS -D_REENTRANT -DGC_NETBSD_THREADS -D_GNU_SOURCE"
libmono_cflags="-D_REENTRANT"
LDFLAGS="$LDFLAGS -pthread"
use_sigposix=yes
;;
*-*-kfreebsd*-gnu)
- host_win32=no
CPPFLAGS="$CPPFLAGS -DGC_FREEBSD_THREADS -D_GNU_SOURCE -D_REENTRANT -DUSE_MMAP -DUSE_MUNMAP -DTHREAD_LOCAL_ALLOC -pthread"
libmono_cflags="-D_REENTRANT -DTHREAD_LOCAL_ALLOC -pthread"
libmono_ldflags="-lpthread -pthread"
use_sigposix=yes
;;
*-*-*freebsd*)
- host_win32=no
if test "x$PTHREAD_CFLAGS" = "x"; then
CPPFLAGS="$CPPFLAGS -DGC_FREEBSD_THREADS"
libmono_cflags=
has_dtrace=yes
;;
*-*-*openbsd*)
- host_win32=no
CPPFLAGS="$CPPFLAGS -D_THREAD_SAFE -DGC_OPENBSD_THREADS -DPLATFORM_BSD -D_REENTRANT -DUSE_MMAP"
if test "x$disable_munmap" != "xyes"; then
CPPFLAGS="$CPPFLAGS -DUSE_MUNMAP"
use_sigposix=yes
;;
*-*-linux-android*)
- host_win32=no
platform_android=yes
AC_DEFINE(PLATFORM_ANDROID,1,[Targeting the Android platform])
AC_DEFINE(TARGET_ANDROID,1,[Targeting the Android platform])
mono_cv_clang=no
;;
*-*-linux*)
- host_win32=no
CPPFLAGS="$CPPFLAGS -DGC_LINUX_THREADS -D_GNU_SOURCE -D_REENTRANT -DUSE_MMAP"
if test "x$disable_munmap" != "xyes"; then
CPPFLAGS="$CPPFLAGS -DUSE_MUNMAP"
support_boehm=no
with_gc=sgen
;;
+ powerpc*-*-linux*)
+ # https://bugzilla.novell.com/show_bug.cgi?id=504411
+ disable_munmap=yes
+ ;;
esac
;;
*-*-nacl*)
- host_win32=no
CPPFLAGS="$CPPFLAGS -DGC_LINUX_THREADS -D_GNU_SOURCE -D_REENTRANT -DUSE_MMAP"
if test "x$disable_munmap" != "xyes"; then
CPPFLAGS="$CPPFLAGS -DUSE_MUNMAP"
AC_DEFINE(DISABLE_ATTACH, 1, [Disable agent attach support])
;;
*-*-hpux*)
- host_win32=no
CPPFLAGS="$CPPFLAGS -DGC_HPUX_THREADS -D_HPUX_SOURCE -D_XOPEN_SOURCE_EXTENDED -D_REENTRANT"
# +ESdbgasm only valid on bundled cc on RISC
# silently ignored for ia64
use_sigposix=yes
;;
*-*-solaris*)
- host_win32=no
CPPFLAGS="$CPPFLAGS -DGC_SOLARIS_THREADS -DGC_SOLARIS_PTHREADS -D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -DUSE_MMAP -DUSE_MUNMAP -DPLATFORM_SOLARIS"
need_link_unlink=yes
libmono_cflags="-D_REENTRANT"
;;
*-*-darwin*)
parallel_mark="Disabled_Currently_Hangs_On_MacOSX"
- host_win32=no
- platform_darwin=yes
+ host_darwin=yes
target_mach=yes
CPPFLAGS="$CPPFLAGS -D_THREAD_SAFE -DGC_MACOSX_THREADS -DPLATFORM_MACOSX -DUSE_MMAP -DUSE_MUNMAP"
libmono_cflags="-D_THREAD_SAFE"
esac
;;
*-*-haiku*)
- host_win32=no
CPPFLAGS="$CPPFLAGS -D_REENTRANT -D_THREAD_SAFE"
libmono_cflags="-D_REENTRANT -D_THREAD_SAFE"
libdl=
;;
*)
AC_MSG_WARN([*** Please add $host to configure.ac checks!])
- host_win32=no
libdl="-ldl"
;;
esac
AC_SUBST(extra_runtime_ldflags)
AM_CONDITIONAL(HOST_WIN32, test x$host_win32 = xyes)
AM_CONDITIONAL(TARGET_WIN32, test x$target_win32 = xyes)
-AM_CONDITIONAL(PLATFORM_GNU, echo x$target_os | grep -q -- -gnu)
AM_CONDITIONAL(PLATFORM_LINUX, echo x$target_os | grep -q linux)
-AM_CONDITIONAL(PLATFORM_DARWIN, test x$platform_darwin = xyes)
+AM_CONDITIONAL(PLATFORM_DARWIN, test x$host_darwin = xyes)
AM_CONDITIONAL(PLATFORM_SIGPOSIX, test x$use_sigposix = xyes)
AM_CONDITIONAL(PLATFORM_ANDROID, test x$platform_android = xyes)
GLIB_CFLAGS='-I$(top_srcdir)/eglib/src -I$(top_builddir)/eglib/src'
GLIB_LIBS='-L$(top_builddir)/eglib/src -leglib -lm'
-BUILD_GLIB_CFLAGS="$GLIB_CFLAGS"
-BUILD_GLIB_LIBS="$GLIB_LIBS"
-GMODULE_CFLAGS="$GLIB_CFLAGS"
-GMODULE_LIBS="$GLIB_LIBS"
AC_SUBST(GLIB_CFLAGS)
AC_SUBST(GLIB_LIBS)
-AC_SUBST(GMODULE_CFLAGS)
-AC_SUBST(GMODULE_LIBS)
-AC_SUBST(BUILD_GLIB_CFLAGS)
-AC_SUBST(BUILD_GLIB_LIBS)
# Enable support for fast thread-local storage
# Some systems have broken support, so we allow to disable it.
AC_MSG_NOTICE([Enabling mono extension module.])
fi
-AC_ARG_ENABLE(gsharing, [ --enable-gsharing Enable gsharing], enable_gsharing=$enableval, enable_gsharing=no)
-if test x$enable_gsharing = xyes; then
- AC_DEFINE(ENABLE_GSHAREDVT,1,[Gsharing])
-fi
-
-# A synonym
AC_ARG_ENABLE(gsharedvt, [ --enable-gsharedvt Enable generic valuetype sharing], enable_gsharedvt=$enableval, enable_gsharedvt=no)
if test x$enable_gsharedvt = xyes; then
AC_DEFINE(ENABLE_GSHAREDVT,1,[Gsharedvt])
dnl * back
dnl **************************************
if test "x$havekqueue" = "xyes" -a "x$ac_cv_header_sys_event_h" = "xyes"; then
- if test "x$platform_darwin" = "xno"; then
+ if test "x$host_darwin" = "xno"; then
AC_DEFINE(USE_KQUEUE_FOR_THREADPOOL, 1, [Use kqueue for the threadpool])
fi
fi
AC_CHECK_FUNCS(readv writev preadv pwritev)
AC_CHECK_FUNCS(setpgid)
AC_CHECK_FUNCS(system)
+ AC_CHECK_FUNCS(fork execve)
AC_CHECK_SIZEOF(size_t)
AC_CHECK_TYPES([blksize_t], [AC_DEFINE(HAVE_BLKSIZE_T)], ,
[#include <sys/types.h>
#endif
])
AC_CHECK_HEADERS([termios.h])
-
- dnl * This is provided in io-layer, but on windows it's only available
- dnl * on xp+
- AC_DEFINE(HAVE_GETPROCESSID, 1, [Define if GetProcessId is available])
else
dnl *********************************
dnl *** Checks for Windows compilation ***
AC_CHECK_DECLS(InterlockedAdd, [], [], [[#include <windows.h>]])
AC_CHECK_DECLS(InterlockedAdd64, [], [], [[#include <windows.h>]])
AC_CHECK_DECLS(__readfsdword, [], [], [[#include <windows.h>]])
-
- AC_MSG_CHECKING(for GetProcessId)
- AC_TRY_COMPILE([#include <windows.h>], [
- GetProcessId (0);
- ], [
- AC_MSG_RESULT(yes)
- AC_DEFINE(HAVE_GETPROCESSID)
- ], [
- AC_MSG_RESULT(no)
- ])
fi
dnl socklen_t check
sizeof_register="SIZEOF_VOID_P"
jit_wanted=true
-sgen_supported=false
boehm_supported=true
case "$host" in
mips*)
TARGET=MIPS;
arch_target=mips;
- sgen_supported=true
ACCESS_UNALIGNED="no"
AC_MSG_CHECKING(for mips n32)
# foo.c:6: warning: visibility attribute not supported in this configuration; ignored
# ld: fatal: relocation error: R_386_GOTOFF: file /var/tmp//ccxYR96k.o: symbol astruct: relocation must bind locally
have_visibility_hidden=no
- sgen_supported=true
;;
mingw*|cygwin*)
- sgen_supported=true
have_visibility_hidden=no
;;
haiku*)
LIBC=libroot.so
;;
linux*)
- sgen_supported=true
AOT_SUPPORTED="yes"
;;
darwin*)
- sgen_supported=true
AOT_SUPPORTED="yes"
;;
openbsd*|freebsd*|kfreebsd-gnu*)
- sgen_supported=true
;;
esac
;;
fi
case $host_os in
linux*)
- sgen_supported=true
AOT_SUPPORTED="yes"
;;
darwin*)
- sgen_supported=true
AOT_SUPPORTED="yes"
;;
openbsd*|freebsd*|kfreebsd-gnu*)
- sgen_supported=true
;;
mingw*)
- sgen_supported=true
;;
esac
case "$host" in
if test x"$AR" = xfalse; then
AC_MSG_ERROR([The required utility 'ar' is not found in your PATH. Usually it can be found in /usr/ccs/bin.])
fi
- sgen_supported=true
;;
*-mingw*|*-*-cygwin*)
# When this is enabled, it leads to very strange crashes at runtime (gcc-3.4.4)
arch_target=ppc;
case $host_os in
linux*|darwin*)
- sgen_supported=true
;;
esac
;;
arch_target=arm;
ACCESS_UNALIGNED="no"
CPPFLAGS="$CPPFLAGS -D__ARM_EABI__"
- sgen_supported=true
;;
arm*-linux*)
TARGET=ARM;
arch_target=arm;
ACCESS_UNALIGNED="no"
- sgen_supported=true
AOT_SUPPORTED="yes"
CPPFLAGS="$CPPFLAGS -D__ARM_EABI__"
;;
# TARGET=ARM;
# arch_target=arm;
# ACCESS_UNALIGNED="no"
-# sgen_supported=true
# AOT_SUPPORTED="no"
# ;;
aarch64-*)
# https://lkml.org/lkml/2012/7/15/133
TARGET=ARM64
arch_target=arm64
- sgen_supported=true
boehm_supported=false
;;
s390x-*-linux*)
TARGET=S390X;
arch_target=s390x;
ACCESS_UNALIGNED="yes"
- sgen_supported=true
CFLAGS="$CFLAGS -mbackchain -D__USE_STRING_INLINES"
;;
esac
AC_DEFINE(TARGET_X86, 1, [...])
AC_DEFINE(TARGET_ANDROID, 1, [...])
CPPFLAGS="$CPPFLAGS"
- sgen_supported=true
# Can't use tls, since it depends on the runtime detection of tls offsets
# in mono-compiler.h
with_tls=pthread
AC_DEFINE(TARGET_AMD64, 1, [...])
AC_DEFINE(TARGET_ANDROID, 1, [...])
CPPFLAGS="$CPPFLAGS"
- sgen_supported=true
# Can't use tls, since it depends on the runtime detection of tls offsets
# in mono-compiler.h
with_tls=pthread
AC_DEFINE(TARGET_AMD64, 1, [...])
AC_DEFINE(TARGET_PS4, 1, [...])
CPPFLAGS="$CPPFLAGS"
- sgen_supported=true
# Can't use tls, since it depends on the runtime detection of tls offsets
# in mono-compiler.h
with_tls=pthread
dnl
dnl Simple Generational checks (sgen)
dnl
-if $sgen_supported; then
- build_sgen_default=yes
-else
- build_sgen_default=no
-fi
SGEN_DEFINES=
-AC_ARG_WITH(sgen, [ --with-sgen=yes,no Extra Generational GC, default=yes],[buildsgen=$with_sgen],[buildsgen=$build_sgen_default])
+AC_ARG_WITH(sgen, [ --with-sgen=yes,no Extra Generational GC, default=yes],[buildsgen=$with_sgen],[buildsgen=yes])
if test x$buildsgen = xyes; then
- if $sgen_supported; then
- SGEN_DEFINES="-DHAVE_SGEN_GC -DHAVE_MOVING_COLLECTOR"
- gc_msg="sgen and $gc_msg"
- else
- buildsgen=no
- AC_MSG_WARN("Sgen is not supported on this platform")
- fi
+ SGEN_DEFINES="-DHAVE_SGEN_GC -DHAVE_MOVING_COLLECTOR"
+ gc_msg="sgen and $gc_msg"
fi
AC_SUBST(SGEN_DEFINES)
AM_CONDITIONAL(SUPPORT_SGEN, test x$buildsgen = xyes)
fpu=NONE
# iOS GCC always uses the 'softfp' ABI.
- if test x"$GCC" = xyes && test x$platform_darwin = xyes; then
+ if test x"$GCC" = xyes && test x$host_darwin = xyes; then
fpu=VFP
fi
fi
], [with_cooperative_gc=no])
+AC_ARG_WITH(checked_build, [ --with-checked-build=yes|no Enable checked build (expensive asserts)) (defaults to no)],[
+ if test x$with_checked_build != xno ; then
+ AC_DEFINE(CHECKED_BUILD,1,[Enable checked build.])
+ fi
+], [with_checked_build=no])
+
+
AC_CHECK_HEADER([malloc.h],
[AC_DEFINE([HAVE_USR_INCLUDE_MALLOC_H], [1],
[Define to 1 if you have /usr/include/malloc.h.])],,)
sed -e "s,-mno-cygwin,,g" libtool > libtool.new; mv libtool.new libtool; chmod 755 libtool
fi
-if test x$platform_darwin = xyes; then
+if test x$host_darwin = xyes; then
# This doesn't seem to be required and it slows down parallel builds
sed -e 's,lock_old_archive_extraction=yes,lock_old_archive_extraction=no,g' < libtool > libtool.new && mv libtool.new libtool && chmod +x libtool
fi
echo "MONO_VERSION = $myver" >> $mcs_topdir/build/config.make
- if test x$platform_darwin = xyes; then
+ if test x$host_darwin = xyes; then
echo "PLATFORM = darwin" >> $mcs_topdir/build/config.make
fi
AC_CHECK_SIZEOF(long long)
AC_CHECK_FUNCS(strlcpy stpcpy strtok_r rewinddir vasprintf)
AC_CHECK_FUNCS(getrlimit)
+AC_CHECK_FUNCS(fork execv execve)
#
# Mono currently supports 10.6, but strndup is not available prior to 10.7; avoiding
AC_CHECK_FUNCS(strndup getpwuid_r)
fi
-AM_CONDITIONAL(NEED_VASPRINTF, test x$have_vasprintf = x )
+AM_CONDITIONAL(NEED_VASPRINTF, test x$ac_cv_func_vasprintf = x )
AM_ICONV()
AC_SEARCH_LIBS(sqrtf, m)
GError **error)
{
#ifdef G_OS_WIN32
+#elif !defined (HAVE_FORK) || !defined (HAVE_EXECV)
+ fprintf (stderr, "g_spawn_command_line_sync not supported on this platform\n");
+ return FALSE;
#else
pid_t pid;
gchar **argv;
GError **error)
{
#ifdef G_OS_WIN32
+#elif !defined (HAVE_FORK) || !defined (HAVE_EXECVE)
+ fprintf (stderr, "g_spawn_async_with_pipes is not supported on this platform\n");
+ return FALSE;
#else
pid_t pid;
int info_pipe [2];
-AM_CPPFLAGS = $(GMODULE_CFLAGS)
+AM_CPPFLAGS = $(GLIB_CFLAGS)
lib_LTLIBRARIES = libikvm-native.la
libikvm_native_la_SOURCES = jni.c os.c jni.h
libikvm_native_la_LDFLAGS = -avoid-version
-libikvm_native_la_LIBADD = $(GMODULE_LIBS)
+libikvm_native_la_LIBADD = $(GLIB_LIBS)
BuildItemGroup big;
BuildItem bi = new BuildItem (this);
- bi.finalItemSpec = ((ITaskItem2)taskitem).EvaluatedIncludeEscaped;
+ bi.finalItemSpec = taskitem.ItemSpec;
foreach (DictionaryEntry de in taskitem.CloneCustomMetadata ()) {
bi.unevaluatedMetadata.Add ((string) de.Key, (string) de.Value);
for (int i = 0; i < lists.Count; i++) {
foreach (object o in lists [i]) {
if (o is string)
- expressionCollection.Add ((string) o);
+ expressionCollection.Add (MSBuildUtils.Unescape ((string) o));
else if (!allowItems && o is ItemReference)
expressionCollection.Add (((ItemReference) o).OriginalString);
else if (!allowMd && o is MetadataReference) {
// Trim and Remove empty items
List<ITaskItem> toRemove = new List<ITaskItem> ();
for (int i = 0; i < finalItems.Count; i ++) {
- string s = ((ITaskItem2)finalItems [i]).EvaluatedIncludeEscaped.Trim ();
+ string s = finalItems [i].ItemSpec.Trim ();
if (s.Length == 0)
toRemove.Add (finalItems [i]);
else
- ((ITaskItem2)finalItems [i]).EvaluatedIncludeEscaped = s;
+ finalItems [i].ItemSpec = s;
}
foreach (ITaskItem ti in toRemove)
finalItems.Remove (ti);
<Message Text='Text5' Importance='normal'/>
<Message Text='Text6' Importance='high'/>
<Message Text='Text7' />
+ <Message Text='%22abc test%22 123 %22def%22' />
<Message Text='Text8' Importance='weird_importance'/>
</Target>
</Project>
Assert.AreEqual (0, testLogger.CheckAny ("Text5", MessageImportance.Normal), "A5");
Assert.AreEqual (0, testLogger.CheckAny ("Text6", MessageImportance.High), "A6");
Assert.AreEqual (0, testLogger.CheckAny ("Text7", MessageImportance.Normal), "A7");
- Assert.AreEqual (1, testLogger.CheckAny ("Text8", MessageImportance.Normal), "A8");
+ Assert.AreEqual (0, testLogger.CheckAny ("\"abc test\" 123 \"def\"", MessageImportance.Normal), "A8");
+ Assert.AreEqual (1, testLogger.CheckAny ("Text8", MessageImportance.Normal), "A9");
}
}
}
}
[Test]
+ [Category("NotWorking")] // this fails due to an xbuild bug, it works on MS.NET
public void TestLineWithEscapedSemicolon ()
{
string[] lines = new string[] { "abc%3Btest%3B%3B", "%3Bdef" };
}
[Test]
+ [Category("NotWorking")] // this fails due to an xbuild bug, it works on MS.NET
public void TestLineWithEscapedSpace ()
{
string[] lines = new string[] { " %20%20abc%20test ", " def%20%20" };
});
}
+ [Test]
+ public void TestLineWithEscapedQuote ()
+ {
+ string[] lines = new string[] { "%22abc test%22 123 %22def%22" };
+ CreateProjectAndCheck (full_filepath, lines, false, true, delegate () {
+ CheckFileExists (full_filepath, true);
+ CheckLines (full_filepath, new string [] {"\"abc test\" 123 \"def\""});
+ });
+ }
+
[Test]
public void TestNoOverwrite ()
{
}
public override string ToString ()
{
- return ItemSpec;
+ return escapedItemSpec;
}
public string ItemSpec {
Assert.AreEqual(dr["Company.Name"], "Test CO");
i += 2;
}
- Assert.IsTrue(dr.FieldCount>0);
+ Assert.IsTrue(dr.FieldCount>0, i.ToString ());
}
- if (BCL.Tests.TestRuntime.CheckSystemVersion (8, 2))
- Assert.IsTrue (false, "Apple fixed bug 27864, this check can now be removed");
}
} catch (SqliteException ex) {
-
- if (BCL.Tests.TestRuntime.CheckSystemVersion (8, 2)) // Expected Exception on iOS 8.2+, if this does not happen anymore it means apple fixed it
+ // Expected Exception from iOS 8.2 (broken) to 9.0 (fixed)
+ if (BCL.Tests.TestRuntime.CheckSystemVersion (8,2) && !BCL.Tests.TestRuntime.CheckSystemVersion (9,0))
Assert.That (ex.Message.Contains ("no such column: com.Name"));
else
throw new AssertionException ("Unexpected Sqlite Error", ex); // This should not happen
first = false;
}
+ // Return null for empty values list
+ if (first)
+ return null;
+
return sb.ToString ();
}
using System.Threading.Tasks;
using System.Collections.Specialized;
using System.Net.Http.Headers;
+using System.Linq;
namespace System.Net.Http
{
// Add request headers
var headers = wr.Headers;
foreach (var header in request.Headers) {
- headers.AddValue (header.Key, HttpRequestHeaders.GetSingleHeaderString (header.Key, header.Value));
+ var values = header.Value;
+ if (header.Key == "Transfer-Encoding") {
+ // Chunked Transfer-Encoding is never set for HttpWebRequest. It's detected
+ // from ContentLength by HttpWebRequest
+ values = values.Where (l => l != "chunked");
+ }
+
+ var values_formated = HttpRequestHeaders.GetSingleHeaderString (header.Key, values);
+ if (values_formated == null)
+ continue;
+
+ headers.AddValue (header.Key, values_formated);
}
return wr;
}
}
+ [Test]
+ public void Send_Transfer_Encoding_Chunked ()
+ {
+ bool? failed = null;
+
+ var listener = CreateListener (l => {
+ var request = l.Request;
+
+ try {
+ Assert.AreEqual (1, request.Headers.Count, "#1");
+ failed = false;
+ } catch {
+ failed = true;
+ }
+ });
+
+ try {
+ var client = new HttpClient ();
+ client.DefaultRequestHeaders.TransferEncodingChunked = true;
+
+ client.GetAsync (LocalServer).Wait ();
+
+ Assert.AreEqual (false, failed, "#102");
+ } finally {
+ listener.Abort ();
+ listener.Close ();
+ }
+ }
+
+ [Test]
+ public void Send_Transfer_Encoding_Custom ()
+ {
+ bool? failed = null;
+
+ var listener = CreateListener (l => {
+ failed = true;
+ });
+
+ try {
+ var client = new HttpClient ();
+ client.DefaultRequestHeaders.TransferEncoding.Add (new TransferCodingHeaderValue ("chunked2"));
+
+ var request = new HttpRequestMessage (HttpMethod.Get, LocalServer);
+
+ try {
+ client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead).Wait ();
+ Assert.Fail ("#1");
+ } catch (AggregateException e) {
+ Assert.AreEqual (typeof (ProtocolViolationException), e.InnerException.GetType (), "#2");
+ }
+ Assert.IsNull (failed, "#102");
+ } finally {
+ listener.Abort ();
+ listener.Close ();
+ }
+ }
[Test]
public void Send_Complete_Content ()
};
[Test] // HttpChannel.Parse ()
- [Ignore ("Fails on MS")]
+ [Category ("NotWorking")] // Fails on MS
public void ParseURL ()
{
HttpChannel channel;
serviceHost.AddServiceEndpoint (typeof (IMetadataExchange), MetadataExchangeBindings.CreateMexHttpBinding (), "mex");
serviceHost.Open ();
+ Thread.Sleep (2000); // let WCF spin up
try {
// client
lock (this) {
idleSince = outIdleSince;
- if (removeList != null) {
+ if (removeList != null && groups != null) {
foreach (var group in removeList)
if (groups.ContainsKey (group.Name))
RemoveConnectionGroup (group);
if (setInternalLength && !no_writestream && writeBuffer != null)
request.InternalContentLength = writeBuffer.Length;
- if (!(sendChunked || request.ContentLength > -1 || no_writestream || webdav))
+ bool has_content = !no_writestream && (writeBuffer == null || request.ContentLength > -1);
+ if (!(sendChunked || has_content || no_writestream || webdav))
return false;
headersSent = true;
builder.Append (scheme);
// note: mailto and news use ':', not "://", as their delimiter
- builder.Append (Uri.GetSchemeDelimiter (scheme));
+ if (UriParser.IsKnownScheme(scheme)) {
+ builder.Append (Uri.GetSchemeDelimiter (scheme));
+ }
+ else {
+ builder.Append (host.Length > 0 ? Uri.SchemeDelimiter : ":");
+ }
if (username != String.Empty) {
builder.Append (username);
if (path != String.Empty &&
builder [builder.Length - 1] != '/' &&
- path.Length > 0 && path [0] != '/')
+ path.Length > 0 && path [0] != '/' &&
+ host.Length > 0)
builder.Append ('/');
builder.Append (path);
builder.Append (query);
p.StartInfo.RedirectStandardError = true;
var exitedCalledCounter = 0;
+ var exited = new ManualResetEventSlim ();
p.Exited += (object sender, EventArgs e) => {
exitedCalledCounter++;
Assert.IsTrue (p.HasExited);
+ exited.Set ();
};
p.EnableRaisingEvents = true;
p.BeginOutputReadLine ();
p.WaitForExit ();
+ exited.Wait (10000);
Assert.AreEqual (1, exitedCalledCounter);
Thread.Sleep (50);
Assert.AreEqual (1, exitedCalledCounter);
p.EnableRaisingEvents = true;
var exitedCalledCounter = 0;
+ var exited = new ManualResetEventSlim ();
p.Exited += (object sender, EventArgs e) => {
exitedCalledCounter++;
Assert.IsTrue (p.HasExited);
+ exited.Set ();
};
p.Start ();
p.BeginOutputReadLine ();
p.WaitForExit ();
+ exited.Wait (10000);
Assert.AreEqual (1, exitedCalledCounter);
Thread.Sleep (50);
Assert.AreEqual (1, exitedCalledCounter);
serverThread.Start ();
Thread clientThread = new Thread (() => StartClientAndAuthenticate (state, endPoint));
clientThread.Start ();
- Assert.AreEqual (server, state.ServerAuthenticated.WaitOne (TimeSpan.FromSeconds (2)),
+ Assert.AreEqual (server, state.ServerAuthenticated.WaitOne (TimeSpan.FromSeconds (5)),
"server not authenticated");
- Assert.AreEqual (client, state.ClientAuthenticated.WaitOne (TimeSpan.FromSeconds (2)),
+ Assert.AreEqual (client, state.ClientAuthenticated.WaitOne (TimeSpan.FromSeconds (5)),
"client not authenticated");
} finally {
if (state.ClientStream != null)
// this is what ASP.NET really means (the ?)
Assert.AreEqual ("http://192.168.0.21/error404.aspx?aspxerrorpath=/WebResource.axd", ub.Uri.ToString ());
}
+
+ [Test]
+ public void NoHostname ()
+ {
+ UriBuilder ub = new UriBuilder ("about", null, -1, "config");
+ Assert.AreEqual ("about:config", ub.ToString ());
+ }
}
}
{
return "Error " + hr;
}
+
+ public class SECURITY_ATTRIBUTES
+ {
+
+ }
}
}
\ No newline at end of file
return ret;
}
set {
- if(value < 0) {
- throw new ArgumentOutOfRangeException("Attempt to set the position to a negative value");
- }
-
+ if (value < 0) throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
+
Seek (value, SeekOrigin.Begin);
}
}
}
}
+ public override Module Module {
+ get {
+ return GetRuntimeModule ();
+ }
+ }
+
+ internal RuntimeType GetDeclaringTypeInternal ()
+ {
+ return (RuntimeType) DeclaringType;
+ }
+
RuntimeType ReflectedTypeInternal {
get {
return (RuntimeType) ReflectedType;
}
}
+ internal RuntimeModule GetRuntimeModule ()
+ {
+ return GetDeclaringTypeInternal ().GetRuntimeModule ();
+ }
+
#region Object Overrides
public override String ToString()
{
[MethodImplAttribute(MethodImplOptions.InternalCall)]
extern static void try_enter_with_atomic_var (object obj, int millisecondsTimeout, ref bool lockTaken);
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ extern static void enter_with_atomic_var (object obj, ref bool lockTaken);
+
public static void Enter (object obj, ref bool lockTaken)
{
- TryEnter (obj, Timeout.Infinite, ref lockTaken);
+ enter_with_atomic_var (obj, ref lockTaken);
}
public static void TryEnter (object obj, ref bool lockTaken)
+++ /dev/null
-//
-// System.Threading.ThreadPool.cs
-//
-// Author:
-// Patrik Torstensson
-// Dick Porter (dick@ximian.com)
-// Maurer Dietmar (dietmar@ximian.com)
-//
-// (C) Ximian, Inc. http://www.ximian.com
-// Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-using System.Collections;
-using System.Collections.Generic;
-using System.Globalization;
-using System.Runtime.CompilerServices;
-using System.Runtime.Remoting.Messaging;
-using System.Runtime.InteropServices;
-using System.Security;
-using System.Security.Permissions;
-
-namespace System.Threading {
-
- public static class ThreadPool {
-
- [Obsolete("This method is obsolete, use BindHandle(SafeHandle) instead")]
- public static bool BindHandle (IntPtr osHandle)
- {
- if (Microsoft.ThreadPool.UseMicrosoftThreadPool)
- return Microsoft.ThreadPool.BindHandle (osHandle);
- else
- return true;
- }
-
- public static bool BindHandle (SafeHandle osHandle)
- {
- if (Microsoft.ThreadPool.UseMicrosoftThreadPool) {
- return Microsoft.ThreadPool.BindHandle (osHandle);
- } else {
- if (osHandle == null)
- throw new ArgumentNullException ("osHandle");
-
- return true;
- }
- }
-
- public static void GetAvailableThreads (out int workerThreads, out int completionPortThreads)
- {
- if (Microsoft.ThreadPool.UseMicrosoftThreadPool)
- Microsoft.ThreadPool.GetAvailableThreads (out workerThreads, out completionPortThreads);
- else
- GetAvailableThreads_internal (out workerThreads, out completionPortThreads);
- }
-
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- static extern void GetAvailableThreads_internal (out int workerThreads, out int completionPortThreads);
-
- public static void GetMaxThreads (out int workerThreads, out int completionPortThreads)
- {
- if (Microsoft.ThreadPool.UseMicrosoftThreadPool)
- Microsoft.ThreadPool.GetMaxThreads (out workerThreads, out completionPortThreads);
- else
- GetMaxThreads_internal (out workerThreads, out completionPortThreads);
- }
-
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- static extern void GetMaxThreads_internal (out int workerThreads, out int completionPortThreads);
-
- public static void GetMinThreads (out int workerThreads, out int completionPortThreads)
- {
- if (Microsoft.ThreadPool.UseMicrosoftThreadPool)
- Microsoft.ThreadPool.GetMinThreads (out workerThreads, out completionPortThreads);
- else
- GetMinThreads_internal (out workerThreads, out completionPortThreads);
- }
-
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- static extern void GetMinThreads_internal (out int workerThreads, out int completionPortThreads);
-
- [MonoTODO("The min number of completion port threads is not evaluated.")]
- [SecurityPermission (SecurityAction.Demand, ControlThread=true)]
- public static bool SetMinThreads (int workerThreads, int completionPortThreads)
- {
- if (Microsoft.ThreadPool.UseMicrosoftThreadPool)
- return Microsoft.ThreadPool.SetMinThreads (workerThreads, completionPortThreads);
- else
- return SetMinThreads_internal (workerThreads, completionPortThreads);
- }
-
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- static extern bool SetMinThreads_internal (int workerThreads, int completionPortThreads);
-
- [SecurityPermission (SecurityAction.Demand, ControlThread=true)]
- public static bool SetMaxThreads (int workerThreads, int completionPortThreads)
- {
- if (Microsoft.ThreadPool.UseMicrosoftThreadPool)
- return Microsoft.ThreadPool.SetMaxThreads (workerThreads, completionPortThreads);
- else
- return SetMaxThreads_internal (workerThreads, completionPortThreads);
- }
-
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- static extern bool SetMaxThreads_internal (int workerThreads, int completionPortThreads);
-
- public static bool QueueUserWorkItem (WaitCallback callBack)
- {
- if (Microsoft.ThreadPool.UseMicrosoftThreadPool)
- return Microsoft.ThreadPool.QueueUserWorkItem (callBack, null);
- else
- return QueueUserWorkItem (callBack, null);
- }
-
- public static bool QueueUserWorkItem (WaitCallback callBack, object state)
- {
- if (Microsoft.ThreadPool.UseMicrosoftThreadPool) {
- return Microsoft.ThreadPool.QueueUserWorkItem (callBack, state);
- } else {
- if (callBack == null)
- throw new ArgumentNullException ("callBack");
-
- if (callBack.IsTransparentProxy ()) {
- IAsyncResult ar = callBack.BeginInvoke (state, null, null);
- if (ar == null)
- return false;
- } else {
- AsyncResult ares = new AsyncResult (callBack, state, !ExecutionContext.IsFlowSuppressed());
- pool_queue (ares);
- }
- return true;
- }
- }
-
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- static extern void pool_queue (AsyncResult ares);
-
- // TODO: It should be interface interface only to avoid extra allocation
- internal static void QueueWorkItem (WaitCallback callBack, object state)
- {
- if (Microsoft.ThreadPool.UseMicrosoftThreadPool)
- Microsoft.ThreadPool.QueueUserWorkItem (callBack, state);
- else
- pool_queue (new AsyncResult (callBack, state, false));
- }
-
- public static RegisteredWaitHandle RegisterWaitForSingleObject (WaitHandle waitObject,
- WaitOrTimerCallback callBack,
- object state,
- int millisecondsTimeOutInterval,
- bool executeOnlyOnce)
- {
- if (Microsoft.ThreadPool.UseMicrosoftThreadPool)
- return Microsoft.ThreadPool.RegisterWaitForSingleObject (waitObject, callBack, state, millisecondsTimeOutInterval, executeOnlyOnce);
- else
- return RegisterWaitForSingleObject (waitObject, callBack, state, (long) millisecondsTimeOutInterval, executeOnlyOnce);
- }
-
- public static RegisteredWaitHandle RegisterWaitForSingleObject (WaitHandle waitObject,
- WaitOrTimerCallback callBack,
- object state,
- long millisecondsTimeOutInterval,
- bool executeOnlyOnce)
- {
- if (Microsoft.ThreadPool.UseMicrosoftThreadPool) {
- return Microsoft.ThreadPool.RegisterWaitForSingleObject (waitObject, callBack, state, millisecondsTimeOutInterval, executeOnlyOnce);
- } else {
- if (waitObject == null)
- throw new ArgumentNullException ("waitObject");
-
- if (callBack == null)
- throw new ArgumentNullException ("callBack");
-
- if (millisecondsTimeOutInterval < -1)
- throw new ArgumentOutOfRangeException ("timeout", "timeout < -1");
-
- if (millisecondsTimeOutInterval > Int32.MaxValue)
- throw new NotSupportedException ("Timeout is too big. Maximum is Int32.MaxValue");
-
- TimeSpan timeout = new TimeSpan (0, 0, 0, 0, (int) millisecondsTimeOutInterval);
-
- RegisteredWaitHandle waiter = new RegisteredWaitHandle (waitObject, callBack, state,
- timeout, executeOnlyOnce);
- QueueUserWorkItem (new WaitCallback (waiter.Wait), null);
- return waiter;
- }
- }
-
- public static RegisteredWaitHandle RegisterWaitForSingleObject (WaitHandle waitObject,
- WaitOrTimerCallback callBack,
- object state,
- TimeSpan timeout,
- bool executeOnlyOnce)
- {
- if (Microsoft.ThreadPool.UseMicrosoftThreadPool)
- return Microsoft.ThreadPool.RegisterWaitForSingleObject (waitObject, callBack, state, timeout, executeOnlyOnce);
- else
- return RegisterWaitForSingleObject (waitObject, callBack, state, (long) timeout.TotalMilliseconds, executeOnlyOnce);
-
- }
-
- [CLSCompliant(false)]
- public static RegisteredWaitHandle RegisterWaitForSingleObject (WaitHandle waitObject,
- WaitOrTimerCallback callBack,
- object state,
- uint millisecondsTimeOutInterval,
- bool executeOnlyOnce)
- {
- if (Microsoft.ThreadPool.UseMicrosoftThreadPool)
- return Microsoft.ThreadPool.RegisterWaitForSingleObject (waitObject, callBack, state, millisecondsTimeOutInterval, executeOnlyOnce);
- else
- return RegisterWaitForSingleObject (waitObject, callBack, state, (long) millisecondsTimeOutInterval, executeOnlyOnce);
- }
-
- [CLSCompliant (false)]
- unsafe public static bool UnsafeQueueNativeOverlapped (NativeOverlapped *overlapped)
- {
- if (Microsoft.ThreadPool.UseMicrosoftThreadPool)
- return Microsoft.ThreadPool.UnsafeQueueNativeOverlapped (overlapped);
- else
- throw new NotImplementedException ();
- }
-
-#if !NET_2_1 || MOBILE
-
- [SecurityPermission (SecurityAction.Demand, ControlEvidence=true, ControlPolicy=true)]
- public static bool UnsafeQueueUserWorkItem (WaitCallback callBack, object state)
- {
- if (Microsoft.ThreadPool.UseMicrosoftThreadPool) {
- return Microsoft.ThreadPool.UnsafeQueueUserWorkItem (callBack, state);
- } else {
- if (callBack == null)
- throw new ArgumentNullException ("callBack");
-
- // no stack propagation here (that's why it's unsafe and requires extra security permissions)
- if (!callBack.IsTransparentProxy ()) {
- AsyncResult ares = new AsyncResult (callBack, state, false);
- pool_queue (ares);
- return true;
- }
- try {
- if (!ExecutionContext.IsFlowSuppressed ())
- ExecutionContext.SuppressFlow (); // on current thread only
- IAsyncResult ar = callBack.BeginInvoke (state, null, null);
- if (ar == null)
- return false;
- } finally {
- if (ExecutionContext.IsFlowSuppressed ())
- ExecutionContext.RestoreFlow ();
- }
- return true;
- }
- }
-
- [MonoTODO("Not implemented")]
- [SecurityPermission (SecurityAction.Demand, ControlEvidence=true, ControlPolicy=true)]
- public static RegisteredWaitHandle UnsafeRegisterWaitForSingleObject (WaitHandle waitObject,
- WaitOrTimerCallback callBack, object state, int millisecondsTimeOutInterval,
- bool executeOnlyOnce)
- {
- if (Microsoft.ThreadPool.UseMicrosoftThreadPool)
- return Microsoft.ThreadPool.UnsafeRegisterWaitForSingleObject (waitObject, callBack, state, millisecondsTimeOutInterval, executeOnlyOnce);
- else
- throw new NotImplementedException ();
- }
-
- [MonoTODO("Not implemented")]
- [SecurityPermission (SecurityAction.Demand, ControlEvidence=true, ControlPolicy=true)]
- public static RegisteredWaitHandle UnsafeRegisterWaitForSingleObject (WaitHandle waitObject,
- WaitOrTimerCallback callBack, object state, long millisecondsTimeOutInterval,
- bool executeOnlyOnce)
- {
- if (Microsoft.ThreadPool.UseMicrosoftThreadPool)
- return Microsoft.ThreadPool.UnsafeRegisterWaitForSingleObject (waitObject, callBack, state, millisecondsTimeOutInterval, executeOnlyOnce);
- else
- throw new NotImplementedException ();
- }
-
- [MonoTODO("Not implemented")]
- [SecurityPermission (SecurityAction.Demand, ControlEvidence=true, ControlPolicy=true)]
- public static RegisteredWaitHandle UnsafeRegisterWaitForSingleObject (WaitHandle waitObject,
- WaitOrTimerCallback callBack, object state, TimeSpan timeout,
- bool executeOnlyOnce)
- {
- if (Microsoft.ThreadPool.UseMicrosoftThreadPool)
- return Microsoft.ThreadPool.UnsafeRegisterWaitForSingleObject (waitObject, callBack, state, timeout, executeOnlyOnce);
- else
- throw new NotImplementedException ();
- }
-
- [MonoTODO("Not implemented")]
- [CLSCompliant (false)]
- [SecurityPermission (SecurityAction.Demand, ControlEvidence=true, ControlPolicy=true)]
- public static RegisteredWaitHandle UnsafeRegisterWaitForSingleObject (WaitHandle waitObject,
- WaitOrTimerCallback callBack, object state, uint millisecondsTimeOutInterval,
- bool executeOnlyOnce)
- {
- if (Microsoft.ThreadPool.UseMicrosoftThreadPool)
- return Microsoft.ThreadPool.UnsafeRegisterWaitForSingleObject (waitObject, callBack, state, millisecondsTimeOutInterval, executeOnlyOnce);
- else
- throw new NotImplementedException ();
- }
-
-#endif
-
-#region ReferenceSources
- // Extracted from ../../../../external/referencesource/mscorlib/system/threading/threadpool.cs
- internal static void UnsafeQueueCustomWorkItem(IThreadPoolWorkItem workItem, bool forceGlobal)
- {
- if (Microsoft.ThreadPool.UseMicrosoftThreadPool)
- Microsoft.ThreadPool.UnsafeQueueCustomWorkItem (workItem, forceGlobal);
- else
- QueueWorkItem ((obj) => ((IThreadPoolWorkItem)obj).ExecuteWorkItem (), workItem);
- }
-
- internal static IEnumerable<IThreadPoolWorkItem> GetQueuedWorkItems()
- {
- if (Microsoft.ThreadPool.UseMicrosoftThreadPool)
- return Microsoft.ThreadPool.GetQueuedWorkItems ();
- else
- return new IThreadPoolWorkItem [0];
- }
-
- internal static bool TryPopCustomWorkItem(IThreadPoolWorkItem workItem)
- {
- if (Microsoft.ThreadPool.UseMicrosoftThreadPool)
- return Microsoft.ThreadPool.TryPopCustomWorkItem (workItem);
- else
- return false;
- }
-
- internal static void NotifyWorkItemProgress()
- {
- if (Microsoft.ThreadPool.UseMicrosoftThreadPool)
- Microsoft.ThreadPool.NotifyWorkItemProgress ();
- }
-#endregion
- }
-}
}
}
+ [Test] // ctor (String)
+ public void Constructor1_Quoted ()
+ {
+ AssemblyName an;
+
+ an = new AssemblyName ("'System', Version=\"10.0.0.0\", Culture='Neutral', PublicKeyToken='b67a5c561934e089', Retargetable='Yes', ProcessorArchitecture='AMD64'");
+ Assert.AreEqual ("System, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b67a5c561934e089, Retargetable=Yes", an.ToString ());
+ Assert.AreEqual (ProcessorArchitecture.Amd64, an.ProcessorArchitecture, "Amd64");
+ }
+
+ [Test] // ctor (String)
+ public void Constructor1_Quoted_Invalid ()
+ {
+ AssemblyName an;
+
+ try {
+ an = new AssemblyName ("System, Version=\"10.0.0.0'");
+ Assert.Fail ("#1");
+ } catch (FileLoadException) {
+ }
+ }
+
[Test (Description="Xamarin bug #99 - whitespaces in key=value")]
public void WhiteSpaceInKeyValue ()
{
{
Type type = typeof (TestClass);
PropertyInfo property = type.GetProperty ("ReadOnlyProperty");
+ Assert.IsNotNull (property.Module, "#0");
MethodInfo [] methods = property.GetAccessors (true);
Assert.AreEqual (1, methods.Length, "#A1");
Assert.AreEqual (typeof (ClassWithNullableDateTime), siblingProperty.DeclaringType, "#3");
Assert.AreEqual (typeof (InheritsFromClassWithNullableDateTime), siblingProperty.ReflectedType, "#4");
}
-
-
+
+ class Super { public long A { get; private set; } }
+
+ class Sub : Super { }
+
+ [Test]
+ public void PrivateSetterFromDerivedType ()
+ {
+ var prop = typeof (Sub).GetProperty ("A");
+ Assert.AreEqual (1, prop.GetAccessors (true).Length, "#1");
+ Assert.IsFalse (prop.CanWrite, "#2");
+ Assert.IsNull (prop.GetSetMethod (true), "#3");
+ }
+
public class ClassWithNullableDateTime
{
public DateTime? Property1 { get; set; }
[Test]
public void Test_Interrupt ()
{
+ ManualResetEvent mre = new ManualResetEvent (false);
bool interruptedExceptionThrown = false;
+
ThreadPool.QueueUserWorkItem (Test_Interrupt_Worker, Thread.CurrentThread);
try {
try {
- Thread.Sleep (3000);
+ mre.WaitOne (3000);
} finally {
try {
- Thread.Sleep (0);
+ mre.WaitOne (0);
} catch (ThreadInterruptedException) {
Assert.Fail ("ThreadInterruptedException thrown twice");
}
[Category ("NotDotNet")] // it crashes nunit.
public void Test_InterruptCurrentThread ()
{
+ ManualResetEvent mre = new ManualResetEvent (false);
bool interruptedExceptionThrown = false;
Thread.CurrentThread.Interrupt ();
try {
- Thread.Sleep (0);
+ mre.WaitOne (0);
Assert.Fail ();
} catch (ThreadInterruptedException) {
}
} else {
Builder.Save (module.Builder.ScopeName, pekind, machine);
}
+ } catch (ArgumentOutOfRangeException) {
+ Report.Error (16, "Output file `{0}' exceeds the 4GB limit");
} catch (Exception e) {
- Report.Error (16, "Could not write to file `" + name + "', cause: " + e.Message);
+ Report.Error (16, "Could not write to file `{0}'. {1}", name, e.Message);
}
Compiler.TimeReporter.Stop (TimeReporter.TimerType.OutputSave);
}
foreach (var existing in das) {
- if (DefiniteAssignmentBitSet.AreEqual (existing, DefiniteAssignment))
+ if (DefiniteAssignmentBitSet.IsIncluded (existing, DefiniteAssignment))
return true;
}
public bool parsing_catch_when;
int parsing_string_interpolation;
+ int string_interpolation_section;
Stack<bool> parsing_string_interpolation_quoted;
public bool parsing_interpolation_format;
public int current_token;
public object val;
public int parsing_string_interpolation;
+ public int string_interpolation_section;
public Stack<bool> parsing_string_interpolation_quoted;
public Position (Tokenizer t)
ifstack = new Stack<int> (clone);
}
parsing_generic_less_than = t.parsing_generic_less_than;
+ string_interpolation_section = t.string_interpolation_section;
current_token = t.current_token;
val = t.val;
parsing_string_interpolation = t.parsing_string_interpolation;
+ string_interpolation_section = t.string_interpolation_section;
if (t.parsing_string_interpolation_quoted != null && t.parsing_string_interpolation_quoted.Count != 0) {
var clone = t.parsing_string_interpolation_quoted.ToArray ();
Array.Reverse (clone);
case '{':
val = ltb.Create (current_source, ref_line, col);
+
+ if (parsing_string_interpolation > 0)
+ ++string_interpolation_section;
+
return Token.OPEN_BRACE;
case '}':
if (parsing_string_interpolation > 0) {
- --parsing_string_interpolation;
- bool quoted;
- if (parsing_string_interpolation_quoted != null && parsing_string_interpolation_quoted.Count > 0) {
- quoted = parsing_string_interpolation_quoted.Pop ();
- } else {
- quoted = false;
+ if (string_interpolation_section == 0) {
+ --parsing_string_interpolation;
+ bool quoted;
+ if (parsing_string_interpolation_quoted != null && parsing_string_interpolation_quoted.Count > 0) {
+ quoted = parsing_string_interpolation_quoted.Pop ();
+ } else {
+ quoted = false;
+ }
+
+ return TokenizeInterpolatedString (quoted);
}
- return TokenizeInterpolatedString (quoted);
+ --string_interpolation_section;
}
val = ltb.Create (current_source, ref_line, col);
public static DefiniteAssignmentBitSet operator & (DefiniteAssignmentBitSet a, DefiniteAssignmentBitSet b)
{
- if (AreEqual (a, b))
+ if (IsEqual (a, b))
return a;
DefiniteAssignmentBitSet res;
public static DefiniteAssignmentBitSet operator | (DefiniteAssignmentBitSet a, DefiniteAssignmentBitSet b)
{
- if (AreEqual (a, b))
+ if (IsEqual (a, b))
return a;
DefiniteAssignmentBitSet res;
large_bits[index >> 5] |= (1 << (index & 31));
}
- public static bool AreEqual (DefiniteAssignmentBitSet a, DefiniteAssignmentBitSet b)
+ static bool IsEqual (DefiniteAssignmentBitSet a, DefiniteAssignmentBitSet b)
{
if (a.large_bits == null)
return (a.bits & ~copy_on_write_flag) == (b.bits & ~copy_on_write_flag);
return true;
}
+
+ public static bool IsIncluded (DefiniteAssignmentBitSet set, DefiniteAssignmentBitSet test)
+ {
+ var set_bits = set.large_bits;
+ if (set_bits == null)
+ return (set.bits & test.bits & ~copy_on_write_flag) == (set.bits & ~copy_on_write_flag);
+
+ var test_bits = test.large_bits;
+ for (int i = 0; i < set_bits.Length; ++i) {
+ if ((set_bits[i] & test_bits[i]) != set_bits[i])
+ return false;
+ }
+
+ return true;
+ }
}
}
//
// The return type is actually Task<T> type argument
//
- if (expr.Type == async_type) {
+ if (expr.Type == async_type && async_type.TypeArguments [0] != ec.Module.PredefinedTypes.Task.TypeSpec) {
ec.Report.Error (4016, loc,
"`{0}': The return expression type of async method must be `{1}' rather than `Task<{1}>'",
ec.GetSignatureForError (), async_type.TypeArguments[0].GetSignatureForError ());
--- /dev/null
+using System.Threading.Tasks;
+
+class X
+{
+ public async Task ReturnsTaskAsync (Task task)
+ {
+ await task;
+ }
+
+ public async Task<Task> ReturnsTaskOfTaskAsync ()
+ {
+ var t1 = Task.FromResult (ReturnsTaskAsync (null));
+ await t1;
+ Task<Task> t2 = Task.FromResult (ReturnsTaskAsync (null));
+ return t2;
+ }
+
+ public static void Main ()
+ {
+ new X ().ReturnsTaskOfTaskAsync ().Wait ();
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+
+public class Program
+{
+ public static int Main ()
+ {
+ var x = $@"({
+ new Dictionary<int, object> {
+ { 1, "bbb" }
+ }.Count
+ });";
+
+ if (x != "(1);")
+ return 1;
+
+ return 0;
+ }
+}
\ No newline at end of file
</method>
</type>
</test>
+ <test name="test-async-68.cs">
+ <type name="X">
+ <method name="System.Threading.Tasks.Task ReturnsTaskAsync(System.Threading.Tasks.Task)" attrs="134">
+ <size>41</size>
+ </method>
+ <method name="System.Threading.Tasks.Task`1[System.Threading.Tasks.Task] ReturnsTaskOfTaskAsync()" attrs="134">
+ <size>41</size>
+ </method>
+ <method name="Void Main()" attrs="150">
+ <size>17</size>
+ </method>
+ <method name="Void .ctor()" attrs="6278">
+ <size>7</size>
+ </method>
+ </type>
+ <type name="X+<ReturnsTaskAsync>c__async0">
+ <method name="Void MoveNext()" attrs="486">
+ <size>157</size>
+ </method>
+ <method name="Void SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine)" attrs="486">
+ <size>13</size>
+ </method>
+ </type>
+ <type name="X+<ReturnsTaskOfTaskAsync>c__async1">
+ <method name="Void MoveNext()" attrs="486">
+ <size>217</size>
+ </method>
+ <method name="Void SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine)" attrs="486">
+ <size>13</size>
+ </method>
+ </type>
+ </test>
<test name="test-async-69.cs">
<type name="Test">
<method name="System.Threading.Tasks.Task`1[System.Int32] YieldValue(Int32)" attrs="145">
</method>
</type>
</test>
+ <test name="test-interpolation-08.cs">
+ <type name="Program">
+ <method name="Int32 Main()" attrs="150">
+ <size>73</size>
+ </method>
+ <method name="Void .ctor()" attrs="6278">
+ <size>7</size>
+ </method>
+ </type>
+ </test>
<test name="test-iter-01.cs">
<type name="X">
<method name="Int32 Main()" attrs="150">
}
ctor_func = args [++i];
break;
+ case "--dos2unix":
+ case "--dos2unix=true":
+ use_dos2unix = true;
+ break;
+ case "--dos2unix=false":
+ use_dos2unix = false;
+ break;
default:
sources.Add (args [i]);
break;
" -L path Adds `path' to the search path for assemblies\n" +
" --nodeps Turns off automatic dependency embedding (default)\n" +
" --deps Turns on automatic dependency embedding\n" +
+ " --dos2unix[=true|false]\n" +
+ " When no value provided, or when `true` specified\n" +
+ " `dos2unix` will be invoked to convert paths on Windows.\n" +
+ " When `--dos2unix=false` used, dos2unix is NEVER used.\n" +
" --keeptemp Keeps the temporary files\n" +
" --config F Bundle system config file `F'\n" +
" --config-dir D Set MONO_CFG_DIR to `D'\n" +
return system (cmdLine);
}
-#if XAMARIN_ANDROID
// on Windows, we have to pipe the output of a
// `cmd` interpolation to dos2unix, because the shell does not
// strip the CRLFs generated by the native pkg-config distributed
}
// and if there is no dos2unix, just run cmd /c.
if (use_dos2unix == false) {
-#endif
Console.WriteLine (cmdLine);
ProcessStartInfo dos2unix = new ProcessStartInfo ();
dos2unix.UseShellExecute = false;
p.WaitForExit ();
return p.ExitCode;
}
-#if XAMARIN_ANDROID
}
-#endif
StringBuilder b = new StringBuilder ();
int count = 0;
for (int i = 0; i < cmdLine.Length; i++) {
if (cmdLine [i] == '`') {
-#if XAMARIN_ANDROID
if (count % 2 != 0) {
b.Append ("|dos2unix");
}
-#endif
count++;
}
b.Append (cmdLine [i]);
basic-tests:
for type in System.Array System.String 'System.Collections.Generic.List`1'; do \
- echo $$type; $(RUNTIME) $(build_lib) $$type >/dev/null || exit 1; done
\ No newline at end of file
+ echo $$type; MONO_PATH="$(topdir)/class/lib/$(PROFILE)$(PLATFORM_PATH_SEPARATOR)$$MONO_PATH" $(RUNTIME) $(build_lib) $$type >/dev/null || exit 1; done
+++ /dev/null
-/*
- * Create trampolines to invoke arbitrary functions.
- * Copyright (c) 2002 Sergey Chaban <serge@wildwestsoftware.com>
- *
- * Contributions by Malte Hildingson
- */
-
-#include "arm-codegen.h"
-#include "arm-dis.h"
-
-#if defined(_WIN32_WCE) || defined (UNDER_CE)
-# include <windows.h>
-#else
-#include <unistd.h>
-#include <sys/mman.h>
-#endif
-
-#if !defined(PLATFORM_MACOSX)
-#include <errno.h>
-
-#include "mono/metadata/class.h"
-#include "mono/metadata/tabledefs.h"
-#include "mono/interpreter/interp.h"
-#include "mono/metadata/appdomain.h"
-
-
-#if 0
-# define ARM_DUMP_DISASM 1
-#endif
-
-/* prototypes for private functions (to avoid compiler warnings) */
-void flush_icache (void);
-void* alloc_code_buff (int num_instr);
-
-
-
-/*
- * The resulting function takes the form:
- * void func (void (*callme)(), void *retval, void *this_obj, stackval *arguments);
- * NOTE: all args passed in ARM registers (A1-A4),
- * then copied to R4-R7 (see definitions below).
- */
-
-#define REG_FUNC_ADDR ARMREG_R4
-#define REG_RETVAL ARMREG_R5
-#define REG_THIS ARMREG_R6
-#define REG_ARGP ARMREG_R7
-
-
-#define ARG_SIZE sizeof(stackval)
-
-
-
-
-void flush_icache ()
-{
-#if defined(_WIN32)
- FlushInstructionCache(GetCurrentProcess(), NULL, 0);
-#else
-# if 0
- asm ("mov r0, r0");
- asm ("mov r0, #0");
- asm ("mcr p15, 0, r0, c7, c7, 0");
-# else
- /* TODO: use (movnv pc, rx) method */
-# endif
-#endif
-}
-
-
-void* alloc_code_buff (int num_instr)
-{
- void* code_buff;
- int code_size = num_instr * sizeof(arminstr_t);
-
-#if defined(_WIN32) || defined(UNDER_CE)
- int old_prot = 0;
-
- code_buff = malloc(code_size);
- VirtualProtect(code_buff, code_size, PAGE_EXECUTE_READWRITE, &old_prot);
-#else
- int page_size = sysconf(_SC_PAGESIZE);
- int new_code_size;
-
- new_code_size = code_size + page_size - 1;
- code_buff = malloc(new_code_size);
- code_buff = (void *) (((int) code_buff + page_size - 1) & ~(page_size - 1));
-
- if (mprotect(code_buff, code_size, PROT_READ|PROT_WRITE|PROT_EXEC) != 0) {
- g_critical (G_GNUC_PRETTY_FUNCTION
- ": mprotect error: %s", g_strerror (errno));
- }
-#endif
-
- return code_buff;
-}
-
-
-/*
- * Refer to ARM Procedure Call Standard (APCS) for more info.
- */
-MonoPIFunc mono_arch_create_trampoline (MonoMethodSignature *sig, gboolean string_ctor)
-{
- MonoType* param;
- MonoPIFunc code_buff;
- arminstr_t* p;
- guint32 code_size, stack_size;
- guint32 simple_type;
- int i, hasthis, aregs, regc, stack_offs;
- int this_loaded;
- guchar reg_alloc [ARM_NUM_ARG_REGS];
-
- /* pessimistic estimation for prologue/epilogue size */
- code_size = 16 + 16;
- /* push/pop work regs */
- code_size += 2;
- /* call */
- code_size += 2;
- /* handle retval */
- code_size += 2;
-
- stack_size = 0;
- hasthis = sig->hasthis ? 1 : 0;
-
- aregs = ARM_NUM_ARG_REGS - hasthis;
-
- for (i = 0, regc = aregs; i < sig->param_count; ++i) {
- param = sig->params [i];
-
- /* keep track of argument sizes */
- if (i < ARM_NUM_ARG_REGS) reg_alloc [i] = 0;
-
- if (param->byref) {
- if (regc > 0) {
- code_size += 1;
- reg_alloc [i] = regc;
- --regc;
- } else {
- code_size += 2;
- stack_size += sizeof(gpointer);
- }
- } else {
- simple_type = param->type;
-enum_calc_size:
- switch (simple_type) {
- case MONO_TYPE_BOOLEAN:
- case MONO_TYPE_CHAR:
- 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_I:
- case MONO_TYPE_U:
- case MONO_TYPE_PTR:
- case MONO_TYPE_R4:
- case MONO_TYPE_SZARRAY:
- case MONO_TYPE_CLASS:
- case MONO_TYPE_OBJECT:
- case MONO_TYPE_STRING:
- if (regc > 0) {
- /* register arg */
- code_size += 1;
- reg_alloc [i] = regc;
- --regc;
- } else {
- /* stack arg */
- code_size += 2;
- stack_size += 4;
- }
- break;
- case MONO_TYPE_I8:
- case MONO_TYPE_U8:
- case MONO_TYPE_R8:
- /* keep track of argument sizes */
- if (regc > 1) {
- /* fits into registers, two LDRs */
- code_size += 2;
- reg_alloc [i] = regc;
- regc -= 2;
- } else if (regc > 0) {
- /* first half fits into register, one LDR */
- code_size += 1;
- reg_alloc [i] = regc;
- --regc;
- /* the rest on the stack, LDR/STR */
- code_size += 2;
- stack_size += 4;
- } else {
- /* stack arg, 4 instrs - 2x(LDR/STR) */
- code_size += 4;
- stack_size += 2 * 4;
- }
- break;
- case MONO_TYPE_VALUETYPE:
- if (param->data.klass->enumtype) {
- simple_type = param->data.klass->enum_basetype->type;
- goto enum_calc_size;
- }
-
- if (mono_class_value_size(param->data.klass, NULL) != 4) {
- g_error("can only marshal enums, not generic structures (size: %d)", mono_class_value_size(param->data.klass, NULL));
- }
- if (regc > 0) {
- /* register arg */
- code_size += 1;
- reg_alloc [i] = regc;
- --regc;
- } else {
- /* stack arg */
- code_size += 2;
- stack_size += 4;
- }
- break;
- default :
- break;
- }
- }
- }
-
- code_buff = (MonoPIFunc)alloc_code_buff(code_size);
- p = (arminstr_t*)code_buff;
-
- /* prologue */
- p = arm_emit_lean_prologue(p, stack_size,
- /* save workset (r4-r7) */
- (1 << ARMREG_R4) | (1 << ARMREG_R5) | (1 << ARMREG_R6) | (1 << ARMREG_R7));
-
-
- /* copy args into workset */
- /* callme - always present */
- ARM_MOV_REG_REG(p, ARMREG_R4, ARMREG_A1);
- /* retval */
- if (sig->ret->byref || string_ctor || (sig->ret->type != MONO_TYPE_VOID)) {
- ARM_MOV_REG_REG(p, ARMREG_R5, ARMREG_A2);
- }
- /* this_obj */
- if (sig->hasthis) {
- this_loaded = 0;
- if (stack_size == 0) {
- ARM_MOV_REG_REG(p, ARMREG_A1, ARMREG_A3);
- this_loaded = 1;
- } else {
- ARM_MOV_REG_REG(p, ARMREG_R6, ARMREG_A3);
- }
- }
- /* args */
- if (sig->param_count != 0) {
- ARM_MOV_REG_REG(p, ARMREG_R7, ARMREG_A4);
- }
-
- stack_offs = stack_size;
-
- /* handle arguments */
- /* in reverse order so we could use r0 (arg1) for memory transfers */
- for (i = sig->param_count; --i >= 0;) {
- param = sig->params [i];
- if (param->byref) {
- if (i < aregs && reg_alloc[i] > 0) {
- ARM_LDR_IMM(p, ARMREG_A1 + i, REG_ARGP, i*ARG_SIZE);
- } else {
- stack_offs -= sizeof(armword_t);
- ARM_LDR_IMM(p, ARMREG_R0, REG_ARGP, i*ARG_SIZE);
- ARM_STR_IMM(p, ARMREG_R0, ARMREG_SP, stack_offs);
- }
- } else {
- simple_type = param->type;
-enum_marshal:
- switch (simple_type) {
- case MONO_TYPE_BOOLEAN:
- case MONO_TYPE_CHAR:
- 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_I:
- case MONO_TYPE_U:
- case MONO_TYPE_PTR:
- case MONO_TYPE_R4:
- case MONO_TYPE_SZARRAY:
- case MONO_TYPE_CLASS:
- case MONO_TYPE_OBJECT:
- case MONO_TYPE_STRING:
- if (i < aregs && reg_alloc [i] > 0) {
- /* pass in register */
- ARM_LDR_IMM(p, ARMREG_A1 + hasthis + (aregs - reg_alloc [i]), REG_ARGP, i*ARG_SIZE);
- } else {
- stack_offs -= sizeof(armword_t);
- ARM_LDR_IMM(p, ARMREG_R0, REG_ARGP, i*ARG_SIZE);
- ARM_STR_IMM(p, ARMREG_R0, ARMREG_SP, stack_offs);
- }
- break;
- case MONO_TYPE_I8:
- case MONO_TYPE_U8:
- case MONO_TYPE_R8:
- if (i < aregs && reg_alloc [i] > 0) {
- if (reg_alloc [i] > 1) {
- /* pass in registers */
- ARM_LDR_IMM(p, ARMREG_A1 + hasthis + (aregs - reg_alloc [i]), REG_ARGP, i*ARG_SIZE);
- ARM_LDR_IMM(p, ARMREG_A1 + hasthis + (aregs - reg_alloc [i]) + 1, REG_ARGP, i*ARG_SIZE + 4);
- } else {
- stack_offs -= sizeof(armword_t);
- ARM_LDR_IMM(p, ARMREG_R0, REG_ARGP, i*ARG_SIZE + 4);
- ARM_STR_IMM(p, ARMREG_R0, ARMREG_SP, stack_offs);
- ARM_LDR_IMM(p, ARMREG_A1 + hasthis + (aregs - reg_alloc [i]), REG_ARGP, i*ARG_SIZE);
- }
- } else {
- /* two words transferred on the stack */
- stack_offs -= 2*sizeof(armword_t);
- ARM_LDR_IMM(p, ARMREG_R0, REG_ARGP, i*ARG_SIZE);
- ARM_STR_IMM(p, ARMREG_R0, ARMREG_SP, stack_offs);
- ARM_LDR_IMM(p, ARMREG_R0, REG_ARGP, i*ARG_SIZE + 4);
- ARM_STR_IMM(p, ARMREG_R0, ARMREG_SP, stack_offs + 4);
- }
- break;
- case MONO_TYPE_VALUETYPE:
- if (param->data.klass->enumtype) {
- /* it's an enum value, proceed based on its base type */
- simple_type = param->data.klass->enum_basetype->type;
- goto enum_marshal;
- } else {
- if (i < aregs && reg_alloc[i] > 0) {
- int vtreg = ARMREG_A1 + hasthis +
- hasthis + (aregs - reg_alloc[i]);
- ARM_LDR_IMM(p, vtreg, REG_ARGP, i * ARG_SIZE);
- ARM_LDR_IMM(p, vtreg, vtreg, 0);
- } else {
- stack_offs -= sizeof(armword_t);
- ARM_LDR_IMM(p, ARMREG_R0, REG_ARGP, i * ARG_SIZE);
- ARM_LDR_IMM(p, ARMREG_R0, ARMREG_R0, 0);
- ARM_STR_IMM(p, ARMREG_R0, ARMREG_SP, stack_offs);
- }
- }
- break;
-
- default:
- break;
- }
- }
- }
-
- if (sig->hasthis && !this_loaded) {
- /* [this] always passed in A1, regardless of sig->call_convention */
- ARM_MOV_REG_REG(p, ARMREG_A1, REG_THIS);
- }
-
- /* call [func] */
- ARM_MOV_REG_REG(p, ARMREG_LR, ARMREG_PC);
- ARM_MOV_REG_REG(p, ARMREG_PC, REG_FUNC_ADDR);
-
- /* handle retval */
- if (sig->ret->byref || string_ctor) {
- ARM_STR_IMM(p, ARMREG_R0, REG_RETVAL, 0);
- } else {
- simple_type = sig->ret->type;
-enum_retvalue:
- switch (simple_type) {
- case MONO_TYPE_BOOLEAN:
- case MONO_TYPE_I1:
- case MONO_TYPE_U1:
- ARM_STRB_IMM(p, ARMREG_R0, REG_RETVAL, 0);
- break;
- case MONO_TYPE_CHAR:
- case MONO_TYPE_I2:
- case MONO_TYPE_U2:
- ARM_STRH_IMM(p, ARMREG_R0, REG_RETVAL, 0);
- break;
- /*
- * A 32-bit integer and integer-equivalent return value
- * is returned in R0.
- * Single-precision floating-point values are returned in R0.
- */
- case MONO_TYPE_I:
- case MONO_TYPE_U:
- case MONO_TYPE_I4:
- case MONO_TYPE_U4:
- case MONO_TYPE_R4:
- case MONO_TYPE_OBJECT:
- case MONO_TYPE_CLASS:
- case MONO_TYPE_ARRAY:
- case MONO_TYPE_SZARRAY:
- case MONO_TYPE_STRING:
- ARM_STR_IMM(p, ARMREG_R0, REG_RETVAL, 0);
- break;
- /*
- * A 64-bit integer is returned in R0 and R1.
- * Double-precision floating-point values are returned in R0 and R1.
- */
- case MONO_TYPE_I8:
- case MONO_TYPE_U8:
- case MONO_TYPE_R8:
- ARM_STR_IMM(p, ARMREG_R0, REG_RETVAL, 0);
- ARM_STR_IMM(p, ARMREG_R1, REG_RETVAL, 4);
- break;
- case MONO_TYPE_VALUETYPE:
- if (sig->ret->data.klass->enumtype) {
- simple_type = sig->ret->data.klass->enum_basetype->type;
- goto enum_retvalue;
- }
- break;
- case MONO_TYPE_VOID:
- break;
- default:
- break;
- }
- }
-
- p = arm_emit_std_epilogue(p, stack_size,
- /* restore R4-R7 */
- (1 << ARMREG_R4) | (1 << ARMREG_R5) | (1 << ARMREG_R6) | (1 << ARMREG_R7));
-
- flush_icache();
-
-#ifdef ARM_DUMP_DISASM
- _armdis_decode((arminstr_t*)code_buff, ((guint8*)p) - ((guint8*)code_buff));
-#endif
-
- return code_buff;
-}
-
-
-
-#define MINV_OFFS(member) G_STRUCT_OFFSET(MonoInvocation, member)
-
-
-
-/*
- * Returns a pointer to a native function that can be used to
- * call the specified method.
- * The function created will receive the arguments according
- * to the call convention specified in the method.
- * This function works by creating a MonoInvocation structure,
- * filling the fields in and calling ves_exec_method on it.
- * Still need to figure out how to handle the exception stuff
- * across the managed/unmanaged boundary.
- */
-void* mono_arch_create_method_pointer (MonoMethod* method)
-{
- MonoMethodSignature* sig;
- guchar* p, * p_method, * p_stackval_from_data, * p_exec;
- void* code_buff;
- int i, stack_size, arg_pos, arg_add, stackval_pos, offs;
- int areg, reg_args, shift, pos;
- MonoJitInfo *ji;
-
- code_buff = alloc_code_buff(128);
- p = (guchar*)code_buff;
-
- sig = method->signature;
-
- ARM_B(p, 3);
-
- /* embed magic number followed by method pointer */
- *p++ = 'M';
- *p++ = 'o';
- *p++ = 'n';
- *p++ = 'o';
- /* method ptr */
- *(void**)p = method;
- p_method = p;
- p += 4;
-
- /* call table */
- *(void**)p = stackval_from_data;
- p_stackval_from_data = p;
- p += 4;
- *(void**)p = ves_exec_method;
- p_exec = p;
- p += 4;
-
- stack_size = sizeof(MonoInvocation) + ARG_SIZE*(sig->param_count + 1) + ARM_NUM_ARG_REGS*2*sizeof(armword_t);
-
- /* prologue */
- p = (guchar*)arm_emit_lean_prologue((arminstr_t*)p, stack_size,
- (1 << ARMREG_R4) |
- (1 << ARMREG_R5) |
- (1 << ARMREG_R6) |
- (1 << ARMREG_R7));
-
- /* R7 - ptr to stack args */
- ARM_MOV_REG_REG(p, ARMREG_R7, ARMREG_IP);
-
- /*
- * Initialize MonoInvocation fields, first the ones known now.
- */
- ARM_MOV_REG_IMM8(p, ARMREG_R4, 0);
- ARM_STR_IMM(p, ARMREG_R4, ARMREG_SP, MINV_OFFS(ex));
- ARM_STR_IMM(p, ARMREG_R4, ARMREG_SP, MINV_OFFS(ex_handler));
- ARM_STR_IMM(p, ARMREG_R4, ARMREG_SP, MINV_OFFS(parent));
-
- /* Set the method pointer. */
- ARM_LDR_IMM(p, ARMREG_R4, ARMREG_PC, -(int)(p - p_method + sizeof(arminstr_t)*2));
- ARM_STR_IMM(p, ARMREG_R4, ARMREG_SP, MINV_OFFS(method));
-
- if (sig->hasthis) {
- /* [this] in A1 */
- ARM_STR_IMM(p, ARMREG_A1, ARMREG_SP, MINV_OFFS(obj));
- } else {
- /* else set minv.obj to NULL */
- ARM_STR_IMM(p, ARMREG_R4, ARMREG_SP, MINV_OFFS(obj));
- }
-
- /* copy args from registers to stack */
- areg = ARMREG_A1 + sig->hasthis;
- arg_pos = -(int)(ARM_NUM_ARG_REGS - sig->hasthis) * 2 * sizeof(armword_t);
- arg_add = 0;
- for (i = 0; i < sig->param_count; ++i) {
- if (areg >= ARM_NUM_ARG_REGS) break;
- ARM_STR_IMM(p, areg, ARMREG_R7, arg_pos);
- ++areg;
- if (!sig->params[i]->byref) {
- switch (sig->params[i]->type) {
- case MONO_TYPE_I8:
- case MONO_TYPE_U8:
- case MONO_TYPE_R8:
- if (areg >= ARM_NUM_ARG_REGS) {
- /* load second half of 64-bit arg */
- ARM_LDR_IMM(p, ARMREG_R4, ARMREG_R7, 0);
- ARM_STR_IMM(p, ARMREG_R4, ARMREG_R7, arg_pos + sizeof(armword_t));
- arg_add = sizeof(armword_t);
- } else {
- /* second half is already the register */
- ARM_STR_IMM(p, areg, ARMREG_R7, arg_pos + sizeof(armword_t));
- ++areg;
- }
- break;
- case MONO_TYPE_VALUETYPE:
- /* assert */
- default:
- break;
- }
- }
- arg_pos += 2 * sizeof(armword_t);
- }
- /* number of args passed in registers */
- reg_args = i;
-
-
-
- /*
- * Calc and save stack args ptr,
- * args follow MonoInvocation struct on the stack.
- */
- ARM_ADD_REG_IMM8(p, ARMREG_R1, ARMREG_SP, sizeof(MonoInvocation));
- ARM_STR_IMM(p, ARMREG_R1, ARMREG_SP, MINV_OFFS(stack_args));
-
- /* convert method args to stackvals */
- arg_pos = -(int)(ARM_NUM_ARG_REGS - sig->hasthis) * 2 * sizeof(armword_t);
- stackval_pos = sizeof(MonoInvocation);
- for (i = 0; i < sig->param_count; ++i) {
- if (i < reg_args) {
- ARM_SUB_REG_IMM8(p, ARMREG_A3, ARMREG_R7, -arg_pos);
- arg_pos += 2 * sizeof(armword_t);
- } else {
- if (arg_pos < 0) arg_pos = 0;
- pos = arg_pos + arg_add;
- if (pos <= 0xFF) {
- ARM_ADD_REG_IMM8(p, ARMREG_A3, ARMREG_R7, pos);
- } else {
- if (is_arm_const((armword_t)pos)) {
- shift = calc_arm_mov_const_shift((armword_t)pos);
- ARM_ADD_REG_IMM(p, ARMREG_A3, ARMREG_R7, pos >> ((32 - shift) & 31), shift >> 1);
- } else {
- p = (guchar*)arm_mov_reg_imm32((arminstr_t*)p, ARMREG_R6, (armword_t)pos);
- ARM_ADD_REG_REG(p, ARMREG_A2, ARMREG_R7, ARMREG_R6);
- }
- }
- arg_pos += sizeof(armword_t);
- if (!sig->params[i]->byref) {
- switch (sig->params[i]->type) {
- case MONO_TYPE_I8:
- case MONO_TYPE_U8:
- case MONO_TYPE_R8:
- arg_pos += sizeof(armword_t);
- break;
- case MONO_TYPE_VALUETYPE:
- /* assert */
- default:
- break;
- }
- }
- }
-
- /* A2 = result */
- if (stackval_pos <= 0xFF) {
- ARM_ADD_REG_IMM8(p, ARMREG_A2, ARMREG_SP, stackval_pos);
- } else {
- if (is_arm_const((armword_t)stackval_pos)) {
- shift = calc_arm_mov_const_shift((armword_t)stackval_pos);
- ARM_ADD_REG_IMM(p, ARMREG_A2, ARMREG_SP, stackval_pos >> ((32 - shift) & 31), shift >> 1);
- } else {
- p = (guchar*)arm_mov_reg_imm32((arminstr_t*)p, ARMREG_R6, (armword_t)stackval_pos);
- ARM_ADD_REG_REG(p, ARMREG_A2, ARMREG_SP, ARMREG_R6);
- }
- }
-
- /* A1 = type */
- p = (guchar*)arm_mov_reg_imm32((arminstr_t*)p, ARMREG_A1, (armword_t)sig->params [i]);
-
- stackval_pos += ARG_SIZE;
-
- offs = -(p + 2*sizeof(arminstr_t) - p_stackval_from_data);
- /* load function address */
- ARM_LDR_IMM(p, ARMREG_R4, ARMREG_PC, offs);
- /* call stackval_from_data */
- ARM_MOV_REG_REG(p, ARMREG_LR, ARMREG_PC);
- ARM_MOV_REG_REG(p, ARMREG_PC, ARMREG_R4);
- }
-
- /* store retval ptr */
- p = (guchar*)arm_mov_reg_imm32((arminstr_t*)p, ARMREG_R5, (armword_t)stackval_pos);
- ARM_ADD_REG_REG(p, ARMREG_R5, ARMREG_SP, ARMREG_R4);
- ARM_STR_IMM(p, ARMREG_R5, ARMREG_SP, MINV_OFFS(retval));
-
- /*
- * Call the method.
- */
- /* A1 = MonoInvocation ptr */
- ARM_MOV_REG_REG(p, ARMREG_A1, ARMREG_SP);
- offs = -(p + 2*sizeof(arminstr_t) - p_exec);
- /* load function address */
- ARM_LDR_IMM(p, ARMREG_R4, ARMREG_PC, offs);
- /* call ves_exec */
- ARM_MOV_REG_REG(p, ARMREG_LR, ARMREG_PC);
- ARM_MOV_REG_REG(p, ARMREG_PC, ARMREG_R4);
-
-
- /*
- * Move retval into reg.
- */
- if (sig->ret->byref) {
- ARM_LDR_IMM(p, ARMREG_R0, ARMREG_R5, 0);
- } else {
- switch (sig->ret->type) {
- case MONO_TYPE_BOOLEAN:
- case MONO_TYPE_I1:
- case MONO_TYPE_U1:
- ARM_LDRB_IMM(p, ARMREG_R0, ARMREG_R5, 0);
- break;
- case MONO_TYPE_CHAR:
- case MONO_TYPE_I2:
- case MONO_TYPE_U2:
- ARM_LDRH_IMM(p, ARMREG_R0, ARMREG_R5, 0);
- break;
- case MONO_TYPE_I:
- case MONO_TYPE_U:
- case MONO_TYPE_I4:
- case MONO_TYPE_U4:
- case MONO_TYPE_R4:
- case MONO_TYPE_OBJECT:
- case MONO_TYPE_CLASS:
- case MONO_TYPE_ARRAY:
- case MONO_TYPE_SZARRAY:
- ARM_LDR_IMM(p, ARMREG_R0, ARMREG_R5, 0);
- break;
- case MONO_TYPE_I8:
- case MONO_TYPE_U8:
- case MONO_TYPE_R8:
- ARM_LDR_IMM(p, ARMREG_R0, ARMREG_R5, 0);
- ARM_LDR_IMM(p, ARMREG_R1, ARMREG_R5, 4);
- break;
- case MONO_TYPE_VOID:
- default:
- break;
- }
- }
-
-
- p = (guchar*)arm_emit_std_epilogue((arminstr_t*)p, stack_size,
- (1 << ARMREG_R4) |
- (1 << ARMREG_R5) |
- (1 << ARMREG_R6) |
- (1 << ARMREG_R7));
-
- flush_icache();
-
-#ifdef ARM_DUMP_DISASM
- _armdis_decode((arminstr_t*)code_buff, ((guint8*)p) - ((guint8*)code_buff));
-#endif
-
- ji = g_new0(MonoJitInfo, 1);
- ji->method = method;
- ji->code_size = ((guint8 *) p) - ((guint8 *) code_buff);
- ji->code_start = (gpointer) code_buff;
-
- mono_jit_info_table_add(mono_get_root_domain (), ji);
-
- return code_buff;
-}
-
-
-/*
- * mono_create_method_pointer () will insert a pointer to the MonoMethod
- * so that the interp can easily get at the data: this function will retrieve
- * the method from the code stream.
- */
-MonoMethod* mono_method_pointer_get (void* code)
-{
- unsigned char* c = code;
- /* check out magic number that follows unconditional branch */
- if (c[4] == 'M' &&
- c[5] == 'o' &&
- c[6] == 'n' &&
- c[7] == 'o') return ((MonoMethod**)code)[2];
- return NULL;
-}
-#endif
guint32 *lowest);
extern void _wapi_handle_unlock_handles (guint32 numhandles,
gpointer *handles);
-extern int _wapi_handle_wait_signal (gboolean poll);
-extern int _wapi_handle_timedwait_signal (struct timespec *timeout, gboolean poll);
-extern int _wapi_handle_wait_signal_handle (gpointer handle, gboolean alertable);
-extern int _wapi_handle_timedwait_signal_handle (gpointer handle,
- struct timespec *timeout, gboolean alertable, gboolean poll);
+extern int _wapi_handle_timedwait_signal (struct timespec *timeout, gboolean poll, gboolean *alerted);
+extern int _wapi_handle_timedwait_signal_handle (gpointer handle, struct timespec *timeout, gboolean alertable, gboolean poll, gboolean *alerted);
extern gboolean _wapi_handle_get_or_set_share (guint64 device, guint64 inode,
guint32 new_sharemode,
guint32 new_access,
#include <mono/utils/mono-mutex.h>
#include <mono/utils/mono-proclib.h>
+#include <mono/utils/mono-threads.h>
#undef DEBUG_REFS
#if 0
return(ret);
}
-int _wapi_handle_wait_signal (gboolean poll)
+int
+_wapi_handle_timedwait_signal (struct timespec *timeout, gboolean poll, gboolean *alerted)
{
- return _wapi_handle_timedwait_signal_handle (_wapi_global_signal_handle, NULL, TRUE, poll);
+ return _wapi_handle_timedwait_signal_handle (_wapi_global_signal_handle, timeout, TRUE, poll, alerted);
}
-int _wapi_handle_timedwait_signal (struct timespec *timeout, gboolean poll)
+static void
+signal_handle_and_unref (gpointer handle)
{
- return _wapi_handle_timedwait_signal_handle (_wapi_global_signal_handle, timeout, TRUE, poll);
-}
+ pthread_cond_t *cond;
+ mono_mutex_t *mutex;
+ guint32 idx;
-int _wapi_handle_wait_signal_handle (gpointer handle, gboolean alertable)
-{
- DEBUG ("%s: waiting for %p", __func__, handle);
-
- return _wapi_handle_timedwait_signal_handle (handle, NULL, alertable, FALSE);
+ g_assert (handle);
+
+ /* If we reach here, then interrupt token is set to the flag value, which
+ * means that the target thread is either
+ * - before the first CAS in timedwait, which means it won't enter the wait.
+ * - it is after the first CAS, so it is already waiting, or it will enter
+ * the wait, and it will be interrupted by the broadcast. */
+ idx = GPOINTER_TO_UINT (handle);
+ cond = &_WAPI_PRIVATE_HANDLES (idx).signal_cond;
+ mutex = &_WAPI_PRIVATE_HANDLES (idx).signal_mutex;
+
+ mono_mutex_lock (mutex);
+ mono_cond_broadcast (cond);
+ mono_mutex_unlock (mutex);
+
+ _wapi_handle_unref (handle);
}
-int _wapi_handle_timedwait_signal_handle (gpointer handle,
- struct timespec *timeout, gboolean alertable, gboolean poll)
+int
+_wapi_handle_timedwait_signal_handle (gpointer handle, struct timespec *timeout,
+ gboolean alertable, gboolean poll, gboolean *alerted)
{
DEBUG ("%s: waiting for %p (type %s)", __func__, handle,
_wapi_handle_typename[_wapi_handle_type (handle)]);
-
+
+ if (alertable)
+ g_assert (alerted);
+
+ if (alerted)
+ *alerted = FALSE;
+
if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
if (WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) {
return (0);
pthread_cond_t *cond;
mono_mutex_t *mutex;
- if (alertable && !wapi_thread_set_wait_handle (handle))
- return 0;
+ if (alertable) {
+ mono_thread_info_install_interrupt (signal_handle_and_unref, handle, alerted);
+ if (*alerted)
+ return 0;
+ _wapi_handle_ref (handle);
+ }
cond = &_WAPI_PRIVATE_HANDLES (idx).signal_cond;
mutex = &_WAPI_PRIVATE_HANDLES (idx).signal_mutex;
res = mono_cond_wait (cond, mutex);
}
- if (alertable)
- wapi_thread_clear_wait_handle (handle);
+ if (alertable) {
+ mono_thread_info_uninstall_interrupt (alerted);
+ if (!*alerted) {
+ /* if it is alerted, then the handle is unref in the interrupt callback */
+ _wapi_handle_unref (handle);
+ }
+ }
return res;
}
WapiStartupInfo *startup,
WapiProcessInformation *process_info)
{
+#if defined (HAVE_FORK) && defined (HAVE_EXECVE)
char *cmd = NULL, *prog = NULL, *full_prog = NULL, *args = NULL, *args_after_prog = NULL;
char *dir = NULL, **env_strings = NULL, **argv = NULL;
guint32 i, env_count = 0;
mono_processes_cleanup ();
return ret;
+#else
+ SetLastError (ERROR_NOT_SUPPORTED);
+ return FALSE;
+#endif // defined (HAVE_FORK) && defined (HAVE_EXECVE)
}
static void
extern struct _WapiHandleOps _wapi_thread_ops;
-#define INTERRUPTION_REQUESTED_HANDLE (gpointer)0xFFFFFFFE
-
struct _WapiHandle_thread
{
pthread_t id;
GPtrArray *owned_mutexes;
- /*
- * Handle this thread waits on. If this is INTERRUPTION_REQUESTED_HANDLE,
- * it means the thread is interrupted by another thread, and shouldn't enter
- * a wait.
- * This also acts as a reference for the handle.
- */
- gpointer wait_handle;
};
typedef struct _WapiHandle_thread WapiHandle_thread;
-extern gboolean _wapi_thread_apc_pending (gpointer handle);
extern gboolean _wapi_thread_cur_apc_pending (void);
extern void _wapi_thread_own_mutex (gpointer mutex);
extern void _wapi_thread_disown_mutex (gpointer mutex);
extern void Sleep(guint32 ms);
extern guint32 SleepEx(guint32 ms, gboolean alertable);
-void wapi_clear_interruption (void);
-gboolean wapi_thread_set_wait_handle (gpointer handle);
-void wapi_thread_clear_wait_handle (gpointer handle);
-void wapi_self_interrupt (void);
-
-gpointer wapi_prepare_interrupt_thread (gpointer thread_handle);
-void wapi_finish_interrupt_thread (gpointer wait_handle);
-
gpointer wapi_create_thread_handle (void);
void wapi_thread_handle_set_exited (gpointer handle, guint32 exitstatus);
void wapi_ref_thread_handle (gpointer handle);
ret = _wapi_handle_ops_special_wait (handle, timeout, alertable);
- if (alertable && _wapi_thread_apc_pending (current_thread)) {
- apc_pending = TRUE;
+ if (alertable && _wapi_thread_cur_apc_pending ())
ret = WAIT_IO_COMPLETION;
- }
- goto check_pending;
+ return ret;
}
goto done;
}
}
-
- if (alertable && _wapi_thread_apc_pending (current_thread)) {
- apc_pending = TRUE;
- ret = WAIT_IO_COMPLETION;
- goto done;
- }
-
+
if (own_if_signalled (handle) == TRUE) {
DEBUG ("%s: handle %p already signalled", __func__,
handle);
ret = WAIT_OBJECT_0;
goto done;
}
-
- if (timeout == INFINITE) {
- waited = _wapi_handle_wait_signal_handle (handle, alertable);
- } else {
- waited = _wapi_handle_timedwait_signal_handle (handle, &abstime, alertable, FALSE);
- }
-
- if (alertable)
- apc_pending = _wapi_thread_apc_pending (current_thread);
+
+ waited = _wapi_handle_timedwait_signal_handle (handle, timeout == INFINITE ? NULL : &abstime, alertable, FALSE, &apc_pending);
if(waited==0 && !apc_pending) {
/* Condition was signalled, so hopefully
DEBUG ("%s: wait on handle %p error: %s", __func__, handle,
strerror (waited));
- ret = WAIT_TIMEOUT;
-
+ ret = apc_pending ? WAIT_IO_COMPLETION : WAIT_TIMEOUT;
+
done:
DEBUG ("%s: unlocking handle %p", __func__, handle);
thr_ret = _wapi_handle_unlock_handle (handle);
g_assert (thr_ret == 0);
-
-check_pending:
- if (apc_pending)
- ret = WAIT_IO_COMPLETION;
-
+
return(ret);
}
goto done;
}
}
-
- if (alertable && _wapi_thread_apc_pending (current_thread)) {
- apc_pending = TRUE;
- ret = WAIT_IO_COMPLETION;
- goto done;
- }
-
+
if (own_if_signalled (wait)) {
DEBUG ("%s: handle %p already signalled", __func__, wait);
ret = WAIT_OBJECT_0;
goto done;
}
-
- if (timeout == INFINITE) {
- waited = _wapi_handle_wait_signal_handle (wait, alertable);
- } else {
- waited = _wapi_handle_timedwait_signal_handle (wait, &abstime, alertable, FALSE);
- }
- if (alertable) {
- apc_pending = _wapi_thread_apc_pending (current_thread);
- }
+ waited = _wapi_handle_timedwait_signal_handle (wait, timeout == INFINITE ? NULL : &abstime, alertable, FALSE, &apc_pending);
if (waited==0 && !apc_pending) {
/* Condition was signalled, so hopefully
DEBUG ("%s: wait on handle %p error: %s", __func__, wait,
strerror (ret));
- ret = WAIT_TIMEOUT;
-
+ ret = apc_pending ? WAIT_IO_COMPLETION : WAIT_TIMEOUT;
+
done:
DEBUG ("%s: unlocking handle %p", __func__, wait);
thr_ret = _wapi_handle_unlock_handle (wait);
g_assert (thr_ret == 0);
- if (apc_pending)
- ret = WAIT_IO_COMPLETION;
-
return(ret);
}
guint32 retval;
gboolean poll;
gpointer sorted_handles [MAXIMUM_WAIT_OBJECTS];
+ gboolean apc_pending = FALSE;
if (current_thread == NULL) {
SetLastError (ERROR_INVALID_HANDLE);
_wapi_calc_timeout (&abstime, timeout);
}
- if (alertable && _wapi_thread_apc_pending (current_thread))
- return WAIT_IO_COMPLETION;
-
for (i = 0; i < numobjects; i++) {
/* Add a reference, as we need to ensure the handle wont
* disappear from under us while we're waiting in the loop
if (!done) {
/* Enter the wait */
- if (timeout == INFINITE) {
- ret = _wapi_handle_wait_signal (poll);
- } else {
- ret = _wapi_handle_timedwait_signal (&abstime, poll);
- }
+ ret = _wapi_handle_timedwait_signal (timeout == INFINITE ? NULL : &abstime, poll, &apc_pending);
} else {
/* No need to wait */
ret = 0;
thr_ret = _wapi_handle_unlock_signal_mutex (NULL);
g_assert (thr_ret == 0);
- if (alertable && _wapi_thread_apc_pending (current_thread)) {
+ if (alertable && apc_pending) {
retval = WAIT_IO_COMPLETION;
break;
}
if (alertable) {
current_thread = get_current_thread_handle ();
- if (_wapi_thread_apc_pending (current_thread))
+ if (_wapi_thread_cur_apc_pending ())
return WAIT_IO_COMPLETION;
}
while (TRUE) {
ret = clock_nanosleep (CLOCK_MONOTONIC, TIMER_ABSTIME, &target, NULL);
- if (alertable && _wapi_thread_apc_pending (current_thread))
+ if (alertable && _wapi_thread_cur_apc_pending ())
return WAIT_IO_COMPLETION;
if (ret == 0)
memset (&rem, 0, sizeof (rem));
ret=nanosleep(&req, &rem);
- if (alertable && _wapi_thread_apc_pending (current_thread))
+ if (alertable && _wapi_thread_cur_apc_pending ())
return WAIT_IO_COMPLETION;
if(ret==-1) {
gboolean
_wapi_thread_cur_apc_pending (void)
{
- return _wapi_thread_apc_pending (get_current_thread_handle ());
-}
-
-gboolean
-_wapi_thread_apc_pending (gpointer handle)
-{
- WapiHandle_thread *thread;
-
- thread = lookup_thread (handle);
-
- return thread->wait_handle == INTERRUPTION_REQUESTED_HANDLE;
-}
-
-/*
- * wapi_interrupt_thread:
- *
- * The state of the thread handle HANDLE is set to 'interrupted' which means that
- * if the thread calls one of the WaitFor functions, the function will return with
- * WAIT_IO_COMPLETION instead of waiting. Also, if the thread was waiting when
- * this function was called, the wait will be broken.
- * It is possible that the wait functions return WAIT_IO_COMPLETION, but the
- * target thread didn't receive the interrupt signal yet, in this case it should
- * call the wait function again. This essentially means that the target thread will
- * busy wait until it is ready to process the interruption.
- */
-gpointer
-wapi_prepare_interrupt_thread (gpointer thread_handle)
-{
- WapiHandle_thread *thread;
- gpointer prev_handle, wait_handle;
-
- thread = lookup_thread (thread_handle); /* FIXME this is wrong, move this whole thing to MonoThreads where it can be done lockfree */
-
- while (TRUE) {
- wait_handle = thread->wait_handle;
-
- /*
- * Atomically obtain the handle the thread is waiting on, and
- * change it to a flag value.
- */
- prev_handle = InterlockedCompareExchangePointer (&thread->wait_handle,
- INTERRUPTION_REQUESTED_HANDLE, wait_handle);
- if (prev_handle == INTERRUPTION_REQUESTED_HANDLE)
- /* Already interrupted */
- return 0;
- if (prev_handle == wait_handle)
- break;
-
- /* Try again */
- }
-
- WAIT_DEBUG (printf ("%p: state -> INTERRUPTED.\n", thread->id););
-
- return wait_handle;
-}
-
-void
-wapi_finish_interrupt_thread (gpointer wait_handle)
-{
- pthread_cond_t *cond;
- mono_mutex_t *mutex;
- guint32 idx;
-
- if (!wait_handle)
- /* Not waiting */
- return;
-
- /* If we reach here, then wait_handle is set to the flag value,
- * which means that the target thread is either
- * - before the first CAS in timedwait, which means it won't enter the
- * wait.
- * - it is after the first CAS, so it is already waiting, or it will
- * enter the wait, and it will be interrupted by the broadcast.
- */
- idx = GPOINTER_TO_UINT(wait_handle);
- cond = &_WAPI_PRIVATE_HANDLES(idx).signal_cond;
- mutex = &_WAPI_PRIVATE_HANDLES(idx).signal_mutex;
-
- mono_mutex_lock (mutex);
- mono_cond_broadcast (cond);
- mono_mutex_unlock (mutex);
-
- /* ref added by set_wait_handle */
- _wapi_handle_unref (wait_handle);
-}
-
-/*
- * wapi_self_interrupt:
- *
- * This is not part of the WIN32 API.
- * Set the 'interrupted' state of the calling thread if it's NULL.
- */
-void
-wapi_self_interrupt (void)
-{
- gpointer wait_handle;
-
- wait_handle = wapi_prepare_interrupt_thread (get_current_thread_handle ());
- if (wait_handle)
- /* ref added by set_wait_handle */
- _wapi_handle_unref (wait_handle);
-}
-
-/*
- * wapi_clear_interruption:
- *
- * This is not part of the WIN32 API.
- * Clear the 'interrupted' state of the calling thread.
- * This function is signal safe
- */
-void
-wapi_clear_interruption (void)
-{
- WapiHandle_thread *thread;
- gpointer prev_handle;
-
- thread = get_current_thread ();
-
- prev_handle = InterlockedCompareExchangePointer (&thread->wait_handle,
- NULL, INTERRUPTION_REQUESTED_HANDLE);
- if (prev_handle == INTERRUPTION_REQUESTED_HANDLE)
- WAIT_DEBUG (printf ("%p: state -> NORMAL.\n", GetCurrentThreadId ()););
-}
-
-/**
- * wapi_thread_set_wait_handle:
- *
- * Set the wait handle for the current thread to HANDLE. Return TRUE on success, FALSE
- * if the thread is in interrupted state, and cannot start waiting.
- */
-gboolean
-wapi_thread_set_wait_handle (gpointer handle)
-{
- WapiHandle_thread *thread;
- gpointer prev_handle;
-
- thread = get_current_thread ();
-
- prev_handle = InterlockedCompareExchangePointer (&thread->wait_handle,
- handle, NULL);
- if (prev_handle == NULL) {
- /* thread->wait_handle acts as an additional reference to the handle */
- _wapi_handle_ref (handle);
-
- WAIT_DEBUG (printf ("%p: state -> WAITING.\n", GetCurrentThreadId ()););
- } else {
- g_assert (prev_handle == INTERRUPTION_REQUESTED_HANDLE);
- WAIT_DEBUG (printf ("%p: unable to set state to WAITING.\n", GetCurrentThreadId ()););
- }
-
- return prev_handle == NULL;
-}
-
-/**
- * wapi_thread_clear_wait_handle:
- *
- * Clear the wait handle of the current thread.
- */
-void
-wapi_thread_clear_wait_handle (gpointer handle)
-{
- WapiHandle_thread *thread;
- gpointer prev_handle;
-
- thread = get_current_thread ();
-
- prev_handle = InterlockedCompareExchangePointer (&thread->wait_handle,
- NULL, handle);
- if (prev_handle == handle) {
- _wapi_handle_unref (handle);
- WAIT_DEBUG (printf ("%p: state -> NORMAL.\n", GetCurrentThreadId ()););
- } else {
- /*It can be NULL if it was asynchronously cleared*/
- g_assert (prev_handle == INTERRUPTION_REQUESTED_HANDLE || prev_handle == NULL);
- WAIT_DEBUG (printf ("%p: finished waiting.\n", GetCurrentThreadId ()););
- }
+ return mono_thread_info_is_interrupt_state (mono_thread_info_current ());
}
void
WapiHandle_thread *thread;
gpointer thread_handle;
int i;
- gpointer handle;
GString* text;
char *res;
thread_handle = get_current_thread_handle ();
thread = lookup_thread (thread_handle);
- handle = thread->wait_handle;
text = g_string_new (0);
g_string_append_printf (text, "thread handle %p state : ", thread_handle);
- if (!handle)
- g_string_append_printf (text, "not waiting");
- else if (handle == INTERRUPTION_REQUESTED_HANDLE)
- g_string_append_printf (text, "interrupted state");
- else
- g_string_append_printf (text, "waiting on %p : %s ", handle, _wapi_handle_typename[_wapi_handle_type (handle)]);
+ mono_thread_info_describe_interrupt_token (mono_thread_info_current (), text);
+
g_string_append_printf (text, " owns (");
- for (i = 0; i < thread->owned_mutexes->len; i++) {
- gpointer mutex = g_ptr_array_index (thread->owned_mutexes, i);
- if (i > 0)
- g_string_append_printf (text, ", %p", mutex);
- else
- g_string_append_printf (text, "%p", mutex);
- }
+ for (i = 0; i < thread->owned_mutexes->len; i++)
+ g_string_append_printf (text, i > 0 ? ", %p" : "%p", g_ptr_array_index (thread->owned_mutexes, i));
g_string_append_printf (text, ")");
res = text->str;
sgen-os-posix.c \
sgen-os-mach.c \
sgen-os-win32.c \
+ sgen-os-coop.c \
sgen-bridge.c \
sgen-bridge.h \
sgen-bridge-internal.h \
{
guint32 result;
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
result = WaitForSingleObjectEx (handle, timeout, alertable);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
return result;
}
{"I18N.Other", 0},
{"I18N.Rare", 0},
{"I18N.West", 0},
+ {"Microsoft.Build.Engine", 2},
+ {"Microsoft.Build.Framework", 2},
{"Microsoft.VisualBasic", 1},
{"Microsoft.VisualC", 1},
{"Mono.Cairo", 0},
#endif
+static char* unquote (const char *str);
+
/* This protects loaded_assemblies and image->references */
#define mono_assemblies_lock() mono_mutex_lock (&assemblies_mutex)
#define mono_assemblies_unlock() mono_mutex_unlock (&assemblies_mutex)
mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
{
gchar *dllname;
+ gchar *dllname_uq;
gchar *version = NULL;
+ gchar *version_uq;
gchar *culture = NULL;
+ gchar *culture_uq;
gchar *token = NULL;
+ gchar *token_uq;
gchar *key = NULL;
+ gchar *key_uq;
gchar *retargetable = NULL;
+ gchar *retargetable_uq;
+ gchar *procarch;
+ gchar *procarch_uq;
gboolean res;
gchar *value, *part_name;
guint32 part_name_len;
if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
retargetable = value;
- if (strlen (retargetable) == 0) {
- goto cleanup_and_fail;
- }
+ retargetable_uq = unquote (retargetable);
+ if (retargetable_uq != NULL)
+ retargetable = retargetable_uq;
+
if (!g_ascii_strcasecmp (retargetable, "yes")) {
flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
} else if (g_ascii_strcasecmp (retargetable, "no")) {
+ free (retargetable_uq);
goto cleanup_and_fail;
}
+
+ free (retargetable_uq);
tmp++;
continue;
}
if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
- if (!g_ascii_strcasecmp (value, "MSIL"))
+ procarch = value;
+ procarch_uq = unquote (procarch);
+ if (procarch_uq != NULL)
+ procarch = procarch_uq;
+
+ if (!g_ascii_strcasecmp (procarch, "MSIL"))
arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
- else if (!g_ascii_strcasecmp (value, "X86"))
+ else if (!g_ascii_strcasecmp (procarch, "X86"))
arch = MONO_PROCESSOR_ARCHITECTURE_X86;
- else if (!g_ascii_strcasecmp (value, "IA64"))
+ else if (!g_ascii_strcasecmp (procarch, "IA64"))
arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
- else if (!g_ascii_strcasecmp (value, "AMD64"))
+ else if (!g_ascii_strcasecmp (procarch, "AMD64"))
arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
- else
+ else {
+ free (procarch_uq);
goto cleanup_and_fail;
+ }
+
+ free (procarch_uq);
tmp++;
continue;
}
goto cleanup_and_fail;
}
- res = build_assembly_name (dllname, version, culture, token, key, flags, arch,
- aname, save_public_key);
+ dllname_uq = unquote (dllname);
+ version_uq = unquote (version);
+ culture_uq = unquote (culture);
+ token_uq = unquote (token);
+ key_uq = unquote (key);
+
+ res = build_assembly_name (
+ dllname_uq == NULL ? dllname : dllname_uq,
+ version_uq == NULL ? version : version_uq,
+ culture_uq == NULL ? culture : culture_uq,
+ token_uq == NULL ? token : token_uq,
+ key_uq == NULL ? key : key_uq,
+ flags, arch, aname, save_public_key);
+
+ free (dllname_uq);
+ free (version_uq);
+ free (culture_uq);
+ free (token_uq);
+ free (key_uq);
+
g_strfreev (parts);
return res;
return FALSE;
}
+static char*
+unquote (const char *str)
+{
+ gint slen;
+ const char *end;
+
+ if (str == NULL)
+ return NULL;
+
+ slen = strlen (str);
+ if (slen < 2)
+ return NULL;
+
+ if (*str != '\'' && *str != '\"')
+ return NULL;
+
+ end = str + slen - 1;
+ if (*str != *end)
+ return NULL;
+
+ return g_strndup (str + 1, slen - 2);
+}
+
/**
* mono_assembly_name_parse:
* @name: name to parse
}
static MonoClass *
-mono_class_from_name_checked_aux (MonoImage *image, const char* name_space, const char *name, MonoError *error, MonoGHashTable* visited_images)
+mono_class_from_name_checked_aux (MonoImage *image, const char* name_space, const char *name, MonoError *error, GHashTable* visited_images)
{
GHashTable *nspace_table;
MonoImage *loaded_image;
mono_error_init (error);
// Checking visited images avoids stack overflows when cyclic references exist.
- if (mono_g_hash_table_lookup (visited_images, image))
+ if (g_hash_table_lookup (visited_images, image))
return NULL;
- mono_g_hash_table_insert (visited_images, image, GUINT_TO_POINTER(1));
+ g_hash_table_insert (visited_images, image, GUINT_TO_POINTER(1));
if ((nested = strchr (name, '/'))) {
int pos = nested - name;
mono_class_from_name_checked (MonoImage *image, const char* name_space, const char *name, MonoError *error)
{
MonoClass *klass;
- MonoGHashTable *visited_images;
+ GHashTable *visited_images;
- visited_images = mono_g_hash_table_new (g_direct_hash, g_direct_equal);
+ visited_images = g_hash_table_new (g_direct_hash, g_direct_equal);
klass = mono_class_from_name_checked_aux (image, name_space, name, error, visited_images);
- mono_g_hash_table_destroy (visited_images);
+ g_hash_table_destroy (visited_images);
return klass;
}
g_assert (method);
- if (method->is_inflated) {
- MonoMethodInflated *imethod = (MonoMethodInflated *)method;
- cache = mono_marshal_get_cache (&imethod->owner->wrapper_caches.cominterop_wrapper_cache, mono_aligned_addr_hash, NULL);
- } else
- cache = mono_marshal_get_cache (&method->klass->image->wrapper_caches.cominterop_wrapper_cache, mono_aligned_addr_hash, NULL);
+ cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_wrapper_cache, mono_aligned_addr_hash, NULL);
if ((res = mono_marshal_find_in_cache (cache, method)))
return res;
int i;
GHashTable* cache;
- if (method->is_inflated) {
- MonoMethodInflated *imethod = (MonoMethodInflated *)method;
- cache = mono_marshal_get_cache (&imethod->owner->wrapper_caches.cominterop_invoke_cache, mono_aligned_addr_hash, NULL);
- } else
- cache = mono_marshal_get_cache (&method->klass->image->wrapper_caches.cominterop_invoke_cache, mono_aligned_addr_hash, NULL);
+ cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_invoke_cache, mono_aligned_addr_hash, NULL);
g_assert (method);
MonoAssembly *ass = NULL;
MonoImageOpenStatus status = MONO_IMAGE_OK;
const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1];
- int n;
+ int n, dummy;
#ifdef DEBUG_DOMAIN_UNLOAD
debug_domain_unload = TRUE;
mono_counters_register ("Total code space allocated", MONO_COUNTER_INT|MONO_COUNTER_JIT, &total_domain_code_alloc);
mono_gc_base_init ();
+ mono_thread_info_attach (&dummy);
MONO_FAST_TLS_INIT (tls_appdomain);
mono_native_tls_alloc (&appdomain_thread_id, NULL);
void
mono_domain_lock (MonoDomain *domain)
{
- MONO_TRY_BLOCKING
+ MONO_TRY_BLOCKING;
mono_locks_acquire (&(domain)->lock, DomainLock);
- MONO_FINISH_TRY_BLOCKING
+ MONO_FINISH_TRY_BLOCKING;
}
void
ves_icall_System_IO_MonoIO_CreateDirectory (MonoString *path, gint32 *error)
{
gboolean ret;
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
*error=ERROR_SUCCESS;
*error=GetLastError ();
}
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
return(ret);
}
ves_icall_System_IO_MonoIO_RemoveDirectory (MonoString *path, gint32 *error)
{
gboolean ret;
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
*error=ERROR_SUCCESS;
*error=GetLastError ();
}
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
return(ret);
}
*error = ERROR_SUCCESS;
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
names = get_filesystem_entries (path, path_with_pattern, attrs, mask, error);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
if (!names) {
// If there's no array and no error, then return an empty array.
IncrementalFind *ifh = handle;
gint32 error;
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
if (FindClose (ifh->find_handle) == FALSE){
error = GetLastError ();
} else
error = ERROR_SUCCESS;
g_free (ifh->utf8_path);
g_free (ifh);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
return error;
}
gint32 *error)
{
gboolean ret;
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
*error=ERROR_SUCCESS;
*error=GetLastError ();
}
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
return(ret);
}
gboolean ret;
gunichar2 *utf16_sourceFileName = NULL, *utf16_destinationFileName = NULL, *utf16_destinationBackupFileName = NULL;
guint32 replaceFlags = REPLACEFILE_WRITE_THROUGH;
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
if (sourceFileName)
utf16_sourceFileName = mono_string_chars (sourceFileName);
if (ret == FALSE)
*error = GetLastError ();
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
return ret;
}
MonoBoolean overwrite, gint32 *error)
{
gboolean ret;
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
*error=ERROR_SUCCESS;
*error=GetLastError ();
}
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
return(ret);
}
ves_icall_System_IO_MonoIO_DeleteFile (MonoString *path, gint32 *error)
{
gboolean ret;
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
*error=ERROR_SUCCESS;
*error=GetLastError ();
}
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
return(ret);
}
ves_icall_System_IO_MonoIO_GetFileAttributes (MonoString *path, gint32 *error)
{
gint32 ret;
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
*error=ERROR_SUCCESS;
*error=GetLastError ();
}
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
return(ret);
}
gint32 *error)
{
gboolean ret;
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
*error=ERROR_SUCCESS;
*error=GetLastError ();
}
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
return(ret);
}
ves_icall_System_IO_MonoIO_GetFileType (HANDLE handle, gint32 *error)
{
gboolean ret;
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
*error=ERROR_SUCCESS;
*error=GetLastError ();
}
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
return(ret);
}
{
gboolean result;
WIN32_FILE_ATTRIBUTE_DATA data;
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
*error=ERROR_SUCCESS;
memset (stat, 0, sizeof (MonoIOStat));
}
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
return result;
}
HANDLE ret;
int attributes, attrs;
gunichar2 *chars;
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
chars = mono_string_chars (filename);
*error=ERROR_SUCCESS;
*error=GetLastError ();
}
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
return(ret);
}
ves_icall_System_IO_MonoIO_Close (HANDLE handle, gint32 *error)
{
gboolean ret;
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
*error=ERROR_SUCCESS;
*error=GetLastError ();
}
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
return(ret);
}
buffer = mono_array_addr (dest, guchar, dest_offset);
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
result = ReadFile (handle, buffer, count, &n, NULL);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
if (!result) {
*error=GetLastError ();
}
buffer = mono_array_addr (src, guchar, src_offset);
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
result = WriteFile (handle, buffer, count, &n, NULL);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
if (!result) {
*error=GetLastError ();
gint32 *error)
{
gint32 offset_hi;
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
*error=ERROR_SUCCESS;
*error=GetLastError ();
}
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
return offset | ((gint64)offset_hi << 32);
}
ves_icall_System_IO_MonoIO_Flush (HANDLE handle, gint32 *error)
{
gboolean ret;
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
*error=ERROR_SUCCESS;
*error=GetLastError ();
}
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
return(ret);
}
{
gint64 length;
guint32 length_hi;
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
*error=ERROR_SUCCESS;
*error=GetLastError ();
}
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
return length | ((gint64)length_hi << 32);
}
const FILETIME *creation_filetime;
const FILETIME *last_access_filetime;
const FILETIME *last_write_filetime;
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
*error=ERROR_SUCCESS;
*error=GetLastError ();
}
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
return(ret);
}
attr.bInheritHandle=TRUE;
attr.lpSecurityDescriptor=NULL;
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
ret=CreatePipe (read_handle, write_handle, &attr, 0);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
if(ret==FALSE) {
/* FIXME: throw an exception? */
/* This is only used on Windows */
gboolean ret;
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
ret=DuplicateHandle (source_process_handle, source_handle, target_process_handle, target_handle, access, inherit, options);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
if(ret==FALSE) {
/* FIXME: throw an exception? */
gunichar2 *name;
int ret;
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
name=g_new0 (gunichar2, 256);
ret=GetTempPath (256, name);
name=g_new0 (gunichar2, ret+2); /* include the terminator */
ret=GetTempPath (ret, name);
}
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
if(ret>0) {
#ifdef DEBUG
gint64 length, gint32 *error)
{
gboolean ret;
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
*error=ERROR_SUCCESS;
*error = GetLastError ();
}
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
}
void ves_icall_System_IO_MonoIO_Unlock (HANDLE handle, gint64 position,
gint64 length, gint32 *error)
{
gboolean ret;
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
*error=ERROR_SUCCESS;
*error = GetLastError ();
}
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
}
//Support for io-layer free mmap'd files.
gint64 res;
char *path = mono_string_to_utf8 (string);
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
if (stat (path, &buf) == -1)
res = -1;
else
g_free (path);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
return res;
}
struct stat buf;
int res;
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
res = fstat (fd, &buf);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
if (res == -1)
return (gint64)-1;
return inotify_rm_watch (fd, watch_descriptor);
}
#endif
-
GCStats gc_stats = {};
#else
GCStats gc_stats;
-#endif
\ No newline at end of file
+#endif
{
guint32 result;
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
result = WaitForSingleObjectEx (handle, timeout, alertable);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
return result;
}
g_assert (mono_domain_get () == mono_get_root_domain ());
mono_gc_set_skip_thread (TRUE);
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
if (wait) {
/* An alertable wait is required so this thread can be suspended on windows */
#endif
}
wait = TRUE;
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
mono_gc_set_skip_thread (FALSE);
mono_threads_perform_thread_dump ();
ICALL(MONIT_5, "Monitor_test_synchronised", ves_icall_System_Threading_Monitor_Monitor_test_synchronised)
ICALL(MONIT_6, "Monitor_try_enter", ves_icall_System_Threading_Monitor_Monitor_try_enter)
ICALL(MONIT_7, "Monitor_wait", ves_icall_System_Threading_Monitor_Monitor_wait)
+ICALL(MONIT_10, "enter_with_atomic_var", mono_monitor_enter_v4)
ICALL(MONIT_9, "try_enter_with_atomic_var", ves_icall_System_Threading_Monitor_Monitor_try_enter_with_atomic_var)
ICALL_TYPE(MUTEX, "System.Threading.Mutex", MUTEX_1)
} PInfo;
ICALL_EXPORT void
-ves_icall_get_property_info (MonoReflectionProperty *property, MonoPropertyInfo *info, PInfo req_info)
+ves_icall_get_property_info (const MonoReflectionProperty *property, MonoPropertyInfo *info, PInfo req_info)
{
MonoDomain *domain = mono_object_domain (property);
+ const MonoProperty *pproperty = property->property;
if ((req_info & PInfo_ReflectedType) != 0)
MONO_STRUCT_SETREF (info, parent, mono_type_get_object (domain, &property->klass->byval_arg));
if ((req_info & PInfo_DeclaringType) != 0)
- MONO_STRUCT_SETREF (info, declaring_type, mono_type_get_object (domain, &property->property->parent->byval_arg));
+ MONO_STRUCT_SETREF (info, declaring_type, mono_type_get_object (domain, &pproperty->parent->byval_arg));
if ((req_info & PInfo_Name) != 0)
- MONO_STRUCT_SETREF (info, name, mono_string_new (domain, property->property->name));
+ MONO_STRUCT_SETREF (info, name, mono_string_new (domain, pproperty->name));
if ((req_info & PInfo_Attributes) != 0)
- info->attrs = property->property->attrs;
+ info->attrs = pproperty->attrs;
if ((req_info & PInfo_GetMethod) != 0)
- MONO_STRUCT_SETREF (info, get, property->property->get ?
- mono_method_get_object (domain, property->property->get, property->klass): NULL);
-
+ MONO_STRUCT_SETREF (info, get, pproperty->get &&
+ (((pproperty->get->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) != METHOD_ATTRIBUTE_PRIVATE) || pproperty->get->klass == property->klass) ?
+ mono_method_get_object (domain, pproperty->get, property->klass): NULL);
if ((req_info & PInfo_SetMethod) != 0)
- MONO_STRUCT_SETREF (info, set, property->property->set ?
- mono_method_get_object (domain, property->property->set, property->klass): NULL);
+ MONO_STRUCT_SETREF (info, set, pproperty->set &&
+ (((pproperty->set->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) != METHOD_ATTRIBUTE_PRIVATE) || pproperty->set->klass == property->klass) ?
+ mono_method_get_object (domain, pproperty->set, property->klass): NULL);
/*
* There may be other methods defined for properties, though, it seems they are not exposed
* in the reflection API
{
guint8 *src_buf, *dest_buf;
+ if (count < 0) {
+ mono_set_pending_exception (mono_get_exception_argument ("count", "is negative"));
+ return FALSE;
+ }
+
+ g_assert (count >= 0);
+
/* This is called directly from the class libraries without going through the managed wrapper */
MONO_CHECK_ARG_NULL (src, FALSE);
MONO_CHECK_ARG_NULL (dest, FALSE);
g_hash_table_destroy (hash);
}
+void
+mono_wrapper_caches_free (MonoWrapperCaches *cache)
+{
+ free_hash (cache->delegate_invoke_cache);
+ free_hash (cache->delegate_begin_invoke_cache);
+ free_hash (cache->delegate_end_invoke_cache);
+ free_hash (cache->runtime_invoke_cache);
+ free_hash (cache->runtime_invoke_vtype_cache);
+
+ free_hash (cache->delegate_abstract_invoke_cache);
+
+ free_hash (cache->runtime_invoke_direct_cache);
+ free_hash (cache->managed_wrapper_cache);
+
+ free_hash (cache->native_wrapper_cache);
+ free_hash (cache->native_wrapper_aot_cache);
+ free_hash (cache->native_wrapper_check_cache);
+ free_hash (cache->native_wrapper_aot_check_cache);
+
+ free_hash (cache->native_func_wrapper_aot_cache);
+ free_hash (cache->remoting_invoke_cache);
+ free_hash (cache->synchronized_cache);
+ free_hash (cache->unbox_wrapper_cache);
+ free_hash (cache->cominterop_invoke_cache);
+ free_hash (cache->cominterop_wrapper_cache);
+ free_hash (cache->thunk_invoke_cache);
+}
+
/*
* Returns whether mono_image_close_finish() must be called as well.
* We must unload images in two steps because clearing the domain in
free_hash (image->native_func_wrapper_cache);
free_hash (image->typespec_cache);
- free_hash (image->wrapper_caches.native_wrapper_cache);
- free_hash (image->wrapper_caches.native_wrapper_aot_cache);
- free_hash (image->wrapper_caches.native_wrapper_check_cache);
- free_hash (image->wrapper_caches.native_wrapper_aot_check_cache);
- free_hash (image->wrapper_caches.managed_wrapper_cache);
- free_hash (image->wrapper_caches.delegate_begin_invoke_cache);
- free_hash (image->wrapper_caches.delegate_end_invoke_cache);
- free_hash (image->wrapper_caches.delegate_invoke_cache);
- free_hash (image->wrapper_caches.delegate_abstract_invoke_cache);
- free_hash (image->wrapper_caches.remoting_invoke_cache);
- free_hash (image->wrapper_caches.runtime_invoke_cache);
- free_hash (image->wrapper_caches.runtime_invoke_vtype_cache);
- free_hash (image->wrapper_caches.runtime_invoke_direct_cache);
- free_hash (image->wrapper_caches.synchronized_cache);
- free_hash (image->wrapper_caches.unbox_wrapper_cache);
- free_hash (image->wrapper_caches.cominterop_invoke_cache);
- free_hash (image->wrapper_caches.cominterop_wrapper_cache);
- free_hash (image->wrapper_caches.thunk_invoke_cache);
+ mono_wrapper_caches_free (&image->wrapper_caches);
for (i = 0; i < image->gshared_types_len; ++i)
free_hash (image->gshared_types [i]);
switch (frame->type) {
case FRAME_TYPE_DEBUGGER_INVOKE:
case FRAME_TYPE_MANAGED_TO_NATIVE:
+ case FRAME_TYPE_TRAMPOLINE:
return FALSE;
case FRAME_TYPE_MANAGED:
g_assert (frame->ji);
- return d->func (mono_jit_info_get_method (frame->ji), frame->native_offset, frame->il_offset, frame->managed, d->user_data);
+ return d->func (frame->actual_method, frame->native_offset, frame->il_offset, frame->managed, d->user_data);
break;
default:
g_assert_not_reached ();
switch (frame->type) {
case FRAME_TYPE_DEBUGGER_INVOKE:
case FRAME_TYPE_MANAGED_TO_NATIVE:
+ case FRAME_TYPE_TRAMPOLINE:
return FALSE;
case FRAME_TYPE_MANAGED:
if (!frame->ji)
return FALSE;
- if (frame->ji->async)
+ if (frame->ji->async) {
return d->func (NULL, frame->domain, frame->ji->code_start, frame->native_offset, d->user_data);
- else
+ } else {
return d->func (frame->actual_method, frame->domain, frame->ji->code_start, frame->native_offset, d->user_data);
+ }
break;
default:
g_assert_not_reached ();
void
mono_loader_lock (void)
{
- MONO_TRY_BLOCKING
+ MONO_TRY_BLOCKING;
mono_locks_acquire (&loader_mutex, LoaderLock);
- MONO_FINISH_TRY_BLOCKING
+ MONO_FINISH_TRY_BLOCKING;
if (G_UNLIKELY (loader_lock_track_ownership)) {
mono_native_tls_set_value (loader_lock_nest_id, GUINT_TO_POINTER (GPOINTER_TO_UINT (mono_native_tls_get_value (loader_lock_nest_id)) + 1));
} else if (callvirt) {
GHashTable **cache_ptr;
- if (method->is_inflated) {
- MonoMethodInflated *imethod = (MonoMethodInflated *)method;
- cache_ptr = &imethod->owner->wrapper_caches.delegate_abstract_invoke_cache;
- } else
- cache_ptr = &method->klass->image->wrapper_caches.delegate_abstract_invoke_cache;
+ cache_ptr = &mono_method_get_wrapper_cache (method)->delegate_abstract_invoke_cache;
/* We need to cache the signature+method pair */
mono_marshal_lock ();
*/
if (virtual)
cache = get_cache (&method->klass->image->runtime_invoke_vcall_cache, mono_aligned_addr_hash, NULL);
- else if (method->is_inflated) {
- MonoMethodInflated *imethod = (MonoMethodInflated *)method;
- cache = get_cache (&imethod->owner->wrapper_caches.runtime_invoke_direct_cache, mono_aligned_addr_hash, NULL);
- } else
- cache = get_cache (&method->klass->image->wrapper_caches.runtime_invoke_direct_cache, mono_aligned_addr_hash, NULL);
+ else
+ cache = get_cache (&mono_method_get_wrapper_cache (method)->runtime_invoke_direct_cache, mono_aligned_addr_hash, NULL);
+
res = mono_marshal_find_in_cache (cache, method);
if (res)
return res;
callsig = mono_marshal_get_runtime_invoke_sig (callsig);
GHashTable **cache_table = NULL;
-
- if (method->is_inflated) {
- MonoMethodInflated *imethod = (MonoMethodInflated *)method;
- if (method->klass->valuetype && mono_method_signature (method)->hasthis)
- cache_table = &imethod->owner->wrapper_caches.runtime_invoke_vtype_cache;
- else
- cache_table = &imethod->owner->wrapper_caches.runtime_invoke_cache;
- } else {
- if (method->klass->valuetype && mono_method_signature (method)->hasthis)
- cache_table = &target_klass->image->wrapper_caches.runtime_invoke_vtype_cache;
- else
- cache_table = &target_klass->image->wrapper_caches.runtime_invoke_cache;
- }
+ if (method->klass->valuetype && mono_method_signature (method)->hasthis)
+ cache_table = &mono_method_get_wrapper_cache (method)->runtime_invoke_vtype_cache;
+ else
+ cache_table = &mono_method_get_wrapper_cache (method)->runtime_invoke_cache;
cache = get_cache (cache_table, (GHashFunc)mono_signature_hash,
(GCompareFunc)runtime_invoke_signature_equal);
res = newm;
g_hash_table_insert (cache, callsig, res);
/* Can't insert it into wrapper_hash since the key is a signature */
-
- if (method->is_inflated)
- direct_cache = ((MonoMethodInflated*)method)->owner->wrapper_caches.runtime_invoke_direct_cache;
- else
- direct_cache = method->klass->image->wrapper_caches.runtime_invoke_direct_cache;
+ direct_cache = mono_method_get_wrapper_cache (method)->runtime_invoke_direct_cache;
g_hash_table_insert (direct_cache, method, res);
} else {
GHashTable **cache_ptr;
- if (method->is_inflated) {
- MonoMethodInflated *imethod = (MonoMethodInflated *)method;
- if (aot) {
- if (check_exceptions)
- cache_ptr = &imethod->owner->wrapper_caches.native_wrapper_aot_check_cache;
- else
- cache_ptr = &imethod->owner->wrapper_caches.native_wrapper_aot_cache;
- } else {
- if (check_exceptions)
- cache_ptr = &imethod->owner->wrapper_caches.native_wrapper_check_cache;
- else
- cache_ptr = &imethod->owner->wrapper_caches.native_wrapper_cache;
- }
+ if (aot) {
+ if (check_exceptions)
+ cache_ptr = &mono_method_get_wrapper_cache (method)->native_wrapper_aot_check_cache;
+ else
+ cache_ptr = &mono_method_get_wrapper_cache (method)->native_wrapper_aot_cache;
} else {
- if (aot) {
- if (check_exceptions)
- cache_ptr = &method->klass->image->wrapper_caches.native_wrapper_aot_check_cache;
- else
- cache_ptr = &method->klass->image->wrapper_caches.native_wrapper_aot_cache;
- } else {
- if (check_exceptions)
- cache_ptr = &method->klass->image->wrapper_caches.native_wrapper_check_cache;
- else
- cache_ptr = &method->klass->image->wrapper_caches.native_wrapper_cache;
- }
+ if (check_exceptions)
+ cache_ptr = &mono_method_get_wrapper_cache (method)->native_wrapper_check_cache;
+ else
+ cache_ptr = &mono_method_get_wrapper_cache (method)->native_wrapper_cache;
}
cache = get_cache (cache_ptr, mono_aligned_addr_hash, NULL);
/*
* The wrapper is associated with the delegate type, to pick up the marshalling info etc.
*/
- if (invoke->is_inflated) {
- MonoMethodInflated *imethod = (MonoMethodInflated *)invoke;
- cache = get_cache (&imethod->owner->wrapper_caches.native_func_wrapper_aot_cache, mono_aligned_addr_hash, NULL);
- } else
- cache = get_cache (&image->wrapper_caches.native_func_wrapper_aot_cache, mono_aligned_addr_hash, NULL);
+ cache = get_cache (&mono_method_get_wrapper_cache (invoke)->native_func_wrapper_aot_cache, mono_aligned_addr_hash, NULL);
if ((res = mono_marshal_find_in_cache (cache, invoke)))
return res;
* could be called with different delegates, thus different marshalling
* options.
*/
- if (method->is_inflated) {
- MonoMethodInflated *imethod = (MonoMethodInflated *)method;
- cache = get_cache (&imethod->owner->wrapper_caches.managed_wrapper_cache, mono_aligned_addr_hash, NULL);
- } else
- cache = get_cache (&method->klass->image->wrapper_caches.managed_wrapper_cache, mono_aligned_addr_hash, NULL);
+ cache = get_cache (&mono_method_get_wrapper_cache (method)->managed_wrapper_cache, mono_aligned_addr_hash, NULL);
if (!target_handle && (res = mono_marshal_find_in_cache (cache, method)))
return res;
MonoMethodBuilder *mb;
MonoMethod *res;
GHashTable *cache;
- int i, pos, this_local, ret_local = 0;
+ int i, pos, pos2, this_local, taken_local, ret_local = 0;
MonoGenericContext *ctx = NULL;
MonoMethod *orig_method = NULL;
MonoGenericContainer *container = NULL;
mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_SYNCHRONIZED);
#ifndef DISABLE_JIT
+ mb->skip_visibility = 1;
/* result */
if (!MONO_TYPE_IS_VOID (sig->ret))
ret_local = mono_mb_add_local (mb, sig->ret);
#ifndef DISABLE_JIT
/* this */
this_local = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
+ taken_local = mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
clause = mono_image_alloc0 (method->klass->image, sizeof (MonoExceptionClause));
clause->flags = MONO_EXCEPTION_CLAUSE_FINALLY;
if (!enter_method) {
MonoMethodDesc *desc;
- desc = mono_method_desc_new ("Monitor:Enter", FALSE);
+ desc = mono_method_desc_new ("Monitor:enter_with_atomic_var(object,bool&)", FALSE);
enter_method = mono_method_desc_search_in_class (desc, mono_defaults.monitor_class);
g_assert (enter_method);
mono_method_desc_free (desc);
/* Call Monitor::Enter() */
mono_mb_emit_ldloc (mb, this_local);
+ mono_mb_emit_ldloc_addr (mb, taken_local);
mono_mb_emit_managed_call (mb, enter_method, NULL);
clause->try_offset = mono_mb_get_label (mb);
clause->try_len = mono_mb_get_pos (mb) - clause->try_offset;
clause->handler_offset = mono_mb_get_label (mb);
- /* Call Monitor::Exit() */
+ /* Call Monitor::Exit() if needed */
+ mono_mb_emit_ldloc (mb, taken_local);
+ pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
mono_mb_emit_ldloc (mb, this_local);
mono_mb_emit_managed_call (mb, exit_method, NULL);
+ mono_mb_patch_branch (mb, pos2);
mono_mb_emit_byte (mb, CEE_ENDFINALLY);
clause->handler_len = mono_mb_get_pos (mb) - clause->handler_offset;
MonoMethod *res;
GHashTable *cache;
- if (method->is_inflated) {
- MonoMethodInflated *imethod = (MonoMethodInflated *)method;
- cache = get_cache (&imethod->owner->wrapper_caches.unbox_wrapper_cache, mono_aligned_addr_hash, NULL);
- } else
- cache = get_cache (&method->klass->image->wrapper_caches.unbox_wrapper_cache, mono_aligned_addr_hash, NULL);
+ cache = get_cache (&mono_method_get_wrapper_cache (method)->unbox_wrapper_cache, mono_aligned_addr_hash, NULL);
if ((res = mono_marshal_find_in_cache (cache, method)))
return res;
klass = method->klass;
image = method->klass->image;
- if (method->is_inflated) {
- MonoMethodInflated *imethod = (MonoMethodInflated *)method;
- cache = get_cache (&imethod->owner->wrapper_caches.thunk_invoke_cache, mono_aligned_addr_hash, NULL);
- } else
- cache = get_cache (&image->wrapper_caches.thunk_invoke_cache, mono_aligned_addr_hash, NULL);
+ cache = get_cache (&mono_method_get_wrapper_cache (method)->thunk_invoke_cache, mono_aligned_addr_hash, NULL);
+
if ((res = mono_marshal_find_in_cache (cache, method)))
return res;
if (marshal_mutex_initialized)
mono_marshal_unlock ();
}
-
-static gboolean
-signature_pointer_pair_matches_signature (gpointer key, gpointer value, gpointer user_data)
-{
- SignaturePointerPair *pair = (SignaturePointerPair*)key;
- MonoMethodSignature *sig = (MonoMethodSignature*)user_data;
-
- return mono_metadata_signature_equal (pair->sig, sig);
-}
guint32
mono_metadata_localscope_from_methoddef (MonoImage *meta, guint32 index);
+void
+mono_wrapper_caches_free (MonoWrapperCaches *cache);
+
+MonoWrapperCaches*
+mono_method_get_wrapper_cache (MonoMethod *method);
+
+MonoWrapperCaches*
+mono_method_get_wrapper_cache (MonoMethod *method);
+
#endif /* __MONO_METADATA_INTERNALS_H__ */
MonoMethodSignature *ret;
sigsize = sig_header_size = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *) + padding;
if (sig->ret)
- sigsize += sizeof (MonoType);
+ sigsize += MONO_SIZEOF_TYPE;
if (image) {
ret = mono_image_alloc (image, sigsize);
// Danger! Do not alter padding use without changing the dup_add_this below
intptr_t end_of_header = (intptr_t)( (char*)(ret) + sig_header_size);
ret->ret = (MonoType *)end_of_header;
- *ret->ret = *sig->ret;
+ memcpy (ret->ret, sig->ret, MONO_SIZEOF_TYPE);
}
return ret;
g_hash_table_destroy (set->gmethod_cache);
g_hash_table_destroy (set->gsignature_cache);
- if (set->wrapper_caches.delegate_abstract_invoke_cache)
- g_hash_table_destroy (set->wrapper_caches.delegate_abstract_invoke_cache);
- if (set->wrapper_caches.runtime_invoke_direct_cache)
- g_hash_table_destroy (set->wrapper_caches.runtime_invoke_direct_cache);
- if (set->wrapper_caches.managed_wrapper_cache)
- g_hash_table_destroy (set->wrapper_caches.managed_wrapper_cache);
- if (set->wrapper_caches.native_wrapper_cache)
- g_hash_table_destroy (set->wrapper_caches.native_wrapper_cache);
- if (set->wrapper_caches.native_wrapper_aot_cache)
- g_hash_table_destroy (set->wrapper_caches.native_wrapper_aot_cache);
- if (set->wrapper_caches.native_wrapper_check_cache)
- g_hash_table_destroy (set->wrapper_caches.native_wrapper_check_cache);
- if (set->wrapper_caches.native_wrapper_aot_check_cache)
- g_hash_table_destroy (set->wrapper_caches.native_wrapper_aot_check_cache);
- if (set->wrapper_caches.native_func_wrapper_aot_cache)
- g_hash_table_destroy (set->wrapper_caches.native_func_wrapper_aot_cache);
- if (set->wrapper_caches.remoting_invoke_cache)
- g_hash_table_destroy (set->wrapper_caches.remoting_invoke_cache);
- if (set->wrapper_caches.unbox_wrapper_cache)
- g_hash_table_destroy (set->wrapper_caches.unbox_wrapper_cache);
- if (set->wrapper_caches.cominterop_invoke_cache)
- g_hash_table_destroy (set->wrapper_caches.cominterop_invoke_cache);
- if (set->wrapper_caches.cominterop_wrapper_cache)
- g_hash_table_destroy (set->wrapper_caches.cominterop_wrapper_cache);
- if (set->wrapper_caches.thunk_invoke_cache)
- g_hash_table_destroy (set->wrapper_caches.thunk_invoke_cache);
- if (set->wrapper_caches.runtime_invoke_cache)
- g_hash_table_destroy (set->wrapper_caches.runtime_invoke_cache);
- if (set->wrapper_caches.delegate_invoke_cache)
- g_hash_table_destroy (set->wrapper_caches.delegate_invoke_cache);
- if (set->wrapper_caches.delegate_begin_invoke_cache)
- g_hash_table_destroy (set->wrapper_caches.delegate_begin_invoke_cache);
- if (set->wrapper_caches.delegate_end_invoke_cache)
- g_hash_table_destroy (set->wrapper_caches.delegate_end_invoke_cache);
- if (set->wrapper_caches.synchronized_cache)
- g_hash_table_destroy (set->wrapper_caches.synchronized_cache);
+ mono_wrapper_caches_free (&set->wrapper_caches);
image_sets_lock ();
return gtd->ext->properties + offset;
}
+MonoWrapperCaches*
+mono_method_get_wrapper_cache (MonoMethod *method)
+{
+ if (method->is_inflated) {
+ MonoMethodInflated *imethod = (MonoMethodInflated *)method;
+ return &imethod->owner->wrapper_caches;
+ } else {
+ return &method->klass->image->wrapper_caches;
+ }
+}
*
* Bacon's thin locks have a fast path that doesn't need a lock record
* for the common case of locking an unlocked or shallow-nested
- * object, but the technique relies on encoding the thread ID in 15
- * bits (to avoid too much per-object space overhead.) Unfortunately
- * I don't think it's possible to reliably encode a pthread_t into 15
- * bits. (The JVM implementation used seems to have a 15-bit
- * per-thread identifier available.)
- *
- * This implementation then combines Dice's basic lock model with
- * Bacon's simplification of keeping a lock record for the lifetime of
- * an object.
+ * object.
*/
static MonitorArray *monitor_allocated;
static int array_size = 16;
+/* MonoThreadsSync status helpers */
+
static inline guint32
mon_status_get_owner (guint32 status)
{
return status & ENTRY_COUNT_WAITERS;
}
+/* LockWord helpers */
+
+static inline MonoThreadsSync*
+lock_word_get_inflated_lock (LockWord lw)
+{
+ lw.lock_word &= (~LOCK_WORD_STATUS_MASK);
+ return lw.sync;
+}
+
+static inline gboolean
+lock_word_is_inflated (LockWord lw)
+{
+ return lw.lock_word & LOCK_WORD_INFLATED;
+}
+
+static inline gboolean
+lock_word_has_hash (LockWord lw)
+{
+ return lw.lock_word & LOCK_WORD_HAS_HASH;
+}
+
+static inline LockWord
+lock_word_set_has_hash (LockWord lw)
+{
+ LockWord nlw;
+ nlw.lock_word = lw.lock_word | LOCK_WORD_HAS_HASH;
+ return nlw;
+}
+
+static inline gboolean
+lock_word_is_free (LockWord lw)
+{
+ return !lw.lock_word;
+}
+
+static inline gboolean
+lock_word_is_flat (LockWord lw)
+{
+ /* Return whether the lock is flat or free */
+ return (lw.lock_word & LOCK_WORD_STATUS_MASK) == LOCK_WORD_FLAT;
+}
+
+static inline gint32
+lock_word_get_hash (LockWord lw)
+{
+ return (gint32) (lw.lock_word >> LOCK_WORD_HASH_SHIFT);
+}
+
+static inline gint32
+lock_word_get_nest (LockWord lw)
+{
+ if (lock_word_is_free (lw))
+ return 0;
+ /* Inword nest count starts from 0 */
+ return ((lw.lock_word & LOCK_WORD_NEST_MASK) >> LOCK_WORD_NEST_SHIFT) + 1;
+}
+
+static inline gboolean
+lock_word_is_nested (LockWord lw)
+{
+ return lw.lock_word & LOCK_WORD_NEST_MASK;
+}
+
+static inline gboolean
+lock_word_is_max_nest (LockWord lw)
+{
+ return (lw.lock_word & LOCK_WORD_NEST_MASK) == LOCK_WORD_NEST_MASK;
+}
+
+static inline LockWord
+lock_word_increment_nest (LockWord lw)
+{
+ lw.lock_word += 1 << LOCK_WORD_NEST_SHIFT;
+ return lw;
+}
+
+static inline LockWord
+lock_word_decrement_nest (LockWord lw)
+{
+ lw.lock_word -= 1 << LOCK_WORD_NEST_SHIFT;
+ return lw;
+}
+
+static inline gint32
+lock_word_get_owner (LockWord lw)
+{
+ return lw.lock_word >> LOCK_WORD_OWNER_SHIFT;
+}
+
+static inline LockWord
+lock_word_new_thin_hash (gint32 hash)
+{
+ LockWord lw;
+ lw.lock_word = (guint32)hash;
+ lw.lock_word = (lw.lock_word << LOCK_WORD_HASH_SHIFT) | LOCK_WORD_HAS_HASH;
+ return lw;
+}
+
+static inline LockWord
+lock_word_new_inflated (MonoThreadsSync *mon)
+{
+ LockWord lw;
+ lw.sync = mon;
+ lw.lock_word |= LOCK_WORD_INFLATED;
+ return lw;
+}
+
+static inline LockWord
+lock_word_new_flat (gint32 owner)
+{
+ LockWord lw;
+ lw.lock_word = owner;
+ lw.lock_word <<= LOCK_WORD_OWNER_SHIFT;
+ return lw;
+}
+
void
mono_monitor_init (void)
{
return new;
}
-/*
- * Format of the lock word:
- * thinhash | fathash | data
- *
- * thinhash is the lower bit: if set data is the shifted hashcode of the object.
- * fathash is another bit: if set the hash code is stored in the MonoThreadsSync
- * struct pointed to by data
- * if neither bit is set and data is non-NULL, data is a MonoThreadsSync
- */
-typedef union {
- gsize lock_word;
- MonoThreadsSync *sync;
-} LockWord;
+static MonoThreadsSync*
+alloc_mon (MonoObject *obj, gint32 id)
+{
+ MonoThreadsSync *mon;
-enum {
- LOCK_WORD_THIN_HASH = 1,
- LOCK_WORD_FAT_HASH = 1 << 1,
- LOCK_WORD_BITS_MASK = 0x3,
- LOCK_WORD_HASH_SHIFT = 2
-};
+ mono_monitor_allocator_lock ();
+ mon = mon_new (id);
+ mono_gc_weak_link_add (&mon->data, obj, TRUE);
+ mono_monitor_allocator_unlock ();
+
+ return mon;
+}
+
+
+static void
+discard_mon (MonoThreadsSync *mon)
+{
+ mono_monitor_allocator_lock ();
+ mono_gc_weak_link_remove (&mon->data, TRUE);
+ mon_finalize (mon);
+ mono_monitor_allocator_unlock ();
+}
+
+static void
+mono_monitor_inflate_owned (MonoObject *obj, int id)
+{
+ MonoThreadsSync *mon;
+ LockWord nlw, old_lw, tmp_lw;
+ guint32 nest;
+
+ old_lw.sync = obj->synchronisation;
+ LOCK_DEBUG (g_message ("%s: (%d) Inflating owned lock object %p; LW = %p", __func__, id, obj, old_lw.sync));
+
+ if (lock_word_is_inflated (old_lw)) {
+ /* Someone else inflated the lock in the meantime */
+ return;
+ }
+
+ mon = alloc_mon (obj, id);
+
+ nest = lock_word_get_nest (old_lw);
+ mon->nest = nest;
+
+ nlw = lock_word_new_inflated (mon);
+
+ mono_memory_write_barrier ();
+ tmp_lw.sync = InterlockedCompareExchangePointer ((gpointer*)&obj->synchronisation, nlw.sync, old_lw.sync);
+ if (tmp_lw.sync != old_lw.sync) {
+ /* Someone else inflated the lock in the meantime */
+ discard_mon (mon);
+ }
+}
+
+static void
+mono_monitor_inflate (MonoObject *obj)
+{
+ MonoThreadsSync *mon;
+ LockWord nlw, old_lw;
+
+ LOCK_DEBUG (g_message ("%s: (%d) Inflating lock object %p; LW = %p", __func__, mono_thread_info_get_small_id (), obj, obj->synchronisation));
+
+ mon = alloc_mon (obj, 0);
+
+ nlw = lock_word_new_inflated (mon);
+
+ old_lw.sync = obj->synchronisation;
+
+ for (;;) {
+ LockWord tmp_lw;
+
+ if (lock_word_is_inflated (old_lw)) {
+ break;
+ }
+#ifdef HAVE_MOVING_COLLECTOR
+ else if (lock_word_has_hash (old_lw)) {
+ mon->hash_code = lock_word_get_hash (old_lw);
+ mon->status = mon_status_set_owner (mon->status, 0);
+ nlw = lock_word_set_has_hash (nlw);
+ }
+#endif
+ else if (lock_word_is_free (old_lw)) {
+ mon->status = mon_status_set_owner (mon->status, 0);
+ mon->nest = 1;
+ } else {
+ /* Lock is flat */
+ mon->status = mon_status_set_owner (mon->status, lock_word_get_owner (old_lw));
+ mon->nest = lock_word_get_nest (old_lw);
+ }
+ mono_memory_write_barrier ();
+ tmp_lw.sync = InterlockedCompareExchangePointer ((gpointer*)&obj->synchronisation, nlw.sync, old_lw.sync);
+ if (tmp_lw.sync == old_lw.sync) {
+ /* Successfully inflated the lock */
+ return;
+ }
+
+ old_lw.sync = tmp_lw.sync;
+ }
+
+ /* Someone else inflated the lock before us */
+ discard_mon (mon);
+}
#define MONO_OBJECT_ALIGNMENT_SHIFT 3
if (!obj)
return 0;
lw.sync = obj->synchronisation;
- if (lw.lock_word & LOCK_WORD_THIN_HASH) {
- /*g_print ("fast thin hash %d for obj %p store\n", (unsigned int)lw.lock_word >> LOCK_WORD_HASH_SHIFT, obj);*/
- return (unsigned int)lw.lock_word >> LOCK_WORD_HASH_SHIFT;
- }
- if (lw.lock_word & LOCK_WORD_FAT_HASH) {
- lw.lock_word &= ~LOCK_WORD_BITS_MASK;
- /*g_print ("fast fat hash %d for obj %p store\n", lw.sync->hash_code, obj);*/
- return lw.sync->hash_code;
+
+ LOCK_DEBUG (g_message("%s: (%d) Get hash for object %p; LW = %p", __func__, mono_thread_info_get_small_id (), obj, obj->synchronisation));
+
+ if (lock_word_has_hash (lw)) {
+ if (lock_word_is_inflated (lw)) {
+ return lock_word_get_inflated_lock (lw)->hash_code;
+ } else {
+ return lock_word_get_hash (lw);
+ }
}
/*
* while we are inside this function, the GC will keep this object pinned,
* with the same value.
*/
hash = (GPOINTER_TO_UINT (obj) >> MONO_OBJECT_ALIGNMENT_SHIFT) * 2654435761u;
+#if SIZEOF_VOID_P == 4
/* clear the top bits as they can be discarded */
- hash &= ~(LOCK_WORD_BITS_MASK << 30);
- /* no hash flags were set, so it must be a MonoThreadsSync pointer if not NULL */
- if (lw.sync) {
- lw.sync->hash_code = hash;
- /*g_print ("storing hash code %d for obj %p in sync %p\n", hash, obj, lw.sync);*/
- lw.lock_word |= LOCK_WORD_FAT_HASH;
- /* this is safe since we don't deflate locks */
- obj->synchronisation = lw.sync;
- } else {
- /*g_print ("storing thin hash code %d for obj %p\n", hash, obj);*/
- lw.lock_word = LOCK_WORD_THIN_HASH | (hash << LOCK_WORD_HASH_SHIFT);
- if (InterlockedCompareExchangePointer ((gpointer*)&obj->synchronisation, lw.sync, NULL) == NULL)
+ hash &= ~(LOCK_WORD_STATUS_MASK << (32 - LOCK_WORD_STATUS_BITS));
+#endif
+ if (lock_word_is_free (lw)) {
+ LockWord old_lw;
+ lw = lock_word_new_thin_hash (hash);
+
+ old_lw.sync = InterlockedCompareExchangePointer ((gpointer*)&obj->synchronisation, lw.sync, NULL);
+ if (old_lw.sync == NULL) {
return hash;
- /*g_print ("failed store\n");*/
- /* someone set the hash flag or someone inflated the object */
- lw.sync = obj->synchronisation;
- if (lw.lock_word & LOCK_WORD_THIN_HASH)
+ }
+
+ if (lock_word_has_hash (old_lw)) {
+ /* Done by somebody else */
return hash;
- lw.lock_word &= ~LOCK_WORD_BITS_MASK;
- lw.sync->hash_code = hash;
- lw.lock_word |= LOCK_WORD_FAT_HASH;
- /* this is safe since we don't deflate locks */
- obj->synchronisation = lw.sync;
+ }
+
+ mono_monitor_inflate (obj);
+ lw.sync = obj->synchronisation;
+ } else if (lock_word_is_flat (lw)) {
+ int id = mono_thread_info_get_small_id ();
+ if (lock_word_get_owner (lw) == id)
+ mono_monitor_inflate_owned (obj, id);
+ else
+ mono_monitor_inflate (obj);
+ lw.sync = obj->synchronisation;
}
+
+ /* At this point, the lock is inflated */
+ lock_word_get_inflated_lock (lw)->hash_code = hash;
+ lw = lock_word_set_has_hash (lw);
+ mono_memory_write_barrier ();
+ obj->synchronisation = lw.sync;
return hash;
#else
/*
#endif
}
+static void
+mono_monitor_ensure_owned (LockWord lw, guint32 id)
+{
+ if (lock_word_is_flat (lw)) {
+ if (lock_word_get_owner (lw) == id)
+ return;
+ } else if (lock_word_is_inflated (lw)) {
+ if (mon_status_get_owner (lock_word_get_inflated_lock (lw)->status) == id)
+ return;
+ }
+
+ mono_set_pending_exception (mono_get_exception_synchronization_lock ("Object synchronization method was called from an unsynchronized block of code."));
+}
+
+/*
+ * When this function is called it has already been established that the
+ * current thread owns the monitor.
+ */
+static void
+mono_monitor_exit_inflated (MonoObject *obj)
+{
+ LockWord lw;
+ MonoThreadsSync *mon;
+ guint32 nest;
+
+ lw.sync = obj->synchronisation;
+ mon = lock_word_get_inflated_lock (lw);
+
+ nest = mon->nest - 1;
+ if (nest == 0) {
+ guint32 new_status, old_status, tmp_status;
+
+ old_status = mon->status;
+
+ /*
+ * Release lock and do the wakeup stuff. It's possible that
+ * the last blocking thread gave up waiting just before we
+ * release the semaphore resulting in a negative entry count
+ * and a futile wakeup next time there's contention for this
+ * object.
+ */
+ for (;;) {
+ gboolean have_waiters = mon_status_have_waiters (old_status);
+
+ new_status = mon_status_set_owner (old_status, 0);
+ if (have_waiters)
+ new_status = mon_status_decrement_entry_count (new_status);
+ tmp_status = InterlockedCompareExchange ((gint32*)&mon->status, new_status, old_status);
+ if (tmp_status == old_status) {
+ if (have_waiters)
+ ReleaseSemaphore (mon->entry_sem, 1, NULL);
+ break;
+ }
+ old_status = tmp_status;
+ }
+ LOCK_DEBUG (g_message ("%s: (%d) Object %p is now unlocked", __func__, mono_thread_info_get_small_id (), obj));
+
+ /* object is now unlocked, leave nest==1 so we don't
+ * need to set it when the lock is reacquired
+ */
+ } else {
+ LOCK_DEBUG (g_message ("%s: (%d) Object %p is now locked %d times", __func__, mono_thread_info_get_small_id (), obj, nest));
+ mon->nest = nest;
+ }
+}
+
+/*
+ * When this function is called it has already been established that the
+ * current thread owns the monitor.
+ */
+static void
+mono_monitor_exit_flat (MonoObject *obj, LockWord old_lw)
+{
+ LockWord new_lw, tmp_lw;
+ if (G_UNLIKELY (lock_word_is_nested (old_lw)))
+ new_lw = lock_word_decrement_nest (old_lw);
+ else
+ new_lw.lock_word = 0;
+
+ tmp_lw.sync = InterlockedCompareExchangePointer ((gpointer*)&obj->synchronisation, new_lw.sync, old_lw.sync);
+ if (old_lw.sync != tmp_lw.sync) {
+ /* Someone inflated the lock in the meantime */
+ mono_monitor_exit_inflated (obj);
+ }
+
+ LOCK_DEBUG (g_message ("%s: (%d) Object %p is now locked %d times; LW = %p", __func__, mono_thread_info_get_small_id (), obj, lock_word_get_nest (new_lw), obj->synchronisation));
+}
+
static void
mon_decrement_entry_count (MonoThreadsSync *mon)
{
* is requested. In this case it returns -1.
*/
static inline gint32
-mono_monitor_try_enter_internal (MonoObject *obj, guint32 ms, gboolean allow_interruption)
+mono_monitor_try_enter_inflated (MonoObject *obj, guint32 ms, gboolean allow_interruption, guint32 id)
{
+ LockWord lw;
MonoThreadsSync *mon;
- gsize id = mono_thread_info_get_small_id ();
HANDLE sem;
guint32 then = 0, now, delta;
guint32 waitms;
LOCK_DEBUG (g_message("%s: (%d) Trying to lock object %p (%d ms)", __func__, id, obj, ms));
if (G_UNLIKELY (!obj)) {
- mono_raise_exception (mono_get_exception_argument_null ("obj"));
+ mono_set_pending_exception (mono_get_exception_argument_null ("obj"));
return FALSE;
}
+ lw.sync = obj->synchronisation;
+ mon = lock_word_get_inflated_lock (lw);
retry:
- mon = obj->synchronisation;
-
- /* If the object has never been locked... */
- if (G_UNLIKELY (mon == NULL)) {
- mono_monitor_allocator_lock ();
- mon = mon_new (id);
- if (InterlockedCompareExchangePointer ((gpointer*)&obj->synchronisation, mon, NULL) == NULL) {
- mono_gc_weak_link_add (&mon->data, obj, TRUE);
- mono_monitor_allocator_unlock ();
- /* Successfully locked */
- return 1;
- } else {
-#ifdef HAVE_MOVING_COLLECTOR
- LockWord lw;
- lw.sync = obj->synchronisation;
- if (lw.lock_word & LOCK_WORD_THIN_HASH) {
- MonoThreadsSync *oldlw = lw.sync;
- /* move the already calculated hash */
- mon->hash_code = lw.lock_word >> LOCK_WORD_HASH_SHIFT;
- lw.sync = mon;
- lw.lock_word |= LOCK_WORD_FAT_HASH;
- if (InterlockedCompareExchangePointer ((gpointer*)&obj->synchronisation, lw.sync, oldlw) == oldlw) {
- mono_gc_weak_link_add (&mon->data, obj, TRUE);
- mono_monitor_allocator_unlock ();
- /* Successfully locked */
- return 1;
- } else {
- mon_finalize (mon);
- mono_monitor_allocator_unlock ();
- goto retry;
- }
- } else if (lw.lock_word & LOCK_WORD_FAT_HASH) {
- mon_finalize (mon);
- mono_monitor_allocator_unlock ();
- /* get the old lock without the fat hash bit */
- lw.lock_word &= ~LOCK_WORD_BITS_MASK;
- mon = lw.sync;
- } else {
- mon_finalize (mon);
- mono_monitor_allocator_unlock ();
- mon = obj->synchronisation;
- }
-#else
- mon_finalize (mon);
- mono_monitor_allocator_unlock ();
- mon = obj->synchronisation;
-#endif
- }
- } else {
-#ifdef HAVE_MOVING_COLLECTOR
- LockWord lw;
- lw.sync = mon;
- if (lw.lock_word & LOCK_WORD_THIN_HASH) {
- MonoThreadsSync *oldlw = lw.sync;
- mono_monitor_allocator_lock ();
- mon = mon_new (id);
- /* move the already calculated hash */
- mon->hash_code = lw.lock_word >> LOCK_WORD_HASH_SHIFT;
- lw.sync = mon;
- lw.lock_word |= LOCK_WORD_FAT_HASH;
- if (InterlockedCompareExchangePointer ((gpointer*)&obj->synchronisation, lw.sync, oldlw) == oldlw) {
- mono_gc_weak_link_add (&mon->data, obj, TRUE);
- mono_monitor_allocator_unlock ();
- /* Successfully locked */
- return 1;
- } else {
- mon_finalize (mon);
- mono_monitor_allocator_unlock ();
- goto retry;
- }
- }
-#endif
- }
-
-#ifdef HAVE_MOVING_COLLECTOR
- {
- LockWord lw;
- lw.sync = mon;
- lw.lock_word &= ~LOCK_WORD_BITS_MASK;
- mon = lw.sync;
- }
-#endif
-
- /* If the object has previously been locked but isn't now... */
-
/* This case differs from Dice's case 3 because we don't
* deflate locks or cache unused lock records
*/
* We pass TRUE instead of allow_interruption since we have to check for the
* StopRequested case below.
*/
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
ret = WaitForSingleObjectEx (mon->entry_sem, waitms, TRUE);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
}
}
+/*
+ * If allow_interruption == TRUE, the method will be interrupted if abort or suspend
+ * is requested. In this case it returns -1.
+ */
+static inline gint32
+mono_monitor_try_enter_internal (MonoObject *obj, guint32 ms, gboolean allow_interruption)
+{
+ LockWord lw;
+ int id = mono_thread_info_get_small_id ();
+
+ LOCK_DEBUG (g_message("%s: (%d) Trying to lock object %p (%d ms)", __func__, id, obj, ms));
+
+ if (G_UNLIKELY (!obj)) {
+ mono_set_pending_exception (mono_get_exception_argument_null ("obj"));
+ return FALSE;
+ }
+
+ lw.sync = obj->synchronisation;
+
+ if (G_LIKELY (lock_word_is_free (lw))) {
+ LockWord nlw = lock_word_new_flat (id);
+ if (InterlockedCompareExchangePointer ((gpointer*)&obj->synchronisation, nlw.sync, NULL) == NULL) {
+ return 1;
+ } else {
+ /* Someone acquired it in the meantime or put a hash */
+ mono_monitor_inflate (obj);
+ return mono_monitor_try_enter_inflated (obj, ms, allow_interruption, id);
+ }
+ } else if (lock_word_is_inflated (lw)) {
+ return mono_monitor_try_enter_inflated (obj, ms, allow_interruption, id);
+ } else if (lock_word_is_flat (lw)) {
+ if (lock_word_get_owner (lw) == id) {
+ if (lock_word_is_max_nest (lw)) {
+ mono_monitor_inflate_owned (obj, id);
+ return mono_monitor_try_enter_inflated (obj, ms, allow_interruption, id);
+ } else {
+ LockWord nlw, old_lw;
+ nlw = lock_word_increment_nest (lw);
+ old_lw.sync = InterlockedCompareExchangePointer ((gpointer*)&obj->synchronisation, nlw.sync, lw.sync);
+ if (old_lw.sync != lw.sync) {
+ /* Someone else inflated it in the meantime */
+ g_assert (lock_word_is_inflated (old_lw));
+ return mono_monitor_try_enter_inflated (obj, ms, allow_interruption, id);
+ }
+ return 1;
+ }
+ } else {
+ mono_monitor_inflate (obj);
+ return mono_monitor_try_enter_inflated (obj, ms, allow_interruption, id);
+ }
+ } else if (lock_word_has_hash (lw)) {
+ mono_monitor_inflate (obj);
+ return mono_monitor_try_enter_inflated (obj, ms, allow_interruption, id);
+ }
+
+ g_assert_not_reached ();
+ return -1;
+}
+
gboolean
mono_monitor_enter (MonoObject *obj)
{
void
mono_monitor_exit (MonoObject *obj)
{
- MonoThreadsSync *mon;
- guint32 nest;
- guint32 new_status, old_status, tmp_status;
+ LockWord lw;
LOCK_DEBUG (g_message ("%s: (%d) Unlocking %p", __func__, mono_thread_info_get_small_id (), obj));
if (G_UNLIKELY (!obj)) {
- mono_raise_exception (mono_get_exception_argument_null ("obj"));
+ mono_set_pending_exception (mono_get_exception_argument_null ("obj"));
return;
}
- mon = obj->synchronisation;
+ lw.sync = obj->synchronisation;
-#ifdef HAVE_MOVING_COLLECTOR
- {
- LockWord lw;
- lw.sync = mon;
- if (lw.lock_word & LOCK_WORD_THIN_HASH)
- return;
- lw.lock_word &= ~LOCK_WORD_BITS_MASK;
- mon = lw.sync;
- }
-#endif
- if (G_UNLIKELY (mon == NULL)) {
- /* No one ever used Enter. Just ignore the Exit request as MS does */
- return;
- }
+ mono_monitor_ensure_owned (lw, mono_thread_info_get_small_id ());
- old_status = mon->status;
- if (G_UNLIKELY (mon_status_get_owner (old_status) != mono_thread_info_get_small_id ())) {
- return;
- }
-
- nest = mon->nest - 1;
- if (nest == 0) {
- /*
- * Release lock and do the wakeup stuff. It's possible that
- * the last blocking thread gave up waiting just before we
- * release the semaphore resulting in a negative entry count
- * and a futile wakeup next time there's contention for this
- * object.
- */
- for (;;) {
- gboolean have_waiters = mon_status_have_waiters (old_status);
-
- new_status = mon_status_set_owner (old_status, 0);
- if (have_waiters)
- new_status = mon_status_decrement_entry_count (new_status);
- tmp_status = InterlockedCompareExchange ((gint32*)&mon->status, new_status, old_status);
- if (tmp_status == old_status) {
- if (have_waiters)
- ReleaseSemaphore (mon->entry_sem, 1, NULL);
- break;
- }
- old_status = tmp_status;
- }
- LOCK_DEBUG (g_message ("%s: (%d) Object %p is now unlocked", __func__, mono_thread_info_get_small_id (), obj));
-
- /* object is now unlocked, leave nest==1 so we don't
- * need to set it when the lock is reacquired
- */
-
- } else {
- LOCK_DEBUG (g_message ("%s: (%d) Object %p is now locked %d times", __func__, mono_thread_info_get_small_id (), obj, nest));
- mon->nest = nest;
- }
+ if (G_UNLIKELY (lock_word_is_inflated (lw)))
+ mono_monitor_exit_inflated (obj);
+ else
+ mono_monitor_exit_flat (obj, lw);
}
void**
mono_monitor_get_object_monitor_weak_link (MonoObject *object)
{
LockWord lw;
- MonoThreadsSync *sync = NULL;
lw.sync = object->synchronisation;
- if (lw.lock_word & LOCK_WORD_FAT_HASH) {
- lw.lock_word &= ~LOCK_WORD_BITS_MASK;
- sync = lw.sync;
- } else if (!(lw.lock_word & LOCK_WORD_THIN_HASH)) {
- sync = lw.sync;
- }
- if (sync && sync->data)
- return &sync->data;
+ if (lock_word_is_inflated (lw)) {
+ MonoThreadsSync *mon = lock_word_get_inflated_lock (lw);
+ if (mon->data)
+ return &mon->data;
+ }
return NULL;
}
void
mono_monitor_enter_v4 (MonoObject *obj, char *lock_taken)
{
- if (*lock_taken == 1)
- mono_raise_exception (mono_get_exception_argument ("lockTaken", "lockTaken is already true"));
+
+ if (*lock_taken == 1) {
+ mono_set_pending_exception (mono_get_exception_argument ("lockTaken", "lockTaken is already true"));
+ return;
+ }
ves_icall_System_Threading_Monitor_Monitor_try_enter_with_atomic_var (obj, INFINITE, lock_taken);
}
gboolean
ves_icall_System_Threading_Monitor_Monitor_test_owner (MonoObject *obj)
{
- MonoThreadsSync *mon;
-
+ LockWord lw;
+
LOCK_DEBUG (g_message ("%s: Testing if %p is owned by thread %d", __func__, obj, mono_thread_info_get_small_id()));
- mon = obj->synchronisation;
-#ifdef HAVE_MOVING_COLLECTOR
- {
- LockWord lw;
- lw.sync = mon;
- if (lw.lock_word & LOCK_WORD_THIN_HASH)
- return FALSE;
- lw.lock_word &= ~LOCK_WORD_BITS_MASK;
- mon = lw.sync;
- }
-#endif
- if (mon == NULL) {
- return FALSE;
- }
-
- if (mon_status_get_owner (mon->status) == mono_thread_info_get_small_id ()) {
- return(TRUE);
+ lw.sync = obj->synchronisation;
+
+ if (lock_word_is_flat (lw)) {
+ return lock_word_get_owner (lw) == mono_thread_info_get_small_id ();
+ } else if (lock_word_is_inflated (lw)) {
+ return mon_status_get_owner (lock_word_get_inflated_lock (lw)->status) == mono_thread_info_get_small_id ();
}
return(FALSE);
gboolean
ves_icall_System_Threading_Monitor_Monitor_test_synchronised (MonoObject *obj)
{
- MonoThreadsSync *mon;
+ LockWord lw;
LOCK_DEBUG (g_message("%s: (%d) Testing if %p is owned by any thread", __func__, mono_thread_info_get_small_id (), obj));
-
- mon = obj->synchronisation;
-#ifdef HAVE_MOVING_COLLECTOR
- {
- LockWord lw;
- lw.sync = mon;
- if (lw.lock_word & LOCK_WORD_THIN_HASH)
- return FALSE;
- lw.lock_word &= ~LOCK_WORD_BITS_MASK;
- mon = lw.sync;
- }
-#endif
- if (mon == NULL) {
- return FALSE;
- }
-
- if (mon_status_get_owner (mon->status) != 0) {
- return TRUE;
+
+ lw.sync = obj->synchronisation;
+
+ if (lock_word_is_flat (lw)) {
+ return !lock_word_is_free (lw);
+ } else if (lock_word_is_inflated (lw)) {
+ return mon_status_get_owner (lock_word_get_inflated_lock (lw)->status) != 0;
}
-
+
return FALSE;
}
void
ves_icall_System_Threading_Monitor_Monitor_pulse (MonoObject *obj)
{
+ int id;
+ LockWord lw;
MonoThreadsSync *mon;
-
+
LOCK_DEBUG (g_message ("%s: (%d) Pulsing %p", __func__, mono_thread_info_get_small_id (), obj));
- mon = obj->synchronisation;
-#ifdef HAVE_MOVING_COLLECTOR
- {
- LockWord lw;
- lw.sync = mon;
- if (lw.lock_word & LOCK_WORD_THIN_HASH) {
- mono_set_pending_exception (mono_get_exception_synchronization_lock ("Not locked"));
- return;
- }
- lw.lock_word &= ~LOCK_WORD_BITS_MASK;
- mon = lw.sync;
- }
-#endif
- if (mon == NULL) {
- mono_set_pending_exception (mono_get_exception_synchronization_lock ("Not locked"));
- return;
- }
- if (mon_status_get_owner (mon->status) != mono_thread_info_get_small_id ()) {
- mono_set_pending_exception (mono_get_exception_synchronization_lock ("Not locked by this thread"));
+ id = mono_thread_info_get_small_id ();
+ lw.sync = obj->synchronisation;
+
+ mono_monitor_ensure_owned (lw, id);
+
+ if (!lock_word_is_inflated (lw)) {
+ /* No threads waiting. A wait would have inflated the lock */
return;
}
+ mon = lock_word_get_inflated_lock (lw);
+
LOCK_DEBUG (g_message ("%s: (%d) %d threads waiting", __func__, mono_thread_info_get_small_id (), g_slist_length (mon->wait_list)));
-
+
if (mon->wait_list != NULL) {
LOCK_DEBUG (g_message ("%s: (%d) signalling and dequeuing handle %p", __func__, mono_thread_info_get_small_id (), mon->wait_list->data));
void
ves_icall_System_Threading_Monitor_Monitor_pulse_all (MonoObject *obj)
{
+ int id;
+ LockWord lw;
MonoThreadsSync *mon;
LOCK_DEBUG (g_message("%s: (%d) Pulsing all %p", __func__, mono_thread_info_get_small_id (), obj));
- mon = obj->synchronisation;
-#ifdef HAVE_MOVING_COLLECTOR
- {
- LockWord lw;
- lw.sync = mon;
- if (lw.lock_word & LOCK_WORD_THIN_HASH) {
- mono_set_pending_exception (mono_get_exception_synchronization_lock ("Not locked"));
- return;
- }
- lw.lock_word &= ~LOCK_WORD_BITS_MASK;
- mon = lw.sync;
- }
-#endif
- if (mon == NULL) {
- mono_set_pending_exception (mono_get_exception_synchronization_lock ("Not locked"));
- return;
- }
- if (mon_status_get_owner (mon->status) != mono_thread_info_get_small_id ()) {
- mono_set_pending_exception (mono_get_exception_synchronization_lock ("Not locked by this thread"));
+ id = mono_thread_info_get_small_id ();
+ lw.sync = obj->synchronisation;
+
+ mono_monitor_ensure_owned (lw, id);
+
+ if (!lock_word_is_inflated (lw)) {
+ /* No threads waiting. A wait would have inflated the lock */
return;
}
+ mon = lock_word_get_inflated_lock (lw);
+
LOCK_DEBUG (g_message ("%s: (%d) %d threads waiting", __func__, mono_thread_info_get_small_id (), g_slist_length (mon->wait_list)));
while (mon->wait_list != NULL) {
gboolean
ves_icall_System_Threading_Monitor_Monitor_wait (MonoObject *obj, guint32 ms)
{
+ LockWord lw;
MonoThreadsSync *mon;
HANDLE event;
guint32 nest;
gboolean success = FALSE;
gint32 regain;
MonoInternalThread *thread = mono_thread_internal_current ();
+ int id = mono_thread_info_get_small_id ();
LOCK_DEBUG (g_message ("%s: (%d) Trying to wait for %p with timeout %dms", __func__, mono_thread_info_get_small_id (), obj, ms));
-
- mon = obj->synchronisation;
-#ifdef HAVE_MOVING_COLLECTOR
- {
- LockWord lw;
- lw.sync = mon;
- if (lw.lock_word & LOCK_WORD_THIN_HASH) {
- mono_set_pending_exception (mono_get_exception_synchronization_lock ("Not locked"));
- return FALSE;
- }
- lw.lock_word &= ~LOCK_WORD_BITS_MASK;
- mon = lw.sync;
- }
-#endif
- if (mon == NULL) {
- mono_set_pending_exception (mono_get_exception_synchronization_lock ("Not locked"));
- return FALSE;
- }
- if (mon_status_get_owner (mon->status) != mono_thread_info_get_small_id ()) {
- mono_set_pending_exception (mono_get_exception_synchronization_lock ("Not locked by this thread"));
- return FALSE;
+
+ lw.sync = obj->synchronisation;
+
+ mono_monitor_ensure_owned (lw, id);
+
+ if (!lock_word_is_inflated (lw)) {
+ mono_monitor_inflate_owned (obj, id);
+ lw.sync = obj->synchronisation;
}
+ mon = lock_word_get_inflated_lock (lw);
+
/* Do this WaitSleepJoin check before creating the event handle */
mono_thread_current_check_pending_interrupt ();
/* Save the nest count, and release the lock */
nest = mon->nest;
mon->nest = 1;
- mono_monitor_exit (obj);
+ mono_memory_write_barrier ();
+ mono_monitor_exit_inflated (obj);
LOCK_DEBUG (g_message ("%s: (%d) Unlocked %p lock %p", __func__, mono_thread_info_get_small_id (), obj, mon));
* is private to this thread. Therefore even if the event was
* signalled before we wait, we still succeed.
*/
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
ret = WaitForSingleObjectEx (event, ms, TRUE);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
/* Reset the thread state fairly early, so we don't have to worry
* about the monitor error checking
/* Regain the lock with the previous nest count */
do {
- regain = mono_monitor_try_enter_internal (obj, INFINITE, TRUE);
+ regain = mono_monitor_try_enter_inflated (obj, INFINITE, TRUE, id);
if (regain == -1)
mono_thread_interruption_checkpoint ();
} while (regain == -1);
/* Poll the event again, just in case it was signalled
* while we were trying to regain the monitor lock
*/
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
ret = WaitForSingleObjectEx (event, 0, FALSE);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
}
/* Pulse will have popped our event from the queue if it signalled
void *data;
};
+/*
+ * Lock word format:
+ *
+ * The least significant bit stores whether a hash for the object is computed
+ * which is stored either in the lock word or in the MonoThreadsSync structure
+ * that the lock word points to.
+ *
+ * The second bit stores whether the lock word is inflated, containing an
+ * address to the MonoThreadsSync structure.
+ *
+ * If both bits are 0, either the lock word is free (entire lock word is 0)
+ * or it is a thin/flat lock.
+ *
+ * 32-bit
+ * LOCK_WORD_FLAT: [owner:22 | nest:8 | status:2]
+ * LOCK_WORD_THIN_HASH: [hash:30 | status:2]
+ * LOCK_WORD_INFLATED: [sync:30 | status:2]
+ * LOCK_WORD_FAT_HASH: [sync:30 | status:2]
+ *
+ * 64-bit
+ * LOCK_WORD_FLAT: [unused:22 | owner:32 | nest:8 | status:2]
+ * LOCK_WORD_THIN_HASH: [hash:62 | status:2]
+ * LOCK_WORD_INFLATED: [sync:62 | status:2]
+ * LOCK_WORD_FAT_HASH: [sync:62 | status:2]
+ *
+ * In order to save processing time and to have one additional value, the nest
+ * count starts from 0 for the lock word (just valid thread ID in the lock word
+ * means that the thread holds the lock once, although nest is 0).
+ * FIXME Have the same convention on inflated locks
+ */
+
+typedef union {
+#if SIZEOF_REGISTER == 8
+ guint64 lock_word;
+#elif SIZEOF_REGISTER == 4
+ guint32 lock_word;
+#endif
+ MonoThreadsSync *sync;
+} LockWord;
+
+
+enum {
+ LOCK_WORD_FLAT = 0,
+ LOCK_WORD_HAS_HASH = 1,
+ LOCK_WORD_INFLATED = 2,
+
+ LOCK_WORD_STATUS_BITS = 2,
+ LOCK_WORD_NEST_BITS = 8,
+
+ LOCK_WORD_STATUS_MASK = (1 << LOCK_WORD_STATUS_BITS) - 1,
+ LOCK_WORD_NEST_MASK = ((1 << LOCK_WORD_NEST_BITS) - 1) << LOCK_WORD_STATUS_BITS,
+
+ LOCK_WORD_HASH_SHIFT = LOCK_WORD_STATUS_BITS,
+ LOCK_WORD_NEST_SHIFT = LOCK_WORD_STATUS_BITS,
+ LOCK_WORD_OWNER_SHIFT = LOCK_WORD_STATUS_BITS + LOCK_WORD_NEST_BITS
+};
MONO_API void mono_locks_dump (gboolean include_untaken);
MonoGHashGCType gc_type;
};
+static MonoGHashTable *
+mono_g_hash_table_new (GHashFunc hash_func, GEqualFunc key_equal_func);
+
#ifdef HAVE_SGEN_GC
static MonoGCDescriptor table_hash_descr = MONO_GC_DESCRIPTOR_NULL;
return hash;
}
-MonoGHashTable *
+static MonoGHashTable *
mono_g_hash_table_new (GHashFunc hash_func, GEqualFunc key_equal_func)
{
MonoGHashTable *hash;
return hash;
}
-MonoGHashTable *
-mono_g_hash_table_new_full (GHashFunc hash_func, GEqualFunc key_equal_func,
- GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
-{
- MonoGHashTable *hash = mono_g_hash_table_new (hash_func, key_equal_func);
- if (hash == NULL)
- return NULL;
-
- hash->key_destroy_func = key_destroy_func;
- hash->value_destroy_func = value_destroy_func;
-
- return hash;
-}
-
typedef struct {
MonoGHashTable *hash;
int new_size;
typedef struct _MonoGHashTable MonoGHashTable;
MONO_API MonoGHashTable *mono_g_hash_table_new_type (GHashFunc hash_func, GEqualFunc key_equal_func, MonoGHashGCType type);
-MONO_API MonoGHashTable *mono_g_hash_table_new (GHashFunc hash_func, GEqualFunc key_equal_func);
-MONO_API MonoGHashTable *mono_g_hash_table_new_full (GHashFunc hash_func, GEqualFunc key_equal_func,
- GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func);
MONO_API guint mono_g_hash_table_size (MonoGHashTable *hash);
MONO_API gpointer mono_g_hash_table_lookup (MonoGHashTable *hash, gconstpointer key);
MONO_API gboolean mono_g_hash_table_lookup_extended (MonoGHashTable *hash, gconstpointer key, gpointer *orig_key, gpointer *value);
MonoObject *state, gpointer data, MonoObject *object_data);
MonoObject *
-mono_async_result_invoke (MonoAsyncResult *ares, MonoObject **exc);
-
-MonoObject *
-ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *this_obj);
+ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares);
MonoWaitHandle *
mono_wait_handle_new (MonoDomain *domain, HANDLE handle);
static void
mono_type_init_lock (TypeInitializationLock *lock)
{
- MONO_TRY_BLOCKING
+ MONO_TRY_BLOCKING;
mono_mutex_lock (&lock->initialization_section);
- MONO_FINISH_TRY_BLOCKING
+ MONO_FINISH_TRY_BLOCKING;
}
static void
}
MonoObject *
-mono_async_result_invoke (MonoAsyncResult *ares, MonoObject **exc)
+ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
{
MonoAsyncCall *ac;
MonoObject *res;
- MonoInternalThread *thread;
g_assert (ares);
g_assert (ares->async_delegate);
- thread = mono_thread_internal_current ();
-
ac = (MonoAsyncCall*) ares->object_data;
if (!ac) {
- res = mono_runtime_delegate_invoke (ares->async_delegate, (void**) &ares->async_state, exc);
+ res = mono_runtime_delegate_invoke (ares->async_delegate, (void**) &ares->async_state, NULL);
} else {
- MonoArray *out_args = NULL;
gpointer wait_event = NULL;
ac->msg->exc = NULL;
- res = mono_message_invoke (ares->async_delegate, ac->msg, exc, &out_args);
- MONO_OBJECT_SETREF (ac->msg, exc, *exc);
+ res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args);
MONO_OBJECT_SETREF (ac, res, res);
- MONO_OBJECT_SETREF (ac, out_args, out_args);
mono_monitor_enter ((MonoObject*) ares);
ares->completed = 1;
if (wait_event != NULL)
SetEvent (wait_event);
- if (!ac->cb_method) {
- *exc = NULL;
- } else {
- mono_runtime_invoke (ac->cb_method, ac->cb_target, (gpointer*) &ares, exc);
+ if (ac->cb_method) {
+ /* we swallow the excepton as it is the behavior on .NET */
+ MonoObject *exc = NULL;
+ mono_runtime_invoke (ac->cb_method, ac->cb_target, (gpointer*) &ares, &exc);
+ if (exc)
+ mono_unhandled_exception (exc);
}
}
return res;
}
-MonoObject *
-ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *this_obj)
-{
- MonoObject *exc = NULL;
- MonoObject *res = mono_async_result_invoke (this_obj, &exc);
- if (exc)
- mono_raise_exception ((MonoException*) exc);
- return res;
-}
-
void
mono_message_init (MonoDomain *domain,
MonoMethodMessage *this_obj,
object_array_klass = klass;
}
- /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
- *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
+ mono_gc_wbarrier_generic_store (out_args, (MonoObject*) mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count));
*exc = NULL;
ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
typedef void (*MonoMainThreadFunc) (void* user_data);
#define MONO_OBJECT_SETREF(obj,fieldname,value) do { \
+ g_assert (sizeof((obj)->fieldname) == sizeof (gpointer*)); \
mono_gc_wbarrier_set_field ((MonoObject*)(obj), &((obj)->fieldname), (MonoObject*)value); \
/*(obj)->fieldname = (value);*/ \
} while (0)
} else {
process_info->process_handle = shellex.hProcess;
process_info->thread_handle = NULL;
- /* It appears that there's no way to get the pid from a
- * process handle before windows xp. Really.
- */
-#if defined(HAVE_GETPROCESSID) && !defined(MONO_CROSS_COMPILE)
+#if !defined(MONO_CROSS_COMPILE)
process_info->pid = GetProcessId (shellex.hProcess);
#else
process_info->pid = 0;
{
guint32 ret;
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
if(ms<0) {
/* Wait forever */
ret=WaitForSingleObjectEx (process, INFINITE, TRUE);
} else {
ret=WaitForSingleObjectEx (process, ms, TRUE);
}
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
if(ret==WAIT_OBJECT_0) {
return(TRUE);
mono_marshal_remoting_find_in_cache (MonoMethod *method, int wrapper_type)
{
MonoMethod *res = NULL;
- MonoRemotingMethods *wrps;
+ MonoRemotingMethods *wrps = NULL;
mono_marshal_lock_internal ();
- if (method->is_inflated && ((MonoMethodInflated *)method)->owner->wrapper_caches.remoting_invoke_cache) {
- MonoMethodInflated *imethod = (MonoMethodInflated *)method;
- wrps = g_hash_table_lookup (imethod->owner->wrapper_caches.remoting_invoke_cache, method);
- } else if (method->klass->image->wrapper_caches.remoting_invoke_cache)
- wrps = g_hash_table_lookup (method->klass->image->wrapper_caches.remoting_invoke_cache, method);
- else
- wrps = NULL;
+ if (mono_method_get_wrapper_cache (method)->remoting_invoke_cache)
+ wrps = g_hash_table_lookup (mono_method_get_wrapper_cache (method)->remoting_invoke_cache, method);
if (wrps) {
switch (wrapper_type) {
MonoRemotingMethods *wrps;
GHashTable *cache;
- if (key->is_inflated) {
- MonoMethodInflated *imethod = (MonoMethodInflated *)key;
- cache = get_cache_full (&imethod->owner->wrapper_caches.remoting_invoke_cache, mono_aligned_addr_hash, NULL, NULL, g_free);
- } else
- cache = get_cache_full (&key->klass->image->wrapper_caches.remoting_invoke_cache, mono_aligned_addr_hash, NULL, NULL, g_free);
+ cache = get_cache_full (&mono_method_get_wrapper_cache (key)->remoting_invoke_cache, mono_aligned_addr_hash, NULL, NULL, g_free);
mono_marshal_lock_internal ();
wrps = g_hash_table_lookup (cache, key);
--- /dev/null
+/*
+ * sgen-os-coop.c: SGen Cooperative backend support.
+ *
+ * Author:
+ * João Matos (joao.matos@xamarin.com)
+ * Copyright (C) 2015 Xamarin Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License 2.0 as published by the Free Software Foundation;
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License 2.0 along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "config.h"
+#ifdef HAVE_SGEN_GC
+
+
+#include <glib.h>
+#include "sgen/sgen-gc.h"
+#include "sgen/sgen-archdep.h"
+#include "sgen/sgen-protocol.h"
+#include "metadata/object-internals.h"
+#include "metadata/gc-internal.h"
+
+
+#if defined(USE_COOP_GC)
+
+gboolean
+sgen_resume_thread (SgenThreadInfo *info)
+{
+ g_error ("FIXME");
+ return FALSE;
+}
+
+gboolean
+sgen_suspend_thread (SgenThreadInfo *info)
+{
+ g_error ("FIXME");
+ return FALSE;
+}
+
+void
+sgen_wait_for_suspend_ack (int count)
+{
+}
+
+/* LOCKING: assumes the GC lock is held */
+int
+sgen_thread_handshake (BOOL suspend)
+{
+ g_error ("FIXME");
+ return 0;
+}
+
+void
+sgen_os_init (void)
+{
+}
+
+int
+mono_gc_get_suspend_signal (void)
+{
+ return -1;
+}
+
+int
+mono_gc_get_restart_signal (void)
+{
+ return -1;
+}
+
+#endif
+#endif
\ No newline at end of file
} END_FOREACH_THREAD_SAFE
return count;
}
-#endif
void
sgen_os_init (void)
}
#endif
#endif
+#endif
#include "config.h"
-#ifdef HAVE_SGEN_GC
+#if defined(HAVE_SGEN_GC) && !defined(USE_COOP_GC)
#if !defined(__MACH__) && !MONO_MACH_ARCH_SUPPORTED && defined(HAVE_PTHREAD_KILL)
#include <errno.h>
{
SOCKET newsock;
MonoInternalThread* curthread G_GNUC_UNUSED = mono_thread_internal_current ();
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
*error = 0;
#ifdef HOST_WIN32
#else
newsock = _wapi_accept (sock, NULL, 0);
#endif
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
if(newsock==INVALID_SOCKET) {
*error = WSAGetLastError ();
return NULL;
}
sa = (salen <= 128) ? alloca (salen) : g_malloc0 (salen);
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
ret = _wapi_getsockname (sock, (struct sockaddr *)sa, &salen);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
if(ret==SOCKET_ERROR) {
*error = WSAGetLastError ();
}
sa = (salen <= 128) ? alloca (salen) : g_malloc0 (salen);
/* Note: linux returns just 2 for AF_UNIX. Always. */
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
ret = _wapi_getpeername (sock, (struct sockaddr *)sa, &salen);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
if(ret==SOCKET_ERROR) {
*error = WSAGetLastError ();
if (salen > 128)
LOGDEBUG (g_message("%s: connecting to %s port %d", __func__, inet_ntoa(((struct sockaddr_in *)sa)->sin_addr), ntohs (((struct sockaddr_in *)sa)->sin_port)));
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
ret = _wapi_connect (sock, sa, sa_size);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
if(ret==SOCKET_ERROR) {
*error = WSAGetLastError ();
LPFN_DISCONNECTEX _wapi_disconnectex = NULL;
LPFN_TRANSMITFILE _wapi_transmitfile = NULL;
gboolean bret;
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
*error = 0;
*error = WSAGetLastError ();
}
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
}
gint32 ves_icall_System_Net_Sockets_Socket_Receive_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, gint32 *error)
return (0);
}
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
#ifdef HOST_WIN32
{
curthread->interrupt_on_stop = (gpointer)TRUE;
#else
ret = _wapi_recv (sock, buf, count, recvflags);
#endif
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
if(ret==SOCKET_ERROR) {
*error = WSAGetLastError ();
return (0);
}
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
ret = _wapi_recvfrom (sock, buf, count, recvflags, sa, &sa_size);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
if(ret==SOCKET_ERROR) {
g_free(sa);
return (0);
}
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
ret = _wapi_send (sock, buf, count, sendflags);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
if(ret==SOCKET_ERROR) {
*error = WSAGetLastError ();
return(0);
return (0);
}
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
ret = _wapi_sendto (sock, buf, count, sendflags, sa, sa_size);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
if(ret==SOCKET_ERROR) {
*error = WSAGetLastError ();
}
gint32 *error)
{
int ret;
- MONO_PREPARE_BLOCKING
*error = 0;
/* Currently, the values for how (recv=0, send=1, both=2) match
* the BSD API
*/
+ MONO_PREPARE_BLOCKING;
ret = _wapi_shutdown (sock, how);
+ MONO_FINISH_BLOCKING;
if(ret==SOCKET_ERROR) {
*error = WSAGetLastError ();
}
-
- MONO_FINISH_BLOCKING
}
gint
char *hostname = mono_string_to_utf8 (host);
int hint = get_addrinfo_family_hint ();
- MONO_PREPARE_BLOCKING
-
if (*hostname == '\0') {
add_local_ips = TRUE;
*h_name = host;
}
+ MONO_PREPARE_BLOCKING;
if (!add_local_ips && gethostname (this_hostname, sizeof (this_hostname)) != -1) {
if (!strcmp (hostname, this_hostname)) {
add_local_ips = TRUE;
add_info_ok = FALSE;
g_free(hostname);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
if (add_info_ok)
return addrinfo_to_IPHostEntry(info, h_name, h_aliases, h_addr_list, add_local_ips);
int hint = get_addrinfo_family_hint ();
gboolean add_info_ok;
- MONO_PREPARE_BLOCKING
-
address = mono_string_to_utf8 (addr);
if (inet_pton (AF_INET, address, &saddr.sin_addr ) <= 0) {
}
g_free(address);
+ MONO_PREPARE_BLOCKING;
+
if(family == AF_INET) {
#if HAVE_SOCKADDR_IN_SIN_LEN
saddr.sin_len = sizeof (saddr);
}
add_info_ok = !mono_get_address_info (hostname, 0, hint | MONO_HINT_CANONICAL_NAME | MONO_HINT_CONFIGURED_ONLY, &info);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
if (add_info_ok)
return addrinfo_to_IPHostEntry (info, h_name, h_aliases, h_addr_list, FALSE);
mono_gc_set_skip_thread (TRUE);
+ MONO_PREPARE_BLOCKING;
+
mono_mutex_lock (&threadpool->active_threads_lock);
if (!mono_runtime_is_shutting_down ()) {
mono_mutex_unlock (&threadpool->active_threads_lock);
+ MONO_FINISH_BLOCKING;
+
mono_gc_set_skip_thread (FALSE);
mono_cond_destroy (&cond);
return NULL;
}
- MONO_OBJECT_SETREF (ares, endinvoke_called, 1);
+ ares->endinvoke_called = 1;
/* wait until we are really finished */
if (ares->completed) {
MONO_OBJECT_SETREF (ares, handle, (MonoObject*) mono_wait_handle_new (mono_object_domain (ares), wait_event));
}
mono_monitor_exit ((MonoObject*) ares);
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
WaitForSingleObjectEx (wait_event, INFINITE, TRUE);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
}
ac = (MonoAsyncCall*) ares->object_data;
mono_memory_write_barrier ();
while (domain->threadpool_jobs) {
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
WaitForSingleObject (sem, timeout);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
if (timeout != -1) {
timeout -= mono_msec_ticks () - start;
if (timeout <= 0) {
static void
mono_threads_lock (void)
{
- MONO_TRY_BLOCKING
+ MONO_TRY_BLOCKING;
mono_locks_acquire (&threads_mutex, ThreadsLock);
- MONO_FINISH_TRY_BLOCKING
+ MONO_FINISH_TRY_BLOCKING;
}
static void
g_assert (thread->synch_cs);
- MONO_TRY_BLOCKING
+ MONO_TRY_BLOCKING;
mono_mutex_lock (thread->synch_cs);
- MONO_FINISH_TRY_BLOCKING
+ MONO_FINISH_TRY_BLOCKING;
}
static inline void
*/
if (thread_start_args == NULL) {
MONO_GC_REGISTER_ROOT_FIXED (thread_start_args);
- thread_start_args = mono_g_hash_table_new (NULL, NULL);
+ thread_start_args = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_CONSERVATIVE_GC);
}
mono_g_hash_table_insert (thread_start_args, thread, start_info->start_arg);
if (threads_starting_up == NULL) {
*/
create_flags = CREATE_SUSPENDED;
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)start_wrapper, start_info,
stack_size, create_flags, &tid);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
if (thread_handle == NULL) {
/* The thread couldn't be created, so throw an exception */
if (!handle_store (thread, FALSE))
return FALSE;
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
mono_thread_info_resume (tid);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
if (internal->start_notify) {
/*
*/
THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for thread %p (%"G_GSIZE_FORMAT") to start", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
WaitForSingleObjectEx (internal->start_notify, INFINITE, FALSE);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
CloseHandle (internal->start_notify);
internal->start_notify = NULL;
while (TRUE) {
mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
res = SleepEx(ms,TRUE);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
ret=WaitForSingleObjectEx (handle, ms, TRUE);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
start = (ms == -1) ? 0 : mono_100ns_ticks ();
do {
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
if (multiple)
ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, alertable);
else
ret = WaitForSingleObjectEx (handles [0], ms, alertable);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
if (ret != WAIT_IO_COMPLETION)
break;
mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
ret = SignalObjectAndWait (toSignal, toWait, ms, TRUE);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
if(ret==WAIT_FAILED) {
/* See the comment in build_wait_tids() */
count++;
}
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
if(ret==WAIT_FAILED) {
/* See the comment in build_wait_tids() */
{
GString *p = (GString*)data;
MonoMethod *method = NULL;
- if (frame->ji)
+ if (frame->type == FRAME_TYPE_MANAGED)
method = mono_jit_info_get_method (frame->ji);
if (method) {
WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
#endif
InterlockedDecrement (&thread_interruption_requested);
+
/* Clear the interrupted flag of the thread so it can wait again */
- mono_thread_info_clear_interruption ();
+ mono_thread_info_clear_self_interrupt ();
}
if ((thread->state & ThreadState_AbortRequested) != 0) {
typedef struct {
MonoInternalThread *thread;
gboolean install_async_abort;
- gpointer interrupt_handle;
+ MonoThreadInfoInterruptToken *interrupt_token;
} AbortThreadData;
static SuspendThreadResult
InterlockedIncrement (&thread_interruption_requested);
ji = mono_thread_info_get_last_managed (info);
- protected_wrapper = ji && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
+ protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
if (!protected_wrapper && running_managed) {
* functions in the io-layer until the signal handler calls QueueUserAPC which will
* make it return.
*/
- data->interrupt_handle = mono_thread_info_prepare_interrupt (thread->handle);
+ data->interrupt_token = mono_thread_info_prepare_interrupt (info);
+
return MonoResumeThread;
}
}
MonoException *exc = mono_thread_request_interruption (can_raise_exception);
if (exc)
mono_raise_exception (exc);
- mono_thread_info_interrupt (thread->handle);
+
+ mono_thread_info_self_interrupt ();
+
return;
}
mono_thread_info_safe_suspend_and_run ((MonoNativeThreadId)(gsize)thread->tid, TRUE, abort_thread_critical, &data);
- if (data.interrupt_handle)
- mono_thread_info_finish_interrupt (data.interrupt_handle);
+ if (data.interrupt_token)
+ mono_thread_info_finish_interrupt (data.interrupt_token);
/*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
}
typedef struct{
MonoInternalThread *thread;
gboolean interrupt;
- gpointer interrupt_handle;
+ MonoThreadInfoInterruptToken *interrupt_token;
} SuspendThreadData;
static SuspendThreadResult
gboolean running_managed;
ji = mono_thread_info_get_last_managed (info);
- protected_wrapper = ji && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
+ protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
if (running_managed && !protected_wrapper) {
if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
InterlockedIncrement (&thread_interruption_requested);
if (data->interrupt)
- data->interrupt_handle = mono_thread_info_prepare_interrupt (thread->handle);
+ data->interrupt_token = mono_thread_info_prepare_interrupt (thread->thread_info);
if (mono_thread_notify_pending_exc_fn && !running_managed)
/* The JIT will notify the thread about the interruption */
data.interrupt = interrupt;
mono_thread_info_safe_suspend_and_run ((MonoNativeThreadId)(gsize)thread->tid, interrupt, suspend_thread_critical, &data);
- if (data.interrupt_handle)
- mono_thread_info_finish_interrupt (data.interrupt_handle);
+ if (data.interrupt_token)
+ mono_thread_info_finish_interrupt (data.interrupt_token);
UNLOCK_THREAD (thread);
}
}
libgc_libs=$(monodir)/libgc/libmonogc.la
libgc_static_libs=$(monodir)/libgc/libmonogc-static.la
-libs= \
+boehm_libs= \
$(monodir)/mono/metadata/libmonoruntime.la \
$(monodir)/mono/io-layer/libwapi.la \
$(monodir)/mono/utils/libmonoutils.la \
$(monodir)/mono/utils/libmonoutils.la \
$(GLIB_LIBS) $(LIBICONV)
-static_libs= \
+boehm_static_libs= \
$(monodir)/mono/metadata/libmonoruntime-static.la \
$(monodir)/mono/io-layer/libwapi.la \
$(monodir)/mono/utils/libmonoutils.la \
$(GLIB_LIBS) $(LIBICONV) \
$(libgc_static_libs)
-sgenstatic_libs = \
+sgen_static_libs = \
$(monodir)/mono/metadata/libmonoruntimesgen-static.la \
$(monodir)/mono/sgen/libmonosgen-static.la \
$(monodir)/mono/io-layer/libwapi.la \
if SUPPORT_SGEN
sgen_binaries = mono-sgen
sgen_libraries = libmonosgen-2.0.la
-sgen_static_libraries = libmini-static.la $(sgenstatic_libs)
+sgen_static_libraries = libmini-static.la $(sgen_static_libs)
endif
if SUPPORT_BOEHM
boehm_libraries = libmonoboehm-2.0.la
-boehm_static_libraries = libmini-static.la $(static_libs)
+boehm_static_libraries = libmini-static.la $(boehm_static_libs)
boehm_binaries = mono-boehm
endif
-#The mono uses sgen, while libmono remains boehm
+# The mono executable uses sgen, while libmono remains boehm
if SUPPORT_SGEN
mono_bin_suffix = sgen
else
if PLATFORM_DARWIN
libmono_llvm_la_LDFLAGS=-Wl,-undefined -Wl,suppress -Wl,-flat_namespace
else
-libmono_llvm_la_LIBADD += $(top_builddir)/mono/mini/libmonoboehm-$(API_VER).la $(libs)
+libmono_llvm_la_LIBADD += $(top_builddir)/mono/mini/libmonoboehm-$(API_VER).la $(boehm_libs)
endif
endif
libmonoboehm_2_0_la_SOURCES =
libmonoboehm_2_0_la_CFLAGS = $(mono_boehm_CFLAGS)
-libmonoboehm_2_0_la_LIBADD = libmini.la $(libs) $(LIBMONO_DTRACE_OBJECT) $(LLVMMONOF)
+libmonoboehm_2_0_la_LIBADD = libmini.la $(boehm_libs) $(LIBMONO_DTRACE_OBJECT) $(LLVMMONOF)
libmonoboehm_2_0_la_LDFLAGS = $(libmonoldflags)
libmonosgen_2_0_la_SOURCES =
fullaot_regtests = $(regtests) aot-tests.exe $(if $(GSHAREDVT),gshared.exe)
+FULLAOT_LIBS = \
+ mscorlib.dll \
+ System.Core.dll \
+ System.dll \
+ Mono.Posix.dll \
+ System.Configuration.dll \
+ System.Security.dll \
+ System.Xml.dll \
+ Mono.Security.dll \
+ Mono.Simd.dll
+
# This currently only works on amd64/arm
fullaotcheck: mono $(fullaot_regtests)
rm -rf fullaot-tmp
mkdir fullaot-tmp
- cp $(CLASS)/mscorlib.dll $(CLASS)/System.Core.dll $(CLASS)/System.dll $(CLASS)/Mono.Posix.dll $(CLASS)/System.Configuration.dll $(CLASS)/System.Security.dll $(CLASS)/System.Xml.dll $(CLASS)/Mono.Security.dll $(CLASS)/Mono.Simd.dll $(regtests) generics-variant-types.dll TestDriver.dll fullaot-tmp/
- cp $(fullaot_regtests) fullaot-tmp/
- MONO_PATH=fullaot-tmp $(top_builddir)/runtime/mono-wrapper $(LLVM_AOT_RUNTIME_OPTS) $(GSHAREDVT_RUNTIME_OPTS) --aot=full fullaot-tmp/* || exit 1
+ $(MAKE) fullaot-libs AOT_FLAGS=full
+ cp $(regtests) $(fullaot_regtests) generics-variant-types.dll TestDriver.dll fullaot-tmp/
+ MONO_PATH=fullaot-tmp $(top_builddir)/runtime/mono-wrapper $(LLVM_AOT_RUNTIME_OPTS) $(GSHAREDVT_RUNTIME_OPTS) --aot=full fullaot-tmp/{generics-variant-types.dll,TestDriver.dll,*.exe} || exit 1
ln -s $$PWD/mono fullaot-tmp/
for i in $(fullaot_regtests); do echo $$i; MONO_PATH=fullaot-tmp $(top_builddir)/runtime/mono-wrapper --full-aot fullaot-tmp/$$i --exclude '!FULLAOT' $(ARCH_FULLAOT_EXCLUDE) || exit 1; done
+# This can run in parallel
+fullaot-libs: $(patsubst %,fullaot-tmp/%.dylib,$(FULLAOT_LIBS))
+
+fullaot-tmp/%.dylib: $(CLASS)/%
+ cp $(CLASS)/$* fullaot-tmp/
+ mkdir fullaot-tmp/$*-tmp
+ MONO_PATH=fullaot-tmp/:$(CLASS) $(top_builddir)/runtime/mono-wrapper --aot=$(AOT_FLAGS),temp-path=fullaot-tmp/$*-tmp fullaot-tmp/$*
+ rm -rf fullaot-tmp/$*-tmp
+
llvmfullaotcheck:
$(MAKE) fullaotcheck LLVM=1
#include <mono/metadata/metadata-internals.h>
#include <mono/metadata/marshal.h>
#include <mono/metadata/gc-internal.h>
-#include <mono/metadata/monitor.h>
#include <mono/metadata/mempool-internals.h>
#include <mono/metadata/mono-endian.h>
#include <mono/metadata/threads-types.h>
#endif
+static guint32
+get_unwind_info_offset (MonoAotCompile *acfg, guint8 *encoded, guint32 encoded_len);
+
static char*
get_plt_entry_debug_sym (MonoAotCompile *acfg, MonoJumpInfo *ji, GHashTable *cache);
#endif
}
+/* Save unwind_info in the module and emit the offset to the information at symbol */
+static void save_unwind_info (MonoAotCompile *acfg, char *symbol, GSList *unwind_ops)
+{
+ guint32 uw_offset, encoded_len;
+ guint8 *encoded;
+
+ emit_section_change (acfg, RODATA_SECT, 0);
+ emit_global (acfg, symbol, FALSE);
+ emit_label (acfg, symbol);
+
+ encoded = mono_unwind_ops_encode (unwind_ops, &encoded_len);
+ uw_offset = get_unwind_info_offset (acfg, encoded, encoded_len);
+ g_free (encoded);
+ emit_int32 (acfg, uw_offset);
+}
+
/*
* arch_emit_specific_trampoline_pages:
*
guint8 *loop_start, *loop_branch_back, *loop_end_check, *imt_found_check;
int i;
int pagesize = MONO_AOT_TRAMP_PAGE_SIZE;
+ GSList *unwind_ops = NULL;
#define COMMON_TRAMP_SIZE 16
int count = (pagesize - COMMON_TRAMP_SIZE) / 8;
int imm8, rot_amount;
/* now the imt trampolines: each specific trampolines puts in the ip register
* the instruction pointer address, so the generic trampoline at the start of the page
* subtracts 4096 to get to the data page and loads the values
- * We again fit the generic trampiline in 16 bytes.
*/
#define IMT_TRAMP_SIZE 72
sprintf (symbol, "%simt_trampolines_page", acfg->user_symbol_prefix);
acfg->tramp_page_code_offsets [MONO_AOT_TRAMP_STATIC_RGCTX] = 16;
acfg->tramp_page_code_offsets [MONO_AOT_TRAMP_IMT_THUNK] = 72;
acfg->tramp_page_code_offsets [MONO_AOT_TRAMP_GSHAREDVT_ARG] = 16;
+
+ /* Unwind info for specifc trampolines */
+ sprintf (symbol, "%sspecific_trampolines_page_gen_p", acfg->user_symbol_prefix);
+ /* We unwind to the original caller, from the stack, since lr is clobbered */
+ mono_add_unwind_op_def_cfa (unwind_ops, 0, 0, ARMREG_SP, 14 * sizeof (mgreg_t));
+ mono_add_unwind_op_offset (unwind_ops, 0, 0, ARMREG_LR, -4);
+ save_unwind_info (acfg, symbol, unwind_ops);
+ mono_free_unwind_info (unwind_ops);
+
+ sprintf (symbol, "%sspecific_trampolines_page_sp_p", acfg->user_symbol_prefix);
+ mono_add_unwind_op_def_cfa (unwind_ops, 0, 0, ARMREG_SP, 0);
+ mono_add_unwind_op_def_cfa_offset (unwind_ops, 4, 0, 14 * sizeof (mgreg_t));
+ save_unwind_info (acfg, symbol, unwind_ops);
+ mono_free_unwind_info (unwind_ops);
+
+ /* Unwind info for rgctx trampolines */
+ sprintf (symbol, "%srgctx_trampolines_page_gen_p", acfg->user_symbol_prefix);
+ mono_add_unwind_op_def_cfa (unwind_ops, 0, 0, ARMREG_SP, 0);
+ save_unwind_info (acfg, symbol, unwind_ops);
+
+ sprintf (symbol, "%srgctx_trampolines_page_sp_p", acfg->user_symbol_prefix);
+ save_unwind_info (acfg, symbol, unwind_ops);
+ mono_free_unwind_info (unwind_ops);
+
+ /* Unwind info for gsharedvt trampolines */
+ sprintf (symbol, "%sgsharedvt_trampolines_page_gen_p", acfg->user_symbol_prefix);
+ mono_add_unwind_op_def_cfa (unwind_ops, 0, 0, ARMREG_SP, 0);
+ mono_add_unwind_op_def_cfa_offset (unwind_ops, 4, 0, 4 * sizeof (mgreg_t));
+ save_unwind_info (acfg, symbol, unwind_ops);
+ mono_free_unwind_info (unwind_ops);
+
+ sprintf (symbol, "%sgsharedvt_trampolines_page_sp_p", acfg->user_symbol_prefix);
+ mono_add_unwind_op_def_cfa (unwind_ops, 0, 0, ARMREG_SP, 0);
+ save_unwind_info (acfg, symbol, unwind_ops);
+ mono_free_unwind_info (unwind_ops);
+
+ /* Unwind info for imt trampolines */
+ sprintf (symbol, "%simt_trampolines_page_gen_p", acfg->user_symbol_prefix);
+ mono_add_unwind_op_def_cfa (unwind_ops, 0, 0, ARMREG_SP, 0);
+ mono_add_unwind_op_def_cfa_offset (unwind_ops, 4, 0, 3 * sizeof (mgreg_t));
+ save_unwind_info (acfg, symbol, unwind_ops);
+ mono_free_unwind_info (unwind_ops);
+
+ sprintf (symbol, "%simt_trampolines_page_sp_p", acfg->user_symbol_prefix);
+ mono_add_unwind_op_def_cfa (unwind_ops, 0, 0, ARMREG_SP, 0);
+ save_unwind_info (acfg, symbol, unwind_ops);
+ mono_free_unwind_info (unwind_ops);
#elif defined(TARGET_ARM64)
arm64_emit_specific_trampoline_pages (acfg);
#endif
/* FIXME: Could this clobber the register needed by get_vcall_slot () ? */
- /* We clobber ECX, since EAX is used as MONO_ARCH_MONITOR_OBJECT_REG */
-#ifdef MONO_ARCH_MONITOR_OBJECT_REG
- g_assert (MONO_ARCH_MONITOR_OBJECT_REG != X86_ECX);
-#ifdef MONO_ARCH_MONITOR_LOCK_TAKEN_REG
- g_assert (MONO_ARCH_MONITOR_LOCK_TAKEN_REG != X86_ECX);
-#endif
-#endif
-
code = buf;
/* Load mscorlib got address */
x86_mov_reg_membase (code, X86_ECX, MONO_ARCH_GOT_REG, sizeof (gpointer), 4);
case MONO_PATCH_INFO_JIT_ICALL_ADDR:
case MONO_PATCH_INFO_ICALL_ADDR:
case MONO_PATCH_INFO_RGCTX_FETCH:
- case MONO_PATCH_INFO_MONITOR_ENTER:
- case MONO_PATCH_INFO_MONITOR_ENTER_V4:
- case MONO_PATCH_INFO_MONITOR_EXIT:
case MONO_PATCH_INFO_LLVM_IMT_TRAMPOLINE:
return TRUE;
default:
encode_patch (acfg, entry->data, p, &p);
break;
}
- case MONO_PATCH_INFO_MONITOR_ENTER:
- case MONO_PATCH_INFO_MONITOR_ENTER_V4:
- case MONO_PATCH_INFO_MONITOR_EXIT:
case MONO_PATCH_INFO_SEQ_POINT_INFO:
break;
case MONO_PATCH_INFO_LLVM_IMT_TRAMPOLINE:
static G_GNUC_UNUSED void
emit_trampoline (MonoAotCompile *acfg, int got_offset, MonoTrampInfo *info)
{
- emit_trampoline_full (acfg, got_offset, info, FALSE);
+ emit_trampoline_full (acfg, got_offset, info, TRUE);
}
static void
emit_trampoline (acfg, acfg->got_offset, info);
}
-#if defined(MONO_ARCH_MONITOR_OBJECT_REG)
- mono_arch_create_monitor_enter_trampoline (&info, FALSE, TRUE);
- emit_trampoline (acfg, acfg->got_offset, info);
-#if defined(MONO_ARCH_MONITOR_LOCK_TAKEN_REG)
- mono_arch_create_monitor_enter_trampoline (&info, TRUE, TRUE);
- emit_trampoline (acfg, acfg->got_offset, info);
-#endif
- mono_arch_create_monitor_exit_trampoline (&info, TRUE);
- emit_trampoline (acfg, acfg->got_offset, info);
-#endif
-
/* Emit the exception related code pieces */
mono_arch_get_restore_context (&info, TRUE);
emit_trampoline (acfg, acfg->got_offset, info);
emit_code (MonoAotCompile *acfg)
{
int oindex, i, prev_index;
+ gboolean saved_unbox_info = FALSE;
char symbol [256];
#if defined(TARGET_POWERPC64)
if (acfg->thumb_mixed && cfg->compile_llvm)
emit_set_arm_mode (acfg);
+
+ if (!saved_unbox_info) {
+ char user_symbol [128];
+ GSList *unwind_ops;
+ sprintf (user_symbol, "%sunbox_trampoline_p", acfg->user_symbol_prefix);
+
+ emit_label (acfg, "ut_end");
+
+ unwind_ops = mono_unwind_get_cie_program ();
+ save_unwind_info (acfg, user_symbol, unwind_ops);
+ mono_free_unwind_info (unwind_ops);
+
+ /* Save the unbox trampoline size */
+ emit_symbol_diff (acfg, "ut_end", symbol, 0);
+
+ saved_unbox_info = TRUE;
+ }
}
if (cfg->compile_llvm)
tmp_outfile_name = g_strdup_printf ("%s.tmp", outfile_name);
if (acfg->llvm) {
- llvm_ofile = g_strdup (acfg->llvm_ofile);
+ llvm_ofile = g_strdup_printf ("\"%s\"", acfg->llvm_ofile);
} else {
llvm_ofile = g_strdup ("");
}
g_strdelimit (ld_flags, ";", ' ');
#ifdef LD_NAME
- command = g_strdup_printf ("%s -o %s %s %s.o %s", LD_NAME, tmp_outfile_name, llvm_ofile, acfg->tmpfname, ld_flags);
+ command = g_strdup_printf ("%s -o \"%s\" %s \"%s.o\" %s", LD_NAME, tmp_outfile_name, llvm_ofile, acfg->tmpfname, ld_flags);
#else
command = g_strdup_printf ("\"%sld\" %s -shared -o %s %s %s.o %s", tool_prefix, LD_OPTIONS, tmp_outfile_name, llvm_ofile,
acfg->tmpfname, ld_flags);
rename (tmp_outfile_name, outfile_name);
#if defined(TARGET_MACH)
- command = g_strdup_printf ("dsymutil %s", outfile_name);
+ command = g_strdup_printf ("dsymutil \"%s\"", outfile_name);
aot_printf (acfg, "Executing dsymutil: %s\n", command);
if (execute_system (command) != 0) {
return 1;
#include <mono/metadata/metadata-internals.h>
#include <mono/metadata/marshal.h>
#include <mono/metadata/gc-internal.h>
-#include <mono/metadata/monitor.h>
#include <mono/metadata/threads-types.h>
#include <mono/metadata/mono-endian.h>
#include <mono/utils/mono-logger-internal.h>
int atype = decode_value (p, &p);
ref->method = mono_gc_get_managed_allocator_by_type (atype, !!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS));
- if (!ref->method) {
- fprintf (stderr, "Error: No managed allocator, but we need one for AOT.\nAre you using non-standard GC options?\n");
- exit (1);
- }
+ if (!ref->method)
+ g_error ("Error: No managed allocator, but we need one for AOT.\nAre you using non-standard GC options?\n");
break;
}
case MONO_WRAPPER_WRITE_BARRIER:
}
if (!sofile && !globals) {
- if (mono_aot_only && assembly->image->tables [MONO_TABLE_METHOD].rows) {
- fprintf (stderr, "Failed to load AOT module '%s' in aot-only mode.\n", aot_name);
- exit (1);
- }
+ if (mono_aot_only && assembly->image->tables [MONO_TABLE_METHOD].rows)
+ g_error ("Failed to load AOT module '%s' in aot-only mode.\n", aot_name);
g_free (aot_name);
return;
}
if (!usable) {
if (mono_aot_only) {
- fprintf (stderr, "Failed to load AOT module '%s' while running in aot-only mode: %s.\n", aot_name, msg);
- exit (1);
+ g_error ("Failed to load AOT module '%s' while running in aot-only mode: %s.\n", aot_name, msg);
} else {
mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT: module %s is unusable: %s.\n", aot_name, msg);
}
init_gots (amodule);
+ /*
+ * Register the plt region as a single trampoline so we can unwind from this code
+ */
+ mono_tramp_info_register (
+ mono_tramp_info_create (
+ NULL,
+ amodule->plt,
+ amodule->plt_end - amodule->plt,
+ NULL,
+ mono_unwind_get_cie_program ()
+ ),
+ NULL
+ );
+
/*
* Since we store methoddef and classdef tokens when referring to methods/classes in
* referenced assemblies, we depend on the exact versions of the referenced assemblies.
if (amodule->out_of_date) {
mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT: Module %s is unusable because a dependency is out-of-date.\n", assembly->image->name);
- if (mono_aot_only) {
- fprintf (stderr, "Failed to load AOT module '%s' while running in aot-only mode because a dependency cannot be found or it is out of date.\n", aot_name);
- exit (1);
- }
+ if (mono_aot_only)
+ g_error ("Failed to load AOT module '%s' while running in aot-only mode because a dependency cannot be found or it is out of date.\n", aot_name);
}
else
mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT: loaded AOT Module for %s.\n", assembly->image->name);
table = (gint32*)p;
if (fde_count > 1) {
- /* mono_aot_personality () */
- g_assert (table [0] == -1);
- *code_start = amodule->methods [table [2]];
+ *code_start = amodule->methods [table [0]];
*code_end = (guint8*)amodule->methods [table [(fde_count - 1) * 2]] + table [fde_count * 2];
} else {
*code_start = NULL;
ji->data.offset = decode_value (p, &p);
break;
case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
- case MONO_PATCH_INFO_MONITOR_ENTER:
- case MONO_PATCH_INFO_MONITOR_ENTER_V4:
- case MONO_PATCH_INFO_MONITOR_EXIT:
case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR:
case MONO_PATCH_INFO_GC_NURSERY_START:
case MONO_PATCH_INFO_JIT_TLS_ID:
amodule_unlock (amodule);
if (!m) {
m = decode_resolve_method_ref_with_target (amodule, method, p, &p);
- if (m) {
+ /*
+ * Can't catche runtime invoke wrappers since it would break
+ * the check in decode_method_ref_with_target ().
+ */
+ if (m && m->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE) {
amodule_lock (amodule);
g_hash_table_insert (amodule->method_ref_to_method, orig_p, m);
amodule_unlock (amodule);
g_assert (res == 1);
target = mono_create_specific_trampoline (GUINT_TO_POINTER (slot), MONO_TRAMPOLINE_RGCTX_LAZY_FETCH, mono_get_root_domain (), NULL);
target = mono_create_ftnptr_malloc (target);
- } else if (!strcmp (ji->data.name, "specific_trampoline_monitor_enter")) {
- target = mono_create_specific_trampoline (NULL, MONO_TRAMPOLINE_MONITOR_ENTER, mono_get_root_domain (), NULL);
- target = mono_create_ftnptr_malloc (target);
- } else if (!strcmp (ji->data.name, "specific_trampoline_monitor_enter_v4")) {
- target = mono_create_specific_trampoline (NULL, MONO_TRAMPOLINE_MONITOR_ENTER_V4, mono_get_root_domain (), NULL);
- target = mono_create_ftnptr_malloc (target);
- } else if (!strcmp (ji->data.name, "specific_trampoline_monitor_exit")) {
- target = mono_create_specific_trampoline (NULL, MONO_TRAMPOLINE_MONITOR_EXIT, mono_get_root_domain (), NULL);
- target = mono_create_ftnptr_malloc (target);
} else if (!strcmp (ji->data.name, "mono_thread_get_and_clear_pending_exception")) {
target = mono_thread_get_and_clear_pending_exception;
} else if (!strcmp (ji->data.name, "debugger_agent_single_step_from_context")) {
gpointer
mono_aot_get_trampoline (const char *name)
{
- return mono_aot_get_trampoline_full (name, NULL);
+ MonoTrampInfo *out_tinfo;
+ gpointer code;
+
+ code = mono_aot_get_trampoline_full (name, &out_tinfo);
+ mono_tramp_info_register (out_tinfo, NULL);
+
+ return code;
+}
+
+static gpointer
+read_unwind_info (MonoAotModule *amodule, MonoTrampInfo *info, const char *symbol_name)
+{
+ gpointer symbol_addr;
+ guint32 uw_offset, uw_info_len;
+ guint8 *uw_info;
+
+ find_symbol (amodule->sofile, amodule->globals, symbol_name, &symbol_addr);
+
+ if (!symbol_addr)
+ return NULL;
+
+ uw_offset = *(guint32*)symbol_addr;
+ uw_info = amodule->unwind_info + uw_offset;
+ uw_info_len = decode_value (uw_info, &uw_info);
+
+ info->uw_info = uw_info;
+ info->uw_info_len = uw_info_len;
+
+ /* If successful return the address of the following data */
+ return (guint32*)symbol_addr + 1;
}
#ifdef MONOTOUCH
static TrampolinePage* trampoline_pages [MONO_AOT_TRAMP_NUM];
+static void
+read_page_trampoline_uwinfo (MonoTrampInfo *info, int tramp_type, gboolean is_generic)
+{
+ char symbol_name [128];
+
+ if (tramp_type == MONO_AOT_TRAMP_SPECIFIC)
+ sprintf (symbol_name, "specific_trampolines_page_%s_p", is_generic ? "gen" : "sp");
+ else if (tramp_type == MONO_AOT_TRAMP_STATIC_RGCTX)
+ sprintf (symbol_name, "rgctx_trampolines_page_%s_p", is_generic ? "gen" : "sp");
+ else if (tramp_type == MONO_AOT_TRAMP_IMT_THUNK)
+ sprintf (symbol_name, "imt_trampolines_page_%s_p", is_generic ? "gen" : "sp");
+ else if (tramp_type == MONO_AOT_TRAMP_GSHAREDVT_ARG)
+ sprintf (symbol_name, "gsharedvt_trampolines_page_%s_p", is_generic ? "gen" : "sp");
+ else
+ g_assert_not_reached ();
+
+ read_unwind_info (mono_defaults.corlib->aot_module, info, symbol_name);
+}
+
static unsigned char*
get_new_trampoline_from_page (int tramp_type)
{
count = 40;
page = NULL;
while (page == NULL && count-- > 0) {
+ MonoTrampInfo *gen_info, *sp_info;
+
addr = 0;
/* allocate two contiguous pages of memory: the first page will contain the data (like a local constant pool)
* while the second will contain the trampolines.
code = page->trampolines;
page->trampolines += specific_trampoline_size;
mono_aot_page_unlock ();
+
+ /* Register the generic part at the beggining of the trampoline page */
+ gen_info = mono_tramp_info_create (NULL, (guint8*)taddr, amodule->info.tramp_page_code_offsets [tramp_type], NULL, NULL);
+ read_page_trampoline_uwinfo (gen_info, tramp_type, TRUE);
+ mono_tramp_info_register (gen_info, NULL);
+ /*
+ * FIXME
+ * Registering each specific trampoline produces a lot of
+ * MonoJitInfo structures. Jump trampolines are also registered
+ * separately.
+ */
+ if (tramp_type != MONO_AOT_TRAMP_SPECIFIC) {
+ /* Register the rest of the page as a single trampoline */
+ sp_info = mono_tramp_info_create (NULL, code, page->trampolines_end - code, NULL, NULL);
+ read_page_trampoline_uwinfo (sp_info, tramp_type, FALSE);
+ mono_tramp_info_register (sp_info, NULL);
+ }
return code;
}
g_error ("Cannot allocate more trampoline pages: %d", ret);
}
/* Return a given kind of trampoline */
+/* FIXME set unwind info for these trampolines */
static gpointer
get_numerous_trampoline (MonoAotTrampoline tramp_type, int n_got_slots, MonoAotModule **out_amodule, guint32 *got_offset, guint32 *out_tramp_size)
{
gpointer code;
guint32 *ut, *ut_end, *entry;
int low, high, entry_index = 0;
+ gpointer symbol_addr;
+ MonoTrampInfo *tinfo;
if (method->is_inflated && !mono_method_is_generic_sharable_full (method, FALSE, FALSE, FALSE)) {
method_index = find_aot_method (method, &amodule);
code = get_call_table_entry (amodule->unbox_trampoline_addresses, entry_index);
g_assert (code);
+ tinfo = mono_tramp_info_create (NULL, code, 0, NULL, NULL);
+
+ symbol_addr = read_unwind_info (amodule, tinfo, "unbox_trampoline_p");
+ if (!symbol_addr) {
+ mono_tramp_info_free (tinfo);
+ return FALSE;
+ }
+
+ tinfo->code_size = *(guint32*)symbol_addr;
+ mono_tramp_info_register (tinfo, NULL);
+
/* The caller expects an ftnptr */
return mono_create_ftnptr (mono_domain_get (), code);
}
gc_liveness_use: len:0
gc_spill_slot_liveness_def: len:0
gc_param_slot_liveness_def: len:0
+gc_safe_point: clob:c src1:i len:40
atomic_add_i4: dest:i src1:i src2:i len:64
atomic_exchange_i4: dest:i src1:i src2:i len:64
jump_table: dest:i len:8
-atomic_add_i4: src1:b src2:i dest:i len:20
+atomic_add_i4: src1:b src2:i dest:i len:28
atomic_cas_i4: src1:b src2:i src3:i dest:i len:38
call: dest:a clob:c len:17
tailcall: len:120 clob:c
br: len:5
-seq_point: len:17
+seq_point: len:24 clob:c
il_seq_point: len:0
int_beq: len:6
int nreply_packets;
#define dbg_lock() do { \
- MONO_TRY_BLOCKING \
+ MONO_TRY_BLOCKING; \
mono_mutex_lock (&debug_mutex); \
- MONO_FINISH_TRY_BLOCKING \
+ MONO_FINISH_TRY_BLOCKING; \
} while (0)
#define dbg_unlock() mono_mutex_unlock (&debug_mutex)
}
}
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
transport_connect (agent_config.address);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
if (!on_startup) {
/* Do some which is usually done after sending the VMStart () event */
}
}
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
conn_fd = socket_transport_accept (sfd);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
if (conn_fd == -1)
exit (1);
/* Write handshake message */
sprintf (handshake_msg, "DWP-Handshake");
/* Must use try blocking as this can nest into code that runs blocking */
- MONO_TRY_BLOCKING
+ MONO_TRY_BLOCKING;
do {
res = transport_send (handshake_msg, strlen (handshake_msg));
} while (res == -1 && get_last_sock_error () == MONO_EINTR);
- MONO_FINISH_TRY_BLOCKING
+ MONO_FINISH_TRY_BLOCKING;
g_assert (res != -1);
/* Read answer */
- MONO_TRY_BLOCKING
+ MONO_TRY_BLOCKING;
res = transport_recv (buf, strlen (handshake_msg));
- MONO_FINISH_TRY_BLOCKING
+ MONO_FINISH_TRY_BLOCKING;
if ((res != strlen (handshake_msg)) || (memcmp (buf, handshake_msg, strlen (handshake_msg)) != 0)) {
fprintf (stderr, "debugger-agent: DWP handshake failed.\n");
return FALSE;
if (!inited)
return;
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
transport_close1 ();
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
/*
* Wait for the thread to exit.
*/
if (GetCurrentThreadId () != debugger_thread_id) {
do {
- MONO_TRY_BLOCKING
+ MONO_TRY_BLOCKING;
mono_mutex_lock (&debugger_thread_exited_mutex);
if (!debugger_thread_exited)
mono_cond_wait (&debugger_thread_exited_cond, &debugger_thread_exited_mutex);
mono_mutex_unlock (&debugger_thread_exited_mutex);
- MONO_FINISH_TRY_BLOCKING
+ MONO_FINISH_TRY_BLOCKING;
} while (!debugger_thread_exited);
}
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
transport_close2 ();
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
}
static void
buffer_add_byte (&buf, command);
memcpy (buf.buf + 11, data->buf, data->p - data->buf);
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
res = transport_send (buf.buf, len);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
buffer_free (&buf);
buffer_add_buffer (&buf, packets [i].data);
}
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
res = transport_send (buf.buf, len);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
buffer_free (&buf);
{
GetLastFrameUserData *data = user_data;
- if (info->type == FRAME_TYPE_MANAGED_TO_NATIVE)
+ if (info->type == FRAME_TYPE_MANAGED_TO_NATIVE || info->type == FRAME_TYPE_TRAMPOLINE)
return FALSE;
if (!data->last_frame_set) {
// FIXME: Races when the thread leaves managed code before hitting a single step
// event.
- if (ji) {
+ if (ji && !ji->is_trampoline) {
/* Running managed code, will be suspended by the single step code */
DEBUG_PRINTF (1, "[%p] Received interrupt while at %s(%p), continuing.\n", (gpointer)(gsize)tid, jinfo_get_method (ji)->name, ip);
} else {
MonoJitInfo *ji;
data->valid_info = TRUE;
- ji = mono_jit_info_table_find (mono_thread_info_get_suspend_state (info)->unwind_data [MONO_UNWIND_DATA_DOMAIN], MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
+ ji = mono_jit_info_table_find_internal (
+ mono_thread_info_get_suspend_state (info)->unwind_data [MONO_UNWIND_DATA_DOMAIN],
+ MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx),
+ TRUE,
+ TRUE);
/* This is signal safe */
thread_interrupt (data->tls, info, ji);
{
mono_loader_lock ();
- MONO_TRY_BLOCKING
+ MONO_TRY_BLOCKING;
mono_mutex_lock (&suspend_mutex);
- MONO_FINISH_TRY_BLOCKING
+ MONO_FINISH_TRY_BLOCKING;
suspend_count ++;
mono_loader_lock ();
- MONO_TRY_BLOCKING
+ MONO_TRY_BLOCKING;
mono_mutex_lock (&suspend_mutex);
- MONO_FINISH_TRY_BLOCKING
+ MONO_FINISH_TRY_BLOCKING;
g_assert (suspend_count > 0);
suspend_count --;
tls = mono_g_hash_table_lookup (thread_to_tls, thread);
g_assert (tls);
- MONO_TRY_BLOCKING
+ MONO_TRY_BLOCKING;
mono_mutex_lock (&suspend_mutex);
- MONO_FINISH_TRY_BLOCKING
+ MONO_FINISH_TRY_BLOCKING;
g_assert (suspend_count > 0);
tls = mono_native_tls_get_value (debugger_tls_id);
g_assert (tls);
- MONO_TRY_BLOCKING
+ MONO_TRY_BLOCKING;
mono_mutex_lock (&suspend_mutex);
- MONO_FINISH_TRY_BLOCKING
+ MONO_FINISH_TRY_BLOCKING;
tls->suspending = FALSE;
tls->really_suspended = TRUE;
DEBUG_PRINTF (1, "[%p] Suspended.\n", (gpointer)GetCurrentThreadId ());
- MONO_TRY_BLOCKING
+ MONO_TRY_BLOCKING;
while (suspend_count - tls->resume_count > 0) {
err = mono_cond_wait (&suspend_cond, &suspend_mutex);
g_assert (err == 0);
}
- MONO_FINISH_TRY_BLOCKING
+ MONO_FINISH_TRY_BLOCKING;
tls->suspended = FALSE;
tls->really_suspended = FALSE;
info->il_offset = mono_debug_il_offset_from_address (method, info->domain, info->native_offset);
}
- DEBUG_PRINTF (1, "\tFrame: %s:%x(%x) %d\n", mono_method_full_name (method, TRUE), info->il_offset, info->native_offset, info->managed);
+ DEBUG_PRINTF (1, "\tFrame: %s:[il=0x%x, native=0x%x] %d\n", mono_method_full_name (method, TRUE), info->il_offset, info->native_offset, info->managed);
if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
if (!CHECK_PROTOCOL_VERSION (2, 17))
#endif
}
- DEBUG_PRINTF (1, "[dbg] Inserted breakpoint at %s:0x%x [%p](%d).\n", mono_method_full_name (jinfo_get_method (ji), TRUE), (int)it.seq_point.il_offset, inst->ip, count);
+ DEBUG_PRINTF (1, "[dbg] Inserted breakpoint at %s:[il=0x%x,native=0x%x] [%p](%d).\n", mono_method_full_name (jinfo_get_method (ji), TRUE), (int)it.seq_point.il_offset, (int)it.seq_point.native_offset, inst->ip, count);
}
static void
ip = MONO_CONTEXT_GET_IP (ctx);
ji = mini_jit_info_table_find (mono_domain_get (), (char*)ip, NULL);
- g_assert (ji);
+ g_assert (ji && !ji->is_trampoline);
method = jinfo_get_method (ji);
/* Compute the native offset of the breakpoint from the ip */
g_assert (found_sp);
- DEBUG_PRINTF (1, "[%p] Breakpoint hit, method=%s, ip=%p, offset=0x%x, sp il offset=0x%x.\n", (gpointer)GetCurrentThreadId (), method->name, ip, native_offset, sp.il_offset);
+ DEBUG_PRINTF (1, "[%p] Breakpoint hit, method=%s, ip=%p, [il=0x%x,native=0x%x].\n", (gpointer)GetCurrentThreadId (), method->name, ip, sp.il_offset, native_offset);
bp = NULL;
for (i = 0; i < breakpoints->len; ++i) {
}
ji = mini_jit_info_table_find (mono_domain_get (), (char*)ip, &domain);
- g_assert (ji);
+ g_assert (ji && !ji->is_trampoline);
method = jinfo_get_method (ji);
g_assert (method);
}
/* Block and wait for client connection */
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
conn_fd = socket_transport_accept (listen_fd);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
DEBUG_PRINTF (1, "Accepted connection on %d\n", conn_fd);
if (conn_fd == -1) {
}
while (!attach_failed) {
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
res = transport_recv (header, HEADER_LENGTH);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
/* This will break if the socket is closed during shutdown too */
if (res != HEADER_LENGTH) {
data = g_malloc (len - HEADER_LENGTH);
if (len - HEADER_LENGTH > 0)
{
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
res = transport_recv (data, len - HEADER_LENGTH);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
if (res != len - HEADER_LENGTH) {
DEBUG_PRINTF (1, "[dbg] transport_recv () returned %d, expected %d.\n", res, len - HEADER_LENGTH);
break;
mono_set_is_debugger_attached (FALSE);
- MONO_TRY_BLOCKING
+ MONO_TRY_BLOCKING;
mono_mutex_lock (&debugger_thread_exited_mutex);
debugger_thread_exited = TRUE;
mono_cond_signal (&debugger_thread_exited_cond);
mono_mutex_unlock (&debugger_thread_exited_mutex);
- MONO_FINISH_TRY_BLOCKING
+ MONO_FINISH_TRY_BLOCKING;
DEBUG_PRINTF (1, "[dbg] Debugger thread exited.\n");
}
/* Convert the list of MonoUnwindOps to the format used by DWARF */
- uw_info = mono_unwind_ops_encode (l, &uw_info_len);
+ uw_info = mono_unwind_ops_encode_full (l, &uw_info_len, FALSE);
emit_bytes (w, uw_info, uw_info_len);
g_free (uw_info);
guint8 *unwind_info;
guint8 *epilog = NULL;
- frame->type = FRAME_TYPE_MANAGED;
+ 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);
MonoTrampInfo *info = l->data;
mono_register_jit_icall (info->code, g_strdup (info->name), NULL, TRUE);
- mono_tramp_info_register (info);
+ mono_tramp_info_register (info, NULL);
}
g_slist_free (tramps);
}
MonoTrampInfo *info = l->data;
mono_register_jit_icall (info->code, g_strdup (info->name), NULL, TRUE);
- mono_tramp_info_register (info);
+ mono_tramp_info_register (info, NULL);
}
g_slist_free (tramps);
}
guint32 unwind_info_len;
guint8 *unwind_info;
- frame->type = FRAME_TYPE_MANAGED;
+ 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);
}
if (ji) {
- frame->type = FRAME_TYPE_MANAGED;
+ if (ji->is_trampoline)
+ frame->type = FRAME_TYPE_TRAMPOLINE;
+ else
+ frame->type = FRAME_TYPE_MANAGED;
frame->ji = ji;
//print_ctx (new_ctx);
guint32 unwind_info_len;
guint8 *unwind_info;
- frame->type = FRAME_TYPE_MANAGED;
+ 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);
guint32 unwind_info_len;
guint8 *unwind_info;
- frame->type = FRAME_TYPE_MANAGED;
+ 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);
sframe = (MonoPPCStackFrame*)MONO_CONTEXT_GET_SP (ctx);
MONO_CONTEXT_SET_BP (new_ctx, sframe->sp);
- if (jinfo_get_method (ji)->save_lmf) {
+ if (!ji->is_trampoline && jinfo_get_method (ji)->save_lmf) {
/* sframe->sp points just past the end of the LMF */
guint8 *lmf_addr = (guint8*)sframe->sp - sizeof (MonoLMF);
memcpy (&new_ctx->fregs, lmf_addr + G_STRUCT_OFFSET (MonoLMF, fregs), sizeof (double) * MONO_SAVED_FREGS);
const char *method;
/* we don't do much now, but we can warn the user with a useful message */
fprintf (stderr, "Stack overflow: IP: %p, SP: %p\n", mono_arch_ip_from_context (sigctx), (gpointer)UCONTEXT_REG_Rn(uc, 1));
- if (ji && jinfo_get_method (ji))
+ if (ji && !ji->is_trampoline && jinfo_get_method (ji))
method = mono_method_full_name (jinfo_get_method (ji), TRUE);
else
method = "Unmanaged";
guint8 *unwind_info;
mgreg_t regs[16];
- frame->type = FRAME_TYPE_MANAGED;
+ 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);
*new_ctx = *ctx;
if (ji != NULL) {
- frame->type = FRAME_TYPE_MANAGED;
+ if (ji->is_trampoline)
+ frame->type = FRAME_TYPE_TRAMPOLINE;
+ else
+ frame->type = FRAME_TYPE_MANAGED;
/* Restore ip and sp from the saved register window */
window = MONO_SPARC_WINDOW_ADDR (ctx->sp);
* <return addr> <- esp (unaligned on apple)
*/
- mono_add_unwind_op_def_cfa (unwind_ops, (guint8*)NULL, (guint8*)NULL, X86_ESP, 4);
- mono_add_unwind_op_offset (unwind_ops, (guint8*)NULL, (guint8*)NULL, X86_NREG, -4);
+ unwind_ops = mono_arch_get_cie_program ();
/* Alloc frame */
x86_alu_reg_imm (code, X86_SUB, X86_ESP, stack_size);
mono_arch_exceptions_init (void)
{
guint8 *tramp;
+ MonoTrampInfo *tinfo;
/*
* If we're running WoW64, we need to set the usermode exception policy
}
/* LLVM needs different throw trampolines */
- tramp = get_throw_trampoline ("llvm_throw_exception_trampoline", FALSE, TRUE, FALSE, FALSE, FALSE, NULL, FALSE);
+ tramp = get_throw_trampoline ("llvm_throw_exception_trampoline", FALSE, TRUE, FALSE, FALSE, FALSE, &tinfo, FALSE);
mono_register_jit_icall (tramp, "llvm_throw_exception_trampoline", NULL, TRUE);
+ mono_tramp_info_register (tinfo, NULL);
- tramp = get_throw_trampoline ("llvm_rethrow_exception_trampoline", TRUE, TRUE, FALSE, FALSE, FALSE, NULL, FALSE);
+ tramp = get_throw_trampoline ("llvm_rethrow_exception_trampoline", TRUE, TRUE, FALSE, FALSE, FALSE, &tinfo, FALSE);
mono_register_jit_icall (tramp, "llvm_rethrow_exception_trampoline", NULL, TRUE);
+ mono_tramp_info_register (tinfo, NULL);
- tramp = get_throw_trampoline ("llvm_throw_corlib_exception_trampoline", FALSE, TRUE, TRUE, FALSE, FALSE, NULL, FALSE);
+ tramp = get_throw_trampoline ("llvm_throw_corlib_exception_trampoline", FALSE, TRUE, TRUE, FALSE, FALSE, &tinfo, FALSE);
mono_register_jit_icall (tramp, "llvm_throw_corlib_exception_trampoline", NULL, TRUE);
+ mono_tramp_info_register (tinfo, NULL);
- tramp = get_throw_trampoline ("llvm_throw_corlib_exception_abs_trampoline", FALSE, TRUE, TRUE, TRUE, FALSE, NULL, FALSE);
+ tramp = get_throw_trampoline ("llvm_throw_corlib_exception_abs_trampoline", FALSE, TRUE, TRUE, TRUE, FALSE, &tinfo, FALSE);
mono_register_jit_icall (tramp, "llvm_throw_corlib_exception_abs_trampoline", NULL, TRUE);
+ mono_tramp_info_register (tinfo, NULL);
- tramp = get_throw_trampoline ("llvm_resume_unwind_trampoline", FALSE, FALSE, FALSE, FALSE, TRUE, NULL, FALSE);
+ tramp = get_throw_trampoline ("llvm_resume_unwind_trampoline", FALSE, FALSE, FALSE, FALSE, TRUE, &tinfo, FALSE);
mono_register_jit_icall (tramp, "llvm_resume_unwind_trampoline", NULL, TRUE);
+ mono_tramp_info_register (tinfo, NULL);
- signal_exception_trampoline = mono_x86_get_signal_exception_trampoline (NULL, FALSE);
+ signal_exception_trampoline = mono_x86_get_signal_exception_trampoline (&tinfo, FALSE);
+ mono_tramp_info_register (tinfo, NULL);
}
/*
guint32 unwind_info_len;
guint8 *unwind_info;
- frame->type = FRAME_TYPE_MANAGED;
+ 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);
start = code = mono_global_codeman_reserve (128);
+ /* FIXME no unwind before we push ip */
/* Caller ip */
x86_push_reg (code, X86_ECX);
- mono_add_unwind_op_def_cfa (unwind_ops, (guint8*)NULL, (guint8*)NULL, X86_ESP, 4);
- mono_add_unwind_op_offset (unwind_ops, (guint8*)NULL, (guint8*)NULL, X86_NREG, -4);
+ mono_add_unwind_op_def_cfa (unwind_ops, code, start, X86_ESP, 4);
+ mono_add_unwind_op_offset (unwind_ops, code, start, X86_NREG, -4);
/* Fix the alignment to be what apple expects */
stack_size = 12;
#include <mono/metadata/security-manager.h>
#include <mono/metadata/threads-types.h>
#include <mono/metadata/security-core-clr.h>
-#include <mono/metadata/monitor.h>
#include <mono/metadata/profiler-private.h>
#include <mono/metadata/profiler.h>
#include <mono/metadata/debug-mono-symfile.h>
/* helper methods signatures */
static MonoMethodSignature *helper_sig_domain_get;
static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
-static MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline;
-static MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline_llvm;
-static MonoMethodSignature *helper_sig_monitor_enter_v4_trampoline_llvm;
/*
* Instruction metadata
{
helper_sig_domain_get = mono_create_icall_signature ("ptr");
helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
- helper_sig_monitor_enter_exit_trampoline = mono_create_icall_signature ("void");
- helper_sig_monitor_enter_exit_trampoline_llvm = mono_create_icall_signature ("void object");
- helper_sig_monitor_enter_v4_trampoline_llvm = mono_create_icall_signature ("void object ptr");
}
static MONO_NEVER_INLINE void
g_hash_table_insert (h, (char*)"Decimal", GUINT_TO_POINTER (1));
g_hash_table_insert (h, (char*)"Number", GUINT_TO_POINTER (1));
g_hash_table_insert (h, (char*)"Buffer", GUINT_TO_POINTER (1));
+ g_hash_table_insert (h, (char*)"Monitor", GUINT_TO_POINTER (1));
mono_memory_barrier ();
direct_icall_type_hash = h;
}
return ins;
}
}
- } else if (cmethod->klass == mono_defaults.monitor_class) {
-#if defined(MONO_ARCH_MONITOR_OBJECT_REG)
- if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 1) {
- MonoCallInst *call;
-
- if (COMPILE_LLVM (cfg)) {
- /*
- * Pass the argument normally, the LLVM backend will handle the
- * calling convention problems.
- */
- call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
- } else {
- call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER,
- NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
- mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
- MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
- }
-
- return (MonoInst*)call;
-#if defined(MONO_ARCH_MONITOR_LOCK_TAKEN_REG)
- } else if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 2) {
- MonoCallInst *call;
-
- if (COMPILE_LLVM (cfg)) {
- /*
- * Pass the argument normally, the LLVM backend will handle the
- * calling convention problems.
- */
- call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER_V4, NULL, helper_sig_monitor_enter_v4_trampoline_llvm, args);
- } else {
- call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER_V4,
- NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
- mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg, MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
- mono_call_inst_add_outarg_reg (cfg, call, args [1]->dreg, MONO_ARCH_MONITOR_LOCK_TAKEN_REG, FALSE);
- }
-
- return (MonoInst*)call;
-#endif
- } else if (strcmp (cmethod->name, "Exit") == 0 && fsig->param_count == 1) {
- MonoCallInst *call;
-
- if (COMPILE_LLVM (cfg)) {
- call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
- } else {
- call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT,
- NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
- mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
- MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
- }
-
- return (MonoInst*)call;
- }
-#endif
} else if (cmethod->klass->image == mono_defaults.corlib &&
(strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
(strcmp (cmethod->klass->name, "Interlocked") == 0)) {
MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
MONO_ADD_INS (tblock, ins);
- if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY) {
+ if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FILTER) {
/* finally clauses already have a seq point */
+ /* seq points for filter clauses are emitted below */
NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
MONO_ADD_INS (tblock, ins);
}
*/
EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
#endif
+
+ if (seq_points && clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
+ NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
+ MONO_ADD_INS (tblock, ins);
+ }
if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
CHECK_CFG_ERROR;
}
+ /* See code below */
+ if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
+ MonoBasicBlock *tbb;
+
+ GET_BBLOCK (cfg, tbb, ip + 5);
+ if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
+ /*
+ * We want to extend the try block to cover the call, but we can't do it if the
+ * call is made directly since its followed by an exception check.
+ */
+ direct_icall = FALSE;
+ }
+ }
+
mono_save_token_info (cfg, image, token, cil_method);
if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
#define mono_mini_arch_unlock() mono_mutex_unlock (&mini_arch_mutex)
static mono_mutex_t mini_arch_mutex;
-MonoBreakpointInfo
-mono_breakpoint_info [MONO_BREAKPOINT_ARRAY_SIZE];
-
/*
* The code generated for sequence points reads from this location, which is
* made read-only when single stepping is enabled.
#define MAX_ARCH_DELEGATE_PARAMS 10
static gpointer
-get_delegate_invoke_impl (gboolean has_target, guint32 param_count, guint32 *code_len)
+get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, guint32 param_count)
{
guint8 *code, *start;
+ GSList *unwind_ops = NULL;
int i;
+ unwind_ops = mono_arch_get_cie_program ();
+
if (has_target) {
start = code = mono_global_codeman_reserve (64);
nacl_global_codeman_validate (&start, 64, &code);
mono_arch_flush_icache (start, code - start);
- if (code_len)
- *code_len = code - start;
+ if (has_target) {
+ *info = mono_tramp_info_create ("delegate_invoke_impl_has_target", start, code - start, NULL, unwind_ops);
+ } else {
+ char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", param_count);
+ *info = mono_tramp_info_create (name, start, code - start, NULL, unwind_ops);
+ g_free (name);
+ }
if (mono_jit_map_is_enabled ()) {
char *buff;
#define MAX_VIRTUAL_DELEGATE_OFFSET 32
static gpointer
-get_delegate_virtual_invoke_impl (gboolean load_imt_reg, int offset, guint32 *code_len)
+get_delegate_virtual_invoke_impl (MonoTrampInfo **info, gboolean load_imt_reg, int offset)
{
guint8 *code, *start;
int size = 20;
+ char *tramp_name;
+ GSList *unwind_ops;
- if (offset / sizeof (gpointer) > MAX_VIRTUAL_DELEGATE_OFFSET)
+ if (offset / (int)sizeof (gpointer) > MAX_VIRTUAL_DELEGATE_OFFSET)
return NULL;
start = code = mono_global_codeman_reserve (size);
+ unwind_ops = mono_arch_get_cie_program ();
+
/* Replace the this argument with the target */
amd64_mov_reg_reg (code, AMD64_RAX, AMD64_ARG_REG1, 8);
amd64_mov_reg_membase (code, AMD64_ARG_REG1, AMD64_RAX, MONO_STRUCT_OFFSET (MonoDelegate, target), 8);
amd64_jump_membase (code, AMD64_RAX, offset);
mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL);
- if (code_len)
- *code_len = code - start;
+ if (load_imt_reg)
+ tramp_name = g_strdup_printf ("delegate_virtual_invoke_imt_%d", - offset / sizeof (gpointer));
+ else
+ tramp_name = g_strdup_printf ("delegate_virtual_invoke_%d", offset / sizeof (gpointer));
+ *info = mono_tramp_info_create (tramp_name, start, code - start, NULL, unwind_ops);
+ g_free (tramp_name);
return start;
}
mono_arch_get_delegate_invoke_impls (void)
{
GSList *res = NULL;
- guint8 *code;
- guint32 code_len;
+ MonoTrampInfo *info;
int i;
- char *tramp_name;
- code = get_delegate_invoke_impl (TRUE, 0, &code_len);
- res = g_slist_prepend (res, mono_tramp_info_create ("delegate_invoke_impl_has_target", code, code_len, NULL, NULL));
+ get_delegate_invoke_impl (&info, TRUE, 0);
+ res = g_slist_prepend (res, info);
- for (i = 0; i < MAX_ARCH_DELEGATE_PARAMS; ++i) {
- code = get_delegate_invoke_impl (FALSE, i, &code_len);
- tramp_name = g_strdup_printf ("delegate_invoke_impl_target_%d", i);
- res = g_slist_prepend (res, mono_tramp_info_create (tramp_name, code, code_len, NULL, NULL));
- g_free (tramp_name);
+ for (i = 0; i <= MAX_ARCH_DELEGATE_PARAMS; ++i) {
+ get_delegate_invoke_impl (&info, FALSE, i);
+ res = g_slist_prepend (res, info);
}
- for (i = 0; i < MAX_VIRTUAL_DELEGATE_OFFSET; ++i) {
- code = get_delegate_virtual_invoke_impl (TRUE, i * SIZEOF_VOID_P, &code_len);
- tramp_name = g_strdup_printf ("delegate_virtual_invoke_imt_%d", i);
- res = g_slist_prepend (res, mono_tramp_info_create (tramp_name, code, code_len, NULL, NULL));
- g_free (tramp_name);
+ for (i = 0; i <= MAX_VIRTUAL_DELEGATE_OFFSET; ++i) {
+ get_delegate_virtual_invoke_impl (&info, TRUE, - i * SIZEOF_VOID_P);
+ res = g_slist_prepend (res, info);
- code = get_delegate_virtual_invoke_impl (FALSE, i * SIZEOF_VOID_P, &code_len);
- tramp_name = g_strdup_printf ("delegate_virtual_invoke_%d", i);
- res = g_slist_prepend (res, mono_tramp_info_create (tramp_name, code, code_len, NULL, NULL));
- g_free (tramp_name);
+ get_delegate_virtual_invoke_impl (&info, FALSE, i * SIZEOF_VOID_P);
+ res = g_slist_prepend (res, info);
}
return res;
if (cached)
return cached;
- if (mono_aot_only)
+ if (mono_aot_only) {
start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
- else
- start = get_delegate_invoke_impl (TRUE, 0, NULL);
+ } else {
+ MonoTrampInfo *info;
+ start = get_delegate_invoke_impl (&info, TRUE, 0);
+ mono_tramp_info_register (info, NULL);
+ }
mono_memory_barrier ();
start = mono_aot_get_trampoline (name);
g_free (name);
} else {
- start = get_delegate_invoke_impl (FALSE, sig->param_count, NULL);
+ MonoTrampInfo *info;
+ start = get_delegate_invoke_impl (&info, FALSE, sig->param_count);
+ mono_tramp_info_register (info, NULL);
}
mono_memory_barrier ();
gpointer
mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method, int offset, gboolean load_imt_reg)
{
- return get_delegate_virtual_invoke_impl (load_imt_reg, offset, NULL);
+ MonoTrampInfo *info;
+ gpointer code;
+
+ code = get_delegate_virtual_invoke_impl (&info, load_imt_reg, offset);
+ if (code)
+ mono_tramp_info_register (info, NULL);
+ return code;
}
void
int size = 0;
guint8 *code, *start;
gboolean vtable_is_32bit = ((gsize)(vtable) == (gsize)(int)(gsize)(vtable));
+ GSList *unwind_ops;
for (i = 0; i < count; ++i) {
MonoIMTCheckItem *item = imt_entries [i];
code = mono_domain_code_reserve (domain, size);
#endif
start = code;
+
+ unwind_ops = mono_arch_get_cie_program ();
+
for (i = 0; i < count; ++i) {
MonoIMTCheckItem *item = imt_entries [i];
item->code_target = code;
nacl_domain_code_validate(domain, &start, size, &code);
mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_IMT_TRAMPOLINE, NULL);
+ mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), domain);
+
return start;
}
#define MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK 1
#define MONO_ARCH_HAVE_LIVERANGE_OPS 1
#define MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX 1
-#define MONO_ARCH_MONITOR_OBJECT_REG MONO_AMD64_ARG_REG1
-#define MONO_ARCH_MONITOR_LOCK_TAKEN_REG MONO_AMD64_ARG_REG2
#define MONO_ARCH_HAVE_GET_TRAMPOLINES 1
#define MONO_ARCH_AOT_SUPPORTED 1
int
mono_amd64_get_tls_gs_offset (void) MONO_LLVM_INTERNAL;
-typedef struct {
- guint8 *address;
- guint8 saved_byte;
-} MonoBreakpointInfo;
-
-extern MonoBreakpointInfo mono_breakpoint_info [MONO_BREAKPOINT_ARRAY_SIZE];
-
#ifdef TARGET_WIN32
void mono_arch_unwindinfo_add_push_nonvol (gpointer* monoui, gpointer codebegin, gpointer nextip, guchar reg );
* within can be tracked. The tls value is returned in R0.
*/
+.macro DECLARE_GLOBAL_SYMBOL name
+#ifdef TARGET_MACH
+ .global _\name
+_\name:
+#else
+ .global \name
+\name:
+#endif
+.endm
+
.text
/* no .arch on clang. it only supports armv6+ anyway */
#ifndef TARGET_MACH
#endif
.arm
.align 4
-#ifdef TARGET_MACH
- .global _mono_fast_get_tls_key
-_mono_fast_get_tls_key :
-#else
- .global mono_fast_get_tls_key
-mono_fast_get_tls_key :
-#endif
+
+DECLARE_GLOBAL_SYMBOL mono_fast_get_tls_key
#if defined(__linux__)
mrc p15, 0, r1, c13, c0, 3
#if defined(HAVE_KW_THREAD)
ldr r0, [r1, r0, lsl #2]
bx lr
#endif
+DECLARE_GLOBAL_SYMBOL mono_fast_get_tls_key_end
/*
* The following thunks fetch the value corresponding to the key/offset
*/
.align 4
-#ifdef TARGET_MACH
- .global _mono_fallback_get_tls_key
-_mono_fallback_get_tls_key :
-#else
- .global mono_fallback_get_tls_key
-mono_fallback_get_tls_key :
-#endif
+DECLARE_GLOBAL_SYMBOL mono_fallback_get_tls_key
#if defined(__linux__)
mov r1, r0
mvn r0, #0xf000
*/
.align 4
-#ifdef TARGET_MACH
- .global _mono_fast_set_tls_key
-_mono_fast_set_tls_key :
-#else
- .global mono_fast_set_tls_key
-mono_fast_set_tls_key :
-#endif
+DECLARE_GLOBAL_SYMBOL mono_fast_set_tls_key
#if defined(__linux__)
mrc p15, 0, r2, c13, c0, 3
#if defined(HAVE_KW_THREAD)
str r1, [r2, r0, lsl #2]
bx lr
#endif
+DECLARE_GLOBAL_SYMBOL mono_fast_set_tls_key_end
/*
* The following thunks set the value corresponding to the key/offset
*/
.align 4
-#ifdef TARGET_MACH
- .global _mono_fallback_set_tls_key
-_mono_fallback_set_tls_key :
-#else
- .global mono_fallback_set_tls_key
-mono_fallback_set_tls_key :
-#endif
+DECLARE_GLOBAL_SYMBOL mono_fallback_set_tls_key
#if defined(__linux__)
mov r2, r0
mvn r0, #0xf000
int mono_fallback_get_tls_key (int);
void mono_fallback_set_tls_key (int, int);
+/* End of thunks */
+
+void mono_fast_get_tls_key_end (void);
+void mono_fast_set_tls_key_end (void);
+
#endif
#define MAX_ARCH_DELEGATE_PARAMS 3
static gpointer
-get_delegate_invoke_impl (gboolean has_target, gboolean param_count, guint32 *code_size)
+get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, gboolean param_count)
{
guint8 *code, *start;
+ GSList *unwind_ops = mono_arch_get_cie_program ();
if (has_target) {
start = code = mono_global_codeman_reserve (12);
mono_arch_flush_icache (start, size);
}
+ if (has_target) {
+ *info = mono_tramp_info_create ("delegate_invoke_impl_has_target", start, code - start, NULL, unwind_ops);
+ } else {
+ char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", param_count);
+ *info = mono_tramp_info_create (name, start, code - start, NULL, unwind_ops);
+ g_free (name);
+ }
+
mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL);
- if (code_size)
- *code_size = code - start;
return start;
}
mono_arch_get_delegate_invoke_impls (void)
{
GSList *res = NULL;
- guint8 *code;
- guint32 code_len;
+ MonoTrampInfo *info;
int i;
- char *tramp_name;
- code = get_delegate_invoke_impl (TRUE, 0, &code_len);
- res = g_slist_prepend (res, mono_tramp_info_create ("delegate_invoke_impl_has_target", code, code_len, NULL, NULL));
+ get_delegate_invoke_impl (&info, TRUE, 0);
+ res = g_slist_prepend (res, info);
for (i = 0; i <= MAX_ARCH_DELEGATE_PARAMS; ++i) {
- code = get_delegate_invoke_impl (FALSE, i, &code_len);
- tramp_name = g_strdup_printf ("delegate_invoke_impl_target_%d", i);
- res = g_slist_prepend (res, mono_tramp_info_create (tramp_name, code, code_len, NULL, NULL));
- g_free (tramp_name);
+ get_delegate_invoke_impl (&info, FALSE, i);
+ res = g_slist_prepend (res, info);
}
return res;
return cached;
}
- if (mono_aot_only)
+ if (mono_aot_only) {
start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
- else
- start = get_delegate_invoke_impl (TRUE, 0, NULL);
+ } else {
+ MonoTrampInfo *info;
+ start = get_delegate_invoke_impl (&info, TRUE, 0);
+ mono_tramp_info_register (info, NULL);
+ }
cached = start;
mono_mini_arch_unlock ();
return cached;
start = mono_aot_get_trampoline (name);
g_free (name);
} else {
- start = get_delegate_invoke_impl (FALSE, sig->param_count, NULL);
+ MonoTrampInfo *info;
+ start = get_delegate_invoke_impl (&info, FALSE, sig->param_count);
+ mono_tramp_info_register (info, NULL);
}
cache [sig->param_count] = start;
mono_mini_arch_unlock ();
/* Free entry */
target_thunk = p;
break;
+ } else if (((guint32*)p) [2] == (guint32)target) {
+ /* Thunk already points to target */
+ target_thunk = p;
+ break;
}
}
}
ins->backend.pc_offset = code - cfg->native_code;
bb->spill_slot_defs = g_slist_prepend_mempool (cfg->mempool, bb->spill_slot_defs, ins);
break;
+ case OP_GC_SAFE_POINT: {
+#if defined (USE_COOP_GC)
+ const char *polling_func = NULL;
+ guint8 *buf [1];
+
+ polling_func = "mono_threads_state_poll";
+ ARM_LDR_IMM (code, ARMREG_IP, ins->sreg1, 0);
+ ARM_CMP_REG_IMM (code, ARMREG_IP, 0, 0);
+ buf [0] = code;
+ ARM_B_COND (code, ARMCOND_EQ, 0);
+ mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, polling_func);
+ code = emit_call_seq (cfg, code);
+ arm_patch (buf [0], code);
+#endif
+ break;
+ }
default:
g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
if (mono_arm_have_fast_tls ()) {
mono_register_jit_icall (mono_fast_get_tls_key, "mono_get_tls_key", mono_create_icall_signature ("ptr ptr"), TRUE);
mono_register_jit_icall (mono_fast_set_tls_key, "mono_set_tls_key", mono_create_icall_signature ("void ptr ptr"), TRUE);
+
+ mono_tramp_info_register (
+ mono_tramp_info_create (
+ "mono_get_tls_key",
+ (guint8*)mono_fast_get_tls_key,
+ (guint8*)mono_fast_get_tls_key_end - (guint8*)mono_fast_get_tls_key,
+ NULL,
+ mono_arch_get_cie_program ()
+ ),
+ NULL
+ );
+ mono_tramp_info_register (
+ mono_tramp_info_create (
+ "mono_set_tls_key",
+ (guint8*)mono_fast_set_tls_key,
+ (guint8*)mono_fast_set_tls_key_end - (guint8*)mono_fast_set_tls_key,
+ NULL,
+ mono_arch_get_cie_program ()
+ ),
+ NULL
+ );
} else {
g_warning ("No fast tls on device. Using fallbacks.");
mono_register_jit_icall (mono_fallback_get_tls_key, "mono_get_tls_key", mono_create_icall_signature ("ptr ptr"), TRUE);
* FIXME: Optimize this.
*/
ARM_PUSH (code, (1 << ARMREG_R7) | (1 << ARMREG_LR));
- ARM_MOV_REG_REG (code, ARMREG_R7, ARMREG_SP);
prev_sp_offset += 8; /* r7 and lr */
mono_emit_unwind_op_def_cfa_offset (cfg, code, prev_sp_offset);
mono_emit_unwind_op_offset (cfg, code, ARMREG_R7, (- prev_sp_offset) + 0);
+ ARM_MOV_REG_REG (code, ARMREG_R7, ARMREG_SP);
}
if (!method->save_lmf) {
*/
code = cfg->native_code + cfg->code_len;
+ /* Save the uwind state which is needed by the out-of-line code */
+ mono_emit_unwind_op_remember_state (cfg, code);
+
if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
}
}
if (method->save_lmf) {
- int lmf_offset, reg, sp_adj, regmask;
+ int lmf_offset, reg, sp_adj, regmask, nused_int_regs = 0;
/* all but r0-r3, sp and pc */
pos += sizeof (MonoLMF) - (MONO_ARM_NUM_SAVED_REGS * sizeof (mgreg_t));
lmf_offset = pos;
regmask &= ~(1 << ARMREG_PC);
/* point sp at the registers to restore: 10 is 14 -4, because we skip r0-r3 */
code = emit_big_add (code, ARMREG_SP, cfg->frame_reg, cfg->stack_usage - lmf_offset + sp_adj);
+ for (i = 0; i < 16; i++) {
+ if (regmask & (1 << i))
+ nused_int_regs ++;
+ }
+ mono_emit_unwind_op_def_cfa (cfg, code, ARMREG_SP, ((iphone_abi ? 3 : 0) + nused_int_regs) * 4);
/* restore iregs */
ARM_POP (code, regmask);
if (iphone_abi) {
+ for (i = 0; i < 16; i++) {
+ if (regmask & (1 << i))
+ mono_emit_unwind_op_same_value (cfg, code, i);
+ }
/* Restore saved r7, restore LR to PC */
/* Skip lr from the lmf */
+ mono_emit_unwind_op_def_cfa_offset (cfg, code, 3 * 4);
ARM_ADD_REG_IMM (code, ARMREG_SP, ARMREG_SP, sizeof (gpointer), 0);
+ mono_emit_unwind_op_def_cfa_offset (cfg, code, 2 * 4);
ARM_POP (code, (1 << ARMREG_R7) | (1 << ARMREG_PC));
}
} else {
+ int i, nused_int_regs = 0;
+
+ for (i = 0; i < 16; i++) {
+ if (cfg->used_int_regs & (1 << i))
+ nused_int_regs ++;
+ }
+
if ((i = mono_arm_is_rotated_imm8 (cfg->stack_usage, &rot_amount)) >= 0) {
ARM_ADD_REG_IMM (code, ARMREG_SP, cfg->frame_reg, i, rot_amount);
} else {
ARM_ADD_REG_REG (code, ARMREG_SP, cfg->frame_reg, ARMREG_IP);
}
+ if (cfg->frame_reg != ARMREG_SP) {
+ mono_emit_unwind_op_def_cfa_reg (cfg, code, ARMREG_SP);
+ }
+
if (iphone_abi) {
/* Restore saved gregs */
- if (cfg->used_int_regs)
+ if (cfg->used_int_regs) {
+ mono_emit_unwind_op_def_cfa_offset (cfg, code, (2 + nused_int_regs) * 4);
ARM_POP (code, cfg->used_int_regs);
+ for (i = 0; i < 16; i++) {
+ if (cfg->used_int_regs & (1 << i))
+ mono_emit_unwind_op_same_value (cfg, code, i);
+ }
+ }
+ mono_emit_unwind_op_def_cfa_offset (cfg, code, 2 * 4);
/* Restore saved r7, restore LR to PC */
ARM_POP (code, (1 << ARMREG_R7) | (1 << ARMREG_PC));
} else {
+ mono_emit_unwind_op_def_cfa_offset (cfg, code, (nused_int_regs + 1) * 4);
ARM_POP (code, cfg->used_int_regs | (1 << ARMREG_PC));
}
}
+ /* Restore the unwind state to be the same as before the epilog */
+ mono_emit_unwind_op_restore_state (cfg, code);
+
cfg->code_len = code - cfg->native_code;
g_assert (cfg->code_len < cfg->code_size);
return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
}
+GSList*
+mono_arch_get_cie_program (void)
+{
+ GSList *l = NULL;
+
+ mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, ARMREG_SP, 0);
+
+ return l;
+}
+
/* #define ENABLE_WRONG_METHOD_CHECK 1 */
#define BASE_SIZE (6 * 4)
#define BSEARCH_ENTRY_SIZE (4 * 4)
#ifdef ENABLE_WRONG_METHOD_CHECK
char * cond;
#endif
+ GSList *unwind_ops;
size = BASE_SIZE;
#ifdef USE_JUMP_TABLES
code = mono_domain_code_reserve (domain, size);
start = code;
+ unwind_ops = mono_arch_get_cie_program ();
+
#ifdef DEBUG_IMT
g_print ("Building IMT thunk for class %s %s entries %d code size %d code at %p end %p vtable %p fail_tramp %p\n", vtable->klass->name_space, vtable->klass->name, count, size, start, ((guint8*)start) + size, vtable, fail_tramp);
for (i = 0; i < count; ++i) {
#ifdef USE_JUMP_TABLES
ARM_PUSH3 (code, ARMREG_R0, ARMREG_R1, ARMREG_R2);
+ mono_add_unwind_op_def_cfa_offset (unwind_ops, code, start, 3 * sizeof (mgreg_t));
#define VTABLE_JTI 0
#define IMT_METHOD_OFFSET 0
#define TARGET_CODE_OFFSET 1
ARM_LDR_IMM (code, ARMREG_IP, ARMREG_R2, VTABLE_JTI);
set_jumptable_element (jte, VTABLE_JTI, vtable);
#else
- if (large_offsets)
+ if (large_offsets) {
ARM_PUSH4 (code, ARMREG_R0, ARMREG_R1, ARMREG_IP, ARMREG_PC);
- else
+ mono_add_unwind_op_def_cfa_offset (unwind_ops, code, start, 4 * sizeof (mgreg_t));
+ } else {
ARM_PUSH2 (code, ARMREG_R0, ARMREG_R1);
+ mono_add_unwind_op_def_cfa_offset (unwind_ops, code, start, 2 * sizeof (mgreg_t));
+ }
ARM_LDR_IMM (code, ARMREG_R0, ARMREG_LR, -4);
vtable_target = code;
ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
code = load_element_with_regbase_cond (code, ARMREG_R1, ARMREG_R2, target_code_jti, ARMCOND_AL);
/* Restore registers */
ARM_POP3 (code, ARMREG_R0, ARMREG_R1, ARMREG_R2);
+ mono_add_unwind_op_def_cfa_offset (unwind_ops, code, start, 0);
/* And branch */
ARM_BX (code, ARMREG_R1);
set_jumptable_element (jte, target_code_jti, item->value.target_code);
ARM_LDR_REG_REG (code, ARMREG_IP, ARMREG_IP, ARMREG_R1);
/* Restore registers and branch */
ARM_POP3 (code, ARMREG_R0, ARMREG_R1, ARMREG_R2);
+ mono_add_unwind_op_def_cfa_offset (unwind_ops, code, start, 0);
ARM_BX (code, ARMREG_IP);
#else
vtable_offset_ins = code;
#ifdef USE_JUMP_TABLES
ARM_LDR_IMM (code, ARMREG_IP, ARMREG_IP, vtable_offset);
ARM_POP3 (code, ARMREG_R0, ARMREG_R1, ARMREG_R2);
+ mono_add_unwind_op_def_cfa_offset (unwind_ops, code, start, 0);
ARM_BX (code, ARMREG_IP);
#else
ARM_POP2 (code, ARMREG_R0, ARMREG_R1);
- if (large_offsets)
+ if (large_offsets) {
+ mono_add_unwind_op_def_cfa_offset (unwind_ops, code, start, 2 * sizeof (mgreg_t));
ARM_ADD_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, 2 * sizeof (gpointer));
+ }
+ mono_add_unwind_op_def_cfa_offset (unwind_ops, code, start, 0);
ARM_LDR_IMM (code, ARMREG_PC, ARMREG_IP, vtable_offset);
#endif
}
code = load_element_with_regbase_cond (code, ARMREG_R1, ARMREG_R2, target_code_jti, ARMCOND_AL);
/* Restore registers */
ARM_POP3 (code, ARMREG_R0, ARMREG_R1, ARMREG_R2);
+ mono_add_unwind_op_def_cfa_offset (unwind_ops, code, start, 0);
/* And branch */
ARM_BX (code, ARMREG_R1);
set_jumptable_element (jte, target_code_jti, fail_tramp);
mono_stats.imt_thunks_size += code - start;
g_assert (DISTANCE (start, code) <= size);
+
+ mono_tramp_info_register (mono_tramp_info_create (NULL, (guint8*)start, DISTANCE (start, code), NULL, unwind_ops), domain);
+
return start;
}
pid_t
mono_runtime_syscall_fork ()
{
+#ifdef HAVE_FORK
return (pid_t) fork ();
+#else
+ g_assert_not_reached ();
+#endif
}
void
mono_gdb_render_native_backtraces (pid_t crashed_pid)
{
+#ifdef HAVE_EXECV
const char *argv [5];
char template [] = "/tmp/mono-gdb-commands.XXXXXX";
FILE *commands;
execv (argv [0], (char**)argv);
unlink (template);
+#else
+ fprintf (stderr, "mono_gdb_render_native_backtraces not supported on this platform\n");
+#endif // HAVE_EXECV
}
gboolean
MonoTrampInfo *info;
restore_context_func = mono_arch_get_restore_context (&info, FALSE);
- mono_tramp_info_register (info);
+ mono_tramp_info_register (info, NULL);
call_filter_func = mono_arch_get_call_filter (&info, FALSE);
- mono_tramp_info_register (info);
+ mono_tramp_info_register (info, NULL);
throw_exception_func = mono_arch_get_throw_exception (&info, FALSE);
- mono_tramp_info_register (info);
+ mono_tramp_info_register (info, NULL);
rethrow_exception_func = mono_arch_get_rethrow_exception (&info, FALSE);
- mono_tramp_info_register (info);
+ mono_tramp_info_register (info, NULL);
}
#ifdef MONO_ARCH_HAVE_RESTORE_STACK_SUPPORT
try_more_restore_tramp = mono_create_specific_trampoline (try_more_restore, MONO_TRAMPOLINE_RESTORE_STACK_PROT, mono_domain_get (), NULL);
code = mono_aot_get_trampoline ("throw_corlib_exception");
else {
code = mono_arch_get_throw_corlib_exception (&info, FALSE);
- mono_tramp_info_register (info);
+ mono_tramp_info_register (info, NULL);
}
mono_memory_barrier ();
if (managed)
*managed = TRUE;
return frame.ji;
+ case FRAME_TYPE_TRAMPOLINE:
+ return frame.ji;
case FRAME_TYPE_MANAGED_TO_NATIVE:
if (frame.ji)
return frame.ji;
if (ji == (gpointer)-1)
return ji;
- if (ji)
+ if (ji && !ji->is_trampoline)
method = jinfo_get_method (ji);
- if (managed2 || (ji && method->wrapper_type)) {
+ if (managed2 || (method && method->wrapper_type)) {
const char *real_ip, *start;
gint32 offset;
*lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~(SIZEOF_VOID_P -1));
}
- if (frame->ji && !frame->ji->async)
+ if (frame->ji && !frame->ji->is_trampoline && !frame->ji->async)
method = jinfo_get_method (frame->ji);
if (frame->type == FRAME_TYPE_MANAGED && method) {
return TRUE;
}
+/*
+ * This function is async-safe.
+ */
static gpointer
get_generic_info_from_stack_frame (MonoJitInfo *ji, MonoContext *ctx)
{
gpointer ip = mono_array_get (ta, gpointer, i * 2 + 0);
gpointer generic_info = mono_array_get (ta, gpointer, i * 2 + 1);
- ji = mono_jit_info_table_find (domain, ip);
+ ji = mono_jit_info_table_find_internal (domain, ip, TRUE, TRUE);
if (ji == NULL) {
/* Unmanaged frame */
g_string_append_printf (trace_str, "in (unmanaged) %p\n", ip);
- } else {
+ } else if (!ji->is_trampoline) {
gchar *location;
gint32 address;
MonoMethod *method = get_method_from_stack_frame (ji, generic_info);
if (!res)
return;
- if ((unwind_options & MONO_UNWIND_LOOKUP_IL_OFFSET) && frame.ji) {
+ if ((unwind_options & MONO_UNWIND_LOOKUP_IL_OFFSET) && frame.ji && !frame.ji->is_trampoline) {
MonoDebugSourceLocation *source;
source = mono_debug_lookup_source_location (jinfo_get_method (frame.ji), frame.native_offset, domain);
frame.il_offset = il_offset;
- if ((unwind_options & MONO_UNWIND_LOOKUP_ACTUAL_METHOD) && frame.ji) {
+ if ((unwind_options & MONO_UNWIND_LOOKUP_ACTUAL_METHOD) && frame.ji && !frame.ji->is_trampoline) {
frame.actual_method = get_method_from_stack_frame (frame.ji, get_generic_info_from_stack_frame (frame.ji, &ctx));
} else {
frame.actual_method = frame.method;
if (!res)
return FALSE;
- if (frame.type == FRAME_TYPE_MANAGED_TO_NATIVE || frame.type == FRAME_TYPE_DEBUGGER_INVOKE)
+ if (frame.type == FRAME_TYPE_MANAGED_TO_NATIVE ||
+ frame.type == FRAME_TYPE_DEBUGGER_INVOKE ||
+ frame.type == FRAME_TYPE_TRAMPOLINE)
continue;
ji = frame.ji;
MonoJitInfo*
mini_jit_info_table_find (MonoDomain *domain, char *addr, MonoDomain **out_domain)
{
- return mini_jit_info_table_find_ext (domain, addr, FALSE, out_domain);
+ return mini_jit_info_table_find_ext (domain, addr, TRUE, out_domain);
}
/*
unwind_res = mono_find_jit_info_ext (domain, jit_tls, NULL, ctx, &new_ctx, NULL, &lmf, NULL, &frame);
if (unwind_res) {
- if (frame.type == FRAME_TYPE_DEBUGGER_INVOKE || frame.type == FRAME_TYPE_MANAGED_TO_NATIVE) {
+ if (frame.type == FRAME_TYPE_DEBUGGER_INVOKE ||
+ frame.type == FRAME_TYPE_MANAGED_TO_NATIVE ||
+ frame.type == FRAME_TYPE_TRAMPOLINE) {
*ctx = new_ctx;
continue;
}
unwind_res = mono_find_jit_info_ext (domain, jit_tls, NULL, ctx, &new_ctx, NULL, &lmf, NULL, &frame);
if (unwind_res) {
- if (frame.type == FRAME_TYPE_DEBUGGER_INVOKE || frame.type == FRAME_TYPE_MANAGED_TO_NATIVE) {
+ if (frame.type == FRAME_TYPE_DEBUGGER_INVOKE ||
+ frame.type == FRAME_TYPE_MANAGED_TO_NATIVE ||
+ frame.type == FRAME_TYPE_TRAMPOLINE) {
*ctx = new_ctx;
continue;
}
return 0;
}
- if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (ctx)) &&
- (ei->flags == MONO_EXCEPTION_CLAUSE_FAULT)) {
+ if (ei->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
if (mono_trace_is_enabled () && mono_trace_eval (method))
g_print ("EXCEPTION: fault clause %d of %s\n", i, mono_method_full_name (method, TRUE));
jit_tls->orig_ex_ctx_set = TRUE;
jit_tls->orig_ex_ctx_set = FALSE;
call_filter (ctx, ei->handler_start);
}
- if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (ctx)) &&
- (ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY)) {
+ if (ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
if (mono_trace_is_enabled () && mono_trace_eval (method))
g_print ("EXCEPTION: finally clause %d of %s\n", i, mono_method_full_name (method, TRUE));
jit_tls->orig_ex_ctx_set = TRUE;
PrintOverflowUserData *user_data = data;
gchar *location;
- if (frame->ji)
+ if (frame->ji && frame->type != FRAME_TYPE_TRAMPOLINE)
method = jinfo_get_method (frame->ji);
if (method) {
mono_walk_stack_with_ctx (print_overflow_stack_frame, &mctx, MONO_UNWIND_LOOKUP_ACTUAL_METHOD, &ud);
#else
- if (ji && jinfo_get_method (ji))
+ if (ji && !ji->is_trampoline && jinfo_get_method (ji))
mono_runtime_printf_err ("At %s", mono_method_full_name (jinfo_get_method (ji), TRUE));
else
mono_runtime_printf_err ("At <unmanaged>.");
{
MonoMethod *method = NULL;
- if (frame->ji)
+ if (frame->ji && frame->type != FRAME_TYPE_TRAMPOLINE)
method = jinfo_get_method (frame->ji);
if (method) {
GString *p = (GString*)data;
MonoMethod *method = NULL;
- if (frame->ji)
+ if (frame->ji && frame->type != FRAME_TYPE_TRAMPOLINE)
method = jinfo_get_method (frame->ji);
if (method && frame->domain) {
#endif
}
+void
+mono_thread_state_init (MonoThreadUnwindState *ctx)
+{
+ MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
+
+#if defined(MONO_CROSS_COMPILE)
+ ctx->valid = FALSE; //A cross compiler doesn't need to suspend.
+#elif MONO_ARCH_HAS_MONO_CONTEXT
+ MONO_CONTEXT_GET_CURRENT (ctx->ctx);
+#else
+ g_error ("Use a null sigctx requires a working mono-context");
+#endif
+
+ ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
+ ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
+ ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread ? thread->jit_data : NULL;
+ ctx->valid = TRUE;
+}
+
+
gboolean
mono_thread_state_init_from_monoctx (MonoThreadUnwindState *ctx, MonoContext *mctx)
{
ji = frame.ji;
// FIXME: For skipped frames, scan the param area of the parent frame conservatively ?
+ // FIXME: trampolines
if (frame.type == FRAME_TYPE_MANAGED_TO_NATIVE) {
/*
mono_stats.imt_thunks_size += size;
+ mono_tramp_info_register (mono_tramp_info_create (NULL, start, size, NULL, NULL), domain);
+
return start;
}
// EngineBuilder no longer has a copy assignment operator (?)
std::unique_ptr<Module> Owner(unwrap(MP));
EngineBuilder b (std::move(Owner));
-#ifdef TARGET_AMD64
- ExecutionEngine *EE = b.setJITMemoryManager (mono_mm).setTargetOptions (opts).setAllocateGVsWithCode (true).setMCPU (cpu_name).setCodeModel (CodeModel::Large).create ();
-#else
ExecutionEngine *EE = b.setJITMemoryManager (mono_mm).setTargetOptions (opts).setAllocateGVsWithCode (true).setMCPU (cpu_name).create ();
-#endif
g_assert (EE);
mono_ee->EE = EE;
members [0] = IntPtrType ();
ret_type = LLVMStructType (members, 1, FALSE);
+ } else if (cinfo->ret.pair_storage [0] == LLVMArgNone && cinfo->ret.pair_storage [1] == LLVMArgNone) {
+ /* Empty struct */
+ ret_type = LLVMVoidType ();
} else {
g_assert_not_reached ();
}
;
}
-/* Have to export this for AOT */
-void
-mono_personality (void)
-{
- /* Not used */
- g_assert_not_reached ();
-}
-
static void
process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, MonoInst *ins)
{
case LLVMArgVtypeInReg: {
LLVMValueRef regs [2];
+ if (LLVMTypeOf (lcall) == LLVMVoidType ())
+ /* Empty struct */
+ break;
+
if (!addresses [ins->dreg])
addresses [ins->dreg] = build_alloca (ctx, sig->ret);
if (cfg->compile_aot) {
/* Use a dummy personality function */
- personality = LLVMGetNamedFunction (module, "mono_aot_personality");
+ personality = LLVMGetNamedFunction (module, "mono_personality");
g_assert (personality);
} else {
personality = LLVMGetNamedFunction (module, "mono_personality");
if (bb->flags & BB_EXCEPTION_HANDLER) {
if (!bblocks [bb->block_num].invoke_target) {
- //LLVM_FAILURE (ctx, "handler without invokes");
+ LLVM_FAILURE (ctx, "handler without invokes");
}
emit_handler_start (ctx, bb, builder);
LLVMSetInitializer (lmodule->got_var, LLVMConstNull (got_type));
}
- /* Add a dummy personality function */
- {
- LLVMBasicBlockRef lbb;
- LLVMBuilderRef lbuilder;
- LLVMValueRef personality;
-
- personality = LLVMAddFunction (lmodule->module, "mono_aot_personality", LLVMFunctionType (LLVMVoidType (), NULL, 0, FALSE));
- LLVMSetLinkage (personality, LLVMInternalLinkage);
- lbb = LLVMAppendBasicBlock (personality, "BB0");
- lbuilder = LLVMCreateBuilder ();
- LLVMPositionBuilderAtEnd (lbuilder, lbb);
- LLVMBuildRetVoid (lbuilder);
- mark_as_used (lmodule, personality);
- }
-
lmodule->llvm_types = g_hash_table_new (NULL, NULL);
lmodule->plt_entries = g_hash_table_new (g_str_hash, g_str_equal);
lmodule->plt_entries_ji = g_hash_table_new (NULL, NULL);
#define MAX_ARCH_DELEGATE_PARAMS (4 - 1)
static gpointer
-get_delegate_invoke_impl (gboolean has_target, gboolean param_count, guint32 *code_size)
+get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, gboolean param_count)
{
guint8 *code, *start;
mono_arch_flush_icache (start, size);
}
- if (code_size)
- *code_size = code - start;
+ if (has_target) {
+ *info = mono_tramp_info_create ("delegate_invoke_impl_has_target", start, code - start, NULL, NULL);
+ } else {
+ char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", param_count);
+ *info = mono_tramp_info_create (name, start, code - start, NULL, NULL);
+ g_free (name);
+ }
return start;
}
mono_arch_get_delegate_invoke_impls (void)
{
GSList *res = NULL;
- guint8 *code;
- guint32 code_len;
+ MonoTrampInfo *info;
int i;
- char *tramp_name;
- code = get_delegate_invoke_impl (TRUE, 0, &code_len);
- res = g_slist_prepend (res, mono_tramp_info_create ("delegate_invoke_impl_has_target", code, code_len, NULL, NULL));
+ get_delegate_invoke_impl (&info, TRUE, 0);
+ res = g_slist_prepend (res, info);
for (i = 0; i <= MAX_ARCH_DELEGATE_PARAMS; ++i) {
- code = get_delegate_invoke_impl (FALSE, i, &code_len);
- tramp_name = g_strdup_printf ("delegate_invoke_impl_target_%d", i);
- res = g_slist_prepend (res, mono_tramp_info_create (tramp_name, code, code_len, NULL, NULL));
- g_free (tramp_name);
+ get_delegate_invoke_impl (&info, FALSE, i);
+ res = g_slist_prepend (res, info);
}
return res;
return cached;
}
- if (mono_aot_only)
+ if (mono_aot_only) {
start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
- else
- start = get_delegate_invoke_impl (TRUE, 0, NULL);
+ } else {
+ MonoTrampInfo *info;
+ start = get_delegate_invoke_impl (&info, TRUE, 0);
+ mono_tramp_info_register (info, NULL);
+ }
cached = start;
mono_mini_arch_unlock ();
return cached;
start = mono_aot_get_trampoline (name);
g_free (name);
} else {
- start = get_delegate_invoke_impl (FALSE, sig->param_count, NULL);
+ MonoTrampInfo *info;
+ start = get_delegate_invoke_impl (&info, FALSE, sig->param_count);
+ mono_tramp_info_register (info, NULL);
}
cache [sig->param_count] = start;
mono_mini_arch_unlock ();
mono_stats.imt_thunks_size += code - start;
g_assert (code - start <= size);
mono_arch_flush_icache (start, size);
+
+ mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);
+
return start;
}
MINI_OP(OP_GENERIC_CLASS_INIT, "generic_class_init", NONE, IREG, NONE)
/* Arch specific opcodes */
-/* #if defined(__native_client_codegen__) || defined(__native_client__) */
-/* We have to define these in terms of the TARGET defines, not NaCl defines */
-/* because genmdesc.pl doesn't have multiple defines per platform. */
-#if defined(TARGET_AMD64) || defined(TARGET_X86)
+#if defined(TARGET_AMD64) || defined(TARGET_X86) || defined(TARGET_ARM)
MINI_OP(OP_GC_SAFE_POINT, "gc_safe_point", NONE, IREG, NONE)
#endif
}
#endif
+void
+mono_runtime_posix_install_handlers(void)
+{
+
+}
+
void
mono_runtime_shutdown_handlers (void)
{
MONO_SIG_HANDLER_GET_CONTEXT;
if (mono_thread_internal_current ())
- ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context (ctx));
+ ji = mono_jit_info_table_find_internal (mono_domain_get (), mono_arch_ip_from_context (ctx), TRUE, TRUE);
if (!ji) {
if (mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
return;
#define MAX_ARCH_DELEGATE_PARAMS 7
static gpointer
-get_delegate_invoke_impl (gboolean has_target, guint32 param_count, guint32 *code_len, gboolean aot)
+get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, guint32 param_count, gboolean aot)
{
guint8 *code, *start;
mono_arch_flush_icache (start, size);
}
- if (code_len)
- *code_len = code - start;
+ if (has_target) {
+ *info = mono_tramp_info_create ("delegate_invoke_impl_has_target", start, code - start, NULL, NULL);
+ } else {
+ char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", param_count);
+ *info = mono_tramp_info_create (name, start, code - start, NULL, NULL);
+ g_free (name);
+ }
return start;
}
mono_arch_get_delegate_invoke_impls (void)
{
GSList *res = NULL;
- guint8 *code;
- guint32 code_len;
+ MonoTrampInfo *info;
int i;
- char *tramp_name;
- code = get_delegate_invoke_impl (TRUE, 0, &code_len, TRUE);
- res = g_slist_prepend (res, mono_tramp_info_create ("delegate_invoke_impl_has_target", code, code_len, NULL, NULL));
+ get_delegate_invoke_impl (&info, TRUE, 0, TRUE);
+ res = g_slist_prepend (res, info);
- for (i = 0; i < MAX_ARCH_DELEGATE_PARAMS; ++i) {
- code = get_delegate_invoke_impl (FALSE, i, &code_len, TRUE);
- tramp_name = g_strdup_printf ("delegate_invoke_impl_target_%d", i);
- res = g_slist_prepend (res, mono_tramp_info_create (tramp_name, code, code_len, NULL, NULL));
- g_free (tramp_name);
+ for (i = 0; i <= MAX_ARCH_DELEGATE_PARAMS; ++i) {
+ get_delegate_invoke_impl (&info, FALSE, i, TRUE);
+ res = g_slist_prepend (res, info);
}
return res;
if (cached)
return cached;
- if (mono_aot_only)
+ if (mono_aot_only) {
start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
- else
- start = get_delegate_invoke_impl (TRUE, 0, NULL, FALSE);
-
+ } else {
+ MonoTrampInfo *info;
+ start = get_delegate_invoke_impl (&info, TRUE, 0, FALSE);
+ mono_tramp_info_register (info, NULL);
+ }
mono_memory_barrier ();
cached = start;
start = mono_aot_get_trampoline (name);
g_free (name);
} else {
- start = get_delegate_invoke_impl (FALSE, sig->param_count, NULL, FALSE);
+ MonoTrampInfo *info;
+ start = get_delegate_invoke_impl (&info, FALSE, sig->param_count, FALSE);
+ mono_tramp_info_register (info, NULL);
}
mono_memory_barrier ();
else
ppc_mr (code, ins->dreg, ins->sreg1);
break;
+#else
+ case OP_ICONV_TO_R4:
+ case OP_ICONV_TO_R8: {
+ if (cpu_hw_caps & PPC_ISA_64) {
+ ppc_srawi(code, ppc_r0, ins->sreg1, 31);
+ ppc_stw (code, ppc_r0, -8, ppc_r1);
+ ppc_stw (code, ins->sreg1, -4, ppc_r1);
+ ppc_lfd (code, ins->dreg, -8, ppc_r1);
+ ppc_fcfid (code, ins->dreg, ins->dreg);
+ if (ins->opcode == OP_ICONV_TO_R4)
+ ppc_frsp (code, ins->dreg, ins->dreg);
+ }
+ break;
+ }
+#endif
+
case OP_ATOMIC_ADD_I4:
CASE_PPC64 (OP_ATOMIC_ADD_I8) {
int location = ins->inst_basereg;
ppc_mr (code, ins->dreg, ppc_r0);
break;
}
-#else
- case OP_ICONV_TO_R4:
- case OP_ICONV_TO_R8: {
- if (cpu_hw_caps & PPC_ISA_64) {
- ppc_srawi(code, ppc_r0, ins->sreg1, 31);
- ppc_stw (code, ppc_r0, -8, ppc_r1);
- ppc_stw (code, ins->sreg1, -4, ppc_r1);
- ppc_lfd (code, ins->dreg, -8, ppc_r1);
- ppc_fcfid (code, ins->dreg, ins->dreg);
- if (ins->opcode == OP_ICONV_TO_R4)
- ppc_frsp (code, ins->dreg, ins->dreg);
- }
- break;
- }
-#endif
case OP_ATOMIC_CAS_I4:
CASE_PPC64 (OP_ATOMIC_CAS_I8) {
int location = ins->sreg1;
mono_stats.imt_thunks_size += code - start;
g_assert (code - start <= size);
mono_arch_flush_icache (start, size);
+
+ mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);
+
return start;
}
if (!domain)
domain = mono_get_root_domain ();
- ji = mono_jit_info_table_find (domain, ip);
+ ji = mono_jit_info_table_find_internal (domain, ip, TRUE, TRUE);
if (!ji) {
user_data.ip = ip;
user_data.method = NULL;
}
else
return NULL;
+ } else if (ji->is_trampoline) {
+ res = g_strdup_printf ("<%p - %s trampoline>", ip, ((MonoTrampInfo*)ji->d.tramp_info)->name);
+ return res;
}
+
method = mono_method_full_name (jinfo_get_method (ji), TRUE);
/* FIXME: unused ? */
location = mono_debug_lookup_source_location (jinfo_get_method (ji), (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
{
MonoMethod *cmethod;
- if (!caller || !callee)
+ if (!caller || caller->is_trampoline || !callee || callee->is_trampoline)
return FALSE;
/*
void
mono_tramp_info_free (MonoTrampInfo *info)
{
- GSList *l;
-
g_free (info->name);
// FIXME: ji
- for (l = info->unwind_ops; l; l = l->next)
- g_free (l->data);
- g_slist_free (info->unwind_ops);
+ mono_free_unwind_info (info->unwind_ops);
g_free (info);
}
mono_jit_info_init (ji, NULL, info->code, info->code_size, 0, 0, 0);
ji->d.tramp_info = info;
ji->is_trampoline = TRUE;
- // FIXME: Unwind info
+
+ ji->unwind_info = mono_cache_unwind_info (info->uw_info, info->uw_info_len);
mono_jit_info_table_add (domain, ji);
}
* Frees INFO.
*/
void
-mono_tramp_info_register (MonoTrampInfo *info)
+mono_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain)
{
MonoTrampInfo *copy;
if (!info)
return;
+ if (!domain)
+ domain = mono_get_root_domain ();
+
copy = g_new0 (MonoTrampInfo, 1);
copy->code = info->code;
copy->code_size = info->code_size;
copy->name = g_strdup (info->name);
+ if (info->unwind_ops) {
+ copy->uw_info = mono_unwind_ops_encode (info->unwind_ops, ©->uw_info_len);
+ } else {
+ /* Trampolines from aot have the unwind ops already encoded */
+ copy->uw_info = info->uw_info;
+ copy->uw_info_len = info->uw_info_len;
+ }
+
mono_jit_lock ();
tramp_infos = g_slist_prepend (tramp_infos, copy);
mono_jit_unlock ();
mono_save_trampoline_xdebug_info (info);
- if (mono_get_root_domain ())
- register_trampoline_jit_info (mono_get_root_domain (), copy);
+ /* Only register trampolines that have unwind infos */
+ if (mono_get_root_domain () && copy->uw_info)
+ register_trampoline_jit_info (domain, copy);
if (mono_jit_map_is_enabled ())
mono_emit_jit_tramp (info->code, info->code_size, info->name);
case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR:
case MONO_PATCH_INFO_GC_NURSERY_START:
case MONO_PATCH_INFO_JIT_TLS_ID:
- case MONO_PATCH_INFO_MONITOR_ENTER:
- case MONO_PATCH_INFO_MONITOR_ENTER_V4:
- case MONO_PATCH_INFO_MONITOR_EXIT:
case MONO_PATCH_INFO_GOT_OFFSET:
case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
return (ji->type << 8);
target = mono_create_rgctx_lazy_fetch_trampoline (slot);
break;
}
- case MONO_PATCH_INFO_MONITOR_ENTER:
- target = mono_create_monitor_enter_trampoline ();
- break;
- case MONO_PATCH_INFO_MONITOR_ENTER_V4:
- target = mono_create_monitor_enter_v4_trampoline ();
- break;
- case MONO_PATCH_INFO_MONITOR_EXIT:
- target = mono_create_monitor_exit_trampoline ();
- break;
#ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
case MONO_PATCH_INFO_SEQ_POINT_INFO:
if (!run_cctors)
MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
MONO_SIG_HANDLER_GET_CONTEXT;
- ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context (ctx));
+ ji = mono_jit_info_table_find_internal (mono_domain_get (), mono_arch_ip_from_context (ctx), TRUE, TRUE);
#if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
if (mono_arch_is_int_overflow (ctx, info))
}
#endif
- ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context (ctx));
+ ji = mono_jit_info_table_find_internal (mono_domain_get (), mono_arch_ip_from_context (ctx), TRUE, TRUE);
#ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
if (mono_handle_soft_stack_ovf (jit_tls, ji, ctx, info, (guint8*)info->si_addr))
/* FIXME Support more cases */
if (mono_aot_only) {
char tramp_name [256];
+ const char *imt = load_imt_reg ? "_imt" : "";
+ int ind = (load_imt_reg ? (-offset) : offset) / SIZEOF_VOID_P;
- sprintf (tramp_name, "delegate_virtual_invoke%s_%d", load_imt_reg ? "_imt" : "", offset / SIZEOF_VOID_P);
+ sprintf (tramp_name, "delegate_virtual_invoke%s_%d", imt, ind);
cache [idx] = mono_aot_get_trampoline (tramp_name);
g_assert (cache [idx]);
} else {
ticallbacks.setup_async_callback = mono_setup_async_callback;
ticallbacks.thread_state_init_from_sigctx = mono_thread_state_init_from_sigctx;
ticallbacks.thread_state_init_from_handle = mono_thread_state_init_from_handle;
+ ticallbacks.thread_state_init = mono_thread_state_init;
mono_counters_init ();
g_hash_table_destroy (assemblies);
}
+/*
+ * Used by LLVM.
+ * Have to export this for AOT.
+ */
+void
+mono_personality (void)
+{
+ /* Not used */
+ g_assert_not_reached ();
+}
+
#ifdef USE_JUMP_TABLES
#define DEFAULT_JUMPTABLE_CHUNK_ELEMENTS 128
/*------------------------------------------------------------------*/
static gpointer
-get_delegate_invoke_impl (gboolean has_target, guint32 param_count, guint32 *code_len, gboolean aot)
+get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, guint32 param_count, gboolean aot)
{
guint8 *code, *start;
mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL);
- if (code_len)
- *code_len = code - start;
+ if (has_target) {
+ *info = mono_tramp_info_create ("delegate_invoke_impl_has_target", start, code - start, NULL, NULL);
+ } else {
+ char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", param_count);
+ *info = mono_tramp_info_create (name, start, code - start, NULL, NULL);
+ g_free (name);
+ }
return start;
}
mono_arch_get_delegate_invoke_impls (void)
{
GSList *res = NULL;
- guint8 *code;
- guint32 code_len;
+ MonoTrampInfo *info;
int i;
- char *tramp_name;
- code = get_delegate_invoke_impl (TRUE, 0, &code_len, TRUE);
- res = g_slist_prepend (res, mono_tramp_info_create ("delegate_invoke_impl_has_target", code, code_len, NULL, NULL));
+ get_delegate_invoke_impl (&info, TRUE, 0, TRUE);
+ res = g_slist_prepend (res, info);
- for (i = 0; i < MAX_ARCH_DELEGATE_PARAMS; ++i) {
- code = get_delegate_invoke_impl (FALSE, i, &code_len, TRUE);
- tramp_name = g_strdup_printf ("delegate_invoke_impl_target_%d", i);
- res = g_slist_prepend (res, mono_tramp_info_create (tramp_name, code, code_len, NULL, NULL));
- g_free (tramp_name);
+ for (i = 0; i <= MAX_ARCH_DELEGATE_PARAMS; ++i) {
+ get_delegate_invoke_impl (&info, FALSE, i, TRUE);
+ res = g_slist_prepend (res, info);
}
return res;
if (cached)
return cached;
- if (mono_aot_only)
+ if (mono_aot_only) {
start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
- else
- start = get_delegate_invoke_impl (TRUE, 0, NULL, FALSE);
+ } else {
+ MonoTrampInfo *info;
+ start = get_delegate_invoke_impl (&info, TRUE, 0, FALSE);
+ mono_tramp_info_register (info, NULL);
+ }
mono_memory_barrier ();
start = mono_aot_get_trampoline (name);
g_free (name);
} else {
- start = get_delegate_invoke_impl (FALSE, sig->param_count, NULL, FALSE);
+ MonoTrampInfo *info;
+ start = get_delegate_invoke_impl (&info, FALSE, sig->param_count, FALSE);
+ mono_tramp_info_register (info, NULL);
}
mono_memory_barrier ();
g_assert (code - start <= size);
+ mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);
+
return (start);
}
#define MONO_ARCH_HAVE_INVALIDATE_METHOD 1
#define MONO_ARCH_HAVE_OP_GENERIC_CLASS_INIT 1
#define MONO_ARCH_HAVE_SETUP_ASYNC_CALLBACK 1
-#define MONO_ARCH_MONITOR_OBJECT_REG s390_r2
-#define MONO_ARCH_LOCK_TAKEN_REG s390_r1
#define S390_STACK_ALIGNMENT 8
#define S390_FIRST_ARG_REG s390_r2
mono_stats.imt_thunks_size += (code - start) * 4;
g_assert (code - start <= size);
+
+ mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);
+
return start;
}
}
}
- if (ji)
+ if (ji && !ji->is_trampoline)
jmethod = jinfo_get_method (ji);
if (callee_gsharedvt && mini_is_gsharedvt_variable_signature (mono_method_signature (jmethod))) {
MonoMethodSignature *sig, *gsig;
return mono_class_fill_runtime_generic_context (arg, index);
}
-void
-mono_monitor_enter_trampoline (mgreg_t *regs, guint8 *code, MonoObject *obj, guint8 *tramp)
-{
- mono_monitor_enter (obj);
-}
-
-void
-mono_monitor_enter_v4_trampoline (mgreg_t *regs, guint8 *code, MonoObject *obj, guint8 *tramp)
-{
-#ifdef MONO_ARCH_MONITOR_LOCK_TAKEN_REG
- char *lock_taken = (char*)regs [MONO_ARCH_MONITOR_LOCK_TAKEN_REG];
- mono_monitor_enter_v4 (obj, lock_taken);
-#else
- g_assert_not_reached ();
-#endif
-}
-
-void
-mono_monitor_exit_trampoline (mgreg_t *regs, guint8 *code, MonoObject *obj, guint8 *tramp)
-{
- mono_monitor_exit (obj);
-}
-
/*
* Precompute data to speed up mono_delegate_trampoline ().
* METHOD might be NULL.
gpointer tmp;
tmp = mono_arch_create_handler_block_trampoline (&info, FALSE);
- mono_tramp_info_register (info);
+ mono_tramp_info_register (info, NULL);
mono_memory_barrier ();
code = tmp;
}
case MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING:
return mono_generic_virtual_remoting_trampoline;
#endif
- case MONO_TRAMPOLINE_MONITOR_ENTER:
- return mono_monitor_enter_trampoline;
- case MONO_TRAMPOLINE_MONITOR_ENTER_V4:
- return mono_monitor_enter_v4_trampoline;
- case MONO_TRAMPOLINE_MONITOR_EXIT:
- return mono_monitor_exit_trampoline;
case MONO_TRAMPOLINE_VCALL:
return mono_vcall_trampoline;
#ifdef MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD
guchar *code;
code = mono_arch_create_generic_trampoline (tramp_type, &info, FALSE);
- mono_tramp_info_register (info);
+ mono_tramp_info_register (info, NULL);
return code;
}
#ifndef DISABLE_REMOTING
mono_trampoline_code [MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING] = create_trampoline_code (MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING);
#endif
- mono_trampoline_code [MONO_TRAMPOLINE_MONITOR_ENTER] = create_trampoline_code (MONO_TRAMPOLINE_MONITOR_ENTER);
- mono_trampoline_code [MONO_TRAMPOLINE_MONITOR_ENTER_V4] = create_trampoline_code (MONO_TRAMPOLINE_MONITOR_ENTER_V4);
- mono_trampoline_code [MONO_TRAMPOLINE_MONITOR_EXIT] = create_trampoline_code (MONO_TRAMPOLINE_MONITOR_EXIT);
mono_trampoline_code [MONO_TRAMPOLINE_VCALL] = create_trampoline_code (MONO_TRAMPOLINE_VCALL);
#ifdef MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD
mono_trampoline_code [MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD] = create_trampoline_code (MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD);
ptr = mono_aot_get_lazy_fetch_trampoline (offset);
} else {
tramp = mono_arch_create_rgctx_lazy_fetch_trampoline (offset, &info, FALSE);
- mono_tramp_info_register (info);
+ mono_tramp_info_register (info, NULL);
ptr = mono_create_ftnptr (mono_get_root_domain (), tramp);
}
return ptr;
}
-
-gpointer
-mono_create_monitor_enter_trampoline (void)
-{
- static gpointer code;
-
- if (mono_aot_only) {
- if (!code)
- code = mono_aot_get_trampoline ("monitor_enter_trampoline");
- return code;
- }
-
-#ifdef MONO_ARCH_MONITOR_OBJECT_REG
- mono_trampolines_lock ();
-
- if (!code) {
- MonoTrampInfo *info;
-
- code = mono_arch_create_monitor_enter_trampoline (&info, FALSE, FALSE);
- mono_tramp_info_register (info);
- }
-
- mono_trampolines_unlock ();
-#else
- code = NULL;
- g_assert_not_reached ();
-#endif
-
- return code;
-}
-
-gpointer
-mono_create_monitor_enter_v4_trampoline (void)
-{
- static gpointer code;
-
- if (mono_aot_only) {
- if (!code)
- code = mono_aot_get_trampoline ("monitor_enter_v4_trampoline");
- return code;
- }
-
-#if defined(MONO_ARCH_MONITOR_OBJECT_REG) && defined(MONO_ARCH_MONITOR_LOCK_TAKEN_REG)
- mono_trampolines_lock ();
-
- if (!code) {
- MonoTrampInfo *info;
-
- code = mono_arch_create_monitor_enter_trampoline (&info, TRUE, FALSE);
- mono_tramp_info_register (info);
- }
-
- mono_trampolines_unlock ();
-#else
- code = NULL;
- g_assert_not_reached ();
-#endif
-
- return code;
-}
-
-gpointer
-mono_create_monitor_exit_trampoline (void)
-{
- static gpointer code;
-
- if (mono_aot_only) {
- if (!code)
- code = mono_aot_get_trampoline ("monitor_exit_trampoline");
- return code;
- }
-
-#ifdef MONO_ARCH_MONITOR_OBJECT_REG
- mono_trampolines_lock ();
-
- if (!code) {
- MonoTrampInfo *info;
-
- code = mono_arch_create_monitor_exit_trampoline (&info, FALSE);
- mono_tramp_info_register (info);
- }
-
- mono_trampolines_unlock ();
-#else
- code = NULL;
- g_assert_not_reached ();
-#endif
- return code;
-}
#ifdef MONO_ARCH_LLVM_SUPPORTED
/*
"delegate",
"restore_stack_prot",
"generic_virtual_remoting",
- "monitor_enter",
- "monitor_enter_v4",
- "monitor_exit",
"vcall",
"handler_block_guard"
};
#ifdef MONO_ARCH_HAVE_SDB_TRAMPOLINES
MonoTrampInfo *info;
tramp = mono_arch_create_sdb_trampoline (TRUE, &info, FALSE);
- mono_tramp_info_register (info);
+ mono_tramp_info_register (info, NULL);
#else
tramp = NULL;
g_assert_not_reached ();
#ifdef MONO_ARCH_HAVE_SDB_TRAMPOLINES
MonoTrampInfo *info;
tramp = mono_arch_create_sdb_trampoline (FALSE, &info, FALSE);
- mono_tramp_info_register (info);
+ mono_tramp_info_register (info, NULL);
#else
tramp = NULL;
g_assert_not_reached ();
#define mono_add_unwind_op_same_value(op_list,code,buf,reg) do { (op_list) = g_slist_append ((op_list), mono_create_unwind_op ((code) - (buf), DW_CFA_same_value, (reg), 0)); } while (0)
#define mono_add_unwind_op_offset(op_list,code,buf,reg,offset) do { (op_list) = g_slist_append ((op_list), mono_create_unwind_op ((code) - (buf), DW_CFA_offset, (reg), (offset))); } while (0)
+#define mono_free_unwind_info(op_list) do { GSList *l; for (l = op_list; l; l = l->next) g_free (l->data); g_slist_free (op_list); op_list = NULL; } while (0)
+
/* Pointer Encoding in the .eh_frame */
enum {
DW_EH_PE_absptr = 0x00,
int
mono_unwind_get_dwarf_pc_reg (void);
+guint8*
+mono_unwind_ops_encode_full (GSList *unwind_ops, guint32 *out_len, gboolean enable_extensions);
+
guint8*
mono_unwind_ops_encode (GSList *unwind_ops, guint32 *out_len);
#endif
#endif
+/* The single step trampoline */
+static gpointer ss_trampoline;
+
+/* The breakpoint trampoline */
+static gpointer bp_trampoline;
+
/* This mutex protects architecture specific caches */
#define mono_mini_arch_lock() mono_mutex_lock (&mini_arch_mutex)
#define mono_mini_arch_unlock() mono_mutex_unlock (&mini_arch_mutex)
#define X86_IS_CALLEE_SAVED_REG(reg) (((reg) == X86_EBX) || ((reg) == X86_EDI) || ((reg) == X86_ESI))
-MonoBreakpointInfo
-mono_breakpoint_info [MONO_BREAKPOINT_ARRAY_SIZE];
+#define OP_SEQ_POINT_BP_OFFSET 7
static guint8*
emit_load_aotconst (guint8 *start, guint8 *code, MonoCompile *cfg, MonoJumpInfo **ji, int dreg, int tramp_type, gconstpointer target);
#endif /* __native_client_codegen__ */
-/*
- * The code generated for sequence points reads from this location, which is
- * made read-only when single stepping is enabled.
- */
-static gpointer ss_trigger_page;
-
-/* Enabled breakpoints read from this trigger page */
-static gpointer bp_trigger_page;
-
const char*
mono_arch_regname (int reg)
{
{
mono_mutex_init_recursive (&mini_arch_mutex);
- ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ);
- bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
- mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
+ bp_trampoline = mini_get_breakpoint_trampoline ();
mono_aot_register_jit_icall ("mono_x86_throw_exception", mono_x86_throw_exception);
mono_aot_register_jit_icall ("mono_x86_throw_corlib_exception", mono_x86_throw_corlib_exception);
void
mono_arch_cleanup (void)
{
- if (ss_trigger_page)
- mono_vfree (ss_trigger_page, mono_pagesize ());
- if (bp_trigger_page)
- mono_vfree (bp_trigger_page, mono_pagesize ());
mono_mutex_destroy (&mini_arch_mutex);
}
cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
}
+ if (cfg->gen_sdb_seq_points) {
+ MonoInst *ins;
+
+ ins = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
+ ins->flags |= MONO_INST_VOLATILE;
+ cfg->arch.ss_tramp_var = ins;
+
+ ins = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
+ ins->flags |= MONO_INST_VOLATILE;
+ cfg->arch.bp_tramp_var = ins;
+ }
+
if (cfg->method->save_lmf) {
cfg->create_lmf_var = TRUE;
cfg->lmf_ir = TRUE;
if (cfg->compile_aot)
NOT_IMPLEMENTED;
+ /* Have to use ecx as a temp reg since this can occur after OP_SETRET */
+
/*
* Read from the single stepping trigger page. This will cause a
* SIGSEGV when single stepping is enabled.
* We do this _before_ the breakpoint, so single stepping after
* a breakpoint is hit will step to the next IL offset.
*/
- if (ins->flags & MONO_INST_SINGLE_STEP_LOC)
- x86_alu_reg_mem (code, X86_CMP, X86_EAX, (guint32)ss_trigger_page);
+ if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
+ MonoInst *var = cfg->arch.ss_tramp_var;
+ guint8 *br [1];
+
+ g_assert (var);
+ g_assert (var->opcode == OP_REGOFFSET);
+ /* Load ss_tramp_var */
+ /* This is equal to &ss_trampoline */
+ x86_mov_reg_membase (code, X86_ECX, var->inst_basereg, var->inst_offset, sizeof (mgreg_t));
+ x86_alu_membase_imm (code, X86_CMP, X86_ECX, 0, 0);
+ br[0] = code; x86_branch8 (code, X86_CC_EQ, 0, FALSE);
+ x86_call_membase (code, X86_ECX, 0);
+ x86_patch (br [0], code);
+ }
+
+ /*
+ * Many parts of sdb depend on the ip after the single step trampoline call to be equal to the seq point offset.
+ * This means we have to put the loading of bp_tramp_var after the offset.
+ */
mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
+ MonoInst *var = cfg->arch.bp_tramp_var;
+
+ g_assert (var);
+ g_assert (var->opcode == OP_REGOFFSET);
+ /* Load the address of the bp trampoline */
+ /* This needs to be constant size */
+ guint8 *start = code;
+ x86_mov_reg_membase (code, X86_ECX, var->inst_basereg, var->inst_offset, 4);
+ if (code < start + OP_SEQ_POINT_BP_OFFSET) {
+ int size = start + OP_SEQ_POINT_BP_OFFSET - code;
+ x86_padding (code, size);
+ }
/*
* A placeholder for a possible breakpoint inserted by
* mono_arch_set_breakpoint ().
*/
- for (i = 0; i < 6; ++i)
+ for (i = 0; i < 2; ++i)
x86_nop (code);
/*
* Add an additional nop so skipping the bp doesn't cause the ip to point
if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
+ {
+ MonoInst *ins;
+
+ if (cfg->arch.ss_tramp_var) {
+ /* Initialize ss_tramp_var */
+ ins = cfg->arch.ss_tramp_var;
+ g_assert (ins->opcode == OP_REGOFFSET);
+
+ g_assert (!cfg->compile_aot);
+ x86_mov_membase_imm (code, ins->inst_basereg, ins->inst_offset, (guint32)&ss_trampoline, 4);
+ }
+
+ if (cfg->arch.bp_tramp_var) {
+ /* Initialize bp_tramp_var */
+ ins = cfg->arch.bp_tramp_var;
+ g_assert (ins->opcode == OP_REGOFFSET);
+
+ g_assert (!cfg->compile_aot);
+ x86_mov_membase_imm (code, ins->inst_basereg, ins->inst_offset, (guint32)&bp_trampoline, 4);
+ }
+ }
+
/* load arguments allocated to register from the stack */
sig = mono_method_signature (method);
pos = 0;
int i;
int size = 0;
guint8 *code, *start;
+ GSList *unwind_ops;
for (i = 0; i < count; ++i) {
MonoIMTCheckItem *item = imt_entries [i];
code = mono_domain_code_reserve (domain, size);
#endif
start = code;
+
+ unwind_ops = mono_arch_get_cie_program ();
+
for (i = 0; i < count; ++i) {
MonoIMTCheckItem *item = imt_entries [i];
item->code_target = code;
nacl_domain_code_validate (domain, &start, size, &code);
mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_IMT_TRAMPOLINE, NULL);
+ mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), domain);
+
return start;
}
#define MAX_ARCH_DELEGATE_PARAMS 10
static gpointer
-get_delegate_invoke_impl (gboolean has_target, guint32 param_count, guint32 *code_len)
+get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, guint32 param_count)
{
guint8 *code, *start;
int code_reserve = 64;
+ GSList *unwind_ops;
+
+ unwind_ops = mono_arch_get_cie_program ();
/*
* The stack contains:
nacl_global_codeman_validate (&start, code_reserve, &code);
- if (code_len)
- *code_len = code - start;
+ if (has_target) {
+ *info = mono_tramp_info_create ("delegate_invoke_impl_has_target", start, code - start, NULL, unwind_ops);
+ } else {
+ char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", param_count);
+ *info = mono_tramp_info_create (name, start, code - start, NULL, unwind_ops);
+ g_free (name);
+ }
if (mono_jit_map_is_enabled ()) {
char *buff;
#define MAX_VIRTUAL_DELEGATE_OFFSET 32
static gpointer
-get_delegate_virtual_invoke_impl (gboolean load_imt_reg, int offset, guint32 *code_size)
+get_delegate_virtual_invoke_impl (MonoTrampInfo **info, gboolean load_imt_reg, int offset)
{
guint8 *code, *start;
int size = 24;
+ char *tramp_name;
+ GSList *unwind_ops;
+
+ if (offset / (int)sizeof (gpointer) > MAX_VIRTUAL_DELEGATE_OFFSET)
+ return NULL;
/*
* The stack contains:
*/
start = code = mono_global_codeman_reserve (size);
+ unwind_ops = mono_arch_get_cie_program ();
+
/* Replace the this argument with the target */
x86_mov_reg_membase (code, X86_EAX, X86_ESP, 4, 4);
x86_mov_reg_membase (code, X86_ECX, X86_EAX, MONO_STRUCT_OFFSET (MonoDelegate, target), 4);
x86_jump_membase (code, X86_EAX, offset);
mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL);
- if (code_size)
- *code_size = code - start;
+ if (load_imt_reg)
+ tramp_name = g_strdup_printf ("delegate_virtual_invoke_imt_%d", - offset / sizeof (gpointer));
+ else
+ tramp_name = g_strdup_printf ("delegate_virtual_invoke_%d", offset / sizeof (gpointer));
+ *info = mono_tramp_info_create (tramp_name, start, code - start, NULL, unwind_ops);
+ g_free (tramp_name);
+
return start;
}
mono_arch_get_delegate_invoke_impls (void)
{
GSList *res = NULL;
- guint8 *code;
- guint32 code_len;
+ MonoTrampInfo *info;
int i;
- char *tramp_name;
- code = get_delegate_invoke_impl (TRUE, 0, &code_len);
- res = g_slist_prepend (res, mono_tramp_info_create ("delegate_invoke_impl_has_target", code, code_len, NULL, NULL));
+ get_delegate_invoke_impl (&info, TRUE, 0);
+ res = g_slist_prepend (res, info);
- for (i = 0; i < MAX_ARCH_DELEGATE_PARAMS; ++i) {
- code = get_delegate_invoke_impl (FALSE, i, &code_len);
- tramp_name = g_strdup_printf ("delegate_invoke_impl_target_%d", i);
- res = g_slist_prepend (res, mono_tramp_info_create (tramp_name, code, code_len, NULL, NULL));
- g_free (tramp_name);
+ for (i = 0; i <= MAX_ARCH_DELEGATE_PARAMS; ++i) {
+ get_delegate_invoke_impl (&info, FALSE, i);
+ res = g_slist_prepend (res, info);
}
- for (i = 0; i < MAX_VIRTUAL_DELEGATE_OFFSET; ++i) {
- code = get_delegate_virtual_invoke_impl (TRUE, i * SIZEOF_VOID_P, &code_len);
- tramp_name = g_strdup_printf ("delegate_virtual_invoke_imt_%d", i);
- res = g_slist_prepend (res, mono_tramp_info_create (tramp_name, code, code_len, NULL, NULL));
- g_free (tramp_name);
+ for (i = 0; i <= MAX_VIRTUAL_DELEGATE_OFFSET; ++i) {
+ get_delegate_virtual_invoke_impl (&info, TRUE, - i * SIZEOF_VOID_P);
+ res = g_slist_prepend (res, info);
- code = get_delegate_virtual_invoke_impl (FALSE, i * SIZEOF_VOID_P, &code_len);
- tramp_name = g_strdup_printf ("delegate_virtual_invoke_%d", i);
- res = g_slist_prepend (res, mono_tramp_info_create (tramp_name, code, code_len, NULL, NULL));
- g_free (tramp_name);
+ get_delegate_virtual_invoke_impl (&info, FALSE, i * SIZEOF_VOID_P);
+ res = g_slist_prepend (res, info);
}
return res;
if (cached)
return cached;
- if (mono_aot_only)
+ if (mono_aot_only) {
start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
- else
- start = get_delegate_invoke_impl (TRUE, 0, NULL);
+ } else {
+ MonoTrampInfo *info;
+ start = get_delegate_invoke_impl (&info, TRUE, 0);
+ mono_tramp_info_register (info, NULL);
+ }
mono_memory_barrier ();
start = mono_aot_get_trampoline (name);
g_free (name);
} else {
- start = get_delegate_invoke_impl (FALSE, sig->param_count, NULL);
+ MonoTrampInfo *info;
+ start = get_delegate_invoke_impl (&info, FALSE, sig->param_count);
+ mono_tramp_info_register (info, NULL);
}
mono_memory_barrier ();
gpointer
mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method, int offset, gboolean load_imt_reg)
{
- return get_delegate_virtual_invoke_impl (load_imt_reg, offset, NULL);
+ MonoTrampInfo *info;
+ gpointer code;
+
+ code = get_delegate_virtual_invoke_impl (&info, load_imt_reg, offset);
+ if (code)
+ mono_tramp_info_register (info, NULL);
+ return code;
}
mgreg_t
void
mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
{
- guint8 *code = ip;
+ guint8 *code = ip + OP_SEQ_POINT_BP_OFFSET;
- /*
- * In production, we will use int3 (has to fix the size in the md
- * file). But that could confuse gdb, so during development, we emit a SIGSEGV
- * instead.
- */
g_assert (code [0] == 0x90);
- x86_alu_reg_mem (code, X86_CMP, X86_EAX, (guint32)bp_trigger_page);
+ x86_call_membase (code, X86_ECX, 0);
}
/*
void
mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
{
- guint8 *code = ip;
+ guint8 *code = ip + OP_SEQ_POINT_BP_OFFSET;
int i;
- for (i = 0; i < 6; ++i)
+ for (i = 0; i < 2; ++i)
x86_nop (code);
}
void
mono_arch_start_single_stepping (void)
{
- mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
+ ss_trampoline = mini_get_single_step_trampoline ();
}
/*
void
mono_arch_stop_single_stepping (void)
{
- mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
+ ss_trampoline = NULL;
}
/*
gboolean
mono_arch_is_single_step_event (void *info, void *sigctx)
{
-#ifdef TARGET_WIN32
- EXCEPTION_RECORD* einfo = ((EXCEPTION_POINTERS*)info)->ExceptionRecord; /* Sometimes the address is off by 4 */
-
- if (((gpointer)einfo->ExceptionInformation[1] >= ss_trigger_page && (guint8*)einfo->ExceptionInformation[1] <= (guint8*)ss_trigger_page + 128))
- return TRUE;
- else
- return FALSE;
-#else
- siginfo_t* sinfo = (siginfo_t*) info;
- /* Sometimes the address is off by 4 */
- if (sinfo->si_signo == DBG_SIGNAL && (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128))
- return TRUE;
- else
- return FALSE;
-#endif
+ /* We use soft breakpoints */
+ return FALSE;
}
gboolean
mono_arch_is_breakpoint_event (void *info, void *sigctx)
{
-#ifdef TARGET_WIN32
- EXCEPTION_RECORD* einfo = ((EXCEPTION_POINTERS*)info)->ExceptionRecord; /* Sometimes the address is off by 4 */
- if (((gpointer)einfo->ExceptionInformation[1] >= bp_trigger_page && (guint8*)einfo->ExceptionInformation[1] <= (guint8*)bp_trigger_page + 128))
- return TRUE;
- else
- return FALSE;
-#else
- siginfo_t* sinfo = (siginfo_t*)info;
- /* Sometimes the address is off by 4 */
- if (sinfo->si_signo == DBG_SIGNAL && (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128))
- return TRUE;
- else
- return FALSE;
-#endif
+ /* We use soft breakpoints */
+ return FALSE;
}
-#define BREAKPOINT_SIZE 6
+#define BREAKPOINT_SIZE 2
/*
* mono_arch_skip_breakpoint:
void
mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
{
- MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + BREAKPOINT_SIZE);
+ g_assert_not_reached ();
}
/*
void
mono_arch_skip_single_step (MonoContext *ctx)
{
- MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 6);
+ g_assert_not_reached ();
}
/*
gboolean need_stack_frame_inited;
gboolean need_stack_frame;
int sp_fp_offset, param_area_size;
+ gpointer ss_tramp_var;
+ gpointer bp_tramp_var;
} MonoCompileArch;
#define MONO_CONTEXT_SET_LLVM_EXC_REG(ctx, exc) do { (ctx)->eax = (gsize)exc; } while (0)
#define MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK 1
#define MONO_ARCH_HAVE_LIVERANGE_OPS 1
#define MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX 1
-#if defined(__linux__) || defined (__APPLE__)
-#define MONO_ARCH_MONITOR_OBJECT_REG X86_EAX
-#define MONO_ARCH_MONITOR_LOCK_TAKEN_REG X86_EDX
-#endif
#if !defined(__native_client_codegen__)
#define MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES 1
#endif
#define MONO_ARCH_HAVE_LLVM_IMT_TRAMPOLINE 1
#define MONO_ARCH_LLVM_SUPPORTED 1
-#if defined(MONO_ARCH_USE_SIGACTION) || defined(TARGET_WIN32)
#define MONO_ARCH_SOFT_DEBUG_SUPPORTED 1
-#endif
#define MONO_ARCH_HAVE_EXCEPTIONS_INIT 1
#define MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD 1
#define MONO_ARCH_HAVE_TRANSLATE_TLS_OFFSET 1
#define MONO_ARCH_HAVE_TLS_GET_REG 1
#define MONO_ARCH_HAVE_DUMMY_INIT 1
+#define MONO_ARCH_HAVE_SDB_TRAMPOLINES 1
#define MONO_ARCH_HAVE_PATCH_CODE_NEW 1
/* Used for optimization, not complete */
MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException"); \
} while (0)
-typedef struct {
- guint8 *address;
- guint8 saved_byte;
-} MonoBreakpointInfo;
-
-extern MonoBreakpointInfo mono_breakpoint_info [MONO_BREAKPOINT_ARRAY_SIZE];
-
/* Return value marshalling for calls between gsharedvt and normal code */
typedef enum {
GSHAREDVT_RET_NONE = 0,
mono_insert_safepoints (MonoCompile *cfg)
{
MonoBasicBlock *bb;
+ if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
+ WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
+#if defined(__native_client__) || defined(__native_client_codegen__)
+ gpointer poll_func = &mono_nacl_gc;
+#elif defined(USE_COOP_GC)
+ gpointer poll_func = &mono_threads_state_poll;
+#else
+ gpointer poll_func = NULL;
+#endif
+
+ if (info && info->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER && info->d.icall.func == poll_func) {
+ if (cfg->verbose_level > 1)
+ printf ("SKIPPING SAFEPOINTS for the polling function icall\n");
+ return;
+ }
+ }
+
if (cfg->verbose_level > 1)
printf ("INSERTING SAFEPOINTS\n");
if (!COMPILE_LLVM (cfg))
mono_if_conversion (cfg);
+ MONO_SUSPEND_CHECK ();
+
/* Depth-first ordering on basic blocks */
cfg->bblocks = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (cfg->num_bblocks + 1));
#endif
/* Version number of the AOT file format */
-#define MONO_AOT_FILE_VERSION 120
+#define MONO_AOT_FILE_VERSION 121
//TODO: This is x86/amd64 specific.
#define mono_simd_shuffle_mask(a,b,c,d) ((a) | ((b) << 2) | ((c) << 4) | ((d) << 6))
MONO_TRAMPOLINE_DELEGATE,
MONO_TRAMPOLINE_RESTORE_STACK_PROT,
MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING,
- MONO_TRAMPOLINE_MONITOR_ENTER,
- MONO_TRAMPOLINE_MONITOR_ENTER_V4,
- MONO_TRAMPOLINE_MONITOR_EXIT,
MONO_TRAMPOLINE_VCALL,
MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD,
MONO_TRAMPOLINE_NUM
/* These trampolines return normally to their caller */
#define MONO_TRAMPOLINE_TYPE_MUST_RETURN(t) \
((t) == MONO_TRAMPOLINE_RESTORE_STACK_PROT || \
- (t) == MONO_TRAMPOLINE_RGCTX_LAZY_FETCH || \
- (t) == MONO_TRAMPOLINE_MONITOR_ENTER || \
- (t) == MONO_TRAMPOLINE_MONITOR_ENTER_V4 || \
- (t) == MONO_TRAMPOLINE_MONITOR_EXIT)
+ (t) == MONO_TRAMPOLINE_RGCTX_LAZY_FETCH)
/* These trampolines receive an argument directly in a register */
#define MONO_TRAMPOLINE_TYPE_HAS_ARG(t) \
- ((t) == MONO_TRAMPOLINE_MONITOR_ENTER || \
- (t) == MONO_TRAMPOLINE_MONITOR_ENTER_V4 || \
- (t) == MONO_TRAMPOLINE_MONITOR_EXIT || \
- (t) == MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD)
+ ((t) == MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD)
/* optimization flags */
#define OPTFLAG(id,shift,name,descr) MONO_OPT_ ## id = 1 << shift,
int val);
MonoTrampInfo* mono_tramp_info_create (const char *name, guint8 *code, guint32 code_size, MonoJumpInfo *ji, GSList *unwind_ops);
void mono_tramp_info_free (MonoTrampInfo *info);
-void mono_tramp_info_register (MonoTrampInfo *info);
+void mono_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain);
int mini_exception_id_by_name (const char *name);
gboolean mini_type_is_hfa (MonoType *t, int *out_nfields, int *out_esize) MONO_LLVM_INTERNAL;
void mono_walk_stack_with_state (MonoJitStackWalk func, MonoThreadUnwindState *state, MonoUnwindOptions unwind_options, void *user_data);
void mono_walk_stack (MonoJitStackWalk func, MonoUnwindOptions options, void *user_data);
gboolean mono_thread_state_init_from_sigctx (MonoThreadUnwindState *ctx, void *sigctx);
+void mono_thread_state_init (MonoThreadUnwindState *ctx);
gboolean mono_thread_state_init_from_current (MonoThreadUnwindState *ctx);
gboolean mono_thread_state_init_from_monoctx (MonoThreadUnwindState *ctx, MonoContext *mctx);
if (keepalive_stacks)
return;
MONO_GC_REGISTER_ROOT_PINNING (keepalive_stacks);
- keepalive_stacks = mono_g_hash_table_new (NULL, NULL);
+ keepalive_stacks = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_CONSERVATIVE_GC);
}
static void*
ctx = new_ctx;
if (endloop)
break;
- if (strcmp (jinfo_get_method (ji)->name, "Mark") == 0)
+ if (!ji->is_trampoline && strcmp (jinfo_get_method (ji)->name, "Mark") == 0)
endloop = TRUE;
} while (1);
#include <mono/metadata/marshal.h>
#include <mono/metadata/tabledefs.h>
#include <mono/metadata/mono-debug-debugger.h>
-#include <mono/metadata/monitor.h>
#include <mono/metadata/profiler-private.h>
#include <mono/metadata/gc-internal.h>
#include <mono/arch/amd64/amd64-codegen.h>
mono_arch_get_unbox_trampoline (MonoMethod *m, gpointer addr)
{
guint8 *code, *start;
+ GSList *unwind_ops;
int this_reg, size = NACL_SIZE (20, 32);
MonoDomain *domain = mono_domain_get ();
start = code = mono_domain_code_reserve (domain, size);
+ unwind_ops = mono_arch_get_cie_program ();
+
amd64_alu_reg_imm (code, X86_ADD, this_reg, sizeof (MonoObject));
/* FIXME: Optimize this */
amd64_mov_reg_imm (code, AMD64_RAX, addr);
mono_arch_flush_icache (start, code - start);
mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_UNBOX_TRAMPOLINE, m);
+ mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), domain);
+
return start;
}
mono_arch_get_static_rgctx_trampoline (MonoMethod *m, MonoMethodRuntimeGenericContext *mrgctx, gpointer addr)
{
guint8 *code, *start;
+ GSList *unwind_ops;
int buf_len;
MonoDomain *domain = mono_domain_get ();
start = code = mono_domain_code_reserve (domain, buf_len);
+ unwind_ops = mono_arch_get_cie_program ();
+
amd64_mov_reg_imm (code, MONO_ARCH_RGCTX_REG, mrgctx);
amd64_jump_code (code, addr);
g_assert ((code - start) < buf_len);
mono_arch_flush_icache (start, code - start);
mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL);
+ mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), domain);
+
return start;
}
offset += sizeof (MonoLMFTramp);
lmf_offset = -offset;
- framesize = ALIGN_TO (offset, MONO_ARCH_FRAME_ALIGNMENT);
+#ifdef TARGET_WIN32
+ /* Reserve space where the callee can save the argument registers */
+ offset += 4 * sizeof (mgreg_t);
+#endif
- orig_rsp_to_rbp_offset = 0;
- r11_save_code = code;
- /* Reserve space for the mov_membase_reg to save R11 */
- code += 5;
- after_r11_save_code = code;
+ framesize = ALIGN_TO (offset, MONO_ARCH_FRAME_ALIGNMENT);
// CFA = sp + 16 (the trampoline address is on the stack)
cfa_offset = 16;
// IP saved at CFA - 8
mono_add_unwind_op_offset (unwind_ops, code, buf, AMD64_RIP, -8);
+ orig_rsp_to_rbp_offset = 0;
+ r11_save_code = code;
+ /* Reserve space for the mov_membase_reg to save R11 */
+ code += 5;
+ after_r11_save_code = code;
+
/* Pop the return address off the stack */
amd64_pop_reg (code, AMD64_R11);
orig_rsp_to_rbp_offset += sizeof(mgreg_t);
//amd64_breakpoint (code);
#endif
- if (tramp_type != MONO_TRAMPOLINE_MONITOR_ENTER &&
- tramp_type != MONO_TRAMPOLINE_MONITOR_ENTER_V4 &&
- tramp_type != MONO_TRAMPOLINE_MONITOR_EXIT &&
- tramp_type != MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD) {
+ if (tramp_type != MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD) {
/* Obtain the trampoline argument which is encoded in the instruction stream */
if (aot) {
/* Load the GOT offset */
/* Restore stack */
amd64_leave (code);
+ cfa_offset -= sizeof (mgreg_t);
+ mono_add_unwind_op_def_cfa (unwind_ops, code, buf, AMD64_RSP, cfa_offset);
+
if (MONO_TRAMPOLINE_TYPE_MUST_RETURN (tramp_type)) {
/* Load result */
int i;
gboolean mrgctx;
MonoJumpInfo *ji = NULL;
- GSList *unwind_ops = NULL;
+ GSList *unwind_ops;
mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
index = MONO_RGCTX_SLOT_INDEX (slot);
return buf;
}
-#ifdef MONO_ARCH_MONITOR_OBJECT_REG
-
-gpointer
-mono_arch_create_monitor_enter_trampoline (MonoTrampInfo **info, gboolean is_v4, gboolean aot)
-{
- guint8 *tramp;
- guint8 *code, *buf;
- guint8 *jump_obj_null, *jump_sync_null, *jump_cmpxchg_failed, *jump_other_owner, *jump_tid, *jump_sync_thin_hash = NULL;
- guint8 *jump_lock_taken_true = NULL;
- int tramp_size;
- int status_offset, nest_offset;
- MonoJumpInfo *ji = NULL;
- GSList *unwind_ops = NULL;
- int obj_reg = MONO_AMD64_ARG_REG1;
- int lock_taken_reg = MONO_AMD64_ARG_REG2;
- int sync_reg = MONO_AMD64_ARG_REG3;
- int tid_reg = MONO_AMD64_ARG_REG4;
- int status_reg = AMD64_RAX;
-
- g_assert (MONO_ARCH_MONITOR_OBJECT_REG == obj_reg);
-#ifdef MONO_ARCH_MONITOR_LOCK_TAKEN_REG
- g_assert (MONO_ARCH_MONITOR_LOCK_TAKEN_REG == lock_taken_reg);
-#else
- g_assert (!is_v4);
-#endif
-
- mono_monitor_threads_sync_members_offset (&status_offset, &nest_offset);
- g_assert (MONO_THREADS_SYNC_MEMBER_SIZE (status_offset) == sizeof (guint32));
- g_assert (MONO_THREADS_SYNC_MEMBER_SIZE (nest_offset) == sizeof (guint32));
- status_offset = MONO_THREADS_SYNC_MEMBER_OFFSET (status_offset);
- nest_offset = MONO_THREADS_SYNC_MEMBER_OFFSET (nest_offset);
-
- tramp_size = 128;
-
- code = buf = mono_global_codeman_reserve (tramp_size);
-
- unwind_ops = mono_arch_get_cie_program ();
-
- if (!aot && mono_thread_get_tls_offset () != -1) {
- /* MonoObject* obj is in obj_reg */
- /* is obj null? */
- amd64_test_reg_reg (code, obj_reg, obj_reg);
- /* if yes, jump to actual trampoline */
- jump_obj_null = code;
- amd64_branch8 (code, X86_CC_Z, -1, 1);
-
- if (is_v4) {
- amd64_test_membase_imm (code, lock_taken_reg, 0, 1);
- /* if *lock_taken is 1, jump to actual trampoline */
- jump_lock_taken_true = code;
- x86_branch8 (code, X86_CC_NZ, -1, 1);
- }
-
- /* load obj->synchronization to sync_reg */
- amd64_mov_reg_membase (code, sync_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, synchronisation), 8);
-
- if (mono_gc_is_moving ()) {
- /*if bit zero is set it's a thin hash*/
- /*FIXME use testb encoding*/
- amd64_test_reg_imm (code, sync_reg, 0x01);
- jump_sync_thin_hash = code;
- amd64_branch8 (code, X86_CC_NE, -1, 1);
-
- /*clear bits used by the gc*/
- amd64_alu_reg_imm (code, X86_AND, sync_reg, ~0x3);
- }
-
- /* is synchronization null? */
- amd64_test_reg_reg (code, sync_reg, sync_reg);
- /* if yes, jump to actual trampoline */
- jump_sync_null = code;
- amd64_branch8 (code, X86_CC_Z, -1, 1);
-
- /* load MonoInternalThread* into tid_reg */
- code = mono_amd64_emit_tls_get (code, tid_reg, mono_thread_get_tls_offset ());
- /* load TID into tid_reg */
- amd64_mov_reg_membase (code, tid_reg, tid_reg, MONO_STRUCT_OFFSET (MonoInternalThread, small_id), 4);
-
- /* is synchronization->owner free */
- amd64_mov_reg_membase (code, status_reg, sync_reg, status_offset, 4);
- amd64_test_reg_imm_size (code, status_reg, OWNER_MASK, 4);
- /* if not, jump to next case */
- jump_tid = code;
- amd64_branch8 (code, X86_CC_NZ, -1, 1);
-
- /* if yes, try a compare-exchange with the TID */
- g_assert (tid_reg != X86_EAX);
- /* Form new status in tid_reg */
- amd64_alu_reg_reg_size (code, X86_OR, tid_reg, status_reg, 4);
- /* compare and exchange */
- amd64_prefix (code, X86_LOCK_PREFIX);
- amd64_cmpxchg_membase_reg_size (code, sync_reg, status_offset, tid_reg, 4);
- /* if not successful, jump to actual trampoline */
- jump_cmpxchg_failed = code;
- amd64_branch8 (code, X86_CC_NZ, -1, 1);
- /* if successful, return */
- if (is_v4)
- amd64_mov_membase_imm (code, lock_taken_reg, 0, 1, 1);
- amd64_ret (code);
-
- /* next case: synchronization->owner is not null */
- x86_patch (jump_tid, code);
- /* is synchronization->owner == TID? */
- amd64_alu_reg_imm_size (code, X86_AND, status_reg, OWNER_MASK, 4);
- amd64_alu_reg_reg_size (code, X86_CMP, status_reg, tid_reg, 4);
- /* if not, jump to actual trampoline */
- jump_other_owner = code;
- amd64_branch8 (code, X86_CC_NZ, -1, 1);
- /* if yes, increment nest */
- amd64_inc_membase_size (code, sync_reg, nest_offset, 4);
- /* return */
- if (is_v4)
- amd64_mov_membase_imm (code, lock_taken_reg, 0, 1, 1);
- amd64_ret (code);
-
- x86_patch (jump_obj_null, code);
- if (jump_sync_thin_hash)
- x86_patch (jump_sync_thin_hash, code);
- x86_patch (jump_sync_null, code);
- x86_patch (jump_cmpxchg_failed, code);
- x86_patch (jump_other_owner, code);
- if (is_v4)
- x86_patch (jump_lock_taken_true, code);
- }
-
- /* jump to the actual trampoline */
- if (MONO_AMD64_ARG_REG1 != obj_reg)
- amd64_mov_reg_reg (code, MONO_AMD64_ARG_REG1, obj_reg, sizeof (mgreg_t));
-
- if (aot) {
- if (is_v4)
- code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "specific_trampoline_monitor_enter_v4");
- else
- code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "specific_trampoline_monitor_enter");
- amd64_jump_reg (code, AMD64_R11);
- } else {
- if (is_v4)
- tramp = mono_arch_create_specific_trampoline (NULL, MONO_TRAMPOLINE_MONITOR_ENTER_V4, mono_get_root_domain (), NULL);
- else
- tramp = mono_arch_create_specific_trampoline (NULL, MONO_TRAMPOLINE_MONITOR_ENTER, mono_get_root_domain (), NULL);
-
- /* jump to the actual trampoline */
- amd64_jump_code (code, tramp);
- }
-
- nacl_global_codeman_validate (&buf, tramp_size, &code);
-
- mono_arch_flush_icache (code, code - buf);
- mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_MONITOR, NULL);
- g_assert (code - buf <= tramp_size);
-
- if (is_v4)
- *info = mono_tramp_info_create ("monitor_enter_v4_trampoline", buf, code - buf, ji, unwind_ops);
- else
- *info = mono_tramp_info_create ("monitor_enter_trampoline", buf, code - buf, ji, unwind_ops);
-
- return buf;
-}
-
-gpointer
-mono_arch_create_monitor_exit_trampoline (MonoTrampInfo **info, gboolean aot)
-{
- guint8 *tramp;
- guint8 *code, *buf;
- guint8 *jump_obj_null, *jump_have_waiters, *jump_sync_null, *jump_not_owned, *jump_cmpxchg_failed;
- guint8 *jump_next, *jump_sync_thin_hash = NULL;
- int tramp_size;
- int status_offset, nest_offset;
- MonoJumpInfo *ji = NULL;
- GSList *unwind_ops = NULL;
- int obj_reg = MONO_AMD64_ARG_REG1;
- int sync_reg = MONO_AMD64_ARG_REG2;
- int status_reg = MONO_AMD64_ARG_REG3;
-
- g_assert (obj_reg == MONO_ARCH_MONITOR_OBJECT_REG);
-
- mono_monitor_threads_sync_members_offset (&status_offset, &nest_offset);
- g_assert (MONO_THREADS_SYNC_MEMBER_SIZE (status_offset) == sizeof (guint32));
- g_assert (MONO_THREADS_SYNC_MEMBER_SIZE (nest_offset) == sizeof (guint32));
- status_offset = MONO_THREADS_SYNC_MEMBER_OFFSET (status_offset);
- nest_offset = MONO_THREADS_SYNC_MEMBER_OFFSET (nest_offset);
-
- tramp_size = 112;
-
- code = buf = mono_global_codeman_reserve (tramp_size);
-
- unwind_ops = mono_arch_get_cie_program ();
-
- if (!aot && mono_thread_get_tls_offset () != -1) {
- /* MonoObject* obj is in obj_reg */
- /* is obj null? */
- amd64_test_reg_reg (code, obj_reg, obj_reg);
- /* if yes, jump to actual trampoline */
- jump_obj_null = code;
- amd64_branch8 (code, X86_CC_Z, -1, 1);
-
- /* load obj->synchronization to RCX */
- amd64_mov_reg_membase (code, sync_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, synchronisation), 8);
-
- if (mono_gc_is_moving ()) {
- /*if bit zero is set it's a thin hash*/
- /*FIXME use testb encoding*/
- amd64_test_reg_imm (code, sync_reg, 0x01);
- jump_sync_thin_hash = code;
- amd64_branch8 (code, X86_CC_NE, -1, 1);
-
- /*clear bits used by the gc*/
- amd64_alu_reg_imm (code, X86_AND, sync_reg, ~0x3);
- }
-
- /* is synchronization null? */
- amd64_test_reg_reg (code, sync_reg, sync_reg);
- /* if yes, jump to actual trampoline */
- jump_sync_null = code;
- amd64_branch8 (code, X86_CC_Z, -1, 1);
-
- /* next case: synchronization is not null */
- /* load MonoInternalThread* into RAX */
- code = mono_amd64_emit_tls_get (code, AMD64_RAX, mono_thread_get_tls_offset ());
- /* load TID into RAX */
- amd64_mov_reg_membase (code, AMD64_RAX, AMD64_RAX, MONO_STRUCT_OFFSET (MonoInternalThread, small_id), 4);
- /* is synchronization->owner == TID */
- amd64_mov_reg_membase (code, status_reg, sync_reg, status_offset, 4);
- amd64_alu_reg_reg_size (code, X86_XOR, AMD64_RAX, status_reg, 4);
- amd64_test_reg_imm_size (code, AMD64_RAX, OWNER_MASK, 4);
-
- /* if no, jump to actual trampoline */
- jump_not_owned = code;
- amd64_branch8 (code, X86_CC_NZ, -1, 1);
-
- /* next case: synchronization->owner == TID */
- /* is synchronization->nest == 1 */
- amd64_alu_membase_imm_size (code, X86_CMP, sync_reg, nest_offset, 1, 4);
- /* if not, jump to next case */
- jump_next = code;
- amd64_branch8 (code, X86_CC_NZ, -1, 1);
- /* if yes, is synchronization->entry_count greater than zero */
- amd64_test_reg_imm_size (code, status_reg, ENTRY_COUNT_WAITERS, 4);
- /* if not, jump to actual trampoline */
- jump_have_waiters = code;
- amd64_branch8 (code, X86_CC_NZ, -1 , 1);
- /* if yes, try to set synchronization->owner to null and return */
- g_assert (status_reg != AMD64_RAX);
- /* old status in RAX */
- amd64_mov_reg_reg (code, AMD64_RAX, status_reg, 4);
- /* form new status */
- amd64_alu_reg_imm_size (code, X86_AND, status_reg, ENTRY_COUNT_MASK, 4);
- /* compare and exchange */
- amd64_prefix (code, X86_LOCK_PREFIX);
- amd64_cmpxchg_membase_reg_size (code, sync_reg, status_offset, status_reg, 4);
- /* if not successful, jump to actual trampoline */
- jump_cmpxchg_failed = code;
- amd64_branch8 (code, X86_CC_NZ, -1, 1);
- amd64_ret (code);
-
- /* next case: synchronization->nest is not 1 */
- x86_patch (jump_next, code);
- /* decrease synchronization->nest and return */
- amd64_dec_membase_size (code, sync_reg, nest_offset, 4);
- amd64_ret (code);
-
- if (jump_sync_thin_hash)
- x86_patch (jump_sync_thin_hash, code);
- x86_patch (jump_obj_null, code);
- x86_patch (jump_have_waiters, code);
- x86_patch (jump_not_owned, code);
- x86_patch (jump_cmpxchg_failed, code);
- x86_patch (jump_sync_null, code);
- }
-
- /* jump to the actual trampoline */
- if (MONO_AMD64_ARG_REG1 != obj_reg)
- amd64_mov_reg_reg (code, MONO_AMD64_ARG_REG1, obj_reg, sizeof (mgreg_t));
-
- if (aot) {
- code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "specific_trampoline_monitor_exit");
- amd64_jump_reg (code, AMD64_R11);
- } else {
- tramp = mono_arch_create_specific_trampoline (NULL, MONO_TRAMPOLINE_MONITOR_EXIT, mono_get_root_domain (), NULL);
- amd64_jump_code (code, tramp);
- }
-
- nacl_global_codeman_validate (&buf, tramp_size, &code);
-
- mono_arch_flush_icache (code, code - buf);
- mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_MONITOR, NULL);
- g_assert (code - buf <= tramp_size);
-
- *info = mono_tramp_info_create ("monitor_exit_trampoline", buf, code - buf, ji, unwind_ops);
-
- return buf;
-}
-
-#else
-
-gpointer
-mono_arch_create_monitor_enter_trampoline (MonoTrampInfo **info, gboolean is_v4, gboolean aot)
-{
- g_assert_not_reached ();
- return NULL;
-}
-
-gpointer
-mono_arch_create_monitor_exit_trampoline (MonoTrampInfo **info, gboolean aot)
-{
- g_assert_not_reached ();
- return NULL;
-}
-
-#endif
-
void
mono_arch_invalidate_method (MonoJitInfo *ji, void *func, gpointer func_arg)
{
guint8 *code, *buf;
int tramp_size = 64;
MonoJumpInfo *ji = NULL;
- GSList *unwind_ops = NULL;
+ GSList *unwind_ops;
g_assert (!aot);
code = buf = mono_global_codeman_reserve (tramp_size);
+ unwind_ops = mono_arch_get_cie_program ();
+
/*
This trampoline restore the call chain of the handler block then jumps into the code that deals with it.
*/
amd64_mov_reg_membase (code, MONO_AMD64_ARG_REG1, MONO_AMD64_ARG_REG1, MONO_STRUCT_OFFSET (MonoJitTlsData, handler_block_return_address), 8);
/* Simulate a call */
amd64_push_reg (code, AMD64_RAX);
+ mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, 16);
amd64_jump_code (code, tramp);
} else {
/*Slow path uses a c helper*/
amd64_mov_reg_reg (code, MONO_AMD64_ARG_REG1, AMD64_RSP, 8);
amd64_mov_reg_imm (code, AMD64_RAX, tramp);
amd64_push_reg (code, AMD64_RAX);
+ mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, 16);
amd64_push_reg (code, AMD64_RAX);
+ mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, 24);
amd64_jump_code (code, handler_block_trampoline_helper);
}
code = buf = mono_global_codeman_reserve (tramp_size);
- framesize = sizeof (MonoContext);
+ framesize = 0;
+#ifdef TARGET_WIN32
+ /* Reserve space where the callee can save the argument registers */
+ framesize += 4 * sizeof (mgreg_t);
+#endif
+
+ ctx_offset = framesize;
+ framesize += sizeof (MonoContext);
+
framesize = ALIGN_TO (framesize, MONO_ARCH_FRAME_ALIGNMENT);
// CFA = sp + 8
mono_add_unwind_op_def_cfa_reg (unwind_ops, code, buf, AMD64_RBP);
amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, framesize);
- ctx_offset = 0;
gregs_offset = ctx_offset + MONO_STRUCT_OFFSET (MonoContext, gregs);
/* Initialize a MonoContext structure on the stack */
amd64_mov_membase_reg (code, AMD64_RBP, sizeof (mgreg_t), AMD64_R11, sizeof (mgreg_t));
amd64_leave (code);
+ cfa_offset -= sizeof (mgreg_t);
+ mono_add_unwind_op_def_cfa (unwind_ops, code, buf, AMD64_RSP, cfa_offset);
amd64_ret (code);
mono_arch_flush_icache (code, code - buf);
/* The offset where lr was saved inside the regsave area */
lr_offset = 13 * sizeof (mgreg_t);
- // FIXME: Finish the unwind info, the current info allows us to unwind
- // when the trampoline is not in the epilog
-
// CFA = SP + (num registers pushed) * 4
cfa_offset = 14 * sizeof (mgreg_t);
mono_add_unwind_op_def_cfa (unwind_ops, code, buf, ARMREG_SP, cfa_offset);
* Note that IP has been conveniently set to the method addr.
*/
ARM_ADD_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, STACK - regsave_size);
+ cfa_offset -= STACK - regsave_size;
+ mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, cfa_offset);
ARM_POP_NWB (code, 0x5fff);
+ mono_add_unwind_op_same_value (unwind_ops, code, buf, ARMREG_LR);
if (tramp_type == MONO_TRAMPOLINE_RGCTX_LAZY_FETCH)
ARM_MOV_REG_REG (code, ARMREG_R0, ARMREG_IP);
ARM_ADD_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, regsave_size);
+ cfa_offset -= regsave_size;
+ g_assert (cfa_offset == 0);
+ mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, cfa_offset);
if (MONO_TRAMPOLINE_TYPE_MUST_RETURN (tramp_type))
code = emit_bx (code, ARMREG_LR);
else
{
guint8 *code, *start;
MonoDomain *domain = mono_domain_get ();
+ GSList *unwind_ops;
#ifdef USE_JUMP_TABLES
gpointer *jte;
guint32 size = 20;
start = code = mono_domain_code_reserve (domain, size);
+ unwind_ops = mono_arch_get_cie_program ();
+
#ifdef USE_JUMP_TABLES
jte = mono_jumptable_add_entry ();
code = mono_arm_load_jumptable_entry (code, jte, ARMREG_IP);
/*g_print ("unbox trampoline at %d for %s:%s\n", this_pos, m->klass->name, m->name);
g_print ("unbox code is at %p for method at %p\n", start, addr);*/
+ mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), domain);
+
return start;
}
mono_arch_get_static_rgctx_trampoline (MonoMethod *m, MonoMethodRuntimeGenericContext *mrgctx, gpointer addr)
{
guint8 *code, *start;
+ GSList *unwind_ops;
#ifdef USE_JUMP_TABLES
int buf_len = 20;
gpointer *jte;
start = code = mono_domain_code_reserve (domain, buf_len);
+ unwind_ops = mono_arch_get_cie_program ();
+
#ifdef USE_JUMP_TABLES
jte = mono_jumptable_add_entries (2);
code = mono_arm_load_jumptable_entry_addr (code, jte, ARMREG_IP);
mono_arch_flush_icache (start, code - start);
mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL);
+ mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), domain);
+
return start;
}
code = buf = mono_global_codeman_reserve (tramp_size);
- mono_add_unwind_op_def_cfa (unwind_ops, code, buf, ARMREG_SP, 0);
+ unwind_ops = mono_arch_get_cie_program ();
rgctx_null_jumps = g_malloc (sizeof (guint8*) * (depth + 2));
njumps = 0;
code = buf = mono_global_codeman_reserve (tramp_size);
- mono_add_unwind_op_def_cfa (unwind_ops, code, buf, ARMREG_SP, 0);
+ unwind_ops = mono_arch_get_cie_program ();
// FIXME: Currently, we always go to the slow path.
/* Load trampoline addr */
code = buf = mono_global_codeman_reserve (tramp_size);
+ unwind_ops = mono_arch_get_cie_program ();
+
tramp = mono_arch_create_specific_trampoline (NULL, MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD, NULL, NULL);
/*
mono_arch_flush_icache (buf, code - buf);
mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL);
+ mono_tramp_info_register (mono_tramp_info_create (NULL, buf, code - buf, NULL, NULL), domain);
+
return buf;
}
desc [0] = buf;
desc [1] = func_gp;
+ mono_tramp_info_register (mono_tramp_info_create (NULL, buf, code.buf - buf, NULL, NULL), domain);
+
return desc;
}
/*g_print ("unbox trampoline at %d for %s:%s\n", this_pos, m->klass->name, m->name);
g_print ("unbox code is at %p for method at %p\n", start, addr);*/
+ mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);
+
return start;
}
mono_arch_flush_icache (start, code - start);
+ mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);
+
return start;
}
/*g_print ("unbox trampoline at %d for %s:%s\n", this_pos, m->klass->name, m->name);
g_print ("unbox code is at %p for method at %p\n", start, addr);*/
+ mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);
+
return start;
}
mono_arch_flush_icache (start, code - start);
g_assert ((code - start) <= size);
+ mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);
+
return start;
}
#include <mono/metadata/appdomain.h>
#include <mono/metadata/gc-internal.h>
#include <mono/metadata/marshal.h>
-#include <mono/metadata/monitor.h>
#include <mono/metadata/profiler-private.h>
#include <mono/metadata/tabledefs.h>
#include <mono/arch/s390x/s390x-codegen.h>
mono_arch_flush_icache (start, code - start);
mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_UNBOX_TRAMPOLINE, method);
+ mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);
+
return start;
}
/*----------------------------------------------------------*/
code = buf = mono_domain_code_reserve (domain, SPECIFIC_TRAMPOLINE_SIZE);
- switch (tramp_type) {
- /*
- * Monitor tramps have the object in r2
- */
- case MONO_TRAMPOLINE_MONITOR_ENTER:
- case MONO_TRAMPOLINE_MONITOR_ENTER_V4:
- case MONO_TRAMPOLINE_MONITOR_EXIT:
- s390_lgr (buf, s390_r1, s390_r2);
- break;
- default :
- S390_SET (buf, s390_r1, arg1);
- }
+ S390_SET (buf, s390_r1, arg1);
displace = (tramp - buf) / 2;
s390_jg (buf, displace);
mono_arch_flush_icache (start, code - start);
mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_HELPER, NULL);
+ mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);
+
return(start);
}
}
/*========================= End of Function ========================*/
-
-#ifdef MONO_ARCH_MONITOR_OBJECT_REG
-/*------------------------------------------------------------------*/
-/* */
-/* Name - mono_arch_create_monitor_enter_trampoline */
-/* */
-/* Function - */
-/* */
-/*------------------------------------------------------------------*/
-
-gpointer
-mono_arch_create_monitor_enter_trampoline (MonoTrampInfo **info, gboolean is_v4, gboolean aot)
-{
- guint8 *tramp,
- *code, *buf;
- gint16 *jump_obj_null,
- *jump_sync_null,
- *jump_cs_failed,
- *jump_other_owner,
- *jump_tid,
- *jump_sync_thin_hash = NULL,
- *jump_lock_taken_true = NULL;
- int tramp_size,
- status_reg = s390_r0,
- lock_taken_reg = s390_r1,
- obj_reg = s390_r2,
- sync_reg = s390_r3,
- tid_reg = s390_r4,
- status_offset,
- nest_offset;
- MonoJumpInfo *ji = NULL;
- GSList *unwind_ops = NULL;
-
- g_assert (MONO_ARCH_MONITOR_OBJECT_REG == obj_reg);
-#ifdef MONO_ARCH_MONITOR_LOCK_TAKEN_REG
- g_assert (MONO_ARCH_MONITOR_LOCK_TAKEN_REG == lock_taken_reg);
-#else
- g_assert (!is_v4);
-#endif
-
- mono_monitor_threads_sync_members_offset (&status_offset, &nest_offset);
- g_assert (MONO_THREADS_SYNC_MEMBER_SIZE (status_offset) == sizeof (guint32));
- g_assert (MONO_THREADS_SYNC_MEMBER_SIZE (nest_offset) == sizeof (guint32));
- status_offset = MONO_THREADS_SYNC_MEMBER_OFFSET (status_offset);
- nest_offset = MONO_THREADS_SYNC_MEMBER_OFFSET (nest_offset);
-
- tramp_size = 160;
-
- code = buf = mono_global_codeman_reserve (tramp_size);
-
- unwind_ops = mono_arch_get_cie_program ();
-
- if (mono_thread_get_tls_offset () != -1) {
- /* MonoObject* obj is in obj_reg */
- /* is obj null? */
- s390_ltgr (code, obj_reg, obj_reg);
- /* if yes, jump to actual trampoline */
- s390_jz (code, 0); CODEPTR(code, jump_obj_null);
-
- if (is_v4) {
- s390_cli (code, lock_taken_reg, 0, 1);
- /* if *lock_taken is 1, jump to actual trampoline */
- s390_je (code, 0); CODEPTR(code, jump_lock_taken_true);
- }
-
- /* load obj->synchronization to sync_reg */
- s390_lg (code, sync_reg, 0, obj_reg, MONO_STRUCT_OFFSET (MonoObject, synchronisation));
-
- if (mono_gc_is_moving ()) {
- /*if bit zero is set it's a thin hash*/
- s390_tmll (code, sync_reg, 1);
- s390_jo (code, 0); CODEPTR(code, jump_sync_thin_hash);
-
- /* Clear bits used by the gc */
- s390_nill (code, sync_reg, ~0x3);
- }
-
- /* is synchronization null? */
- s390_ltgr (code, sync_reg, sync_reg);
- /* if yes, jump to actual trampoline */
- s390_jz (code, 0); CODEPTR(code, jump_sync_null);
-
- /* load MonoInternalThread* into tid_reg */
- s390_ear (code, s390_r5, 0);
- s390_sllg(code, s390_r5, s390_r5, 0, 32);
- s390_ear (code, s390_r5, 1);
- /* load tid */
- s390_lg (code, tid_reg, 0, s390_r5, mono_thread_get_tls_offset ());
- s390_lgf (code, tid_reg, 0, tid_reg, MONO_STRUCT_OFFSET (MonoInternalThread, small_id));
-
- /* is synchronization->owner free */
- s390_lgf (code, status_reg, 0, sync_reg, status_offset);
- s390_nilf (code, status_reg, OWNER_MASK);
- /* if not, jump to next case */
- s390_jnz (code, 0); CODEPTR(code, jump_tid);
-
- /* if yes, try a compare-exchange with the TID */
- /* Form new status in tid_reg */
- s390_xr (code, tid_reg, status_reg);
- /* compare and exchange */
- s390_cs (code, status_reg, tid_reg, sync_reg, status_offset);
- s390_jnz (code, 0); CODEPTR(code, jump_cs_failed);
- /* if successful, return */
- if (is_v4)
- s390_mvi (code, lock_taken_reg, 0, 1);
- s390_br (code, s390_r14);
-
- /* next case: synchronization->owner is not null */
- PTRSLOT(code, jump_tid);
- /* is synchronization->owner == TID? */
- s390_nilf (code, status_reg, OWNER_MASK);
- s390_cr (code, status_reg, tid_reg);
- /* if not, jump to actual trampoline */
- s390_jnz (code, 0); CODEPTR(code, jump_other_owner);
- /* if yes, increment nest */
- s390_lgf (code, s390_r5, 0, sync_reg, nest_offset);
- s390_ahi (code, s390_r5, 1);
- s390_st (code, s390_r5, 0, sync_reg, nest_offset);
- /* return */
- if (is_v4)
- s390_mvi (code, lock_taken_reg, 0, 1);
- s390_br (code, s390_r14);
-
- PTRSLOT (code, jump_obj_null);
- if (jump_sync_thin_hash)
- PTRSLOT (code, jump_sync_thin_hash);
- PTRSLOT (code, jump_sync_null);
- PTRSLOT (code, jump_cs_failed);
- PTRSLOT (code, jump_other_owner);
- if (is_v4)
- PTRSLOT (code, jump_lock_taken_true);
- }
-
- /* jump to the actual trampoline */
- if (is_v4)
- tramp = mono_arch_create_specific_trampoline (NULL, MONO_TRAMPOLINE_MONITOR_ENTER_V4, mono_get_root_domain (), NULL);
- else
- tramp = mono_arch_create_specific_trampoline (NULL, MONO_TRAMPOLINE_MONITOR_ENTER, mono_get_root_domain (), NULL);
-
- /* jump to the actual trampoline */
- S390_SET (code, s390_r1, tramp);
- s390_br (code, s390_r1);
-
- mono_arch_flush_icache (code, code - buf);
- mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_MONITOR, NULL);
- g_assert (code - buf <= tramp_size);
-
- if (info) {
- if (is_v4)
- *info = mono_tramp_info_create ("monitor_enter_v4_trampoline", buf, code - buf, ji, unwind_ops);
- else
- *info = mono_tramp_info_create ("monitor_enter_trampoline", buf, code - buf, ji, unwind_ops);
- }
-
- return buf;
-}
-
-/*========================= End of Function ========================*/
-
-/*------------------------------------------------------------------*/
-/* */
-/* Name - mono_arch_create_monitor_exit_trampoline */
-/* */
-/* Function - */
-/* */
-/*------------------------------------------------------------------*/
-
-gpointer
-mono_arch_create_monitor_exit_trampoline (MonoTrampInfo **info, gboolean aot)
-{
- guint8 *tramp,
- *code, *buf;
- gint16 *jump_obj_null,
- *jump_have_waiters,
- *jump_sync_null,
- *jump_not_owned,
- *jump_cs_failed,
- *jump_next,
- *jump_sync_thin_hash = NULL;
- int tramp_size,
- status_offset, nest_offset;
- MonoJumpInfo *ji = NULL;
- GSList *unwind_ops = NULL;
- int obj_reg = s390_r2,
- sync_reg = s390_r3,
- status_reg = s390_r4;
-
- g_assert (obj_reg == MONO_ARCH_MONITOR_OBJECT_REG);
-
- mono_monitor_threads_sync_members_offset (&status_offset, &nest_offset);
- g_assert (MONO_THREADS_SYNC_MEMBER_SIZE (status_offset) == sizeof (guint32));
- g_assert (MONO_THREADS_SYNC_MEMBER_SIZE (nest_offset) == sizeof (guint32));
- status_offset = MONO_THREADS_SYNC_MEMBER_OFFSET (status_offset);
- nest_offset = MONO_THREADS_SYNC_MEMBER_OFFSET (nest_offset);
-
- tramp_size = 160;
-
- code = buf = mono_global_codeman_reserve (tramp_size);
-
- unwind_ops = mono_arch_get_cie_program ();
-
- if (mono_thread_get_tls_offset () != -1) {
- /* MonoObject* obj is in obj_reg */
- /* is obj null? */
- s390_ltgr (code, obj_reg, obj_reg);
- /* if yes, jump to actual trampoline */
- s390_jz (code, 0); CODEPTR(code, jump_obj_null);
-
- /* load obj->synchronization to RCX */
- s390_lg (code, sync_reg, 0, obj_reg, MONO_STRUCT_OFFSET (MonoObject, synchronisation));
-
- if (mono_gc_is_moving ()) {
- /*if bit zero is set it's a thin hash*/
- s390_tmll (code, sync_reg, 1);
- s390_jo (code, 0); CODEPTR(code, jump_sync_thin_hash);
-
- /* Clear bits used by the gc */
- s390_nill (code, sync_reg, ~0x3);
- }
-
- /* is synchronization null? */
- s390_ltgr (code, sync_reg, sync_reg);
- /* if yes, jump to actual trampoline */
- s390_jz (code, 0); CODEPTR(code, jump_sync_null);
-
- /* next case: synchronization is not null */
- /* load MonoInternalThread* into r5 */
- s390_ear (code, s390_r5, 0);
- s390_sllg(code, s390_r5, s390_r5, 0, 32);
- s390_ear (code, s390_r5, 1);
- /* load TID into r1 */
- s390_lg (code, s390_r1, 0, s390_r5, mono_thread_get_tls_offset ());
- s390_lgf (code, s390_r1, 0, s390_r1, MONO_STRUCT_OFFSET (MonoInternalThread, small_id));
- /* is synchronization->owner == TID */
- s390_lgf (code, status_reg, 0, sync_reg, status_offset);
- s390_xr (code, s390_r1, status_reg);
- s390_tmlh (code, s390_r1, OWNER_MASK);
- /* if not, jump to actual trampoline */
- s390_jno (code, 0); CODEPTR(code, jump_not_owned);
-
- /* next case: synchronization->owner == TID */
- /* is synchronization->nest == 1 */
- s390_lgf (code, s390_r0, 0, sync_reg, nest_offset);
- s390_chi (code, s390_r0, 1);
- /* if not, jump to next case */
- s390_jne (code, 0); CODEPTR(code, jump_next);
- /* if yes, is synchronization->entry_count greater than zero */
- s390_cfi (code, status_reg, ENTRY_COUNT_WAITERS);
- /* if not, jump to actual trampoline */
- s390_jnz (code, 0); CODEPTR(code, jump_have_waiters);
- /* if yes, try to set synchronization->owner to null and return */
- /* old status in s390_r0 */
- s390_lgfr (code, s390_r0, status_reg);
- /* form new status */
- s390_nilf (code, status_reg, ENTRY_COUNT_MASK);
- /* compare and exchange */
- s390_cs (code, s390_r0, status_reg, sync_reg, status_offset);
- /* if not successful, jump to actual trampoline */
- s390_jnz (code, 0); CODEPTR(code, jump_cs_failed);
- s390_br (code, s390_r14);
-
- /* next case: synchronization->nest is not 1 */
- PTRSLOT (code, jump_next);
- /* decrease synchronization->nest and return */
- s390_lgf (code, s390_r0, 0, sync_reg, nest_offset);
- s390_ahi (code, s390_r0, -1);
- s390_st (code, s390_r0, 0, sync_reg, nest_offset);
- s390_br (code, s390_r14);
-
- PTRSLOT (code, jump_obj_null);
- if (jump_sync_thin_hash)
- PTRSLOT (code, jump_sync_thin_hash);
- PTRSLOT (code, jump_have_waiters);
- PTRSLOT (code, jump_not_owned);
- PTRSLOT (code, jump_cs_failed);
- PTRSLOT (code, jump_sync_null);
- }
-
- /* jump to the actual trampoline */
- tramp = mono_arch_create_specific_trampoline (NULL, MONO_TRAMPOLINE_MONITOR_EXIT, mono_get_root_domain (), NULL);
-
- S390_SET (code, s390_r1, tramp);
- s390_br (code, s390_r1);
-
- mono_arch_flush_icache (code, code - buf);
- mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_MONITOR, NULL);
- g_assert (code - buf <= tramp_size);
-
- if (info)
- *info = mono_tramp_info_create ("monitor_exit_trampoline", buf, code - buf, ji, unwind_ops);
-
- return buf;
-}
-
-/*========================= End of Function ========================*/
-#endif
mono_arch_flush_icache (start, code - start);
+ mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), NULL);
+
return start;
}
#include <mono/metadata/tabledefs.h>
#include <mono/metadata/mono-debug.h>
#include <mono/metadata/mono-debug-debugger.h>
-#include <mono/metadata/monitor.h>
#include <mono/metadata/profiler-private.h>
#include <mono/metadata/gc-internal.h>
#include <mono/arch/x86/x86-codegen.h>
#include "mini.h"
#include "mini-x86.h"
+#include "debugger-agent.h"
#define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
guint8 *code, *start;
int this_pos = 4, size = NACL_SIZE(16, 32);
MonoDomain *domain = mono_domain_get ();
+ GSList *unwind_ops;
start = code = mono_domain_code_reserve (domain, size);
+ unwind_ops = mono_arch_get_cie_program ();
+
x86_alu_membase_imm (code, X86_ADD, X86_ESP, this_pos, sizeof (MonoObject));
x86_jump_code (code, addr);
g_assert ((code - start) < size);
nacl_domain_code_validate (domain, &start, size, &code);
mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_UNBOX_TRAMPOLINE, m);
+ mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), domain);
+
return start;
}
{
guint8 *code, *start;
int buf_len;
+ GSList *unwind_ops;
MonoDomain *domain = mono_domain_get ();
start = code = mono_domain_code_reserve (domain, buf_len);
+ unwind_ops = mono_arch_get_cie_program ();
+
x86_mov_reg_imm (code, MONO_ARCH_RGCTX_REG, mrgctx);
x86_jump_code (code, addr);
g_assert ((code - start) <= buf_len);
mono_arch_flush_icache (start, code - start);
mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL);
+ mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), domain);
+
return start;
}
GSList *unwind_ops = NULL;
MonoJumpInfo *ji = NULL;
int i, offset, frame_size, regarray_offset, lmf_offset, caller_ip_offset, arg_offset;
-
- unwind_ops = mono_arch_get_cie_program ();
+ int cfa_offset; /* cfa = cfa_reg + cfa_offset */
code = buf = mono_global_codeman_reserve (256);
* the ret address is at: esp + (pushed_args + 1) * sizeof (gpointer)
*/
- // FIXME: Unwind info
-
/* Compute frame offsets relative to the frame pointer %ebp */
arg_offset = sizeof (mgreg_t);
caller_ip_offset = 2 * sizeof (mgreg_t);
offset += 4 * sizeof (mgreg_t);
frame_size = ALIGN_TO (offset, MONO_ARCH_FRAME_ALIGNMENT);
+ /* ret addr and arg are on the stack */
+ cfa_offset = 2 * sizeof (mgreg_t);
+ mono_add_unwind_op_def_cfa (unwind_ops, code, buf, X86_ESP, cfa_offset);
+ // IP saved at CFA - 4
+ mono_add_unwind_op_offset (unwind_ops, code, buf, X86_NREG, -4);
+
/* Allocate frame */
x86_push_reg (code, X86_EBP);
+ cfa_offset += sizeof (mgreg_t);
+ mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, cfa_offset);
+ mono_add_unwind_op_offset (unwind_ops, code, buf, X86_EBP, -cfa_offset);
+
x86_mov_reg_reg (code, X86_EBP, X86_ESP, sizeof (mgreg_t));
+ mono_add_unwind_op_def_cfa_reg (unwind_ops, code, buf, X86_EBP);
+
/* There are three words on the stack, adding + 4 aligns the stack to 16, which is needed on osx */
x86_alu_reg_imm (code, X86_SUB, X86_ESP, frame_size + sizeof (mgreg_t));
/* Restore frame */
x86_leave (code);
+ cfa_offset -= sizeof (mgreg_t);
+ mono_add_unwind_op_def_cfa (unwind_ops, code, buf, X86_ESP, cfa_offset);
+ mono_add_unwind_op_same_value (unwind_ops, code, buf, X86_EBP);
if (MONO_TRAMPOLINE_TYPE_MUST_RETURN (tramp_type)) {
/* Load the value returned by the trampoline */
x86_mov_reg_membase (code, X86_EAX, X86_ESP, 0, 4);
/* The trampoline returns normally, pop the trampoline argument */
x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
+ cfa_offset -= sizeof (mgreg_t);
+ mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, cfa_offset);
x86_ret (code);
} else {
/* The trampoline argument is at the top of the stack, and it contains the address we need to branch to */
if (tramp_type == MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD) {
x86_pop_reg (code, X86_EAX);
+ cfa_offset -= sizeof (mgreg_t);
+ mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, cfa_offset);
x86_alu_reg_imm (code, X86_ADD, X86_ESP, 0x8);
x86_jump_reg (code, X86_EAX);
} else {
return buf;
}
-#ifdef MONO_ARCH_MONITOR_OBJECT_REG
-/*
- * The code produced by this trampoline is equivalent to this:
- *
- * if (obj) {
- * if (obj->synchronisation) {
- * if (obj->synchronisation->owner == 0) {
- * if (cmpxch (&obj->synchronisation->owner, TID, 0) == 0)
- * return;
- * }
- * if (obj->synchronisation->owner == TID) {
- * ++obj->synchronisation->nest;
- * return;
- * }
- * }
- * }
- * return full_monitor_enter ();
- *
- */
-gpointer
-mono_arch_create_monitor_enter_trampoline (MonoTrampInfo **info, gboolean is_v4, gboolean aot)
-{
- guint8 *code, *buf;
- guint8 *jump_obj_null, *jump_sync_null, *jump_other_owner, *jump_cmpxchg_failed, *jump_tid, *jump_sync_thin_hash = NULL;
- guint8 *jump_lock_taken_true = NULL;
- int tramp_size;
- int status_offset, nest_offset;
- MonoJumpInfo *ji = NULL;
- GSList *unwind_ops = NULL;
-
- g_assert (MONO_ARCH_MONITOR_OBJECT_REG == X86_EAX);
-#ifdef MONO_ARCH_MONITOR_LOCK_TAKEN_REG
- g_assert (MONO_ARCH_MONITOR_LOCK_TAKEN_REG == X86_EDX);
-#else
- g_assert (!is_v4);
-#endif
-
- mono_monitor_threads_sync_members_offset (&status_offset, &nest_offset);
- g_assert (MONO_THREADS_SYNC_MEMBER_SIZE (status_offset) == sizeof (guint32));
- g_assert (MONO_THREADS_SYNC_MEMBER_SIZE (nest_offset) == sizeof (guint32));
- status_offset = MONO_THREADS_SYNC_MEMBER_OFFSET (status_offset);
- nest_offset = MONO_THREADS_SYNC_MEMBER_OFFSET (nest_offset);
-
- tramp_size = NACL_SIZE (128, 192);
-
- code = buf = mono_global_codeman_reserve (tramp_size);
-
- x86_push_reg (code, X86_EAX);
- if (mono_thread_get_tls_offset () != -1) {
- if (is_v4) {
- x86_test_membase_imm (code, X86_EDX, 0, 1);
- /* if *lock_taken is 1, jump to actual trampoline */
- jump_lock_taken_true = code;
- x86_branch8 (code, X86_CC_NZ, -1, 1);
- x86_push_reg (code, X86_EDX);
- }
- /* MonoObject* obj is in EAX */
- /* is obj null? */
- x86_test_reg_reg (code, X86_EAX, X86_EAX);
- /* if yes, jump to actual trampoline */
- jump_obj_null = code;
- x86_branch8 (code, X86_CC_Z, -1, 1);
-
- /* load obj->synchronization to ECX */
- x86_mov_reg_membase (code, X86_ECX, X86_EAX, MONO_STRUCT_OFFSET (MonoObject, synchronisation), 4);
-
- if (mono_gc_is_moving ()) {
- /*if bit zero is set it's a thin hash*/
- /*FIXME use testb encoding*/
- x86_test_reg_imm (code, X86_ECX, 0x01);
- jump_sync_thin_hash = code;
- x86_branch8 (code, X86_CC_NE, -1, 1);
-
- /*clear bits used by the gc*/
- x86_alu_reg_imm (code, X86_AND, X86_ECX, ~0x3);
- }
-
- /* is synchronization null? */
- x86_test_reg_reg (code, X86_ECX, X86_ECX);
-
- /* if yes, jump to actual trampoline */
- jump_sync_null = code;
- x86_branch8 (code, X86_CC_Z, -1, 1);
-
- /* load MonoInternalThread* into EDX */
- if (aot) {
- /* load_aotconst () puts the result into EAX */
- x86_mov_reg_reg (code, X86_EDX, X86_EAX, sizeof (mgreg_t));
- code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_TLS_OFFSET, GINT_TO_POINTER (TLS_KEY_THREAD));
- code = mono_x86_emit_tls_get_reg (code, X86_EAX, X86_EAX);
- x86_xchg_reg_reg (code, X86_EAX, X86_EDX, sizeof (mgreg_t));
- } else {
- code = mono_x86_emit_tls_get (code, X86_EDX, mono_thread_get_tls_offset ());
- }
- /* load TID into EDX */
- x86_mov_reg_membase (code, X86_EDX, X86_EDX, MONO_STRUCT_OFFSET (MonoInternalThread, small_id), 4);
-
- /* is synchronization->owner free */
- x86_mov_reg_membase (code, X86_EAX, X86_ECX, status_offset, 4);
- x86_test_reg_imm (code, X86_EAX, OWNER_MASK);
- /* if not, jump to next case */
- jump_tid = code;
- x86_branch8 (code, X86_CC_NZ, -1, 1);
-
- /* if yes, try a compare-exchange with the TID */
- /* Form new status */
- x86_alu_reg_reg (code, X86_OR, X86_EDX, X86_EAX);
- /* compare and exchange */
- x86_prefix (code, X86_LOCK_PREFIX);
- x86_cmpxchg_membase_reg (code, X86_ECX, status_offset, X86_EDX);
- /* if not successful, jump to actual trampoline */
- jump_cmpxchg_failed = code;
- x86_branch8 (code, X86_CC_NZ, -1, 1);
- /* if successful, pop and return */
- if (is_v4) {
- x86_pop_reg (code, X86_EDX);
- x86_mov_membase_imm (code, X86_EDX, 0, 1, 1);
- }
- x86_pop_reg (code, X86_EAX);
- x86_ret (code);
-
- /* next case: synchronization->owner is not null */
- x86_patch (jump_tid, code);
- /* is synchronization->owner == TID? */
- x86_alu_reg_imm (code, X86_AND, X86_EAX, OWNER_MASK);
- x86_alu_reg_reg (code, X86_CMP, X86_EAX, X86_EDX);
- /* if not, jump to actual trampoline */
- jump_other_owner = code;
- x86_branch8 (code, X86_CC_NZ, -1, 1);
- /* if yes, increment nest */
- x86_inc_membase (code, X86_ECX, nest_offset);
- if (is_v4) {
- x86_pop_reg (code, X86_EDX);
- x86_mov_membase_imm (code, X86_EDX, 0, 1, 1);
- }
- x86_pop_reg (code, X86_EAX);
- /* return */
- x86_ret (code);
-
- /* obj is pushed, jump to the actual trampoline */
- x86_patch (jump_obj_null, code);
- if (jump_sync_thin_hash)
- x86_patch (jump_sync_thin_hash, code);
- x86_patch (jump_sync_null, code);
- x86_patch (jump_other_owner, code);
- x86_patch (jump_cmpxchg_failed, code);
-
- if (is_v4) {
- x86_pop_reg (code, X86_EDX);
- x86_patch (jump_lock_taken_true, code);
- }
- }
-
- if (aot) {
- /* We are calling the generic trampoline directly, the argument is pushed
- * on the stack just like a specific trampoline.
- */
- if (is_v4)
- code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "generic_trampoline_monitor_enter_v4");
- else
- code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "generic_trampoline_monitor_enter");
- x86_jump_reg (code, X86_EAX);
- } else {
- if (is_v4)
- x86_jump_code (code, mono_get_trampoline_code (MONO_TRAMPOLINE_MONITOR_ENTER_V4));
- else
- x86_jump_code (code, mono_get_trampoline_code (MONO_TRAMPOLINE_MONITOR_ENTER));
- }
-
- mono_arch_flush_icache (buf, code - buf);
- g_assert (code - buf <= tramp_size);
-
- nacl_global_codeman_validate (&buf, tramp_size, &code);
- mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_MONITOR, NULL);
-
- if (is_v4)
- *info = mono_tramp_info_create ("monitor_enter_v4_trampoline", buf, code - buf, ji, unwind_ops);
- else
- *info = mono_tramp_info_create ("monitor_enter_trampoline", buf, code - buf, ji, unwind_ops);
-
- return buf;
-}
-
-gpointer
-mono_arch_create_monitor_exit_trampoline (MonoTrampInfo **info, gboolean aot)
-{
- guint8 *tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_MONITOR_EXIT);
- guint8 *code, *buf;
- guint8 *jump_obj_null, *jump_have_waiters, *jump_sync_null, *jump_not_owned, *jump_sync_thin_hash = NULL;
- guint8 *jump_next, *jump_cmpxchg_failed;
- int tramp_size;
- int status_offset, nest_offset;
- MonoJumpInfo *ji = NULL;
- GSList *unwind_ops = NULL;
-
- g_assert (MONO_ARCH_MONITOR_OBJECT_REG == X86_EAX);
-
- mono_monitor_threads_sync_members_offset (&status_offset, &nest_offset);
- g_assert (MONO_THREADS_SYNC_MEMBER_SIZE (status_offset) == sizeof (guint32));
- g_assert (MONO_THREADS_SYNC_MEMBER_SIZE (nest_offset) == sizeof (guint32));
- status_offset = MONO_THREADS_SYNC_MEMBER_OFFSET (status_offset);
- nest_offset = MONO_THREADS_SYNC_MEMBER_OFFSET (nest_offset);
-
- tramp_size = NACL_SIZE (128, 192);
-
- code = buf = mono_global_codeman_reserve (tramp_size);
-
- x86_push_reg (code, X86_EAX);
- if (mono_thread_get_tls_offset () != -1) {
- /* MonoObject* obj is in EAX */
- /* is obj null? */
- x86_test_reg_reg (code, X86_EAX, X86_EAX);
- /* if yes, jump to actual trampoline */
- jump_obj_null = code;
- x86_branch8 (code, X86_CC_Z, -1, 1);
-
- /* load obj->synchronization to ECX */
- x86_mov_reg_membase (code, X86_ECX, X86_EAX, MONO_STRUCT_OFFSET (MonoObject, synchronisation), 4);
-
- if (mono_gc_is_moving ()) {
- /*if bit zero is set it's a thin hash*/
- /*FIXME use testb encoding*/
- x86_test_reg_imm (code, X86_ECX, 0x01);
- jump_sync_thin_hash = code;
- x86_branch8 (code, X86_CC_NE, -1, 1);
-
- /*clear bits used by the gc*/
- x86_alu_reg_imm (code, X86_AND, X86_ECX, ~0x3);
- }
-
- /* is synchronization null? */
- x86_test_reg_reg (code, X86_ECX, X86_ECX);
- /* if yes, jump to actual trampoline */
- jump_sync_null = code;
- x86_branch8 (code, X86_CC_Z, -1, 1);
-
- /* next case: synchronization is not null */
- /* load MonoInternalThread* into EDX */
- if (aot) {
- /* load_aotconst () puts the result into EAX */
- x86_mov_reg_reg (code, X86_EDX, X86_EAX, sizeof (mgreg_t));
- code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_TLS_OFFSET, GINT_TO_POINTER (TLS_KEY_THREAD));
- code = mono_x86_emit_tls_get_reg (code, X86_EAX, X86_EAX);
- x86_xchg_reg_reg (code, X86_EAX, X86_EDX, sizeof (mgreg_t));
- } else {
- code = mono_x86_emit_tls_get (code, X86_EDX, mono_thread_get_tls_offset ());
- }
- /* load TID into EDX */
- x86_mov_reg_membase (code, X86_EDX, X86_EDX, MONO_STRUCT_OFFSET (MonoInternalThread, small_id), 4);
- /* is synchronization->owner == TID */
- x86_mov_reg_membase (code, X86_EAX, X86_ECX, status_offset, 4);
- x86_alu_reg_reg (code, X86_XOR, X86_EDX, X86_EAX);
- x86_test_reg_imm (code, X86_EDX, OWNER_MASK);
- /* if no, jump to actual trampoline */
- jump_not_owned = code;
- x86_branch8 (code, X86_CC_NZ, -1, 1);
-
- /* next case: synchronization->owner == TID */
- /* is synchronization->nest == 1 */
- x86_alu_membase_imm (code, X86_CMP, X86_ECX, nest_offset, 1);
- /* if not, jump to next case */
- jump_next = code;
- x86_branch8 (code, X86_CC_NZ, -1, 1);
- /* if yes, is synchronization->entry_count greater than zero? */
- x86_test_reg_imm (code, X86_EAX, ENTRY_COUNT_WAITERS);
- /* if yes, jump to actual trampoline */
- jump_have_waiters = code;
- x86_branch8 (code, X86_CC_NZ, -1 , 1);
- /* if not, try to set synchronization->owner to null and return */
- x86_mov_reg_reg (code, X86_EDX, X86_EAX, 4);
- x86_alu_reg_imm (code, X86_AND, X86_EDX, ENTRY_COUNT_MASK);
- /* compare and exchange */
- x86_prefix (code, X86_LOCK_PREFIX);
- /* EAX contains the previous status */
- x86_cmpxchg_membase_reg (code, X86_ECX, status_offset, X86_EDX);
- /* if not successful, jump to actual trampoline */
- jump_cmpxchg_failed = code;
- x86_branch8 (code, X86_CC_NZ, -1, 1);
-
- x86_pop_reg (code, X86_EAX);
- x86_ret (code);
-
- /* next case: synchronization->nest is not 1 */
- x86_patch (jump_next, code);
- /* decrease synchronization->nest and return */
- x86_dec_membase (code, X86_ECX, nest_offset);
- x86_pop_reg (code, X86_EAX);
- x86_ret (code);
-
- /* push obj and jump to the actual trampoline */
- x86_patch (jump_obj_null, code);
- if (jump_sync_thin_hash)
- x86_patch (jump_sync_thin_hash, code);
- x86_patch (jump_have_waiters, code);
- x86_patch (jump_cmpxchg_failed, code);
- x86_patch (jump_not_owned, code);
- x86_patch (jump_sync_null, code);
- }
-
- /* obj is pushed, jump to the actual trampoline */
- if (aot) {
- code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "generic_trampoline_monitor_exit");
- x86_jump_reg (code, X86_EAX);
- } else {
- x86_jump_code (code, tramp);
- }
-
- nacl_global_codeman_validate (&buf, tramp_size, &code);
-
- mono_arch_flush_icache (buf, code - buf);
- g_assert (code - buf <= tramp_size);
- mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_MONITOR, NULL);
-
- *info = mono_tramp_info_create ("monitor_exit_trampoline", buf, code - buf, ji, unwind_ops);
-
- return buf;
-}
-
-#else
-
-gpointer
-mono_arch_create_monitor_enter_trampoline (MonoTrampInfo **info, gboolean is_v4, gboolean aot)
-{
- g_assert_not_reached ();
- return NULL;
-}
-
-gpointer
-mono_arch_create_monitor_exit_trampoline (MonoTrampInfo **info, gboolean aot)
-{
- g_assert_not_reached ();
- return NULL;
-}
-
-#endif
-
void
mono_arch_invalidate_method (MonoJitInfo *ji, void *func, gpointer func_arg)
{
guint8 *code, *buf;
int tramp_size = 64;
MonoJumpInfo *ji = NULL;
+ int cfa_offset;
GSList *unwind_ops = NULL;
g_assert (!aot);
code = buf = mono_global_codeman_reserve (tramp_size);
+ unwind_ops = mono_arch_get_cie_program ();
+ cfa_offset = sizeof (mgreg_t);
/*
This trampoline restore the call chain of the handler block then jumps into the code that deals with it.
*/
/* Simulate a call */
/*Fix stack alignment*/
x86_alu_reg_imm (code, X86_SUB, X86_ESP, 0x4);
+ cfa_offset += sizeof (mgreg_t);
+ mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, cfa_offset);
+
/* This is the address the trampoline will return to */
x86_push_reg (code, X86_EAX);
+ cfa_offset += sizeof (mgreg_t);
+ mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, cfa_offset);
+
/* Dummy trampoline argument, since we call the generic trampoline directly */
x86_push_imm (code, 0);
+ cfa_offset += sizeof (mgreg_t);
+ mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, cfa_offset);
x86_jump_code (code, tramp);
nacl_global_codeman_validate (&buf, tramp_size, &code);
{
guint8 *code, *start;
int buf_len;
+ GSList *unwind_ops;
+
buf_len = 10;
start = code = mono_domain_code_reserve (domain, buf_len);
+ unwind_ops = mono_arch_get_cie_program ();
+
x86_mov_reg_imm (code, X86_EAX, arg);
x86_jump_code (code, addr);
g_assert ((code - start) <= buf_len);
mono_arch_flush_icache (start, code - start);
mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL);
+ mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), domain);
+
return start;
}
+/*
+ * mono_arch_create_sdb_trampoline:
+ *
+ * Return a trampoline which captures the current context, passes it to
+ * debugger_agent_single_step_from_context ()/debugger_agent_breakpoint_from_context (),
+ * then restores the (potentially changed) context.
+ */
+guint8*
+mono_arch_create_sdb_trampoline (gboolean single_step, MonoTrampInfo **info, gboolean aot)
+{
+ int tramp_size = 256;
+ int framesize, ctx_offset, cfa_offset;
+ guint8 *code, *buf;
+ GSList *unwind_ops = NULL;
+ MonoJumpInfo *ji = NULL;
+
+ code = buf = mono_global_codeman_reserve (tramp_size);
+
+ framesize = 0;
+
+ /* Argument area */
+ framesize += sizeof (mgreg_t);
+
+ ctx_offset = framesize;
+ framesize += sizeof (MonoContext);
+
+ framesize = ALIGN_TO (framesize, MONO_ARCH_FRAME_ALIGNMENT);
+
+ // CFA = sp + 4
+ cfa_offset = 4;
+ mono_add_unwind_op_def_cfa (unwind_ops, code, buf, X86_ESP, 4);
+ // IP saved at CFA - 4
+ mono_add_unwind_op_offset (unwind_ops, code, buf, X86_NREG, -cfa_offset);
+
+ x86_push_reg (code, X86_EBP);
+ cfa_offset += sizeof(mgreg_t);
+ mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, cfa_offset);
+ mono_add_unwind_op_offset (unwind_ops, code, buf, X86_EBP, - cfa_offset);
+
+ x86_mov_reg_reg (code, X86_EBP, X86_ESP, sizeof(mgreg_t));
+ mono_add_unwind_op_def_cfa_reg (unwind_ops, code, buf, X86_EBP);
+ /* The + 8 makes the stack aligned */
+ x86_alu_reg_imm (code, X86_SUB, X86_ESP, framesize + 8);
+
+ /* Initialize a MonoContext structure on the stack */
+ x86_mov_membase_reg (code, X86_ESP, ctx_offset + G_STRUCT_OFFSET (MonoContext, eax), X86_EAX, sizeof (mgreg_t));
+ x86_mov_membase_reg (code, X86_ESP, ctx_offset + G_STRUCT_OFFSET (MonoContext, ebx), X86_EBX, sizeof (mgreg_t));
+ x86_mov_membase_reg (code, X86_ESP, ctx_offset + G_STRUCT_OFFSET (MonoContext, ecx), X86_ECX, sizeof (mgreg_t));
+ x86_mov_membase_reg (code, X86_ESP, ctx_offset + G_STRUCT_OFFSET (MonoContext, edx), X86_EDX, sizeof (mgreg_t));
+ x86_mov_reg_membase (code, X86_EAX, X86_EBP, 0, sizeof (mgreg_t));
+ x86_mov_membase_reg (code, X86_ESP, ctx_offset + G_STRUCT_OFFSET (MonoContext, ebp), X86_EAX, sizeof (mgreg_t));
+ x86_mov_reg_reg (code, X86_EAX, X86_EBP, sizeof (mgreg_t));
+ x86_alu_reg_imm (code, X86_ADD, X86_EAX, cfa_offset);
+ x86_mov_membase_reg (code, X86_ESP, ctx_offset + G_STRUCT_OFFSET (MonoContext, esp), X86_ESP, sizeof (mgreg_t));
+ x86_mov_membase_reg (code, X86_ESP, ctx_offset + G_STRUCT_OFFSET (MonoContext, esi), X86_ESI, sizeof (mgreg_t));
+ x86_mov_membase_reg (code, X86_ESP, ctx_offset + G_STRUCT_OFFSET (MonoContext, edi), X86_EDI, sizeof (mgreg_t));
+ x86_mov_reg_membase (code, X86_EAX, X86_EBP, 4, sizeof (mgreg_t));
+ x86_mov_membase_reg (code, X86_ESP, ctx_offset + G_STRUCT_OFFSET (MonoContext, eip), X86_EAX, sizeof (mgreg_t));
+
+ /* Call the single step/breakpoint function in sdb */
+ x86_lea_membase (code, X86_EAX, X86_ESP, ctx_offset);
+ x86_mov_membase_reg (code, X86_ESP, 0, X86_EAX, sizeof (mgreg_t));
+
+ if (aot) {
+ g_assert_not_reached ();
+ } else {
+ if (single_step)
+ x86_call_code (code, debugger_agent_single_step_from_context);
+ else
+ x86_call_code (code, debugger_agent_breakpoint_from_context);
+ }
+
+ /* Restore registers from ctx */
+ /* Overwrite the saved ebp */
+ x86_mov_reg_membase (code, X86_EAX, X86_ESP, ctx_offset + G_STRUCT_OFFSET (MonoContext, ebp), sizeof (mgreg_t));
+ x86_mov_membase_reg (code, X86_EBP, 0, X86_EAX, sizeof (mgreg_t));
+ /* Overwrite saved eip */
+ x86_mov_reg_membase (code, X86_EAX, X86_ESP, ctx_offset + G_STRUCT_OFFSET (MonoContext, eip), sizeof (mgreg_t));
+ x86_mov_membase_reg (code, X86_EBP, 4, X86_EAX, sizeof (mgreg_t));
+ x86_mov_reg_membase (code, X86_EAX, X86_ESP, ctx_offset + G_STRUCT_OFFSET (MonoContext, eax), sizeof (mgreg_t));
+ x86_mov_reg_membase (code, X86_EBX, X86_ESP, ctx_offset + G_STRUCT_OFFSET (MonoContext, ebx), sizeof (mgreg_t));
+ x86_mov_reg_membase (code, X86_ECX, X86_ESP, ctx_offset + G_STRUCT_OFFSET (MonoContext, ecx), sizeof (mgreg_t));
+ x86_mov_reg_membase (code, X86_EDX, X86_ESP, ctx_offset + G_STRUCT_OFFSET (MonoContext, edx), sizeof (mgreg_t));
+ x86_mov_reg_membase (code, X86_ESI, X86_ESP, ctx_offset + G_STRUCT_OFFSET (MonoContext, esi), sizeof (mgreg_t));
+ x86_mov_reg_membase (code, X86_EDI, X86_ESP, ctx_offset + G_STRUCT_OFFSET (MonoContext, edi), sizeof (mgreg_t));
+
+ x86_leave (code);
+ cfa_offset -= sizeof (mgreg_t);
+ mono_add_unwind_op_def_cfa (unwind_ops, code, buf, X86_ESP, cfa_offset);
+ x86_ret (code);
+
+ mono_arch_flush_icache (code, code - buf);
+ g_assert (code - buf <= tramp_size);
+
+ 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);
+
+ return buf;
+}
+
#if defined(ENABLE_GSHAREDVT)
#include "../../../mono-extensions/mono/mini/tramp-x86-gsharedvt.c"
}
/*
- * mono_unwind_ops_encode:
+ * mono_unwind_ops_encode_full:
*
* Encode the unwind ops in UNWIND_OPS into the compact DWARF encoding.
* Return a pointer to malloc'ed memory.
+ * If ENABLE_EXTENSIONS is FALSE, avoid encoding the mono extension
+ * opcode (DW_CFA_mono_advance_loc).
*/
guint8*
-mono_unwind_ops_encode (GSList *unwind_ops, guint32 *out_len)
+mono_unwind_ops_encode_full (GSList *unwind_ops, guint32 *out_len, gboolean enable_extensions)
{
GSList *l;
MonoUnwindOp *op;
*p ++ = op->op;
break;
case DW_CFA_mono_advance_loc:
+ if (!enable_extensions)
+ break;
/* Only one location is supported */
g_assert (op->val == 0);
*p ++ = op->op;
return res;
}
+guint8*
+mono_unwind_ops_encode (GSList *unwind_ops, guint32 *out_len)
+{
+ return mono_unwind_ops_encode_full (unwind_ops, out_len, TRUE);
+}
+
#if 0
#define UNW_DEBUG(stmt) do { stmt; } while (0)
#else
GSList*
mono_unwind_get_cie_program (void)
{
-#if defined(TARGET_AMD64) || defined(TARGET_X86) || defined(TARGET_POWERPC)
+#if defined(TARGET_AMD64) || defined(TARGET_X86) || defined(TARGET_POWERPC) || defined(TARGET_ARM)
return mono_arch_get_cie_program ();
#else
return NULL;
SUBDIRS = assemblyresolve gc-descriptors
-check-local: assemblyresolve/test/asm.dll testjit test-generic-sharing test-type-load test-cattr-type-load test-reflection-load-with-context test_platform test-process-exit test-messages rm-empty-logs
+check-local: assemblyresolve/test/asm.dll testjit test-generic-sharing test-type-load test-cattr-type-load test-reflection-load-with-context test_platform test-process-exit test-messages test-unhandled-exception-2 rm-empty-logs
check-full: test-sgen check-local
check-parallel: compile-tests check-full
MONO_GC_PARAMS=max-heap-size=16m $(RUNTIME) $$fn > $$fn.stdout || exit 1; \
done
+if HOST_WIN32
+test-unhandled-exception-2:
+else
+test-unhandled-exception-2: unhandled-exception.exe
+ @echo "Testing unhandled-exception_1 ..."; $(RUNTIME) $+ 1 1> unhandled-exception_1.exe.stdout 2> unhandled-exception_1.exe.stderr; if test "x$$?" != "x1"; then exit 1; fi; \
+ echo "Testing unhandled-exception_2 ..."; $(RUNTIME) $+ 2 1> unhandled-exception_2.exe.stdout 2> unhandled-exception_2.exe.stderr; if test "x$$?" != "x0"; then exit 2; fi; \
+ echo "Testing unhandled-exception_3 ..."; $(RUNTIME) $+ 3 1> unhandled-exception_3.exe.stdout 2> unhandled-exception_3.exe.stderr; if test "x$$?" != "x0"; then exit 3; fi; \
+ echo "Testing unhandled-exception_4 ..."; $(RUNTIME) $+ 4 1> unhandled-exception_4.exe.stdout 2> unhandled-exception_4.exe.stderr; if test "x$$?" != "x0"; then exit 4; fi; \
+ echo "Testing unhandled-exception_5 ..."; $(RUNTIME) $+ 5 1> unhandled-exception_5.exe.stdout 2> unhandled-exception_5.exe.stderr; if test "x$$?" != "x255"; then exit 5; fi; \
+ echo "Testing unhandled-exception_6 ..."; $(RUNTIME) $+ 6 1> unhandled-exception_6.exe.stdout 2> unhandled-exception_6.exe.stderr; if test "x$$?" != "x0"; then exit 6; fi; \
+ echo "Testing unhandled-exception_7 ..."; $(RUNTIME) $+ 7 1> unhandled-exception_7.exe.stdout 2> unhandled-exception_7.exe.stderr; if test "x$$?" != "x0"; then exit 7; fi; \
+ echo "Testing unhandled-exception_8 ..."; $(RUNTIME) $+ 8 1> unhandled-exception_8.exe.stdout 2> unhandled-exception_8.exe.stderr; if test "x$$?" != "x3"; then exit 8; fi
+endif
noinst_LTLIBRARIES = libtest.la
-AM_CPPFLAGS = $(GLIB_CFLAGS) $(GMODULE_CFLAGS)
+AM_CPPFLAGS = $(GLIB_CFLAGS)
if HOST_WIN32
# gcc-3.4.4 emits incorrect code when making indirect calls to stdcall functions using a tail call
resurrect = this;
}
+ public static void EnterMonitor (object obj)
+ {
+ for (int i = 0; i < 257; i++)
+ Monitor.Enter (obj);
+ }
+
+ public static void ExitMonitor (object obj)
+ {
+ for (int i = 0; i < 257; i++)
+ Monitor.Exit (obj);
+ }
+
public static void CreateFoo (int level)
{
if (level == 0) {
reference = new Foo ();
/* Allocate a MonoThreadsSync for the object */
- Monitor.Enter (reference);
- Monitor.Exit (reference);
+ EnterMonitor (reference);
+ ExitMonitor (reference);
reference = null;
} else {
CreateFoo (level - 1);
/* Make sure these are not collected */
list.Add (foo);
- Monitor.Enter (foo);
+ EnterMonitor (foo);
}
}
}
b.test_exception ();
}
catch (SynchronizationLockException ex) {
- return 1;
+ // OK
}
catch (Exception ex) {
- // OK
+ // The other exception should be overwritten by the lock one
+ return 1;
}
Console.WriteLine ("Test4...");
d ();
}
catch (SynchronizationLockException ex) {
- return 2;
+ // OK
}
catch (Exception ex) {
- // OK
+ return 2;
}
return 0;
b.test_exception ();
}
catch (SynchronizationLockException ex) {
- return 1;
+ // OK
}
catch (Exception ex) {
- // OK
+ // The other exception should be overwritten by the lock one
+ return 1;
}
if (is_synchronized (b))
return 1;
d ();
}
catch (SynchronizationLockException ex) {
- return 2;
+ // OK
}
catch (Exception ex) {
- // OK
+ return 2;
}
if (is_synchronized (b))
return 1;
--- /dev/null
+using System;
+using System.Diagnostics;
+using System.Threading;
+using System.Threading.Tasks;
+
+class CustomException : Exception
+{
+}
+
+class CustomException2 : Exception
+{
+}
+
+
+class CrossDomain : MarshalByRefObject
+{
+ public Action NewDelegateWithTarget ()
+ {
+ return new Action (Bar);
+ }
+
+ public Action NewDelegateWithoutTarget ()
+ {
+ return () => { throw new CustomException (); };
+ }
+
+ public void Bar ()
+ {
+ throw new CustomException ();
+ }
+}
+
+class Driver {
+ static ManualResetEvent mre = new ManualResetEvent (false);
+
+ static void DoTest1 ()
+ {
+ mre.Reset ();
+
+ var t = new Thread (new ThreadStart (() => { try { throw new CustomException (); } finally { mre.Set (); } }));
+ t.Start ();
+
+ if (!mre.WaitOne (5000))
+ Environment.Exit (2);
+
+ t.Join ();
+ }
+
+ static void DoTest2 ()
+ {
+ mre.Reset ();
+
+ var a = new Action (() => { try { throw new CustomException (); } finally { mre.Set (); } });
+ var ares = a.BeginInvoke (null, null);
+
+ if (!mre.WaitOne (5000))
+ Environment.Exit (2);
+
+ try {
+ a.EndInvoke (ares);
+ throw new Exception ();
+ } catch (CustomException) {
+ } catch (Exception) {
+ Environment.Exit (3);
+ }
+ }
+
+ static void DoTest3 ()
+ {
+ mre.Reset ();
+
+ ThreadPool.QueueUserWorkItem (_ => { try { throw new CustomException (); } finally { mre.Set (); } });
+
+ if (!mre.WaitOne (5000))
+ Environment.Exit (2);
+ }
+
+ static void DoTest4 ()
+ {
+ mre.Reset ();
+
+ var t = Task.Factory.StartNew (new Action (() => { try { throw new CustomException (); } finally { mre.Set (); } }));
+
+ if (!mre.WaitOne (5000))
+ Environment.Exit (2);
+
+ try {
+ t.Wait ();
+ throw new Exception ();
+ } catch (AggregateException ae) {
+ if (!(ae.InnerExceptions [0] is CustomException))
+ Environment.Exit (4);
+ } catch (Exception) {
+ Environment.Exit (3);
+ }
+ }
+
+ class FinalizedClass
+ {
+ ~FinalizedClass ()
+ {
+ try {
+ throw new CustomException ();
+ } finally {
+ mre.Set ();
+ }
+ }
+ }
+
+ static void DoTest5 ()
+ {
+ mre.Reset ();
+
+ new FinalizedClass();
+
+ GC.Collect ();
+ GC.WaitForPendingFinalizers ();
+
+ if (!mre.WaitOne (5000))
+ Environment.Exit (2);
+ }
+
+ static void DoTest6 ()
+ {
+ ManualResetEvent mre2 = new ManualResetEvent (false);
+
+ mre.Reset ();
+
+ var a = new Action (() => { try { throw new CustomException (); } finally { mre.Set (); } });
+ var ares = a.BeginInvoke (_ => { mre2.Set (); throw new CustomException2 (); }, null);
+
+ if (!mre.WaitOne (5000))
+ Environment.Exit (2);
+ if (!mre2.WaitOne (5000))
+ Environment.Exit (22);
+
+ try {
+ a.EndInvoke (ares);
+ throw new Exception ();
+ } catch (CustomException) {
+ } catch (Exception) {
+ Environment.Exit (3);
+ }
+ }
+
+ static void DoTest7 ()
+ {
+ var cd = (CrossDomain) AppDomain.CreateDomain ("ad").CreateInstanceAndUnwrap (typeof(CrossDomain).Assembly.FullName, "CrossDomain");
+
+ var a = cd.NewDelegateWithoutTarget ();
+ var ares = a.BeginInvoke (delegate { throw new CustomException2 (); }, null);
+
+ try {
+ a.EndInvoke (ares);
+ throw new Exception ();
+ } catch (CustomException) {
+ } catch (Exception) {
+ Environment.Exit (3);
+ }
+ }
+
+ static void DoTest8 ()
+ {
+ var cd = (CrossDomain) AppDomain.CreateDomain ("ad").CreateInstanceAndUnwrap (typeof(CrossDomain).Assembly.FullName, "CrossDomain");
+
+ var a = cd.NewDelegateWithTarget ();
+ var ares = a.BeginInvoke (delegate { throw new CustomException2 (); }, null);
+
+ try {
+ a.EndInvoke (ares);
+ throw new Exception ();
+ } catch (CustomException) {
+ } catch (Exception) {
+ Environment.Exit (3);
+ }
+ }
+
+ static void Main (string[] args)
+ {
+ switch (int.Parse (args [0])) {
+ case 1: DoTest1 (); break;
+ case 2: DoTest2 (); break;
+ case 3: DoTest3 (); break;
+ case 4: DoTest4 (); break;
+ case 5: DoTest5 (); break;
+ case 6: DoTest6 (); break;
+ case 7: DoTest7 (); break;
+ case 8: DoTest8 (); break;
+ default: throw new ArgumentOutOfRangeException ();
+ }
+ Environment.Exit (0);
+ }
+}
#define MONO_THREAD_VAR_OFFSET(var,offset) (offset) = -1
#endif
-#elif defined(TARGET_MACH) && 0
+#elif defined(TARGET_MACH) && (defined(__i386__) || defined(__x86_64__))
-#define MONO_HAVE_FAST_TLS
+#define MONO_HAVE_FAST_TLS 1
#define MONO_FAST_TLS_SET(x,y) pthread_setspecific(x, y)
#define MONO_FAST_TLS_GET(x) pthread_getspecific(x)
#define MONO_FAST_TLS_ADDR(x) (mono_mach_get_tls_address_from_thread (pthread_self (), x))
FRAME_TYPE_DEBUGGER_INVOKE = 1,
/* Frame for transitioning to native code */
FRAME_TYPE_MANAGED_TO_NATIVE = 2,
- FRAME_TYPE_SENTINEL = 3
+ FRAME_TYPE_TRAMPOLINE = 3,
+ FRAME_TYPE_NUM = 4
} MonoStackFrameType;
typedef enum {
if (!(info->thread_state & (STATE_ASYNC_SUSPEND_REQUESTED | STATE_SELF_SUSPEND_REQUESTED)))
return;
- g_assert (mono_threads_get_runtime_callbacks ()->thread_state_init_from_sigctx (&info->thread_saved_state [SELF_SUSPEND_STATE_INDEX], NULL));
+ mono_threads_get_runtime_callbacks ()->thread_state_init (&info->thread_saved_state [SELF_SUSPEND_STATE_INDEX]);
/* commit the saved state and notify others if needed */
switch (mono_threads_transition_state_poll (info)) {
}
retry:
- /*The JIT might not be able to save*/
- if (!mono_threads_get_runtime_callbacks ()->thread_state_init_from_sigctx (&info->thread_saved_state [SELF_SUSPEND_STATE_INDEX], NULL)) {
- THREADS_SUSPEND_DEBUG ("PREPARE-BLOCKING failed %p to save thread state\n", mono_thread_info_get_tid (info));
- return NULL;
- }
+ mono_threads_get_runtime_callbacks ()->thread_state_init (&info->thread_saved_state [SELF_SUSPEND_STATE_INDEX]);
switch (mono_threads_transition_do_blocking (info)) {
case DoBlockingContinue:
}
retry:
- /*The JIT might not be able to save*/
- if (!mono_threads_get_runtime_callbacks ()->thread_state_init_from_sigctx (&info->thread_saved_state [SELF_SUSPEND_STATE_INDEX], NULL)) {
- THREADS_SUSPEND_DEBUG ("PREPARE-TRY-BLOCKING failed %p to save thread state\n", mono_thread_info_get_tid (info));
- return NULL;
- }
+ mono_threads_get_runtime_callbacks ()->thread_state_init (&info->thread_saved_state [SELF_SUSPEND_STATE_INDEX]);
switch (mono_threads_transition_do_blocking (info)) {
case DoBlockingContinue:
/* Runtime consumable API */
#define MONO_SUSPEND_CHECK() do { \
- if (G_UNLIKELY (mono_threads_polling_required)) mono_threads_state_poll (); \
+ if (G_UNLIKELY (mono_polling_required)) mono_threads_state_poll (); \
} while (0);
#define MONO_PREPARE_BLOCKING \
/* Internal API */
-extern volatile size_t mono_threads_polling_required;
-
void mono_threads_state_poll (void);
void* mono_threads_prepare_blocking (void);
void mono_threads_finish_blocking (void* cookie);
void mono_threads_finish_try_blocking (void* cookie);
/* JIT specific interface */
-extern volatile size_t mono_polling_required ;
+extern volatile size_t mono_polling_required;
#else
-#define MONO_SUSPEND_CHECK do { } while (0);
+#define MONO_SUSPEND_CHECK() do { } while (0);
#define MONO_PREPARE_BLOCKING {
#define MONO_FINISH_BLOCKING }
#define MONO_PREPARE_RESET_BLOCKING {
mono_threads_init_dead_letter ();
}
-void
-mono_threads_core_interrupt (MonoThreadInfo *info)
-{
- thread_abort (info->native_handle);
-}
-
void
mono_threads_core_abort_syscall (MonoThreadInfo *info)
{
start_info->handle = handle;
info = mono_thread_info_attach (&result);
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
info->runtime_thread = TRUE;
info->handle = handle;
MONO_SEM_DESTROY (&info->create_suspended_sem);
}
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
/* Run the actual main function of the thread */
result = start_func (t_arg);
return handle;
}
-gpointer
-mono_threads_core_prepare_interrupt (HANDLE thread_handle)
-{
- return wapi_prepare_interrupt_thread (thread_handle);
-}
-
-void
-mono_threads_core_finish_interrupt (gpointer wait_handle)
-{
- wapi_finish_interrupt_thread (wait_handle);
-}
-
-void
-mono_threads_core_self_interrupt (void)
-{
- wapi_self_interrupt ();
-}
-
-void
-mono_threads_core_clear_interruption (void)
-{
- wapi_clear_interruption ();
-}
-
int
mono_threads_pthread_kill (MonoThreadInfo *info, int signum)
{
#endif
}
-
-gpointer
-mono_threads_core_prepare_interrupt (HANDLE thread_handle)
-{
- return NULL;
-}
-
-void
-mono_threads_core_finish_interrupt (gpointer wait_handle)
-{
-}
-
-void
-mono_threads_core_self_interrupt (void)
-{
-}
-
-void
-mono_threads_core_clear_interruption (void)
-{
-}
-
#endif
MonoThreadInfo *info;
MonoThreadInfo *cur = mono_thread_info_current ();
- MOSTLY_ASYNC_SAFE_PRINTF ("STATE CUE CARD: (? means a positive number, usually 1 or 2)\n");
+ MOSTLY_ASYNC_SAFE_PRINTF ("STATE CUE CARD: (? means a positive number, usually 1 or 2, * means any number)\n");
MOSTLY_ASYNC_SAFE_PRINTF ("\t0x0\t- starting (GOOD, unless the thread is running managed code)\n");
MOSTLY_ASYNC_SAFE_PRINTF ("\t0x1\t- running (BAD, unless it's the gc thread)\n");
MOSTLY_ASYNC_SAFE_PRINTF ("\t0x2\t- detached (GOOD, unless the thread is running managed code)\n");
MOSTLY_ASYNC_SAFE_PRINTF ("\t0x?04\t- self suspended (GOOD)\n");
MOSTLY_ASYNC_SAFE_PRINTF ("\t0x?05\t- async suspend requested (BAD)\n");
MOSTLY_ASYNC_SAFE_PRINTF ("\t0x?06\t- self suspend requested (BAD)\n");
- MOSTLY_ASYNC_SAFE_PRINTF ("\t0x07\t- blocking (GOOD)\n");
+ MOSTLY_ASYNC_SAFE_PRINTF ("\t0x*07\t- blocking (GOOD)\n");
MOSTLY_ASYNC_SAFE_PRINTF ("\t0x?08\t- blocking with pending suspend (GOOD)\n");
FOREACH_THREAD_SAFE (info) {
This ensures that we won't lose any suspend requests as a suspend initiator must hold the lock.
Once we're holding the suspend lock, no threads can suspend us and once we unregister, no thread can find us.
*/
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
mono_thread_info_suspend_lock ();
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
/*
Now perform the callback that must be done under locks.
return;
THREADS_SUSPEND_DEBUG ("FINISH SELF SUSPEND OF %p\n", info);
- g_assert (mono_threads_get_runtime_callbacks ()->thread_state_init_from_sigctx (&info->thread_saved_state [SELF_SUSPEND_STATE_INDEX], NULL));
+ mono_threads_get_runtime_callbacks ()->thread_state_init (&info->thread_saved_state [SELF_SUSPEND_STATE_INDEX]);
/* commit the saved state and notify others if needed */
switch (mono_threads_transition_state_poll (info)) {
mono_threads_core_set_name (tid, name);
}
+#define INTERRUPT_STATE ((MonoThreadInfoInterruptToken*) (size_t) -1)
+
+struct _MonoThreadInfoInterruptToken {
+ void (*callback) (gpointer data);
+ gpointer data;
+};
+
/*
- * mono_thread_info_prepare_interrupt:
+ * mono_thread_info_install_interrupt: install an interruption token for the current thread.
*
- * See wapi_prepare_interrupt ().
+ * - @callback: must be able to be called from another thread and always cancel the wait
+ * - @data: passed to the callback
+ * - @interrupted: will be set to TRUE if a token is already installed, FALSE otherwise
+ * if set to TRUE, it must mean that the thread is in interrupted state
*/
-gpointer
-mono_thread_info_prepare_interrupt (HANDLE thread_handle)
+void
+mono_thread_info_install_interrupt (void (*callback) (gpointer data), gpointer data, gboolean *interrupted)
{
- return mono_threads_core_prepare_interrupt (thread_handle);
+ MonoThreadInfo *info;
+ MonoThreadInfoInterruptToken *previous_token, *token;
+
+ g_assert (callback);
+
+ g_assert (interrupted);
+ *interrupted = FALSE;
+
+ info = mono_thread_info_current ();
+ g_assert (info);
+
+ /* The memory of this token can be freed at 2 places:
+ * - if the token is not interrupted: it will be freed in uninstall, as info->interrupt_token has not been replaced
+ * by the INTERRUPT_STATE flag value, and it still contains the pointer to the memory location
+ * - if the token is interrupted: it will be freed in finish, as the token is now owned by the prepare/finish
+ * functions, and info->interrupt_token does not contains a pointer to the memory anymore */
+ token = g_new0 (MonoThreadInfoInterruptToken, 1);
+ token->callback = callback;
+ token->data = data;
+
+ previous_token = InterlockedCompareExchangePointer ((gpointer*) &info->interrupt_token, token, NULL);
+
+ if (previous_token) {
+ if (previous_token != INTERRUPT_STATE)
+ g_error ("mono_thread_info_install_interrupt: previous_token should be INTERRUPT_STATE (%p), but it was %p", INTERRUPT_STATE, previous_token);
+
+ g_free (token);
+
+ *interrupted = TRUE;
+ }
+
+ THREADS_INTERRUPT_DEBUG ("interrupt install tid %p token %p previous_token %p interrupted %s\n",
+ mono_thread_info_get_tid (info), token, previous_token, *interrupted ? "TRUE" : "FALSE");
}
void
-mono_thread_info_finish_interrupt (gpointer wait_handle)
+mono_thread_info_uninstall_interrupt (gboolean *interrupted)
+{
+ MonoThreadInfo *info;
+ MonoThreadInfoInterruptToken *previous_token;
+
+ g_assert (interrupted);
+ *interrupted = FALSE;
+
+ info = mono_thread_info_current ();
+ g_assert (info);
+
+ previous_token = InterlockedExchangePointer ((gpointer*) &info->interrupt_token, NULL);
+
+ /* only the installer can uninstall the token */
+ g_assert (previous_token);
+
+ if (previous_token == INTERRUPT_STATE) {
+ /* if it is interrupted, then it is going to be freed in finish interrupt */
+ *interrupted = TRUE;
+ } else {
+ g_free (previous_token);
+ }
+
+ THREADS_INTERRUPT_DEBUG ("interrupt uninstall tid %p previous_token %p interrupted %s\n",
+ mono_thread_info_get_tid (info), previous_token, *interrupted ? "TRUE" : "FALSE");
+}
+
+static MonoThreadInfoInterruptToken*
+set_interrupt_state (MonoThreadInfo *info)
+{
+ MonoThreadInfoInterruptToken *token, *previous_token;
+
+ g_assert (info);
+
+ /* Atomically obtain the token the thread is
+ * waiting on, and change it to a flag value. */
+
+ do {
+ previous_token = info->interrupt_token;
+
+ /* Already interrupted */
+ if (previous_token == INTERRUPT_STATE) {
+ token = NULL;
+ break;
+ }
+
+ token = previous_token;
+ } while (InterlockedCompareExchangePointer ((gpointer*) &info->interrupt_token, INTERRUPT_STATE, previous_token) != previous_token);
+
+ return token;
+}
+
+/*
+ * mono_thread_info_prepare_interrupt:
+ *
+ * The state of the thread info interrupt token is set to 'interrupted' which means that :
+ * - if the thread calls one of the WaitFor functions, the function will return with
+ * WAIT_IO_COMPLETION instead of waiting
+ * - if the thread was waiting when this function was called, the wait will be broken
+ *
+ * It is possible that the wait functions return WAIT_IO_COMPLETION, but the target thread
+ * didn't receive the interrupt signal yet, in this case it should call the wait function
+ * again. This essentially means that the target thread will busy wait until it is ready to
+ * process the interruption.
+ */
+MonoThreadInfoInterruptToken*
+mono_thread_info_prepare_interrupt (MonoThreadInfo *info)
{
- mono_threads_core_finish_interrupt (wait_handle);
+ MonoThreadInfoInterruptToken *token;
+
+ token = set_interrupt_state (info);
+
+ THREADS_INTERRUPT_DEBUG ("interrupt prepare tid %p token %p\n",
+ mono_thread_info_get_tid (info), token);
+
+ return token;
}
void
-mono_thread_info_interrupt (HANDLE thread_handle)
+mono_thread_info_finish_interrupt (MonoThreadInfoInterruptToken *token)
{
- gpointer wait_handle;
+ THREADS_INTERRUPT_DEBUG ("interrupt finish token %p\n", token);
- wait_handle = mono_thread_info_prepare_interrupt (thread_handle);
- mono_thread_info_finish_interrupt (wait_handle);
+ if (token == NULL)
+ return;
+
+ g_assert (token->callback);
+
+ token->callback (token->data);
+
+ g_free (token);
}
-
+
void
mono_thread_info_self_interrupt (void)
{
- mono_threads_core_self_interrupt ();
+ MonoThreadInfo *info;
+ MonoThreadInfoInterruptToken *token;
+
+ info = mono_thread_info_current ();
+ g_assert (info);
+
+ token = set_interrupt_state (info);
+ g_assert (!token);
+
+ THREADS_INTERRUPT_DEBUG ("interrupt self tid %p\n",
+ mono_thread_info_get_tid (info));
+}
+
+/* Clear the interrupted flag of the current thread, set with
+ * mono_thread_info_self_interrupt, so it can wait again */
+void
+mono_thread_info_clear_self_interrupt ()
+{
+ MonoThreadInfo *info;
+ MonoThreadInfoInterruptToken *previous_token;
+
+ info = mono_thread_info_current ();
+ g_assert (info);
+
+ previous_token = InterlockedCompareExchangePointer ((gpointer*) &info->interrupt_token, NULL, INTERRUPT_STATE);
+ g_assert (previous_token == NULL || previous_token == INTERRUPT_STATE);
+
+ THREADS_INTERRUPT_DEBUG ("interrupt clear self tid %p previous_token %p\n", mono_thread_info_get_tid (info), previous_token);
+}
+
+gboolean
+mono_thread_info_is_interrupt_state (MonoThreadInfo *info)
+{
+ g_assert (info);
+ return InterlockedReadPointer ((gpointer*) &info->interrupt_token) == INTERRUPT_STATE;
}
void
-mono_thread_info_clear_interruption (void)
+mono_thread_info_describe_interrupt_token (MonoThreadInfo *info, GString *text)
{
- mono_threads_core_clear_interruption ();
+ g_assert (info);
+
+ if (!InterlockedReadPointer ((gpointer*) &info->interrupt_token))
+ g_string_append_printf (text, "not waiting");
+ else if (InterlockedReadPointer ((gpointer*) &info->interrupt_token) == INTERRUPT_STATE)
+ g_string_append_printf (text, "interrupted state");
+ else
+ g_string_append_printf (text, "waiting");
}
/* info must be self or be held in a hazard pointer. */
#define THREADS_STATE_MACHINE_DEBUG MOSTLY_ASYNC_SAFE_PRINTF
#endif
+#if 1
+#define THREADS_INTERRUPT_DEBUG(...)
+#else
+#define THREADS_INTERRUPT_DEBUG MOSTLY_ASYNC_SAFE_PRINTF
+#endif
+
/* If this is defined, use the signals backed on Mach. Debug only as signals can't be made usable on OSX. */
// #define USE_SIGNALS_ON_MACH
MONO_SERVICE_REQUEST_SAMPLE = 1,
} MonoAsyncJob;
+typedef struct _MonoThreadInfoInterruptToken MonoThreadInfoInterruptToken;
+
typedef struct {
MonoLinkedListSetNode node;
guint32 small_id; /*Used by hazard pointers */
volatile gint32 service_requests;
void *jit_data;
+
+ MonoThreadInfoInterruptToken *interrupt_token;
} MonoThreadInfo;
typedef struct {
void (*setup_async_callback) (MonoContext *ctx, void (*async_cb)(void *fun), gpointer user_data);
gboolean (*thread_state_init_from_sigctx) (MonoThreadUnwindState *state, void *sigctx);
gboolean (*thread_state_init_from_handle) (MonoThreadUnwindState *tctx, MonoThreadInfo *info);
+ void (*thread_state_init) (MonoThreadUnwindState *tctx);
} MonoThreadInfoRuntimeCallbacks;
//Not using 0 and 1 to ensure callbacks are not returning bad data
HANDLE
mono_thread_info_open_handle (void);
-gpointer
-mono_thread_info_prepare_interrupt (HANDLE thread_handle);
+void
+mono_thread_info_install_interrupt (void (*callback) (gpointer data), gpointer data, gboolean *interrupted);
void
-mono_thread_info_finish_interrupt (gpointer wait_handle);
+mono_thread_info_uninstall_interrupt (gboolean *interrupted);
+
+MonoThreadInfoInterruptToken*
+mono_thread_info_prepare_interrupt (THREAD_INFO_TYPE *info);
void
-mono_thread_info_interrupt (HANDLE thread_handle);
+mono_thread_info_finish_interrupt (MonoThreadInfoInterruptToken *token);
void
mono_thread_info_self_interrupt (void);
void
-mono_thread_info_clear_interruption (void);
+mono_thread_info_clear_self_interrupt (void);
+
+gboolean
+mono_thread_info_is_interrupt_state (THREAD_INFO_TYPE *info);
+
+void
+mono_thread_info_describe_interrupt_token (THREAD_INFO_TYPE *info, GString *text);
gboolean
mono_thread_info_is_live (THREAD_INFO_TYPE *info);
gboolean mono_threads_core_resume (THREAD_INFO_TYPE *info);
void mono_threads_platform_register (THREAD_INFO_TYPE *info); //ok
void mono_threads_platform_free (THREAD_INFO_TYPE *info);
-void mono_threads_core_interrupt (THREAD_INFO_TYPE *info);
void mono_threads_core_abort_syscall (THREAD_INFO_TYPE *info);
gboolean mono_threads_core_needs_abort_syscall (void);
HANDLE mono_threads_core_create_thread (LPTHREAD_START_ROUTINE start, gpointer arg, guint32 stack_size, guint32 creation_flags, MonoNativeThreadId *out_tid);
HANDLE mono_threads_core_open_handle (void);
HANDLE mono_threads_core_open_thread_handle (HANDLE handle, MonoNativeThreadId tid);
void mono_threads_core_set_name (MonoNativeThreadId tid, const char *name);
-gpointer mono_threads_core_prepare_interrupt (HANDLE thread_handle);
-void mono_threads_core_finish_interrupt (gpointer wait_handle);
-void mono_threads_core_self_interrupt (void);
-void mono_threads_core_clear_interruption (void);
MonoNativeThreadId mono_native_thread_id_get (void);