CurrentSystemTimeZone.GetUtcOffset now supports multiple DST periods.
|amd64-*-freebsd*|i?86-*-freebsd*|ia64-*-freebsd*|arm*-*-linux*|sparc*-*-linux*|mips*-*-linux*|x86_64-apple-darwin*|aarch64*)
pic_options='-fPIC'
;;
-?86-pc-cygwin*|i?86-pc-cygwin*)
+?86-pc-cygwin*|i?86-pc-cygwin*|i?86-pc-mingw32*)
pic_options='-DDLL_EXPORT'
;;
i?86-apple-darwin*|arm-apple-darwin*)
--- /dev/null
+#
+# Appveyor configuration file for CI build of Mono on Windows (under Cygwin)
+#
+# For further details see http://www.appveyor.com
+#
+
+# Use 'unstable' Appveyor build worker image as Appveyor have added Cygwin to this for us
+os: Unstable
+
+#
+# Custom environment variables
+#
+environment:
+ global:
+ CYG_ROOT: C:/cygwin
+ CYG_MIRROR: http://cygwin.mirror.constant.com
+ CYG_CACHE: C:/cygwin/var/cache/setup
+ NSIS_ROOT: C:\nsis
+
+#
+# Initialisation prior to pulling the Mono repository
+#
+init:
+ - 'echo Building Mono for Windows'
+ - 'echo System architecture: %PLATFORM%'
+ - 'echo Repo build branch is: %APPVEYOR_REPO_BRANCH%'
+ - 'echo Build folder is: %APPVEYOR_BUILD_FOLDER%'
+# Attempt to ensure we don't try to convert line endings to Win32 CRLF as this will cause build to fail
+ - 'git config --global core.autocrlf input'
+
+#
+# Install needed build dependencies
+#
+install:
+# NOTE: Already installed on current Appveyor unstable image
+# - 'echo Retrieving Cygwin'
+# - 'appveyor DownloadFile http://cygwin.com/setup-x86.exe -FileName %CYGROOT%/setup-x86.exe'
+ - 'echo Setting up Cygwin dependencies'
+ - '%CYG_ROOT%\setup-x86.exe -qnNdO -R "%CYG_ROOT%" -s "%CYG_MIRROR%" -l "%CYG_CACHE%" -P autoconf -P automake -P bison -P gcc-core -P gcc-g++ -P mingw-runtime -P mingw-binutils -P mingw-gcc-core -P mingw-gcc-g++ -P mingw-pthreads -P mingw-w32api -P libtool -P make -P python -P gettext-devel -P gettext -P intltool -P libiconv -P pkg-config -P git -P wget -P curl > NUL'
+ - 'echo Check Cygwin setup'
+ - '%CYG_ROOT%/bin/bash -lc "cygcheck -dc cygwin"'
+ - 'echo Done setting up Cygwin'
+ - 'echo Retrieving NSIS'
+ - 'appveyor DownloadFile "http://sunet.dl.sourceforge.net/project/nsis/NSIS 2/2.46/nsis-2.46-setup.exe" -FileName nsissetup.exe'
+ - 'echo Setting up NSIS'
+ - 'nsissetup.exe /S /D=%NSIS_ROOT%'
+ - 'echo Done setting up NSIS'
+
+#
+# NOTE: msbuild doesn't work at present so use Cygwin to build
+#
+#build:
+# project: C:\projects\mono\msvc\mono.sln
+# verbosity: detailed
+
+# Cygwin build script
+#
+# NOTES:
+#
+# The stdin/stdout file descriptor appears not to be valid for the Appveyor
+# build which causes failures as certain functions attempt to redirect
+# default file handles. Ensure a dummy file descriptor is opened with exec.
+#
+build_script:
+ - cmd: 'echo Cygwin root is: %CYG_ROOT%'
+ - cmd: 'echo Build folder is: %APPVEYOR_BUILD_FOLDER%'
+ - cmd: 'echo Repo build branch is: %APPVEYOR_REPO_BRANCH%'
+ - cmd: 'echo Repo build commit is: %APPVEYOR_REPO_COMMIT%'
+ - cmd: 'echo Autogen running...'
+ - cmd: '%CYG_ROOT%/bin/bash -lc "cd $APPVEYOR_BUILD_FOLDER; exec 0</dev/null; NOCONFIGURE=1 ./autogen.sh --prefix=/usr/local --with-preview=yes"'
+ - cmd: 'echo Configure running...'
+ - cmd: '%CYG_ROOT%/bin/bash -lc "cd $APPVEYOR_BUILD_FOLDER; exec 0</dev/null; ./configure --host=i686-pc-mingw32"'
+ - cmd: 'echo Pulling monolite latest...'
+ - cmd: '%CYG_ROOT%/bin/bash -lc "cd $APPVEYOR_BUILD_FOLDER; exec 0</dev/null; make get-monolite-latest"'
+ - cmd: 'echo Make running...'
+ - cmd: '%CYG_ROOT%/bin/bash -lc "cd $APPVEYOR_BUILD_FOLDER; exec 0</dev/null; make"'
+ - cmd: 'echo Installing...'
+ - cmd: 'mkdir %APPVEYOR_BUILD_FOLDER%\install'
+ - cmd: '%CYG_ROOT%/bin/bash --login -lc "export CYGWIN=winsymlinks:native; mount \"$APPVEYOR_BUILD_FOLDER\install\" /usr/local; cd $APPVEYOR_BUILD_FOLDER; exec 0</dev/null; make install; umount /usr/local"'
+# - cmd: 'echo Building package...'
+# - cmd: 'cd %APPVEYOR_BUILD_FOLDER%'
+# - cmd: '%NSIS_ROOT%\makensis /DMILESTONE=%APPVEYOR_REPO_BRANCH% /DSOURCE_INSTALL_DIR=%APPVEYOR_BUILD_FOLDER\install\*.* /DBUILDNUM=%APPVEYOR_BUILD_VERSION% monowiz.win32.nsi'
+# - cmd: 'Building distribution...'
+# - cmd: '%CYG_ROOT%/bin/bash -lc "export CYGWIN=winsymlinks:native; cd $APPVEYOR_BUILD_FOLDER; exec 0</dev/null; make dist"'
+
+#
+# Disable tests for now
+#
+test: off
+
+#
+# NOTE: Currently this is the Mono installation tree. In future we will create an installation package artifact.
+# It has to be relative to the project path. Thus we have installed to within the build tree.
+#
+artifacts:
+ - path: install
+ name: mono-binaries
+ type: zip
AC_DEFINE(MINGW_CROSS_COMPILE,1,[Cross-compiling using MinGW])
fi
HOST_CC="gcc"
- # Windows 2000 is required that includes Internet Explorer 5.01
+ # Windows XP SP2 is required
CPPFLAGS="$CPPFLAGS -DWINVER=0x0502 -D_WIN32_WINNT=0x0502 -D_WIN32_IE=0x0501 -D_UNICODE -DUNICODE -DWIN32_THREADS -DFD_SETSIZE=1024"
- LDFLAGS="$LDFLAGS -lmswsock -lws2_32 -lole32 -loleaut32 -lpsapi -lversion -ladvapi32 -lwinmm -lkernel32"
+ LDFLAGS="$LDFLAGS -lmswsock -lws2_32 -lole32 -loleaut32 -lpsapi -lversion -ladvapi32 -lwinmm -lkernel32 -liphlpapi"
libmono_cflags="-mms-bitfields -mwindows"
libmono_ldflags="-mms-bitfields -mwindows"
libdl=
AC_ARG_ENABLE(minimal, [ --enable-minimal=LIST drop support for LIST subsystems.
LIST is a comma-separated list from: aot, profiler, decimal, pinvoke, debug, appdomains, verifier,
reflection_emit, reflection_emit_save, large_code, logging, com, ssa, generics, attach, jit, simd, soft_debug, perfcounters, normalization, assembly_remapping, shared_perfcounters, remoting,
- security, sgen_remset, sgen_marksweep_par, sgen_marksweep_fixed, sgen_marksweep_fixed_par, sgen_copying.],
+ security, sgen_remset, sgen_marksweep_par, sgen_marksweep_fixed, sgen_marksweep_fixed_par, sgen_copying, shared_handles.],
[
for feature in `echo "$enable_minimal" | sed -e "s/,/ /g"`; do
eval "mono_feature_disable_$feature='yes'"
AC_MSG_NOTICE([Disabled major=copying support in SGEN.])
fi
+if test "x$mono_feature_disable_shared_handles" = "xyes"; then
+ AC_DEFINE(DISABLE_SHARED_HANDLES, 1, [Disable inter-process shared handles])
+ AC_SUBST(DISABLE_SHARED_HANDLES)
+fi
+
AC_ARG_ENABLE(executables, [ --disable-executables disable the build of the runtime executables], enable_executables=$enableval, enable_executables=yes)
AM_CONDITIONAL(DISABLE_EXECUTABLES, test x$enable_executables = xno)
AC_CHECK_HEADERS(execinfo.h)
- AC_CHECK_HEADERS(sys/auxv.h)
+ AC_CHECK_HEADERS(sys/auxv.h sys/resource.h)
AC_CHECK_FUNCS(getgrgid_r)
AC_CHECK_FUNCS(getgrnam_r)
AC_CHECK_FUNCS(dl_iterate_phdr)
AC_CHECK_FUNCS(dladdr)
AC_CHECK_FUNCS(sysconf)
+ AC_CHECK_FUNCS(getrlimit)
AC_CHECK_FUNCS(sched_setaffinity)
AC_CHECK_FUNCS(sched_getcpu)
fi
AC_MSG_CHECKING([if inter-process shared handles are requested])
+# Same as --enable-minimal=shared_handles
AC_ARG_ENABLE(shared-handles, [ --disable-shared-handles disable inter-process shared handles], try_shared_handles=$enableval, try_shared_handles=yes)
AC_MSG_RESULT($try_shared_handles)
if test "x$try_shared_handles" != "xyes"; then
TARGET="unknown"
ACCESS_UNALIGNED="yes"
-JIT_SUPPORTED=no
LIBC="libc.so.6"
INTL="libc.so.6"
SQLITE="libsqlite.so.0"
arch_target=mips;
sgen_supported=true
ACCESS_UNALIGNED="no"
- JIT_SUPPORTED=yes
AC_MSG_CHECKING(for mips n32)
AC_TRY_COMPILE([],[
i*86-*-*)
TARGET=X86;
arch_target=x86;
- JIT_SUPPORTED=yes
case $host_os in
solaris*)
LIBC="libc.so"
x86_64-*-* | amd64-*-*)
TARGET=AMD64;
arch_target=amd64;
- JIT_SUPPORTED=yes
if test "x$ac_cv_sizeof_void_p" = "x4"; then
AC_DEFINE(__mono_ilp32__, 1, [64 bit mode with 4 byte longs and pointers])
sizeof_register=8
TARGET=IA64
arch_target=ia64
ACCESS_UNALIGNED="no"
- JIT_SUPPORTED=yes
LIBC="libc.so.6.1"
INTL="libc.so.6.1"
AC_CHECK_LIB(unwind, _U_dyn_register, [], [AC_MSG_ERROR(library libunwind not found)])
TARGET=SPARC
fi
arch_target=sparc;
- JIT_SUPPORTED=yes
ACCESS_UNALIGNED="no"
case $host_os in
linux*) ;;
CPPFLAGS="$CPPFLAGS -D__mono_ppc__"
fi
arch_target=ppc;
- JIT_SUPPORTED=yes
case $host_os in
linux*|darwin*)
sgen_supported=true
TARGET=ARM;
arch_target=arm;
ACCESS_UNALIGNED="no"
- JIT_SUPPORTED=yes
CPPFLAGS="$CPPFLAGS -D__ARM_EABI__"
sgen_supported=true
;;
TARGET=ARM;
arch_target=arm;
ACCESS_UNALIGNED="no"
- JIT_SUPPORTED=yes
sgen_supported=true
AOT_SUPPORTED="yes"
CPPFLAGS="$CPPFLAGS -D__ARM_EABI__"
# TARGET=ARM;
# arch_target=arm;
# ACCESS_UNALIGNED="no"
-# JIT_SUPPORTED=yes
# sgen_supported=true
# AOT_SUPPORTED="no"
# ;;
# https://lkml.org/lkml/2012/7/15/133
TARGET=ARM64
arch_target=arm64
- JIT_SUPPORTED=yes
sgen_supported=true
boehm_supported=false
;;
TARGET=S390X;
arch_target=s390x;
ACCESS_UNALIGNED="yes"
- JIT_SUPPORTED=yes
sgen_supported=true
CFLAGS="$CFLAGS -mbackchain -D__USE_STRING_INLINES"
;;
TARGET=ARM;
arch_target=arm;
ACCESS_UNALIGNED="no"
- JIT_SUPPORTED=yes
CPPFLAGS="$CPPFLAGS -D__ARM_EABI__"
- jit_wanted=true
# Can't use tls, since it depends on the runtime detection of tls offsets
# in mono-compiler.h
with_tls=pthread
# arch_target=arm
# AC_DEFINE(TARGET_ARM, 1, [...])
# ACCESS_UNALIGNED="no"
-# JIT_SUPPORTED=yes
# sizeof_register=4
# CPPFLAGS="$CPPFLAGS \
# -D__ARM_EABI__ \
# -DDISABLE_SOCKETS \
# -DDISABLE_ATTACH \
# -DUSE_NEWLIB"
-# jit_wanted=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_ARM, 1, [...])
AC_DEFINE(TARGET_ANDROID, 1, [...])
ACCESS_UNALIGNED="no"
- JIT_SUPPORTED=yes
CPPFLAGS="$CPPFLAGS -D__ARM_EABI__"
- jit_wanted=true
# Can't use tls, since it depends on the runtime detection of tls offsets
# in mono-compiler.h
with_tls=pthread
arch_target=x86;
AC_DEFINE(TARGET_X86, 1, [...])
AC_DEFINE(TARGET_ANDROID, 1, [...])
- JIT_SUPPORTED=yes
CPPFLAGS="$CPPFLAGS"
- jit_wanted=true
sgen_supported=true
# Can't use tls, since it depends on the runtime detection of tls offsets
# in mono-compiler.h
;;
aarch64-*)
TARGET=ARM64
- JIT_SUPPORTED=yes
- jit_wanted=true
;;
*)
AC_MSG_ERROR([Cross compiling is not supported for target $target])
AC_SUBST(SGEN_DEFINES)
AM_CONDITIONAL(SUPPORT_SGEN, test x$buildsgen = xyes)
-USEJIT=false
-if test x$JIT_SUPPORTED = xyes; then
- if $jit_wanted; then
- USEJIT=true
- jit_status="Building and using the JIT"
- else
- AC_ERROR(No JIT support available or selected.)
- fi
-else
- AC_ERROR(No JIT support available or selected.)
-fi
-
-AM_CONDITIONAL(USE_JIT, test x$USEJIT = xtrue)
+jit_status="Building and using the JIT"
libsuffix=".so"
AM_CONDITIONAL(HOST_ARM64, test x$HOST = xARM64)
AM_CONDITIONAL(CROSS_COMPILE, test "x$host" != "x$target")
-AM_CONDITIONAL(JIT_SUPPORTED, test x$JIT_SUPPORTED = xyes)
AM_CONDITIONAL(INCLUDED_LIBGC, test x$libgc = xincluded)
AC_SUBST(LIBC)
SGENPCFILE=
endif
-if JIT_SUPPORTED
pkgconfig_DATA= mono.pc mono-2.pc dotnet.pc dotnet35.pc wcf.pc mono-nunit.pc mono-cairo.pc mono-options.pc cecil.pc monodoc.pc mono-lineeditor.pc system.web.extensions_1.0.pc \
system.web.extensions.design_1.0.pc system.web.mvc.pc system.web.mvc2.pc system.web.mvc3.pc aspnetwebstack.pc reactive.pc xbuild12.pc $(SGENPCFILE)
-else
-pkgconfig_DATA= mint.pc mono-nunit.pc mono-cairo.pc mono-options.pc cecil.pc monodoc.pc mono-lineeditor.pc
-endif
DISTCLEANFILES= mono-2.pc mono.pc mint.pc dotnet.pc dotnet35.pc wcf.pc mono-nunit.pc mono-cairo.pc mono-options.pc cecil.pc monodoc.pc mono-lineeditor.pc system.web.extensions_1.0.pc \
system.web.extensions.design_1.0.pc system.web.mvc.pc system.web.mvc2.pc system.web.mvc3.pc aspnetwebstack.pc reactive.pc $(SGENPCFILE) mono-sgen-gdb.py
|amd64-*-freebsd*|i?86-*-freebsd*|ia64-*-freebsd*|arm*-*-linux*|sparc*-*-linux*|mips*-*-linux*|x86_64-apple-darwin*|aarch64*)
pic_options='-fPIC'
;;
-?86-pc-cygwin*|i?86-pc-cygwin*)
+?86-pc-cygwin*|i?86-pc-cygwin*|i?86-pc-mingw32*)
pic_options='-DDLL_EXPORT'
;;
i?86-apple-darwin*|arm-apple-darwin*)
|amd64-*-freebsd*|i?86-*-freebsd*|ia64-*-freebsd*|arm*-*-linux*|sparc*-*-linux*|mips*-*-linux*|x86_64-apple-darwin*|aarch64*)
pic_options='-fPIC'
;;
-?86-pc-cygwin*|i?86-pc-cygwin*)
+?86-pc-cygwin*|i?86-pc-cygwin*|i?86-pc-mingw32*)
pic_options='-DDLL_EXPORT'
;;
i?86-apple-darwin*|arm-apple-darwin*)
sgen-gc.c. You can then use this command to explore the output
.nf
sgen-grep-binprot 0x1234 0x5678 < file
+.TP
+\fBnursery-canaries\fR
+If set, objects allocated in the nursery are suffixed with a canary (guard)
+word, which is checked on each minor collection. Can be used to detect/debug
+heap corruption issues.
.fi
.ne
.RE
public RelaxngPattern Parse (TextReader source, string baseUri, string defaultNamespace)
{
- this.defaultNamespace = defaultNamespace;
+ this.defaultNamespace = defaultNamespace ?? string.Empty;
if (defaultNamespace != null && defaultNamespace.Length != 0)
nsmgr.AddNamespace (String.Empty, defaultNamespace);
try {
r.Close ();
}
}
+
+ [Test]
+ public void SimpleDefaultNamespace ()
+ {
+ var g = RncParser.ParseRnc (new StringReader ("element e { empty }"));
+ var x = XmlReader.Create (new StringReader ("<e/>"));
+ var r = new RelaxngValidatingReader (x, g);
+ try {
+ while (!r.EOF)
+ r.Read ();
+ } finally {
+ r.Close ();
+ }
+ }
}
}
RNCTESTS = test/RNCTest.xml
RNCTEST_ARCHIVE = anglia-test-suite.zip
-all : relaxngtest.exe anglia-test-runner.exe
+all : relaxngtest.exe #anglia-test-runner.exe
relaxngtest.exe : relaxngtest.cs $(TESTS)
$(MCS_RUNTIME) $(MCS) -debug+ relaxngtest.cs -r:Commons.Xml.Relaxng.dll
Rectangle text_rectangle;
Rectangle image_rectangle;
- ThemeEngine.Current.CalculateButtonTextAndImageLayout (this, out text_rectangle, out image_rectangle);
+ ThemeEngine.Current.CalculateButtonTextAndImageLayout (pevent.Graphics, this, out text_rectangle, out image_rectangle);
// Draw our button
if (this.FlatStyle == FlatStyle.Standard)
StringFormat sf = FlagsToStringFormat (flags);
Size retval;
-
+
+ int proposedWidth;
+ if (proposedSize.Width == 0)
+ proposedWidth = Int32.MaxValue;
+ else {
+ proposedWidth = proposedSize.Width;
+ if ((flags & TextFormatFlags.NoPadding) == 0)
+ proposedWidth -= 9;
+ }
if (dc is Graphics)
- retval = (dc as Graphics).MeasureString (text, font, proposedSize.Width == 0 ? Int32.MaxValue : proposedSize.Width, sf).ToSize ();
+ retval = (dc as Graphics).MeasureString (text, font, proposedWidth, sf).ToSize ();
else
- retval = TextRenderer.MeasureString (text, font, proposedSize.Width == 0 ? Int32.MaxValue : proposedSize.Width, sf).ToSize ();
+ retval = TextRenderer.MeasureString (text, font, proposedWidth, sf).ToSize ();
if (retval.Width > 0 && (flags & TextFormatFlags.NoPadding) == 0)
retval.Width += 9;
#region Button
public abstract Size CalculateButtonAutoSize (Button button);
- public abstract void CalculateButtonTextAndImageLayout (ButtonBase b, out Rectangle textRectangle, out Rectangle imageRectangle);
+ public abstract void CalculateButtonTextAndImageLayout (Graphics g, ButtonBase b, out Rectangle textRectangle, out Rectangle imageRectangle);
public abstract void DrawButton (Graphics g, Button b, Rectangle textBounds, Rectangle imageBounds, Rectangle clipRectangle);
public abstract void DrawFlatButton (Graphics g, ButtonBase b, Rectangle textBounds, Rectangle imageBounds, Rectangle clipRectangle);
public abstract void DrawPopupButton (Graphics g, Button b, Rectangle textBounds, Rectangle imageBounds, Rectangle clipRectangle);
return ret_size;
}
- public override void CalculateButtonTextAndImageLayout (ButtonBase button, out Rectangle textRectangle, out Rectangle imageRectangle)
+ public override void CalculateButtonTextAndImageLayout (Graphics g, ButtonBase button, out Rectangle textRectangle, out Rectangle imageRectangle)
{
Image image = button.Image;
string text = button.Text;
Rectangle content_rect = button.PaddingClientRectangle;
- Size text_size = TextRenderer.MeasureTextInternal (text, button.Font, content_rect.Size, button.TextFormatFlags, button.UseCompatibleTextRendering);
+ Size text_size = TextRenderer.MeasureTextInternal (g, text, button.Font, content_rect.Size, button.TextFormatFlags | TextFormatFlags.NoPadding, button.UseCompatibleTextRendering);
Size image_size = image == null ? Size.Empty : image.Size;
- textRectangle = Rectangle.Empty;
+ textRectangle = Rectangle.Inflate (content_rect, -4, -4);
imageRectangle = Rectangle.Empty;
switch (button.TextImageRelation) {
case TextImageRelation.Overlay:
// Overlay is easy, text always goes here
- textRectangle = Rectangle.Inflate (content_rect, -4, -4);
- if (button.Pressed)
- textRectangle.Offset (1, 1);
+ if (button.Pressed)
+ textRectangle.Offset (1, 1);
// Image is dependent on ImageAlign
if (image == null)
imageRectangle = new Rectangle (image_x, image_y, image_width, image_height);
break;
case TextImageRelation.ImageAboveText:
- content_rect.Inflate (-4, -4);
- LayoutTextAboveOrBelowImage (content_rect, false, text_size, image_size, button.TextAlign, button.ImageAlign, out textRectangle, out imageRectangle);
+ LayoutTextAboveOrBelowImage (textRectangle, false, text_size, image_size, button.TextAlign, button.ImageAlign, out textRectangle, out imageRectangle);
break;
case TextImageRelation.TextAboveImage:
- content_rect.Inflate (-4, -4);
- LayoutTextAboveOrBelowImage (content_rect, true, text_size, image_size, button.TextAlign, button.ImageAlign, out textRectangle, out imageRectangle);
+ LayoutTextAboveOrBelowImage (textRectangle, true, text_size, image_size, button.TextAlign, button.ImageAlign, out textRectangle, out imageRectangle);
break;
case TextImageRelation.ImageBeforeText:
- content_rect.Inflate (-4, -4);
- LayoutTextBeforeOrAfterImage (content_rect, false, text_size, image_size, button.TextAlign, button.ImageAlign, out textRectangle, out imageRectangle);
+ LayoutTextBeforeOrAfterImage (textRectangle, false, text_size, image_size, button.TextAlign, button.ImageAlign, out textRectangle, out imageRectangle);
break;
case TextImageRelation.TextBeforeImage:
- content_rect.Inflate (-4, -4);
- LayoutTextBeforeOrAfterImage (content_rect, true, text_size, image_size, button.TextAlign, button.ImageAlign, out textRectangle, out imageRectangle);
+ LayoutTextBeforeOrAfterImage (textRectangle, true, text_size, image_size, button.TextAlign, button.ImageAlign, out textRectangle, out imageRectangle);
break;
}
}
offset += (int)(2 * (excess_height / 3));
if (textFirst) {
- final_text_rect = new Rectangle (AlignInRectangle (totalArea, textSize, textAlign).Left, totalArea.Top + offset, textSize.Width, textSize.Height);
+ var textHeight = excess_height >= 0 ? totalArea.Height - imageSize.Height - element_spacing: textSize.Height;
+ final_text_rect = new Rectangle (AlignInRectangle (totalArea, textSize, textAlign).Left, totalArea.Top + offset, textSize.Width, textHeight);
final_image_rect = new Rectangle (AlignInRectangle (totalArea, imageSize, imageAlign).Left, final_text_rect.Bottom + element_spacing, imageSize.Width, imageSize.Height);
}
else {
final_image_rect = new Rectangle (AlignInRectangle (totalArea, imageSize, imageAlign).Left, totalArea.Top + offset, imageSize.Width, imageSize.Height);
- final_text_rect = new Rectangle (AlignInRectangle (totalArea, textSize, textAlign).Left, final_image_rect.Bottom + element_spacing, textSize.Width, textSize.Height);
+ var textHeight = excess_height >= 0 ? totalArea.Height - final_image_rect.Height : textSize.Height;
+ final_text_rect = new Rectangle (AlignInRectangle (totalArea, textSize, textAlign).Left, final_image_rect.Bottom + element_spacing, textSize.Width, textHeight);
if (final_text_rect.Bottom > totalArea.Bottom)
final_text_rect.Y = totalArea.Top;
buffer [i] = Marshal.ReadByte (prop, i);
Clipboard.Item = Encoding.UTF8.GetString (buffer);
} else if (property == UTF16_STRING) {
- Clipboard.Item = Marshal.PtrToStringUni (prop, Encoding.Unicode.GetMaxCharCount ((int)nitems));
+ Clipboard.Item = Marshal.PtrToStringUni (prop);
} else if (property == RICHTEXTFORMAT)
Clipboard.Item = Marshal.PtrToStringAnsi(prop);
else if (DataFormats.ContainsFormat (property.ToInt32 ())) {
<Compile Include="Microsoft.Build.BuildEngine\TaskBatchingImpl.cs" />\r
<Compile Include="Microsoft.Build.BuildEngine\TaskDatabase.cs" />\r
<Compile Include="Microsoft.Build.BuildEngine\TaskEngine.cs" />\r
+ <Compile Include="Microsoft.Build.BuildEngine\TaskExecutionMode.cs" />\r
<Compile Include="Microsoft.Build.BuildEngine\Token.cs" />\r
<Compile Include="Microsoft.Build.BuildEngine\Toolset.cs" />\r
<Compile Include="Microsoft.Build.BuildEngine\ToolsetCollection.cs" />\r
// block size (which isn't their real internal block size)
public BlockProcessor (ICryptoTransform transform, int blockSize)
{
- if (transform == null)
- throw new ArgumentNullException ("transform");
- if (blockSize <= 0)
- throw new ArgumentOutOfRangeException ("blockSize");
this.transform = transform;
this.blockSize = blockSize;
block = new byte [blockSize];
: db.GetAvailableIds ();
}
- static TimeZoneInfo _GetTimeZone (string name)
+ static TimeZoneInfo _GetTimeZone (string id, string name)
{
if (db == null)
return null;
byte[] buffer = db.GetTimeZoneData (name);
if (buffer == null)
return null;
- return TimeZoneInfo.ParseTZBuffer (name, buffer, buffer.Length);
+ return TimeZoneInfo.ParseTZBuffer (id, buffer, buffer.Length);
}
- internal static TimeZoneInfo GetTimeZone (string id)
+ internal static TimeZoneInfo GetTimeZone (string id, string name)
{
- if (id != null) {
- if (id == "GMT" || id == "UTC")
- return new TimeZoneInfo (id, TimeSpan.FromSeconds (0), id, id, id, null, true);
- if (id.StartsWith ("GMT"))
+ if (name != null) {
+ if (name == "GMT" || name == "UTC")
+ return new TimeZoneInfo (id, TimeSpan.FromSeconds (0), id, name, name, null, disableDaylightSavingTime:true);
+ if (name.StartsWith ("GMT"))
return new TimeZoneInfo (id,
- TimeSpan.FromSeconds (ParseNumericZone (id)),
- id, id, id, null, true);
+ TimeSpan.FromSeconds (ParseNumericZone (name)),
+ id, name, name, null, disableDaylightSavingTime:true);
}
try {
- return _GetTimeZone (id);
+ return _GetTimeZone (id, name);
} catch (Exception) {
return null;
}
static readonly object _lock = new object ();
static TimeZoneInfo defaultZone;
- internal static TimeZoneInfo Default {
+ internal static TimeZoneInfo Local {
get {
lock (_lock) {
if (defaultZone != null)
return defaultZone;
- return defaultZone = GetTimeZone (GetDefaultTimeZoneName ());
+ return defaultZone = GetTimeZone ("Local", GetDefaultTimeZoneName ());
}
}
}
{
IntPtr value = IntPtr.Zero;
int n = 0;
- string defaultTimeZone;
+ string defaultTimeZone = Environment.GetEnvironmentVariable ("__XA_OVERRIDE_TIMEZONE_ID__");
+
+ if (!string.IsNullOrEmpty (defaultTimeZone))
+ return defaultTimeZone;
// Used by the tests
if (Environment.GetEnvironmentVariable ("__XA_USE_JAVA_DEFAULT_TIMEZONE_ID__") == null)
#if SELF_TEST
/*
* Compile:
- * mcs /out:tzi.exe /unsafe "/d:INSIDE_CORLIB;MONODROID;NET_4_0;LIBC;SELF_TEST" System/TimeZone*.cs ../../build/common/Consts.cs ../Mono.Options/Mono.Options/Options.cs
+ * mcs /debug+ /out:tzi.exe /unsafe "/d:INSIDE_CORLIB;MONODROID;NET_4_0;LIBC;SELF_TEST" ../corlib/System/AndroidPlatform.cs System/TimeZone*.cs ../../build/common/Consts.cs ../Mono.Options/Mono.Options/Options.cs
* Prep:
* mkdir -p usr/share/zoneinfo
+ * mkdir -p misc/zoneinfo/zoneinfo
* android_root=`adb shell echo '$ANDROID_ROOT' | tr -d "\r"`
+ * android_data=`adb shell echo '$ANDROID_DATA' | tr -d "\r"`
* adb pull $android_root/usr/share/zoneinfo usr/share/zoneinfo
+ * adb pull $android_data/misc/zoneinfo/tzdata misc/zoneinfo
* Run:
- * ANDROID_ROOT=`pwd` mono tzi.exe
+ * __XA_OVERRIDE_TIMEZONE_ID__=America/New_York ANDROID_ROOT=`pwd` ANDROID_DATA=`pwd` mono --debug tzi.exe --offset=1969-01-01
*/
static void Main (string[] args)
{
+ DateTime? offset = null;
Func<IAndroidTimeZoneDB> c = () => GetDefaultTimeZoneDB ();
Mono.Options.OptionSet p = null;
p = new Mono.Options.OptionSet () {
{ "Z=", "Create ZoneInfoDB from {DIR}.", v => {
c = () => new ZoneInfoDB (v);
} },
+ { "offset=", "Show timezone info offset for DateTime {OFFSET}.", v => {
+ offset = DateTime.Parse (v);
+ Console.WriteLine ("Using DateTime Offset: {0}", offset);
+ } },
{ "help", "Show this message and exit", v => {
p.WriteOptionDescriptions (Console.Out);
Environment.Exit (0);
foreach (var id in GetAvailableIds ()) {
Console.Write ("name={0,-40}", id);
try {
- TimeZoneInfo zone = _GetTimeZone (id);
- if (zone != null)
- Console.Write (" {0}", zone);
+ TimeZoneInfo zone = _GetTimeZone (id, id);
+ if (zone != null) {
+ Console.Write (" {0,-40}", zone);
+ if (offset.HasValue) {
+ Console.Write ("From Offset: {0}", zone.GetUtcOffset (offset.Value));
+ }
+ }
else {
Console.Write (" ERROR:null");
}
static TimeZoneInfo CreateLocal ()
{
#if MONODROID
- return AndroidTimeZones.Default;
+ return AndroidTimeZones.Local;
#elif MONOTOUCH
using (Stream stream = GetMonoTouchData (null)) {
return BuildFromStream ("Local", stream);
}
#endif
#if MONODROID
- var timeZoneInfo = AndroidTimeZones.GetTimeZone (id);
+ var timeZoneInfo = AndroidTimeZones.GetTimeZone (id, id);
if (timeZoneInfo == null)
throw new TimeZoneNotFoundException ();
return timeZoneInfo;
#endif
#if MONODROID
foreach (string id in AndroidTimeZones.GetAvailableIds ()) {
- var tz = AndroidTimeZones.GetTimeZone (id);
+ var tz = AndroidTimeZones.GetTimeZone (id, id);
if (tz != null)
systemTimeZones.Add (tz);
}
<Compile Include="System.Data.SqlClient\SqlCommandBuilder.cs" />\r
<Compile Include="System.Data.SqlClient\SqlConnection.cs" />\r
<Compile Include="System.Data.SqlClient\SqlConnectionStringBuilder.cs" />\r
+ <Compile Include="System.Data.SqlClient\SqlCredential.cs" />\r
<Compile Include="System.Data.SqlClient\SqlDataAdapter.cs" />\r
<Compile Include="System.Data.SqlClient\SqlDataReader.cs" />\r
<Compile Include="System.Data.SqlClient\SqlDataSourceConverter.cs" />\r
throw new ArgumentOutOfRangeException ("maxItemsInObjectGraph");
this.type = type;
- known_types = new ReadOnlyCollection<Type> (knownTypes != null ? knownTypes.ToArray () : Type.EmptyTypes);
+
+ var knownTypesFromAttributes = new List<Type> ();
+
+ foreach (var attr in type.GetCustomAttributes (typeof (KnownTypeAttribute), false))
+ knownTypesFromAttributes.Add ((attr as KnownTypeAttribute).Type);
+
+ if (knownTypes != null)
+ knownTypesFromAttributes.AddRange (knownTypes);
+
+ known_types = new ReadOnlyCollection<Type> (knownTypesFromAttributes);
+
root = rootName;
max_items = maxItemsInObjectGraph;
ignore_extension = ignoreExtensionDataObject;
public bool IgnoreExtensionDataObject {
get { return ignore_extension; }
}
-
- [MonoTODO]
public ReadOnlyCollection<Type> KnownTypes {
get { return known_types; }
}
if (ct != null) {
return DeserializeGenericCollection (type, ct, instance);
} else {
- TypeMap map = GetTypeMap (type);
- return map.Deserialize (this, instance);
+ string typeHint = reader.GetAttribute ("__type");
+ if (typeHint != null) {
+ // this might be a derived & known type. We allow it when it's both.
+ Type exactType = GetRuntimeType (typeHint, type);
+ if (exactType == null)
+ throw SerializationError (String.Format ("Cannot load type '{0}'", typeHint));
+ TypeMap map = GetTypeMap (exactType);
+ return map.Deserialize (this, instance);
+ } else { // no type hint
+ TypeMap map = GetTypeMap (type);
+ return map.Deserialize (this, instance);
+ }
}
}
else
}
- Type GetRuntimeType (string name)
+ Type GetRuntimeType (string name, Type baseType)
{
- name = ToRuntimeTypeName (name);
+ string properName = ToRuntimeTypeName (name);
+
+ if (baseType != null && baseType.FullName.Equals (properName))
+ return baseType;
+
if (serializer.KnownTypes != null)
foreach (Type t in serializer.KnownTypes)
- if (t.FullName == name)
+ if (t.FullName.Equals (properName))
return t;
- var ret = root_type.Assembly.GetType (name, false) ?? Type.GetType (name, false);
- if (ret != null)
- return ret;
- // We probably have to iterate all the existing
- // assemblies that are loaded in current domain.
- foreach (var ass in AppDomain.CurrentDomain.GetAssemblies ()) {
- ret = ass.GetType (name, false);
- if (ret != null)
- return ret;
- }
+ if (baseType != null)
+ foreach (var attr in baseType.GetCustomAttributes (typeof (KnownTypeAttribute), false))
+ if ((attr as KnownTypeAttribute).Type.FullName.Equals (properName))
+ return (attr as KnownTypeAttribute).Type;
return null;
}
case "object":
string runtimeType = reader.GetAttribute ("__type");
if (runtimeType != null) {
- Type t = GetRuntimeType (runtimeType);
+ Type t = GetRuntimeType (runtimeType, null);
if (t == null)
throw SerializationError (String.Format ("Cannot load type '{0}'", runtimeType));
return ReadObject (t);
return ser.ReadObject (xr);
}
+ public T Deserialize<T>(string json)
+ {
+ var bytes = Encoding.Unicode.GetBytes (json);
+ using (MemoryStream stream = new MemoryStream (bytes)) {
+ var serializer = new DataContractJsonSerializer (typeof(T));
+ return (T)serializer.ReadObject (stream);
+ }
+ }
+
[Test]
public void IsStartObject ()
{
serializer.WriteObject (stream, o);
}
+ // properly deserialize object with a polymorphic property (known derived type)
+ [Test]
+ public void Bug23058()
+ {
+ string serializedObj = @"{""PolymorphicProperty"":{""__type"":""KnownDerivedType:#MonoTests.System.Runtime.Serialization.Json"",""BaseTypeProperty"":""Base"",""DerivedProperty"":""Derived 1""},""Name"":""Parent2""}";
+ ParentType deserializedObj = Deserialize<ParentType> (serializedObj);
+
+ Assert.AreEqual (deserializedObj.PolymorphicProperty.GetType ().FullName, "MonoTests.System.Runtime.Serialization.Json.KnownDerivedType");
+ Assert.AreEqual (deserializedObj.PolymorphicProperty.BaseTypeProperty, "Base");
+ Assert.AreEqual ((deserializedObj.PolymorphicProperty as KnownDerivedType).DerivedProperty, "Derived 1");
+ Assert.AreEqual (deserializedObj.Name, "Parent2");
+ }
+
+ // properly deserialize object with a polymorphic property (base type with __type hint)
+ [Test]
+ public void DeserializeBaseTypePropHint()
+ {
+ string serializedObj = @"{""PolymorphicProperty"":{""__type"":""BaseType:#MonoTests.System.Runtime.Serialization.Json"",""BaseTypeProperty"":""Base""},""Name"":""Parent2""}";
+ ParentType deserializedObj = Deserialize<ParentType> (serializedObj);
+
+ Assert.AreEqual (deserializedObj.PolymorphicProperty.GetType ().FullName, "MonoTests.System.Runtime.Serialization.Json.BaseType");
+ Assert.AreEqual (deserializedObj.PolymorphicProperty.BaseTypeProperty, "Base");
+ }
+
+ // properly deserialize object with a polymorphic property (base type with __type hint)
+ [Test]
+ public void DeserializeBaseTypePropNoHint()
+ {
+ string serializedObj = @"{""PolymorphicProperty"":{""BaseTypeProperty"":""Base""},""Name"":""Parent2""}";
+ ParentType deserializedObj = Deserialize<ParentType> (serializedObj);
+
+ Assert.AreEqual (deserializedObj.PolymorphicProperty.GetType ().FullName, "MonoTests.System.Runtime.Serialization.Json.BaseType");
+ Assert.AreEqual (deserializedObj.PolymorphicProperty.BaseTypeProperty, "Base");
+ }
+
+ // properly fail deserializing object with a polymorphic property (unknown derived type)
+ [ExpectedException (typeof (SerializationException))]
+ [Test]
+ public void FailDeserializingUnknownTypeProp()
+ {
+ string serializedObj = @"{""PolymorphicProperty"":{""__type"":""UnknownDerivedType:#MonoTests.System.Runtime.Serialization.Json"",""BaseTypeProperty"":""Base"",""DerivedProperty"":""Derived 1""},""Name"":""Parent2""}";
+ ParentType deserializedObj = Deserialize<ParentType> (serializedObj);
+ }
+
#endregion
}
public long CodedServerTimeUTC { get; set; }
public DateTime ServerTimeUTC { get; set; }
}
+
+ #region polymorphism test helper classes
+
+ [DataContract]
+ [KnownType (typeof (KnownDerivedType))]
+ public class ParentType
+ {
+ [DataMember]
+ public string Name { get; set; }
+
+ [DataMember]
+ public BaseType PolymorphicProperty { get; set; }
+ }
+
+ [DataContract]
+ public class BaseType
+ {
+ [DataMember]
+ public string BaseTypeProperty { get; set; }
+ }
+
+ [DataContract]
+ public class KnownDerivedType : BaseType
+ {
+ [DataMemberAttribute]
+ public string DerivedProperty { get; set; }
+ }
+
+ [DataContract]
+ public class UnknownDerivedType : BaseType
+ {
+ [DataMember]
+ public string DerivedProperty { get; set; }
+ }
+
+ #endregion
}
[DataContract]
public virtual int TotalBytes { get { NotImplemented (); return 0; } }
+#if NET_4_5
+ public virtual ReadEntityBodyMode ReadEntityBodyMode { get { NotImplemented(); return ReadEntityBodyMode.Classic; } }
+#endif
public virtual Uri Url { get { NotImplemented (); return null; } }
public virtual Uri UrlReferrer { get { NotImplemented (); return null; } }
public virtual string [] UserLanguages { get { NotImplemented (); return null; } }
+#if NET_4_5
+ public virtual void Abort ()
+ {
+ NotImplemented();
+ }
+#endif
public virtual byte [] BinaryRead (int count)
{
get { return w.UserLanguages; }
}
+#if NET_4_5
+ public void Abort ()
+ {
+ w.WorkerRequest.CloseConnection();
+ }
+#endif
+
public override byte [] BinaryRead (int count)
{
return w.BinaryRead (count);
public virtual bool SuppressContent { get { NotImplemented (); return false; } set { NotImplemented (); } }
+#if NET_4_5
+ public virtual bool SuppressFormsAuthenticationRedirect { get { NotImplemented (); return false; } set { NotImplemented (); } }
+#endif
+
public virtual bool TrySkipIisCustomErrors { get { NotImplemented (); return false; } set { NotImplemented (); } }
set { w.SuppressContent = value; }
}
+#if NET_4_5
+ public override bool SuppressFormsAuthenticationRedirect {
+ get { return w.SuppressFormsAuthenticationRedirect; }
+ set { w.SuppressFormsAuthenticationRedirect = value; }
+ }
+#endif
+
public override bool TrySkipIisCustomErrors {
get { return w.TrySkipIisCustomErrors; }
set { w.TrySkipIisCustomErrors = value; }
<Compile Include="System.Web\ProcessShutdownReason.cs" />\r
<Compile Include="System.Web\ProcessStatus.cs" />\r
<Compile Include="System.Web\QueueManager.cs" />\r
+ <Compile Include="System.Web\ReadEntityBodyMode.cs" />\r
<Compile Include="System.Web\RequestNotification.cs" />\r
<Compile Include="System.Web\RequestNotificationStatus.cs" />\r
<Compile Include="System.Web\ServerVariablesCollection.cs" />\r
static readonly char[] pathTrimChars = { '/' };
static readonly object suppressAppReloadLock = new object ();
static readonly object saveLocationsCacheLock = new object ();
+ static readonly object getSectionLock = new object ();
// See comment for the cacheLock field at top of System.Web.Caching/Cache.cs
static readonly ReaderWriterLockSlim sectionCacheLock;
cachePath = path;
}
- ConfigurationSection section = c.GetSection (sectionName);
+ ConfigurationSection section;
+ lock (getSectionLock) {
+ section = c.GetSection (sectionName);
+ }
if (section == null)
return null;
value = collection;
}
#else
- object value = SettingsMappingManager.MapSection (get_runtime_object.Invoke (section, new object [0]));
+ object value = SettingsMappingManager.MapSection (section.GetRuntimeObject ());
#endif
if (cachePath != null)
cacheKey = baseCacheKey ^ cachePath.GetHashCode ();
configurations.Remove (GetCurrentPath (ctx));
}
+#if TARGET_J2EE
readonly static MethodInfo get_runtime_object = typeof (ConfigurationSection).GetMethod ("GetRuntimeObject", BindingFlags.NonPublic | BindingFlags.Instance);
+#endif
public static object GetWebApplicationSection (string sectionName)
{
{
if (obj == null)
throw new ArgumentNullException ("obj");
- Host.RegisterObject (obj, false);
+
+ if (Host != null)
+ Host.RegisterObject (obj, false);
}
public static void RegisterVirtualPathProvider (VirtualPathProvider virtualPathProvider)
{
if (obj == null)
throw new ArgumentNullException ("obj");
- Host.UnregisterObject (obj);
+
+ if (Host != null)
+ Host.UnregisterObject (obj);
}
}
}
if (context.Response.StatusCode != 401 || context.Request.QueryString ["ReturnUrl"] != null)
return;
+#if NET_4_5
+ if (context.Response.StatusCode == 401 && context.Response.SuppressFormsAuthenticationRedirect)
+ return;
+#endif
+
string loginPage;
InitConfig (context);
#if NET_2_0
}
} catch (Exception e) {
initialization_exception = e;
+ Console.Error.WriteLine("Exception while initOnce: "+e.ToString());
+ // Once initialization_exception != null, we always respond with this exception
+ // You have to restart the HttpApplication to "unlock" it
+ Console.Error.WriteLine("Please restart your app to unlock it");
} finally {
if (mustNullContext)
context = null;
if (initialization_exception != null) {
Exception e = initialization_exception;
HttpException exc = HttpException.NewWithCode (String.Empty, e, WebEventCodes.RuntimeErrorRequestAbort);
+ context.Response.StatusCode = 500;
FinalErrorWrite (context.Response, exc.GetHtmlErrorMessage ());
PipelineDone ();
return;
set;
}
+#if NET_4_5
+ public bool SuppressFormsAuthenticationRedirect {
+ get;
+ set;
+ }
+#endif
+
public bool TrySkipIisCustomErrors {
get;
set;
StringBuilder sb = new StringBuilder ();
string [] keys = AllKeys;
for (int i = 0; i < count; i++) {
- sb.AppendFormat ("{0}={1}&", keys [i], this [keys [i]]);
+ sb.AppendFormat ("{0}={1}&", keys [i], UrlEncode (this [keys [i]]));
}
if (sb.Length > 0)
sb.Length--;
--- /dev/null
+//
+// ReadEntityBodyMode.cs
+//
+// Author: Martin Thwaites (github@my2cents.co.uk)
+//
+// Copyright (C) 2014 Martin Thwaites
+//
+// 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.
+
+namespace System.Web {
+ public enum ReadEntityBodyMode {
+ None,
+ Classic,
+ Bufferless,
+ Buffered,
+ }
+}
using MonoTests.SystemWeb.Framework;
namespace MonoTests.System.Web.Hosting {
+ public class MyRegisteredObject : IRegisteredObject {
+ public void Stop(bool immediate) {}
+ }
+
[TestFixture]
public class HostingEnvironmentTest {
[Test]
{
Assert.IsNull (HostingEnvironment.MapPath ("hola"));
}
+
+ [Test]
+ public void RegisterAndUnregisterObject ()
+ {
+ var registered = new MyRegisteredObject ();
+
+ HostingEnvironment.RegisterObject (registered);
+ HostingEnvironment.UnregisterObject (registered);
+ }
}
}
#endif
@" ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ",
};
+ [Test]
+ public void ToStringEncoding ()
+ {
+ var queryStringNameValues = HttpUtility.ParseQueryString(string.Empty);
+ queryStringNameValues.Add("ReturnUrl", @"http://localhost/login/authenticate?ReturnUrl=http://localhost/secured_area&__provider__=google");
+
+ var expected = "ReturnUrl=http%3a%2f%2flocalhost%2flogin%2fauthenticate%3fReturnUrl%3dhttp%3a%2f%2flocalhost%2fsecured_area%26__provider__%3dgoogle";
+ Assert.AreEqual (expected, queryStringNameValues.ToString());
+ }
}
}
#include net_4_0_System.Web.dll.sources
System.Web/MimeMapping.cs
+System.Web/ReadEntityBodyMode.cs
+
InitializeContext (url, context, fragment, fragType);
}
- Uri ResolveUri (string url)
- {
- return resolver == null ? null : resolver.ResolveUri (null, url);
- }
-
Stream GetStreamFromUrl (string url, out string absoluteUriString)
{
#if NET_2_1
if (url.Length == 0)
throw new ArgumentException ("url");
#endif
- Uri uri = ResolveUri (url);
+ //
+ // This needs to work even if resolver is explicitly set to null
+ //
+ var res = resolver ?? new XmlUrlResolver ();
+ var uri = res.ResolveUri (null, url);
absoluteUriString = uri != null ? uri.ToString () : String.Empty;
- return resolver == null ? null : resolver.GetEntity (uri, null, typeof (Stream)) as Stream;
+ return res.GetEntity (uri, null, typeof (Stream)) as Stream;
}
#endregion
if (valueCache != null)
return valueCache;
if (ValueBufferStart >= 0) {
-//Console.WriteLine (NodeType + " / " + ValueBuffer.Length + " / " + ValueBufferStart + " / " + ValueBufferEnd);
valueCache = Reader.valueBuffer.ToString (ValueBufferStart, ValueBufferEnd - ValueBufferStart);
return valueCache;
}
value,
false);
ati.Value = value;
+ ati.ValueTokenStartIndex = ati.ValueTokenEndIndex = currentAttributeValue;
attributeCount++;
}
get { return entity != null ? ReadState.Interactive : source.ReadState; }
}
+#if NET_4_0
+ [MonoTODO]
+ public DtdProcessing DtdProcessing { get; set; }
+#endif
+
#if !NET_4_5
public override XmlReaderSettings Settings {
get { return base.Settings; }
var xtr = new XmlTextReader (ms);
xtr.Read ();
}
+
+ [Test]
+ public void XmlDeclarationReadAttributeValue ()
+ {
+ const string input = "<?xml version=\"1.0\" encoding=\"utf-8\"?><hello />";
+ var reader = new XmlTextReader (new StringReader (input));
+ reader.WhitespaceHandling = WhitespaceHandling.All;
+ reader.Read ();
+
+ Assert.AreEqual ("1.0", reader.GetAttribute ("version"), "#0");
+ Assert.AreEqual ("utf-8", reader.GetAttribute ("encoding"), "#0-2");
+
+ Assert.IsTrue (reader.MoveToNextAttribute (), "#1");
+ Assert.AreEqual ("1.0", reader.Value, "#1-1");
+ Assert.IsTrue (reader.ReadAttributeValue (), "#2");
+ Assert.AreEqual ("1.0", reader.Value, "#3");
+ Assert.IsFalse (reader.ReadAttributeValue (), "#4");
+
+ Assert.IsTrue (reader.MoveToNextAttribute (), "#5");
+ Assert.AreEqual ("utf-8", reader.Value, "#5-1");
+ Assert.IsTrue (reader.ReadAttributeValue (), "#6");
+ Assert.AreEqual ("utf-8", reader.Value, "#7");
+ Assert.IsFalse (reader.ReadAttributeValue (), "#8");
+
+ Assert.IsFalse (reader.MoveToNextAttribute (), "#9");
+ Assert.IsFalse (reader.ReadAttributeValue (), "#10");
+ }
+
+ [Test]
+ public void XmlDeclarationReadAttributeValue2 ()
+ {
+ const string input = "<?xml version=\"1.0\" encoding=\"utf-8\"?><hello />";
+ var reader = new XmlTextReader (new StringReader (input));
+ reader.WhitespaceHandling = WhitespaceHandling.All;
+ reader.Read ();
+ Assert.IsTrue (reader.MoveToNextAttribute (), "#1a");
+ Assert.IsTrue (reader.ReadAttributeValue (), "#1b");
+ Assert.AreEqual (XmlNodeType.Text, reader.NodeType, "#1c");
+ Assert.AreEqual ("1.0", reader.Value, "#1d");
+ Assert.IsFalse (reader.ReadAttributeValue(), "#1e");
+
+ Assert.IsTrue (reader.MoveToNextAttribute(), "#2a");
+ Assert.IsTrue (reader.ReadAttributeValue(), "#2b");
+ Assert.AreEqual (XmlNodeType.Text, reader.NodeType, "#2c");
+ Assert.AreEqual ("utf-8", reader.Value, "#2d");
+ Assert.IsFalse (reader.ReadAttributeValue(), "#2e");
+
+ Assert.IsFalse (reader.MoveToNextAttribute(), "#3");
+ Assert.IsFalse (reader.ReadAttributeValue(), "#4");
+ Assert.AreEqual (XmlNodeType.Text, reader.NodeType, "#5");
+ }
}
}
int cachedRemoveId = removeId;
int itemsIn = cachedAddId - cachedRemoveId;
+ // Check our transaction id against completed stored one
+ if (isComplete.Value && cachedAddId >= completeId)
+ ThrowCompleteException ();
+
// If needed, we check and wait that the collection isn't full
- if (upperBound != -1 && itemsIn > upperBound) {
+ if (upperBound != -1 && itemsIn >= upperBound) {
if (millisecondsTimeout == 0)
return false;
continue;
}
- // Check our transaction id against completed stored one
- if (isComplete.Value && cachedAddId >= completeId)
- ThrowCompleteException ();
-
// Validate the steps we have been doing until now
if (Interlocked.CompareExchange (ref addId, cachedAddId + 1, cachedAddId) != cachedAddId)
continue;
public static int AddToAny (BlockingCollection<T>[] collections, T item)
{
- CheckArray (collections);
- int index = 0;
- foreach (var coll in collections) {
- try {
- coll.Add (item);
- return index;
- } catch {}
- index++;
- }
- return -1;
+ return AddToAny (collections, item, CancellationToken.None);
}
public static int AddToAny (BlockingCollection<T>[] collections, T item, CancellationToken cancellationToken)
{
CheckArray (collections);
- int index = 0;
- foreach (var coll in collections) {
- try {
- coll.Add (item, cancellationToken);
- return index;
- } catch {}
- index++;
+ WaitHandle[] wait_table = null;
+ while (true) {
+ for (int i = 0; i < collections.Length; ++i) {
+ if (collections [i].TryAdd (item))
+ return i;
+ }
+ cancellationToken.ThrowIfCancellationRequested ();
+ if (wait_table == null) {
+ wait_table = new WaitHandle [collections.Length + 1];
+ for (int i = 0; i < collections.Length; ++i)
+ wait_table [i] = collections [i].mreAdd.WaitHandle;
+ wait_table [collections.Length] = cancellationToken.WaitHandle;
+ }
+ WaitHandle.WaitAny (wait_table);
+ cancellationToken.ThrowIfCancellationRequested ();
}
- return -1;
}
public static int TryAddToAny (BlockingCollection<T>[] collections, T item)
public static int TakeFromAny (BlockingCollection<T>[] collections, out T item)
{
- item = default (T);
- CheckArray (collections);
- WaitHandle[] wait_table = null;
- while (true) {
- for (int i = 0; i < collections.Length; ++i) {
- if (collections [i].TryTake (out item))
- return i;
- }
- if (wait_table == null) {
- wait_table = new WaitHandle [collections.Length];
- for (int i = 0; i < collections.Length; ++i)
- wait_table [i] = collections [i].mreRemove.WaitHandle;
- }
- WaitHandle.WaitAny (wait_table);
- }
+ return TakeFromAny (collections, out item, CancellationToken.None);
}
public static int TakeFromAny (BlockingCollection<T>[] collections, out T item, CancellationToken cancellationToken)
//
using System;
-using System.Collections;
+using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
DateFormat, CultureInfo.InvariantCulture);
DateTime timeWritten = File.GetLastWriteTime (file);
int stringNums = int.Parse (tr.ReadLine ().Substring (20));
- ArrayList replacementTemp = new ArrayList ();
+ var replacementTemp = new List<string> ();
StringBuilder sb = new StringBuilder ();
while (replacementTemp.Count < stringNums) {
char c = (char) tr.Read ();
sb.Append (c);
}
}
- string [] replacementStrings = new string [replacementTemp.Count];
- replacementTemp.CopyTo (replacementStrings, 0);
+ string [] replacementStrings = replacementTemp.ToArray ();
string message = FormatMessage (source, instanceID, replacementStrings);
int eventID = EventLog.GetEventID (instanceID);
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security.Permissions;
-using System.Collections;
+using System.Collections.Generic;
using System.Security;
using System.Threading;
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private extern static int[] GetProcesses_internal();
- public static Process[] GetProcesses()
+ public static Process[] GetProcesses ()
{
int [] pids = GetProcesses_internal ();
if (pids == null)
return new Process [0];
- ArrayList proclist = new ArrayList (pids.Length);
+ var proclist = new List<Process> (pids.Length);
for (int i = 0; i < pids.Length; i++) {
try {
proclist.Add (GetProcessById (pids [i]));
}
}
- return ((Process []) proclist.ToArray (typeof (Process)));
+ return proclist.ToArray ();
}
[MonoTODO ("There is no support for retrieving process information from a remote machine")]
if (pids == null)
return new Process [0];
- ArrayList proclist = new ArrayList (pids.Length);
+ var proclist = new List<Process> (pids.Length);
for (int i = 0; i < pids.Length; i++) {
try {
Process p = GetProcessById (pids [i]);
}
}
- return ((Process []) proclist.ToArray (typeof (Process)));
+ return proclist.ToArray ();
}
[MonoTODO]
ref proc_info);
} finally {
if (proc_info.Password != IntPtr.Zero)
- Marshal.FreeBSTR (proc_info.Password);
+ Marshal.ZeroFreeBSTR (proc_info.Password);
proc_info.Password = IntPtr.Zero;
}
if (!ret) {
ref proc_info);
} finally {
if (proc_info.Password != IntPtr.Zero)
- Marshal.FreeBSTR (proc_info.Password);
+ Marshal.ZeroFreeBSTR (proc_info.Password);
proc_info.Password = IntPtr.Zero;
}
if (!ret) {
//
using System;
-using System.Collections;
+using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
string [] sources = (string []) logKey.GetValue ("Sources");
if (sources != null) {
- ArrayList temp = new ArrayList ();
+ var temp = new List<string> ();
for (int i = 0; i < sources.Length; i++)
if (sources [i] != source)
temp.Add (sources [i]);
- string [] newSources = new string [temp.Count];
- temp.CopyTo (newSources, 0);
+ string [] newSources = temp.ToArray ();
logKey.SetValue ("Sources", newSources);
}
}
// Probe for Linux-styled devices: /dev/ttyS* or /dev/ttyUSB*
//
foreach (string dev in ttys) {
- if (dev.StartsWith("/dev/ttyS") || dev.StartsWith("/dev/ttyUSB")){
+ if (dev.StartsWith("/dev/ttyS") || dev.StartsWith("/dev/ttyUSB") || dev.StartsWith("/dev/ttyACM")) {
linux_style = true;
break;
}
foreach (string dev in ttys) {
if (linux_style){
- if (dev.StartsWith("/dev/ttyS") || dev.StartsWith("/dev/ttyUSB"))
+ if (dev.StartsWith("/dev/ttyS") || dev.StartsWith("/dev/ttyUSB") || dev.StartsWith("/dev/ttyACM"))
serial_ports.Add (dev);
} else {
if (dev != "/dev/tty" && dev.StartsWith ("/dev/tty") && !dev.StartsWith ("/dev/ttyC"))
using System;
using System.Collections;
+using System.Collections.Generic;
using System.IO;
using System.Threading;
return;
/* Removed files */
- ArrayList removed = null;
+ List<string> removed = null;
foreach (string filename in data.Files.Keys) {
FileData fd = (FileData) data.Files [filename];
if (fd.NotExists) {
if (removed == null)
- removed = new ArrayList ();
+ removed = new List<string> ();
removed.Add (filename);
DispatchEvents (data.FSW, FileAction.Removed, filename);
} catch {
/* Deleted */
if (removed == null)
- removed = new ArrayList ();
+ removed = new List<string> ();
removed.Add (filename);
DispatchEvents (data.FSW, FileAction.Removed, filename);
internal SearchPattern2 Pattern {
get {
if (pattern == null) {
- pattern = new SearchPattern2 (MangledFilter);
+ if (watcher.GetType () == typeof (KeventWatcher))
+ pattern = new SearchPattern2 (MangledFilter, true); //assume we want to ignore case (OS X)
+ else
+ pattern = new SearchPattern2 (MangledFilter);
}
return pattern;
}
ErrorEvent,
RenameEvent
}
- private void RaiseEvent (Delegate ev, EventArgs arg, EventType evtype)
- {
- if (ev == null)
- return;
-
- if (synchronizingObject == null) {
- switch (evtype) {
- case EventType.RenameEvent:
- ((RenamedEventHandler)ev).BeginInvoke (this, (RenamedEventArgs) arg, null, null);
- break;
- case EventType.ErrorEvent:
- ((ErrorEventHandler)ev).BeginInvoke (this, (ErrorEventArgs) arg, null, null);
- break;
- case EventType.FileSystemEvent:
- ((FileSystemEventHandler)ev).BeginInvoke (this, (FileSystemEventArgs) arg, null, null);
- break;
- }
- return;
- }
- synchronizingObject.BeginInvoke (ev, new object [] {this, arg});
- }
-
protected void OnChanged (FileSystemEventArgs e)
{
- RaiseEvent (Changed, e, EventType.FileSystemEvent);
+ if (Changed == null)
+ return;
+
+ if (synchronizingObject == null)
+ Changed (this, e);
+ else
+ synchronizingObject.BeginInvoke (Changed, new object[] { this, e });
}
protected void OnCreated (FileSystemEventArgs e)
{
- RaiseEvent (Created, e, EventType.FileSystemEvent);
+ if (Created == null)
+ return;
+
+ if (synchronizingObject == null)
+ Created (this, e);
+ else
+ synchronizingObject.BeginInvoke (Created, new object[] { this, e });
}
protected void OnDeleted (FileSystemEventArgs e)
{
- RaiseEvent (Deleted, e, EventType.FileSystemEvent);
+ if (Deleted == null)
+ return;
+
+ if (synchronizingObject == null)
+ Deleted (this, e);
+ else
+ synchronizingObject.BeginInvoke (Deleted, new object[] { this, e });
}
- protected void OnError (ErrorEventArgs e)
+ internal void OnError (ErrorEventArgs e)
{
- RaiseEvent (Error, e, EventType.ErrorEvent);
+ if (Error == null)
+ return;
+
+ if (synchronizingObject == null)
+ Error (this, e);
+ else
+ synchronizingObject.BeginInvoke (Error, new object[] { this, e });
}
protected void OnRenamed (RenamedEventArgs e)
{
- RaiseEvent (Renamed, e, EventType.RenameEvent);
+ if (Renamed == null)
+ return;
+
+ if (synchronizingObject == null)
+ Renamed (this, e);
+ else
+ synchronizingObject.BeginInvoke (Renamed, new object[] { this, e });
}
public WaitForChangedResult WaitForChanged (WatcherChangeTypes changeType)
//
// Authors:
// Geoff Norton (gnorton@customerdna.com)
+// Cody Russell (cody@xamarin.com)
+// Alexis Christoforides (lexas@xamarin.com)
//
// (c) 2004 Geoff Norton
// Copyright 2014 Xamarin Inc
using System;
using System.Collections;
+using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
+using System.Reflection;
namespace System.IO {
VM = -11
}
+ [Flags]
enum FilterFlags : uint {
ReadPoll = EventFlags.Flag0,
ReadOutOfBand = EventFlags.Flag1,
TimerNanoSeconds = 0x00000004,
TimerAbsolute = 0x00000008,
}
-
+
+ [StructLayout(LayoutKind.Sequential)]
struct kevent : IDisposable {
- public int ident;
+ public UIntPtr ident;
public EventFilter filter;
public EventFlags flags;
public FilterFlags fflags;
- public int data;
+ public IntPtr data;
public IntPtr udata;
public void Dispose ()
if (udata != IntPtr.Zero)
Marshal.FreeHGlobal (udata);
}
+
+
}
+ [StructLayout(LayoutKind.Sequential)]
struct timespec {
- public int tv_sec;
- public int tv_usec;
+ public IntPtr tv_sec;
+ public IntPtr tv_usec;
}
- class KeventFileData {
- public FileSystemInfo fsi;
- public DateTime LastAccessTime;
- public DateTime LastWriteTime;
+ class PathData
+ {
+ public string Path;
+ public bool IsDirectory;
+ public int Fd;
+ }
- public KeventFileData(FileSystemInfo fsi, DateTime LastAccessTime, DateTime LastWriteTime) {
- this.fsi = fsi;
- this.LastAccessTime = LastAccessTime;
- this.LastWriteTime = LastWriteTime;
+ class KqueueMonitor : IDisposable
+ {
+ public int Connection
+ {
+ get { return conn; }
}
- }
- class KeventData {
- public FileSystemWatcher FSW;
- public string Directory;
- public string FileMask;
- public bool IncludeSubdirs;
- public bool Enabled;
- public Hashtable DirEntries;
- public kevent ev;
- }
+ public KqueueMonitor (FileSystemWatcher fsw)
+ {
+ this.fsw = fsw;
+ this.conn = -1;
+ }
- class KeventWatcher : IFileWatcher
- {
- static bool failed;
- static KeventWatcher instance;
- static Hashtable watches;
- static Hashtable requests;
- static Thread thread;
- static int conn;
- static bool stop;
-
- private KeventWatcher ()
+ public void Dispose ()
{
+ CleanUp ();
}
-
- // Locked by caller
- public static bool GetInstance (out IFileWatcher watcher)
+
+ public void Start ()
{
- if (failed == true) {
- watcher = null;
- return false;
- }
+ lock (stateLock) {
+ if (started)
+ return;
- if (instance != null) {
- watcher = instance;
- return true;
- }
+ conn = kqueue ();
- watches = Hashtable.Synchronized (new Hashtable ());
- requests = Hashtable.Synchronized (new Hashtable ());
- conn = kqueue();
- if (conn == -1) {
- failed = true;
- watcher = null;
- return false;
- }
+ if (conn == -1)
+ throw new IOException (String.Format (
+ "kqueue() error at init, error code = '{0}'", Marshal.GetLastWin32Error ()));
+
+ thread = new Thread (() => DoMonitor ());
+ thread.IsBackground = true;
+ thread.Start ();
- instance = new KeventWatcher ();
- watcher = instance;
- return true;
+ startedEvent.WaitOne ();
+
+ if (failedInit) {
+ thread.Join ();
+ CleanUp ();
+ throw new IOException ("Monitor thread failed while initializing.");
+ }
+ else
+ started = true;
+ }
}
-
- public void StartDispatching (FileSystemWatcher fsw)
+
+ public void Stop ()
{
- KeventData data;
- lock (this) {
- if (thread == null) {
- thread = new Thread (new ThreadStart (Monitor));
- thread.IsBackground = true;
- thread.Start ();
- }
+ lock (stateLock) {
+ if (!started)
+ return;
+
+ requestStop = true;
+ thread.Join ();
+ requestStop = false;
- data = (KeventData) watches [fsw];
+ CleanUp ();
+ started = false;
}
+ }
- if (data == null) {
- data = new KeventData ();
- data.FSW = fsw;
- data.Directory = fsw.FullPath;
- data.FileMask = fsw.MangledFilter;
- data.IncludeSubdirs = fsw.IncludeSubdirectories;
-
- data.Enabled = true;
- lock (this) {
- StartMonitoringDirectory (data);
- watches [fsw] = data;
- stop = false;
- }
- }
+ void CleanUp ()
+ {
+ if (conn != -1)
+ close (conn);
+
+ conn = -1;
+
+ foreach (int fd in fdsDict.Keys)
+ close (fd);
+
+ fdsDict.Clear ();
+ pathsDict.Clear ();
}
- static void StartMonitoringDirectory (KeventData data)
+ void DoMonitor ()
{
- DirectoryInfo dir = new DirectoryInfo (data.Directory);
- if(data.DirEntries == null) {
- data.DirEntries = new Hashtable();
- foreach (FileSystemInfo fsi in dir.GetFileSystemInfos() )
- data.DirEntries.Add(fsi.FullName, new KeventFileData(fsi, fsi.LastAccessTime, fsi.LastWriteTime));
+ Exception exc = null;
+ failedInit = false;
+
+ try {
+ Setup ();
+ } catch (Exception e) {
+ failedInit = true;
+ exc = e;
+ } finally {
+ startedEvent.Set ();
}
- int fd = open(data.Directory, 0, 0);
- kevent ev = new kevent();
- ev.udata = IntPtr.Zero;
- timespec nullts = new timespec();
- nullts.tv_sec = 0;
- nullts.tv_usec = 0;
- if (fd > 0) {
- ev.ident = fd;
- ev.filter = EventFilter.Vnode;
- ev.flags = EventFlags.Add | EventFlags.Enable | EventFlags.OneShot;
- ev.fflags = // 20 | 2 | 1 | 8;
- FilterFlags.VNodeDelete |
- FilterFlags.VNodeWrite |
- FilterFlags.VNodeAttrib |
- // The following two values are the equivalent of the original value "20", but we suspect the original author meant
- // 0x20, we will review later with some test cases
- FilterFlags.VNodeLink |
- FilterFlags.VNodeExtend;
- ev.data = 0;
- ev.udata = Marshal.StringToHGlobalAuto (data.Directory);
- kevent outev = new kevent();
- outev.udata = IntPtr.Zero;
- kevent (conn, ref ev, 1, ref outev, 0, ref nullts);
- data.ev = ev;
- requests [fd] = data;
- }
-
- if (!data.IncludeSubdirs)
+ if (failedInit) {
+ fsw.OnError (new ErrorEventArgs (exc));
return;
+ }
+ try {
+ Monitor ();
+ } catch (Exception e) {
+ exc = e;
+ } finally {
+ if (!requestStop) { // failure
+ CleanUp ();
+ started = false;
+ }
+ if (exc != null)
+ fsw.OnError (new ErrorEventArgs (exc));
+ }
}
- public void StopDispatching (FileSystemWatcher fsw)
- {
- KeventData data;
- lock (this) {
- data = (KeventData) watches [fsw];
- if (data == null)
- return;
+ void Setup ()
+ {
+ var initialFds = new List<int> ();
- StopMonitoringDirectory (data);
- watches.Remove (fsw);
- if (watches.Count == 0)
- stop = true;
+ // GetFilenameFromFd() returns the *realpath* which can be different than fsw.FullPath because symlinks.
+ // If so, introduce a fixup step.
+ int fd = open (fsw.FullPath, O_EVTONLY, 0);
+ var resolvedFullPath = GetFilenameFromFd (fd);
+ close (fd);
- if (!data.IncludeSubdirs)
- return;
+ if (resolvedFullPath != fsw.FullPath)
+ fixupPath = resolvedFullPath;
+ else
+ fixupPath = null;
+
+ Scan (fsw.FullPath, false, ref initialFds);
+ var immediate_timeout = new timespec { tv_sec = (IntPtr)0, tv_usec = (IntPtr)0 };
+ var eventBuffer = new kevent[0]; // we don't want to take any events from the queue at this point
+ var changes = CreateChangeList (ref initialFds);
+
+ int numEvents = kevent (conn, changes, changes.Length, eventBuffer, eventBuffer.Length, ref immediate_timeout);
+
+ if (numEvents == -1) {
+ var errMsg = String.Format ("kevent() error at initial event registration, error code = '{0}'", Marshal.GetLastWin32Error ());
+ throw new IOException (errMsg);
}
}
- static void StopMonitoringDirectory (KeventData data)
+ kevent[] CreateChangeList (ref List<int> FdList)
{
- close(data.ev.ident);
+ if (FdList.Count == 0)
+ return emptyEventList;
+
+ var changes = new List<kevent> ();
+ foreach (int fd in FdList) {
+ var change = new kevent {
+
+ ident = (UIntPtr)fd,
+ filter = EventFilter.Vnode,
+ flags = EventFlags.Add | EventFlags.Enable | EventFlags.Clear,
+ fflags = FilterFlags.VNodeDelete | FilterFlags.VNodeExtend |
+ FilterFlags.VNodeRename | FilterFlags.VNodeAttrib |
+ FilterFlags.VNodeLink | FilterFlags.VNodeRevoke |
+ FilterFlags.VNodeWrite,
+ data = IntPtr.Zero,
+ udata = IntPtr.Zero
+ };
+
+ changes.Add (change);
+ }
+ FdList.Clear ();
+
+ return changes.ToArray ();
}
void Monitor ()
{
-
- while (!stop) {
- kevent ev = new kevent();
- ev.udata = IntPtr.Zero;
- kevent nullev = new kevent();
- nullev.udata = IntPtr.Zero;
- timespec ts = new timespec();
- ts.tv_sec = 0;
- ts.tv_usec = 0;
- int haveEvents;
- lock (this) {
- haveEvents = kevent (conn, ref nullev, 0, ref ev, 1, ref ts);
+ var timeout = new timespec { tv_sec = (IntPtr)0, tv_usec = (IntPtr)500000000 };
+ var eventBuffer = new kevent[32];
+ var newFds = new List<int> ();
+ List<PathData> removeQueue = new List<PathData> ();
+ List<string> rescanQueue = new List<string> ();
+
+ while (!requestStop) {
+ var changes = CreateChangeList (ref newFds);
+
+ int numEvents = kevent (conn, changes, changes.Length, eventBuffer, eventBuffer.Length, ref timeout);
+
+ if (numEvents == -1) {
+ var errMsg = String.Format ("kevent() error, error code = '{0}'", Marshal.GetLastWin32Error ());
+ fsw.OnError (new ErrorEventArgs (new IOException (errMsg)));
}
- if (haveEvents > 0) {
- // Restart monitoring
- KeventData data = (KeventData) requests [ev.ident];
- StopMonitoringDirectory (data);
- StartMonitoringDirectory (data);
- ProcessEvent (ev);
- } else {
- System.Threading.Thread.Sleep (500);
+ if (numEvents == 0)
+ continue;
+
+ for (var i = 0; i < numEvents; i++) {
+ var kevt = eventBuffer [i];
+ var pathData = fdsDict [(int)kevt.ident];
+
+ if ((kevt.flags & EventFlags.Error) == EventFlags.Error) {
+ var errMsg = String.Format ("kevent() error watching path '{0}', error code = '{1}'", pathData.Path, kevt.data);
+ fsw.OnError (new ErrorEventArgs (new IOException (errMsg)));
+ continue;
+ }
+
+ if ((kevt.fflags & FilterFlags.VNodeDelete) == FilterFlags.VNodeDelete || (kevt.fflags & FilterFlags.VNodeRevoke) == FilterFlags.VNodeRevoke)
+ removeQueue.Add (pathData);
+
+ else if ((kevt.fflags & FilterFlags.VNodeWrite) == FilterFlags.VNodeWrite) {
+ if (pathData.IsDirectory)
+ rescanQueue.Add (pathData.Path);
+ else
+ PostEvent (FileAction.Modified, pathData.Path);
+ }
+
+ else if ((kevt.fflags & FilterFlags.VNodeRename) == FilterFlags.VNodeRename) {
+ var newFilename = GetFilenameFromFd (pathData.Fd);
+
+ if (newFilename.StartsWith (fsw.FullPath))
+ Rename (pathData, newFilename);
+ else //moved outside of our watched dir so stop watching
+ RemoveTree (pathData);
+ }
+
+ else if ((kevt.fflags & FilterFlags.VNodeAttrib) == FilterFlags.VNodeAttrib || (kevt.fflags & FilterFlags.VNodeExtend) == FilterFlags.VNodeExtend)
+ PostEvent (FileAction.Modified, pathData.Path);
}
+
+ removeQueue.ForEach (Remove);
+ removeQueue.Clear ();
+
+ rescanQueue.ForEach (path => {
+ Scan (path, true, ref newFds);
+ });
+ rescanQueue.Clear ();
+ }
+ }
+
+ PathData Add (string path, bool postEvents, ref List<int> fds)
+ {
+ PathData pathData;
+ pathsDict.TryGetValue (path, out pathData);
+
+ if (pathData != null)
+ return pathData;
+
+ var fd = open (path, O_EVTONLY, 0);
+
+ if (fd == -1) {
+ fsw.OnError (new ErrorEventArgs (new IOException (String.Format (
+ "open() error while attempting to process path '{0}', error code = '{1}'", path, Marshal.GetLastWin32Error ()))));
+ return null;
}
- lock (this) {
- thread = null;
- stop = false;
+ try {
+ fds.Add (fd);
+
+ var attrs = File.GetAttributes (path);
+
+ pathData = new PathData {
+ Path = path,
+ Fd = fd,
+ IsDirectory = (attrs & FileAttributes.Directory) == FileAttributes.Directory
+ };
+
+ pathsDict.Add (path, pathData);
+ fdsDict.Add (fd, pathData);
+
+ if (postEvents)
+ PostEvent (FileAction.Added, path);
+
+ return pathData;
+ } catch (Exception e) {
+ close (fd);
+ fsw.OnError (new ErrorEventArgs (e));
+ return null;
}
+
}
- void ProcessEvent (kevent ev)
+ void Remove (PathData pathData)
{
- lock (this) {
- KeventData data = (KeventData) requests [ev.ident];
- if (!data.Enabled)
- return;
+ fdsDict.Remove (pathData.Fd);
+ pathsDict.Remove (pathData.Path);
+ close (pathData.Fd);
+ PostEvent (FileAction.Removed, pathData.Path);
+ }
- FileSystemWatcher fsw;
- string filename = "";
+ void RemoveTree (PathData pathData)
+ {
+ var toRemove = new List<PathData> ();
- fsw = data.FSW;
- FileAction fa = 0;
- DirectoryInfo dir = new DirectoryInfo (data.Directory);
- FileSystemInfo changedFsi = null;
+ toRemove.Add (pathData);
- try {
- foreach (FileSystemInfo fsi in dir.GetFileSystemInfos() )
- if (data.DirEntries.ContainsKey (fsi.FullName) && (fsi is FileInfo)) {
- KeventFileData entry = (KeventFileData) data.DirEntries [fsi.FullName];
- if (entry.LastWriteTime != fsi.LastWriteTime) {
- filename = fsi.Name;
- fa = FileAction.Modified;
- data.DirEntries [fsi.FullName] = new KeventFileData(fsi, fsi.LastAccessTime, fsi.LastWriteTime);
- if (fsw.IncludeSubdirectories && fsi is DirectoryInfo) {
- data.Directory = filename;
- requests [ev.ident] = data;
- ProcessEvent(ev);
- }
- changedFsi = fsi;
- PostEvent(filename, fsw, fa, changedFsi);
- }
- }
- } catch (Exception) {
- // The file system infos were changed while we processed them
- }
- // Deleted
- try {
- bool deleteMatched = true;
- while(deleteMatched) {
- foreach (KeventFileData entry in data.DirEntries.Values) {
- if (!File.Exists (entry.fsi.FullName) && !Directory.Exists (entry.fsi.FullName)) {
- filename = entry.fsi.Name;
- fa = FileAction.Removed;
- data.DirEntries.Remove (entry.fsi.FullName);
- changedFsi = entry.fsi;
- PostEvent(filename, fsw, fa, changedFsi);
- break;
- }
- }
- deleteMatched = false;
+ if (pathData.IsDirectory) {
+ var prefix = pathData.Path + Path.DirectorySeparatorChar;
+ foreach (var path in pathsDict.Keys)
+ if (path.StartsWith (prefix)) {
+ toRemove.Add (pathsDict [path]);
}
- } catch (Exception) {
- // The file system infos were changed while we processed them
- }
- // Added
- try {
- foreach (FileSystemInfo fsi in dir.GetFileSystemInfos())
- if (!data.DirEntries.ContainsKey (fsi.FullName)) {
- changedFsi = fsi;
- filename = fsi.Name;
- fa = FileAction.Added;
- data.DirEntries [fsi.FullName] = new KeventFileData(fsi, fsi.LastAccessTime, fsi.LastWriteTime);
- PostEvent(filename, fsw, fa, changedFsi);
- }
- } catch (Exception) {
- // The file system infos were changed while we processed them
- }
-
+ }
+ toRemove.ForEach (Remove);
+ }
+ void Rename (PathData pathData, string newRoot)
+ {
+ var toRename = new List<PathData> ();
+ var oldRoot = pathData.Path;
+
+ toRename.Add (pathData);
+
+ if (pathData.IsDirectory) {
+ var prefix = oldRoot + Path.DirectorySeparatorChar;
+ foreach (var path in pathsDict.Keys)
+ if (path.StartsWith (prefix))
+ toRename.Add (pathsDict [path]);
}
+
+ toRename.ForEach ((pd) => {
+ var oldPath = pd.Path;
+ var newPath = newRoot + oldPath.Substring (oldRoot.Length);
+ pd.Path = newPath;
+ pathsDict.Remove (oldPath);
+ pathsDict.Add (newPath, pd);
+ });
+
+ PostEvent (FileAction.RenamedNewName, oldRoot, newRoot);
}
- private void PostEvent (string filename, FileSystemWatcher fsw, FileAction fa, FileSystemInfo changedFsi) {
- RenamedEventArgs renamed = null;
- if (fa == 0)
+ void Scan (string path, bool postEvents, ref List<int> fds)
+ {
+ if (requestStop)
return;
-
- if (fsw.IncludeSubdirectories && fa == FileAction.Added) {
- if (changedFsi is DirectoryInfo) {
- KeventData newdirdata = new KeventData ();
- newdirdata.FSW = fsw;
- newdirdata.Directory = changedFsi.FullName;
- newdirdata.FileMask = fsw.MangledFilter;
- newdirdata.IncludeSubdirs = fsw.IncludeSubdirectories;
-
- newdirdata.Enabled = true;
- lock (this) {
- StartMonitoringDirectory (newdirdata);
- }
+
+ var pathData = Add (path, postEvents, ref fds);
+
+ if (pathData == null)
+ return;
+
+ if (!pathData.IsDirectory)
+ return;
+
+ var dirsToProcess = new List<string> ();
+ dirsToProcess.Add (path);
+
+ while (dirsToProcess.Count > 0) {
+ var tmp = dirsToProcess [0];
+ dirsToProcess.RemoveAt (0);
+
+ var info = new DirectoryInfo (tmp);
+ FileSystemInfo[] fsInfos = null;
+ try {
+ fsInfos = info.GetFileSystemInfos ();
+
+ } catch (IOException) {
+ // this can happen if the directory has been deleted already.
+ // that's okay, just keep processing the other dirs.
+ fsInfos = new FileSystemInfo[0];
+ }
+
+ foreach (var fsi in fsInfos) {
+ if ((fsi.Attributes & FileAttributes.Directory) == FileAttributes.Directory && !fsw.IncludeSubdirectories)
+ continue;
+
+ if ((fsi.Attributes & FileAttributes.Directory) != FileAttributes.Directory && !fsw.Pattern.IsMatch (fsi.FullName))
+ continue;
+
+ var currentPathData = Add (fsi.FullName, postEvents, ref fds);
+
+ if (currentPathData != null && currentPathData.IsDirectory)
+ dirsToProcess.Add (fsi.FullName);
}
}
-
- if (!fsw.Pattern.IsMatch(filename, true))
+ }
+
+ void PostEvent (FileAction action, string path, string newPath = null)
+ {
+ RenamedEventArgs renamed = null;
+
+ if (action == 0)
return;
+ // only post events that match filter pattern. check both old and new paths for renames
+ if (!fsw.Pattern.IsMatch (path) && (newPath == null || !fsw.Pattern.IsMatch (newPath)))
+ return;
+
+ if (action == FileAction.RenamedNewName)
+ renamed = new RenamedEventArgs (WatcherChangeTypes.Renamed, "", newPath, path);
+
lock (fsw) {
- if (changedFsi.FullName.StartsWith (fsw.FullPath, StringComparison.Ordinal)) {
- if (fsw.FullPath.EndsWith ("/", StringComparison.Ordinal)) {
- filename = changedFsi.FullName.Substring (fsw.FullPath.Length);
- } else {
- filename = changedFsi.FullName.Substring (fsw.FullPath.Length + 1);
- }
- }
- fsw.DispatchEvents (fa, filename, ref renamed);
+ fsw.DispatchEvents (action, path, ref renamed);
+
if (fsw.Waiting) {
fsw.Waiting = false;
System.Threading.Monitor.PulseAll (fsw);
}
}
+ private string GetFilenameFromFd (int fd)
+ {
+ var sb = new StringBuilder (__DARWIN_MAXPATHLEN);
+
+ if (fcntl (fd, F_GETPATH, sb) != -1) {
+ if (fixupPath != null)
+ sb.Replace (fixupPath, fsw.FullPath, 0, fixupPath.Length); // see Setup()
+ return sb.ToString ();
+ } else {
+ fsw.OnError (new ErrorEventArgs (new IOException (String.Format (
+ "fcntl() error while attempting to get path for fd '{0}', error code = '{1}'", fd, Marshal.GetLastWin32Error ()))));
+ return String.Empty;
+ }
+ }
+
+ const int O_EVTONLY = 0x8000;
+ const int F_GETPATH = 50;
+ const int __DARWIN_MAXPATHLEN = 1024;
+ static readonly kevent[] emptyEventList = new System.IO.kevent[0];
+
+ FileSystemWatcher fsw;
+ int conn;
+ Thread thread;
+ volatile bool requestStop = false;
+ AutoResetEvent startedEvent = new AutoResetEvent (false);
+ bool started = false;
+ bool failedInit = false;
+ object stateLock = new object ();
+
+ readonly Dictionary<string, PathData> pathsDict = new Dictionary<string, PathData> ();
+ readonly Dictionary<int, PathData> fdsDict = new Dictionary<int, PathData> ();
+ string fixupPath = null;
+
+ [DllImport ("libc", EntryPoint="fcntl", CharSet=CharSet.Auto, SetLastError=true)]
+ static extern int fcntl (int file_names_by_descriptor, int cmd, StringBuilder sb);
+
+ [DllImport ("libc")]
+ extern static int open (string path, int flags, int mode_t);
+
[DllImport ("libc")]
- extern static int open(string path, int flags, int mode_t);
-
+ extern static int close (int fd);
+
[DllImport ("libc")]
- extern static int close(int fd);
+ extern static int kqueue ();
[DllImport ("libc")]
- extern static int kqueue();
+ extern static int kevent (int kq, [In]kevent[] ev, int nchanges, [Out]kevent[] evtlist, int nevents, [In] ref timespec time);
+ }
+
+ class KeventWatcher : IFileWatcher
+ {
+ static bool failed;
+ static KeventWatcher instance;
+ static Hashtable watches; // <FileSystemWatcher, KqueueMonitor>
+
+ private KeventWatcher ()
+ {
+ }
+
+ // Locked by caller
+ public static bool GetInstance (out IFileWatcher watcher)
+ {
+ if (failed == true) {
+ watcher = null;
+ return false;
+ }
+
+ if (instance != null) {
+ watcher = instance;
+ return true;
+ }
+
+ watches = Hashtable.Synchronized (new Hashtable ());
+ var conn = kqueue();
+ if (conn == -1) {
+ failed = true;
+ watcher = null;
+ return false;
+ }
+ close (conn);
+
+ instance = new KeventWatcher ();
+ watcher = instance;
+ return true;
+ }
+
+ public void StartDispatching (FileSystemWatcher fsw)
+ {
+ KqueueMonitor monitor;
+
+ if (watches.ContainsKey (fsw)) {
+ monitor = (KqueueMonitor)watches [fsw];
+ } else {
+ monitor = new KqueueMonitor (fsw);
+ watches.Add (fsw, monitor);
+ }
+
+ monitor.Start ();
+ }
+
+ public void StopDispatching (FileSystemWatcher fsw)
+ {
+ KqueueMonitor monitor = (KqueueMonitor)watches [fsw];
+ if (monitor == null)
+ return;
+
+ monitor.Stop ();
+ }
+
+ [DllImport ("libc")]
+ extern static int close (int fd);
[DllImport ("libc")]
- extern static int kevent(int kqueue, ref kevent ev, int nchanges, ref kevent evtlist, int nevents, ref timespec ts);
+ extern static int kqueue ();
}
}
Compile (pattern);
}
- // OSX has a retarded case-insensitive yet case-aware filesystem
+ // OSX has a case-insensitive yet case-aware filesystem
// so we need a overload in here for the Kqueue watcher
public bool IsMatch (string text, bool ignorecase)
{
bool match = String.Compare (pattern, text, ignorecase) == 0;
if (match)
return true;
-
- // This is a special case for FSW. It needs to match e.g. subdir/file.txt
- // when the pattern is "file.txt"
- int idx = text.LastIndexOf ('/');
- if (idx == -1)
- return false;
- idx++;
- if (idx == text.Length)
- return false;
-
- return (String.Compare (pattern, text.Substring (idx), ignorecase) == 0);
}
+
+ // This is a special case for FSW. It needs to match e.g. subdir/file.txt
+ // when the pattern is "file.txt"
+ var fileName = Path.GetFileName (text);
+
+ if (!hasWildcard)
+ return (String.Compare (pattern, fileName, ignorecase) == 0);
+
- return Match (ops, text, 0);
+ return Match (ops, fileName, 0);
}
public bool IsMatch (string text)
snd_pcm_hw_params_free (hw_param);
if (handle != IntPtr.Zero)
snd_pcm_close (handle);
+ sw_param = IntPtr.Zero;
+ hw_param = IntPtr.Zero;
handle = IntPtr.Zero;
}
Console.WriteLine ("failed to alloc Alsa sw param struct");
}
- if (hw_param != IntPtr.Zero)
+ if (hw_param != IntPtr.Zero) {
snd_pcm_hw_params_free (hw_param); // free hw params
- if (sw_param != IntPtr.Zero)
+ hw_param = IntPtr.Zero;
+ }
+ if (sw_param != IntPtr.Zero) {
snd_pcm_sw_params_free (sw_param); // free sw params
+ sw_param = IntPtr.Zero;
+ }
return alsa_err == 0;
}
curSocket.EndConnect (ares);
} catch (SocketException se) {
SocketError = se.SocketErrorCode;
+ } catch (ObjectDisposedException) {
+ SocketError = SocketError.OperationAborted;
} finally {
OnCompleted (this);
}
#endif
}
+#if NET_4_5
+ [MonoTODO ("Currently hardcoded to IPv4. Ideally, support v4/v6 dual-stack.")]
+ public Socket (SocketType socketType, ProtocolType protocolType)
+ : this (AddressFamily.InterNetwork, socketType, protocolType)
+ {
+ }
+#endif
+
~Socket ()
{
Dispose (false);
Assert.AreEqual (-10, t.Result, "#5");
Assert.AreEqual ("canceled", res, "#6");
}
+
+ [Test, ExpectedException (typeof(OperationCanceledException))]
+ public void BoundedAddLimit ()
+ {
+ const int elNumber = 5;
+
+ var c = new BlockingCollection <int> (elNumber);
+ var token = new CancellationTokenSource (100);
+
+ for (var i = 0; i < elNumber + 1; i++) {
+ c.Add (1, token.Token);
+ }
+ }
+
+ [Test]
+ public void AddAnyCancellable ()
+ {
+ const int elNumber = 5;
+ const int colNumber = 5;
+
+ var cols = new BlockingCollection <int> [colNumber];
+ for (var i = 0; i < colNumber; i++) {
+ cols[i] = new BlockingCollection <int> (elNumber);
+ }
+
+ var token = new CancellationTokenSource (100);
+ for (var i = 0; i < colNumber * elNumber; i++) {
+ BlockingCollection <int>.AddToAny (cols, 1, token.Token);
+ }
+
+ foreach (var col in cols) {
+ Assert.AreEqual (elNumber, col.Count);
+ }
+ }
}
}
#endif
namespace MonoTests.System.Net {
[TestFixture]
public class HttpListenerTest {
+
+ int port;
+
+ [SetUp]
+ public void SetUp () {
+ port = new Random ().Next (7777, 8000);
+ }
+
[Test]
public void DefaultProperties ()
{
[Test]
public void TwoListeners_SameAddress ()
{
+ if (!CanOpenPort (port))
+ Assert.Ignore ("port");
HttpListener listener1 = new HttpListener ();
- listener1.Prefixes.Add ("http://127.0.0.1:7777/");
+ listener1.Prefixes.Add ("http://127.0.0.1:" + port + "/");
HttpListener listener2 = new HttpListener ();
- listener2.Prefixes.Add ("http://127.0.0.1:7777/hola/");
+ listener2.Prefixes.Add ("http://127.0.0.1:" + port + "/hola/");
listener1.Start ();
listener2.Start ();
}
[ExpectedException (typeof (HttpListenerException))]
public void TwoListeners_SameURL ()
{
+ if (!CanOpenPort (port))
+ Assert.Ignore ("port");
HttpListener listener1 = new HttpListener ();
- listener1.Prefixes.Add ("http://127.0.0.1:7777/hola/");
+ listener1.Prefixes.Add ("http://127.0.0.1:" + port + "/hola/");
HttpListener listener2 = new HttpListener ();
- listener2.Prefixes.Add ("http://127.0.0.1:7777/hola/");
+ listener2.Prefixes.Add ("http://127.0.0.1:" + port + "/hola/");
listener1.Start ();
listener2.Start ();
}
[ExpectedException (typeof (HttpListenerException))]
public void MultipleSlashes ()
{
+ if (!CanOpenPort (port))
+ Assert.Ignore ("port");
HttpListener listener = new HttpListener ();
- listener.Prefixes.Add ("http://localhost:7777/hola////");
+ listener.Prefixes.Add ("http://localhost:" + port + "/hola////");
// this one throws on Start(), not when adding it.
listener.Start ();
}
[ExpectedException (typeof (HttpListenerException))]
public void PercentSign ()
{
+ if (!CanOpenPort (port))
+ Assert.Ignore ("port");
HttpListener listener = new HttpListener ();
- listener.Prefixes.Add ("http://localhost:7777/hola%3E/");
+ listener.Prefixes.Add ("http://localhost:" + port + "/hola%3E/");
// this one throws on Start(), not when adding it.
listener.Start ();
}
[Test]
public void CloseTwice ()
{
+ if (!CanOpenPort (port))
+ Assert.Ignore ("port");
HttpListener listener = new HttpListener ();
- listener.Prefixes.Add ("http://localhost:7777/hola/");
+ listener.Prefixes.Add ("http://localhost:" + port + "/hola/");
listener.Start ();
listener.Close ();
listener.Close ();
[Test]
public void StartStopStart ()
{
+ if (!CanOpenPort (port))
+ Assert.Ignore ("port");
HttpListener listener = new HttpListener ();
- listener.Prefixes.Add ("http://localhost:7777/hola/");
+ listener.Prefixes.Add ("http://localhost:" + port + "/hola/");
listener.Start ();
listener.Stop ();
listener.Start ();
[Test]
public void StartStopDispose ()
{
+ if (!CanOpenPort (port))
+ Assert.Ignore ("port");
using (HttpListener listener = new HttpListener ()){
- listener.Prefixes.Add ("http://localhost:7777/hola/");
+ listener.Prefixes.Add ("http://localhost:" + port + "/hola/");
listener.Start ();
listener.Stop ();
}
[Test]
public void AbortTwice ()
{
+ if (!CanOpenPort (port))
+ Assert.Ignore ("port");
HttpListener listener = new HttpListener ();
- listener.Prefixes.Add ("http://localhost:7777/hola/");
+ listener.Prefixes.Add ("http://localhost:" + port + "/hola/");
listener.Start ();
listener.Abort ();
listener.Abort ();
public override object [] GetCustomAttributes (bool inherit)
{
+ if (IsCreated)
+ return generic_type.GetCustomAttributes (inherit);
throw new NotSupportedException ();
}
public override object [] GetCustomAttributes (Type attributeType, bool inherit)
{
+ if (IsCreated)
+ return generic_type.GetCustomAttributes (attributeType, inherit);
throw new NotSupportedException ();
}
// don't read stream unless object is ready to use
if (disposed)
throw new ObjectDisposedException ("HashAlgorithm");
- if (inputStream == null)
- throw new ArgumentNullException ("InputStream");
byte[] buffer = new byte [4096];
int len = inputStream.Read (buffer, 0, 4096);
#region Cancel and Wait related method
- internal void CancelReal ()
+ internal void CancelReal (bool notifyParent = false)
{
Status = TaskStatus.Canceled;
wait_handle.Set ();
ProcessCompleteDelegates ();
+
+ if (notifyParent && parent != null && NotifyParentOnFinish ())
+ parent = null;
}
void HandleGenericException (Exception e)
public void Execute ()
{
if (!ContinuationStatusCheck (continuationOptions)) {
- task.CancelReal ();
+ task.CancelReal (notifyParent : true);
task.Dispose ();
return;
}
DomainUnload(this, null);
}
+ internal void DoUnhandledException (UnhandledExceptionEventArgs args) {
+ if (UnhandledException != null)
+ UnhandledException (this, args);
+ }
+
internal byte[] GetMarshalledDomainObjRef ()
{
ObjRef oref = RemotingServices.Marshal (AppDomain.CurrentDomain, null, typeof (AppDomain));
}
}
- internal unsafe void InternalSetLength (int newLength)
- {
- if (newLength > length)
- throw new ArgumentOutOfRangeException ("newLength", "newLength as to be <= length");
-
- // zero terminate, we can pass string objects directly via pinvoke
- // we also zero the rest of the string, since the new GC needs to be
- // able to handle the changing size (it will skip the 0 bytes).
- fixed (char * pStr = &start_char) {
- char *p = pStr + newLength;
- char *end = pStr + length;
- while (p < end) {
- p [0] = '\0';
- p++;
- }
- }
- length = newLength;
- }
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ internal extern void InternalSetLength (int newLength);
[ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
// When modifying it, GetCaseInsensitiveHashCode() should be modified as well.
}
[Test]
- [ExpectedException (typeof (ArgumentNullException))]
+ [ExpectedException (typeof (NullReferenceException))]
public void NullStream ()
{
Stream s = null;
}
[Test]
- [ExpectedException (typeof (ArgumentNullException))]
+ //[ExpectedException (typeof (ArgumentNullException))]
+ [ExpectedException (typeof (NullReferenceException))]
public void SignDataStreamNull ()
{
rsa = new RSACryptoServiceProvider (minKeySize);
}
}
+ int workerThreads;
+ int completionPortThreads;
Task[] tasks;
const int max = 6;
[SetUp]
public void Setup()
{
+ ThreadPool.GetMinThreads (out workerThreads, out completionPortThreads);
+ ThreadPool.SetMinThreads (1, 1);
+
tasks = new Task[max];
}
+ [TearDown]
+ public void Teardown()
+ {
+ ThreadPool.SetMinThreads (workerThreads, completionPortThreads);
+ }
+
void InitWithDelegate(Action action)
{
for (int i = 0; i < max; i++) {
public void ContinueWithChildren ()
{
ParallelTestHelper.Repeat (delegate {
- bool result = false;
+ bool result = false;
- var t = Task.Factory.StartNew (() => Task.Factory.StartNew (() => {}, TaskCreationOptions.AttachedToParent));
+ var t = Task.Factory.StartNew (() => Task.Factory.StartNew (() => {}, TaskCreationOptions.AttachedToParent));
var mre = new ManualResetEvent (false);
- t.ContinueWith (l => {
+ t.ContinueWith (l => {
result = true;
mre.Set ();
});
Assert.IsTrue (mre.WaitOne (1000), "#1");
- Assert.IsTrue (result, "#2");
+ Assert.IsTrue (result, "#2");
}, 2);
}
{
ParallelTestHelper.Repeat (delegate {
var evt = new ManualResetEventSlim ();
- var t = Task.Factory.StartNew (() => evt.Wait (5000));
+ var monitor = new object ();
+ int finished = 0;
+ var t = Task.Factory.StartNew (delegate {
+ var r = evt.Wait (5000);
+ lock (monitor) {
+ finished ++;
+ Monitor.Pulse (monitor);
+ }
+ return r;
+ });
var cntd = new CountdownEvent (2);
var cntd2 = new CountdownEvent (2);
bool r1 = false, r2 = false;
- ThreadPool.QueueUserWorkItem (delegate { cntd.Signal (); r1 = t.Wait (1000) && t.Result; cntd2.Signal (); });
- ThreadPool.QueueUserWorkItem (delegate { cntd.Signal (); r2 = t.Wait (1000) && t.Result; cntd2.Signal (); });
-
+ ThreadPool.QueueUserWorkItem (delegate {
+ cntd.Signal ();
+ r1 = t.Wait (1000) && t.Result;
+ cntd2.Signal ();
+ lock (monitor) {
+ finished ++;
+ Monitor.Pulse (monitor);
+ }
+ });
+ ThreadPool.QueueUserWorkItem (delegate {
+ cntd.Signal ();
+ r2 = t.Wait (1000) && t.Result;
+ cntd2.Signal ();
+ lock (monitor) {
+ finished ++;
+ Monitor.Pulse (monitor);
+ }
+ });
Assert.IsTrue (cntd.Wait (2000), "#1");
evt.Set ();
Assert.IsTrue (cntd2.Wait (2000), "#2");
Assert.IsTrue (r1, "r1");
Assert.IsTrue (r2, "r2");
+
+ // Wait for everything to finish to avoid overloading the tpool
+ lock (monitor) {
+ while (true) {
+ if (finished == 3)
+ break;
+ else
+ Monitor.Wait (monitor);
+ }
+ }
}, 10);
}
};
var inner = new ApplicationException ();
Thread t = new Thread (delegate () {
- Task.Factory.StartNew (() => { Console.WriteLine ("HIT!"); throw inner; });
+ Task.Factory.StartNew (() => { throw inner; });
});
t.Start ();
t.Join ();
var t = new Task (() => {
new Task (() => { r1 = true; }, TaskCreationOptions.AttachedToParent).RunSynchronously ();
Task.Factory.StartNew (() => { Thread.Sleep (100); r2 = true; }, TaskCreationOptions.AttachedToParent);
- });
+ });
t.RunSynchronously ();
Assert.IsTrue (r1);
}
}
+ [Test]
+ public void ChildTaskWithUnscheduledContinuationAttachedToParent ()
+ {
+ Task inner = null;
+ var child = Task.Factory.StartNew (() => {
+ inner = Task.Run (() => {
+ throw new ApplicationException ();
+ }).ContinueWith (task => { }, TaskContinuationOptions.AttachedToParent | TaskContinuationOptions.NotOnFaulted | TaskContinuationOptions.ExecuteSynchronously);
+ });
+
+ int counter = 0;
+ var t = child.ContinueWith (t2 => ++counter, TaskContinuationOptions.ExecuteSynchronously);
+ Assert.IsTrue (t.Wait (5000), "#1");
+ Assert.AreEqual (1, counter, "#2");
+ Assert.AreEqual (TaskStatus.RanToCompletion, child.Status, "#3");
+ Assert.AreEqual (TaskStatus.Canceled, inner.Status, "#4");
+ }
+
[Test]
[Category("NotWorking")]
public void TaskContinuationChainLeak()
<Compile Include="System\Exception.cs" />\r
<Compile Include="System\ExecutionEngineException.cs" />\r
<Compile Include="System\FieldAccessException.cs" />\r
+ <Compile Include="System\FirstChanceExceptionEventArgs.cs" />\r
<Compile Include="System\FlagsAttribute.cs" />\r
<Compile Include="System\FormatException.cs" />\r
<Compile Include="System\Funcs.cs" />\r
--- /dev/null
+// CS0677: `X.e': A volatile field cannot be of the type `E'
+// Line: 10
+
+enum E : long
+{
+}
+
+class X
+{
+ volatile E e;
+}
if (TypeSpec.IsReferenceType (MemberType))
return true;
- if (MemberType.IsEnum)
+ if (MemberType.IsPointer)
return true;
+ if (MemberType.IsEnum) {
+ switch (EnumSpec.GetUnderlyingType (MemberType).BuiltinType) {
+ case BuiltinTypeSpec.Type.SByte:
+ case BuiltinTypeSpec.Type.Byte:
+ case BuiltinTypeSpec.Type.Short:
+ case BuiltinTypeSpec.Type.UShort:
+ case BuiltinTypeSpec.Type.Int:
+ case BuiltinTypeSpec.Type.UInt:
+ return true;
+ default:
+ return false;
+ }
+ }
+
return false;
}
+// Compiler options: -unsafe
//
// Tests the valid value types for volatile fields.
//
A
}
+struct S {
+}
+
class X {
volatile byte a;
volatile sbyte b;
volatile XX dd;
volatile IntPtr ip;
volatile UIntPtr uip;
+ unsafe volatile ushort* uc;
+ unsafe volatile XX* udd;
+ unsafe volatile S* us;
public static void Main () {}
}
get { return ignoreAdded; }
}
+ static List<Regex> ignoreNew = new List<Regex> ();
+ public static List<Regex> IgnoreNew {
+ get { return ignoreNew; }
+ }
+
static List<Regex> ignoreRemoved = new List<Regex> ();
public static List<Regex> IgnoreRemoved {
get { return ignoreRemoved; }
var options = new OptionSet {
{ "h|help", "Show this help", v => showHelp = true },
{ "d|diff=", "HTML diff file out output (omit for stdout)", v => diff = v },
- { "i|ignore=", "Ignore both added and removed members whose description matches a given C# regular expression (see below).",
+ { "i|ignore=", "Ignore new, added, and removed members whose description matches a given C# regular expression (see below).",
v => {
var r = new Regex (v);
State.IgnoreAdded.Add (r);
State.IgnoreRemoved.Add (r);
+ State.IgnoreNew.Add (r);
}
},
{ "a|ignore-added=", "Ignore added members whose description matches a given C# regular expression (see below).",
{ "r|ignore-removed=", "Ignore removed members whose description matches a given C# regular expression (see below).",
v => State.IgnoreRemoved.Add (new Regex (v))
},
+ { "n|ignore-new=", "Ignore new namespaces and types whose description matches a given C# regular expression (see below).",
+ v => State.IgnoreNew.Add (new Regex (v))
+ },
{ "x|lax", "Ignore duplicate XML entries", v => State.Lax = true }
};
using System;
using System.Collections.Generic;
using System.IO;
+using System.Linq;
using System.Xml.Linq;
namespace Xamarin.ApiDiff {
public override void Added (XElement target)
{
- Output.WriteLine ("<h3>New Type {0}.{1}</h3>", State.Namespace, target.Attribute ("name").Value);
+ string name = target.Attribute ("name").Value;
+ if (State.IgnoreNew.Any (re => re.IsMatch (name)))
+ return;
+ Output.WriteLine ("<h3>New Type {0}.{1}</h3>", State.Namespace, name);
Output.WriteLine ("<pre>");
State.Indent = 0;
AddedInner (target);
using System;
using System.IO;
+using System.Linq;
using System.Xml.Linq;
namespace Xamarin.ApiDiff {
public override void Added (XElement target)
{
- Output.WriteLine ("<h2>New Namespace {0}</h2>", target.Attribute ("name").Value);
+ string name = target.Attribute ("name").Value;
+ if (State.IgnoreNew.Any (re => re.IsMatch (name)))
+ return;
+
+ Output.WriteLine ("<h2>New Namespace {0}</h2>", name);
Output.WriteLine ();
// list all new types
foreach (var addedType in target.Element ("classes").Elements ("class"))
export HOST_CC
endif
-if JIT_SUPPORTED
if !SHARED_MONO
static_libs= \
$(top_builddir)/mono/metadata/libmonoruntime-static.la \
else
runtime_lib=../mini/$(LIBMONO_LA)
endif
-else
-runtime_lib=../interpreter/libmint.la
-endif
if DISABLE_EXECUTABLES
bin_PROGRAMS =
# include <dirent.h>
#endif
#include <sys/stat.h>
+#ifdef HAVE_SYS_RESOURCE_H
+# include <sys/resource.h>
+#endif
#include <mono/io-layer/wapi.h>
#include <mono/io-layer/wapi-private.h>
g_free (_wapi_private_handles [i]);
}
+int
+wapi_getdtablesize (void)
+{
+#ifdef HAVE_GETRLIMIT
+ struct rlimit limit;
+ int res;
+
+ res = getrlimit (RLIMIT_NOFILE, &limit);
+ g_assert (res == 0);
+ return limit.rlim_cur;
+#else
+ return getdtablesize ();
+#endif
+}
+
/*
* wapi_init:
*
{
g_assert ((sizeof (handle_ops) / sizeof (handle_ops[0]))
== WAPI_HANDLE_COUNT);
-
- _wapi_fd_reserve = getdtablesize();
+
+ _wapi_fd_reserve = wapi_getdtablesize ();
/* This is needed by the code in _wapi_handle_new_internal */
_wapi_fd_reserve = (_wapi_fd_reserve + (_WAPI_HANDLE_INITIAL_COUNT - 1)) & ~(_WAPI_HANDLE_INITIAL_COUNT - 1);
_wapi_global_signal_cond = &_WAPI_PRIVATE_HANDLES (GPOINTER_TO_UINT (_wapi_global_signal_handle)).signal_cond;
_wapi_global_signal_mutex = &_WAPI_PRIVATE_HANDLES (GPOINTER_TO_UINT (_wapi_global_signal_handle)).signal_mutex;
+ wapi_processes_init ();
/* Using g_atexit here instead of an explicit function call in
* a cleanup routine lets us cope when a third-party library
}
}
- for (i = 0; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
- struct _WapiHandleShared *shared;
- struct _WapiHandle_process *process_handle;
-
- shared = &_wapi_shared_layout->handles[i];
-
- if (shared->type == WAPI_HANDLE_PROCESS) {
- DIR *fd_dir;
- struct dirent *fd_entry;
- char subdir[_POSIX_PATH_MAX];
-
- process_handle = &shared->u.process;
- pid = process_handle->id;
-
- /* Look in /proc/<pid>/fd/ but ignore
- * /proc/<our pid>/fd/<fd>, as we have the
- * file open too
- */
- g_snprintf (subdir, _POSIX_PATH_MAX, "/proc/%d/fd",
- pid);
-
- fd_dir = opendir (subdir);
- if (fd_dir == NULL) {
- continue;
- }
-
- DEBUG ("%s: Looking in %s", __func__, subdir);
-
- proc_fds = TRUE;
-
- while ((fd_entry = readdir (fd_dir)) != NULL) {
- char path[_POSIX_PATH_MAX];
- struct stat link_stat;
-
- if (!strcmp (fd_entry->d_name, ".") ||
- !strcmp (fd_entry->d_name, "..") ||
- (pid == self &&
- fd == atoi (fd_entry->d_name))) {
- continue;
- }
-
- g_snprintf (path, _POSIX_PATH_MAX,
- "/proc/%d/fd/%s", pid,
- fd_entry->d_name);
-
- stat (path, &link_stat);
- if (link_stat.st_dev == share_info->device &&
- link_stat.st_ino == share_info->inode) {
- DEBUG ("%s: Found it at %s",
- __func__, path);
-
- found = TRUE;
- }
- }
-
- closedir (fd_dir);
- }
- }
-
if (proc_fds == FALSE) {
_wapi_handle_check_share_by_pid (share_info);
} else if (found == FALSE) {
extern void wapi_init (void);
extern void wapi_cleanup (void);
+int wapi_getdtablesize (void);
+
G_END_DECLS
#endif /* _WAPI_HANDLES_H_ */
/* There doesn't seem to be a defined symbol for this */
#define _WAPI_PROCESS_CURRENT (gpointer)0xFFFFFFFF
+/*
+ * Handles > _WAPI_PROCESS_UNHANDLED are pseudo handles which represent processes
+ * not started by the runtime.
+ */
/* This marks a system process that we don't have a handle on */
/* FIXME: Cope with PIDs > sizeof guint */
#define _WAPI_PROCESS_UNHANDLED (1 << (8*sizeof(pid_t)-1))
#define _WAPI_PROCESS_UNHANDLED_PID_MASK (-1 & ~_WAPI_PROCESS_UNHANDLED)
+#define WAPI_IS_PSEUDO_PROCESS_HANDLE(handle) ((GPOINTER_TO_UINT(handle) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED)
+#define WAPI_PID_TO_HANDLE(pid) GINT_TO_POINTER (_WAPI_PROCESS_UNHANDLED + (pid))
+#define WAPI_HANDLE_TO_PID(handle) (GPOINTER_TO_UINT ((handle)) - _WAPI_PROCESS_UNHANDLED)
+void wapi_processes_init (void);
extern gpointer _wapi_process_duplicate (void);
extern void wapi_processes_cleanup (void);
extern struct _WapiHandleOps _wapi_process_ops;
-#define _WAPI_PROC_NAME_MAX_LEN _POSIX_PATH_MAX
-
/*
* MonoProcess describes processes we create.
* It contains a semaphore that can be waited on in order to wait
gint32 handle_count; /* the number of handles to this mono_process instance */
/* we keep a ref to the creating _WapiHandle_process handle until
* the process has exited, so that the information there isn't lost.
- * If we put the information there in this structure, it won't be
- * available to other processes when using shared handles. */
+ */
gpointer handle;
struct MonoProcess *next;
};
/*
* _WapiHandle_process is a structure containing all the required information
* for process handling.
- * The mono_process field is only present if this process has created
- * the corresponding process.
*/
struct _WapiHandle_process
{
gpointer main_thread;
WapiFileTime create_time;
WapiFileTime exit_time;
- gchar proc_name[_WAPI_PROC_NAME_MAX_LEN];
+ char *proc_name;
size_t min_working_set;
size_t max_working_set;
gboolean exited;
- pid_t self; /* mono_process is shared among processes, but only usable in the process that created it */
struct MonoProcess *mono_process;
};
+typedef struct _WapiHandle_process WapiHandle_process;
+
#endif /* _WAPI_PROCESS_PRIVATE_H_ */
* arm-apple-darwin9. We'll manually define the symbol on Apple as it does
* in fact exist on all implementations (so far)
*/
-gchar ***_NSGetEnviron(void);
+char ***_NSGetEnviron(void);
#define environ (*_NSGetEnviron())
#else
extern char **environ;
static mono_mutex_t mono_processes_mutex;
static void mono_processes_cleanup (void);
-static mono_once_t process_current_once=MONO_ONCE_INIT;
-static gpointer current_process=NULL;
+static gpointer current_process;
static char *cli_launcher;
-static mono_once_t process_ops_once=MONO_ONCE_INIT;
-
-static void process_ops_init (void)
+static WapiHandle_process *
+lookup_process_handle (gpointer handle)
{
- _wapi_handle_register_capabilities (WAPI_HANDLE_PROCESS,
- WAPI_HANDLE_CAP_WAIT |
- WAPI_HANDLE_CAP_SPECIAL_WAIT);
-}
+ WapiHandle_process *process_data;
+ gboolean ret;
+ ret = _wapi_lookup_handle (handle, WAPI_HANDLE_PROCESS,
+ (gpointer *)&process_data);
+ if (!ret)
+ return NULL;
+ return process_data;
+}
/* Check if a pid is valid - i.e. if a process exists with this pid. */
-static gboolean is_pid_valid (pid_t pid)
+static gboolean
+is_pid_valid (pid_t pid)
{
gboolean result = FALSE;
if (get_team_info ((team_id)pid, &teamInfo) == B_OK)
result = TRUE;
#else
- gchar *dir = g_strdup_printf ("/proc/%d", pid);
+ char *dir = g_strdup_printf ("/proc/%d", pid);
if (!access (dir, F_OK))
result = TRUE;
g_free (dir);
return result;
}
-static void process_set_defaults (struct _WapiHandle_process *process_handle)
+static void
+process_set_defaults (WapiHandle_process *process_handle)
{
/* These seem to be the defaults on w2k */
process_handle->min_working_set = 204800;
return ret;
}
-#ifdef PLATFORM_MACOSX
-
-/* 0 = no detection; -1 = not 10.5 or higher; 1 = 10.5 or higher */
-static int osx_10_5_or_higher;
-
-static void
-detect_osx_10_5_or_higher (void)
-{
- struct utsname u;
- char *p;
- int v;
-
- if (uname (&u) != 0){
- osx_10_5_or_higher = 1;
- return;
- }
-
- p = u.release;
- v = atoi (p);
-
- if (v < 9)
- osx_10_5_or_higher = -1;
- else
- osx_10_5_or_higher = 1;
-}
-
-static gboolean
-is_macos_10_5_or_higher (void)
-{
- if (osx_10_5_or_higher == 0)
- detect_osx_10_5_or_higher ();
-
- return (osx_10_5_or_higher == 1);
-}
-#endif
-
static const gunichar2 utf16_space_bytes [2] = { 0x20, 0 };
static const gunichar2 *utf16_space = utf16_space_bytes;
static const gunichar2 utf16_quote_bytes [2] = { 0x22, 0 };
void
print_utf16 (gunichar2 *str)
{
- gchar *res;
+ char *res;
res = g_utf16_to_utf8 (str, -1, NULL, NULL, NULL);
g_print ("%s\n", res);
#endif
/* Implemented as just a wrapper around CreateProcess () */
-gboolean ShellExecuteEx (WapiShellExecuteInfo *sei)
+gboolean
+ShellExecuteEx (WapiShellExecuteInfo *sei)
{
gboolean ret;
WapiProcessInformation process_info;
* that
*/
SetLastError (ERROR_INVALID_PARAMETER);
- return (FALSE);
+ return FALSE;
}
- if (sei->lpFile == NULL) {
+ if (sei->lpFile == NULL)
/* w2k returns TRUE for this, for some reason. */
- return (TRUE);
- }
+ return TRUE;
/* Put both executable and parameters into the second argument
* to CreateProcess (), so it searches $PATH. The conversion
* g_strdup_printf () equivalent for gunichar2 :-(
*/
args = utf16_concat (utf16_quote, sei->lpFile, utf16_quote, sei->lpParameters == NULL ? NULL : utf16_space, sei->lpParameters, NULL);
- if (args == NULL){
+ if (args == NULL) {
SetLastError (ERROR_INVALID_DATA);
- return (FALSE);
+ return FALSE;
}
ret = CreateProcess (NULL, args, NULL, NULL, TRUE,
CREATE_UNICODE_ENVIRONMENT, NULL,
handler = g_find_program_in_path ("kfmclient");
if (handler == NULL){
handler_utf16 = (gunichar2 *) -1;
- return (FALSE);
+ return FALSE;
} else {
/* kfmclient needs exec argument */
char *old = handler;
sei->lpFile, utf16_quote,
sei->lpParameters == NULL ? NULL : utf16_space,
sei->lpParameters, NULL);
- if (args == NULL){
+ if (args == NULL) {
SetLastError (ERROR_INVALID_DATA);
return FALSE;
}
CREATE_UNICODE_ENVIRONMENT, NULL,
sei->lpDirectory, NULL, &process_info);
g_free (args);
- if (!ret){
+ if (!ret) {
if (GetLastError () != ERROR_OUTOFMEMORY)
SetLastError (ERROR_INVALID_DATA);
return FALSE;
process_info.hProcess = NULL;
}
- if (sei->fMask & SEE_MASK_NOCLOSEPROCESS) {
+ if (sei->fMask & SEE_MASK_NOCLOSEPROCESS)
sei->hProcess = process_info.hProcess;
- } else {
+ else
CloseHandle (process_info.hProcess);
- }
- return (ret);
+ return ret;
}
static gboolean
-is_managed_binary (const gchar *filename)
+is_managed_binary (const char *filename)
{
int original_errno = errno;
#if defined(HAVE_LARGE_FILE_SUPPORT) && defined(O_LARGEFILE)
return managed;
}
-gboolean CreateProcessWithLogonW (const gunichar2 *username,
- const gunichar2 *domain,
- const gunichar2 *password,
- const guint32 logonFlags,
- const gunichar2 *appname,
- const gunichar2 *cmdline,
- guint32 create_flags,
- gpointer env,
- const gunichar2 *cwd,
- WapiStartupInfo *startup,
- WapiProcessInformation *process_info)
+gboolean
+CreateProcessWithLogonW (const gunichar2 *username,
+ const gunichar2 *domain,
+ const gunichar2 *password,
+ const guint32 logonFlags,
+ const gunichar2 *appname,
+ const gunichar2 *cmdline,
+ guint32 create_flags,
+ gpointer env,
+ const gunichar2 *cwd,
+ WapiStartupInfo *startup,
+ WapiProcessInformation *process_info)
{
/* FIXME: use user information */
return CreateProcess (appname, cmdline, NULL, NULL, FALSE, create_flags, env, cwd, startup, process_info);
}
static void
-switchDirectorySeparators(gchar *path)
+switch_dir_separators (char *path)
{
size_t i, pathLength = strlen(path);
/* Turn all the slashes round the right way, except for \' */
/* There are probably other characters that need to be excluded as well. */
- for (i = 0; i < pathLength; i++)
- {
- if (path[i] == '\\' && i < pathLength - 1 && path[i+1] != '\'' ) {
+ for (i = 0; i < pathLength; i++) {
+ if (path[i] == '\\' && i < pathLength - 1 && path[i+1] != '\'' )
path[i] = '/';
- }
}
}
WapiStartupInfo *startup,
WapiProcessInformation *process_info)
{
- gchar *cmd=NULL, *prog = NULL, *full_prog = NULL, *args = NULL, *args_after_prog = NULL, *dir = NULL, **env_strings = NULL, **argv = NULL;
+ 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;
gboolean ret = FALSE;
gpointer handle;
- struct _WapiHandle_process process_handle = {0}, *process_handle_data;
+ WapiHandle_process process_handle = {0}, *process_handle_data;
GError *gerr = NULL;
int in_fd, out_fd, err_fd;
pid_t pid;
int dummy;
struct MonoProcess *mono_process;
gboolean fork_failed = FALSE;
-
- mono_once (&process_ops_once, process_ops_init);
+
mono_once (&process_sig_chld_once, process_add_sigchld_handler);
-
+
/* appname and cmdline specify the executable and its args:
*
* If appname is not NULL, it is the name of the executable.
goto free_strings;
}
- switchDirectorySeparators(cmd);
+ switch_dir_separators(cmd);
}
if (cmdline != NULL) {
}
/* Turn all the slashes round the right way */
- switchDirectorySeparators(dir);
+ switch_dir_separators(dir);
}
/* We can't put off locating the executable any longer :-( */
if (cmd != NULL) {
- gchar *unquoted;
+ char *unquoted;
if (g_ascii_isalpha (cmd[0]) && (cmd[1] == ':')) {
/* Strip off the drive letter. I can't
* believe that CP/M holdover is still
args_after_prog = args;
} else {
- gchar *token = NULL;
+ char *token = NULL;
char quote;
/* Dig out the first token from args, taking quotation
/* Turn all the slashes round the right way. Only for
* the prg. name
*/
- switchDirectorySeparators(token);
+ switch_dir_separators(token);
if (g_ascii_isalpha (token[0]) && (token[1] == ':')) {
/* Strip off the drive letter. I can't
SetLastError (ERROR_FILE_NOT_FOUND);
goto free_strings;
}
-
} else {
char *curdir = g_get_current_dir ();
}
if (args_after_prog != NULL && *args_after_prog) {
- gchar *qprog;
+ char *qprog;
qprog = g_shell_quote (prog);
full_prog = g_strconcat (qprog, " ", args_after_prog, NULL);
err_fd = GPOINTER_TO_UINT (GetStdHandle (STD_ERROR_HANDLE));
}
- g_strlcpy (process_handle.proc_name, prog,
- _WAPI_PROC_NAME_MAX_LEN - 1);
+ process_handle.proc_name = g_strdup (prog);
process_set_defaults (&process_handle);
* environment variables in the new process. Otherwise the
* new process inherits the same environment.
*/
- if (new_environ != NULL) {
+ if (new_environ) {
gunichar2 *new_environp;
/* Count the number of strings */
/* +2: one for the process handle value, and the last
* one is NULL
*/
- env_strings = g_new0 (gchar *, env_count + 2);
+ env_strings = g_new0 (char *, env_count + 2);
/* Copy each environ string into 'strings' turning it
* into utf8 (or the requested encoding) at the same
}
}
} else {
- for (i = 0; environ[i] != NULL; i++) {
+ for (i = 0; environ[i] != NULL; i++)
env_count++;
- }
/* +2: one for the process handle value, and the last
* one is NULL
*/
- env_strings = g_new0 (gchar *, env_count + 2);
+ env_strings = g_new0 (char *, env_count + 2);
/* Copy each environ string into 'strings' turning it
* into utf8 (or the requested encoding) at the same
env_count++;
}
}
- /* pass process handle info to the child, so it doesn't have
- * to do an expensive search over the whole list
- */
- if (env_strings != NULL) {
- struct _WapiHandleUnshared *handle_data;
- struct _WapiHandle_shared_ref *ref;
-
- handle_data = &_WAPI_PRIVATE_HANDLES(GPOINTER_TO_UINT(handle));
- ref = &handle_data->u.shared;
-
- env_strings[env_count] = g_strdup_printf ("_WAPI_PROCESS_HANDLE_OFFSET=%d", ref->offset);
- }
/* Create a pipe to make sure the child doesn't exit before
* we can add the process to the linked list of mono_processes */
}
/* Close all file descriptors */
- for (i = getdtablesize () - 1; i > 2; i--) {
+ for (i = wapi_getdtablesize () - 1; i > 2; i--)
close (i);
- }
#ifdef DEBUG_ENABLED
DEBUG ("%s: exec()ing [%s] in dir [%s]", __func__, cmd,
- dir==NULL?".":dir);
- for (i = 0; argv[i] != NULL; i++) {
+ dir == NULL?".":dir);
+ for (i = 0; argv[i] != NULL; i++)
g_message ("arg %d: [%s]", i, argv[i]);
- }
- for (i = 0; env_strings[i] != NULL; i++) {
+ for (i = 0; env_strings[i] != NULL; i++)
g_message ("env %d: [%s]", i, env_strings[i]);
- }
#endif
/* set cwd */
}
/* parent */
- ret = _wapi_lookup_handle (handle, WAPI_HANDLE_PROCESS,
- (gpointer *)&process_handle_data);
- if (ret == FALSE) {
+ process_handle_data = lookup_process_handle (handle);
+ if (!process_handle_data) {
g_warning ("%s: error looking up process handle %p", __func__,
handle);
_wapi_handle_unref (handle);
_wapi_handle_ref (handle);
mono_process->handle = handle;
- process_handle_data->self = _wapi_getpid ();
process_handle_data->mono_process = mono_process;
mono_mutex_lock (&mono_processes_mutex);
}
free_strings:
- if (cmd != NULL) {
+ if (cmd)
g_free (cmd);
- }
- if (full_prog != NULL) {
+ if (full_prog)
g_free (full_prog);
- }
- if (prog != NULL) {
+ if (prog)
g_free (prog);
- }
- if (args != NULL) {
+ if (args)
g_free (args);
- }
- if (dir != NULL) {
+ if (dir)
g_free (dir);
- }
- if(env_strings != NULL) {
+ if (env_strings)
g_strfreev (env_strings);
- }
- if (argv != NULL) {
+ if (argv)
g_strfreev (argv);
- }
DEBUG ("%s: returning handle %p for pid %d", __func__, handle,
pid);
/* Check if something needs to be cleaned up. */
mono_processes_cleanup ();
- return(ret);
+ return ret;
}
-static void process_set_name (struct _WapiHandle_process *process_handle)
+static void
+process_set_name (WapiHandle_process *process_handle)
{
- gchar *progname, *utf8_progname, *slash;
+ char *progname, *utf8_progname, *slash;
- progname=g_get_prgname ();
- utf8_progname=mono_utf8_from_external (progname);
+ progname = g_get_prgname ();
+ utf8_progname = mono_utf8_from_external (progname);
DEBUG ("%s: using [%s] as prog name", __func__, progname);
- if(utf8_progname!=NULL) {
- slash=strrchr (utf8_progname, '/');
- if(slash!=NULL) {
- g_strlcpy (process_handle->proc_name, slash+1,
- _WAPI_PROC_NAME_MAX_LEN - 1);
- } else {
- g_strlcpy (process_handle->proc_name, utf8_progname,
- _WAPI_PROC_NAME_MAX_LEN - 1);
- }
-
+ if (utf8_progname) {
+ slash = strrchr (utf8_progname, '/');
+ if (slash)
+ process_handle->proc_name = g_strdup (slash+1);
+ else
+ process_handle->proc_name = g_strdup (utf8_progname);
g_free (utf8_progname);
}
}
-extern void _wapi_time_t_to_filetime (time_t timeval, WapiFileTime *filetime);
-
-#if !GLIB_CHECK_VERSION (2,4,0)
-#define g_setenv(a,b,c) setenv(a,b,c)
-#define g_unsetenv(a) unsetenv(a)
-#endif
-
-static void process_set_current (void)
+void
+wapi_processes_init (void)
{
pid_t pid = _wapi_getpid ();
- const char *handle_env;
- struct _WapiHandle_process process_handle = {0};
-
- mono_once (&process_ops_once, process_ops_init);
-
- handle_env = g_getenv ("_WAPI_PROCESS_HANDLE_OFFSET");
- g_unsetenv ("_WAPI_PROCESS_HANDLE_OFFSET");
-
- if (handle_env != NULL) {
- struct _WapiHandle_process *process_handlep;
- gchar *procname = NULL;
- gboolean ok;
-
- current_process = _wapi_handle_new_from_offset (WAPI_HANDLE_PROCESS, atoi (handle_env), TRUE);
-
- DEBUG ("%s: Found my process handle: %p (offset %d 0x%x)",
- __func__, current_process, atoi (handle_env),
- atoi (handle_env));
-
- ok = _wapi_lookup_handle (current_process, WAPI_HANDLE_PROCESS,
- (gpointer *)&process_handlep);
- if (ok) {
- /* This test will probably break on linuxthreads, but
- * that should be ancient history on all distros we
- * care about by now
- */
- if (process_handlep->id == pid) {
- procname = process_handlep->proc_name;
- if (!strcmp (procname, "mono")) {
- /* Set a better process name */
- DEBUG ("%s: Setting better process name", __func__);
-
- process_set_name (process_handlep);
- } else {
- DEBUG ("%s: Leaving process name: %s", __func__, procname);
- }
-
- return;
- }
-
- /* Wrong pid, so drop this handle and fall through to
- * create a new one
- */
- _wapi_handle_unref (current_process);
- }
- }
-
- /* We get here if the handle wasn't specified in the
- * environment, or if the process ID was wrong, or if the
- * handle lookup failed (eg if the parent process forked and
- * quit immediately, and deleted the shared data before the
- * child got a chance to attach it.)
- */
-
- DEBUG ("%s: Need to create my own process handle", __func__);
+ WapiHandle_process process_handle = {0};
+ _wapi_handle_register_capabilities (WAPI_HANDLE_PROCESS,
+ WAPI_HANDLE_CAP_WAIT |
+ WAPI_HANDLE_CAP_SPECIAL_WAIT);
+
process_handle.id = pid;
process_set_defaults (&process_handle);
current_process = _wapi_handle_new (WAPI_HANDLE_PROCESS,
&process_handle);
- if (current_process == _WAPI_HANDLE_INVALID) {
- g_warning ("%s: error creating process handle", __func__);
- return;
- }
+ g_assert (current_process);
}
-gpointer _wapi_process_duplicate ()
+gpointer
+_wapi_process_duplicate (void)
{
- mono_once (&process_current_once, process_set_current);
-
_wapi_handle_ref (current_process);
- return(current_process);
+ return current_process;
}
/* Returns a pseudo handle that doesn't need to be closed afterwards */
-gpointer GetCurrentProcess (void)
+gpointer
+GetCurrentProcess (void)
{
- mono_once (&process_current_once, process_set_current);
-
- return(_WAPI_PROCESS_CURRENT);
+ return _WAPI_PROCESS_CURRENT;
}
-guint32 GetProcessId (gpointer handle)
+guint32
+GetProcessId (gpointer handle)
{
- struct _WapiHandle_process *process_handle;
- gboolean ok;
+ WapiHandle_process *process_handle;
- if ((GPOINTER_TO_UINT (handle) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
+ if (WAPI_IS_PSEUDO_PROCESS_HANDLE (handle))
/* This is a pseudo handle */
- return(GPOINTER_TO_UINT (handle) & _WAPI_PROCESS_UNHANDLED_PID_MASK);
- }
+ return WAPI_HANDLE_TO_PID (handle);
- ok = _wapi_lookup_handle (handle, WAPI_HANDLE_PROCESS,
- (gpointer *)&process_handle);
- if (ok == FALSE) {
+ process_handle = lookup_process_handle (handle);
+ if (!process_handle) {
SetLastError (ERROR_INVALID_HANDLE);
- return (0);
+ return 0;
}
- return (process_handle->id);
+ return process_handle->id;
}
-guint32 GetCurrentProcessId (void)
+static gboolean
+process_open_compare (gpointer handle, gpointer user_data)
{
- mono_once (&process_current_once, process_set_current);
-
- return (GetProcessId (current_process));
-}
+ pid_t wanted_pid;
+ WapiHandle_process *process_handle;
+ pid_t checking_pid;
-/* Returns the process id as a convenience to the functions that call this */
-static pid_t signal_process_if_gone (gpointer handle)
-{
- struct _WapiHandle_process *process_handle;
- gboolean ok;
+ g_assert (!WAPI_IS_PSEUDO_PROCESS_HANDLE (handle));
- g_assert ((GPOINTER_TO_UINT (handle) & _WAPI_PROCESS_UNHANDLED) != _WAPI_PROCESS_UNHANDLED);
-
- /* Make sure the process is signalled if it has exited - if
- * the parent process didn't wait for it then it won't be
- */
- ok = _wapi_lookup_handle (handle, WAPI_HANDLE_PROCESS,
- (gpointer *)&process_handle);
- if (ok == FALSE) {
- /* It's possible that the handle has vanished during
- * the _wapi_search_handle before it gets here, so
- * don't spam the console with warnings.
- */
-/* g_warning ("%s: error looking up process handle %p",
- __func__, handle);*/
-
- return (0);
- }
+ process_handle = lookup_process_handle (handle);
+ g_assert (process_handle);
DEBUG ("%s: looking at process %d", __func__, process_handle->id);
- if (kill (process_handle->id, 0) == -1 &&
- (errno == ESRCH ||
- errno == EPERM)) {
- /* The process is dead, (EPERM tells us a new process
- * has that ID, but as it's owned by someone else it
- * can't be the one listed in our shared memory file)
- */
- _wapi_shared_handle_set_signal_state (handle, TRUE);
- }
-
- return (process_handle->id);
-}
-
-#ifdef UNUSED_CODE
-static gboolean process_enum (gpointer handle, gpointer user_data)
-{
- GArray *processes=user_data;
- pid_t pid = signal_process_if_gone (handle);
- int i;
-
- if (pid == 0) {
- return (FALSE);
- }
-
- /* Ignore processes that have already exited (ie they are signalled) */
- if (_wapi_handle_issignalled (handle) == FALSE) {
- DEBUG ("%s: process %d added to array", __func__, pid);
-
- /* This ensures that duplicates aren't returned (see
- * the comment above _wapi_search_handle () for why
- * it's needed
- */
- for (i = 0; i < processes->len; i++) {
- if (g_array_index (processes, pid_t, i) == pid) {
- /* We've already got this one, return
- * FALSE to keep searching
- */
- return (FALSE);
- }
- }
-
- g_array_append_val (processes, pid);
- }
-
- /* Return false to keep searching */
- return(FALSE);
-}
-#endif /* UNUSED_CODE */
-
-#if defined(PLATFORM_MACOSX) || defined(__OpenBSD__)
-
-gboolean EnumProcesses (guint32 *pids, guint32 len, guint32 *needed)
-{
- guint32 count, fit, i, j;
- gint32 err;
- gboolean done;
- size_t proclength, size;
-#if defined(__OpenBSD__)
- struct kinfo_proc *result;
- int name[6];
- name[0] = CTL_KERN;
- name[1] = KERN_PROC;
- name[2] = KERN_PROC_ALL;
- name[3] = 0;
- name[4] = sizeof(struct kinfo_proc);
- name[5] = 0;
-#else
- struct kinfo_proc *result;
- static const int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
-#endif
-
- mono_once (&process_current_once, process_set_current);
-
- result = NULL;
- done = FALSE;
-
- do {
- proclength = 0;
-#if defined(__OpenBSD__)
- size = (sizeof(name) / sizeof(*name));
-#else
- size = (sizeof(name) / sizeof(*name)) - 1;
-#endif
- err = sysctl ((int *)name, size, NULL, &proclength, NULL, 0);
-
- if (err == 0) {
- result = malloc (proclength);
-
- if (result == NULL)
- return FALSE;
+ checking_pid = process_handle->id;
-#if defined(__OpenBSD__)
- name[5] = (int)(proclength / sizeof(struct kinfo_proc));
-#endif
-
- err = sysctl ((int *) name, size, result, &proclength, NULL, 0);
-
- if (err == 0)
- done = TRUE;
- else {
- free (result);
- result = NULL;
- }
- }
- } while (err == 0 && !done);
-
- if (err != 0) {
- if (result != NULL) {
- free (result);
- result = NULL;
- }
- return(FALSE);
- }
-
- count = proclength / sizeof(struct kinfo_proc);
-
- fit = len / sizeof(guint32);
- for (i = 0, j = 0; j< fit && i < count; i++) {
-#if defined(__OpenBSD__)
- pids [j++] = result [i].p_pid;
-#else
- if (result[i].kp_proc.p_pid > 0) /* Pid 0 not supported */
- pids [j++] = result [i].kp_proc.p_pid;
-#endif
- }
- free (result);
- result = NULL;
- *needed = j * sizeof(guint32);
-
- return(TRUE);
-}
-#elif defined(__HAIKU__)
-
-gboolean EnumProcesses (guint32 *pids, guint32 len, guint32 *needed)
-{
- guint32 fit, i = 0;
- int32 cookie = 0;
- team_info teamInfo;
-
- mono_once (&process_current_once, process_set_current);
-
- fit = len / sizeof (guint32);
- while (get_next_team_info (&cookie, &teamInfo) == B_OK && i < fit) {
- pids [i++] = teamInfo.team;
- }
- *needed = i * sizeof (guint32);
-
- return TRUE;
-}
-#else
-gboolean EnumProcesses (guint32 *pids, guint32 len, guint32 *needed)
-{
- guint32 fit, i;
- DIR *dir;
- struct dirent *entry;
-
- mono_once (&process_current_once, process_set_current);
-
- dir = opendir ("/proc");
- if (dir == NULL) {
- return(FALSE);
- }
-
- i = 0;
- fit = len / sizeof (guint32);
- while(i < fit && (entry = readdir (dir)) != NULL) {
- pid_t pid;
- char *endptr;
-
- if (!isdigit (entry->d_name[0]))
- continue;
-
- pid = (pid_t) strtol (entry->d_name, &endptr, 10);
- if (*endptr == '\0')
- pids [i++] = (guint32) pid;
- }
- closedir (dir);
- *needed = i * sizeof(guint32);
-
- return(TRUE);
-}
-#endif
-
-static gboolean process_open_compare (gpointer handle, gpointer user_data)
-{
- pid_t wanted_pid;
- pid_t checking_pid = signal_process_if_gone (handle);
-
- if (checking_pid == 0) {
- return(FALSE);
- }
+ if (checking_pid == 0)
+ return FALSE;
wanted_pid = GPOINTER_TO_UINT (user_data);
* unsignalled
*/
if (checking_pid == wanted_pid &&
- _wapi_handle_issignalled (handle) == FALSE) {
+ !_wapi_handle_issignalled (handle)) {
/* If the handle is blown away in the window between
* returning TRUE here and _wapi_search_handle pinging
* the timestamp, the search will continue
*/
- return(TRUE);
+ return TRUE;
} else {
- return(FALSE);
+ return FALSE;
}
}
-gboolean CloseProcess(gpointer handle)
+gboolean
+CloseProcess (gpointer handle)
{
- if ((GPOINTER_TO_UINT (handle) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
- /* This is a pseudo handle */
- return(TRUE);
- }
-
+ if (WAPI_IS_PSEUDO_PROCESS_HANDLE (handle))
+ return TRUE;
return CloseHandle (handle);
}
/*
* The caller owns the returned handle and must call CloseProcess () on it to clean it up.
*/
-gpointer OpenProcess (guint32 req_access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, guint32 pid)
+gpointer
+OpenProcess (guint32 req_access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, guint32 pid)
{
/* Find the process handle that corresponds to pid */
gpointer handle = NULL;
- mono_once (&process_current_once, process_set_current);
-
DEBUG ("%s: looking for process %d", __func__, pid);
handle = _wapi_search_handle (WAPI_HANDLE_PROCESS,
/* Return a pseudo handle for processes we
* don't have handles for
*/
- return GINT_TO_POINTER (_WAPI_PROCESS_UNHANDLED + pid);
+ return WAPI_PID_TO_HANDLE (pid);
} else {
DEBUG ("%s: Can't find pid %d", __func__, pid);
SetLastError (ERROR_PROC_NOT_FOUND);
- return(NULL);
+ return NULL;
}
}
/* _wapi_search_handle () already added a ref */
- return(handle);
+ return handle;
}
-gboolean GetExitCodeProcess (gpointer process, guint32 *code)
+gboolean
+GetExitCodeProcess (gpointer process, guint32 *code)
{
- struct _WapiHandle_process *process_handle;
- gboolean ok;
+ WapiHandle_process *process_handle;
guint32 pid = -1;
- mono_once (&process_current_once, process_set_current);
-
- if(code==NULL) {
- return(FALSE);
- }
+ if (!code)
+ return FALSE;
- pid = GPOINTER_TO_UINT (process) - _WAPI_PROCESS_UNHANDLED;
- if ((GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
+ if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process)) {
+ pid = WAPI_HANDLE_TO_PID (process);
/* This is a pseudo handle, so we don't know what the
* exit code was, but we can check whether it's alive or not
*/
}
}
- ok=_wapi_lookup_handle (process, WAPI_HANDLE_PROCESS,
- (gpointer *)&process_handle);
- if(ok==FALSE) {
+ process_handle = lookup_process_handle (process);
+ if (!process_handle) {
DEBUG ("%s: Can't find process %p", __func__, process);
- return(FALSE);
+ return FALSE;
}
/* A process handle is only signalled if the process has exited
*/
process_wait (process, 0, TRUE);
- if (_wapi_handle_issignalled (process) == TRUE) {
+ if (_wapi_handle_issignalled (process))
*code = process_handle->exitstatus;
- } else {
+ else
*code = STILL_ACTIVE;
- }
- return(TRUE);
+ return TRUE;
}
-gboolean GetProcessTimes (gpointer process, WapiFileTime *create_time,
- WapiFileTime *exit_time, WapiFileTime *kernel_time,
- WapiFileTime *user_time)
+gboolean
+GetProcessTimes (gpointer process, WapiFileTime *create_time,
+ WapiFileTime *exit_time, WapiFileTime *kernel_time,
+ WapiFileTime *user_time)
{
- struct _WapiHandle_process *process_handle;
- gboolean ok;
+ WapiHandle_process *process_handle;
gboolean ku_times_set = FALSE;
- mono_once (&process_current_once, process_set_current);
-
- if(create_time==NULL || exit_time==NULL || kernel_time==NULL ||
- user_time==NULL) {
+ if (create_time == NULL || exit_time == NULL || kernel_time == NULL ||
+ user_time == NULL)
/* Not sure if w32 allows NULLs here or not */
- return(FALSE);
- }
+ return FALSE;
- if ((GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
+ if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process))
/* This is a pseudo handle, so just fail for now
*/
- return(FALSE);
- }
+ return FALSE;
- ok=_wapi_lookup_handle (process, WAPI_HANDLE_PROCESS,
- (gpointer *)&process_handle);
- if(ok==FALSE) {
+ process_handle = lookup_process_handle (process);
+ if (!process_handle) {
DEBUG ("%s: Can't find process %p", __func__, process);
- return(FALSE);
+ return FALSE;
}
- *create_time=process_handle->create_time;
+ *create_time = process_handle->create_time;
/* A process handle is only signalled if the process has
* exited. Otherwise exit_time isn't set
*/
- if(_wapi_handle_issignalled (process)==TRUE) {
- *exit_time=process_handle->exit_time;
- }
+ if (_wapi_handle_issignalled (process))
+ *exit_time = process_handle->exit_time;
#ifdef HAVE_GETRUSAGE
if (process_handle->id == getpid ()) {
memset (user_time, 0, sizeof (WapiFileTime));
}
- return(TRUE);
+ return TRUE;
}
typedef struct
{
gpointer address_start;
gpointer address_end;
- gchar *perms;
+ char *perms;
gpointer address_offset;
dev_t device;
ino_t inode;
- gchar *filename;
+ char *filename;
} WapiProcModule;
static void free_procmodule (WapiProcModule *mod)
{
GSList *ret = NULL;
WapiProcModule *mod;
- gchar buf[MAXPATHLEN + 1], *p, *endp;
- gchar *start_start, *end_start, *prot_start, *offset_start;
- gchar *maj_dev_start, *min_dev_start, *inode_start, prot_buf[5];
+ char buf[MAXPATHLEN + 1], *p, *endp;
+ char *start_start, *end_start, *prot_start, *offset_start;
+ char *maj_dev_start, *min_dev_start, *inode_start, prot_buf[5];
gpointer address_start, address_end, address_offset;
guint32 maj_dev, min_dev;
ino_t inode;
}
#endif
-static gboolean match_procname_to_modulename (gchar *procname, gchar *modulename)
+static gboolean match_procname_to_modulename (char *procname, char *modulename)
{
char* lastsep = NULL;
char* lastsep2 = NULL;
open_process_map (int pid, const char *mode)
{
FILE *fp = NULL;
- const gchar *proc_path[] = {
+ const char *proc_path[] = {
"/proc/%d/maps", /* GNU/Linux */
"/proc/%d/map", /* FreeBSD */
NULL
};
int i;
- gchar *filename;
+ char *filename;
for (i = 0; fp == NULL && proc_path [i]; i++) {
filename = g_strdup_printf (proc_path[i], pid);
gboolean EnumProcessModules (gpointer process, gpointer *modules,
guint32 size, guint32 *needed)
{
- struct _WapiHandle_process *process_handle;
- gboolean ok;
+ WapiHandle_process *process_handle;
#if !defined(__OpenBSD__) && !defined(PLATFORM_MACOSX)
FILE *fp;
#endif
guint32 count, avail = size / sizeof(gpointer);
int i;
pid_t pid;
- gchar *proc_name = NULL;
+ char *proc_name = NULL;
/* Store modules in an array of pointers (main module as
* modules[0]), using the load address for each module as a
* implement /dev/kmem reading or whatever other horrid
* technique is needed.
*/
- if (size < sizeof(gpointer)) {
- return(FALSE);
- }
+ if (size < sizeof(gpointer))
+ return FALSE;
- if ((GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
- /* This is a pseudo handle */
- pid = (pid_t)(GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED_PID_MASK);
+ if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process)) {
+ pid = WAPI_HANDLE_TO_PID (process);
} else {
- ok = _wapi_lookup_handle (process, WAPI_HANDLE_PROCESS,
- (gpointer *)&process_handle);
- if (ok == FALSE) {
+ process_handle = lookup_process_handle (process);
+ if (!process_handle) {
DEBUG ("%s: Can't find process %p", __func__, process);
- return(FALSE);
+ return FALSE;
}
pid = process_handle->id;
proc_name = process_handle->proc_name;
}
#if defined(PLATFORM_MACOSX) || defined(__OpenBSD__) || defined(__HAIKU__)
- {
- mods = load_modules ();
+ mods = load_modules ();
+ if (!proc_name) {
+ modules[0] = NULL;
+ *needed = sizeof(gpointer);
+ return TRUE;
+ }
#else
- if ((fp = open_process_map (pid, "r")) == NULL) {
+ fp = open_process_map (pid, "r");
+ if (!fp) {
/* No /proc/<pid>/maps so just return the main module
* shortcut for now
*/
modules[0] = NULL;
*needed = sizeof(gpointer);
- } else {
- mods = load_modules (fp);
- fclose (fp);
+ return TRUE;
+ }
+ mods = load_modules (fp);
+ fclose (fp);
#endif
- count = g_slist_length (mods);
+ count = g_slist_length (mods);
- /* count + 1 to leave slot 0 for the main module */
- *needed = sizeof(gpointer) * (count + 1);
-
- /* Use the NULL shortcut, as the first line in
- * /proc/<pid>/maps isn't the executable, and we need
- * that first in the returned list. Check the module name
- * to see if it ends with the proc name and substitute
- * the first entry with it. FIXME if this turns out to
- * be a problem.
- */
- modules[0] = NULL;
- for (i = 0; i < (avail - 1) && i < count; i++) {
- module = (WapiProcModule *)g_slist_nth_data (mods, i);
- if (modules[0] != NULL)
- modules[i] = module->address_start;
- else if (match_procname_to_modulename (proc_name, module->filename))
- modules[0] = module->address_start;
- else
- modules[i + 1] = module->address_start;
- }
+ /* count + 1 to leave slot 0 for the main module */
+ *needed = sizeof(gpointer) * (count + 1);
+
+ /*
+ * Use the NULL shortcut, as the first line in
+ * /proc/<pid>/maps isn't the executable, and we need
+ * that first in the returned list. Check the module name
+ * to see if it ends with the proc name and substitute
+ * the first entry with it. FIXME if this turns out to
+ * be a problem.
+ */
+ modules[0] = NULL;
+ for (i = 0; i < (avail - 1) && i < count; i++) {
+ module = (WapiProcModule *)g_slist_nth_data (mods, i);
+ if (modules[0] != NULL)
+ modules[i] = module->address_start;
+ else if (match_procname_to_modulename (proc_name, module->filename))
+ modules[0] = module->address_start;
+ else
+ modules[i + 1] = module->address_start;
+ }
- for (i = 0; i < count; i++) {
- free_procmodule (g_slist_nth_data (mods, i));
- }
- g_slist_free (mods);
+ for (i = 0; i < count; i++) {
+ free_procmodule (g_slist_nth_data (mods, i));
}
+ g_slist_free (mods);
- return(TRUE);
+ return TRUE;
}
-static gchar *get_process_name_from_proc (pid_t pid)
+static char *
+get_process_name_from_proc (pid_t pid)
{
#if defined(__OpenBSD__)
int mib [6];
#endif
#else
FILE *fp;
- gchar *filename = NULL;
+ char *filename = NULL;
#endif
- gchar buf[256];
- gchar *ret = NULL;
+ char buf[256];
+ char *ret = NULL;
#if defined(PLATFORM_SOLARIS)
filename = g_strdup_printf ("/proc/%d/psinfo", pid);
filename = g_strdup_printf ("/proc/%d/stat", pid);
if ((fp = fopen (filename, "r")) != NULL) {
if (fgets (buf, 256, fp) != NULL) {
- gchar *start, *end;
+ char *start, *end;
start = strchr (buf, '(');
if (start != NULL) {
* Return the full path of the executable of the process PID, or NULL if it cannot be determined.
* Returns malloc-ed memory.
*/
-gchar*
+char*
wapi_process_get_path (pid_t pid)
{
#if defined(PLATFORM_MACOSX) && !defined(__mono_ppc__) && defined(TARGET_OSX)
- gchar buf [PROC_PIDPATHINFO_MAXSIZE];
+ char buf [PROC_PIDPATHINFO_MAXSIZE];
int res;
res = proc_pidpath (pid, buf, sizeof (buf));
cli_launcher = path ? g_strdup (path) : NULL;
}
-static guint32 get_module_name (gpointer process, gpointer module,
- gunichar2 *basename, guint32 size,
- gboolean base)
+static guint32
+get_module_name (gpointer process, gpointer module,
+ gunichar2 *basename, guint32 size,
+ gboolean base)
{
- struct _WapiHandle_process *process_handle;
- gboolean ok;
+ WapiHandle_process *process_handle;
pid_t pid;
gunichar2 *procname;
- gchar *procname_ext = NULL;
+ char *procname_ext = NULL;
glong len;
gsize bytes;
#if !defined(__OpenBSD__) && !defined(PLATFORM_MACOSX)
WapiProcModule *found_module;
guint32 count;
int i;
- gchar *proc_name = NULL;
+ char *proc_name = NULL;
- mono_once (&process_current_once, process_set_current);
-
DEBUG ("%s: Getting module base name, process handle %p module %p",
__func__, process, module);
- size = size*sizeof(gunichar2); /* adjust for unicode characters */
+ size = size * sizeof (gunichar2); /* adjust for unicode characters */
- if (basename == NULL || size == 0) {
- return(0);
- }
+ if (basename == NULL || size == 0)
+ return 0;
- if ((GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
+ if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process)) {
/* This is a pseudo handle */
- pid = (pid_t)(GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED_PID_MASK);
+ pid = (pid_t)WAPI_HANDLE_TO_PID (process);
proc_name = get_process_name_from_proc (pid);
} else {
- ok = _wapi_lookup_handle (process, WAPI_HANDLE_PROCESS,
- (gpointer *)&process_handle);
- if (ok == FALSE) {
+ process_handle = lookup_process_handle (process);
+ if (!process_handle) {
DEBUG ("%s: Can't find process %p", __func__,
process);
- return(0);
+ return 0;
}
pid = process_handle->id;
proc_name = g_strdup (process_handle->proc_name);
/* Look up the address in /proc/<pid>/maps */
#if defined(PLATFORM_MACOSX) || defined(__OpenBSD__) || defined(__HAIKU__)
- {
- mods = load_modules ();
+ mods = load_modules ();
#else
- if ((fp = open_process_map (pid, "r")) == NULL) {
+ fp = open_process_map (pid, "r");
+ if (fp == NULL) {
if (errno == EACCES && module == NULL && base == TRUE) {
procname_ext = get_process_name_from_proc (pid);
} else {
* for now
*/
g_free (proc_name);
- return(0);
+ return 0;
}
} else {
mods = load_modules (fp);
fclose (fp);
+ }
#endif
- count = g_slist_length (mods);
-
- /* If module != NULL compare the address.
- * If module == NULL we are looking for the main module.
- * The best we can do for now check it the module name end with the process name.
- */
- for (i = 0; i < count; i++) {
- found_module = (WapiProcModule *)g_slist_nth_data (mods, i);
- if (procname_ext == NULL &&
- ((module == NULL && match_procname_to_modulename (proc_name, found_module->filename)) ||
- (module != NULL && found_module->address_start == module))) {
- if (base) {
- procname_ext = g_path_get_basename (found_module->filename);
- } else {
- procname_ext = g_strdup (found_module->filename);
- }
- }
+ count = g_slist_length (mods);
- free_procmodule (found_module);
+ /* If module != NULL compare the address.
+ * If module == NULL we are looking for the main module.
+ * The best we can do for now check it the module name end with the process name.
+ */
+ for (i = 0; i < count; i++) {
+ found_module = (WapiProcModule *)g_slist_nth_data (mods, i);
+ if (procname_ext == NULL &&
+ ((module == NULL && match_procname_to_modulename (proc_name, found_module->filename)) ||
+ (module != NULL && found_module->address_start == module))) {
+ if (base)
+ procname_ext = g_path_get_basename (found_module->filename);
+ else
+ procname_ext = g_strdup (found_module->filename);
}
- if (procname_ext == NULL)
- {
- /* If it's *still* null, we might have hit the
- * case where reading /proc/$pid/maps gives an
- * empty file for this user.
- */
- procname_ext = get_process_name_from_proc (pid);
- }
+ free_procmodule (found_module);
+ }
- g_slist_free (mods);
- g_free (proc_name);
+ if (procname_ext == NULL) {
+ /* If it's *still* null, we might have hit the
+ * case where reading /proc/$pid/maps gives an
+ * empty file for this user.
+ */
+ procname_ext = get_process_name_from_proc (pid);
}
- if (procname_ext != NULL) {
+ g_slist_free (mods);
+ g_free (proc_name);
+
+ if (procname_ext) {
DEBUG ("%s: Process name is [%s]", __func__,
procname_ext);
if (procname == NULL) {
/* bugger */
g_free (procname_ext);
- return(0);
+ return 0;
}
len = (bytes / 2);
g_free (procname);
g_free (procname_ext);
- return(len);
+ return len;
}
- return(0);
+ return 0;
}
-guint32 GetModuleBaseName (gpointer process, gpointer module,
- gunichar2 *basename, guint32 size)
+guint32
+GetModuleBaseName (gpointer process, gpointer module,
+ gunichar2 *basename, guint32 size)
{
- return(get_module_name (process, module, basename, size, TRUE));
+ return get_module_name (process, module, basename, size, TRUE);
}
-guint32 GetModuleFileNameEx (gpointer process, gpointer module,
- gunichar2 *filename, guint32 size)
+guint32
+GetModuleFileNameEx (gpointer process, gpointer module,
+ gunichar2 *filename, guint32 size)
{
- return(get_module_name (process, module, filename, size, FALSE));
+ return get_module_name (process, module, filename, size, FALSE);
}
-gboolean GetModuleInformation (gpointer process, gpointer module,
- WapiModuleInfo *modinfo, guint32 size)
+gboolean
+GetModuleInformation (gpointer process, gpointer module,
+ WapiModuleInfo *modinfo, guint32 size)
{
- struct _WapiHandle_process *process_handle;
- gboolean ok;
+ WapiHandle_process *process_handle;
pid_t pid;
#if !defined(__OpenBSD__) && !defined(PLATFORM_MACOSX)
FILE *fp;
guint32 count;
int i;
gboolean ret = FALSE;
- gchar *proc_name = NULL;
-
- mono_once (&process_current_once, process_set_current);
+ char *proc_name = NULL;
DEBUG ("%s: Getting module info, process handle %p module %p",
__func__, process, module);
- if (modinfo == NULL || size < sizeof(WapiModuleInfo)) {
- return(FALSE);
- }
+ if (modinfo == NULL || size < sizeof (WapiModuleInfo))
+ return FALSE;
- if ((GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
- /* This is a pseudo handle */
- pid = (pid_t)(GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED_PID_MASK);
+ if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process)) {
+ pid = (pid_t)WAPI_HANDLE_TO_PID (process);
proc_name = get_process_name_from_proc (pid);
} else {
- ok = _wapi_lookup_handle (process, WAPI_HANDLE_PROCESS,
- (gpointer *)&process_handle);
- if (ok == FALSE) {
+ process_handle = lookup_process_handle (process);
+ if (!process_handle) {
DEBUG ("%s: Can't find process %p", __func__,
process);
- return(FALSE);
+ return FALSE;
}
pid = process_handle->id;
proc_name = g_strdup (process_handle->proc_name);
}
#if defined(PLATFORM_MACOSX) || defined(__OpenBSD__) || defined(__HAIKU__)
- {
- mods = load_modules ();
+ mods = load_modules ();
#else
/* Look up the address in /proc/<pid>/maps */
if ((fp = open_process_map (pid, "r")) == NULL) {
* for now
*/
g_free (proc_name);
- return(FALSE);
- } else {
- mods = load_modules (fp);
- fclose (fp);
+ return FALSE;
+ }
+ mods = load_modules (fp);
+ fclose (fp);
#endif
- count = g_slist_length (mods);
+ count = g_slist_length (mods);
- /* If module != NULL compare the address.
- * If module == NULL we are looking for the main module.
- * The best we can do for now check it the module name end with the process name.
- */
- for (i = 0; i < count; i++) {
+ /* If module != NULL compare the address.
+ * If module == NULL we are looking for the main module.
+ * The best we can do for now check it the module name end with the process name.
+ */
+ for (i = 0; i < count; i++) {
found_module = (WapiProcModule *)g_slist_nth_data (mods, i);
- if ( ret == FALSE &&
- ((module == NULL && match_procname_to_modulename (proc_name, found_module->filename)) ||
- (module != NULL && found_module->address_start == module))) {
+ if (ret == FALSE &&
+ ((module == NULL && match_procname_to_modulename (proc_name, found_module->filename)) ||
+ (module != NULL && found_module->address_start == module))) {
modinfo->lpBaseOfDll = found_module->address_start;
modinfo->SizeOfImage = (gsize)(found_module->address_end) - (gsize)(found_module->address_start);
modinfo->EntryPoint = found_module->address_offset;
}
free_procmodule (found_module);
- }
-
- g_slist_free (mods);
- g_free (proc_name);
}
- return(ret);
+ g_slist_free (mods);
+ g_free (proc_name);
+
+ return ret;
}
-gboolean GetProcessWorkingSetSize (gpointer process, size_t *min, size_t *max)
+gboolean
+GetProcessWorkingSetSize (gpointer process, size_t *min, size_t *max)
{
- struct _WapiHandle_process *process_handle;
- gboolean ok;
+ WapiHandle_process *process_handle;
- mono_once (&process_current_once, process_set_current);
-
- if(min==NULL || max==NULL) {
+ if (min == NULL || max == NULL)
/* Not sure if w32 allows NULLs here or not */
- return(FALSE);
- }
+ return FALSE;
- if ((GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
- /* This is a pseudo handle, so just fail for now
- */
- return(FALSE);
- }
+ if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process))
+ /* This is a pseudo handle, so just fail for now */
+ return FALSE;
- ok=_wapi_lookup_handle (process, WAPI_HANDLE_PROCESS,
- (gpointer *)&process_handle);
- if(ok==FALSE) {
+ process_handle = lookup_process_handle (process);
+ if (!process_handle) {
DEBUG ("%s: Can't find process %p", __func__, process);
- return(FALSE);
+ return FALSE;
}
- *min=process_handle->min_working_set;
- *max=process_handle->max_working_set;
+ *min = process_handle->min_working_set;
+ *max = process_handle->max_working_set;
- return(TRUE);
+ return TRUE;
}
-gboolean SetProcessWorkingSetSize (gpointer process, size_t min, size_t max)
+gboolean
+SetProcessWorkingSetSize (gpointer process, size_t min, size_t max)
{
- struct _WapiHandle_process *process_handle;
- gboolean ok;
+ WapiHandle_process *process_handle;
- mono_once (&process_current_once, process_set_current);
-
- if ((GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
+ if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process))
/* This is a pseudo handle, so just fail for now
*/
- return(FALSE);
- }
+ return FALSE;
- ok=_wapi_lookup_handle (process, WAPI_HANDLE_PROCESS,
- (gpointer *)&process_handle);
- if(ok==FALSE) {
+ process_handle = lookup_process_handle (process);
+ if (!process_handle) {
DEBUG ("%s: Can't find process %p", __func__, process);
- return(FALSE);
+ return FALSE;
}
- process_handle->min_working_set=min;
- process_handle->max_working_set=max;
+ process_handle->min_working_set = min;
+ process_handle->max_working_set = max;
- return(TRUE);
+ return TRUE;
}
gboolean
TerminateProcess (gpointer process, gint32 exitCode)
{
- struct _WapiHandle_process *process_handle;
- gboolean ok;
+ WapiHandle_process *process_handle;
int signo;
int ret;
pid_t pid;
- if ((GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
+ if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process)) {
/* This is a pseudo handle */
- pid = (pid_t)(GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED_PID_MASK);
+ pid = (pid_t)WAPI_HANDLE_TO_PID (process);
} else {
- ok = _wapi_lookup_handle (process, WAPI_HANDLE_PROCESS,
- (gpointer *) &process_handle);
-
- if (ok == FALSE) {
- DEBUG ("%s: Can't find process %p", __func__,
- process);
+ process_handle = lookup_process_handle (process);
+ if (!process_handle) {
+ DEBUG ("%s: Can't find process %p", __func__, process);
SetLastError (ERROR_INVALID_HANDLE);
return FALSE;
}
GetPriorityClass (gpointer process)
{
#ifdef HAVE_GETPRIORITY
- struct _WapiHandle_process *process_handle;
- gboolean ok;
+ WapiHandle_process *process_handle;
int ret;
pid_t pid;
- if ((GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
+ if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process)) {
/* This is a pseudo handle */
- pid = (pid_t)(GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED_PID_MASK);
+ pid = (pid_t)WAPI_HANDLE_TO_PID (process);
} else {
- ok = _wapi_lookup_handle (process, WAPI_HANDLE_PROCESS,
- (gpointer *) &process_handle);
-
- if (!ok) {
+ process_handle = lookup_process_handle (process);
+ if (!process_handle) {
SetLastError (ERROR_INVALID_HANDLE);
return FALSE;
}
SetPriorityClass (gpointer process, guint32 priority_class)
{
#ifdef HAVE_SETPRIORITY
- struct _WapiHandle_process *process_handle;
- gboolean ok;
+ WapiHandle_process *process_handle;
int ret;
int prio;
pid_t pid;
- if ((GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
+ if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process)) {
/* This is a pseudo handle */
- pid = (pid_t)(GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED_PID_MASK);
+ pid = (pid_t)WAPI_HANDLE_TO_PID (process);
} else {
- ok = _wapi_lookup_handle (process, WAPI_HANDLE_PROCESS,
- (gpointer *) &process_handle);
-
- if (!ok) {
+ process_handle = lookup_process_handle (process);
+ if (!process_handle) {
SetLastError (ERROR_INVALID_HANDLE);
return FALSE;
}
mp = mp->next;
}
+ /*
+ * Remove processes which exited from the mono_processes list.
+ * We need to synchronize with the sigchld handler here, which runs
+ * asynchronously. The handler requires that the mono_processes list
+ * remain valid.
+ */
mp = mono_processes;
spin = 0;
while (mp != NULL) {
/* We've found a candidate */
mono_mutex_lock (&mono_processes_mutex);
+ /*
+ * This code can run parallel with the sigchld handler, but the
+ * modifications it makes are safe.
+ */
if (candidate == NULL) {
/* unlink it */
if (mp == mono_processes) {
static void
process_close (gpointer handle, gpointer data)
{
- struct _WapiHandle_process *process_handle;
+ WapiHandle_process *process_handle;
DEBUG ("%s", __func__);
- process_handle = (struct _WapiHandle_process *) data;
- if (process_handle->mono_process && process_handle->self == _wapi_getpid ())
+ process_handle = (WapiHandle_process *) data;
+ g_free (process_handle->proc_name);
+ process_handle->proc_name = NULL;
+ if (process_handle->mono_process)
InterlockedDecrement (&process_handle->mono_process->handle_count);
mono_processes_cleanup ();
}
int pid;
struct MonoProcess *p;
-#if DEBUG
- fprintf (stdout, "SIG CHILD handler for pid: %i\n", info->si_pid);
-#endif
+ DEBUG ("SIG CHILD handler for pid: %i\n", info->si_pid);
InterlockedIncrement (&mono_processes_read_lock);
if (pid <= 0)
break;
-#if DEBUG
- fprintf (stdout, "child ended: %i", pid);
-#endif
+ DEBUG ("child ended: %i", pid);
p = mono_processes;
while (p != NULL) {
if (p->pid == pid) {
InterlockedDecrement (&mono_processes_read_lock);
-#if DEBUG
- fprintf (stdout, "SIG CHILD handler: done looping.");
-#endif
+ DEBUG ("SIG CHILD handler: done looping.");
}
#endif
-static void process_add_sigchld_handler (void)
+static void
+process_add_sigchld_handler (void)
{
#if HAVE_SIGACTION
struct sigaction sa;
#endif
}
-static guint32 process_wait (gpointer handle, guint32 timeout, gboolean alertable)
+static guint32
+process_wait (gpointer handle, guint32 timeout, gboolean alertable)
{
- struct _WapiHandle_process *process_handle;
- gboolean ok;
+ WapiHandle_process *process_handle;
pid_t pid, ret;
int status;
guint32 start;
guint32 now;
struct MonoProcess *mp;
- gboolean spin;
- gpointer current_thread;
-
- current_thread = wapi_get_current_thread_handle ();
- if (current_thread == NULL) {
- SetLastError (ERROR_INVALID_HANDLE);
- return WAIT_FAILED;
- }
/* FIXME: We can now easily wait on processes that aren't our own children,
* but WaitFor*Object won't call us for pseudo handles. */
DEBUG ("%s (%p, %u)", __func__, handle, timeout);
- ok = _wapi_lookup_handle (handle, WAPI_HANDLE_PROCESS, (gpointer *)&process_handle);
- if (ok == FALSE) {
+ process_handle = lookup_process_handle (handle);
+ if (!process_handle) {
g_warning ("%s: error looking up process handle %p", __func__, handle);
return WAIT_FAILED;
}
/* We don't need to lock mono_processes here, the entry
* has a handle_count > 0 which means it will not be freed. */
mp = process_handle->mono_process;
- if (mp && process_handle->self != _wapi_getpid ()) {
- /* mono_process points to memory in another process' address space: we can't use it */
- mp = NULL;
- }
+ g_assert (mp);
start = mono_msec_ticks ();
now = start;
- spin = mp == NULL;
while (1) {
- if (mp != NULL) {
- /* We have a semaphore we can wait on */
- if (timeout != INFINITE) {
- DEBUG ("%s (%p, %u): waiting on semaphore for %li ms...",
- __func__, handle, timeout, (timeout - (now - start)));
+ if (timeout != INFINITE) {
+ DEBUG ("%s (%p, %u): waiting on semaphore for %li ms...",
+ __func__, handle, timeout, (timeout - (now - start)));
- ret = MONO_SEM_TIMEDWAIT_ALERTABLE (&mp->exit_sem, (timeout - (now - start)), alertable);
- } else {
- DEBUG ("%s (%p, %u): waiting on semaphore forever...",
- __func__, handle, timeout);
- ret = MONO_SEM_WAIT_ALERTABLE (&mp->exit_sem, alertable);
- }
+ ret = MONO_SEM_TIMEDWAIT_ALERTABLE (&mp->exit_sem, (timeout - (now - start)), alertable);
+ } else {
+ DEBUG ("%s (%p, %u): waiting on semaphore forever...",
+ __func__, handle, timeout);
+ ret = MONO_SEM_WAIT_ALERTABLE (&mp->exit_sem, alertable);
+ }
- if (ret == -1 && errno != EINTR && errno != ETIMEDOUT) {
- DEBUG ("%s (%p, %u): sem_timedwait failure: %s",
- __func__, handle, timeout, g_strerror (errno));
- /* Should we return a failure here? */
- }
+ if (ret == -1 && errno != EINTR && errno != ETIMEDOUT) {
+ DEBUG ("%s (%p, %u): sem_timedwait failure: %s",
+ __func__, handle, timeout, g_strerror (errno));
+ /* Should we return a failure here? */
+ }
- if (ret == 0) {
- /* Success, process has exited */
- MONO_SEM_POST (&mp->exit_sem);
- break;
- }
- } else {
- /* We did not create this process, so we can't waidpid / sem_wait it.
- * We need to poll for the pid existence */
- DEBUG ("%s (%p, %u): polling on pid...", __func__, handle, timeout);
- if (!is_pid_valid (pid)) {
- /* Success, process has exited */
- break;
- }
+ if (ret == 0) {
+ /* Success, process has exited */
+ MONO_SEM_POST (&mp->exit_sem);
+ break;
}
if (timeout == 0) {
DEBUG ("%s (%p, %u): WAIT_TIMEOUT", __func__, handle, timeout);
return WAIT_TIMEOUT;
}
-
- if (spin) {
- /* "timeout - (now - start)" will not underflow, since timeout is always >=0,
- * and we passed the check just above */
- _wapi_handle_spin (MIN (100, timeout - (now - start)));
- }
- if (alertable && _wapi_thread_apc_pending (current_thread)) {
+ if (alertable && _wapi_thread_cur_apc_pending ()) {
DEBUG ("%s (%p, %u): WAIT_IO_COMPLETION", __func__, handle, timeout);
return WAIT_IO_COMPLETION;
}
g_assert (ret == 0);
status = mp ? mp->status : 0;
- if (WIFSIGNALED (status)) {
+ if (WIFSIGNALED (status))
process_handle->exitstatus = 128 + WTERMSIG (status);
- } else {
+ else
process_handle->exitstatus = WEXITSTATUS (status);
- }
_wapi_time_t_to_filetime (time (NULL), &process_handle->exit_time);
process_handle->exited = TRUE;
DEBUG ("%s (%p, %u): Setting pid %d signalled, exit status %d",
__func__, handle, timeout, process_handle->id, process_handle->exitstatus);
- _wapi_shared_handle_set_signal_state (handle, TRUE);
+ _wapi_handle_set_signal_state (handle, TRUE, TRUE);
_wapi_handle_unlock_shared_handles ();
#ifndef _WAPI_PROCESSES_H_
#define _WAPI_PROCESSES_H_
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
#include <glib.h>
#include <mono/io-layer/handles.h>
extern gpointer GetCurrentProcess (void);
extern guint32 GetProcessId (gpointer handle);
-extern guint32 GetCurrentProcessId (void);
-extern gboolean EnumProcesses (guint32 *pids, guint32 len, guint32 *needed);
extern gboolean CloseProcess (gpointer handle);
extern gpointer OpenProcess (guint32 access, gboolean inherit, guint32 pid);
extern gboolean GetExitCodeProcess (gpointer process, guint32 *code);
static mono_mutex_t noshm_sems[_WAPI_SHARED_SEM_COUNT];
-gboolean _wapi_shm_disabled = TRUE;
-
static gpointer wapi_storage [16];
static void
}
gboolean
-_wapi_shm_enabled (void)
+_wapi_shm_enabled_internal (void)
{
return FALSE;
}
-#else
+#else /* DISABLE_SHARED_HANDLES */
+
/*
* Use POSIX shared memory if possible, it is simpler, and it has the advantage that
* writes to the shared area does not need to be written to disk, avoiding spinning up
#define USE_SHM 1
#endif
+static gboolean _wapi_shm_disabled = TRUE;
+
static gchar *
_wapi_shm_base_name (_wapi_shm_t type)
{
}
gboolean
-_wapi_shm_enabled (void)
+_wapi_shm_enabled_internal (void)
{
static gboolean env_checked;
WAPI_SHM_FILESHARE
} _wapi_shm_t;
-extern gboolean _wapi_shm_disabled;
-
extern gpointer _wapi_shm_attach (_wapi_shm_t type);
extern void _wapi_shm_detach (_wapi_shm_t type);
-extern gboolean _wapi_shm_enabled (void);
+extern gboolean _wapi_shm_enabled_internal (void);
extern void _wapi_shm_semaphores_init (void);
extern void _wapi_shm_semaphores_remove (void);
extern int _wapi_shm_sem_lock (int sem);
extern int _wapi_shm_sem_trylock (int sem);
extern int _wapi_shm_sem_unlock (int sem);
+static inline gboolean
+_wapi_shm_enabled (void)
+{
+#ifdef DISABLE_SHARED_HANDLES
+ return FALSE;
+#else
+ return _wapi_shm_enabled_internal ();
+#endif
+}
+
#endif /* _WAPI_SHARED_H_ */
extern const char *_wapi_handle_typename[];
-#define _WAPI_SHARED_HANDLE(type) (type == WAPI_HANDLE_PROCESS || \
- type == WAPI_HANDLE_NAMEDMUTEX || \
+#define _WAPI_SHARED_HANDLE(type) (type == WAPI_HANDLE_NAMEDMUTEX || \
type == WAPI_HANDLE_NAMEDSEM || \
type == WAPI_HANDLE_NAMEDEVENT)
struct _WapiHandle_sem sem;
struct _WapiHandle_socket sock;
struct _WapiHandle_thread thread;
+ struct _WapiHandle_process process;
struct _WapiHandle_shared_ref shared;
} u;
};
union
{
- struct _WapiHandle_process process;
struct _WapiHandle_namedmutex namedmutex;
struct _WapiHandle_namedsem namedsem;
struct _WapiHandle_namedevent namedevent;
icall.c \
icall-def.h \
image.c \
+ jit-info.c \
loader.c \
locales.c \
locales.h \
bytes_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
if (atype == ATYPE_STRING) {
/* a string alloator method takes the args: (vtable, len) */
- /* bytes = (sizeof (MonoString) + ((len + 1) * 2)); */
+ /* bytes = (offsetof (MonoString, chars) + ((len + 1) * 2)); */
mono_mb_emit_ldarg (mb, 1);
mono_mb_emit_icon (mb, 1);
mono_mb_emit_byte (mb, MONO_CEE_ADD);
return G_MAXINT;
}
+void
+mono_gc_set_string_length (MonoString *str, gint32 new_length)
+{
+ mono_unichar2 *new_end = str->chars + new_length;
+
+ /* zero the discarded string. This null-delimits the string and allows
+ * the space to be reclaimed by SGen. */
+
+ memset (new_end, 0, (str->length - new_length + 1) * sizeof (mono_unichar2));
+ str->length = new_length;
+}
+
gboolean
mono_gc_user_markers_supported (void)
{
MONO_EXCEPTION_GENERIC_SHARING_FAILED = 11,
MONO_EXCEPTION_BAD_IMAGE = 12,
MONO_EXCEPTION_OBJECT_SUPPLIED = 13, /*The exception object is already created.*/
- MONO_EXCEPTION_OUT_OF_MEMORY = 14
- /* add other exception type */
+ MONO_EXCEPTION_OUT_OF_MEMORY = 14,
+ MONO_EXCEPTION_INLINE_FAILED = 15
};
/* This struct collects the info needed for the runtime use of a class,
}
}
break;
- case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT:
+ case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT: {
+ guint8 *ref_bitmap;
+
real_size = 0;
for (i = 0; i < top; i++) {
gint32 align;
* There must be info about all the fields in a type if it
* uses explicit layout.
*/
-
if (mono_field_is_deleted (field))
continue;
if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
*/
real_size = MAX (real_size, size + field->offset);
}
+
+ if (class->has_references) {
+ ref_bitmap = g_new0 (guint8, real_size / sizeof (gpointer));
+
+ /* Check for overlapping reference and non-reference fields */
+ for (i = 0; i < top; i++) {
+ MonoType *ftype;
+
+ field = &class->fields [i];
+
+ if (mono_field_is_deleted (field))
+ continue;
+ if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
+ continue;
+ ftype = mono_type_get_underlying_type (field->type);
+ if (MONO_TYPE_IS_REFERENCE (ftype))
+ ref_bitmap [field->offset / sizeof (gpointer)] = 1;
+ }
+ for (i = 0; i < top; i++) {
+ field = &class->fields [i];
+
+ if (mono_field_is_deleted (field))
+ continue;
+ if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
+ continue;
+
+ if (!MONO_TYPE_IS_REFERENCE (field->type) && ref_bitmap [field->offset / sizeof (gpointer)]) {
+ char *err_msg = g_strdup_printf ("Could not load type '%s' because it contains an object field at offset %d that is incorrectly aligned or overlapped by a non-object field.", class->name, field->offset);
+ mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, err_msg);
+ }
+ }
+ g_free (ref_bitmap);
+ }
+
class->instance_size = MAX (real_size, class->instance_size);
if (class->instance_size & (class->min_align - 1)) {
class->instance_size += class->min_align - 1;
}
break;
}
+ }
if (layout != TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
/*
if (class->generic_class) {
MonoClass *gklass = class->generic_class->container_class;
- MonoGenericContext *context;
+ MonoGenericContext *context = NULL;
mono_class_setup_events (gklass);
if (gklass->exception_type) {
static gboolean in_sigint;
-MONO_SIGNAL_HANDLER_FUNC (static, sigint_handler, (int signo))
+MONO_SIG_HANDLER_FUNC (static, sigint_handler)
{
int save_errno;
MONO_ARCH_SAVE_REGS;
static struct sigaction save_sigcont, save_sigint, save_sigwinch;
-MONO_SIGNAL_HANDLER_FUNC (static, sigcont_handler, (int signo, void *the_siginfo, void *data))
+MONO_SIG_HANDLER_FUNC (static, sigcont_handler)
{
int unused;
// Ignore error, there is not much we can do in the sigcont handler.
if (save_sigcont.sa_sigaction != NULL &&
save_sigcont.sa_sigaction != (void *)SIG_DFL &&
save_sigcont.sa_sigaction != (void *)SIG_IGN)
- (*save_sigcont.sa_sigaction) (signo, the_siginfo, data);
+ (*save_sigcont.sa_sigaction) (MONO_SIG_HANDLER_PARAMS);
}
-MONO_SIGNAL_HANDLER_FUNC (static, sigwinch_handler, (int signo, void *the_siginfo, void *data))
+MONO_SIG_HANDLER_FUNC (static, sigwinch_handler)
{
int dims = terminal_get_dimensions ();
if (dims != -1)
if (save_sigwinch.sa_sigaction != NULL &&
save_sigwinch.sa_sigaction != (void *)SIG_DFL &&
save_sigwinch.sa_sigaction != (void *)SIG_IGN)
- (*save_sigwinch.sa_sigaction) (signo, the_siginfo, data);
+ (*save_sigwinch.sa_sigaction) (MONO_SIG_HANDLER_PARAMS);
}
/*
gboolean cas_method_permitonly:1;
} MonoMethodCasInfo;
+typedef enum {
+ JIT_INFO_NONE = 0,
+ JIT_INFO_HAS_CAS_INFO = (1 << 0),
+ JIT_INFO_HAS_GENERIC_JIT_INFO = (1 << 1),
+ JIT_INFO_HAS_TRY_BLOCK_HOLES = (1 << 2),
+ JIT_INFO_HAS_ARCH_EH_INFO = (1 << 3)
+} MonoJitInfoFlags;
+
struct _MonoJitInfo {
/* NOTE: These first two elements (method and
next_jit_code_hash) must be in the same order and at the
void
mono_close_exe_image (void) MONO_INTERNAL;
+int
+mono_jit_info_size (MonoJitInfoFlags flags, int num_clauses, int num_holes) MONO_INTERNAL;
+
+void
+mono_jit_info_init (MonoJitInfo *ji, MonoMethod *method, guint8 *code, int code_size,
+ MonoJitInfoFlags flags, int num_clauses, int num_holes) MONO_INTERNAL;
+
+MonoJitInfoTable *
+mono_jit_info_table_new (MonoDomain *domain) MONO_INTERNAL;
+
+void
+mono_jit_info_table_free (MonoJitInfoTable *table) MONO_INTERNAL;
+
void
mono_jit_info_table_add (MonoDomain *domain, MonoJitInfo *ji) MONO_INTERNAL;
static const MonoRuntimeInfo *current_runtime = NULL;
-static MonoJitInfoFindInAot jit_info_find_in_aot_func = NULL;
-
/* This is the list of runtime versions supported by this JIT.
*/
static const MonoRuntimeInfo supported_runtimes[] = {
return offset;
}
-#define JIT_INFO_TABLE_FILL_RATIO_NOM 3
-#define JIT_INFO_TABLE_FILL_RATIO_DENOM 4
-#define JIT_INFO_TABLE_FILLED_NUM_ELEMENTS (MONO_JIT_INFO_TABLE_CHUNK_SIZE * JIT_INFO_TABLE_FILL_RATIO_NOM / JIT_INFO_TABLE_FILL_RATIO_DENOM)
-
-#define JIT_INFO_TABLE_LOW_WATERMARK(n) ((n) / 2)
-#define JIT_INFO_TABLE_HIGH_WATERMARK(n) ((n) * 5 / 6)
-
-#define JIT_INFO_TOMBSTONE_MARKER ((MonoMethod*)NULL)
-#define IS_JIT_INFO_TOMBSTONE(ji) ((ji)->d.method == JIT_INFO_TOMBSTONE_MARKER)
-
-#define JIT_INFO_TABLE_HAZARD_INDEX 0
-#define JIT_INFO_HAZARD_INDEX 1
-
-static int
-jit_info_table_num_elements (MonoJitInfoTable *table)
-{
- int i;
- int num_elements = 0;
-
- for (i = 0; i < table->num_chunks; ++i) {
- MonoJitInfoTableChunk *chunk = table->chunks [i];
- int chunk_num_elements = chunk->num_elements;
- int j;
-
- for (j = 0; j < chunk_num_elements; ++j) {
- if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j]))
- ++num_elements;
- }
- }
-
- return num_elements;
-}
-
-static MonoJitInfoTableChunk*
-jit_info_table_new_chunk (void)
-{
- MonoJitInfoTableChunk *chunk = g_new0 (MonoJitInfoTableChunk, 1);
- chunk->refcount = 1;
-
- return chunk;
-}
-
-static MonoJitInfoTable *
-jit_info_table_new (MonoDomain *domain)
-{
- MonoJitInfoTable *table = g_malloc0 (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*));
-
- table->domain = domain;
- table->num_chunks = 1;
- table->chunks [0] = jit_info_table_new_chunk ();
-
- return table;
-}
-
-static void
-jit_info_table_free (MonoJitInfoTable *table)
-{
- int i;
- int num_chunks = table->num_chunks;
- MonoDomain *domain = table->domain;
-
- mono_domain_lock (domain);
-
- table->domain->num_jit_info_tables--;
- if (table->domain->num_jit_info_tables <= 1) {
- GSList *list;
-
- for (list = table->domain->jit_info_free_queue; list; list = list->next)
- g_free (list->data);
-
- g_slist_free (table->domain->jit_info_free_queue);
- table->domain->jit_info_free_queue = NULL;
- }
-
- /* At this point we assume that there are no other threads
- still accessing the table, so we don't have to worry about
- hazardous pointers. */
-
- for (i = 0; i < num_chunks; ++i) {
- MonoJitInfoTableChunk *chunk = table->chunks [i];
- int num_elements;
- int j;
-
- if (--chunk->refcount > 0)
- continue;
-
- num_elements = chunk->num_elements;
- for (j = 0; j < num_elements; ++j) {
- MonoJitInfo *ji = chunk->data [j];
-
- if (IS_JIT_INFO_TOMBSTONE (ji))
- g_free (ji);
- }
-
- g_free (chunk);
- }
-
- mono_domain_unlock (domain);
-
- g_free (table);
-}
-
-/* The jit_info_table is sorted in ascending order by the end
- * addresses of the compiled methods. The reason why we have to do
- * this is that once we introduce tombstones, it becomes possible for
- * code ranges to overlap, and if we sort by code start and insert at
- * the back of the table, we cannot guarantee that we won't overlook
- * an entry.
- *
- * There are actually two possible ways to do the sorting and
- * inserting which work with our lock-free mechanism:
- *
- * 1. Sort by start address and insert at the front. When looking for
- * an entry, find the last one with a start address lower than the one
- * you're looking for, then work your way to the front of the table.
- *
- * 2. Sort by end address and insert at the back. When looking for an
- * entry, find the first one with an end address higher than the one
- * you're looking for, then work your way to the end of the table.
- *
- * We chose the latter out of convenience.
- */
-static int
-jit_info_table_index (MonoJitInfoTable *table, gint8 *addr)
-{
- int left = 0, right = table->num_chunks;
-
- g_assert (left < right);
-
- do {
- int pos = (left + right) / 2;
- MonoJitInfoTableChunk *chunk = table->chunks [pos];
-
- if (addr < chunk->last_code_end)
- right = pos;
- else
- left = pos + 1;
- } while (left < right);
- g_assert (left == right);
-
- if (left >= table->num_chunks)
- return table->num_chunks - 1;
- return left;
-}
-
-static int
-jit_info_table_chunk_index (MonoJitInfoTableChunk *chunk, MonoThreadHazardPointers *hp, gint8 *addr)
-{
- int left = 0, right = chunk->num_elements;
-
- while (left < right) {
- int pos = (left + right) / 2;
- MonoJitInfo *ji = get_hazardous_pointer((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
- gint8 *code_end = (gint8*)ji->code_start + ji->code_size;
-
- if (addr < code_end)
- right = pos;
- else
- left = pos + 1;
- }
- g_assert (left == right);
-
- return left;
-}
-
-static MonoJitInfo*
-jit_info_table_find (MonoJitInfoTable *table, MonoThreadHazardPointers *hp, gint8 *addr)
-{
- MonoJitInfo *ji;
- int chunk_pos, pos;
-
- chunk_pos = jit_info_table_index (table, (gint8*)addr);
- g_assert (chunk_pos < table->num_chunks);
-
- pos = jit_info_table_chunk_index (table->chunks [chunk_pos], hp, (gint8*)addr);
-
- /* We now have a position that's very close to that of the
- first element whose end address is higher than the one
- we're looking for. If we don't have the exact position,
- then we have a position below that one, so we'll just
- search upward until we find our element. */
- do {
- MonoJitInfoTableChunk *chunk = table->chunks [chunk_pos];
-
- while (pos < chunk->num_elements) {
- ji = get_hazardous_pointer ((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
-
- ++pos;
-
- if (IS_JIT_INFO_TOMBSTONE (ji)) {
- mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
- continue;
- }
- if ((gint8*)addr >= (gint8*)ji->code_start
- && (gint8*)addr < (gint8*)ji->code_start + ji->code_size) {
- mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
- return ji;
- }
-
- /* If we find a non-tombstone element which is already
- beyond what we're looking for, we have to end the
- search. */
- if ((gint8*)addr < (gint8*)ji->code_start)
- goto not_found;
- }
-
- ++chunk_pos;
- pos = 0;
- } while (chunk_pos < table->num_chunks);
-
- not_found:
- if (hp)
- mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
- return NULL;
-}
-
-/*
- * mono_jit_info_table_find_internal:
- *
- * If TRY_AOT is FALSE, avoid loading information for missing methods from AOT images, which is currently not async safe.
- * In this case, only those AOT methods will be found whose jit info is already loaded.
- * ASYNC SAFETY: When called in an async context (mono_thread_info_is_async_context ()), this is async safe.
- * In this case, the returned MonoJitInfo might not have metadata information, in particular,
- * mono_jit_info_get_method () could fail.
- */
-MonoJitInfo*
-mono_jit_info_table_find_internal (MonoDomain *domain, char *addr, gboolean try_aot)
-{
- MonoJitInfoTable *table;
- MonoJitInfo *ji, *module_ji;
- MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
-
- ++mono_stats.jit_info_table_lookup_count;
-
- /* First we have to get the domain's jit_info_table. This is
- complicated by the fact that a writer might substitute a
- new table and free the old one. What the writer guarantees
- us is that it looks at the hazard pointers after it has
- changed the jit_info_table pointer. So, if we guard the
- table by a hazard pointer and make sure that the pointer is
- still there after we've made it hazardous, we don't have to
- worry about the writer freeing the table. */
- table = get_hazardous_pointer ((gpointer volatile*)&domain->jit_info_table, hp, JIT_INFO_TABLE_HAZARD_INDEX);
-
- ji = jit_info_table_find (table, hp, (gint8*)addr);
- if (hp)
- mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
- if (ji)
- return ji;
-
- /* Maybe its an AOT module */
- if (try_aot && mono_root_domain && mono_root_domain->aot_modules) {
- table = get_hazardous_pointer ((gpointer volatile*)&mono_root_domain->aot_modules, hp, JIT_INFO_TABLE_HAZARD_INDEX);
- module_ji = jit_info_table_find (table, hp, (gint8*)addr);
- if (module_ji)
- ji = jit_info_find_in_aot_func (domain, module_ji->d.image, addr);
- if (hp)
- mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
- }
-
- return ji;
-}
-
-MonoJitInfo*
-mono_jit_info_table_find (MonoDomain *domain, char *addr)
-{
- return mono_jit_info_table_find_internal (domain, addr, TRUE);
-}
-
-static G_GNUC_UNUSED void
-jit_info_table_check (MonoJitInfoTable *table)
-{
- int i;
-
- for (i = 0; i < table->num_chunks; ++i) {
- MonoJitInfoTableChunk *chunk = table->chunks [i];
- int j;
-
- g_assert (chunk->refcount > 0 /* && chunk->refcount <= 8 */);
- if (chunk->refcount > 10)
- printf("warning: chunk refcount is %d\n", chunk->refcount);
- g_assert (chunk->num_elements <= MONO_JIT_INFO_TABLE_CHUNK_SIZE);
-
- for (j = 0; j < chunk->num_elements; ++j) {
- MonoJitInfo *this = chunk->data [j];
- MonoJitInfo *next;
-
- g_assert ((gint8*)this->code_start + this->code_size <= chunk->last_code_end);
-
- if (j < chunk->num_elements - 1)
- next = chunk->data [j + 1];
- else if (i < table->num_chunks - 1) {
- int k;
-
- for (k = i + 1; k < table->num_chunks; ++k)
- if (table->chunks [k]->num_elements > 0)
- break;
-
- if (k >= table->num_chunks)
- return;
-
- g_assert (table->chunks [k]->num_elements > 0);
- next = table->chunks [k]->data [0];
- } else
- return;
-
- g_assert ((gint8*)this->code_start + this->code_size <= (gint8*)next->code_start + next->code_size);
- }
- }
-}
-
-static MonoJitInfoTable*
-jit_info_table_realloc (MonoJitInfoTable *old)
-{
- int i;
- int num_elements = jit_info_table_num_elements (old);
- int required_size;
- int num_chunks;
- int new_chunk, new_element;
- MonoJitInfoTable *new;
-
- /* number of needed places for elements needed */
- required_size = (int)((long)num_elements * JIT_INFO_TABLE_FILL_RATIO_DENOM / JIT_INFO_TABLE_FILL_RATIO_NOM);
- num_chunks = (required_size + MONO_JIT_INFO_TABLE_CHUNK_SIZE - 1) / MONO_JIT_INFO_TABLE_CHUNK_SIZE;
- if (num_chunks == 0) {
- g_assert (num_elements == 0);
- return jit_info_table_new (old->domain);
- }
- g_assert (num_chunks > 0);
-
- new = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*) * num_chunks);
- new->domain = old->domain;
- new->num_chunks = num_chunks;
-
- for (i = 0; i < num_chunks; ++i)
- new->chunks [i] = jit_info_table_new_chunk ();
-
- new_chunk = 0;
- new_element = 0;
- for (i = 0; i < old->num_chunks; ++i) {
- MonoJitInfoTableChunk *chunk = old->chunks [i];
- int chunk_num_elements = chunk->num_elements;
- int j;
-
- for (j = 0; j < chunk_num_elements; ++j) {
- if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j])) {
- g_assert (new_chunk < num_chunks);
- new->chunks [new_chunk]->data [new_element] = chunk->data [j];
- if (++new_element >= JIT_INFO_TABLE_FILLED_NUM_ELEMENTS) {
- new->chunks [new_chunk]->num_elements = new_element;
- ++new_chunk;
- new_element = 0;
- }
- }
- }
- }
-
- if (new_chunk < num_chunks) {
- g_assert (new_chunk == num_chunks - 1);
- new->chunks [new_chunk]->num_elements = new_element;
- g_assert (new->chunks [new_chunk]->num_elements > 0);
- }
-
- for (i = 0; i < num_chunks; ++i) {
- MonoJitInfoTableChunk *chunk = new->chunks [i];
- MonoJitInfo *ji = chunk->data [chunk->num_elements - 1];
-
- new->chunks [i]->last_code_end = (gint8*)ji->code_start + ji->code_size;
- }
-
- return new;
-}
-
-static void
-jit_info_table_split_chunk (MonoJitInfoTableChunk *chunk, MonoJitInfoTableChunk **new1p, MonoJitInfoTableChunk **new2p)
-{
- MonoJitInfoTableChunk *new1 = jit_info_table_new_chunk ();
- MonoJitInfoTableChunk *new2 = jit_info_table_new_chunk ();
-
- g_assert (chunk->num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE);
-
- new1->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE / 2;
- new2->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE - new1->num_elements;
-
- memcpy ((void*)new1->data, (void*)chunk->data, sizeof (MonoJitInfo*) * new1->num_elements);
- memcpy ((void*)new2->data, (void*)(chunk->data + new1->num_elements), sizeof (MonoJitInfo*) * new2->num_elements);
-
- new1->last_code_end = (gint8*)new1->data [new1->num_elements - 1]->code_start
- + new1->data [new1->num_elements - 1]->code_size;
- new2->last_code_end = (gint8*)new2->data [new2->num_elements - 1]->code_start
- + new2->data [new2->num_elements - 1]->code_size;
-
- *new1p = new1;
- *new2p = new2;
-}
-
-static MonoJitInfoTable*
-jit_info_table_copy_and_split_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
-{
- MonoJitInfoTable *new_table = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
- + sizeof (MonoJitInfoTableChunk*) * (table->num_chunks + 1));
- int i, j;
-
- new_table->domain = table->domain;
- new_table->num_chunks = table->num_chunks + 1;
-
- j = 0;
- for (i = 0; i < table->num_chunks; ++i) {
- if (table->chunks [i] == chunk) {
- jit_info_table_split_chunk (chunk, &new_table->chunks [j], &new_table->chunks [j + 1]);
- j += 2;
- } else {
- new_table->chunks [j] = table->chunks [i];
- ++new_table->chunks [j]->refcount;
- ++j;
- }
- }
-
- g_assert (j == new_table->num_chunks);
-
- return new_table;
-}
-
-static MonoJitInfoTableChunk*
-jit_info_table_purify_chunk (MonoJitInfoTableChunk *old)
-{
- MonoJitInfoTableChunk *new = jit_info_table_new_chunk ();
- int i, j;
-
- j = 0;
- for (i = 0; i < old->num_elements; ++i) {
- if (!IS_JIT_INFO_TOMBSTONE (old->data [i]))
- new->data [j++] = old->data [i];
- }
-
- new->num_elements = j;
- if (new->num_elements > 0)
- new->last_code_end = (gint8*)new->data [j - 1]->code_start + new->data [j - 1]->code_size;
- else
- new->last_code_end = old->last_code_end;
-
- return new;
-}
-
-static MonoJitInfoTable*
-jit_info_table_copy_and_purify_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
-{
- MonoJitInfoTable *new_table = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
- + sizeof (MonoJitInfoTableChunk*) * table->num_chunks);
- int i, j;
-
- new_table->domain = table->domain;
- new_table->num_chunks = table->num_chunks;
-
- j = 0;
- for (i = 0; i < table->num_chunks; ++i) {
- if (table->chunks [i] == chunk)
- new_table->chunks [j++] = jit_info_table_purify_chunk (table->chunks [i]);
- else {
- new_table->chunks [j] = table->chunks [i];
- ++new_table->chunks [j]->refcount;
- ++j;
- }
- }
-
- g_assert (j == new_table->num_chunks);
-
- return new_table;
-}
-
-/* As we add an element to the table the case can arise that the chunk
- * to which we need to add is already full. In that case we have to
- * allocate a new table and do something about that chunk. We have
- * several strategies:
- *
- * If the number of elements in the table is below the low watermark
- * or above the high watermark, we reallocate the whole table.
- * Otherwise we only concern ourselves with the overflowing chunk:
- *
- * If there are no tombstones in the chunk then we split the chunk in
- * two, each half full.
- *
- * If the chunk does contain tombstones, we just make a new copy of
- * the chunk without the tombstones, which will have room for at least
- * the one element we have to add.
- */
-static MonoJitInfoTable*
-jit_info_table_chunk_overflow (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
-{
- int num_elements = jit_info_table_num_elements (table);
- int i;
-
- if (num_elements < JIT_INFO_TABLE_LOW_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)
- || num_elements > JIT_INFO_TABLE_HIGH_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)) {
- //printf ("reallocing table\n");
- return jit_info_table_realloc (table);
- }
-
- /* count the number of non-tombstone elements in the chunk */
- num_elements = 0;
- for (i = 0; i < chunk->num_elements; ++i) {
- if (!IS_JIT_INFO_TOMBSTONE (chunk->data [i]))
- ++num_elements;
- }
-
- if (num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
- //printf ("splitting chunk\n");
- return jit_info_table_copy_and_split_chunk (table, chunk);
- }
-
- //printf ("purifying chunk\n");
- return jit_info_table_copy_and_purify_chunk (table, chunk);
-}
-
-/* We add elements to the table by first making space for them by
- * shifting the elements at the back to the right, one at a time.
- * This results in duplicate entries during the process, but during
- * all the time the table is in a sorted state. Also, when an element
- * is replaced by another one, the element that replaces it has an end
- * address that is equal to or lower than that of the replaced
- * element. That property is necessary to guarantee that when
- * searching for an element we end up at a position not higher than
- * the one we're looking for (i.e. we either find the element directly
- * or we end up to the left of it).
- */
-static void
-jit_info_table_add (MonoDomain *domain, MonoJitInfoTable *volatile *table_ptr, MonoJitInfo *ji)
-{
- MonoJitInfoTable *table;
- MonoJitInfoTableChunk *chunk;
- int chunk_pos, pos;
- int num_elements;
- int i;
-
- table = *table_ptr;
-
- restart:
- chunk_pos = jit_info_table_index (table, (gint8*)ji->code_start + ji->code_size);
- g_assert (chunk_pos < table->num_chunks);
- chunk = table->chunks [chunk_pos];
-
- if (chunk->num_elements >= MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
- MonoJitInfoTable *new_table = jit_info_table_chunk_overflow (table, chunk);
-
- /* Debugging code, should be removed. */
- //jit_info_table_check (new_table);
-
- *table_ptr = new_table;
- mono_memory_barrier ();
- domain->num_jit_info_tables++;
- mono_thread_hazardous_free_or_queue (table, (MonoHazardousFreeFunc)jit_info_table_free, TRUE, FALSE);
- table = new_table;
-
- goto restart;
- }
-
- /* Debugging code, should be removed. */
- //jit_info_table_check (table);
-
- num_elements = chunk->num_elements;
-
- pos = jit_info_table_chunk_index (chunk, NULL, (gint8*)ji->code_start + ji->code_size);
-
- /* First we need to size up the chunk by one, by copying the
- last item, or inserting the first one, if the table is
- empty. */
- if (num_elements > 0)
- chunk->data [num_elements] = chunk->data [num_elements - 1];
- else
- chunk->data [0] = ji;
- mono_memory_write_barrier ();
- chunk->num_elements = ++num_elements;
-
- /* Shift the elements up one by one. */
- for (i = num_elements - 2; i >= pos; --i) {
- mono_memory_write_barrier ();
- chunk->data [i + 1] = chunk->data [i];
- }
-
- /* Now we have room and can insert the new item. */
- mono_memory_write_barrier ();
- chunk->data [pos] = ji;
-
- /* Set the high code end address chunk entry. */
- chunk->last_code_end = (gint8*)chunk->data [chunk->num_elements - 1]->code_start
- + chunk->data [chunk->num_elements - 1]->code_size;
-
- /* Debugging code, should be removed. */
- //jit_info_table_check (table);
-}
-
-void
-mono_jit_info_table_add (MonoDomain *domain, MonoJitInfo *ji)
-{
- g_assert (ji->d.method != NULL);
-
- mono_domain_lock (domain);
-
- ++mono_stats.jit_info_table_insert_count;
-
- jit_info_table_add (domain, &domain->jit_info_table, ji);
-
- mono_domain_unlock (domain);
-}
-
-static MonoJitInfo*
-mono_jit_info_make_tombstone (MonoJitInfo *ji)
-{
- MonoJitInfo *tombstone = g_new0 (MonoJitInfo, 1);
-
- tombstone->code_start = ji->code_start;
- tombstone->code_size = ji->code_size;
- tombstone->d.method = JIT_INFO_TOMBSTONE_MARKER;
-
- return tombstone;
-}
-
-/*
- * LOCKING: domain lock
- */
-static void
-mono_jit_info_free_or_queue (MonoDomain *domain, MonoJitInfo *ji)
-{
- if (domain->num_jit_info_tables <= 1) {
- /* Can it actually happen that we only have one table
- but ji is still hazardous? */
- mono_thread_hazardous_free_or_queue (ji, g_free, TRUE, FALSE);
- } else {
- domain->jit_info_free_queue = g_slist_prepend (domain->jit_info_free_queue, ji);
- }
-}
-
-static void
-jit_info_table_remove (MonoJitInfoTable *table, MonoJitInfo *ji)
-{
- MonoJitInfoTableChunk *chunk;
- gpointer start = ji->code_start;
- int chunk_pos, pos;
-
- chunk_pos = jit_info_table_index (table, start);
- g_assert (chunk_pos < table->num_chunks);
-
- pos = jit_info_table_chunk_index (table->chunks [chunk_pos], NULL, start);
-
- do {
- chunk = table->chunks [chunk_pos];
-
- while (pos < chunk->num_elements) {
- if (chunk->data [pos] == ji)
- goto found;
-
- g_assert (IS_JIT_INFO_TOMBSTONE (chunk->data [pos]));
- g_assert ((guint8*)chunk->data [pos]->code_start + chunk->data [pos]->code_size
- <= (guint8*)ji->code_start + ji->code_size);
-
- ++pos;
- }
-
- ++chunk_pos;
- pos = 0;
- } while (chunk_pos < table->num_chunks);
-
- found:
- g_assert (chunk->data [pos] == ji);
-
- chunk->data [pos] = mono_jit_info_make_tombstone (ji);
-
- /* Debugging code, should be removed. */
- //jit_info_table_check (table);
-}
-
-void
-mono_jit_info_table_remove (MonoDomain *domain, MonoJitInfo *ji)
-{
- MonoJitInfoTable *table;
-
- mono_domain_lock (domain);
- table = domain->jit_info_table;
-
- ++mono_stats.jit_info_table_remove_count;
-
- jit_info_table_remove (table, ji);
-
- mono_jit_info_free_or_queue (domain, ji);
-
- mono_domain_unlock (domain);
-}
-
-void
-mono_jit_info_add_aot_module (MonoImage *image, gpointer start, gpointer end)
-{
- MonoJitInfo *ji;
-
- g_assert (mono_root_domain);
- mono_domain_lock (mono_root_domain);
-
- /*
- * We reuse MonoJitInfoTable to store AOT module info,
- * this gives us async-safe lookup.
- */
- if (!mono_root_domain->aot_modules) {
- mono_root_domain->num_jit_info_tables ++;
- mono_root_domain->aot_modules = jit_info_table_new (mono_root_domain);
- }
-
- ji = g_new0 (MonoJitInfo, 1);
- ji->d.image = image;
- ji->code_start = start;
- ji->code_size = (guint8*)end - (guint8*)start;
- jit_info_table_add (mono_root_domain, &mono_root_domain->aot_modules, ji);
-
- mono_domain_unlock (mono_root_domain);
-}
-
-void
-mono_install_jit_info_find_in_aot (MonoJitInfoFindInAot func)
-{
- jit_info_find_in_aot_func = func;
-}
-
-gpointer
-mono_jit_info_get_code_start (MonoJitInfo* ji)
-{
- return ji->code_start;
-}
-
-int
-mono_jit_info_get_code_size (MonoJitInfo* ji)
-{
- return ji->code_size;
-}
-
-MonoMethod*
-mono_jit_info_get_method (MonoJitInfo* ji)
-{
- g_assert (!ji->async);
- return ji->d.method;
-}
-
-static gpointer
-jit_info_key_extract (gpointer value)
-{
- MonoJitInfo *info = (MonoJitInfo*)value;
-
- return info->d.method;
-}
-
-static gpointer*
-jit_info_next_value (gpointer value)
-{
- MonoJitInfo *info = (MonoJitInfo*)value;
-
- return (gpointer*)&info->next_jit_code_hash;
-}
-
-void
-mono_jit_code_hash_init (MonoInternalHashTable *jit_code_hash)
-{
- mono_internal_hash_table_init (jit_code_hash,
- mono_aligned_addr_hash,
- jit_info_key_extract,
- jit_info_next_value);
-}
-
-MonoGenericJitInfo*
-mono_jit_info_get_generic_jit_info (MonoJitInfo *ji)
-{
- if (ji->has_generic_jit_info)
- return (MonoGenericJitInfo*)&ji->clauses [ji->num_clauses];
- else
- return NULL;
-}
-
-/*
- * mono_jit_info_get_generic_sharing_context:
- * @ji: a jit info
- *
- * Returns the jit info's generic sharing context, or NULL if it
- * doesn't have one.
- */
-MonoGenericSharingContext*
-mono_jit_info_get_generic_sharing_context (MonoJitInfo *ji)
-{
- MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
-
- if (gi)
- return gi->generic_sharing_context;
- else
- return NULL;
-}
-
-/*
- * mono_jit_info_set_generic_sharing_context:
- * @ji: a jit info
- * @gsctx: a generic sharing context
- *
- * Sets the jit info's generic sharing context. The jit info must
- * have memory allocated for the context.
- */
-void
-mono_jit_info_set_generic_sharing_context (MonoJitInfo *ji, MonoGenericSharingContext *gsctx)
-{
- MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
-
- g_assert (gi);
-
- gi->generic_sharing_context = gsctx;
-}
-
-MonoTryBlockHoleTableJitInfo*
-mono_jit_info_get_try_block_hole_table_info (MonoJitInfo *ji)
-{
- if (ji->has_try_block_holes) {
- char *ptr = (char*)&ji->clauses [ji->num_clauses];
- if (ji->has_generic_jit_info)
- ptr += sizeof (MonoGenericJitInfo);
- return (MonoTryBlockHoleTableJitInfo*)ptr;
- } else {
- return NULL;
- }
-}
-
-static int
-try_block_hole_table_size (MonoJitInfo *ji)
-{
- MonoTryBlockHoleTableJitInfo *table;
-
- table = mono_jit_info_get_try_block_hole_table_info (ji);
- g_assert (table);
- return sizeof (MonoTryBlockHoleTableJitInfo) + table->num_holes * sizeof (MonoTryBlockHoleJitInfo);
-}
-
-MonoArchEHJitInfo*
-mono_jit_info_get_arch_eh_info (MonoJitInfo *ji)
-{
- if (ji->has_arch_eh_info) {
- char *ptr = (char*)&ji->clauses [ji->num_clauses];
- if (ji->has_generic_jit_info)
- ptr += sizeof (MonoGenericJitInfo);
- if (ji->has_try_block_holes)
- ptr += try_block_hole_table_size (ji);
- return (MonoArchEHJitInfo*)ptr;
- } else {
- return NULL;
- }
-}
-
-MonoMethodCasInfo*
-mono_jit_info_get_cas_info (MonoJitInfo *ji)
-{
- if (ji->has_cas_info) {
- char *ptr = (char*)&ji->clauses [ji->num_clauses];
- if (ji->has_generic_jit_info)
- ptr += sizeof (MonoGenericJitInfo);
- if (ji->has_try_block_holes)
- ptr += try_block_hole_table_size (ji);
- if (ji->has_arch_eh_info)
- ptr += sizeof (MonoArchEHJitInfo);
- return (MonoMethodCasInfo*)ptr;
- } else {
- return NULL;
- }
-}
-
#define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
#define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1)))
mono_jit_code_hash_init (&domain->jit_code_hash);
domain->ldstr_table = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC);
domain->num_jit_info_tables = 1;
- domain->jit_info_table = jit_info_table_new (domain);
+ domain->jit_info_table = mono_jit_info_table_new (domain);
domain->jit_info_free_queue = NULL;
domain->finalizable_objects_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
domain->ftnptrs_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
*/
mono_thread_hazardous_try_free_all ();
if (domain->aot_modules)
- jit_info_table_free (domain->aot_modules);
+ mono_jit_info_table_free (domain->aot_modules);
g_assert (domain->num_jit_info_tables == 1);
- jit_info_table_free (domain->jit_info_table);
+ mono_jit_info_table_free (domain->jit_info_table);
domain->jit_info_table = NULL;
g_assert (!domain->jit_info_free_queue);
*/
gboolean mono_gc_is_disabled (void) MONO_INTERNAL;
+void mono_gc_set_string_length (MonoString *str, gint32 new_length) MONO_INTERNAL;
+
#if defined(__MACH__)
void mono_gc_register_mach_exception_thread (pthread_t thread) MONO_INTERNAL;
pthread_t mono_gc_get_mach_exception_thread (void) MONO_INTERNAL;
ret = WaitForSingleObjectEx (gc_thread->handle, INFINITE, TRUE);
g_assert (ret == WAIT_OBJECT_0);
- mono_thread_join ((gpointer)gc_thread->tid);
+ mono_thread_join (MONO_UINT_TO_NATIVE_THREAD_ID (gc_thread->tid));
}
}
gc_thread = NULL;
ICALL(STRING_9, "InternalAllocateStr", ves_icall_System_String_InternalAllocateStr)
ICALL(STRING_10, "InternalIntern", ves_icall_System_String_InternalIntern)
ICALL(STRING_11, "InternalIsInterned", ves_icall_System_String_InternalIsInterned)
+ICALL(STRING_12, "InternalSetLength", ves_icall_System_String_InternalSetLength)
ICALL_TYPE(TENC, "System.Text.Encoding", TENC_1)
ICALL(TENC_1, "InternalCodePage", ves_icall_System_Text_Encoding_InternalCodePage)
--- /dev/null
+/*
+ * jit-info.c: MonoJitInfo functionality
+ *
+ * Author:
+ * Dietmar Maurer (dietmar@ximian.com)
+ * Patrik Torstensson
+ *
+ * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
+ * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
+ * Copyright 2011-2012 Xamarin, Inc (http://www.xamarin.com)
+ */
+
+#include <config.h>
+#include <glib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include <mono/metadata/gc-internal.h>
+
+#include <mono/utils/atomic.h>
+#include <mono/utils/mono-compiler.h>
+#include <mono/utils/mono-logger-internal.h>
+#include <mono/utils/mono-membar.h>
+#include <mono/utils/mono-counters.h>
+#include <mono/utils/hazard-pointer.h>
+#include <mono/utils/mono-tls.h>
+#include <mono/utils/mono-mmap.h>
+#include <mono/utils/mono-threads.h>
+#include <mono/metadata/object.h>
+#include <mono/metadata/object-internals.h>
+#include <mono/metadata/domain-internals.h>
+#include <mono/metadata/class-internals.h>
+#include <mono/metadata/assembly.h>
+#include <mono/metadata/exception.h>
+#include <mono/metadata/metadata-internals.h>
+#include <mono/metadata/gc-internal.h>
+#include <mono/metadata/appdomain.h>
+#include <mono/metadata/mono-debug-debugger.h>
+#include <mono/metadata/mono-config.h>
+#include <mono/metadata/threads-types.h>
+#include <mono/metadata/runtime.h>
+#include <metadata/threads.h>
+#include <metadata/profiler-private.h>
+#include <mono/metadata/coree.h>
+
+static MonoJitInfoFindInAot jit_info_find_in_aot_func = NULL;
+
+#define JIT_INFO_TABLE_FILL_RATIO_NOM 3
+#define JIT_INFO_TABLE_FILL_RATIO_DENOM 4
+#define JIT_INFO_TABLE_FILLED_NUM_ELEMENTS (MONO_JIT_INFO_TABLE_CHUNK_SIZE * JIT_INFO_TABLE_FILL_RATIO_NOM / JIT_INFO_TABLE_FILL_RATIO_DENOM)
+
+#define JIT_INFO_TABLE_LOW_WATERMARK(n) ((n) / 2)
+#define JIT_INFO_TABLE_HIGH_WATERMARK(n) ((n) * 5 / 6)
+
+#define JIT_INFO_TOMBSTONE_MARKER ((MonoMethod*)NULL)
+#define IS_JIT_INFO_TOMBSTONE(ji) ((ji)->d.method == JIT_INFO_TOMBSTONE_MARKER)
+
+#define JIT_INFO_TABLE_HAZARD_INDEX 0
+#define JIT_INFO_HAZARD_INDEX 1
+
+static int
+jit_info_table_num_elements (MonoJitInfoTable *table)
+{
+ int i;
+ int num_elements = 0;
+
+ for (i = 0; i < table->num_chunks; ++i) {
+ MonoJitInfoTableChunk *chunk = table->chunks [i];
+ int chunk_num_elements = chunk->num_elements;
+ int j;
+
+ for (j = 0; j < chunk_num_elements; ++j) {
+ if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j]))
+ ++num_elements;
+ }
+ }
+
+ return num_elements;
+}
+
+static MonoJitInfoTableChunk*
+jit_info_table_new_chunk (void)
+{
+ MonoJitInfoTableChunk *chunk = g_new0 (MonoJitInfoTableChunk, 1);
+ chunk->refcount = 1;
+
+ return chunk;
+}
+
+MonoJitInfoTable *
+mono_jit_info_table_new (MonoDomain *domain)
+{
+ MonoJitInfoTable *table = g_malloc0 (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*));
+
+ table->domain = domain;
+ table->num_chunks = 1;
+ table->chunks [0] = jit_info_table_new_chunk ();
+
+ return table;
+}
+
+void
+mono_jit_info_table_free (MonoJitInfoTable *table)
+{
+ int i;
+ int num_chunks = table->num_chunks;
+ MonoDomain *domain = table->domain;
+
+ mono_domain_lock (domain);
+
+ table->domain->num_jit_info_tables--;
+ if (table->domain->num_jit_info_tables <= 1) {
+ GSList *list;
+
+ for (list = table->domain->jit_info_free_queue; list; list = list->next)
+ g_free (list->data);
+
+ g_slist_free (table->domain->jit_info_free_queue);
+ table->domain->jit_info_free_queue = NULL;
+ }
+
+ /* At this point we assume that there are no other threads
+ still accessing the table, so we don't have to worry about
+ hazardous pointers. */
+
+ for (i = 0; i < num_chunks; ++i) {
+ MonoJitInfoTableChunk *chunk = table->chunks [i];
+ int num_elements;
+ int j;
+
+ if (--chunk->refcount > 0)
+ continue;
+
+ num_elements = chunk->num_elements;
+ for (j = 0; j < num_elements; ++j) {
+ MonoJitInfo *ji = chunk->data [j];
+
+ if (IS_JIT_INFO_TOMBSTONE (ji))
+ g_free (ji);
+ }
+
+ g_free (chunk);
+ }
+
+ mono_domain_unlock (domain);
+
+ g_free (table);
+}
+
+/* The jit_info_table is sorted in ascending order by the end
+ * addresses of the compiled methods. The reason why we have to do
+ * this is that once we introduce tombstones, it becomes possible for
+ * code ranges to overlap, and if we sort by code start and insert at
+ * the back of the table, we cannot guarantee that we won't overlook
+ * an entry.
+ *
+ * There are actually two possible ways to do the sorting and
+ * inserting which work with our lock-free mechanism:
+ *
+ * 1. Sort by start address and insert at the front. When looking for
+ * an entry, find the last one with a start address lower than the one
+ * you're looking for, then work your way to the front of the table.
+ *
+ * 2. Sort by end address and insert at the back. When looking for an
+ * entry, find the first one with an end address higher than the one
+ * you're looking for, then work your way to the end of the table.
+ *
+ * We chose the latter out of convenience.
+ */
+static int
+jit_info_table_index (MonoJitInfoTable *table, gint8 *addr)
+{
+ int left = 0, right = table->num_chunks;
+
+ g_assert (left < right);
+
+ do {
+ int pos = (left + right) / 2;
+ MonoJitInfoTableChunk *chunk = table->chunks [pos];
+
+ if (addr < chunk->last_code_end)
+ right = pos;
+ else
+ left = pos + 1;
+ } while (left < right);
+ g_assert (left == right);
+
+ if (left >= table->num_chunks)
+ return table->num_chunks - 1;
+ return left;
+}
+
+static int
+jit_info_table_chunk_index (MonoJitInfoTableChunk *chunk, MonoThreadHazardPointers *hp, gint8 *addr)
+{
+ int left = 0, right = chunk->num_elements;
+
+ while (left < right) {
+ int pos = (left + right) / 2;
+ MonoJitInfo *ji = get_hazardous_pointer((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
+ gint8 *code_end = (gint8*)ji->code_start + ji->code_size;
+
+ if (addr < code_end)
+ right = pos;
+ else
+ left = pos + 1;
+ }
+ g_assert (left == right);
+
+ return left;
+}
+
+static MonoJitInfo*
+jit_info_table_find (MonoJitInfoTable *table, MonoThreadHazardPointers *hp, gint8 *addr)
+{
+ MonoJitInfo *ji;
+ int chunk_pos, pos;
+
+ chunk_pos = jit_info_table_index (table, (gint8*)addr);
+ g_assert (chunk_pos < table->num_chunks);
+
+ pos = jit_info_table_chunk_index (table->chunks [chunk_pos], hp, (gint8*)addr);
+
+ /* We now have a position that's very close to that of the
+ first element whose end address is higher than the one
+ we're looking for. If we don't have the exact position,
+ then we have a position below that one, so we'll just
+ search upward until we find our element. */
+ do {
+ MonoJitInfoTableChunk *chunk = table->chunks [chunk_pos];
+
+ while (pos < chunk->num_elements) {
+ ji = get_hazardous_pointer ((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
+
+ ++pos;
+
+ if (IS_JIT_INFO_TOMBSTONE (ji)) {
+ mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
+ continue;
+ }
+ if ((gint8*)addr >= (gint8*)ji->code_start
+ && (gint8*)addr < (gint8*)ji->code_start + ji->code_size) {
+ mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
+ return ji;
+ }
+
+ /* If we find a non-tombstone element which is already
+ beyond what we're looking for, we have to end the
+ search. */
+ if ((gint8*)addr < (gint8*)ji->code_start)
+ goto not_found;
+ }
+
+ ++chunk_pos;
+ pos = 0;
+ } while (chunk_pos < table->num_chunks);
+
+ not_found:
+ if (hp)
+ mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
+ return NULL;
+}
+
+/*
+ * mono_jit_info_table_find_internal:
+ *
+ * If TRY_AOT is FALSE, avoid loading information for missing methods from AOT images, which is currently not async safe.
+ * In this case, only those AOT methods will be found whose jit info is already loaded.
+ * ASYNC SAFETY: When called in an async context (mono_thread_info_is_async_context ()), this is async safe.
+ * In this case, the returned MonoJitInfo might not have metadata information, in particular,
+ * mono_jit_info_get_method () could fail.
+ */
+MonoJitInfo*
+mono_jit_info_table_find_internal (MonoDomain *domain, char *addr, gboolean try_aot)
+{
+ MonoJitInfoTable *table;
+ MonoJitInfo *ji, *module_ji;
+ MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
+
+ ++mono_stats.jit_info_table_lookup_count;
+
+ /* First we have to get the domain's jit_info_table. This is
+ complicated by the fact that a writer might substitute a
+ new table and free the old one. What the writer guarantees
+ us is that it looks at the hazard pointers after it has
+ changed the jit_info_table pointer. So, if we guard the
+ table by a hazard pointer and make sure that the pointer is
+ still there after we've made it hazardous, we don't have to
+ worry about the writer freeing the table. */
+ table = get_hazardous_pointer ((gpointer volatile*)&domain->jit_info_table, hp, JIT_INFO_TABLE_HAZARD_INDEX);
+
+ ji = jit_info_table_find (table, hp, (gint8*)addr);
+ if (hp)
+ mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
+ if (ji)
+ return ji;
+
+ /* Maybe its an AOT module */
+ if (try_aot && mono_get_root_domain () && mono_get_root_domain ()->aot_modules) {
+ table = get_hazardous_pointer ((gpointer volatile*)&mono_get_root_domain ()->aot_modules, hp, JIT_INFO_TABLE_HAZARD_INDEX);
+ module_ji = jit_info_table_find (table, hp, (gint8*)addr);
+ if (module_ji)
+ ji = jit_info_find_in_aot_func (domain, module_ji->d.image, addr);
+ if (hp)
+ mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
+ }
+
+ return ji;
+}
+
+MonoJitInfo*
+mono_jit_info_table_find (MonoDomain *domain, char *addr)
+{
+ return mono_jit_info_table_find_internal (domain, addr, TRUE);
+}
+
+static G_GNUC_UNUSED void
+jit_info_table_check (MonoJitInfoTable *table)
+{
+ int i;
+
+ for (i = 0; i < table->num_chunks; ++i) {
+ MonoJitInfoTableChunk *chunk = table->chunks [i];
+ int j;
+
+ g_assert (chunk->refcount > 0 /* && chunk->refcount <= 8 */);
+ if (chunk->refcount > 10)
+ printf("warning: chunk refcount is %d\n", chunk->refcount);
+ g_assert (chunk->num_elements <= MONO_JIT_INFO_TABLE_CHUNK_SIZE);
+
+ for (j = 0; j < chunk->num_elements; ++j) {
+ MonoJitInfo *this = chunk->data [j];
+ MonoJitInfo *next;
+
+ g_assert ((gint8*)this->code_start + this->code_size <= chunk->last_code_end);
+
+ if (j < chunk->num_elements - 1)
+ next = chunk->data [j + 1];
+ else if (i < table->num_chunks - 1) {
+ int k;
+
+ for (k = i + 1; k < table->num_chunks; ++k)
+ if (table->chunks [k]->num_elements > 0)
+ break;
+
+ if (k >= table->num_chunks)
+ return;
+
+ g_assert (table->chunks [k]->num_elements > 0);
+ next = table->chunks [k]->data [0];
+ } else
+ return;
+
+ g_assert ((gint8*)this->code_start + this->code_size <= (gint8*)next->code_start + next->code_size);
+ }
+ }
+}
+
+static MonoJitInfoTable*
+jit_info_table_realloc (MonoJitInfoTable *old)
+{
+ int i;
+ int num_elements = jit_info_table_num_elements (old);
+ int required_size;
+ int num_chunks;
+ int new_chunk, new_element;
+ MonoJitInfoTable *new;
+
+ /* number of needed places for elements needed */
+ required_size = (int)((long)num_elements * JIT_INFO_TABLE_FILL_RATIO_DENOM / JIT_INFO_TABLE_FILL_RATIO_NOM);
+ num_chunks = (required_size + MONO_JIT_INFO_TABLE_CHUNK_SIZE - 1) / MONO_JIT_INFO_TABLE_CHUNK_SIZE;
+ if (num_chunks == 0) {
+ g_assert (num_elements == 0);
+ return mono_jit_info_table_new (old->domain);
+ }
+ g_assert (num_chunks > 0);
+
+ new = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*) * num_chunks);
+ new->domain = old->domain;
+ new->num_chunks = num_chunks;
+
+ for (i = 0; i < num_chunks; ++i)
+ new->chunks [i] = jit_info_table_new_chunk ();
+
+ new_chunk = 0;
+ new_element = 0;
+ for (i = 0; i < old->num_chunks; ++i) {
+ MonoJitInfoTableChunk *chunk = old->chunks [i];
+ int chunk_num_elements = chunk->num_elements;
+ int j;
+
+ for (j = 0; j < chunk_num_elements; ++j) {
+ if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j])) {
+ g_assert (new_chunk < num_chunks);
+ new->chunks [new_chunk]->data [new_element] = chunk->data [j];
+ if (++new_element >= JIT_INFO_TABLE_FILLED_NUM_ELEMENTS) {
+ new->chunks [new_chunk]->num_elements = new_element;
+ ++new_chunk;
+ new_element = 0;
+ }
+ }
+ }
+ }
+
+ if (new_chunk < num_chunks) {
+ g_assert (new_chunk == num_chunks - 1);
+ new->chunks [new_chunk]->num_elements = new_element;
+ g_assert (new->chunks [new_chunk]->num_elements > 0);
+ }
+
+ for (i = 0; i < num_chunks; ++i) {
+ MonoJitInfoTableChunk *chunk = new->chunks [i];
+ MonoJitInfo *ji = chunk->data [chunk->num_elements - 1];
+
+ new->chunks [i]->last_code_end = (gint8*)ji->code_start + ji->code_size;
+ }
+
+ return new;
+}
+
+static void
+jit_info_table_split_chunk (MonoJitInfoTableChunk *chunk, MonoJitInfoTableChunk **new1p, MonoJitInfoTableChunk **new2p)
+{
+ MonoJitInfoTableChunk *new1 = jit_info_table_new_chunk ();
+ MonoJitInfoTableChunk *new2 = jit_info_table_new_chunk ();
+
+ g_assert (chunk->num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE);
+
+ new1->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE / 2;
+ new2->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE - new1->num_elements;
+
+ memcpy ((void*)new1->data, (void*)chunk->data, sizeof (MonoJitInfo*) * new1->num_elements);
+ memcpy ((void*)new2->data, (void*)(chunk->data + new1->num_elements), sizeof (MonoJitInfo*) * new2->num_elements);
+
+ new1->last_code_end = (gint8*)new1->data [new1->num_elements - 1]->code_start
+ + new1->data [new1->num_elements - 1]->code_size;
+ new2->last_code_end = (gint8*)new2->data [new2->num_elements - 1]->code_start
+ + new2->data [new2->num_elements - 1]->code_size;
+
+ *new1p = new1;
+ *new2p = new2;
+}
+
+static MonoJitInfoTable*
+jit_info_table_copy_and_split_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
+{
+ MonoJitInfoTable *new_table = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
+ + sizeof (MonoJitInfoTableChunk*) * (table->num_chunks + 1));
+ int i, j;
+
+ new_table->domain = table->domain;
+ new_table->num_chunks = table->num_chunks + 1;
+
+ j = 0;
+ for (i = 0; i < table->num_chunks; ++i) {
+ if (table->chunks [i] == chunk) {
+ jit_info_table_split_chunk (chunk, &new_table->chunks [j], &new_table->chunks [j + 1]);
+ j += 2;
+ } else {
+ new_table->chunks [j] = table->chunks [i];
+ ++new_table->chunks [j]->refcount;
+ ++j;
+ }
+ }
+
+ g_assert (j == new_table->num_chunks);
+
+ return new_table;
+}
+
+static MonoJitInfoTableChunk*
+jit_info_table_purify_chunk (MonoJitInfoTableChunk *old)
+{
+ MonoJitInfoTableChunk *new = jit_info_table_new_chunk ();
+ int i, j;
+
+ j = 0;
+ for (i = 0; i < old->num_elements; ++i) {
+ if (!IS_JIT_INFO_TOMBSTONE (old->data [i]))
+ new->data [j++] = old->data [i];
+ }
+
+ new->num_elements = j;
+ if (new->num_elements > 0)
+ new->last_code_end = (gint8*)new->data [j - 1]->code_start + new->data [j - 1]->code_size;
+ else
+ new->last_code_end = old->last_code_end;
+
+ return new;
+}
+
+static MonoJitInfoTable*
+jit_info_table_copy_and_purify_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
+{
+ MonoJitInfoTable *new_table = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
+ + sizeof (MonoJitInfoTableChunk*) * table->num_chunks);
+ int i, j;
+
+ new_table->domain = table->domain;
+ new_table->num_chunks = table->num_chunks;
+
+ j = 0;
+ for (i = 0; i < table->num_chunks; ++i) {
+ if (table->chunks [i] == chunk)
+ new_table->chunks [j++] = jit_info_table_purify_chunk (table->chunks [i]);
+ else {
+ new_table->chunks [j] = table->chunks [i];
+ ++new_table->chunks [j]->refcount;
+ ++j;
+ }
+ }
+
+ g_assert (j == new_table->num_chunks);
+
+ return new_table;
+}
+
+/* As we add an element to the table the case can arise that the chunk
+ * to which we need to add is already full. In that case we have to
+ * allocate a new table and do something about that chunk. We have
+ * several strategies:
+ *
+ * If the number of elements in the table is below the low watermark
+ * or above the high watermark, we reallocate the whole table.
+ * Otherwise we only concern ourselves with the overflowing chunk:
+ *
+ * If there are no tombstones in the chunk then we split the chunk in
+ * two, each half full.
+ *
+ * If the chunk does contain tombstones, we just make a new copy of
+ * the chunk without the tombstones, which will have room for at least
+ * the one element we have to add.
+ */
+static MonoJitInfoTable*
+jit_info_table_chunk_overflow (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
+{
+ int num_elements = jit_info_table_num_elements (table);
+ int i;
+
+ if (num_elements < JIT_INFO_TABLE_LOW_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)
+ || num_elements > JIT_INFO_TABLE_HIGH_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)) {
+ //printf ("reallocing table\n");
+ return jit_info_table_realloc (table);
+ }
+
+ /* count the number of non-tombstone elements in the chunk */
+ num_elements = 0;
+ for (i = 0; i < chunk->num_elements; ++i) {
+ if (!IS_JIT_INFO_TOMBSTONE (chunk->data [i]))
+ ++num_elements;
+ }
+
+ if (num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
+ //printf ("splitting chunk\n");
+ return jit_info_table_copy_and_split_chunk (table, chunk);
+ }
+
+ //printf ("purifying chunk\n");
+ return jit_info_table_copy_and_purify_chunk (table, chunk);
+}
+
+/* We add elements to the table by first making space for them by
+ * shifting the elements at the back to the right, one at a time.
+ * This results in duplicate entries during the process, but during
+ * all the time the table is in a sorted state. Also, when an element
+ * is replaced by another one, the element that replaces it has an end
+ * address that is equal to or lower than that of the replaced
+ * element. That property is necessary to guarantee that when
+ * searching for an element we end up at a position not higher than
+ * the one we're looking for (i.e. we either find the element directly
+ * or we end up to the left of it).
+ */
+static void
+jit_info_table_add (MonoDomain *domain, MonoJitInfoTable *volatile *table_ptr, MonoJitInfo *ji)
+{
+ MonoJitInfoTable *table;
+ MonoJitInfoTableChunk *chunk;
+ int chunk_pos, pos;
+ int num_elements;
+ int i;
+
+ table = *table_ptr;
+
+ restart:
+ chunk_pos = jit_info_table_index (table, (gint8*)ji->code_start + ji->code_size);
+ g_assert (chunk_pos < table->num_chunks);
+ chunk = table->chunks [chunk_pos];
+
+ if (chunk->num_elements >= MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
+ MonoJitInfoTable *new_table = jit_info_table_chunk_overflow (table, chunk);
+
+ /* Debugging code, should be removed. */
+ //jit_info_table_check (new_table);
+
+ *table_ptr = new_table;
+ mono_memory_barrier ();
+ domain->num_jit_info_tables++;
+ mono_thread_hazardous_free_or_queue (table, (MonoHazardousFreeFunc)mono_jit_info_table_free, TRUE, FALSE);
+ table = new_table;
+
+ goto restart;
+ }
+
+ /* Debugging code, should be removed. */
+ //jit_info_table_check (table);
+
+ num_elements = chunk->num_elements;
+
+ pos = jit_info_table_chunk_index (chunk, NULL, (gint8*)ji->code_start + ji->code_size);
+
+ /* First we need to size up the chunk by one, by copying the
+ last item, or inserting the first one, if the table is
+ empty. */
+ if (num_elements > 0)
+ chunk->data [num_elements] = chunk->data [num_elements - 1];
+ else
+ chunk->data [0] = ji;
+ mono_memory_write_barrier ();
+ chunk->num_elements = ++num_elements;
+
+ /* Shift the elements up one by one. */
+ for (i = num_elements - 2; i >= pos; --i) {
+ mono_memory_write_barrier ();
+ chunk->data [i + 1] = chunk->data [i];
+ }
+
+ /* Now we have room and can insert the new item. */
+ mono_memory_write_barrier ();
+ chunk->data [pos] = ji;
+
+ /* Set the high code end address chunk entry. */
+ chunk->last_code_end = (gint8*)chunk->data [chunk->num_elements - 1]->code_start
+ + chunk->data [chunk->num_elements - 1]->code_size;
+
+ /* Debugging code, should be removed. */
+ //jit_info_table_check (table);
+}
+
+void
+mono_jit_info_table_add (MonoDomain *domain, MonoJitInfo *ji)
+{
+ g_assert (ji->d.method != NULL);
+
+ mono_domain_lock (domain);
+
+ ++mono_stats.jit_info_table_insert_count;
+
+ jit_info_table_add (domain, &domain->jit_info_table, ji);
+
+ mono_domain_unlock (domain);
+}
+
+static MonoJitInfo*
+mono_jit_info_make_tombstone (MonoJitInfo *ji)
+{
+ MonoJitInfo *tombstone = g_new0 (MonoJitInfo, 1);
+
+ tombstone->code_start = ji->code_start;
+ tombstone->code_size = ji->code_size;
+ tombstone->d.method = JIT_INFO_TOMBSTONE_MARKER;
+
+ return tombstone;
+}
+
+/*
+ * LOCKING: domain lock
+ */
+static void
+mono_jit_info_free_or_queue (MonoDomain *domain, MonoJitInfo *ji)
+{
+ if (domain->num_jit_info_tables <= 1) {
+ /* Can it actually happen that we only have one table
+ but ji is still hazardous? */
+ mono_thread_hazardous_free_or_queue (ji, g_free, TRUE, FALSE);
+ } else {
+ domain->jit_info_free_queue = g_slist_prepend (domain->jit_info_free_queue, ji);
+ }
+}
+
+static void
+jit_info_table_remove (MonoJitInfoTable *table, MonoJitInfo *ji)
+{
+ MonoJitInfoTableChunk *chunk;
+ gpointer start = ji->code_start;
+ int chunk_pos, pos;
+
+ chunk_pos = jit_info_table_index (table, start);
+ g_assert (chunk_pos < table->num_chunks);
+
+ pos = jit_info_table_chunk_index (table->chunks [chunk_pos], NULL, start);
+
+ do {
+ chunk = table->chunks [chunk_pos];
+
+ while (pos < chunk->num_elements) {
+ if (chunk->data [pos] == ji)
+ goto found;
+
+ g_assert (IS_JIT_INFO_TOMBSTONE (chunk->data [pos]));
+ g_assert ((guint8*)chunk->data [pos]->code_start + chunk->data [pos]->code_size
+ <= (guint8*)ji->code_start + ji->code_size);
+
+ ++pos;
+ }
+
+ ++chunk_pos;
+ pos = 0;
+ } while (chunk_pos < table->num_chunks);
+
+ found:
+ g_assert (chunk->data [pos] == ji);
+
+ chunk->data [pos] = mono_jit_info_make_tombstone (ji);
+
+ /* Debugging code, should be removed. */
+ //jit_info_table_check (table);
+}
+
+void
+mono_jit_info_table_remove (MonoDomain *domain, MonoJitInfo *ji)
+{
+ MonoJitInfoTable *table;
+
+ mono_domain_lock (domain);
+ table = domain->jit_info_table;
+
+ ++mono_stats.jit_info_table_remove_count;
+
+ jit_info_table_remove (table, ji);
+
+ mono_jit_info_free_or_queue (domain, ji);
+
+ mono_domain_unlock (domain);
+}
+
+void
+mono_jit_info_add_aot_module (MonoImage *image, gpointer start, gpointer end)
+{
+ MonoJitInfo *ji;
+ MonoDomain *domain = mono_get_root_domain ();
+
+ g_assert (domain);
+ mono_domain_lock (domain);
+
+ /*
+ * We reuse MonoJitInfoTable to store AOT module info,
+ * this gives us async-safe lookup.
+ */
+ if (!domain->aot_modules) {
+ domain->num_jit_info_tables ++;
+ domain->aot_modules = mono_jit_info_table_new (domain);
+ }
+
+ ji = g_new0 (MonoJitInfo, 1);
+ ji->d.image = image;
+ ji->code_start = start;
+ ji->code_size = (guint8*)end - (guint8*)start;
+ jit_info_table_add (domain, &domain->aot_modules, ji);
+
+ mono_domain_unlock (domain);
+}
+
+void
+mono_install_jit_info_find_in_aot (MonoJitInfoFindInAot func)
+{
+ jit_info_find_in_aot_func = func;
+}
+
+int
+mono_jit_info_size (MonoJitInfoFlags flags, int num_clauses, int num_holes)
+{
+ int size = MONO_SIZEOF_JIT_INFO;
+
+ size += num_clauses * sizeof (MonoJitExceptionInfo);
+ if (flags & JIT_INFO_HAS_CAS_INFO)
+ size += sizeof (MonoMethodCasInfo);
+ if (flags & JIT_INFO_HAS_GENERIC_JIT_INFO)
+ size += sizeof (MonoGenericJitInfo);
+ if (flags & JIT_INFO_HAS_TRY_BLOCK_HOLES)
+ size += sizeof (MonoTryBlockHoleTableJitInfo) + num_holes * sizeof (MonoTryBlockHoleJitInfo);
+ if (flags & JIT_INFO_HAS_ARCH_EH_INFO)
+ size += sizeof (MonoArchEHJitInfo);
+ return size;
+}
+
+void
+mono_jit_info_init (MonoJitInfo *ji, MonoMethod *method, guint8 *code, int code_size,
+ MonoJitInfoFlags flags, int num_clauses, int num_holes)
+{
+ ji->d.method = method;
+ ji->code_start = code;
+ ji->code_size = code_size;
+ ji->num_clauses = num_clauses;
+ if (flags & JIT_INFO_HAS_CAS_INFO)
+ ji->has_cas_info = 1;
+ if (flags & JIT_INFO_HAS_GENERIC_JIT_INFO)
+ ji->has_generic_jit_info = 1;
+ if (flags & JIT_INFO_HAS_TRY_BLOCK_HOLES)
+ ji->has_try_block_holes = 1;
+ if (flags & JIT_INFO_HAS_ARCH_EH_INFO)
+ ji->has_arch_eh_info = 1;
+}
+
+gpointer
+mono_jit_info_get_code_start (MonoJitInfo* ji)
+{
+ return ji->code_start;
+}
+
+int
+mono_jit_info_get_code_size (MonoJitInfo* ji)
+{
+ return ji->code_size;
+}
+
+MonoMethod*
+mono_jit_info_get_method (MonoJitInfo* ji)
+{
+ g_assert (!ji->async);
+ return ji->d.method;
+}
+
+static gpointer
+jit_info_key_extract (gpointer value)
+{
+ MonoJitInfo *info = (MonoJitInfo*)value;
+
+ return info->d.method;
+}
+
+static gpointer*
+jit_info_next_value (gpointer value)
+{
+ MonoJitInfo *info = (MonoJitInfo*)value;
+
+ return (gpointer*)&info->next_jit_code_hash;
+}
+
+void
+mono_jit_code_hash_init (MonoInternalHashTable *jit_code_hash)
+{
+ mono_internal_hash_table_init (jit_code_hash,
+ mono_aligned_addr_hash,
+ jit_info_key_extract,
+ jit_info_next_value);
+}
+
+MonoGenericJitInfo*
+mono_jit_info_get_generic_jit_info (MonoJitInfo *ji)
+{
+ if (ji->has_generic_jit_info)
+ return (MonoGenericJitInfo*)&ji->clauses [ji->num_clauses];
+ else
+ return NULL;
+}
+
+/*
+ * mono_jit_info_get_generic_sharing_context:
+ * @ji: a jit info
+ *
+ * Returns the jit info's generic sharing context, or NULL if it
+ * doesn't have one.
+ */
+MonoGenericSharingContext*
+mono_jit_info_get_generic_sharing_context (MonoJitInfo *ji)
+{
+ MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
+
+ if (gi)
+ return gi->generic_sharing_context;
+ else
+ return NULL;
+}
+
+/*
+ * mono_jit_info_set_generic_sharing_context:
+ * @ji: a jit info
+ * @gsctx: a generic sharing context
+ *
+ * Sets the jit info's generic sharing context. The jit info must
+ * have memory allocated for the context.
+ */
+void
+mono_jit_info_set_generic_sharing_context (MonoJitInfo *ji, MonoGenericSharingContext *gsctx)
+{
+ MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
+
+ g_assert (gi);
+
+ gi->generic_sharing_context = gsctx;
+}
+
+MonoTryBlockHoleTableJitInfo*
+mono_jit_info_get_try_block_hole_table_info (MonoJitInfo *ji)
+{
+ if (ji->has_try_block_holes) {
+ char *ptr = (char*)&ji->clauses [ji->num_clauses];
+ if (ji->has_generic_jit_info)
+ ptr += sizeof (MonoGenericJitInfo);
+ return (MonoTryBlockHoleTableJitInfo*)ptr;
+ } else {
+ return NULL;
+ }
+}
+
+static int
+try_block_hole_table_size (MonoJitInfo *ji)
+{
+ MonoTryBlockHoleTableJitInfo *table;
+
+ table = mono_jit_info_get_try_block_hole_table_info (ji);
+ g_assert (table);
+ return sizeof (MonoTryBlockHoleTableJitInfo) + table->num_holes * sizeof (MonoTryBlockHoleJitInfo);
+}
+
+MonoArchEHJitInfo*
+mono_jit_info_get_arch_eh_info (MonoJitInfo *ji)
+{
+ if (ji->has_arch_eh_info) {
+ char *ptr = (char*)&ji->clauses [ji->num_clauses];
+ if (ji->has_generic_jit_info)
+ ptr += sizeof (MonoGenericJitInfo);
+ if (ji->has_try_block_holes)
+ ptr += try_block_hole_table_size (ji);
+ return (MonoArchEHJitInfo*)ptr;
+ } else {
+ return NULL;
+ }
+}
+
+MonoMethodCasInfo*
+mono_jit_info_get_cas_info (MonoJitInfo *ji)
+{
+ if (ji->has_cas_info) {
+ char *ptr = (char*)&ji->clauses [ji->num_clauses];
+ if (ji->has_generic_jit_info)
+ ptr += sizeof (MonoGenericJitInfo);
+ if (ji->has_try_block_holes)
+ ptr += try_block_hole_table_size (ji);
+ if (ji->has_arch_eh_info)
+ ptr += sizeof (MonoArchEHJitInfo);
+ return (MonoMethodCasInfo*)ptr;
+ } else {
+ return NULL;
+ }
+}
volatile gint tail;
MonoArray *queue;
gint32 mask;
+ gint32 suspended;
MonoSemType lock;
};
wsq = g_new0 (MonoWSQ, 1);
wsq->mask = INITIAL_LENGTH - 1;
+ wsq->suspended = 0;
MONO_GC_REGISTER_ROOT_SINGLE (wsq->queue);
root = mono_get_root_domain ();
wsq->queue = mono_array_new_cached (root, mono_defaults.object_class, INITIAL_LENGTH);
return wsq;
}
+gboolean
+mono_wsq_suspend (MonoWSQ *wsq)
+{
+ return InterlockedCompareExchange (&wsq->suspended, 1, 0) == 0;
+}
+
void
mono_wsq_destroy (MonoWSQ *wsq)
{
return FALSE;
}
+ if (wsq->suspended) {
+ WSQ_DEBUG ("local_push: wsq suspended\n");
+ return FALSE;
+ }
+
tail = wsq->tail;
if (tail < wsq->head + wsq->mask) {
mono_array_setref (wsq->queue, tail & wsq->mask, (MonoObject *) obj);
gboolean mono_wsq_local_pop (void **ptr) MONO_INTERNAL;
void mono_wsq_try_steal (MonoWSQ *wsq, void **ptr, guint32 ms_timeout) MONO_INTERNAL;
gint mono_wsq_count (MonoWSQ *wsq) MONO_INTERNAL;
+gboolean mono_wsq_suspend (MonoWSQ *wsq) MONO_INTERNAL;
G_END_DECLS
size_t size;
/* check for overflow */
- if (len < 0 || len > ((SIZE_MAX - sizeof (MonoString) - 2) / 2))
+ if (len < 0 || len > ((SIZE_MAX - offsetof (MonoString, chars) - 2) / 2))
mono_gc_out_of_memory (-1);
- size = (sizeof (MonoString) + ((len + 1) * 2));
+ size = (offsetof (MonoString, chars) + ((len + 1) * 2));
g_assert (size > 0);
vtable = mono_class_vtable (domain, mono_defaults.string_class);
#include <mono/utils/strenc.h>
#include <mono/utils/mono-proclib.h>
#include <mono/io-layer/io-layer.h>
-#ifndef HAVE_GETPROCESSID
-#if defined(_MSC_VER) || defined(HAVE_WINTERNL_H)
-#include <winternl.h>
-#ifndef NT_SUCCESS
-#define NT_SUCCESS(status) ((NTSTATUS) (status) >= 0)
-#endif /* !NT_SUCCESS */
-#else /* ! (defined(_MSC_VER) || defined(HAVE_WINTERNL_H)) */
-#include <ddk/ntddk.h>
-#include <ddk/ntapi.h>
-#endif /* (defined(_MSC_VER) || defined(HAVE_WINTERNL_H)) */
-#endif /* !HAVE_GETPROCESSID */
-/* FIXME: fix this code to not depend so much on the inetrnals */
+/* FIXME: fix this code to not depend so much on the internals */
#include <mono/metadata/class-internals.h>
#define LOGDEBUG(...)
return(handle);
}
-guint32 ves_icall_System_Diagnostics_Process_GetPid_internal (void)
+guint32
+ves_icall_System_Diagnostics_Process_GetPid_internal (void)
{
MONO_ARCH_SAVE_REGS;
- return(GetCurrentProcessId ());
+ return mono_process_current_pid ();
}
void ves_icall_System_Diagnostics_Process_Process_free_internal (MonoObject *this,
return TRUE;
}
-#ifndef HAVE_GETPROCESSID
-/* Run-time GetProcessId detection for Windows */
-#ifdef TARGET_WIN32
-#define HAVE_GETPROCESSID
-
-typedef DWORD (WINAPI *GETPROCESSID_PROC) (HANDLE);
-typedef DWORD (WINAPI *NTQUERYINFORMATIONPROCESS_PROC) (HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);
-typedef DWORD (WINAPI *RTLNTSTATUSTODOSERROR_PROC) (NTSTATUS);
-
-static DWORD WINAPI GetProcessId_detect (HANDLE process);
-
-static GETPROCESSID_PROC GetProcessId = &GetProcessId_detect;
-static NTQUERYINFORMATIONPROCESS_PROC NtQueryInformationProcess_proc = NULL;
-static RTLNTSTATUSTODOSERROR_PROC RtlNtStatusToDosError_proc = NULL;
-
-static DWORD WINAPI GetProcessId_ntdll (HANDLE process)
-{
- PROCESS_BASIC_INFORMATION pi;
- NTSTATUS status;
-
- status = NtQueryInformationProcess_proc (process, ProcessBasicInformation, &pi, sizeof (pi), NULL);
- if (NT_SUCCESS (status)) {
- return pi.UniqueProcessId;
- } else {
- SetLastError (RtlNtStatusToDosError_proc (status));
- return 0;
- }
-}
-
-static DWORD WINAPI GetProcessId_stub (HANDLE process)
-{
- SetLastError (ERROR_CALL_NOT_IMPLEMENTED);
- return 0;
-}
-
-static DWORD WINAPI GetProcessId_detect (HANDLE process)
-{
- HMODULE module_handle;
- GETPROCESSID_PROC GetProcessId_kernel;
-
- /* Windows XP SP1 and above have GetProcessId API */
- module_handle = GetModuleHandle (L"kernel32.dll");
- if (module_handle != NULL) {
- GetProcessId_kernel = (GETPROCESSID_PROC) GetProcAddress (module_handle, "GetProcessId");
- if (GetProcessId_kernel != NULL) {
- GetProcessId = GetProcessId_kernel;
- return GetProcessId (process);
- }
- }
-
- /* Windows 2000 and above have deprecated NtQueryInformationProcess API */
- module_handle = GetModuleHandle (L"ntdll.dll");
- if (module_handle != NULL) {
- NtQueryInformationProcess_proc = (NTQUERYINFORMATIONPROCESS_PROC) GetProcAddress (module_handle, "NtQueryInformationProcess");
- if (NtQueryInformationProcess_proc != NULL) {
- RtlNtStatusToDosError_proc = (RTLNTSTATUSTODOSERROR_PROC) GetProcAddress (module_handle, "RtlNtStatusToDosError");
- if (RtlNtStatusToDosError_proc != NULL) {
- GetProcessId = &GetProcessId_ntdll;
- return GetProcessId (process);
- }
- }
- }
-
- /* Fall back to ERROR_CALL_NOT_IMPLEMENTED */
- GetProcessId = &GetProcessId_stub;
- return GetProcessId (process);
-}
-#endif /* HOST_WIN32 */
-#endif /* !HAVE_GETPROCESSID */
-
MonoBoolean ves_icall_System_Diagnostics_Process_ShellExecuteEx_internal (MonoProcessStartInfo *proc_start_info, MonoProcInfo *process_info)
{
SHELLEXECUTEINFO shellex = {0};
/* Returns an array of pids */
MonoArray *ves_icall_System_Diagnostics_Process_GetProcesses_internal (void)
{
+#if !defined(HOST_WIN32)
+ MonoArray *procs;
+ gpointer *pidarray;
+ int i, count;
+
+ MONO_ARCH_SAVE_REGS;
+
+ pidarray = mono_process_list (&count);
+ if (!pidarray)
+ mono_raise_exception (mono_get_exception_not_supported ("This system does not support EnumProcesses"));
+ procs = mono_array_new (mono_domain_get (), mono_get_int32_class (), count);
+ if (sizeof (guint32) == sizeof (gpointer)) {
+ memcpy (mono_array_addr (procs, guint32, 0), pidarray, count);
+ } else {
+ for (i = 0; i < count; ++i)
+ *(mono_array_addr (procs, guint32, i)) = GPOINTER_TO_UINT (pidarray [i]);
+ }
+ g_free (pidarray);
+
+ return procs;
+#else
MonoArray *procs;
gboolean ret;
DWORD needed;
- guint32 count;
+ int count;
guint32 *pids;
- MONO_ARCH_SAVE_REGS;
-
count = 512;
do {
pids = g_new0 (guint32, count);
pids = NULL;
return procs;
+#endif
}
MonoBoolean ves_icall_System_Diagnostics_Process_GetWorkingSet_internal (HANDLE process, guint32 *min, guint32 *max)
if (is_field_on_inst (f->field)) {
MonoDynamicGenericClass *dgclass = (MonoDynamicGenericClass*)f->field->parent->generic_class;
- int field_index = f->field - dgclass->fields;
- MonoObject *obj;
- g_assert (field_index >= 0 && field_index < dgclass->count_fields);
- obj = dgclass->field_objects [field_index];
- return mono_reflection_get_token (obj);
+ if (f->field >= dgclass->fields && f->field < dgclass->fields + dgclass->count_fields) {
+ int field_index = f->field - dgclass->fields;
+ MonoObject *obj;
+
+ g_assert (field_index >= 0 && field_index < dgclass->count_fields);
+ obj = dgclass->field_objects [field_index];
+ return mono_reflection_get_token (obj);
+ }
}
token = mono_class_get_field_token (f->field);
} else if (strcmp (klass->name, "MonoProperty") == 0) {
void **p;
char *new_next;
TLAB_ACCESS_INIT;
+ size_t real_size = size;
+
+ CANARIFY_SIZE(size);
HEAVY_STAT (++stat_objects_alloced);
- if (size <= SGEN_MAX_SMALL_OBJ_SIZE)
+ if (real_size <= SGEN_MAX_SMALL_OBJ_SIZE)
HEAVY_STAT (stat_bytes_alloced += size);
else
HEAVY_STAT (stat_bytes_alloced_los += size);
if (collect_before_allocs) {
if (((current_alloc % collect_before_allocs) == 0) && nursery_section) {
sgen_perform_collection (0, GENERATION_NURSERY, "collect-before-alloc-triggered", TRUE);
- if (!degraded_mode && sgen_can_alloc_size (size) && size <= SGEN_MAX_SMALL_OBJ_SIZE) {
+ if (!degraded_mode && sgen_can_alloc_size (size) && real_size <= SGEN_MAX_SMALL_OBJ_SIZE) {
// FIXME:
g_assert_not_reached ();
}
* specially by the world-stopping code.
*/
- if (size > SGEN_MAX_SMALL_OBJ_SIZE) {
- p = sgen_los_alloc_large_inner (vtable, size);
+ if (real_size > SGEN_MAX_SMALL_OBJ_SIZE) {
+ p = sgen_los_alloc_large_inner (vtable, ALIGN_UP (real_size));
} else {
/* tlab_next and tlab_temp_end are TLS vars so accessing them might be expensive */
* visible before the vtable store.
*/
+ CANARIFY_ALLOC(p,real_size);
SGEN_LOG (6, "Allocated object %p, vtable: %p (%s), size: %zd", p, vtable, vtable->klass->name, size);
binary_protocol_alloc (p , vtable, size);
if (G_UNLIKELY (MONO_GC_NURSERY_OBJ_ALLOC_ENABLED ()))
do {
p = sgen_nursery_alloc (size);
if (!p) {
- sgen_ensure_free_space (size);
+ sgen_ensure_free_space (real_size);
if (degraded_mode)
return alloc_degraded (vtable, size, FALSE);
else
TLAB_TEMP_END = MIN (TLAB_REAL_END, TLAB_NEXT + SGEN_SCAN_START_SIZE);
SGEN_LOG (5, "Expanding local alloc: %p-%p", TLAB_NEXT, TLAB_TEMP_END);
}
+ CANARIFY_ALLOC(p,real_size);
}
if (G_LIKELY (p)) {
SGEN_LOG (6, "Allocated object %p, vtable: %p (%s), size: %zd", p, vtable, vtable->klass->name, size);
binary_protocol_alloc (p, vtable, size);
if (G_UNLIKELY (MONO_GC_MAJOR_OBJ_ALLOC_LARGE_ENABLED ()|| MONO_GC_NURSERY_OBJ_ALLOC_ENABLED ())) {
- if (size > SGEN_MAX_SMALL_OBJ_SIZE)
+ if (real_size > SGEN_MAX_SMALL_OBJ_SIZE)
MONO_GC_MAJOR_OBJ_ALLOC_LARGE ((mword)p, size, vtable->klass->name_space, vtable->klass->name);
else
MONO_GC_NURSERY_OBJ_ALLOC ((mword)p, size, vtable->klass->name_space, vtable->klass->name);
void **p;
char *new_next;
TLAB_ACCESS_INIT;
+ size_t real_size = size;
+
+ CANARIFY_SIZE(size);
size = ALIGN_UP (size);
- SGEN_ASSERT (9, size >= sizeof (MonoObject), "Object too small");
+ SGEN_ASSERT (9, real_size >= sizeof (MonoObject), "Object too small");
g_assert (vtable->gc_descr);
- if (size > SGEN_MAX_SMALL_OBJ_SIZE)
+ if (real_size > SGEN_MAX_SMALL_OBJ_SIZE)
return NULL;
if (G_UNLIKELY (size > tlab_size)) {
HEAVY_STAT (++stat_objects_alloced);
HEAVY_STAT (stat_bytes_alloced += size);
+ CANARIFY_ALLOC(p,real_size);
SGEN_LOG (6, "Allocated object %p, vtable: %p (%s), size: %zd", p, vtable, vtable->klass->name, size);
binary_protocol_alloc (p, vtable, size);
if (G_UNLIKELY (MONO_GC_NURSERY_OBJ_ALLOC_ENABLED ()))
/*
* a string allocator method takes the args: (vtable, len)
*
- * bytes = sizeof (MonoString) + ((len + 1) * 2)
+ * bytes = offsetof (MonoString, chars) + ((len + 1) * 2)
*
* condition:
*
*
* therefore:
*
- * sizeof (MonoString) + ((len + 1) * 2) <= INT32_MAX - (SGEN_ALLOC_ALIGN - 1)
- * len <= (INT32_MAX - (SGEN_ALLOC_ALIGN - 1) - sizeof (MonoString)) / 2 - 1
+ * offsetof (MonoString, chars) + ((len + 1) * 2) <= INT32_MAX - (SGEN_ALLOC_ALIGN - 1)
+ * len <= (INT32_MAX - (SGEN_ALLOC_ALIGN - 1) - offsetof (MonoString, chars)) / 2 - 1
*/
mono_mb_emit_ldarg (mb, 1);
- mono_mb_emit_icon (mb, (INT32_MAX - (SGEN_ALLOC_ALIGN - 1) - sizeof (MonoString)) / 2 - 1);
+ mono_mb_emit_icon (mb, (INT32_MAX - (SGEN_ALLOC_ALIGN - 1) - MONO_STRUCT_OFFSET (MonoString, chars)) / 2 - 1);
pos = mono_mb_emit_short_branch (mb, MONO_CEE_BLE_UN_S);
mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
mono_mb_emit_icon (mb, 1);
mono_mb_emit_byte (mb, MONO_CEE_SHL);
//WE manually fold the above + 2 here
- mono_mb_emit_icon (mb, sizeof (MonoString) + 2);
+ mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoString, chars) + 2);
mono_mb_emit_byte (mb, CEE_ADD);
mono_mb_emit_stloc (mb, size_var);
} else {
#ifndef __MONO_SGENARCHDEP_H__
#define __MONO_SGENARCHDEP_H__
-#include <mono/utils/mono-sigcontext.h>
+#include <mono/utils/mono-context.h>
+
+/*
+ * Define either USE_MONO_CTX, or
+ * ARCH_SIGCTX_SP/ARCH_SIGCTX_IP/ARCH_STORE_REGS/ARCH_COPY_SIGCTX_REGS.
+ * Define ARCH_NUM_REGS to be the number of general registers in MonoContext, or the
+ * number of registers stored by ARCH_STORE_REGS.
+ */
#if defined(MONO_CROSS_COMPILE)
#elif defined(TARGET_X86)
-#include <mono/utils/mono-context.h>
-
#define REDZONE_SIZE 0
#define ARCH_NUM_REGS 8
-#ifdef MONO_ARCH_HAS_MONO_CONTEXT
-#define USE_MONO_CTX
-#else
+#ifndef MONO_ARCH_HAS_MONO_CONTEXT
#error 0
#endif
-/*FIXME, move this to mono-sigcontext as this is generaly useful.*/
-#define ARCH_SIGCTX_SP(ctx) (UCONTEXT_REG_ESP ((ctx)))
-#define ARCH_SIGCTX_IP(ctx) (UCONTEXT_REG_EIP ((ctx)))
+#define USE_MONO_CTX
#elif defined(TARGET_AMD64)
-#include <mono/utils/mono-context.h>
-
#define REDZONE_SIZE 128
#define ARCH_NUM_REGS 16
#define USE_MONO_CTX
-/*FIXME, move this to mono-sigcontext as this is generaly useful.*/
-#define ARCH_SIGCTX_SP(ctx) (UCONTEXT_REG_RSP (ctx))
-#define ARCH_SIGCTX_IP(ctx) (UCONTEXT_REG_RIP (ctx))
-
#elif defined(TARGET_POWERPC)
#define REDZONE_SIZE 224
/* We dont store ip, sp */
#define ARCH_NUM_REGS 14
-#define ARCH_STORE_REGS(ptr) \
- __asm__ __volatile__( \
- "push {lr}\n" \
- "mov lr, %0\n" \
- "stmia lr!, {r0-r12}\n" \
- "pop {lr}\n" \
- : \
- : "r" (ptr) \
- )
-
-#define ARCH_SIGCTX_SP(ctx) (UCONTEXT_REG_SP((ctx)))
-#define ARCH_SIGCTX_IP(ctx) (UCONTEXT_REG_PC((ctx)))
-#define ARCH_COPY_SIGCTX_REGS(a,ctx) do { \
- ((a)[0]) = (gpointer) (UCONTEXT_REG_R0((ctx))); \
- ((a)[1]) = (gpointer) (UCONTEXT_REG_R1((ctx))); \
- ((a)[2]) = (gpointer) (UCONTEXT_REG_R2((ctx))); \
- ((a)[3]) = (gpointer) (UCONTEXT_REG_R3((ctx))); \
- ((a)[4]) = (gpointer) (UCONTEXT_REG_R4((ctx))); \
- ((a)[5]) = (gpointer) (UCONTEXT_REG_R5((ctx))); \
- ((a)[6]) = (gpointer) (UCONTEXT_REG_R6((ctx))); \
- ((a)[7]) = (gpointer) (UCONTEXT_REG_R7((ctx))); \
- ((a)[8]) = (gpointer) (UCONTEXT_REG_R8((ctx))); \
- ((a)[9]) = (gpointer) (UCONTEXT_REG_R9((ctx))); \
- ((a)[10]) = (gpointer) (UCONTEXT_REG_R10((ctx))); \
- ((a)[11]) = (gpointer) (UCONTEXT_REG_R11((ctx))); \
- ((a)[12]) = (gpointer) (UCONTEXT_REG_R12((ctx))); \
- ((a)[13]) = (gpointer) (UCONTEXT_REG_LR((ctx))); \
- } while (0)
#elif defined(TARGET_ARM64)
-#include <mono/utils/mono-sigcontext.h>
-
#ifdef __linux__
#define REDZONE_SIZE 0
#elif defined(__APPLE__)
#define USE_MONO_CTX
#define ARCH_NUM_REGS 31
-#define ARCH_STORE_REGS(ptr) do { g_assert_not_reached (); } while (0)
-
-#define ARCH_SIGCTX_SP(ctx) UCONTEXT_REG_SP (ctx)
-#define ARCH_SIGCTX_IP(ctx) UCONTEXT_REG_PC (ctx)
-#define ARCH_COPY_SIGCTX_REGS(a,ctx) do { g_assert_not_reached (); } while (0)
-
#elif defined(__mips__)
#define REDZONE_SIZE 0
#define USE_MONO_CTX
#define ARCH_NUM_REGS 32
-/*
- * These casts are necessary since glibc always makes the
- * gregs 64-bit values in userland.
- */
-#define ARCH_SIGCTX_SP(ctx) ((gsize) UCONTEXT_GREGS((ctx))[29])
-#define ARCH_SIGCTX_IP(ctx) ((gsize) UCONTEXT_REG_PC((ctx)))
-
#elif defined(__s390x__)
#define REDZONE_SIZE 0
-#include <mono/utils/mono-context.h>
-
#define USE_MONO_CTX
#define ARCH_NUM_REGS 16
-#define ARCH_SIGCTX_SP(ctx) ((UCONTEXT_GREGS((ctx))) [15])
-#define ARCH_SIGCTX_IP(ctx) ((ucontext_t *) (ctx))->uc_mcontext.psw.addr
#elif defined(__sparc__)
}
#if 0
-static void
-collect_faulted_cards (void)
-{
-#define CARD_PAGES (CARD_COUNT_IN_BYTES / 4096)
- int i, count = 0;
- unsigned char faulted [CARD_PAGES] = { 0 };
- mincore (sgen_cardtable, CARD_COUNT_IN_BYTES, faulted);
-
- for (i = 0; i < CARD_PAGES; ++i) {
- if (faulted [i])
- ++count;
- }
-
- printf ("TOTAL card pages %d faulted %d\n", CARD_PAGES, count);
-}
-
void
sgen_card_table_dump_obj_card (char *object, size_t size, void *dummy)
{
gboolean do_pin_stats = FALSE;
static gboolean do_verify_nursery = FALSE;
static gboolean do_dump_nursery_content = FALSE;
+static gboolean enable_nursery_canaries = FALSE;
#ifdef HEAVY_STATISTICS
long long stat_objects_alloced_degraded = 0;
static long long time_major_sweep = 0;
static long long time_major_fragment_creation = 0;
+static long long time_max = 0;
+
static SGEN_TV_DECLARE (time_major_conc_collection_start);
static SGEN_TV_DECLARE (time_major_conc_collection_end);
return vt->klass->name;
}
+gboolean
+nursery_canaries_enabled (void)
+{
+ return enable_nursery_canaries;
+}
+
#define safe_object_get_size sgen_safe_object_get_size
const char*
obj = start;
}
- size = ALIGN_UP (safe_object_get_size ((MonoObject*)obj));
-
- if ((MonoVTable*)SGEN_LOAD_VTABLE (obj) != array_fill_vtable)
+ if ((MonoVTable*)SGEN_LOAD_VTABLE (obj) != array_fill_vtable) {
+ CHECK_CANARY_FOR_OBJECT (obj);
+ size = ALIGN_UP (safe_object_get_size ((MonoObject*)obj));
callback (obj, size, data);
+ CANARIFY_SIZE (size);
+ } else {
+ size = ALIGN_UP (safe_object_get_size ((MonoObject*)obj));
+ }
start += size;
}
static void
clear_domain_process_minor_object_callback (char *obj, size_t size, MonoDomain *domain)
{
- if (clear_domain_process_object (obj, domain))
+ if (clear_domain_process_object (obj, domain)) {
+ CANARIFY_SIZE (size);
memset (obj, 0, size);
+ }
}
static void
}
/* Skip to the next object */
+ if (((MonoObject*)search_start)->synchronisation != GINT_TO_POINTER (-1)) {
+ CHECK_CANARY_FOR_OBJECT (search_start);
+ CANARIFY_SIZE (obj_size);
+ CANARIFY_SIZE (obj_to_pin_size);
+ }
search_start = (void*)((char*)search_start + obj_size);
} while (search_start <= addr);
if (inited)
return;
+ mono_counters_register ("Collection max time", MONO_COUNTER_GC | MONO_COUNTER_LONG | MONO_COUNTER_TIME | MONO_COUNTER_MONOTONIC, &time_max);
+
mono_counters_register ("Minor fragment clear", MONO_COUNTER_GC | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &time_minor_pre_collection_fragment_clear);
mono_counters_register ("Minor pinning", MONO_COUNTER_GC | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &time_minor_pinning);
mono_counters_register ("Minor scan remembered set", MONO_COUNTER_GC | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &time_minor_scan_remsets);
if (!do_verify_nursery)
return;
+
+ if (nursery_canaries_enabled ())
+ SGEN_LOG (1, "Checking nursery canaries...");
/*This cleans up unused fragments */
sgen_nursery_allocator_prepare_for_pinning ();
SGEN_LOG (1, "HOLE [%p %p %d]", hole_start, cur, (int)(cur - hole_start));
SGEN_LOG (1, "OBJ [%p %p %d %d %s %d]", cur, cur + size, (int)size, (int)ss, sgen_safe_name ((MonoObject*)cur), (gpointer)LOAD_VTABLE (cur) == sgen_get_array_fill_vtable ());
}
+ if (nursery_canaries_enabled () && (MonoVTable*)SGEN_LOAD_VTABLE (cur) != array_fill_vtable) {
+ CHECK_CANARY_FOR_OBJECT (cur);
+ CANARIFY_SIZE (size);
+ }
cur += size;
hole_start = cur;
}
sgen_perform_collection (size_t requested_size, int generation_to_collect, const char *reason, gboolean wait_to_finish)
{
TV_DECLARE (gc_end);
+ TV_DECLARE (gc_total_start);
+ TV_DECLARE (gc_total_end);
GGTimingInfo infos [2];
int overflow_generation_to_collect = -1;
int oldest_generation_collected = generation_to_collect;
sgen_stop_world (generation_to_collect);
+ TV_GETTIME (gc_total_start);
+
if (concurrent_collection_in_progress) {
if (major_update_or_finish_concurrent_collection (wait_to_finish && generation_to_collect == GENERATION_OLD)) {
oldest_generation_collected = GENERATION_OLD;
done:
g_assert (sgen_gray_object_queue_is_empty (&gray_queue));
+ TV_GETTIME (gc_total_end);
+ time_max = MAX (time_max, TV_ELAPSED (gc_total_start, gc_total_end));
+
sgen_restart_world (oldest_generation_collected, infos);
mono_profiler_gc_event (MONO_GC_EVENT_END, generation_to_collect);
return MAX_SMALL_OBJ_SIZE;
}
+void
+mono_gc_set_string_length (MonoString *str, gint32 new_length)
+{
+ mono_unichar2 *new_end = str->chars + new_length;
+
+ /* zero the discarded string. This null-delimits the string and allows
+ * the space to be reclaimed by SGen. */
+
+ if (nursery_canaries_enabled () && sgen_ptr_in_nursery (str)) {
+ CHECK_CANARY_FOR_OBJECT (str);
+ memset (new_end, 0, (str->length - new_length + 1) * sizeof (mono_unichar2) + CANARY_SIZE);
+ memcpy (new_end + 1 , CANARY_STRING, CANARY_SIZE);
+ } else {
+ memset (new_end, 0, (str->length - new_length + 1) * sizeof (mono_unichar2));
+ }
+
+ str->length = new_length;
+}
+
gboolean
mono_gc_user_markers_supported (void)
{
if (opt [0] == ':')
opt++;
if (opt [0]) {
-#ifdef HOST_WIN32
- char *rf = g_strdup_printf ("%s.%d", opt, GetCurrentProcessId ());
-#else
- char *rf = g_strdup_printf ("%s.%d", opt, getpid ());
-#endif
+ char *rf = g_strdup_printf ("%s.%d", opt, mono_process_current_pid ());
gc_debug_file = fopen (rf, "wb");
if (!gc_debug_file)
gc_debug_file = stderr;
*colon = '\0';
}
binary_protocol_init (filename, (long long)limit);
+ } else if (!strcmp (opt, "nursery-canaries")) {
+ do_verify_nursery = TRUE;
+ sgen_set_use_managed_allocator (FALSE);
+ enable_nursery_canaries = TRUE;
} else if (!sgen_bridge_handle_gc_debug (opt)) {
sgen_env_var_error (MONO_GC_DEBUG_NAME, "Ignoring.", "Unknown option `%s`.", opt);
fprintf (stderr, " print-pinning\n");
fprintf (stderr, " heap-dump=<filename>\n");
fprintf (stderr, " binary-protocol=<filename>[:<file-size-limit>]\n");
+ fprintf (stderr, " nursery-canaries\n");
sgen_bridge_print_gc_debug_usage ();
fprintf (stderr, "\n");
fin_callbacks = *callbacks;
}
+
+
+
+
#endif /* HAVE_SGEN_GC */
* mono_array_length_fast not using the object's vtable.
*/
if (klass == mono_defaults.string_class) {
- return sizeof (MonoString) + 2 * mono_string_length_fast ((MonoString*) o) + 2;
+ return offsetof (MonoString, chars) + 2 * mono_string_length_fast ((MonoString*) o) + 2;
} else if (klass->rank) {
MonoArray *array = (MonoArray*)o;
size_t size = sizeof (MonoArray) + klass->sizes.element_size * mono_array_length_fast (array);
if (type == DESC_TYPE_RUN_LENGTH || type == DESC_TYPE_SMALL_BITMAP) {
mword size = descr & 0xfff8;
if (size == 0) /* This is used to encode a string */
- return sizeof (MonoString) + 2 * mono_string_length_fast ((MonoString*) o) + 2;
+ return offsetof (MonoString, chars) + 2 * mono_string_length_fast ((MonoString*) o) + 2;
return size;
} else if (type == DESC_TYPE_VECTOR) {
int element_size = ((descr) >> VECTOR_ELSIZE_SHIFT) & MAX_ELEMENT_SIZE;
return sgen_par_object_get_size ((MonoVTable*)SGEN_LOAD_VTABLE (obj), obj);
}
+/*
+ * This variant guarantees to return the exact size of the object
+ * before alignment. Needed for canary support.
+ */
+static inline guint
+sgen_safe_object_get_size_unaligned (MonoObject *obj)
+{
+ char *forwarded;
+
+ if ((forwarded = SGEN_OBJECT_IS_FORWARDED (obj))) {
+ obj = (MonoObject*)forwarded;
+ }
+
+ return slow_object_get_size ((MonoVTable*)SGEN_LOAD_VTABLE (obj), obj);
+}
+
const char* sgen_safe_name (void* obj) MONO_INTERNAL;
gboolean sgen_object_is_live (void *obj) MONO_INTERNAL;
void sgen_qsort (void *base, size_t nel, size_t width, int (*compar) (const void*, const void*)) MONO_INTERNAL;
gint64 sgen_timestamp (void) MONO_INTERNAL;
+/*
+ * Canary (guard word) support
+ * Notes:
+ * - CANARY_SIZE must be multiple of word size in bytes
+ * - Canary space is not included on checks against SGEN_MAX_SMALL_OBJ_SIZE
+ */
+
+gboolean nursery_canaries_enabled (void) MONO_INTERNAL;
+
+#define CANARY_SIZE 8
+#define CANARY_STRING "koupepia"
+
+#define CANARIFY_SIZE(size) if (nursery_canaries_enabled ()) { \
+ size = size + CANARY_SIZE; \
+ }
+
+#define CANARIFY_ALLOC(addr,size) if (nursery_canaries_enabled ()) { \
+ memcpy ((char*) (addr) + (size), CANARY_STRING, CANARY_SIZE); \
+ }
+
+#define CANARY_VALID(addr) (strncmp ((char*) (addr), CANARY_STRING, CANARY_SIZE) == 0)
+
+#define CHECK_CANARY_FOR_OBJECT(addr) if (nursery_canaries_enabled ()) { \
+ char* canary_ptr = (char*) (addr) + sgen_safe_object_get_size_unaligned ((MonoObject *) (addr)); \
+ if (!CANARY_VALID(canary_ptr)) { \
+ char canary_copy[CANARY_SIZE +1]; \
+ strncpy (canary_copy, canary_ptr, 8); \
+ canary_copy[CANARY_SIZE] = 0; \
+ g_error ("CORRUPT CANARY:\naddr->%p\ntype->%s\nexcepted->'%s'\nfound->'%s'\n", (char*) addr, ((MonoObject*)addr)->vtable->klass->name, CANARY_STRING, canary_copy); \
+ } }
+
#endif /* HAVE_SGEN_GC */
#endif /* __MONO_SGENGC_H__ */
#include "utils/mono-counters.h"
#include "metadata/sgen-gc.h"
+#include "utils/mono-mmap.h"
#include "utils/lock-free-alloc.h"
#include "metadata/sgen-memory-governor.h"
8, 16, 24, 32, 40, 48, 64, 80,
96, 128, 160, 192, 224, 248, 296, 320,
384, 448, 504, 528, 584, 680, 816, 1088,
- 1360, 2040, 2336, 2728, 3272, 4088, 5456, 8184 };
+ 1360, 2044, 2336, 2728, 3272, 4092, 5456, 8188 };
#else
static const int allocator_sizes [] = {
8, 16, 24, 32, 40, 48, 64, 80,
#define NUM_ALLOCATORS (sizeof (allocator_sizes) / sizeof (int))
+static int allocator_block_sizes [NUM_ALLOCATORS];
+
static MonoLockFreeAllocSizeClass size_classes [NUM_ALLOCATORS];
static MonoLockFreeAllocator allocators [NUM_ALLOCATORS];
+#ifdef HEAVY_STATISTICS
+static int allocator_sizes_stats [NUM_ALLOCATORS];
+#endif
+
+static size_t
+block_size (size_t slot_size)
+{
+ static int pagesize = -1;
+
+ int size;
+
+ if (pagesize == -1)
+ pagesize = mono_pagesize ();
+
+ for (size = pagesize; size < LOCK_FREE_ALLOC_SB_MAX_SIZE; size <<= 1) {
+ if (slot_size * 2 <= LOCK_FREE_ALLOC_SB_USABLE_SIZE (size))
+ return size;
+ }
+ return LOCK_FREE_ALLOC_SB_MAX_SIZE;
+}
+
/*
* Find the allocator index for memory chunks that can contain @size
* objects.
int slot;
g_assert (type >= 0 && type < INTERNAL_MEM_MAX);
+ g_assert (size <= allocator_sizes [NUM_ALLOCATORS - 1]);
slot = index_for_size (size);
g_assert (slot >= 0);
} else {
index = index_for_size (size);
+#ifdef HEAVY_STATISTICS
+ ++ allocator_sizes_stats [index];
+#endif
+
p = mono_lock_free_alloc (&allocators [index]);
if (!p)
sgen_assert_memory_alloc (NULL, size, description_for_type (type));
if (size > allocator_sizes [NUM_ALLOCATORS - 1])
sgen_free_os_memory (addr, size, SGEN_ALLOC_INTERNAL);
else
- mono_lock_free_free (addr);
+ mono_lock_free_free (addr, block_size (size));
MONO_GC_INTERNAL_DEALLOC ((mword)addr, size, type);
}
void*
sgen_alloc_internal (int type)
{
- int index = fixed_type_allocator_indexes [type];
- int size = allocator_sizes [index];
+ int index, size;
void *p;
+
+ index = fixed_type_allocator_indexes [type];
g_assert (index >= 0 && index < NUM_ALLOCATORS);
+
+#ifdef HEAVY_STATISTICS
+ ++ allocator_sizes_stats [index];
+#endif
+
+ size = allocator_sizes [index];
+
p = mono_lock_free_alloc (&allocators [index]);
memset (p, 0, size);
index = fixed_type_allocator_indexes [type];
g_assert (index >= 0 && index < NUM_ALLOCATORS);
- mono_lock_free_free (addr);
+ mono_lock_free_free (addr, allocator_block_sizes [index]);
if (MONO_GC_INTERNAL_DEALLOC_ENABLED ()) {
int size G_GNUC_UNUSED = allocator_sizes [index];
void
sgen_report_internal_mem_usage (void)
{
- /* FIXME: implement */
- printf ("not implemented yet\n");
+ int i G_GNUC_UNUSED;
+#ifdef HEAVY_STATISTICS
+ printf ("size -> # allocations\n");
+ for (i = 0; i < NUM_ALLOCATORS; ++i)
+ printf ("%d -> %d\n", allocator_sizes [i], allocator_sizes_stats [i]);
+#endif
}
void
sgen_init_internal_allocator (void)
{
- int i;
+ int i, size;
for (i = 0; i < INTERNAL_MEM_MAX; ++i)
fixed_type_allocator_indexes [i] = -1;
for (i = 0; i < NUM_ALLOCATORS; ++i) {
- mono_lock_free_allocator_init_size_class (&size_classes [i], allocator_sizes [i]);
+ allocator_block_sizes [i] = block_size (allocator_sizes [i]);
+ mono_lock_free_allocator_init_size_class (&size_classes [i], allocator_sizes [i], allocator_block_sizes [i]);
mono_lock_free_allocator_init_allocator (&allocators [i], &size_classes [i]);
}
+
+ for (size = mono_pagesize (); size <= LOCK_FREE_ALLOC_SB_MAX_SIZE; size <<= 1) {
+ int max_size = LOCK_FREE_ALLOC_SB_USABLE_SIZE (size) / 2;
+ /*
+ * we assert that allocator_sizes contains the biggest possible object size
+ * per block (4K => 4080 / 2 = 2040, 8k => 8176 / 2 = 4088, 16k => 16368 / 2 = 8184 on 64bits),
+ * so that we do not get different block sizes for sizes that should go to the same one
+ */
+ g_assert (allocator_sizes [index_for_size (max_size)] == max_size);
+ }
}
#endif
/**/
static mword allocated_heap;
static mword total_alloc = 0;
+static mword total_alloc_max = 0;
/* GC triggers. */
static mword sgen_memgov_available_free_space (void);
-static mword
-double_to_mword_with_saturation (double value)
-{
- if (value >= (double)MWORD_MAX_VALUE)
- return MWORD_MAX_VALUE;
- return (mword)value;
-}
-
/* GC trigger heuristics. */
static void
sgen_memgov_try_calculate_minor_collection_allowance (gboolean overwrite)
{
- size_t num_major_sections, num_major_sections_saved;
- mword los_memory_saved, new_major, new_heap_size, save_target, allowance_target;
+ size_t num_major_sections;
+ mword new_major, new_heap_size, allowance_target;
if (overwrite)
g_assert (need_calculate_minor_collection_allowance);
num_major_sections = major_collector.get_num_major_sections ();
- num_major_sections_saved = MAX (last_collection_old_num_major_sections - num_major_sections, 0);
- los_memory_saved = MAX (last_collection_old_los_memory_usage - last_collection_los_memory_usage, 1);
-
new_major = num_major_sections * major_collector.section_size;
new_heap_size = new_major + last_collection_los_memory_usage;
- save_target = (mword)((new_major + last_collection_los_memory_usage) * SGEN_DEFAULT_SAVE_TARGET_RATIO);
-
/*
- * We aim to allow the allocation of as many sections as is
- * necessary to reclaim save_target sections in the next
- * collection. We assume the collection pattern won't change.
- * In the last cycle, we had num_major_sections_saved for
- * minor_collection_sections_alloced. Assuming things won't
- * change, this must be the same ratio as save_target for
- * allowance_target, i.e.
- *
- * num_major_sections_saved save_target
- * --------------------------------- == ----------------
- * minor_collection_sections_alloced allowance_target
- *
- * hence:
+ * We allow the heap to grow by one third its current size before we start the next
+ * major collection.
*/
- allowance_target = double_to_mword_with_saturation ((double)save_target * (double)(minor_collection_sections_alloced * major_collector.section_size + last_collection_los_memory_alloced) / (double)(num_major_sections_saved * major_collector.section_size + los_memory_saved));
+ allowance_target = new_heap_size / 3;
- minor_collection_allowance = MAX (MIN (allowance_target, num_major_sections * major_collector.section_size + los_memory_usage), MIN_MINOR_COLLECTION_ALLOWANCE);
+ minor_collection_allowance = MAX (allowance_target, MIN_MINOR_COLLECTION_ALLOWANCE);
if (new_heap_size + minor_collection_allowance > soft_heap_limit) {
if (new_heap_size > soft_heap_limit)
SGEN_ATOMIC_ADD_P (total_alloc, size);
if (flags & SGEN_ALLOC_HEAP)
MONO_GC_HEAP_ALLOC ((mword)ptr, size);
+ total_alloc_max = MAX (total_alloc_max, total_alloc);
}
return ptr;
}
SGEN_ATOMIC_ADD_P (total_alloc, size);
if (flags & SGEN_ALLOC_HEAP)
MONO_GC_HEAP_ALLOC ((mword)ptr, size);
+ total_alloc_max = MAX (total_alloc_max, total_alloc);
}
return ptr;
}
SGEN_ATOMIC_ADD_P (total_alloc, -(gssize)size);
if (flags & SGEN_ALLOC_HEAP)
MONO_GC_HEAP_FREE ((mword)addr, size);
+ total_alloc_max = MAX (total_alloc_max, total_alloc);
}
int64_t
debug_print_allowance = debug_allowance;
minor_collection_allowance = MIN_MINOR_COLLECTION_ALLOWANCE;
+ mono_counters_register ("Memgov alloc", MONO_COUNTER_GC | MONO_COUNTER_WORD | MONO_COUNTER_BYTES | MONO_COUNTER_VARIABLE, &total_alloc);
+ mono_counters_register ("Memgov max alloc", MONO_COUNTER_GC | MONO_COUNTER_WORD | MONO_COUNTER_BYTES | MONO_COUNTER_MONOTONIC, &total_alloc_max);
+
if (max_heap == 0)
return;
GRAY_OBJECT_ENQUEUE (unpin_queue, addr0, sgen_obj_get_descriptor_safe (addr0));
else
SGEN_UNPIN_OBJECT (addr0);
+ size = SGEN_ALIGN_UP (sgen_safe_object_get_size ((MonoObject*)addr0));
+ CANARIFY_SIZE (size);
sgen_set_nursery_scan_start (addr0);
frag_end = addr0;
- size = SGEN_ALIGN_UP (sgen_safe_object_get_size ((MonoObject*)addr0));
++i;
} else {
frag_end = addr1;
void*
sgen_nursery_alloc (size_t size)
{
- SGEN_ASSERT (1, size >= sizeof (MonoObject) && size <= SGEN_MAX_SMALL_OBJ_SIZE, "Invalid nursery object size");
+ SGEN_ASSERT (1, size >= sizeof (MonoObject) && size <= (SGEN_MAX_SMALL_OBJ_SIZE + CANARY_SIZE), "Invalid nursery object size");
SGEN_LOG (4, "Searching nursery for size: %zd", size);
size = SGEN_ALIGN_UP (size);
#ifndef USE_MONO_CTX
gpointer regs [ARCH_NUM_REGS];
#endif
+ MonoContext ctx;
gpointer stack_start;
info->stopped_domain = mono_domain_get ();
- info->stopped_ip = context ? (gpointer) ARCH_SIGCTX_IP (context) : NULL;
info->signal = 0;
stop_count = sgen_global_stop_count;
/* duplicate signal */
if (0 && info->stop_count == stop_count)
return;
+#ifdef USE_MONO_CTX
+ if (context) {
+ mono_sigctx_to_monoctx (context, &ctx);
+ info->stopped_ip = MONO_CONTEXT_GET_IP (&ctx);
+ stack_start = MONO_CONTEXT_GET_SP (&ctx) - REDZONE_SIZE;
+ } else {
+ info->stopped_ip = NULL;
+ stack_start = NULL;
+ }
+#else
+ info->stopped_ip = context ? (gpointer) ARCH_SIGCTX_IP (context) : NULL;
stack_start = context ? (char*) ARCH_SIGCTX_SP (context) - REDZONE_SIZE : NULL;
+#endif
+
/* If stack_start is not within the limits, then don't set it
in info and we will be restarted. */
if (stack_start >= info->stack_start_limit && info->stack_start <= info->stack_end) {
#ifdef USE_MONO_CTX
if (context) {
- mono_sigctx_to_monoctx (context, &info->ctx);
+ memcpy (&info->ctx, &ctx, sizeof (MonoContext));
} else {
memset (&info->ctx, 0, sizeof (MonoContext));
}
}
/* LOCKING: assumes the GC lock is held (by the stopping thread) */
-MONO_SIGNAL_HANDLER_FUNC (static, suspend_handler, (int sig, siginfo_t *siginfo, void *context))
+MONO_SIG_HANDLER_FUNC (static, suspend_handler)
{
/*
* The suspend signal handler potentially uses syscalls that
* must restore those to the values they had when we
* interrupted.
*/
-
SgenThreadInfo *info;
int old_errno = errno;
int hp_save_index = mono_hazard_pointer_save_for_signal_handler ();
+ MONO_SIG_HANDLER_GET_CONTEXT;
info = mono_thread_info_current ();
- suspend_thread (info, context);
+ suspend_thread (info, ctx);
mono_hazard_pointer_restore_for_signal_handler (hp_save_index);
errno = old_errno;
}
-MONO_SIGNAL_HANDLER_FUNC (static, restart_handler, (int sig))
+MONO_SIG_HANDLER_FUNC (static, restart_handler)
{
SgenThreadInfo *info;
int old_errno = errno;
end = queue->data + queue->next_slot;
while (cur < end) {
*start = *cur++;
- while (*start == *cur && cur < end)
+ while (cur < end && *start == *cur)
cur++;
start++;
};
#ifdef USE_MONO_CTX
static MonoContext cur_thread_ctx;
#else
-static mword cur_thread_regs [ARCH_NUM_REGS] = {0};
+static mword cur_thread_regs [ARCH_NUM_REGS];
#endif
static void
#include <glib.h>
#include <string.h>
#include <stdlib.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <errno.h>
-
-#include <sys/types.h>
#ifdef HOST_WIN32
#include <ws2tcpip.h>
#else
#include <netdb.h>
#include <arpa/inet.h>
#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <errno.h>
+
+#include <sys/types.h>
#include <mono/metadata/object.h>
#include <mono/io-layer/io-layer.h>
{
int limit = mono_gc_get_los_limit ();
- return (limit - 2 - sizeof (MonoString)) / 2;
+ return (limit - 2 - offsetof (MonoString, chars)) / 2;
}
+
+void
+ves_icall_System_String_InternalSetLength (MonoString *str, gint32 new_length)
+{
+ mono_gc_set_string_length (str, new_length);
+}
+
int
ves_icall_System_String_GetLOSLimit (void) MONO_INTERNAL;
+void
+ves_icall_System_String_InternalSetLength (MonoString *str, gint32 new_length) MONO_INTERNAL;
+
#endif /* _MONO_CLI_STRING_ICALLS_H_ */
#include <unistd.h>
#endif
#include <string.h>
+#include <math.h>
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#define THREAD_WANTS_A_BREAK(t) ((t->state & (ThreadState_StopRequested | \
ThreadState_SuspendRequested)) != 0)
-#define SPIN_TRYLOCK(i) (InterlockedCompareExchange (&(i), 1, 0) == 0)
-#define SPIN_LOCK(i) do { \
- if (SPIN_TRYLOCK (i)) \
- break; \
- } while (1)
-
-#define SPIN_UNLOCK(i) i = 0
#define SMALL_STACK (128 * (sizeof (gpointer) / 4) * 1024)
/* DEBUG: prints tp data every 2s */
KQUEUE_BACKEND
};
+enum {
+ MONITOR_STATE_AWAKE,
+ MONITOR_STATE_FALLING_ASLEEP,
+ MONITOR_STATE_SLEEPING
+};
+
typedef struct {
mono_mutex_t io_lock; /* access to sock_to_state */
int inited; // 0 -> not initialized , 1->initializing, 2->initialized, 3->cleaned up
void *pc_nthreads; /* Performance counter for total number of active threads */
/**/
volatile gint destroy_thread;
- volatile gint ignore_times; /* Used when there's a thread being created or destroyed */
- volatile gint sp_lock; /* spin lock used to protect ignore_times */
- volatile gint64 last_check;
- volatile gint64 time_sum;
- volatile gint n_sum;
- gint64 averages [2];
+#if DEBUG
+ volatile gint32 njobs;
+#endif
+ volatile gint32 nexecuted;
gboolean is_io;
} ThreadPool;
static void threadpool_start_idle_threads (ThreadPool *tp);
static void threadpool_kill_idle_threads (ThreadPool *tp);
static gboolean threadpool_start_thread (ThreadPool *tp);
+static void threadpool_kill_thread (ThreadPool *tp);
static void monitor_thread (gpointer data);
static void socket_io_cleanup (SocketIOData *data);
static MonoObject *get_io_event (MonoMList **list, gint event);
static MonoClass *socket_async_call_klass;
static MonoClass *process_async_call_klass;
+static GPtrArray *threads;
+mono_mutex_t threads_lock;
static GPtrArray *wsqs;
mono_mutex_t wsqs_lock;
static gboolean suspended;
+static volatile gint32 monitor_njobs = 0;
+static volatile gint32 monitor_state;
+static MonoSemType monitor_sem;
+static MonoInternalThread *monitor_internal_thread;
+
/* Hooks */
static MonoThreadPoolFunc tp_start_func;
static MonoThreadPoolFunc tp_finish_func;
mono_thread_set_execution_context (ares->original_context);
ares->original_context = NULL;
}
+
+#if DEBUG
+ InterlockedDecrement (&tp->njobs);
+#endif
+ if (!tp->is_io)
+ InterlockedIncrement (&tp->nexecuted);
+
+ if (InterlockedDecrement (&monitor_njobs) == 0)
+ monitor_state = MONITOR_STATE_FALLING_ASLEEP;
+
return exc;
}
}
#endif
+#define SAMPLES_PERIOD 500
+#define HISTORY_SIZE 10
+/* number of iteration without any jobs
+ in the queue before going to sleep */
+#define NUM_WAITING_ITERATIONS 10
+
+typedef struct {
+ gint32 nexecuted;
+ gint32 nthreads;
+ gint8 nthreads_diff;
+} SamplesHistory;
+
+/*
+ * returns :
+ * - 1 if the number of threads should increase
+ * - 0 if it should not change
+ * - -1 if it should decrease
+ * - -2 in case of error
+ */
+static gint8
+monitor_heuristic (gint16 *current, gint16 *history_size, SamplesHistory *history, ThreadPool *tp)
+{
+ int i;
+ gint8 decision;
+ gint16 cur, max = 0;
+ gboolean all_waitsleepjoin;
+ MonoInternalThread *thread;
+
+ /*
+ * The following heuristic tries to approach the optimal number of threads to maximize jobs throughput. To
+ * achieve this, it simply stores the number of jobs executed (nexecuted), the number of Threads (nthreads)
+ * and the decision (nthreads_diff) for the past HISTORY_SIZE periods of time, each period being of
+ * duration SAMPLES_PERIOD ms. This history gives us an insight into what happened, and to see if we should
+ * increase or reduce the number of threads by comparing the last period (current) to the best one.
+ *
+ * The algorithm can be describe as following :
+ * - if we have a better throughput than the best period : we should either increase the number of threads
+ * in case we already have more threads, either reduce the number of threads if we have less threads; this
+ * is equivalent to move away from the number of threads of the best period, because we are currently better
+ * - if we have a worse throughput than the best period : we should either decrease the number of threads if
+ * we have more threads, either increase the number of threads if we have less threads; this is equivalent
+ * to get closer to the number of threads of the best period, because we are currently worse
+ */
+
+ *history_size = MIN (*history_size + 1, HISTORY_SIZE);
+ cur = *current = (*current + 1) % *history_size;
+
+ history [cur].nthreads = tp->nthreads;
+ history [cur].nexecuted = InterlockedExchange (&tp->nexecuted, 0);
+
+ if (tp->waiting) {
+ /* if we have waiting thread in the pool, then do not create a new one */
+ history [cur].nthreads_diff = tp->waiting > 1 ? -1 : 0;
+ decision = 0;
+ } else if (tp->nthreads < tp->min_threads) {
+ history [cur].nthreads_diff = 1;
+ decision = 1;
+ } else if (*history_size <= 1) {
+ /* first iteration, let's add a thread by default */
+ history [cur].nthreads_diff = 1;
+ decision = 2;
+ } else {
+ mono_mutex_lock (&threads_lock);
+ if (threads == NULL) {
+ mono_mutex_unlock (&threads_lock);
+ return -2;
+ }
+ all_waitsleepjoin = TRUE;
+ for (i = 0; i < threads->len; ++i) {
+ thread = g_ptr_array_index (threads, i);
+ if (!(thread->state & ThreadState_WaitSleepJoin)) {
+ all_waitsleepjoin = FALSE;
+ break;
+ }
+ }
+ mono_mutex_unlock (&threads_lock);
+
+ if (all_waitsleepjoin) {
+ /* we might be in a condition of starvation/deadlock with tasks waiting for each others */
+ history [cur].nthreads_diff = 1;
+ decision = 5;
+ } else {
+ max = cur == 0 ? 1 : 0;
+ for (i = 0; i < *history_size; i++) {
+ if (i == cur)
+ continue;
+ if (history [i].nexecuted > history [max].nexecuted)
+ max = i;
+ }
+
+ if (history [cur].nexecuted >= history [max].nexecuted) {
+ /* we improved the situation, let's continue ! */
+ history [cur].nthreads_diff = history [cur].nthreads >= history [max].nthreads ? 1 : -1;
+ decision = 3;
+ } else {
+ /* we made it worse, let's return to previous situation */
+ history [cur].nthreads_diff = history [cur].nthreads >= history [max].nthreads ? -1 : 1;
+ decision = 4;
+ }
+ }
+ }
+
+#if DEBUG
+ printf ("monitor_thread: decision: %1d, history [current]: {nexecuted: %5d, nthreads: %3d, waiting: %2d, nthreads_diff: %2d}, history [max]: {nexecuted: %5d, nthreads: %3d}\n",
+ decision, history [cur].nexecuted, history [cur].nthreads, tp->waiting, history [cur].nthreads_diff, history [max].nexecuted, history [max].nthreads);
+#endif
+
+ return history [cur].nthreads_diff;
+}
+
static void
monitor_thread (gpointer unused)
{
ThreadPool *pools [2];
MonoInternalThread *thread;
- guint32 ms;
- gboolean need_one;
int i;
+ guint32 ms;
+ gint8 num_waiting_iterations = 0;
+
+ gint16 history_size = 0, current = -1;
+ SamplesHistory *history = malloc (sizeof (SamplesHistory) * HISTORY_SIZE);
+
pools [0] = &async_tp;
pools [1] = &async_io_tp;
thread = mono_thread_internal_current ();
ves_icall_System_Threading_Thread_SetName_internal (thread, mono_string_new (mono_domain_get (), "Threadpool monitor"));
while (1) {
- ms = 500;
+ ms = SAMPLES_PERIOD;
i = 10; //number of spurious awakes we tolerate before doing a round of rebalancing.
do {
guint32 ts;
if (suspended)
continue;
+ /* threadpool is cleaning up */
+ if (async_tp.pool_status == 2 || async_io_tp.pool_status == 2)
+ break;
+
+ switch (monitor_state) {
+ case MONITOR_STATE_AWAKE:
+ num_waiting_iterations = 0;
+ break;
+ case MONITOR_STATE_FALLING_ASLEEP:
+ if (++num_waiting_iterations == NUM_WAITING_ITERATIONS) {
+ if (monitor_state == MONITOR_STATE_FALLING_ASLEEP && InterlockedCompareExchange (&monitor_state, MONITOR_STATE_SLEEPING, MONITOR_STATE_FALLING_ASLEEP) == MONITOR_STATE_FALLING_ASLEEP) {
+ MONO_SEM_WAIT (&monitor_sem);
+
+ num_waiting_iterations = 0;
+ current = -1;
+ history_size = 0;
+ }
+ }
+ break;
+ case MONITOR_STATE_SLEEPING:
+ g_assert_not_reached ();
+ }
+
for (i = 0; i < 2; i++) {
ThreadPool *tp;
tp = pools [i];
- if (tp->waiting > 0)
- continue;
- need_one = (mono_cq_count (tp->queue) > 0);
- if (!need_one && !tp->is_io) {
- mono_mutex_lock (&wsqs_lock);
- for (i = 0; wsqs != NULL && i < wsqs->len; i++) {
- MonoWSQ *wsq;
- wsq = g_ptr_array_index (wsqs, i);
- if (mono_wsq_count (wsq) != 0) {
- need_one = TRUE;
- break;
- }
- }
- mono_mutex_unlock (&wsqs_lock);
+
+ if (tp->is_io) {
+ if (!tp->waiting && mono_cq_count (tp->queue) > 0)
+ threadpool_start_thread (tp);
+ } else {
+ gint8 nthreads_diff = monitor_heuristic (¤t, &history_size, history, tp);
+
+ if (nthreads_diff == 1)
+ threadpool_start_thread (tp);
+ else if (nthreads_diff == -1)
+ threadpool_kill_thread (tp);
}
- if (need_one)
- threadpool_start_thread (tp);
}
}
}
async_call_klass = mono_class_from_name (mono_defaults.corlib, "System", "MonoAsyncCall");
g_assert (async_call_klass);
+ mono_mutex_init (&threads_lock);
+ threads = g_ptr_array_sized_new (thread_count);
+ g_assert (threads);
+
mono_mutex_init_recursive (&wsqs_lock);
wsqs = g_ptr_array_sized_new (MAX (100 * cpu_count, thread_count));
signal (SIGALRM, signal_handler);
alarm (2);
#endif
+
+ MONO_SEM_INIT (&monitor_sem, 0);
+ monitor_state = MONITOR_STATE_AWAKE;
+ monitor_njobs = 0;
}
static MonoAsyncResult *
threadpool_kill_idle_threads (&async_tp);
threadpool_free_queue (&async_tp);
}
+
+ if (threads) {
+ mono_mutex_lock (&threads_lock);
+ if (threads)
+ g_ptr_array_free (threads, FALSE);
+ threads = NULL;
+ mono_mutex_unlock (&threads_lock);
+ }
if (wsqs) {
mono_mutex_lock (&wsqs_lock);
mono_mutex_unlock (&wsqs_lock);
MONO_SEM_DESTROY (&async_tp.new_job);
}
+
+ MONO_SEM_DESTROY (&monitor_sem);
}
static gboolean
{
gint n;
guint32 stack_size;
+ MonoInternalThread *thread;
stack_size = (!tp->is_io) ? 0 : SMALL_STACK;
while (!mono_runtime_is_shutting_down () && (n = tp->nthreads) < tp->max_threads) {
#ifndef DISABLE_PERFCOUNTERS
mono_perfcounter_update_value (tp->pc_nthreads, TRUE, 1);
#endif
- mono_thread_create_internal (mono_get_root_domain (), tp->async_invoke, tp, TRUE, stack_size);
+ thread = mono_thread_create_internal (mono_get_root_domain (), tp->async_invoke, tp, TRUE, stack_size);
+ if (!tp->is_io) {
+ mono_mutex_lock (&threads_lock);
+ g_assert (threads != NULL);
+ g_ptr_array_add (threads, thread);
+ mono_mutex_unlock (&threads_lock);
+ }
return TRUE;
}
}
MONO_SEM_POST (&tp->new_job);
}
+static void
+threadpool_kill_thread (ThreadPool *tp)
+{
+ if (tp->destroy_thread == 0 && InterlockedCompareExchange (&tp->destroy_thread, 1, 0) == 0)
+ pulse_on_new_job (tp);
+}
+
void
icall_append_job (MonoObject *ar)
{
static void
threadpool_append_jobs (ThreadPool *tp, MonoObject **jobs, gint njobs)
{
- static int job_counter;
MonoObject *ar;
gint i;
if (tp->pool_status == 0 && InterlockedCompareExchange (&tp->pool_status, 1, 0) == 0) {
if (!tp->is_io) {
- mono_thread_create_internal (mono_get_root_domain (), monitor_thread, NULL, TRUE, SMALL_STACK);
+ monitor_internal_thread = mono_thread_create_internal (mono_get_root_domain (), monitor_thread, NULL, TRUE, SMALL_STACK);
+ monitor_internal_thread->flags |= MONO_THREAD_FLAG_DONT_MANAGE;
threadpool_start_thread (tp);
}
/* Create on demand up to min_threads to avoid startup penalty for apps that don't use
}
}
+ InterlockedAdd (&monitor_njobs, njobs);
+
+ if (monitor_state == MONITOR_STATE_SLEEPING && InterlockedCompareExchange (&monitor_state, MONITOR_STATE_AWAKE, MONITOR_STATE_SLEEPING) == MONITOR_STATE_SLEEPING)
+ MONO_SEM_POST (&monitor_sem);
+
+ if (monitor_state == MONITOR_STATE_FALLING_ASLEEP)
+ InterlockedCompareExchange (&monitor_state, MONITOR_STATE_AWAKE, MONITOR_STATE_FALLING_ASLEEP);
+
for (i = 0; i < njobs; i++) {
ar = jobs [i];
if (ar == NULL || mono_domain_is_unloading (ar->vtable->domain))
continue; /* Might happen when cleaning domain jobs */
- if (!tp->is_io && (InterlockedIncrement (&job_counter) % 10) == 0) {
- MonoAsyncResult *o = (MonoAsyncResult *) ar;
- o->add_time = mono_100ns_ticks ();
- }
threadpool_jobs_inc (ar);
#ifndef DISABLE_PERFCOUNTERS
mono_perfcounter_update_value (tp->pc_nitems, TRUE, 1);
mono_cq_enqueue (tp->queue, ar);
}
+#if DEBUG
+ InterlockedAdd (&tp->njobs, njobs);
+#endif
+
for (i = 0; tp->waiting > 0 && i < MIN(njobs, tp->max_threads); i++)
pulse_on_new_job (tp);
}
return (*data != NULL);
}
-static void
-process_idle_times (ThreadPool *tp, gint64 t)
-{
- gint64 ticks;
- gint64 avg;
- gboolean compute_avg;
- gint new_threads;
- gint64 per1;
-
- if (tp->ignore_times || t <= 0)
- return;
-
- compute_avg = FALSE;
- ticks = mono_100ns_ticks ();
- t = ticks - t;
- SPIN_LOCK (tp->sp_lock);
- if (tp->ignore_times) {
- SPIN_UNLOCK (tp->sp_lock);
- return;
- }
- tp->time_sum += t;
- tp->n_sum++;
- if (tp->last_check == 0)
- tp->last_check = ticks;
- else if (tp->last_check > 0 && (ticks - tp->last_check) > 5000000) {
- tp->ignore_times = 1;
- compute_avg = TRUE;
- }
- SPIN_UNLOCK (tp->sp_lock);
-
- if (!compute_avg)
- return;
-
- //printf ("Items: %d Time elapsed: %.3fs\n", tp->n_sum, (ticks - tp->last_check) / 10000.0);
- tp->last_check = ticks;
- new_threads = 0;
- avg = tp->time_sum / tp->n_sum;
- if (tp->averages [1] == 0) {
- tp->averages [1] = avg;
- } else {
- per1 = ((100 * (ABS (avg - tp->averages [1]))) / tp->averages [1]);
- if (per1 > 5) {
- if (avg > tp->averages [1]) {
- if (tp->averages [1] < tp->averages [0]) {
- new_threads = -1;
- } else {
- new_threads = 1;
- }
- } else if (avg < tp->averages [1] && tp->averages [1] < tp->averages [0]) {
- new_threads = 1;
- }
- } else {
- int min, n;
- min = tp->min_threads;
- n = tp->nthreads;
- if ((n - min) < min && tp->busy_threads == n)
- new_threads = 1;
- }
- /*
- if (new_threads != 0) {
- printf ("n: %d per1: %lld avg=%lld avg1=%lld avg0=%lld\n", new_threads, per1, avg, tp->averages [1], tp->averages [0]);
- }
- */
- }
-
- tp->time_sum = 0;
- tp->n_sum = 0;
-
- tp->averages [0] = tp->averages [1];
- tp->averages [1] = avg;
- tp->ignore_times = 0;
-
- if (new_threads == -1) {
- if (tp->destroy_thread == 0 && InterlockedCompareExchange (&tp->destroy_thread, 1, 0) == 0)
- pulse_on_new_job (tp);
- }
-}
-
static gboolean
should_i_die (ThreadPool *tp)
{
if (tp_item_begin_func)
tp_item_begin_func (tp_item_user_data);
- if (!is_io_task && ar->add_time > 0)
- process_idle_times (tp, ar->add_time);
exc = mono_async_invoke (tp, ar);
if (tp_item_end_func)
tp_item_end_func (tp_item_user_data);
ar = NULL;
data = NULL;
must_die = should_i_die (tp);
- if (!must_die && (tp->is_io || !mono_wsq_local_pop (&data)))
- dequeue_or_steal (tp, &data, wsq);
+ if (must_die) {
+ mono_wsq_suspend (wsq);
+ } else {
+ if (tp->is_io || !mono_wsq_local_pop (&data))
+ dequeue_or_steal (tp, &data, wsq);
+ }
n_naps = 0;
while (!must_die && !data && n_naps < 4) {
if (tp_finish_func)
tp_finish_func (tp_hooks_user_data);
+
+ if (!tp->is_io) {
+ if (threads) {
+ mono_mutex_lock (&threads_lock);
+ if (threads)
+ g_ptr_array_remove_fast (threads, mono_thread_current ()->internal_thread);
+ mono_mutex_unlock (&threads_lock);
+ }
+ }
+
return;
}
}
endif
endif
-if JIT_SUPPORTED
-
if SUPPORT_SGEN
sgen_binaries = mono-sgen
sgen_libraries = libmonosgen-2.0.la
endif
endif
-endif
-
mono_boehm_SOURCES = \
main.c
endif
@echo "const char *build_date = \"`date`\";" > buildver-boehm.h
mono_boehm-main.$(OBJEXT): buildver-boehm.h
+main.c: buildver-boehm.h
+
endif
if DISABLE_EXECUTABLES
endif
@echo "const char *build_date = \"`date`\";" > buildver-sgen.h
mono_sgen-main-sgen.$(OBJEXT): buildver-sgen.h
+main-sgen.c: buildver-sgen.h
+
if DTRACE_G_REQUIRED
LIBMONO_DTRACE_OBJECT = .libs/mono-dtrace.$(OBJEXT)
s390x_sources = \
mini-s390x.c \
mini-s390x.h \
+ support-s390x.h \
exceptions-s390x.c \
tramp-s390x.c
pkgconfigdir = $(libdir)/pkgconfig
-if JIT_SUPPORTED
BUILT_SOURCES = version.h $(arch_built)
-else
-BUILT_SOURCES = version.h
-endif
CLEANFILES= $(BUILT_SOURCES) *.exe *.dll
EXTRA_DIST = TestDriver.cs ldscript ldscript.mono \
if (info && !has_nullable) {
/* Supported by the dynamic runtime-invoke wrapper */
skip = TRUE;
- g_free (info);
}
+ if (info)
+ mono_arch_dyn_call_free (info);
}
#endif
plt_entry = g_hash_table_lookup (acfg->plt_offset_to_entry, GUINT_TO_POINTER (i));
ji = plt_entry->ji;
- if (acfg->llvm) {
- /*
- * If the target is directly callable, alias the plt symbol to point to
- * the method code.
- * FIXME: Use this to simplify emit_and_reloc_code ().
- * FIXME: Avoid the got slot.
- * FIXME: Add support to the binary writer.
- */
- if (ji && is_direct_callable (acfg, NULL, ji) && !acfg->use_bin_writer) {
- MonoCompile *callee_cfg = g_hash_table_lookup (acfg->method_to_cfg, ji->data.method);
-
- if (callee_cfg) {
- if (acfg->thumb_mixed && !callee_cfg->compile_llvm) {
- /* LLVM calls the PLT entries using bl, so emit a stub */
- emit_set_thumb_mode (acfg);
- fprintf (acfg->fp, "\n.thumb_func\n");
- emit_label (acfg, plt_entry->llvm_symbol);
- fprintf (acfg->fp, "bx pc\n");
- fprintf (acfg->fp, "nop\n");
- emit_set_arm_mode (acfg);
- fprintf (acfg->fp, "b %s\n", callee_cfg->asm_symbol);
- } else {
- fprintf (acfg->fp, "\n.set %s, %s\n", plt_entry->llvm_symbol, callee_cfg->asm_symbol);
- }
- continue;
- }
- }
- }
-
debug_sym = plt_entry->debug_sym;
if (acfg->thumb_mixed && !plt_entry->jit_used)
/* Emit only a thumb version */
continue;
+ /* Skip plt entries not actually called */
+ if (!plt_entry->jit_used && !plt_entry->llvm_used)
+ continue;
+
if (acfg->llvm && !acfg->thumb_mixed)
emit_label (acfg, plt_entry->llvm_symbol);
plt_entry = g_hash_table_lookup (acfg->plt_offset_to_entry, GUINT_TO_POINTER (i));
ji = plt_entry->ji;
- if (ji && is_direct_callable (acfg, NULL, ji) && !acfg->use_bin_writer)
- continue;
-
/* Skip plt entries not actually called by LLVM code */
if (!plt_entry->llvm_used)
continue;
{
MonoMethod *method = (MonoMethod*)key;
MonoJumpInfoToken *ji = (MonoJumpInfoToken*)value;
- MonoJumpInfoToken *new_ji = g_new0 (MonoJumpInfoToken, 1);
MonoAotCompile *acfg = user_data;
+ MonoJumpInfoToken *new_ji;
+ new_ji = mono_mempool_alloc0 (acfg->mempool, sizeof (MonoJumpInfoToken));
new_ji->image = ji->image;
new_ji->token = ji->token;
g_hash_table_insert (acfg->token_info_hash, method, new_ji);
mono_acfg_lock (acfg);
g_hash_table_foreach (cfg->token_info_hash, add_token_info_hash, acfg);
mono_acfg_unlock (acfg);
+ g_hash_table_destroy (cfg->token_info_hash);
+ cfg->token_info_hash = NULL;
/*
* Check for absolute addresses.
return get_debug_sym (cfg->orig_method, "", llvm_acfg->method_label_hash);
}
+gboolean
+mono_aot_is_direct_callable (MonoJumpInfo *patch_info)
+{
+ return is_direct_callable (llvm_acfg, NULL, patch_info);
+}
+
+void
+mono_aot_mark_unused_llvm_plt_entry (MonoJumpInfo *patch_info)
+{
+ MonoPltEntry *plt_entry;
+
+ plt_entry = get_plt_entry (llvm_acfg, patch_info);
+ plt_entry->llvm_used = FALSE;
+}
+
char*
mono_aot_get_plt_symbol (MonoJumpInfoType type, gconstpointer data)
{
acfg->patch_to_got_offset_by_type [i] = g_hash_table_new (mono_patch_info_hash, mono_patch_info_equal);
acfg->got_patches = g_ptr_array_new ();
acfg->method_to_cfg = g_hash_table_new (NULL, NULL);
- acfg->token_info_hash = g_hash_table_new_full (NULL, NULL, NULL, g_free);
+ acfg->token_info_hash = g_hash_table_new_full (NULL, NULL, NULL, NULL);
acfg->method_to_pinvoke_import = g_hash_table_new_full (NULL, NULL, NULL, g_free);
acfg->image_hash = g_hash_table_new (NULL, NULL);
acfg->image_table = g_ptr_array_new ();
decode_llvm_mono_eh_frame (MonoAotModule *amodule, MonoDomain *domain,
MonoMethod *method, guint8 *code,
MonoJitExceptionInfo *clauses, int num_clauses,
- int extra_size, GSList **nesting,
+ MonoJitInfoFlags flags,
+ GSList **nesting,
int *this_reg, int *this_offset)
{
guint8 *p;
* allocate a new JI.
*/
jinfo =
- mono_domain_alloc0_lock_free (domain, MONO_SIZEOF_JIT_INFO + (sizeof (MonoJitExceptionInfo) * (ei_len + nested_len)) + extra_size);
+ mono_domain_alloc0_lock_free (domain, mono_jit_info_size (flags, ei_len + nested_len, 0));
+ mono_jit_info_init (jinfo, method, code, code_len, flags, ei_len + nested_len, 0);
- jinfo->code_size = code_len;
jinfo->unwind_info = mono_cache_unwind_info (info.unw_info, info.unw_info_len);
- jinfo->d.method = method;
- jinfo->code_start = code;
- jinfo->domain_neutral = 0;
/* This signals that unwind_info points to a normal cached unwind info */
jinfo->from_aot = 0;
- jinfo->num_clauses = ei_len + nested_len;
+ jinfo->from_llvm = 1;
for (i = 0; i < ei_len; ++i) {
/*
- * orig_jinfo contains the original IL exception info saved by the AOT
+ * clauses contains the original IL exception info saved by the AOT
* compiler, we have to combine that with the information produced by LLVM
*/
/* The type_info entries contain IL clause indexes */
{
int i, buf_len, num_clauses, len;
MonoJitInfo *jinfo;
- guint unwind_info, flags;
+ MonoJitInfoFlags flags = JIT_INFO_NONE;
+ guint unwind_info, eflags;
gboolean has_generic_jit_info, has_dwarf_unwind_info, has_clauses, has_seq_points, has_try_block_holes, has_arch_eh_jit_info;
gboolean from_llvm, has_gc_map;
guint8 *p;
async = mono_thread_info_is_async_context ();
p = ex_info;
- flags = decode_value (p, &p);
- has_generic_jit_info = (flags & 1) != 0;
- has_dwarf_unwind_info = (flags & 2) != 0;
- has_clauses = (flags & 4) != 0;
- has_seq_points = (flags & 8) != 0;
- from_llvm = (flags & 16) != 0;
- has_try_block_holes = (flags & 32) != 0;
- has_gc_map = (flags & 64) != 0;
- has_arch_eh_jit_info = (flags & 128) != 0;
+ eflags = decode_value (p, &p);
+ has_generic_jit_info = (eflags & 1) != 0;
+ has_dwarf_unwind_info = (eflags & 2) != 0;
+ has_clauses = (eflags & 4) != 0;
+ has_seq_points = (eflags & 8) != 0;
+ from_llvm = (eflags & 16) != 0;
+ has_try_block_holes = (eflags & 32) != 0;
+ has_gc_map = (eflags & 64) != 0;
+ has_arch_eh_jit_info = (eflags & 128) != 0;
if (has_dwarf_unwind_info) {
unwind_info = decode_value (p, &p);
} else {
unwind_info = decode_value (p, &p);
}
- if (has_generic_jit_info)
+ if (has_generic_jit_info) {
+ flags |= JIT_INFO_HAS_GENERIC_JIT_INFO;
generic_info_size = sizeof (MonoGenericJitInfo);
- else
+ } else {
generic_info_size = 0;
+ }
if (has_try_block_holes) {
num_holes = decode_value (p, &p);
+ flags |= JIT_INFO_HAS_TRY_BLOCK_HOLES;
try_holes_info_size = sizeof (MonoTryBlockHoleTableJitInfo) + num_holes * sizeof (MonoTryBlockHoleJitInfo);
} else {
num_holes = try_holes_info_size = 0;
num_clauses = decode_value (p, &p);
else
num_clauses = 0;
- if (has_arch_eh_jit_info)
+ if (has_arch_eh_jit_info) {
+ flags |= JIT_INFO_HAS_ARCH_EH_INFO;
arch_eh_jit_info_size = sizeof (MonoArchEHJitInfo);
- else
+ } else {
arch_eh_jit_info_size = 0;
+ }
if (from_llvm) {
MonoJitExceptionInfo *clauses;
}
}
- jinfo = decode_llvm_mono_eh_frame (amodule, domain, method, code, clauses, num_clauses, generic_info_size + try_holes_info_size + arch_eh_jit_info_size, nesting, &this_reg, &this_offset);
- jinfo->from_llvm = 1;
+ jinfo = decode_llvm_mono_eh_frame (amodule, domain, method, code, clauses, num_clauses, flags, nesting, &this_reg, &this_offset);
g_free (clauses);
for (i = 0; i < num_clauses; ++i)
g_slist_free (nesting [i]);
g_free (nesting);
} else {
- len = MONO_SIZEOF_JIT_INFO + (sizeof (MonoJitExceptionInfo) * num_clauses) + generic_info_size + try_holes_info_size + arch_eh_jit_info_size;
+ len = mono_jit_info_size (flags, num_clauses, num_holes);
jinfo = alloc0_jit_info_data (domain, len, async);
- jinfo->num_clauses = num_clauses;
+ mono_jit_info_init (jinfo, method, code, code_len, flags, num_clauses, num_holes);
for (i = 0; i < jinfo->num_clauses; ++i) {
MonoJitExceptionInfo *ei = &jinfo->clauses [i];
ei->handler_start = code + decode_value (p, &p);
}
- jinfo->code_size = code_len;
jinfo->unwind_info = unwind_info;
- jinfo->d.method = method;
- jinfo->code_start = code;
jinfo->domain_neutral = 0;
jinfo->from_aot = 1;
}
- /*
- * Set all the 'has' flags, the mono_jit_info_get () functions depends on this to
- * compute the addresses of data blocks.
- */
- if (has_generic_jit_info)
- jinfo->has_generic_jit_info = 1;
- if (has_arch_eh_jit_info)
- jinfo->has_arch_eh_info = 1;
- if (has_try_block_holes)
- jinfo->has_try_block_holes = 1;
-
if (has_try_block_holes) {
MonoTryBlockHoleTableJitInfo *table;
/* branches to the following block can be removed */
if (bb->last_ins && bb->last_ins->opcode == OP_BR && !bbn->out_of_line) {
- bb->last_ins->opcode = OP_NOP;
+ NULLIFY_INS (bb->last_ins);
changed = TRUE;
if (cfg->verbose_level > 2)
g_print ("br removal triggered %d -> %d\n", bb->block_num, bbn->block_num);
br_reg: src1:i len:8
bigmul: len:8 dest:l src1:i src2:i
bigmul_un: len:8 dest:l src1:i src2:i
-tls_get: len:8 dest:i clob:c
+tls_get: len:24 dest:i clob:c
# 32 bit opcodes
int_add: dest:i src1:i src2:i len:4
}
#endif
MONO_EMIT_NEW_BIALU (cfg, ins->opcode, ins->dreg, ins->sreg1, ins->sreg2);
- ins->opcode = OP_NOP;
+ NULLIFY_INS (ins);
} else {
emulate = TRUE;
}
if (power > 1) {
intermediate_reg = compensator_reg;
- MONO_EMIT_NEW_BIALU_IMM (cfg, is_long ? OP_LSHR_IMM : OP_SHR_IMM, intermediate_reg, ins->sreg1, is_long ? 63 : 31);
+ MONO_EMIT_NEW_BIALU_IMM (cfg, is_long ? OP_LSHR_IMM : OP_ISHR_IMM, intermediate_reg, ins->sreg1, is_long ? 63 : 31);
} else {
intermediate_reg = ins->sreg1;
}
- MONO_EMIT_NEW_BIALU_IMM (cfg, is_long ? OP_LSHR_UN_IMM : OP_SHR_UN_IMM, compensator_reg, intermediate_reg, (is_long ? 64 : 32) - power);
+ MONO_EMIT_NEW_BIALU_IMM (cfg, is_long ? OP_LSHR_UN_IMM : OP_ISHR_UN_IMM, compensator_reg, intermediate_reg, (is_long ? 64 : 32) - power);
MONO_EMIT_NEW_BIALU (cfg, is_long ? OP_LADD : OP_IADD, ins->dreg, ins->sreg1, compensator_reg);
/* Compute remainder */
MONO_EMIT_NEW_BIALU_IMM (cfg, is_long ? OP_LAND_IMM : OP_AND_IMM, ins->dreg, ins->dreg, (1 << power) - 1);
MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
- next->opcode = OP_NOP;
+ NULLIFY_INS (next);
break;
}
case OP_LBGE:
MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
- next->opcode = OP_NOP;
+ NULLIFY_INS (next);
break;
case OP_LCEQ: {
int d1, d2;
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
- next->opcode = OP_NOP;
+ NULLIFY_INS (next);
break;
}
case OP_LCLT:
MONO_START_BB (cfg, set_to_1);
MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
MONO_START_BB (cfg, set_to_0);
- next->opcode = OP_NOP;
+ NULLIFY_INS (next);
break;
}
default:
MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
- next->opcode = OP_NOP;
+ NULLIFY_INS (next);
break;
}
MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
- next->opcode = OP_NOP;
+ NULLIFY_INS (next);
break;
case OP_LCEQ: {
int d1, d2;
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
- next->opcode = OP_NOP;
+ NULLIFY_INS (next);
break;
}
case OP_LCLT:
MONO_START_BB (cfg, set_to_1);
MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
MONO_START_BB (cfg, set_to_0);
- next->opcode = OP_NOP;
+ NULLIFY_INS (next);
break;
}
default:
if (call->vret_in_reg) {
MonoCallInst *call2;
- /* Replace the vcall with an integer call */
+ /* Replace the vcall with a scalar call */
MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
memcpy (call2, call, sizeof (MonoCallInst));
switch (ins->opcode) {
case OP_VCALL:
- call2->inst.opcode = OP_CALL;
+ call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL : OP_CALL;
break;
case OP_VCALL_REG:
- call2->inst.opcode = OP_CALL_REG;
+ call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_REG : OP_CALL_REG;
break;
case OP_VCALL_MEMBASE:
- call2->inst.opcode = OP_CALL_MEMBASE;
+ call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_MEMBASE : OP_CALL_MEMBASE;
break;
}
call2->inst.dreg = alloc_preg (cfg);
break;
case 3:
case 4:
- MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
+ if (call->vret_in_reg_fp)
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
+ else
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
break;
case 5:
case 6:
case 7:
case 8:
+ if (call->vret_in_reg_fp) {
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
+ break;
+ }
#if SIZEOF_REGISTER == 4
/*
FIXME Other ABIs might return in different regs than the ones used for LCALL.
} else {
cfailed++;
- if (verbose)
- g_print ("Test '%s' failed compilation.\n", method->name);
+ g_print ("Test '%s' failed compilation.\n", method->name);
}
if (mini_stats_fd)
fprintf (mini_stats_fd, "%f, ",
mono_load_coree (argv [i]);
#endif
+ /* Set rootdir before loading config */
+ mono_set_rootdir ();
+
/* Parse gac loading options before loading assemblies. */
if (mono_compile_aot || action == DO_EXEC || action == DO_DEBUGGER) {
mono_config_parse (config_file);
/* Try dead code elimination */
if ((var != cfg->ret) && !(var->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT)) && ((ins->opcode == OP_ICONST) || (ins->opcode == OP_I8CONST) || (ins->opcode == OP_R8CONST)) && !(var->flags & MONO_INST_VOLATILE)) {
LIVENESS_DEBUG (printf ("\tdead def of R%d, eliminated\n", ins->dreg));
- ins->opcode = OP_NOP;
- ins->dreg = -1;
- MONO_INST_NULLIFY_SREGS (ins);
+ NULLIFY_INS (ins);
return;
}
#define BRANCH_COST 10
#define INLINE_LENGTH_LIMIT 20
+
+/* These have 'cfg' as an implicit argument */
#define INLINE_FAILURE(msg) do { \
- if ((cfg->method != method) && (method->wrapper_type == MONO_WRAPPER_NONE)) { \
- if (cfg->verbose_level >= 2) \
- printf ("inline failed: %s\n", msg); \
- goto inline_failure; \
+ if ((cfg->method != cfg->current_method) && (cfg->current_method->wrapper_type == MONO_WRAPPER_NONE)) { \
+ inline_failure (cfg, msg); \
+ goto exception_exit; \
} \
} while (0)
#define CHECK_CFG_EXCEPTION do {\
- if (cfg->exception_type != MONO_EXCEPTION_NONE)\
- goto exception_exit;\
+ if (cfg->exception_type != MONO_EXCEPTION_NONE) \
+ goto exception_exit; \
} while (0)
-#define METHOD_ACCESS_FAILURE do { \
- char *method_fname = mono_method_full_name (method, TRUE); \
- char *cil_method_fname = mono_method_full_name (cil_method, TRUE); \
- mono_cfg_set_exception (cfg, MONO_EXCEPTION_METHOD_ACCESS); \
- cfg->exception_message = g_strdup_printf ("Method `%s' is inaccessible from method `%s'\n", cil_method_fname, method_fname); \
- g_free (method_fname); \
- g_free (cil_method_fname); \
- goto exception_exit; \
+#define METHOD_ACCESS_FAILURE(method, cmethod) do { \
+ method_access_failure ((cfg), (method), (cmethod)); \
+ goto exception_exit; \
} while (0)
-#define FIELD_ACCESS_FAILURE do { \
- char *method_fname = mono_method_full_name (method, TRUE); \
- char *field_fname = mono_field_full_name (field); \
- mono_cfg_set_exception (cfg, MONO_EXCEPTION_FIELD_ACCESS); \
- cfg->exception_message = g_strdup_printf ("Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname); \
- g_free (method_fname); \
- g_free (field_fname); \
+#define FIELD_ACCESS_FAILURE(method, field) do { \
+ field_access_failure ((cfg), (method), (field)); \
goto exception_exit; \
} while (0)
#define GENERIC_SHARING_FAILURE(opcode) do { \
- if (cfg->generic_sharing_context) { \
- if (cfg->verbose_level > 2) \
- printf ("sharing failed for method %s.%s.%s/%d opcode %s line %d\n", method->klass->name_space, method->klass->name, method->name, method->signature->param_count, mono_opcode_name ((opcode)), __LINE__); \
- mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
+ if (cfg->gshared) { \
+ gshared_failure (cfg, opcode, __FILE__, __LINE__); \
goto exception_exit; \
} \
} while (0)
#define GSHAREDVT_FAILURE(opcode) do { \
if (cfg->gsharedvt) { \
- cfg->exception_message = g_strdup_printf ("gsharedvt failed for method %s.%s.%s/%d opcode %s %s:%d", method->klass->name_space, method->klass->name, method->name, method->signature->param_count, mono_opcode_name ((opcode)), __FILE__, __LINE__); \
- if (cfg->verbose_level >= 2) \
- printf ("%s\n", cfg->exception_message); \
- mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
+ gsharedvt_failure (cfg, opcode, __FILE__, __LINE__); \
goto exception_exit; \
} \
} while (0)
printf ("AOT disabled: %s:%d\n", __FILE__, __LINE__); \
(cfg)->disable_aot = TRUE; \
} while (0)
+#define LOAD_ERROR do { \
+ break_on_unverified (); \
+ mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD); \
+ goto exception_exit; \
+ } while (0)
+
+#define TYPE_LOAD_ERROR(klass) do { \
+ cfg->exception_ptr = klass; \
+ LOAD_ERROR; \
+ } while (0)
/* Determine whenever 'ins' represents a load of the 'this' argument */
#define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && ((ins)->opcode == OP_MOVE) && ((ins)->sreg1 == cfg->args [0]->dreg))
(vi)->idx = (id); \
} while (0)
-void
-mono_inst_set_src_registers (MonoInst *ins, int *regs)
-{
- ins->sreg1 = regs [0];
- ins->sreg2 = regs [1];
- ins->sreg3 = regs [2];
-}
-
guint32
mono_alloc_ireg (MonoCompile *cfg)
{
helper_sig_monitor_enter_exit_trampoline_llvm = mono_create_icall_signature ("void object");
}
+static MONO_NEVER_INLINE void
+break_on_unverified (void)
+{
+ if (mini_get_debug_options ()->break_on_unverified)
+ G_BREAKPOINT ();
+}
+
+static MONO_NEVER_INLINE void
+method_access_failure (MonoCompile *cfg, MonoMethod *method, MonoMethod *cil_method)
+{
+ char *method_fname = mono_method_full_name (method, TRUE);
+ char *cil_method_fname = mono_method_full_name (cil_method, TRUE);
+ mono_cfg_set_exception (cfg, MONO_EXCEPTION_METHOD_ACCESS);
+ cfg->exception_message = g_strdup_printf ("Method `%s' is inaccessible from method `%s'\n", cil_method_fname, method_fname);
+ g_free (method_fname);
+ g_free (cil_method_fname);
+}
+
+static MONO_NEVER_INLINE void
+field_access_failure (MonoCompile *cfg, MonoMethod *method, MonoClassField *field)
+{
+ char *method_fname = mono_method_full_name (method, TRUE);
+ char *field_fname = mono_field_full_name (field);
+ mono_cfg_set_exception (cfg, MONO_EXCEPTION_FIELD_ACCESS);
+ cfg->exception_message = g_strdup_printf ("Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);
+ g_free (method_fname);
+ g_free (field_fname);
+}
+
+static MONO_NEVER_INLINE void
+inline_failure (MonoCompile *cfg, const char *msg)
+{
+ if (cfg->verbose_level >= 2)
+ printf ("inline failed: %s\n", msg);
+ mono_cfg_set_exception (cfg, MONO_EXCEPTION_INLINE_FAILED);
+}
+
+static MONO_NEVER_INLINE void
+gshared_failure (MonoCompile *cfg, int opcode, const char *file, int line)
+{
+ if (cfg->verbose_level > 2) \
+ printf ("sharing failed for method %s.%s.%s/%d opcode %s line %d\n", cfg->current_method->klass->name_space, cfg->current_method->klass->name, cfg->current_method->name, cfg->current_method->signature->param_count, mono_opcode_name ((opcode)), __LINE__);
+ mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
+}
+
+static MONO_NEVER_INLINE void
+gsharedvt_failure (MonoCompile *cfg, int opcode, const char *file, int line)
+{
+ cfg->exception_message = g_strdup_printf ("gsharedvt failed for method %s.%s.%s/%d opcode %s %s:%d", cfg->current_method->klass->name_space, cfg->current_method->klass->name, cfg->current_method->name, cfg->current_method->signature->param_count, mono_opcode_name ((opcode)), file, line);
+ if (cfg->verbose_level >= 2)
+ printf ("%s\n", cfg->exception_message);
+ mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
+}
+
/*
* When using gsharedvt, some instatiations might be verifiable, and some might be not. i.e.
* foo<T> (int i) { ldarg.0; box T; }
mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
goto exception_exit; \
} \
- if (mini_get_debug_options ()->break_on_unverified) \
- G_BREAKPOINT (); \
- else \
- goto unverified; \
+ break_on_unverified (); \
+ goto unverified; \
} while (0)
-#define LOAD_ERROR do { if (mini_get_debug_options ()->break_on_unverified) G_BREAKPOINT (); else goto load_error; } while (0)
-
-#define TYPE_LOAD_ERROR(klass) do { if (mini_get_debug_options ()->break_on_unverified) G_BREAKPOINT (); else { cfg->exception_ptr = klass; goto load_error; } } while (0)
-
#define GET_BBLOCK(cfg,tblock,ip) do { \
(tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
if (!(tblock)) { \
int i;
#endif
+ if (cfg->disable_inline)
+ return FALSE;
if (cfg->generic_sharing_context)
return FALSE;
}
#endif
+ if (g_list_find (cfg->dont_inline, method))
+ return FALSE;
+
return TRUE;
}
}
}
+/*
+ * inline_method:
+ *
+ * Return the cost of inlining CMETHOD.
+ */
static int
inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
- guchar *ip, guint real_offset, GList *dont_inline, gboolean inline_always)
+ guchar *ip, guint real_offset, gboolean inline_always, MonoBasicBlock **out_cbb)
{
MonoInst *ins, *rvar = NULL;
MonoMethodHeader *cheader;
guint32 prev_cil_offset_to_bb_len;
MonoMethod *prev_current_method;
MonoGenericContext *prev_generic_context;
- gboolean ret_var_set, prev_ret_var_set, virtual = FALSE;
+ gboolean ret_var_set, prev_ret_var_set, prev_disable_inline, virtual = FALSE;
g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
prev_current_method = cfg->current_method;
prev_generic_context = cfg->generic_context;
prev_ret_var_set = cfg->ret_var_set;
+ prev_disable_inline = cfg->disable_inline;
if (*ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
virtual = TRUE;
- costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, dont_inline, sp, real_offset, virtual);
+ costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, sp, real_offset, virtual);
ret_var_set = cfg->ret_var_set;
cfg->current_method = prev_current_method;
cfg->generic_context = prev_generic_context;
cfg->ret_var_set = prev_ret_var_set;
+ cfg->disable_inline = prev_disable_inline;
cfg->inline_depth --;
if ((costs >= 0 && costs < 60) || inline_always) {
cfg->cbb = ebblock;
}
+ *out_cbb = cfg->cbb;
+
if (rvar) {
/*
* If the inlined method contains only a throw, then the ret var is not
#define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
#define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
#define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
-#define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) {cfg->exception_ptr = klass; LOAD_ERROR;}
+#define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) TYPE_LOAD_ERROR ((klass))
/* offset from br.s -> br like opcodes */
#define BIG_BRANCH_OFFSET 13
emit_init_local (cfg, local, type, TRUE);
return ip + 6;
}
-load_error:
+ exception_exit:
return NULL;
}
return addr;
}
+/*
+ * handle_ctor_call:
+ *
+ * Handle calls made to ctors from NEWOBJ opcodes.
+ *
+ * REF_BBLOCK will point to the current bblock after the call.
+ */
+static void
+handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used,
+ MonoInst **sp, guint8 *ip, MonoBasicBlock **ref_bblock, int *inline_costs)
+{
+ MonoInst *vtable_arg = NULL, *callvirt_this_arg = NULL, *ins;
+ MonoBasicBlock *bblock = *ref_bblock;
+
+ if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
+ mono_method_is_generic_sharable (cmethod, TRUE)) {
+ if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
+ mono_class_vtable (cfg->domain, cmethod->klass);
+ CHECK_TYPELOAD (cmethod->klass);
+
+ vtable_arg = emit_get_rgctx_method (cfg, context_used,
+ cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
+ } else {
+ if (context_used) {
+ vtable_arg = emit_get_rgctx_klass (cfg, context_used,
+ cmethod->klass, MONO_RGCTX_INFO_VTABLE);
+ } else {
+ MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
+
+ CHECK_TYPELOAD (cmethod->klass);
+ EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
+ }
+ }
+ }
+
+ /* Avoid virtual calls to ctors if possible */
+ if (mono_class_is_marshalbyref (cmethod->klass))
+ callvirt_this_arg = sp [0];
+
+ if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
+ g_assert (MONO_TYPE_IS_VOID (fsig->ret));
+ CHECK_CFG_EXCEPTION;
+ } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
+ mono_method_check_inlining (cfg, cmethod) &&
+ !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE)) {
+ int costs;
+
+ if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, FALSE, &bblock))) {
+ cfg->real_offset += 5;
+
+ *inline_costs += costs - 5;
+ *ref_bblock = bblock;
+ } else {
+ INLINE_FAILURE ("inline failure");
+ // FIXME-VT: Clean this up
+ if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))
+ GSHAREDVT_FAILURE(*ip);
+ mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
+ }
+ } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
+ MonoInst *addr;
+
+ addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
+ mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
+ } else if (context_used &&
+ ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
+ !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
+ MonoInst *cmethod_addr;
+
+ /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
+
+ cmethod_addr = emit_get_rgctx_method (cfg, context_used,
+ cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
+
+ mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
+ } else {
+ INLINE_FAILURE ("ctor call");
+ ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
+ callvirt_this_arg, NULL, vtable_arg);
+ }
+ exception_exit:
+ return;
+}
+
/*
* mono_method_to_ir:
*
*/
int
mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock,
- MonoInst *return_var, GList *dont_inline, MonoInst **inline_args,
+ MonoInst *return_var, MonoInst **inline_args,
guint inline_offset, gboolean is_virtual_call)
{
MonoError error;
gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
int context_used;
gboolean init_locals, seq_points, skip_dead_blocks;
- gboolean disable_inline, sym_seq_points = FALSE;
+ gboolean sym_seq_points = FALSE;
MonoInst *cached_tls_addr = NULL;
MonoDebugMethodInfo *minfo;
MonoBitSet *seq_point_locs = NULL;
MonoBitSet *seq_point_set_locs = NULL;
- disable_inline = is_jit_optimizer_disabled (method);
+ cfg->disable_inline = is_jit_optimizer_disabled (method);
/* serialization and xdomain stuff may need access to private fields and methods */
dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
param_types [n + sig->hasthis] = sig->params [n];
cfg->arg_types = param_types;
- dont_inline = g_list_prepend (dont_inline, method);
+ cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
if (cfg->method == method) {
if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
}
if (!mono_method_can_access_method (method_definition, target_method) &&
!mono_method_can_access_method (method, cil_method))
- METHOD_ACCESS_FAILURE;
+ METHOD_ACCESS_FAILURE (method, cil_method);
}
if (mono_security_core_clr_enabled ())
/* Inlining */
if (cmethod && (cfg->opt & MONO_OPT_INLINE) &&
(!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
- !disable_inline && mono_method_check_inlining (cfg, cmethod) &&
- !g_list_find (dont_inline, cmethod)) {
+ mono_method_check_inlining (cfg, cmethod)) {
int costs;
gboolean always = FALSE;
always = TRUE;
}
- costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, dont_inline, always);
+ costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always, &bblock);
if (costs) {
cfg->real_offset += 5;
- bblock = cfg->cbb;
if (!MONO_TYPE_IS_VOID (fsig->ret)) {
/* *sp is already set by inline_method */
ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
ins->sreg2 = -1;
- sp [1]->opcode = OP_NOP;
+ NULLIFY_INS (sp [1]);
}
}
/* Might be followed by an instruction added by ADD_WIDEN_OP */
if (sp [1]->next == NULL)
- sp [1]->opcode = OP_NOP;
+ NULLIFY_INS (sp [1]);
}
}
MONO_ADD_INS ((cfg)->cbb, (ins));
}
*/
- if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
- mono_method_is_generic_sharable (cmethod, TRUE)) {
- if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
- mono_class_vtable (cfg->domain, cmethod->klass);
- CHECK_TYPELOAD (cmethod->klass);
-
- vtable_arg = emit_get_rgctx_method (cfg, context_used,
- cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
- } else {
- if (context_used) {
- vtable_arg = emit_get_rgctx_klass (cfg, context_used,
- cmethod->klass, MONO_RGCTX_INFO_VTABLE);
- } else {
- MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
-
- CHECK_TYPELOAD (cmethod->klass);
- EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
- }
- }
- }
-
n = fsig->param_count;
CHECK_STACK (n);
((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
MonoInst *iargs [3];
- g_assert (!vtable_arg);
-
sp -= n;
EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
iargs [0] = NULL;
if (mini_class_is_system_array (cmethod->klass)) {
- g_assert (!vtable_arg);
-
*sp = emit_get_rgctx_method (cfg, context_used,
cmethod, MONO_RGCTX_INFO_METHOD);
/* now call the string ctor */
alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
} else {
- MonoInst* callvirt_this_arg = NULL;
-
if (cmethod->klass->valuetype) {
iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
/* Now call the actual ctor */
- /* Avoid virtual calls to ctors if possible */
- if (mono_class_is_marshalbyref (cmethod->klass))
- callvirt_this_arg = sp [0];
-
-
- if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
- if (!MONO_TYPE_IS_VOID (fsig->ret)) {
- type_to_eval_stack_type ((cfg), fsig->ret, ins);
- *sp = ins;
- sp++;
- }
-
- CHECK_CFG_EXCEPTION;
- } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
- !disable_inline && mono_method_check_inlining (cfg, cmethod) &&
- !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE) &&
- !g_list_find (dont_inline, cmethod)) {
- int costs;
-
- if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, dont_inline, FALSE))) {
- cfg->real_offset += 5;
- bblock = cfg->cbb;
-
- inline_costs += costs - 5;
- } else {
- INLINE_FAILURE ("inline failure");
- // FIXME-VT: Clean this up
- if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))
- GSHAREDVT_FAILURE(*ip);
- mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
- }
- } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
- MonoInst *addr;
-
- addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
- mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
- } else if (context_used &&
- ((!mono_method_is_generic_sharable (cmethod, TRUE) ||
- !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
- MonoInst *cmethod_addr;
-
- /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
-
- cmethod_addr = emit_get_rgctx_method (cfg, context_used,
- cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
-
- mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
- } else {
- INLINE_FAILURE ("ctor call");
- ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
- callvirt_this_arg, NULL, vtable_arg);
- }
+ handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &bblock, &inline_costs);
+ CHECK_CFG_EXCEPTION;
}
if (alloc == NULL) {
EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
*sp++= ins;
- }
- else
+ } else {
*sp++ = alloc;
+ }
ip += 5;
inline_costs += 5;
save_cast_details (cfg, klass, sp [0]->dreg, TRUE, &bblock);
costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass),
- iargs, ip, cfg->real_offset, dont_inline, TRUE);
+ iargs, ip, cfg->real_offset, TRUE, &bblock);
reset_cast_details (cfg);
CHECK_CFG_EXCEPTION;
g_assert (costs > 0);
ip += 5;
cfg->real_offset += 5;
- bblock = cfg->cbb;
*sp++ = iargs [0];
iargs [0] = sp [0];
costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst),
- iargs, ip, cfg->real_offset, dont_inline, TRUE);
+ iargs, ip, cfg->real_offset, TRUE, &bblock);
CHECK_CFG_EXCEPTION;
g_assert (costs > 0);
ip += 5;
cfg->real_offset += 5;
- bblock = cfg->cbb;
*sp++= iargs [0];
iargs [0] = sp [0];
costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass),
- iargs, ip, cfg->real_offset, dont_inline, TRUE);
+ iargs, ip, cfg->real_offset, TRUE, &bblock);
CHECK_CFG_EXCEPTION;
g_assert (costs > 0);
ip += 5;
cfg->real_offset += 5;
- bblock = cfg->cbb;
*sp++ = iargs [0];
inline_costs += costs;
if (!field)
LOAD_ERROR;
if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
- FIELD_ACCESS_FAILURE;
+ FIELD_ACCESS_FAILURE (method, field);
mono_class_init (klass);
if (is_instance && *ip != CEE_LDFLDA && is_magic_tls_access (field))
if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper),
- iargs, ip, cfg->real_offset, dont_inline, TRUE);
+ iargs, ip, cfg->real_offset, TRUE, &bblock);
CHECK_CFG_EXCEPTION;
g_assert (costs > 0);
cfg->real_offset += 5;
- bblock = cfg->cbb;
inline_costs += costs;
} else {
EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
costs = inline_method (cfg, wrapper, mono_method_signature (wrapper),
- iargs, ip, cfg->real_offset, dont_inline, TRUE);
+ iargs, ip, cfg->real_offset, TRUE, &bblock);
CHECK_CFG_EXCEPTION;
- bblock = cfg->cbb;
g_assert (costs > 0);
cfg->real_offset += 5;
* The backends expect the fceq opcodes to do the
* comparison too.
*/
- cmp->opcode = OP_NOP;
ins->sreg1 = cmp->sreg1;
ins->sreg2 = cmp->sreg2;
+ NULLIFY_INS (cmp);
}
MONO_ADD_INS (bblock, ins);
*sp++ = ins;
cil_method = cmethod;
if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
- METHOD_ACCESS_FAILURE;
+ METHOD_ACCESS_FAILURE (method, cil_method);
if (mono_security_cas_enabled ()) {
if (check_linkdemand (cfg, method, cmethod))
* stack overflows which is different behavior than the
* non-inlined case, thus disable inlining in this case.
*/
- goto inline_failure;
+ INLINE_FAILURE("localloc");
MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
ins->dreg = alloc_preg (cfg);
}
}
- g_slist_free (class_inits);
- dont_inline = g_list_remove (dont_inline, method);
-
if (inline_costs < 0) {
char *mname;
mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
g_free (mname);
- cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
- mono_basic_block_free (original_bb);
- return -1;
}
if ((cfg->verbose_level > 2) && (cfg->method == method))
mono_print_code (cfg, "AFTER METHOD-TO-IR");
- cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
- mono_basic_block_free (original_bb);
- return inline_costs;
+ goto cleanup;
exception_exit:
g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
goto cleanup;
- inline_failure:
- goto cleanup;
-
- load_error:
- mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
- goto cleanup;
-
unverified:
set_exception_type_from_invalid_il (cfg, method, ip);
goto cleanup;
cleanup:
g_slist_free (class_inits);
mono_basic_block_free (original_bb);
- dont_inline = g_list_remove (dont_inline, method);
+ cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
- return -1;
+ if (cfg->exception_type)
+ return -1;
+ else
+ return inline_costs;
}
static int
guint alignment_check;
#endif
- cfg->code_size = MAX (cfg->header->code_size * 4, 10240);
+ cfg->code_size = MAX (cfg->header->code_size * 4, 1024);
#if defined(__default_codegen__)
code = cfg->native_code = g_malloc (cfg->code_size);
cfg->native_code = mono_realloc_native_code (cfg);
cfg->stat_code_reallocs++;
}
-
code = cfg->native_code + cfg->code_len;
cfg->has_unwind_info_for_epilog = TRUE;
}
}
-/*MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD*/
gpointer
mono_arch_install_handler_block_guard (MonoJitInfo *ji, MonoJitExceptionInfo *clause, MonoContext *ctx, gpointer new_value)
{
- int offset;
gpointer *sp, old_value;
char *bp;
- const unsigned char *handler;
-
- /*Decode the first instruction to figure out where did we store the spvar*/
- /*Our jit MUST generate the following:
- mov %rsp, ?(%rbp)
-
- Which is encoded as: REX.W 0x89 mod_rm
- mod_rm (rsp, rbp, imm) which can be: (imm will never be zero)
- mod (reg + imm8): 01 reg(rsp): 100 rm(rbp): 101 -> 01100101 (0x65)
- mod (reg + imm32): 10 reg(rsp): 100 rm(rbp): 101 -> 10100101 (0xA5)
-
- FIXME can we generate frameless methods on this case?
-
- */
- handler = clause->handler_start;
-
- /*REX.W*/
- if (*handler != 0x48)
- return NULL;
- ++handler;
-
- /*mov r, r/m */
- if (*handler != 0x89)
- return NULL;
- ++handler;
-
- if (*handler == 0x65)
- offset = *(signed char*)(handler + 1);
- else if (*handler == 0xA5)
- offset = *(int*)(handler + 1);
- else
- return NULL;
/*Load the spvar*/
bp = MONO_CONTEXT_GET_BP (ctx);
- sp = *(gpointer*)(bp + offset);
+ sp = *(gpointer*)(bp + clause->exvar_offset);
old_value = *sp;
if (old_value < ji->code_start || (char*)old_value > ((char*)ji->code_start + ji->code_size))
#endif /* !HOST_WIN32 && !__native_client__ */
-#if defined (__APPLE__)
-
-#define MONO_ARCH_NOMAP32BIT
-
-#elif defined (__NetBSD__)
-
-#define REG_RAX 14
-#define REG_RCX 3
-#define REG_RDX 2
-#define REG_RBX 13
-#define REG_RSP 24
-#define REG_RBP 12
-#define REG_RSI 1
-#define REG_RDI 0
-#define REG_R8 4
-#define REG_R9 5
-#define REG_R10 6
-#define REG_R11 7
-#define REG_R12 8
-#define REG_R13 9
-#define REG_R14 10
-#define REG_R15 11
-#define REG_RIP 21
-
-#define MONO_ARCH_NOMAP32BIT
-
-#elif defined (__OpenBSD__)
-
-#define MONO_ARCH_NOMAP32BIT
-
-#elif defined (__DragonFly__)
-
-#define MONO_ARCH_NOMAP32BIT
-
-#elif defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
-
-#define REG_RAX 7
-#define REG_RCX 4
-#define REG_RDX 3
-#define REG_RBX 8
-#define REG_RSP 23
-#define REG_RBP 9
-#define REG_RSI 2
-#define REG_RDI 1
-#define REG_R8 5
-#define REG_R9 6
-#define REG_R10 10
-#define REG_R11 11
-#define REG_R12 12
-#define REG_R13 13
-#define REG_R14 14
-#define REG_R15 15
-#define REG_RIP 20
-
-/*
- * FreeBSD does not have MAP_32BIT, so code allocated by the code manager might not have a
- * 32 bit address.
- */
-#define MONO_ARCH_NOMAP32BIT
-
-#elif defined(HOST_WIN32)
-
+#if !defined(__linux__)
#define MONO_ARCH_NOMAP32BIT 1
-
-#endif /* __FreeBSD__ */
+#endif
#ifdef HOST_WIN32
#define MONO_AMD64_ARG_REG1 AMD64_RCX
#define MONO_ARCH_EMULATE_FREM 1
#define MONO_ARCH_HAVE_IS_INT_OVERFLOW 1
-#define MONO_ARCH_ENABLE_REGALLOC_IN_EH_BLOCKS 1
#define MONO_ARCH_ENABLE_MONO_LMF_VAR 1
#define MONO_ARCH_HAVE_INVALIDATE_METHOD 1
#define MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE 1
#define MONO_ARCH_ENABLE_GLOBAL_RA 1
#define MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK 1
#define MONO_ARCH_HAVE_LIVERANGE_OPS 1
-#define MONO_ARCH_HAVE_XP_UNWIND 1
#define MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX 1
#define MONO_ARCH_MONITOR_OBJECT_REG MONO_AMD64_ARG_REG1
#define MONO_ARCH_HAVE_GET_TRAMPOLINES 1
#define MONO_ARCH_HAVE_LLVM_IMT_TRAMPOLINE 1
#define MONO_ARCH_LLVM_SUPPORTED 1
-#define MONO_ARCH_THIS_AS_FIRST_ARG 1
#define MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD 1
#define MONO_ARCH_HAVE_CARD_TABLE_WBARRIER 1
#define MONO_ARCH_HAVE_SETUP_RESUME_FROM_SIGNAL_HANDLER_CTX 1
return mono_arm_get_exception_trampolines (aot);
}
+gpointer
+mono_arch_install_handler_block_guard (MonoJitInfo *ji, MonoJitExceptionInfo *clause, MonoContext *ctx, gpointer new_value)
+{
+ gpointer *lr_loc;
+ char *old_value;
+ char *bp;
+
+ /*Load the spvar*/
+ bp = MONO_CONTEXT_GET_BP (ctx);
+ lr_loc = (gpointer*)(bp + clause->exvar_offset);
+
+ old_value = *lr_loc;
+ if ((char*)old_value < (char*)ji->code_start || (char*)old_value > ((char*)ji->code_start + ji->code_size))
+ return old_value;
+
+ *lr_loc = new_value;
+
+ return old_value;
+}
+
#if defined(MONO_ARCH_SOFT_DEBUG_SUPPORTED)
/*
* mono_arch_set_breakpoint:
#define MONO_ARCH_NEED_DIV_CHECK 1
#define MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
-#define MONO_ARCH_HAVE_XP_UNWIND 1
#define MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK 1
#define ARM_NUM_REG_ARGS (ARM_LAST_ARG_REG-ARM_FIRST_ARG_REG+1)
#define MONO_ARCH_AOT_SUPPORTED 1
#define MONO_ARCH_LLVM_SUPPORTED 1
-#define MONO_ARCH_THIS_AS_FIRST_ARG 1
#define MONO_ARCH_GSHARED_SUPPORTED 1
#define MONO_ARCH_DYN_CALL_SUPPORTED 1
#define MONO_ARCH_GC_MAPS_SUPPORTED 1
#define MONO_ARCH_HAVE_SETUP_ASYNC_CALLBACK 1
#define MONO_ARCH_HAVE_CONTEXT_SET_INT_REG 1
+#define MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD 1
#define MONO_ARCH_HAVE_SETUP_RESUME_FROM_SIGNAL_HANDLER_CTX 1
#define MONO_ARCH_GSHAREDVT_SUPPORTED 1
#define MONO_ARCH_HAVE_GENERAL_RGCTX_LAZY_FETCH_TRAMPOLINE 1
* bblock.
*/
for (ins = bb->code; ins; ins = ins->next) {
+ gboolean modify = FALSE;
+
spec = ins_get_spec (ins->opcode);
if ((ins->dreg != -1) && (ins->dreg < max)) {
#if SIZEOF_REGISTER == 4
if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_SRC1 + j])) {
sregs [j]++;
+ modify = TRUE;
memset (®info [sregs [j] + 1], 0, sizeof (RegTrack));
}
#endif
}
}
- mono_inst_set_src_registers (ins, sregs);
+ if (modify)
+ mono_inst_set_src_registers (ins, sregs);
}
/*if (cfg->opt & MONO_OPT_COPYPROP)
if (frame->ji)
method = jinfo_get_method (frame->ji);
- if (method) {
- gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, mono_domain_get ());
+ if (method && frame->domain) {
+ gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
g_string_append_printf (p, " %s\n", location);
g_free (location);
} else
#define MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE 1
#define MONO_ARCH_HAVE_SAVE_UNWIND_INFO 1
#define MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK 1
-#define MONO_ARCH_THIS_AS_FIRST_ARG 1
#endif /* __MONO_MINI_IA64_H__ */
#include <mono/metadata/mempool-internals.h>
#include <mono/utils/mono-tls.h>
#include <mono/utils/mono-dl.h>
+#include <mono/utils/mono-time.h>
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
LLVMValueRef got_var;
const char *got_symbol;
GHashTable *plt_entries;
+ GHashTable *plt_entries_ji;
+ GHashTable *method_to_lmethod;
char **bb_names;
int bb_names_len;
GPtrArray *used;
{
char *callee_name = mono_aot_get_plt_symbol (type, data);
LLVMValueRef callee;
+ MonoJumpInfo *ji = NULL;
if (!callee_name)
return NULL;
g_hash_table_insert (ctx->lmodule->plt_entries, (char*)callee_name, callee);
}
+ if (ctx->cfg->compile_aot) {
+ ji = g_new0 (MonoJumpInfo, 1);
+ ji->type = type;
+ ji->data.target = data;
+
+ g_hash_table_insert (ctx->lmodule->plt_entries_ji, ji, callee);
+ }
+
return callee;
}
/* FIXME: Free the LLVM IL for the function */
}
+ if (ctx->lmodule->method_to_lmethod)
+ g_hash_table_insert (ctx->lmodule->method_to_lmethod, cfg->method, method);
+
goto CLEANUP;
FAILURE:
aot_module.llvm_types = g_hash_table_new (NULL, NULL);
aot_module.plt_entries = g_hash_table_new (g_str_hash, g_str_equal);
+ aot_module.plt_entries_ji = g_hash_table_new (NULL, NULL);
+ aot_module.method_to_lmethod = g_hash_table_new (NULL, NULL);
}
/*
{
LLVMTypeRef got_type;
LLVMValueRef real_got;
+ MonoLLVMModule *module = &aot_module;
/*
* Create the real got variable and replace all uses of the dummy variable with
emit_llvm_used (&aot_module);
+ /* Replace PLT entries for directly callable methods with the methods themselves */
+ {
+ GHashTableIter iter;
+ MonoJumpInfo *ji;
+ LLVMValueRef callee;
+
+ g_hash_table_iter_init (&iter, aot_module.plt_entries_ji);
+ while (g_hash_table_iter_next (&iter, (void**)&ji, (void**)&callee)) {
+ if (mono_aot_is_direct_callable (ji)) {
+ LLVMValueRef lmethod;
+
+ lmethod = g_hash_table_lookup (module->method_to_lmethod, ji->data.method);
+ if (lmethod) {
+ mono_llvm_replace_uses_of (callee, lmethod);
+ mono_aot_mark_unused_llvm_plt_entry (ji);
+ }
+ }
+ }
+ }
+
#if 0
{
char *verifier_err;
#define MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK 1
#define MONO_ARCH_SOFT_DEBUG_SUPPORTED 1
#define MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX 1
-#define MONO_ARCH_HAVE_XP_UNWIND 1
#define MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE 1
#define MONO_ARCH_HAVE_SETUP_RESUME_FROM_SIGNAL_HANDLER_CTX 1
#define MONO_ARCH_GSHARED_SUPPORTED 1
#define MONO_ARCH_NEED_DIV_CHECK 1
#define MONO_ARCH_NO_IOV_CHECK 1
-#define MONO_ARCH_THIS_AS_FIRST_ARG 1
-
#define MIPS_NUM_REG_ARGS (MIPS_LAST_ARG_REG-MIPS_FIRST_ARG_REG+1)
#define MIPS_NUM_REG_FPARGS (MIPS_LAST_FPARG_REG-MIPS_FIRST_FPARG_REG+1)
gboolean
-SIG_HANDLER_SIGNATURE (mono_chain_signal)
+MONO_SIG_HANDLER_SIGNATURE (mono_chain_signal)
{
return FALSE;
}
* was called, false otherwise.
*/
gboolean
-SIG_HANDLER_SIGNATURE (mono_chain_signal)
+MONO_SIG_HANDLER_SIGNATURE (mono_chain_signal)
{
- int signal = _dummy;
+ int signal = MONO_SIG_HANDLER_GET_SIGNO ();
struct sigaction *saved_handler = get_saved_signal_handler (signal);
- GET_CONTEXT;
-
if (saved_handler && saved_handler->sa_handler) {
if (!(saved_handler->sa_flags & SA_SIGINFO)) {
saved_handler->sa_handler (signal);
} else {
#ifdef MONO_ARCH_USE_SIGACTION
- saved_handler->sa_sigaction (signal, info, ctx);
+ saved_handler->sa_sigaction (MONO_SIG_HANDLER_PARAMS);
#endif /* MONO_ARCH_USE_SIGACTION */
}
return TRUE;
return FALSE;
}
-SIG_HANDLER_FUNC (static, sigabrt_signal_handler)
+MONO_SIG_HANDLER_FUNC (static, sigabrt_signal_handler)
{
MonoJitInfo *ji = NULL;
- GET_CONTEXT;
+ 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 (mono_domain_get (), mono_arch_ip_from_context (ctx));
if (!ji) {
- if (mono_chain_signal (SIG_HANDLER_PARAMS))
+ if (mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
return;
mono_handle_native_sigsegv (SIGABRT, ctx);
}
}
-SIG_HANDLER_FUNC (static, sigusr1_signal_handler)
+MONO_SIG_HANDLER_FUNC (static, sigusr1_signal_handler)
{
gboolean running_managed;
MonoException *exc;
MonoInternalThread *thread = mono_thread_internal_current ();
MonoDomain *domain = mono_domain_get ();
void *ji;
-
- GET_CONTEXT;
+ MONO_SIG_HANDLER_GET_CONTEXT;
if (!thread || !domain) {
/* The thread might not have started up yet */
#ifdef SIGPROF
#if defined(__ia64__) || defined(__sparc__) || defined(sparc) || defined(__s390__) || defined(s390)
-SIG_HANDLER_FUNC (static, sigprof_signal_handler)
+MONO_SIG_HANDLER_FUNC (static, sigprof_signal_handler)
{
- if (mono_chain_signal (SIG_HANDLER_PARAMS))
+ if (mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
return;
NOT_IMPLEMENTED;
#else
-SIG_HANDLER_FUNC (static, sigprof_signal_handler)
+MONO_SIG_HANDLER_FUNC (static, sigprof_signal_handler)
{
int call_chain_depth = mono_profiler_stat_get_call_chain_depth ();
MonoProfilerCallChainStrategy call_chain_strategy = mono_profiler_stat_get_call_chain_strategy ();
- GET_CONTEXT;
+ MONO_SIG_HANDLER_GET_CONTEXT;
if (call_chain_depth == 0) {
mono_profiler_stat_hit (mono_arch_ip_from_context (ctx), ctx);
mono_profiler_stat_call_chain (current_frame_index, & ips [0], ctx);
}
- mono_chain_signal (SIG_HANDLER_PARAMS);
+ mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
}
#endif
#endif
-SIG_HANDLER_FUNC (static, sigquit_signal_handler)
+MONO_SIG_HANDLER_FUNC (static, sigquit_signal_handler)
{
gboolean res;
-
- GET_CONTEXT;
+ MONO_SIG_HANDLER_GET_CONTEXT;
/* We use this signal to start the attach agent too */
res = mono_attach_start ();
mono_print_thread_dump (ctx);
}
- mono_chain_signal (SIG_HANDLER_PARAMS);
+ mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
}
-SIG_HANDLER_FUNC (static, sigusr2_signal_handler)
+MONO_SIG_HANDLER_FUNC (static, sigusr2_signal_handler)
{
gboolean enabled = mono_trace_is_enabled ();
mono_trace_enable (!enabled);
- mono_chain_signal (SIG_HANDLER_PARAMS);
+ mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
}
static void
#define MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK 1
#define MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES 1
-#define MONO_ARCH_HAVE_XP_UNWIND 1
#define MONO_ARCH_GSHARED_SUPPORTED 1
#if !defined(MONO_CROSS_COMPILE) && !defined(TARGET_PS3)
#define MONO_ARCH_SOFT_DEBUG_SUPPORTED 1
#endif
-#define MONO_ARCH_THIS_AS_FIRST_ARG 1
#define MONO_ARCH_HAVE_OP_TAIL_CALL 1
#define PPC_NUM_REG_ARGS (PPC_LAST_ARG_REG-PPC_FIRST_ARG_REG+1)
#define MONO_ARCH_IMT_REG s390_r9
#define MONO_ARCH_VTABLE_REG MONO_ARCH_IMT_REG
#define MONO_ARCH_RGCTX_REG MONO_ARCH_IMT_REG
-#define MONO_ARCH_THIS_AS_FIRST_ARG 1
-#define MONO_ARCH_HAVE_XP_UNWIND 1
#define MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX 1
#define MONO_ARCH_SOFT_DEBUG_SUPPORTED 1
#define MONO_ARCH_HAVE_CONTEXT_SET_INT_REG 1
#define MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
#endif
-#define MONO_ARCH_THIS_AS_FIRST_ARG 1
-
#ifndef __GNUC__
/* assume Sun compiler if not GCC */
static void * __builtin_return_address(int depth)
* We use one vtable trampoline per vtable slot index, so we need only the vtable,
* the other two can be computed from the vtable + the slot index.
*/
-#ifndef MONO_ARCH_THIS_AS_FIRST_ARG
- /* All architectures should support this */
- g_assert_not_reached ();
-#endif
/*
* Obtain the vtable from the 'this' arg.
* was called, false otherwise.
*/
gboolean
-SIG_HANDLER_SIGNATURE (mono_chain_signal)
+MONO_SIG_HANDLER_SIGNATURE (mono_chain_signal)
{
MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
jit_tls->mono_win_chained_exception_needs_run = TRUE;
* result there.
*/
call->vret_in_reg = TRUE;
+#if defined(__APPLE__)
+ if (cinfo->ret.pair_storage [0] == ArgOnDoubleFpStack || cinfo->ret.pair_storage [0] == ArgOnFloatFpStack)
+ call->vret_in_reg_fp = TRUE;
+#endif
if (call->vret_var)
NULLIFY_INS (call->vret_var);
}
#define MONO_ARCH_RGCTX_REG MONO_ARCH_IMT_REG
#define MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK 1
#define MONO_ARCH_HAVE_LIVERANGE_OPS 1
-#define MONO_ARCH_HAVE_XP_UNWIND 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_GSHARED_SUPPORTED 1
#define MONO_ARCH_HAVE_LLVM_IMT_TRAMPOLINE 1
#define MONO_ARCH_LLVM_SUPPORTED 1
-#define MONO_ARCH_THIS_AS_FIRST_ARG 1
#if defined(MONO_ARCH_USE_SIGACTION) || defined(TARGET_WIN32)
#define MONO_ARCH_SOFT_DEBUG_SUPPORTED 1
{
static int count = 0;
count ++;
+ static gboolean inited;
+ static const char *value;
- if (!g_getenv ("COUNT"))
+ if (!inited) {
+ value = g_getenv ("COUNT");
+ inited = TRUE;
+ }
+
+ if (!value)
return TRUE;
- if (count == atoi (g_getenv ("COUNT"))) {
+ if (count == atoi (value))
break_count ();
- }
- if (count > atoi (g_getenv ("COUNT"))) {
+ if (count > atoi (value))
return FALSE;
- }
return TRUE;
}
if ((num + 1) >= cfg->varinfo_count) {
int orig_count = cfg->varinfo_count;
- cfg->varinfo_count = cfg->varinfo_count ? (cfg->varinfo_count * 2) : 64;
+ cfg->varinfo_count = cfg->varinfo_count ? (cfg->varinfo_count * 2) : 32;
cfg->varinfo = (MonoInst **)g_realloc (cfg->varinfo, sizeof (MonoInst*) * cfg->varinfo_count);
cfg->vars = (MonoMethodVar *)g_realloc (cfg->vars, sizeof (MonoMethodVar) * cfg->varinfo_count);
memset (&cfg->vars [orig_count], 0, (cfg->varinfo_count - orig_count) * sizeof (MonoMethodVar));
GSList *tmp;
MonoMethodHeader *header;
MonoJitInfo *jinfo;
- int num_clauses;
- int generic_info_size, arch_eh_info_size = 0;
- int holes_size = 0, num_holes = 0, cas_size = 0;
+ MonoJitInfoFlags flags = JIT_INFO_NONE;
+ int num_clauses, num_holes = 0;
guint32 stack_size = 0;
g_assert (method_to_compile == cfg->method);
header = cfg->header;
if (cfg->generic_sharing_context)
- generic_info_size = sizeof (MonoGenericJitInfo);
- else
- generic_info_size = 0;
+ flags |= JIT_INFO_HAS_GENERIC_JIT_INFO;
if (cfg->arch_eh_jit_info) {
MonoJitArgumentInfo *arg_info;
stack_size = mono_arch_get_argument_info (cfg->generic_sharing_context, sig, sig->param_count, arg_info);
if (stack_size)
- arch_eh_info_size = sizeof (MonoArchEHJitInfo);
+ flags |= JIT_INFO_HAS_ARCH_EH_INFO;
}
- if (cfg->has_unwind_info_for_epilog && !arch_eh_info_size)
- arch_eh_info_size = sizeof (MonoArchEHJitInfo);
+ if (cfg->has_unwind_info_for_epilog && !(flags & JIT_INFO_HAS_ARCH_EH_INFO))
+ flags |= JIT_INFO_HAS_ARCH_EH_INFO;
if (cfg->try_block_holes) {
for (tmp = cfg->try_block_holes; tmp; tmp = tmp->next) {
++num_holes;
}
if (num_holes)
- holes_size = sizeof (MonoTryBlockHoleTableJitInfo) + num_holes * sizeof (MonoTryBlockHoleJitInfo);
+ flags |= JIT_INFO_HAS_TRY_BLOCK_HOLES;
if (G_UNLIKELY (cfg->verbose_level >= 4))
printf ("Number of try block holes %d\n", num_holes);
}
- if (mono_security_method_has_declsec (cfg->method_to_register)) {
- cas_size = sizeof (MonoMethodCasInfo);
- }
+ if (mono_security_method_has_declsec (cfg->method_to_register))
+ flags |= JIT_INFO_HAS_ARCH_EH_INFO;
if (COMPILE_LLVM (cfg))
num_clauses = cfg->llvm_ex_info_len;
else
num_clauses = header->num_clauses;
- if (cfg->method->dynamic) {
- jinfo = g_malloc0 (MONO_SIZEOF_JIT_INFO + (num_clauses * sizeof (MonoJitExceptionInfo)) +
- generic_info_size + holes_size + arch_eh_info_size + cas_size);
- } else {
- jinfo = mono_domain_alloc0 (cfg->domain, MONO_SIZEOF_JIT_INFO +
- (num_clauses * sizeof (MonoJitExceptionInfo)) +
- generic_info_size + holes_size + arch_eh_info_size + cas_size);
- }
-
- jinfo->d.method = cfg->method_to_register;
- jinfo->code_start = cfg->native_code;
- jinfo->code_size = cfg->code_len;
+ if (cfg->method->dynamic)
+ jinfo = g_malloc0 (mono_jit_info_size (flags, num_clauses, num_holes));
+ else
+ jinfo = mono_domain_alloc0 (cfg->domain, mono_jit_info_size (flags, num_clauses, num_holes));
+ mono_jit_info_init (jinfo, cfg->method_to_register, cfg->native_code, cfg->code_len, flags, num_clauses, num_holes);
jinfo->domain_neutral = (cfg->opt & MONO_OPT_SHARED) != 0;
- jinfo->num_clauses = num_clauses;
if (COMPILE_LLVM (cfg))
jinfo->from_llvm = TRUE;
MonoGenericJitInfo *gi;
GSList *loclist = NULL;
- jinfo->has_generic_jit_info = 1;
-
gi = mono_jit_info_get_generic_jit_info (jinfo);
g_assert (gi);
MonoTryBlockHoleTableJitInfo *table;
int i;
- jinfo->has_try_block_holes = 1;
table = mono_jit_info_get_try_block_hole_table_info (jinfo);
table->num_holes = (guint16)num_holes;
i = 0;
g_assert (i == num_holes);
}
- if (arch_eh_info_size) {
+ if (jinfo->has_arch_eh_info) {
MonoArchEHJitInfo *info;
- jinfo->has_arch_eh_info = 1;
info = mono_jit_info_get_arch_eh_info (jinfo);
info->stack_size = stack_size;
}
- if (cas_size) {
- jinfo->has_cas_info = 1;
- }
-
if (COMPILE_LLVM (cfg)) {
if (num_clauses)
memcpy (&jinfo->clauses [0], &cfg->llvm_ex_info [0], num_clauses * sizeof (MonoJitExceptionInfo));
#ifdef ENABLE_LLVM
gboolean llvm = (flags & JIT_FLAG_LLVM) ? 1 : 0;
#endif
+ static gboolean verbose_method_inited;
+ static const char *verbose_method_name;
InterlockedIncrement (&mono_jit_stats.methods_compiled);
if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)
if (cfg->generic_sharing_context) {
method_to_register = method_to_compile;
+ cfg->gshared = TRUE;
} else {
g_assert (method == method_to_compile);
method_to_register = method;
{
static gboolean inited;
- if (!inited) {
+ if (!inited)
inited = TRUE;
- }
/*
* Check for methods which cannot be compiled by LLVM early, to avoid
cfg->opt |= MONO_OPT_ABCREM;
}
- if (g_getenv ("MONO_VERBOSE_METHOD")) {
- const char *name = g_getenv ("MONO_VERBOSE_METHOD");
+ if (!verbose_method_inited) {
+ verbose_method_name = g_getenv ("MONO_VERBOSE_METHOD");
+ verbose_method_inited = TRUE;
+ }
+ if (verbose_method_name) {
+ const char *name = verbose_method_name;
if ((strchr (name, '.') > name) || strchr (name, ':')) {
MonoMethodDesc *desc;
}
mono_method_desc_free (desc);
} else {
- if (strcmp (cfg->method->name, g_getenv ("MONO_VERBOSE_METHOD")) == 0)
+ if (strcmp (cfg->method->name, name) == 0)
cfg->verbose_level = 4;
}
}
/* SSAPRE is not supported on linear IR */
cfg->opt &= ~MONO_OPT_SSAPRE;
- i = mono_method_to_ir (cfg, method_to_compile, NULL, NULL, NULL, NULL, NULL, 0, FALSE);
+ i = mono_method_to_ir (cfg, method_to_compile, NULL, NULL, NULL, NULL, 0, FALSE);
if (i < 0) {
if (try_generic_shared && cfg->exception_type == MONO_EXCEPTION_GENERIC_SHARING_FAILED) {
return runtime_invoke (obj, params, exc, info->compiled_method);
}
-SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler)
+MONO_SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler)
{
MonoException *exc = NULL;
MonoJitInfo *ji;
-#if !(defined(MONO_ARCH_USE_SIGACTION) || defined(HOST_WIN32))
- void *info = NULL;
-#endif
- GET_CONTEXT;
+ void *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));
#endif
if (!ji) {
- if (!mono_do_crash_chaining && mono_chain_signal (SIG_HANDLER_PARAMS))
+ if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
return;
mono_handle_native_sigsegv (SIGSEGV, ctx);
if (mono_do_crash_chaining) {
- mono_chain_signal (SIG_HANDLER_PARAMS);
+ mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
return;
}
}
mono_arch_handle_exception (ctx, exc);
}
-SIG_HANDLER_FUNC (, mono_sigill_signal_handler)
+MONO_SIG_HANDLER_FUNC (, mono_sigill_signal_handler)
{
MonoException *exc;
- GET_CONTEXT;
+ MONO_SIG_HANDLER_GET_CONTEXT;
exc = mono_get_exception_execution_engine ("SIGILL");
#define HAVE_SIG_INFO
#endif
-SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
+MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
{
MonoJitInfo *ji;
MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
gpointer fault_addr = NULL;
-
- GET_CONTEXT;
+#ifdef HAVE_SIG_INFO
+ MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
+#endif
+ MONO_SIG_HANDLER_GET_CONTEXT;
#if defined(MONO_ARCH_SOFT_DEBUG_SUPPORTED) && defined(HAVE_SIG_INFO)
if (mono_arch_is_single_step_event (info, ctx)) {
/* The thread might no be registered with the runtime */
if (!mono_domain_get () || !jit_tls) {
- if (!mono_do_crash_chaining && mono_chain_signal (SIG_HANDLER_PARAMS))
+ if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
return;
mono_handle_native_sigsegv (SIGSEGV, ctx);
if (mono_do_crash_chaining) {
- mono_chain_signal (SIG_HANDLER_PARAMS);
+ mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
return;
}
}
g_assert_not_reached ();
} else {
/* The original handler might not like that it is executed on an altstack... */
- if (!ji && mono_chain_signal (SIG_HANDLER_PARAMS))
+ if (!ji && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
return;
mono_arch_handle_altstack_exception (ctx, info->si_addr, FALSE);
#else
if (!ji) {
- if (!mono_do_crash_chaining && mono_chain_signal (SIG_HANDLER_PARAMS))
+ if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
return;
mono_handle_native_sigsegv (SIGSEGV, ctx);
if (mono_do_crash_chaining) {
- mono_chain_signal (SIG_HANDLER_PARAMS);
+ mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
return;
}
}
#endif
}
-SIG_HANDLER_FUNC (, mono_sigint_signal_handler)
+MONO_SIG_HANDLER_FUNC (, mono_sigint_signal_handler)
{
MonoException *exc;
- GET_CONTEXT;
+ MONO_SIG_HANDLER_GET_CONTEXT;
exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
method = mono_get_method (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL);
if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
continue;
+ if (method->is_generic || method->klass->generic_container)
+ continue;
count++;
if (mini_verbose > 1) {
#include <mono/utils/mono-tls.h>
#include <mono/utils/atomic.h>
#include <mono/utils/mono-conc-hashtable.h>
+#include <mono/utils/mono-signal-handler.h>
#define MONO_BREAKPOINT_ARRAY_SIZE 64
#error "The code in mini/ should not depend on these defines."
#endif
-#ifndef G_LIKELY
-#define G_LIKELY(a) (a)
-#define G_UNLIKELY(a) (a)
-#endif
-
-#ifndef G_MAXINT32
-#define G_MAXINT32 2147483647
-#endif
-
-#ifndef G_MININT32
-#define G_MININT32 (-G_MAXINT32 - 1)
-#endif
-
#ifndef __GNUC__
/*#define __alignof__(a) sizeof(a)*/
#define __alignof__(type) G_STRUCT_OFFSET(struct { char c; type x; }, x)
* calling convention as OP_CALL.
*/
guint vret_in_reg : 1;
+ /* Whenever vret_in_reg returns fp values */
+ guint vret_in_reg_fp : 1;
/* Whenever there is an IMT argument and it is dynamic */
guint dynamic_imt_arg : 1;
/* Whenever there is an RGCTX argument */
#define inst_phi_args data.op[1].phi_args
#define inst_eh_block data.op[1].exception_clause
+static inline void
+mono_inst_set_src_registers (MonoInst *ins, int *regs)
+{
+ ins->sreg1 = regs [0];
+ ins->sreg2 = regs [1];
+ ins->sreg3 = regs [2];
+}
+
/* instruction description for use in regalloc/scheduling */
enum {
MONO_INST_DEST,
MonoGenericSharingContext gsctx;
MonoGenericContext *gsctx_context;
- gboolean gsharedvt;
-
MonoGSharedVtMethodInfo *gsharedvt_info;
/* Points to the gsharedvt locals area at runtime */
guint has_atomic_cas_i4 : 1;
guint check_pinvoke_callconv : 1;
guint has_unwind_info_for_epilog : 1;
+ guint disable_inline : 1;
+ guint gshared : 1;
+ guint gsharedvt : 1;
gpointer debug_info;
guint32 lmf_offset;
guint16 *intvars;
guint32 encoded_unwind_ops_len;
GSList* unwind_ops;
+ GList* dont_inline;
+
/* Fields used by the local reg allocator */
void* reginfo;
int reginfo_len;
MONO_API char *mono_pmip (void *ip);
gboolean mono_debug_count (void) MONO_INTERNAL;
MONO_API const char* mono_inst_name (int op);
-void mono_inst_set_src_registers (MonoInst *ins, int *regs) MONO_INTERNAL;
int mono_op_to_op_imm (int opcode) MONO_INTERNAL;
int mono_op_imm_to_op (int opcode) MONO_INTERNAL;
int mono_load_membase_to_load_mem (int opcode) MONO_INTERNAL;
MonoMethod* mono_aot_get_array_helper_from_wrapper (MonoMethod *method) MONO_INTERNAL;
guint32 mono_aot_get_got_offset (MonoJumpInfo *ji) MONO_LLVM_INTERNAL;
char* mono_aot_get_method_name (MonoCompile *cfg) MONO_LLVM_INTERNAL;
+gboolean mono_aot_is_direct_callable (MonoJumpInfo *patch_info) MONO_LLVM_INTERNAL;
+void mono_aot_mark_unused_llvm_plt_entry(MonoJumpInfo *patch_info) MONO_LLVM_INTERNAL;
char* mono_aot_get_plt_symbol (MonoJumpInfoType type, gconstpointer data) MONO_LLVM_INTERNAL;
int mono_aot_get_method_index (MonoMethod *method) MONO_LLVM_INTERNAL;
MonoJumpInfo* mono_aot_patch_info_dup (MonoJumpInfo* ji) MONO_LLVM_INTERNAL;
int mini_exception_id_by_name (const char *name) MONO_INTERNAL;
int mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock,
- MonoInst *return_var, GList *dont_inline, MonoInst **inline_args,
+ MonoInst *return_var, MonoInst **inline_args,
guint inline_offset, gboolean is_virtual_call) MONO_INTERNAL;
MonoInst *mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins) MONO_INTERNAL;
/*
* Signal handling
*/
-#ifdef MONO_GET_CONTEXT
-#define GET_CONTEXT MONO_GET_CONTEXT
-#endif
-
-#ifndef GET_CONTEXT
-#ifdef HOST_WIN32
-/* seh_vectored_exception_handler () passes in a CONTEXT* */
-#define GET_CONTEXT \
- void *ctx = context;
-#else
-#ifdef MONO_ARCH_USE_SIGACTION
-#define GET_CONTEXT \
- void *ctx = context;
-#elif defined(__HAIKU__)
-#define GET_CONTEXT \
- void *ctx = ®s;
-#else
-#define GET_CONTEXT \
- void **_p = (void **)&_dummy; \
- struct sigcontext *ctx = (struct sigcontext *)++_p;
-#endif
-#endif
-#endif
-
-#if defined(MONO_ARCH_USE_SIGACTION) && !defined(HOST_WIN32)
-#define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy, siginfo_t *info, void *context)
-#define SIG_HANDLER_FUNC(access, ftn) MONO_SIGNAL_HANDLER_FUNC (access, ftn, (int _dummy, siginfo_t *info, void *context))
-#define SIG_HANDLER_PARAMS _dummy, info, context
-#elif defined(HOST_WIN32)
-#define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy, EXCEPTION_POINTERS *info, void *context)
-#define SIG_HANDLER_FUNC(access, ftn) MONO_SIGNAL_HANDLER_FUNC (access, ftn, (int _dummy, EXCEPTION_POINTERS *info, void *context))
-#define SIG_HANDLER_PARAMS _dummy, info, context
-#elif defined(__HAIKU__)
-#define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy, void *userData, vregs regs)
-#define SIG_HANDLER_FUNC(access, ftn) MONO_SIGNAL_HANDLER_FUNC (access, ftn, (int _dummy, void *userData, vregs regs))
-#define SIG_HANDLER_PARAMS _dummy, userData, regs
-#else
-#define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy)
-#define SIG_HANDLER_FUNC(access, ftn) MONO_SIGNAL_HANDLER_FUNC (access, ftn, (int _dummy))
-#define SIG_HANDLER_PARAMS _dummy
-#endif
-void SIG_HANDLER_SIGNATURE (mono_sigfpe_signal_handler) MONO_INTERNAL;
-void SIG_HANDLER_SIGNATURE (mono_sigill_signal_handler) MONO_INTERNAL;
-void SIG_HANDLER_SIGNATURE (mono_sigsegv_signal_handler) MONO_INTERNAL;
-void SIG_HANDLER_SIGNATURE (mono_sigint_signal_handler) MONO_INTERNAL;
-gboolean SIG_HANDLER_SIGNATURE (mono_chain_signal) MONO_INTERNAL;
+void MONO_SIG_HANDLER_SIGNATURE (mono_sigfpe_signal_handler) MONO_INTERNAL;
+void MONO_SIG_HANDLER_SIGNATURE (mono_sigill_signal_handler) MONO_INTERNAL;
+void MONO_SIG_HANDLER_SIGNATURE (mono_sigsegv_signal_handler) MONO_INTERNAL;
+void MONO_SIG_HANDLER_SIGNATURE (mono_sigint_signal_handler) MONO_INTERNAL;
+gboolean MONO_SIG_HANDLER_SIGNATURE (mono_chain_signal) MONO_INTERNAL;
#ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
#define ARCH_HAVE_DELEGATE_TRAMPOLINES 1
//#define DEBUG_SSA 1
#define NEW_PHI(cfg,dest,val) do { \
- (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
- (dest)->opcode = OP_PHI; \
- (dest)->inst_c0 = (val); \
- (dest)->dreg = (dest)->sreg1 = (dest)->sreg2 = -1; \
+ MONO_INST_NEW ((cfg), (dest), OP_PHI); \
+ (dest)->inst_c0 = (val); \
} while (0)
typedef struct {
}
}
- ins->opcode = OP_NOP;
- ins->dreg = -1;
+ NULLIFY_INS (ins);
}
}
}
MonoInst *src_var = get_vreg_to_inst (cfg, def->sreg1);
if (src_var && !(src_var->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT)))
add_to_dce_worklist (cfg, info, MONO_VARINFO (cfg, src_var->inst_c0), &work_list);
- def->opcode = OP_NOP;
- def->dreg = def->sreg1 = def->sreg2 = -1;
+ NULLIFY_INS (def);
info->reg = -1;
} else if ((def->opcode == OP_ICONST) || (def->opcode == OP_I8CONST) || MONO_IS_ZERO (def)) {
- def->opcode = OP_NOP;
- def->dreg = def->sreg1 = def->sreg2 = -1;
+ NULLIFY_INS (def);
info->reg = -1;
} else if (MONO_IS_PHI (def)) {
int j;
MonoMethodVar *u = MONO_VARINFO (cfg, get_vreg_to_inst (cfg, def->inst_phi_args [j])->inst_c0);
add_to_dce_worklist (cfg, info, u, &work_list);
}
- def->opcode = OP_NOP;
- def->dreg = def->sreg1 = def->sreg2 = -1;
+ NULLIFY_INS (def);
info->reg = -1;
}
else if (def->opcode == OP_NOP) {
tramp = mono_get_trampoline_code (tramp_type);
- mono_domain_lock (domain);
+ if (domain) {
+ mono_domain_lock (domain);
#ifdef USE_JUMP_TABLES
- code = buf = mono_domain_code_reserve_align (domain, size, 4);
+ code = buf = mono_domain_code_reserve_align (domain, size, 4);
#else
- code = buf = mono_domain_code_reserve_align (domain, size, 4);
- if ((short_branch = branch_for_target_reachable (code + 4, tramp))) {
- size = 12;
- mono_domain_code_commit (domain, code, SPEC_TRAMP_SIZE, size);
+ code = buf = mono_domain_code_reserve_align (domain, size, 4);
+ if ((short_branch = branch_for_target_reachable (code + 4, tramp))) {
+ size = 12;
+ mono_domain_code_commit (domain, code, SPEC_TRAMP_SIZE, size);
}
#endif
- mono_domain_unlock (domain);
+ mono_domain_unlock (domain);
+ } else {
+ code = buf = mono_global_codeman_reserve (size);
+ }
#ifdef USE_JUMP_TABLES
/* For jumptables case we always generate the same code for trampolines,
return buf;
}
+static gpointer
+handler_block_trampoline_helper (gpointer *ptr)
+{
+ MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
+ return jit_tls->handler_block_return_address;
+}
+
+gpointer
+mono_arch_create_handler_block_trampoline (MonoTrampInfo **info, gboolean aot)
+{
+ guint8 *tramp;
+ guint8 *code, *buf;
+ int tramp_size = 64;
+ MonoJumpInfo *ji = NULL;
+ GSList *unwind_ops = NULL;
+
+ g_assert (!aot);
+
+ code = buf = mono_global_codeman_reserve (tramp_size);
+
+ tramp = mono_arch_create_specific_trampoline (NULL, MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD, NULL, NULL);
+
+ /*
+ This trampoline restore the call chain of the handler block then jumps into the code that deals with it.
+ */
+
+ /*
+ * We are in a method frame after the call emitted by OP_CALL_HANDLER.
+ */
+ /* Obtain jit_tls->handler_block_return_address */
+ ARM_LDR_IMM (code, ARMREG_R0, ARMREG_PC, 0);
+ ARM_B (code, 0);
+ *(gpointer*)code = handler_block_trampoline_helper;
+ code += 4;
+
+ /* Set it as the return address so the trampoline will return to it */
+ ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_R0);
+
+ /* Call the trampoline */
+ ARM_LDR_IMM (code, ARMREG_R0, ARMREG_PC, 0);
+ code = emit_bx (code, ARMREG_R0);
+ *(gpointer*)code = tramp;
+ code += 4;
+
+ mono_arch_flush_icache (buf, code - buf);
+ g_assert (code - buf <= tramp_size);
+
+ if (info)
+ *info = mono_tramp_info_create ("handler_block_trampoline", buf, code - buf, ji, unwind_ops);
+
+ return buf;
+}
+
#else
guchar*
g_assert_not_reached ();
return NULL;
}
+
+gpointer
+mono_arch_create_handler_block_trampoline (MonoTrampInfo **info, gboolean aot)
+{
+ g_assert_not_reached ();
+ return NULL;
+}
#endif /* DISABLE_JIT */
GSList *l;
MonoUnwindOp *op;
int loc;
- guint8 *buf, *p, *res;
+ guint8 buf [4096];
+ guint8 *p, *res;
- p = buf = g_malloc0 (4096);
+ p = buf;
loc = 0;
l = unwind_ops;
*out_len = p - buf;
res = g_malloc (p - buf);
memcpy (res, buf, p - buf);
- g_free (buf);
return res;
}
int state_stack_pos;
memset (reg_saved, 0, sizeof (reg_saved));
+ state_stack [0].cfa_reg = -1;
+ state_stack [0].cfa_offset = 0;
p = unwind_info;
pos = 0;
#include "mini.h"
-#if defined(HOST_WIN32) || !defined(HAVE_SYS_IPC_H) || !defined(HAVE_SYS_SEM_H) || (defined(__native_client__) && defined(__GLIBC__))
+#if defined(HOST_WIN32) || !defined(HAVE_SYS_IPC_H) || !defined(HAVE_SYS_SEM_H) || (defined(__native_client__) && defined(__GLIBC__)) || defined(DISABLE_SHARED_HANDLES)
int mini_wapi_hps (int argc, char **argv)
{
static const gchar *namedmutex_details (struct _WapiHandleShared *handle);
static const gchar *namedsem_details (struct _WapiHandleShared *handle);
static const gchar *namedevent_details (struct _WapiHandleShared *handle);
-static const gchar *process_details (struct _WapiHandleShared *handle);
/* This depends on the ordering of the enum WapiHandleType in
* io-layer/wapi-private.h
unshared_details, /* event */
unshared_details, /* socket */
unshared_details, /* find */
- process_details,
+ unshared_details, /* process */
unshared_details, /* pipe */
namedmutex_details,
namedsem_details,
return(buf);
}
-static const gchar *process_details (struct _WapiHandleShared *handle)
-{
- static gchar buf[80];
- gchar *name;
- struct _WapiHandle_process *proc=&handle->u.process;
-
- name = proc->proc_name;
-
- g_snprintf (buf, sizeof(buf), "[%25.25s] pid: %5u exit: %u",
- name==NULL?(gchar *)"":name, proc->id, proc->exitstatus);
-
- return(buf);
-}
-
/* The old handles/semdel.c */
int mini_wapi_semdel (int argc, char **argv)
{
export HOST_CC
endif
-if JIT_SUPPORTED
if DISABLE_EXECUTABLES
runtime_lib=../mini/$(LIBMONO_LA) $(static_libs)
else
runtime_lib=../mini/$(LIBMONO_LA)
endif
endif
-else
-runtime_lib=../interpreter/libmint.la
-endif
if DISABLE_EXECUTABLES
bin_PROGRAMS =
if !DISABLE_LIBRARIES
if !DISABLE_PROFILER
-if JIT_SUPPORTED
bin_PROGRAMS = mprof-report
lib_LTLIBRARIES = libmono-profiler-cov.la libmono-profiler-aot.la libmono-profiler-iomap.la libmono-profiler-log.la
if PLATFORM_DARWIN
endif
endif
endif
-endif
if HAVE_OPROFILE
# Do something that uses OPROFILE_CFLAGS and OPROFILE_LIBS
return res;
}
+typedef struct {
+ double d;
+} SingleDoubleStruct;
+
+LIBTEST_API SingleDoubleStruct STDCALL
+mono_test_marshal_return_single_double_struct (void)
+{
+ SingleDoubleStruct res;
+
+ res.d = 3.0;
+
+ return res;
+}
+
#ifndef TARGET_X86
public SimpleDelegate del3;
}
+ [StructLayout (LayoutKind.Sequential)]
+ public struct SingleDoubleStruct {
+ public double d;
+ }
+
/* sparcv9 has complex conventions when passing structs with doubles in them
by value, some simple tests for them */
[StructLayout (LayoutKind.Sequential)]
return 0;
}
+
+ [DllImport ("libtest", EntryPoint = "mono_test_marshal_return_single_double_struct")]
+ public static extern SingleDoubleStruct mono_test_marshal_return_single_double_struct ();
+
+ public static int test_0_x86_single_double_struct_ret () {
+ double d = mono_test_marshal_return_single_double_struct ().d;
+ if (d != 3.0)
+ return 1;
+ else
+ return 0;
+ }
}
lock (monitor) {
foreach (Process p in processes) {
Console.WriteLine (process_data [p].test);
+ p.Kill ();
}
}
return 1;
mono-math.c \
mono-mmap.c \
mono-mmap.h \
+ mono-mmap-internal.h \
mono-mutex.c \
mono-mutex.h \
mono-networkinterfaces.c \
MonoLockFreeAllocator *heap;
volatile Anchor anchor;
unsigned int slot_size;
+ unsigned int block_size;
unsigned int max_count;
gpointer sb;
#ifndef DESC_AVAIL_DUMMY
#define NUM_DESC_BATCH 64
-#define SB_SIZE 16384
-#define SB_HEADER_SIZE 16
-#define SB_USABLE_SIZE (SB_SIZE - SB_HEADER_SIZE)
-
-#define SB_HEADER_FOR_ADDR(a) ((gpointer)((size_t)(a) & ~(size_t)(SB_SIZE-1)))
-#define DESCRIPTOR_FOR_ADDR(a) (*(Descriptor**)SB_HEADER_FOR_ADDR (a))
+static MONO_ALWAYS_INLINE gpointer
+sb_header_for_addr (gpointer addr, size_t block_size)
+{
+ return (gpointer)(((size_t)addr) & (~(block_size - 1)));
+}
/* Taken from SGen */
return prot_flags | MONO_MMAP_PRIVATE | MONO_MMAP_ANON;
}
-static void*
-mono_sgen_alloc_os_memory (size_t size, int activate)
+static gpointer
+alloc_sb (Descriptor *desc)
{
- return mono_valloc (0, size, prot_flags_for_activate (activate));
-}
+ static int pagesize = -1;
-static void
-mono_sgen_free_os_memory (void *addr, size_t size)
-{
- mono_vfree (addr, size);
-}
+ gpointer sb_header;
-/* size must be a power of 2 */
-static void*
-mono_sgen_alloc_os_memory_aligned (size_t size, size_t alignment, gboolean activate)
-{
- return mono_valloc_aligned (size, alignment, prot_flags_for_activate (activate));
-}
+ if (pagesize == -1)
+ pagesize = mono_pagesize ();
-static gpointer
-alloc_sb (Descriptor *desc)
-{
- gpointer sb_header = mono_sgen_alloc_os_memory_aligned (SB_SIZE, SB_SIZE, TRUE);
- g_assert (sb_header == SB_HEADER_FOR_ADDR (sb_header));
- DESCRIPTOR_FOR_ADDR (sb_header) = desc;
+ sb_header = desc->block_size == pagesize ?
+ mono_valloc (0, desc->block_size, prot_flags_for_activate (TRUE)) :
+ mono_valloc_aligned (desc->block_size, desc->block_size, prot_flags_for_activate (TRUE));
+
+ g_assert (sb_header == sb_header_for_addr (sb_header, desc->block_size));
+
+ *(Descriptor**)sb_header = desc;
//g_print ("sb %p for %p\n", sb_header, desc);
- return (char*)sb_header + SB_HEADER_SIZE;
+
+ return (char*)sb_header + LOCK_FREE_ALLOC_SB_HEADER_SIZE;
}
static void
-free_sb (gpointer sb)
+free_sb (gpointer sb, size_t block_size)
{
- gpointer sb_header = SB_HEADER_FOR_ADDR (sb);
- g_assert ((char*)sb_header + SB_HEADER_SIZE == sb);
- mono_sgen_free_os_memory (sb_header, SB_SIZE);
+ gpointer sb_header = sb_header_for_addr (sb, block_size);
+ g_assert ((char*)sb_header + LOCK_FREE_ALLOC_SB_HEADER_SIZE == sb);
+ mono_vfree (sb_header, block_size);
//g_print ("free sb %p\n", sb_header);
}
Descriptor *d;
int i;
- desc = mono_sgen_alloc_os_memory (desc_size * NUM_DESC_BATCH, TRUE);
+ desc = mono_valloc (0, desc_size * NUM_DESC_BATCH, prot_flags_for_activate (TRUE));
/* Organize into linked list. */
d = desc;
success = (InterlockedCompareExchangePointer ((gpointer * volatile)&desc_avail, desc->next, NULL) == NULL);
if (!success)
- mono_sgen_free_os_memory (desc, desc_size * NUM_DESC_BATCH);
+ mono_vfree (desc, desc_size * NUM_DESC_BATCH);
}
mono_hazard_pointer_clear (hp, 1);
g_assert (desc->anchor.data.state == STATE_EMPTY);
g_assert (desc->in_use);
desc->in_use = FALSE;
- free_sb (desc->sb);
+ free_sb (desc->sb, desc->block_size);
mono_thread_hazardous_free_or_queue (desc, desc_enqueue_avail, FALSE, TRUE);
}
#else
static void
desc_retire (Descriptor *desc)
{
- free_sb (desc->sb);
+ free_sb (desc->sb, desc->block_size);
mono_lock_free_queue_enqueue (&available_descs, &desc->node);
}
#endif
mono_memory_read_barrier ();
next = *(unsigned int*)addr;
- g_assert (next < SB_USABLE_SIZE / desc->slot_size);
+ g_assert (next < LOCK_FREE_ALLOC_SB_USABLE_SIZE (desc->block_size) / desc->slot_size);
new_anchor.data.avail = next;
--new_anchor.data.count;
static gpointer
alloc_from_new_sb (MonoLockFreeAllocator *heap)
{
- unsigned int slot_size, count, i;
+ unsigned int slot_size, block_size, count, i;
Descriptor *desc = desc_alloc ();
- desc->sb = alloc_sb (desc);
-
slot_size = desc->slot_size = heap->sc->slot_size;
- count = SB_USABLE_SIZE / slot_size;
-
- /* Organize blocks into linked list. */
- for (i = 1; i < count - 1; ++i)
- *(unsigned int*)((char*)desc->sb + i * slot_size) = i + 1;
+ block_size = desc->block_size = heap->sc->block_size;
+ count = LOCK_FREE_ALLOC_SB_USABLE_SIZE (block_size) / slot_size;
desc->heap = heap;
/*
desc->anchor.data.count = desc->max_count - 1;
desc->anchor.data.state = STATE_PARTIAL;
+ desc->sb = alloc_sb (desc);
+
+ /* Organize blocks into linked list. */
+ for (i = 1; i < count - 1; ++i)
+ *(unsigned int*)((char*)desc->sb + i * slot_size) = i + 1;
+
mono_memory_write_barrier ();
/* Make it active or free it again. */
}
void
-mono_lock_free_free (gpointer ptr)
+mono_lock_free_free (gpointer ptr, size_t block_size)
{
Anchor old_anchor, new_anchor;
Descriptor *desc;
gpointer sb;
MonoLockFreeAllocator *heap = NULL;
- desc = DESCRIPTOR_FOR_ADDR (ptr);
+ desc = *(Descriptor**) sb_header_for_addr (ptr, block_size);
+ g_assert (block_size == desc->block_size);
+
sb = desc->sb;
- g_assert (SB_HEADER_FOR_ADDR (ptr) == SB_HEADER_FOR_ADDR (sb));
do {
new_anchor = old_anchor = *(volatile Anchor*)&desc->anchor.value;
*(unsigned int*)ptr = old_anchor.data.avail;
new_anchor.data.avail = ((char*)ptr - (char*)sb) / desc->slot_size;
- g_assert (new_anchor.data.avail < SB_USABLE_SIZE / desc->slot_size);
+ g_assert (new_anchor.data.avail < LOCK_FREE_ALLOC_SB_USABLE_SIZE (block_size) / desc->slot_size);
if (old_anchor.data.state == STATE_FULL)
new_anchor.data.state = STATE_PARTIAL;
descriptor_check_consistency (Descriptor *desc, gboolean print)
{
int count = desc->anchor.data.count;
- int max_count = SB_USABLE_SIZE / desc->slot_size;
+ int max_count = LOCK_FREE_ALLOC_SB_USABLE_SIZE (desc->block_size) / desc->slot_size;
#if _MSC_VER
gboolean* linked = alloca(max_count*sizeof(gboolean));
#else
}
void
-mono_lock_free_allocator_init_size_class (MonoLockFreeAllocSizeClass *sc, unsigned int slot_size)
+mono_lock_free_allocator_init_size_class (MonoLockFreeAllocSizeClass *sc, unsigned int slot_size, unsigned int block_size)
{
- g_assert (slot_size <= SB_USABLE_SIZE / 2);
+ g_assert (block_size > 0);
+ g_assert ((block_size & (block_size - 1)) == 0); /* check if power of 2 */
+ g_assert (slot_size * 2 <= LOCK_FREE_ALLOC_SB_USABLE_SIZE (block_size));
mono_lock_free_queue_init (&sc->partial);
sc->slot_size = slot_size;
+ sc->block_size = block_size;
}
void
typedef struct {
MonoLockFreeQueue partial;
unsigned int slot_size;
+ unsigned int block_size;
} MonoLockFreeAllocSizeClass;
struct _MonoLockFreeAllocDescriptor;
MonoLockFreeAllocSizeClass *sc;
} MonoLockFreeAllocator;
-void mono_lock_free_allocator_init_size_class (MonoLockFreeAllocSizeClass *sc, unsigned int slot_size) MONO_INTERNAL;
+#define LOCK_FREE_ALLOC_SB_MAX_SIZE 16384
+#define LOCK_FREE_ALLOC_SB_HEADER_SIZE (sizeof (MonoLockFreeAllocator))
+#define LOCK_FREE_ALLOC_SB_USABLE_SIZE(block_size) ((block_size) - LOCK_FREE_ALLOC_SB_HEADER_SIZE)
+
+void mono_lock_free_allocator_init_size_class (MonoLockFreeAllocSizeClass *sc, unsigned int slot_size, unsigned int block_size) MONO_INTERNAL;
void mono_lock_free_allocator_init_allocator (MonoLockFreeAllocator *heap, MonoLockFreeAllocSizeClass *sc) MONO_INTERNAL;
gpointer mono_lock_free_alloc (MonoLockFreeAllocator *heap) MONO_INTERNAL;
-void mono_lock_free_free (gpointer ptr) MONO_INTERNAL;
+void mono_lock_free_free (gpointer ptr, size_t block_size) MONO_INTERNAL;
gboolean mono_lock_free_allocator_check_consistency (MonoLockFreeAllocator *heap) MONO_INTERNAL;
#elif (defined(__arm__) && !defined(MONO_CROSS_COMPILE)) || (defined(TARGET_ARM)) /* defined(__x86_64__) */
+#include <mono/arch/arm/arm-codegen.h>
+
typedef struct {
mgreg_t pc;
mgreg_t regs [16];
--- /dev/null
+/*
+ * mono-mmap-internal.h: Internal virtual memory stuff.
+ *
+ * Copyright (C) 2014 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.
+ */
+
+#ifndef __MONO_UTILS_MMAP_INTERNAL_H__
+#define __MONO_UTILS_MMAP_INTERNAL_H__
+
+#include "mono-compiler.h"
+
+int mono_pages_not_faulted (void *addr, size_t length) MONO_INTERNAL;
+
+#endif /* __MONO_UTILS_MMAP_INTERNAL_H__ */
+
#endif
#include "mono-mmap.h"
+#include "mono-mmap-internal.h"
#include "mono-proclib.h"
#ifndef MAP_ANONYMOUS
return 0;
}
+int
+mono_pages_not_faulted (void *addr, size_t length)
+{
+ return -1;
+}
+
#else
#if defined(HAVE_MMAP)
}
#endif // __native_client__
+int
+mono_pages_not_faulted (void *addr, size_t size)
+{
+ int i;
+ gint64 count;
+ int pagesize = mono_pagesize ();
+ int npages = (size + pagesize - 1) / pagesize;
+ char *faulted = g_malloc0 (sizeof (char*) * npages);
+
+ if (mincore (addr, size, faulted) != 0) {
+ count = -1;
+ } else {
+ count = 0;
+ for (i = 0; i < npages; ++i) {
+ if (faulted [i] != 0)
+ ++count;
+ }
+ }
+
+ g_free (faulted);
+
+ return count;
+}
+
#else
/* dummy malloc-based implementation */
}
return 0;
}
+
+int
+mono_pages_not_faulted (void *addr, size_t length)
+{
+ return -1;
+}
+
#endif // HAVE_MMAP
#if defined(HAVE_SHM_OPEN) && !defined (DISABLE_SHARED_PERFCOUNTERS)
if (size)
*size = res;
return buf;
+#elif defined(__HAIKU__)
+ /* FIXME: Add back the code from 9185fcc305e43428d0f40f3ee37c8a405d41c9ae */
+ g_assert_not_reached ();
+ return NULL;
#else
const char *name;
void **buf = NULL;
#include <config.h>
#if defined(PLATFORM_ANDROID)
#include <asm/sigcontext.h>
+#ifdef HAVE_UCONTEXT_H
+#include <ucontext.h>
+#endif
#endif
#ifdef HAVE_UNISTD_H
#define UCONTEXT_REG_EIP(ctx) (((ucontext_t*)(ctx))->uc_mcontext.gregs [EIP])
#else
-#if defined(TARGET_ANDROID)
+#if defined(PLATFORM_ANDROID)
/* No ucontext.h as of NDK v6b */
typedef int greg_t;
#define NGREG 19
#ifdef ENABLE_EXTENSION_MODULE
#include "../../../mono-extensions/mono/utils/mono-signal-handler.h"
#endif
-/*
-Not all platforms support signal handlers in the same way. Some have the same concept but
-for some weird reason pass different kind of arguments.
-
-All signal handler helpers should go here so they can be properly shared across the JIT,
-utils and sgen.
-
-TODO: Cleanup & move mini's macros to here so they can leveraged by other parts.
-*/
+/* Don't use this */
#ifndef MONO_SIGNAL_HANDLER_FUNC
#define MONO_SIGNAL_HANDLER_FUNC(access, name, arglist) access void name arglist
#endif
+/*
+ * Macros to work around signal handler differences on various platforms.
+ *
+ * To declare a signal handler function:
+ * void MONO_SIG_HANDLER_SIGNATURE (handler_func)
+ * To define a signal handler function:
+ * MONO_SIG_HANDLER_FUNC(access, name)
+ * To call another signal handler function:
+ * handler_func (MONO_SIG_HANDLER_PARAMS);
+ * To obtain the signal number:
+ * int signo = MONO_SIG_HANDLER_GET_SIGNO ();
+ * To obtain the signal context:
+ * MONO_SIG_HANDLER_GET_CONTEXT ().
+ * This will define a variable name 'ctx'.
+ */
+
+#ifdef HOST_WIN32
+#define MONO_SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy, EXCEPTION_POINTERS *_info, void *context)
+#define MONO_SIG_HANDLER_FUNC(access, ftn) MONO_SIGNAL_HANDLER_FUNC (access, ftn, (int _dummy, EXCEPTION_POINTERS *_info, void *context))
+#define MONO_SIG_HANDLER_PARAMS _dummy, _info, context
+#define MONO_SIG_HANDLER_GET_SIGNO() (_dummy)
+#define MONO_SIG_HANDLER_GET_INFO() (_info)
+#define MONO_SIG_HANDLER_INFO_TYPE EXCEPTION_POINTERS
+/* seh_vectored_exception_handler () passes in a CONTEXT* */
+#define MONO_SIG_HANDLER_GET_CONTEXT \
+ void *ctx = context;
+#else
+/* sigaction */
+#define MONO_SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy, siginfo_t *_info, void *context)
+#define MONO_SIG_HANDLER_FUNC(access, ftn) MONO_SIGNAL_HANDLER_FUNC (access, ftn, (int _dummy, siginfo_t *_info, void *context))
+#define MONO_SIG_HANDLER_PARAMS _dummy, _info, context
+#define MONO_SIG_HANDLER_GET_SIGNO() (_dummy)
+#define MONO_SIG_HANDLER_GET_INFO() (_info)
+#define MONO_SIG_HANDLER_INFO_TYPE siginfo_t
+#define MONO_SIG_HANDLER_GET_CONTEXT \
+ void *ctx = context;
+#endif
+
#endif
#if defined(__FreeBSD__)
+#include <mono/utils/mono-threads.h>
#include <pthread.h>
#include <pthread_np.h>
if (threads_callbacks.thread_register) {
if (threads_callbacks.thread_register (info, baseptr) == NULL) {
- g_warning ("thread registation failed\n");
+ // g_warning ("thread registation failed\n");
g_free (info);
return NULL;
}
for (;;) {
const char *suspend_error = "Unknown error";
if (!(info = mono_thread_info_suspend_sync (id, interrupt_kernel, &suspend_error))) {
- g_warning ("failed to suspend thread %p due to %s, hopefully it is dead", (gpointer)id, suspend_error);
+ // g_warning ("failed to suspend thread %p due to %s, hopefully it is dead", (gpointer)id, suspend_error);
mono_thread_info_suspend_unlock ();
return NULL;
}
break;
if (!mono_thread_info_core_resume (info)) {
- g_warning ("failed to resume thread %p, hopefully it is dead", (gpointer)id);
+ // g_warning ("failed to resume thread %p, hopefully it is dead", (gpointer)id);
mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
mono_thread_info_suspend_unlock ();
return NULL;
<Platform>x64</Platform>\r
</ProjectConfiguration>\r
</ItemGroup>\r
+ <Import Project="mono.props" />
<PropertyGroup Label="Globals">\r
<ProjectGuid>{B7098DFA-31E6-4006-8A15-1C9A4E925149}</ProjectGuid>\r
<RootNamespace>genmdesc</RootNamespace>\r
<ClCompile>\r
<Optimization>Disabled</Optimization>\r
<AdditionalIncludeDirectories>..\libgc\include;..\;..\mono\;..\eglib\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>_DEBUG;__x86_64__;TARGET_AMD64;WIN64;_WIN64;WIN32;_WIN32;__WIN32__;_WINDOWS;WINDOWS;HOST_WIN32;TARGET_WIN32;_CRT_SECURE_NO_DEPRECATE;_CONSOLE;HAVE_CONFIG_H;WINVER=0x0500;_WIN32_WINNT=0x0500;_WIN32_IE=0x0501;WIN32_THREADS;FD_SETSIZE=1024;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+ <PreprocessorDefinitions>_DEBUG;__x86_64__;TARGET_AMD64;WIN64;_WIN64;WIN32;_WIN32;__WIN32__;_WINDOWS;WINDOWS;HOST_WIN32;TARGET_WIN32;_CRT_SECURE_NO_DEPRECATE;_CONSOLE;HAVE_CONFIG_H;WINVER=0x0502;_WIN32_WINNT=0x0502;_WIN32_IE=0x0501;WIN32_THREADS;FD_SETSIZE=1024;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>\r
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>\r
<Optimization>MinSpace</Optimization>\r
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>\r
<AdditionalIncludeDirectories>..\libgc\include;..\;..\mono\;..\eglib\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>NDEBUG;__x86_64__;TARGET_AMD64;WIN64;_WIN64;WIN32;_WIN32;__WIN32__;_WINDOWS;WINDOWS;HOST_WIN32;TARGET_WIN32;_CRT_SECURE_NO_DEPRECATE;_CONSOLE;HAVE_CONFIG_H;WINVER=0x0500;_WIN32_WINNT=0x0500;_WIN32_IE=0x0501;WIN32_THREADS;FD_SETSIZE=1024;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+ <PreprocessorDefinitions>NDEBUG;__x86_64__;TARGET_AMD64;WIN64;_WIN64;WIN32;_WIN32;__WIN32__;_WINDOWS;WINDOWS;HOST_WIN32;TARGET_WIN32;_CRT_SECURE_NO_DEPRECATE;_CONSOLE;HAVE_CONFIG_H;WINVER=0x0502;_WIN32_WINNT=0x0502;_WIN32_IE=0x0501;WIN32_THREADS;FD_SETSIZE=1024;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>\r
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>\r
<FunctionLevelLinking>true</FunctionLevelLinking>\r
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
<ImportGroup Label="ExtensionTargets">\r
</ImportGroup>\r
-</Project>
\ No newline at end of file
+</Project>
<ClCompile>\r
<Optimization>Disabled</Optimization>\r
<AdditionalIncludeDirectories>..\libgc\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>_DEBUG;__i386__;TARGET_X86;i386;WIN32;_WIN32;__WIN32__;_WINDOWS;WINDOWS;HOST_WIN32;TARGET_WIN32;_CRT_SECURE_NO_DEPRECATE;__STDC__;PACKAGE_NAME="libgc-mono";PACKAGE_TARNAME="libgc-mono";PACKAGE_VERSION="6.6";PACKAGE_STRING="libgc-mono 6.6";PACKAGE_BUGREPORT="Hans_Boehm%40hp.com";GC_WIN32_THREADS=1;NO_GETENV=1;GC_INSIDE_DLL=1;GC_NOT_DLL=1;STDC_HEADERS=1;HAVE_SYS_TYPES_H=1;HAVE_SYS_STAT_H=1;HAVE_STDLIB_H=1;HAVE_STRING_H=1;HAVE_MEMORY_H=1;HAVE_STRINGS_H=1;HAVE_INTTYPES_H=1;HAVE_STDINT_H=1;HAVE_UNISTD_H=1;SILENT=1;NO_SIGNALS=1;NO_EXECUTE_PERMISSION=1;JAVA_FINALIZATION=1;GC_GCJ_SUPPORT=1;ATOMIC_UNCOLLECTABLE=1;_IN_LIBGC=1;WINVER=0x0500;_WIN32_WINNT=0x0500;_WIN32_IE=0x0501;WIN32_THREADS;FD_SETSIZE=1024;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+ <PreprocessorDefinitions>_DEBUG;__i386__;TARGET_X86;i386;WIN32;_WIN32;__WIN32__;_WINDOWS;WINDOWS;HOST_WIN32;TARGET_WIN32;_CRT_SECURE_NO_DEPRECATE;__STDC__;PACKAGE_NAME="libgc-mono";PACKAGE_TARNAME="libgc-mono";PACKAGE_VERSION="6.6";PACKAGE_STRING="libgc-mono 6.6";PACKAGE_BUGREPORT="Hans_Boehm%40hp.com";GC_WIN32_THREADS=1;NO_GETENV=1;GC_INSIDE_DLL=1;GC_NOT_DLL=1;STDC_HEADERS=1;HAVE_SYS_TYPES_H=1;HAVE_SYS_STAT_H=1;HAVE_STDLIB_H=1;HAVE_STRING_H=1;HAVE_MEMORY_H=1;HAVE_STRINGS_H=1;HAVE_INTTYPES_H=1;HAVE_STDINT_H=1;HAVE_UNISTD_H=1;SILENT=1;NO_SIGNALS=1;NO_EXECUTE_PERMISSION=1;JAVA_FINALIZATION=1;GC_GCJ_SUPPORT=1;ATOMIC_UNCOLLECTABLE=1;_IN_LIBGC=1;WINVER=0x0502;_WIN32_WINNT=0x0502;_WIN32_IE=0x0501;WIN32_THREADS;FD_SETSIZE=1024;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>\r
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>\r
<ClCompile>\r
<Optimization>MinSpace</Optimization>\r
<AdditionalIncludeDirectories>..\libgc\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>NDEBUG;__i386__;TARGET_X86;i386;i386;WIN32;_WIN32;__WIN32__;_WINDOWS;WINDOWS;HOST_WIN32;TARGET_WIN32;_CRT_SECURE_NO_DEPRECATE;__STDC__;PACKAGE_NAME="libgc-mono";PACKAGE_TARNAME="libgc-mono";PACKAGE_VERSION="6.6";PACKAGE_STRING="libgc-mono 6.6";PACKAGE_BUGREPORT="Hans_Boehm%40hp.com";GC_WIN32_THREADS=1;NO_GETENV=1;GC_INSIDE_DLL=1;GC_NOT_DLL=1;STDC_HEADERS=1;HAVE_SYS_TYPES_H=1;HAVE_SYS_STAT_H=1;HAVE_STDLIB_H=1;HAVE_STRING_H=1;HAVE_MEMORY_H=1;HAVE_STRINGS_H=1;HAVE_INTTYPES_H=1;HAVE_STDINT_H=1;HAVE_UNISTD_H=1;SILENT=1;NO_SIGNALS=1;NO_EXECUTE_PERMISSION=1;JAVA_FINALIZATION=1;GC_GCJ_SUPPORT=1;ATOMIC_UNCOLLECTABLE=1;_IN_LIBGC=1;WINVER=0x0500;_WIN32_WINNT=0x0500;_WIN32_IE=0x0501;WIN32_THREADS;FD_SETSIZE=1024;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+ <PreprocessorDefinitions>NDEBUG;__i386__;TARGET_X86;i386;i386;WIN32;_WIN32;__WIN32__;_WINDOWS;WINDOWS;HOST_WIN32;TARGET_WIN32;_CRT_SECURE_NO_DEPRECATE;__STDC__;PACKAGE_NAME="libgc-mono";PACKAGE_TARNAME="libgc-mono";PACKAGE_VERSION="6.6";PACKAGE_STRING="libgc-mono 6.6";PACKAGE_BUGREPORT="Hans_Boehm%40hp.com";GC_WIN32_THREADS=1;NO_GETENV=1;GC_INSIDE_DLL=1;GC_NOT_DLL=1;STDC_HEADERS=1;HAVE_SYS_TYPES_H=1;HAVE_SYS_STAT_H=1;HAVE_STDLIB_H=1;HAVE_STRING_H=1;HAVE_MEMORY_H=1;HAVE_STRINGS_H=1;HAVE_INTTYPES_H=1;HAVE_STDINT_H=1;HAVE_UNISTD_H=1;SILENT=1;NO_SIGNALS=1;NO_EXECUTE_PERMISSION=1;JAVA_FINALIZATION=1;GC_GCJ_SUPPORT=1;ATOMIC_UNCOLLECTABLE=1;_IN_LIBGC=1;WINVER=0x0502;_WIN32_WINNT=0x0502;_WIN32_IE=0x0501;WIN32_THREADS;FD_SETSIZE=1024;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>\r
<BufferSecurityCheck>true</BufferSecurityCheck>\r
<PrecompiledHeader>\r
<ClCompile>\r
<Optimization>Disabled</Optimization>\r
<AdditionalIncludeDirectories>..\libgc\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>_DEBUG;__x86_64__;WIN64;_WIN64;WIN32;_WIN32;__WIN32__;_WINDOWS;WINDOWS;HOST_WIN32;TARGET_WIN32;_CRT_SECURE_NO_DEPRECATE;__STDC__;PACKAGE_NAME="libgc-mono";PACKAGE_TARNAME="libgc-mono";PACKAGE_VERSION="6.6";PACKAGE_STRING="libgc-mono 6.6";PACKAGE_BUGREPORT="Hans_Boehm%40hp.com";GC_WIN32_THREADS=1;NO_GETENV=1;GC_INSIDE_DLL=1;GC_NOT_DLL=1;STDC_HEADERS=1;HAVE_SYS_TYPES_H=1;HAVE_SYS_STAT_H=1;HAVE_STDLIB_H=1;HAVE_STRING_H=1;HAVE_MEMORY_H=1;HAVE_STRINGS_H=1;HAVE_INTTYPES_H=1;HAVE_STDINT_H=1;HAVE_UNISTD_H=1;SILENT=1;NO_SIGNALS=1;NO_EXECUTE_PERMISSION=1;JAVA_FINALIZATION=1;GC_GCJ_SUPPORT=1;ATOMIC_UNCOLLECTABLE=1;_IN_LIBGC=1;WINVER=0x0500;_WIN32_WINNT=0x0500;_WIN32_IE=0x0501;WIN32_THREADS;FD_SETSIZE=1024</PreprocessorDefinitions>\r
+ <PreprocessorDefinitions>_DEBUG;__x86_64__;WIN64;_WIN64;WIN32;_WIN32;__WIN32__;_WINDOWS;WINDOWS;HOST_WIN32;TARGET_WIN32;_CRT_SECURE_NO_DEPRECATE;__STDC__;PACKAGE_NAME="libgc-mono";PACKAGE_TARNAME="libgc-mono";PACKAGE_VERSION="6.6";PACKAGE_STRING="libgc-mono 6.6";PACKAGE_BUGREPORT="Hans_Boehm%40hp.com";GC_WIN32_THREADS=1;NO_GETENV=1;GC_INSIDE_DLL=1;GC_NOT_DLL=1;STDC_HEADERS=1;HAVE_SYS_TYPES_H=1;HAVE_SYS_STAT_H=1;HAVE_STDLIB_H=1;HAVE_STRING_H=1;HAVE_MEMORY_H=1;HAVE_STRINGS_H=1;HAVE_INTTYPES_H=1;HAVE_STDINT_H=1;HAVE_UNISTD_H=1;SILENT=1;NO_SIGNALS=1;NO_EXECUTE_PERMISSION=1;JAVA_FINALIZATION=1;GC_GCJ_SUPPORT=1;ATOMIC_UNCOLLECTABLE=1;_IN_LIBGC=1;WINVER=0x0502;_WIN32_WINNT=0x0502;_WIN32_IE=0x0501;WIN32_THREADS;FD_SETSIZE=1024</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>\r
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>\r
<ClCompile>\r
<Optimization>MinSpace</Optimization>\r
<AdditionalIncludeDirectories>..\libgc\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>NDEBUG;__x86_64__;WIN64;_WIN64;WIN32;_WIN32;__WIN32__;_WINDOWS;WINDOWS;HOST_WIN32;TARGET_WIN32;_CRT_SECURE_NO_DEPRECATE;__STDC__;PACKAGE_NAME="libgc-mono";PACKAGE_TARNAME="libgc-mono";PACKAGE_VERSION="6.6";PACKAGE_STRING="libgc-mono 6.6";PACKAGE_BUGREPORT="Hans_Boehm%40hp.com";GC_WIN32_THREADS=1;NO_GETENV=1;GC_INSIDE_DLL=1;GC_NOT_DLL=1;STDC_HEADERS=1;HAVE_SYS_TYPES_H=1;HAVE_SYS_STAT_H=1;HAVE_STDLIB_H=1;HAVE_STRING_H=1;HAVE_MEMORY_H=1;HAVE_STRINGS_H=1;HAVE_INTTYPES_H=1;HAVE_STDINT_H=1;HAVE_UNISTD_H=1;SILENT=1;NO_SIGNALS=1;NO_EXECUTE_PERMISSION=1;JAVA_FINALIZATION=1;GC_GCJ_SUPPORT=1;ATOMIC_UNCOLLECTABLE=1;_IN_LIBGC=1;WINVER=0x0500;_WIN32_WINNT=0x0500;_WIN32_IE=0x0501;WIN32_THREADS;FD_SETSIZE=1024;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+ <PreprocessorDefinitions>NDEBUG;__x86_64__;WIN64;_WIN64;WIN32;_WIN32;__WIN32__;_WINDOWS;WINDOWS;HOST_WIN32;TARGET_WIN32;_CRT_SECURE_NO_DEPRECATE;__STDC__;PACKAGE_NAME="libgc-mono";PACKAGE_TARNAME="libgc-mono";PACKAGE_VERSION="6.6";PACKAGE_STRING="libgc-mono 6.6";PACKAGE_BUGREPORT="Hans_Boehm%40hp.com";GC_WIN32_THREADS=1;NO_GETENV=1;GC_INSIDE_DLL=1;GC_NOT_DLL=1;STDC_HEADERS=1;HAVE_SYS_TYPES_H=1;HAVE_SYS_STAT_H=1;HAVE_STDLIB_H=1;HAVE_STRING_H=1;HAVE_MEMORY_H=1;HAVE_STRINGS_H=1;HAVE_INTTYPES_H=1;HAVE_STDINT_H=1;HAVE_UNISTD_H=1;SILENT=1;NO_SIGNALS=1;NO_EXECUTE_PERMISSION=1;JAVA_FINALIZATION=1;GC_GCJ_SUPPORT=1;ATOMIC_UNCOLLECTABLE=1;_IN_LIBGC=1;WINVER=0x0502;_WIN32_WINNT=0x0502;_WIN32_IE=0x0501;WIN32_THREADS;FD_SETSIZE=1024;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>\r
<BufferSecurityCheck>true</BufferSecurityCheck>\r
<PrecompiledHeader>\r
<ClCompile Include="..\mono\metadata\gc.c" />\r
<ClCompile Include="..\mono\metadata\icall.c" />\r
<ClCompile Include="..\mono\metadata\image.c" />\r
+ <ClCompile Include="..\mono\metadata\jit-info.c" />\r
<ClCompile Include="..\mono\metadata\loader.c" />\r
<ClCompile Include="..\mono\metadata\locales.c" />\r
<ClCompile Include="..\mono\metadata\lock-tracer.c" />\r
<ClCompile Include="..\mono\metadata\sgen-hash-table.c" />\r
<ClCompile Include="..\mono\metadata\sgen-internal.c" />\r
<ClCompile Include="..\mono\metadata\sgen-los.c" />\r
- <ClCompile Include="..\mono\metadata\sgen-marksweep-fixed-par.c" />\r
- <ClCompile Include="..\mono\metadata\sgen-marksweep-fixed.c" />\r
- <ClCompile Include="..\mono\metadata\sgen-marksweep-par.c" />\r
<ClCompile Include="..\mono\metadata\sgen-marksweep.c" />\r
<ClCompile Include="..\mono\metadata\sgen-memory-governor.c" />\r
<ClCompile Include="..\mono\metadata\sgen-new-bridge.c" />\r
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
<ImportGroup Label="ExtensionTargets">\r
</ImportGroup>\r
-</Project>
\ No newline at end of file
+</Project>\r
<Platform>x64</Platform>\r
</ProjectConfiguration>\r
</ItemGroup>\r
+ <Import Project="mono.props" />\r
<PropertyGroup Label="Globals">\r
<ProjectGuid>{5A435710-E6D2-4DD4-9B3F-A7239A32C6F4}</ProjectGuid>\r
<RootNamespace>libtest</RootNamespace>\r
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
<ImportGroup Label="ExtensionTargets">\r
</ImportGroup>\r
-</Project>
\ No newline at end of file
+</Project>\r
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
- <PreprocessorDefinitions>__default_codegen__;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;HAVE_CONFIG_H;GC_NOT_DLL;WIN32_THREADS;WINVER=0x0500;_WIN32_WINNT=0x0500;_WIN32_IE=0x0501;_UNICODE;UNICODE;WIN32_THREADS;FD_SETSIZE=1024;$(PreprocessorDefinitions);_WINSOCKAPI_</PreprocessorDefinitions>
+ <PreprocessorDefinitions>__default_codegen__;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;HAVE_CONFIG_H;GC_NOT_DLL;WIN32_THREADS;WINVER=0x0502;_WIN32_WINNT=0x0502;_WIN32_IE=0x0501;_UNICODE;UNICODE;WIN32_THREADS;FD_SETSIZE=1024;$(PreprocessorDefinitions);_WINSOCKAPI_</PreprocessorDefinitions>
<DisableSpecificWarnings>4273;4005</DisableSpecificWarnings>
</ClCompile>
<Link>
<AdditionalDependencies>Mswsock.lib;ws2_32.lib;ole32.lib;oleaut32.lib;psapi.lib;version.lib;advapi32.lib;winmm.lib;kernel32.lib;$(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
-</Project>
\ No newline at end of file
+</Project>
<ClCompile>\r
<Optimization>Disabled</Optimization>\r
<AdditionalIncludeDirectories>..\libgc\include;..\;..\mono\;..\mono\jit;..\mono\eglib\src;..\..\mono\eglib\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>TARGET_X86;_DEBUG;__i386__;TARGET_X86;i386;WIN32;_WIN32;__WIN32__;_WINDOWS;WINDOWS;HOST_WIN32;TARGET_WIN32;_CRT_SECURE_NO_DEPRECATE;GC_NOT_DLL;HAVE_CONFIG_H;WINVER=0x0500;_WIN32_WINNT=0x0500;_WIN32_IE=0x0501;WIN32_THREADS;FD_SETSIZE=1024;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+ <PreprocessorDefinitions>TARGET_X86;_DEBUG;__i386__;TARGET_X86;i386;WIN32;_WIN32;__WIN32__;_WINDOWS;WINDOWS;HOST_WIN32;TARGET_WIN32;_CRT_SECURE_NO_DEPRECATE;GC_NOT_DLL;HAVE_CONFIG_H;WINVER=0x0502;_WIN32_WINNT=0x0502;_WIN32_IE=0x0501;WIN32_THREADS;FD_SETSIZE=1024;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>\r
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>\r
<ClCompile>\r
<Optimization>Disabled</Optimization>\r
<AdditionalIncludeDirectories>..\libgc\include;..\;..\mono\;..\mono\jit;..\mono\eglib\src;..\..\mono\eglib\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>TARGET_X86;_DEBUG;__i386__;TARGET_X86;i386;WIN32;_WIN32;__WIN32__;_WINDOWS;WINDOWS;HOST_WIN32;TARGET_WIN32;_CRT_SECURE_NO_DEPRECATE;GC_NOT_DLL;HAVE_CONFIG_H;WINVER=0x0500;_WIN32_WINNT=0x0500;_WIN32_IE=0x0501;WIN32_THREADS;FD_SETSIZE=1024;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+ <PreprocessorDefinitions>TARGET_X86;_DEBUG;__i386__;TARGET_X86;i386;WIN32;_WIN32;__WIN32__;_WINDOWS;WINDOWS;HOST_WIN32;TARGET_WIN32;_CRT_SECURE_NO_DEPRECATE;GC_NOT_DLL;HAVE_CONFIG_H;WINVER=0x0502;_WIN32_WINNT=0x0502;_WIN32_IE=0x0501;WIN32_THREADS;FD_SETSIZE=1024;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>\r
<PrecompiledHeader>\r
get-cygwin-deps.sh \
mono-configuration-crypto.in
-if USE_JIT
mono_interp = mono
-else
-mono_interp = mint
-endif
if HOST_WIN32
if CROSS_COMPILING
#endif
#if _WIN32_WINNT < 0x0502
-/* Required for Vectored Exception Handling.
- Interlocked* functions are also not available in XP SP1 and below
-*/
-#undef _WIN32_WINNT
-#define _WIN32_WINNT 0x0502
+#error "Mono requires WinXP SP2 or later"
#endif /* _WIN32_WINNT < 0x0502 */
/*
/* #undef HAVE_GETPRIORITY */
/* Define to 1 if you have the `GetProcessId' function. */
-#if (_WIN32_WINNT >= 0x0502)
#define HAVE_GETPROCESSID 1
-#endif
/* Define to 1 if you have the `getpwnam_r' function. */
/* #undef HAVE_GETPWNAM_R */