diff --git a/acinclude.m4 b/acinclude.m4 index 5216cd14a5e..bbc2781eab0 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -26,7 +26,7 @@ i?86-*-linux*|i?86-apple-darwin*|x86_64-*-linux*|powerpc-*-linux*|powerpc64-*-li |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*) diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 00000000000..58c9a3a60b5 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,98 @@ +# +# 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` AC_MSG_CHECKING(LLVM version) AC_MSG_RESULT($llvm_version) @@ -2474,14 +2480,8 @@ if test "x$enable_llvm" = "xyes"; then AC_MSG_ERROR([Compiling with stock LLVM is not supported, please use the Mono LLVM repo at https://github.com/mono/llvm, with the GIT branch which matches this version of mono, i.e. 'mono-2-10' for Mono 2.10.]) fi - AC_DEFINE_UNQUOTED(LLVM_MAJOR_VERSION, $major_version, [Major version of LLVM libraries]) - AC_DEFINE_UNQUOTED(LLVM_MINOR_VERSION, $minor_version, [Minor version of LLVM libraries]) AC_DEFINE_UNQUOTED(LLVM_VERSION, "$llvm_version", [Full version of LLVM libraties]) - # Have to pass these on the command line since mini-llvm-cpp.h already includes - # llvm's config.h - LLVM_CXXFLAGS="$LLVM_CXXFLAGS -DLLVM_MAJOR_VERSION=$major_version -DLLVM_MINOR_VERSION=$minor_version" - AC_SUBST(LLVM_CFLAGS) AC_SUBST(LLVM_CXXFLAGS) AC_SUBST(LLVM_LIBS) @@ -2498,7 +2498,6 @@ AM_CONDITIONAL(LOADED_LLVM, [test x$enable_loadedllvm = xyes]) TARGET="unknown" ACCESS_UNALIGNED="yes" -JIT_SUPPORTED=no LIBC="libc.so.6" INTL="libc.so.6" SQLITE="libsqlite.so.0" @@ -2519,7 +2518,6 @@ case "$host" in arch_target=mips; sgen_supported=true ACCESS_UNALIGNED="no" - JIT_SUPPORTED=yes AC_MSG_CHECKING(for mips n32) AC_TRY_COMPILE([],[ @@ -2537,7 +2535,6 @@ case "$host" in i*86-*-*) TARGET=X86; arch_target=x86; - JIT_SUPPORTED=yes case $host_os in solaris*) LIBC="libc.so" @@ -2583,7 +2580,6 @@ case "$host" in 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 @@ -2615,7 +2611,6 @@ case "$host" in 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)]) @@ -2628,7 +2623,6 @@ case "$host" in TARGET=SPARC fi arch_target=sparc; - JIT_SUPPORTED=yes ACCESS_UNALIGNED="no" case $host_os in linux*) ;; @@ -2661,7 +2655,6 @@ case "$host" in CPPFLAGS="$CPPFLAGS -D__mono_ppc__" fi arch_target=ppc; - JIT_SUPPORTED=yes case $host_os in linux*|darwin*) sgen_supported=true @@ -2672,7 +2665,6 @@ case "$host" in TARGET=ARM; arch_target=arm; ACCESS_UNALIGNED="no" - JIT_SUPPORTED=yes CPPFLAGS="$CPPFLAGS -D__ARM_EABI__" sgen_supported=true ;; @@ -2680,7 +2672,6 @@ case "$host" in TARGET=ARM; arch_target=arm; ACCESS_UNALIGNED="no" - JIT_SUPPORTED=yes sgen_supported=true AOT_SUPPORTED="yes" CPPFLAGS="$CPPFLAGS -D__ARM_EABI__" @@ -2690,7 +2681,6 @@ case "$host" in # TARGET=ARM; # arch_target=arm; # ACCESS_UNALIGNED="no" -# JIT_SUPPORTED=yes # sgen_supported=true # AOT_SUPPORTED="no" # ;; @@ -2698,7 +2688,6 @@ case "$host" in # https://lkml.org/lkml/2012/7/15/133 TARGET=ARM64 arch_target=arm64 - JIT_SUPPORTED=yes sgen_supported=true boehm_supported=false ;; @@ -2706,7 +2695,6 @@ case "$host" in TARGET=S390X; arch_target=s390x; ACCESS_UNALIGNED="yes" - JIT_SUPPORTED=yes sgen_supported=true CFLAGS="$CFLAGS -mbackchain -D__USE_STRING_INLINES" ;; @@ -2722,9 +2710,7 @@ if test "x$host" != "x$target"; then 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 @@ -2762,7 +2748,6 @@ if test "x$host" != "x$target"; then # arch_target=arm # AC_DEFINE(TARGET_ARM, 1, [...]) # ACCESS_UNALIGNED="no" -# JIT_SUPPORTED=yes # sizeof_register=4 # CPPFLAGS="$CPPFLAGS \ # -D__ARM_EABI__ \ @@ -2772,7 +2757,6 @@ if test "x$host" != "x$target"; then # -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 @@ -2789,9 +2773,7 @@ if test "x$host" != "x$target"; then 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 @@ -2806,10 +2788,20 @@ if test "x$host" != "x$target"; then ;; esac ;; + i686*-linux-*) + TARGET=X86; + arch_target=x86; + AC_DEFINE(TARGET_X86, 1, [...]) + AC_DEFINE(TARGET_ANDROID, 1, [...]) + CPPFLAGS="$CPPFLAGS" + sgen_supported=true + # Can't use tls, since it depends on the runtime detection of tls offsets + # in mono-compiler.h + with_tls=pthread + target_mach=no + ;; aarch64-*) TARGET=ARM64 - JIT_SUPPORTED=yes - jit_wanted=true ;; *) AC_MSG_ERROR([Cross compiling is not supported for target $target]) @@ -2932,19 +2924,7 @@ fi 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" @@ -3347,7 +3327,6 @@ AM_CONDITIONAL(HOST_ARM, test x$HOST = xARM) 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) diff --git a/data/Makefile.am b/data/Makefile.am index 32a13623cb9..daf6f38a79b 100644 --- a/data/Makefile.am +++ b/data/Makefile.am @@ -26,12 +26,8 @@ else 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 diff --git a/data/config.in b/data/config.in index 51cac3f0b43..b7601766e95 100644 --- a/data/config.in +++ b/data/config.in @@ -10,7 +10,7 @@ - + diff --git a/docs/Makefile.am b/docs/Makefile.am index 39527b5f8eb..811955257bb 100644 --- a/docs/Makefile.am +++ b/docs/Makefile.am @@ -99,14 +99,14 @@ mono-file-formats.tree: $(srcdir)/docs.make $(srcdir)/Makefile.am $(srcdir)/depl deploy/.stamp: convert.exe Makefile.am $(mkdir_p) html runtimedir=`cd ../runtime && pwd`; export runtimedir; \ - MONO_PATH=../mcs/class/lib/net_2_0 perl $(srcdir)/exdoc -h $(srcdir) -t . $(srcdir)/../mono/*/*.c + MONO_PATH=../mcs/class/lib/net_4_5 perl $(srcdir)/exdoc -h $(srcdir) -t . $(srcdir)/../mono/*/*.c touch $@ extract: deploy/.stamp convert.exe: convert.cs AgilityPack.dll - $(TOOL_MAKE) PROFILE=net_2_0 convert.exe + $(TOOL_MAKE) PROFILE=net_4_5 convert.exe AgilityPack.dll: - $(TOOL_MAKE) PROFILE=net_2_0 AgilityPack.dll + $(TOOL_MAKE) PROFILE=net_4_5 AgilityPack.dll diff --git a/eglib/acinclude.m4 b/eglib/acinclude.m4 index 5216cd14a5e..bbc2781eab0 100644 --- a/eglib/acinclude.m4 +++ b/eglib/acinclude.m4 @@ -26,7 +26,7 @@ i?86-*-linux*|i?86-apple-darwin*|x86_64-*-linux*|powerpc-*-linux*|powerpc64-*-li |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*) diff --git a/eglib/src/goutput.c b/eglib/src/goutput.c index 1dc8bd6faff..9756b67a47d 100644 --- a/eglib/src/goutput.c +++ b/eglib/src/goutput.c @@ -176,7 +176,7 @@ default_stderr_handler (const gchar *message) } -#elif MONOTOUCH +#elif defined(HOST_IOS) #include static int diff --git a/libgc/acinclude.m4 b/libgc/acinclude.m4 index 5216cd14a5e..bbc2781eab0 100644 --- a/libgc/acinclude.m4 +++ b/libgc/acinclude.m4 @@ -26,7 +26,7 @@ i?86-*-linux*|i?86-apple-darwin*|x86_64-*-linux*|powerpc-*-linux*|powerpc64-*-li |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*) diff --git a/libgc/include/gc_config_macros.h b/libgc/include/gc_config_macros.h index c11caa7748e..caf8de527c3 100644 --- a/libgc/include/gc_config_macros.h +++ b/libgc/include/gc_config_macros.h @@ -32,7 +32,7 @@ # define GC_LINUX_THREADS #endif #if defined(WIN32_THREADS) -# define GC_WIN32_THREADS +# define GC_WIN32_THREADS 1 #endif #if defined(USE_LD_WRAP) # define GC_USE_LD_WRAP diff --git a/man/mono.1 b/man/mono.1 index 3d4bd54e989..784c078d381 100644 --- a/man/mono.1 +++ b/man/mono.1 @@ -1075,19 +1075,10 @@ first generation (of two). A larger nursery will usually speed up the program but will obviously use more memory. The default nursery size 4 MB. .TP -\fBmajor=\fIcollector\fR -Specifies which major collector to use. Options are `marksweep' for -the Mark&Sweep collector, `marksweep-conc' for concurrent Mark&Sweep, -`marksweep-par' for parallel Mark&Sweep, `marksweep-fixed' for -Mark&Sweep with a fixed heap, and `marksweep-fixed-par' for parallel -Mark&Sweep with a fixed heap. The Mark&Sweep collector is the default. -.TP -\fBmajor-heap-size=\fIsize\fR -Sets the size of the major heap (not including the large object space) -for the fixed-heap Mark&Sweep collector (i.e. `marksweep-fixed' and -`marksweep-fixed-par'). The size is in bytes, with optional suffixes -`k', `m' and `g' to specify kilo-, mega- and gigabytes, respectively. -The default is 512 megabytes. +\fBmajor=\fIcollector\fR Specifies which major collector to use. +Options are `marksweep' for the Mark&Sweep collector, and +`marksweep-conc' for concurrent Mark&Sweep. The non-concurrent +Mark&Sweep collector is the default. .TP \fBsoft-heap-limit=\fIsize\fR Once the heap size gets larger than this size, ignore what the default @@ -1266,6 +1257,11 @@ work, Mono needs to be compiled with the BINARY_PROTOCOL define on 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 diff --git a/mcs/Makefile b/mcs/Makefile index e557f6ab315..1a4841a40d9 100644 --- a/mcs/Makefile +++ b/mcs/Makefile @@ -12,6 +12,7 @@ monotouch_SUBDIRS := build class monotouch_runtime_SUBDIRS := build class xammac_SUBDIRS := build class mobile_SUBDIRS := build class +mobile_static_SUBDIRS := build class net_3_5_SUBDIRS := build class tools/xbuild net_4_0_SUBDIRS := build class net_4_5_SUBDIRS := build mcs class nunit24 ilasm tools tests errors docs @@ -114,6 +115,7 @@ $(_boot_:%=profile-do--monotouch--%): profile-do--monotouch--%: $(_boot_:%=profile-do--monotouch_runtime--%): profile-do--monotouch_runtime--%: profile-do--build--% $(_boot_:%=profile-do--xammac--%): profile-do--xammac--%: profile-do--build--% $(_boot_:%=profile-do--mobile--%): profile-do--mobile--%: profile-do--build--% +$(_boot_:%=profile-do--mobile_static--%): profile-do--mobile_static--%: profile-do--build--% $(_boot_:%=profile-do--net_2_0--%): profile-do--net_2_0--%: profile-do--build--% $(_boot_:%=profile-do--build--%): profile-do--build--%: profile-do--basic--% diff --git a/mcs/build/profiles/mobile.make b/mcs/build/profiles/mobile.make index 87c51f407c8..117ac605151 100644 --- a/mcs/build/profiles/mobile.make +++ b/mcs/build/profiles/mobile.make @@ -12,7 +12,22 @@ profile-check: @: DEFAULT_REFERENCES = -r:mscorlib.dll -PROFILE_MCS_FLAGS = -d:NET_1_1 -d:NET_2_0 -d:NET_2_1 -d:MOBILE -d:NET_3_5 -d:NET_4_0 -d:NET_4_5 -nowarn:1699 -nostdlib -lib:$(topdir)/class/lib/$(PROFILE) $(DEFAULT_REFERENCES) $(PLATFORM_DEBUG_FLAGS) + +PROFILE_MCS_FLAGS = \ + -d:NET_1_1 \ + -d:NET_2_0 \ + -d:NET_2_1 \ + -d:MOBILE \ + -d:MOBILE_DYNAMIC \ + -d:NET_3_5 \ + -d:NET_4_0 \ + -d:NET_4_5 \ + -nowarn:1699 \ + -nostdlib \ + -lib:$(topdir)/class/lib/$(PROFILE) \ + $(DEFAULT_REFERENCES) \ + $(PLATFORM_DEBUG_FLAGS) + FRAMEWORK_VERSION = 2.1 NO_INSTALL = yes diff --git a/mcs/build/profiles/mobile_static.make b/mcs/build/profiles/mobile_static.make index 59505666ad7..b7898235194 100644 --- a/mcs/build/profiles/mobile_static.make +++ b/mcs/build/profiles/mobile_static.make @@ -12,7 +12,24 @@ profile-check: @: DEFAULT_REFERENCES = -r:mscorlib.dll -PROFILE_MCS_FLAGS = -d:NET_1_1 -d:NET_2_0 -d:NET_2_1 -d:NET_3_5 -d:NET_4_0 -d:NET_4_5 -d:MOBILE -d:FULL_AOT_RUNTIME -d:DISABLE_REMOTING -d:DISABLE_COM -nowarn:1699 -nostdlib -lib:$(topdir)/class/lib/$(PROFILE) $(DEFAULT_REFERENCES) $(PLATFORM_DEBUG_FLAGS) + +PROFILE_MCS_FLAGS = \ + -d:NET_1_1 \ + -d:NET_2_0 \ + -d:NET_2_1 \ + -d:NET_3_5 \ + -d:NET_4_0 \ + -d:NET_4_5 \ + -d:MOBILE \ + -d:FULL_AOT_RUNTIME \ + -d:DISABLE_REMOTING \ + -d:DISABLE_COM \ + -nowarn:1699 \ + -nostdlib \ + -lib:$(topdir)/class/lib/$(PROFILE) \ + $(DEFAULT_REFERENCES) \ + $(PLATFORM_DEBUG_FLAGS) + FRAMEWORK_VERSION = 2.1 NO_TEST = yes diff --git a/mcs/build/profiles/monodroid.make b/mcs/build/profiles/monodroid.make index 7336ced7b7b..c14f61c6087 100644 --- a/mcs/build/profiles/monodroid.make +++ b/mcs/build/profiles/monodroid.make @@ -12,7 +12,24 @@ profile-check: @: DEFAULT_REFERENCES = -r:mscorlib.dll -PROFILE_MCS_FLAGS = -d:NET_1_1 -d:NET_2_0 -d:NET_2_1 -d:NET_3_5 -d:NET_4_0 -d:NET_4_5 -d:MOBILE -d:MOBILE_DYNAMIC -d:MONODROID -nowarn:1699 -nostdlib -lib:$(topdir)/class/lib/$(PROFILE) $(DEFAULT_REFERENCES) $(PLATFORM_DEBUG_FLAGS) + +PROFILE_MCS_FLAGS = \ + -d:NET_1_1 \ + -d:NET_2_0 \ + -d:NET_2_1 \ + -d:NET_3_5 \ + -d:NET_4_0 \ + -d:NET_4_5 \ + -d:MOBILE \ + -d:MOBILE_DYNAMIC \ + -d:MONODROID \ + -d:ANDROID \ + -nowarn:1699 \ + -nostdlib \ + -lib:$(topdir)/class/lib/$(PROFILE) \ + $(DEFAULT_REFERENCES) \ + $(PLATFORM_DEBUG_FLAGS) + FRAMEWORK_VERSION = 2.1 NO_TEST = yes diff --git a/mcs/build/profiles/monotouch.make b/mcs/build/profiles/monotouch.make index b841a1027ae..706463d748c 100644 --- a/mcs/build/profiles/monotouch.make +++ b/mcs/build/profiles/monotouch.make @@ -12,9 +12,27 @@ profile-check: @: DEFAULT_REFERENCES = -r:mscorlib.dll -PROFILE_MCS_FLAGS = -d:NET_1_1 -d:NET_2_0 -d:NET_2_1 -d:NET_3_5 -d:NET_4_0 -d:NET_4_5 -d:MOBILE -d:MONOTOUCH -d:DISABLE_REMOTING -d:DISABLE_COM -d:FULL_AOT_RUNTIME -nowarn:1699 -nostdlib -lib:$(topdir)/class/lib/$(PROFILE) $(DEFAULT_REFERENCES) $(PLATFORM_DEBUG_FLAGS) + +PROFILE_MCS_FLAGS = \ + -d:NET_1_1 \ + -d:NET_2_0 \ + -d:NET_2_1 \ + -d:NET_3_5 \ + -d:NET_4_0 \ + -d:NET_4_5 \ + -d:MOBILE \ + -d:MONOTOUCH \ + -d:DISABLE_REMOTING \ + -d:DISABLE_COM \ + -d:FULL_AOT_RUNTIME \ + -nowarn:1699 \ + -nostdlib \ + -lib:$(topdir)/class/lib/$(PROFILE) \ + $(DEFAULT_REFERENCES) \ + $(PLATFORM_DEBUG_FLAGS) + FRAMEWORK_VERSION = 2.1 NO_TEST = yes # the tuner takes care of the install -NO_INSTALL = yes \ No newline at end of file +NO_INSTALL = yes diff --git a/mcs/class/Commons.Xml.Relaxng/Commons.Xml.Relaxng.Rnc/RncParser.jay b/mcs/class/Commons.Xml.Relaxng/Commons.Xml.Relaxng.Rnc/RncParser.jay index df3157f022a..625df5ca152 100644 --- a/mcs/class/Commons.Xml.Relaxng/Commons.Xml.Relaxng.Rnc/RncParser.jay +++ b/mcs/class/Commons.Xml.Relaxng/Commons.Xml.Relaxng.Rnc/RncParser.jay @@ -107,7 +107,7 @@ namespace Commons.Xml.Relaxng.Rnc 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 { diff --git a/mcs/class/Commons.Xml.Relaxng/Test/NvdlValidatingReaderTests.cs b/mcs/class/Commons.Xml.Relaxng/Test/NvdlValidatingReaderTests.cs index e7d600c5ea0..8f0ae73cf6d 100644 --- a/mcs/class/Commons.Xml.Relaxng/Test/NvdlValidatingReaderTests.cs +++ b/mcs/class/Commons.Xml.Relaxng/Test/NvdlValidatingReaderTests.cs @@ -13,7 +13,7 @@ using Commons.Xml.Nvdl; using NUnit.Framework; -namespace MonoTests.Commons.Xml.Nvdl +namespace MonoTests.Commons.Xml.Relaxng { [TestFixture] public class NvdlValidatingReaderTests diff --git a/mcs/class/Commons.Xml.Relaxng/Test/RncTests.cs b/mcs/class/Commons.Xml.Relaxng/Test/RncTests.cs index d25fcb1e1c7..fb7ac65e9c7 100644 --- a/mcs/class/Commons.Xml.Relaxng/Test/RncTests.cs +++ b/mcs/class/Commons.Xml.Relaxng/Test/RncTests.cs @@ -95,5 +95,19 @@ public void InheritDefaultNamespace () r.Close (); } } + + [Test] + public void SimpleDefaultNamespace () + { + var g = RncParser.ParseRnc (new StringReader ("element e { empty }")); + var x = XmlReader.Create (new StringReader ("")); + var r = new RelaxngValidatingReader (x, g); + try { + while (!r.EOF) + r.Read (); + } finally { + r.Close (); + } + } } } diff --git a/mcs/class/Commons.Xml.Relaxng/Test/standalone_tests/Makefile b/mcs/class/Commons.Xml.Relaxng/Test/standalone_tests/Makefile index 6653702d556..9be0e7ff400 100644 --- a/mcs/class/Commons.Xml.Relaxng/Test/standalone_tests/Makefile +++ b/mcs/class/Commons.Xml.Relaxng/Test/standalone_tests/Makefile @@ -8,7 +8,7 @@ TEST_ARCHIVE = testSuite.zip 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 diff --git a/mcs/class/Facades/System.Runtime.InteropServices/TypeForwarders.cs b/mcs/class/Facades/System.Runtime.InteropServices/TypeForwarders.cs index 060d9292265..3fb4b16a435 100644 --- a/mcs/class/Facades/System.Runtime.InteropServices/TypeForwarders.cs +++ b/mcs/class/Facades/System.Runtime.InteropServices/TypeForwarders.cs @@ -40,6 +40,7 @@ [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.InteropServices.COMException))] [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.InteropServices.ComMemberType))] [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.InteropServices.ComSourceInterfacesAttribute))] +[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.InteropServices.ComInterfaceType))] [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.InteropServices.ComTypes.IStream))] [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.InteropServices.ComTypes.STATSTG))] [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.InteropServices.CriticalHandle))] diff --git a/mcs/class/Makefile b/mcs/class/Makefile index 7ee9b1e7c00..de9656dd705 100644 --- a/mcs/class/Makefile +++ b/mcs/class/Makefile @@ -33,6 +33,7 @@ net_2_0_dirs := \ System.EnterpriseServices \ Mono.Data.Tds \ System.Data \ + System.ComponentModel.DataAnnotations \ Accessibility \ Mono.WebBrowser \ System.Runtime.Serialization.Formatters.Soap \ @@ -81,7 +82,6 @@ net_2_0_dirs := \ System.ServiceModel \ System.Web.Extensions \ System.Web.Extensions.Design \ - System.ComponentModel.DataAnnotations \ System.Web.DynamicData \ System.Web.Mvc2 \ Mono.C5 \ @@ -106,7 +106,7 @@ net_2_0_only_dirs := \ pcl_facade_dirs := Facades -mobile_dirs := \ +mobile_common_dirs := \ corlib \ System \ System.Core \ @@ -134,19 +134,27 @@ mobile_dirs := \ System.Net \ System.Windows \ System.Xml.Serialization \ + Mono.CSharp \ + Microsoft.CSharp \ $(pcl_facade_dirs) -monodroid_dirs := \ +mobile_static_dirs := \ + $(mobile_common_dirs) \ + Mono.Dynamic.Interpreter + +mobile_dynamic_dirs := \ + $(mobile_common_dirs) \ Mono.CompilerServices.SymbolWriter \ - Mono.CSharp \ - Microsoft.CSharp \ System.Net.Http xammac_dirs := \ - Mono.CompilerServices.SymbolWriter \ - Mono.CSharp \ - Microsoft.CSharp \ - System.Net.Http + $(mobile_dynamic_dirs) + +monodroid_dirs := \ + $(mobile_dynamic_dirs) + +monotouch_dirs := \ + $(mobile_static_dirs) monotouch_runtime_dirs := \ corlib \ @@ -155,11 +163,6 @@ monotouch_runtime_dirs := \ System.XML \ Mono.CSharp -monotouch_dirs := \ - Mono.CSharp \ - Microsoft.CSharp \ - Mono.Dynamic.Interpreter - net_4_0_dirs := \ System.Numerics \ Microsoft.CSharp \ @@ -235,12 +238,12 @@ xbuild_4_0_dirs := \ Microsoft.Build net_2_0_SUBDIRS := $(net_2_0_dirs) $(net_2_0_only_dirs) $(xbuild_2_0_dirs) aot-compiler -monodroid_SUBDIRS := $(mobile_dirs) $(monodroid_dirs) -monotouch_SUBDIRS := $(mobile_dirs) $(monotouch_dirs) +monodroid_SUBDIRS := $(monodroid_dirs) +monotouch_SUBDIRS := $(monotouch_dirs) monotouch_runtime_SUBDIRS := $(monotouch_runtime_dirs) -mobile_static_SUBDIRS := $(mobile_dirs) -mobile_SUBDIRS := $(mobile_dirs) -xammac_SUBDIRS := $(mobile_dirs) $(xammac_dirs) +mobile_static_SUBDIRS := $(mobile_static_dirs) +mobile_SUBDIRS := $(mobile_dynamic_dirs) +xammac_SUBDIRS := $(xammac_dirs) net_3_5_SUBDIRS := $(xbuild_2_0_dirs) net_4_0_SUBDIRS := $(net_2_0_dirs) $(net_4_0_dirs) $(net_4_0_only_dirs) $(xbuild_4_0_dirs) net_4_5_SUBDIRS := $(net_2_0_dirs) $(net_4_0_dirs) $(net_4_5_dirs) $(xbuild_4_0_dirs) aot-compiler @@ -248,7 +251,7 @@ xbuild_12_SUBDIRS := $(xbuild_4_0_dirs) include ../build/rules.make -SUBDIRS = $(net_2_0_dirs) $(net_2_0_only_dirs) $(mobile_dirs) $(monotouch_dirs) $(net_4_0_dirs) $(net_4_0_only_dirs) $(net_4_5_dirs) +SUBDIRS = $(net_2_0_dirs) $(net_2_0_only_dirs) $(mobile_static_dirs) $(mobile_dynamic_dirs) $(monotouch_dirs) $(monodroid_dirs) $(xammac_dirs) $(net_4_0_dirs) $(net_4_0_only_dirs) $(net_4_5_dirs) DIST_ONLY_SUBDIRS = dlr aot-compiler $(xbuild_4_0_dirs) diff --git a/mcs/class/Managed.Windows.Forms/System.Windows.Forms/Button.cs b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/Button.cs index dc640e836cd..e04f3997168 100644 --- a/mcs/class/Managed.Windows.Forms/System.Windows.Forms/Button.cs +++ b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/Button.cs @@ -175,7 +175,7 @@ internal override void Draw (PaintEventArgs pevent) 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) diff --git a/mcs/class/Managed.Windows.Forms/System.Windows.Forms/TextRenderer.cs b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/TextRenderer.cs index 6f3be9db10b..b82629a0483 100644 --- a/mcs/class/Managed.Windows.Forms/System.Windows.Forms/TextRenderer.cs +++ b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/TextRenderer.cs @@ -258,11 +258,19 @@ internal static Size MeasureTextInternal (IDeviceContext dc, string text, Font f 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; @@ -484,9 +492,6 @@ private static Rectangle PadDrawStringRectangle (Rectangle r, TextFormatFlags fl r.X += 2; r.Width -= 2; } - if ((flags & TextFormatFlags.WordEllipsis) == TextFormatFlags.WordEllipsis || (flags & TextFormatFlags.EndEllipsis) == TextFormatFlags.EndEllipsis || (flags & TextFormatFlags.WordBreak) == TextFormatFlags.WordBreak) { - r.Width -= 4; - } if ((flags & TextFormatFlags.VerticalCenter) == TextFormatFlags.VerticalCenter && XplatUI.RunningOnUnix) { r.Y -= 1; } diff --git a/mcs/class/Managed.Windows.Forms/System.Windows.Forms/Theme.cs b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/Theme.cs index 18ee3dd8117..b8cc63b7e81 100644 --- a/mcs/class/Managed.Windows.Forms/System.Windows.Forms/Theme.cs +++ b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/Theme.cs @@ -698,7 +698,7 @@ public virtual Image Images(string mimetype, string extension, int size) { #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); diff --git a/mcs/class/Managed.Windows.Forms/System.Windows.Forms/ThemeWin32Classic.cs b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/ThemeWin32Classic.cs index 522dec40ec6..d6214c5e93b 100644 --- a/mcs/class/Managed.Windows.Forms/System.Windows.Forms/ThemeWin32Classic.cs +++ b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/ThemeWin32Classic.cs @@ -364,28 +364,29 @@ public override Size CalculateButtonAutoSize (Button button) 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; + bool displayEllipsis = (button.TextFormatFlags & (TextFormatFlags.EndEllipsis | TextFormatFlags.PathEllipsis | TextFormatFlags.WordEllipsis)) != 0; + 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); - // Image is dependent on ImageAlign - if (image == null) + if (image == null) { + if (button.Pressed) + textRectangle.Offset (1, 1); return; + } int image_x = 0; int image_y = 0; @@ -438,22 +439,20 @@ public override void CalculateButtonTextAndImageLayout (ButtonBase button, out R 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, displayEllipsis, 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, displayEllipsis, 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; } + if (button.Pressed) + textRectangle.Offset (1, 1); } private void LayoutTextBeforeOrAfterImage (Rectangle totalArea, bool textFirst, Size textSize, Size imageSize, System.Drawing.ContentAlignment textAlign, System.Drawing.ContentAlignment imageAlign, out Rectangle textRect, out Rectangle imageRect) @@ -501,7 +500,7 @@ private void LayoutTextBeforeOrAfterImage (Rectangle totalArea, bool textFirst, imageRect = final_image_rect; } - private void LayoutTextAboveOrBelowImage (Rectangle totalArea, bool textFirst, Size textSize, Size imageSize, System.Drawing.ContentAlignment textAlign, System.Drawing.ContentAlignment imageAlign, out Rectangle textRect, out Rectangle imageRect) + private void LayoutTextAboveOrBelowImage (Rectangle totalArea, bool textFirst, Size textSize, Size imageSize, System.Drawing.ContentAlignment textAlign, System.Drawing.ContentAlignment imageAlign, bool displayEllipsis, out Rectangle textRect, out Rectangle imageRect) { int element_spacing = 0; // Spacing between the Text and the Image int total_height = textSize.Height + element_spacing + imageSize.Height; @@ -537,17 +536,25 @@ private void LayoutTextAboveOrBelowImage (Rectangle totalArea, bool textFirst, S 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; } + if (displayEllipsis) { + // Don't use more space than is available otherwise ellipsis won't show + if (final_text_rect.Height > totalArea.Bottom) + final_text_rect.Height = totalArea.Bottom - final_text_rect.Top; + } + textRect = final_text_rect; imageRect = final_image_rect; } @@ -1095,11 +1102,11 @@ public override void CalculateCheckBoxTextAndImageLayout (ButtonBase button, Poi 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 (content_rect, false, text_size, image_size, button.TextAlign, button.ImageAlign, false, 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 (content_rect, true, text_size, image_size, button.TextAlign, button.ImageAlign, false, out textRectangle, out imageRectangle); break; case TextImageRelation.ImageBeforeText: content_rect.Inflate (-4, -4); diff --git a/mcs/class/Managed.Windows.Forms/System.Windows.Forms/XplatUIX11.cs b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/XplatUIX11.cs index 1f3af258464..657a42457c9 100644 --- a/mcs/class/Managed.Windows.Forms/System.Windows.Forms/XplatUIX11.cs +++ b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/XplatUIX11.cs @@ -1296,7 +1296,7 @@ void TranslatePropertyToClipboard(IntPtr property) { 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 ())) { diff --git a/mcs/class/Microsoft.Build.Engine/Microsoft.Build.BuildEngine/ConsoleLogger.cs b/mcs/class/Microsoft.Build.Engine/Microsoft.Build.BuildEngine/ConsoleLogger.cs index 5fb7d21899c..0d776b9fbb2 100644 --- a/mcs/class/Microsoft.Build.Engine/Microsoft.Build.BuildEngine/ConsoleLogger.cs +++ b/mcs/class/Microsoft.Build.Engine/Microsoft.Build.BuildEngine/ConsoleLogger.cs @@ -1018,13 +1018,27 @@ public void ExecuteFinishedHandler (BuildStatusEventArgs finished_args) if (!StartHandlerHasExecuted) return; - if (EventArgs is ProjectStartedEventArgs) - ConsoleLogger.ProjectFinishedHandler (Sender, finished_args as ProjectFinishedEventArgs); - else if (EventArgs is TargetStartedEventArgs) - ConsoleLogger.TargetFinishedHandler (Sender, finished_args as TargetFinishedEventArgs); - else if (EventArgs is TaskStartedEventArgs) - ConsoleLogger.TaskFinishedHandler (Sender, finished_args as TaskFinishedEventArgs); - else if (!(EventArgs is BuildStartedEventArgs)) + if (EventArgs is ProjectStartedEventArgs) { + var pfa = finished_args as ProjectFinishedEventArgs; + // FIXME: BuildFinishedHandlerActual sends us BuildFinishedEventArgs via PopEvent + if (pfa == null) + return; + + ConsoleLogger.ProjectFinishedHandler (Sender, pfa); + } else if (EventArgs is TargetStartedEventArgs) { + var fa = finished_args as TargetFinishedEventArgs; + // FIXME: BuildFinishedHandlerActual sends us BuildFinishedEventArgs via PopEvent + if (fa == null) + return; + + ConsoleLogger.TargetFinishedHandler (Sender, fa); + } else if (EventArgs is TaskStartedEventArgs) { + // FIXME: BuildFinishedHandlerActual sends us BuildFinishedEventArgs via PopEvent + if (!(finished_args is TaskFinishedEventArgs)) + return; + + ConsoleLogger.TaskFinishedHandler (Sender, (TaskFinishedEventArgs) finished_args); + } else if (!(EventArgs is BuildStartedEventArgs)) throw new InvalidOperationException ("Unexpected event on the stack, type: " + EventArgs.GetType ()); } } diff --git a/mcs/class/Microsoft.Build.Engine/Microsoft.Build.BuildEngine/TargetBatchingImpl.cs b/mcs/class/Microsoft.Build.Engine/Microsoft.Build.BuildEngine/TargetBatchingImpl.cs index 76284d1660e..8597b026b34 100644 --- a/mcs/class/Microsoft.Build.Engine/Microsoft.Build.BuildEngine/TargetBatchingImpl.cs +++ b/mcs/class/Microsoft.Build.Engine/Microsoft.Build.BuildEngine/TargetBatchingImpl.cs @@ -99,8 +99,12 @@ bool RunTargetWithBucket (Dictionary bucket, Target targ try { TaskExecutionMode taskExecutionMode; string reason; - if (!BuildTargetNeeded (out reason)) { + bool skip_completely; + if (!BuildTargetNeeded (out reason, out skip_completely)) { LogTargetSkipped (target, reason); + if (skip_completely) + return true; + taskExecutionMode = TaskExecutionMode.SkipAndSetOutput; } else { taskExecutionMode = TaskExecutionMode.Complete; @@ -113,8 +117,27 @@ bool RunTargetWithBucket (Dictionary bucket, Target targ //FIXME: parsing attributes repeatedly IBuildTask bt = target.BuildTasks [i]; + // HACK: need some form of cross references checks + var tem = taskExecutionMode; + if (tem == TaskExecutionMode.SkipAndSetOutput) { + var bti = bt as BuildTask; + + // + // BuildTargetNeeded checks only files timestamps but ignores any metadata dependencies + // that way we can end up in the situation when output metadata are populated but from + // incomplete dependencies. + // + // E.g. + // + // + // + // + if (bti != null && bti.Name == "CreateItem") + tem = TaskExecutionMode.Complete; + } + TaskBatchingImpl batchingImpl = new TaskBatchingImpl (project); - bool task_result = batchingImpl.Build (bt, taskExecutionMode, out executeOnErrors); + bool task_result = batchingImpl.Build (bt, tem, out executeOnErrors); if (task_result) continue; @@ -149,15 +172,17 @@ void ParseTargetAttributes (Target target) ParseAttribute (outputs); } - bool BuildTargetNeeded (out string reason) + bool BuildTargetNeeded (out string reason, out bool skipCompletely) { reason = String.Empty; ITaskItem [] inputFiles; ITaskItem [] outputFiles; DateTime youngestInput, oldestOutput; + skipCompletely = false; - if (String.IsNullOrEmpty (inputs.Trim ())) + if (String.IsNullOrEmpty (inputs.Trim ())) { return true; + } if (String.IsNullOrEmpty (outputs.Trim ())) { project.ParentEngine.LogError ("Target {0} has inputs but no outputs specified.", name); @@ -178,6 +203,7 @@ bool BuildTargetNeeded (out string reason) } if (inputFiles == null || inputFiles.Length == 0) { + skipCompletely = true; reason = String.Format ("No input files were specified for target {0}, skipping.", name); return false; } diff --git a/mcs/class/Microsoft.Build.Engine/Microsoft.Build.Engine-net_4_5.csproj b/mcs/class/Microsoft.Build.Engine/Microsoft.Build.Engine-net_4_5.csproj index df6603cfa85..2c42dc4da76 100644 --- a/mcs/class/Microsoft.Build.Engine/Microsoft.Build.Engine-net_4_5.csproj +++ b/mcs/class/Microsoft.Build.Engine/Microsoft.Build.Engine-net_4_5.csproj @@ -112,6 +112,7 @@ + diff --git a/mcs/class/Microsoft.Build.Utilities/Microsoft.Build.Utilities/ToolTask.cs b/mcs/class/Microsoft.Build.Utilities/Microsoft.Build.Utilities/ToolTask.cs index ded4b425c6c..572c75c1bfa 100644 --- a/mcs/class/Microsoft.Build.Utilities/Microsoft.Build.Utilities/ToolTask.cs +++ b/mcs/class/Microsoft.Build.Utilities/Microsoft.Build.Utilities/ToolTask.cs @@ -1,12 +1,14 @@ // // ToolTask.cs: Base class for command line tool tasks. // -// Author: +// Authors: // Marek Sieradzki (marek.sieradzki@gmail.com) // Ankit Jain (jankit@novell.com) +// Marek Safar (marek.safar@gmail.com) // // (C) 2005 Marek Sieradzki // Copyright 2009 Novell, Inc (http://www.novell.com) +// Copyright 2014 Xamarin Inc // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -90,12 +92,45 @@ protected virtual bool CallHostObjectToExecute () return true; } + string CreateToolPath () + { + string tp; + if (string.IsNullOrEmpty (ToolPath)) { + tp = GenerateFullPathToTool (); + if (string.IsNullOrEmpty (tp)) + return null; + + // + // GenerateFullPathToTool can return path including tool name + // + if (string.IsNullOrEmpty (ToolExe)) + return tp; + + tp = Path.GetDirectoryName (tp); + } else { + tp = ToolPath; + } + + var path = Path.Combine (tp, ToolExe); + if (!File.Exists (path)) { + if (Log != null) + Log.LogError ("Tool executable '{0}' could not be found", path); + return null; + } + + return path; + } + public override bool Execute () { if (SkipTaskExecution ()) return true; - exitCode = ExecuteTool (GenerateFullPathToTool (), GenerateResponseFileCommands (), + var tool_path = CreateToolPath (); + if (tool_path == null) + return false; + + exitCode = ExecuteTool (tool_path, GenerateResponseFileCommands (), GenerateCommandLineCommands ()); // HandleTaskExecutionErrors is called only if exitCode != 0 @@ -289,14 +324,14 @@ protected virtual void LogEventsFromTextOutput (string singleLine, MessageImport protected virtual string GenerateCommandLineCommands () { - return null; + return ""; } protected abstract string GenerateFullPathToTool (); protected virtual string GenerateResponseFileCommands () { - return null; + return ""; } protected virtual string GetResponseFileSwitch (string responseFilePath) diff --git a/mcs/class/Microsoft.Build.Utilities/Test/Microsoft.Build.Utilities/ToolTaskTest.cs b/mcs/class/Microsoft.Build.Utilities/Test/Microsoft.Build.Utilities/ToolTaskTest.cs index ec1e34768b3..7c2a3843b62 100644 --- a/mcs/class/Microsoft.Build.Utilities/Test/Microsoft.Build.Utilities/ToolTaskTest.cs +++ b/mcs/class/Microsoft.Build.Utilities/Test/Microsoft.Build.Utilities/ToolTaskTest.cs @@ -26,6 +26,7 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. using System; +using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; @@ -424,6 +425,53 @@ public void ToolExeAndPath () Assert.AreEqual (a.ToolPath, "Bar", "#5"); a.ToolPath = ""; Assert.AreEqual (a.ToolPath, "", "#6"); + + a.Execute (); + } + + [Test] + public void Execute_1 () + { + var t = new TestExecuteToolTask (); + t.OnExecuteTool = delegate { Assert.Fail ("#1"); }; + t.BuildEngine = new MockBuildEngine (); + Assert.IsFalse (t.Execute (), "result"); + } + + [Test] + public void Execute_2 () + { + var t = new TestExecuteToolTask (); + t.BuildEngine = new MockBuildEngine (); + t.ToolPath = Directory.GetCurrentDirectory (); + t.ToolExe = "Makefile"; + + t.OnExecuteTool = (pathToTool, responseFileCommands, commandLineCommands) => { + Assert.AreEqual (Path.Combine (Directory.GetCurrentDirectory (), "Makefile"), pathToTool, "#1"); + Assert.AreEqual ("", responseFileCommands, "#2"); + Assert.AreEqual ("", commandLineCommands, "#3"); + + }; + + Assert.IsTrue (t.Execute (), "result"); + } + + [Test] + public void Execute_3 () + { + var t = new TestExecuteToolTask (); + t.FullPathToTool = "fpt"; + t.BuildEngine = new MockBuildEngine (); + t.ToolExe = "Makefile.mk"; + + t.OnExecuteTool = (pathToTool, responseFileCommands, commandLineCommands) => { + Assert.AreEqual ("Makefile.mk", pathToTool, "#1"); + Assert.AreEqual ("", responseFileCommands, "#2"); + Assert.AreEqual ("", commandLineCommands, "#3"); + + }; + + Assert.IsFalse (t.Execute (), "result"); } } @@ -548,9 +596,86 @@ protected override string ToolName { } protected override string GenerateFullPathToTool () + { + return ""; + } + } + + class MockBuildEngine : IBuildEngine + { + public int ColumnNumberOfTaskNode { + get { + return 0; + } + } + + public bool ContinueOnError { + get { + throw new NotImplementedException (); + } + } + + public int LineNumberOfTaskNode { + get { + return 0; + } + } + + public string ProjectFileOfTaskNode { + get { + return "ProjectFileOfTaskNode"; + } + } + + public bool BuildProjectFile (string projectFileName, string[] targetNames, IDictionary globalProperties, IDictionary targetOutputs) { throw new NotImplementedException (); } + + public void LogCustomEvent (CustomBuildEventArgs e) + { + } + + public void LogErrorEvent (BuildErrorEventArgs e) + { + Console.WriteLine (e.Message); + } + + public void LogMessageEvent (BuildMessageEventArgs e) + { + } + + public void LogWarningEvent (BuildWarningEventArgs e) + { + } + } + + class TestExecuteToolTask : ToolTask + { + public Action OnExecuteTool; + public string FullPathToTool; + + protected override string ToolName { + get { return "TestTool.exe"; } + } + + protected override bool CallHostObjectToExecute () + { + return base.CallHostObjectToExecute (); + } + + protected override string GenerateFullPathToTool () + { + return FullPathToTool; + } + + protected override int ExecuteTool (string pathToTool, string responseFileCommands, string commandLineCommands) + { + if (OnExecuteTool != null) + OnExecuteTool (pathToTool, responseFileCommands, commandLineCommands); + + return 0; + } } } diff --git a/mcs/class/Mono.CSharp/Makefile b/mcs/class/Mono.CSharp/Makefile index 85b86e0f466..35ee0a302bc 100644 --- a/mcs/class/Mono.CSharp/Makefile +++ b/mcs/class/Mono.CSharp/Makefile @@ -6,7 +6,9 @@ LIBRARY = Mono.CSharp.dll LIB_MCS_FLAGS = -r:System.Core.dll -r:System.Xml.dll -r:System.dll -ifeq (monotouch, $(PROFILE)) +MOBILE_STATIC := $(filter mobile_static monotouch, $(PROFILE)) + +ifdef MOBILE_STATIC LIB_MCS_FLAGS += -d:IOS_REFLECTION endif diff --git a/mcs/class/Mono.CSharp/Test/Evaluator/TypesTest.cs b/mcs/class/Mono.CSharp/Test/Evaluator/TypesTest.cs index 970aa33443d..c124ad3739f 100644 --- a/mcs/class/Mono.CSharp/Test/Evaluator/TypesTest.cs +++ b/mcs/class/Mono.CSharp/Test/Evaluator/TypesTest.cs @@ -104,7 +104,15 @@ public void NestedType () { Evaluator.Run ("class A { class B { } }"); Evaluator.Run ("var x = new A ();"); + } + [Test] + public void DelegateType () + { + Evaluator.Run ("public delegate int D();"); + Evaluator.Run ("D d = delegate () { return 7; };"); + object res = Evaluator.Evaluate ("d();"); + Assert.AreEqual (7, res); } } } \ No newline at end of file diff --git a/mcs/class/Mono.CSharp/mobile_static_Mono.CSharp.dll.sources b/mcs/class/Mono.CSharp/mobile_static_Mono.CSharp.dll.sources new file mode 100644 index 00000000000..6e4c34213be --- /dev/null +++ b/mcs/class/Mono.CSharp/mobile_static_Mono.CSharp.dll.sources @@ -0,0 +1,13 @@ +#include Mono.CSharp.dll.sources +../corlib/System.Reflection.Emit/AssemblyBuilderAccess.cs +../corlib/System.Reflection.Emit/FlowControl.cs +../corlib/System.Reflection.Emit/OpCode.cs +../corlib/System.Reflection.Emit/OpCodeNames.cs +../corlib/System.Reflection.Emit/OpCodes.cs +../corlib/System.Reflection.Emit/OpCodeType.cs +../corlib/System.Reflection.Emit/OperandType.cs +../corlib/System.Reflection.Emit/PEFileKinds.cs +../corlib/System.Reflection.Emit/Label.cs +../corlib/System.Reflection.Emit/MethodToken.cs +../corlib/System.Reflection.Emit/StackBehaviour.cs +monotouch.cs \ No newline at end of file diff --git a/mcs/class/Mono.CSharp/monotouch_Mono.CSharp.dll.sources b/mcs/class/Mono.CSharp/monotouch_Mono.CSharp.dll.sources index 6e4c34213be..6a71501e34c 100644 --- a/mcs/class/Mono.CSharp/monotouch_Mono.CSharp.dll.sources +++ b/mcs/class/Mono.CSharp/monotouch_Mono.CSharp.dll.sources @@ -1,13 +1,2 @@ -#include Mono.CSharp.dll.sources -../corlib/System.Reflection.Emit/AssemblyBuilderAccess.cs -../corlib/System.Reflection.Emit/FlowControl.cs -../corlib/System.Reflection.Emit/OpCode.cs -../corlib/System.Reflection.Emit/OpCodeNames.cs -../corlib/System.Reflection.Emit/OpCodes.cs -../corlib/System.Reflection.Emit/OpCodeType.cs -../corlib/System.Reflection.Emit/OperandType.cs -../corlib/System.Reflection.Emit/PEFileKinds.cs -../corlib/System.Reflection.Emit/Label.cs -../corlib/System.Reflection.Emit/MethodToken.cs -../corlib/System.Reflection.Emit/StackBehaviour.cs -monotouch.cs \ No newline at end of file +#include mobile_static_Mono.CSharp.dll.sources +monotouch.cs diff --git a/mcs/class/Mono.Cecil/Makefile b/mcs/class/Mono.Cecil/Makefile index d9643b7f5a9..37d7fb0f56d 100644 --- a/mcs/class/Mono.Cecil/Makefile +++ b/mcs/class/Mono.Cecil/Makefile @@ -9,8 +9,4 @@ LIB_MCS_FLAGS = /r:$(corlib) -keyfile:$(LIBRARY_SNK) -r:System.Core.dll -d:NET_3 NO_TEST = yes -ifneq (net_2_0, $(PROFILE)) -NO_INSTALL = yes -endif - include ../../build/library.make diff --git a/mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/Tds.cs b/mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/Tds.cs index 6865df9adbe..f06932c8026 100644 --- a/mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/Tds.cs +++ b/mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/Tds.cs @@ -41,7 +41,9 @@ using System.Diagnostics; using System.Net.Sockets; using System.Globalization; +using System.Security; using System.Text; +using System.Runtime.InteropServices; namespace Mono.Data.Tds.Protocol { @@ -1468,7 +1470,7 @@ protected internal int ProcessAuthentication () t3.Domain = this.connectionParms.DefaultDomain; t3.Host = this.connectionParms.Hostname; t3.Username = this.connectionParms.User; - t3.Password = this.connectionParms.Password; + t3.Password = GetPlainPassword(this.connectionParms.Password); Comm.StartPacket (TdsPacketType.SspAuth); // 0x11 Comm.Append (t3.GetBytes ()); @@ -1919,6 +1921,20 @@ protected virtual void ProcessReturnStatus () comm.Skip(4); } + public static string GetPlainPassword(SecureString secPass) + { + IntPtr plainString = IntPtr.Zero; + try + { + plainString = Marshal.SecureStringToGlobalAllocUnicode(secPass); + return Marshal.PtrToStringUni(plainString); + } + finally + { + Marshal.ZeroFreeGlobalAllocUnicode(plainString); + } + } + #endregion // Private Methods #if NET_2_0 diff --git a/mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/Tds42.cs b/mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/Tds42.cs index fdca83087b1..fb517d013d5 100644 --- a/mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/Tds42.cs +++ b/mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/Tds42.cs @@ -29,6 +29,7 @@ // using System; +using System.Security; namespace Mono.Data.Tds.Protocol { public sealed class Tds42 : Tds @@ -77,7 +78,7 @@ public override bool Connect (TdsConnectionParameters connectionParameters) Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30)); // password (offset 62 0x3e) - tmp = Comm.Append (connectionParameters.Password, 30, pad); + tmp = Comm.Append (GetPlainPassword(connectionParameters.Password), 30, pad); Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30)); // hostproc (offset 93 0x5d) @@ -145,7 +146,7 @@ public override bool Connect (TdsConnectionParameters connectionParameters) // remote passwords Comm.Append (empty, 2, pad); - tmp = Comm.Append (connectionParameters.Password, 253, pad); + tmp = Comm.Append (GetPlainPassword(connectionParameters.Password), 253, pad); Comm.Append ((byte) (tmp.Length < 253 ? tmp.Length + 2 : 253 + 2)); // tds version diff --git a/mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/Tds50.cs b/mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/Tds50.cs index 0d0e86c023d..88219125df5 100644 --- a/mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/Tds50.cs +++ b/mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/Tds50.cs @@ -31,6 +31,7 @@ using Mono.Data.Tds; using System; using System.Text; +using System.Security; namespace Mono.Data.Tds.Protocol { @@ -118,7 +119,7 @@ public override bool Connect (TdsConnectionParameters connectionParameters) // password (offset 62 0x3e) // 62-92 - tmp = Comm.Append (connectionParameters.Password, 30, pad); + tmp = Comm.Append (GetPlainPassword(connectionParameters.Password), 30, pad); Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30)); // hostproc (offset 93 0x5d) @@ -187,7 +188,7 @@ public override bool Connect (TdsConnectionParameters connectionParameters) // remote passwords // 202-457 Comm.Append (empty, 2, pad); - tmp = Comm.Append (connectionParameters.Password, 253, pad); + tmp = Comm.Append (GetPlainPassword(connectionParameters.Password), 253, pad); Comm.Append ((byte) (tmp.Length < 253 ? tmp.Length + 2 : 253 + 2)); // tds version diff --git a/mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/Tds70.cs b/mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/Tds70.cs index c67b6e8c3bb..2f4fef03e19 100644 --- a/mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/Tds70.cs +++ b/mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/Tds70.cs @@ -37,6 +37,7 @@ using System; using System.Globalization; using System.Text; +using System.Security; using Mono.Security.Protocol.Ntlm; @@ -392,11 +393,12 @@ public override bool Connect (TdsConnectionParameters connectionParameters) return IsConnected; } - private static string EncryptPassword (string pass) + private static string EncryptPassword (SecureString secPass) { int xormask = 0x5a5a; - int len = pass.Length; + int len = secPass.Length; char[] chars = new char[len]; + string pass = GetPlainPassword(secPass); for (int i = 0; i < len; ++i) { int c = ((int) (pass[i])) ^ xormask; @@ -487,6 +489,19 @@ protected void ExecRPC (TdsRpcProcId rpcId, string sql, Comm.Append ((byte) 0x00); // no param meta data name Comm.Append ((byte) 0x00); // no status flags + + // Convert BigNVarChar values larger than 4000 chars to nvarchar(max) + // Need to do this here so WritePreparedParameterInfo emit the + // correct data type + foreach (TdsMetaParameter param2 in parameters) { + var colType = param2.GetMetaType (); + + if (colType == TdsColumnType.BigNVarChar) { + int size = param2.GetActualSize (); + if ((size >> 1) > 4000) + param2.Size = -1; + } + } // Write sql as a parameter value - UCS2 TdsMetaParameter param = new TdsMetaParameter ("sql", diff --git a/mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/TdsConnectionParameters.cs b/mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/TdsConnectionParameters.cs index 19f676077d7..e3b83aa257c 100644 --- a/mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/TdsConnectionParameters.cs +++ b/mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/TdsConnectionParameters.cs @@ -31,6 +31,7 @@ // using System; +using System.Security; namespace Mono.Data.Tds.Protocol { @@ -42,7 +43,8 @@ public class TdsConnectionParameters public string Hostname; public string Language; public string LibraryName; - public string Password; + public SecureString Password; + public bool PasswordSet; public string ProgName; public string User; public bool DomainLogin; @@ -62,7 +64,8 @@ public void Reset () Hostname = System.Net.Dns.GetHostName(); Language = String.Empty; LibraryName = "Mono"; - Password = String.Empty; + Password = new SecureString(); + PasswordSet = false; ProgName = "Mono"; User = String.Empty; DomainLogin = false; diff --git a/mcs/class/Mono.Data.Tds/Test/bug-4786.cs b/mcs/class/Mono.Data.Tds/Test/bug-4786.cs index e8436a7deca..91f8a06fc1a 100644 --- a/mcs/class/Mono.Data.Tds/Test/bug-4786.cs +++ b/mcs/class/Mono.Data.Tds/Test/bug-4786.cs @@ -27,11 +27,11 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -namespace bug4786test +namespace MonoTests.Mono.Data.Tds { using NUnit.Framework; - using Mono.Data.Tds.Protocol; + using global::Mono.Data.Tds.Protocol; using System; using System.Net; using System.Net.Sockets; diff --git a/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/Connection.cs b/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/Connection.cs index 14bf701f46f..a54315f175e 100644 --- a/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/Connection.cs +++ b/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/Connection.cs @@ -155,11 +155,12 @@ enum ValueTypeId { [Flags] enum InvokeFlags { - NONE = 0x0, - DISABLE_BREAKPOINTS = 0x1, - SINGLE_THREADED = 0x2, - OUT_THIS = 0x4, - OUT_ARGS = 0x8, + NONE = 0, + DISABLE_BREAKPOINTS = 1, + SINGLE_THREADED = 2, + OUT_THIS = 4, + OUT_ARGS = 8, + VIRTUAL = 16, } enum ElementType { @@ -416,7 +417,7 @@ public abstract class Connection * with newer runtimes, and vice versa. */ internal const int MAJOR_VERSION = 2; - internal const int MINOR_VERSION = 35; + internal const int MINOR_VERSION = 37; enum WPSuspendPolicy { NONE = 0, diff --git a/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/InvokeOptions.cs b/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/InvokeOptions.cs index 5ca987ec694..99dc87fa805 100644 --- a/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/InvokeOptions.cs +++ b/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/InvokeOptions.cs @@ -22,6 +22,11 @@ public enum InvokeOptions { /* * Return the values of out arguments */ - ReturnOutArgs = 8 + ReturnOutArgs = 8, + /* + * Do a virtual invoke + * Since protocol version 2.37 + */ + Virtual = 16 } } diff --git a/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/ObjectMirror.cs b/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/ObjectMirror.cs index d83e3a1a481..e65f62fc945 100644 --- a/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/ObjectMirror.cs +++ b/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/ObjectMirror.cs @@ -307,6 +307,8 @@ internal static IInvokeAsyncResult BeginInvokeMethod (VirtualMachine vm, ThreadM f |= InvokeFlags.OUT_THIS; if ((options & InvokeOptions.ReturnOutArgs) != 0) f |= InvokeFlags.OUT_ARGS; + if ((options & InvokeOptions.Virtual) != 0) + f |= InvokeFlags.VIRTUAL; InvokeAsyncResult r = new InvokeAsyncResult { AsyncState = state, AsyncWaitHandle = new ManualResetEvent (false), VM = vm, Thread = thread, Callback = callback }; thread.InvalidateFrames (); diff --git a/mcs/class/Mono.Debugger.Soft/Test/dtest-app.cs b/mcs/class/Mono.Debugger.Soft/Test/dtest-app.cs index 3c9b2877c21..f75951b8bc6 100644 --- a/mcs/class/Mono.Debugger.Soft/Test/dtest-app.cs +++ b/mcs/class/Mono.Debugger.Soft/Test/dtest-app.cs @@ -22,6 +22,10 @@ public class TestsBase static string base_static_s = "C"; #pragma warning restore 0414 #pragma warning restore 0169 + + public virtual string virtual_method () { + return "V1"; + } } public enum AnEnum { @@ -1365,6 +1369,10 @@ public static void set_ip () { j = 5; set_ip_2 (); } + + public override string virtual_method () { + return "V2"; + } } class TypeLoadClass { diff --git a/mcs/class/Mono.Debugger.Soft/Test/dtest.cs b/mcs/class/Mono.Debugger.Soft/Test/dtest.cs index 9a671202a82..df4fbcc6648 100644 --- a/mcs/class/Mono.Debugger.Soft/Test/dtest.cs +++ b/mcs/class/Mono.Debugger.Soft/Test/dtest.cs @@ -2137,6 +2137,11 @@ public void Invoke () { v = this_obj.InvokeMethod (e.Thread, m, null); AssertValue (42, v); + // virtual call + m = t.BaseType.GetMethod ("virtual_method"); + v = this_obj.InvokeMethod (e.Thread, m, null, InvokeOptions.Virtual); + AssertValue ("V2", v); + #if NET_4_5 // instance m = t.GetMethod ("invoke_pass_ref"); diff --git a/mcs/class/Mono.Dynamic.Interpreter/Makefile b/mcs/class/Mono.Dynamic.Interpreter/Makefile index 76777611827..bbb733bf693 100644 --- a/mcs/class/Mono.Dynamic.Interpreter/Makefile +++ b/mcs/class/Mono.Dynamic.Interpreter/Makefile @@ -9,7 +9,9 @@ LIB_MCS_FLAGS = -r:System.dll -r:System.Core.dll \ -d:MONO_INTERPRETER \ -delaysign -keyfile:../mono.pub -ifeq (monotouch, $(subst _runtime,,$(PROFILE))) +MOBILE_STATIC := $(filter mobile_static monotouch monotouch_runtime, $(PROFILE)) + +ifdef MOBILE_STATIC mono_dynamic_interpreter_deps = $(the_libdir_base)plaincore/System.Core.dll LIB_MCS_FLAGS += -lib:$(the_libdir_base)plaincore endif @@ -21,4 +23,4 @@ $(the_libdir_base)Mono.Dynamic.Interpreter.dll: $(mono_dynamic_interpreter_deps) $(the_libdir_base)plaincore/System.Core.dll: (cd ../System.Core; $(MAKE) $@) -.NOTPARALLEL: $(the_libdir_base)plaincore/System.Core.dll \ No newline at end of file +.NOTPARALLEL: $(the_libdir_base)plaincore/System.Core.dll diff --git a/mcs/class/Mono.Options/Test/Mono.Options/OptionContextTest.cs b/mcs/class/Mono.Options/Test/Mono.Options/OptionContextTest.cs index 8eb61b2c93b..ec3fb02270f 100644 --- a/mcs/class/Mono.Options/Test/Mono.Options/OptionContextTest.cs +++ b/mcs/class/Mono.Options/Test/Mono.Options/OptionContextTest.cs @@ -39,7 +39,7 @@ #if NDESK_OPTIONS namespace Tests.NDesk.Options #else -namespace Tests.Mono.Options +namespace MonoTests.Mono.Options #endif { [TestFixture] diff --git a/mcs/class/Mono.Options/Test/Mono.Options/OptionSetTest.cs b/mcs/class/Mono.Options/Test/Mono.Options/OptionSetTest.cs index 086c6d9c8c2..688297a0f68 100644 --- a/mcs/class/Mono.Options/Test/Mono.Options/OptionSetTest.cs +++ b/mcs/class/Mono.Options/Test/Mono.Options/OptionSetTest.cs @@ -46,7 +46,7 @@ #if NDESK_OPTIONS namespace Tests.NDesk.Options #else -namespace Tests.Mono.Options +namespace MonoTests.Mono.Options #endif { class FooConverter : TypeConverter { diff --git a/mcs/class/Mono.Options/Test/Mono.Options/OptionTest.cs b/mcs/class/Mono.Options/Test/Mono.Options/OptionTest.cs index 5242609162a..fad1b484784 100644 --- a/mcs/class/Mono.Options/Test/Mono.Options/OptionTest.cs +++ b/mcs/class/Mono.Options/Test/Mono.Options/OptionTest.cs @@ -39,7 +39,7 @@ #if NDESK_OPTIONS namespace Tests.NDesk.Options #else -namespace Tests.Mono.Options +namespace MonoTests.Mono.Options #endif { class DefaultOption : Option { diff --git a/mcs/class/Mono.Options/Test/Mono.Options/Utils.cs b/mcs/class/Mono.Options/Test/Mono.Options/Utils.cs index e5439aae4c3..074478e3e21 100644 --- a/mcs/class/Mono.Options/Test/Mono.Options/Utils.cs +++ b/mcs/class/Mono.Options/Test/Mono.Options/Utils.cs @@ -31,7 +31,7 @@ #if NDESK_OPTIONS namespace Tests.NDesk.Options #else -namespace Tests.Mono.Options +namespace MonoTests.Mono.Options #endif { static class Utils { diff --git a/mcs/class/Mono.Posix/Mono.Unix.Native/NativeConvert.cs b/mcs/class/Mono.Posix/Mono.Unix.Native/NativeConvert.cs index 7951d08ae17..ffa329f1b5b 100644 --- a/mcs/class/Mono.Posix/Mono.Unix.Native/NativeConvert.cs +++ b/mcs/class/Mono.Posix/Mono.Unix.Native/NativeConvert.cs @@ -195,6 +195,11 @@ public static DateTime ToDateTime (long time) return FromTimeT (time); } + public static DateTime ToDateTime (long time, long nanoTime) + { + return FromTimeT (time).AddMilliseconds (nanoTime / 1000); + } + public static long FromDateTime (DateTime time) { return ToTimeT (time); diff --git a/mcs/class/Mono.Posix/Mono.Unix/UnixFileSystemInfo.cs b/mcs/class/Mono.Posix/Mono.Unix/UnixFileSystemInfo.cs index c6a9b283b5f..149f79b84ed 100644 --- a/mcs/class/Mono.Posix/Mono.Unix/UnixFileSystemInfo.cs +++ b/mcs/class/Mono.Posix/Mono.Unix/UnixFileSystemInfo.cs @@ -192,7 +192,7 @@ public long BlocksAllocated { } public DateTime LastAccessTime { - get {AssertValid (); return Native.NativeConvert.ToDateTime (stat.st_atime);} + get {AssertValid (); return Native.NativeConvert.ToDateTime (stat.st_atime, stat.st_atime_nsec);} } public DateTime LastAccessTimeUtc { @@ -200,7 +200,7 @@ public DateTime LastAccessTimeUtc { } public DateTime LastWriteTime { - get {AssertValid (); return Native.NativeConvert.ToDateTime (stat.st_mtime);} + get {AssertValid (); return Native.NativeConvert.ToDateTime (stat.st_mtime, stat.st_mtime_nsec);} } public DateTime LastWriteTimeUtc { @@ -208,7 +208,7 @@ public DateTime LastWriteTimeUtc { } public DateTime LastStatusChangeTime { - get {AssertValid (); return Native.NativeConvert.ToDateTime (stat.st_ctime);} + get {AssertValid (); return Native.NativeConvert.ToDateTime (stat.st_ctime, stat.st_ctime_nsec);} } public DateTime LastStatusChangeTimeUtc { diff --git a/mcs/class/Mono.Security/Mono.Security.X509/X509Store.cs b/mcs/class/Mono.Security/Mono.Security.X509/X509Store.cs index c4bb4b99afc..d3671c0bf9f 100644 --- a/mcs/class/Mono.Security/Mono.Security.X509/X509Store.cs +++ b/mcs/class/Mono.Security/Mono.Security.X509/X509Store.cs @@ -97,10 +97,26 @@ public string Name { // methods public void Clear () + { + /* + * Both _certificates and _crls extend CollectionBase, whose Clear() method calls OnClear() and + * OnClearComplete(), which should be overridden in derivative classes. So we should not worry about + * other threads that might be holding references to _certificates or _crls. They should be smart enough + * to handle this gracefully. And if not, it's their own fault. + */ + ClearCertificates (); + ClearCrls (); + } + + void ClearCertificates() { if (_certificates != null) _certificates.Clear (); _certificates = null; + } + + void ClearCrls () + { if (_crls != null) _crls.Clear (); _crls = null; @@ -117,6 +133,7 @@ public void Import (X509Certificate certificate) fs.Write (data, 0, data.Length); fs.Close (); } + ClearCertificates (); // We have modified the store on disk. So forget the old state. } #if !NET_2_1 // Try to save privateKey if available.. @@ -141,6 +158,7 @@ public void Import (X509Crl crl) byte[] data = crl.RawData; fs.Write (data, 0, data.Length); } + ClearCrls (); // We have modified the store on disk. So forget the old state. } } @@ -149,6 +167,7 @@ public void Remove (X509Certificate certificate) string filename = Path.Combine (_storePath, GetUniqueName (certificate)); if (File.Exists (filename)) { File.Delete (filename); + ClearCertificates (); // We have modified the store on disk. So forget the old state. } } @@ -157,6 +176,7 @@ public void Remove (X509Crl crl) string filename = Path.Combine (_storePath, GetUniqueName (crl)); if (File.Exists (filename)) { File.Delete (filename); + ClearCrls (); // We have modified the store on disk. So forget the old state. } } @@ -236,8 +256,13 @@ private X509Certificate LoadCertificate (string filename) cspParams.Flags = CspProviderFlags.UseMachineKeyStore; KeyPairPersistence kpp = new KeyPairPersistence (cspParams); - if (!kpp.Load ()) + try { + if (!kpp.Load ()) + return cert; + } + catch { return cert; + } if (cert.RSA != null) cert.RSA = new RSACryptoServiceProvider (cspParams); diff --git a/mcs/class/System.ComponentModel.Composition.4.5/Makefile b/mcs/class/System.ComponentModel.Composition.4.5/Makefile index 4fe0fee915e..b71beeab45d 100644 --- a/mcs/class/System.ComponentModel.Composition.4.5/Makefile +++ b/mcs/class/System.ComponentModel.Composition.4.5/Makefile @@ -12,7 +12,7 @@ CLEAN_FILES += $(STRING_MESSAGES) EXTRA_DISTFILES = \ src/ComponentModel/Strings.resx -VALID_PROFILE := $(filter net_4_0 net_4_5 monotouch monodroid xammac mobile_static, $(PROFILE)) +VALID_PROFILE := $(filter net_4_0 net_4_5 monotouch monodroid xammac mobile mobile_static, $(PROFILE)) ifndef VALID_PROFILE LIBRARY_NAME = dummy-System.ComponentModel.Composition.dll NO_INSTALL = yes diff --git a/mcs/class/System.ComponentModel.DataAnnotations/Makefile b/mcs/class/System.ComponentModel.DataAnnotations/Makefile index 713754ccdb3..3d9ff9e2586 100644 --- a/mcs/class/System.ComponentModel.DataAnnotations/Makefile +++ b/mcs/class/System.ComponentModel.DataAnnotations/Makefile @@ -18,7 +18,7 @@ endif TEST_MCS_FLAGS = $(LIB_MCS_FLAGS) # This is a .NET 3.5+ assembly -VALID_PROFILE := $(filter net_2_0 net_4_0 net_4_5 monotouch monodroid xammac mobile_static, $(PROFILE)) +VALID_PROFILE := $(filter net_2_0 net_4_0 net_4_5 monotouch monodroid xammac mobile mobile_static, $(PROFILE)) ifndef VALID_PROFILE LIBRARY_NAME = dummy-System.ComponentModel.DataAnnotations.dll NO_INSTALL = yes diff --git a/mcs/class/System.ComponentModel.DataAnnotations/mobile_System.ComponentModel.DataAnnotations.dll.sources b/mcs/class/System.ComponentModel.DataAnnotations/mobile_System.ComponentModel.DataAnnotations.dll.sources new file mode 100644 index 00000000000..3de14f5e0a7 --- /dev/null +++ b/mcs/class/System.ComponentModel.DataAnnotations/mobile_System.ComponentModel.DataAnnotations.dll.sources @@ -0,0 +1 @@ +#include net_4_5_System.ComponentModel.DataAnnotations.dll.sources diff --git a/mcs/class/System.Core/Makefile b/mcs/class/System.Core/Makefile index c8836d3125b..eeca6391a14 100644 --- a/mcs/class/System.Core/Makefile +++ b/mcs/class/System.Core/Makefile @@ -10,17 +10,16 @@ ifneq (2.1, $(FRAMEWORK_VERSION)) LIB_MCS_FLAGS += -d:NET_3_5 -nowarn:1720 endif -ifeq (monodroid, $(PROFILE)) -LIB_MCS_FLAGS += -d:FEATURE_CORE_DLR,FEATURE_REFEMIT,ANDROID -endif +MOBILE_DYNAMIC := $(filter monodroid xammac mobile, $(PROFILE)) +MOBILE_STATIC := $(filter mobile_static monotouch monotouch_runtime, $(PROFILE)) -ifeq (xammac, $(PROFILE)) +ifdef MOBILE_DYNAMIC LIB_MCS_FLAGS += -d:FEATURE_CORE_DLR,FEATURE_REFEMIT endif system_core_plain_libdir = $(the_libdir_base)plaincore -ifeq (monotouch, $(subst _runtime,,$(PROFILE))) +ifdef MOBILE_STATIC extra_test_flags := -exclude:NotWorkingInterpreter system_core_library_deps = $(the_libdir_base)Mono.Dynamic.Interpreter.dll $(system_core_plain_libdir)/System.Core.dll LIB_MCS_FLAGS += -d:FEATURE_CORE_DLR @@ -72,4 +71,23 @@ ifneq ($(PROFILE),basic) csproj-local: $(MAKE) csproj-local intermediate=plaincore/ endif -endif \ No newline at end of file +endif + +# +# Android TimeZoneInfo testing.... +# + +tzi.exe: ../corlib/System/AndroidPlatform.cs $(wildcard System/TimeZone*.cs) ../../build/common/Consts.cs ../Mono.Options/Mono.Options/Options.cs + mcs /debug+ /out:$@ /unsafe "/d:INSIDE_CORLIB;MONODROID;NET_4_0;LIBC;SELF_TEST" $^ + +android-pull-tzdb: + mkdir -p android/tzdb/usr/share/zoneinfo + mkdir -p android/tzdb/misc/zoneinfo/zoneinfo + android_root=`adb shell echo '$$ANDROID_ROOT' | tr -d "\r"` ; \ + android_data=`adb shell echo '$$ANDROID_DATA' | tr -d "\r"` ; \ + adb $(ADB_TARGET) pull $$android_root/usr/share/zoneinfo android/tzdb/usr/share/zoneinfo ; \ + adb $(ADB_TARGET) pull $$android_data/misc/zoneinfo/tzdata android/tzdb/misc/zoneinfo + mkdir -p android/tzdb/ + +android-dump-tzdata: tzi.exe android-pull-tzdb + __XA_OVERRIDE_TIMEZONE_ID__=America/New_York ANDROID_ROOT=`pwd` ANDROID_DATA=`pwd` mono --debug tzi.exe -o android/tzdata diff --git a/mcs/class/System.Core/System/TimeZoneInfo.AdjustmentRule.cs b/mcs/class/System.Core/System/TimeZoneInfo.AdjustmentRule.cs index 637d0c400df..37f21464dcf 100644 --- a/mcs/class/System.Core/System/TimeZoneInfo.AdjustmentRule.cs +++ b/mcs/class/System.Core/System/TimeZoneInfo.AdjustmentRule.cs @@ -24,13 +24,16 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#if (INSIDE_CORLIB && NET_4_0) || (!INSIDE_CORLIB && (NET_3_5 && !NET_4_0 && !MOBILE)) +#if INSIDE_CORLIB || (NET_3_5 && !NET_4_0 && !MOBILE) using System.Runtime.CompilerServices; using System.Runtime.Serialization; namespace System { - public sealed partial class TimeZoneInfo { +#if NET_4_0 || !INSIDE_CORLIB + public +#endif + sealed partial class TimeZoneInfo { [SerializableAttribute] #if MOBILE [TypeForwardedFrom (Consts.AssemblySystem_Core)] diff --git a/mcs/class/System.Core/System/TimeZoneInfo.Android.cs b/mcs/class/System.Core/System/TimeZoneInfo.Android.cs index 63502e555fa..72285cc0dab 100644 --- a/mcs/class/System.Core/System/TimeZoneInfo.Android.cs +++ b/mcs/class/System.Core/System/TimeZoneInfo.Android.cs @@ -246,6 +246,7 @@ public byte[] GetTimeZoneData (string id) tzdataPath, offset, length, r, buffer.Length)); } + TimeZoneInfo.DumpTimeZoneDataToFile (id, buffer); return buffer; } } @@ -453,29 +454,29 @@ internal static IEnumerable GetAvailableIds () : 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; } @@ -533,12 +534,12 @@ static int ParseNumericZone (string name) 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 ()); } } } @@ -553,7 +554,10 @@ static string 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) @@ -576,25 +580,52 @@ static string GetDefaultTimeZoneName () #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 android/tzdb/usr/share/zoneinfo + * mkdir -p android/tzdb/misc/zoneinfo/zoneinfo * android_root=`adb shell echo '$ANDROID_ROOT' | tr -d "\r"` - * adb pull $android_root/usr/share/zoneinfo usr/share/zoneinfo + * android_data=`adb shell echo '$ANDROID_DATA' | tr -d "\r"` + * adb pull $android_root/usr/share/zoneinfo android/tzdb/usr/share/zoneinfo + * adb pull $android_data/misc/zoneinfo/tzdata android/tzdb/misc/zoneinfo * Run: - * ANDROID_ROOT=`pwd` mono tzi.exe + * # Dump all timezone names + * __XA_OVERRIDE_TIMEZONE_ID__=America/New_York ANDROID_ROOT=`pwd` ANDROID_DATA=`pwd` mono --debug tzi.exe --offset=1969-01-01 + * + * # Dump TimeZone data to files under path `tzdata` + * __XA_OVERRIDE_TIMEZONE_ID__=America/New_York ANDROID_ROOT=`pwd` ANDROID_DATA=`pwd` mono --debug tzi.exe -o android/tzdata + * + * # Dump TimeZone rules for specific timezone data (as dumped above) + * mono tzi.exe --offset=2012-10-24 -i=tzdata/Asia/Amman */ static void Main (string[] args) { + DateTime? offset = null; Func c = () => GetDefaultTimeZoneDB (); + bool dump_rules = false; Mono.Options.OptionSet p = null; p = new Mono.Options.OptionSet () { + { "i=", + "TimeZone data {FILE} to parse and dump", + v => DumpTimeZoneFile (v, offset) + }, + { "o=", + "Write TimeZone data files to {PATH}", + v => TimeZoneInfo.TimeZoneDataExportPath = v + }, { "T=", "Create AndroidTzData from {PATH}.", v => { c = () => new AndroidTzData (v); } }, { "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); + } }, + { "R|dump-rules", + "Show timezone info offset for DateTime {OFFSET}.", + v => dump_rules = v != null }, { "help", "Show this message and exit", v => { p.WriteOptionDescriptions (Console.Out); Environment.Exit (0); @@ -606,9 +637,16 @@ static void Main (string[] args) 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)); + } + if (dump_rules) { + WriteZoneRules (zone); + } + } else { Console.Write (" ERROR:null"); } @@ -619,6 +657,53 @@ static void Main (string[] args) Console.WriteLine (); } } + + static void WriteZoneRules (TimeZoneInfo zone) + { + var rules = zone.GetAdjustmentRules (); + for (int i = 0; i < rules.Length; ++i) { + var rule = rules [i]; + Console.WriteLine (); + Console.Write ("\tAdjustmentRules[{0,3}]: DaylightDelta={1}; DateStart={2:yyyy-MM}; DateEnd={3:yyyy-MM}; DaylightTransitionStart={4:D2}-{5:D2}T{6}; DaylightTransitionEnd={7:D2}-{8:D2}T{9}", + i, + rule.DaylightDelta, + rule.DateStart, rule.DateEnd, + rule.DaylightTransitionStart.Month, rule.DaylightTransitionStart.Day, rule.DaylightTransitionStart.TimeOfDay.TimeOfDay, + rule.DaylightTransitionEnd.Month, rule.DaylightTransitionEnd.Day, rule.DaylightTransitionEnd.TimeOfDay.TimeOfDay); + } + } + + static void DumpTimeZoneFile (string path, DateTime? time) + { + var buffer = File.ReadAllBytes (path); + var zone = ParseTZBuffer (path, buffer, buffer.Length); + Console.Write ("Rules for: {0}", path); + WriteZoneRules (zone); + Console.WriteLine (); + if (time.HasValue) { + var offset = zone.GetUtcOffset (time.Value); + var isDst = zone.IsDaylightSavingTime (time.Value); + Console.WriteLine ("\tDate({0}): Offset({1}) IsDST({2})", time.Value, offset, isDst); + } + } +#endif + } + +#if SELF_TEST + static string TimeZoneDataExportPath; +#endif + + internal static void DumpTimeZoneDataToFile (string id, byte[] buffer) + { +#if SELF_TEST + int p = id.LastIndexOf ('/'); + var o = Path.Combine (TimeZoneDataExportPath, + p >= 0 ? id.Substring (0, p) : id); + if (p >= 0) + o = Path.Combine (o, id.Substring (p+1)); + Directory.CreateDirectory (Path.GetDirectoryName (o)); + using (var f = File.OpenWrite (o)) + f.Write (buffer, 0, buffer.Length); #endif } } diff --git a/mcs/class/System.Core/System/TimeZoneInfo.Serialization.cs b/mcs/class/System.Core/System/TimeZoneInfo.Serialization.cs index 22aa38c5fa6..3a7da39ec7f 100644 --- a/mcs/class/System.Core/System/TimeZoneInfo.Serialization.cs +++ b/mcs/class/System.Core/System/TimeZoneInfo.Serialization.cs @@ -24,7 +24,7 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#if (INSIDE_CORLIB && NET_4_0) || (!INSIDE_CORLIB && (NET_3_5 && !NET_4_0 && !MOBILE)) +#if INSIDE_CORLIB || (NET_3_5 && !NET_4_0 && !MOBILE) using System.Collections.Generic; using System.Globalization; @@ -33,7 +33,10 @@ namespace System { - public partial class TimeZoneInfo +#if NET_4_0 || !INSIDE_CORLIB + public +#endif + partial class TimeZoneInfo { public static TimeZoneInfo FromSerializedString (string source) { diff --git a/mcs/class/System.Core/System/TimeZoneInfo.TransitionTime.cs b/mcs/class/System.Core/System/TimeZoneInfo.TransitionTime.cs index d57df150f05..719bb9d51f3 100644 --- a/mcs/class/System.Core/System/TimeZoneInfo.TransitionTime.cs +++ b/mcs/class/System.Core/System/TimeZoneInfo.TransitionTime.cs @@ -24,14 +24,17 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#if (INSIDE_CORLIB && NET_4_0) || (!INSIDE_CORLIB && (NET_3_5 && !NET_4_0 && !MOBILE)) +#if INSIDE_CORLIB || (NET_3_5 && !NET_4_0 && !MOBILE) using System.Runtime.CompilerServices; using System.Runtime.Serialization; namespace System { - public sealed partial class TimeZoneInfo +#if NET_4_0 || !INSIDE_CORLIB + public +#endif + sealed partial class TimeZoneInfo { [SerializableAttribute] #if MOBILE diff --git a/mcs/class/System.Core/System/TimeZoneInfo.cs b/mcs/class/System.Core/System/TimeZoneInfo.cs index aead18c764f..354b47a2a06 100644 --- a/mcs/class/System.Core/System/TimeZoneInfo.cs +++ b/mcs/class/System.Core/System/TimeZoneInfo.cs @@ -35,7 +35,7 @@ [assembly:TypeForwardedTo (typeof(TimeZoneInfo))] -#elif (INSIDE_CORLIB && NET_4_0) || (!INSIDE_CORLIB && (NET_3_5 && !NET_4_0 && !MOBILE)) +#elif INSIDE_CORLIB || (NET_3_5 && !NET_4_0 && !MOBILE) using System.Collections.Generic; using System.Collections.ObjectModel; @@ -57,7 +57,10 @@ namespace System [TypeForwardedFrom (Consts.AssemblySystemCore_3_5)] #endif [SerializableAttribute] - public sealed partial class TimeZoneInfo : IEquatable, ISerializable, IDeserializationCallback +#if NET_4_0 || !INSIDE_CORLIB + public +#endif + sealed partial class TimeZoneInfo : IEquatable, ISerializable, IDeserializationCallback { TimeSpan baseUtcOffset; public TimeSpan BaseUtcOffset { @@ -100,15 +103,31 @@ public static TimeZoneInfo Local { } } + /* + TimeZone transitions are stored when there is a change on the base offset. + */ + private List> transitions; + static TimeZoneInfo CreateLocal () { #if MONODROID - return AndroidTimeZones.Default; + return AndroidTimeZones.Local; #elif MONOTOUCH using (Stream stream = GetMonoTouchData (null)) { return BuildFromStream ("Local", stream); } #elif LIBC + var tz = Environment.GetEnvironmentVariable ("TZ"); + if (tz != null) { + if (tz == String.Empty) + return Utc; + try { + return FindSystemTimeZoneByFileName (tz, Path.Combine (TimeZoneDirectory, tz)); + } catch { + return Utc; + } + } + try { return FindSystemTimeZoneByFileName ("Local", "/etc/localtime"); } catch { @@ -332,8 +351,7 @@ public static DateTime ConvertTimeToUtc (DateTime dateTime) if (dateTime.Kind == DateTimeKind.Utc) return dateTime; - //FIXME: do not rely on DateTime implementation ! - return DateTime.SpecifyKind (dateTime.ToUniversalTime (), DateTimeKind.Utc); + return ConvertTimeToUtc (dateTime, TimeZoneInfo.Local); } public static DateTime ConvertTimeToUtc (DateTime dateTime, TimeZoneInfo sourceTimeZone) @@ -350,15 +368,9 @@ public static DateTime ConvertTimeToUtc (DateTime dateTime, TimeZoneInfo sourceT if (sourceTimeZone.IsInvalidTime (dateTime)) throw new ArgumentException ("dateTime parameter is an invalid time"); - if (dateTime.Kind == DateTimeKind.Utc && sourceTimeZone == TimeZoneInfo.Utc) - return dateTime; - if (dateTime.Kind == DateTimeKind.Utc) return dateTime; - if (dateTime.Kind == DateTimeKind.Local) - return ConvertTimeToUtc (dateTime); - if (sourceTimeZone.IsAmbiguousTime (dateTime) || !sourceTimeZone.IsDaylightSavingTime (dateTime)) return DateTime.SpecifyKind (dateTime - sourceTimeZone.BaseUtcOffset, DateTimeKind.Utc); else { @@ -415,7 +427,7 @@ public static TimeZoneInfo FindSystemTimeZoneById (string id) } #endif #if MONODROID - var timeZoneInfo = AndroidTimeZones.GetTimeZone (id); + var timeZoneInfo = AndroidTimeZones.GetTimeZone (id, id); if (timeZoneInfo == null) throw new TimeZoneNotFoundException (); return timeZoneInfo; @@ -644,7 +656,7 @@ public static ReadOnlyCollection GetSystemTimeZones () #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); } @@ -684,13 +696,8 @@ public static ReadOnlyCollection GetSystemTimeZones () public TimeSpan GetUtcOffset (DateTime dateTime) { - if (IsDaylightSavingTime (dateTime)) { - AdjustmentRule rule = GetApplicableRule (dateTime); - if (rule != null) - return BaseUtcOffset + rule.DaylightDelta; - } - - return BaseUtcOffset; + bool isDST; + return GetUtcOffset (dateTime, out isDST); } public TimeSpan GetUtcOffset (DateTimeOffset dateTimeOffset) @@ -698,6 +705,82 @@ public TimeSpan GetUtcOffset (DateTimeOffset dateTimeOffset) throw new NotImplementedException (); } + private TimeSpan GetUtcOffset (DateTime dateTime, out bool isDST) + { + isDST = false; + + TimeZoneInfo tz = this; + if (dateTime.Kind == DateTimeKind.Utc) + tz = TimeZoneInfo.Utc; + + if (dateTime.Kind == DateTimeKind.Local) + tz = TimeZoneInfo.Local; + + bool isTzDst; + var tzOffset = GetUtcOffset (dateTime, tz, out isTzDst); + + if (tz == this) { + isDST = isTzDst; + return tzOffset; + } + + var utcTicks = dateTime.Ticks - tzOffset.Ticks; + if (utcTicks < 0 || utcTicks > DateTime.MaxValue.Ticks) + return BaseUtcOffset; + + var utcDateTime = new DateTime (utcTicks, DateTimeKind.Utc); + + return GetUtcOffset (utcDateTime, this, out isDST); + } + + private static TimeSpan GetUtcOffset (DateTime dateTime, TimeZoneInfo tz, out bool isDST) + { + if (dateTime.Kind == DateTimeKind.Local && tz != TimeZoneInfo.Local) + throw new Exception (); + + isDST = false; + + if (tz == TimeZoneInfo.Utc) + return TimeSpan.Zero; + + TimeSpan offset; + if (tz.TryGetTransitionOffset(dateTime, out offset, out isDST)) + return offset; + + if (dateTime.Kind == DateTimeKind.Utc) { + var utcRule = tz.GetApplicableRule (dateTime); + if (utcRule != null && tz.IsInDST (utcRule, dateTime)) { + isDST = true; + return tz.BaseUtcOffset + utcRule.DaylightDelta; + } + + return tz.BaseUtcOffset; + } + + var stdTicks = dateTime.Ticks - tz.BaseUtcOffset.Ticks; + if (stdTicks < 0 || stdTicks > DateTime.MaxValue.Ticks) + return tz.BaseUtcOffset; + + var stdUtcDateTime = new DateTime (stdTicks, DateTimeKind.Utc); + var tzRule = tz.GetApplicableRule (stdUtcDateTime); + + DateTime dstUtcDateTime = DateTime.MinValue; + if (tzRule != null) { + var dstTicks = stdUtcDateTime.Ticks - tzRule.DaylightDelta.Ticks; + if (dstTicks < 0 || dstTicks > DateTime.MaxValue.Ticks) + return tz.BaseUtcOffset; + + dstUtcDateTime = new DateTime (dstTicks, DateTimeKind.Utc); + } + + if (tzRule != null && tz.IsInDST (tzRule, stdUtcDateTime) && tz.IsInDST (tzRule, dstUtcDateTime)) { + isDST = true; + return tz.BaseUtcOffset + tzRule.DaylightDelta; + } + + return tz.BaseUtcOffset; + } + public bool HasSameRules (TimeZoneInfo other) { if (other == null) @@ -752,6 +835,16 @@ public bool IsAmbiguousTime (DateTimeOffset dateTimeOffset) throw new NotImplementedException (); } + private bool IsInDST (AdjustmentRule rule, DateTime dateTime) + { + // Check whether we're in the dateTime year's DST period + if (IsInDSTForYear (rule, dateTime, dateTime.Year)) + return true; + + // We might be in the dateTime previous year's DST period + return IsInDSTForYear (rule, dateTime, dateTime.Year - 1); + } + bool IsInDSTForYear (AdjustmentRule rule, DateTime dateTime, int year) { DateTime DST_start = TransitionPoint (rule.DaylightTransitionStart, year); @@ -774,25 +867,11 @@ public bool IsDaylightSavingTime (DateTime dateTime) if (!SupportsDaylightSavingTime) return false; - - //FIXME: do not rely on DateTime implementation ! - if ((dateTime.Kind == DateTimeKind.Local || dateTime.Kind == DateTimeKind.Unspecified) && this == TimeZoneInfo.Local) - return dateTime.IsDaylightSavingTime (); - - //FIXME: do not rely on DateTime implementation ! - if (dateTime.Kind == DateTimeKind.Local && this != TimeZoneInfo.Utc) - return IsDaylightSavingTime (DateTime.SpecifyKind (dateTime.ToUniversalTime (), DateTimeKind.Utc)); - - AdjustmentRule rule = GetApplicableRule (dateTime.Date); - if (rule == null) - return false; - // Check whether we're in the dateTime year's DST period - if (IsInDSTForYear (rule, dateTime, dateTime.Year)) - return true; + bool isDst; + GetUtcOffset (dateTime, out isDst); - // We might be in the dateTime previous year's DST period - return IsInDSTForYear (rule, dateTime, dateTime.Year - 1); + return isDst; } public bool IsDaylightSavingTime (DateTimeOffset dateTimeOffset) @@ -969,6 +1048,40 @@ private AdjustmentRule GetApplicableRule (DateTime dateTime) return null; } + private bool TryGetTransitionOffset (DateTime dateTime, out TimeSpan offset,out bool isDst) + { + offset = BaseUtcOffset; + isDst = false; + + if (transitions == null) + return false; + + //Transitions are always in standard time + DateTime date = dateTime; + + if (dateTime.Kind == DateTimeKind.Local && this != TimeZoneInfo.Local) + date = date.ToUniversalTime () + BaseUtcOffset; + + if (dateTime.Kind == DateTimeKind.Utc && this != TimeZoneInfo.Utc) + date = date + BaseUtcOffset; + + for (var i = transitions.Count - 1; i >= 0; i--) { + var pair = transitions [i]; + DateTime ttime = pair.Key; + TimeType ttype = pair.Value; + + if (ttime > date) + continue; + + offset = new TimeSpan (0, 0, ttype.Offset); + isDst = ttype.IsDst; + + return true; + } + + return false; + } + private static DateTime TransitionPoint (TransitionTime transition, int year) { if (transition.IsFixedDateRule) @@ -1059,16 +1172,19 @@ private static TimeZoneInfo ParseTZBuffer (string id, byte [] buffer, int length bool dst_observed = false; DateTime dst_start = DateTime.MinValue; List adjustmentRules = new List (); + bool storeTransition = false; for (int i = 0; i < transitions.Count; i++) { var pair = transitions [i]; DateTime ttime = pair.Key; TimeType ttype = pair.Value; if (!ttype.IsDst) { - if (standardDisplayName != ttype.Name || baseUtcOffset.TotalSeconds != ttype.Offset) { + if (standardDisplayName != ttype.Name) standardDisplayName = ttype.Name; - daylightDisplayName = null; + if (baseUtcOffset.TotalSeconds != ttype.Offset) { baseUtcOffset = new TimeSpan (0, 0, ttype.Offset); + if (adjustmentRules.Count > 0) // We ignore AdjustmentRules but store transitions. + storeTransition = true; adjustmentRules = new List (); dst_observed = false; } @@ -1101,25 +1217,32 @@ private static TimeZoneInfo ParseTZBuffer (string id, byte [] buffer, int length } dst_observed = false; } else { - if (daylightDisplayName != ttype.Name || dstDelta.TotalSeconds != ttype.Offset - baseUtcOffset.TotalSeconds) { + if (daylightDisplayName != ttype.Name) daylightDisplayName = ttype.Name; + if (dstDelta.TotalSeconds != ttype.Offset - baseUtcOffset.TotalSeconds) dstDelta = new TimeSpan(0, 0, ttype.Offset) - baseUtcOffset; - } + dst_start = ttime; dst_observed = true; } } - if (adjustmentRules.Count == 0) { + TimeZoneInfo tz; + if (adjustmentRules.Count == 0 && !storeTransition) { TimeType t = (TimeType)time_types [0]; if (standardDisplayName == null) { standardDisplayName = t.Name; baseUtcOffset = new TimeSpan (0, 0, t.Offset); } - return CreateCustomTimeZone (id, baseUtcOffset, id, standardDisplayName); + tz = CreateCustomTimeZone (id, baseUtcOffset, id, standardDisplayName); } else { - return CreateCustomTimeZone (id, baseUtcOffset, id, standardDisplayName, daylightDisplayName, ValidateRules (adjustmentRules).ToArray ()); + tz = CreateCustomTimeZone (id, baseUtcOffset, id, standardDisplayName, daylightDisplayName, ValidateRules (adjustmentRules).ToArray ()); } + + if (storeTransition) + tz.transitions = transitions; + + return tz; } static Dictionary ParseAbbreviations (byte [] buffer, int index, int count) diff --git a/mcs/class/System.Core/Test/System/TimeZoneInfoTest.cs b/mcs/class/System.Core/Test/System/TimeZoneInfoTest.cs index f6ea66e98c6..c3972e747c1 100644 --- a/mcs/class/System.Core/Test/System/TimeZoneInfoTest.cs +++ b/mcs/class/System.Core/Test/System/TimeZoneInfoTest.cs @@ -232,7 +232,7 @@ public void DSTTransisions () DateTime afterDST = new DateTime (2007, 10, 28, 2, 0, 0, DateTimeKind.Unspecified); Assert.IsFalse (london.IsDaylightSavingTime (beforeDST), "Just before DST"); Assert.IsTrue (london.IsDaylightSavingTime (startDST), "the first seconds of DST"); - Assert.IsTrue (london.IsDaylightSavingTime (endDST), "The last seconds of DST"); + Assert.IsFalse (london.IsDaylightSavingTime (endDST), "The last seconds of DST"); Assert.IsFalse (london.IsDaylightSavingTime (afterDST), "Just after DST"); } @@ -804,6 +804,143 @@ public void Serialization_Deserialization () Assert.IsTrue (london.Equals (deserialized)); } } + + [TestFixture] + public class MultipleDaylightSavingTimeTests { + private TimeZoneInfo cairo; + private DateTime dst1Start; + private DateTime dst1End; + private DateTime dst2Start; + private DateTime dst2End; + + private TimeSpan baseUtcOffset; + private TimeSpan dstUtcOffset; + private TimeSpan dstOffset; + + [SetUp] + public void CreateTimeZones () + { + /* + From 1/1/2014 12:00:00 AM to 6/30/2014 12:00:00 AM + Delta: 01:00:00 + Begins at 12:00 AM on 16 May + Ends at 1:00 AM on 29 June + From 7/1/2014 12:00:00 AM to 12/31/2014 12:00:00 AM + Delta: 01:00:00 + Begins at 12:00 AM on 29 July + Ends at 12:00 AM on 26 September + */ + dst1Start = new DateTime (2014, 5, 16); + dst1End = new DateTime (2014, 6, 29); + dst2Start = new DateTime (2014, 7, 29); + dst2End = new DateTime (2014, 9, 26); + + baseUtcOffset = new TimeSpan (2, 0, 0); + dstUtcOffset = new TimeSpan (3, 0, 0); + dstOffset = dstUtcOffset - baseUtcOffset; + + var rule1 = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule ( + new DateTime (2014, 1, 1), new DateTime (2014, 6, 30), dstOffset, + CreateFixedDateRule (dst1Start), CreateFixedDateRule (dst1End)); + + var rule2 = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule ( + new DateTime (2014, 7, 1), new DateTime (2014, 12, 31), dstOffset, + CreateFixedDateRule (dst2Start), CreateFixedDateRule (dst2End)); + + cairo = TimeZoneInfo.CreateCustomTimeZone ("Africa/Cairo", baseUtcOffset, "Africa/Cairo", "EET", "EEST", + new [] {rule1, rule2}); + } + + private static TimeZoneInfo.TransitionTime CreateFixedDateRule (DateTime dateTime) + { + var time = new DateTime (dateTime.Ticks - dateTime.Date.Ticks); + return TimeZoneInfo.TransitionTime.CreateFixedDateRule (time, dateTime.Month, dateTime.Day); + } + + [Test] + public void GetUtcOffset_FromUTC () + { + var d = dst1Start.Add (-baseUtcOffset); + d = DateTime.SpecifyKind (d, DateTimeKind.Utc); + Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1)))); + Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d)); + Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1)))); + + d = dst1End.Add (-baseUtcOffset-dstOffset); + d = DateTime.SpecifyKind (d, DateTimeKind.Utc); + Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1)))); + Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d)); + Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1)))); + + d = dst2Start.Add (-baseUtcOffset); + d = DateTime.SpecifyKind (d, DateTimeKind.Utc); + Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1)))); + Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d)); + Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1)))); + + d = dst2End.Add (-baseUtcOffset-dstOffset); + d = DateTime.SpecifyKind (d, DateTimeKind.Utc); + Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1)))); + Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d)); + Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1)))); + } + + [Test] + public void GetUtcOffset_FromLocal () + { + var d = dst1Start.Add (-baseUtcOffset); + d = DateTime.SpecifyKind (d, DateTimeKind.Utc); + d = d.ToLocalTime (); + Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1)))); + Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d)); + Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1)))); + + d = dst1End.Add (-baseUtcOffset-dstOffset); + d = DateTime.SpecifyKind (d, DateTimeKind.Utc); + d = d.ToLocalTime (); + Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1)))); + Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d)); + Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1)))); + + d = dst2Start.Add (-baseUtcOffset); + d = DateTime.SpecifyKind (d, DateTimeKind.Utc); + d = d.ToLocalTime (); + Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1)))); + Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d)); + Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1)))); + + d = dst2End.Add (-baseUtcOffset-dstOffset); + d = DateTime.SpecifyKind (d, DateTimeKind.Utc); + d = d.ToLocalTime (); + Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1)))); + Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d)); + Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1)))); + } + + [Test] + public void GetUtcOffset_FromUnspecified () + { + var d = dst1Start.Add (dstOffset); + Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1)))); + Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d)); + Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1)))); + + d = dst1End.Add (-dstOffset); + Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1)))); + Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d)); + Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1)))); + + d = dst2Start.Add (dstOffset); + Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1)))); + Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d)); + Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1)))); + + d = dst2End.Add (-dstOffset); + Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1)))); + Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d)); + Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1)))); + } + } } } #endif diff --git a/mcs/class/System.Core/mobile_System.Core.dll.sources b/mcs/class/System.Core/mobile_System.Core.dll.sources index dee2534a29b..5cd8ddf660b 100644 --- a/mcs/class/System.Core/mobile_System.Core.dll.sources +++ b/mcs/class/System.Core/mobile_System.Core.dll.sources @@ -1,109 +1,4 @@ -Assembly/AssemblyInfo.cs -System/Actions.cs -System/Funcs.cs -System/InvalidTimeZoneException.cs -System/TimeZoneInfo.AdjustmentRule.cs -System/TimeZoneInfo.cs -System/TimeZoneInfo.Serialization.cs -System/TimeZoneInfo.TransitionTime.cs -System/TimeZoneNotFoundException.cs -System/Util.cs -System.Runtime.CompilerServices/DynamicAttribute.cs -System.Runtime.CompilerServices/ExecutionScope.cs -System.Runtime.CompilerServices/ExtensionAttribute.cs -System.Runtime.CompilerServices/IStrongBox.cs -System.Runtime.CompilerServices/StrongBox_T.cs -System.Linq/Check.cs -System.Linq/Enumerable.cs -System.Linq/QueryableEnumerable.cs -System.Linq/QueryableTransformer.cs -System.Linq/Grouping.cs -System.Linq/IGrouping.cs -System.Linq/IOrderedQueryable.cs -System.Linq/IOrderedQueryable_T.cs -System.Linq/IOrderedEnumerable_T.cs -System.Linq/IQueryable.cs -System.Linq/IQueryable_T.cs -System.Linq/Lookup.cs -System.Linq/ILookup_T.cs -System.Linq/OrderedEnumerable.cs -System.Linq/OrderedSequence.cs -System.Linq/Queryable.cs -System.Linq/QuickSort.cs -System.Linq/SortContext.cs -System.Linq/SortDirection.cs -System.Linq/SortSequenceContext.cs -System.Linq/IQueryProvider.cs -System.Collections.Generic/HashSet.cs -System.Security.Cryptography/Aes.cs -System.Threading/LockRecursionPolicy.cs -System.Threading/ReaderWriterLockSlim.cs -System.Threading/ThreadLockState.cs -System.Threading/ReaderWriterLockSlimExtensions.cs -System.Linq.Parallel.QueryNodes/QueryBaseNode.cs -System.Linq.Parallel.QueryNodes/QueryCastNode.cs -System.Linq.Parallel.QueryNodes/QueryChildNode.cs -System.Linq.Parallel.QueryNodes/QueryConcatNode.cs -System.Linq.Parallel.QueryNodes/QueryDefaultEmptyNode.cs -System.Linq.Parallel.QueryNodes/QueryGroupByNode.cs -System.Linq.Parallel.QueryNodes/QueryHeadWorkerNode.cs -System.Linq.Parallel.QueryNodes/QueryJoinNode.cs -System.Linq.Parallel.QueryNodes/QueryMuxNode.cs -System.Linq.Parallel.QueryNodes/QueryOptionNode.cs -System.Linq.Parallel.QueryNodes/QueryOrderByNode.cs -System.Linq.Parallel.QueryNodes/QueryOrderGuardNode.cs -System.Linq.Parallel.QueryNodes/QueryOrderedStreamNode.cs -System.Linq.Parallel.QueryNodes/QueryReverseNode.cs -System.Linq.Parallel.QueryNodes/QuerySelectManyNode.cs -System.Linq.Parallel.QueryNodes/QuerySelectNode.cs -System.Linq.Parallel.QueryNodes/QuerySetNode.cs -System.Linq.Parallel.QueryNodes/QueryStartNode.cs -System.Linq.Parallel.QueryNodes/QueryStreamNode.cs -System.Linq.Parallel.QueryNodes/QueryWhereNode.cs -System.Linq.Parallel.QueryNodes/QueryZipNode.cs -System.Linq.Parallel.QueryNodes/SetInclusion.cs -System.Linq.Parallel.QueryNodes/WrapHelper.cs -System.Linq.Parallel/AggregationList.cs -System.Linq.Parallel/ConcurrentGrouping.cs -System.Linq.Parallel/ConcurrentLookup.cs -System.Linq.Parallel/INodeVisitor.cs -System.Linq.Parallel/IVisitableNode.cs -System.Linq.Parallel/OrderingEnumerator.cs -System.Linq.Parallel/ParallelExecuter.cs -System.Linq.Parallel/ParallelPartitioner.cs -System.Linq.Parallel/ParallelQueryEnumerator.cs -System.Linq.Parallel/ParallelQuickSort.cs -System.Linq.Parallel/QueryCheckerVisitor.cs -System.Linq.Parallel/QueryIsOrderedVisitor.cs -System.Linq.Parallel/QueryOptions.cs -System.Linq.Parallel/RangeList.cs -System.Linq.Parallel/RepeatList.cs -System.Linq.Parallel/ReverseList.cs -System.Linq.Parallel/StripPartitioner.cs -System.Linq.Parallel/TemporaryArea.cs -System.Linq/EnumerableExecutor.cs -System.Linq/EnumerableExecutor_T.cs -System.Linq/EnumerableQuery.cs -System.Linq/EnumerableQuery_T.cs -System.Linq/OrderedParallelQuery.cs -System.Linq/ParallelEnumerable.cs -System.Linq/ParallelExecutionMode.cs -System.Linq/ParallelMergeOptions.cs -System.Linq/ParallelQuery.cs -System.IO.MemoryMappedFiles/MemoryMappedFile.cs -System.IO.MemoryMappedFiles/MemoryMappedFileAccess.cs -System.IO.MemoryMappedFiles/MemoryMappedFileOptions.cs -System.IO.MemoryMappedFiles/MemoryMappedFileRights.cs -System.IO.MemoryMappedFiles/MemoryMappedFileSecurity.cs -System.IO.MemoryMappedFiles/MemoryMappedViewStream.cs -System.IO.MemoryMappedFiles/MemoryMappedViewAccessor.cs -Microsoft.Win32.SafeHandles/SafeMemoryMappedFileHandle.cs -Microsoft.Win32.SafeHandles/SafeMemoryMappedViewHandle.cs -System.IO/HandleInheritability.cs -System.Threading.Tasks/TaskExtensions.cs -System.Linq.Expressions/Extensions.cs -System.Linq.Expressions/ExpressionTransformer.cs -../dlr/Runtime/Microsoft.Scripting.Core/Ast/DynamicExpression.cs -../dlr/Runtime/Microsoft.Scripting.Core/Compiler/Closure.cs -System.Linq.Expressions/DynamicExpressionVisitor.cs +#include mobile_common_System.Core.dll.sources + +#include dynamic_System.Core.dll.sources diff --git a/mcs/class/System.Core/mobile_common_System.Core.dll.sources b/mcs/class/System.Core/mobile_common_System.Core.dll.sources new file mode 100644 index 00000000000..10e86231252 --- /dev/null +++ b/mcs/class/System.Core/mobile_common_System.Core.dll.sources @@ -0,0 +1,108 @@ +Assembly/AssemblyInfo.cs +System/Actions.cs +System/Funcs.cs +System/InvalidTimeZoneException.cs +System/TimeZoneInfo.AdjustmentRule.cs +System/TimeZoneInfo.cs +System/TimeZoneInfo.Serialization.cs +System/TimeZoneInfo.TransitionTime.cs +System/TimeZoneNotFoundException.cs +System/Util.cs +System.Runtime.CompilerServices/DynamicAttribute.cs +System.Runtime.CompilerServices/ExecutionScope.cs +System.Runtime.CompilerServices/ExtensionAttribute.cs +System.Runtime.CompilerServices/IStrongBox.cs +System.Runtime.CompilerServices/StrongBox_T.cs +System.Linq/Check.cs +System.Linq/Enumerable.cs +System.Linq/QueryableEnumerable.cs +System.Linq/QueryableTransformer.cs +System.Linq/Grouping.cs +System.Linq/IGrouping.cs +System.Linq/IOrderedQueryable.cs +System.Linq/IOrderedQueryable_T.cs +System.Linq/IOrderedEnumerable_T.cs +System.Linq/IQueryable.cs +System.Linq/IQueryable_T.cs +System.Linq/Lookup.cs +System.Linq/ILookup_T.cs +System.Linq/OrderedEnumerable.cs +System.Linq/OrderedSequence.cs +System.Linq/Queryable.cs +System.Linq/QuickSort.cs +System.Linq/SortContext.cs +System.Linq/SortDirection.cs +System.Linq/SortSequenceContext.cs +System.Linq/IQueryProvider.cs +System.Collections.Generic/HashSet.cs +System.Security.Cryptography/Aes.cs +System.Threading/LockRecursionPolicy.cs +System.Threading/ReaderWriterLockSlim.cs +System.Threading/ThreadLockState.cs +System.Threading/ReaderWriterLockSlimExtensions.cs +System.Linq.Parallel.QueryNodes/QueryBaseNode.cs +System.Linq.Parallel.QueryNodes/QueryCastNode.cs +System.Linq.Parallel.QueryNodes/QueryChildNode.cs +System.Linq.Parallel.QueryNodes/QueryConcatNode.cs +System.Linq.Parallel.QueryNodes/QueryDefaultEmptyNode.cs +System.Linq.Parallel.QueryNodes/QueryGroupByNode.cs +System.Linq.Parallel.QueryNodes/QueryHeadWorkerNode.cs +System.Linq.Parallel.QueryNodes/QueryJoinNode.cs +System.Linq.Parallel.QueryNodes/QueryMuxNode.cs +System.Linq.Parallel.QueryNodes/QueryOptionNode.cs +System.Linq.Parallel.QueryNodes/QueryOrderByNode.cs +System.Linq.Parallel.QueryNodes/QueryOrderGuardNode.cs +System.Linq.Parallel.QueryNodes/QueryOrderedStreamNode.cs +System.Linq.Parallel.QueryNodes/QueryReverseNode.cs +System.Linq.Parallel.QueryNodes/QuerySelectManyNode.cs +System.Linq.Parallel.QueryNodes/QuerySelectNode.cs +System.Linq.Parallel.QueryNodes/QuerySetNode.cs +System.Linq.Parallel.QueryNodes/QueryStartNode.cs +System.Linq.Parallel.QueryNodes/QueryStreamNode.cs +System.Linq.Parallel.QueryNodes/QueryWhereNode.cs +System.Linq.Parallel.QueryNodes/QueryZipNode.cs +System.Linq.Parallel.QueryNodes/SetInclusion.cs +System.Linq.Parallel.QueryNodes/WrapHelper.cs +System.Linq.Parallel/AggregationList.cs +System.Linq.Parallel/ConcurrentGrouping.cs +System.Linq.Parallel/ConcurrentLookup.cs +System.Linq.Parallel/INodeVisitor.cs +System.Linq.Parallel/IVisitableNode.cs +System.Linq.Parallel/OrderingEnumerator.cs +System.Linq.Parallel/ParallelExecuter.cs +System.Linq.Parallel/ParallelPartitioner.cs +System.Linq.Parallel/ParallelQueryEnumerator.cs +System.Linq.Parallel/ParallelQuickSort.cs +System.Linq.Parallel/QueryCheckerVisitor.cs +System.Linq.Parallel/QueryIsOrderedVisitor.cs +System.Linq.Parallel/QueryOptions.cs +System.Linq.Parallel/RangeList.cs +System.Linq.Parallel/RepeatList.cs +System.Linq.Parallel/ReverseList.cs +System.Linq.Parallel/StripPartitioner.cs +System.Linq.Parallel/TemporaryArea.cs +System.Linq/EnumerableExecutor.cs +System.Linq/EnumerableExecutor_T.cs +System.Linq/EnumerableQuery.cs +System.Linq/EnumerableQuery_T.cs +System.Linq/OrderedParallelQuery.cs +System.Linq/ParallelEnumerable.cs +System.Linq/ParallelExecutionMode.cs +System.Linq/ParallelMergeOptions.cs +System.Linq/ParallelQuery.cs +System.IO.MemoryMappedFiles/MemoryMappedFile.cs +System.IO.MemoryMappedFiles/MemoryMappedFileAccess.cs +System.IO.MemoryMappedFiles/MemoryMappedFileOptions.cs +System.IO.MemoryMappedFiles/MemoryMappedFileRights.cs +System.IO.MemoryMappedFiles/MemoryMappedFileSecurity.cs +System.IO.MemoryMappedFiles/MemoryMappedViewStream.cs +System.IO.MemoryMappedFiles/MemoryMappedViewAccessor.cs +Microsoft.Win32.SafeHandles/SafeMemoryMappedFileHandle.cs +Microsoft.Win32.SafeHandles/SafeMemoryMappedViewHandle.cs +System.IO/HandleInheritability.cs +System.Threading.Tasks/TaskExtensions.cs +System.Linq.Expressions/Extensions.cs +System.Linq.Expressions/ExpressionTransformer.cs +../dlr/Runtime/Microsoft.Scripting.Core/Ast/DynamicExpression.cs +../dlr/Runtime/Microsoft.Scripting.Core/Compiler/Closure.cs +System.Linq.Expressions/DynamicExpressionVisitor.cs diff --git a/mcs/class/System.Core/mobile_static_System.Core.dll.sources b/mcs/class/System.Core/mobile_static_System.Core.dll.sources new file mode 100644 index 00000000000..6da190e2546 --- /dev/null +++ b/mcs/class/System.Core/mobile_static_System.Core.dll.sources @@ -0,0 +1,2 @@ +#include mobile_common_System.Core.dll.sources +#include interpreter_System.Core.dll.sources diff --git a/mcs/class/System.Core/monodroid_System.Core.dll.sources b/mcs/class/System.Core/monodroid_System.Core.dll.sources index c681f5a1f8b..7228e910c42 100644 --- a/mcs/class/System.Core/monodroid_System.Core.dll.sources +++ b/mcs/class/System.Core/monodroid_System.Core.dll.sources @@ -1,4 +1,4 @@ -#include mobile_System.Core.dll.sources +#include mobile_common_System.Core.dll.sources #include dynamic_System.Core.dll.sources diff --git a/mcs/class/System.Core/monotouch_System.Core.dll.sources b/mcs/class/System.Core/monotouch_System.Core.dll.sources index fad05a08f1c..1296c8186d0 100644 --- a/mcs/class/System.Core/monotouch_System.Core.dll.sources +++ b/mcs/class/System.Core/monotouch_System.Core.dll.sources @@ -1,3 +1,3 @@ -#include mobile_System.Core.dll.sources +#include mobile_common_System.Core.dll.sources #include interpreter_System.Core.dll.sources System/TimeZoneInfo.MonoTouch.cs diff --git a/mcs/class/System.Core/xammac_System.Core.dll.sources b/mcs/class/System.Core/xammac_System.Core.dll.sources index 6ede304927a..5cd8ddf660b 100644 --- a/mcs/class/System.Core/xammac_System.Core.dll.sources +++ b/mcs/class/System.Core/xammac_System.Core.dll.sources @@ -1,4 +1,4 @@ -#include mobile_System.Core.dll.sources +#include mobile_common_System.Core.dll.sources #include dynamic_System.Core.dll.sources diff --git a/mcs/class/System.Data.OracleClient/System.Data.OracleClient.Oci/OciCalls.cs b/mcs/class/System.Data.OracleClient/System.Data.OracleClient.Oci/OciCalls.cs index 3e1ce930785..e6125bf5c91 100644 --- a/mcs/class/System.Data.OracleClient/System.Data.OracleClient.Oci/OciCalls.cs +++ b/mcs/class/System.Data.OracleClient/System.Data.OracleClient.Oci/OciCalls.cs @@ -95,7 +95,7 @@ internal static extern int OCIBindByName (IntPtr stmtp, IntPtr valuep, int value_sz, [MarshalAs (UnmanagedType.U2)] OciDataType dty, - ref short indp, + IntPtr indp, IntPtr alenp, IntPtr rcodep, uint maxarr_len, @@ -111,7 +111,7 @@ internal static extern int OCIBindByNameRef (IntPtr stmtp, ref IntPtr valuep, int value_sz, [MarshalAs (UnmanagedType.U2)] OciDataType dty, - ref short indp, + IntPtr indp, IntPtr alenp, IntPtr rcodep, uint maxarr_len, @@ -127,7 +127,7 @@ internal static extern int OCIBindByNameBytes (IntPtr stmtp, byte[] valuep, int value_sz, [MarshalAs (UnmanagedType.U2)] OciDataType dty, - ref short indp, + IntPtr indp, IntPtr alenp, IntPtr rcodep, uint maxarr_len, @@ -142,7 +142,7 @@ internal static extern int OCIBindByPos (IntPtr stmtp, IntPtr valuep, int value_sz, [MarshalAs (UnmanagedType.U2)] OciDataType dty, - ref short indp, + IntPtr indp, IntPtr alenp, IntPtr rcodep, uint maxarr_len, @@ -157,7 +157,7 @@ internal static extern int OCIBindByPosBytes (IntPtr stmtp, byte[] valuep, int value_sz, [MarshalAs (UnmanagedType.U2)] OciDataType dty, - ref short indp, + IntPtr indp, IntPtr alenp, IntPtr rcodep, uint maxarr_len, @@ -172,7 +172,7 @@ internal static extern int OCIBindByPosRef (IntPtr stmtp, ref IntPtr valuep, int value_sz, [MarshalAs (UnmanagedType.U2)] OciDataType dty, - ref short indp, + IntPtr indp, IntPtr alenp, IntPtr rcodep, uint maxarr_len, @@ -193,8 +193,8 @@ internal static extern int OCIDefineByPos (IntPtr stmtp, IntPtr valuep, int value_sz, [MarshalAs (UnmanagedType.U4)] OciDataType dty, - ref short indp, - ref short rlenp, + IntPtr indp, + IntPtr rlenp, IntPtr rcodep, uint mode); @@ -206,8 +206,8 @@ internal static extern int OCIDefineByPosPtr (IntPtr stmtp, ref IntPtr valuep, int value_sz, [MarshalAs (UnmanagedType.U4)] OciDataType dty, - ref short indp, - ref short rlenp, + IntPtr indp, + IntPtr rlenp, IntPtr rcodep, uint mode); @@ -547,7 +547,7 @@ internal static int OCIBindByName (IntPtr stmtp, IntPtr valuep, int value_sz, OciDataType dty, - ref short indp, + IntPtr indp, IntPtr alenp, IntPtr rcodep, uint maxarr_len, @@ -558,7 +558,7 @@ internal static int OCIBindByName (IntPtr stmtp, Trace.WriteLineIf(traceOci, "OCIBindByName", "OCI"); #endif return OciNativeCalls.OCIBindByName (stmtp, out bindpp, errhp, placeholder, placeh_len, valuep, - value_sz, dty, ref indp, alenp, rcodep, maxarr_len, curelp, mode); + value_sz, dty, indp, alenp, rcodep, maxarr_len, curelp, mode); } internal static int OCIBindByNameRef (IntPtr stmtp, @@ -569,7 +569,7 @@ internal static int OCIBindByNameRef (IntPtr stmtp, ref IntPtr valuep, int value_sz, OciDataType dty, - ref short indp, + IntPtr indp, IntPtr alenp, IntPtr rcodep, uint maxarr_len, @@ -580,7 +580,7 @@ internal static int OCIBindByNameRef (IntPtr stmtp, Trace.WriteLineIf(traceOci, "OCIBindByName", "OCI"); #endif return OciNativeCalls.OCIBindByNameRef (stmtp, out bindpp, errhp, placeholder, placeh_len, ref valuep, - value_sz, dty, ref indp, alenp, rcodep, maxarr_len, curelp, mode); + value_sz, dty, indp, alenp, rcodep, maxarr_len, curelp, mode); } internal static int OCIBindByNameBytes (IntPtr stmtp, @@ -591,7 +591,7 @@ internal static int OCIBindByNameBytes (IntPtr stmtp, byte[] valuep, int value_sz, [MarshalAs (UnmanagedType.U2)] OciDataType dty, - ref short indp, + IntPtr indp, IntPtr alenp, IntPtr rcodep, uint maxarr_len, @@ -602,7 +602,7 @@ internal static int OCIBindByNameBytes (IntPtr stmtp, Trace.WriteLineIf(traceOci, "OCIBindByName", "OCI"); #endif return OciNativeCalls.OCIBindByNameBytes (stmtp, out bindpp, errhp, placeholder, placeh_len, valuep, - value_sz, dty, ref indp, alenp, rcodep, maxarr_len, curelp, mode); + value_sz, dty, indp, alenp, rcodep, maxarr_len, curelp, mode); } internal static int OCIBindByPos (IntPtr stmtp, @@ -612,7 +612,7 @@ internal static int OCIBindByPos (IntPtr stmtp, IntPtr valuep, int value_sz, [MarshalAs (UnmanagedType.U2)] OciDataType dty, - ref short indp, + IntPtr indp, IntPtr alenp, IntPtr rcodep, uint maxarr_len, @@ -623,7 +623,7 @@ internal static int OCIBindByPos (IntPtr stmtp, Trace.WriteLineIf(traceOci, "OCIBindByPos", "OCI"); #endif return OciNativeCalls.OCIBindByPos (stmtp, out bindpp, errhp, position, valuep, - value_sz, dty, ref indp, alenp, rcodep, maxarr_len, curelp, mode); + value_sz, dty, indp, alenp, rcodep, maxarr_len, curelp, mode); } internal static int OCIBindByPosRef (IntPtr stmtp, @@ -633,7 +633,7 @@ internal static int OCIBindByPosRef (IntPtr stmtp, ref IntPtr valuep, int value_sz, [MarshalAs (UnmanagedType.U2)] OciDataType dty, - ref short indp, + IntPtr indp, IntPtr alenp, IntPtr rcodep, uint maxarr_len, @@ -644,7 +644,7 @@ internal static int OCIBindByPosRef (IntPtr stmtp, Trace.WriteLineIf(traceOci, "OCIBindByPos", "OCI"); #endif return OciNativeCalls.OCIBindByPosRef (stmtp, out bindpp, errhp, position, ref valuep, - value_sz, dty, ref indp, alenp, rcodep, maxarr_len, curelp, mode); + value_sz, dty, indp, alenp, rcodep, maxarr_len, curelp, mode); } internal static int OCIBindByPosBytes (IntPtr stmtp, @@ -654,7 +654,7 @@ internal static int OCIBindByPosBytes (IntPtr stmtp, byte[] valuep, int value_sz, [MarshalAs (UnmanagedType.U2)] OciDataType dty, - ref short indp, + IntPtr indp, IntPtr alenp, IntPtr rcodep, uint maxarr_len, @@ -665,7 +665,7 @@ internal static int OCIBindByPosBytes (IntPtr stmtp, Trace.WriteLineIf(traceOci, "OCIBindByPos", "OCI"); #endif return OciNativeCalls.OCIBindByPosBytes (stmtp, out bindpp, errhp, position, valuep, - value_sz, dty, ref indp, alenp, rcodep, maxarr_len, curelp, mode); + value_sz, dty, indp, alenp, rcodep, maxarr_len, curelp, mode); } [DllImport ("oci")] @@ -723,8 +723,8 @@ internal static int OCIDefineByPos (IntPtr stmtp, IntPtr valuep, int value_sz, OciDataType dty, - ref short indp, - ref short rlenp, + IntPtr indp, + IntPtr rlenp, IntPtr rcodep, uint mode) { @@ -732,7 +732,7 @@ internal static int OCIDefineByPos (IntPtr stmtp, Trace.WriteLineIf(traceOci, "OCIDefineByPos", "OCI"); #endif return OciNativeCalls.OCIDefineByPos (stmtp, out defnpp, errhp, position, valuep, - value_sz, dty, ref indp, ref rlenp, rcodep, mode); + value_sz, dty, indp, rlenp, rcodep, mode); } internal static int OCIDefineByPosPtr (IntPtr stmtp, @@ -742,8 +742,8 @@ internal static int OCIDefineByPosPtr (IntPtr stmtp, ref IntPtr valuep, int value_sz, OciDataType dty, - ref short indp, - ref short rlenp, + IntPtr indp, + IntPtr rlenp, IntPtr rcodep, uint mode) { @@ -751,7 +751,7 @@ internal static int OCIDefineByPosPtr (IntPtr stmtp, Trace.WriteLineIf(traceOci, "OCIDefineByPosPtr", "OCI"); #endif return OciNativeCalls.OCIDefineByPosPtr (stmtp, out defnpp, errhp, position, ref valuep, - value_sz, dty, ref indp, ref rlenp, rcodep, mode); + value_sz, dty, indp, rlenp, rcodep, mode); } internal static int OCIDescriptorFree (IntPtr hndlp, diff --git a/mcs/class/System.Data.OracleClient/System.Data.OracleClient.Oci/OciDefineHandle.cs b/mcs/class/System.Data.OracleClient/System.Data.OracleClient.Oci/OciDefineHandle.cs index baf90c1865f..9f46f98509b 100644 --- a/mcs/class/System.Data.OracleClient/System.Data.OracleClient.Oci/OciDefineHandle.cs +++ b/mcs/class/System.Data.OracleClient/System.Data.OracleClient.Oci/OciDefineHandle.cs @@ -32,16 +32,16 @@ internal sealed class OciDefineHandle : OciHandle, IDisposable //IntPtr handle; IntPtr value; - short indicator; + IntPtr indicator; //OracleType type; OciDataType ociType; OciDataType definedType; int definedSize; - short rlenp = 0; + IntPtr rlenp; //short precision; short scale; Type fieldType; - //string name; + string name; // Oracle defines the LONG VARCHAR and LONG VARRAW to have a size of 2 to the 31 power - 5 // see DefineLongVarChar and DefineLongVarRaw @@ -70,11 +70,13 @@ internal void DefineByPosition (int position, OracleConnection connection) { OciParameterDescriptor parameter = ((OciStatementHandle) Parent).GetParameter (position); - //name = parameter.GetName (); + name = parameter.GetName (); definedType = parameter.GetDataType (); definedSize = parameter.GetDataSize (); //precision = parameter.GetPrecision (); scale = parameter.GetScale (); + rlenp = OciCalls.AllocateClear (sizeof(short)); + indicator = OciCalls.AllocateClear (sizeof(short)); Define (position, connection); @@ -103,7 +105,7 @@ internal OciErrorHandle ErrorHandle { } internal bool IsNull { - get { return (indicator == -1); } + get { return (Indicator == -1); } } internal short Scale { @@ -111,7 +113,13 @@ internal short Scale { } internal short Size { - get { return rlenp; } + get { return(Marshal.ReadInt16(rlenp)); } + set { Marshal.WriteInt16(rlenp, value); } + } + + internal short Indicator { + get { return(Marshal.ReadInt16(indicator)); } + set { Marshal.WriteInt16(indicator, value); } } internal IntPtr Value { @@ -192,8 +200,8 @@ void DefineTimeStamp (int position, OracleConnection connection) ref value, definedSize, ociType, - ref indicator, - ref rlenp, + indicator, + rlenp, IntPtr.Zero, 0); @@ -222,8 +230,8 @@ void DefineDate (int position, OracleConnection connection) value, definedSize, ociType, - ref indicator, - ref rlenp, + indicator, + rlenp, IntPtr.Zero, 0); @@ -261,11 +269,11 @@ void DefineLongVarChar (int position, OracleConnection connection) value, definedSize, ociType, - ref indicator, - ref rlenp, + indicator, + rlenp, IntPtr.Zero, 0); - rlenp = (short) definedSize; + Size = (short) definedSize; if (status != 0) { OciErrorInfo info = ErrorHandle.HandleError (); @@ -291,8 +299,8 @@ void DefineChar (int position, OracleConnection connection) value, maxByteCount, ociType, - ref indicator, - ref rlenp, + indicator, + rlenp, IntPtr.Zero, 0); OciErrorHandle.ThrowExceptionIfError (ErrorHandle, status); @@ -312,10 +320,10 @@ void DefineNumber (int position, OracleConnection connection) ErrorHandle, position + 1, value, - definedSize * 2, + definedSize, ociType, - ref indicator, - ref rlenp, + indicator, + rlenp, IntPtr.Zero, 0); @@ -357,8 +365,8 @@ void DefineLob (int position, OciDataType type, OracleConnection connection) ref value, definedSize, ociType, - ref indicator, - ref rlenp, + indicator, + rlenp, IntPtr.Zero, 0); @@ -386,8 +394,8 @@ void DefineRaw (int position, OracleConnection connection) value, definedSize, ociType, - ref indicator, - ref rlenp, + indicator, + rlenp, IntPtr.Zero, 0); if (status != 0) { @@ -415,8 +423,8 @@ void DefineLongVarRaw (int position, OracleConnection connection) value, definedSize, ociType, - ref indicator, - ref rlenp, + indicator, + rlenp, IntPtr.Zero, 0); if (status != 0) { @@ -459,8 +467,8 @@ void DefineInterval (int position, OciDataType type, OracleConnection connection ref value, definedSize, ociType, - ref indicator, - ref rlenp, + indicator, + rlenp, IntPtr.Zero, 0); @@ -487,6 +495,8 @@ protected override void Dispose (bool disposing) } disposed = true; } finally { + Marshal.FreeHGlobal (indicator); + Marshal.FreeHGlobal (rlenp); base.Dispose (disposing); value = IntPtr.Zero; } diff --git a/mcs/class/System.Data.OracleClient/System.Data.OracleClient/OracleParameter.cs b/mcs/class/System.Data.OracleClient/System.Data.OracleClient/OracleParameter.cs index 6f11d970f0d..ef5eb270207 100644 --- a/mcs/class/System.Data.OracleClient/System.Data.OracleClient/OracleParameter.cs +++ b/mcs/class/System.Data.OracleClient/System.Data.OracleClient/OracleParameter.cs @@ -37,12 +37,13 @@ namespace System.Data.OracleClient { [TypeConverter (typeof(OracleParameter.OracleParameterConverter))] - public sealed class OracleParameter : + public sealed class OracleParameter : #if NET_2_0 - DbParameter, IDbDataParameter, ICloneable + DbParameter, IDbDataParameter, ICloneable, #else - MarshalByRefObject, IDbDataParameter, IDataParameter, ICloneable + MarshalByRefObject, IDbDataParameter, IDataParameter, ICloneable, #endif + IDisposable { #region Fields @@ -66,6 +67,7 @@ public sealed class OracleParameter : object value = DBNull.Value; OciLobLocator lobLocator; // only if Blob or Clob IntPtr bindOutValue = IntPtr.Zero; + IntPtr indicator = IntPtr.Zero; OciDateTimeDescriptor dateTimeDesc; IntPtr cursor = IntPtr.Zero; @@ -77,7 +79,6 @@ public sealed class OracleParameter : bool useRef; OciDataType bindType; - short indicator; int bindSize; bool sizeManuallySet; @@ -104,6 +105,7 @@ private OracleParameter (OracleParameter value) this.value = value.value; this.lobLocator = value.lobLocator; this.oracleTypeSet = value.oracleTypeSet; + this.indicator = OciCalls.AllocateClear (sizeof(short)); } public OracleParameter () @@ -119,6 +121,7 @@ public OracleParameter () this.srcVersion = DataRowVersion.Current; this.value = null; this.oracleTypeSet = false; + this.indicator = OciCalls.AllocateClear (sizeof(short)); } public OracleParameter (string name, object value) @@ -129,6 +132,7 @@ public OracleParameter (string name, object value) srcColumn = string.Empty; SourceVersion = DataRowVersion.Current; InferOracleType (value); + this.indicator = OciCalls.AllocateClear (sizeof(short)); #if NET_2_0 // Find the OciType before inferring for the size if (value != null && value != DBNull.Value) { @@ -173,6 +177,7 @@ public OracleParameter (string name, OracleType oracleType, int size, ParameterD OracleType = oracleType; SourceColumn = sourceColumn; SourceVersion = sourceVersion; + this.indicator = OciCalls.AllocateClear (sizeof(short)); } #endif @@ -199,6 +204,12 @@ public OracleParameter (string name, OracleType oracleType, int size, ParameterD OracleType = oracleType; SourceColumn = srcColumn; SourceVersion = srcVersion; + this.indicator = OciCalls.AllocateClear (sizeof(short)); + } + + ~OracleParameter () + { + Dispose(false); } #endregion // Constructors @@ -210,6 +221,11 @@ internal OracleParameterCollection Container { set { container = value; } } + internal short Indicator { + get { return (Marshal.ReadInt16(indicator)); } + set { Marshal.WriteInt16(indicator, value); } + } + #if !NET_2_0 [Browsable (false)] [RefreshProperties (RefreshProperties.All)] @@ -453,7 +469,6 @@ internal void Bind (OciStatementHandle statement, OracleConnection con, uint pos } if (isnull == true && direction == ParameterDirection.Input) { - indicator = 0; bindType = OciDataType.VarChar2; bindSize = 0; } else { @@ -465,7 +480,6 @@ internal void Bind (OciStatementHandle statement, OracleConnection con, uint pos case OciDataType.CharZ: case OciDataType.OciString: bindType = OciDataType.String; - indicator = 0; svalue = "\0"; // convert value from managed type to type to marshal if (direction == ParameterDirection.Input || @@ -558,7 +572,7 @@ internal void Bind (OciStatementHandle statement, OracleConnection con, uint pos dt = DateTime.MinValue; sDate = ""; if (isnull) - indicator = -1; + Indicator = -1; else if (v is String) { sDate = (string) v; dt = DateTime.Parse (sDate); @@ -594,7 +608,7 @@ internal void Bind (OciStatementHandle statement, OracleConnection con, uint pos case OciDataType.Float: case OciDataType.Number: bindType = OciDataType.String; - indicator = 0; + Indicator = 0; svalue = "\0"; // convert value from managed type to type to marshal if (direction == ParameterDirection.Input || @@ -638,7 +652,7 @@ internal void Bind (OciStatementHandle statement, OracleConnection con, uint pos bindSize = Size + 5; // 4 bytes prepended for length, bytes, 1 byte NUL character - indicator = 0; + Indicator = 0; svalue = "\0"; // convert value from managed type to type to marshal if (direction == ParameterDirection.Input || @@ -758,7 +772,7 @@ internal void Bind (OciStatementHandle statement, OracleConnection con, uint pos case OciDataType.VarRaw: bindType = OciDataType.VarRaw; bindSize = Size + 2; // include 2 bytes prepended to hold the length - indicator = 0; + Indicator = 0; bytes = new byte [bindSize]; if (direction == ParameterDirection.Input || direction == ParameterDirection.InputOutput) { @@ -784,7 +798,7 @@ internal void Bind (OciStatementHandle statement, OracleConnection con, uint pos case OciDataType.LongVarRaw: bindType = OciDataType.LongVarRaw; bindSize = Size + 4; // include 4 bytes prepended to hold the length - indicator = 0; + Indicator = 0; bytes = new byte [bindSize]; if (direction == ParameterDirection.Input || direction == ParameterDirection.InputOutput) { @@ -854,7 +868,7 @@ internal void Bind (OciStatementHandle statement, OracleConnection con, uint pos ref bindValue, bindSize, bindType, - ref indicator, + indicator, IntPtr.Zero, IntPtr.Zero, 0, @@ -870,7 +884,7 @@ internal void Bind (OciStatementHandle statement, OracleConnection con, uint pos ref bindValue, bindSize, bindType, - ref indicator, + indicator, IntPtr.Zero, IntPtr.Zero, 0, @@ -887,7 +901,7 @@ internal void Bind (OciStatementHandle statement, OracleConnection con, uint pos ref cursor, bindSize, bindType, - ref indicator, + indicator, IntPtr.Zero, IntPtr.Zero, 0, @@ -903,7 +917,7 @@ internal void Bind (OciStatementHandle statement, OracleConnection con, uint pos bytes, bindSize, bindType, - ref indicator, + indicator, IntPtr.Zero, IntPtr.Zero, 0, @@ -919,7 +933,7 @@ internal void Bind (OciStatementHandle statement, OracleConnection con, uint pos bindValue, bindSize, bindType, - ref indicator, + indicator, IntPtr.Zero, IntPtr.Zero, 0, @@ -1251,7 +1265,7 @@ private void GetOutValue (OracleCommand cmd) // used to update the parameter value // for Output, the output of InputOutput, and Return parameters value = DBNull.Value; - if (indicator == -1) + if (Indicator == -1) return; int rsize = 0; @@ -1453,6 +1467,22 @@ private byte[] PackDate (DateTime dateValue) return buffer; } + public void Dispose () + { + Dispose (true); + } + + void Dispose (bool disposing) + { + if (disposing) { + GC.SuppressFinalize(this); + } + if (indicator != IntPtr.Zero) { + Marshal.FreeHGlobal (indicator); + indicator = IntPtr.Zero; + } + } + #endregion // Methods internal sealed class OracleParameterConverter : ExpandableObjectConverter diff --git a/mcs/class/System.Data.Services.Client/mobile_System.Data.Services.Client.dll.sources b/mcs/class/System.Data.Services.Client/mobile_System.Data.Services.Client.dll.sources index 5ad9459d88a..37dc2990c8d 100644 --- a/mcs/class/System.Data.Services.Client/mobile_System.Data.Services.Client.dll.sources +++ b/mcs/class/System.Data.Services.Client/mobile_System.Data.Services.Client.dll.sources @@ -1,2 +1 @@ -#include System.Data.Services.Client.dll.sources -./Client/AssemblyAttributes.cs +#include net_4_5_System.Data.Services.Client.dll.sources diff --git a/mcs/class/System.Data.Services/Test/ChangeInterceptorAttributeTests.cs b/mcs/class/System.Data.Services/Test/ChangeInterceptorAttributeTests.cs index d8d0e157a8e..3cc769d05e3 100644 --- a/mcs/class/System.Data.Services/Test/ChangeInterceptorAttributeTests.cs +++ b/mcs/class/System.Data.Services/Test/ChangeInterceptorAttributeTests.cs @@ -26,9 +26,11 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // +using System; +using System.Data.Services; using NUnit.Framework; -namespace System.Data.Services.Tests { +namespace MonoTests.System.Data.Services { [TestFixture] public class ChangeInterceptorAttributeTests { [Test] @@ -45,4 +47,4 @@ public void Ctor() Assert.AreEqual ("setName", ci.EntitySetName); } } -} \ No newline at end of file +} diff --git a/mcs/class/System.Data.Services/Test/DataServiceExceptionTests.cs b/mcs/class/System.Data.Services/Test/DataServiceExceptionTests.cs index 6058fc3e386..5f9758a44c5 100644 --- a/mcs/class/System.Data.Services/Test/DataServiceExceptionTests.cs +++ b/mcs/class/System.Data.Services/Test/DataServiceExceptionTests.cs @@ -26,9 +26,11 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // +using System; +using System.Data.Services; using NUnit.Framework; -namespace System.Data.Services.Tests { +namespace MonoTests.System.Data.Services { [TestFixture] public class DataServiceExceptionTests { [Test] @@ -68,4 +70,4 @@ public void CtorStatusAndErrorMessageLanguageException() Assert.AreEqual (inner, ex.InnerException); } } -} \ No newline at end of file +} diff --git a/mcs/class/System.Data.Services/Test/DataServiceTests.cs b/mcs/class/System.Data.Services/Test/DataServiceTests.cs index 58b67859593..2bcc6a9dd75 100644 --- a/mcs/class/System.Data.Services/Test/DataServiceTests.cs +++ b/mcs/class/System.Data.Services/Test/DataServiceTests.cs @@ -26,9 +26,11 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // +using System; +using System.Data.Services; using NUnit.Framework; -namespace System.Data.Services.Tests { +namespace MonoTests.System.Data.Services { [TestFixture] public class DataServiceTests { [Test] @@ -79,4 +81,4 @@ public void TestOnStartProcessingRequest (ProcessRequestArgs args) this.OnStartProcessingRequest (args); } } -} \ No newline at end of file +} diff --git a/mcs/class/System.Data.Services/Test/ETagAttributeTests.cs b/mcs/class/System.Data.Services/Test/ETagAttributeTests.cs index 8b40de6c5bd..706e02c6992 100644 --- a/mcs/class/System.Data.Services/Test/ETagAttributeTests.cs +++ b/mcs/class/System.Data.Services/Test/ETagAttributeTests.cs @@ -26,10 +26,12 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // +using System; +using System.Data.Services; using System.Linq; using NUnit.Framework; -namespace System.Data.Services.Tests { +namespace MonoTests.System.Data.Services { [TestFixture] public class ETagAttributeTests { [Test] @@ -63,4 +65,4 @@ public void CtorPropertyNames() Assert.AreEqual ("bar", e.PropertyNames[1]); } } -} \ No newline at end of file +} diff --git a/mcs/class/System.Data.Services/Test/ExpandSegmentCollectionTests.cs b/mcs/class/System.Data.Services/Test/ExpandSegmentCollectionTests.cs index e0eb629d5be..cd5e9a1d31f 100644 --- a/mcs/class/System.Data.Services/Test/ExpandSegmentCollectionTests.cs +++ b/mcs/class/System.Data.Services/Test/ExpandSegmentCollectionTests.cs @@ -26,10 +26,11 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // +using System.Data.Services; using System.Linq.Expressions; using NUnit.Framework; -namespace System.Data.Services.Tests { +namespace MonoTests.System.Data.Services { [TestFixture] public class ExpandSegmentCollectionTests { [Test] @@ -101,4 +102,4 @@ public void HasFilterRemoveFilteredMultiple() Assert.IsFalse (esc.HasFilter); } } -} \ No newline at end of file +} diff --git a/mcs/class/System.Data.Services/Test/ExpandSegmentTests.cs b/mcs/class/System.Data.Services/Test/ExpandSegmentTests.cs index f64faa8fad2..ce6712c94e0 100644 --- a/mcs/class/System.Data.Services/Test/ExpandSegmentTests.cs +++ b/mcs/class/System.Data.Services/Test/ExpandSegmentTests.cs @@ -26,10 +26,12 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // +using System; +using System.Data.Services; using System.Linq.Expressions; using NUnit.Framework; -namespace System.Data.Services.Tests { +namespace MonoTests.System.Data.Services { [TestFixture] public class ExpandSegmentTests { [Test] @@ -84,4 +86,4 @@ public void PathDoesntHaveFilter() { new ExpandSegment ("first", null), new ExpandSegment ("second", null), new ExpandSegment ("third", null) })); } } -} \ No newline at end of file +} diff --git a/mcs/class/System.Data.Services/Test/IgnorePropertiesAttributeTests.cs b/mcs/class/System.Data.Services/Test/IgnorePropertiesAttributeTests.cs index 04c17e3d3ce..090b3bf64bd 100644 --- a/mcs/class/System.Data.Services/Test/IgnorePropertiesAttributeTests.cs +++ b/mcs/class/System.Data.Services/Test/IgnorePropertiesAttributeTests.cs @@ -26,10 +26,12 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // +using System; +using System.Data.Services; using System.Linq; using NUnit.Framework; -namespace System.Data.Services.Tests { +namespace MonoTests.System.Data.Services { [TestFixture] public class IgnorePropertiesAttributeTests { [Test] @@ -63,4 +65,4 @@ public void CtorPropertyNames() Assert.AreEqual ("bar", e.PropertyNames[1]); } } -} \ No newline at end of file +} diff --git a/mcs/class/System.Data.Services/Test/MimeTypeAttributeTests.cs b/mcs/class/System.Data.Services/Test/MimeTypeAttributeTests.cs index 6b5533ffa50..824cab9fcb1 100644 --- a/mcs/class/System.Data.Services/Test/MimeTypeAttributeTests.cs +++ b/mcs/class/System.Data.Services/Test/MimeTypeAttributeTests.cs @@ -26,9 +26,10 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // +using System.Data.Services; using NUnit.Framework; -namespace System.Data.Services.Tests { +namespace MonoTests.System.Data.Services { [TestFixture] public class MimeTypeAttributeTests { [Test] @@ -39,4 +40,4 @@ public void Ctor() Assert.AreEqual ("type", mt.MimeType); } } -} \ No newline at end of file +} diff --git a/mcs/class/System.Data.Services/Test/QueryInterceptorAttributeTests.cs b/mcs/class/System.Data.Services/Test/QueryInterceptorAttributeTests.cs index b483fbe1cdd..e4b0147cccd 100644 --- a/mcs/class/System.Data.Services/Test/QueryInterceptorAttributeTests.cs +++ b/mcs/class/System.Data.Services/Test/QueryInterceptorAttributeTests.cs @@ -26,9 +26,11 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // +using System; +using System.Data.Services; using NUnit.Framework; -namespace System.Data.Services.Tests { +namespace MonoTests.System.Data.Services { [TestFixture] public class QueryInterceptorAttributeTests { [Test] @@ -45,4 +47,4 @@ public void CtorNull() new QueryInterceptorAttribute (null); } } -} \ No newline at end of file +} diff --git a/mcs/class/System.Data/System.Data-net_4_5.csproj b/mcs/class/System.Data/System.Data-net_4_5.csproj index 95dead37499..eb65112a417 100644 --- a/mcs/class/System.Data/System.Data-net_4_5.csproj +++ b/mcs/class/System.Data/System.Data-net_4_5.csproj @@ -206,6 +206,7 @@ + diff --git a/mcs/class/System.Data/System.Data.SqlClient/SqlConnection.cs b/mcs/class/System.Data/System.Data.SqlClient/SqlConnection.cs index 8712eca6cf9..e1fa878c4ca 100644 --- a/mcs/class/System.Data/System.Data.SqlClient/SqlConnection.cs +++ b/mcs/class/System.Data/System.Data.SqlClient/SqlConnection.cs @@ -56,6 +56,7 @@ #if NET_2_0 using System.Collections.Generic; #endif +using System.Security; namespace System.Data.SqlClient { @@ -93,6 +94,9 @@ public sealed class SqlConnection : Component, IDbConnection, ICloneable // The connection string that identifies this connection string connectionString; + // The connection credentials + SqlCredential credentials; + // The transaction object for the current transaction SqlTransaction transaction; @@ -133,6 +137,12 @@ public SqlConnection (string connectionString) ConnectionString = connectionString; } + public SqlConnection (string connectionString, SqlCredential cred) + { + ConnectionString = connectionString; + Credentials = cred; + } + #endregion // Constructors #region Properties @@ -155,6 +165,15 @@ public override string ConnectionString { } } + public SqlCredential Credentials { + get { + return credentials; + } + set { + credentials = value; + } + } + #if !NET_2_0 [DataSysDescription ("Current connection timeout value, 'Connect Timeout=X' in the ConnectionString.")] #endif @@ -563,6 +582,16 @@ void Open () if (!tds.IsConnected) { try { + if (Credentials != null) { + if (parms.User != String.Empty) + throw new ArgumentException("UserID already specified"); + if (parms.PasswordSet) + throw new ArgumentException("Password already specified"); + if (parms.DomainLogin != false) + throw new ArgumentException("Cannot use credentials with DomainLogin"); + parms.User = Credentials.UserId; + parms.Password = Credentials.Password; + } tds.Connect (parms); } catch { if (pooling) @@ -879,7 +908,10 @@ private void SetProperties (string name , string value) break; case "password" : case "pwd" : - parms.Password = value; + parms.Password = new SecureString(); + foreach (char c in value) + parms.Password.AppendChar(c); + parms.PasswordSet = true; break; case "persistsecurityinfo" : case "persist security info" : diff --git a/mcs/class/System.Data/System.Data.SqlClient/SqlCredential.cs b/mcs/class/System.Data/System.Data.SqlClient/SqlCredential.cs new file mode 100644 index 00000000000..5b15b48cb66 --- /dev/null +++ b/mcs/class/System.Data/System.Data.SqlClient/SqlCredential.cs @@ -0,0 +1,76 @@ +// +// System.Data.SqlClient.SqlCredential.cs +// +// Author: +// Neale Ferguson (neale@sinenomine.net) +// +// Copyright (C) Neale Ferguson, 2014 +// + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Data; +using System.Runtime.InteropServices; +using System.Security; + +namespace System.Data.SqlClient { + /// + /// Describes an error from a SQL database. + /// + [Serializable] + public sealed class SqlCredential + { + #region Fields + + string uid = ""; + SecureString pwd = null; + + #endregion // Fields + + #region Constructors + + public SqlCredential (string user, SecureString password) + { + if (user == null) + throw new ArgumentNullException("UserID"); + if (password == null) + throw new ArgumentNullException("Password"); + this.uid = user; + this.pwd = password; + } + + #endregion // Constructors + + #region Properties + + public string UserId { + get { return uid; } + } + + public SecureString Password { + get { return pwd; } + } + + #endregion + } +} diff --git a/mcs/class/System.Data/System.Data.dll.sources b/mcs/class/System.Data/System.Data.dll.sources index aeae903dbc9..5ec88803ea6 100644 --- a/mcs/class/System.Data/System.Data.dll.sources +++ b/mcs/class/System.Data/System.Data.dll.sources @@ -289,6 +289,7 @@ System.Data.SqlClient/SqlCommand.cs System.Data.SqlClient/SqlCommandBuilder.cs System.Data.SqlClient/SqlConnection.cs System.Data.SqlClient/SqlConnectionStringBuilder.cs +System.Data.SqlClient/SqlCredential.cs System.Data.SqlClient/SqlDataAdapter.cs System.Data.SqlClient/SqlDataReader.cs System.Data.SqlClient/SqlDataSourceConverter.cs diff --git a/mcs/class/System.Data/Test/System.Data.Common/DbDataReaderMock.cs b/mcs/class/System.Data/Test/System.Data.Common/DbDataReaderMock.cs index 5d561b44dd5..2957cd73deb 100644 --- a/mcs/class/System.Data/Test/System.Data.Common/DbDataReaderMock.cs +++ b/mcs/class/System.Data/Test/System.Data.Common/DbDataReaderMock.cs @@ -31,7 +31,7 @@ using System.Data.Common; using System.IO; -namespace Test.System.Data.Common +namespace MonoTests.System.Data.Common { internal class DbDataReaderMock : DbDataReader { diff --git a/mcs/class/System.Data/Test/System.Data.Common/DbDataReaderTest.cs b/mcs/class/System.Data/Test/System.Data.Common/DbDataReaderTest.cs index 0a7235f1b90..20d5c1ab0bf 100644 --- a/mcs/class/System.Data/Test/System.Data.Common/DbDataReaderTest.cs +++ b/mcs/class/System.Data/Test/System.Data.Common/DbDataReaderTest.cs @@ -32,7 +32,7 @@ using System.Data.Common; using System.IO; -namespace Test.System.Data.Common +namespace MonoTests.System.Data.Common { [TestFixture] public class DbDataReaderTest diff --git a/mcs/class/System.Data/Test/System.Data/BinarySerializationTest.cs b/mcs/class/System.Data/Test/System.Data/BinarySerializationTest.cs index 5eae92a3963..efbe64a1a4a 100644 --- a/mcs/class/System.Data/Test/System.Data/BinarySerializationTest.cs +++ b/mcs/class/System.Data/Test/System.Data/BinarySerializationTest.cs @@ -12,6 +12,8 @@ using NUnit.Framework; +namespace MonoTests.System.Data +{ [TestFixture] public class BinarySerializationTest { @@ -751,3 +753,4 @@ ds1.Tables [3].Constraints [i].GetType (), } #endif +} diff --git a/mcs/class/System.Data/Test/System.Data/ConstraintExceptionTest.cs b/mcs/class/System.Data/Test/System.Data/ConstraintExceptionTest.cs index c98a03c5aa4..fe575137ea4 100644 --- a/mcs/class/System.Data/Test/System.Data/ConstraintExceptionTest.cs +++ b/mcs/class/System.Data/Test/System.Data/ConstraintExceptionTest.cs @@ -33,7 +33,7 @@ using System.Data; using MonoTests.System.Data.Utils; -namespace MonoTests_System.Data +namespace MonoTests.System.Data { [TestFixture] public class ConstraintExceptionTest { diff --git a/mcs/class/System.Data/Test/System.Data/DBConcurrencyExceptionTest.cs b/mcs/class/System.Data/Test/System.Data/DBConcurrencyExceptionTest.cs index bfae78d6e6e..35e876ff51f 100644 --- a/mcs/class/System.Data/Test/System.Data/DBConcurrencyExceptionTest.cs +++ b/mcs/class/System.Data/Test/System.Data/DBConcurrencyExceptionTest.cs @@ -31,7 +31,7 @@ using NUnit.Framework; -namespace MonoTests_System.Data +namespace MonoTests.System.Data { [TestFixture] public class DBConcurrencyExceptionTest diff --git a/mcs/class/System.Data/Test/System.Data/DataSetTest2.cs b/mcs/class/System.Data/Test/System.Data/DataSetTest2.cs index 27df0f58984..6e338558389 100644 --- a/mcs/class/System.Data/Test/System.Data/DataSetTest2.cs +++ b/mcs/class/System.Data/Test/System.Data/DataSetTest2.cs @@ -39,7 +39,7 @@ using System.Runtime.Serialization.Formatters.Binary; using System.Globalization; -namespace MonoTests_System.Data +namespace MonoTests.System.Data { [TestFixture] public class DataSetTest2 @@ -448,7 +448,7 @@ [Test] public void GetXml() dt.Rows.Add(new object[] {2,"Value3","Value4"}); dt.Rows.Add(new object[] {3,"Value5","Value5"}); - System.Text.StringBuilder resultXML = new System.Text.StringBuilder(); + StringBuilder resultXML = new StringBuilder(); resultXML.Append("<" + ds.DataSetName + "xmlns=\"namespace\">"); @@ -975,13 +975,13 @@ [Test] public void InferXmlSchema_elementText2() [Test] public void Locale() { DataSet ds = new DataSet("MyDataSet"); - System.Globalization.CultureInfo culInfo = System.Globalization.CultureInfo.CurrentCulture ; + CultureInfo culInfo = CultureInfo.CurrentCulture ; // Checking Locale default from system Assert.AreEqual(culInfo, ds.Locale , "DS156"); // Checking Locale get/set - culInfo = new System.Globalization.CultureInfo("fr"); // = french + culInfo = new CultureInfo("fr"); // = french ds.Locale = culInfo ; Assert.AreEqual(culInfo , ds.Locale , "DS157"); } @@ -1998,11 +1998,11 @@ [Test] public void ReadXmlSchema_ByStream() ds1.Tables.Add(DataProvider.CreateParentDataTable()); ds1.Tables.Add(DataProvider.CreateChildDataTable()); - System.IO.MemoryStream ms = new System.IO.MemoryStream(); + MemoryStream ms = new MemoryStream(); //write xml schema only ds1.WriteXmlSchema(ms); - System.IO.MemoryStream ms1 = new System.IO.MemoryStream(ms.GetBuffer()); + MemoryStream ms1 = new MemoryStream(ms.GetBuffer()); //copy schema DataSet ds2 = new DataSet(); ds2.ReadXmlSchema(ms1); @@ -2073,7 +2073,7 @@ [Test] public void ReadXmlSchema_ByFileName() Assert.AreEqual(0, ds2.Tables[1].Rows.Count , "DS282"); //try to delete the file - System.IO.File.Delete(sTempFileName); + File.Delete(sTempFileName); } [Test] public void ReadXmlSchema_ByTextReader() @@ -2082,11 +2082,11 @@ [Test] public void ReadXmlSchema_ByTextReader() ds1.Tables.Add(DataProvider.CreateParentDataTable()); ds1.Tables.Add(DataProvider.CreateChildDataTable()); - System.IO.StringWriter sw = new System.IO.StringWriter(); + StringWriter sw = new StringWriter(); //write xml file, schema only ds1.WriteXmlSchema(sw); - System.IO.StringReader sr = new System.IO.StringReader(sw.GetStringBuilder().ToString()); + StringReader sr = new StringReader(sw.GetStringBuilder().ToString()); //copy both data and schema DataSet ds2 = new DataSet(); ds2.ReadXmlSchema(sr); @@ -2122,14 +2122,14 @@ [Test] public void ReadXmlSchema_ByXmlReader() ds1.Tables.Add(DataProvider.CreateParentDataTable()); ds1.Tables.Add(DataProvider.CreateChildDataTable()); - System.IO.StringWriter sw = new System.IO.StringWriter(); - System.Xml.XmlTextWriter xmlTW = new System.Xml.XmlTextWriter(sw); + StringWriter sw = new StringWriter(); + XmlTextWriter xmlTW = new XmlTextWriter(sw); //write xml file, schema only ds1.WriteXmlSchema(xmlTW); xmlTW.Flush(); - System.IO.StringReader sr = new System.IO.StringReader(sw.ToString()); - System.Xml.XmlTextReader xmlTR = new System.Xml.XmlTextReader(sr); + StringReader sr = new StringReader(sw.ToString()); + XmlTextReader xmlTR = new XmlTextReader(sr); //copy both data and schema DataSet ds2 = new DataSet(); @@ -2196,7 +2196,7 @@ public void ReadXml_Strg() Assert.AreEqual(ds2.Tables[1].Rows.Count, ds1.Tables[1].Rows.Count , "DS299"); //try to delete the file - System.IO.File.Delete(sTempFileName); + File.Delete(sTempFileName); } [Test] @@ -2212,7 +2212,7 @@ public void ReadXml_Strm() ds1.Tables[1].Rows.Add(new object[] {7,2," "," ",new DateTime(2000,1,1,0,0,0,0),35}); ds1.Tables[1].Rows.Add(new object[] {7,3,"","",new DateTime(2000,1,1,0,0,0,0),35}); - System.IO.MemoryStream ms = new System.IO.MemoryStream(); + MemoryStream ms = new MemoryStream(); //write xml file, data only ds1.WriteXml(ms); @@ -2241,7 +2241,7 @@ [Test] public void ReadXml_Strm2() { string input = string.Empty; - System.IO.StringReader sr; + StringReader sr; DataSet ds = new DataSet(); input += ""; @@ -2261,7 +2261,7 @@ [Test] public void ReadXml_Strm2() input += " "; input += ""; - sr = new System.IO.StringReader(input); + sr = new StringReader(input); ds.ReadXml(sr); @@ -2311,7 +2311,7 @@ [Test] public void ReadXml_Strm3() { DataSet ds = new DataSet("TestDataSet"); string input = string.Empty; - System.IO.StringReader sr; + StringReader sr; input += ""; input += "10.0"; @@ -2320,7 +2320,7 @@ [Test] public void ReadXml_Strm3() input += "22.2302/12/2001"; input += "1.9704/20/20033.0"; input += "TODAY"; - sr = new System.IO.StringReader(input); + sr = new StringReader(input); ds.EnforceConstraints = false; ds.ReadXml(sr); @@ -2339,7 +2339,7 @@ [Test] public void ReadXml_Strm4() { m_ds = new DataSet("Stocks"); string input = string.Empty; - System.IO.StringReader sr; + StringReader sr; input += ""; input += ""; @@ -2408,7 +2408,7 @@ [Test] public void ReadXml_Strm4() input += " "; input += ""; - sr = new System.IO.StringReader(input); + sr = new StringReader(input); m_ds.EnforceConstraints = true; m_ds.ReadXml(sr); this.privateTestCase("TestCase 1", "Company", "name='Microsoft Corp.'", "Stock", "name='MSFT'", "DS320"); @@ -2444,14 +2444,14 @@ public void ReadXml_Strm5() #region "TestCase 1 - Empty string" // Empty string DataSet ds = new DataSet(); - System.IO.StringReader sr = new System.IO.StringReader (string.Empty); - System.Xml.XmlTextReader xReader = new System.Xml.XmlTextReader(sr); + StringReader sr = new StringReader (string.Empty); + XmlTextReader xReader = new XmlTextReader(sr); try { ds.ReadXml (xReader); Assert.Fail("DS335: ReadXml Failed to throw XmlException"); } - catch (System.Xml.XmlException) {} + catch (XmlException) {} catch (AssertionException exc) {throw exc;} catch (Exception exc) { @@ -2635,8 +2635,8 @@ public void ReadXml_Strm5() private void PrivateTestCase(string a_name, string a_expected, string a_xmlData) { DataSet ds = new DataSet(); - System.IO.StringReader sr = new System.IO.StringReader(a_xmlData) ; - System.Xml.XmlTextReader xReader = new System.Xml.XmlTextReader(sr) ; + StringReader sr = new StringReader(a_xmlData) ; + XmlTextReader xReader = new XmlTextReader(sr) ; ds.ReadXml (xReader); Assert.AreEqual(a_expected, this.dataSetDescription(ds), "DS337"); } @@ -2681,8 +2681,8 @@ [Test] public void ReadXml_Strm6() xmlData += "3"; xmlData += ""; xmlData += ""; - System.IO.StringReader sr = new System.IO.StringReader(xmlData) ; - System.Xml.XmlTextReader xReader = new System.Xml.XmlTextReader(sr) ; + StringReader sr = new StringReader(xmlData) ; + XmlTextReader xReader = new XmlTextReader(sr) ; ds.ReadXml (xReader); Assert.AreEqual(3, ds.Tables["c"].Rows.Count, "DS338"); } @@ -2738,7 +2738,7 @@ public void ReadXml_ByTextReader() ds1.Tables[1].Rows.Add(new object[] {7,2," "," ",new DateTime(2000,1,1,0,0,0,0),35}); ds1.Tables[1].Rows.Add(new object[] {7,3,"","",new DateTime(2000,1,1,0,0,0,0),35}); - System.IO.StringWriter sw = new System.IO.StringWriter(); + StringWriter sw = new StringWriter(); //write xml file, data only ds1.WriteXml(sw); @@ -2747,7 +2747,7 @@ public void ReadXml_ByTextReader() //clear the data ds2.Clear(); - System.IO.StringReader sr = new System.IO.StringReader(sw.GetStringBuilder().ToString()); + StringReader sr = new StringReader(sw.GetStringBuilder().ToString()); ds2.ReadXml(sr); //check xml data @@ -2777,8 +2777,8 @@ public void ReadXml_ByXmlReader() ds1.Tables[1].Rows.Add(new object[] {7,2," "," ",new DateTime(2000,1,1,0,0,0,0),35}); ds1.Tables[1].Rows.Add(new object[] {7,3,"","",new DateTime(2000,1,1,0,0,0,0),35}); - System.IO.StringWriter sw = new System.IO.StringWriter(); - System.Xml.XmlTextWriter xmlTW = new System.Xml.XmlTextWriter(sw); + StringWriter sw = new StringWriter(); + XmlTextWriter xmlTW = new XmlTextWriter(sw); //write xml file, data only ds1.WriteXml(xmlTW); @@ -2788,8 +2788,8 @@ public void ReadXml_ByXmlReader() DataSet ds2 = ds1.Copy(); //clear the data ds2.Clear(); - System.IO.StringReader sr = new System.IO.StringReader(sw.ToString()); - System.Xml.XmlTextReader xmlTR = new System.Xml.XmlTextReader(sr); + StringReader sr = new StringReader(sw.ToString()); + XmlTextReader xmlTR = new XmlTextReader(sr); ds2.ReadXml(xmlTR); //check xml data @@ -2847,8 +2847,8 @@ [Test] public void WriteXmlSchema_RelationAnnotation () [Test] public void WriteXmlSchema_Relations_ForeignKeys () { - System.IO.MemoryStream ms = null; - System.IO.MemoryStream ms1 = null; + MemoryStream ms = null; + MemoryStream ms1 = null; DataSet ds1 = new DataSet(); @@ -2884,10 +2884,10 @@ [Test] public void WriteXmlSchema_Relations_ForeignKeys () new DataColumn[] {col1_5, col1_6}, new DataColumn[] {col2_5, col2_6}); - ms = new System.IO.MemoryStream(); + ms = new MemoryStream(); ds1.WriteXmlSchema (ms); - ms1 = new System.IO.MemoryStream (ms.GetBuffer()); + ms1 = new MemoryStream (ms.GetBuffer()); DataSet ds2 = new DataSet(); ds2.ReadXmlSchema(ms1); @@ -3096,18 +3096,18 @@ [Test] public void Tables() [Test] public void WriteXml_ByTextWriterXmlWriteMode() { - System.IO.StringReader sr = null; - System.IO.StringWriter sw = null; + StringReader sr = null; + StringWriter sw = null; try // For real { // ReadXml - DataSetOut DataSet oDataset = new DataSet("DataSetOut"); - sw = new System.IO.StringWriter(); - oDataset.WriteXml(sw,System.Data.XmlWriteMode.WriteSchema); + sw = new StringWriter(); + oDataset.WriteXml(sw, XmlWriteMode.WriteSchema); - sr = new System.IO.StringReader(sw.GetStringBuilder().ToString()); + sr = new StringReader(sw.GetStringBuilder().ToString()); oDataset = new DataSet("DataSetOut"); oDataset.ReadXml(sr); @@ -3252,13 +3252,13 @@ public void WriteXml_Stream() { DataSet ds = new DataSet(); string input = "2"; - System.IO.StringReader sr = new System.IO.StringReader(input) ; - System.Xml.XmlTextReader xReader = new System.Xml.XmlTextReader(sr) ; + StringReader sr = new StringReader(input) ; + XmlTextReader xReader = new XmlTextReader(sr) ; ds.ReadXml (xReader); - System.Text.StringBuilder sb = new System.Text.StringBuilder(); - System.IO.StringWriter sw = new System.IO.StringWriter(sb); - System.Xml.XmlTextWriter xWriter = new System.Xml.XmlTextWriter(sw); + StringBuilder sb = new StringBuilder(); + StringWriter sw = new StringWriter(sb); + XmlTextWriter xWriter = new XmlTextWriter(sw); ds.WriteXml(xWriter); string output = sb.ToString(); Assert.AreEqual(input,output, "DS76"); @@ -3267,20 +3267,20 @@ public void WriteXml_Stream() DataSet ds = new DataSet(); string input = "2"; string expectedOutput = "2"; - System.IO.StringReader sr = new System.IO.StringReader(input) ; - System.Xml.XmlTextReader xReader = new System.Xml.XmlTextReader(sr) ; + StringReader sr = new StringReader(input) ; + XmlTextReader xReader = new XmlTextReader(sr) ; ds.ReadXml (xReader); - System.Text.StringBuilder sb = new System.Text.StringBuilder(); - System.IO.StringWriter sw = new System.IO.StringWriter(sb); - System.Xml.XmlTextWriter xWriter = new System.Xml.XmlTextWriter(sw); + StringBuilder sb = new StringBuilder(); + StringWriter sw = new StringWriter(sb); + XmlTextWriter xWriter = new XmlTextWriter(sw); ds.WriteXml(xWriter); string output = sb.ToString(); Assert.AreEqual(expectedOutput,output, "DS77"); } { DataSet ds = new DataSet("DSName"); - System.IO.StringWriter sr = new System.IO.StringWriter(); + StringWriter sr = new StringWriter(); ds.WriteXml(sr); Assert.AreEqual("",sr.ToString(), "DS78"); } @@ -3315,7 +3315,7 @@ public void WriteXml_Stream() ds.Tables.Remove("ChildTable"); //Get the xml representation of the dataset. - System.IO.StringWriter sr = new System.IO.StringWriter(); + StringWriter sr = new StringWriter(); ds.WriteXml(sr); string xml = sr.ToString(); diff --git a/mcs/class/System.Data/Test/System.Data/DataTableCollectionTest2.cs b/mcs/class/System.Data/Test/System.Data/DataTableCollectionTest2.cs index 9229265648c..053825e3501 100644 --- a/mcs/class/System.Data/Test/System.Data/DataTableCollectionTest2.cs +++ b/mcs/class/System.Data/Test/System.Data/DataTableCollectionTest2.cs @@ -28,10 +28,12 @@ using NUnit.Framework; using System; +using System.Collections; +using System.ComponentModel; using System.Data; using MonoTests.System.Data.Utils; -namespace MonoTests_System.Data +namespace MonoTests.System.Data { [TestFixture] public class DataTableCollectionTest2 { @@ -143,7 +145,7 @@ public void CollectionChanged() { counter = 0; DataSet ds = new DataSet(); - ds.Tables.CollectionChanged+=new System.ComponentModel.CollectionChangeEventHandler(Tables_CollectionChanged); + ds.Tables.CollectionChanged+=new CollectionChangeEventHandler(Tables_CollectionChanged); ds.Tables.Add(); ds.Tables.Add(); Assert.AreEqual(2, counter, "DTC15"); @@ -153,7 +155,7 @@ public void CollectionChanged() Assert.AreEqual(4, counter, "DTC16"); } - private void Tables_CollectionChanged(object sender, System.ComponentModel.CollectionChangeEventArgs e) + private void Tables_CollectionChanged(object sender, CollectionChangeEventArgs e) { counter++; } @@ -163,7 +165,7 @@ public void CollectionChanging() { counter = 0; DataSet ds = new DataSet(); - ds.Tables.CollectionChanging+=new System.ComponentModel.CollectionChangeEventHandler(Tables_CollectionChanging); + ds.Tables.CollectionChanging+=new CollectionChangeEventHandler(Tables_CollectionChanging); ds.Tables.Add(); ds.Tables.Add(); Assert.AreEqual(2, counter, "DTC17"); @@ -173,7 +175,7 @@ public void CollectionChanging() Assert.AreEqual(4, counter, "DTC18"); } - private void Tables_CollectionChanging(object sender, System.ComponentModel.CollectionChangeEventArgs e) + private void Tables_CollectionChanging(object sender, CollectionChangeEventArgs e) { counter++; } @@ -233,7 +235,7 @@ public void GetEnumerator() ds.Tables.Add(); int count=0; - System.Collections.IEnumerator myEnumerator = ds.Tables.GetEnumerator(); + IEnumerator myEnumerator = ds.Tables.GetEnumerator(); while (myEnumerator.MoveNext()) { diff --git a/mcs/class/System.Data/Test/System.Data/DataTableTest2.cs b/mcs/class/System.Data/Test/System.Data/DataTableTest2.cs index 331875ac888..bed6e55e50c 100644 --- a/mcs/class/System.Data/Test/System.Data/DataTableTest2.cs +++ b/mcs/class/System.Data/Test/System.Data/DataTableTest2.cs @@ -36,7 +36,7 @@ using NUnit.Framework; -namespace MonoTests_System.Data +namespace MonoTests.System.Data { [TestFixture] public class DataTableTest2 diff --git a/mcs/class/System.Data/Test/System.Data/DataTableTest3.cs b/mcs/class/System.Data/Test/System.Data/DataTableTest3.cs index 6fc2d64b20b..c706778c67b 100644 --- a/mcs/class/System.Data/Test/System.Data/DataTableTest3.cs +++ b/mcs/class/System.Data/Test/System.Data/DataTableTest3.cs @@ -31,7 +31,7 @@ using NUnit.Framework; -namespace Monotests_System.Data +namespace MonoTests.System.Data { [TestFixture] public class DataTableTest3 diff --git a/mcs/class/System.Data/Test/System.Data/DataTableTest4.cs b/mcs/class/System.Data/Test/System.Data/DataTableTest4.cs index 2cdd5af913b..c7cb3a35e85 100644 --- a/mcs/class/System.Data/Test/System.Data/DataTableTest4.cs +++ b/mcs/class/System.Data/Test/System.Data/DataTableTest4.cs @@ -31,7 +31,7 @@ using System.Xml; using NUnit.Framework; -namespace Monotests_System.Data +namespace MonoTests.System.Data { [TestFixture] public class DataTableTest4 @@ -1600,7 +1600,7 @@ public void XmlTest21 () DataSet ds = new DataSet (); DataTable table = new DataTable ("ParentTable"); XmlReadMode mode = XmlReadMode.Auto; - table.Columns.Add (new DataColumn ("id", System.Type.GetType ("System.Int32"))); + table.Columns.Add (new DataColumn ("id", Type.GetType ("System.Int32"))); ds.Tables.Add (table); using (FileStream stream = new FileStream (tempFile, FileMode.Open)) { @@ -1638,7 +1638,7 @@ public void XmlTest22 () using (FileStream stream = new FileStream (tempFile, FileMode.Open)) { DataSet ds = new DataSet (); DataTable table = new DataTable ("Table1"); - table.Columns.Add (new DataColumn ("id", System.Type.GetType ("System.Int32"))); + table.Columns.Add (new DataColumn ("id", Type.GetType ("System.Int32"))); ds.Tables.Add (table); try { @@ -1852,7 +1852,7 @@ public void XmlTest28 () DataTable table = new DataTable ("DummyTable"); //define the table schame partially with a column name which does not match with any //table columns in the diffgram - table.Columns.Add (new DataColumn ("WrongColumnName", System.Type.GetType ("System.String"))); + table.Columns.Add (new DataColumn ("WrongColumnName", Type.GetType ("System.String"))); XmlReadMode mode = XmlReadMode.Auto; @@ -2013,8 +2013,8 @@ public void XmlTest31 () Assert.AreEqual ("NewDataSet", table.DataSet.DataSetName, "#2"); Assert.AreEqual (2, table.Columns.Count, "#3"); Assert.AreEqual (2, table.Rows.Count, "#4"); - Assert.AreEqual (typeof (System.Int32), table.Columns [0].DataType, "#5"); - Assert.AreEqual (typeof (System.String), table.Columns [1].DataType, "#6"); + Assert.AreEqual (typeof (Int32), table.Columns [0].DataType, "#5"); + Assert.AreEqual (typeof (String), table.Columns [1].DataType, "#6"); Assert.AreEqual (1, table.Constraints.Count, "#7"); Assert.AreEqual (typeof (UniqueConstraint), table.Constraints [0].GetType (), "#8"); Assert.AreEqual (1, table.ChildRelations.Count, "#9"); @@ -2027,9 +2027,9 @@ public void XmlTest31 () Assert.AreEqual ("NewDataSet", table1.DataSet.DataSetName, "#14"); Assert.AreEqual (3, table1.Columns.Count, "#15"); Assert.AreEqual (4, table1.Rows.Count, "#16"); - Assert.AreEqual (typeof (System.Int32), table1.Columns [0].DataType, "#17"); - Assert.AreEqual (typeof (System.String), table1.Columns [1].DataType, "#18"); - Assert.AreEqual (typeof (System.Int32), table1.Columns [2].DataType, "#19"); + Assert.AreEqual (typeof (Int32), table1.Columns [0].DataType, "#17"); + Assert.AreEqual (typeof (String), table1.Columns [1].DataType, "#18"); + Assert.AreEqual (typeof (Int32), table1.Columns [2].DataType, "#19"); Assert.AreEqual (2, table1.Constraints.Count, "#20"); Assert.AreEqual (typeof (UniqueConstraint), table1.Constraints [0].GetType (), "#21"); Assert.AreEqual (typeof (ForeignKeyConstraint), table1.Constraints [1].GetType (), "#22"); @@ -2045,8 +2045,8 @@ public void XmlTest31 () Assert.AreEqual ("NewDataSet", table1.DataSet.DataSetName, "#29"); Assert.AreEqual (2, table1.Columns.Count, "#30"); Assert.AreEqual (8, table1.Rows.Count, "#31"); - Assert.AreEqual (typeof (System.Int32), table1.Columns [0].DataType, "#32"); - Assert.AreEqual (typeof (System.String), table1.Columns [1].DataType, "#33"); + Assert.AreEqual (typeof (Int32), table1.Columns [0].DataType, "#32"); + Assert.AreEqual (typeof (String), table1.Columns [1].DataType, "#33"); Assert.AreEqual (1, table1.Constraints.Count, "#34"); Assert.AreEqual (typeof (ForeignKeyConstraint), table1.Constraints [0].GetType (), "#35"); Assert.AreEqual (1, table1.ParentRelations.Count, "#36"); diff --git a/mcs/class/System.Data/Test/System.Data/DataTableTest5.cs b/mcs/class/System.Data/Test/System.Data/DataTableTest5.cs index 3bcbf75889a..0cacc8ea9ef 100644 --- a/mcs/class/System.Data/Test/System.Data/DataTableTest5.cs +++ b/mcs/class/System.Data/Test/System.Data/DataTableTest5.cs @@ -34,7 +34,7 @@ using NUnit.Framework; -namespace Monotests_System.Data +namespace MonoTests.System.Data { [TestFixture] public class DataTableTest5 diff --git a/mcs/class/System.Data/Test/System.Data/DataViewTest2.cs b/mcs/class/System.Data/Test/System.Data/DataViewTest2.cs index f6c6b3f9a8c..58ca232fb53 100644 --- a/mcs/class/System.Data/Test/System.Data/DataViewTest2.cs +++ b/mcs/class/System.Data/Test/System.Data/DataViewTest2.cs @@ -28,12 +28,13 @@ using NUnit.Framework; using System; -using System.IO; +using System.Collections; using System.ComponentModel; +using System.IO; using System.Data; using MonoTests.System.Data.Utils; -namespace MonoTests_System.Data +namespace MonoTests.System.Data { [TestFixture] public class DataViewTest2 { @@ -41,7 +42,7 @@ [TestFixture] public class DataViewTest2 class EventProperties //hold the event properties to be checked { - public System.ComponentModel.ListChangedType lstType ; + public ListChangedType lstType ; public int NewIndex; public int OldIndex; } @@ -508,7 +509,7 @@ [Test] public void GetEnumerator() //create the dataview for the table DataView dv = new DataView(dt); - System.Collections.IEnumerator ienm = null; + IEnumerator ienm = null; // GetEnumerator != null ienm = dv.GetEnumerator(); @@ -549,7 +550,7 @@ [Test] public void ListChanged() DataView dv = new DataView(dt); //add event handler - dv.ListChanged +=new System.ComponentModel.ListChangedEventHandler(dv_ListChanged); + dv.ListChanged +=new ListChangedEventHandler(dv_ListChanged); // ----- Change Value --------- evProp = null; @@ -557,7 +558,7 @@ [Test] public void ListChanged() dv[1]["String1"] = "something"; Assert.AreEqual(true , evProp!=null , "DV58"); // change value - ListChangedType - Assert.AreEqual(System.ComponentModel.ListChangedType.ItemChanged, evProp.lstType , "DV59"); + Assert.AreEqual(ListChangedType.ItemChanged, evProp.lstType , "DV59"); // change value - NewIndex Assert.AreEqual(1, evProp.NewIndex, "DV60"); // change value - OldIndex @@ -569,7 +570,7 @@ [Test] public void ListChanged() dv.AddNew(); Assert.AreEqual(true , evProp!=null , "DV62"); // Add New - ListChangedType - Assert.AreEqual(System.ComponentModel.ListChangedType.ItemAdded , evProp.lstType , "DV63"); + Assert.AreEqual(ListChangedType.ItemAdded , evProp.lstType , "DV63"); // Add New - NewIndex Assert.AreEqual(6, evProp.NewIndex, "DV64"); // Add New - OldIndex @@ -581,7 +582,7 @@ [Test] public void ListChanged() dv.Sort = "ParentId Desc"; Assert.AreEqual(true , evProp!=null , "DV66"); // sort - ListChangedType - Assert.AreEqual(System.ComponentModel.ListChangedType.Reset , evProp.lstType , "DV67"); + Assert.AreEqual(ListChangedType.Reset , evProp.lstType , "DV67"); // sort - NewIndex Assert.AreEqual(-1, evProp.NewIndex, "DV68"); // sort - OldIndex @@ -627,12 +628,12 @@ public void ClearTable () Assert.AreEqual(true , evProp != null , "DV168"); // Clear DataTable - should emit ListChangedType.Reset - Assert.AreEqual(System.ComponentModel.ListChangedType.Reset , evProp.lstType , "DV169"); + Assert.AreEqual(ListChangedType.Reset , evProp.lstType , "DV169"); // Clear DataTable - should clear view count Assert.AreEqual(0, dt.DefaultView.Count , "DV169"); } - private void dv_ListChanged(object sender, System.ComponentModel.ListChangedEventArgs e) + private void dv_ListChanged(object sender, ListChangedEventArgs e) { evProp = new EventProperties(); evProp.lstType = e.ListChangedType; @@ -646,7 +647,7 @@ [Test] public void RowFilter() // this test also check DataView.Count property DataRowView[] drvResult = null; - System.Collections.ArrayList al = new System.Collections.ArrayList(); + ArrayList al = new ArrayList(); //create the source datatable DataTable dt = DataProvider.CreateChildDataTable(); @@ -763,7 +764,7 @@ Unchanged An unchanged row. 2 */ //DataRowView[] drvResult = null; - System.Collections.ArrayList al = new System.Collections.ArrayList(); + ArrayList al = new ArrayList(); DataTable dt = DataProvider.CreateParentDataTable(); @@ -821,7 +822,7 @@ Unchanged An unchanged row. 2 private DataRow[] GetResultRows(DataTable dt,DataRowState State) { //get expected rows - System.Collections.ArrayList al = new System.Collections.ArrayList(); + ArrayList al = new ArrayList(); DataRowVersion drVer = DataRowVersion.Current; //From MSDN - The row the default version for the current DataRowState. diff --git a/mcs/class/System.Data/Test/System.Data/DeletedRowInaccessibleExceptionTest.cs b/mcs/class/System.Data/Test/System.Data/DeletedRowInaccessibleExceptionTest.cs index 89fdeb547b1..be2810330fd 100644 --- a/mcs/class/System.Data/Test/System.Data/DeletedRowInaccessibleExceptionTest.cs +++ b/mcs/class/System.Data/Test/System.Data/DeletedRowInaccessibleExceptionTest.cs @@ -33,7 +33,7 @@ using System.Data; using MonoTests.System.Data.Utils; -namespace MonoTests_System.Data +namespace MonoTests.System.Data { [TestFixture] public class DeletedRowInaccessibleExceptionTest { diff --git a/mcs/class/System.Data/Test/System.Data/DuplicateNameExceptionTest.cs b/mcs/class/System.Data/Test/System.Data/DuplicateNameExceptionTest.cs index c26a71db1e1..77cf583fc81 100644 --- a/mcs/class/System.Data/Test/System.Data/DuplicateNameExceptionTest.cs +++ b/mcs/class/System.Data/Test/System.Data/DuplicateNameExceptionTest.cs @@ -33,7 +33,7 @@ using System.Data; using MonoTests.System.Data.Utils; -namespace MonoTests_System.Data +namespace MonoTests.System.Data { [TestFixture] public class DuplicateNameExceptionTest { diff --git a/mcs/class/System.Data/Test/System.Data/EvaluateExceptionTest.cs b/mcs/class/System.Data/Test/System.Data/EvaluateExceptionTest.cs index dd6fe52c914..a9c41f0c2a1 100644 --- a/mcs/class/System.Data/Test/System.Data/EvaluateExceptionTest.cs +++ b/mcs/class/System.Data/Test/System.Data/EvaluateExceptionTest.cs @@ -33,7 +33,7 @@ using System.Data; //using GHTUtils; -namespace MonoTests_System.Data +namespace MonoTests.System.Data { [TestFixture] public class EvaluateExceptionTest { diff --git a/mcs/class/System.Data/Test/System.Data/ForeignKeyConstraintTest2.cs b/mcs/class/System.Data/Test/System.Data/ForeignKeyConstraintTest2.cs index c0ed174c96d..591fef23f04 100644 --- a/mcs/class/System.Data/Test/System.Data/ForeignKeyConstraintTest2.cs +++ b/mcs/class/System.Data/Test/System.Data/ForeignKeyConstraintTest2.cs @@ -31,7 +31,7 @@ using System.Data; using MonoTests.System.Data.Utils; -namespace MonoTests_System.Data +namespace MonoTests.System.Data { [TestFixture] public class ForeignKeyConstraintTest2 { diff --git a/mcs/class/System.Data/Test/System.Data/InRowChangingEventExceptionTest.cs b/mcs/class/System.Data/Test/System.Data/InRowChangingEventExceptionTest.cs index 08dd7f08c69..549076cbb39 100644 --- a/mcs/class/System.Data/Test/System.Data/InRowChangingEventExceptionTest.cs +++ b/mcs/class/System.Data/Test/System.Data/InRowChangingEventExceptionTest.cs @@ -33,7 +33,7 @@ using System.Data; using MonoTests.System.Data.Utils; -namespace MonoTests_System.Data +namespace MonoTests.System.Data { [TestFixture] public class InRowChangingEventExceptionTest { diff --git a/mcs/class/System.Data/Test/System.Data/InvalidConstraintExceptionTest.cs b/mcs/class/System.Data/Test/System.Data/InvalidConstraintExceptionTest.cs index 1aacff1ee99..04c19bfc75f 100644 --- a/mcs/class/System.Data/Test/System.Data/InvalidConstraintExceptionTest.cs +++ b/mcs/class/System.Data/Test/System.Data/InvalidConstraintExceptionTest.cs @@ -33,7 +33,7 @@ using System.Data; using MonoTests.System.Data.Utils; -namespace MonoTests_System.Data +namespace MonoTests.System.Data { [TestFixture] public class InvalidConstraintExceptionTest { diff --git a/mcs/class/System.Data/Test/System.Data/MissingPrimaryKeyExceptionTest.cs b/mcs/class/System.Data/Test/System.Data/MissingPrimaryKeyExceptionTest.cs index 75791b325b4..14404f2b35f 100644 --- a/mcs/class/System.Data/Test/System.Data/MissingPrimaryKeyExceptionTest.cs +++ b/mcs/class/System.Data/Test/System.Data/MissingPrimaryKeyExceptionTest.cs @@ -32,7 +32,7 @@ using NUnit.Framework; using MonoTests.System.Data.Utils; -namespace MonoTests_System.Data +namespace MonoTests.System.Data { [TestFixture] class MissingPrimaryKeyExceptionTest @@ -57,4 +57,4 @@ public void Generate2() tbl.Rows.Contains("Something"); } } -} \ No newline at end of file +} diff --git a/mcs/class/System.Data/Test/System.Data/NoNullAllowedExceptionTest.cs b/mcs/class/System.Data/Test/System.Data/NoNullAllowedExceptionTest.cs index 5b1506a857d..45a5c5f3f76 100644 --- a/mcs/class/System.Data/Test/System.Data/NoNullAllowedExceptionTest.cs +++ b/mcs/class/System.Data/Test/System.Data/NoNullAllowedExceptionTest.cs @@ -33,7 +33,7 @@ using System.Data; using MonoTests.System.Data.Utils; -namespace MonoTests_System.Data +namespace MonoTests.System.Data { [TestFixture] public class NoNullAllowedExceptionTest { diff --git a/mcs/class/System.Data/Test/System.Data/ReadOnlyExceptionTest.cs b/mcs/class/System.Data/Test/System.Data/ReadOnlyExceptionTest.cs index 4969ea0a93d..dd16e85714a 100644 --- a/mcs/class/System.Data/Test/System.Data/ReadOnlyExceptionTest.cs +++ b/mcs/class/System.Data/Test/System.Data/ReadOnlyExceptionTest.cs @@ -33,7 +33,7 @@ using System.Data; using MonoTests.System.Data.Utils; -namespace MonoTests_System.Data +namespace MonoTests.System.Data { [TestFixture] public class ReadOnlyExceptionTest { diff --git a/mcs/class/System.Data/Test/System.Data/RowNotInTableExceptionTest.cs b/mcs/class/System.Data/Test/System.Data/RowNotInTableExceptionTest.cs index 349bdb8ae88..edade038354 100644 --- a/mcs/class/System.Data/Test/System.Data/RowNotInTableExceptionTest.cs +++ b/mcs/class/System.Data/Test/System.Data/RowNotInTableExceptionTest.cs @@ -31,7 +31,7 @@ using System.Data; using MonoTests.System.Data.Utils; -namespace MonoTests_System.Data +namespace MonoTests.System.Data { [TestFixture] public class RowNotInTableExceptionTest { diff --git a/mcs/class/System.Data/Test/System.Data/SyntaxErrorExceptionTest.cs b/mcs/class/System.Data/Test/System.Data/SyntaxErrorExceptionTest.cs index 875be983894..e1e2b08e24b 100644 --- a/mcs/class/System.Data/Test/System.Data/SyntaxErrorExceptionTest.cs +++ b/mcs/class/System.Data/Test/System.Data/SyntaxErrorExceptionTest.cs @@ -32,7 +32,7 @@ using System.IO; using System.Data; -namespace MonoTests_System.Data +namespace MonoTests.System.Data { [TestFixture] public class SyntaxErrorExceptionTest { diff --git a/mcs/class/System.Data/Test/System.Data/TrailingSpaceTest.cs b/mcs/class/System.Data/Test/System.Data/TrailingSpaceTest.cs index 788cc5a390e..8c6d6a0d863 100644 --- a/mcs/class/System.Data/Test/System.Data/TrailingSpaceTest.cs +++ b/mcs/class/System.Data/Test/System.Data/TrailingSpaceTest.cs @@ -2,7 +2,7 @@ using System; using System.Data; -namespace Monotests_Mono.Data.SqlExpressions +namespace MonoTests.System.Data { [TestFixture] public class ComparisonTest { @@ -10,7 +10,7 @@ public class ComparisonTest { [Test] public void TestStringTrailingSpaceHandling () { // test for bug 79695 - does not ignore certain trailing whitespace chars when comparing strings - System.Data.DataTable dataTable = new System.Data.DataTable ("Person"); + DataTable dataTable = new DataTable ("Person"); dataTable.Columns.Add ("Name", typeof (string)); dataTable.Rows.Add (new object[] {"Mike "}); DataRow[] selectedRows = dataTable.Select ("Name = 'Mike'"); diff --git a/mcs/class/System.Data/Test/System.Data/UniqueConstraintTest2.cs b/mcs/class/System.Data/Test/System.Data/UniqueConstraintTest2.cs index a21d94f1883..4e0224430c0 100644 --- a/mcs/class/System.Data/Test/System.Data/UniqueConstraintTest2.cs +++ b/mcs/class/System.Data/Test/System.Data/UniqueConstraintTest2.cs @@ -31,7 +31,7 @@ using System.Data; using MonoTests.System.Data.Utils; -namespace MonoTests_System.Data +namespace MonoTests.System.Data { [TestFixture] public class UniqueConstraintTest2 { diff --git a/mcs/class/System.Data/Test/System.Data/VersionNotFoundException.cs b/mcs/class/System.Data/Test/System.Data/VersionNotFoundException.cs index 8c2e7a9f7f1..235e30890a2 100644 --- a/mcs/class/System.Data/Test/System.Data/VersionNotFoundException.cs +++ b/mcs/class/System.Data/Test/System.Data/VersionNotFoundException.cs @@ -32,7 +32,7 @@ using NUnit.Framework; using MonoTests.System.Data.Utils; -namespace MonoTests_System.Data +namespace MonoTests.System.Data { [TestFixture] class VersionNotFoundExceptionTest @@ -73,4 +73,4 @@ public void Generate3() object obj = drParent[0,DataRowVersion.Original]; } } -} \ No newline at end of file +} diff --git a/mcs/class/System.Data/Test/System.Data/XmlDataLoaderTest.cs b/mcs/class/System.Data/Test/System.Data/XmlDataLoaderTest.cs index dee7e6e378f..2e0fe018304 100644 --- a/mcs/class/System.Data/Test/System.Data/XmlDataLoaderTest.cs +++ b/mcs/class/System.Data/Test/System.Data/XmlDataLoaderTest.cs @@ -32,7 +32,7 @@ using NUnit.Framework; -namespace Monotests_System.Data +namespace MonoTests.System.Data { [TestFixture] public class XmlDataLoaderTest @@ -74,7 +74,7 @@ private static DataSet Create () DataSet ds = new DataSet ("Set"); DataTable dt = new DataTable ("Test"); dt.Columns.Add ("CustName", typeof (String)); - dt.Columns.Add ("Type", typeof (System.Type)); + dt.Columns.Add ("Type", typeof (Type)); ds.Tables.Add (dt); return ds; } diff --git a/mcs/class/System.Data/Test/System.Data/XmlDataReaderTest.cs b/mcs/class/System.Data/Test/System.Data/XmlDataReaderTest.cs index 546db60bfb9..9bff68d0b92 100644 --- a/mcs/class/System.Data/Test/System.Data/XmlDataReaderTest.cs +++ b/mcs/class/System.Data/Test/System.Data/XmlDataReaderTest.cs @@ -33,7 +33,7 @@ using System.Xml.Schema; using NUnit.Framework; -namespace Monotests_System.Data +namespace MonoTests.System.Data { [TestFixture] public class XmlDataReaderTest @@ -103,7 +103,7 @@ public void XmlLoadCustomTypesTest () StringReader sr = new StringReader (xml); XmlTextReader xr = new XmlTextReader (sr); DataTable tbl = new DataTable("CustomTypesTable"); - tbl.Columns.Add("Dummy", typeof(System.UInt32)); + tbl.Columns.Add("Dummy", typeof(UInt32)); tbl.Columns.Add("FuncXml", typeof(CustomTypeXml)); DataSet ds = new DataSet("CustomTypesData"); diff --git a/mcs/class/System.Data/mobile_System.Data.dll.sources b/mcs/class/System.Data/mobile_System.Data.dll.sources index b1174b83615..5a5ed877c55 100644 --- a/mcs/class/System.Data/mobile_System.Data.dll.sources +++ b/mcs/class/System.Data/mobile_System.Data.dll.sources @@ -225,6 +225,7 @@ System.Data.SqlClient/SqlCommand.cs System.Data.SqlClient/SqlCommandBuilder.cs System.Data.SqlClient/SqlConnection.cs System.Data.SqlClient/SqlConnectionStringBuilder.cs +System.Data.SqlClient/SqlCredential.cs System.Data.SqlClient/SqlDataAdapter.cs System.Data.SqlClient/SqlDataReader.cs System.Data.SqlClient/SqlDataSourceConverter.cs diff --git a/mcs/class/System.Drawing/Assembly/AssemblyInfo.cs b/mcs/class/System.Drawing/Assembly/AssemblyInfo.cs index 115adf5d92e..c036603b98a 100644 --- a/mcs/class/System.Drawing/Assembly/AssemblyInfo.cs +++ b/mcs/class/System.Drawing/Assembly/AssemblyInfo.cs @@ -56,7 +56,9 @@ [assembly: CLSCompliant (true)] [assembly: AssemblyDelaySign (true)] +#if !MOBILE [assembly: AssemblyKeyFile("../msfinal.pub")] +#endif [assembly: AssemblyFileVersion (Consts.FxFileVersion)] [assembly: CompilationRelaxations (CompilationRelaxations.NoStringInterning)] diff --git a/mcs/class/System.IdentityModel/System.IdentityModel-net_4_5.csproj b/mcs/class/System.IdentityModel/System.IdentityModel-net_4_5.csproj index 3022c52ab5b..1e07337738e 100644 --- a/mcs/class/System.IdentityModel/System.IdentityModel-net_4_5.csproj +++ b/mcs/class/System.IdentityModel/System.IdentityModel-net_4_5.csproj @@ -50,6 +50,7 @@ + @@ -147,9 +148,12 @@ - + + + + @@ -170,7 +174,8 @@ - + + - - - - - - + + + + + + + + + + + - - - - - @@ -236,4 +241,4 @@ - + diff --git a/mcs/class/System.IdentityModel/System.IdentityModel.Tokens/BootstrapContext.cs b/mcs/class/System.IdentityModel/System.IdentityModel.Tokens/BootstrapContext.cs new file mode 100644 index 00000000000..5e9f589c294 --- /dev/null +++ b/mcs/class/System.IdentityModel/System.IdentityModel.Tokens/BootstrapContext.cs @@ -0,0 +1,117 @@ +// +// BootstrapContext.cs +// +// Author: +// Robert J. van der Boon (rjvdboon@gmail.com) +// +// Copyright (C) 2014 Robert J. van der Boon +// +// 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. +// +#if NET_4_5 +using System; +using System.IO; +using System.Runtime.Serialization; +using System.Text; +using System.Xml; + +namespace System.IdentityModel.Tokens { + [Serializable] + public class BootstrapContext : ISerializable { + /// Gets the string that was used to initialize the context. + public string Token { get; private set; } + /// Gets the array that was used to initialize the context. + public byte [] TokenBytes { get; private set; } + /// Gets the security token that was used to initialize the context. + public SecurityToken SecurityToken { get; private set; } + /// Gets the token handler that was used to initialize the context. + public SecurityTokenHandler SecurityTokenHandler { get; private set; } + + /// Initializes a new instance of the class by using the specified string. + public BootstrapContext (string token) + { + if (token == null) + throw new ArgumentNullException ("token"); + Token = token; + } + + /// Initializes a new instance of the class by using the specified array. + public BootstrapContext (byte [] token) + { + if (token == null) + throw new ArgumentNullException ("token"); + TokenBytes = token; + } + + /// Initializes a new instance of the class by using the specified security token and token handler. + public BootstrapContext (SecurityToken token, SecurityTokenHandler handler) + { + if (token == null) + throw new ArgumentNullException ("token"); + if (handler == null) + throw new ArgumentNullException ("handler"); + SecurityToken = token; + SecurityTokenHandler = handler; + } + + /// Initializes a new instance of the class from a stream. + protected BootstrapContext (SerializationInfo info, StreamingContext context) + { + if (info == null) + throw new ArgumentNullException ("info"); + char type = info.GetChar ("K"); + switch (type) { + case 'S': + Token = info.GetString ("T"); + break; + case 'B': + TokenBytes = (byte [])info.GetValue ("T", typeof (byte [])); + break; + case 'T': + Token = Encoding.UTF8.GetString (Convert.FromBase64String (info.GetString ("T"))); + break; + } + } + + /// Populates the with data needed to serialize the current object. + public void GetObjectData (SerializationInfo info, StreamingContext context) + { + if (info == null) + throw new ArgumentNullException ("info"); + if (Token != null) { + info.AddValue ("K", 'S'); + info.AddValue ("T", Token); + } else if (TokenBytes != null) { + info.AddValue ("K", 'B'); + info.AddValue ("T", TokenBytes); + } else if (SecurityToken != null && SecurityTokenHandler != null) { + info.AddValue ("K", 'T'); + using (var ms = new MemoryStream ()) + using (var streamWriter = new StreamWriter (ms, new UTF8Encoding (false))) + using (var writer = XmlWriter.Create (streamWriter, new XmlWriterSettings { OmitXmlDeclaration = true })) { + SecurityTokenHandler.WriteToken (writer, SecurityToken); + writer.Flush (); + info.AddValue ("T", Convert.ToBase64String (ms.ToArray ())); + } + } + } + } +} +#endif diff --git a/mcs/class/System.IdentityModel/System.IdentityModel.Tokens/SecurityTokenExpiredException.cs b/mcs/class/System.IdentityModel/System.IdentityModel.Tokens/SecurityTokenExpiredException.cs new file mode 100644 index 00000000000..2f10c949029 --- /dev/null +++ b/mcs/class/System.IdentityModel/System.IdentityModel.Tokens/SecurityTokenExpiredException.cs @@ -0,0 +1,54 @@ +// +// SecurityTokenExpiredException.cs +// +// Author: +// Noesis Labs (Ryan.Melena@noesislabs.com) +// +// Copyright (C) 2014 Noesis Labs, LLC https://noesislabs.com +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +#if NET_4_5 + +using System; +using System.Runtime.Serialization; + +namespace System.IdentityModel.Tokens +{ + public class SecurityTokenExpiredException : SecurityTokenValidationException + { + public SecurityTokenExpiredException() + : base("ID4181: The security token has expired.") + { } + + public SecurityTokenExpiredException(string message) + : base(message) + { } + + public SecurityTokenExpiredException(string message, Exception innerException) + : base(message, innerException) + { } + + public SecurityTokenExpiredException(SerializationInfo info, StreamingContext context) + : base(info, context) + { } + } +} +#endif diff --git a/mcs/class/System.IdentityModel/System.IdentityModel.Tokens/SecurityTokenNotYetValidException.cs b/mcs/class/System.IdentityModel/System.IdentityModel.Tokens/SecurityTokenNotYetValidException.cs new file mode 100644 index 00000000000..9f15b7b6448 --- /dev/null +++ b/mcs/class/System.IdentityModel/System.IdentityModel.Tokens/SecurityTokenNotYetValidException.cs @@ -0,0 +1,54 @@ +// +// SecurityTokenNotYetValidException.cs +// +// Author: +// Noesis Labs (Ryan.Melena@noesislabs.com) +// +// Copyright (C) 2014 Noesis Labs, LLC https://noesislabs.com +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +#if NET_4_5 + +using System; +using System.Runtime.Serialization; + +namespace System.IdentityModel.Tokens +{ + public class SecurityTokenNotYetValidException : SecurityTokenValidationException + { + public SecurityTokenNotYetValidException() + : base("ID4182: The security token is not valid yet.") + { } + + public SecurityTokenNotYetValidException(string message) + : base(message) + { } + + public SecurityTokenNotYetValidException(string message, Exception innerException) + : base(message, innerException) + { } + + public SecurityTokenNotYetValidException(SerializationInfo info, StreamingContext context) + : base(info, context) + { } + } +} +#endif diff --git a/mcs/class/System.IdentityModel/System.IdentityModel.Tokens/SecurityTokenReplayDetectedException.cs b/mcs/class/System.IdentityModel/System.IdentityModel.Tokens/SecurityTokenReplayDetectedException.cs new file mode 100644 index 00000000000..eb4a786b336 --- /dev/null +++ b/mcs/class/System.IdentityModel/System.IdentityModel.Tokens/SecurityTokenReplayDetectedException.cs @@ -0,0 +1,54 @@ +// +// SecurityTokenReplayDetectedException.cs +// +// Author: +// Noesis Labs (Ryan.Melena@noesislabs.com) +// +// Copyright (C) 2014 Noesis Labs, LLC https://noesislabs.com +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +#if NET_4_5 + +using System; +using System.Runtime.Serialization; + +namespace System.IdentityModel.Tokens +{ + public class SecurityTokenReplayDetectedException : SecurityTokenValidationException + { + public SecurityTokenReplayDetectedException() + : base("ID1070: Replay has been detected for a SecurityToken.") + { } + + public SecurityTokenReplayDetectedException(string message) + : base(message) + { } + + public SecurityTokenReplayDetectedException(string message, Exception innerException) + : base(message, innerException) + { } + + public SecurityTokenReplayDetectedException(SerializationInfo info, StreamingContext context) + : base(info, context) + { } + } +} +#endif diff --git a/mcs/class/System.IdentityModel/System.IdentityModel.dll.sources b/mcs/class/System.IdentityModel/System.IdentityModel.dll.sources index 32942efdb5c..4d705d24d57 100755 --- a/mcs/class/System.IdentityModel/System.IdentityModel.dll.sources +++ b/mcs/class/System.IdentityModel/System.IdentityModel.dll.sources @@ -3,6 +3,7 @@ Assembly/AssemblyInfo.cs System.IdentityModel/CookieTransform.cs System.IdentityModel/OpenObject.cs +System.IdentityModel/SignatureVerificationFailedException.cs System.IdentityModel.Claims/Claim.cs System.IdentityModel.Claims/ClaimSet.cs System.IdentityModel.Claims/ClaimTypes.cs @@ -54,6 +55,7 @@ System.IdentityModel.Tokens/AudienceRestriction.cs System.IdentityModel.Tokens/AuthenticationContext.cs System.IdentityModel.Tokens/AuthenticationInformation.cs System.IdentityModel.Tokens/BinaryKeyIdentifierClause.cs +System.IdentityModel.Tokens/BootstrapContext.cs System.IdentityModel.Tokens/EncryptedKeyIdentifierClause.cs System.IdentityModel.Tokens/EncryptingCredentials.cs System.IdentityModel.Tokens/GenericXmlSecurityToken.cs @@ -99,9 +101,12 @@ System.IdentityModel.Tokens/SecurityKeyUsage.cs System.IdentityModel.Tokens/SecurityToken.cs System.IdentityModel.Tokens/SecurityTokenDescriptor.cs System.IdentityModel.Tokens/SecurityTokenException.cs +System.IdentityModel.Tokens/SecurityTokenExpiredException.cs System.IdentityModel.Tokens/SecurityTokenHandler.cs System.IdentityModel.Tokens/SecurityTokenHandlerCollection.cs System.IdentityModel.Tokens/SecurityTokenHandlerConfiguration.cs +System.IdentityModel.Tokens/SecurityTokenNotYetValidException.cs +System.IdentityModel.Tokens/SecurityTokenReplayDetectedException.cs System.IdentityModel.Tokens/SecurityTokenTypes.cs System.IdentityModel.Tokens/SecurityTokenValidationException.cs System.IdentityModel.Tokens/SessionSecurityToken.cs @@ -123,4 +128,4 @@ System.IdentityModel.Tokens/X509SubjectKeyIdentifierClause.cs System.IdentityModel.Tokens/X509ThumbprintKeyIdentifierClause.cs System.IdentityModel.Tokens/X509WindowsSecurityToken.cs System.Security.Claims/AuthenticationTypes.cs -System.ServiceModel.Security/X509CertificateValidationMode.cs \ No newline at end of file +System.ServiceModel.Security/X509CertificateValidationMode.cs diff --git a/mcs/class/System.IdentityModel/System.IdentityModel/SignatureVerificationFailedException.cs b/mcs/class/System.IdentityModel/System.IdentityModel/SignatureVerificationFailedException.cs new file mode 100644 index 00000000000..2e1e7115ca9 --- /dev/null +++ b/mcs/class/System.IdentityModel/System.IdentityModel/SignatureVerificationFailedException.cs @@ -0,0 +1,54 @@ +// +// SignatureVerificationFailedException.cs +// +// Author: +// Noesis Labs (Ryan.Melena@noesislabs.com) +// +// Copyright (C) 2014 Noesis Labs, LLC https://noesislabs.com +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +#if NET_4_5 + +using System; +using System.Runtime.Serialization; + +namespace System.IdentityModel +{ + public class SignatureVerificationFailedException : Exception + { + public SignatureVerificationFailedException() + : base("ID4038: Signature verification failed.") + { } + + public SignatureVerificationFailedException(string message) + : base(message) + { } + + public SignatureVerificationFailedException(string message, Exception innerException) + : base(message, innerException) + { } + + public SignatureVerificationFailedException(SerializationInfo info, StreamingContext context) + : base(info, context) + { } + } +} +#endif diff --git a/mcs/class/System.IdentityModel/System.IdentityModel_test.dll.sources b/mcs/class/System.IdentityModel/System.IdentityModel_test.dll.sources index 86d286ce11c..2fcb687a3a5 100644 --- a/mcs/class/System.IdentityModel/System.IdentityModel_test.dll.sources +++ b/mcs/class/System.IdentityModel/System.IdentityModel_test.dll.sources @@ -12,6 +12,7 @@ System.IdentityModel.Selectors/SecurityTokenResolverTest.cs System.IdentityModel.Selectors/TestEvaluationContext.cs System.IdentityModel.Selectors/X509SecurityTokenAuthenticatorTest.cs System.IdentityModel.Selectors/X509SecurityTokenProviderTest.cs +System.IdentityModel.Tokens/BootstrapContextTest.cs System.IdentityModel.Tokens/EncryptedKeyIdentifierClauseTest.cs System.IdentityModel.Tokens/InMemorySymmetricSecurityKeyTest.cs System.IdentityModel.Tokens/LocalIdKeyIdentifierClauseTest.cs diff --git a/mcs/class/System.IdentityModel/Test/System.IdentityModel.Tokens/BootstrapContextTest.cs b/mcs/class/System.IdentityModel/Test/System.IdentityModel.Tokens/BootstrapContextTest.cs new file mode 100644 index 00000000000..1d5090748cd --- /dev/null +++ b/mcs/class/System.IdentityModel/Test/System.IdentityModel.Tokens/BootstrapContextTest.cs @@ -0,0 +1,251 @@ +// +// BootstrapContextTest.cs - NUnit Test Cases for System.IdentityModel.Tokens.BootstrapContext +// + +#if NET_4_5 +using System; +using System.IO; +using System.IdentityModel.Tokens; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters.Binary; +using System.Text; +using System.Xml; +using NUnit.Framework; + +namespace MonoTests.System.IdentityModel.Tokens.net_4_5 { + [TestFixture] + public class BootstrapContextTest { + // The following byte arrays are the serialized bytes as emitted on Microsoft .Net 4.5. + private static readonly byte [] SerializedBootstrapContextByteArray = new byte [] { 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x02, 0x00, 0x00, 0x00, 0x57, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x2E, 0x49, 0x64, 0x65, 0x6E, 0x74, 0x69, 0x74, 0x79, 0x4D, 0x6F, 0x64, 0x65, 0x6C, 0x2C, 0x20, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x3D, 0x34, 0x2E, 0x30, 0x2E, 0x30, 0x2E, 0x30, 0x2C, 0x20, 0x43, 0x75, 0x6C, 0x74, 0x75, 0x72, 0x65, 0x3D, 0x6E, 0x65, 0x75, 0x74, 0x72, 0x61, 0x6C, 0x2C, 0x20, 0x50, 0x75, 0x62, 0x6C, 0x69, 0x63, 0x4B, 0x65, 0x79, 0x54, 0x6F, 0x6B, 0x65, 0x6E, 0x3D, 0x62, 0x37, 0x37, 0x61, 0x35, 0x63, 0x35, 0x36, 0x31, 0x39, 0x33, 0x34, 0x65, 0x30, 0x38, 0x39, 0x05, 0x01, 0x00, 0x00, 0x00, 0x2C, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x2E, 0x49, 0x64, 0x65, 0x6E, 0x74, 0x69, 0x74, 0x79, 0x4D, 0x6F, 0x64, 0x65, 0x6C, 0x2E, 0x54, 0x6F, 0x6B, 0x65, 0x6E, 0x73, 0x2E, 0x42, 0x6F, 0x6F, 0x74, 0x73, 0x74, 0x72, 0x61, 0x70, 0x43, 0x6F, 0x6E, 0x74, 0x65, 0x78, 0x74, 0x02, 0x00, 0x00, 0x00, 0x01, 0x4B, 0x01, 0x54, 0x00, 0x07, 0x03, 0x02, 0x02, 0x00, 0x00, 0x00, 0x42, 0x09, 0x03, 0x00, 0x00, 0x00, 0x0F, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x01, 0x0B }; + private static readonly byte [] SerializedBootstrapContextString = new byte [] { 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x02, 0x00, 0x00, 0x00, 0x57, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x2E, 0x49, 0x64, 0x65, 0x6E, 0x74, 0x69, 0x74, 0x79, 0x4D, 0x6F, 0x64, 0x65, 0x6C, 0x2C, 0x20, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x3D, 0x34, 0x2E, 0x30, 0x2E, 0x30, 0x2E, 0x30, 0x2C, 0x20, 0x43, 0x75, 0x6C, 0x74, 0x75, 0x72, 0x65, 0x3D, 0x6E, 0x65, 0x75, 0x74, 0x72, 0x61, 0x6C, 0x2C, 0x20, 0x50, 0x75, 0x62, 0x6C, 0x69, 0x63, 0x4B, 0x65, 0x79, 0x54, 0x6F, 0x6B, 0x65, 0x6E, 0x3D, 0x62, 0x37, 0x37, 0x61, 0x35, 0x63, 0x35, 0x36, 0x31, 0x39, 0x33, 0x34, 0x65, 0x30, 0x38, 0x39, 0x05, 0x01, 0x00, 0x00, 0x00, 0x2C, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x2E, 0x49, 0x64, 0x65, 0x6E, 0x74, 0x69, 0x74, 0x79, 0x4D, 0x6F, 0x64, 0x65, 0x6C, 0x2E, 0x54, 0x6F, 0x6B, 0x65, 0x6E, 0x73, 0x2E, 0x42, 0x6F, 0x6F, 0x74, 0x73, 0x74, 0x72, 0x61, 0x70, 0x43, 0x6F, 0x6E, 0x74, 0x65, 0x78, 0x74, 0x02, 0x00, 0x00, 0x00, 0x01, 0x4B, 0x01, 0x54, 0x00, 0x01, 0x03, 0x02, 0x00, 0x00, 0x00, 0x53, 0x06, 0x03, 0x00, 0x00, 0x00, 0x05, 0x74, 0x6F, 0x6B, 0x65, 0x6E, 0x0B }; + + // Put in some non-ascii/latin1 characters to test the encoding scheme + // \u018E == Latin capital letter Reversed E + private const string user = "us\u018Er"; + // \u00BD == Vulgar Fraction one half + private const string password = "pass\u00BDword"; + private static readonly string SerializedBootstrapContextSecurityTokenString = ""; + private static readonly byte [] SerializedBootstrapContextSecurityToken = new byte [] { 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x02, 0x00, 0x00, 0x00, 0x57, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x2E, 0x49, 0x64, 0x65, 0x6E, 0x74, 0x69, 0x74, 0x79, 0x4D, 0x6F, 0x64, 0x65, 0x6C, 0x2C, 0x20, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x3D, 0x34, 0x2E, 0x30, 0x2E, 0x30, 0x2E, 0x30, 0x2C, 0x20, 0x43, 0x75, 0x6C, 0x74, 0x75, 0x72, 0x65, 0x3D, 0x6E, 0x65, 0x75, 0x74, 0x72, 0x61, 0x6C, 0x2C, 0x20, 0x50, 0x75, 0x62, 0x6C, 0x69, 0x63, 0x4B, 0x65, 0x79, 0x54, 0x6F, 0x6B, 0x65, 0x6E, 0x3D, 0x62, 0x37, 0x37, 0x61, 0x35, 0x63, 0x35, 0x36, 0x31, 0x39, 0x33, 0x34, 0x65, 0x30, 0x38, 0x39, 0x05, 0x01, 0x00, 0x00, 0x00, 0x2C, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x2E, 0x49, 0x64, 0x65, 0x6E, 0x74, 0x69, 0x74, 0x79, 0x4D, 0x6F, 0x64, 0x65, 0x6C, 0x2E, 0x54, 0x6F, 0x6B, 0x65, 0x6E, 0x73, 0x2E, 0x42, 0x6F, 0x6F, 0x74, 0x73, 0x74, 0x72, 0x61, 0x70, 0x43, 0x6F, 0x6E, 0x74, 0x65, 0x78, 0x74, 0x02, 0x00, 0x00, 0x00, 0x01, 0x4B, 0x01, 0x54, 0x00, 0x01, 0x03, 0x02, 0x00, 0x00, 0x00, 0x54, 0x06, 0x03, 0x00, 0x00, 0x00, 0x98, 0x01, 0x50, 0x46, 0x56, 0x7A, 0x5A, 0x58, 0x4A, 0x4F, 0x59, 0x57, 0x31, 0x6C, 0x55, 0x32, 0x56, 0x6A, 0x64, 0x58, 0x4A, 0x70, 0x64, 0x48, 0x6C, 0x55, 0x62, 0x32, 0x74, 0x6C, 0x62, 0x69, 0x42, 0x4A, 0x5A, 0x44, 0x30, 0x69, 0x64, 0x58, 0x56, 0x70, 0x5A, 0x43, 0x30, 0x35, 0x4D, 0x6A, 0x64, 0x6A, 0x4D, 0x47, 0x49, 0x35, 0x4F, 0x43, 0x31, 0x69, 0x59, 0x54, 0x45, 0x34, 0x4C, 0x54, 0x51, 0x35, 0x5A, 0x44, 0x49, 0x74, 0x59, 0x54, 0x59, 0x31, 0x4D, 0x79, 0x30, 0x7A, 0x4D, 0x44, 0x5A, 0x6B, 0x4E, 0x6A, 0x42, 0x6D, 0x4F, 0x44, 0x55, 0x33, 0x4E, 0x54, 0x45, 0x74, 0x4D, 0x79, 0x49, 0x67, 0x56, 0x58, 0x4E, 0x6C, 0x63, 0x6D, 0x35, 0x68, 0x62, 0x57, 0x55, 0x39, 0x49, 0x6E, 0x56, 0x7A, 0x78, 0x6F, 0x35, 0x79, 0x49, 0x69, 0x42, 0x51, 0x59, 0x58, 0x4E, 0x7A, 0x64, 0x32, 0x39, 0x79, 0x5A, 0x44, 0x30, 0x69, 0x63, 0x47, 0x46, 0x7A, 0x63, 0x38, 0x4B, 0x39, 0x64, 0x32, 0x39, 0x79, 0x5A, 0x43, 0x49, 0x76, 0x50, 0x67, 0x3D, 0x3D, 0x0B }; + + [Test] + public void Ctor_StringToken_Works () + { + BootstrapContext bootstrapContext = new BootstrapContext ("token"); + + Assert.AreEqual ("token", bootstrapContext.Token, "#1"); + Assert.IsNull (bootstrapContext.TokenBytes, "#2"); + Assert.IsNull (bootstrapContext.SecurityToken, "#3"); + Assert.IsNull (bootstrapContext.SecurityTokenHandler, "#4"); + } + [Test] + [ExpectedException (typeof (ArgumentNullException))] + public void Ctor_StringToken_NullToken_Throws () + { + BootstrapContext bootstrapContext = new BootstrapContext ((string)null); + Assert.Fail ("Should have thrown"); + } + + [Test] + public void Serialize_StringToken_Works () + { + BootstrapContext bootstrapContext = new BootstrapContext ("token"); + BinaryFormatter binaryFormatter = new BinaryFormatter (); + using (var s = new MemoryStream ()) { + binaryFormatter.Serialize (s, bootstrapContext); + s.Position = 0; + BootstrapContext bootstrapContext2 = binaryFormatter.Deserialize (s) as BootstrapContext; + Assert.IsNotNull (bootstrapContext2, "#1"); + Assert.AreEqual (bootstrapContext.Token, bootstrapContext2.Token, "#2"); + Assert.AreEqual (bootstrapContext.TokenBytes, bootstrapContext2.TokenBytes, "#3"); + Assert.AreEqual (bootstrapContext.SecurityToken, bootstrapContext2.SecurityToken, "#4"); + Assert.AreEqual (bootstrapContext.SecurityTokenHandler, bootstrapContext2.SecurityTokenHandler, "#5"); + } + } + + [Test] + public void Deserialize_StringToken_Works () + { + BinaryFormatter binaryFormatter = new BinaryFormatter (); + using (var s = new MemoryStream (SerializedBootstrapContextString)) { + BootstrapContext bootstrapContext = binaryFormatter.Deserialize (s) as BootstrapContext; + Assert.IsNotNull (bootstrapContext, "#1"); + Assert.AreEqual ("token", bootstrapContext.Token, "#2"); + Assert.IsNull (bootstrapContext.TokenBytes, "#3"); + Assert.IsNull (bootstrapContext.SecurityToken, "#4"); + Assert.IsNull (bootstrapContext.SecurityTokenHandler, "#5"); + } + } + + [Test] + public void Ctor_ByteArrayToken_Works () + { + BootstrapContext bootstrapContext = new BootstrapContext (new byte [] { 0x01 }); + + Assert.IsNotNull (bootstrapContext.TokenBytes, "#1"); + Assert.AreEqual (1, bootstrapContext.TokenBytes.Length, "#2"); + Assert.AreEqual (1, bootstrapContext.TokenBytes [0], "#3"); + Assert.IsNull (bootstrapContext.Token, "#4"); + Assert.IsNull (bootstrapContext.SecurityToken, "#5"); + Assert.IsNull (bootstrapContext.SecurityTokenHandler, "#6"); + } + + [Test] + [ExpectedException (typeof (ArgumentNullException))] + public void Ctor_ByteArrayToken_NullToken_Throws () + { + BootstrapContext bootstrapContext = new BootstrapContext ((byte [])null); + Assert.Fail ("Should have thrown"); + } + + [Test] + public void Serialize_ByteArrayToken_Works () + { + BootstrapContext bootstrapContext = new BootstrapContext (new byte [] { 0x1 }); + BinaryFormatter binaryFormatter = new BinaryFormatter (); + using (var s = new MemoryStream ()) { + binaryFormatter.Serialize (s, bootstrapContext); + s.Position = 0; + BootstrapContext bootstrapContext2 = binaryFormatter.Deserialize (s) as BootstrapContext; + Assert.IsNotNull (bootstrapContext2, "#1"); + Assert.AreEqual (bootstrapContext.Token, bootstrapContext2.Token, "#2"); + Assert.AreEqual (bootstrapContext.TokenBytes, bootstrapContext2.TokenBytes, "#3"); + Assert.AreEqual (bootstrapContext.SecurityToken, bootstrapContext2.SecurityToken, "#4"); + Assert.AreEqual (bootstrapContext.SecurityTokenHandler, bootstrapContext2.SecurityTokenHandler, "#5"); + } + } + + [Test] + public void Deserialize_ByteArrayToken_Works () + { + BinaryFormatter binaryFormatter = new BinaryFormatter (); + using (var s = new MemoryStream (SerializedBootstrapContextByteArray)) { + BootstrapContext bootstrapContext = binaryFormatter.Deserialize (s) as BootstrapContext; + Assert.IsNotNull (bootstrapContext, "#1"); + Assert.IsNotNull (bootstrapContext.TokenBytes, "#2"); + Assert.AreEqual (1, bootstrapContext.TokenBytes.Length, "#3"); + Assert.AreEqual (1, bootstrapContext.TokenBytes [0], "#4"); + Assert.IsNull (bootstrapContext.Token, "#5"); + Assert.IsNull (bootstrapContext.SecurityToken, "#6"); + Assert.IsNull (bootstrapContext.SecurityTokenHandler, "#7"); + } + } + + [Test] + public void Ctor_SecurityToken_Works () + { + var securityToken = new UserNameSecurityToken (user, password); + var securityTokenHandler = new SimpleSecurityTokenHandler (); + BootstrapContext bootstrapContext = new BootstrapContext (securityToken, securityTokenHandler); + + Assert.IsNotNull (bootstrapContext.SecurityToken, "#1"); + Assert.AreEqual (user, securityToken.UserName, "#2"); + Assert.AreEqual (password, securityToken.Password, "#3"); + Assert.AreEqual (securityTokenHandler, bootstrapContext.SecurityTokenHandler, "#4"); + + Assert.IsNull (bootstrapContext.Token, "#5"); + Assert.IsNull (bootstrapContext.TokenBytes, "#6"); + } + + [Test] + [ExpectedException (typeof (ArgumentNullException))] + public void Ctor_SecurityToken_NullToken_Throws () + { + BootstrapContext bootstrapContext = new BootstrapContext (null, new SimpleSecurityTokenHandler ()); + Assert.Fail ("Should have thrown"); + } + + [Test] + [ExpectedException (typeof (ArgumentNullException))] + public void Ctor_SecurityToken_NullHandler_Throws () + { + BootstrapContext bootstrapContext = new BootstrapContext (new UserNameSecurityToken ("user", "password"), null); + Assert.Fail ("Should have thrown"); + } + + [Test] + public void Serialize_SecurityTokenAndHandler_Works () + { + var securityToken = new UserNameSecurityToken (user, password, "uuid-927c0b98-ba18-49d2-a653-306d60f85751-3"); + var securityTokenHandler = new SimpleSecurityTokenHandler (); + BootstrapContext bootstrapContext = new BootstrapContext (securityToken, securityTokenHandler); + + BinaryFormatter binaryFormatter = new BinaryFormatter (); + using (var s = new MemoryStream ()) { + binaryFormatter.Serialize (s, bootstrapContext); + s.Position = 0; + BootstrapContext bootstrapContext2 = binaryFormatter.Deserialize (s) as BootstrapContext; + Assert.IsNotNull (bootstrapContext2, "#1"); + // Deserialize does not restore the SecurityToken, but restores into the Token. + Assert.IsNotNull (bootstrapContext2.Token, "#3"); + // We replace ' /' by '/' to accomodate the xml writer differences between mono and .net + Assert.AreEqual (SerializedBootstrapContextSecurityTokenString.Replace (" /", "/"), bootstrapContext2.Token.Replace (" /", "/"), "#2"); + Assert.AreEqual (bootstrapContext.TokenBytes, bootstrapContext2.TokenBytes, "#3"); + Assert.IsNull (bootstrapContext2.SecurityToken, "#4"); + Assert.IsNull (bootstrapContext2.SecurityTokenHandler, "#5"); + } + } + + [Test] + public void Deserialize_SecurityTokenAndHandler_Works () + { + BinaryFormatter binaryFormatter = new BinaryFormatter (); + using (var s = new MemoryStream (SerializedBootstrapContextSecurityToken)) { + BootstrapContext bootstrapContext = binaryFormatter.Deserialize (s) as BootstrapContext; + Assert.IsNotNull (bootstrapContext, "#1"); + Assert.AreEqual (SerializedBootstrapContextSecurityTokenString, bootstrapContext.Token, "#2"); + Assert.IsNull (bootstrapContext.SecurityToken, "#3"); + Assert.IsNull (bootstrapContext.SecurityTokenHandler, "#4"); + Assert.IsNull (bootstrapContext.TokenBytes, "#5"); + } + } + + private static void DumpAsText (byte [] data) + { + Console.WriteLine ("{0}", Encoding.ASCII.GetString (data)); + } + + private static void Dump (byte [] data) + { + var sb = new StringBuilder (); + sb.Append ("new byte[] { "); + bool first = true; + foreach (byte b in data) { + if (!first) + sb.Append (", "); + else + first = false; + sb.AppendFormat ("0x{0:X2}", b); + } + sb.Append (" };"); + Console.WriteLine (sb.ToString ()); + } + + private class SimpleSecurityTokenHandler : SecurityTokenHandler { + public override string [] GetTokenTypeIdentifiers () + { + throw new NotImplementedException (); + } + + public override Type TokenType { + get { return typeof (UserNameSecurityToken); } + } + + public override bool CanWriteToken { + get { return true; } + } + + public override void WriteToken (XmlWriter writer, SecurityToken token) + { + UserNameSecurityToken unst = token as UserNameSecurityToken; + if (unst == null) + throw new ArgumentException ("Token must be of type UserNameSecurityToken", "token"); + writer.WriteStartElement ("UserNameSecurityToken"); + writer.WriteAttributeString ("Id", unst.Id); + writer.WriteAttributeString ("Username", unst.UserName); + writer.WriteAttributeString ("Password", unst.Password); + writer.WriteEndElement (); + } + } + } +} +#endif diff --git a/mcs/class/System.Interactive.Async/Makefile b/mcs/class/System.Interactive.Async/Makefile index 70740170701..71e2b0dfc58 100644 --- a/mcs/class/System.Interactive.Async/Makefile +++ b/mcs/class/System.Interactive.Async/Makefile @@ -21,7 +21,7 @@ TEST_MCS_FLAGS = $(LIB_MCS_FLAGS) EXTRA_DISTFILES = more_build_args -VALID_PROFILE := $(filter monotouch monodroid xammac net_4_0 net_4_5, $(PROFILE)) +VALID_PROFILE := $(filter monotouch monodroid mobile mobile_static xammac net_4_0 net_4_5, $(PROFILE)) ifndef VALID_PROFILE LIBRARY_NAME = dummy-System.System.Interactive.Async.dll NO_SIGN_ASSEMBLY = yes diff --git a/mcs/class/System.Interactive.Providers/Makefile b/mcs/class/System.Interactive.Providers/Makefile index c74dccb7271..ae8749cc694 100644 --- a/mcs/class/System.Interactive.Providers/Makefile +++ b/mcs/class/System.Interactive.Providers/Makefile @@ -22,7 +22,7 @@ TEST_MCS_FLAGS = $(LIB_MCS_FLAGS) EXTRA_DISTFILES = more_build_args -VALID_PROFILE := $(filter monotouch monodroid xammac net_4_0 net_4_5, $(PROFILE)) +VALID_PROFILE := $(filter monotouch monodroid xammac mobile mobile_static net_4_0 net_4_5, $(PROFILE)) ifndef VALID_PROFILE LIBRARY_NAME = dummy-System.System.Interactive.Providers.dll NO_SIGN_ASSEMBLY = yes diff --git a/mcs/class/System.Interactive/Makefile b/mcs/class/System.Interactive/Makefile index ec5cd5c01df..1429c533ef9 100644 --- a/mcs/class/System.Interactive/Makefile +++ b/mcs/class/System.Interactive/Makefile @@ -21,7 +21,7 @@ TEST_MCS_FLAGS = $(LIB_MCS_FLAGS) EXTRA_DISTFILES = more_build_args -VALID_PROFILE := $(filter monotouch monodroid xammac net_4_0 net_4_5, $(PROFILE)) +VALID_PROFILE := $(filter monotouch monodroid xammac mobile mobile_static net_4_0 net_4_5, $(PROFILE)) ifndef VALID_PROFILE LIBRARY_NAME = dummy-System.System.Interactive.dll NO_SIGN_ASSEMBLY = yes diff --git a/mcs/class/System.Management/System.Management/ManagementObjectSearcher.cs b/mcs/class/System.Management/System.Management/ManagementObjectSearcher.cs index 90ed57e3dce..f79d9662bcd 100644 --- a/mcs/class/System.Management/System.Management/ManagementObjectSearcher.cs +++ b/mcs/class/System.Management/System.Management/ManagementObjectSearcher.cs @@ -26,28 +26,28 @@ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // - using System.ComponentModel; namespace System.Management { - [MonoTODO ("System.Management is not implemented")] [ToolboxItem (false)] public class ManagementObjectSearcher : Component { + ObjectQuery mQueryObject; + public ManagementObjectSearcher () { - throw new NotImplementedException (); + mQueryObject = new ObjectQuery (); } public ManagementObjectSearcher (ObjectQuery query) { - throw new NotImplementedException (); + mQueryObject = (ObjectQuery)query.Clone (); } public ManagementObjectSearcher (string queryString) { - throw new NotImplementedException (); + mQueryObject = new ObjectQuery (queryString); } public ManagementObjectSearcher (ManagementScope scope, ObjectQuery query) @@ -81,10 +81,10 @@ public EnumerationOptions Options { public ObjectQuery Query { get { - throw new NotImplementedException (); + return mQueryObject; } set { - throw new NotImplementedException (); + mQueryObject = value; } } diff --git a/mcs/class/System.Net.Http/System.Net.Http.Headers/ContentDispositionHeaderValue.cs b/mcs/class/System.Net.Http/System.Net.Http.Headers/ContentDispositionHeaderValue.cs index 0e28b728388..9329ac5796f 100644 --- a/mcs/class/System.Net.Http/System.Net.Http.Headers/ContentDispositionHeaderValue.cs +++ b/mcs/class/System.Net.Http/System.Net.Http.Headers/ContentDispositionHeaderValue.cs @@ -120,9 +120,17 @@ public DateTimeOffset? ModificationDate { public string Name { get { - return FindParameter ("name"); + var value = FindParameter ("name"); + + if (value == null) + return null; + + return DecodeValue (value, false); } set { + if (value != null) + value = EncodeBase64Value (value); + SetValue ("name", value); } } diff --git a/mcs/class/System.Net.Http/System.Net.Http.Headers/ContentRangeHeaderValue.cs b/mcs/class/System.Net.Http/System.Net.Http.Headers/ContentRangeHeaderValue.cs index 118d65085f7..1bea52b76e8 100644 --- a/mcs/class/System.Net.Http/System.Net.Http.Headers/ContentRangeHeaderValue.cs +++ b/mcs/class/System.Net.Http/System.Net.Http.Headers/ContentRangeHeaderValue.cs @@ -170,7 +170,7 @@ public static bool TryParse (string input, out ContentRangeHeaderValue parsedVal } else { value.From = nvalue; - t = lexer.Scan (); + t = lexer.Scan (recognizeDash: true); if (t != Token.Type.SeparatorDash) return false; diff --git a/mcs/class/System.Net.Http/System.Net.Http.Headers/HttpHeaders.cs b/mcs/class/System.Net.Http/System.Net.Http.Headers/HttpHeaders.cs index 5717ddd67dc..4f1137a8ccc 100644 --- a/mcs/class/System.Net.Http/System.Net.Http.Headers/HttpHeaders.cs +++ b/mcs/class/System.Net.Http/System.Net.Http.Headers/HttpHeaders.cs @@ -96,6 +96,7 @@ static HttpHeaders () HeaderInfo.CreateSingle ("Authorization", AuthenticationHeaderValue.TryParse, HttpHeaderKind.Request), HeaderInfo.CreateSingle ("Cache-Control", CacheControlHeaderValue.TryParse, HttpHeaderKind.Request | HttpHeaderKind.Response), HeaderInfo.CreateMulti ("Connection", CollectionParser.TryParse, HttpHeaderKind.Request | HttpHeaderKind.Response), + HeaderInfo.CreateSingle ("Content-Disposition", ContentDispositionHeaderValue.TryParse, HttpHeaderKind.Content), HeaderInfo.CreateMulti ("Content-Encoding", CollectionParser.TryParse, HttpHeaderKind.Content), HeaderInfo.CreateMulti ("Content-Language", CollectionParser.TryParse, HttpHeaderKind.Content), HeaderInfo.CreateSingle ("Content-Length", Parser.Long.TryParse, HttpHeaderKind.Content), diff --git a/mcs/class/System.Net.Http/System.Net.Http.Headers/Lexer.cs b/mcs/class/System.Net.Http/System.Net.Http.Headers/Lexer.cs index 5bd7d093acf..622e36b0ec2 100644 --- a/mcs/class/System.Net.Http/System.Net.Http.Headers/Lexer.cs +++ b/mcs/class/System.Net.Http/System.Net.Http.Headers/Lexer.cs @@ -247,7 +247,7 @@ public bool ScanCommentOptional (out string value, out Token readToken) return false; } - public Token Scan () + public Token Scan (bool recognizeDash = false) { int start = pos; if (s == null) @@ -279,8 +279,12 @@ public Token Scan () ttype = Token.Type.SeparatorSlash; break; case '-': - ttype = Token.Type.SeparatorDash; - break; + if (recognizeDash) { + ttype = Token.Type.SeparatorDash; + break; + } + + goto default; case ',': ttype = Token.Type.SeparatorComma; break; diff --git a/mcs/class/System.Net.Http/System.Net.Http.Headers/RangeHeaderValue.cs b/mcs/class/System.Net.Http/System.Net.Http.Headers/RangeHeaderValue.cs index ad8e7e2b4f3..36e9c806157 100644 --- a/mcs/class/System.Net.Http/System.Net.Http.Headers/RangeHeaderValue.cs +++ b/mcs/class/System.Net.Http/System.Net.Http.Headers/RangeHeaderValue.cs @@ -127,7 +127,7 @@ public static bool TryParse (string input, out RangeHeaderValue parsedValue) int number; token_read = false; - t = lexer.Scan (); + t = lexer.Scan (recognizeDash: true); switch (t.Kind) { case Token.Type.SeparatorDash: t = lexer.Scan (); @@ -144,7 +144,7 @@ public static bool TryParse (string input, out RangeHeaderValue parsedValue) switch (values.Length) { case 1: - t = lexer.Scan (); + t = lexer.Scan (recognizeDash: true); from = number; switch (t.Kind) { case Token.Type.SeparatorDash: diff --git a/mcs/class/System.Net.Http/System.Net.Http/HttpClientHandler.cs b/mcs/class/System.Net.Http/System.Net.Http/HttpClientHandler.cs index 865a8062b77..b4de2a029cf 100644 --- a/mcs/class/System.Net.Http/System.Net.Http/HttpClientHandler.cs +++ b/mcs/class/System.Net.Http/System.Net.Http/HttpClientHandler.cs @@ -50,7 +50,6 @@ public class HttpClientHandler : HttpMessageHandler bool useProxy; ClientCertificateOption certificate; bool sentRequest; - HttpWebRequest wrequest; string connectionGroupName; bool disposed; @@ -221,12 +220,9 @@ public bool UseProxy { protected override void Dispose (bool disposing) { - if (disposing) { - if (wrequest != null) { - wrequest.ServicePoint.CloseConnectionGroup (wrequest.ConnectionGroupName); - Volatile.Write (ref wrequest, null); - } + if (disposing && !disposed) { Volatile.Write (ref disposed, true); + ServicePointManager.CloseConnectionGroup (connectionGroupName); } base.Dispose (disposing); @@ -317,7 +313,7 @@ protected async internal override Task SendAsync (HttpReque throw new ObjectDisposedException (GetType ().ToString ()); Volatile.Write (ref sentRequest, true); - wrequest = CreateWebRequest (request); + var wrequest = CreateWebRequest (request); if (request.Content != null) { var headers = wrequest.Headers; diff --git a/mcs/class/System.Net.Http/Test/System.Net.Http.Headers/ContentDispositionHeaderValueTest.cs b/mcs/class/System.Net.Http/Test/System.Net.Http.Headers/ContentDispositionHeaderValueTest.cs index b9c8a7796ee..e9a7ab8de0a 100644 --- a/mcs/class/System.Net.Http/Test/System.Net.Http.Headers/ContentDispositionHeaderValueTest.cs +++ b/mcs/class/System.Net.Http/Test/System.Net.Http.Headers/ContentDispositionHeaderValueTest.cs @@ -239,6 +239,33 @@ public void Properties_FileNameStar () Assert.AreEqual (new NameValueHeaderValue ("filename*", "utf-8''%C4%8D"), value.Parameters.First (), "#12"); } + + [Test] + public void Properties_Name () + { + var value = new ContentDispositionHeaderValue ("a"); + + value.Name = "aa"; + Assert.AreEqual ("aa", value.Name, "#1"); + Assert.AreEqual (new NameValueHeaderValue ("name", "aa"), value.Parameters.First (), "#2"); + + value.Name = "č"; + Assert.AreEqual ("č", value.Name, "#11"); + Assert.AreEqual (new NameValueHeaderValue ("name", "\"=?utf-8?B?xI0=?=\""), value.Parameters.First (), "#12"); + + value.Name = "(@)"; + Assert.AreEqual ("\"(@)\"", value.Name, "#21"); + Assert.AreEqual (new NameValueHeaderValue ("name", "\"(@)\""), value.Parameters.First (), "#22"); + + value.Name = "\"č\""; + Assert.AreEqual ("č", value.Name, "#31"); + Assert.AreEqual (new NameValueHeaderValue ("name", "\"=?utf-8?B?xI0=?=\""), value.Parameters.First (), "#32"); + + value.Name = "\"quoted\""; + Assert.AreEqual ("\"quoted\"", value.Name, "#41"); + Assert.AreEqual (new NameValueHeaderValue ("name", "\"quoted\""), value.Parameters.First (), "#42"); + } + [Test] public void Properties_ModificationDate () { diff --git a/mcs/class/System.Net.Http/Test/System.Net.Http.Headers/MediaTypeHeaderValueTest.cs b/mcs/class/System.Net.Http/Test/System.Net.Http.Headers/MediaTypeHeaderValueTest.cs index afbf8274b9f..c4b882467aa 100644 --- a/mcs/class/System.Net.Http/Test/System.Net.Http.Headers/MediaTypeHeaderValueTest.cs +++ b/mcs/class/System.Net.Http/Test/System.Net.Http.Headers/MediaTypeHeaderValueTest.cs @@ -31,6 +31,7 @@ using System.Collections.Generic; using NUnit.Framework; using System.Net.Http.Headers; +using System.Linq; namespace MonoTests.System.Net.Http.Headers { @@ -81,6 +82,13 @@ public void Parse () Assert.AreEqual ("mu/m", res.MediaType, "#2"); Assert.AreEqual ("jj'", res.CharSet, "#2b"); Assert.AreEqual ("mu/m; CHarset=jj'", res.ToString (), "#2c"); + + res = MediaTypeHeaderValue.Parse ("multipart/form-data; boundary=----Wk"); + Assert.AreEqual ("multipart/form-data", res.MediaType, "#3"); + Assert.IsNull (res.CharSet, "#3b"); + Assert.AreEqual (1, res.Parameters.Count, "#3c"); + Assert.AreEqual (new NameValueHeaderValue ("boundary", "----Wk"), res.Parameters.First (), "#3d"); + Assert.AreEqual ("multipart/form-data; boundary=----Wk", res.ToString (), "#3e"); } [Test] diff --git a/mcs/class/System.Net.Http/Test/System.Net.Http/StreamContentTest.cs b/mcs/class/System.Net.Http/Test/System.Net.Http/StreamContentTest.cs index be0c47c5cc0..5d7cd12490c 100644 --- a/mcs/class/System.Net.Http/Test/System.Net.Http/StreamContentTest.cs +++ b/mcs/class/System.Net.Http/Test/System.Net.Http/StreamContentTest.cs @@ -222,6 +222,7 @@ public void Headers () Assert.AreEqual (330, scm.Headers.ContentLength, "#2"); headers.Allow.Add ("a1"); + headers.ContentDisposition = new ContentDispositionHeaderValue ("cd1"); headers.ContentEncoding.Add ("ce1"); headers.ContentLanguage.Add ("cl1"); headers.ContentLength = 23; @@ -234,6 +235,12 @@ public void Headers () headers.Add ("allow", "a2"); + try { + headers.Add ("content-disposition", "cd2"); + Assert.Fail ("content-disposition"); + } catch (FormatException) { + } + headers.Add ("content-encoding", "ce3"); headers.Add ("content-language", "cl2"); @@ -307,6 +314,7 @@ public void Headers () Assert.AreEqual (new MediaTypeHeaderValue ("multipart/*"), headers.ContentType); Assert.AreEqual (new DateTimeOffset (DateTime.Today), headers.Expires); Assert.AreEqual (new DateTimeOffset (DateTime.Today), headers.LastModified); + Assert.AreEqual (new ContentDispositionHeaderValue ("cd1"), headers.ContentDisposition); } [Test] diff --git a/mcs/class/System.Numerics/System.Numerics/BigInteger.cs b/mcs/class/System.Numerics/System.Numerics/BigInteger.cs index 329f91eed1f..93fb7b939e4 100644 --- a/mcs/class/System.Numerics/System.Numerics/BigInteger.cs +++ b/mcs/class/System.Numerics/System.Numerics/BigInteger.cs @@ -1,10 +1,12 @@ // // System.Numerics.BigInteger // -// Rodrigo Kumpera (rkumpera@novell.com) - +// Authors: +// Rodrigo Kumpera (rkumpera@novell.com) +// Marek Safar // // Copyright (C) 2010 Novell, Inc (http://www.novell.com) +// Copyright (C) 2014 Xamarin Inc (http://www.xamarin.com) // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -68,7 +70,6 @@ public struct BigInteger : IComparable, IFormattable, IComparable, I readonly uint[] data; readonly short sign; - static readonly uint[] ZERO = new uint [1]; static readonly uint[] ONE = new uint [1] { 1 }; BigInteger (short sign, uint[] data) @@ -81,7 +82,7 @@ public BigInteger (int value) { if (value == 0) { sign = 0; - data = ZERO; + data = null; } else if (value > 0) { sign = 1; data = new uint[] { (uint) value }; @@ -96,7 +97,7 @@ public BigInteger (uint value) { if (value == 0) { sign = 0; - data = ZERO; + data = null; } else { sign = 1; data = new uint [1] { value }; @@ -107,7 +108,7 @@ public BigInteger (long value) { if (value == 0) { sign = 0; - data = ZERO; + data = null; } else if (value > 0) { sign = 1; uint low = (uint)value; @@ -135,7 +136,7 @@ public BigInteger (ulong value) { if (value == 0) { sign = 0; - data = ZERO; + data = null; } else { sign = 1; uint low = (uint)value; @@ -180,7 +181,7 @@ public BigInteger (double value) int exponent = Exponent (bytes); if (exponent == 0) { sign = 0; - data = ZERO; + data = null; return; } @@ -217,7 +218,7 @@ public BigInteger (decimal value) if (size == 0) { sign = 0; - data = ZERO; + data = null; return; } @@ -241,7 +242,7 @@ public BigInteger (byte[] value) if (len == 0 || (len == 1 && value [0] == 0)) { sign = 0; - data = ZERO; + data = null; return; } @@ -254,7 +255,7 @@ public BigInteger (byte[] value) while (value [len - 1] == 0) { if (--len == 0) { sign = 0; - data = ZERO; + data = null; return; } } @@ -456,12 +457,12 @@ public static BigInteger One { } public static BigInteger Zero { - get { return new BigInteger (0, ZERO); } + get { return new BigInteger (0); } } public static explicit operator int (BigInteger value) { - if (value.sign == 0) + if (value.data == null) return 0; if (value.data.Length > 1) throw new OverflowException (); @@ -483,7 +484,7 @@ public static explicit operator int (BigInteger value) [CLSCompliantAttribute (false)] public static explicit operator uint (BigInteger value) { - if (value.sign == 0) + if (value.data == null) return 0; if (value.data.Length > 1 || value.sign == -1) throw new OverflowException (); @@ -527,7 +528,7 @@ public static explicit operator sbyte (BigInteger value) public static explicit operator long (BigInteger value) { - if (value.sign == 0) + if (value.data == null) return 0; if (value.data.Length > 2) @@ -569,7 +570,7 @@ long.MinValue works fine since it's bigint encoding looks like a negative [CLSCompliantAttribute (false)] public static explicit operator ulong (BigInteger value) { - if (value.sign == 0) + if (value.data == null) return 0; if (value.data.Length > 2 || value.sign == -1) throw new OverflowException (); @@ -584,9 +585,10 @@ public static explicit operator ulong (BigInteger value) public static explicit operator double (BigInteger value) { - switch (value.data.Length) { - case 0: + if (value.data == null) return 0.0; + + switch (value.data.Length) { case 1: return BuildDouble (value.sign, value.data [0], 0); case 2: @@ -613,7 +615,7 @@ public static explicit operator float (BigInteger value) public static explicit operator decimal (BigInteger value) { - if (value.sign == 0) + if (value.data == null) return Decimal.Zero; uint[] data = value.data; @@ -703,7 +705,7 @@ public static explicit operator BigInteger (decimal value) int r = CoreCompare (left.data, right.data); if (r == 0) - return new BigInteger (0, ZERO); + return Zero; if (r > 0) //left > right return new BigInteger (left.sign, CoreSub (left.data, right.data)); @@ -722,7 +724,7 @@ public static explicit operator BigInteger (decimal value) int r = CoreCompare (left.data, right.data); if (r == 0) - return new BigInteger (0, ZERO); + return Zero; if (r > 0) //left > right return new BigInteger (left.sign, CoreSub (left.data, right.data)); @@ -736,7 +738,7 @@ public static explicit operator BigInteger (decimal value) public static BigInteger operator* (BigInteger left, BigInteger right) { if (left.sign == 0 || right.sign == 0) - return new BigInteger (0, ZERO); + return Zero; if (left.data [0] == 1 && left.data.Length == 1) { if (left.sign == 1) @@ -797,7 +799,7 @@ public static explicit operator BigInteger (decimal value) int i; for (i = quotient.Length - 1; i >= 0 && quotient [i] == 0; --i) ; if (i == -1) - return new BigInteger (0, ZERO); + return Zero; if (i < quotient.Length - 1) quotient = Resize (quotient, i + 1); @@ -820,7 +822,7 @@ public static explicit operator BigInteger (decimal value) int i; for (i = remainder_value.Length - 1; i >= 0 && remainder_value [i] == 0; --i) ; if (i == -1) - return new BigInteger (0, ZERO); + return Zero; if (i < remainder_value.Length - 1) remainder_value = Resize (remainder_value, i + 1); @@ -829,7 +831,7 @@ public static explicit operator BigInteger (decimal value) public static BigInteger operator- (BigInteger value) { - if (value.sign == 0) + if (value.data == null) return value; return new BigInteger ((short)-value.sign, value.data); } @@ -841,14 +843,14 @@ public static explicit operator BigInteger (decimal value) public static BigInteger operator++ (BigInteger value) { - if (value.sign == 0) + if (value.data == null) return One; short sign = value.sign; uint[] data = value.data; if (data.Length == 1) { if (sign == -1 && data [0] == 1) - return new BigInteger (0, ZERO); + return Zero; if (sign == 0) return new BigInteger (1, ONE); } @@ -863,14 +865,14 @@ public static explicit operator BigInteger (decimal value) public static BigInteger operator-- (BigInteger value) { - if (value.sign == 0) + if (value.data == null) return MinusOne; short sign = value.sign; uint[] data = value.data; if (data.Length == 1) { if (sign == 1 && data [0] == 1) - return new BigInteger (0, ZERO); + return Zero; if (sign == 0) return new BigInteger (-1, ONE); } @@ -935,7 +937,7 @@ public static explicit operator BigInteger (decimal value) for (i = result.Length - 1; i >= 0 && result [i] == 0; --i) ; if (i == -1) - return new BigInteger (0, ZERO); + return Zero; if (i < result.Length - 1) result = Resize (result, i + 1); @@ -995,7 +997,7 @@ public static explicit operator BigInteger (decimal value) for (i = result.Length - 1; i >= 0 && result [i] == 0; --i) ; if (i == -1) - return new BigInteger (0, ZERO); + return Zero; if (i < result.Length - 1) result = Resize (result, i + 1); @@ -1055,7 +1057,7 @@ public static explicit operator BigInteger (decimal value) for (i = result.Length - 1; i >= 0 && result [i] == 0; --i) ; if (i == -1) - return new BigInteger (0, ZERO); + return Zero; if (i < result.Length - 1) result = Resize (result, i + 1); @@ -1065,7 +1067,7 @@ public static explicit operator BigInteger (decimal value) public static BigInteger operator~ (BigInteger value) { - if (value.sign == 0) + if (value.data == null) return new BigInteger (-1, ONE); uint[] data = value.data; @@ -1099,7 +1101,7 @@ public static explicit operator BigInteger (decimal value) for (i = result.Length - 1; i >= 0 && result [i] == 0; --i) ; if (i == -1) - return new BigInteger (0, ZERO); + return Zero; if (i < result.Length - 1) result = Resize (result, i + 1); @@ -1121,7 +1123,7 @@ static int BitScanBackward (uint word) public static BigInteger operator<< (BigInteger value, int shift) { - if (shift == 0 || value.sign == 0) + if (shift == 0 || value.data == null) return value; if (shift < 0) return value >> -shift; @@ -1177,7 +1179,7 @@ static int BitScanBackward (uint word) if (size <= 0) { if (sign == 1) - return new BigInteger (0, ZERO); + return Zero; return new BigInteger (-1, ONE); } @@ -2142,7 +2144,7 @@ public static BigInteger DivRem (BigInteger dividend, BigInteger divisor, out Bi int i; for (i = remainder_value.Length - 1; i >= 0 && remainder_value [i] == 0; --i) ; if (i == -1) { - remainder = new BigInteger (0, ZERO); + remainder = Zero; } else { if (i < remainder_value.Length - 1) remainder_value = Resize (remainder_value, i + 1); @@ -2151,7 +2153,7 @@ public static BigInteger DivRem (BigInteger dividend, BigInteger divisor, out Bi for (i = quotient.Length - 1; i >= 0 && quotient [i] == 0; --i) ; if (i == -1) - return new BigInteger (0, ZERO); + return Zero; if (i < quotient.Length - 1) quotient = Resize (quotient, i + 1); @@ -2264,7 +2266,7 @@ public static double Log (BigInteger value, Double baseValue) if (baseValue == 0.0d || baseValue == Double.PositiveInfinity) return value.IsOne ? 0 : double.NaN; - if (value.sign == 0) + if (value.data == null) return double.NegativeInfinity; int length = value.data.Length - 1; diff --git a/mcs/class/System.Numerics/Test/System.Numerics/BigIntegerTest.cs b/mcs/class/System.Numerics/Test/System.Numerics/BigIntegerTest.cs index 817d13e40c1..e9b81a71cd9 100644 --- a/mcs/class/System.Numerics/Test/System.Numerics/BigIntegerTest.cs +++ b/mcs/class/System.Numerics/Test/System.Numerics/BigIntegerTest.cs @@ -70,6 +70,7 @@ public void SetUpFixture() NfiUser.PercentNegativePattern = 2; NfiUser.PercentPositivePattern = 2; NfiUser.PercentSymbol = "%%%"; + NfiUser.NumberDecimalSeparator = "."; } [Test] @@ -625,10 +626,12 @@ public void TestIntCtorProperties () Assert.IsTrue (new BigInteger (1).IsOne, "#7"); Assert.IsTrue (new BigInteger (32).IsPowerOfTwo, "#8"); Assert.IsTrue (new BigInteger (0).IsZero, "#9"); + Assert.IsTrue (new BigInteger ().IsZero, "#9b"); Assert.AreEqual (0, new BigInteger (0).Sign, "#10"); Assert.AreEqual (-1, new BigInteger (-99999).Sign, "#11"); Assert.IsFalse (new BigInteger (0).IsPowerOfTwo, "#12"); + Assert.IsFalse (new BigInteger ().IsPowerOfTwo, "#12b"); Assert.IsFalse (new BigInteger (-16).IsPowerOfTwo, "#13"); Assert.IsTrue (new BigInteger (1).IsPowerOfTwo, "#14"); } @@ -647,6 +650,7 @@ public void TestToStringFmt () Assert.AreEqual ("0000000005", new BigInteger (5).ToString ("d10"), "#2"); Assert.AreEqual ("0A8", new BigInteger (168).ToString ("X"), "#3"); Assert.AreEqual ("0", new BigInteger (0).ToString ("X"), "#4"); + Assert.AreEqual ("0", new BigInteger ().ToString ("X"), "#4b"); Assert.AreEqual ("1", new BigInteger (1).ToString ("X"), "#5"); Assert.AreEqual ("0A", new BigInteger (10).ToString ("X"), "#6"); Assert.AreEqual ("F6", new BigInteger (-10).ToString ("X"), "#7"); @@ -750,6 +754,7 @@ public void TestIntCtorToByteArray () Assert.AreEqual (new byte[] { 0x7F }, new BigInteger (0x7F).ToByteArray (), "#10"); Assert.AreEqual (new byte[] { 0x45, 0xCC, 0xD0 }, new BigInteger (-0x2F33BB).ToByteArray (), "#11"); Assert.AreEqual (new byte[] { 0 }, new BigInteger (0).ToByteArray (), "#12"); + Assert.AreEqual (new byte[] { 0 }, new BigInteger ().ToByteArray (), "#13"); } [Test] @@ -886,6 +891,14 @@ public void DecimalConversion () { Assert.AreEqual (-1m, (decimal)new BigInteger (-1), "#6"); Assert.AreEqual (9999999999999999999999999999m, (decimal)new BigInteger (9999999999999999999999999999m), "#7"); + Assert.AreEqual (0m, (decimal)new BigInteger (), "#8"); + } + + [SetCulture ("pt-BR")] + [Test] + public void Parse_pt_BR () + { + Parse (); } [Test] @@ -938,7 +951,8 @@ public void Parse () { Assert.AreEqual (-23, (int)BigInteger.Parse(" -23 ", NumberStyles.AllowLeadingSign | NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite), "#19"); Assert.AreEqual (300000, (int)BigInteger.Parse("3E5", NumberStyles.AllowExponent), "#20"); - Assert.AreEqual (250, (int)BigInteger.Parse("2"+Nfi.NumberDecimalSeparator+"5E2", NumberStyles.AllowExponent | NumberStyles.AllowDecimalPoint), "#21");//2.5E2 = 250 + var dsep = NumberFormatInfo.CurrentInfo.NumberDecimalSeparator; + Assert.AreEqual (250, (int)BigInteger.Parse("2" + dsep + "5E2", NumberStyles.AllowExponent | NumberStyles.AllowDecimalPoint), "#21");//2.5E2 = 250 Assert.AreEqual (25, (int)BigInteger.Parse("2500E-2", NumberStyles.AllowExponent), "#22"); Assert.AreEqual ("136236974127783066520110477975349088954559032721408", BigInteger.Parse("136236974127783066520110477975349088954559032721408", NumberStyles.None).ToString(), "#23"); @@ -951,7 +965,7 @@ public void Parse () { } try { - Int32.Parse ("2.09E1", NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent); + Int32.Parse ("2" + dsep + "09E1", NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent); Assert.Fail ("#26"); } catch (OverflowException) { } @@ -1276,6 +1290,9 @@ public void DefaultCtorWorks () a = new BigInteger (); Assert.AreEqual (BigInteger.Zero.GetHashCode (), a.GetHashCode (), "#15"); + + a = new BigInteger (); + Assert.AreEqual (BigInteger.Zero, a, "#16"); } [Test] diff --git a/mcs/class/System.Reactive.Core/Makefile b/mcs/class/System.Reactive.Core/Makefile index 3f74f8bf98e..624018c1098 100644 --- a/mcs/class/System.Reactive.Core/Makefile +++ b/mcs/class/System.Reactive.Core/Makefile @@ -35,7 +35,7 @@ TEST_MCS_FLAGS = $(LIB_MCS_FLAGS) EXTRA_DISTFILES = more_build_args $(RESX_RESOURCES:.resources=.resx) $(PREBUILT) -VALID_PROFILE := $(filter monotouch monodroid xammac net_4_0 net_4_5, $(PROFILE)) +VALID_PROFILE := $(filter monotouch monodroid xammac mobile mobile_static net_4_0 net_4_5, $(PROFILE)) ifndef VALID_PROFILE LIBRARY_NAME = dummy-System.System.Reactive.Core.dll NO_SIGN_ASSEMBLY = yes diff --git a/mcs/class/System.Reactive.Debugger/Makefile b/mcs/class/System.Reactive.Debugger/Makefile index c603f89a68a..3e308212455 100644 --- a/mcs/class/System.Reactive.Debugger/Makefile +++ b/mcs/class/System.Reactive.Debugger/Makefile @@ -24,7 +24,7 @@ TEST_MCS_FLAGS = $(LIB_MCS_FLAGS) EXTRA_DISTFILES = more_build_args -VALID_PROFILE := $(filter monotouch monodroid xammac net_4_0 net_4_5, $(PROFILE)) +VALID_PROFILE := $(filter monotouch monodroid xammac mobile mobile_static net_4_0 net_4_5, $(PROFILE)) ifndef VALID_PROFILE LIBRARY_NAME = dummy-System.System.Reactive.Debugger.dll NO_SIGN_ASSEMBLY = yes diff --git a/mcs/class/System.Reactive.Experimental/Makefile b/mcs/class/System.Reactive.Experimental/Makefile index 234a63b12d9..834240acccc 100644 --- a/mcs/class/System.Reactive.Experimental/Makefile +++ b/mcs/class/System.Reactive.Experimental/Makefile @@ -24,7 +24,7 @@ TEST_MCS_FLAGS = $(LIB_MCS_FLAGS) EXTRA_DISTFILES = more_build_args -VALID_PROFILE := $(filter monotouch monodroid xammac net_4_0 net_4_5, $(PROFILE)) +VALID_PROFILE := $(filter monotouch monodroid xammac mobile mobile_static net_4_0 net_4_5, $(PROFILE)) ifndef VALID_PROFILE LIBRARY_NAME = dummy-System.System.Reactive.Experimental.dll NO_SIGN_ASSEMBLY = yes diff --git a/mcs/class/System.Reactive.Interfaces/Makefile b/mcs/class/System.Reactive.Interfaces/Makefile index acee40d2960..fae46634976 100644 --- a/mcs/class/System.Reactive.Interfaces/Makefile +++ b/mcs/class/System.Reactive.Interfaces/Makefile @@ -21,7 +21,7 @@ TEST_MCS_FLAGS = $(LIB_MCS_FLAGS) EXTRA_DISTFILES = more_build_args -VALID_PROFILE := $(filter monotouch monodroid xammac net_4_0 net_4_5, $(PROFILE)) +VALID_PROFILE := $(filter monotouch monodroid xammac mobile mobile_static net_4_0 net_4_5, $(PROFILE)) ifndef VALID_PROFILE LIBRARY_NAME = dummy-System.System.Reactive.Interfaces.dll NO_SIGN_ASSEMBLY = yes diff --git a/mcs/class/System.Reactive.Linq/Makefile b/mcs/class/System.Reactive.Linq/Makefile index 18a3360dafe..3906cfc6adc 100644 --- a/mcs/class/System.Reactive.Linq/Makefile +++ b/mcs/class/System.Reactive.Linq/Makefile @@ -36,7 +36,7 @@ TEST_MCS_FLAGS = $(LIB_MCS_FLAGS) EXTRA_DISTFILES = more_build_args $(RESX_RESOURCES:.resources=.resx) $(PREBUILT) -VALID_PROFILE := $(filter monotouch monodroid xammac net_4_0 net_4_5, $(PROFILE)) +VALID_PROFILE := $(filter monotouch monodroid xammac mobile mobile_static net_4_0 net_4_5, $(PROFILE)) ifndef VALID_PROFILE LIBRARY_NAME = dummy-System.System.Reactive.Linq.dll NO_SIGN_ASSEMBLY = yes diff --git a/mcs/class/System.Reactive.PlatformServices/Makefile b/mcs/class/System.Reactive.PlatformServices/Makefile index 187dd7702ff..6fccc274c42 100644 --- a/mcs/class/System.Reactive.PlatformServices/Makefile +++ b/mcs/class/System.Reactive.PlatformServices/Makefile @@ -42,7 +42,7 @@ TEST_MCS_FLAGS = $(LIB_MCS_FLAGS) -r:Mono.Reactive.Tests.dll EXTRA_DISTFILES = more_build_args $(RESX_RESOURCES:.resources=.resx) $(PREBUILT) -VALID_PROFILE := $(filter monotouch monodroid xammac net_4_0 net_4_5, $(PROFILE)) +VALID_PROFILE := $(filter monotouch monodroid xammac mobile mobile_static net_4_0 net_4_5, $(PROFILE)) ifndef VALID_PROFILE LIBRARY_NAME = dummy-System.System.Reactive.PlatformServices.dll NO_SIGN_ASSEMBLY = yes diff --git a/mcs/class/System.ServiceModel.Web/System.Runtime.Serialization.Json/DataContractJsonSerializer.cs b/mcs/class/System.ServiceModel.Web/System.Runtime.Serialization.Json/DataContractJsonSerializer.cs index 295161932b5..8ae0ce57356 100644 --- a/mcs/class/System.ServiceModel.Web/System.Runtime.Serialization.Json/DataContractJsonSerializer.cs +++ b/mcs/class/System.ServiceModel.Web/System.Runtime.Serialization.Json/DataContractJsonSerializer.cs @@ -84,7 +84,17 @@ public DataContractJsonSerializer (Type type, XmlDictionaryString rootName, IEnu throw new ArgumentOutOfRangeException ("maxItemsInObjectGraph"); this.type = type; - known_types = new ReadOnlyCollection (knownTypes != null ? knownTypes.ToArray () : Type.EmptyTypes); + + var knownTypesFromAttributes = new List (); + + 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 (knownTypesFromAttributes); + root = rootName; max_items = maxItemsInObjectGraph; ignore_extension = ignoreExtensionDataObject; @@ -134,8 +144,6 @@ public IDataContractSurrogate DataContractSurrogate { public bool IgnoreExtensionDataObject { get { return ignore_extension; } } - - [MonoTODO] public ReadOnlyCollection KnownTypes { get { return known_types; } } diff --git a/mcs/class/System.ServiceModel.Web/System.Runtime.Serialization.Json/JsonSerializationReader.cs b/mcs/class/System.ServiceModel.Web/System.Runtime.Serialization.Json/JsonSerializationReader.cs index 10d147adf18..26a132f9d5d 100644 --- a/mcs/class/System.ServiceModel.Web/System.Runtime.Serialization.Json/JsonSerializationReader.cs +++ b/mcs/class/System.ServiceModel.Web/System.Runtime.Serialization.Json/JsonSerializationReader.cs @@ -182,8 +182,18 @@ public object ReadObject (Type type, object instance) 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 @@ -198,24 +208,22 @@ object ReadValueType (Type type, bool nullable) } - 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; } @@ -230,7 +238,7 @@ object ReadInstanceDrivenObject () 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); @@ -264,7 +272,7 @@ object ReadInstanceDrivenObject () if (double.TryParse (v, NumberStyles.None, CultureInfo.InvariantCulture, out dbl)) return dbl; decimal dec; - if (decimal.TryParse (v, NumberStyles.None, CultureInfo.InvariantCulture, out dec)) + if (decimal.TryParse (v, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out dec)) return dec; throw SerializationError (String.Format ("Invalid JSON input: {0}", v)); default: diff --git a/mcs/class/System.ServiceModel.Web/System.ServiceModel.Syndication/Rss20ItemFormatter.cs b/mcs/class/System.ServiceModel.Web/System.ServiceModel.Syndication/Rss20ItemFormatter.cs index cd4c1ffccdf..cd586fa05c3 100644 --- a/mcs/class/System.ServiceModel.Web/System.ServiceModel.Syndication/Rss20ItemFormatter.cs +++ b/mcs/class/System.ServiceModel.Web/System.ServiceModel.Syndication/Rss20ItemFormatter.cs @@ -203,10 +203,9 @@ void ReadXml (XmlReader reader, bool fromSerializable) Item.Links.Add (l); continue; case "guid": + Item.Id = reader.ReadElementContentAsString (); if (reader.GetAttribute ("isPermaLink") == "true") - Item.AddPermalink (CreateUri (reader.ReadElementContentAsString ())); - else - Item.Id = reader.ReadElementContentAsString (); + Item.AddPermalink (CreateUri (Item.Id)); continue; case "pubDate": Item.PublishDate = FromRFC822DateString (reader.ReadElementContentAsString ()); diff --git a/mcs/class/System.ServiceModel.Web/Test/System.Runtime.Serialization.Json/DataContractJsonSerializerTest.cs b/mcs/class/System.ServiceModel.Web/Test/System.Runtime.Serialization.Json/DataContractJsonSerializerTest.cs index 68d9fb6a083..8a11d70baf1 100644 --- a/mcs/class/System.ServiceModel.Web/Test/System.Runtime.Serialization.Json/DataContractJsonSerializerTest.cs +++ b/mcs/class/System.ServiceModel.Web/Test/System.Runtime.Serialization.Json/DataContractJsonSerializerTest.cs @@ -1191,6 +1191,15 @@ private object Deserialize (string xml, Type type, params Type [] knownTypes) return ser.ReadObject (xr); } + public T Deserialize(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 () { @@ -1819,6 +1828,50 @@ public void TestNonCollectionGetOnlyProperty () 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 (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 (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 (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 (serializedObj); + } + #endregion } @@ -2037,6 +2090,42 @@ void OnDeserialized (StreamingContext c) 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] diff --git a/mcs/class/System.ServiceModel.Web/Test/System.Runtime.Serialization.Json/JsonReaderTest.cs b/mcs/class/System.ServiceModel.Web/Test/System.Runtime.Serialization.Json/JsonReaderTest.cs index 0ca6f2fb050..de884aeac9a 100644 --- a/mcs/class/System.ServiceModel.Web/Test/System.Runtime.Serialization.Json/JsonReaderTest.cs +++ b/mcs/class/System.ServiceModel.Web/Test/System.Runtime.Serialization.Json/JsonReaderTest.cs @@ -855,5 +855,16 @@ public void UnicodeEncodingAutoDetect () r.ReadStartElement (); r.Read (); } + + [Test] + public void ReadNumberAsObject () + { + const double testValue = 42.42D; + var serializer = new DataContractJsonSerializer (typeof (object)); + var serializedStream = GetInput (testValue.ToString (CultureInfo.InvariantCulture)); + var deserializedValue = serializer.ReadObject (serializedStream); + Assert.AreEqual (typeof (decimal), deserializedValue.GetType ()); + Assert.AreEqual (testValue, (decimal) deserializedValue); + } } } diff --git a/mcs/class/System.ServiceModel.Web/Test/System.ServiceModel.Syndication/Rss20ItemFormatterTest.cs b/mcs/class/System.ServiceModel.Web/Test/System.ServiceModel.Syndication/Rss20ItemFormatterTest.cs index 3b83d230cb4..d0ea17ff6ad 100644 --- a/mcs/class/System.ServiceModel.Web/Test/System.ServiceModel.Syndication/Rss20ItemFormatterTest.cs +++ b/mcs/class/System.ServiceModel.Web/Test/System.ServiceModel.Syndication/Rss20ItemFormatterTest.cs @@ -351,6 +351,24 @@ public void GetSchema () { Assert.IsNull (((IXmlSerializable) new Rss20ItemFormatter ()).GetSchema ()); } + + [Test] + public void ReadFromGuidPermaLink () + { + const string xml1 = "urn:myid"; + using (XmlReader r = CreateReader (xml1)) { + var rss = new Rss20ItemFormatter (); + rss.ReadFrom (r); + Assert.AreEqual ("urn:myid", rss.Item.Id); + } + + const string xml2 = "urn:myid"; + using (XmlReader r = CreateReader (xml2)) { + var rss = new Rss20ItemFormatter (); + rss.ReadFrom (r); + Assert.AreEqual ("urn:myid", rss.Item.Id); + } + } } } #endif \ No newline at end of file diff --git a/mcs/class/System.ServiceModel/System.ServiceModel.Description/ContractDescription.cs b/mcs/class/System.ServiceModel/System.ServiceModel.Description/ContractDescription.cs index 6c0c3366f75..805053196d4 100644 --- a/mcs/class/System.ServiceModel/System.ServiceModel.Description/ContractDescription.cs +++ b/mcs/class/System.ServiceModel/System.ServiceModel.Description/ContractDescription.cs @@ -234,6 +234,9 @@ void PopulateClientOperation (ClientRuntime proxy, OperationDescription od, bool foreach (var fd in od.Faults) o.FaultContractInfos.Add (new FaultContractInfo (fd.Action, fd.DetailType)); + o.BeginMethod = od.BeginMethod; + o.EndMethod = od.EndMethod; + // FIXME: at initialization time it does not seem to // fill default formatter. It should be filled after // applying all behaviors. (Tthat causes regression, so diff --git a/mcs/class/System.ServiceModel/System.ServiceModel.Description/ContractDescriptionGenerator.cs b/mcs/class/System.ServiceModel/System.ServiceModel.Description/ContractDescriptionGenerator.cs index 929a450d22b..a7665b8cab6 100644 --- a/mcs/class/System.ServiceModel/System.ServiceModel.Description/ContractDescriptionGenerator.cs +++ b/mcs/class/System.ServiceModel/System.ServiceModel.Description/ContractDescriptionGenerator.cs @@ -237,7 +237,6 @@ static void FillOperationsForInterface (ContractDescription cd, Type exactContra for (int i = 0; i < contractMethods.Length; ++i) { - MethodInfo mi = contractMethods [i]; OperationContractAttribute oca = GetOperationContractAttribute (mi); if (oca == null) @@ -253,7 +252,7 @@ static void FillOperationsForInterface (ContractDescription cd, Type exactContra if (GetOperationContractAttribute (end) != null) throw new InvalidOperationException ("Async 'End' method must not have OperationContractAttribute. It is automatically treated as the EndMethod of the corresponding 'Begin' method."); } - OperationDescription od = GetOrCreateOperation (cd, mi, serviceMethods [i], oca, end != null ? end.ReturnType : null, isCallback, givenServiceType); + OperationDescription od = GetOrCreateOperation (cd, mi, serviceMethods [i], oca, end, isCallback, givenServiceType); if (end != null) od.EndMethod = end; } @@ -286,7 +285,7 @@ static IEnumerable GetAllInterfaceTypes (Type type) static OperationDescription GetOrCreateOperation ( ContractDescription cd, MethodInfo mi, MethodInfo serviceMethod, OperationContractAttribute oca, - Type asyncReturnType, + MethodInfo endMethod, bool isCallback, Type givenServiceType) { @@ -311,7 +310,8 @@ static OperationDescription GetOrCreateOperation ( od.Messages.Add (GetMessage (od, mi, oca, true, isCallback, null)); if (!od.IsOneWay) { - var md = GetMessage (od, mi, oca, false, isCallback, asyncReturnType); + var asyncReturnType = endMethod != null ? endMethod.ReturnType : null; + var md = GetMessage (od, endMethod ?? mi, oca, false, isCallback, asyncReturnType); od.Messages.Add (md); var mpa = mi.ReturnParameter.GetCustomAttribute (true); if (mpa != null) { @@ -522,8 +522,12 @@ public static MessageDescription CreateMessageDescription ( int index = 0; foreach (ParameterInfo pi in plist) { // AsyncCallback and state are extraneous. - if (oca.AsyncPattern && pi.Position == plist.Length - 2) - break; + if (oca.AsyncPattern) { + if (isRequest && pi.Position == plist.Length - 2) + break; + if (!isRequest && pi.Position == plist.Length - 1) + break; + } // They are ignored: // - out parameter in request diff --git a/mcs/class/System.ServiceModel/System.ServiceModel.Dispatcher/BaseMessagesFormatter.cs b/mcs/class/System.ServiceModel/System.ServiceModel.Dispatcher/BaseMessagesFormatter.cs index f512ea37553..db1c49650c1 100644 --- a/mcs/class/System.ServiceModel/System.ServiceModel.Dispatcher/BaseMessagesFormatter.cs +++ b/mcs/class/System.ServiceModel/System.ServiceModel.Dispatcher/BaseMessagesFormatter.cs @@ -281,9 +281,10 @@ public object DeserializeReply (Message message, object [] parameters) } else { int index = ParamsOffset (md.Body); - foreach (ParameterInfo pi in requestMethodParams) + foreach (ParameterInfo pi in replyMethodParams) { if (pi.IsOut || pi.ParameterType.IsByRef) parameters [pi.Position] = parts [index++]; + } return HasReturnValue (md.Body) ? parts [0] : null; } } diff --git a/mcs/class/System.ServiceModel/System.ServiceModel/ClientBase.cs b/mcs/class/System.ServiceModel/System.ServiceModel/ClientBase.cs index 702217017d0..07952e04f14 100644 --- a/mcs/class/System.ServiceModel/System.ServiceModel/ClientBase.cs +++ b/mcs/class/System.ServiceModel/System.ServiceModel/ClientBase.cs @@ -389,7 +389,7 @@ protected object Invoke (string methodName, object [] args) var od = cd.Operations.Find (methodName); if (od == null) throw new ArgumentException (String.Format ("Operation '{0}' not found in the service contract '{1}' in namespace '{2}'", methodName, cd.Name, cd.Namespace)); - return Inner.Process (od.SyncMethod, methodName, args); + return Inner.Process (od.SyncMethod, methodName, args, OperationContext.Current); } protected IAsyncResult BeginInvoke (string methodName, object [] args, AsyncCallback callback, object state) diff --git a/mcs/class/System.ServiceModel/System.ServiceModel/ClientRealProxy.cs b/mcs/class/System.ServiceModel/System.ServiceModel/ClientRealProxy.cs index 1c94718b6b9..41d75e98f9c 100644 --- a/mcs/class/System.ServiceModel/System.ServiceModel/ClientRealProxy.cs +++ b/mcs/class/System.ServiceModel/System.ServiceModel/ClientRealProxy.cs @@ -108,8 +108,7 @@ IMessage DoInvoke (IMessage inputMessage) // sync invocation pl = new object [inmsg.MethodBase.GetParameters ().Length]; Array.Copy (inmsg.Args, pl, inmsg.ArgCount); - channel.Context = OperationContext.Current; - ret = channel.Process (inmsg.MethodBase, od.Name, pl); + ret = channel.Process (inmsg.MethodBase, od.Name, pl, OperationContext.Current); method = od.SyncMethod; } else if (inmsg.MethodBase.Equals (od.BeginMethod)) { // async invocation diff --git a/mcs/class/System.ServiceModel/System.ServiceModel/ClientRuntimeChannel.cs b/mcs/class/System.ServiceModel/System.ServiceModel/ClientRuntimeChannel.cs index 6d073e3d575..043b2ab7af0 100644 --- a/mcs/class/System.ServiceModel/System.ServiceModel/ClientRuntimeChannel.cs +++ b/mcs/class/System.ServiceModel/System.ServiceModel/ClientRuntimeChannel.cs @@ -46,9 +46,7 @@ interface IInternalContextChannel { ContractDescription Contract { get; } - OperationContext Context { set; } - - object Process (MethodBase method, string operationName, object [] parameters); + object Process (MethodBase method, string operationName, object [] parameters, OperationContext context); IAsyncResult BeginProcess (MethodBase method, string operationName, object [] parameters, AsyncCallback callback, object asyncState); @@ -69,12 +67,11 @@ class ClientRuntimeChannel TimeSpan default_open_timeout, default_close_timeout; IChannel channel; IChannelFactory factory; - OperationContext context; #region delegates readonly ProcessDelegate _processDelegate; - delegate object ProcessDelegate (MethodBase method, string operationName, object [] parameters); + delegate object ProcessDelegate (MethodBase method, string operationName, bool isAsync, ref object [] parameters, OperationContext context); readonly RequestDelegate requestDelegate; @@ -149,10 +146,6 @@ internal IDuplexChannel DuplexChannel { get { return channel as IDuplexChannel; } } - public OperationContext Context { - set { context = value; } - } - #region IClientChannel bool did_interactive_initialization; @@ -445,42 +438,48 @@ public IExtensionCollection Extensions { public IAsyncResult BeginProcess (MethodBase method, string operationName, object [] parameters, AsyncCallback callback, object asyncState) { - if (context != null) - throw new InvalidOperationException ("another operation is in progress"); - context = OperationContext.Current; - - try { - return _processDelegate.BeginInvoke (method, operationName, parameters, callback, asyncState); - } catch { - context = null; - throw; - } + var p = parameters; + var retval = _processDelegate.BeginInvoke (method, operationName, true, ref p, OperationContext.Current, callback, asyncState); + if (p != parameters) + throw new InvalidOperationException (); + return retval; } public object EndProcess (MethodBase method, string operationName, object [] parameters, IAsyncResult result) { - try { - if (result == null) - throw new ArgumentNullException ("result"); - if (parameters == null) - throw new ArgumentNullException ("parameters"); - // FIXME: the method arguments should be verified to be - // identical to the arguments in the corresponding begin method. - return _processDelegate.EndInvoke (result); - } finally { - context = null; - } + if (result == null) + throw new ArgumentNullException ("result"); + if (parameters == null) + throw new ArgumentNullException ("parameters"); + + object[] p = parameters; + var retval = _processDelegate.EndInvoke (ref p, result); + if (p == parameters) + return retval; + + if (p.Length != parameters.Length) + throw new InvalidOperationException (); + Array.Copy (p, parameters, p.Length); + return retval; + } + + public object Process (MethodBase method, string operationName, object [] parameters, OperationContext context) + { + var p = parameters; + var retval = Process (method, operationName, false, ref p, context); + if (p != parameters) + throw new InvalidOperationException (); + return retval; } - public object Process (MethodBase method, string operationName, object [] parameters) + object Process (MethodBase method, string operationName, bool isAsync, ref object [] parameters, OperationContext context) { var previousContext = OperationContext.Current; try { // Inherit the context from the calling thread - if (this.context != null) - OperationContext.Current = this.context; + OperationContext.Current = context; - return DoProcess (method, operationName, parameters); + return DoProcess (method, operationName, isAsync, ref parameters, context); } catch (Exception ex) { throw; } finally { @@ -489,7 +488,7 @@ public object Process (MethodBase method, string operationName, object [] parame } } - object DoProcess (MethodBase method, string operationName, object [] parameters) + object DoProcess (MethodBase method, string operationName, bool isAsync, ref object [] parameters, OperationContext context) { if (AllowInitializationUI) DisplayInitializationUI (); @@ -499,9 +498,9 @@ object DoProcess (MethodBase method, string operationName, object [] parameters) Open (); if (!od.IsOneWay) - return Request (od, parameters); + return Request (od, isAsync, ref parameters, context); else { - Output (od, parameters); + Output (od, parameters, context); return null; } } @@ -519,17 +518,17 @@ OperationDescription SelectOperation (MethodBase method, string operationName, o return od; } - void Output (OperationDescription od, object [] parameters) + void Output (OperationDescription od, object [] parameters, OperationContext context) { ClientOperation op = runtime.Operations [od.Name]; - Send (CreateRequest (op, parameters), OperationTimeout); + Send (CreateRequest (op, parameters, context), OperationTimeout); } - object Request (OperationDescription od, object [] parameters) + object Request (OperationDescription od, bool isAsync, ref object [] parameters, OperationContext context) { ClientOperation op = runtime.Operations [od.Name]; object [] inspections = new object [runtime.MessageInspectors.Count]; - Message req = CreateRequest (op, parameters); + Message req = CreateRequest (op, parameters, context); for (int i = 0; i < inspections.Length; i++) inspections [i] = runtime.MessageInspectors [i].BeforeSendRequest (ref req, this); @@ -566,10 +565,15 @@ object Request (OperationDescription od, object [] parameters) for (int i = 0; i < inspections.Length; i++) runtime.MessageInspectors [i].AfterReceiveReply (ref res, inspections [i]); - if (op.DeserializeReply) - return op.Formatter.DeserializeReply (res, parameters); - else + if (!op.DeserializeReply) return res; + + if (isAsync && od.EndMethod != null) { + var endParams = od.EndMethod.GetParameters (); + parameters = new object [endParams.Length - 1]; + } + + return op.Formatter.DeserializeReply (res, parameters); } #region Message-based Request() and Send() @@ -621,7 +625,7 @@ internal void EndSend (IAsyncResult result) } #endregion - Message CreateRequest (ClientOperation op, object [] parameters) + Message CreateRequest (ClientOperation op, object [] parameters, OperationContext context) { MessageVersion version = message_version; if (version == null) diff --git a/mcs/class/System.ServiceModel/System.ServiceModel/ServiceRuntimeChannel.cs b/mcs/class/System.ServiceModel/System.ServiceModel/ServiceRuntimeChannel.cs index 0fe0d47b3dc..7bc54823627 100644 --- a/mcs/class/System.ServiceModel/System.ServiceModel/ServiceRuntimeChannel.cs +++ b/mcs/class/System.ServiceModel/System.ServiceModel/ServiceRuntimeChannel.cs @@ -114,9 +114,9 @@ public object EndProcess (MethodBase method, string operationName, object [] par return client.EndProcess (method, operationName, parameters, result); } - public object Process (MethodBase method, string operationName, object [] parameters) + public object Process (MethodBase method, string operationName, object [] parameters, OperationContext context) { - return client.Process (method, operationName, parameters); + return client.Process (method, operationName, parameters, context); } } diff --git a/mcs/class/System.ServiceModel/Test/System.ServiceModel.Channels/CommunicationObjectSyncTest.cs b/mcs/class/System.ServiceModel/Test/System.ServiceModel.Channels/CommunicationObjectSyncTest.cs index 1650bead02d..798a77915f1 100644 --- a/mcs/class/System.ServiceModel/Test/System.ServiceModel.Channels/CommunicationObjectSyncTest.cs +++ b/mcs/class/System.ServiceModel/Test/System.ServiceModel.Channels/CommunicationObjectSyncTest.cs @@ -35,7 +35,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Mono.Moonlight.UnitTesting; -namespace MoonTest.ServiceModel { +namespace MonoTests.System.ServiceModel.Channels { [TestClass] public class CommunicationObjectSyncTest { diff --git a/mcs/class/System.ServiceModel/Test/System.ServiceModel.Dispatcher/Bug652331Test.cs b/mcs/class/System.ServiceModel/Test/System.ServiceModel.Dispatcher/Bug652331Test.cs index d0e0ea09ba0..ed5fb8b65c9 100644 --- a/mcs/class/System.ServiceModel/Test/System.ServiceModel.Dispatcher/Bug652331Test.cs +++ b/mcs/class/System.ServiceModel/Test/System.ServiceModel.Dispatcher/Bug652331Test.cs @@ -70,7 +70,7 @@ public void Bug652331_2 () // test in one of the comment }; client.GetDataAsync (); - if (!wait.WaitOne (TimeSpan.FromSeconds (10))) + if (!wait.WaitOne (TimeSpan.FromSeconds (20))) Assert.Fail ("timeout"); } finally { serviceHost.Close (); diff --git a/mcs/class/System.ServiceProcess/Test/System.ServiceProcess/ServiceBaseTest.cs b/mcs/class/System.ServiceProcess/Test/System.ServiceProcess/ServiceBaseTest.cs index 7a3c014f7cd..ec6a3a236b8 100644 --- a/mcs/class/System.ServiceProcess/Test/System.ServiceProcess/ServiceBaseTest.cs +++ b/mcs/class/System.ServiceProcess/Test/System.ServiceProcess/ServiceBaseTest.cs @@ -27,10 +27,11 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // +using System.ComponentModel; using System.ServiceProcess; using NUnit.Framework; -namespace Test +namespace MonoTests.System.ServiceProcess { [TestFixture] public class ServiceBaseTest @@ -84,7 +85,7 @@ partial class ServiceFoo /// /// Required designer variable. /// - private System.ComponentModel.IContainer components = null; + private IContainer components = null; /// /// Clean up any resources being used. @@ -107,7 +108,7 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { - components = new System.ComponentModel.Container(); + components = new Container(); this.ServiceName = "ServiceFoo"; } diff --git a/mcs/class/System.Web.Abstractions/System.Web/HttpContextWrapper.cs b/mcs/class/System.Web.Abstractions/System.Web/HttpContextWrapper.cs index 22feb8530d7..6581c0c1f77 100644 --- a/mcs/class/System.Web.Abstractions/System.Web/HttpContextWrapper.cs +++ b/mcs/class/System.Web.Abstractions/System.Web/HttpContextWrapper.cs @@ -183,10 +183,9 @@ public override object GetSection (string sectionName) return w.GetSection (sectionName); } - [MonoTODO] public override object GetService (Type serviceType) { - throw new NotImplementedException (); + return ((IServiceProvider)w).GetService (serviceType); } #if NET_4_0 public override void RemapHandler (IHttpHandler handler) diff --git a/mcs/class/System.Web.Abstractions/System.Web/HttpRequestBase.cs b/mcs/class/System.Web.Abstractions/System.Web/HttpRequestBase.cs index 3a4c58e9513..bf1d6f576aa 100644 --- a/mcs/class/System.Web.Abstractions/System.Web/HttpRequestBase.cs +++ b/mcs/class/System.Web.Abstractions/System.Web/HttpRequestBase.cs @@ -136,6 +136,12 @@ public virtual RequestContext RequestContext { public virtual int TotalBytes { get { NotImplemented (); return 0; } } +#if NET_4_5 + public virtual ReadEntityBodyMode ReadEntityBodyMode { get { NotImplemented(); return ReadEntityBodyMode.Classic; } } + + public virtual UnvalidatedRequestValuesBase Unvalidated { get { NotImplemented (); return null; } } +#endif + public virtual Uri Url { get { NotImplemented (); return null; } } public virtual Uri UrlReferrer { get { NotImplemented (); return null; } } @@ -148,6 +154,12 @@ public virtual RequestContext RequestContext { public virtual string [] UserLanguages { get { NotImplemented (); return null; } } +#if NET_4_5 + public virtual void Abort () + { + NotImplemented(); + } +#endif public virtual byte [] BinaryRead (int count) { diff --git a/mcs/class/System.Web.Abstractions/System.Web/HttpRequestWrapper.cs b/mcs/class/System.Web.Abstractions/System.Web/HttpRequestWrapper.cs index 41969c6468b..197a7abd1c4 100644 --- a/mcs/class/System.Web.Abstractions/System.Web/HttpRequestWrapper.cs +++ b/mcs/class/System.Web.Abstractions/System.Web/HttpRequestWrapper.cs @@ -208,6 +208,18 @@ public override int TotalBytes { get { return w.TotalBytes; } } +#if NET_4_5 + public override UnvalidatedRequestValuesBase Unvalidated { + get { return new UnvalidatedRequestValuesWrapper (w.Unvalidated); } + } +#endif + +#if NET_4_5 + public override ReadEntityBodyMode ReadEntityBodyMode { + get { return ReadEntityBodyMode.Classic; } + } +#endif + public override Uri Url { get { return w.Url; } } @@ -232,6 +244,13 @@ public override string [] UserLanguages { 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); diff --git a/mcs/class/System.Web.Abstractions/System.Web/HttpResponseBase.cs b/mcs/class/System.Web.Abstractions/System.Web/HttpResponseBase.cs index 0a3aa6694dd..2bf8ebd2f21 100644 --- a/mcs/class/System.Web.Abstractions/System.Web/HttpResponseBase.cs +++ b/mcs/class/System.Web.Abstractions/System.Web/HttpResponseBase.cs @@ -39,6 +39,7 @@ using System.Security.Principal; using System.Text; using System.Web.Caching; +using System.Threading; #if NET_4_0 using System.Web.Routing; @@ -69,6 +70,10 @@ void NotImplemented () public virtual string Charset { get { NotImplemented (); return null; } set { NotImplemented (); } } +#if NET_4_5 + public virtual CancellationToken ClientDisconnectedToken { get { NotImplemented (); return CancellationToken.None; } } +#endif + public virtual Encoding ContentEncoding { get { NotImplemented (); return null; } set { NotImplemented (); } } public virtual string ContentType { get { NotImplemented (); return null; } set { NotImplemented (); } } @@ -105,6 +110,10 @@ void NotImplemented () 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 (); } } diff --git a/mcs/class/System.Web.Abstractions/System.Web/HttpResponseWrapper.cs b/mcs/class/System.Web.Abstractions/System.Web/HttpResponseWrapper.cs index eed3415cd1c..adb5f74edd7 100644 --- a/mcs/class/System.Web.Abstractions/System.Web/HttpResponseWrapper.cs +++ b/mcs/class/System.Web.Abstractions/System.Web/HttpResponseWrapper.cs @@ -39,6 +39,7 @@ using System.Security.Principal; using System.Text; using System.Web.Caching; +using System.Threading; namespace System.Web { @@ -82,6 +83,12 @@ public override string Charset { set { w.Charset = value; } } +#if NET_4_5 + public override CancellationToken ClientDisconnectedToken { + get { return CancellationToken.None; } + } +#endif + public override Encoding ContentEncoding { get { return w.ContentEncoding; } set { w.ContentEncoding = value; } @@ -169,6 +176,13 @@ public override bool SuppressContent { 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; } diff --git a/mcs/class/System.Web.Extensions/System.Web.Script.Serialization/JavaScriptSerializer.cs b/mcs/class/System.Web.Extensions/System.Web.Script.Serialization/JavaScriptSerializer.cs index 14a03b2f0dc..9095cb866d3 100644 --- a/mcs/class/System.Web.Extensions/System.Web.Script.Serialization/JavaScriptSerializer.cs +++ b/mcs/class/System.Web.Extensions/System.Web.Script.Serialization/JavaScriptSerializer.cs @@ -204,7 +204,11 @@ public T Deserialize (string input) { } public object Deserialize (string input, Type targetType) { - return DeserializeObjectInternal (input); + object obj = DeserializeObjectInternal (input); + + if (obj == null) return null; + + return ConvertToType (obj, targetType); } static object Evaluate (object value) { diff --git a/mcs/class/System.Web.Extensions/System.Web.Script.Services/LogicalTypeInfo.cs b/mcs/class/System.Web.Extensions/System.Web.Script.Services/LogicalTypeInfo.cs index 5f8defbff81..a9b6fc01711 100644 --- a/mcs/class/System.Web.Extensions/System.Web.Script.Services/LogicalTypeInfo.cs +++ b/mcs/class/System.Web.Extensions/System.Web.Script.Services/LogicalTypeInfo.cs @@ -411,7 +411,7 @@ IDictionary BuildInvokeParameters (HttpRequest request) var ret = new Dictionary (); for (int i = nvc.Count - 1; i >= 0; i--) - ret.Add (nvc.GetKey (i), JavaScriptSerializer.DefaultSerializer.DeserializeObjectInternal (nvc.Get (i))); + ret.Add (nvc.GetKey (i), nvc.Get (i)); return ret; } diff --git a/mcs/class/System.Web.Extensions/Test/System.Web.Script.Serialization/JavaScriptSerializerTest.cs b/mcs/class/System.Web.Extensions/Test/System.Web.Script.Serialization/JavaScriptSerializerTest.cs index 995590eeb2e..8274ef9c3f8 100644 --- a/mcs/class/System.Web.Extensions/Test/System.Web.Script.Serialization/JavaScriptSerializerTest.cs +++ b/mcs/class/System.Web.Extensions/Test/System.Web.Script.Serialization/JavaScriptSerializerTest.cs @@ -415,6 +415,22 @@ public void TestDeserialize () { //object oo = ser.DeserializeObject ("{value:'Purple\\r \\n monkey\\'s:\\tdishwasher'}"); } + [Test] + public void TestDeserializeNonGenericOverload() + { + JavaScriptSerializer ser = new JavaScriptSerializer(); + Assert.IsNull(ser.Deserialize("", typeof(X))); + + X s = new X(); + s.Init(); + string x = ser.Serialize(s); + + Assert.AreEqual("{\"z\":8,\"ch\":\"v\",\"ch_null\":null,\"str\":\"vwF59g\",\"b\":253,\"sb\":-48,\"sh\":-32740,\"ush\":65511,\"i\":-234235453,\"ui\":4294733061,\"l\":-9223372036854775780,\"ul\":18446744073709551612,\"f\":NaN,\"f1\":-Infinity,\"f2\":Infinity,\"f3\":-3.40282347E+38,\"f4\":3.40282347E+38,\"d\":NaN,\"d1\":-Infinity,\"d2\":Infinity,\"d3\":-1.7976931348623157E+308,\"d4\":1.7976931348623157E+308,\"de\":-1,\"de1\":0,\"de2\":1,\"de3\":-79228162514264337593543950335,\"de4\":79228162514264337593543950335,\"g\":\"000000ea-0002-0162-0102-030405060708\",\"nb\":null,\"dbn\":null,\"uri\":\"http://kostat@mainsoft/adfasdf/asdfasdf.aspx/asda/ads?a=b&c=d\",\"hash\":{\"mykey\":{\"BB\":10}},\"point\":{\"IsEmpty\":false,\"X\":150,\"Y\":150},\"MyEnum\":[1,10,345],\"MyEnum1\":[1,10,345],\"AA\":5,\"AA1\":[{\"BB\":10},{\"BB\":10}],\"BB\":18446744073709551610,\"YY\":[{\"BB\":10},{\"BB\":10}]}", x, "#A1"); + + X n = ser.Deserialize(x, typeof(X)) as X; + Assert.AreEqual(s, n, "#A2"); + } + [Test] public void TestDeserializeTypeResolver () { diff --git a/mcs/class/System.Web/Makefile b/mcs/class/System.Web/Makefile index c11810f1f8a..bcde5188662 100644 --- a/mcs/class/System.Web/Makefile +++ b/mcs/class/System.Web/Makefile @@ -255,6 +255,7 @@ LIB_MCS_FLAGS = \ -r:System.Xml.dll \ -r:System.EnterpriseServices.dll \ -r:System.Runtime.Serialization.Formatters.Soap \ + -r:System.ComponentModel.DataAnnotations.dll \ $(OTHER_LIB_MCS_FLAGS) \ $(RESX_RES:%=/resource:%) \ $(OTHER_RES:%=/resource:%) @@ -447,4 +448,4 @@ ifneq ($(PROFILE),basic) csproj-local: $(MAKE) csproj-local intermediate=plainweb/ endif -endif \ No newline at end of file +endif diff --git a/mcs/class/System.Web/System.Web-net_4_5.csproj b/mcs/class/System.Web/System.Web-net_4_5.csproj index 787662b4184..0c32f157647 100644 --- a/mcs/class/System.Web/System.Web-net_4_5.csproj +++ b/mcs/class/System.Web/System.Web-net_4_5.csproj @@ -1249,6 +1249,7 @@ + @@ -1294,6 +1295,7 @@ + @@ -1321,6 +1323,7 @@ + @@ -1332,6 +1335,8 @@ + + diff --git a/mcs/class/System.Web/System.Web-plainweb-net_4_5.csproj b/mcs/class/System.Web/System.Web-plainweb-net_4_5.csproj index 5f49197e3f6..d4a107dec05 100644 --- a/mcs/class/System.Web/System.Web-plainweb-net_4_5.csproj +++ b/mcs/class/System.Web/System.Web-plainweb-net_4_5.csproj @@ -1249,6 +1249,7 @@ + @@ -1294,6 +1295,7 @@ + @@ -1321,6 +1323,7 @@ + @@ -1332,6 +1335,8 @@ + + diff --git a/mcs/class/System.Web/System.Web-tests-net_4_5.csproj b/mcs/class/System.Web/System.Web-tests-net_4_5.csproj index 6db954a2f78..bb9302e4995 100644 --- a/mcs/class/System.Web/System.Web-tests-net_4_5.csproj +++ b/mcs/class/System.Web/System.Web-tests-net_4_5.csproj @@ -556,6 +556,7 @@ + @@ -591,6 +592,7 @@ + @@ -602,6 +604,7 @@ + diff --git a/mcs/class/System.Web/System.Web.Configuration_2.0/WebConfigurationManager.cs b/mcs/class/System.Web/System.Web.Configuration_2.0/WebConfigurationManager.cs index 14bcf13a6e0..75fd8723e70 100644 --- a/mcs/class/System.Web/System.Web.Configuration_2.0/WebConfigurationManager.cs +++ b/mcs/class/System.Web/System.Web.Configuration_2.0/WebConfigurationManager.cs @@ -67,6 +67,7 @@ public ConfigPath (string path, bool inAnotherApp) 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; @@ -517,7 +518,10 @@ internal static object GetSection (string sectionName, string path, HttpContext cachePath = path; } - ConfigurationSection section = c.GetSection (sectionName); + ConfigurationSection section; + lock (getSectionLock) { + section = c.GetSection (sectionName); + } if (section == null) return null; @@ -529,7 +533,7 @@ internal static object GetSection (string sectionName, string path, HttpContext 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 (); @@ -677,7 +681,9 @@ internal static void RemoveConfigurationFromCache (HttpContext ctx) 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) { diff --git a/mcs/class/System.Web/System.Web.Hosting/HostingEnvironment.cs b/mcs/class/System.Web/System.Web.Hosting/HostingEnvironment.cs index f5855311943..a2b87e029ce 100644 --- a/mcs/class/System.Web/System.Web.Hosting/HostingEnvironment.cs +++ b/mcs/class/System.Web/System.Web.Hosting/HostingEnvironment.cs @@ -160,7 +160,9 @@ public static void RegisterObject (IRegisteredObject obj) { if (obj == null) throw new ArgumentNullException ("obj"); - Host.RegisterObject (obj, false); + + if (Host != null) + Host.RegisterObject (obj, false); } public static void RegisterVirtualPathProvider (VirtualPathProvider virtualPathProvider) @@ -200,7 +202,9 @@ public static void UnregisterObject (IRegisteredObject obj) { if (obj == null) throw new ArgumentNullException ("obj"); - Host.UnregisterObject (obj); + + if (Host != null) + Host.UnregisterObject (obj); } } } diff --git a/mcs/class/System.Web/System.Web.Security/FormsAuthenticationModule.cs b/mcs/class/System.Web/System.Web.Security/FormsAuthenticationModule.cs index cab57fea2f2..54f07294e28 100644 --- a/mcs/class/System.Web/System.Web.Security/FormsAuthenticationModule.cs +++ b/mcs/class/System.Web/System.Web.Security/FormsAuthenticationModule.cs @@ -180,6 +180,11 @@ void OnEndRequest (object sender, EventArgs args) 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 diff --git a/mcs/class/System.Web/System.Web.Security/MembershipPasswordAttribute.cs b/mcs/class/System.Web/System.Web.Security/MembershipPasswordAttribute.cs new file mode 100644 index 00000000000..7c85bd06e6f --- /dev/null +++ b/mcs/class/System.Web/System.Web.Security/MembershipPasswordAttribute.cs @@ -0,0 +1,110 @@ +// +// System.Web.Security.MembershipPasswordAttribute +// +// Authors: +// Martin Thwaites (github@my2cents.co.uk) +// +// (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. +// + +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text.RegularExpressions; + +namespace System.Web.Security +{ + [AttributeUsageAttribute (AttributeTargets.Property|AttributeTargets.Field|AttributeTargets.Parameter, AllowMultiple = false)] + public class MembershipPasswordAttribute : ValidationAttribute + { + public string MinNonAlphanumericCharactersError { get; set; } + public string MinPasswordLengthError { get; set; } + public int MinRequiredNonAlphanumericCharacters { get; set; } + public int MinRequiredPasswordLength { get; set; } + public string PasswordStrengthError { get; set; } + public string PasswordStrengthRegularExpression { get; set; } + public Type ResourceType { get; set; } + + public MembershipPasswordAttribute () + { + if (Membership.Provider != null) + { + MinRequiredNonAlphanumericCharacters = Membership.Provider.MinRequiredNonAlphanumericCharacters; + MinRequiredPasswordLength = Membership.Provider.MinRequiredPasswordLength; + PasswordStrengthRegularExpression = Membership.Provider.PasswordStrengthRegularExpression; + } + else + { + MinRequiredPasswordLength = 7; + MinRequiredNonAlphanumericCharacters = 1; + PasswordStrengthRegularExpression = @"(?=.{6,})(?=(.*\d){1,})(?=(.*\W){1,})"; + } + MinNonAlphanumericCharactersError = "The '{0}' field is an invalid password. Password must have {1} or more non-alphanumeric characters."; + MinPasswordLengthError = "The '{0}' field is an invalid password. Password must have {1} or more characters."; + PasswordStrengthError = "The '{0}' field is an invalid password. It does not meet the password strength requirements"; + ErrorMessage = "The field {0} is invalid."; + } + + protected override ValidationResult IsValid (object value, ValidationContext validationContext) + { + var password = value as string; + var isError = false; + if (string.IsNullOrEmpty(password)) + return null; + + var errorMessage = string.Empty; + var parameter = 0; + var pattern = new Regex (@"\W|_"); + + if (MinRequiredPasswordLength > 0 && + password.Length < MinRequiredPasswordLength) { + errorMessage = MinPasswordLengthError; + parameter = MinRequiredPasswordLength; + isError = true; + } + + if (!isError && MinRequiredNonAlphanumericCharacters > 0 && + pattern.Matches (password).Count < MinRequiredNonAlphanumericCharacters) { + errorMessage = MinNonAlphanumericCharactersError; + parameter = MinRequiredNonAlphanumericCharacters; + isError = true; + } + + if (!isError && !string.IsNullOrEmpty (PasswordStrengthRegularExpression) && + new Regex (PasswordStrengthRegularExpression).IsMatch (password)) { + errorMessage = PasswordStrengthError; + isError = true; + } + + if (isError) { + if (validationContext == null) + return new ValidationResult("error"); + + return new ValidationResult ( + string.Format (errorMessage, validationContext.DisplayName, parameter), + new[] {validationContext.MemberName}); + } + + return ValidationResult.Success; + } + } +} diff --git a/mcs/class/System.Web/System.Web.Security/MembershipUser.cs b/mcs/class/System.Web/System.Web.Security/MembershipUser.cs index b2bae459a52..13a7319cbae 100644 --- a/mcs/class/System.Web/System.Web.Security/MembershipUser.cs +++ b/mcs/class/System.Web/System.Web.Security/MembershipUser.cs @@ -94,7 +94,7 @@ void UpdateSelf (MembershipUser fromUser) internal void UpdateUser () { - MembershipUser newUser = Provider.GetUser (name, false); + MembershipUser newUser = Provider.GetUser (UserName, false); UpdateSelf (newUser); } diff --git a/mcs/class/System.Web/System.Web/EventHandlerTaskAsyncHelper.cs b/mcs/class/System.Web/System.Web/EventHandlerTaskAsyncHelper.cs new file mode 100644 index 00000000000..d80188befb3 --- /dev/null +++ b/mcs/class/System.Web/System.Web/EventHandlerTaskAsyncHelper.cs @@ -0,0 +1,62 @@ +// +// System.Web.EventHandlerTaskAsyncHelper.cs +// +// Author: +// Kornel Pal (kornelpal@gmail.com) +// +// Copyright (C) 2014 Kornel Pal +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System.Threading.Tasks; + +namespace System.Web +{ + public sealed class EventHandlerTaskAsyncHelper + { + readonly TaskEventHandler taskEventHandler; + readonly BeginEventHandler beginEventHandler; + static readonly EndEventHandler endEventHandler = TaskAsyncResult.Wait; + + public BeginEventHandler BeginEventHandler { + get { return beginEventHandler; } + } + + public EndEventHandler EndEventHandler { + get { return endEventHandler; } + } + + public EventHandlerTaskAsyncHelper (TaskEventHandler handler) + { + if (handler == null) + throw new ArgumentNullException ("handler"); + + taskEventHandler = handler; + beginEventHandler = GetAsyncResult; + } + + IAsyncResult GetAsyncResult (object sender, EventArgs e, AsyncCallback callback, object state) + { + Task task = taskEventHandler (sender, e); + return TaskAsyncResult.GetAsyncResult (task, callback, state); + } + } +} diff --git a/mcs/class/System.Web/System.Web/HttpApplication.cs b/mcs/class/System.Web/System.Web/HttpApplication.cs index efa4432011a..da393081d5e 100644 --- a/mcs/class/System.Web/System.Web/HttpApplication.cs +++ b/mcs/class/System.Web/System.Web/HttpApplication.cs @@ -230,6 +230,10 @@ internal void InitOnce (bool full_init) } } 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; @@ -1549,6 +1553,7 @@ void Start (object x) 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; diff --git a/mcs/class/System.Web/System.Web/HttpRequest.cs b/mcs/class/System.Web/System.Web/HttpRequest.cs index a2dd750eff4..6f845dbe108 100755 --- a/mcs/class/System.Web/System.Web/HttpRequest.cs +++ b/mcs/class/System.Web/System.Web/HttpRequest.cs @@ -80,13 +80,17 @@ public sealed partial class HttpRequest string unescaped_path; string original_path; string path_info; + string path_info_unvalidated; string raw_url; + string raw_url_unvalidated; WebROCollection all_params; - WebROCollection headers; + NameValueCollection headers; + WebROCollection headers_unvalidated; Stream input_stream; InputFilterStream input_filter; Stream filter; HttpCookieCollection cookies; + HttpCookieCollection cookies_unvalidated; string http_method; WebROCollection form; @@ -440,17 +444,27 @@ public string ContentType { } } - public HttpCookieCollection Cookies { + internal HttpCookieCollection CookiesNoValidation { get { - if (cookies == null) { + if (cookies_unvalidated == null) { if (worker_request == null) { - cookies = new HttpCookieCollection (); + cookies_unvalidated = new HttpCookieCollection (); } else { string cookie_hv = worker_request.GetKnownRequestHeader (HttpWorkerRequest.HeaderCookie); - cookies = new HttpCookieCollection (cookie_hv); + cookies_unvalidated = new HttpCookieCollection (cookie_hv); } } + return cookies_unvalidated; + } + } + + public HttpCookieCollection Cookies { + get { + if (cookies == null) { + cookies = CookiesNoValidation; + } + #if TARGET_J2EE // For J2EE portal support we emulate cookies using the session. GetSessionCookiesForPortal (cookies); @@ -737,10 +751,20 @@ public NameValueCollection Form { } } + internal NameValueCollection HeadersNoValidation { + get { + if (headers_unvalidated == null) { + headers_unvalidated = new HeadersCollection (this); + } + + return headers_unvalidated; + } + } + public NameValueCollection Headers { get { if (headers == null) { - headers = new HeadersCollection (this); + headers = HeadersNoValidation; #if NET_4_0 if (validateRequestNewMode) { RequestValidator validator = RequestValidator.Current; @@ -1226,12 +1250,23 @@ public string Path { } } + internal string PathInfoNoValidation { + get { + if (path_info_unvalidated == null) { + if (worker_request == null) + return String.Empty; + + path_info_unvalidated = worker_request.GetPathInfo () ?? String.Empty; + } + + return path_info_unvalidated; + } + } + public string PathInfo { get { if (path_info == null) { - if (worker_request == null) - return String.Empty; - path_info = worker_request.GetPathInfo () ?? String.Empty; + path_info = PathInfoNoValidation; #if NET_4_0 if (validateRequestNewMode) { RequestValidator validator = RequestValidator.Current; @@ -1335,16 +1370,26 @@ public NameValueCollection QueryString { } } - public string RawUrl { + internal string RawUrlUnvalidated { get { - if (raw_url == null) { + if (raw_url_unvalidated == null) { if (worker_request != null) - raw_url = worker_request.GetRawUrl (); + raw_url_unvalidated = worker_request.GetRawUrl (); else - raw_url = UrlComponents.Path + UrlComponents.Query; + raw_url_unvalidated = UrlComponents.Path + UrlComponents.Query; - if (raw_url == null) - raw_url = String.Empty; + if (raw_url_unvalidated == null) + raw_url_unvalidated = String.Empty; + } + + return raw_url_unvalidated; + } + } + + public string RawUrl { + get { + if (raw_url == null) { + raw_url = RawUrlUnvalidated; #if NET_4_0 if (validateRequestNewMode) { RequestValidator validator = RequestValidator.Current; @@ -1398,6 +1443,26 @@ public int TotalBytes { } } +#if NET_4_5 + public UnvalidatedRequestValues Unvalidated { + get { + var vals = new UnvalidatedRequestValues (); + + vals.Cookies = CookiesNoValidation; + vals.Files = Files; + vals.Form = FormUnvalidated; + vals.Headers = HeadersNoValidation; + vals.Path = PathNoValidation; + vals.PathInfo = PathInfoNoValidation; + vals.QueryString = QueryStringUnvalidated; + vals.RawUrl = RawUrlUnvalidated; + vals.Url = Url; + + return vals; + } + } +#endif + public Uri Url { get { if (cached_url == null) { diff --git a/mcs/class/System.Web/System.Web/HttpResponse.cs b/mcs/class/System.Web/System.Web/HttpResponse.cs index 65718e5cd9b..4bd3380a8f8 100644 --- a/mcs/class/System.Web/System.Web/HttpResponse.cs +++ b/mcs/class/System.Web/System.Web/HttpResponse.cs @@ -400,6 +400,13 @@ public int SubStatusCode { set; } +#if NET_4_5 + public bool SuppressFormsAuthenticationRedirect { + get; + set; + } +#endif + public bool TrySkipIisCustomErrors { get; set; diff --git a/mcs/class/System.Web/System.Web/HttpTaskAsyncHandler.cs b/mcs/class/System.Web/System.Web/HttpTaskAsyncHandler.cs new file mode 100644 index 00000000000..9cdcf730793 --- /dev/null +++ b/mcs/class/System.Web/System.Web/HttpTaskAsyncHandler.cs @@ -0,0 +1,59 @@ +// +// System.Web.HttpTaskAsyncHandler.cs +// +// Author: +// Kornel Pal (kornelpal@gmail.com) +// +// Copyright (C) 2014 Kornel Pal +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System.ComponentModel; +using System.Threading.Tasks; + +namespace System.Web +{ + public abstract class HttpTaskAsyncHandler : IHttpAsyncHandler, IHttpHandler + { + public virtual bool IsReusable { + get { return false; } + } + + [EditorBrowsable (EditorBrowsableState.Never)] + public virtual void ProcessRequest (HttpContext context) + { + throw new NotSupportedException ("This handler cannot be executed synchronously."); + } + + public abstract Task ProcessRequestAsync (HttpContext context); + + IAsyncResult IHttpAsyncHandler.BeginProcessRequest (HttpContext context, AsyncCallback cb, object extraData) + { + Task task = ProcessRequestAsync (context); + return TaskAsyncResult.GetAsyncResult (task, cb, extraData); + } + + void IHttpAsyncHandler.EndProcessRequest (IAsyncResult result) + { + TaskAsyncResult.Wait (result); + } + } +} diff --git a/mcs/class/System.Web/System.Web/HttpUtility.cs b/mcs/class/System.Web/System.Web/HttpUtility.cs index bb821a573cf..71892767469 100644 --- a/mcs/class/System.Web/System.Web/HttpUtility.cs +++ b/mcs/class/System.Web/System.Web/HttpUtility.cs @@ -56,7 +56,7 @@ public override string ToString () 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--; diff --git a/mcs/class/System.Web/System.Web/MimeTypes.cs b/mcs/class/System.Web/System.Web/MimeTypes.cs index 8b7bfcadf75..673507d1cf8 100644 --- a/mcs/class/System.Web/System.Web/MimeTypes.cs +++ b/mcs/class/System.Web/System.Web/MimeTypes.cs @@ -233,6 +233,7 @@ static MimeTypes () mimeTypes.Add ("la", "audio/nspaudio"); mimeTypes.Add ("lam", "audio/x-liveaudio"); mimeTypes.Add ("latex", "application/x-latex"); + mimeTypes.Add ("less", "text/css"); mimeTypes.Add ("list", "text/plain"); mimeTypes.Add ("lma", "audio/nspaudio"); mimeTypes.Add ("log", "text/plain"); @@ -529,7 +530,7 @@ static MimeTypes () mimeTypes.Add ("wmls", "text/vnd.wap.wmlscript"); mimeTypes.Add ("wml", "text/vnd.wap.wml"); mimeTypes.Add ("wmp", "video/x-ms-wmp"); - mimeTypes.Add ("woff", "application/x-woff"); + mimeTypes.Add ("woff", "application/font-woff"); mimeTypes.Add ("word", "application/msword"); mimeTypes.Add ("wp5", "application/wordperfect"); mimeTypes.Add ("wp6", "application/wordperfect"); diff --git a/mcs/class/System.Web/System.Web/ReadEntityBodyMode.cs b/mcs/class/System.Web/System.Web/ReadEntityBodyMode.cs new file mode 100644 index 00000000000..a97c3cf5f11 --- /dev/null +++ b/mcs/class/System.Web/System.Web/ReadEntityBodyMode.cs @@ -0,0 +1,34 @@ +// +// 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, + } +} diff --git a/mcs/class/System.Web/System.Web/TaskAsyncResult.cs b/mcs/class/System.Web/System.Web/TaskAsyncResult.cs new file mode 100644 index 00000000000..2e3bd2737f0 --- /dev/null +++ b/mcs/class/System.Web/System.Web/TaskAsyncResult.cs @@ -0,0 +1,101 @@ +// +// System.Web.TaskAsyncResult.cs +// +// Author: +// Kornel Pal (kornelpal@gmail.com) +// +// Copyright (C) 2014 Kornel Pal +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System.Threading; +using System.Threading.Tasks; + +namespace System.Web +{ + sealed class TaskAsyncResult : IAsyncResult + { + static readonly Action invokeCallback = InvokeCallback; + readonly Task task; + readonly AsyncCallback callback; + + public object AsyncState { + get; + private set; + } + + public WaitHandle AsyncWaitHandle { + get { return ((IAsyncResult) task).AsyncWaitHandle; } + } + + public bool CompletedSynchronously { + get; + private set; + } + + public bool IsCompleted { + get { return task.IsCompleted; } + } + + TaskAsyncResult (Task task, AsyncCallback callback, object state) + { + this.task = task; + this.callback = callback; + this.AsyncState = state; + this.CompletedSynchronously = task.IsCompleted; + } + + public static IAsyncResult GetAsyncResult (Task task, AsyncCallback callback, object state) + { + if (task == null) + return null; + + var result = new TaskAsyncResult (task, callback, state); + + if (callback != null) { + if (result.CompletedSynchronously) + callback (result); + else + task.ContinueWith (invokeCallback, result); + } + + return result; + } + + public static void Wait (IAsyncResult result) + { + if (result == null) + throw new ArgumentNullException ("result"); + + var taskAsyncResult = result as TaskAsyncResult; + if (taskAsyncResult == null) + throw new ArgumentException ("The provided IAsyncResult is invalid.", "result"); + + taskAsyncResult.task.GetAwaiter ().GetResult (); + } + + static void InvokeCallback (Task task, object state) + { + var result = (TaskAsyncResult) state; + result.callback (result); + } + } +} diff --git a/mcs/class/System.Web/System.Web/TaskEventHandler.cs b/mcs/class/System.Web/System.Web/TaskEventHandler.cs new file mode 100644 index 00000000000..9fc7988ce50 --- /dev/null +++ b/mcs/class/System.Web/System.Web/TaskEventHandler.cs @@ -0,0 +1,34 @@ +// +// System.Web.TaskEventHandler.cs +// +// Author: +// Kornel Pal (kornelpal@gmail.com) +// +// Copyright (C) 2014 Kornel Pal +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System.Threading.Tasks; + +namespace System.Web +{ + public delegate Task TaskEventHandler (object sender, EventArgs e); +} diff --git a/mcs/class/System.Web/System.Web/UnvalidatedRequestValues.cs b/mcs/class/System.Web/System.Web/UnvalidatedRequestValues.cs new file mode 100644 index 00000000000..707b67e4139 --- /dev/null +++ b/mcs/class/System.Web/System.Web/UnvalidatedRequestValues.cs @@ -0,0 +1,66 @@ +// +// System.Web.UnvalidatedRequestValues.cs +// +// Author: +// Mike Morano +// + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections.Specialized; + + +namespace System.Web { + public sealed class UnvalidatedRequestValues { + public HttpCookieCollection Cookies { get; internal set; } + public HttpFileCollection Files { get; internal set; } + public NameValueCollection Form { get; internal set; } + public NameValueCollection Headers { get; internal set; } + public string Path { get; internal set; } + public string PathInfo { get; internal set; } + public NameValueCollection QueryString { get; internal set; } + public string RawUrl { get; internal set; } + public Uri Url { get; internal set; } + + public string this[string field] { + get { + if (Form != null && Form [field] != null) { + return Form [field]; + } + + if (Cookies != null && Cookies [field] != null) { + return Cookies [field].Value; + } + + if (QueryString != null && QueryString [field] != null) { + return QueryString [field]; + } + + // msdn docs also suggest the ServerVariables are inspected by this indexer, + // but that seems odd given what is available in this class + + return null; + } + } + } +} diff --git a/mcs/class/System.Web/System.Web/UnvalidatedRequestValuesBase.cs b/mcs/class/System.Web/System.Web/UnvalidatedRequestValuesBase.cs new file mode 100644 index 00000000000..9b54b072e28 --- /dev/null +++ b/mcs/class/System.Web/System.Web/UnvalidatedRequestValuesBase.cs @@ -0,0 +1,90 @@ +// +// System.Web.UnvalidatedRequestValuesBase.cs +// +// Author: +// Mike Morano +// + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections.Specialized; + + +namespace System.Web { + public abstract class UnvalidatedRequestValuesBase { + void NotImplemented () + { + throw new NotImplementedException (); + } + + public virtual HttpCookieCollection Cookies + { + get { NotImplemented (); return null; } + } + + public virtual HttpFileCollection Files + { + get { NotImplemented (); return null; } + } + + public virtual NameValueCollection Form + { + get { NotImplemented (); return null; } + } + + public virtual NameValueCollection Headers + { + get { NotImplemented (); return null; } + } + + public virtual string this[string field] + { + get { NotImplemented (); return null; } + } + + public virtual string Path + { + get { NotImplemented (); return null; } + } + + public virtual string PathInfo + { + get { NotImplemented (); return null; } + } + + public virtual NameValueCollection QueryString + { + get { NotImplemented (); return null; } + } + + public virtual string RawUrl + { + get { NotImplemented (); return null; } + } + + public virtual Uri Url + { + get { NotImplemented (); return null; } + } + } +} diff --git a/mcs/class/System.Web/System.Web/UnvalidatedRequestValuesWrapper.cs b/mcs/class/System.Web/System.Web/UnvalidatedRequestValuesWrapper.cs new file mode 100644 index 00000000000..e6b6084f2f2 --- /dev/null +++ b/mcs/class/System.Web/System.Web/UnvalidatedRequestValuesWrapper.cs @@ -0,0 +1,92 @@ +// +// System.Web.UnvalidatedRequestValuesWrapper.cs +// +// Author: +// Mike Morano +// + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections.Specialized; + + +namespace System.Web { + public class UnvalidatedRequestValuesWrapper : UnvalidatedRequestValuesBase { + UnvalidatedRequestValues rv; + + public UnvalidatedRequestValuesWrapper (UnvalidatedRequestValues requestValues) + { + rv = requestValues; + } + + public override HttpCookieCollection Cookies + { + get { return rv.Cookies; } + } + + public override HttpFileCollection Files + { + get { return rv.Files; } + } + + public override NameValueCollection Form + { + get { return rv.Form; } + } + + public override NameValueCollection Headers + { + get { return rv.Headers; } + } + + public override string this[string field] + { + get { return rv[field]; } + } + + public override string Path + { + get { return rv.Path; } + } + + public override string PathInfo + { + get { return rv.PathInfo; } + } + + public override NameValueCollection QueryString + { + get { return rv.QueryString; } + } + + public override string RawUrl + { + get { return rv.RawUrl; } + } + + public override Uri Url + { + get { return rv.Url; } + } + } +} diff --git a/mcs/class/System.Web/System.Web_test.dll.sources b/mcs/class/System.Web/System.Web_test.dll.sources index fd634af76c3..29339b428c9 100644 --- a/mcs/class/System.Web/System.Web_test.dll.sources +++ b/mcs/class/System.Web/System.Web_test.dll.sources @@ -45,6 +45,7 @@ mainsoft/NunitWeb/NunitWeb/Tests/AuthorConverter.cs mainsoft/NunitWeb/NunitWeb/Tests/Book.cs mainsoft/NunitWeb/NunitWeb/Tests/BookType.cs System.Web/AppBrowsersTest.cs +System.Web/EventHandlerTaskAsyncHelperTest.cs System.Web/HttpApplicationTest.cs System.Web/HttpBrowserCapabilitiesTest.cs System.Web/HttpCacheVaryByContentEncodingsTest.cs @@ -58,10 +59,12 @@ System.Web/HttpRequestTest.cs System.Web/HttpResponseTest.cs System.Web/HttpRuntimeTest.cs System.Web/HttpServerUtilityTest.cs +System.Web/HttpTaskAsyncHandlerTest.cs System.Web/HttpUtilityTest.cs System.Web/SiteMapProviderTest.cs System.Web/SiteMapNodeTest.cs System.Web/StaticSiteMapProviderTest.cs +System.Web/TaskAsyncResultTest.cs System.Web/TraceContextRecordTest.cs System.Web.Compilation/BuildManagerTest.cs System.Web.Compilation/ClientBuildManagerParameterTest.cs @@ -103,6 +106,7 @@ System.Web.Profile/ProfileInfoTest.cs System.Web.Security/FormsAuthenticationTest.cs System.Web.Security/FormsIdentityTest.cs System.Web.Security/MembershipTest.cs +System.Web.Security/MembershipPasswordAttributeTest.cs System.Web.Security/MembershipProviderCollectionTest.cs System.Web.Security/MembershipProviderTest.cs System.Web.Security/MembershipUserCollectionTest.cs diff --git a/mcs/class/System.Web/Test/System.Web.Hosting/HostingEnvironmentTest.cs b/mcs/class/System.Web/Test/System.Web.Hosting/HostingEnvironmentTest.cs index eb3aa2a3e00..2f039d02894 100644 --- a/mcs/class/System.Web/Test/System.Web.Hosting/HostingEnvironmentTest.cs +++ b/mcs/class/System.Web/Test/System.Web.Hosting/HostingEnvironmentTest.cs @@ -35,6 +35,10 @@ using MonoTests.SystemWeb.Framework; namespace MonoTests.System.Web.Hosting { + public class MyRegisteredObject : IRegisteredObject { + public void Stop(bool immediate) {} + } + [TestFixture] public class HostingEnvironmentTest { [Test] @@ -105,6 +109,15 @@ public void MapPath3 () { Assert.IsNull (HostingEnvironment.MapPath ("hola")); } + + [Test] + public void RegisterAndUnregisterObject () + { + var registered = new MyRegisteredObject (); + + HostingEnvironment.RegisterObject (registered); + HostingEnvironment.UnregisterObject (registered); + } } } #endif diff --git a/mcs/class/System.Web/Test/System.Web.Security/MembershipPasswordAttributeTest.cs b/mcs/class/System.Web/Test/System.Web.Security/MembershipPasswordAttributeTest.cs new file mode 100644 index 00000000000..4ace2ca1b37 --- /dev/null +++ b/mcs/class/System.Web/Test/System.Web.Security/MembershipPasswordAttributeTest.cs @@ -0,0 +1,140 @@ +#if NET_4_5 + +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Web.Security; +using NUnit.Framework; + +namespace MonoTests.System.Web.Security { + + [TestFixture] + public class MembershipPasswordAttributeTest + { + private ValidationContext _validationContext; + + public MembershipPasswordAttributeTest () + { + _validationContext = new ValidationContext (new object ()) + { + DisplayName = "testDisplay", + MemberName = "testMember" + }; + } + + [Test] + public void IsValid () + { + var passwordAttribute = new MembershipPasswordAttributeTestClass (); + Assert.IsTrue (passwordAttribute.IsValid (""), "sending an empty password password should should be treated as valid"); + } + + [Test] + public void IsValid_with_ValidationContext () + { + var passwordAttribute = new MembershipPasswordAttributeTestClass (); + var result = passwordAttribute.TestValidation ("", _validationContext); + Assert.IsNull (result, "sending an empty password password should return a null response"); + + result = passwordAttribute.TestValidation ("a!12345", _validationContext); + Assert.AreEqual (ValidationResult.Success, result, "Should suceed with a 7 character length and a single nonalphanumeric"); + + // test error priority + passwordAttribute.MinRequiredPasswordLength = 4; + passwordAttribute.MinRequiredNonAlphanumericCharacters = 2; + result = passwordAttribute.TestValidation ("aaa", _validationContext); + Assert.AreEqual ("The 'testDisplay' field is an invalid password. Password must have 4 or more characters.", result.ErrorMessage); + + } + + [Test] + public void MinRequiredPasswordLength () + { + var passwordAttribute = new MembershipPasswordAttributeTestClass (); + var result = passwordAttribute.TestValidation ("a!1234", _validationContext); + Assert.AreEqual ("The 'testDisplay' field is an invalid password. Password must have 7 or more characters.", result.ErrorMessage, "Error message not correct for lower Min characters"); + Assert.AreEqual (_validationContext.MemberName, result.MemberNames.FirstOrDefault (), "Member name not correct"); + + passwordAttribute.MinRequiredPasswordLength = 6; + result = passwordAttribute.TestValidation ("a!1234", _validationContext); + Assert.AreEqual (ValidationResult.Success, result, "Should suceed with a 6 character length after it's reset"); + + result = passwordAttribute.TestValidation ("a!123", _validationContext); + Assert.AreEqual("The 'testDisplay' field is an invalid password. Password must have 6 or more characters.", result.ErrorMessage, "Error message not correct for Min characters of 6"); + + + passwordAttribute.MinRequiredPasswordLength = 1; + result = passwordAttribute.TestValidation ("!", _validationContext); + Assert.AreEqual(ValidationResult.Success, result, "Should suceed with a 6 character length after it's reset"); + + // Note there is no test for empty password here as it returns null and is therefore in the generic test + + // Error Message changes + passwordAttribute.MinRequiredPasswordLength = 5; + passwordAttribute.MinPasswordLengthError = "There was an error"; + result = passwordAttribute.TestValidation ("a!13", _validationContext); + Assert.AreEqual("There was an error", result.ErrorMessage, "Error Message wasn't correct without parameters."); + + passwordAttribute.MinPasswordLengthError = "There was an error parameter1: {0}"; + result = passwordAttribute.TestValidation ("a!13", _validationContext); + Assert.AreEqual("There was an error parameter1: testDisplay", result.ErrorMessage, "Error Message wasn't correct with 1 parameter."); + + passwordAttribute.MinPasswordLengthError = "There was an error parameter1: {0} parameter2: {1}"; + result = passwordAttribute.TestValidation ("a!13", _validationContext); + Assert.AreEqual ("There was an error parameter1: testDisplay parameter2: 5", result.ErrorMessage, "Error Message wasn't correct with 2 parameters."); + + } + + [Test] + public void MinRequiredNonAlphanumericCharacters () + { + var passwordAttribute = new MembershipPasswordAttributeTestClass (); + var result = passwordAttribute.TestValidation ("a!12345", _validationContext); + Assert.AreEqual (ValidationResult.Success, result, "Should succeed with the default 1 non alpha numeric"); + + result = passwordAttribute.TestValidation ("a123456", _validationContext); + Assert.AreEqual ("The 'testDisplay' field is an invalid password. Password must have 1 or more non-alphanumeric characters.", result.ErrorMessage, "Expected validation to fail without non-alphanumerics"); + + + passwordAttribute.MinRequiredNonAlphanumericCharacters = 3; + result = passwordAttribute.TestValidation ("a!&12345", _validationContext); + Assert.AreEqual ("The 'testDisplay' field is an invalid password. Password must have 3 or more non-alphanumeric characters.", result.ErrorMessage, "Expected validation to fail without 3 non-alphanumerics"); + + result = passwordAttribute.TestValidation ("a!?&132154", _validationContext); + Assert.AreEqual (ValidationResult.Success, result, "Should succeed with 3 non alpha numerics"); + + passwordAttribute.MinRequiredNonAlphanumericCharacters = 0; + result = passwordAttribute.TestValidation ("a123456", _validationContext); + Assert.AreEqual (ValidationResult.Success, result, "Should succeed with 0 non alpha numerics"); + + // Error Message changes + passwordAttribute.MinRequiredNonAlphanumericCharacters = 1; + passwordAttribute.MinNonAlphanumericCharactersError = "There was an error"; + result = passwordAttribute.TestValidation ("a123456", _validationContext); + Assert.AreEqual ("There was an error", result.ErrorMessage, "Error Message wasn't correct without parameters."); + + passwordAttribute.MinNonAlphanumericCharactersError = "There was an error parameter1: {0}"; + result = passwordAttribute.TestValidation ("a123456", _validationContext); + Assert.AreEqual("There was an error parameter1: testDisplay", result.ErrorMessage, "Error Message wasn't correct with 1 parameter."); + + passwordAttribute.MinNonAlphanumericCharactersError = "There was an error parameter1: {0} parameter2: {1}"; + result = passwordAttribute.TestValidation ("a123456", _validationContext); + Assert.AreEqual ("There was an error parameter1: testDisplay parameter2: 1", result.ErrorMessage, "Error Message wasn't correct with 2 parameters."); + } + + [Test] + public void FormatErrorMessage () + { + var passwordAttribute = new MembershipPasswordAttribute (); + Assert.AreEqual ("The field testDisplay2 is invalid.", passwordAttribute.FormatErrorMessage ("testDisplay2")); + } + + internal class MembershipPasswordAttributeTestClass : MembershipPasswordAttribute + { + public ValidationResult TestValidation (object val, ValidationContext context) + { + return IsValid (val, context); + } + } + } +} +#endif diff --git a/mcs/class/System.Web/Test/System.Web/EventHandlerTaskAsyncHelperTest.cs b/mcs/class/System.Web/Test/System.Web/EventHandlerTaskAsyncHelperTest.cs new file mode 100644 index 00000000000..9ae8aae0554 --- /dev/null +++ b/mcs/class/System.Web/Test/System.Web/EventHandlerTaskAsyncHelperTest.cs @@ -0,0 +1,118 @@ +// +// MonoTests.System.Web.EventHandlerTaskAsyncHelperTest.cs +// +// Author: +// Kornel Pal (kornelpal@gmail.com) +// +// Copyright (C) 2014 Kornel Pal +// +// 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. +// + +#if NET_4_5 + +using System; +using System.Threading.Tasks; +using System.Web; +using NUnit.Framework; + +namespace MonoTests.System.Web +{ + [TestFixture] + public sealed class EventHandlerTaskAsyncHelperTest : TaskAsyncResultTest + { + EventHandlerTaskAsyncHelper helper; + object expectedSender; + EventArgs expectedEventArgs; + + static Task DummyTaskEventHandler (object sender, EventArgs e) + { + throw new AssertionException ("Should not be called."); + } + + protected override void SetNullArguments () + { + expectedSender = null; + expectedEventArgs = null; + } + + protected override IAsyncResult GetAsyncResult (Func taskFactory, AsyncCallback callback, object state) + { + Assert.IsNull (helper, "GetAsyncResult#A01"); + + TaskEventHandler handler = (sender, e) => { + Assert.AreSame (expectedSender, sender, "GetAsyncResult#A02"); + Assert.AreSame (expectedEventArgs, e, "GetAsyncResult#A03"); + + return taskFactory (); + }; + + helper = new EventHandlerTaskAsyncHelper (handler); + return helper.BeginEventHandler (expectedSender, expectedEventArgs, callback, state); + } + + protected override void Wait (IAsyncResult result) + { + Assert.IsNotNull (helper, "Wait#A01"); + + helper.EndEventHandler (result); + } + + protected override void TestSetUp () + { + base.TestSetUp (); + + helper = null; + expectedSender = new object (); + expectedEventArgs = new EventArgs (); + } + + [Test] + public void Constructor () + { + var helper = new EventHandlerTaskAsyncHelper (DummyTaskEventHandler); + } + + [Test] + [ExpectedException (typeof (ArgumentNullException))] + public void Constructor_NullHandler () + { + var helper = new EventHandlerTaskAsyncHelper (null); + } + + [Test] + public void BeginEventHandler () + { + var helper = new EventHandlerTaskAsyncHelper (DummyTaskEventHandler); + + Assert.IsNotNull (helper.BeginEventHandler, "#A01"); + } + + [Test] + public void EndEventHandler () + { + var helper = new EventHandlerTaskAsyncHelper (DummyTaskEventHandler); + + Assert.IsNotNull (helper.EndEventHandler, "#A01"); + } + } +} + +#endif diff --git a/mcs/class/System.Web/Test/System.Web/HttpTaskAsyncHandlerTest.cs b/mcs/class/System.Web/Test/System.Web/HttpTaskAsyncHandlerTest.cs new file mode 100644 index 00000000000..50afda19bcb --- /dev/null +++ b/mcs/class/System.Web/Test/System.Web/HttpTaskAsyncHandlerTest.cs @@ -0,0 +1,132 @@ +// +// MonoTests.System.Web.HttpTaskAsyncHandlerTest.cs +// +// Author: +// Kornel Pal (kornelpal@gmail.com) +// +// Copyright (C) 2014 Kornel Pal +// +// 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. +// + +#if NET_4_5 + +using System; +using System.IO; +using System.Threading.Tasks; +using System.Web; +using NUnit.Framework; + +namespace MonoTests.System.Web +{ + [TestFixture] + public sealed class HttpTaskAsyncHandlerTest : TaskAsyncResultTest + { + sealed class DummyHttpTaskAsyncHandler : HttpTaskAsyncHandler + { + public DummyHttpTaskAsyncHandler () + { + } + + public override Task ProcessRequestAsync (HttpContext context) + { + throw new AssertionException ("Should not be called."); + } + } + + sealed class TestHttpTaskAsyncHandler : HttpTaskAsyncHandler + { + readonly Func taskFactory; + readonly HttpContext expectedContext; + + public TestHttpTaskAsyncHandler (Func taskFactory, HttpContext expectedContext) + { + this.taskFactory = taskFactory; + this.expectedContext = expectedContext; + } + + public override Task ProcessRequestAsync (HttpContext context) + { + Assert.AreSame (expectedContext, context, "TestHttpTaskAsyncHandler#A01"); + + return taskFactory (); + } + } + + IHttpAsyncHandler handler; + HttpContext expectedContext; + + protected override void SetNullArguments () + { + expectedContext = null; + } + + protected override IAsyncResult GetAsyncResult (Func taskFactory, AsyncCallback callback, object state) + { + Assert.IsNull (handler, "GetAsyncResult#A01"); + + handler = new TestHttpTaskAsyncHandler (taskFactory, expectedContext); + return handler.BeginProcessRequest (expectedContext, callback, state); + } + + protected override void Wait (IAsyncResult result) + { + Assert.IsNotNull (handler, "Wait#A01"); + + handler.EndProcessRequest (result); + } + + protected override void TestSetUp () + { + base.TestSetUp (); + + handler = null; + + var request = new HttpRequest (string.Empty, "http://localhost/", string.Empty); + var response = new HttpResponse (TextWriter.Null); + expectedContext = new HttpContext (request, response); + } + + [Test] + public void IsReusable () + { + var handler = new DummyHttpTaskAsyncHandler (); + Assert.IsFalse (handler.IsReusable, "#A01"); + } + + [Test] + [ExpectedException (typeof (NotSupportedException))] + public void ProcessRequest () + { + var handler = new DummyHttpTaskAsyncHandler (); + handler.ProcessRequest (expectedContext); + } + + [Test] + [ExpectedException (typeof (NotSupportedException))] + public void ProcessRequest_NullContext () + { + var handler = new DummyHttpTaskAsyncHandler (); + handler.ProcessRequest (null); + } + } +} + +#endif diff --git a/mcs/class/System.Web/Test/System.Web/HttpUtilityTest.cs b/mcs/class/System.Web/Test/System.Web/HttpUtilityTest.cs index 4c7228dd6a2..5ead2173893 100644 --- a/mcs/class/System.Web/Test/System.Web/HttpUtilityTest.cs +++ b/mcs/class/System.Web/Test/System.Web/HttpUtilityTest.cs @@ -861,6 +861,15 @@ static void ParseQueryString_Helper (NameValueCollection nvc, string msg, string @" ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ", }; + [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()); + } } } diff --git a/mcs/class/System.Web/Test/System.Web/TaskAsyncResultTest.cs b/mcs/class/System.Web/Test/System.Web/TaskAsyncResultTest.cs new file mode 100644 index 00000000000..301a2988a3c --- /dev/null +++ b/mcs/class/System.Web/Test/System.Web/TaskAsyncResultTest.cs @@ -0,0 +1,334 @@ +// +// MonoTests.System.Web.TaskAsyncResultTest.cs +// +// Author: +// Kornel Pal (kornelpal@gmail.com) +// +// Copyright (C) 2014 Kornel Pal +// +// 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. +// + +#if NET_4_5 + +using System; +using System.Threading; +using System.Threading.Tasks; +using NUnit.Framework; + +namespace MonoTests.System.Web +{ + public abstract class TaskAsyncResultTest + { + sealed class TestException : Exception + { + public TestException () + : base ("Test exception") + { + } + } + + sealed class DummyAsyncResult : IAsyncResult + { + public object AsyncState { + get { throw new AssertionException ("Should not be called."); } + } + + public WaitHandle AsyncWaitHandle { + get { throw new AssertionException ("Should not be called."); } + } + + public bool CompletedSynchronously { + get { throw new AssertionException ("Should not be called."); } + } + + public bool IsCompleted { + get { throw new AssertionException ("Should not be called."); } + } + } + + int testThreadId; + int factoryCount; + int callbackCount; + object expectedState; + Exception expectedException; + TaskCompletionSource taskCompletion; + TaskCompletionSource callbackCompletion; + IAsyncResult taskAsyncResult; + + static Task NullTaskFatory () + { + return null; + } + + static Task CompletedTaskFatory () + { + return Task.FromResult (null); + } + + static Task FailingTaskFatory () + { + throw new TestException (); + } + + void DummyCallback (IAsyncResult result) + { + Interlocked.Increment (ref callbackCount); + + Assert.Fail ("Should not be called."); + } + + void FailingCallback (IAsyncResult result) + { + Interlocked.Increment (ref callbackCount); + + throw new TestException (); + } + + protected abstract void SetNullArguments (); + protected abstract IAsyncResult GetAsyncResult (Func taskFactory, AsyncCallback callback, object state); + protected abstract void Wait (IAsyncResult result); + + [SetUp] + protected virtual void TestSetUp () + { + testThreadId = Thread.CurrentThread.ManagedThreadId; + factoryCount = 0; + callbackCount = 0; + expectedState = new object (); + expectedException = null; + taskCompletion = new TaskCompletionSource (); + callbackCompletion = new TaskCompletionSource (); + taskAsyncResult = null; + } + + [Test] + public void Invoke_NullArguments () + { + SetNullArguments (); + + IAsyncResult result = GetAsyncResult (CompletedTaskFatory, null, null); + Wait (result); + } + + [Test] + public void Invoke_NullTask () + { + IAsyncResult result = GetAsyncResult (NullTaskFatory, DummyCallback, null); + + Assert.AreEqual (0, callbackCount, "#A01"); + Assert.IsNull (result, "#A02"); + } + + [Test] + [ExpectedException (typeof (TestException))] + public void Invoke_TaskFatoryException () + { + try { + GetAsyncResult (FailingTaskFatory, DummyCallback, expectedState); + } finally { + Assert.AreEqual (0, callbackCount, "#A01"); + } + } + + [Test] + [ExpectedException (typeof (TestException))] + public void Invoke_CallbackException () + { + try { + GetAsyncResult (CompletedTaskFatory, FailingCallback, expectedState); + } finally { + Assert.AreEqual (1, callbackCount, "#A01"); + } + } + + [Test] + [ExpectedException (typeof (ArgumentNullException))] + public void Invoke_NullResult () + { + GetAsyncResult (NullTaskFatory, DummyCallback, null); + Wait (null); + } + + [Test] + [ExpectedException (typeof (ArgumentException))] + public void Invoke_InvalidResult () + { + GetAsyncResult (NullTaskFatory, DummyCallback, null); + Wait (new DummyAsyncResult ()); + } + + void SetTaskResult () + { + if (expectedException == null) + taskCompletion.SetResult (null); + else + taskCompletion.SetException (expectedException); + } + + void WaitTaskResult () + { + if (expectedException == null) { + Wait (taskAsyncResult); + return; + } + + try { + Wait (taskAsyncResult); + + Assert.Fail ("Expected exception was not thrown."); + } catch (AssertionException) { + throw; + } catch (Exception ex) { + Assert.AreSame (expectedException, ex, "WaitTaskResult#A01"); + } + } + + [Test] + public void InvokeSync () + { + InvokeSyncCore (); + } + + [Test] + public void InvokeSync_Failed () + { + expectedException = new TestException (); + + InvokeSyncCore (); + } + + void InvokeSyncCore () + { + IAsyncResult result = GetAsyncResult (SyncTaskFatory, SyncCallback, expectedState); + + Assert.IsNotNull (result, "InvokeSyncCore#A01"); + Assert.AreSame (taskAsyncResult, result, "InvokeSyncCore#A02"); + + WaitTaskResult (); + + Assert.AreEqual (1, factoryCount, "InvokeSyncCore#A03"); + Assert.AreEqual (1, callbackCount, "InvokeSyncCore#A04"); + } + + Task SyncTaskFatory () + { + Interlocked.Increment (ref factoryCount); + + Assert.AreEqual (testThreadId, Thread.CurrentThread.ManagedThreadId, "SyncTaskFatory#A01"); + + SetTaskResult (); + + return taskCompletion.Task; + } + + void SyncCallback (IAsyncResult result) + { + Interlocked.Increment (ref callbackCount); + + Assert.AreEqual (testThreadId, Thread.CurrentThread.ManagedThreadId, "SyncCallback#A01"); + + Assert.IsNotNull (result, "SyncCallback#A02"); + Assert.AreSame (expectedState, result.AsyncState, "SyncCallback#A03"); + Assert.IsTrue (result.IsCompleted, "SyncCallback#A04"); + Assert.IsTrue (result.CompletedSynchronously, "SyncCallback#A05"); + Assert.IsNotNull (result.AsyncWaitHandle, "SyncCallback#A06"); + Assert.IsTrue (result.AsyncWaitHandle.WaitOne (0), "SyncCallback#A07"); + + taskAsyncResult = result; + + Assert.AreEqual (1, factoryCount, "SyncCallback#A08"); + Assert.AreEqual (1, callbackCount, "SyncCallback#A09"); + } + + [Test] + public void InvokeAsync () + { + InvokeAsyncCore (); + } + + [Test] + public void InvokeAsync_Failed () + { + expectedException = new TestException (); + + InvokeAsyncCore (); + } + + void InvokeAsyncCore () + { + IAsyncResult result = GetAsyncResult (AsyncTaskFatory, AsyncCallback, expectedState); + + Assert.IsNotNull (result, "InvokeAsyncCore#A01"); + Assert.AreSame (expectedState, result.AsyncState, "InvokeAsyncCore#A02"); + Assert.IsFalse (result.IsCompleted, "InvokeAsyncCore#A03"); + Assert.IsFalse (result.CompletedSynchronously, "InvokeAsyncCore#A04"); + Assert.IsNotNull (result.AsyncWaitHandle, "InvokeAsyncCore#A05"); + Assert.IsFalse (result.AsyncWaitHandle.WaitOne (0), "InvokeAsyncCore#A06"); + + Assert.AreEqual (1, factoryCount, "InvokeAsyncCore#A07"); + Assert.AreEqual (0, callbackCount, "InvokeAsyncCore#A08"); + + taskAsyncResult = result; + + SetTaskResult (); + + callbackCompletion.Task.GetAwaiter ().GetResult (); + + Assert.AreEqual (1, factoryCount, "InvokeAsyncCore#A09"); + Assert.AreEqual (1, callbackCount, "InvokeAsyncCore#A10"); + } + + Task AsyncTaskFatory () + { + Interlocked.Increment (ref factoryCount); + + Assert.AreEqual (testThreadId, Thread.CurrentThread.ManagedThreadId, "AsyncTaskFatory#A01"); + + return taskCompletion.Task; + } + + void AsyncCallback (IAsyncResult result) + { + try { + Interlocked.Increment (ref callbackCount); + + Assert.AreNotEqual (testThreadId, Thread.CurrentThread.ManagedThreadId, "AsyncCallback#A01"); + + Assert.IsNotNull (result, "AsyncCallback#A02"); + Assert.AreSame (expectedState, result.AsyncState, "AsyncCallback#A03"); + Assert.IsTrue (result.IsCompleted, "AsyncCallback#A04"); + Assert.IsFalse (result.CompletedSynchronously, "AsyncCallback#A05"); + Assert.IsNotNull (result.AsyncWaitHandle, "AsyncCallback#A06"); + Assert.IsTrue (result.AsyncWaitHandle.WaitOne (0), "AsyncCallback#A07"); + + Assert.AreSame (taskAsyncResult, result, "AsyncCallback#A08"); + + WaitTaskResult (); + + callbackCompletion.TrySetResult (null); + } catch (Exception ex) { + callbackCompletion.TrySetException (ex); + } + } + } +} + +#endif diff --git a/mcs/class/System.Web/net_4_5_System.Web.dll.sources b/mcs/class/System.Web/net_4_5_System.Web.dll.sources index a7957a0019c..8703eb00471 100644 --- a/mcs/class/System.Web/net_4_5_System.Web.dll.sources +++ b/mcs/class/System.Web/net_4_5_System.Web.dll.sources @@ -1,3 +1,12 @@ #include net_4_0_System.Web.dll.sources +System.Web/EventHandlerTaskAsyncHelper.cs +System.Web/HttpTaskAsyncHandler.cs System.Web/MimeMapping.cs +System.Web/ReadEntityBodyMode.cs +System.Web/UnvalidatedRequestValues.cs +System.Web/UnvalidatedRequestValuesBase.cs +System.Web/UnvalidatedRequestValuesWrapper.cs +System.Web/TaskAsyncResult.cs +System.Web/TaskEventHandler.cs +System.Web.Security/MembershipPasswordAttribute.cs diff --git a/mcs/class/System.Windows.Forms.DataVisualization/Test/System.Windows.Forms.DataVisualization.Charting/AnnotationPathPointTest.cs b/mcs/class/System.Windows.Forms.DataVisualization/Test/System.Windows.Forms.DataVisualization.Charting/AnnotationPathPointTest.cs index 1933373d27b..a802e4b8c03 100644 --- a/mcs/class/System.Windows.Forms.DataVisualization/Test/System.Windows.Forms.DataVisualization.Charting/AnnotationPathPointTest.cs +++ b/mcs/class/System.Windows.Forms.DataVisualization/Test/System.Windows.Forms.DataVisualization.Charting/AnnotationPathPointTest.cs @@ -27,7 +27,7 @@ using System.Windows.Forms.DataVisualization.Charting; using NUnit.Framework; -namespace ChartingTests +namespace MonoTests.System.Windows.Forms.DataVisualization.Charting { [TestFixture] public class AnnotationPathPointTest diff --git a/mcs/class/System.Windows.Forms.DataVisualization/Test/System.Windows.Forms.DataVisualization.Charting/AnovaResultTest.cs b/mcs/class/System.Windows.Forms.DataVisualization/Test/System.Windows.Forms.DataVisualization.Charting/AnovaResultTest.cs index 8a146d266bd..ef1f648777d 100644 --- a/mcs/class/System.Windows.Forms.DataVisualization/Test/System.Windows.Forms.DataVisualization.Charting/AnovaResultTest.cs +++ b/mcs/class/System.Windows.Forms.DataVisualization/Test/System.Windows.Forms.DataVisualization.Charting/AnovaResultTest.cs @@ -27,7 +27,7 @@ using System.Windows.Forms.DataVisualization.Charting; using NUnit.Framework; -namespace ChartingTests +namespace MonoTests.System.Windows.Forms.DataVisualization.Charting { [TestFixture] public class AnovaResultTest diff --git a/mcs/class/System.Windows.Forms.DataVisualization/Test/System.Windows.Forms.DataVisualization.Charting/ArrowAnnotationTest.cs b/mcs/class/System.Windows.Forms.DataVisualization/Test/System.Windows.Forms.DataVisualization.Charting/ArrowAnnotationTest.cs index ccc57005014..9fced81aade 100644 --- a/mcs/class/System.Windows.Forms.DataVisualization/Test/System.Windows.Forms.DataVisualization.Charting/ArrowAnnotationTest.cs +++ b/mcs/class/System.Windows.Forms.DataVisualization/Test/System.Windows.Forms.DataVisualization.Charting/ArrowAnnotationTest.cs @@ -27,7 +27,7 @@ using System.Windows.Forms.DataVisualization.Charting; using NUnit.Framework; -namespace ChartingTests +namespace MonoTests.System.Windows.Forms.DataVisualization.Charting { [TestFixture] public class ArrowAnnotationTest diff --git a/mcs/class/System.Windows.Forms.DataVisualization/Test/System.Windows.Forms.DataVisualization.Charting/AxisScaleBreakStyleTest.cs b/mcs/class/System.Windows.Forms.DataVisualization/Test/System.Windows.Forms.DataVisualization.Charting/AxisScaleBreakStyleTest.cs index e820427d526..3871898efdf 100644 --- a/mcs/class/System.Windows.Forms.DataVisualization/Test/System.Windows.Forms.DataVisualization.Charting/AxisScaleBreakStyleTest.cs +++ b/mcs/class/System.Windows.Forms.DataVisualization/Test/System.Windows.Forms.DataVisualization.Charting/AxisScaleBreakStyleTest.cs @@ -28,7 +28,7 @@ using NUnit.Framework; using System.Drawing; -namespace ChartingTests +namespace MonoTests.System.Windows.Forms.DataVisualization.Charting { [TestFixture] public class AxisScaleBreakStyleTest diff --git a/mcs/class/System.Windows.Forms.DataVisualization/Test/System.Windows.Forms.DataVisualization.Charting/ChartElementTest.cs b/mcs/class/System.Windows.Forms.DataVisualization/Test/System.Windows.Forms.DataVisualization.Charting/ChartElementTest.cs index c7053c6a7ee..3afeffe4238 100644 --- a/mcs/class/System.Windows.Forms.DataVisualization/Test/System.Windows.Forms.DataVisualization.Charting/ChartElementTest.cs +++ b/mcs/class/System.Windows.Forms.DataVisualization/Test/System.Windows.Forms.DataVisualization.Charting/ChartElementTest.cs @@ -27,7 +27,7 @@ using System.Windows.Forms.DataVisualization.Charting; using NUnit.Framework; -namespace ChartingTests +namespace MonoTests.System.Windows.Forms.DataVisualization.Charting { [TestFixture] public class ChartElementTest diff --git a/mcs/class/System.Windows.Forms.DataVisualization/Test/System.Windows.Forms.DataVisualization.Charting/DataPointTest.cs b/mcs/class/System.Windows.Forms.DataVisualization/Test/System.Windows.Forms.DataVisualization.Charting/DataPointTest.cs index 5431d77ea52..ec98463aa9b 100644 --- a/mcs/class/System.Windows.Forms.DataVisualization/Test/System.Windows.Forms.DataVisualization.Charting/DataPointTest.cs +++ b/mcs/class/System.Windows.Forms.DataVisualization/Test/System.Windows.Forms.DataVisualization.Charting/DataPointTest.cs @@ -27,7 +27,7 @@ using System.Windows.Forms.DataVisualization.Charting; using NUnit.Framework; -namespace ChartingTests +namespace MonoTests.System.Windows.Forms.DataVisualization.Charting { [TestFixture] public class DataPointTest diff --git a/mcs/class/System.XML/Makefile b/mcs/class/System.XML/Makefile index c52a56468ff..f44d93a6f0e 100644 --- a/mcs/class/System.XML/Makefile +++ b/mcs/class/System.XML/Makefile @@ -13,7 +13,7 @@ ifdef USE_BOOT_COMPILE LIBRARY_COMPILE = $(BOOT_COMPILE) endif -PROFILE_ANY_MOBILE := $(filter monotouch monotouch_runtime monodroid xammac, $(PROFILE)) +PROFILE_ANY_MOBILE := $(filter monotouch monotouch_runtime monodroid xammac mobile mobile_static, $(PROFILE)) LIB_MCS_FLAGS = -r:$(corlib) -r:System.dll -nowarn:0618,0612,0642 ifeq (2.1, $(FRAMEWORK_VERSION)) @@ -127,4 +127,4 @@ ifneq ($(PROFILE),basic) csproj-local: $(MAKE) csproj-local intermediate=bare/ endif -endif \ No newline at end of file +endif diff --git a/mcs/class/System.XML/System.Xml.Serialization/SerializationCodeGenerator.cs b/mcs/class/System.XML/System.Xml.Serialization/SerializationCodeGenerator.cs index 0ac2cd5e0ba..27848d10ea0 100644 --- a/mcs/class/System.XML/System.Xml.Serialization/SerializationCodeGenerator.cs +++ b/mcs/class/System.XML/System.Xml.Serialization/SerializationCodeGenerator.cs @@ -1242,8 +1242,15 @@ string GenerateMemberHasValueCondition (XmlTypeMapMember member, string ob, bool else return mem + " != " + GetLiteral (member.DefaultValue); } - else if (member.IsOptionalValueType) - return ob + ".@" + member.Name + "Specified"; + else if (member.HasSpecified) { + var sb = new StringBuilder (); + sb.AppendFormat ("{0}.@{1}Specified", ob, member.Name); + if (member.HasShouldSerialize) + sb.AppendFormat (" && {0}.@ShouldSerialize{1} ()", ob, member.Name); + return sb.ToString (); + } else if (member.HasShouldSerialize) + return ob + ".@ShouldSerialize" + member.Name + " ()"; + return null; } @@ -1948,14 +1955,12 @@ void GenerateReadMembers (XmlMapping xmlMap, ClassMap map, string ob, bool isVal { XmlTypeMapMemberElement mem = (XmlTypeMapMemberElement) map.XmlTextCollector; XmlTypeMapElementInfo info = (XmlTypeMapElementInfo) mem.ElementInfo [0]; + string str = GetStrTempVar (); + WriteLine ("string " + str + " = Reader.ReadString();"); if (info.TypeData.Type == typeof (string)) - GenerateSetMemberValue (mem, ob, "ReadString (" + GenerateGetMemberValue (mem, ob, isValueList) + ")", isValueList); + GenerateSetMemberValue (mem, ob, str, isValueList); else { - WriteLineInd ("{"); - string str = GetStrTempVar (); - WriteLine ("string " + str + " = Reader.ReadString();"); GenerateSetMemberValue (mem, ob, GenerateGetValueFromXmlString (str, info.TypeData, info.MappedType, info.IsNullable), isValueList); - WriteLineUni ("}"); } GenerateEndHook (); } @@ -2137,7 +2142,7 @@ void GenerateSetMemberValue (XmlTypeMapMember member, string ob, string value, b } else { WriteLine (ob + ".@" + member.Name + " = " + value + ";"); - if (member.IsOptionalValueType) { + if (member.IsOptionalValueType && member.IsValueSpecifiedSettable ()) { string val = initializingMember ? "false" : "true"; WriteLine (ob + "." + member.Name + "Specified = " + val + ";"); } diff --git a/mcs/class/System.XML/System.Xml.Serialization/TypeData.cs b/mcs/class/System.XML/System.Xml.Serialization/TypeData.cs index 861fcc11de6..79c89c25670 100644 --- a/mcs/class/System.XML/System.Xml.Serialization/TypeData.cs +++ b/mcs/class/System.XML/System.Xml.Serialization/TypeData.cs @@ -255,7 +255,7 @@ public static string ToCSharpName (Type type, bool full) sb.Append (type.Name); } else { - if (full && type.Namespace.Length > 0) + if (full && !string.IsNullOrEmpty(type.Namespace)) sb.Append (type.Namespace).Append ('.'); sb.Append (type.Name); } diff --git a/mcs/class/System.XML/System.Xml.Serialization/XmlReflectionImporter.cs b/mcs/class/System.XML/System.Xml.Serialization/XmlReflectionImporter.cs index 14afa1d0610..554d673251d 100644 --- a/mcs/class/System.XML/System.Xml.Serialization/XmlReflectionImporter.cs +++ b/mcs/class/System.XML/System.Xml.Serialization/XmlReflectionImporter.cs @@ -516,7 +516,7 @@ XmlTypeMapping ImportListMapping (TypeData typeData, XmlRootAttribute root, stri elem.Form = att.Form; if (att.Form == XmlSchemaForm.Unqualified) elem.Namespace = string.Empty; - elem.IsNullable = att.IsNullable && CanBeNull (elem.TypeData); + elem.IsNullable = (!att.IsNullableSpecified || att.IsNullable) && CanBeNull (elem.TypeData); elem.NestingLevel = att.NestingLevel; if (isMultiArray) { diff --git a/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs b/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs index a90ae2bfb31..5d9e4b24f34 100644 --- a/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs +++ b/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs @@ -505,7 +505,7 @@ void ReadMembers (ClassMap map, object ob, bool isValueList, bool readBySoapOrde XmlTypeMapMemberElement mem = (XmlTypeMapMemberElement) map.XmlTextCollector; XmlTypeMapElementInfo info = (XmlTypeMapElementInfo) mem.ElementInfo [0]; if (info.TypeData.Type == typeof (string)) - SetMemberValue (mem, ob, ReadString ((string) GetMemberValue (mem, ob, isValueList)), isValueList); + SetMemberValue (mem, ob, Reader.ReadString (), isValueList); else SetMemberValue (mem, ob, GetValueFromXmlString (Reader.ReadString(), info.TypeData, info.MappedType), isValueList); } @@ -585,6 +585,10 @@ bool IsReadOnly (XmlTypeMapMember member, TypeData memType, object ob, bool isVa void SetMemberValue (XmlTypeMapMember member, object ob, object value, bool isValueList) { + var memberType = member.TypeData.Type; + if (value != null && !value.GetType().IsAssignableFrom (memberType)) + value = XmlSerializationWriterInterpreter.ImplicitConvert (value, memberType); + if (isValueList) ((object[])ob)[member.GlobalIndex] = value; else diff --git a/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationWriterInterpreter.cs b/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationWriterInterpreter.cs index 846848a39a3..cf7985349eb 100644 --- a/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationWriterInterpreter.cs +++ b/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationWriterInterpreter.cs @@ -120,6 +120,10 @@ protected virtual void WriteObject (XmlTypeMapping typeMap, object ob, string el return; } + var obExpectedType = typeMap.TypeData.Type; + if (!ob.GetType().IsAssignableFrom (obExpectedType)) + ob = ImplicitConvert (ob, obExpectedType); + XmlTypeMapping map = typeMap.GetRealTypeMap (ob.GetType()); if (map == null) @@ -355,20 +359,19 @@ void WriteMemberElement (XmlTypeMapElementInfo elem, object memberValue) } } - object ImplicitConvert (object obj, Type type) + internal static object ImplicitConvert (object obj, Type type) { if (obj == null) return null; - for (Type t = type; t != typeof (object); t = t.BaseType) { - MethodInfo mi = t.GetMethod ("op_Implicit", new Type [] {t}); - if (mi != null && mi.ReturnType.IsAssignableFrom (obj.GetType ())) - return mi.Invoke (null, new object [] {obj}); - } for (Type t = obj.GetType (); t != typeof (object); t = t.BaseType) { MethodInfo mi = t.GetMethod ("op_Implicit", new Type [] {t}); if (mi != null && mi.ReturnType == type) return mi.Invoke (null, new object [] {obj}); + + mi = type.GetMethod ("op_Implicit", new Type [] {t}); + if (mi != null && mi.ReturnType == type) + return mi.Invoke (null, new object [] {obj}); } return obj; } diff --git a/mcs/class/System.XML/System.Xml.Serialization/XmlTypeMapMember.cs b/mcs/class/System.XML/System.Xml.Serialization/XmlTypeMapMember.cs index e023321ba40..df6d3361a46 100644 --- a/mcs/class/System.XML/System.Xml.Serialization/XmlTypeMapMember.cs +++ b/mcs/class/System.XML/System.Xml.Serialization/XmlTypeMapMember.cs @@ -46,6 +46,7 @@ internal class XmlTypeMapMember TypeData _typeData; MemberInfo _member; MemberInfo _specifiedMember; + MethodInfo _shouldSerialize; object _defaultValue = System.DBNull.Value; string documentation; int _flags; @@ -118,8 +119,12 @@ void InitMember (Type type) mems = type.GetMember (_name + "Specified", BindingFlags.Instance|BindingFlags.Public); if (mems.Length > 0) _specifiedMember = mems[0]; - if (_specifiedMember is PropertyInfo && !((PropertyInfo) _specifiedMember).CanWrite) + if (_specifiedMember is PropertyInfo && !((PropertyInfo) _specifiedMember).CanRead) _specifiedMember = null; + + var method = type.GetMethod ("ShouldSerialize" + _name, BindingFlags.Instance | BindingFlags.Public, null, Type.EmptyTypes, null); + if (method != null && method.ReturnType == typeof (bool) && !method.IsGenericMethod) + _shouldSerialize = method; } public TypeData TypeData @@ -167,7 +172,7 @@ public void CheckOptionalValueType (Type type) { // Used when reflecting a type if (_member == null) InitMember (type); - IsOptionalValueType = (_specifiedMember != null); + IsOptionalValueType = (_specifiedMember != null || _shouldSerialize != null); } public void CheckOptionalValueType (XmlReflectionMember[] members) @@ -182,26 +187,54 @@ public void CheckOptionalValueType (XmlReflectionMember[] members) } } } - + + public bool HasSpecified { + get { return _specifiedMember != null; } + } + + public bool HasShouldSerialize { + get { return _shouldSerialize != null; } + } + public bool GetValueSpecified (object ob) { if (_specifiedGlobalIndex != -1) { object[] array = (object[])ob; return _specifiedGlobalIndex < array.Length && (bool) array [_specifiedGlobalIndex]; } - else if (_specifiedMember is PropertyInfo) - return (bool) ((PropertyInfo)_specifiedMember).GetValue (ob, null); - else - return (bool) ((FieldInfo)_specifiedMember).GetValue (ob); + bool specified = true; + + if (_specifiedMember != null) { + if (_specifiedMember is PropertyInfo) + specified = (bool)((PropertyInfo)_specifiedMember).GetValue (ob, null); + else + specified = (bool)((FieldInfo)_specifiedMember).GetValue (ob); + } + if (_shouldSerialize != null) + specified = specified && (bool)_shouldSerialize.Invoke (ob, new object [] {}); + + return specified; + } + + public bool IsValueSpecifiedSettable () { + if (_specifiedMember is PropertyInfo) + return ((PropertyInfo) _specifiedMember).CanWrite; + + if (_specifiedMember is FieldInfo) + return ((FieldInfo) _specifiedMember).IsInitOnly; + + return false; } public void SetValueSpecified (object ob, bool value) { if (_specifiedGlobalIndex != -1) ((object[])ob) [_specifiedGlobalIndex] = value; - else if (_specifiedMember is PropertyInfo) + else if (_specifiedMember is PropertyInfo) { + if (!((PropertyInfo) _specifiedMember).CanWrite) + return; ((PropertyInfo)_specifiedMember).SetValue (ob, value, null); - else + } else if (_specifiedMember is FieldInfo) ((FieldInfo)_specifiedMember).SetValue (ob, value); } diff --git a/mcs/class/System.XML/System.Xml/XmlDocument.cs b/mcs/class/System.XML/System.Xml/XmlDocument.cs index 4d1db5db58f..c93d68b5f37 100644 --- a/mcs/class/System.XML/System.Xml/XmlDocument.cs +++ b/mcs/class/System.XML/System.Xml/XmlDocument.cs @@ -858,20 +858,7 @@ internal void ReadAttributeNodeValue (XmlReader reader, XmlAttribute attribute) [PermissionSet (SecurityAction.InheritanceDemand, Unrestricted = true)] public virtual XmlNode ReadNode (XmlReader reader) { - if (PreserveWhitespace) - return ReadNodeCore (reader); - XmlTextReader xtr = reader as XmlTextReader; - if (xtr != null && xtr.WhitespaceHandling == - WhitespaceHandling.All) { - try { - xtr.WhitespaceHandling = WhitespaceHandling.Significant; - return ReadNodeCore (reader); - } finally { - xtr.WhitespaceHandling = WhitespaceHandling.All; - } - } - else - return ReadNodeCore (reader); + return ReadNodeCore (reader); } XmlNode ReadNodeCore (XmlReader reader) diff --git a/mcs/class/System.XML/System.Xml/XmlElement.cs b/mcs/class/System.XML/System.Xml/XmlElement.cs index 120355f5843..2d9d1e0e930 100644 --- a/mcs/class/System.XML/System.Xml/XmlElement.cs +++ b/mcs/class/System.XML/System.Xml/XmlElement.cs @@ -152,11 +152,17 @@ public override string InnerXml { XmlTextReader xmlReader = new XmlTextReader (value, XmlNodeType.Element, ctx); xmlReader.XmlResolver = OwnerDocument.Resolver; - do { - XmlNode n = OwnerDocument.ReadNode (xmlReader); - if(n == null) break; - AppendChild (n); - } while (true); + bool pw = OwnerDocument.PreserveWhitespace; + OwnerDocument.PreserveWhitespace = true; + try { + do { + XmlNode n = OwnerDocument.ReadNode (xmlReader); + if(n == null) break; + AppendChild (n); + } while (true); + } finally { + OwnerDocument.PreserveWhitespace = pw; + } } } diff --git a/mcs/class/System.XML/System.Xml/XmlTextReader.cs b/mcs/class/System.XML/System.Xml/XmlTextReader.cs index 63745fe3039..eee0580d44d 100644 --- a/mcs/class/System.XML/System.Xml/XmlTextReader.cs +++ b/mcs/class/System.XML/System.Xml/XmlTextReader.cs @@ -164,11 +164,6 @@ internal XmlTextReader (string url, TextReader fragment, XmlNodeType fragType, X 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 @@ -177,9 +172,13 @@ Stream GetStreamFromUrl (string url, out string absoluteUriString) 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 @@ -717,7 +716,6 @@ public virtual string Value { if (valueCache != null) return valueCache; if (ValueBufferStart >= 0) { -//Console.WriteLine (NodeType + " / " + ValueBuffer.Length + " / " + ValueBufferStart + " / " + ValueBufferEnd); valueCache = Reader.valueBuffer.ToString (ValueBufferStart, ValueBufferEnd - ValueBufferStart); return valueCache; } @@ -1801,6 +1799,7 @@ private void AddAttributeWithValue (string name, string value) value, false); ati.Value = value; + ati.ValueTokenStartIndex = ati.ValueTokenEndIndex = currentAttributeValue; attributeCount++; } diff --git a/mcs/class/System.XML/System.Xml/XmlTextReader2.cs b/mcs/class/System.XML/System.Xml/XmlTextReader2.cs index 2110bb62f17..52a7a9e6878 100644 --- a/mcs/class/System.XML/System.Xml/XmlTextReader2.cs +++ b/mcs/class/System.XML/System.Xml/XmlTextReader2.cs @@ -254,6 +254,11 @@ public override ReadState ReadState { 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; } diff --git a/mcs/class/System.XML/Test/System.Xml.Serialization/XmlSerializerTestClasses.cs b/mcs/class/System.XML/Test/System.Xml.Serialization/XmlSerializerTestClasses.cs index 62b3698c837..872e6cbdf71 100644 --- a/mcs/class/System.XML/Test/System.Xml.Serialization/XmlSerializerTestClasses.cs +++ b/mcs/class/System.XML/Test/System.Xml.Serialization/XmlSerializerTestClasses.cs @@ -1117,5 +1117,83 @@ public class Bug9193Class [XmlElement ("Extra", Order=1)] public string[] Extra; } + + public class SimpleObjectA + { + [XmlAttribute] + public string Text + { + get; set; + } + + public static implicit operator SimpleObjectA (SimpleObjectB o) + { + return new SimpleObjectA { Text = o.Text }; + } + + public static implicit operator SimpleObjectB (SimpleObjectA o) + { + return new SimpleObjectB { Text = o.Text }; + } + } + + public class SimpleObjectB + { + [XmlAttribute] + public string Text + { + get; set; + } + } + + public class ObjectWithElementRequiringImplicitCast + { + public ObjectWithElementRequiringImplicitCast () { } + public ObjectWithElementRequiringImplicitCast (string text) + { + Object = new SimpleObjectB { Text = text }; + } + + [XmlElement(Type = typeof (SimpleObjectA))] + public SimpleObjectB Object + { + get; set; + } + } + + public class ObjectWithNullableArrayItems + { + [XmlArrayItem ("Element", IsNullable = true)] + public List Elements; + } + + public class ObjectWithNonNullableArrayItems + { + [XmlArrayItem ("Element", IsNullable = false)] + public List Elements; + } + + public class ObjectWithNotSpecifiedNullableArrayItems + { + [XmlArrayItem ("Element")] + public List Elements; + } + + [Serializable] + public sealed class ClassWithDefaultTextNotNull + { + [XmlText] + public string Value; + + public const string DefaultValue = "NotNull"; + + public ClassWithDefaultTextNotNull (string v) { + Value = v; + } + + public ClassWithDefaultTextNotNull () { + Value = DefaultValue; + } + } } diff --git a/mcs/class/System.XML/Test/System.Xml.Serialization/XmlSerializerTests.cs b/mcs/class/System.XML/Test/System.Xml.Serialization/XmlSerializerTests.cs index 6001f7f2476..ef6ba78867f 100644 --- a/mcs/class/System.XML/Test/System.Xml.Serialization/XmlSerializerTests.cs +++ b/mcs/class/System.XML/Test/System.Xml.Serialization/XmlSerializerTests.cs @@ -3332,6 +3332,194 @@ public void TestClassWithXmlAnyElement () using (var sw = new StringWriter ()) ser.Serialize (sw, c); } + + [Test] + public void ClassWithImplicitlyConvertibleElement () + { + var ser = new XmlSerializer (typeof (ObjectWithElementRequiringImplicitCast)); + + var obj = new ObjectWithElementRequiringImplicitCast ("test"); + + using (var w = new StringWriter ()) { + ser.Serialize (w, obj); + using (var r = new StringReader ( w.ToString ())) { + var desObj = (ObjectWithElementRequiringImplicitCast) ser.Deserialize (r); + Assert.AreEqual (obj.Object.Text, desObj.Object.Text); + } + } + } + + public class ClassWithOptionalMethods + { + private readonly bool shouldSerializeX; + private readonly bool xSpecified; + + [XmlAttribute] + public int X { get; set; } + + public bool ShouldSerializeX () { return shouldSerializeX; } + + public bool XSpecified + { + get { return xSpecified; } + } + + public ClassWithOptionalMethods () + { + } + + public ClassWithOptionalMethods (int x, bool shouldSerializeX, bool xSpecified) + { + this.X = x; + this.shouldSerializeX = shouldSerializeX; + this.xSpecified = xSpecified; + } + } + + [Test] + public void OptionalMethods () + { + var ser = new XmlSerializer (typeof (ClassWithOptionalMethods)); + + var expectedValueWithoutX = Infoset ("" + Environment.NewLine + + ""); + + var expectedValueWithX = Infoset ("" + Environment.NewLine + + ""); + + using (var t = new StringWriter ()) { + var obj = new ClassWithOptionalMethods (11, false, false); + ser.Serialize (t, obj); + Assert.AreEqual (expectedValueWithoutX, Infoset (t.ToString ())); + } + + using (var t = new StringWriter ()) { + var obj = new ClassWithOptionalMethods (11, true, false); + ser.Serialize (t, obj); + Assert.AreEqual (expectedValueWithoutX, Infoset (t.ToString ())); + } + + using (var t = new StringWriter ()) { + var obj = new ClassWithOptionalMethods (11, false, true); + ser.Serialize (t, obj); + Assert.AreEqual (expectedValueWithoutX, Infoset (t.ToString ())); + } + + using (var t = new StringWriter ()) { + var obj = new ClassWithOptionalMethods (11, true, true); + ser.Serialize (t, obj); + Assert.AreEqual (expectedValueWithX, Infoset (t.ToString ())); + } + } + + public class ClassWithShouldSerializeGeneric + { + [XmlAttribute] + public int X { get; set; } + + public bool ShouldSerializeX () { return false; } + } + + [Test] + [Category("NotDotNet")] + public void ShouldSerializeGeneric () + { + var ser = new XmlSerializer (typeof (ClassWithShouldSerializeGeneric)); + + var expectedValueWithX = Infoset ("" + Environment.NewLine + + ""); + + using (var t = new StringWriter ()) { + var obj = new ClassWithShouldSerializeGeneric { X = 11 }; + ser.Serialize (t, obj); + Assert.AreEqual (expectedValueWithX, Infoset (t.ToString ())); + } + } + + [Test] + public void NullableArrayItems () + { + var ser = new XmlSerializer (typeof (ObjectWithNullableArrayItems)); + + var obj = new ObjectWithNullableArrayItems (); + obj.Elements = new List (); + obj.Elements.Add (new SimpleClass { something = "Hello" }); + obj.Elements.Add (null); + obj.Elements.Add (new SimpleClass { something = "World" }); + + using (var w = new StringWriter ()) { + ser.Serialize (w, obj); + using (var r = new StringReader ( w.ToString ())) { + var desObj = (ObjectWithNullableArrayItems) ser.Deserialize (r); + Assert.IsNull (desObj.Elements [1]); + } + } + } + + [Test] + public void NonNullableArrayItems () + { + var ser = new XmlSerializer (typeof (ObjectWithNonNullableArrayItems)); + + var obj = new ObjectWithNonNullableArrayItems (); + obj.Elements = new List (); + obj.Elements.Add (new SimpleClass { something = "Hello" }); + obj.Elements.Add (null); + obj.Elements.Add (new SimpleClass { something = "World" }); + + using (var w = new StringWriter ()) { + ser.Serialize (w, obj); + using (var r = new StringReader ( w.ToString ())) { + var desObj = (ObjectWithNonNullableArrayItems) ser.Deserialize (r); + Assert.IsNotNull (desObj.Elements [1]); + } + } + } + + [Test] + public void NotSpecifiedNullableArrayItems () + { + var ser = new XmlSerializer (typeof (ObjectWithNotSpecifiedNullableArrayItems)); + + var obj = new ObjectWithNotSpecifiedNullableArrayItems (); + obj.Elements = new List (); + obj.Elements.Add (new SimpleClass { something = "Hello" }); + obj.Elements.Add (null); + obj.Elements.Add (new SimpleClass { something = "World" }); + + using (var w = new StringWriter ()) { + ser.Serialize (w, obj); + using (var r = new StringReader ( w.ToString ())) { + var desObj = (ObjectWithNotSpecifiedNullableArrayItems) ser.Deserialize (r); + Assert.IsNull (desObj.Elements [1]); + } + } + } + + private static void TestClassWithDefaultTextNotNullAux (string value, string expected) + { + var obj = new ClassWithDefaultTextNotNull (value); + var ser = new XmlSerializer (typeof (ClassWithDefaultTextNotNull)); + + using (var mstream = new MemoryStream ()) + using (var writer = new XmlTextWriter (mstream, Encoding.ASCII)) { + ser.Serialize (writer, obj); + + mstream.Seek (0, SeekOrigin.Begin); + using (var reader = new XmlTextReader (mstream)) { + var result = (ClassWithDefaultTextNotNull) ser.Deserialize (reader); + Assert.AreEqual (expected, result.Value); + } + } + } + + [Test] + public void TestClassWithDefaultTextNotNull () + { + TestClassWithDefaultTextNotNullAux ("my_text", "my_text"); + TestClassWithDefaultTextNotNullAux ("", ClassWithDefaultTextNotNull.DefaultValue); + TestClassWithDefaultTextNotNullAux (null, ClassWithDefaultTextNotNull.DefaultValue); + } } // Test generated serialization code. diff --git a/mcs/class/System.XML/Test/System.Xml/XmlResolverTest.cs b/mcs/class/System.XML/Test/System.Xml/XmlResolverTest.cs index fcdc34e7f7a..80a46e5c99f 100644 --- a/mcs/class/System.XML/Test/System.Xml/XmlResolverTest.cs +++ b/mcs/class/System.XML/Test/System.Xml/XmlResolverTest.cs @@ -33,7 +33,7 @@ using NUnit.Framework; -namespace MonoTest.System.Xml { +namespace MonoTests.System.Xml { [TestFixture] public class XmlResolverTest { diff --git a/mcs/class/System.XML/Test/System.Xml/XmlSecureResolverCas.cs b/mcs/class/System.XML/Test/System.Xml/XmlSecureResolverCas.cs index 52de90d1414..2e5316c1ffe 100644 --- a/mcs/class/System.XML/Test/System.Xml/XmlSecureResolverCas.cs +++ b/mcs/class/System.XML/Test/System.Xml/XmlSecureResolverCas.cs @@ -38,7 +38,7 @@ using System.Security.Policy; using System.Xml; -using MonoTestsXml; +using MonoTests.System.Xml; namespace MonoCasTests.System.Xml { @@ -85,4 +85,4 @@ public void DenyUnrestricted_CreateEvidenceForUrl_Local () } } -#endif \ No newline at end of file +#endif diff --git a/mcs/class/System.XML/Test/System.Xml/XmlSecureResolverTests.cs b/mcs/class/System.XML/Test/System.Xml/XmlSecureResolverTests.cs index c97407de984..a2eaa8b1064 100644 --- a/mcs/class/System.XML/Test/System.Xml/XmlSecureResolverTests.cs +++ b/mcs/class/System.XML/Test/System.Xml/XmlSecureResolverTests.cs @@ -20,7 +20,7 @@ using System.Xml; using NUnit.Framework; -namespace MonoTestsXml +namespace MonoTests.System.Xml { [TestFixture] public class XmlSecureResolverTests diff --git a/mcs/class/System.XML/Test/System.Xml/XmlTextReaderTests.cs b/mcs/class/System.XML/Test/System.Xml/XmlTextReaderTests.cs index 7ecd83780ae..596a808aac3 100644 --- a/mcs/class/System.XML/Test/System.Xml/XmlTextReaderTests.cs +++ b/mcs/class/System.XML/Test/System.Xml/XmlTextReaderTests.cs @@ -1382,5 +1382,94 @@ public void BOMLessUTF16Detection () // bug #674580 var xtr = new XmlTextReader (ms); xtr.Read (); } + + [Test] + public void XmlDeclarationReadAttributeValue () + { + const string input = ""; + 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 = ""; + 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"); + } + + [Test] + public void Whitespaces () + { + const string xml = " World Bar"; + var reader = new XmlTextReader (new StringReader (xml)); + //reader.WhitespaceHandling = WhitespaceHandling.All; + + reader.Read (); + Assert.AreEqual (XmlNodeType.XmlDeclaration, reader.NodeType, "#1a"); + reader.Read (); + Assert.AreEqual (XmlNodeType.Element, reader.NodeType, "#1b"); + Assert.AreEqual ("test", reader.Name, "#1c"); + + reader.Read (); + if (reader.NodeType == XmlNodeType.Whitespace) + reader.Read (); + + Assert.AreEqual (XmlNodeType.Element, reader.NodeType, "#2a"); + Assert.AreEqual ("foo", reader.Name, "#2b"); + + var doc = new XmlDocument (); + //doc.PreserveWhitespace = true; + doc.ReadNode (reader); + + Assert.AreEqual (XmlNodeType.Whitespace, reader.NodeType, "#3"); + + reader.Read (); + if (reader.NodeType == XmlNodeType.Whitespace) + reader.Read (); + + Assert.AreEqual (XmlNodeType.Element, reader.NodeType, "#4"); + Assert.AreEqual ("foo", reader.Name, "#4b"); + + doc.ReadNode (reader); + + Assert.AreEqual (XmlNodeType.EndElement, reader.NodeType, "#5"); + } } } diff --git a/mcs/class/System.Xaml/Makefile b/mcs/class/System.Xaml/Makefile index 17d16132910..5104e87b042 100644 --- a/mcs/class/System.Xaml/Makefile +++ b/mcs/class/System.Xaml/Makefile @@ -18,7 +18,7 @@ TEST_EXTRA_DISTFILES = \ Test/XmlFiles/*.xml \ Test/XmlFiles/*.xaml -VALID_PROFILE := $(filter 4 monodroid monotouch, $(FRAMEWORK_VERSION_MAJOR)) +VALID_PROFILE := $(filter 4 monodroid monotouch mobile mobile_static, $(FRAMEWORK_VERSION_MAJOR)) ifndef VALID_PROFILE LIBRARY_NAME = dummy-System.Xaml.dll NO_INSTALL = yes diff --git a/mcs/class/System.Xml.Linq/System.Xml.Linq/XComment.cs b/mcs/class/System.Xml.Linq/System.Xml.Linq/XComment.cs index edab3fb4775..f7b5e7b6c66 100644 --- a/mcs/class/System.Xml.Linq/System.Xml.Linq/XComment.cs +++ b/mcs/class/System.Xml.Linq/System.Xml.Linq/XComment.cs @@ -25,6 +25,7 @@ // using System; +using System.Linq; using System.Xml; namespace System.Xml.Linq @@ -54,7 +55,9 @@ public string Value { public override void WriteTo (XmlWriter writer) { - writer.WriteComment (value); + var v = value.Replace ("--", "- -"); + v = v.LastOrDefault () == '-' ? v.Substring (0, v.Length - 1) +"D;" : v; + writer.WriteComment (v); } } } diff --git a/mcs/class/System.Xml.Linq/System.Xml.Linq_test.dll.sources b/mcs/class/System.Xml.Linq/System.Xml.Linq_test.dll.sources index 77007ae238d..693d4a2e296 100644 --- a/mcs/class/System.Xml.Linq/System.Xml.Linq_test.dll.sources +++ b/mcs/class/System.Xml.Linq/System.Xml.Linq_test.dll.sources @@ -1,5 +1,6 @@ System.Xml.Linq/ExtensionsTest.cs System.Xml.Linq/XAttributeTest.cs +System.Xml.Linq/XCommentTest.cs System.Xml.Linq/XDocumentTest.cs System.Xml.Linq/XElementTest.cs System.Xml.Linq/XNameTest.cs diff --git a/mcs/class/System.Xml.Linq/Test/System.Xml.Linq/XCommentTest.cs b/mcs/class/System.Xml.Linq/Test/System.Xml.Linq/XCommentTest.cs new file mode 100644 index 00000000000..b324bb68fcc --- /dev/null +++ b/mcs/class/System.Xml.Linq/Test/System.Xml.Linq/XCommentTest.cs @@ -0,0 +1,66 @@ +// +// Authors: +// Atsushi Enomoto +// +// Copyright 2014 Xamarin Inc. (http://www.xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.IO; +using System.Xml; +using System.Xml.Linq; +using System.Linq; + +using NUnit.Framework; + +namespace MonoTests.System.Xml.Linq +{ + [TestFixture] + public class XCommentTest + { + [Test] + public void EscapeSequentialDashes () + { + XComment c; + + c = new XComment ("<--foo-->"); + Assert.AreEqual ("<--foo-->", c.Value, "#1"); + // bug #23318 + // Unlike XmlWriter.WriteComment(), XComment.ToString() seems to accept "--" in the value. + Assert.AreEqual ("", c.ToString (), "#2"); + // make sure if it can be read... + XmlReader.Create (new StringReader (c.ToString ())).Read (); + + // The last '-' causes some glitch... + c = new XComment ("--foo--"); + Assert.AreEqual ("--foo--", c.Value, "#3"); + Assert.AreEqual ("", c.ToString (), "#4"); + XmlReader.Create (new StringReader (c.ToString ())).Read (); + + // What if "); + Assert.AreEqual ("", c.Value, "#5"); + Assert.AreEqual ("", c.ToString (), "#6"); + XmlReader.Create (new StringReader (c.ToString ())).Read (); + } + } +} diff --git a/mcs/class/System/Makefile b/mcs/class/System/Makefile index 50bc1fce7d1..cfa7564d4b6 100644 --- a/mcs/class/System/Makefile +++ b/mcs/class/System/Makefile @@ -24,14 +24,10 @@ TEST_MCS_FLAGS = -r:System.Drawing.dll -r:Mono.Security.dll -r:System.Data -r:Sy LIB_MCS_FLAGS = -nowarn:618 -d:CONFIGURATION_2_0 -unsafe $(RESOURCE_FILES:%=-resource:%) TEST_MCS_FLAGS += -r:System.Configuration -PROFILE_ANY_MOBILE := $(filter monotouch monotouch_runtime monodroid xammac, $(PROFILE)) -NOT_SL := $(filter net_2_0 net_4_0 net_4_5 monotouch_runtime mobile xammac, $(PROFILE)) +PROFILE_ANY_MOBILE := $(filter monotouch monotouch_runtime monodroid xammaci mobile mobile_static, $(PROFILE)) ifeq (2.1, $(FRAMEWORK_VERSION)) LIB_MCS_FLAGS += -d:INSIDE_SYSTEM -ifeq (moonlight_raw, $(PROFILE)) -LIB_MCS_FLAGS += -d:SECURITY_DEP -endif endif ifeq (monotouch, $(subst _runtime,,$(PROFILE))) LIB_MCS_FLAGS += -d:SECURITY_DEP @@ -154,4 +150,4 @@ csproj-local: $(MAKE) csproj-local intermediate=bare/ $(MAKE) csproj-local intermediate=secxml/ endif -endif \ No newline at end of file +endif diff --git a/mcs/class/System/System-bare-net_4_5.csproj b/mcs/class/System/System-bare-net_4_5.csproj index 26714d1f7bb..8790db08575 100644 --- a/mcs/class/System/System-bare-net_4_5.csproj +++ b/mcs/class/System/System-bare-net_4_5.csproj @@ -1124,6 +1124,7 @@ + diff --git a/mcs/class/System/System-net_4_5.csproj b/mcs/class/System/System-net_4_5.csproj index 8367ee9e16b..d8abc97e11a 100644 --- a/mcs/class/System/System-net_4_5.csproj +++ b/mcs/class/System/System-net_4_5.csproj @@ -1124,6 +1124,7 @@ + diff --git a/mcs/class/System/System-secxml-net_4_5.csproj b/mcs/class/System/System-secxml-net_4_5.csproj index 2e69308ad30..b13fc18c245 100644 --- a/mcs/class/System/System-secxml-net_4_5.csproj +++ b/mcs/class/System/System-secxml-net_4_5.csproj @@ -1124,6 +1124,7 @@ + diff --git a/mcs/class/System/System.Collections.Concurrent/BlockingCollection.cs b/mcs/class/System/System.Collections.Concurrent/BlockingCollection.cs index 893cd8e3a46..395bc68e96d 100644 --- a/mcs/class/System/System.Collections.Concurrent/BlockingCollection.cs +++ b/mcs/class/System/System.Collections.Concurrent/BlockingCollection.cs @@ -124,8 +124,12 @@ public bool TryAdd (T item, int millisecondsTimeout, CancellationToken cancellat 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; @@ -144,10 +148,6 @@ public bool TryAdd (T item, int millisecondsTimeout, CancellationToken cancellat 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; @@ -291,30 +291,28 @@ static bool IsThereANullElement (BlockingCollection[] collections) public static int AddToAny (BlockingCollection[] 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[] 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[] collections, T item) @@ -368,21 +366,7 @@ public static int TryAddToAny (BlockingCollection[] collections, T item, int public static int TakeFromAny (BlockingCollection[] 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[] collections, out T item, CancellationToken cancellationToken) diff --git a/mcs/class/System/System.Diagnostics/DiagnosticsConfigurationHandler.cs b/mcs/class/System/System.Diagnostics/DiagnosticsConfigurationHandler.cs index 149ad3bc5ba..c3937530f66 100644 --- a/mcs/class/System/System.Diagnostics/DiagnosticsConfigurationHandler.cs +++ b/mcs/class/System/System.Diagnostics/DiagnosticsConfigurationHandler.cs @@ -94,6 +94,7 @@ public class DiagnosticsConfigurationHandler : IConfigurationSectionHandler public DiagnosticsConfigurationHandler () { elementHandlers ["assert"] = new ElementHandler (AddAssertNode); + elementHandlers ["performanceCounters"] = new ElementHandler (AddPerformanceCountersNode); elementHandlers ["switches"] = new ElementHandler (AddSwitchesNode); elementHandlers ["trace"] = new ElementHandler (AddTraceNode); elementHandlers ["sources"] = new ElementHandler (AddSourcesNode); @@ -181,6 +182,25 @@ private void AddAssertNode (IDictionary d, XmlNode node) ThrowUnrecognizedElement (node.ChildNodes[0]); } + private void AddPerformanceCountersNode (IDictionary d, XmlNode node) + { + XmlAttributeCollection c = node.Attributes; + string filemappingsize = GetAttribute (c, "filemappingsize", false, node); + ValidateInvalidAttributes (c, node); + if (filemappingsize != null) { + try { + d ["filemappingsize"] = int.Parse (filemappingsize); + } + catch (Exception e) { + throw new ConfigurationException ("The `filemappingsize' attribute must be an integral value.", + e, node); + } + } + + if (node.ChildNodes.Count > 0) + ThrowUnrecognizedElement (node.ChildNodes[0]); + } + // name and value attributes are required // Docs do not define "remove" or "clear" elements, but .NET recognizes // them diff --git a/mcs/class/System/System.Diagnostics/LocalFileEventLog.cs b/mcs/class/System/System.Diagnostics/LocalFileEventLog.cs index e5a34ff1a41..c013223d081 100644 --- a/mcs/class/System/System.Diagnostics/LocalFileEventLog.cs +++ b/mcs/class/System/System.Diagnostics/LocalFileEventLog.cs @@ -29,7 +29,7 @@ // using System; -using System.Collections; +using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Globalization; @@ -227,7 +227,7 @@ protected override EventLogEntry GetEntry (int index) DateFormat, CultureInfo.InvariantCulture); DateTime timeWritten = File.GetLastWriteTime (file); int stringNums = int.Parse (tr.ReadLine ().Substring (20)); - ArrayList replacementTemp = new ArrayList (); + var replacementTemp = new List (); StringBuilder sb = new StringBuilder (); while (replacementTemp.Count < stringNums) { char c = (char) tr.Read (); @@ -238,8 +238,7 @@ protected override EventLogEntry GetEntry (int index) 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); diff --git a/mcs/class/System/System.Diagnostics/Process.cs b/mcs/class/System/System.Diagnostics/Process.cs index 795ebaaa80f..0cf197af1dc 100644 --- a/mcs/class/System/System.Diagnostics/Process.cs +++ b/mcs/class/System/System.Diagnostics/Process.cs @@ -39,7 +39,7 @@ 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; @@ -832,13 +832,13 @@ public static Process GetProcessById(int processId, string machineName) { [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 (pids.Length); for (int i = 0; i < pids.Length; i++) { try { proclist.Add (GetProcessById (pids [i])); @@ -851,7 +851,7 @@ public static Process[] GetProcesses() } } - return ((Process []) proclist.ToArray (typeof (Process))); + return proclist.ToArray (); } [MonoTODO ("There is no support for retrieving process information from a remote machine")] @@ -871,7 +871,7 @@ public static Process[] GetProcessesByName(string processName) if (pids == null) return new Process [0]; - ArrayList proclist = new ArrayList (pids.Length); + var proclist = new List (pids.Length); for (int i = 0; i < pids.Length; i++) { try { Process p = GetProcessById (pids [i]); @@ -886,7 +886,7 @@ public static Process[] GetProcessesByName(string processName) } } - return ((Process []) proclist.ToArray (typeof (Process))); + return proclist.ToArray (); } [MonoTODO] @@ -940,7 +940,7 @@ private static bool Start_shell (ProcessStartInfo startInfo, Process process) 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) { @@ -1080,7 +1080,7 @@ private static bool Start_noshell (ProcessStartInfo startInfo, 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) { diff --git a/mcs/class/System/System.Diagnostics/SourceSwitch.cs b/mcs/class/System/System.Diagnostics/SourceSwitch.cs index d991271478e..e9b29ca3b85 100644 --- a/mcs/class/System/System.Diagnostics/SourceSwitch.cs +++ b/mcs/class/System/System.Diagnostics/SourceSwitch.cs @@ -59,15 +59,11 @@ public bool ShouldTrace (TraceEventType eventType) { switch (eventType) { case TraceEventType.Critical: - return (Level & SourceLevels.Critical) != 0; case TraceEventType.Error: - return (Level & SourceLevels.Error) != 0; case TraceEventType.Warning: - return (Level & SourceLevels.Warning) != 0; case TraceEventType.Information: - return (Level & SourceLevels.Information) != 0; case TraceEventType.Verbose: - return (Level & SourceLevels.Verbose) != 0; + return (Level & (SourceLevels)eventType) != 0; case TraceEventType.Start: case TraceEventType.Stop: case TraceEventType.Suspend: @@ -78,6 +74,7 @@ public bool ShouldTrace (TraceEventType eventType) } } + protected override void OnValueChanged () { SwitchSetting = (int) Enum.Parse (typeof (SourceLevels), diff --git a/mcs/class/System/System.Diagnostics/Switch.cs b/mcs/class/System/System.Diagnostics/Switch.cs index 216cde7fa24..94d1f4d19fe 100644 --- a/mcs/class/System/System.Diagnostics/Switch.cs +++ b/mcs/class/System/System.Diagnostics/Switch.cs @@ -64,8 +64,8 @@ public abstract class Switch protected Switch(string displayName, string description) { - this.name = displayName; - this.description = description; + this.name = displayName ?? string.Empty; + this.description = description ?? string.Empty; } protected Switch(string displayName, string description, string defaultSwitchValue) diff --git a/mcs/class/System/System.Diagnostics/Win32EventLog.cs b/mcs/class/System/System.Diagnostics/Win32EventLog.cs index 40fe3a36b15..4002c3b7cdc 100644 --- a/mcs/class/System/System.Diagnostics/Win32EventLog.cs +++ b/mcs/class/System/System.Diagnostics/Win32EventLog.cs @@ -28,7 +28,7 @@ // using System; -using System.Collections; +using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Globalization; @@ -177,12 +177,11 @@ public override void DeleteEventSource (string source, string machineName) string [] sources = (string []) logKey.GetValue ("Sources"); if (sources != null) { - ArrayList temp = new ArrayList (); + var temp = new List (); 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); } } diff --git a/mcs/class/System/System.IO.Ports/SerialPort.cs b/mcs/class/System/System.IO.Ports/SerialPort.cs index 08a9a655b2e..65189c5813f 100644 --- a/mcs/class/System/System.IO.Ports/SerialPort.cs +++ b/mcs/class/System/System.IO.Ports/SerialPort.cs @@ -529,7 +529,7 @@ public static string [] GetPortNames () // 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; } @@ -537,7 +537,7 @@ public static string [] GetPortNames () 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")) diff --git a/mcs/class/System/System.IO/DefaultWatcher.cs b/mcs/class/System/System.IO/DefaultWatcher.cs index 8988a6b9703..d2d8b28d86c 100644 --- a/mcs/class/System/System.IO/DefaultWatcher.cs +++ b/mcs/class/System/System.IO/DefaultWatcher.cs @@ -30,6 +30,7 @@ using System; using System.Collections; +using System.Collections.Generic; using System.IO; using System.Threading; @@ -240,12 +241,12 @@ void DoFiles (DefaultWatcherData data, string directory, bool dispatch) return; /* Removed files */ - ArrayList removed = null; + List 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 (); removed.Add (filename); DispatchEvents (data.FSW, FileAction.Removed, filename); @@ -269,7 +270,7 @@ void DoFiles (DefaultWatcherData data, string directory, bool dispatch) } catch { /* Deleted */ if (removed == null) - removed = new ArrayList (); + removed = new List (); removed.Add (filename); DispatchEvents (data.FSW, FileAction.Removed, filename); diff --git a/mcs/class/System/System.IO/FileSystemWatcher.cs b/mcs/class/System/System.IO/FileSystemWatcher.cs index 125f07805f9..0d293e53188 100644 --- a/mcs/class/System/System.IO/FileSystemWatcher.cs +++ b/mcs/class/System/System.IO/FileSystemWatcher.cs @@ -183,7 +183,10 @@ internal string MangledFilter { 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; } @@ -372,52 +375,60 @@ enum EventType { 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) diff --git a/mcs/class/System/System.IO/KeventWatcher.cs b/mcs/class/System/System.IO/KeventWatcher.cs index e673f99739b..f3cc7dcc183 100644 --- a/mcs/class/System/System.IO/KeventWatcher.cs +++ b/mcs/class/System/System.IO/KeventWatcher.cs @@ -3,6 +3,8 @@ // // Authors: // Geoff Norton (gnorton@customerdna.com) +// Cody Russell (cody@xamarin.com) +// Alexis Christoforides (lexas@xamarin.com) // // (c) 2004 Geoff Norton // Copyright 2014 Xamarin Inc @@ -29,11 +31,13 @@ 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 { @@ -71,6 +75,7 @@ enum EventFilter : short { VM = -11 } + [Flags] enum FilterFlags : uint { ReadPoll = EventFlags.Flag0, ReadOutOfBand = EventFlags.Flag1, @@ -123,13 +128,14 @@ enum FilterFlags : uint { 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 () @@ -137,307 +143,405 @@ 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 (); - 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 FdList) { - close(data.ev.ident); + if (FdList.Count == 0) + return emptyEventList; + + var changes = new List (); + 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 (); + List removeQueue = new List (); + List rescanQueue = new List (); + + 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 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 (); - 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 (); + 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 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 (); + 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); @@ -445,17 +549,120 @@ private void PostEvent (string filename, FileSystemWatcher fsw, FileAction fa, F } } + 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 pathsDict = new Dictionary (); + readonly Dictionary fdsDict = new Dictionary (); + 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; // + + 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 (); } } diff --git a/mcs/class/System/System.IO/SearchPattern.cs b/mcs/class/System/System.IO/SearchPattern.cs index 0fbab4e5e7e..f302dffaaa0 100644 --- a/mcs/class/System/System.IO/SearchPattern.cs +++ b/mcs/class/System/System.IO/SearchPattern.cs @@ -47,7 +47,7 @@ public SearchPattern2 (string pattern, bool ignore) 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) { @@ -55,20 +55,17 @@ 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) diff --git a/mcs/class/System/System.Media/AudioDevice.cs b/mcs/class/System/System.Media/AudioDevice.cs index 628c04d8edd..a1d0896dba6 100644 --- a/mcs/class/System/System.Media/AudioDevice.cs +++ b/mcs/class/System/System.Media/AudioDevice.cs @@ -200,6 +200,8 @@ protected virtual void Dispose (bool disposing) { 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; } @@ -278,10 +280,14 @@ public override bool SetFormat (AudioFormat format, int channels, int rate) { 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; } diff --git a/mcs/class/System/System.Net.Sockets/SocketAsyncEventArgs.cs b/mcs/class/System/System.Net.Sockets/SocketAsyncEventArgs.cs index a7eeb67d883..c7f6259172d 100644 --- a/mcs/class/System/System.Net.Sockets/SocketAsyncEventArgs.cs +++ b/mcs/class/System/System.Net.Sockets/SocketAsyncEventArgs.cs @@ -260,6 +260,8 @@ void ConnectCallback (IAsyncResult ares) curSocket.EndConnect (ares); } catch (SocketException se) { SocketError = se.SocketErrorCode; + } catch (ObjectDisposedException) { + SocketError = SocketError.OperationAborted; } finally { OnCompleted (this); } diff --git a/mcs/class/System/System.Net.Sockets/Socket_2_1.cs b/mcs/class/System/System.Net.Sockets/Socket_2_1.cs index b0295bef71b..b44a0611592 100644 --- a/mcs/class/System/System.Net.Sockets/Socket_2_1.cs +++ b/mcs/class/System/System.Net.Sockets/Socket_2_1.cs @@ -952,6 +952,14 @@ public Socket(AddressFamily addressFamily, SocketType socketType, ProtocolType p #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); diff --git a/mcs/class/System/System.Net.WebSockets/ClientWebSocket.cs b/mcs/class/System/System.Net.WebSockets/ClientWebSocket.cs index add2c20075c..ff011d2f930 100644 --- a/mcs/class/System/System.Net.WebSockets/ClientWebSocket.cs +++ b/mcs/class/System/System.Net.WebSockets/ClientWebSocket.cs @@ -61,6 +61,7 @@ public class ClientWebSocket : WebSocket, IDisposable const int HeaderMaxLength = 14; byte[] headerBuffer; byte[] sendBuffer; + long remaining; public ClientWebSocket () { @@ -226,32 +227,43 @@ public override Task ReceiveAsync (ArraySegment bu ValidateArraySegment (buffer); return Task.Run (() => { EnsureWebSocketState (WebSocketState.Open, WebSocketState.CloseSent); - // First read the two first bytes to know what we are doing next - connection.Read (req, headerBuffer, 0, 2); - var isLast = (headerBuffer[0] >> 7) > 0; - var isMasked = (headerBuffer[1] >> 7) > 0; - int mask = 0; - var type = WireToMessageType ((byte)(headerBuffer[0] & 0xF)); - long length = headerBuffer[1] & 0x7F; - int offset = 0; - if (length == 126) { - offset = 2; - connection.Read (req, headerBuffer, 2, offset); + + bool isLast; + WebSocketMessageType type; + long length; + + if (remaining == 0) { + // First read the two first bytes to know what we are doing next + connection.Read (req, headerBuffer, 0, 2); + isLast = (headerBuffer[0] >> 7) > 0; + var isMasked = (headerBuffer[1] >> 7) > 0; + int mask = 0; + type = WireToMessageType ((byte)(headerBuffer[0] & 0xF)); + length = headerBuffer[1] & 0x7F; + int offset = 0; + if (length == 126) { + offset = 2; + connection.Read (req, headerBuffer, 2, offset); length = (headerBuffer[2] << 8) | headerBuffer[3]; - } else if (length == 127) { - offset = 8; - connection.Read (req, headerBuffer, 2, offset); - length = 0; - for (int i = 2; i <= 9; i++) - length = (length << 8) | headerBuffer[i]; - } + } else if (length == 127) { + offset = 8; + connection.Read (req, headerBuffer, 2, offset); + length = 0; + for (int i = 2; i <= 9; i++) + length = (length << 8) | headerBuffer[i]; + } - if (isMasked) { - connection.Read (req, headerBuffer, 2 + offset, 4); - for (int i = 0; i < 4; i++) { - var pos = i + offset + 2; - mask = (mask << 8) | headerBuffer[pos]; + if (isMasked) { + connection.Read (req, headerBuffer, 2 + offset, 4); + for (int i = 0; i < 4; i++) { + var pos = i + offset + 2; + mask = (mask << 8) | headerBuffer[pos]; + } } + } else { + isLast = (headerBuffer[0] >> 7) > 0; + type = WireToMessageType ((byte)(headerBuffer[0] & 0xF)); + length = remaining; } if (type == WebSocketMessageType.Close) { @@ -264,8 +276,9 @@ public override Task ReceiveAsync (ArraySegment bu } else { var readLength = (int)(buffer.Count < length ? buffer.Count : length); connection.Read (req, buffer.Array, buffer.Offset, readLength); + remaining = length - readLength; - return new WebSocketReceiveResult ((int)length, type, isLast); + return new WebSocketReceiveResult ((int)readLength, type, isLast && remaining == 0); } }); } diff --git a/mcs/class/System/System.Net/HttpListenerRequest.cs b/mcs/class/System/System.Net/HttpListenerRequest.cs index 23a17199bf9..d1133f9c342 100644 --- a/mcs/class/System/System.Net/HttpListenerRequest.cs +++ b/mcs/class/System/System.Net/HttpListenerRequest.cs @@ -329,6 +329,9 @@ internal bool FlushInput () return false; if (InputStream.EndRead (ares) <= 0) return true; + } catch (ObjectDisposedException e) { + input_stream = null; + return true; } catch { return false; } diff --git a/mcs/class/System/System.Net/MacProxy.cs b/mcs/class/System/System.Net/MacProxy.cs index 45740306db5..0b5d6a76e4b 100644 --- a/mcs/class/System/System.Net/MacProxy.cs +++ b/mcs/class/System/System.Net/MacProxy.cs @@ -225,6 +225,14 @@ public CFRange (int loc, int len) } } + internal struct CFStreamClientContext { + public IntPtr Version; + public IntPtr Info; + public IntPtr Retain; + public IntPtr Release; + public IntPtr CopyDescription; + } + internal class CFString : CFObject { string str; @@ -361,6 +369,52 @@ public static CFUrl Create (string absolute) } } + internal class CFRunLoop : CFObject + { + [DllImport (CFObject.CoreFoundationLibrary)] + static extern void CFRunLoopAddSource (IntPtr rl, IntPtr source, IntPtr mode); + + [DllImport (CFObject.CoreFoundationLibrary)] + static extern void CFRunLoopRemoveSource (IntPtr rl, IntPtr source, IntPtr mode); + + [DllImport (CFObject.CoreFoundationLibrary)] + static extern int CFRunLoopRunInMode (IntPtr mode, double seconds, bool returnAfterSourceHandled); + + [DllImport (CFObject.CoreFoundationLibrary)] + static extern IntPtr CFRunLoopGetCurrent (); + + [DllImport (CFObject.CoreFoundationLibrary)] + static extern void CFRunLoopStop (IntPtr rl); + + public CFRunLoop (IntPtr handle, bool own): base (handle, own) + { + } + + public static CFRunLoop CurrentRunLoop { + get { return new CFRunLoop (CFRunLoopGetCurrent (), false); } + } + + public void AddSource (IntPtr source, CFString mode) + { + CFRunLoopAddSource (Handle, source, mode.Handle); + } + + public void RemoveSource (IntPtr source, CFString mode) + { + CFRunLoopRemoveSource (Handle, source, mode.Handle); + } + + public int RunInMode (CFString mode, double seconds, bool returnAfterSourceHandled) + { + return CFRunLoopRunInMode (mode.Handle, seconds, returnAfterSourceHandled); + } + + public void Stop () + { + CFRunLoopStop (Handle); + } + } + internal enum CFProxyType { None, AutoConfigurationUrl, @@ -615,6 +669,10 @@ internal static class CFNetwork { // CFArrayRef CFNetworkCopyProxiesForAutoConfigurationScript (CFStringRef proxyAutoConfigurationScript, CFURLRef targetURL, CFErrorRef* error); extern static IntPtr CFNetworkCopyProxiesForAutoConfigurationScriptSequential (IntPtr proxyAutoConfigurationScript, IntPtr targetURL, out IntPtr error); + [DllImport (CFNetworkLibrary)] + extern static IntPtr CFNetworkExecuteProxyAutoConfigurationURL (IntPtr proxyAutoConfigURL, IntPtr targetURL, CFProxyAutoConfigurationResultCallback cb, ref CFStreamClientContext clientContext); + + class GetProxyData : IDisposable { public IntPtr script; public IntPtr targetUri; @@ -737,6 +795,45 @@ public static CFProxy[] GetProxiesForAutoConfigurationScript (IntPtr proxyAutoCo return proxies; } + + delegate void CFProxyAutoConfigurationResultCallback (IntPtr client, IntPtr proxyList, IntPtr error); + + public static CFProxy[] ExecuteProxyAutoConfigurationURL (IntPtr proxyAutoConfigURL, Uri targetURL) + { + CFUrl url = CFUrl.Create (targetURL.AbsoluteUri); + if (url == null) + return null; + + CFProxy[] proxies = null; + + var runLoop = CFRunLoop.CurrentRunLoop; + + // Callback that will be called after executing the configuration script + CFProxyAutoConfigurationResultCallback cb = delegate (IntPtr client, IntPtr proxyList, IntPtr error) { + if (proxyList != IntPtr.Zero) { + var array = new CFArray (proxyList, false); + proxies = new CFProxy [array.Count]; + for (int i = 0; i < proxies.Length; i++) { + CFDictionary dict = new CFDictionary (array[i], false); + proxies[i] = new CFProxy (dict); + } + array.Dispose (); + } + runLoop.Stop (); + }; + + var clientContext = new CFStreamClientContext (); + var loopSource = CFNetworkExecuteProxyAutoConfigurationURL (proxyAutoConfigURL, url.Handle, cb, ref clientContext); + + // Create a private mode + var mode = CFString.Create ("Mono.MacProxy"); + + runLoop.AddSource (loopSource, mode); + runLoop.RunInMode (mode, double.MaxValue, false); + runLoop.RemoveSource (loopSource, mode); + + return proxies; + } [DllImport (CFNetworkLibrary)] // CFArrayRef CFNetworkCopyProxiesForURL (CFURLRef url, CFDictionaryRef proxySettings); @@ -859,7 +956,18 @@ static Uri GetProxyUri (CFProxy proxy, out NetworkCredential credentials) static Uri GetProxyUriFromScript (IntPtr script, Uri targetUri, out NetworkCredential credentials) { CFProxy[] proxies = CFNetwork.GetProxiesForAutoConfigurationScript (script, targetUri); - + return SelectProxy (proxies, targetUri, out credentials); + } + + static Uri ExecuteProxyAutoConfigurationURL (IntPtr proxyAutoConfigURL, Uri targetUri, out NetworkCredential credentials) + { + CFProxy[] proxies = CFNetwork.ExecuteProxyAutoConfigurationURL (proxyAutoConfigURL, targetUri); + return SelectProxy (proxies, targetUri, out credentials); + } + + + static Uri SelectProxy (CFProxy[] proxies, Uri targetUri, out NetworkCredential credentials) + { if (proxies == null) { credentials = null; return targetUri; @@ -907,7 +1015,7 @@ public Uri GetProxy (Uri targetUri) proxy = GetProxyUriFromScript (proxies[i].AutoConfigurationJavaScript, targetUri, out credentials); break; case CFProxyType.AutoConfigurationUrl: - // unsupported proxy type (requires fetching script from remote url) + proxy = ExecuteProxyAutoConfigurationURL (proxies[i].AutoConfigurationUrl, targetUri, out credentials); break; case CFProxyType.HTTPS: case CFProxyType.HTTP: diff --git a/mcs/class/System/System.Net/ServicePointManager.cs b/mcs/class/System/System.Net/ServicePointManager.cs index b6095b08904..dc7412d725a 100644 --- a/mcs/class/System/System.Net/ServicePointManager.cs +++ b/mcs/class/System/System.Net/ServicePointManager.cs @@ -369,6 +369,15 @@ public static ServicePoint FindServicePoint (Uri address, IWebProxy proxy) return sp; } + + internal static void CloseConnectionGroup (string connectionGroupName) + { + lock (servicePoints) { + foreach (ServicePoint sp in servicePoints.Values) { + sp.CloseConnectionGroup (connectionGroupName); + } + } + } #if SECURITY_DEP internal class ChainValidationHelper { diff --git a/mcs/class/System/System.Net/WebClient.cs b/mcs/class/System/System.Net/WebClient.cs index ded7767114a..38415f05c5f 100644 --- a/mcs/class/System/System.Net/WebClient.cs +++ b/mcs/class/System/System.Net/WebClient.cs @@ -1972,20 +1972,17 @@ public async Task UploadFileTaskAsync (Uri address, string method, strin if (fileName == null) throw new ArgumentNullException ("fileName"); - WebRequest request = null; try { SetBusy (); cts = new CancellationTokenSource (); - request = await SetupRequestAsync (address, method, true).ConfigureAwait (false); - var result = await UploadFileTaskAsyncCore (request, method, fileName, cts.Token).ConfigureAwait (false); + + var result = await UploadFileTaskAsyncCore (address, method, fileName, cts.Token).ConfigureAwait (false); OnUploadFileCompleted (new UploadFileCompletedEventArgs (result, null, false, null)); return result; } catch (WebException ex) { OnUploadFileCompleted (new UploadFileCompletedEventArgs (null, ex, false, null)); throw; } catch (OperationCanceledException) { - if (request != null) - request.Abort (); OnUploadFileCompleted (new UploadFileCompletedEventArgs (null, null, true, null)); throw; } catch (Exception ex) { @@ -1994,8 +1991,7 @@ public async Task UploadFileTaskAsync (Uri address, string method, strin } } - async Task UploadFileTaskAsyncCore (WebRequest request, string method, - string fileName, CancellationToken token) + async Task UploadFileTaskAsyncCore (Uri address, string method, string fileName, CancellationToken token) { token.ThrowIfCancellationRequested (); @@ -2018,9 +2014,15 @@ async Task UploadFileTaskAsyncCore (WebRequest request, string method, Stream reqStream = null; Stream fStream = null; WebResponse response = null; + WebRequest request = null; fileName = Path.GetFullPath (fileName); + try { + request = await SetupRequestAsync (address, method, true).ConfigureAwait (false); + } catch (OperationCanceledException) { + } + try { fStream = File.OpenRead (fileName); token.ThrowIfCancellationRequested (); @@ -2042,7 +2044,9 @@ async Task UploadFileTaskAsyncCore (WebRequest request, string method, Path.GetFileName (fileName), fileCType); byte [] partHeadersBytes = Encoding.UTF8.GetBytes (partHeaders); ms.Write (partHeadersBytes, 0, partHeadersBytes.Length); - await ms.CopyToAsync (reqStream, (int)ms.Position, token).ConfigureAwait (false); + var msLength = (int)ms.Position; + ms.Seek (0, SeekOrigin.Begin); + await ms.CopyToAsync (reqStream, msLength, token).ConfigureAwait (false); } } int nread; @@ -2084,7 +2088,9 @@ async Task UploadFileTaskAsyncCore (WebRequest request, string method, ms.WriteByte ((byte) '-'); ms.WriteByte ((byte) '\r'); ms.WriteByte ((byte) '\n'); - await ms.CopyToAsync (reqStream, (int)ms.Position, token).ConfigureAwait (false); + var msLength = (int)ms.Position; + ms.Seek (0, SeekOrigin.Begin); + await ms.CopyToAsync (reqStream, msLength, token).ConfigureAwait (false); } } reqStream.Close (); diff --git a/mcs/class/System/System/Uri.cs b/mcs/class/System/System/Uri.cs index 0716b1d6751..fb9c14eead1 100644 --- a/mcs/class/System/System/Uri.cs +++ b/mcs/class/System/System/Uri.cs @@ -235,11 +235,6 @@ public Uri (string uriString, UriKind uriKind) success = false; break; } - - if (success && host.Length > 1 && host [0] != '[' && host [host.Length - 1] != ']') { - // host name present (but not an IPv6 address) - host = host.ToLower (CultureInfo.InvariantCulture); - } } } @@ -1147,6 +1142,9 @@ private void ParseUri (UriKind kind) { Parse (kind, source); + if (userEscaped) + return; + if (host.Length > 1 && host [0] != '[' && host [host.Length - 1] != ']') { // host name present (but not an IPv6 address) host = host.ToLower (CultureInfo.InvariantCulture); @@ -1727,7 +1725,7 @@ protected virtual bool IsReservedCharacter (char character) private UriParser Parser { get { if (parser == null) { - parser = UriParser.GetParser (Scheme); + parser = UriParser.GetParser (scheme); // no specific parser ? then use a default one if (parser == null) parser = new DefaultUriParser ("*"); @@ -1739,6 +1737,9 @@ private UriParser Parser { public string GetComponents (UriComponents components, UriFormat format) { + if ((components & UriComponents.SerializationInfoString) == 0) + EnsureAbsoluteUri (); + return Parser.GetComponents (this, components, format); } diff --git a/mcs/class/System/System/UriParseComponents.cs b/mcs/class/System/System/UriParseComponents.cs index 0de6d8f91ef..dfbd0e75b21 100644 --- a/mcs/class/System/System/UriParseComponents.cs +++ b/mcs/class/System/System/UriParseComponents.cs @@ -269,15 +269,6 @@ private static bool ParseScheme (ParserState state) return state.remaining.Length > 0; } - if (state.elements.scheme == Uri.UriSchemeFile) { - // under Windows all file:// URI are considered UNC, which is not the case other MacOS (e.g. Silverlight) -#if BOOTSTRAP_BASIC - state.elements.isUnc = (Path.DirectorySeparatorChar == '\\'); -#else - state.elements.isUnc = Environment.IsRunningOnWindows; -#endif - } - return ParseDelimiter (state); } @@ -336,7 +327,13 @@ private static bool ParseUser (ParserState state) if (ch == '%'){ if (!Uri.IsHexEncoding (part, index)) return false; + var oldIndex = index; ch = Uri.HexUnescape (part, ref index); + index--; + if (ch == '@') { + sb.Append (part.Substring (oldIndex, index - oldIndex + 1)); + continue; + } } if (Char.IsLetterOrDigit (ch) || IsUnreserved (ch) || IsSubDelim (ch) || ch == ':'){ @@ -424,7 +421,17 @@ private static bool ParseHost (ParserState state) state.elements.host = state.elements.host.ToLowerInvariant (); state.remaining = part.Substring (state.elements.host.Length); - + + if (state.elements.scheme == Uri.UriSchemeFile && + state.elements.host != "") { + // under Windows all file://host URI are considered UNC, which is not the case other MacOS (e.g. Silverlight) +#if BOOTSTRAP_BASIC + state.elements.isUnc = (Path.DirectorySeparatorChar == '\\'); +#else + state.elements.isUnc = Environment.IsRunningOnWindows; +#endif + } + return state.remaining.Length > 0; } diff --git a/mcs/class/System/System/UriParser.cs b/mcs/class/System/System/UriParser.cs index 8abfdc9b359..5eda9aadc17 100644 --- a/mcs/class/System/System/UriParser.cs +++ b/mcs/class/System/System/UriParser.cs @@ -50,6 +50,16 @@ protected internal virtual string GetComponents (Uri uri, UriComponents componen if ((format < UriFormat.UriEscaped) || (format > UriFormat.SafeUnescaped)) throw new ArgumentOutOfRangeException ("format"); + if ((components & UriComponents.SerializationInfoString) != 0) { + if (components != UriComponents.SerializationInfoString) + throw new ArgumentOutOfRangeException ("components", "UriComponents.SerializationInfoString must not be combined with other UriComponents."); + + if (!uri.IsAbsoluteUri) + return UriHelper.FormatRelative (uri.OriginalString, "", format); + + components |= UriComponents.AbsoluteUri; + } + return GetComponentsHelper (uri, components, format); } diff --git a/mcs/class/System/System_test.dll.sources b/mcs/class/System/System_test.dll.sources index e47a4c98214..6ff1a9488a3 100644 --- a/mcs/class/System/System_test.dll.sources +++ b/mcs/class/System/System_test.dll.sources @@ -182,6 +182,7 @@ System.Diagnostics/DelimitedListTraceListenerTest.cs System.Diagnostics/EventLogTest.cs System.Diagnostics/StopwatchTest.cs System.Diagnostics/SourceSwitchTest.cs +System.Diagnostics/TextWriterTraceListenerHelper.cs System.Diagnostics/TextWriterTraceListenerTest.cs System.Diagnostics/TraceSourceTest.cs System.Diagnostics/TraceListenerTest.cs diff --git a/mcs/class/System/Test/System.CodeDom.Compiler/CodeDomProviderCas.cs b/mcs/class/System/Test/System.CodeDom.Compiler/CodeDomProviderCas.cs index 979734af059..a9d536085bb 100644 --- a/mcs/class/System/Test/System.CodeDom.Compiler/CodeDomProviderCas.cs +++ b/mcs/class/System/Test/System.CodeDom.Compiler/CodeDomProviderCas.cs @@ -317,7 +317,7 @@ public void LinkDemand_GetLanguageFromExtension_Deny_Anything () [ExpectedException (typeof (SecurityException))] public void LinkDemand_IsDefinedExtension_Deny_Anything () { - MethodInfo mi = mi = typeof (CodeDomProvider).GetMethod ("IsDefinedExtension"); + MethodInfo mi = typeof (CodeDomProvider).GetMethod ("IsDefinedExtension"); Assert.IsNotNull (mi, "IsDefinedExtension"); Assert.IsFalse ((bool) mi.Invoke (null, new object[1] { String.Empty }), "IsDefinedExtension('')"); // requires full trust (i.e. unrestricted permission set) @@ -328,7 +328,7 @@ public void LinkDemand_IsDefinedExtension_Deny_Anything () [ExpectedException (typeof (SecurityException))] public void LinkDemand_IsDefinedLanguage_Deny_Anything () { - MethodInfo mi = mi = typeof (CodeDomProvider).GetMethod ("IsDefinedLanguage"); + MethodInfo mi = typeof (CodeDomProvider).GetMethod ("IsDefinedLanguage"); Assert.IsNotNull (mi, "IsDefinedLanguage"); Assert.IsFalse ((bool) mi.Invoke (null, new object[1] { String.Empty }), "IsDefinedLanguage('')"); // requires full trust (i.e. unrestricted permission set) diff --git a/mcs/class/System/Test/System.Collections.Concurrent/BlockingCollectionTests.cs b/mcs/class/System/Test/System.Collections.Concurrent/BlockingCollectionTests.cs index 9f0e9b0190d..bf41aeee21a 100644 --- a/mcs/class/System/Test/System.Collections.Concurrent/BlockingCollectionTests.cs +++ b/mcs/class/System/Test/System.Collections.Concurrent/BlockingCollectionTests.cs @@ -237,7 +237,7 @@ public void TakeAnyCancellable () t = Task.Factory.StartNew (() => { try { return BlockingCollection.TakeFromAny (arr, out res, cts.Token); - } catch (OperationCanceledException WE_GOT_CANCELED) { + } catch (OperationCanceledException) { res = "canceled"; return -10; } @@ -247,6 +247,40 @@ public void TakeAnyCancellable () 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 (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 [colNumber]; + for (var i = 0; i < colNumber; i++) { + cols[i] = new BlockingCollection (elNumber); + } + + var token = new CancellationTokenSource (100); + for (var i = 0; i < colNumber * elNumber; i++) { + BlockingCollection .AddToAny (cols, 1, token.Token); + } + + foreach (var col in cols) { + Assert.AreEqual (elNumber, col.Count); + } + } } } #endif diff --git a/mcs/class/System/Test/System.ComponentModel.Design.Serialization/InstanceDescriptorTest.cs b/mcs/class/System/Test/System.ComponentModel.Design.Serialization/InstanceDescriptorTest.cs index 16d12af943c..dbc4110cb20 100644 --- a/mcs/class/System/Test/System.ComponentModel.Design.Serialization/InstanceDescriptorTest.cs +++ b/mcs/class/System/Test/System.ComponentModel.Design.Serialization/InstanceDescriptorTest.cs @@ -277,7 +277,7 @@ public static string Name { } } - class InstanceField + public class InstanceField { public string Name; } diff --git a/mcs/class/System/Test/System.ComponentModel/CharConverterTest.cs b/mcs/class/System/Test/System.ComponentModel/CharConverterTest.cs index d0b78f97fba..815a9a62554 100644 --- a/mcs/class/System/Test/System.ComponentModel/CharConverterTest.cs +++ b/mcs/class/System/Test/System.ComponentModel/CharConverterTest.cs @@ -20,7 +20,6 @@ namespace MonoTests.System.ComponentModel public class CharConverterTest { private CharConverter converter; - private string pattern; [SetUp] public void SetUp () @@ -28,7 +27,6 @@ public void SetUp () converter = new CharConverter (); DateTimeFormatInfo info = CultureInfo.CurrentCulture.DateTimeFormat; - pattern = info.ShortDatePattern + " " + info.ShortTimePattern; } [Test] diff --git a/mcs/class/System/Test/System.ComponentModel/ContainerTest.cs b/mcs/class/System/Test/System.ComponentModel/ContainerTest.cs index 16a6a4124dc..46706fd348e 100644 --- a/mcs/class/System/Test/System.ComponentModel/ContainerTest.cs +++ b/mcs/class/System/Test/System.ComponentModel/ContainerTest.cs @@ -733,10 +733,6 @@ public Container CreateContainer () container.Add (this); return container; } - - public Container Container { - get { return container; } - } } class MyContainer : IContainer diff --git a/mcs/class/System/Test/System.Diagnostics/DiagnosticsConfigurationHandlerTest.cs b/mcs/class/System/Test/System.Diagnostics/DiagnosticsConfigurationHandlerTest.cs index 9af93d5a2f8..8c9049470d7 100644 --- a/mcs/class/System/Test/System.Diagnostics/DiagnosticsConfigurationHandlerTest.cs +++ b/mcs/class/System/Test/System.Diagnostics/DiagnosticsConfigurationHandlerTest.cs @@ -159,6 +159,30 @@ public void AssertTag () ValidateExceptions ("#TAT:BadChildren", "{0}", badChildren); } + [Test] + [Category ("NotDotNet")] + public void PerformanceCountersTag () + { + string[] goodAttributes = { + "", + "filemappingsize=\"1048576\"", + "filemappingsize=\"0\"" + }; + ValidateSuccess ("#PCT:Good", "", goodAttributes); + + string[] badAttributes = { + "FileMappingSize=\"1048576\"", + "filemappingsize=\"\"", + "filemappingsize=\"non-int-value\"" + }; + ValidateExceptions ("#PCT:BadAttrs", "", badAttributes); + + string[] badChildren = { + "" + }; + ValidateExceptions ("#PCT:BadChildren", "{0}", badChildren); + } + [Test] [Category ("NotDotNet")] public void TraceTag_Attributes () diff --git a/mcs/class/System/Test/System.Diagnostics/ProcessTest.cs b/mcs/class/System/Test/System.Diagnostics/ProcessTest.cs index 88de1d72a8c..d6ae37eb0f6 100644 --- a/mcs/class/System/Test/System.Diagnostics/ProcessTest.cs +++ b/mcs/class/System/Test/System.Diagnostics/ProcessTest.cs @@ -722,7 +722,7 @@ static bool RunningOnUnix { } } - int bytesRead = -1; + public int bytesRead = -1; #if NET_2_0 // Not technically a 2.0 only test, but I use lambdas, so I need gmcs @@ -836,7 +836,7 @@ public void Handle_ThrowsOnNotStarted () try { var x = p.Handle; Assert.Fail ("Handle should throw for unstated procs, but returned " + x); - } catch (InvalidOperationException ex) { + } catch (InvalidOperationException) { } } } diff --git a/mcs/class/System/Test/System.Diagnostics/SourceSwitchTest.cs b/mcs/class/System/Test/System.Diagnostics/SourceSwitchTest.cs index 05e0a6d1294..820e84d2a89 100644 --- a/mcs/class/System/Test/System.Diagnostics/SourceSwitchTest.cs +++ b/mcs/class/System/Test/System.Diagnostics/SourceSwitchTest.cs @@ -31,6 +31,8 @@ #if !MOBILE +#define TRACE + using NUnit.Framework; using System; using System.Text; @@ -43,11 +45,15 @@ namespace MonoTests.System.Diagnostics [TestFixture] public class SourceSwitchTest { + internal TraceSource traceSource { get; set; } + internal TestTextWriterTraceListener txtTraceListener; + + [Test] public void ConstructorNullName () { SourceSwitch s = new SourceSwitch (null); - Assert.IsNull (s.DisplayName); + Assert.IsEmpty (s.DisplayName); } [Test] @@ -98,6 +104,80 @@ public void ShouldTrace2 () Assert.IsTrue (s.ShouldTrace (TraceEventType.Resume), "#9"); Assert.IsTrue (s.ShouldTrace (TraceEventType.Transfer), "#10"); } + + + [SetUp] + public void InitalizeSourceSwitchTest() + { + // Initializing the TraceSource instance + traceSource = new TraceSource ("LoggingTraceSource"); + traceSource.Listeners.Remove("Default"); + traceSource.Switch = new SourceSwitch ("MySwitch"); + + // Initializing the TraceListener instance + txtTraceListener = new TestTextWriterTraceListener (Console.Out); + traceSource.Listeners.Add (txtTraceListener); + } + + [Test] + public void setSwitchToCritical() + { + traceSource.Switch.Level = SourceLevels.Critical; + LogAllTraceLevels (); + // Switch.Level is Critical so it should log Critical + Assert.AreEqual (1, txtTraceListener.TotalMessageCount); + Assert.AreEqual (1, txtTraceListener.CritialMessageCount); + } + + [Test] + public void setSwitchToError() + { + traceSource.Switch.Level = SourceLevels.Error; + LogAllTraceLevels (); + // Switch.Level is Error so it should log Critical, Error + Assert.AreEqual (2, txtTraceListener.TotalMessageCount); + Assert.AreEqual (1, txtTraceListener.ErrorMessageCount); + } + + [Test] + public void setSwitchToWarning() + { + traceSource.Switch.Level = SourceLevels.Warning; + LogAllTraceLevels (); + // Switch.Level is Warning so it should log Critical, Error, Warning + Assert.AreEqual (3, txtTraceListener.TotalMessageCount); + Assert.AreEqual (1, txtTraceListener.WarningMessageCount); + } + + [Test] + public void setSwitchToInfo() + { + traceSource.Switch.Level = SourceLevels.Information; + LogAllTraceLevels (); + // Switch.Level is Information so it should log Critical, Error, Warning, Information + Assert.AreEqual (4, txtTraceListener.TotalMessageCount); + Assert.AreEqual (1, txtTraceListener.InfoMessageCount); + } + + [Test] + public void setSwitchToVerbose() + { + traceSource.Switch.Level = SourceLevels.Verbose; + LogAllTraceLevels (); + // Switch.Level is Verbose so it should log Critical, Error, Warning, Information, Verbose + Assert.AreEqual (5, txtTraceListener.TotalMessageCount); + Assert.AreEqual (1, txtTraceListener.VerboseMessageCount); + } + + void LogAllTraceLevels () + { + traceSource.TraceEvent (TraceEventType.Critical, 123, "Critical Level message."); + traceSource.TraceEvent (TraceEventType.Error, 123, "Error Level message."); + traceSource.TraceEvent (TraceEventType.Warning, 123, "Warning Level message."); + traceSource.TraceEvent (TraceEventType.Information, 123, "Information Level message."); + traceSource.TraceEvent (TraceEventType.Verbose, 123, "Verbose Level message."); + traceSource.Flush (); + } } } diff --git a/mcs/class/System/Test/System.Diagnostics/SwitchesTest.cs b/mcs/class/System/Test/System.Diagnostics/SwitchesTest.cs index c21a1ca5248..4c52cb109af 100644 --- a/mcs/class/System/Test/System.Diagnostics/SwitchesTest.cs +++ b/mcs/class/System/Test/System.Diagnostics/SwitchesTest.cs @@ -80,6 +80,12 @@ protected override void OnSwitchSettingChanged () } } + class TestNullSwitch : Switch { + public TestNullSwitch () : base (null, null) + { + } + } + [TestFixture] public class SwitchesTest { @@ -184,8 +190,16 @@ public void BooleanSwitchInvalidDefaultValue () BooleanSwitch s = new BooleanSwitch ("test", "", "hoge"); Assert.IsTrue (!s.Enabled); } + + [Test] + public void NullSwitchHasEmptyDisplayNameAndDescription () + { + var s = new TestNullSwitch (); + Assert.IsEmpty (s.DisplayName); + Assert.IsEmpty (s.Description); + } #endif } } -#endif \ No newline at end of file +#endif diff --git a/mcs/class/System/Test/System.Diagnostics/TextWriterTraceListenerHelper.cs b/mcs/class/System/Test/System.Diagnostics/TextWriterTraceListenerHelper.cs new file mode 100644 index 00000000000..248e2ee0814 --- /dev/null +++ b/mcs/class/System/Test/System.Diagnostics/TextWriterTraceListenerHelper.cs @@ -0,0 +1,88 @@ +// TextWriterTraceListenerHelper.cs - +// Test Helper for System.Diagnostics/SourceSwitchTest.cs + +// +// Author: +// Ramtin Raji Kermani +// +// Copyright (C) 2006 Novell, Inc (http://www.novell.com) +// +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +#if !MOBILE + +using System; +using System.IO; +using System.Diagnostics; + +namespace MonoTests.System.Diagnostics +{ + public class TestTextWriterTraceListener: TextWriterTraceListener + { + public int TotalMessageCount { set; get;} + public int CritialMessageCount { get; set;} + public int ErrorMessageCount { get; set;} + public int WarningMessageCount { get; set;} + public int InfoMessageCount { get; set;} + public int VerboseMessageCount { set; get;} + + public TestTextWriterTraceListener(TextWriter textWriter): base(textWriter) + { + Console.WriteLine ("TextWriterTraceListener is instantiated."); + } + + + public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id, string message) + { + base.TraceEvent (eventCache, source, eventType, id, message); + TotalMessageCount++; + + switch (eventType) { + case TraceEventType.Critical: + CritialMessageCount++; break; + case TraceEventType.Error: + ErrorMessageCount++; break; + case TraceEventType.Warning: + WarningMessageCount++; break; + case TraceEventType.Information: + InfoMessageCount++; break; + case TraceEventType.Verbose: + VerboseMessageCount++; break; + default: + break; + } + } + + public void clearMessageCounters() + { + TotalMessageCount = 0; + CritialMessageCount = 0; + WarningMessageCount = 0; + ErrorMessageCount = 0; + InfoMessageCount = 0; + VerboseMessageCount = 0; + } + + } +} + +#endif \ No newline at end of file diff --git a/mcs/class/System/Test/System.Net.Sockets/TcpClientCas.cs b/mcs/class/System/Test/System.Net.Sockets/TcpClientCas.cs index 9b2577c41e2..e245fcd5b06 100644 --- a/mcs/class/System/Test/System.Net.Sockets/TcpClientCas.cs +++ b/mcs/class/System/Test/System.Net.Sockets/TcpClientCas.cs @@ -29,7 +29,6 @@ public class TcpClientCas { static ManualResetEvent reset; private string message; - private string uri = "http://www.google.com"; [TestFixtureSetUp] public void FixtureSetUp () diff --git a/mcs/class/System/Test/System.Net.Sockets/UdpClientTest.cs b/mcs/class/System/Test/System.Net.Sockets/UdpClientTest.cs index 9b2453bd6f1..51c3ac795b5 100644 --- a/mcs/class/System/Test/System.Net.Sockets/UdpClientTest.cs +++ b/mcs/class/System/Test/System.Net.Sockets/UdpClientTest.cs @@ -936,7 +936,7 @@ public void CloseInReceive () try { client = new UdpClient (port); break; - } catch (Exception ex) { + } catch (Exception) { if (i == 5) throw; } diff --git a/mcs/class/System/Test/System.Net.WebSockets/ClientWebSocketTest.cs b/mcs/class/System/Test/System.Net.WebSockets/ClientWebSocketTest.cs index 7c89da6ef71..a990f67e658 100644 --- a/mcs/class/System/Test/System.Net.WebSockets/ClientWebSocketTest.cs +++ b/mcs/class/System/Test/System.Net.WebSockets/ClientWebSocketTest.cs @@ -49,7 +49,10 @@ public void Teardown () [Test] public void ServerHandshakeReturnCrapStatusCodeTest () { + // On purpose, + #pragma warning disable 4014 HandleHttpRequestAsync ((req, resp) => resp.StatusCode = 418); + #pragma warning restore 4014 try { Assert.IsTrue (socket.ConnectAsync (new Uri ("ws://localhost:" + Port), CancellationToken.None).Wait (5000)); } catch (AggregateException e) { @@ -62,10 +65,12 @@ public void ServerHandshakeReturnCrapStatusCodeTest () [Test] public void ServerHandshakeReturnWrongUpgradeHeader () { + #pragma warning disable 4014 HandleHttpRequestAsync ((req, resp) => { resp.StatusCode = 101; resp.Headers["Upgrade"] = "gtfo"; }); + #pragma warning restore 4014 try { Assert.IsTrue (socket.ConnectAsync (new Uri ("ws://localhost:" + Port), CancellationToken.None).Wait (5000)); } catch (AggregateException e) { @@ -78,12 +83,14 @@ public void ServerHandshakeReturnWrongUpgradeHeader () [Test] public void ServerHandshakeReturnWrongConnectionHeader () { + #pragma warning disable 4014 HandleHttpRequestAsync ((req, resp) => { resp.StatusCode = 101; resp.Headers["Upgrade"] = "websocket"; // Mono http request doesn't like the forcing, test still valid since the default connection header value is empty //ForceSetHeader (resp.Headers, "Connection", "Foo"); }); + #pragma warning restore 4014 try { Assert.IsTrue (socket.ConnectAsync (new Uri ("ws://localhost:" + Port), CancellationToken.None).Wait (5000)); } catch (AggregateException e) { diff --git a/mcs/class/System/Test/System.Net/DnsCas.cs b/mcs/class/System/Test/System.Net/DnsCas.cs index f362e8291ea..b532428fd53 100644 --- a/mcs/class/System/Test/System.Net/DnsCas.cs +++ b/mcs/class/System/Test/System.Net/DnsCas.cs @@ -30,14 +30,13 @@ public class DnsCas { static ManualResetEvent reset; private string message; private string hostname; - private IPAddress ip; [TestFixtureSetUp] public void FixtureSetUp () { reset = new ManualResetEvent (false); hostname = Dns.GetHostName (); - ip = Dns.Resolve (site).AddressList[0]; + var ip = Dns.Resolve (site).AddressList[0]; } [TestFixtureTearDown] diff --git a/mcs/class/System/Test/System.Net/HttpListenerTest.cs b/mcs/class/System/Test/System.Net/HttpListenerTest.cs index 25f7b96a9b9..5c1591169ed 100644 --- a/mcs/class/System/Test/System.Net/HttpListenerTest.cs +++ b/mcs/class/System/Test/System.Net/HttpListenerTest.cs @@ -36,6 +36,14 @@ namespace MonoTests.System.Net { [TestFixture] public class HttpListenerTest { + + int port; + + [SetUp] + public void SetUp () { + port = new Random ().Next (7777, 8000); + } + [Test] public void DefaultProperties () { @@ -115,7 +123,7 @@ private bool CanOpenPort(int port) socket.Listen(1); } } - catch(Exception ex) { + catch(Exception) { //Can be AccessDeniedException(ports 80/443 need root access) or //SocketException because other application is listening return false; @@ -152,10 +160,12 @@ public void DefaultHttpsPort () [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 (); } @@ -164,10 +174,12 @@ public void TwoListeners_SameAddress () [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 (); } @@ -176,8 +188,10 @@ public void TwoListeners_SameURL () [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 (); } @@ -186,8 +200,10 @@ public void MultipleSlashes () [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 (); } @@ -202,8 +218,10 @@ public void CloseBeforeStart () [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 (); @@ -212,8 +230,10 @@ public void CloseTwice () [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 (); @@ -223,8 +243,10 @@ public void StartStopStart () [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 (); } @@ -240,8 +262,10 @@ public void AbortBeforeStart () [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 (); @@ -450,6 +474,57 @@ public void Dispose () Event.Close (); } } + + [Test] + public void ConnectionReuse () + { + var uri = "http://localhost:1338/"; + + HttpListener listener = new HttpListener (); + listener.Prefixes.Add (uri); + listener.Start (); + + IPEndPoint expectedIpEndPoint = CreateListenerRequest (listener, uri); + + Assert.AreEqual (expectedIpEndPoint, CreateListenerRequest (listener, uri), "reuse1"); + Assert.AreEqual (expectedIpEndPoint, CreateListenerRequest (listener, uri), "reuse2"); + } + + public IPEndPoint CreateListenerRequest (HttpListener listener, string uri) + { + IPEndPoint ipEndPoint = null; + listener.BeginGetContext ((result) => ipEndPoint = ListenerCallback (result), listener); + + var request = (HttpWebRequest) WebRequest.Create (uri); + request.Method = "POST"; + + // We need to write something + request.GetRequestStream ().Write (new byte [] {(byte)'a'}, 0, 1); + request.GetRequestStream ().Dispose (); + + // Send request, socket is created or reused. + var response = request.GetResponse (); + + // Close response so socket can be reused. + response.Close (); + + return ipEndPoint; + } + + public static IPEndPoint ListenerCallback (IAsyncResult result) + { + var listener = (HttpListener) result.AsyncState; + var context = listener.EndGetContext (result); + var clientEndPoint = context.Request.RemoteEndPoint; + + // Disposing InputStream should not avoid socket reuse + context.Request.InputStream.Dispose (); + + // Close OutputStream to send response + context.Response.OutputStream.Close (); + + return clientEndPoint; + } } } #endif diff --git a/mcs/class/System/Test/System.Net/NetworkCredentialTest.cs b/mcs/class/System/Test/System.Net/NetworkCredentialTest.cs index 610b4aca31f..dbe3255cd68 100644 --- a/mcs/class/System/Test/System.Net/NetworkCredentialTest.cs +++ b/mcs/class/System/Test/System.Net/NetworkCredentialTest.cs @@ -31,7 +31,7 @@ using NUnit.Framework; -namespace MoonTest.System.Net { +namespace MonoTests.System.Net { [TestFixture] public class NetworkCredentialTest { diff --git a/mcs/class/System/Test/System.Net/WebClientTest.cs b/mcs/class/System/Test/System.Net/WebClientTest.cs index 48722d45510..ef3f6817425 100644 --- a/mcs/class/System/Test/System.Net/WebClientTest.cs +++ b/mcs/class/System/Test/System.Net/WebClientTest.cs @@ -2221,6 +2221,28 @@ public void UploadFileAsyncCancelEvent () webClient.UploadFileAsync (uri, "PUT", tempFile); }); } + + [Test] + public void UploadFileAsyncContentType () + { + var serverUri = "http://localhost:13370/"; + var filename = Path.GetTempFileName (); + + HttpListener listener = new HttpListener (); + listener.Prefixes.Add (serverUri); + listener.Start (); + + using (var client = new WebClient ()) + { + client.UploadFileTaskAsync (new Uri (serverUri), filename); + var request = listener.GetContext ().Request; + + var expected = "multipart/form-data; boundary=------------"; + Assert.AreEqual (expected.Length + 15, request.ContentType.Length); + Assert.AreEqual (expected, request.ContentType.Substring (0, expected.Length)); + } + listener.Close (); + } #endif #if NET_4_0 diff --git a/mcs/class/System/Test/System.Security.Cryptography.X509Certificates/X500DistinguishedNameTest.cs b/mcs/class/System/Test/System.Security.Cryptography.X509Certificates/X500DistinguishedNameTest.cs index 88bd3b1cddc..799152f5bbd 100644 --- a/mcs/class/System/Test/System.Security.Cryptography.X509Certificates/X500DistinguishedNameTest.cs +++ b/mcs/class/System/Test/System.Security.Cryptography.X509Certificates/X500DistinguishedNameTest.cs @@ -52,6 +52,7 @@ public class X500DistinguishedNameTest { private static byte[] cert_a_issuer_raw = new byte[] { 0x30, 0x5F, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x20, 0x30, 0x1E, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x13, 0x17, 0x52, 0x53, 0x41, 0x20, 0x44, 0x61, 0x74, 0x61, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x2C, 0x20, 0x49, 0x6E, 0x63, 0x2E, 0x31, 0x2E, 0x30, 0x2C, 0x06, 0x03, 0x55, 0x04, 0x0B, 0x13, 0x25, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6F, 0x72, 0x69, 0x74, 0x79 }; +#if false private static byte[] cert_b = { 0x30,0x82,0x03,0x04,0x30,0x82,0x02,0xC4,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x03,0x30,0x09,0x06,0x07,0x2A,0x86,0x48,0xCE,0x38,0x04,0x03,0x30,0x51,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x18,0x30,0x16,0x06,0x03,0x55,0x04,0x0A,0x13,0x0F,0x55,0x2E,0x53,0x2E,0x20,0x47,0x6F,0x76,0x65,0x72,0x6E,0x6D,0x65,0x6E,0x74,0x31,0x0C,0x30,0x0A,0x06,0x03,0x55,0x04,0x0B,0x13,0x03,0x44,0x6F,0x44,0x31,0x1A,0x30,0x18,0x06,0x03,0x55,0x04,0x03,0x13,0x11,0x41,0x72,0x6D,0x65,0x64,0x20,0x46,0x6F, 0x72,0x63,0x65,0x73,0x20,0x52,0x6F,0x6F,0x74,0x30,0x1E,0x17,0x0D,0x30,0x30,0x31,0x30,0x32,0x35,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x30,0x33,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x30,0x51,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x18,0x30,0x16,0x06,0x03,0x55,0x04,0x0A,0x13,0x0F,0x55,0x2E,0x53,0x2E,0x20,0x47,0x6F,0x76,0x65,0x72,0x6E,0x6D,0x65,0x6E,0x74,0x31,0x0C,0x30,0x0A,0x06,0x03,0x55,0x04,0x0B,0x13,0x03,0x44,0x6F,0x44,0x31,0x1A,0x30,0x18, 0x06,0x03,0x55,0x04,0x03,0x13,0x11,0x41,0x72,0x6D,0x65,0x64,0x20,0x46,0x6F,0x72,0x63,0x65,0x73,0x20,0x52,0x6F,0x6F,0x74,0x30,0x82,0x01,0xB6,0x30,0x82,0x01,0x2B,0x06,0x07,0x2A,0x86,0x48,0xCE,0x38,0x04,0x01,0x30,0x82,0x01,0x1E,0x02,0x81,0x81,0x00,0x90,0x89,0x3E,0x18,0x1B,0xFE,0xA3,0x1D,0x16,0x89,0x00,0xB4,0xD5,0x40,0x82,0x4C,0x2E,0xEC,0x3D,0x66,0x0D,0x0D,0xB9,0x17,0x40,0x6E,0x3A,0x5C,0x03,0x7B,0x1B,0x93,0x28,0x0C,0xEF,0xB9,0x97,0xE3,0xA1,0xEB,0xE2,0xA3,0x7C,0x61,0xDD,0x6F,0xD5,0xAD,0x15,0x69,0x00, @@ -60,6 +61,7 @@ public class X500DistinguishedNameTest { 0x54,0x4B,0xC0,0xA8,0x40,0xEF,0x71,0xE8,0x56,0x6B,0xA2,0x29,0xCB,0x1E,0x09,0x7D,0x27,0x39,0x91,0x3B,0x20,0x4F,0x98,0x39,0xE8,0x39,0xCA,0x98,0xC5,0xAF,0x54,0x03,0x81,0x84,0x00,0x02,0x81,0x80,0x54,0xA8,0x88,0xB5,0x8F,0x01,0x56,0xCE,0x18,0x8F,0xA6,0xD6,0x7C,0x29,0x29,0x75,0x45,0xE8,0x31,0xA4,0x07,0x17,0xED,0x1E,0x5D,0xB2,0x7B,0xBB,0xCE,0x3C,0x97,0x67,0x1E,0x88,0x0A,0xFE,0x7D,0x00,0x22,0x27,0x1D,0x66,0xEE,0xF6,0x1B,0xB6,0x95,0x7F,0x5A,0xFF,0x06,0x34,0x02,0x43,0xC3,0x83,0xC4,0x66,0x2C,0xA1,0x05,0x0E, 0x68,0xB3,0xCA,0xDC,0xD3,0xF9,0x0C,0xC0,0x66,0xDF,0x85,0x84,0x4B,0x20,0x5D,0x41,0xAC,0xC0,0xEC,0x37,0x92,0x0E,0x97,0x19,0xBF,0x53,0x35,0x63,0x27,0x18,0x33,0x35,0x42,0x4D,0xF0,0x2D,0x6D,0xA7,0xA4,0x98,0xAA,0x57,0xF3,0xD2,0xB8,0x6E,0x4E,0x8F,0xFF,0xBE,0x6F,0x4E,0x0F,0x0B,0x44,0x24,0xEE,0xDF,0x4C,0x22,0x5B,0x44,0x98,0x94,0xCB,0xB8,0xA3,0x2F,0x30,0x2D,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x9D,0x2D,0x73,0xC3,0xB8,0xE3,0x4D,0x29,0x28,0xC3,0x65,0xBE,0xA9,0x98,0xCB,0xD6,0x8A,0x06,0x68, 0x9C,0x30,0x0C,0x06,0x03,0x55,0x1D,0x13,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x09,0x06,0x07,0x2A,0x86,0x48,0xCE,0x38,0x04,0x03,0x03,0x2F,0x00,0x30,0x2C,0x02,0x14,0x5A,0x1B,0x2D,0x08,0x0E,0xE6,0x99,0x38,0x8F,0xB5,0x09,0xC9,0x89,0x79,0x7E,0x01,0x30,0xBD,0xCE,0xF0,0x02,0x14,0x71,0x7B,0x08,0x51,0x97,0xCE,0x4D,0x1F,0x6A,0x84,0x47,0x3A,0xC0,0xBD,0x13,0x89,0x81,0xB9,0x01,0x97 }; +#endif static public byte[] RFC3280MandatoryAttributeTypesCACert_crt = { 0x30, 0x82, 0x02, 0xC1, 0x30, 0x82, 0x02, 0x2A, 0xA0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x60, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x40, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x1A, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x13, 0x11, 0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0C, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x41, 0x6E, 0x63, 0x68, 0x6F, 0x72, 0x30, 0x1E, 0x17, 0x0D, 0x30, 0x31, 0x30, 0x34, 0x31, 0x39, 0x31, 0x34, 0x35, 0x37, 0x32, 0x30, 0x5A, 0x17, 0x0D, 0x31, 0x31, 0x30, 0x34, 0x31, 0x39, 0x31, 0x34, 0x35, 0x37, 0x32, 0x30, 0x5A, 0x30, 0x81, 0x8E, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x1A, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x13, 0x11, 0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x31, 0x13, 0x30, 0x11, 0x06, 0x0A, 0x09, 0x92, 0x26, 0x89, 0x93, 0xF2, 0x2C, 0x64, 0x01, 0x19, 0x16, 0x03, 0x67, 0x6F, 0x76, 0x31, 0x20, 0x30, 0x1E, 0x06, 0x0A, 0x09, @@ -82,13 +84,13 @@ public class X500DistinguishedNameTest { static public AsnEncodedData emptyData = new AsnEncodedData (new byte[0]); private X509Certificate2 x509a; - private X509Certificate2 x509b; + //private X509Certificate2 x509b; [TestFixtureSetUp] public void FixtureSetUp () { x509a = new X509Certificate2 (cert_a); - x509b = new X509Certificate2 (cert_b); + //x509b = new X509Certificate2 (cert_b); } private void Empty (X500DistinguishedName dn) diff --git a/mcs/class/System/Test/System.Security.Cryptography.X509Certificates/X509ChainTest.cs b/mcs/class/System/Test/System.Security.Cryptography.X509Certificates/X509ChainTest.cs index 9439f666cc8..0ef6418bc14 100644 --- a/mcs/class/System/Test/System.Security.Cryptography.X509Certificates/X509ChainTest.cs +++ b/mcs/class/System/Test/System.Security.Cryptography.X509Certificates/X509ChainTest.cs @@ -41,7 +41,7 @@ namespace MonoTests.System.Security.Cryptography.X509Certificates { [TestFixture] public class X509ChainTest { - private X509Certificate2Collection empty; + //private X509Certificate2Collection empty; private X509Certificate2Collection collection; private X509Certificate2 cert_empty; @@ -56,7 +56,7 @@ public void FixtureSetUp () cert1 = new X509Certificate2 (X509Certificate2Test.farscape_pfx, "farscape", X509KeyStorageFlags.Exportable); cert2 = new X509Certificate2 (Encoding.ASCII.GetBytes (X509Certificate2Test.base64_cert)); - empty = new X509Certificate2Collection (); + //empty = new X509Certificate2Collection (); collection = new X509Certificate2Collection (); collection.Add (cert1); collection.Add (cert2); diff --git a/mcs/class/System/Test/System.Text.RegularExpressions/RegexReplaceTests.cs b/mcs/class/System/Test/System.Text.RegularExpressions/RegexReplaceTests.cs index 5d30f5d7ed0..55dd1e6d05d 100644 --- a/mcs/class/System/Test/System.Text.RegularExpressions/RegexReplaceTests.cs +++ b/mcs/class/System/Test/System.Text.RegularExpressions/RegexReplaceTests.cs @@ -22,7 +22,7 @@ public void Execute () { try { result = Regex.Replace (original, pattern, replacement); } - catch (Exception e) { + catch (Exception) { result = "Error."; } Assert.AreEqual (expected, result, "rr#: {0} ~ s,{1},{2},", diff --git a/mcs/class/System/Test/System.Text.RegularExpressions/RegexResultTests.cs b/mcs/class/System/Test/System.Text.RegularExpressions/RegexResultTests.cs index 1cf18ee74da..4129b75a125 100644 --- a/mcs/class/System/Test/System.Text.RegularExpressions/RegexResultTests.cs +++ b/mcs/class/System/Test/System.Text.RegularExpressions/RegexResultTests.cs @@ -24,7 +24,7 @@ public void Execute () { Match match = Regex.Match (original, pattern); result = match.Result (replacement); } - catch (Exception e) { + catch (Exception) { result = "Error."; } Assert.AreEqual (expected, result, "rr#: {0} ~ s,{1},{2},", diff --git a/mcs/class/System/Test/System/UriParserTest.cs b/mcs/class/System/Test/System/UriParserTest.cs index 79111f90fc4..0373ef20c4c 100644 --- a/mcs/class/System/Test/System/UriParserTest.cs +++ b/mcs/class/System/Test/System/UriParserTest.cs @@ -217,28 +217,28 @@ public void GetComponents_Ftp () public void GetComponents_Ftp2 () { UnitTestUriParser p = new UnitTestUriParser (); - Assert.AreEqual ("ftp", p._GetComponents (ftp, UriComponents.Scheme, UriFormat.Unescaped), "ftp.Scheme"); - Assert.AreEqual ("username:password", p._GetComponents (ftp, UriComponents.UserInfo, UriFormat.Unescaped), "ftp.UserInfo"); - Assert.AreEqual ("ftp.go-mono.com", p._GetComponents (ftp, UriComponents.Host, UriFormat.Unescaped), "ftp.Host"); - Assert.AreEqual (String.Empty, p._GetComponents (ftp, UriComponents.Port, UriFormat.Unescaped), "ftp.Port"); - Assert.AreEqual ("with some spaces/mono.tgz", p._GetComponents (ftp, UriComponents.Path, UriFormat.Unescaped), "ftp.Path"); - Assert.AreEqual ("with%20some%20spaces/mono.tgz", p._GetComponents (ftp, UriComponents.Path, UriFormat.UriEscaped), "ftp.Path-UriEscaped"); - Assert.AreEqual ("with some spaces/mono.tgz", p._GetComponents (ftp, UriComponents.Path, UriFormat.SafeUnescaped), "ftp.Path-SafeUnescaped"); - Assert.AreEqual (String.Empty, p._GetComponents (ftp, UriComponents.Query, UriFormat.Unescaped), "ftp.Query"); - Assert.AreEqual (String.Empty, p._GetComponents (ftp, UriComponents.Fragment, UriFormat.Unescaped), "ftp.Fragment"); - Assert.AreEqual ("21", p._GetComponents (ftp, UriComponents.StrongPort, UriFormat.Unescaped), "ftp.StrongPort"); - Assert.AreEqual (String.Empty, p._GetComponents (ftp, UriComponents.KeepDelimiter, UriFormat.Unescaped), "http.KeepDelimiter"); - Assert.AreEqual ("ftp.go-mono.com:21", p._GetComponents (ftp, UriComponents.HostAndPort, UriFormat.Unescaped), "http.HostAndPort"); - Assert.AreEqual ("username:password@ftp.go-mono.com:21", p._GetComponents (ftp, UriComponents.StrongAuthority, UriFormat.Unescaped), "http.StrongAuthority"); - Assert.AreEqual ("ftp://username:password@ftp.go-mono.com/with some spaces/mono.tgz", p._GetComponents (ftp, UriComponents.AbsoluteUri, UriFormat.Unescaped), "http.AbsoluteUri"); - Assert.AreEqual ("/with some spaces/mono.tgz", p._GetComponents (ftp, UriComponents.PathAndQuery, UriFormat.Unescaped), "http.PathAndQuery"); - Assert.AreEqual ("ftp://ftp.go-mono.com/with some spaces/mono.tgz", p._GetComponents (ftp, UriComponents.HttpRequestUrl, UriFormat.Unescaped), "http.HttpRequestUrl"); - Assert.AreEqual ("ftp://ftp.go-mono.com", p._GetComponents (ftp, UriComponents.SchemeAndServer, UriFormat.Unescaped), "http.SchemeAndServer"); - Assert.AreEqual ("ftp://username:password@ftp.go-mono.com/with some spaces/mono.tgz", p._GetComponents (ftp, UriComponents.SerializationInfoString, UriFormat.Unescaped), "http.SerializationInfoString"); + Assert.AreEqual ("ftp", p._GetComponents (ftp2, UriComponents.Scheme, UriFormat.Unescaped), "ftp.Scheme"); + Assert.AreEqual ("username:password", p._GetComponents (ftp2, UriComponents.UserInfo, UriFormat.Unescaped), "ftp.UserInfo"); + Assert.AreEqual ("ftp.go-mono.com", p._GetComponents (ftp2, UriComponents.Host, UriFormat.Unescaped), "ftp.Host"); + Assert.AreEqual (String.Empty, p._GetComponents (ftp2, UriComponents.Port, UriFormat.Unescaped), "ftp.Port"); + Assert.AreEqual ("with some spaces/mono.tgz", p._GetComponents (ftp2, UriComponents.Path, UriFormat.Unescaped), "ftp.Path"); + Assert.AreEqual ("with%20some%20spaces/mono.tgz", p._GetComponents (ftp2, UriComponents.Path, UriFormat.UriEscaped), "ftp.Path-UriEscaped"); + Assert.AreEqual ("with some spaces/mono.tgz", p._GetComponents (ftp2, UriComponents.Path, UriFormat.SafeUnescaped), "ftp.Path-SafeUnescaped"); + Assert.AreEqual (String.Empty, p._GetComponents (ftp2, UriComponents.Query, UriFormat.Unescaped), "ftp.Query"); + Assert.AreEqual (String.Empty, p._GetComponents (ftp2, UriComponents.Fragment, UriFormat.Unescaped), "ftp.Fragment"); + Assert.AreEqual ("21", p._GetComponents (ftp2, UriComponents.StrongPort, UriFormat.Unescaped), "ftp.StrongPort"); + Assert.AreEqual (String.Empty, p._GetComponents (ftp2, UriComponents.KeepDelimiter, UriFormat.Unescaped), "http.KeepDelimiter"); + Assert.AreEqual ("ftp.go-mono.com:21", p._GetComponents (ftp2, UriComponents.HostAndPort, UriFormat.Unescaped), "http.HostAndPort"); + Assert.AreEqual ("username:password@ftp.go-mono.com:21", p._GetComponents (ftp2, UriComponents.StrongAuthority, UriFormat.Unescaped), "http.StrongAuthority"); + Assert.AreEqual ("ftp://username:password@ftp.go-mono.com/with some spaces/mono.tgz", p._GetComponents (ftp2, UriComponents.AbsoluteUri, UriFormat.Unescaped), "http.AbsoluteUri"); + Assert.AreEqual ("/with some spaces/mono.tgz", p._GetComponents (ftp2, UriComponents.PathAndQuery, UriFormat.Unescaped), "http.PathAndQuery"); + Assert.AreEqual ("ftp://ftp.go-mono.com/with some spaces/mono.tgz", p._GetComponents (ftp2, UriComponents.HttpRequestUrl, UriFormat.Unescaped), "http.HttpRequestUrl"); + Assert.AreEqual ("ftp://ftp.go-mono.com", p._GetComponents (ftp2, UriComponents.SchemeAndServer, UriFormat.Unescaped), "http.SchemeAndServer"); + Assert.AreEqual ("ftp://username:password@ftp.go-mono.com/with some spaces/mono.tgz", p._GetComponents (ftp2, UriComponents.SerializationInfoString, UriFormat.Unescaped), "http.SerializationInfoString"); Assert.AreSame (p, p._OnNewUri (), "OnNewUri"); // strange mixup - Assert.AreEqual ("ftp://username:password@", p._GetComponents (ftp, UriComponents.Scheme | UriComponents.UserInfo, UriFormat.Unescaped), "ftp.Scheme+UserInfo"); - Assert.AreEqual (":21/with some spaces/mono.tgz", p._GetComponents (ftp, UriComponents.Path | UriComponents.StrongPort, UriFormat.Unescaped), "ftp.Path+StrongPort"); + Assert.AreEqual ("ftp://username:password@", p._GetComponents (ftp2, UriComponents.Scheme | UriComponents.UserInfo, UriFormat.Unescaped), "ftp.Scheme+UserInfo"); + Assert.AreEqual (":21/with some spaces/mono.tgz", p._GetComponents (ftp2, UriComponents.Path | UriComponents.StrongPort, UriFormat.Unescaped), "ftp.Path+StrongPort"); } // Test case for Xamarin#17665 diff --git a/mcs/class/System/Test/System/UriTest.cs b/mcs/class/System/Test/System/UriTest.cs index f0a67b7a7cd..fa76c2a67d4 100644 --- a/mcs/class/System/Test/System/UriTest.cs +++ b/mcs/class/System/Test/System/UriTest.cs @@ -1951,6 +1951,38 @@ public void LocalPathWithBaseUrl () Assert.IsTrue (Uri.TryCreate (mainUri, uriPath, out result), "#1"); Assert.AreEqual ("http://www.imdb.com/title/tt0106521", result.ToString (), "#2"); } + + [Test] + public void GetSerializationInfoStringOnRelativeUri () + { + var uri = new Uri ("/relative/path", UriKind.Relative); + var result = uri.GetComponents (UriComponents.SerializationInfoString, UriFormat.UriEscaped); + + Assert.AreEqual (uri.OriginalString, result); + } + + [Test] + [ExpectedException (typeof (ArgumentOutOfRangeException))] + public void GetSerializationInfoStringException () + { + var uri = new Uri ("/relative/path", UriKind.Relative); + uri.GetComponents (UriComponents.SerializationInfoString | UriComponents.Host, UriFormat.UriEscaped); + } + + [Test] + public void UserInfo_EscapedLetter () + { + var uri = new Uri ("https://first%61second@host"); + Assert.AreEqual ("firstasecond", uri.UserInfo); + } + + [Test] + public void UserInfo_EscapedAt () + { + var userinfo = "first%40second"; + var uri = new Uri ("https://" + userinfo + "@host"); + Assert.AreEqual (userinfo, uri.UserInfo); + } } // Tests non default IriParsing @@ -1961,7 +1993,7 @@ public class UriTestAux : UriTest private bool originalIriParsing; [TestFixtureSetUp] - public void GetReady () + public void GetReady2 () { isWin32 = (Path.DirectorySeparatorChar == '\\'); diff --git a/mcs/class/System/Test/System/UriTest2.cs b/mcs/class/System/Test/System/UriTest2.cs index 73b143aae2f..e3a4530e0c6 100644 --- a/mcs/class/System/Test/System/UriTest2.cs +++ b/mcs/class/System/Test/System/UriTest2.cs @@ -919,6 +919,102 @@ public void FileScheme () Assert.AreEqual ("/%3C%3E%25%22%7B%7D%7C/%5E%60;/:@&=+$,%5B%5D%3F", uri.AbsolutePath, "Special"); } + [Test] + public void LocalFile () + { + Uri uri = new Uri ("file:///c:/subdir/file"); + + Assert.AreEqual ("c:/subdir/file", uri.AbsolutePath, "AbsolutePath"); + Assert.AreEqual ("file:///c:/subdir/file", uri.AbsoluteUri, "AbsoluteUri"); + Assert.AreEqual ("c:\\subdir\\file", uri.LocalPath, "LocalPath"); + Assert.AreEqual ("c:/subdir/file", uri.PathAndQuery, "PathAndQuery"); + Assert.AreEqual (String.Empty, uri.Query, "Query"); + Assert.AreEqual ("file", uri.Segments [3], "Segments [3]"); + + Assert.AreEqual (String.Empty, uri.Authority, "Authority"); + Assert.AreEqual (String.Empty, uri.DnsSafeHost, "DnsSafeHost"); + Assert.AreEqual (String.Empty, uri.Fragment, "Fragment"); + Assert.AreEqual (String.Empty, uri.Host, "Host"); + Assert.AreEqual (UriHostNameType.Basic, uri.HostNameType, "HostNameType"); + Assert.IsTrue (uri.IsAbsoluteUri, "IsAbsoluteUri"); + Assert.IsTrue (uri.IsDefaultPort, "IsDefaultPort"); + Assert.IsTrue (uri.IsFile, "IsFile"); + Assert.IsTrue (uri.IsLoopback, "IsLoopback"); + Assert.IsFalse (uri.IsUnc, "IsUnc"); + Assert.AreEqual ("file:///c:/subdir/file", uri.OriginalString, "OriginalString"); + Assert.AreEqual (-1, uri.Port, "Port"); + Assert.AreEqual ("file", uri.Scheme, "Scheme"); + Assert.AreEqual ("/", uri.Segments [0], "Segments [0]"); + Assert.AreEqual ("c:/", uri.Segments [1], "Segments [1]"); + Assert.AreEqual ("subdir/", uri.Segments [2], "Segments [2]"); + Assert.IsFalse (uri.UserEscaped, "UserEscaped"); + Assert.AreEqual (String.Empty, uri.UserInfo, "UserInfo"); + } + + [Test] + public void LocalhostWinFile () + { + Uri uri = new Uri ("file://localhost/c:/subdir/file"); + + Assert.AreEqual ("/c:/subdir/file", uri.AbsolutePath, "AbsolutePath"); + Assert.AreEqual ("file://localhost/c:/subdir/file", uri.AbsoluteUri, "AbsoluteUri"); + Assert.AreEqual (isWin32 ? "\\\\localhost\\c:\\subdir\\file" : "/c:/subdir/file", uri.LocalPath, "LocalPath"); + Assert.AreEqual ("/c:/subdir/file", uri.PathAndQuery, "PathAndQuery"); + Assert.AreEqual (String.Empty, uri.Query, "Query"); + Assert.AreEqual ("file", uri.Segments [3], "Segments [3]"); + + Assert.AreEqual ("localhost", uri.Authority, "Authority"); + Assert.AreEqual ("localhost", uri.DnsSafeHost, "DnsSafeHost"); + Assert.AreEqual (String.Empty, uri.Fragment, "Fragment"); + Assert.AreEqual ("localhost", uri.Host, "Host"); + Assert.AreEqual (UriHostNameType.Dns, uri.HostNameType, "HostNameType"); + Assert.IsTrue (uri.IsAbsoluteUri, "IsAbsoluteUri"); + Assert.IsTrue (uri.IsDefaultPort, "IsDefaultPort"); + Assert.IsTrue (uri.IsFile, "IsFile"); + Assert.IsTrue (uri.IsLoopback, "IsLoopback"); + Assert.AreEqual (isWin32, uri.IsUnc, "IsUnc"); + Assert.AreEqual ("file://localhost/c:/subdir/file", uri.OriginalString, "OriginalString"); + Assert.AreEqual (-1, uri.Port, "Port"); + Assert.AreEqual ("file", uri.Scheme, "Scheme"); + Assert.AreEqual ("/", uri.Segments [0], "Segments [0]"); + Assert.AreEqual ("c:/", uri.Segments [1], "Segments [1]"); + Assert.AreEqual ("subdir/", uri.Segments [2], "Segments [2]"); + Assert.IsFalse (uri.UserEscaped, "UserEscaped"); + Assert.AreEqual (String.Empty, uri.UserInfo, "UserInfo"); + } + + [Test] + public void LocalhostFile () + { + Uri uri = new Uri ("file://localhost/dir/subdir/file"); + + Assert.AreEqual ("/dir/subdir/file", uri.AbsolutePath, "AbsolutePath"); + Assert.AreEqual ("file://localhost/dir/subdir/file", uri.AbsoluteUri, "AbsoluteUri"); + Assert.AreEqual (isWin32 ? "\\\\localhost\\dir\\subdir\\file" : "/dir/subdir/file", uri.LocalPath, "LocalPath"); + Assert.AreEqual ("/dir/subdir/file", uri.PathAndQuery, "PathAndQuery"); + Assert.AreEqual (String.Empty, uri.Query, "Query"); + Assert.AreEqual ("file", uri.Segments [3], "Segments [3]"); + + Assert.AreEqual ("localhost", uri.Authority, "Authority"); + Assert.AreEqual ("localhost", uri.DnsSafeHost, "DnsSafeHost"); + Assert.AreEqual (String.Empty, uri.Fragment, "Fragment"); + Assert.AreEqual ("localhost", uri.Host, "Host"); + Assert.AreEqual (UriHostNameType.Dns, uri.HostNameType, "HostNameType"); + Assert.IsTrue (uri.IsAbsoluteUri, "IsAbsoluteUri"); + Assert.IsTrue (uri.IsDefaultPort, "IsDefaultPort"); + Assert.IsTrue (uri.IsFile, "IsFile"); + Assert.IsTrue (uri.IsLoopback, "IsLoopback"); + Assert.AreEqual (isWin32, uri.IsUnc, "IsUnc"); + Assert.AreEqual ("file://localhost/dir/subdir/file", uri.OriginalString, "OriginalString"); + Assert.AreEqual (-1, uri.Port, "Port"); + Assert.AreEqual ("file", uri.Scheme, "Scheme"); + Assert.AreEqual ("/", uri.Segments [0], "Segments [0]"); + Assert.AreEqual ("dir/", uri.Segments [1], "Segments [1]"); + Assert.AreEqual ("subdir/", uri.Segments [2], "Segments [2]"); + Assert.IsFalse (uri.UserEscaped, "UserEscaped"); + Assert.AreEqual (String.Empty, uri.UserInfo, "UserInfo"); + } + [Test] public void PathReduction_2e () { diff --git a/mcs/class/System/Test/System/UriTypeConverterTest.cs b/mcs/class/System/Test/System/UriTypeConverterTest.cs index b37d5a86578..fa92b2d04ac 100644 --- a/mcs/class/System/Test/System/UriTypeConverterTest.cs +++ b/mcs/class/System/Test/System/UriTypeConverterTest.cs @@ -230,13 +230,8 @@ public void ConvertFromString () Assert.AreEqual ("~/SomeUri.txt", (o as Uri).ToString (), "CFS_02"); o = converter.ConvertFrom ("/SomeUri.txt"); - if (isWin32) { - Assert.IsFalse ((o as Uri).IsAbsoluteUri, "CFS_03_WIN"); - Assert.AreEqual ("/SomeUri.txt", (o as Uri).ToString (), "CFS_04_WIN"); - } else { - Assert.IsTrue ((o as Uri).IsAbsoluteUri, "CFS_03_UNIX"); - Assert.AreEqual ("file:///SomeUri.txt", (o as Uri).ToString (), "CFS_04_UNIX"); - } + Assert.IsFalse ((o as Uri).IsAbsoluteUri, "CFS_03"); + Assert.AreEqual ("/SomeUri.txt", (o as Uri).ToString (), "CFS_04"); } [Test] diff --git a/mcs/class/WindowsBase/Test/System.IO.Packaging/FakePackage.cs b/mcs/class/WindowsBase/Test/System.IO.Packaging/FakePackage.cs index 54df0eb5e8e..2818cd5e453 100644 --- a/mcs/class/WindowsBase/Test/System.IO.Packaging/FakePackage.cs +++ b/mcs/class/WindowsBase/Test/System.IO.Packaging/FakePackage.cs @@ -25,9 +25,11 @@ using System; +using System.IO; +using System.IO.Packaging; using System.Collections.Generic; -namespace System.IO.Packaging.Tests { +namespace MonoTests.System.IO.Packaging { public class FakePackage : Package { Dictionary Parts { get; set; } @@ -77,4 +79,4 @@ protected override PackagePart [] GetPartsCore () return p; } } -} \ No newline at end of file +} diff --git a/mcs/class/WindowsBase/Test/System.IO.Packaging/FakePackagePart.cs b/mcs/class/WindowsBase/Test/System.IO.Packaging/FakePackagePart.cs index 9a7871c6ed0..1ca0bb20f05 100644 --- a/mcs/class/WindowsBase/Test/System.IO.Packaging/FakePackagePart.cs +++ b/mcs/class/WindowsBase/Test/System.IO.Packaging/FakePackagePart.cs @@ -24,9 +24,11 @@ // using System; +using System.IO; +using System.IO.Packaging; using System.Collections.Generic; -namespace System.IO.Packaging.Tests { +namespace MonoTests.System.IO.Packaging { class FakePackagePart : PackagePart { diff --git a/mcs/class/WindowsBase/Test/System.IO.Packaging/FakePackagePartTests.cs b/mcs/class/WindowsBase/Test/System.IO.Packaging/FakePackagePartTests.cs index 731aed62ff9..216a1686f64 100644 --- a/mcs/class/WindowsBase/Test/System.IO.Packaging/FakePackagePartTests.cs +++ b/mcs/class/WindowsBase/Test/System.IO.Packaging/FakePackagePartTests.cs @@ -26,9 +26,12 @@ using System; using System.Linq; using System.Collections.Generic; +using System.IO; +using System.IO.Packaging; +using System.Xml; using NUnit.Framework; -namespace System.IO.Packaging.Tests { +namespace MonoTests.System.IO.Packaging { [TestFixture] public class FakePackagePartTests : TestBase { @@ -146,7 +149,7 @@ public void CreateRelationship7 () } [Test] - [ExpectedException (typeof (Xml.XmlException))] + [ExpectedException (typeof (XmlException))] public void CreateDupeRelationship () { part.CreateRelationship (uris [1], TargetMode.External, "blah", "asda"); @@ -154,7 +157,7 @@ public void CreateDupeRelationship () } [Test] - [ExpectedException (typeof (Xml.XmlException))] + [ExpectedException (typeof (XmlException))] public void CreateDupeRelationshipId () { part.CreateRelationship (uris [1], TargetMode.External, "blah", "asda"); diff --git a/mcs/class/WindowsBase/Test/System.IO.Packaging/FakePackageTests.cs b/mcs/class/WindowsBase/Test/System.IO.Packaging/FakePackageTests.cs index bd751542927..bfea3c84973 100644 --- a/mcs/class/WindowsBase/Test/System.IO.Packaging/FakePackageTests.cs +++ b/mcs/class/WindowsBase/Test/System.IO.Packaging/FakePackageTests.cs @@ -26,11 +26,13 @@ using System; using System.Collections.Generic; +using System.IO; +using System.IO.Packaging; using System.Linq; using System.Text; using NUnit.Framework; -namespace System.IO.Packaging.Tests +namespace MonoTests.System.IO.Packaging { [TestFixture] diff --git a/mcs/class/WindowsBase/Test/System.IO.Packaging/FakeStream.cs b/mcs/class/WindowsBase/Test/System.IO.Packaging/FakeStream.cs index b095375b177..aafc02e25ed 100644 --- a/mcs/class/WindowsBase/Test/System.IO.Packaging/FakeStream.cs +++ b/mcs/class/WindowsBase/Test/System.IO.Packaging/FakeStream.cs @@ -25,9 +25,10 @@ using System; +using System.IO; using System.Collections.Generic; -namespace System.IO.Packaging.Tests { +namespace MonoTests.System.IO.Packaging { public class FakeStream : MemoryStream { public bool canRead; diff --git a/mcs/class/WindowsBase/Test/System.IO.Packaging/PackUriHelperTests.cs b/mcs/class/WindowsBase/Test/System.IO.Packaging/PackUriHelperTests.cs index c5361214f7b..d231315a0e9 100644 --- a/mcs/class/WindowsBase/Test/System.IO.Packaging/PackUriHelperTests.cs +++ b/mcs/class/WindowsBase/Test/System.IO.Packaging/PackUriHelperTests.cs @@ -8,7 +8,7 @@ using System.IO.Packaging; using NUnit.Framework; -namespace System.IO.Packaging.Tests { +namespace MonoTests.System.IO.Packaging { [TestFixture] public class PackUriHelperTests { diff --git a/mcs/class/WindowsBase/Test/System.IO.Packaging/PackagePartFileTests.cs b/mcs/class/WindowsBase/Test/System.IO.Packaging/PackagePartFileTests.cs index 3f2850b602b..557e4a98b51 100644 --- a/mcs/class/WindowsBase/Test/System.IO.Packaging/PackagePartFileTests.cs +++ b/mcs/class/WindowsBase/Test/System.IO.Packaging/PackagePartFileTests.cs @@ -3,7 +3,7 @@ using System.IO.Packaging; using NUnit.Framework; -namespace System.IO.Packaging.Tests +namespace MonoTests.System.IO.Packaging { [TestFixture] public class PackagePartFileTests @@ -135,4 +135,4 @@ public void TestOverwrite() } } } -} \ No newline at end of file +} diff --git a/mcs/class/WindowsBase/Test/System.IO.Packaging/PackagePartStreamTests.cs b/mcs/class/WindowsBase/Test/System.IO.Packaging/PackagePartStreamTests.cs index 915c2a09a98..1bf60221082 100644 --- a/mcs/class/WindowsBase/Test/System.IO.Packaging/PackagePartStreamTests.cs +++ b/mcs/class/WindowsBase/Test/System.IO.Packaging/PackagePartStreamTests.cs @@ -26,11 +26,13 @@ using System; using System.Collections.Generic; +using System.IO; +using System.IO.Packaging; using System.Linq; using System.Text; using NUnit.Framework; -namespace System.IO.Packaging.Tests { +namespace MonoTests.System.IO.Packaging { [TestFixture] public class PackagePartStreamTests : TestBase { @@ -190,4 +192,4 @@ public void CheckFlushTest2 () Assert.IsTrue (stream.Length > buffer.Length * 2, "#4"); } } -} \ No newline at end of file +} diff --git a/mcs/class/WindowsBase/Test/System.IO.Packaging/PackagePartTest.cs b/mcs/class/WindowsBase/Test/System.IO.Packaging/PackagePartTest.cs index 07015c20173..ad7eb968c3a 100644 --- a/mcs/class/WindowsBase/Test/System.IO.Packaging/PackagePartTest.cs +++ b/mcs/class/WindowsBase/Test/System.IO.Packaging/PackagePartTest.cs @@ -26,12 +26,14 @@ using System; using System.Collections.Generic; +using System.IO; +using System.IO.Packaging; using System.Linq; using System.Text; using NUnit.Framework; using System.Xml; -namespace System.IO.Packaging.Tests { +namespace MonoTests.System.IO.Packaging { [TestFixture] public class PackagePartTest : TestBase { diff --git a/mcs/class/WindowsBase/Test/System.IO.Packaging/PackageRelationshipTests.cs b/mcs/class/WindowsBase/Test/System.IO.Packaging/PackageRelationshipTests.cs index 8c4b031de95..6ce92d31e57 100644 --- a/mcs/class/WindowsBase/Test/System.IO.Packaging/PackageRelationshipTests.cs +++ b/mcs/class/WindowsBase/Test/System.IO.Packaging/PackageRelationshipTests.cs @@ -28,12 +28,14 @@ using System; using System.Collections.Generic; +using System.IO; +using System.IO.Packaging; using System.Linq; using System.Text; using System.Xml; using NUnit.Framework; -namespace System.IO.Packaging.Tests { +namespace MonoTests.System.IO.Packaging { [TestFixture] public class PackageRelationshipTests : TestBase { diff --git a/mcs/class/WindowsBase/Test/System.IO.Packaging/PackageTest.cs b/mcs/class/WindowsBase/Test/System.IO.Packaging/PackageTest.cs index ae7c5945de9..933449052f3 100644 --- a/mcs/class/WindowsBase/Test/System.IO.Packaging/PackageTest.cs +++ b/mcs/class/WindowsBase/Test/System.IO.Packaging/PackageTest.cs @@ -26,11 +26,13 @@ using System; using System.Collections.Generic; +using System.IO; +using System.IO.Packaging; using System.Linq; using System.Text; using NUnit.Framework; -namespace System.IO.Packaging.Tests { +namespace MonoTests.System.IO.Packaging { [TestFixture] public class PackageTest : TestBase { @@ -411,8 +413,8 @@ public void ReadWriteAccessDoesntExist () [ExpectedException (typeof (FileFormatException))] public void WriteOnlyAccessExists () { - System.IO.File.Create (path).Close (); + File.Create (path).Close (); package = Package.Open (path, FileMode.OpenOrCreate, FileAccess.Write); } } -} \ No newline at end of file +} diff --git a/mcs/class/WindowsBase/Test/System.IO.Packaging/TestBase.cs b/mcs/class/WindowsBase/Test/System.IO.Packaging/TestBase.cs index 6d8b43d057e..28afcd43151 100644 --- a/mcs/class/WindowsBase/Test/System.IO.Packaging/TestBase.cs +++ b/mcs/class/WindowsBase/Test/System.IO.Packaging/TestBase.cs @@ -26,11 +26,13 @@ using System; using System.Collections.Generic; +using System.IO; +using System.IO.Packaging; using System.Linq; using System.Text; using NUnit.Framework; -namespace System.IO.Packaging.Tests { +namespace MonoTests.System.IO.Packaging { public abstract class TestBase { protected string contentType = "mime/type"; diff --git a/mcs/class/corlib/DateTime.Now_Test.sh b/mcs/class/corlib/DateTime.Now_Test.sh new file mode 100755 index 00000000000..2d43f635d0c --- /dev/null +++ b/mcs/class/corlib/DateTime.Now_Test.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +SCRIPT_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +CSHARP=$SCRIPT_PATH/../lib/net_4_5/csharp.exe +MONO=$SCRIPT_PATH/../../../mono/mini/mono + +export MONO_PATH=${MONO_PATH:-$SCRIPT_PATH/../lib/net_4_5} + +TZ_FAILS=0 +TZ_COUNT=0 +FORMAT="%a %b %d %T %Y" + +for tz in $(cd /usr/share/zoneinfo/; find * -type f -print); do + TZ_COUNT=$(expr $TZ_COUNT + 1) + SYS_DATETIME=$(date -ju -f "$FORMAT" "$(TZ=$tz date "+$FORMAT")" "+%s") + CS_DATETIME=$(TZ=$tz $MONO $CSHARP -e '(int)(DateTime.Now - new DateTime(1970, 1, 1)).TotalSeconds;') + DIFF=$(expr $SYS_DATETIME - $CS_DATETIME) + if [ "$DIFF" -gt "5" ] || [ "$DIFF" -lt "-5" ]; then + TZ_FAILS=$(expr $TZ_FAILS + 1) + echo "" + echo "DateTime.Now failed with timezone: $tz" + echo " System: $(date -ju -f "%s" "$SYS_DATETIME" "+%Y-%m-%d %T")" + echo " DateTime.Now: $(date -ju -f "%s" "$CS_DATETIME" "+%Y-%m-%d %T")" + fi + echo ".\c" +done +echo "" +echo "DateTime.Now failed with $TZ_FAILS of $TZ_COUNT timezones." diff --git a/mcs/class/corlib/System.Collections.Concurrent/ConcurrentQueue.cs b/mcs/class/corlib/System.Collections.Concurrent/ConcurrentQueue.cs index ea8984394b4..958fc615359 100644 --- a/mcs/class/corlib/System.Collections.Concurrent/ConcurrentQueue.cs +++ b/mcs/class/corlib/System.Collections.Concurrent/ConcurrentQueue.cs @@ -63,7 +63,7 @@ public void Enqueue (T item) { Node node = new Node (); node.Value = item; - + Node oldTail = null; Node oldNext = null; @@ -71,6 +71,8 @@ public void Enqueue (T item) while (!update) { oldTail = tail; oldNext = oldTail.Next; + + Thread.MemoryBarrier (); // Did tail was already updated ? if (tail == oldTail) { @@ -104,6 +106,8 @@ public bool TryDequeue (out T result) Node oldHead = head; Node oldTail = tail; oldNext = oldHead.Next; + + Thread.MemoryBarrier (); if (oldHead == head) { // Empty case ? @@ -146,6 +150,8 @@ public bool TryPeek (out T result) } result = oldNext.Value; + + Thread.MemoryBarrier (); //check if head has been updated update = head != oldHead; diff --git a/mcs/class/corlib/System.Globalization/CalendricalCalculations.cs b/mcs/class/corlib/System.Globalization/CalendricalCalculations.cs index 685c0f372fa..accba935b62 100644 --- a/mcs/class/corlib/System.Globalization/CalendricalCalculations.cs +++ b/mcs/class/corlib/System.Globalization/CalendricalCalculations.cs @@ -466,6 +466,11 @@ public static bool is_leap_year(int year) { /// An integer value representing the fixed day number. /// public static int fixed_from_dmy(int day, int month, int year) { + if (month > 12) { + year += CCMath.div_mod (out month, month - 1, 12); + month++; + } + int k = epoch - 1; k += 365 * (year-1); k += CCMath.div(year-1, 4); @@ -944,6 +949,12 @@ public static bool is_leap_year(int year) { /// public static int fixed_from_dmy(int day, int month, int year) { int y = year < 0 ? year+1 : year; + + if (month > 12) { + y += CCMath.div_mod (out month, month - 1, 12); + month++; + } + int k = epoch - 1; k += 365 * (y-1); k += CCMath.div(y-1, 4); @@ -1371,6 +1382,13 @@ public static int days_in_year(int year) { /// An integer value representing the fixed day number. /// public static int fixed_from_dmy(int day, int month, int year) { + var lastMonth = last_month_of_year (year); + while (month > lastMonth) { + year++; + month -= lastMonth; + lastMonth = last_month_of_year (year); + } + int m; int k = epoch-1; k += elapsed_days(year); @@ -1686,6 +1704,11 @@ public static bool is_leap_year(int year) { /// An integer value representing the fixed day number. /// public static int fixed_from_dmy(int day, int month, int year) { + if (month > 12) { + year += CCMath.div_mod (out month, month - 1, 12); + month++; + } + int k = epoch - 1; k += 354 * (year-1); k += CCMath.div(3+11*year, 30); diff --git a/mcs/class/corlib/System.IO/DirectoryInfo.cs b/mcs/class/corlib/System.IO/DirectoryInfo.cs index ce558743516..09ed552f62e 100644 --- a/mcs/class/corlib/System.IO/DirectoryInfo.cs +++ b/mcs/class/corlib/System.IO/DirectoryInfo.cs @@ -6,10 +6,12 @@ // Jim Richardson, develop@wtfo-guru.com // Dan Lewis, dihlewis@yahoo.co.uk // Sebastien Pouliot +// Marek Safar // // Copyright (C) 2002 Ximian, Inc. // Copyright (C) 2001 Moonlight Enterprises, All Rights Reserved // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com) +// Copyright (C) 2014 Xamarin, Inc (http://www.xamarin.com) // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -441,25 +443,19 @@ static internal IEnumerable EnumerateFileSystemInfos (string ful throw MonoIO.GetException (Path.GetDirectoryName (path_with_pattern), (MonoIOError) error); try { - if (((rattr & FileAttributes.ReparsePoint) == 0)){ - if ((rattr & FileAttributes.Directory) != 0) - yield return new DirectoryInfo (s); - else - yield return new FileInfo (s); - } - - while ((s = MonoIO.FindNext (handle, out rattr, out error)) != null){ - if ((rattr & FileAttributes.ReparsePoint) != 0) - continue; - if ((rattr & FileAttributes.Directory) != 0) - yield return new DirectoryInfo (s); - else - yield return new FileInfo (s); - + do { + if (((rattr & FileAttributes.ReparsePoint) == 0)){ + if ((rattr & FileAttributes.Directory) != 0) + yield return new DirectoryInfo (s); + else + yield return new FileInfo (s); + } + if (((rattr & FileAttributes.Directory) != 0) && subdirs) foreach (FileSystemInfo child in EnumerateFileSystemInfos (s, searchPattern, searchOption)) yield return child; - } + + } while ((s = MonoIO.FindNext (handle, out rattr, out error)) != null); } finally { MonoIO.FindClose (handle); } diff --git a/mcs/class/corlib/System.Reflection/MonoGenericClass.cs b/mcs/class/corlib/System.Reflection/MonoGenericClass.cs index c053a4bbfc3..34c2b848949 100644 --- a/mcs/class/corlib/System.Reflection/MonoGenericClass.cs +++ b/mcs/class/corlib/System.Reflection/MonoGenericClass.cs @@ -495,11 +495,15 @@ public override bool IsDefined (Type attributeType, bool inherit) 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 (); } diff --git a/mcs/class/corlib/System.Runtime.InteropServices/Marshal.cs b/mcs/class/corlib/System.Runtime.InteropServices/Marshal.cs index e339f94955a..48c5db2ea62 100644 --- a/mcs/class/corlib/System.Runtime.InteropServices/Marshal.cs +++ b/mcs/class/corlib/System.Runtime.InteropServices/Marshal.cs @@ -414,9 +414,11 @@ public static IntPtr GetHINSTANCE (Module m) #endif // !FULL_AOT_RUNTIME #if !FULL_AOT_RUNTIME - [MonoTODO ("SetErrorInfo")] public static int GetHRForException (Exception e) { + var errorInfo = new ManagedErrorInfo(e); + SetErrorInfo (0, errorInfo); + return e.hresult; } @@ -1314,27 +1316,310 @@ public static void WriteIntPtr([In, Out, MarshalAs(UnmanagedType.AsAny)] object throw new NotImplementedException (); } - public static Exception GetExceptionForHR (int errorCode) { - return GetExceptionForHR (errorCode, IntPtr.Zero); - } - - public static Exception GetExceptionForHR (int errorCode, IntPtr errorInfo) { - + private static Exception ConvertHrToException (int errorCode) + { + const int MSEE_E_APPDOMAINUNLOADED = unchecked ((int)0x80131014L); + const int COR_E_APPLICATION = unchecked ((int)0x80131600L); + const int E_INVALIDARG = unchecked ((int)0x80070057); + const int COR_E_ARGUMENTOUTOFRANGE = unchecked ((int)0x80131502L); + const int COR_E_ARITHMETIC = unchecked ((int)0x80070216); + const int COR_E_ARRAYTYPEMISMATCH = unchecked ((int)0x80131503L); + const int COR_E_BADIMAGEFORMAT = unchecked ((int)0x8007000BL); + const int ERROR_BAD_FORMAT = unchecked ((int)0x0B); + //const int COR_E_COMEMULATE_ERROR = unchecked ((int)?); + const int COR_E_CONTEXTMARSHAL = unchecked ((int)0x80131504L); + //const int COR_E_CORE = unchecked ((int)?); + const int NTE_FAIL = unchecked ((int)0x80090020L); + const int COR_E_DIRECTORYNOTFOUND = unchecked ((int)0x80070003L); + const int ERROR_PATH_NOT_FOUND = unchecked ((int)0x03); + const int COR_E_DIVIDEBYZERO = unchecked ((int)0x80020012L); + const int COR_E_DUPLICATEWAITOBJECT = unchecked ((int)0x80131529L); + const int COR_E_ENDOFSTREAM = unchecked ((int)0x80070026L); + const int COR_E_TYPELOAD = unchecked ((int)0x80131522L); + const int COR_E_EXCEPTION = unchecked ((int)0x80131500L); + const int COR_E_EXECUTIONENGINE = unchecked ((int)0x80131506L); + const int COR_E_FIELDACCESS = unchecked ((int)0x80131507L); + const int COR_E_FILENOTFOUND = unchecked ((int)0x80070002L); + const int ERROR_FILE_NOT_FOUND = unchecked ((int)0x02); + const int COR_E_FORMAT = unchecked ((int)0x80131537L); + const int COR_E_INDEXOUTOFRANGE = unchecked ((int)0x80131508L); + const int COR_E_INVALIDCAST = unchecked ((int)0x80004002L); + const int COR_E_INVALIDCOMOBJECT = unchecked ((int)0x80131527L); + const int COR_E_INVALIDFILTERCRITERIA = unchecked ((int)0x80131601L); + const int COR_E_INVALIDOLEVARIANTTYPE = unchecked ((int)0x80131531L); + const int COR_E_INVALIDOPERATION = unchecked ((int)0x80131509L); + const int COR_E_IO = unchecked ((int)0x80131620L); + const int COR_E_MEMBERACCESS = unchecked ((int)0x8013151AL); + const int COR_E_METHODACCESS = unchecked ((int)0x80131510L); + const int COR_E_MISSINGFIELD = unchecked ((int)0x80131511L); + const int COR_E_MISSINGMANIFESTRESOURCE = unchecked ((int)0x80131532L); + const int COR_E_MISSINGMEMBER = unchecked ((int)0x80131512L); + const int COR_E_MISSINGMETHOD = unchecked ((int)0x80131513L); + const int COR_E_MULTICASTNOTSUPPORTED = unchecked ((int)0x80131514L); + const int COR_E_NOTFINITENUMBER = unchecked ((int)0x80131528L); + const int E_NOTIMPL = unchecked ((int)0x80004001L); + const int COR_E_NOTSUPPORTED = unchecked ((int)0x80131515L); + const int COR_E_NULLREFERENCE = unchecked ((int)0x80004003L); const int E_OUTOFMEMORY = unchecked ((int)0x8007000EL); - const int E_INVALIDARG = unchecked ((int)0X80070057); - - switch (errorCode) - { - case E_OUTOFMEMORY: - return new OutOfMemoryException (); - case E_INVALIDARG: - return new ArgumentException (); + const int COR_E_OVERFLOW = unchecked ((int)0x80131516L); + const int COR_E_PATHTOOLONG = unchecked ((int)0x800700CEL); + const int ERROR_FILENAME_EXCED_RANGE = unchecked ((int)0xCE); + const int COR_E_RANK = unchecked ((int)0x80131517L); + const int COR_E_REFLECTIONTYPELOAD = unchecked ((int)0x80131602L); + const int COR_E_REMOTING = unchecked ((int)0x8013150BL); + const int COR_E_SAFEARRAYTYPEMISMATCH = unchecked ((int)0x80131533L); + const int COR_E_SECURITY = unchecked ((int)0x8013150AL); + const int COR_E_SERIALIZATION = unchecked ((int)0x8013150CL); + const int COR_E_STACKOVERFLOW = unchecked ((int)0x800703E9L); + const int ERROR_STACK_OVERFLOW = unchecked ((int)0x03E9); + const int COR_E_SYNCHRONIZATIONLOCK = unchecked ((int)0x80131518L); + const int COR_E_SYSTEM = unchecked ((int)0x80131501L); + const int COR_E_TARGET = unchecked ((int)0x80131603L); + const int COR_E_TARGETINVOCATION = unchecked ((int)0x80131604L); + const int COR_E_TARGETPARAMCOUNT = unchecked ((int)0x8002000EL); + const int COR_E_THREADABORTED = unchecked ((int)0x80131530L); + const int COR_E_THREADINTERRUPTED = unchecked ((int)0x80131519L); + const int COR_E_THREADSTATE = unchecked ((int)0x80131520L); + const int COR_E_THREADSTOP = unchecked ((int)0x80131521L); + const int COR_E_TYPEINITIALIZATION = unchecked ((int)0x80131534L); + const int COR_E_VERIFICATION = unchecked ((int)0x8013150DL); + //const int COR_E_WEAKREFERENCE = unchecked ((int)?); + //const int COR_E_VTABLECALLSNOTSUPPORTED = unchecked ((int)); + + switch (errorCode) { + case MSEE_E_APPDOMAINUNLOADED: + return new AppDomainUnloadedException (); + case COR_E_APPLICATION: + return new ApplicationException (); + case E_INVALIDARG: + return new ArgumentException (); + case COR_E_ARGUMENTOUTOFRANGE: + return new ArgumentOutOfRangeException (); + case COR_E_ARITHMETIC: + return new ArithmeticException (); + case COR_E_ARRAYTYPEMISMATCH: + return new ArrayTypeMismatchException (); + case COR_E_BADIMAGEFORMAT: + case ERROR_BAD_FORMAT: + return new BadImageFormatException (); +// case COR_E_COMEMULATE_ERROR: +// return new COMEmulateException (); + case COR_E_CONTEXTMARSHAL: + return new ContextMarshalException (); +// case COR_E_CORE: +// return new CoreException (); + case NTE_FAIL: + return new System.Security.Cryptography.CryptographicException (); + case COR_E_DIRECTORYNOTFOUND: + case ERROR_PATH_NOT_FOUND: + return new System.IO.DirectoryNotFoundException (); + case COR_E_DIVIDEBYZERO: + return new DivideByZeroException (); + case COR_E_DUPLICATEWAITOBJECT: + return new DuplicateWaitObjectException (); + case COR_E_ENDOFSTREAM: + return new System.IO.EndOfStreamException (); + case COR_E_EXCEPTION: + return new Exception (); + case COR_E_EXECUTIONENGINE: + return new ExecutionEngineException (); + case COR_E_FIELDACCESS: + return new FieldAccessException (); + case COR_E_FILENOTFOUND: + case ERROR_FILE_NOT_FOUND: + return new System.IO.FileNotFoundException (); + case COR_E_FORMAT: + return new FormatException (); + case COR_E_INDEXOUTOFRANGE: + return new IndexOutOfRangeException (); + case COR_E_INVALIDCAST: + // E_NOINTERFACE has same value as COR_E_INVALIDCAST + return new InvalidCastException (); + case COR_E_INVALIDCOMOBJECT: + return new InvalidComObjectException (); + case COR_E_INVALIDFILTERCRITERIA: + return new InvalidFilterCriteriaException (); + case COR_E_INVALIDOLEVARIANTTYPE: + return new InvalidOleVariantTypeException (); + case COR_E_INVALIDOPERATION: + return new InvalidOperationException (); + case COR_E_IO: + return new System.IO.IOException (); + case COR_E_MEMBERACCESS: + return new MemberAccessException (); + case COR_E_METHODACCESS: + return new MethodAccessException (); + case COR_E_MISSINGFIELD: + return new MissingFieldException (); + case COR_E_MISSINGMANIFESTRESOURCE: + return new System.Resources.MissingManifestResourceException (); + case COR_E_MISSINGMEMBER: + return new MissingMemberException (); + case COR_E_MISSINGMETHOD: + return new MissingMethodException (); + case COR_E_MULTICASTNOTSUPPORTED: + return new MulticastNotSupportedException (); + case COR_E_NOTFINITENUMBER: + return new NotFiniteNumberException (); + case E_NOTIMPL: + return new NotImplementedException (); + case COR_E_NOTSUPPORTED: + return new NotSupportedException (); + case COR_E_NULLREFERENCE: + // E_POINTER has the same value as COR_E_NULLREFERENCE + return new NullReferenceException (); + case E_OUTOFMEMORY: + // COR_E_OUTOFMEMORY has the same value as E_OUTOFMEMORY + return new OutOfMemoryException (); + case COR_E_OVERFLOW: + return new OverflowException (); + case COR_E_PATHTOOLONG: + case ERROR_FILENAME_EXCED_RANGE: + return new System.IO.PathTooLongException (); + case COR_E_RANK: + return new RankException (); + case COR_E_REFLECTIONTYPELOAD: + return new System.Reflection.ReflectionTypeLoadException (new Type[] { }, new Exception[] { }); + case COR_E_REMOTING: + return new System.Runtime.Remoting.RemotingException (); + case COR_E_SAFEARRAYTYPEMISMATCH: + return new SafeArrayTypeMismatchException (); + case COR_E_SECURITY: + return new SecurityException (); + case COR_E_SERIALIZATION: + return new System.Runtime.Serialization.SerializationException (); + case COR_E_STACKOVERFLOW: + case ERROR_STACK_OVERFLOW: + return new StackOverflowException (); + case COR_E_SYNCHRONIZATIONLOCK: + return new SynchronizationLockException (); + case COR_E_SYSTEM: + return new SystemException (); + case COR_E_TARGET: + return new TargetException (); + case COR_E_TARGETINVOCATION: + return new System.Reflection.TargetInvocationException (null); + case COR_E_TARGETPARAMCOUNT: + return new TargetParameterCountException (); +// case COR_E_THREADABORTED: +// ThreadAbortException c'tor is inaccessible +// return new System.Threading.ThreadAbortException (); + case COR_E_THREADINTERRUPTED: + return new ThreadInterruptedException (); + case COR_E_THREADSTATE: + return new ThreadStateException (); +// case COR_E_THREADSTOP: +// ThreadStopException does not exist +// return new System.Threading.ThreadStopException (); + case COR_E_TYPELOAD: + return new TypeLoadException (); + // MSDN lists COR_E_TYPELOAD twice with different exceptions. + // return new EntryPointNotFoundException (); + case COR_E_TYPEINITIALIZATION: + return new TypeInitializationException("", null); + case COR_E_VERIFICATION: + return new VerificationException (); +// case COR_E_WEAKREFERENCE: +// return new WeakReferenceException (); +// case COR_E_VTABLECALLSNOTSUPPORTED: +// return new VTableCallsNotSupportedException (); } if (errorCode < 0) return new COMException ("", errorCode); return null; } + [DllImport ("oleaut32.dll", CharSet=CharSet.Unicode, EntryPoint = "SetErrorInfo")] + static extern int _SetErrorInfo (int dwReserved, + [MarshalAs(UnmanagedType.Interface)] IErrorInfo pIErrorInfo); + + [DllImport ("oleaut32.dll", CharSet=CharSet.Unicode, EntryPoint = "GetErrorInfo")] + static extern int _GetErrorInfo (int dwReserved, + [MarshalAs(UnmanagedType.Interface)] out IErrorInfo ppIErrorInfo); + + static bool SetErrorInfoNotAvailable; + static bool GetErrorInfoNotAvailable; + + internal static int SetErrorInfo (int dwReserved, IErrorInfo errorInfo) + { + int retVal = 0; + errorInfo = null; + + if (SetErrorInfoNotAvailable) + return -1; + + try { + retVal = _SetErrorInfo (dwReserved, errorInfo); + } + catch (Exception) { + // ignore any exception - probably there's no suitable SetErrorInfo + // method available. + SetErrorInfoNotAvailable = true; + } + return retVal; + } + + internal static int GetErrorInfo (int dwReserved, out IErrorInfo errorInfo) + { + int retVal = 0; + errorInfo = null; + + if (GetErrorInfoNotAvailable) + return -1; + + try { + retVal = _GetErrorInfo (dwReserved, out errorInfo); + } + catch (Exception) { + // ignore any exception - probably there's no suitable GetErrorInfo + // method available. + GetErrorInfoNotAvailable = true; + } + return retVal; + } + + public static Exception GetExceptionForHR (int errorCode) + { + return GetExceptionForHR (errorCode, IntPtr.Zero); + } + + public static Exception GetExceptionForHR (int errorCode, IntPtr errorInfo) + { + IErrorInfo info = null; + if (errorInfo != (IntPtr)(-1)) { + if (errorInfo == IntPtr.Zero) { + if (GetErrorInfo (0, out info) != 0) { + info = null; + } + } else { + info = Marshal.GetObjectForIUnknown (errorInfo) as IErrorInfo; + } + } + + if (info is ManagedErrorInfo && ((ManagedErrorInfo) info).Exception.hresult == errorCode) { + return ((ManagedErrorInfo) info).Exception; + } + + Exception e = ConvertHrToException (errorCode); + if (info != null && e != null) { + uint helpContext; + info.GetHelpContext (out helpContext); + string str; + info.GetSource (out str); + e.Source = str; + info.GetDescription (out str); + e.SetMessage (str); + info.GetHelpFile (out str); + + if (helpContext == 0) { + e.HelpLink = str; + } else { + e.HelpLink = string.Format ("{0}#{1}", str, helpContext); + } + } + return e; + } + #if !FULL_AOT_RUNTIME public static int FinalReleaseComObject (object o) { diff --git a/mcs/class/corlib/System.Security.Claims/Claim.cs b/mcs/class/corlib/System.Security.Claims/Claim.cs index ffb7ce73449..0347052d236 100644 --- a/mcs/class/corlib/System.Security.Claims/Claim.cs +++ b/mcs/class/corlib/System.Security.Claims/Claim.cs @@ -58,6 +58,9 @@ public Claim (string type, string value, string valueType, string issuer, string throw new ArgumentNullException ("type"); if (value == null) throw new ArgumentNullException ("value"); + + Properties = new Dictionary (); + Type = type; Value = value; ValueType = valueType == null ? ClaimValueTypes.String : valueType; @@ -91,4 +94,4 @@ public override string ToString () } } } -#endif \ No newline at end of file +#endif diff --git a/mcs/class/corlib/System.Security.Cryptography/HMAC.cs b/mcs/class/corlib/System.Security.Cryptography/HMAC.cs index e83eb67e69e..eb165dc56cb 100644 --- a/mcs/class/corlib/System.Security.Cryptography/HMAC.cs +++ b/mcs/class/corlib/System.Security.Cryptography/HMAC.cs @@ -117,6 +117,7 @@ private byte[] KeySetup (byte[] key, byte padding) protected override void Dispose (bool disposing) { if (!_disposed) { + _disposed = true; base.Dispose (disposing); } } diff --git a/mcs/class/corlib/System.Text/UTF8Encoding.cs b/mcs/class/corlib/System.Text/UTF8Encoding.cs index cdddb802b16..b3a93f14274 100644 --- a/mcs/class/corlib/System.Text/UTF8Encoding.cs +++ b/mcs/class/corlib/System.Text/UTF8Encoding.cs @@ -436,7 +436,7 @@ public unsafe override int GetBytes (char* chars, int charCount, byte* bytes, in private unsafe static int InternalGetCharCount ( byte[] bytes, int index, int count, uint leftOverBits, uint leftOverCount, object provider, - ref DecoderFallbackBuffer fallbackBuffer, ref byte [] bufferArg, bool flush) + ref DecoderFallbackBuffer fallbackBuffer, bool flush) { // Validate the parameters. if (bytes == null) { @@ -453,22 +453,22 @@ private unsafe static int InternalGetCharCount ( return 0; fixed (byte *bptr = bytes) return InternalGetCharCount (bptr + index, count, - leftOverBits, leftOverCount, provider, ref fallbackBuffer, ref bufferArg, flush); + leftOverBits, leftOverCount, provider, ref fallbackBuffer, flush); } private unsafe static int InternalGetCharCount ( - byte* bytes, int count, uint leftOverBits, + byte* bytes, int byteCount, uint leftOverBits, uint leftOverCount, object provider, - ref DecoderFallbackBuffer fallbackBuffer, ref byte [] bufferArg, bool flush) + ref DecoderFallbackBuffer fallbackBuffer, bool flush) { - int index = 0; + int byteIndex = 0; int length = 0; if (leftOverCount == 0) { - int end = index + count; - for (; index < end; index++, count--) { - if (bytes [index] < 0x80) + int end = byteIndex + byteCount; + for (; byteIndex < end; byteIndex++, byteCount--) { + if (bytes [byteIndex] < 0x80) length++; else break; @@ -480,9 +480,11 @@ private unsafe static int InternalGetCharCount ( uint leftBits = leftOverBits; uint leftSoFar = (leftOverCount & (uint)0x0F); uint leftSize = ((leftOverCount >> 4) & (uint)0x0F); - while (count > 0) { - ch = (uint)(bytes[index++]); - --count; + + int byteEnd = byteIndex + byteCount; + for(; byteIndex < byteEnd; byteIndex++) { + // Fetch the next character from the byte buffer. + ch = (uint)(bytes[byteIndex]); if (leftSize == 0) { // Process a UTF-8 start character. if (ch < (uint)0x0080) { @@ -515,7 +517,7 @@ private unsafe static int InternalGetCharCount ( leftSize = 6; } else { // Invalid UTF-8 start character. - length += Fallback (provider, ref fallbackBuffer, ref bufferArg, bytes, index - 1, 1); + length += Fallback (provider, ref fallbackBuffer, bytes, byteIndex, 1); } } else { // Process an extra byte in a multi-byte sequence. @@ -544,34 +546,34 @@ private unsafe static int InternalGetCharCount ( break; } if (overlong) { - length += Fallback (provider, ref fallbackBuffer, ref bufferArg, bytes, index - leftSoFar, leftSoFar); + length += Fallback (provider, ref fallbackBuffer, bytes, byteIndex - leftSoFar, leftSoFar); + --byteIndex; //process byte again } else if ((leftBits & 0xF800) == 0xD800) { // UTF-8 doesn't use surrogate characters - length += Fallback (provider, ref fallbackBuffer, ref bufferArg, bytes, index - leftSoFar, leftSoFar); + length += Fallback (provider, ref fallbackBuffer, bytes, byteIndex - leftSoFar, leftSoFar); } else ++length; } else if (leftBits < (uint)0x110000) { length += 2; } else { - length += Fallback (provider, ref fallbackBuffer, ref bufferArg, bytes, index - leftSoFar, leftSoFar); + length += Fallback (provider, ref fallbackBuffer, bytes, byteIndex - leftSoFar, leftSoFar); } leftSize = 0; } } else { // Invalid UTF-8 sequence: clear and restart. - length += Fallback (provider, ref fallbackBuffer, ref bufferArg, bytes, index - leftSoFar, leftSoFar); + length += Fallback (provider, ref fallbackBuffer, bytes, byteIndex - leftSoFar, leftSoFar); leftSize = 0; - --index; - ++count; + --byteIndex; } } } if (flush && leftSize != 0) { // We had left-over bytes that didn't make up // a complete UTF-8 character sequence. - length += Fallback (provider, ref fallbackBuffer, ref bufferArg, bytes, index - leftSoFar, leftSoFar); + length += Fallback (provider, ref fallbackBuffer, bytes, byteIndex - leftSoFar, leftSoFar); } // Return the final length to the caller. @@ -579,7 +581,7 @@ private unsafe static int InternalGetCharCount ( } // for GetCharCount() - static unsafe int Fallback (object provider, ref DecoderFallbackBuffer buffer, ref byte [] bufferArg, byte* bytes, long index, uint size) + static unsafe int Fallback (object provider, ref DecoderFallbackBuffer buffer, byte* bytes, long index, uint size) { if (buffer == null) { DecoderFallback fb = provider as DecoderFallback; @@ -588,20 +590,21 @@ static unsafe int Fallback (object provider, ref DecoderFallbackBuffer buffer, r else buffer = ((Decoder) provider).FallbackBuffer; } - if (bufferArg == null) - bufferArg = new byte [1]; - int ret = 0; - for (int i = 0; i < size; i++) { - bufferArg [0] = bytes [(int) index + i]; - buffer.Fallback (bufferArg, 0); - ret += buffer.Remaining; - buffer.Reset (); - } + + var bufferArg = new byte [size]; + + for (int i = 0; i < size; i++) + bufferArg [i] = bytes [(int) index + i]; + + buffer.Fallback (bufferArg, 0); + int ret = buffer.Remaining; + buffer.Reset (); + return ret; } // for GetChars() - static unsafe void Fallback (object provider, ref DecoderFallbackBuffer buffer, ref byte [] bufferArg, byte* bytes, long byteIndex, uint size, + static unsafe void Fallback (object provider, ref DecoderFallbackBuffer buffer, byte* bytes, long byteIndex, uint size, char* chars, ref int charIndex) { if (buffer == null) { @@ -611,23 +614,23 @@ static unsafe void Fallback (object provider, ref DecoderFallbackBuffer buffer, else buffer = ((Decoder) provider).FallbackBuffer; } - if (bufferArg == null) - bufferArg = new byte [1]; - for (int i = 0; i < size; i++) { - bufferArg [0] = bytes [byteIndex + i]; - buffer.Fallback (bufferArg, 0); - while (buffer.Remaining > 0) - chars [charIndex++] = buffer.GetNextChar (); - buffer.Reset (); - } + + var bufferArg = new byte [size]; + + for (int i = 0; i < size; i++) + bufferArg [i] = bytes [byteIndex + i]; + + buffer.Fallback (bufferArg, 0); + while (buffer.Remaining > 0) + chars [charIndex++] = buffer.GetNextChar (); + buffer.Reset (); } // Get the number of characters needed to decode a byte buffer. public override int GetCharCount (byte[] bytes, int index, int count) { DecoderFallbackBuffer buf = null; - byte [] bufferArg = null; - return InternalGetCharCount (bytes, index, count, 0, 0, DecoderFallback, ref buf, ref bufferArg, true); + return InternalGetCharCount (bytes, index, count, 0, 0, DecoderFallback, ref buf, true); } [CLSCompliant (false)] @@ -635,8 +638,7 @@ public override int GetCharCount (byte[] bytes, int index, int count) public unsafe override int GetCharCount (byte* bytes, int count) { DecoderFallbackBuffer buf = null; - byte [] bufferArg = null; - return InternalGetCharCount (bytes, count, 0, 0, DecoderFallback, ref buf, ref bufferArg, true); + return InternalGetCharCount (bytes, count, 0, 0, DecoderFallback, ref buf, true); } // Get the characters that result from decoding a byte buffer. @@ -644,7 +646,7 @@ private unsafe static int InternalGetChars ( byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex, ref uint leftOverBits, ref uint leftOverCount, object provider, - ref DecoderFallbackBuffer fallbackBuffer, ref byte [] bufferArg, bool flush) + ref DecoderFallbackBuffer fallbackBuffer, bool flush) { // Validate the parameters. if (bytes == null) { @@ -668,10 +670,10 @@ private unsafe static int InternalGetChars ( fixed (char* cptr = chars) { if (byteCount == 0 || byteIndex == bytes.Length) - return InternalGetChars (null, 0, cptr + charIndex, chars.Length - charIndex, ref leftOverBits, ref leftOverCount, provider, ref fallbackBuffer, ref bufferArg, flush); + return InternalGetChars (null, 0, cptr + charIndex, chars.Length - charIndex, ref leftOverBits, ref leftOverCount, provider, ref fallbackBuffer, flush); // otherwise... fixed (byte* bptr = bytes) - return InternalGetChars (bptr + byteIndex, byteCount, cptr + charIndex, chars.Length - charIndex, ref leftOverBits, ref leftOverCount, provider, ref fallbackBuffer, ref bufferArg, flush); + return InternalGetChars (bptr + byteIndex, byteCount, cptr + charIndex, chars.Length - charIndex, ref leftOverBits, ref leftOverCount, provider, ref fallbackBuffer, flush); } } @@ -679,7 +681,7 @@ private unsafe static int InternalGetChars ( byte* bytes, int byteCount, char* chars, int charCount, ref uint leftOverBits, ref uint leftOverCount, object provider, - ref DecoderFallbackBuffer fallbackBuffer, ref byte [] bufferArg, bool flush) + ref DecoderFallbackBuffer fallbackBuffer, bool flush) { int charIndex = 0, byteIndex = 0; int length = charCount; @@ -744,7 +746,7 @@ private unsafe static int InternalGetChars ( leftSize = 6; } else { // Invalid UTF-8 start character. - Fallback (provider, ref fallbackBuffer, ref bufferArg, bytes, byteIndex, 1, chars, ref posn); + Fallback (provider, ref fallbackBuffer, bytes, byteIndex, 1, chars, ref posn); } } else { // Process an extra byte in a multi-byte sequence. @@ -773,11 +775,12 @@ private unsafe static int InternalGetChars ( break; } if (overlong) { - Fallback (provider, ref fallbackBuffer, ref bufferArg, bytes, byteIndex - leftSoFar, leftSoFar, chars, ref posn); + Fallback (provider, ref fallbackBuffer, bytes, byteIndex - leftSoFar, leftSoFar, chars, ref posn); + --byteIndex; //process byte again } else if ((leftBits & 0xF800) == 0xD800) { // UTF-8 doesn't use surrogate characters - Fallback (provider, ref fallbackBuffer, ref bufferArg, bytes, byteIndex - leftSoFar, leftSoFar, chars, ref posn); + Fallback (provider, ref fallbackBuffer, bytes, byteIndex - leftSoFar, leftSoFar, chars, ref posn); } else { if (posn >= length) { @@ -797,13 +800,13 @@ private unsafe static int InternalGetChars ( chars[posn++] = (char)((leftBits & (uint)0x3FF) + (uint)0xDC00); } else { - Fallback (provider, ref fallbackBuffer, ref bufferArg, bytes, byteIndex - leftSoFar, leftSoFar, chars, ref posn); + Fallback (provider, ref fallbackBuffer, bytes, byteIndex - leftSoFar, leftSoFar, chars, ref posn); } leftSize = 0; } } else { // Invalid UTF-8 sequence: clear and restart. - Fallback (provider, ref fallbackBuffer, ref bufferArg, bytes, byteIndex - leftSoFar, leftSoFar, chars, ref posn); + Fallback (provider, ref fallbackBuffer, bytes, byteIndex - leftSoFar, leftSoFar, chars, ref posn); leftSize = 0; --byteIndex; } @@ -812,7 +815,7 @@ private unsafe static int InternalGetChars ( if (flush && leftSize != 0) { // We had left-over bytes that didn't make up // a complete UTF-8 character sequence. - Fallback (provider, ref fallbackBuffer, ref bufferArg, bytes, byteIndex - leftSoFar, leftSoFar, chars, ref posn); + Fallback (provider, ref fallbackBuffer, bytes, byteIndex - leftSoFar, leftSoFar, chars, ref posn); } leftOverBits = leftBits; leftOverCount = (leftSoFar | (leftSize << 4)); @@ -828,9 +831,8 @@ public override int GetChars (byte[] bytes, int byteIndex, int byteCount, uint leftOverBits = 0; uint leftOverCount = 0; DecoderFallbackBuffer buf = null; - byte [] bufferArg = null; return InternalGetChars (bytes, byteIndex, byteCount, chars, - charIndex, ref leftOverBits, ref leftOverCount, DecoderFallback, ref buf, ref bufferArg, true); + charIndex, ref leftOverBits, ref leftOverCount, DecoderFallback, ref buf, true); } [CLSCompliant (false)] @@ -838,11 +840,10 @@ public override int GetChars (byte[] bytes, int byteIndex, int byteCount, public unsafe override int GetChars (byte* bytes, int byteCount, char* chars, int charCount) { DecoderFallbackBuffer buf = null; - byte [] bufferArg = null; uint leftOverBits = 0; uint leftOverCount = 0; return InternalGetChars (bytes, byteCount, chars, - charCount, ref leftOverBits, ref leftOverCount, DecoderFallback, ref buf, ref bufferArg, true); + charCount, ref leftOverBits, ref leftOverCount, DecoderFallback, ref buf, true); } // Get the maximum number of bytes needed to encode a @@ -952,17 +953,15 @@ public UTF8Decoder (Encoding encoding) public override int GetCharCount (byte[] bytes, int index, int count) { DecoderFallbackBuffer buf = null; - byte [] bufferArg = null; return InternalGetCharCount (bytes, index, count, - leftOverBits, leftOverCount, this, ref buf, ref bufferArg, false); + leftOverBits, leftOverCount, this, ref buf, false); } public override int GetChars (byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex) { DecoderFallbackBuffer buf = null; - byte [] bufferArg = null; return InternalGetChars (bytes, byteIndex, byteCount, - chars, charIndex, ref leftOverBits, ref leftOverCount, this, ref buf, ref bufferArg, false); + chars, charIndex, ref leftOverBits, ref leftOverCount, this, ref buf, false); } } // class UTF8Decoder diff --git a/mcs/class/corlib/System.Text/UnicodeEncoding.cs b/mcs/class/corlib/System.Text/UnicodeEncoding.cs index edb57e69ca2..48077a2452b 100644 --- a/mcs/class/corlib/System.Text/UnicodeEncoding.cs +++ b/mcs/class/corlib/System.Text/UnicodeEncoding.cs @@ -345,7 +345,7 @@ public override int GetMaxByteCount (int charCount) if (charCount < 0) { throw new ArgumentOutOfRangeException ("charCount", _("ArgRange_NonNegative")); } - return charCount * 2; + return charCount * 2 + 2; } // Get the maximum number of characters needed to decode a @@ -356,7 +356,7 @@ public override int GetMaxCharCount (int byteCount) throw new ArgumentOutOfRangeException ("byteCount", _("ArgRange_NonNegative")); } - return byteCount / 2; + return (byteCount + 1) / 2 + 1; } // Get a Unicode-specific decoder that is attached to this instance. diff --git a/mcs/class/corlib/System.Threading.Tasks/Task.cs b/mcs/class/corlib/System.Threading.Tasks/Task.cs index 1f8165a0d48..4f4abd33e9c 100644 --- a/mcs/class/corlib/System.Threading.Tasks/Task.cs +++ b/mcs/class/corlib/System.Threading.Tasks/Task.cs @@ -635,7 +635,7 @@ void ProcessChildExceptions (bool isParent = false) #region Cancel and Wait related method - internal void CancelReal () + internal void CancelReal (bool notifyParent = false) { Status = TaskStatus.Canceled; @@ -643,6 +643,9 @@ internal void CancelReal () wait_handle.Set (); ProcessCompleteDelegates (); + + if (notifyParent && parent != null && NotifyParentOnFinish ()) + parent = null; } void HandleGenericException (Exception e) diff --git a/mcs/class/corlib/System.Threading.Tasks/TaskContinuation.cs b/mcs/class/corlib/System.Threading.Tasks/TaskContinuation.cs index 2a0547850bd..8ede25eebe4 100644 --- a/mcs/class/corlib/System.Threading.Tasks/TaskContinuation.cs +++ b/mcs/class/corlib/System.Threading.Tasks/TaskContinuation.cs @@ -94,7 +94,7 @@ bool ContinuationStatusCheck (TaskContinuationOptions kind) public void Execute () { if (!ContinuationStatusCheck (continuationOptions)) { - task.CancelReal (); + task.CancelReal (notifyParent : true); task.Dispose (); return; } diff --git a/mcs/class/corlib/System/AppDomain.cs b/mcs/class/corlib/System/AppDomain.cs index 5ebd4db216e..f04fe2a006d 100644 --- a/mcs/class/corlib/System/AppDomain.cs +++ b/mcs/class/corlib/System/AppDomain.cs @@ -1354,6 +1354,11 @@ private void DoDomainUnload () 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)); @@ -1405,6 +1410,10 @@ internal void ProcessMessageInDomain (byte[] arrRequest, CADMethodCallMessage ca [method: SecurityPermission (SecurityAction.LinkDemand, ControlAppDomain = true)] public event UnhandledExceptionEventHandler UnhandledException; +#if NET_4_5 + public event EventHandler FirstChanceException; +#endif + #if NET_4_0 [MonoTODO] public bool IsHomogenous { diff --git a/mcs/class/corlib/System/DateTime.cs b/mcs/class/corlib/System/DateTime.cs index 735599680c5..8ff4901e4a3 100644 --- a/mcs/class/corlib/System/DateTime.cs +++ b/mcs/class/corlib/System/DateTime.cs @@ -107,7 +107,7 @@ public struct DateTime : IFormattable, IConvertible, IComparable, ISerializable, "H:mzzz", "H:m", "H tt", // Specifies AM to disallow '8'. - "H'\u6642'm'\u5206's'\u79D2'", + "H'\u6642'm'\u5206's'\u79D2'" }; // DateTime.Parse date patterns extend ParseExact patterns as follows: @@ -885,6 +885,9 @@ internal static bool CoreParse (string s, IFormatProvider provider, DateTimeStyl if (_DoParse (s, firstPart, ParseTimeFormats [j], false, out result, out dto, dfi, styles, true, ref incompleteFormat, ref longYear)) return true; } + + if (_DoParse (s, firstPart, "zzz", false, out result, out dto, dfi, styles, true, ref incompleteFormat, ref longYear)) + return true; } // @@ -1466,6 +1469,25 @@ private static bool _DoParse (string s, if (num_parsed == -1) return false; fractionalSeconds = decimalNumber / Math.Pow(10.0, num_parsed); + + //Parse ISO8601 with an unlimited number of fractional digits. + if (!exact && num == 6 && hour != -1 && minute != -1 && second != -1) { + var total_num_parsed = num_parsed; + while (true) { + valuePos += num_parsed; + decimalNumber = (double) _ParseNumber (s, valuePos, 0, 1, leading_zeros, sloppy_parsing, out num_parsed); + if (num_parsed < 1) { + num_parsed = 0; + break; + } + + total_num_parsed += num_parsed; + if (total_num_parsed > 15) + continue; //not enough precision, ignore additional digits. + + fractionalSeconds += decimalNumber / Math.Pow (10.0, total_num_parsed); + } + } break; case 't': if (!_ParseAmPm (s, valuePos, num > 0 ? 0 : 1, dfi, exact, out num_parsed, ref ampm)) @@ -1722,7 +1744,7 @@ private static bool _DoParse (string s, if (tzsign == -1) { if (result != DateTime.MinValue) { try { - if ((style & DateTimeStyles.AssumeUniversal) != 0) { + if (((style & DateTimeStyles.AssumeUniversal) != 0) || useutc) { dto = new DateTimeOffset (result, TimeSpan.Zero); } else if ((style & DateTimeStyles.AssumeLocal) != 0) { var offset = use_invariant ? diff --git a/mcs/class/corlib/System/Environment.cs b/mcs/class/corlib/System/Environment.cs index 12260621239..21128defd9b 100644 --- a/mcs/class/corlib/System/Environment.cs +++ b/mcs/class/corlib/System/Environment.cs @@ -44,7 +44,7 @@ namespace System { [ComVisible (true)] - public static class Environment { + public static partial class Environment { /* * This is the version number of the corlib-runtime interface. When @@ -475,9 +475,6 @@ public static IDictionary GetEnvironmentVariables () } #endif - [MethodImplAttribute (MethodImplOptions.InternalCall)] - private extern static string GetWindowsFolderPath (int folder); - /// /// Returns the fully qualified path of the /// folder specified by the "folder" parameter @@ -486,6 +483,12 @@ public static string GetFolderPath (SpecialFolder folder) { return GetFolderPath (folder, SpecialFolderOption.None); } + +// for monotouch, not monotouch_runtime +#if !(MONOTOUCH && FULL_AOT_RUNTIME) + [MethodImplAttribute (MethodImplOptions.InternalCall)] + private extern static string GetWindowsFolderPath (int folder); + #if NET_4_0 public #endif @@ -577,38 +580,15 @@ internal static string UnixGetFolderPath (SpecialFolder folder, SpecialFolderOpt // personal == ~ case SpecialFolder.Personal: -#if MONOTOUCH - return Path.Combine (home, "Documents"); -#else return home; -#endif + // use FDO's CONFIG_HOME. This data will be synced across a network like the windows counterpart. case SpecialFolder.ApplicationData: -#if MONOTOUCH - { - string dir = Path.Combine (Path.Combine (home, "Documents"), ".config"); - if (option == SpecialFolderOption.Create){ - if (!Directory.Exists (dir)) - Directory.CreateDirectory (dir); - } - return dir; - } -#else return config; -#endif + //use FDO's DATA_HOME. This is *NOT* synced case SpecialFolder.LocalApplicationData: -#if MONOTOUCH - { - string dir = Path.Combine (home, "Documents"); - if (!Directory.Exists (dir)) - Directory.CreateDirectory (dir); - - return dir; - } -#else return data; -#endif case SpecialFolder.Desktop: case SpecialFolder.DesktopDirectory: @@ -705,8 +685,9 @@ internal static string UnixGetFolderPath (SpecialFolder folder, SpecialFolderOpt return "/usr/share"; default: throw new ArgumentException ("Invalid SpecialFolder"); - } - } + } + } +#endif [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)] @@ -884,7 +865,7 @@ public static extern int ProcessorCount { } // private methods -#if MOBILE +#if (MONOTOUCH || MONODROID || XAMMAC) internal const bool IsRunningOnWindows = false; #else internal static bool IsRunningOnWindows { diff --git a/mcs/class/corlib/System/FirstChanceExceptionEventArgs.cs b/mcs/class/corlib/System/FirstChanceExceptionEventArgs.cs new file mode 100644 index 00000000000..d39fbdc715e --- /dev/null +++ b/mcs/class/corlib/System/FirstChanceExceptionEventArgs.cs @@ -0,0 +1,44 @@ +// +// System.FirstChangeExceptionEventArgs.cs +// +// Copyright 2014 Xamarin Inc (http://www.xamarin.com). +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +#if NET_4_5 +using System; + +public class FirstChanceExceptionEventArgs : EventArgs +{ + Exception exception; + + public FirstChanceExceptionEventArgs (Exception exception) { + this.exception = exception; + } + + public Exception Exception { + get { + return exception; + } + } +} + +#endif \ No newline at end of file diff --git a/mcs/class/corlib/System/InvalidTimeZoneException.cs b/mcs/class/corlib/System/InvalidTimeZoneException.cs index 7096e56cd33..7beb2d4982c 100644 --- a/mcs/class/corlib/System/InvalidTimeZoneException.cs +++ b/mcs/class/corlib/System/InvalidTimeZoneException.cs @@ -24,8 +24,6 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#if NET_4_0 - using System.Runtime.CompilerServices; namespace System @@ -36,7 +34,10 @@ namespace System #elif NET_4_0 [TypeForwardedFrom (Consts.AssemblySystemCore_3_5)] #endif - public class InvalidTimeZoneException : Exception +#if NET_4_0 + public +#endif + class InvalidTimeZoneException : Exception { public InvalidTimeZoneException () : base () {} @@ -51,5 +52,3 @@ protected InvalidTimeZoneException (Runtime.Serialization.SerializationInfo info {} } } - -#endif diff --git a/mcs/class/corlib/System/String.cs b/mcs/class/corlib/System/String.cs index 2a408933eac..65e460647ca 100644 --- a/mcs/class/corlib/System/String.cs +++ b/mcs/class/corlib/System/String.cs @@ -2688,24 +2688,8 @@ internal unsafe void InternalSetChar (int idx, char val) } } - 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. diff --git a/mcs/class/corlib/System/TimeSpan.cs b/mcs/class/corlib/System/TimeSpan.cs index 7762dfc9177..f6937ef3ca2 100644 --- a/mcs/class/corlib/System/TimeSpan.cs +++ b/mcs/class/corlib/System/TimeSpan.cs @@ -614,41 +614,76 @@ string ToStringCustom (string format) element = parser.GetNextElement (); switch (element.Type) { - case FormatElementType.Days: - value = Math.Abs (Days); - break; - case FormatElementType.Hours: - value = Math.Abs (Hours); - break; - case FormatElementType.Minutes: - value = Math.Abs (Minutes); - break; - case FormatElementType.Seconds: - value = Math.Abs (Seconds); - break; - case FormatElementType.Ticks: - case FormatElementType.TicksUppercase: - value = Math.Abs (Milliseconds); - if (value == 0) { - if (element.Type == FormatElementType.Ticks) - break; - - continue; - } + case FormatElementType.Days: + value = Math.Abs (Days); + break; + case FormatElementType.Hours: + value = Math.Abs (Hours); + break; + case FormatElementType.Minutes: + value = Math.Abs (Minutes); + break; + case FormatElementType.Seconds: + value = Math.Abs (Seconds); + break; + case FormatElementType.Ticks: + case FormatElementType.TicksUppercase: + // + // TODO: Unify with datetime ticks formatting + // + value = (int)(_ticks % TicksPerSecond); + if (value == 0) { + if (element.Type == FormatElementType.Ticks) + break; - int threshold = (int)Math.Pow (10, element.IntValue); - while (value >= threshold) - value /= 10; - sb.Append (value.ToString ()); continue; - case FormatElementType.EscapedChar: - sb.Append (element.CharValue); + } + + int total_length = element.IntValue; + const int max_length = 7; + int digits = max_length; + for (var dv = (int)Math.Pow (10, max_length - 1); dv > value; dv /= 10, --digits) + ; + + // + // Skip only leading zeros in F format + // + if (element.Type == FormatElementType.TicksUppercase && max_length - digits >= total_length) continue; - case FormatElementType.Literal: - sb.Append (element.StringValue); + + // + // Add leading zeros + // + int leading = 0; + for (; leading < total_length && leading < max_length - digits; ++leading) { + sb.Append ("0"); + } + + if (total_length == leading) continue; - default: - throw new FormatException ("The format is not recognized."); + + // + // Remove trailing zeros + // + if (element.Type == FormatElementType.TicksUppercase) { + while (value % 10 == 0) + value /= 10; + } + + var max_value = (int)Math.Pow (10, total_length - leading); + while (value >= max_value) + value /= 10; + + sb.Append (value.ToString (CultureInfo.InvariantCulture)); + continue; + case FormatElementType.EscapedChar: + sb.Append (element.CharValue); + continue; + case FormatElementType.Literal: + sb.Append (element.StringValue); + continue; + default: + throw new FormatException ("The format is not recognized."); } sb.Append (value.ToString ("D" + element.IntValue.ToString ())); diff --git a/mcs/class/corlib/System/TimeZone.cs b/mcs/class/corlib/System/TimeZone.cs index cea224133e4..f4e01b03be3 100644 --- a/mcs/class/corlib/System/TimeZone.cs +++ b/mcs/class/corlib/System/TimeZone.cs @@ -144,22 +144,7 @@ public virtual DateTime ToLocalTime (DateTime time) return DateTime.SpecifyKind (DateTime.MinValue, DateTimeKind.Local); } - DateTime local = DateTime.SpecifyKind (time.Add (utcOffset), DateTimeKind.Local); - DaylightTime dlt = GetDaylightChanges (time.Year); - if (dlt.Delta.Ticks == 0) - return DateTime.SpecifyKind (local, DateTimeKind.Local); - - // FIXME: check all of the combination of - // - basis: local-based or UTC-based - // - hemisphere: Northern or Southern - // - offset: positive or negative - - // PST should work fine here. - if (local < dlt.End && dlt.End.Subtract (dlt.Delta) <= local) - return DateTime.SpecifyKind (local, DateTimeKind.Local); - - TimeSpan localOffset = GetUtcOffset (local); - return DateTime.SpecifyKind (time.Add (localOffset), DateTimeKind.Local); + return DateTime.SpecifyKind (time.Add (utcOffset), DateTimeKind.Local); } public virtual DateTime ToUniversalTime (DateTime time) @@ -252,17 +237,6 @@ internal class CurrentSystemTimeZone : TimeZone, IDeserializationCallback { // A yearwise cache of DaylightTime. private Dictionary m_CachedDaylightChanges = new Dictionary (1); - // the offset when daylightsaving is not on (in ticks) - private long m_ticksOffset; - - // the offset when daylightsaving is not on. - [NonSerialized] - private TimeSpan utcOffsetWithOutDLS; - - // the offset when daylightsaving is on. - [NonSerialized] - private TimeSpan utcOffsetWithDLS; - internal enum TimeZoneData { DaylightSavingStartIdx, @@ -315,8 +289,6 @@ internal CurrentSystemTimeZone (long lnow) m_standardName = Locale.GetText (names[(int)TimeZoneNames.StandardNameIdx]); m_daylightName = Locale.GetText (names[(int)TimeZoneNames.DaylightNameIdx]); - m_ticksOffset = data[(int)TimeZoneData.UtcOffsetIdx]; - DaylightTime dlt = GetDaylightTimeFromData (data); m_CachedDaylightChanges.Add (now.Year, dlt); OnDeserialization (dlt); @@ -366,20 +338,7 @@ public override TimeSpan GetUtcOffset (DateTime time) if (time.Kind == DateTimeKind.Utc) return TimeSpan.Zero; - if (IsDaylightSavingTime (time) && !IsAmbiguousTime (time)) - return utcOffsetWithDLS; - - return utcOffsetWithOutDLS; - } - - private bool IsAmbiguousTime (DateTime time) - { - if (time.Kind == DateTimeKind.Utc) - return false; - - DaylightTime changes = GetDaylightChanges (time.Year); - - return time < changes.End && time >= changes.End - changes.Delta; + return TimeZoneInfo.Local.GetUtcOffset (time); } void IDeserializationCallback.OnDeserialization (object sender) @@ -400,8 +359,6 @@ private void OnDeserialization (DaylightTime dlt) } else this_year = dlt.Start.Year; - utcOffsetWithOutDLS = new TimeSpan (m_ticksOffset); - utcOffsetWithDLS = new TimeSpan (m_ticksOffset + dlt.Delta.Ticks); this_year_dlt = dlt; } diff --git a/mcs/class/corlib/System/TimeZoneNotFoundException.cs b/mcs/class/corlib/System/TimeZoneNotFoundException.cs index 79b094ddde0..643b82104b3 100644 --- a/mcs/class/corlib/System/TimeZoneNotFoundException.cs +++ b/mcs/class/corlib/System/TimeZoneNotFoundException.cs @@ -24,7 +24,6 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#if NET_4_0 using System.Runtime.CompilerServices; @@ -36,7 +35,10 @@ namespace System #elif NET_4_0 [TypeForwardedFrom (Consts.AssemblySystemCore_3_5)] #endif - public class TimeZoneNotFoundException : Exception +#if NET_4_0 + public +#endif + class TimeZoneNotFoundException : Exception { public TimeZoneNotFoundException () : base () {} @@ -51,5 +53,3 @@ protected TimeZoneNotFoundException (Runtime.Serialization.SerializationInfo inf {} } } - -#endif diff --git a/mcs/class/corlib/Test/Mono/DataConvertTest.cs b/mcs/class/corlib/Test/Mono/DataConvertTest.cs index 89f99e918c1..f02a6a7db40 100644 --- a/mcs/class/corlib/Test/Mono/DataConvertTest.cs +++ b/mcs/class/corlib/Test/Mono/DataConvertTest.cs @@ -8,7 +8,7 @@ using NUnit.Framework.SyntaxHelpers; #endif -namespace MonoTests { +namespace MonoTests.Mono { [TestFixture] public class DataConverterTest @@ -50,9 +50,9 @@ public void ArrayTests () [Test] public void StringAlignment () { - byte[] packed = Mono.DataConverter.Pack ("bz8", 1, TEST_STRING); + byte[] packed = global::Mono.DataConverter.Pack ("bz8", 1, TEST_STRING); - IList unpacked = Mono.DataConverter.Unpack ("bz8", packed, 0); + IList unpacked = global::Mono.DataConverter.Unpack ("bz8", packed, 0); Assert.AreEqual(1, (byte) unpacked[0]); Assert.AreEqual(TEST_STRING, new string((char[]) unpacked[1])); @@ -65,4 +65,4 @@ public void UnpackTests () Assert.That ((f - 3.14f), Is.LessThanOrEqualTo (Single.Epsilon)); } } -} \ No newline at end of file +} diff --git a/mcs/class/corlib/Test/System.Globalization/CalendarTest.cs b/mcs/class/corlib/Test/System.Globalization/CalendarTest.cs index 0987da7aed6..c1b34196e95 100644 --- a/mcs/class/corlib/Test/System.Globalization/CalendarTest.cs +++ b/mcs/class/corlib/Test/System.Globalization/CalendarTest.cs @@ -3,6 +3,7 @@ // (C) 2002 Ulrich Kunitz // +using System.Collections.Generic; using NUnit.Framework; using System; using System.Globalization; @@ -797,6 +798,44 @@ public void TestToFourDigitYear2 () Assert.AreEqual (4363, kc.ToFourDigitYear (4363), "#4-4"); } + public void TestDaysInYear (Calendar calendar, int year) + { + var daysInYear = calendar.GetDaysInYear (year); + var daysInMonths = 0; + var monthInYear = calendar.GetMonthsInYear (year); + for (var m = 1; m <= monthInYear; m++) + daysInMonths += calendar.GetDaysInMonth (year, m); + + Assert.AreEqual (daysInYear, daysInMonths, string.Format("Calendar:{0} Year:{1}",calendar.GetType(), year)); + } + + [Test] + public void DaysInYear () + { + var calendars = new List (acal) { + new UmAlQuraCalendar () + }; + + foreach (var calendar in calendars) { + var minYear = calendar.GetYear (calendar.MinSupportedDateTime); + var maxYear = calendar.GetYear (calendar.MaxSupportedDateTime) - 1 ; + var midYear = calendar.GetYear (DateTime.Now); + var yearsTested = Math.Min (1000, (maxYear - minYear) / 2); + + midYear -= yearsTested / 2; + + int y1 = minYear, y2 = maxYear, y3 = midYear; + for (var i = 0; i < yearsTested; i++) { + TestDaysInYear (calendar, y1); + TestDaysInYear (calendar, y2); + if (y3 > minYear && y3 < maxYear) + TestDaysInYear (calendar, y3); + + y1++; y2--; y3++; + } + } + } + // TODO: more tests :-) } // class CalendarTest diff --git a/mcs/class/corlib/Test/System.IO/DirectoryInfoTest.cs b/mcs/class/corlib/Test/System.IO/DirectoryInfoTest.cs index 699f94be803..3e34c81352a 100644 --- a/mcs/class/corlib/Test/System.IO/DirectoryInfoTest.cs +++ b/mcs/class/corlib/Test/System.IO/DirectoryInfoTest.cs @@ -10,6 +10,7 @@ using System; using System.Collections; +using System.Collections.Generic; using System.IO; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; @@ -1059,6 +1060,23 @@ public void ToStringTest () Assert.AreEqual (TempFolder + DSC + "ToString.Test", info.ToString ()); } +#if NET_4_0 + [Test] + public void EnumerateFileSystemInfosTest () + { + var dirInfo = new DirectoryInfo (TempFolder); + dirInfo.CreateSubdirectory ("1").CreateSubdirectory ("a"); + dirInfo.CreateSubdirectory ("2").CreateSubdirectory ("b"); + + var l = new List (); + foreach (var info in dirInfo.EnumerateFileSystemInfos ("*", SearchOption.AllDirectories)) + l.Add (info.Name); + + l.Sort (); + Assert.AreEqual ("1,2,a,b", string.Join (",", l), "#1"); + } +#endif + #if !MOBILE [Test] public void Serialization () @@ -1111,7 +1129,7 @@ private void Symlink_helper () try { Directory.CreateDirectory (path); Directory.CreateDirectory (dir); - Mono.Unix.UnixSymbolicLinkInfo li = new Mono.Unix.UnixSymbolicLinkInfo (link); + global::Mono.Unix.UnixSymbolicLinkInfo li = new global::Mono.Unix.UnixSymbolicLinkInfo (link); li.CreateSymbolicLinkTo (dir); DirectoryInfo info = new DirectoryInfo (path); diff --git a/mcs/class/corlib/Test/System.IO/DirectoryTest.cs b/mcs/class/corlib/Test/System.IO/DirectoryTest.cs index 82536169f59..f2d7e03d3d6 100644 --- a/mcs/class/corlib/Test/System.IO/DirectoryTest.cs +++ b/mcs/class/corlib/Test/System.IO/DirectoryTest.cs @@ -374,11 +374,11 @@ public void ExistsAccessDenied () string path = TempFolder + DSC + "ExistsAccessDenied"; Directory.CreateDirectory (path); - Mono.Posix.Syscall.chmod (path, 0); + global::Mono.Posix.Syscall.chmod (path, 0); try { Assert.IsFalse (Directory.Exists(path + DSC + "b")); } finally { - Mono.Posix.Syscall.chmod (path, (Mono.Posix.FileMode) 755); + global::Mono.Posix.Syscall.chmod (path, (global::Mono.Posix.FileMode) 755); Directory.Delete (path); } } diff --git a/mcs/class/corlib/Test/System.Reflection.Emit/DynamicMethodTest.cs b/mcs/class/corlib/Test/System.Reflection.Emit/DynamicMethodTest.cs index 271412269c0..f65ac28ef5e 100644 --- a/mcs/class/corlib/Test/System.Reflection.Emit/DynamicMethodTest.cs +++ b/mcs/class/corlib/Test/System.Reflection.Emit/DynamicMethodTest.cs @@ -317,10 +317,12 @@ public void Circular_Refs () { m1.Invoke(null, new object[] { 5 }); } + // Disabl known warning, the Field is never used directly from C# + #pragma warning disable 414 class Host { static string Field = "foo"; } - + #pragma warning restore 414 [Test] [Category ("NotDotNet")] // https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=297416 public void TestOwnerMemberAccess () diff --git a/mcs/class/corlib/Test/System.Reflection.Emit/GenericTypeParameterBuilderTest.cs b/mcs/class/corlib/Test/System.Reflection.Emit/GenericTypeParameterBuilderTest.cs index 1559d66369a..7f9db3b99fd 100644 --- a/mcs/class/corlib/Test/System.Reflection.Emit/GenericTypeParameterBuilderTest.cs +++ b/mcs/class/corlib/Test/System.Reflection.Emit/GenericTypeParameterBuilderTest.cs @@ -27,7 +27,6 @@ public class GenericTypeParameterBuilderTest { AssemblyBuilder assembly; ModuleBuilder module; - int typeCount; static string ASSEMBLY_NAME = "MonoTests.System.Reflection.Emit.TypeBuilderTest"; [SetUp] @@ -46,7 +45,6 @@ protected void SetUp (AssemblyBuilderAccess mode) assemblyName, mode, Path.GetTempPath ()); module = assembly.DefineDynamicModule ("module1"); - typeCount = 0; } [Test] diff --git a/mcs/class/corlib/Test/System.Reflection.Emit/TypeBuilderTest.cs b/mcs/class/corlib/Test/System.Reflection.Emit/TypeBuilderTest.cs index 382f3f25527..b1b7cf320f3 100644 --- a/mcs/class/corlib/Test/System.Reflection.Emit/TypeBuilderTest.cs +++ b/mcs/class/corlib/Test/System.Reflection.Emit/TypeBuilderTest.cs @@ -92,8 +92,8 @@ public interface IDestroyable } public class Tuple { - A a; - B b; + public A a; + public B b; } private AssemblyBuilder assembly; diff --git a/mcs/class/corlib/Test/System.Reflection/AssemblyNameCas.cs b/mcs/class/corlib/Test/System.Reflection/AssemblyNameCas.cs index a24a4868d9b..087297b6f24 100644 --- a/mcs/class/corlib/Test/System.Reflection/AssemblyNameCas.cs +++ b/mcs/class/corlib/Test/System.Reflection/AssemblyNameCas.cs @@ -42,7 +42,6 @@ namespace MonoCasTests.System.Reflection { public class AssemblyNameCas { private MonoTests.System.Reflection.AssemblyNameTest ant; - private AssemblyName main; [TestFixtureSetUp] public void FixtureSetUp () diff --git a/mcs/class/corlib/Test/System.Reflection/FieldInfoTest.cs b/mcs/class/corlib/Test/System.Reflection/FieldInfoTest.cs index ccd923fa59c..a3639864f6a 100644 --- a/mcs/class/corlib/Test/System.Reflection/FieldInfoTest.cs +++ b/mcs/class/corlib/Test/System.Reflection/FieldInfoTest.cs @@ -73,6 +73,8 @@ public class Class3 : Class2 { } + // Disable this warning, as the purpose of this struct is to poke at the internal via reflection + #pragma warning disable 649 class FieldInvokeMatrix { public Byte field_Byte; @@ -102,6 +104,7 @@ class FieldInvokeMatrix public Int64Enum field_Int64Enum; public UInt64Enum field_UInt64Enum; } + #pragma warning restore 649 public enum ByteEnum : byte { @@ -376,10 +379,13 @@ public void PseudoCustomAttributes () Assert.AreEqual (typeof (Marshal1), Type.GetType (attr.MarshalType), "#I4"); } + // Disable "field not used warning", this is intended. +#pragma warning disable 649 class Foo { public static int static_field; public int field; } +#pragma warning restore 649 [ExpectedException (typeof (ArgumentException))] public void GetValueWrongObject () @@ -1359,16 +1365,24 @@ public enum LongEnum : long { } + // We do not refernece the field, that is expected +#pragma warning disable 169 // Helper classes class RefOnlyFieldClass { // Helper property static int RefOnlyField; } - +#pragma warning restore 169 + class NonPublicFieldClass { protected int protectedField; + + public void Dummy () + { + protectedField = 1; + } } public class FieldInfoTest diff --git a/mcs/class/corlib/Test/System.Reflection/MethodInfoTest.cs b/mcs/class/corlib/Test/System.Reflection/MethodInfoTest.cs index 65adf97aa51..00349880e1f 100644 --- a/mcs/class/corlib/Test/System.Reflection/MethodInfoTest.cs +++ b/mcs/class/corlib/Test/System.Reflection/MethodInfoTest.cs @@ -42,9 +42,12 @@ #endif namespace A.B.C { + // Disable expected warning +#pragma warning disable 169 public struct MethodInfoTestStruct { int p; } +#pragma warning restore 169 } namespace MonoTests.System.Reflection { @@ -253,7 +256,7 @@ public void ToStringWithPointerSignatures () //bug #409583 public struct SimpleStruct { - int a; + public int a; } public static unsafe SimpleStruct* PtrFunc2 (SimpleStruct* a, A.B.C.MethodInfoTestStruct *b) diff --git a/mcs/class/corlib/Test/System.Reflection/MonoGenericClassTest.cs b/mcs/class/corlib/Test/System.Reflection/MonoGenericClassTest.cs index 0b02596ec5b..e47b5e1eb79 100644 --- a/mcs/class/corlib/Test/System.Reflection/MonoGenericClassTest.cs +++ b/mcs/class/corlib/Test/System.Reflection/MonoGenericClassTest.cs @@ -178,7 +178,7 @@ public void ClassMustNotBeRegisteredAfterTypeBuilderIsFinished () } public class Bar { - public class Foo {} + public class Foo {} } [Test] diff --git a/mcs/class/corlib/Test/System.Reflection/ReflectedTypeTest.cs b/mcs/class/corlib/Test/System.Reflection/ReflectedTypeTest.cs index bcc814e04d3..8347b4dabf7 100644 --- a/mcs/class/corlib/Test/System.Reflection/ReflectedTypeTest.cs +++ b/mcs/class/corlib/Test/System.Reflection/ReflectedTypeTest.cs @@ -29,6 +29,8 @@ using System.Reflection; using NUnit.Framework; +// Various fields in this class are not used directly by the C# code, they are only here to be reflected upon +#pragma warning disable 649 namespace MonoTests.System.Reflection { [TestFixture] diff --git a/mcs/class/corlib/Test/System.Runtime.CompilerServices/ConditionalWeakTableTest.cs b/mcs/class/corlib/Test/System.Runtime.CompilerServices/ConditionalWeakTableTest.cs index 92d19fe367e..f6f4dabe2ba 100644 --- a/mcs/class/corlib/Test/System.Runtime.CompilerServices/ConditionalWeakTableTest.cs +++ b/mcs/class/corlib/Test/System.Runtime.CompilerServices/ConditionalWeakTableTest.cs @@ -402,9 +402,12 @@ public void PromotedCwtPointingToYoungStuff () { static int reachable = 0; public class FinalizableLink { + // The sole purpose of this object is to keep a reference to another object, so it is fine to not use it. + #pragma warning disable 414 object obj; - ConditionalWeakTable cwt; int id; + #pragma warning restore 414 + ConditionalWeakTable cwt; public FinalizableLink (int id, object obj, ConditionalWeakTable cwt) { this.id = id; diff --git a/mcs/class/corlib/Test/System.Runtime.CompilerServices/RuntimeHelpersTest.cs b/mcs/class/corlib/Test/System.Runtime.CompilerServices/RuntimeHelpersTest.cs index fc4010bd21c..593305d4a67 100644 --- a/mcs/class/corlib/Test/System.Runtime.CompilerServices/RuntimeHelpersTest.cs +++ b/mcs/class/corlib/Test/System.Runtime.CompilerServices/RuntimeHelpersTest.cs @@ -94,8 +94,10 @@ public void RunClassConstructor_Default () RuntimeHelpers.RunClassConstructor (rth); } + // Expected the handle here is that way, because we are going to test for an ArgumentException being thrown +#pragma warning disable 649 static RuntimeTypeHandle handle; - +#pragma warning restore 649 [Test] [ExpectedException (typeof (ArgumentException))] public void RunClassConstructor_Uninitialized () @@ -122,7 +124,11 @@ class Fielder { } static RuntimeFieldHandle rfh = typeof (Fielder).GetField ("array").FieldHandle; + + // Disable expected warning: the point of the test is to validate that an exception is thrown for something with a null (the default value in this case) + #pragma warning disable 649 static RuntimeFieldHandle static_rfh; + #pragma warning restore 649 [Test] [ExpectedException (typeof (ArgumentNullException))] diff --git a/mcs/class/corlib/Test/System.Runtime.CompilerServices/TaskAwaiterTest.cs b/mcs/class/corlib/Test/System.Runtime.CompilerServices/TaskAwaiterTest.cs index 5237e377e38..1bc9d384147 100644 --- a/mcs/class/corlib/Test/System.Runtime.CompilerServices/TaskAwaiterTest.cs +++ b/mcs/class/corlib/Test/System.Runtime.CompilerServices/TaskAwaiterTest.cs @@ -72,6 +72,11 @@ protected override bool TryExecuteTaskInline (Task task, bool taskWasPreviouslyQ Interlocked.Increment (ref ic); return false; } + + public override string ToString () + { + return "Scheduler-" + name; + } } class SingleThreadSynchronizationContext : SynchronizationContext diff --git a/mcs/class/corlib/Test/System.Runtime.InteropServices/GCHandleTest.cs b/mcs/class/corlib/Test/System.Runtime.InteropServices/GCHandleTest.cs index 1ac8a825b64..17fe0d9045d 100644 --- a/mcs/class/corlib/Test/System.Runtime.InteropServices/GCHandleTest.cs +++ b/mcs/class/corlib/Test/System.Runtime.InteropServices/GCHandleTest.cs @@ -18,8 +18,11 @@ namespace MonoTests.System.Runtime.InteropServices [TestFixture] public class GCHandleTest { + // Expected warning, the tests that reference this handle are testing for the default values of the object + #pragma warning disable 649 static GCHandle handle; - + #pragma warning restore 649 + [Test] public void DefaultZeroValue_Allocated () { diff --git a/mcs/class/corlib/Test/System.Runtime.InteropServices/MarshalTest.cs b/mcs/class/corlib/Test/System.Runtime.InteropServices/MarshalTest.cs index d6f2a49bf38..28943159aa1 100644 --- a/mcs/class/corlib/Test/System.Runtime.InteropServices/MarshalTest.cs +++ b/mcs/class/corlib/Test/System.Runtime.InteropServices/MarshalTest.cs @@ -28,7 +28,7 @@ class ClsSequential { public int field; } - class ClsNoLayout { + public class ClsNoLayout { public int field; } @@ -173,12 +173,12 @@ public void AllocHGlobalZeroSize () Marshal.FreeHGlobal (ptr); } - struct Foo { - int a; - static int b; - long c; - static char d; - int e; + public struct Foo { + public int a; + public static int b; + public long c; + public static char d; + public int e; } [Test] diff --git a/mcs/class/corlib/Test/System.Runtime.Serialization/SerializationTest.cs b/mcs/class/corlib/Test/System.Runtime.Serialization/SerializationTest.cs index 90b2d3f73fc..48e686ab8dd 100644 --- a/mcs/class/corlib/Test/System.Runtime.Serialization/SerializationTest.cs +++ b/mcs/class/corlib/Test/System.Runtime.Serialization/SerializationTest.cs @@ -637,6 +637,8 @@ public void CheckEquals (SomeValues obj, string context) Assert.AreEqual (_char, obj._char, context + "._char"); Assert.AreEqual (_dateTime, obj._dateTime, context + "._dateTime"); Assert.AreEqual (_decimal, obj._decimal, context + "._decimal"); + Assert.AreEqual (_double, obj._double, context + "._double"); + Assert.AreEqual (_short, obj._short, context = "._short"); Assert.AreEqual (_int, obj._int, context + "._int"); Assert.AreEqual (_long, obj._long, context + "._long"); Assert.AreEqual (_sbyte, obj._sbyte, context + "._sbyte"); diff --git a/mcs/class/corlib/Test/System.Security.Cryptography/CryptoStreamTest.cs b/mcs/class/corlib/Test/System.Security.Cryptography/CryptoStreamTest.cs index 10328b8e60f..3ad6cce71f9 100644 --- a/mcs/class/corlib/Test/System.Security.Cryptography/CryptoStreamTest.cs +++ b/mcs/class/corlib/Test/System.Security.Cryptography/CryptoStreamTest.cs @@ -144,7 +144,6 @@ public class CryptoStreamTest { Stream readStream; Stream writeStream; ICryptoTransform encryptor; - ICryptoTransform decryptor; CryptoStream cs; SymmetricAlgorithm aes; @@ -156,7 +155,6 @@ public void SetUp () writeStream = new MemoryStream (new byte [0], true); aes = SymmetricAlgorithm.Create (); encryptor = aes.CreateEncryptor (); - decryptor = aes.CreateEncryptor (); } } diff --git a/mcs/class/corlib/Test/System.Security.Cryptography/HMACSHA384Test.cs b/mcs/class/corlib/Test/System.Security.Cryptography/HMACSHA384Test.cs index 115bdf30cc4..e243712d80c 100644 --- a/mcs/class/corlib/Test/System.Security.Cryptography/HMACSHA384Test.cs +++ b/mcs/class/corlib/Test/System.Security.Cryptography/HMACSHA384Test.cs @@ -28,6 +28,9 @@ public int BlockSize { public class SelectableHmacSha384: HMAC { + // legacy parameter: + // http://blogs.msdn.com/shawnfa/archive/2007/01/31/please-do-not-use-the-net-2-0-hmacsha512-and-hmacsha384-classes.aspx + public SelectableHmacSha384 (byte[] key, bool legacy) { HashName = "SHA384"; @@ -45,7 +48,6 @@ public SelectableHmacSha384 (byte[] key, bool legacy) public class HMACSHA384Test : KeyedHashAlgorithmTest { protected HMACSHA384 algo; - private bool legacy; [SetUp] public override void SetUp () @@ -53,8 +55,6 @@ public override void SetUp () algo = new HMACSHA384 (); algo.Key = new byte [8]; hash = algo; - // http://blogs.msdn.com/shawnfa/archive/2007/01/31/please-do-not-use-the-net-2-0-hmacsha512-and-hmacsha384-classes.aspx - legacy = (new HS384 ().BlockSize == 64); } // the hash algorithm only exists as a managed implementation diff --git a/mcs/class/corlib/Test/System.Security.Cryptography/HMACSHA512Test.cs b/mcs/class/corlib/Test/System.Security.Cryptography/HMACSHA512Test.cs index 04497415d0e..55a7b87589c 100644 --- a/mcs/class/corlib/Test/System.Security.Cryptography/HMACSHA512Test.cs +++ b/mcs/class/corlib/Test/System.Security.Cryptography/HMACSHA512Test.cs @@ -26,6 +26,9 @@ public int BlockSize { public class SelectableHmacSha512: HMAC { + // Legacy parameter explanation: + // http://blogs.msdn.com/shawnfa/archive/2007/01/31/please-do-not-use-the-net-2-0-hmacsha512-and-hmacsha384-classes.aspx + public SelectableHmacSha512 (byte[] key, bool legacy) { HashName = "SHA512"; @@ -43,7 +46,6 @@ public SelectableHmacSha512 (byte[] key, bool legacy) public class HMACSHA512Test : KeyedHashAlgorithmTest { protected HMACSHA512 algo; - private bool legacy; [SetUp] public override void SetUp () @@ -51,8 +53,6 @@ public override void SetUp () algo = new HMACSHA512 (); algo.Key = new byte [8]; hash = algo; - // http://blogs.msdn.com/shawnfa/archive/2007/01/31/please-do-not-use-the-net-2-0-hmacsha512-and-hmacsha384-classes.aspx - legacy = (new HS512 ().BlockSize == 64); } // the hash algorithm only exists as a managed implementation diff --git a/mcs/class/corlib/Test/System.Security.Permissions/RegistryPermissionTest.cs b/mcs/class/corlib/Test/System.Security.Permissions/RegistryPermissionTest.cs index fb3770db4b4..f95691c7f54 100644 --- a/mcs/class/corlib/Test/System.Security.Permissions/RegistryPermissionTest.cs +++ b/mcs/class/corlib/Test/System.Security.Permissions/RegistryPermissionTest.cs @@ -38,7 +38,6 @@ public class RegistryPermissionTest { private static string className = "System.Security.Permissions.RegistryPermission, "; private static string keyCurrentUser = @"HKEY_CURRENT_USER\Software\Novell iFolder\spouliot\Home"; - private static string keyCurrentUserSubset = @"HKEY_CURRENT_USER\Software\Novell iFolder\"; private static string keyLocalMachine = @"HKEY_LOCAL_MACHINE\SOFTWARE\Novell\Novell iFolder\1.00.000"; private static string keyLocalMachineSubset = @"HKEY_LOCAL_MACHINE\SOFTWARE\Novell\"; diff --git a/mcs/class/corlib/Test/System.Security.Permissions/UrlIdentityPermissionTest.cs b/mcs/class/corlib/Test/System.Security.Permissions/UrlIdentityPermissionTest.cs index 62a0c35e1cd..f9a7d8ae21a 100644 --- a/mcs/class/corlib/Test/System.Security.Permissions/UrlIdentityPermissionTest.cs +++ b/mcs/class/corlib/Test/System.Security.Permissions/UrlIdentityPermissionTest.cs @@ -51,12 +51,6 @@ public class UrlIdentityPermissionTest { "*", }; - // accepted as Url but fails to work (as expected) in some methods - static string[] SemiBadUrls = { - "www.mono-project.com:80", - String.Empty, - }; - [Test] public void PermissionState_None () { diff --git a/mcs/class/corlib/Test/System.Text/EncodingTester.cs b/mcs/class/corlib/Test/System.Text/EncodingTester.cs new file mode 100644 index 00000000000..939d38160fb --- /dev/null +++ b/mcs/class/corlib/Test/System.Text/EncodingTester.cs @@ -0,0 +1,116 @@ +// +// EncodingTester.cs +// +// Author: +// Marcos Henrich +// +// (C) 2014 Xamarin, Inc. +// + +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Text; + +namespace MonoTests.System.Text +{ + class EncodingTester + { + class DecoderTestFallbackBuffer : DecoderFallbackBuffer + { + DecoderFallbackBuffer buffer; + private FallbackDelegate fallbackAction; + + public DecoderTestFallbackBuffer (DecoderReplacementFallback fallback, FallbackDelegate fallbackAction) + { + this.fallbackAction = fallbackAction; + buffer = new DecoderReplacementFallbackBuffer (fallback); + } + + public override bool Fallback (byte [] bytesUnknown, int index) + { + fallbackAction (bytesUnknown, index); + return buffer.Fallback (bytesUnknown, index); + } + + public override char GetNextChar () + { + return buffer.GetNextChar (); + } + + public override bool MovePrevious () + { + return buffer.MovePrevious (); + } + + public override int Remaining + { + get { return buffer.Remaining; } + } + + public override void Reset () + { + buffer.Reset (); + } + } + + class DecoderTestFallback : DecoderFallback + { + private DecoderReplacementFallback fallback; + private FallbackDelegate fallbackAction; + + public DecoderTestFallback (FallbackDelegate fallbackAction) + { + this.fallbackAction = fallbackAction; + } + + public override DecoderFallbackBuffer CreateFallbackBuffer () + { + fallback = new DecoderReplacementFallback (); + return new DecoderTestFallbackBuffer (fallback, fallbackAction); + } + + public override int MaxCharCount + { + get { return fallback.MaxCharCount; } + } + } + + public delegate void FallbackDelegate (byte [] bytesUnknown, int index); + + Encoding encoding; + + byte [][] expectedUnknownBytes; + int expectedUnknownBytesIndex; + + public EncodingTester (string encodingName) + { + var decoderFallback = new DecoderTestFallback (this.DecoderFallback); + encoding = Encoding.GetEncoding (encodingName, new EncoderReplacementFallback(), decoderFallback); + } + + private void DecoderFallback (byte [] bytesUnknown, int index) + { + if (expectedUnknownBytesIndex == expectedUnknownBytes.Length) + expectedUnknownBytesIndex = 0; + + var expectedBytes = expectedUnknownBytes [expectedUnknownBytesIndex++]; + Assert.AreEqual (expectedBytes, bytesUnknown); + } + + public void TestDecoderFallback (byte [] data, string expectedString, params byte [][] expectedUnknownBytes) + { + lock (this) + { + this.expectedUnknownBytes = expectedUnknownBytes; + this.expectedUnknownBytesIndex = 0; + + Assert.AreEqual (expectedString.Length, encoding.GetCharCount (data)); + Assert.AreEqual (expectedUnknownBytesIndex, expectedUnknownBytes.Length); + + Assert.AreEqual (expectedString, encoding.GetString (data)); + Assert.AreEqual (expectedUnknownBytesIndex, expectedUnknownBytes.Length); + } + } + } +} \ No newline at end of file diff --git a/mcs/class/corlib/Test/System.Text/UTF8EncodingTest.cs b/mcs/class/corlib/Test/System.Text/UTF8EncodingTest.cs index 91a465c13d3..8943ab6b099 100644 --- a/mcs/class/corlib/Test/System.Text/UTF8EncodingTest.cs +++ b/mcs/class/corlib/Test/System.Text/UTF8EncodingTest.cs @@ -1198,5 +1198,88 @@ public void Bug10789() int charactersWritten = Encoding.UTF8.GetDecoder ().GetChars (bytes, 0, 0, chars, 10, false); Assert.AreEqual (0, charactersWritten, "#3"); } + + [Test] + public void EncodingFallback () + { + /* Legal UTF-8 Byte Sequences + * 1st 2nd 3rd 4th + * 00..7F + * C2..DF 80..BF + * E0 A0..BF 80..BF + * E1..EF 80..BF 80..BF + * F0 90..BF 80..BF 80..BF + * F1..F3 80..BF 80..BF 80..BF + * F4 80..8F 80..BF 80..BF + */ + + var t = new EncodingTester ("utf-8"); + byte [] data; + + // Invalid 1st byte + for (byte b = 0x80; b <= 0xC1; b++) { + data = new byte [] { b }; + t.TestDecoderFallback (data, "?", new byte [] { b }); + } + + ///Invalid 2nd byte + // C2..DF 80..BF + for (byte b = 0xC2; b <= 0xDF; b++) { + data = new byte [] { b, 0x61 }; + t.TestDecoderFallback (data, "?a", new byte [] { b }); + } + + // E0 A0..BF + data = new byte [] { 0xE0, 0x99}; + t.TestDecoderFallback (data, "?", new byte [] { 0xE0, 0x99}); + + // E1..EF 80..BF + for (byte b = 0xE1; b <= 0xEF; b++) { + data = new byte [] { b, 0x61 }; + t.TestDecoderFallback (data, "?a", new byte [] { b }); + } + + // F0 90..BF + data = new byte [] { 0xF0, 0x8F}; + t.TestDecoderFallback (data, "?", new byte [] { 0xF0, 0x8F }); + + // F1..F4 80..XX + for (byte b = 0xF1; b <= 0xF4; b++) { + data = new byte [] { b, 0x61 }; + t.TestDecoderFallback (data, "?a", new byte [] { b }); + } + + // C2..F3 XX..BF + for (byte b = 0xC2; b <= 0xF3; b++) { + data = new byte [] { b, 0xC0 }; + t.TestDecoderFallback (data, "??", new byte [] { b }, new byte [] { 0xC0 }); + } + + // Invalid 3rd byte + // E0..F3 90..BF 80..BF + for (byte b = 0xE0; b <= 0xF3; b++) { + data = new byte [] { b, 0xB0, 0x61 }; + t.TestDecoderFallback (data, "?a", new byte [] { b, 0xB0 }); + data = new byte [] { b, 0xB0, 0xC0 }; + t.TestDecoderFallback (data, "??", new byte [] { b, 0xB0 }, new byte [] { 0xC0 }); + } + + // F4 80..8F 80..BF + data = new byte [] { 0xF4, 0x8F, 0xC0 }; + t.TestDecoderFallback (data, "??", new byte [] { 0xF4, 0x8F }, new byte [] { 0xC0 }); + + // Invalid 4th byte + // F0..F3 90..BF 80..BF 80..BF + for (byte b = 0xF0; b <= 0xF3; b++) { + data = new byte [] { b, 0xB0, 0xB0, 0x61 }; + t.TestDecoderFallback (data, "?a", new byte [] { b, 0xB0, 0xB0 }); + data = new byte [] { b, 0xB0, 0xB0, 0xC0 }; + t.TestDecoderFallback (data, "??", new byte [] { b, 0xB0, 0xB0 }, new byte [] { 0xC0 }); + } + + // F4 80..8F 80..BF 80..BF + data = new byte [] { 0xF4, 0x8F, 0xB0, 0xC0 }; + t.TestDecoderFallback (data, "??", new byte [] { 0xF4, 0x8F, 0xB0 }, new byte [] { 0xC0 }); + } } } diff --git a/mcs/class/corlib/Test/System.Text/UnicodeEncodingTest.cs b/mcs/class/corlib/Test/System.Text/UnicodeEncodingTest.cs index 9938bcef1ae..e780524afe1 100644 --- a/mcs/class/corlib/Test/System.Text/UnicodeEncodingTest.cs +++ b/mcs/class/corlib/Test/System.Text/UnicodeEncodingTest.cs @@ -164,34 +164,18 @@ public void TestPreamble3() } [Test] -#if NET_2_0 - [Category ("NotWorking")] -#endif public void TestMaxCharCount() { UnicodeEncoding UnicodeEnc = new UnicodeEncoding (); -#if NET_2_0 - // where is this extra 1 coming from? Assert.AreEqual (26, UnicodeEnc.GetMaxCharCount(50), "UTF #1"); Assert.AreEqual (27, UnicodeEnc.GetMaxCharCount(51), "UTF #2"); -#else - Assert.AreEqual (25, UnicodeEnc.GetMaxCharCount(50), "UTF #1"); -#endif } [Test] -#if NET_2_0 - [Category ("NotWorking")] -#endif public void TestMaxByteCount() { UnicodeEncoding UnicodeEnc = new UnicodeEncoding (); -#if NET_2_0 - // is this extra 2 BOM? Assert.AreEqual (102, UnicodeEnc.GetMaxByteCount(50), "UTF #1"); -#else - Assert.AreEqual (100, UnicodeEnc.GetMaxByteCount(50), "UTF #1"); -#endif } [Test] @@ -257,5 +241,27 @@ public void GetString_Odd_Count_ff () Assert.AreEqual (2, s.Length, "Length"); Assert.AreEqual (65533, (int) s [1], "1"); } + + [Test] + public void GetMaxByteCountIncludesBOM () + { + Assert.AreEqual (2, Encoding.Unicode.GetMaxByteCount (0), "#1"); + Assert.AreEqual (4, Encoding.Unicode.GetMaxByteCount (1), "#2"); + Assert.AreEqual (6, Encoding.Unicode.GetMaxByteCount (2), "#3"); + Assert.AreEqual (10, Encoding.Unicode.GetMaxByteCount (4), "#4"); + Assert.AreEqual (20, Encoding.Unicode.GetMaxByteCount (9), "#5"); + Assert.AreEqual (22, Encoding.Unicode.GetMaxByteCount (10), "#6"); + } + + [Test] + public void GetMaxCharCountRoundsCorrectly () + { + Assert.AreEqual (1, Encoding.Unicode.GetMaxCharCount (0), "#1"); + Assert.AreEqual (2, Encoding.Unicode.GetMaxCharCount (1), "#2"); + Assert.AreEqual (2, Encoding.Unicode.GetMaxCharCount (2), "#3"); + Assert.AreEqual (3, Encoding.Unicode.GetMaxCharCount (4), "#4"); + Assert.AreEqual (6, Encoding.Unicode.GetMaxCharCount (9), "#5"); + Assert.AreEqual (6, Encoding.Unicode.GetMaxCharCount (10), "#6"); + } } } diff --git a/mcs/class/corlib/Test/System.Threading.Tasks/TaskTest.cs b/mcs/class/corlib/Test/System.Threading.Tasks/TaskTest.cs index 63eb8a2aff1..524988828b9 100644 --- a/mcs/class/corlib/Test/System.Threading.Tasks/TaskTest.cs +++ b/mcs/class/corlib/Test/System.Threading.Tasks/TaskTest.cs @@ -104,6 +104,8 @@ protected override bool TryExecuteTaskInline (Task task, bool taskWasPreviouslyQ } } + int workerThreads; + int completionPortThreads; Task[] tasks; const int max = 6; @@ -111,9 +113,18 @@ protected override bool TryExecuteTaskInline (Task task, bool taskWasPreviouslyQ [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++) { @@ -616,18 +627,18 @@ public void ContinueWithWithStart () 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); } @@ -788,19 +799,53 @@ public void DoubleWaitTest () { 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); } @@ -905,7 +950,7 @@ public void UnobservedExceptionOnFinalizerThreadTest () }; 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 (); @@ -1094,7 +1139,7 @@ public void InlineNotTrashingParentRelationship () 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); @@ -1932,6 +1977,24 @@ public void LazyCancelationTest () } } + [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() diff --git a/mcs/class/corlib/Test/System.Threading/ThreadTest.cs b/mcs/class/corlib/Test/System.Threading/ThreadTest.cs index 8c82931acc5..67bcd941d45 100644 --- a/mcs/class/corlib/Test/System.Threading/ThreadTest.cs +++ b/mcs/class/corlib/Test/System.Threading/ThreadTest.cs @@ -85,10 +85,10 @@ public static void CopyOnNewThread () [Category("MobileNotWorking")] // Abort #10240 public class ThreadTest { - TimeSpan Infinite = new TimeSpan (-10000); // -10000 ticks == -1 ms + //TimeSpan Infinite = new TimeSpan (-10000); // -10000 ticks == -1 ms TimeSpan SmallNegative = new TimeSpan (-2); // between 0 and -1.0 (infinite) ms TimeSpan Negative = new TimeSpan (-20000); // really negative - TimeSpan MaxValue = TimeSpan.FromMilliseconds ((long) Int32.MaxValue); + //TimeSpan MaxValue = TimeSpan.FromMilliseconds ((long) Int32.MaxValue); TimeSpan TooLarge = TimeSpan.FromMilliseconds ((long) Int32.MaxValue + 1); static bool is_win32; @@ -526,13 +526,44 @@ public void Name () [Test] [ExpectedException (typeof (InvalidOperationException))] - public void ReName () + public void Rename () { - Thread t = new Thread (new ThreadStart (ReName)); + Thread t = new Thread (new ThreadStart (Rename)); t.Name = "a"; t.Name = "b"; } + bool rename_finished; + bool rename_failed; + + [Test] + public void RenameTpThread () + { + object monitor = new object (); + ThreadPool.QueueUserWorkItem (new WaitCallback (Rename_callback), monitor); + lock (monitor) { + if (!rename_finished) + Monitor.Wait (monitor); + } + Assert.IsTrue (!rename_failed); + } + + void Rename_callback (object o) { + Thread.CurrentThread.Name = "a"; + try { + Thread.CurrentThread.Name = "b"; + //Console.WriteLine ("Thread name is: {0}", Thread.CurrentThread.Name); + } catch (Exception e) { + //Console.Error.WriteLine (e); + rename_failed = true; + } + object monitor = o; + lock (monitor) { + rename_finished = true; + Monitor.Pulse (monitor); + } + } + [Test] public void TestNestedThreads1() { diff --git a/mcs/class/corlib/Test/System/AppDomainTest.cs b/mcs/class/corlib/Test/System/AppDomainTest.cs index 8772d7afdea..0836640057e 100644 --- a/mcs/class/corlib/Test/System/AppDomainTest.cs +++ b/mcs/class/corlib/Test/System/AppDomainTest.cs @@ -3240,6 +3240,7 @@ private static Assembly CurrentDomain_ReflectionOnlyAssemblyResolve(object sende } #endif + public class StuffToPick { public StuffToPick () {} @@ -3248,6 +3249,11 @@ public void Method () {} public event Action Event; public int Field; public void GenericMethod () {} + + public void Dummy () + { + Event += delegate {}; + } } public class StuffToPick @@ -3257,7 +3263,12 @@ public void Method () {} public int Property { get; set; } public event Action Event; public int Field; - public void GenericMethod () {} + public void GenericMethod () {} + + public void Dummy () + { + Event += delegate {}; + } } static void TestSerialization (CrossDomainTester tester, object o) diff --git a/mcs/class/corlib/Test/System/DateTimeOffsetTest.cs b/mcs/class/corlib/Test/System/DateTimeOffsetTest.cs index a898f2db6e9..13564426aed 100644 --- a/mcs/class/corlib/Test/System/DateTimeOffsetTest.cs +++ b/mcs/class/corlib/Test/System/DateTimeOffsetTest.cs @@ -705,6 +705,23 @@ public void TestPartialDateTimeParsing () expected = string.Format ("{0:D2}/{1:D2}/{2} 00:00:45 +00:00", now.Month, now.Day, now.Year); Assert.AreEqual (expected, date.ToString (CultureInfo.InvariantCulture)); } + + [Test] + public void TestDateOnlyWithTimeOffset () + { + var fp = CultureInfo.InvariantCulture; + var date = DateTimeOffset.Parse("2013-11-07+11:00", fp, DateTimeStyles.AssumeUniversal); + var expected = string.Format ("{0:D2}/{1:D2}/{2} 00:00:00 +11:00", 11, 7, 2013); + Assert.AreEqual (expected, date.ToString (CultureInfo.InvariantCulture)); + } + + [Test] + public void GMTDateTime () + { + var date = DateTimeOffset.Parse ("Wed, 10 Sep 2014 22:01:40 GMT", CultureInfo.InvariantCulture); + var expected = "09/10/2014 22:01:40 +00:00"; + Assert.AreEqual (expected, date.ToString (CultureInfo.InvariantCulture)); + } } } diff --git a/mcs/class/corlib/Test/System/DateTimeTest.cs b/mcs/class/corlib/Test/System/DateTimeTest.cs index 343e723be82..202c3d2117d 100644 --- a/mcs/class/corlib/Test/System/DateTimeTest.cs +++ b/mcs/class/corlib/Test/System/DateTimeTest.cs @@ -2584,5 +2584,40 @@ public void Parse_ThaiCalendar () Assert.AreEqual (dt, parsed, "#1"); } + + [Test] + public void ISO8601FractionalDigits () + { + string date = "2014-08-25T01:20:23.601911612343423423465789789365674575676746756747467Z"; + long expectedTicks = 635445264236019116; + + var dt = DateTime.Parse (date, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind); + + Assert.AreEqual (expectedTicks, dt.Ticks); + } + + [Test] + [ExpectedException (typeof (FormatException))] + public void ISO8601FractionalDigitsException1 () + { + string date = "2014-08-25T01:20:23.60191161234342342346578978936567457567:6746756747467Z"; + DateTime.Parse (date, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind); + } + + [Test] + [ExpectedException (typeof (FormatException))] + public void ISO8601FractionalDigitsException2 () + { + string date = "2014-08-25T01:20:23.6019116-12343423423465789789365674575676746756747467Z"; + DateTime.Parse (date, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind); + } + + [Test] + [ExpectedException (typeof (FormatException))] + public void ISO8601FractionalDigitsException3 () + { + string date = "2014-08-25T01:20:23.601911612343423423465789789365674575676746756747467%Z"; + DateTime.Parse (date, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind); + } } } diff --git a/mcs/class/corlib/Test/System/SByteTest.cs b/mcs/class/corlib/Test/System/SByteTest.cs index 9bf4d31a1cd..c8d40396c29 100644 --- a/mcs/class/corlib/Test/System/SByteTest.cs +++ b/mcs/class/corlib/Test/System/SByteTest.cs @@ -24,12 +24,15 @@ public class SByteTest private const string MyString3 = "127"; private string[] Formats1 = {"c", "d", "e", "f", "g", "n", "p", "x" }; private string[] Formats2 = {"c5", "d5", "e5", "f5", "g5", "n5", "p5", "x5" }; +#if false + // These are not currently being tested against, due to the locale-specific nature of the test, we need a different way of doing this private string[] Results1 = {"("+NumberFormatInfo.CurrentInfo.CurrencySymbol+"128.00)", "-128", "-1.280000e+002", "-128.00", "-128", "-128.00", "-12,800.00 %", "80"}; private string[] Results2 = {NumberFormatInfo.CurrentInfo.CurrencySymbol+"127.00000", "00127", "1.27000e+002", "127.00000", "127", "127.00000", "12,700.00000 %", "0007f"}; +#endif private string[] ResultsNfi1 = {"("+NumberFormatInfo.InvariantInfo.CurrencySymbol+"128.00)", "-128", "-1.280000e+002", "-128.00", "-128", "-128.00", "-12,800.00 %", "80"}; @@ -161,14 +164,17 @@ public void TestToString() Assert.IsTrue(String.Compare(MyString2, MySByte2.ToString()) == 0, "MyString2, MySByte2.ToString()"); Assert.IsTrue(String.Compare(MyString3, MySByte3.ToString()) == 0, "MyString3, MySByte3.ToString()"); //test ToString(string format) + +#if false /* - TODO: These tests depend on the culture of the system running the test. - So, this needs to be tested in a different way. + * TODO: These tests depend on the culture of the system running the test. + * So, this needs to be tested in a different way. + / for (int i=0; i < Formats1.Length; i++) { Assert.IsTrue("i="+i+", Results1[i]="+Results1[i]+", MySByte2.ToString(Formats1[i])="+MySByte2.ToString(Formats1[i]), String.Compare(Results1[i], MySByte2.ToString(Formats1[i])) == 0); Assert.IsTrue(String.Compare(Results2[i], MySByte3.ToString(Formats2[i])) == 0, "Results2[i], MySByte3.ToString(Formats2[i])"); } - */ +#endif //test ToString(string format, IFormatProvider provider); for (int i=0; i < Formats1.Length; i++) { Assert.IsTrue(String.Compare(ResultsNfi1[i], MySByte2.ToString(Formats1[i], Nfi)) == 0, "i="+i+", ResultsNfi1[i]="+ResultsNfi1[i]+", MySByte2.ToString(Formats1[i]="+Formats1[i]+"): Expected "+ResultsNfi1[i]+" but got "+MySByte2.ToString(Formats1[i], Nfi)); diff --git a/mcs/class/corlib/Test/System/TimeSpanTest.cs b/mcs/class/corlib/Test/System/TimeSpanTest.cs index 101cad48a92..2d9e0984996 100644 --- a/mcs/class/corlib/Test/System/TimeSpanTest.cs +++ b/mcs/class/corlib/Test/System/TimeSpanTest.cs @@ -1430,6 +1430,18 @@ public void ToStringCustomFormats () ts = new TimeSpan (123456789); Assert.AreEqual ("12.3", ts.ToString ("s\\.f"), "#F0"); Assert.AreEqual ("12.3", ts.ToString ("s\\.F"), "#F1"); + Assert.AreEqual ("12.3456789", ts.ToString ("s\\.fffffff"), "#F2"); + Assert.AreEqual ("12.345678", ts.ToString ("s\\.ffffff"), "#F3"); + + ts = new TimeSpan (1234); + Assert.AreEqual ("0.000123", ts.ToString ("s\\.ffffff"), "#G0"); + Assert.AreEqual ("0.0001", ts.ToString ("s\\.ffff"), "#G1"); + Assert.AreEqual ("0.", ts.ToString ("s\\.F"), "#G2"); + Assert.AreEqual ("0.", ts.ToString ("s\\.FFF"), "#G3"); + + ts = TimeSpan.FromSeconds (0.05); + Assert.AreEqual (".0", ts.ToString ("\\.f"), "#H0"); + Assert.AreEqual (".", ts.ToString ("\\.F"), "#H1"); } [Test] diff --git a/mcs/class/corlib/Test/System/TimeZoneTest.cs b/mcs/class/corlib/Test/System/TimeZoneTest.cs index 6f97c359ebc..47915f722b4 100644 --- a/mcs/class/corlib/Test/System/TimeZoneTest.cs +++ b/mcs/class/corlib/Test/System/TimeZoneTest.cs @@ -303,11 +303,12 @@ public void GetUtcOffsetAtDSTBoundary () TimeZone tz = TimeZone.CurrentTimeZone; - DaylightTime daylightChanges = tz.GetDaylightChanges(2007); + int year = DateTime.Now.Year; + DaylightTime daylightChanges = tz.GetDaylightChanges(year); DateTime dst_end = daylightChanges.End; if (dst_end == DateTime.MinValue) - Assert.Ignore (tz.StandardName + " did not observe daylight saving time during 2007."); + Assert.Ignore (tz.StandardName + " did not observe daylight saving time during " + year + "."); var standardOffset = tz.GetUtcOffset(daylightChanges.Start.AddMinutes(-1)); diff --git a/mcs/class/corlib/Test/System/TypeTest.cs b/mcs/class/corlib/Test/System/TypeTest.cs index 00131c8d47f..6acbac2dd9f 100644 --- a/mcs/class/corlib/Test/System/TypeTest.cs +++ b/mcs/class/corlib/Test/System/TypeTest.cs @@ -143,6 +143,10 @@ public virtual int Foo { } public event EventHandler E; + public void Dummy () + { + E += delegate {}; + } } class Derived1 : Base1 @@ -159,7 +163,11 @@ class Derived2 : Base1 set { } } - public event Action E; + public new event Action E; + public new void Dummy () + { + E += delegate {}; + } } public class Foo @@ -1860,7 +1868,9 @@ public void TestAssemblyQualifiedName () struct B { + #pragma warning disable 169 int value; + #pragma warning restore 169 } [Test] @@ -2153,7 +2163,7 @@ public static void OutTest (out string[] a1) a1 = new string [10]; } - class X + public class X { public static int Value; } diff --git a/mcs/class/corlib/corlib-net_4_5.csproj b/mcs/class/corlib/corlib-net_4_5.csproj index 43e03fbfa33..bf5bf190955 100644 --- a/mcs/class/corlib/corlib-net_4_5.csproj +++ b/mcs/class/corlib/corlib-net_4_5.csproj @@ -1399,6 +1399,8 @@ + + @@ -1585,6 +1587,7 @@ + diff --git a/mcs/class/corlib/corlib.dll.sources b/mcs/class/corlib/corlib.dll.sources index 2626ca0fa3e..5268a3a9766 100644 --- a/mcs/class/corlib/corlib.dll.sources +++ b/mcs/class/corlib/corlib.dll.sources @@ -160,6 +160,7 @@ System/EventHandler.cs System/Exception.cs System/ExecutionEngineException.cs System/FieldAccessException.cs +System/FirstChanceExceptionEventArgs.cs System/FlagsAttribute.cs System/FormatException.cs System/Funcs.cs @@ -810,6 +811,7 @@ System.Runtime.InteropServices/IDispatchImplAttribute.cs System.Runtime.InteropServices/IDispatchImplType.cs System.Runtime.InteropServices/IDLDESC.cs System.Runtime.InteropServices/IDLFLAG.cs +System.Runtime.InteropServices/IErrorInfo.cs System.Runtime.InteropServices/IMPLTYPEFLAGS.cs System.Runtime.InteropServices/INVOKEKIND.cs System.Runtime.InteropServices/IRegistrationServices.cs @@ -826,6 +828,7 @@ System.Runtime.InteropServices/InvalidOleVariantTypeException.cs System.Runtime.InteropServices/LCIDConversionAttribute.cs System.Runtime.InteropServices/LIBFLAGS.cs System.Runtime.InteropServices/LayoutKind.cs +System.Runtime.InteropServices/ManagedErrorInfo.cs System.Runtime.InteropServices/Marshal.cs System.Runtime.InteropServices/MarshalAsAttribute.cs System.Runtime.InteropServices/MarshalDirectiveException.cs diff --git a/mcs/class/corlib/corlib_test.dll.sources b/mcs/class/corlib/corlib_test.dll.sources index 1742ea7ff24..8cb367e813e 100644 --- a/mcs/class/corlib/corlib_test.dll.sources +++ b/mcs/class/corlib/corlib_test.dll.sources @@ -394,6 +394,7 @@ System.Text/EncoderReplacementFallbackTest.cs System.Text/EncoderReplacementFallbackBufferTest.cs System.Text/EncoderTest.cs System.Text/EncodingTest.cs +System.Text/EncodingTester.cs System.Text/EncodingInfoTest.cs System.Text/StringBuilderTest.cs System.Text/TestEncoding.cs diff --git a/mcs/errors/cs0023-25.cs b/mcs/errors/cs0023-25.cs new file mode 100644 index 00000000000..d6f5c5bbe1a --- /dev/null +++ b/mcs/errors/cs0023-25.cs @@ -0,0 +1,10 @@ +// CS0023: The `?' operator cannot be applied to operand of type `T' +// Line: 8 + +class C +{ + static void Foo (T t) where T : struct + { + var r = t?.ToString (); + } +} \ No newline at end of file diff --git a/mcs/errors/cs0111-12.cs b/mcs/errors/cs0111-12.cs new file mode 100644 index 00000000000..034963c22a0 --- /dev/null +++ b/mcs/errors/cs0111-12.cs @@ -0,0 +1,15 @@ +// CS0111: A member `S3.S3(string)' is already defined. Rename this member or use different parameter types +// Line: 6 + +struct S3 (string s) +{ + public S3 (string s) + : this (1) + { + } + + public S3 (int i) + : this ("") + { + } +} diff --git a/mcs/errors/cs0411-24.cs b/mcs/errors/cs0411-24.cs new file mode 100644 index 00000000000..1462cbac233 --- /dev/null +++ b/mcs/errors/cs0411-24.cs @@ -0,0 +1,15 @@ +// CS0411: The type arguments for method `C.Foo(out T)' cannot be inferred from the usage. Try specifying the type arguments explicitly +// Line: 8 + +public class C +{ + public static void Main () + { + Foo (out var y); + } + + static void Foo (out T t) + { + t = default (T); + } +} \ No newline at end of file diff --git a/mcs/errors/cs0429-5.cs b/mcs/errors/cs0429-5.cs deleted file mode 100644 index 1cc67a22817..00000000000 --- a/mcs/errors/cs0429-5.cs +++ /dev/null @@ -1,26 +0,0 @@ -// CS0429: Unreachable expression code detected -// Line: 24 -// Compiler options: -warnaserror - -using System; - -struct S -{ -} - -class C -{ - public static implicit operator S (C c) - { - return new S (); - } -} - -class Program -{ - static void Main () - { - C c = new C (); - Console.WriteLine (c ?? new S ()); - } -} diff --git a/mcs/errors/cs0516-3.cs b/mcs/errors/cs0516-3.cs new file mode 100644 index 00000000000..1ff6d062893 --- /dev/null +++ b/mcs/errors/cs0516-3.cs @@ -0,0 +1,9 @@ +// CS0516: Constructor `Sample.Sample()' cannot call itself +// Line: 6 + +struct Sample { + public Sample () + : this () + { + } +} diff --git a/mcs/errors/cs0516.cs b/mcs/errors/cs0516.cs index 47b0fdee730..5c41f8dc4e7 100644 --- a/mcs/errors/cs0516.cs +++ b/mcs/errors/cs0516.cs @@ -1,9 +1,9 @@ // CS0516: Constructor `Sample.Sample()' cannot call itself -// Line: 5 +// Line: 6 class Sample { - public Sample (): this () {} + public Sample () + : this () + { + } } - - - diff --git a/mcs/errors/cs0568.cs b/mcs/errors/cs0568.cs deleted file mode 100644 index 944d7a90b79..00000000000 --- a/mcs/errors/cs0568.cs +++ /dev/null @@ -1,14 +0,0 @@ -// CS0568: Structs cannot contain explicit parameterless constructors -// Line: 5 -struct A { - int a; - A () { a = 1; } -} - -class D { - static void Main () - { - A [] a = new A [10]; - - } -} diff --git a/mcs/errors/cs0573-2.cs b/mcs/errors/cs0573-2.cs new file mode 100644 index 00000000000..443bed39123 --- /dev/null +++ b/mcs/errors/cs0573-2.cs @@ -0,0 +1,7 @@ +// CS0573: 'S': Structs cannot have instance property or field initializers +// Line: 6 + +struct S +{ + public int Prop { get; set; } = 3; +} diff --git a/mcs/errors/cs0573.cs b/mcs/errors/cs0573.cs new file mode 100644 index 00000000000..fd8de1ebc6e --- /dev/null +++ b/mcs/errors/cs0573.cs @@ -0,0 +1,7 @@ +// CS0573: 'S': Structs cannot have instance property or field initializers +// Line: 6 + +struct S +{ + int v = 0; +} diff --git a/mcs/errors/cs0619-58.cs b/mcs/errors/cs0619-58.cs new file mode 100644 index 00000000000..faf79c7dab8 --- /dev/null +++ b/mcs/errors/cs0619-58.cs @@ -0,0 +1,20 @@ +// CS0619: `S.S()' is obsolete: `ctor' +// Line: 18 + +using System; + +struct S +{ + [Obsolete ("ctor", true)] + public S () + { + } +} + +class C +{ + public static void Main () + { + new S (); + } +} diff --git a/mcs/errors/cs0677-5.cs b/mcs/errors/cs0677-5.cs new file mode 100644 index 00000000000..a6d22486408 --- /dev/null +++ b/mcs/errors/cs0677-5.cs @@ -0,0 +1,11 @@ +// CS0677: `X.e': A volatile field cannot be of the type `E' +// Line: 10 + +enum E : long +{ +} + +class X +{ + volatile E e; +} diff --git a/mcs/errors/cs0815-7.cs b/mcs/errors/cs0815-7.cs new file mode 100644 index 00000000000..ae41a72d91a --- /dev/null +++ b/mcs/errors/cs0815-7.cs @@ -0,0 +1,15 @@ +// CS0815: An implicitly typed local variable declaration cannot be initialized with `void' +// Line: 8 + +class X +{ + public static void Main () + { + Foo (out var x = Main ()); + } + + static void Foo (out int i) + { + i = 0; + } +} \ No newline at end of file diff --git a/mcs/errors/cs0841-5.cs b/mcs/errors/cs0841-5.cs new file mode 100644 index 00000000000..798b33547c8 --- /dev/null +++ b/mcs/errors/cs0841-5.cs @@ -0,0 +1,15 @@ +// CS0841: A local variable `x' cannot be used before it is declared +// Line: 8 + +class X +{ + public static void Main () + { + Foo (x, out var x); + } + + static void Foo (int arg, out int value) + { + value = 3; + } +} \ No newline at end of file diff --git a/mcs/errors/cs1501-18.cs b/mcs/errors/cs1501-18.cs new file mode 100644 index 00000000000..b22ab55c406 --- /dev/null +++ b/mcs/errors/cs1501-18.cs @@ -0,0 +1,22 @@ +// CS1501: No overload for method `Bar' takes `2' arguments +// Line: 19 + +using System; + +class T +{ + void Foo (int arg, Action a) + { + } + + void Foo (string title, Action a) + { + } + + void Bar () + { + Foo (arg: 1, a: () => { + Bar ("a", "b"); + }); + } +} \ No newline at end of file diff --git a/mcs/errors/cs1503-17.cs b/mcs/errors/cs1503-17.cs new file mode 100644 index 00000000000..26766c0ade7 --- /dev/null +++ b/mcs/errors/cs1503-17.cs @@ -0,0 +1,14 @@ +// CS1501: Argument `#1' cannot convert `ref string' expression to type `ref int' +// Line: 8 + +class C +{ + public static void Main () + { + Foo (ref var x = ""); + } + + static void Foo (ref int i) + { + } +} \ No newline at end of file diff --git a/mcs/errors/cs1615-3.cs b/mcs/errors/cs1615-3.cs new file mode 100644 index 00000000000..c64fb7fe842 --- /dev/null +++ b/mcs/errors/cs1615-3.cs @@ -0,0 +1,18 @@ +// CS1615: Argument `#1' does not require `out' modifier. Consider removing `out' modifier +// Line: 8 + +public class C +{ + public static void Main () + { + Foo (out var y); + } + + static void Foo (int x) + { + } + + static void Foo (string x) + { + } +} \ No newline at end of file diff --git a/mcs/errors/cs1644-45.cs b/mcs/errors/cs1644-45.cs new file mode 100644 index 00000000000..3aa2033141d --- /dev/null +++ b/mcs/errors/cs1644-45.cs @@ -0,0 +1,10 @@ +// CS1644: Feature `struct parameterless instance constructor' cannot be used because it is not part of the C# 5.0 language specification +// Line: 12 +// Compiler options: -langversion:5 + +struct S +{ + public S () + { + } +} \ No newline at end of file diff --git a/mcs/errors/cs1644-47.cs b/mcs/errors/cs1644-47.cs new file mode 100644 index 00000000000..b756cd7b60c --- /dev/null +++ b/mcs/errors/cs1644-47.cs @@ -0,0 +1,11 @@ +// CS1644: Feature `declaration expression' cannot be used because it is not part of the C# 5.0 language specification +// Line: 12 +// Compiler options: -langversion:5 + +class C +{ + public static void Main () + { + int.TryParse ("0", out var v); + } +} \ No newline at end of file diff --git a/mcs/errors/cs1736-2.cs b/mcs/errors/cs1736-2.cs new file mode 100644 index 00000000000..c9c9e849a24 --- /dev/null +++ b/mcs/errors/cs1736-2.cs @@ -0,0 +1,16 @@ +// CS1736: The expression being assigned to optional parameter `s' must be a constant or default value +// Line: 11 + +struct S +{ + public S () + { + } +} + +class X +{ + public void Foo (S s = new S ()) + { + } +} \ No newline at end of file diff --git a/mcs/errors/cs8046.cs b/mcs/errors/cs8046.cs new file mode 100644 index 00000000000..f8b9ad556f0 --- /dev/null +++ b/mcs/errors/cs8046.cs @@ -0,0 +1,19 @@ +// CS8046: An expression tree cannot contain a declaration expression +// Line: 11 + +using System; +using System.Linq.Expressions; + +class C +{ + static void Main() + { + Expression> e = () => Out (out int x); + } + + static bool Out (out int value) + { + value = 3; + return true; + } +} \ No newline at end of file diff --git a/mcs/errors/cs8047.cs b/mcs/errors/cs8047.cs new file mode 100644 index 00000000000..7171d569ce3 --- /dev/null +++ b/mcs/errors/cs8047.cs @@ -0,0 +1,19 @@ +// CS8047: Declaration expression cannot be used in this context +// Line: 8 + +public class C +{ + public static void Main () + { + dynamic target = 3; + var x = new Test (target, out var y); + } +} + +class Test +{ + public Test (int x, out int y) + { + y = 0; + } +} \ No newline at end of file diff --git a/mcs/errors/cs8054-2.cs b/mcs/errors/cs8054-2.cs deleted file mode 100644 index e633f176068..00000000000 --- a/mcs/errors/cs8054-2.cs +++ /dev/null @@ -1,6 +0,0 @@ -// CS0573: `A.a': Structs without explicit constructors cannot contain members with initializers -// Line: 5 - -partial struct A { - int a = 1; -} diff --git a/mcs/errors/cs8054-3.cs b/mcs/errors/cs8054-3.cs deleted file mode 100644 index b06047fb6ee..00000000000 --- a/mcs/errors/cs8054-3.cs +++ /dev/null @@ -1,6 +0,0 @@ -// CS0573: `A.a': Structs without explicit constructors cannot contain members with initializers -// Line: 5 - -struct A { - int a = 1; -} diff --git a/mcs/errors/cs8054.cs b/mcs/errors/cs8054.cs deleted file mode 100644 index 4b8fc2ed446..00000000000 --- a/mcs/errors/cs8054.cs +++ /dev/null @@ -1,7 +0,0 @@ -// CS8054: `S.P': Structs without explicit constructors cannot contain members with initializers -// Line: 6 - -struct S -{ - public decimal P { get; } = -3; -} \ No newline at end of file diff --git a/mcs/errors/cs8075.cs b/mcs/errors/cs8075.cs new file mode 100644 index 00000000000..93333f7187b --- /dev/null +++ b/mcs/errors/cs8075.cs @@ -0,0 +1,9 @@ +// CS8075: `A.A()': Structs parameterless instance constructor must be public +// Line: 6 + +struct A +{ + A () + { + } +} diff --git a/mcs/mcs/anonymous.cs b/mcs/mcs/anonymous.cs index 6df8f8f2363..ced240f47a3 100644 --- a/mcs/mcs/anonymous.cs +++ b/mcs/mcs/anonymous.cs @@ -1814,11 +1814,9 @@ AnonymousMethodMethod DoCreateMethodHost (EmitContext ec) // this argument is generated during compilation which speeds up dispatch // by about 25% // - - // - // Disabled for now due to JIT bug + // Unused as it breaks compatibility // - //method_parameters = ParametersCompiled.Prefix (method_parameters, + // method_parameters = ParametersCompiled.Prefix (method_parameters, // new Parameter (null, null, 0, null, loc), ec.Module.Compiler.BuiltinTypes.Object); } diff --git a/mcs/mcs/class.cs b/mcs/mcs/class.cs index 9b480450f8e..b70c3589dc5 100644 --- a/mcs/mcs/class.cs +++ b/mcs/mcs/class.cs @@ -1151,7 +1151,7 @@ public bool IsAsBindableClass { } } - public virtual void RegisterFieldForInitialization (MemberCore field, FieldInitializer expression) + public void RegisterFieldForInitialization (MemberCore field, FieldInitializer expression) { if (IsPartialPart) PartialContainer.RegisterFieldForInitialization (field, expression); @@ -1164,6 +1164,13 @@ public virtual void RegisterFieldForInitialization (MemberCore field, FieldIniti initialized_static_fields.Add (expression); } else { + if (Kind == MemberKind.Struct) { + if (Compiler.Settings.Version != LanguageVersion.Experimental) { + Report.Error (573, expression.Location, "'{0}': Structs cannot have instance property or field initializers", + GetSignatureForError ()); + } + } + if (initialized_fields == null) initialized_fields = new List (4); @@ -1234,7 +1241,7 @@ public void ResolveFieldInitializers (BlockContext ec) // // Field is re-initialized to its default value => removed // - if (fi.IsDefaultInitializer && ec.Module.Compiler.Settings.Optimize) + if (fi.IsDefaultInitializer && Kind != MemberKind.Struct && ec.Module.Compiler.Settings.Optimize) continue; ec.AssignmentInfoOffset += fi.AssignmentOffset; @@ -2910,8 +2917,10 @@ protected virtual Constructor DefineDefaultConstructor (bool is_static) if (Kind == MemberKind.Class) c.Initializer = new GeneratedBaseInitializer (Location, PrimaryConstructorBaseArguments); - if (PrimaryConstructorParameters != null && !is_static) + if (PrimaryConstructorParameters != null && !is_static) { c.IsPrimaryConstructor = true; + c.caching_flags |= Flags.MethodOverloadsExist; + } AddConstructor (c, true); if (PrimaryConstructorBlock == null) { @@ -2930,6 +2939,7 @@ protected override bool DoDefineMembers () CheckProtectedModifier (); if (PrimaryConstructorParameters != null) { + foreach (Parameter p in PrimaryConstructorParameters.FixedParameters) { if (p.Name == MemberName.Name) { Report.Error (8039, p.Location, "Primary constructor of type `{0}' has parameter of same name as containing type", @@ -3487,10 +3497,14 @@ static bool CheckFieldTypeCycle (TypeSpec ts) protected override bool DoDefineMembers () { - if (PrimaryConstructorParameters != null) + var res = base.DoDefineMembers (); + + if (PrimaryConstructorParameters != null || (initialized_fields != null && !HasUserDefaultConstructor ())) { generated_primary_constructor = DefineDefaultConstructor (false); + generated_primary_constructor.Define (); + } - return base.DoDefineMembers (); + return res; } public override void Emit () @@ -3500,14 +3514,14 @@ public override void Emit () base.Emit (); } - bool HasExplicitConstructor () + bool HasUserDefaultConstructor () { - foreach (var m in Members) { + foreach (var m in PartialContainer.Members) { var c = m as Constructor; if (c == null) continue; - if (!c.ParameterInfo.IsEmpty) + if (!c.IsStatic && c.ParameterInfo.IsEmpty) return true; } @@ -3566,18 +3580,6 @@ protected override TypeSpec[] ResolveBaseTypes (out FullNamedExpression base_cla base_type = Compiler.BuiltinTypes.ValueType; return ifaces; } - - public override void RegisterFieldForInitialization (MemberCore field, FieldInitializer expression) - { - if ((field.ModFlags & Modifiers.STATIC) == 0 && !HasExplicitConstructor ()) { - Report.Error (8054, field.Location, "`{0}': Structs without explicit constructors cannot contain members with initializers", - field.GetSignatureForError ()); - - return; - } - - base.RegisterFieldForInitialization (field, expression); - } } /// diff --git a/mcs/mcs/codegen.cs b/mcs/mcs/codegen.cs index 15855b5f5b2..27bfed474ec 100644 --- a/mcs/mcs/codegen.cs +++ b/mcs/mcs/codegen.cs @@ -228,6 +228,8 @@ public List StatementEpilogue { public List TryFinallyUnwind { get; set; } + public Label RecursivePatternLabel { get; set; } + #endregion public void AddStatementEpilog (IExpressionCleanup cleanupExpression) @@ -553,13 +555,10 @@ public void EmitArrayLoad (ArrayContainer ac) switch (type.BuiltinType) { case BuiltinTypeSpec.Type.Bool: // - // Workaround MSIL limitation. Load bool element as single bit, - // bool array can actually store any byte value + // bool array can actually store any byte value in underlying byte slot + // and C# spec does not specify any normalization rule, except the result + // is undefined // - ig.Emit (OpCodes.Ldelem_U1); - ig.Emit (OpCodes.Ldc_I4_0); - ig.Emit (OpCodes.Cgt_Un); - break; case BuiltinTypeSpec.Type.Byte: ig.Emit (OpCodes.Ldelem_U1); break; @@ -775,12 +774,8 @@ public void EmitLoadFromPtr (TypeSpec type) ig.Emit (OpCodes.Ldind_U1); break; case BuiltinTypeSpec.Type.SByte: - ig.Emit (OpCodes.Ldind_I1); - break; case BuiltinTypeSpec.Type.Bool: ig.Emit (OpCodes.Ldind_I1); - ig.Emit (OpCodes.Ldc_I4_0); - ig.Emit (OpCodes.Cgt_Un); break; case BuiltinTypeSpec.Type.ULong: case BuiltinTypeSpec.Type.Long: @@ -1070,7 +1065,7 @@ public void EmitPredefined (EmitContext ec, MethodSpec method, Arguments Argumen var ie = new InstanceEmitter (instance_copy, IsAddressCall (instance_copy, call_op, method.DeclaringType)); if (Arguments == null) { - ie.EmitLoad (ec); + ie.EmitLoad (ec, true); } } else if (!InstanceExpressionOnStack) { var ie = new InstanceEmitter (InstanceExpression, IsAddressCall (InstanceExpression, call_op, method.DeclaringType)); @@ -1232,7 +1227,7 @@ public void Emit (EmitContext ec, bool conditionalAccess) instance_address = instance as LocalTemporary; if (instance_address == null) { - EmitLoad (ec); + EmitLoad (ec, false); ec.Emit (OpCodes.Dup); ec.EmitLoadFromPtr (instance.Type); @@ -1240,11 +1235,8 @@ public void Emit (EmitContext ec, bool conditionalAccess) } else { instance.Emit (ec); } - - if (instance.Type.Kind == MemberKind.TypeParameter) - ec.Emit (OpCodes.Box, instance.Type); } else { - EmitLoad (ec); + EmitLoad (ec, !conditionalAccess); if (conditionalAccess) { conditional_access_dup = !IsInexpensiveLoad (); @@ -1254,6 +1246,9 @@ public void Emit (EmitContext ec, bool conditionalAccess) } if (conditionalAccess) { + if (instance.Type.Kind == MemberKind.TypeParameter) + ec.Emit (OpCodes.Box, instance.Type); + ec.Emit (OpCodes.Brtrue_S, NullOperatorLabel); if (conditional_access_dup) @@ -1286,7 +1281,7 @@ public void Emit (EmitContext ec, bool conditionalAccess) } } - public void EmitLoad (EmitContext ec) + public void EmitLoad (EmitContext ec, bool boxInstance) { var instance_type = instance.Type; @@ -1317,8 +1312,9 @@ public void EmitLoad (EmitContext ec) instance.Emit (ec); // Only to make verifier happy - if (RequiresBoxing ()) + if (boxInstance && RequiresBoxing ()) { ec.Emit (OpCodes.Box, instance_type); + } } public TypeSpec GetStackType (EmitContext ec) @@ -1346,6 +1342,9 @@ bool RequiresBoxing () return false; } + // + // Returns true for cheap race-free load, where we can avoid using dup + // bool IsInexpensiveLoad () { if (instance is Constant) @@ -1355,8 +1354,10 @@ bool IsInexpensiveLoad () return false; var vr = instance as VariableReference; - if (vr != null) - return !vr.IsRef; + if (vr != null) { + // Load from captured local would be racy without dup + return !vr.IsRef && !vr.IsHoisted; + } if (instance is LocalTemporary) return true; diff --git a/mcs/mcs/cs-parser.jay b/mcs/mcs/cs-parser.jay index 5ad7bcce087..2db083886ca 100644 --- a/mcs/mcs/cs-parser.jay +++ b/mcs/mcs/cs-parser.jay @@ -871,7 +871,7 @@ named_attribute_argument ; named_argument - : identifier_inside_body COLON opt_named_modifier expression_or_error + : identifier_inside_body COLON opt_named_modifier named_argument_expr { if (lang_version <= LanguageVersion.V_3) FeatureIsNotAvailable (GetLocation ($1), "named argument"); @@ -884,6 +884,11 @@ named_argument lbag.AddLocation ($$, GetLocation($2)); } ; + +named_argument_expr + : expression_or_error + | declaration_expression + ; opt_named_modifier : /* empty */ { $$ = null; } @@ -2143,33 +2148,23 @@ operator_declaration { OperatorDeclaration decl = (OperatorDeclaration) $3; if (decl != null) { - - if (current_local_parameters.Count < 1) { - - // This is obviously wrong.. but don't know the correct error to display. - Error_SyntaxError (yyToken); - - } else { - - Operator op = new Operator ( - current_type, decl.optype, decl.ret_type, (Modifiers) $2, - current_local_parameters, - (ToplevelBlock) $5, (Attributes) $1, decl.location); - - if (op.Block == null) - op.ParameterInfo.CheckParameters (op); - - if (doc_support) { - op.DocComment = tmpComment; - Lexer.doc_state = XmlCommentState.Allowed; - } - - // Note again, checking is done in semantic analysis - current_type.AddOperator (op); - - lbag.AddMember (op, mod_locations, lbag.GetLocations (decl)); + Operator op = new Operator ( + current_type, decl.optype, decl.ret_type, (Modifiers) $2, + current_local_parameters, + (ToplevelBlock) $5, (Attributes) $1, decl.location); + if (op.Block == null) + op.ParameterInfo.CheckParameters (op); + + if (doc_support) { + op.DocComment = tmpComment; + Lexer.doc_state = XmlCommentState.Allowed; } + + // Note again, checking is done in semantic analysis + current_type.AddOperator (op); + + lbag.AddMember (op, mod_locations, lbag.GetLocations (decl)); } current_local_parameters = null; @@ -2189,6 +2184,8 @@ operator_declarator : operator_type OPERATOR overloadable_operator OPEN_PARENS { valid_param_mod = ParameterModifierType.DefaultValue; + if ((Operator.OpType) $3 == Operator.OpType.Is) + valid_param_mod |= ParameterModifierType.Out; } opt_formal_parameter_list CLOSE_PARENS { @@ -2213,6 +2210,8 @@ operator_declarator report.Error (1535, loc, "Overloaded unary operator `{0}' takes one parameter", Operator.GetName (op)); } + } else if (op == Operator.OpType.Is) { + // TODO: Special checks for is operator } else { if (p_count == 1) { report.Error (1019, loc, "Overloadable unary operator expected"); @@ -2259,6 +2258,13 @@ overloadable_operator | OP_LT { $$ = Operator.OpType.LessThan; } | OP_GE { $$ = Operator.OpType.GreaterThanOrEqual; } | OP_LE { $$ = Operator.OpType.LessThanOrEqual; } + | IS + { + if (lang_version != LanguageVersion.Experimental) + FeatureIsNotAvailable (GetLocation ($1), "is user operator"); + + $$ = Operator.OpType.Is; + } ; conversion_operator_declarator @@ -2362,11 +2368,25 @@ constructor_declarator if (lt.Value != current_container.MemberName.Name) { report.Error (1520, c.Location, "Class, struct, or interface method must have a return type"); } else if ((mods & Modifiers.STATIC) != 0) { + if (!current_local_parameters.IsEmpty) { + report.Error (132, c.Location, "`{0}': The static constructor must be parameterless", + c.GetSignatureForError ()); + } + if ((mods & Modifiers.AccessibilityMask) != 0){ report.Error (515, c.Location, "`{0}': static constructor cannot have an access modifier", c.GetSignatureForError ()); } + } else { + if (current_type.Kind == MemberKind.Struct && current_local_parameters.IsEmpty) { + if (lang_version < LanguageVersion.V_6) + FeatureIsNotAvailable (GetLocation ($3), "struct parameterless instance constructor"); + + if ((mods & Modifiers.PUBLIC) == 0) { + report.Error (8075, c.Location, "`{0}': Structs parameterless instance constructor must be public", c.GetSignatureForError ()); + } + } } current_type.AddConstructor (c); @@ -3250,7 +3270,7 @@ integral_type primary_expression - : primary_expression_or_type + : type_name_expression | literal | array_creation_expression | parenthesized_expression @@ -3272,7 +3292,7 @@ primary_expression | undocumented_expressions ; -primary_expression_or_type +type_name_expression : simple_name_expr | IDENTIFIER GENERATE_COMPLETION { var lt = (LocatedToken) $1; @@ -3591,11 +3611,19 @@ non_simple_argument $$ = new Argument ((Expression) $2, Argument.AType.Ref); lbag.AddLocation ($$, GetLocation ($1)); } + | REF declaration_expression + { + $$ = new Argument ((Expression) $2, Argument.AType.Ref); + } | OUT variable_reference { $$ = new Argument ((Expression) $2, Argument.AType.Out); lbag.AddLocation ($$, GetLocation ($1)); } + | OUT declaration_expression + { + $$ = new Argument ((Expression) $2, Argument.AType.Out); + } | ARGLIST OPEN_PARENS argument_list CLOSE_PARENS { $$ = new Argument (new Arglist ((Arguments) $3, GetLocation ($1))); @@ -3608,6 +3636,48 @@ non_simple_argument } ; +declaration_expression + : OPEN_PARENS declaration_expression CLOSE_PARENS + { + $$ = new ParenthesizedExpression ((Expression) $2, GetLocation ($1)); + lbag.AddLocation ($$, GetLocation ($1), GetLocation ($3)); + } +/* + | CHECKED open_parens_any declaration_expression CLOSE_PARENS + { + $$ = new CheckedExpr ((Expression) $3, GetLocation ($1)); + lbag.AddLocation ($$, GetLocation ($2), GetLocation ($4)); + } + | UNCHECKED open_parens_any declaration_expression CLOSE_PARENS + { + $$ = new UnCheckedExpr ((Expression) $3, GetLocation ($1)); + lbag.AddLocation ($$, GetLocation ($2), GetLocation ($4)); + } +*/ + | variable_type identifier_inside_body + { + if (lang_version < LanguageVersion.V_6) + FeatureIsNotAvailable (GetLocation ($1), "declaration expression"); + + var lt = (LocatedToken) $2; + var lv = new LocalVariable (current_block, lt.Value, lt.Location); + current_block.AddLocalName (lv); + $$ = new DeclarationExpression ((FullNamedExpression) $1, lv); + } + | variable_type identifier_inside_body ASSIGN expression + { + if (lang_version < LanguageVersion.V_6) + FeatureIsNotAvailable (GetLocation ($1), "declaration expression"); + + var lt = (LocatedToken) $2; + var lv = new LocalVariable (current_block, lt.Value, lt.Location); + current_block.AddLocalName (lv); + $$ = new DeclarationExpression ((FullNamedExpression) $1, lv) { + Initializer = (Expression) $4 + }; + } + ; + variable_reference : expression ; @@ -4290,7 +4360,7 @@ additive_expression { $$ = new As ((Expression) $1, (Expression) $3, GetLocation ($2)); } - | additive_expression IS is_match_expr opt_identifier + | additive_expression IS pattern_type_expr opt_identifier { var is_expr = new Is ((Expression) $1, (Expression) $3, GetLocation ($2)); if ($4 != null) { @@ -4302,6 +4372,14 @@ additive_expression current_block.AddLocalName (is_expr.Variable); } + $$ = is_expr; + } + | additive_expression IS pattern_expr + { + var is_expr = new Is ((Expression) $1, (Expression) $3, GetLocation ($2)); + if (lang_version != LanguageVersion.Experimental) + FeatureIsNotAvailable (GetLocation ($2), "pattern matching"); + $$ = is_expr; } | additive_expression AS error @@ -4328,16 +4406,12 @@ additive_expression } ; -is_match_expr - : match_type - | match_type rank_specifiers - { - if ($1 is VarExpr) - $1 = new SimpleName ("var", ((VarExpr) $1).Location); +pattern_type_expr + : variable_type + ; - $$ = new ComposedCast ((FullNamedExpression) $1, (ComposedTypeSpecifier) $2); - } - | literal +pattern_expr + : literal | PLUS prefixed_unary_expression { $$ = new Unary (Unary.Operator.UnaryPlus, (Expression) $2, GetLocation ($1)); @@ -4346,38 +4420,106 @@ is_match_expr { $$ = new Unary (Unary.Operator.UnaryNegation, (Expression) $2, GetLocation ($1)); } + | sizeof_expression + | default_value_expression + | OPEN_PARENS_CAST type CLOSE_PARENS prefixed_unary_expression + { + $$ = new Cast ((FullNamedExpression) $2, (Expression) $4, GetLocation ($1)); + lbag.AddLocation ($$, GetLocation ($3)); + } + | STAR + { + $$ = new WildcardPattern (GetLocation ($1)); + } + | pattern_expr_invocation + | pattern_property ; -match_type - : primary_expression_or_type opt_nullable +pattern_expr_invocation + : type_name_expression OPEN_PARENS opt_pattern_list CLOSE_PARENS { - Expression expr = (Expression) $1; - if ($2 == null) { - SimpleName sn = expr as SimpleName; - if (sn != null && sn.Name == "var") - $$ = new VarExpr (sn.Location); - else - $$ = $1; - } else if (expr is ATypeNameExpression) { - $$ = new ComposedCast ((ATypeNameExpression)expr, (ComposedTypeSpecifier) $2); - } else { - Error_ExpectingTypeName (expr); - $$ = null; - } + $$ = new RecursivePattern ((ATypeNameExpression) $1, (Arguments) $3, GetLocation ($2)); } - | primary_expression_or_type pointer_stars + ; + +pattern_property + : type_name_expression OPEN_BRACE pattern_property_list CLOSE_BRACE { - ATypeNameExpression expr = $1 as ATypeNameExpression; + $$ = new PropertyPattern ((ATypeNameExpression) $1, (List) $3, GetLocation ($2)); + } + ; - if (expr != null) { - $$ = new ComposedCast (expr, (ComposedTypeSpecifier) $2); - } else { - Error_ExpectingTypeName ((Expression)$1); - $$ = expr; +pattern_property_list + : pattern_property_entry + { + var list = new List (); + list.Add ((PropertyPatternMember) $1); + $$ = list; + } + | pattern_property_list COMMA pattern_property_entry + { + var list = (List) $1; + list.Add ((PropertyPatternMember) $3); + $$ = list; + } + ; + +pattern_property_entry + : identifier_inside_body IS pattern + { + var lt = (LocatedToken) $1; + $$ = new PropertyPatternMember (lt.Value, (Expression) $3, lt.Location); + } + ; + +pattern + : pattern_expr + | pattern_type_expr opt_identifier + { + if ($2 != null) { + var lt = (LocatedToken) $2; + var variable = new LocalVariable (current_block, lt.Value, lt.Location); + current_block.AddLocalName (variable); } } - | builtin_type_expression - | void_invalid + ; + +opt_pattern_list + : /* empty */ + { + $$ = new Arguments (0); + } + | pattern_list + ; + +pattern_list + : pattern_argument + { + Arguments args = new Arguments (4); + args.Add ((Argument) $1); + $$ = args; + } + | pattern_list COMMA pattern_argument + { + Arguments args = (Arguments) $1; + if (args [args.Count - 1] is NamedArgument && !($3 is NamedArgument)) + Error_NamedArgumentExpected ((NamedArgument) args [args.Count - 1]); + + args.Add ((Argument) $3); + $$ = args; + } + ; + +pattern_argument + : pattern + { + $$ = new Argument ((Expression) $1); + } + | IDENTIFIER COLON pattern + { + var lt = (LocatedToken) $1; + $$ = new NamedArgument (lt.Value, lt.Location, (Expression) $3); + } ; shift_expression @@ -5436,7 +5578,7 @@ variable_type * > The expressions are converted into types during semantic analysis. */ variable_type_simple - : primary_expression_or_type opt_nullable + : type_name_expression opt_nullable { // Ok, the above "primary_expression" is there to get rid of // both reduce/reduce and shift/reduces in the grammar, it should @@ -5452,30 +5594,20 @@ variable_type_simple // SimpleName is when you have // Blah i; - Expression expr = (Expression) $1; + var expr = (ATypeNameExpression) $1; if ($2 == null) { - SimpleName sn = expr as SimpleName; - if (sn != null && sn.Name == "var") - $$ = new VarExpr (sn.Location); + if (expr.Name == "var" && expr is SimpleName) + $$ = new VarExpr (expr.Location); else $$ = $1; - } else if (expr is ATypeNameExpression) { - $$ = new ComposedCast ((ATypeNameExpression)expr, (ComposedTypeSpecifier) $2); } else { - Error_ExpectingTypeName (expr); - $$ = null; + $$ = new ComposedCast (expr, (ComposedTypeSpecifier) $2); } } - | primary_expression_or_type pointer_stars + | type_name_expression pointer_stars { - ATypeNameExpression expr = $1 as ATypeNameExpression; - - if (expr != null) { - $$ = new ComposedCast (expr, (ComposedTypeSpecifier) $2); - } else { - Error_ExpectingTypeName ((Expression)$1); - $$ = expr; - } + var expr = (ATypeNameExpression) $1; + $$ = new ComposedCast (expr, (ComposedTypeSpecifier) $2); } | builtin_type_expression | void_invalid @@ -5795,6 +5927,16 @@ switch_label Error_SyntaxError (yyToken); $$ = new SwitchLabel ((Expression) $2, GetLocation ($1)); } + | CASE pattern_expr_invocation COLON + { + if (lang_version != LanguageVersion.Experimental) + FeatureIsNotAvailable (GetLocation ($2), "pattern matching"); + + $$ = new SwitchLabel ((Expression) $2, GetLocation ($1)) { + PatternMatching = true + }; + lbag.AddLocation ($$, GetLocation ($3)); + } | DEFAULT_COLON { $$ = new SwitchLabel (null, GetLocation ($1)); @@ -7944,6 +8086,7 @@ static string GetTokenName (int token) case Token.OP_AND_ASSIGN: case Token.OP_XOR_ASSIGN: case Token.OP_OR_ASSIGN: + case Token.INTERR_OPERATOR: return ""; case Token.BOOL: diff --git a/mcs/mcs/cs-tokenizer.cs b/mcs/mcs/cs-tokenizer.cs index 2147c145e6c..9647a4bd7e6 100644 --- a/mcs/mcs/cs-tokenizer.cs +++ b/mcs/mcs/cs-tokenizer.cs @@ -1268,6 +1268,7 @@ int TokenizePossibleNullableType () int next_token; int parens = 0; int generics = 0; + int brackets = 0; var nt = xtoken (); switch (nt) { @@ -1333,6 +1334,11 @@ int TokenizePossibleNullableType () ++parens; goto default; + case Token.OPEN_BRACKET: + case Token.OPEN_BRACKET_EXPR: + ++brackets; + goto default; + case Token.CLOSE_PARENS: --parens; goto default; @@ -1348,7 +1354,6 @@ int TokenizePossibleNullableType () int interrs = 1; int colons = 0; int braces = 0; - int brackets = 0; // // All shorcuts failed, do it hard way // diff --git a/mcs/mcs/delegate.cs b/mcs/mcs/delegate.cs index 90b3d7fbc7c..4133cb94571 100644 --- a/mcs/mcs/delegate.cs +++ b/mcs/mcs/delegate.cs @@ -404,6 +404,9 @@ void DefineAsyncMethods (TypeExpression returnType) public override void PrepareEmit () { + if ((caching_flags & Flags.CloseTypeCreated) != 0) + return; + if (!Parameters.IsEmpty) { parameters.ResolveDefaultValues (this); } diff --git a/mcs/mcs/dynamic.cs b/mcs/mcs/dynamic.cs index dcdbc998920..b1516c0700a 100644 --- a/mcs/mcs/dynamic.cs +++ b/mcs/mcs/dynamic.cs @@ -328,7 +328,14 @@ protected override Expression DoResolve (ResolveContext rc) protected bool DoResolveCore (ResolveContext rc) { - if (rc.CurrentTypeParameters != null && rc.CurrentTypeParameters [0].IsMethodTypeParameter) + foreach (var arg in arguments) { + if (arg.Type == InternalType.VarOutType) { + // Should be special error message about dynamic dispatch + rc.Report.Error (8047, arg.Expr.Location, "Declaration expression cannot be used in this context"); + } + } + + if (rc.CurrentTypeParameters != null && rc.CurrentTypeParameters[0].IsMethodTypeParameter) context_mvars = rc.CurrentTypeParameters; int errors = rc.Report.Errors; diff --git a/mcs/mcs/ecore.cs b/mcs/mcs/ecore.cs index 19818c4b7d4..264ba680236 100644 --- a/mcs/mcs/ecore.cs +++ b/mcs/mcs/ecore.cs @@ -230,10 +230,10 @@ public virtual Expression DoResolveLValue (ResolveContext rc, Expression right_s // public virtual TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false) { - ResolveContext ec = new ResolveContext (mc); - Expression e = Resolve (ec); + var rc = mc as ResolveContext ?? new ResolveContext (mc); + Expression e = Resolve (rc); if (e != null) - e.Error_UnexpectedKind (ec, ResolveFlags.Type, loc); + e.Error_UnexpectedKind (rc, ResolveFlags.Type, loc); return null; } @@ -482,6 +482,8 @@ protected static bool IsNullPropagatingValid (TypeSpec type) return false; case MemberKind.InternalCompilerType: return type.BuiltinType == BuiltinTypeSpec.Type.Dynamic; + case MemberKind.TypeParameter: + return !((TypeParameterSpec) type).IsValueType; default: return true; } @@ -794,6 +796,10 @@ public static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, re if (ctors == null) { switch (type.Kind) { case MemberKind.Struct: + // Every struct has implicit default constructor if not provided by user + if (args == null) + return null; + rc.Report.SymbolRelatedToPreviousError (type); // Report meaningful error for struct as they always have default ctor in C# context OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc); @@ -814,6 +820,18 @@ public static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, re return null; } + if (args == null && type.IsStruct) { + bool includes_empty = false; + foreach (MethodSpec ctor in ctors) { + if (ctor.Parameters.IsEmpty) { + includes_empty = true; + } + } + + if (!includes_empty) + return null; + } + var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc); if (!rc.HasSet (ResolveContext.Options.BaseInitializer)) { r.InstanceQualifier = new ConstructorInstanceQualifier (type); @@ -1089,7 +1107,11 @@ protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, L static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc) { var op = is_true ? Operator.OpType.True : Operator.OpType.False; - var methods = MemberCache.GetUserOperator (e.type, op, false); + var type = e.type; + if (type.IsNullableType) + type = Nullable.NullableInfo.GetUnderlyingType (type); + + var methods = MemberCache.GetUserOperator (type, op, false); if (methods == null) return null; @@ -3398,6 +3420,11 @@ public FullNamedExpression LookupTypeOrNamespace (IMemberContext ctx, string nam { return ns.LookupTypeOrNamespace (ctx, name, arity, mode, loc); } + + public override string ToString () + { + return Namespace.Name; + } } /// @@ -4962,11 +4989,23 @@ public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, // one being the virtual base for the parameter types and modifiers. // // A return value rates candidate method compatibility, - // 0 = the best, int.MaxValue = the worst // -1 = fatal error + // 0 = the best, int.MaxValue = the worst // int IsApplicable (ResolveContext ec, ref Arguments arguments, int arg_count, ref MemberSpec candidate, IParametersMember pm, ref bool params_expanded_form, ref bool dynamicArgument, ref TypeSpec returnType, bool errorMode) { + // + // Each step has allocated 10 values, it can overflow for + // more than 10 arguments but that's ok as it's used for + // better error reporting only + // + const int ArgumentCountMismatch = 1000000000; + const int NamedArgumentsMismatch = 100000000; + const int DefaultArgumentMismatch = 10000000; + const int UnexpectedTypeArguments = 1000000; + const int TypeArgumentsMismatch = 100000; + const int InflatedTypesMismatch = 10000; + // Parameters of most-derived type used mainly for named and optional parameters var pd = pm.Parameters; @@ -4999,17 +5038,17 @@ int IsApplicable (ResolveContext ec, ref Arguments arguments, int arg_count, ref param_count--; } else if (arg_count > param_count) { int args_gap = System.Math.Abs (arg_count - param_count); - return int.MaxValue - 10000 + args_gap; + return ArgumentCountMismatch + args_gap; } else if (arg_count < param_count - optional_count) { int args_gap = System.Math.Abs (param_count - optional_count - arg_count); - return int.MaxValue - 10000 + args_gap; + return ArgumentCountMismatch + args_gap; } } else if (arg_count != param_count) { int args_gap = System.Math.Abs (arg_count - param_count); if (!cpd.HasParams) - return int.MaxValue - 10000 + args_gap; + return ArgumentCountMismatch + args_gap; if (arg_count < param_count - 1) - return int.MaxValue - 10000 + args_gap; + return ArgumentCountMismatch + args_gap; } // Resize to fit optional arguments @@ -5046,7 +5085,7 @@ int IsApplicable (ResolveContext ec, ref Arguments arguments, int arg_count, ref // Named parameter not found if (index < 0) - return (i + 1) * 3; + return NamedArgumentsMismatch - i; // already reordered if (index == i) @@ -5062,8 +5101,8 @@ int IsApplicable (ResolveContext ec, ref Arguments arguments, int arg_count, ref ++arg_count; temp = null; } else { - if (index == arg_count) - return (i + 1) * 3; + if (index == arg_count) + return NamedArgumentsMismatch - i - 1; temp = arguments [index]; @@ -5100,7 +5139,7 @@ int IsApplicable (ResolveContext ec, ref Arguments arguments, int arg_count, ref // Don't do any expensive checks when the candidate cannot succeed // if (arg_count != param_count && !cpd.HasParams) - return (param_count - arg_count) * 2 + 1; + return DefaultArgumentMismatch - System.Math.Abs (param_count - arg_count); var dep = candidate.GetMissingDependencies (); if (dep != null) { @@ -5117,7 +5156,7 @@ int IsApplicable (ResolveContext ec, ref Arguments arguments, int arg_count, ref if (type_arguments != null) { var g_args_count = ms.Arity; if (g_args_count != type_arguments.Count) - return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count); + return TypeArgumentsMismatch - System.Math.Abs (type_arguments.Count - g_args_count); if (type_arguments.Arguments != null) ms = ms.MakeGenericMethod (ec, type_arguments.Arguments); @@ -5149,7 +5188,7 @@ int IsApplicable (ResolveContext ec, ref Arguments arguments, int arg_count, ref TypeSpec[] i_args = ti.InferMethodArguments (ec, ms); if (i_args == null) - return ti.InferenceScore - 20000; + return TypeArgumentsMismatch - ti.InferenceScore; // // Clear any error messages when the result was success @@ -5159,9 +5198,10 @@ int IsApplicable (ResolveContext ec, ref Arguments arguments, int arg_count, ref if (i_args.Length != 0) { if (!errorMode) { - foreach (var ta in i_args) { + for (int i = 0; i < i_args.Length; ++i) { + var ta = i_args [i]; if (!ta.IsAccessible (ec)) - return ti.InferenceScore - 10000; + return TypeArgumentsMismatch - i; } } @@ -5174,7 +5214,7 @@ int IsApplicable (ResolveContext ec, ref Arguments arguments, int arg_count, ref // if (!CheckInflatedArguments (ms)) { candidate = ms; - return int.MaxValue - 25000; + return InflatedTypesMismatch; } // @@ -5197,7 +5237,7 @@ int IsApplicable (ResolveContext ec, ref Arguments arguments, int arg_count, ref ptypes = pd.Types; } else { if (type_arguments != null) - return int.MaxValue - 15000; + return UnexpectedTypeArguments; ptypes = cpd.Types; } @@ -5358,31 +5398,36 @@ int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifi // is used and argument is not of dynamic type // if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) { - if (argument.Type != parameter) { + var arg_type = argument.Type; + + if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) { + // + // Using dynamic for ref/out parameter can still succeed at runtime + // + if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0) + return -1; + + return 1; + } + + if (arg_type != parameter) { + if (arg_type == InternalType.VarOutType) + return 0; + // // Do full equality check after quick path // - if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) { + if (!TypeSpecComparer.IsEqual (arg_type, parameter)) { // // Using dynamic for ref/out parameter can still succeed at runtime // - if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0) + if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0) return -1; return 2; } } - if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) { - // - // Using dynamic for ref/out parameter can still succeed at runtime - // - if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0) - return -1; - - return 1; - } - } else { if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0) return -1; @@ -5963,10 +6008,20 @@ bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask)) break; - if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) + var arg_type = a.Type; + if (arg_type == pt) continue; - break; + if (arg_type == InternalType.VarOutType) { + // + // Set underlying variable type based on parameter type + // + ((DeclarationExpression)a.Expr).Variable.Type = pt; + continue; + } + + if (!TypeSpecComparer.IsEqual (arg_type, pt)) + break; } NamedArgument na = a as NamedArgument; @@ -6038,6 +6093,20 @@ bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, } if (a_idx != arg_count) { + // + // Convert all var out argument to error type for less confusing error reporting + // when no matching overload is found + // + for (; a_idx < arg_count; a_idx++) { + var arg = args [a_idx]; + if (arg == null) + continue; + + if (arg.Type == InternalType.VarOutType) { + ((DeclarationExpression)arg.Expr).Variable.Type = InternalType.ErrorType; + } + } + ReportArgumentMismatch (ec, a_pos, member, a, pd, pt); return false; } diff --git a/mcs/mcs/eval.cs b/mcs/mcs/eval.cs index 357eb879bdc..538dfda354d 100644 --- a/mcs/mcs/eval.cs +++ b/mcs/mcs/eval.cs @@ -887,13 +887,19 @@ static string Quote (string s) public string GetUsing () { + if (source_file == null || source_file.Usings == null) + return string.Empty; + StringBuilder sb = new StringBuilder (); // TODO: //foreach (object x in ns.using_alias_list) // sb.AppendFormat ("using {0};\n", x); foreach (var ue in source_file.Usings) { - sb.AppendFormat ("using {0};", ue.ToString ()); + if (ue.Alias != null || ue.ResolvedExpression == null) + continue; + + sb.AppendFormat("using {0};", ue.ToString ()); sb.Append (Environment.NewLine); } @@ -904,7 +910,11 @@ internal List GetUsingList () { var res = new List (); - foreach (var ue in source_file.Usings) { + if (source_file == null || source_file.Usings == null) + return res; + + foreach (var ue in source_file.Usings) + { if (ue.Alias != null || ue.ResolvedExpression == null) continue; diff --git a/mcs/mcs/expression.cs b/mcs/mcs/expression.cs index 625edee0b8a..8fe94f57402 100644 --- a/mcs/mcs/expression.cs +++ b/mcs/mcs/expression.cs @@ -1655,7 +1655,12 @@ Expression CreateConstantResult (ResolveContext rc, bool result) public override void Emit (EmitContext ec) { if (probe_type_expr == null) { - EmitConstantMatch (ec); + if (ProbeType is WildcardPattern) { + expr.EmitSideEffect (ec); + ProbeType.Emit (ec); + } else { + EmitPatternMatch (ec); + } return; } @@ -1670,7 +1675,7 @@ public override void Emit (EmitContext ec) public override void EmitBranchable (EmitContext ec, Label target, bool on_true) { if (probe_type_expr == null) { - EmitConstantMatch (ec); + EmitPatternMatch (ec); } else { EmitLoad (ec); } @@ -1678,7 +1683,7 @@ public override void EmitBranchable (EmitContext ec, Label target, bool on_true) ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target); } - void EmitConstantMatch (EmitContext ec) + void EmitPatternMatch (EmitContext ec) { var no_match = ec.DefineLabel (); var end = ec.DefineLabel (); @@ -1709,22 +1714,42 @@ void EmitConstantMatch (EmitContext ec) return; } + var probe_type = ProbeType.Type; + Expr.Emit (ec); - ec.Emit (OpCodes.Isinst, ProbeType.Type); + ec.Emit (OpCodes.Isinst, probe_type); ec.Emit (OpCodes.Dup); ec.Emit (OpCodes.Brfalse, no_match); + bool complex_pattern = ProbeType is ComplexPatternExpression; + Label prev = ec.RecursivePatternLabel; + if (complex_pattern) + ec.RecursivePatternLabel = ec.DefineLabel (); + if (number_mg != null) { var ce = new CallEmitter (); ce.Emit (ec, number_mg, number_args, loc); } else { + if (TypeSpec.IsValueType (probe_type)) + ec.Emit (OpCodes.Unbox_Any, probe_type); + ProbeType.Emit (ec); - ec.Emit (OpCodes.Ceq); + if (complex_pattern) { + ec.EmitInt (1); + } else { + ec.Emit (OpCodes.Ceq); + } } ec.Emit (OpCodes.Br_S, end); ec.MarkLabel (no_match); ec.Emit (OpCodes.Pop); + + if (complex_pattern) + ec.MarkLabel (ec.RecursivePatternLabel); + + ec.RecursivePatternLabel = prev; + ec.EmitInt (0); ec.MarkLabel (end); } @@ -1812,14 +1837,48 @@ public override void FlowAnalysis (FlowAnalysisContext fc) protected override void ResolveProbeType (ResolveContext rc) { if (!(ProbeType is TypeExpr) && rc.Module.Compiler.Settings.Version == LanguageVersion.Experimental) { - ProbeType = ProbeType.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup | ResolveFlags.Type); - if (ProbeType == null) + if (ProbeType is PatternExpression) { + ProbeType.Resolve (rc); return; + } + + // + // Have to use session recording because we don't have reliable type probing + // mechanism (similar issue as in attributes resolving) + // + // TODO: This is still wrong because ResolveAsType can be destructive + // + var type_printer = new SessionReportPrinter (); + var prev_recorder = rc.Report.SetPrinter (type_printer); + + probe_type_expr = ProbeType.ResolveAsType (rc); + type_printer.EndSession (); - if (ProbeType.eclass == ExprClass.Type) { - probe_type_expr = ProbeType.Type; + if (probe_type_expr != null) { + type_printer.Merge (rc.Report.Printer); + rc.Report.SetPrinter (prev_recorder); + return; } + var vexpr = ProbeType as VarExpr; + if (vexpr != null && vexpr.InferType (rc, expr)) { + probe_type_expr = vexpr.Type; + rc.Report.SetPrinter (prev_recorder); + return; + } + + var expr_printer = new SessionReportPrinter (); + rc.Report.SetPrinter (expr_printer); + ProbeType = ProbeType.Resolve (rc); + expr_printer.EndSession (); + + if (ProbeType != null) { + expr_printer.Merge (rc.Report.Printer); + } else { + type_printer.Merge (rc.Report.Printer); + } + + rc.Report.SetPrinter (prev_recorder); return; } @@ -1848,6 +1907,10 @@ Expression ResolveMatchingExpression (ResolveContext rc) if (Expr.Type.IsNullableType) { expr_unwrap = new Nullable.Unwrap (Expr); expr_unwrap.Resolve (rc); + ProbeType = Convert.ImplicitConversion (rc, ProbeType, expr_unwrap.Type, loc); + } else if (ProbeType.Type == Expr.Type) { + // TODO: Better error handling + return new Binary (Binary.Operator.Equality, Expr, mc, loc).Resolve (rc); } else if (ProbeType.Type.IsEnum || (ProbeType.Type.BuiltinType >= BuiltinTypeSpec.Type.Byte && ProbeType.Type.BuiltinType <= BuiltinTypeSpec.Type.Decimal)) { var helper = rc.Module.CreatePatterMatchingHelper (); number_mg = helper.NumberMatcher.Spec; @@ -1866,7 +1929,17 @@ Expression ResolveMatchingExpression (ResolveContext rc) return this; } - throw new NotImplementedException (); + if (ProbeType is PatternExpression) { + if (!(ProbeType is WildcardPattern) && !Convert.ImplicitConversionExists (rc, ProbeType, Expr.Type)) { + ProbeType.Error_ValueCannotBeConverted (rc, Expr.Type, false); + } + + return this; + } + + // TODO: Better error message + rc.Report.Error (150, ProbeType.Location, "A constant value is expected"); + return this; } Expression ResolveResultExpression (ResolveContext ec) @@ -2052,6 +2125,339 @@ public override object Accept (StructuralVisitor visitor) } } + class WildcardPattern : PatternExpression + { + public WildcardPattern (Location loc) + : base (loc) + { + } + + protected override Expression DoResolve (ResolveContext rc) + { + eclass = ExprClass.Value; + type = rc.BuiltinTypes.Object; + return this; + } + + public override void Emit (EmitContext ec) + { + ec.EmitInt (1); + } + } + + class RecursivePattern : ComplexPatternExpression + { + MethodGroupExpr operator_mg; + Arguments operator_args; + + public RecursivePattern (ATypeNameExpression typeExpresion, Arguments arguments, Location loc) + : base (typeExpresion, loc) + { + Arguments = arguments; + } + + public Arguments Arguments { get; private set; } + + protected override Expression DoResolve (ResolveContext rc) + { + type = TypeExpression.ResolveAsType (rc); + if (type == null) + return null; + + var operators = MemberCache.GetUserOperator (type, Operator.OpType.Is, true); + if (operators == null) { + Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator"); + return null; + } + + var ops = FindMatchingOverloads (operators); + if (ops == null) { + // TODO: better error message + Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator"); + return null; + } + + bool dynamic_args; + Arguments.Resolve (rc, out dynamic_args); + if (dynamic_args) + throw new NotImplementedException ("dynamic argument"); + + var op = FindBestOverload (rc, ops); + if (op == null) { + // TODO: better error message + Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator"); + return null; + } + + var op_types = op.Parameters.Types; + operator_args = new Arguments (op_types.Length); + operator_args.Add (new Argument (new EmptyExpression (type))); + + for (int i = 0; i < Arguments.Count; ++i) { + // TODO: Needs releasing optimization + var lt = new LocalTemporary (op_types [i + 1]); + operator_args.Add (new Argument (lt, Argument.AType.Out)); + + if (comparisons == null) + comparisons = new Expression[Arguments.Count]; + + int arg_comp_index; + Expression expr; + + var arg = Arguments [i]; + var named = arg as NamedArgument; + if (named != null) { + arg_comp_index = op.Parameters.GetParameterIndexByName (named.Name) - 1; + expr = Arguments [arg_comp_index].Expr; + } else { + arg_comp_index = i; + expr = arg.Expr; + } + + comparisons [arg_comp_index] = ResolveComparison (rc, expr, lt); + } + + operator_mg = MethodGroupExpr.CreatePredefined (op, type, loc); + + eclass = ExprClass.Value; + return this; + } + + List FindMatchingOverloads (IList members) + { + int arg_count = Arguments.Count + 1; + List best = null; + foreach (MethodSpec method in members) { + var pm = method.Parameters; + if (pm.Count != arg_count) + continue; + + // TODO: Needs more thorough operator checks elsewhere to avoid doing this every time + bool ok = true; + for (int ii = 1; ii < pm.Count; ++ii) { + if ((pm.FixedParameters [ii].ModFlags & Parameter.Modifier.OUT) == 0) { + ok = false; + break; + } + } + + if (!ok) + continue; + + if (best == null) + best = new List (); + + best.Add (method); + } + + return best; + } + + MethodSpec FindBestOverload (ResolveContext rc, List methods) + { + for (int ii = 0; ii < Arguments.Count; ++ii) { + var arg = Arguments [ii]; + var expr = arg.Expr; + if (expr is WildcardPattern) + continue; + + var na = arg as NamedArgument; + for (int i = 0; i < methods.Count; ++i) { + var pd = methods [i].Parameters; + + int index; + if (na != null) { + index = pd.GetParameterIndexByName (na.Name); + if (index < 1) { + methods.RemoveAt (i--); + continue; + } + } else { + index = ii + 1; + } + + var m = pd.Types [index]; + if (!Convert.ImplicitConversionExists (rc, expr, m)) + methods.RemoveAt (i--); + } + } + + if (methods.Count != 1) + return null; + + return methods [0]; + } + + public override void EmitBranchable (EmitContext ec, Label target, bool on_true) + { + operator_mg.EmitCall (ec, operator_args, false); + ec.Emit (OpCodes.Brfalse, target); + + base.EmitBranchable (ec, target, on_true); + } + + static Expression ResolveComparison (ResolveContext rc, Expression expr, LocalTemporary lt) + { + if (expr is WildcardPattern) + return new EmptyExpression (expr.Type); + + var recursive = expr as RecursivePattern; + expr = Convert.ImplicitConversionRequired (rc, expr, lt.Type, expr.Location); + if (expr == null) + return null; + + if (recursive != null) { + recursive.SetParentInstance (lt); + return expr; + } + + // TODO: Better error handling + return new Binary (Binary.Operator.Equality, lt, expr, expr.Location).Resolve (rc); + } + + public void SetParentInstance (Expression instance) + { + operator_args [0] = new Argument (instance); + } + } + + class PropertyPattern : ComplexPatternExpression + { + LocalTemporary instance; + + public PropertyPattern (ATypeNameExpression typeExpresion, List members, Location loc) + : base (typeExpresion, loc) + { + Members = members; + } + + public List Members { get; private set; } + + protected override Expression DoResolve (ResolveContext rc) + { + type = TypeExpression.ResolveAsType (rc); + if (type == null) + return null; + + comparisons = new Expression[Members.Count]; + + // TODO: optimize when source is VariableReference, it'd save dup+pop + instance = new LocalTemporary (type); + + for (int i = 0; i < Members.Count; i++) { + var lookup = Members [i]; + + var member = MemberLookup (rc, false, type, lookup.Name, 0, Expression.MemberLookupRestrictions.ExactArity, loc); + if (member == null) { + member = MemberLookup (rc, true, type, lookup.Name, 0, Expression.MemberLookupRestrictions.ExactArity, loc); + if (member != null) { + Expression.ErrorIsInaccesible (rc, member.GetSignatureForError (), loc); + continue; + } + } + + if (member == null) { + Expression.Error_TypeDoesNotContainDefinition (rc, Location, Type, lookup.Name); + continue; + } + + var pe = member as PropertyExpr; + if (pe == null || member is FieldExpr) { + rc.Report.Error (-2001, lookup.Location, "`{0}' is not a valid pattern member", lookup.Name); + continue; + } + + // TODO: Obsolete checks + // TODO: check accessibility + if (pe != null && !pe.PropertyInfo.HasGet) { + rc.Report.Error (-2002, lookup.Location, "Property `{0}.get' accessor is required", pe.GetSignatureForError ()); + continue; + } + + var expr = lookup.Expr.Resolve (rc); + if (expr == null) + continue; + + var me = (MemberExpr)member; + me.InstanceExpression = instance; + + comparisons [i] = ResolveComparison (rc, expr, me); + } + + eclass = ExprClass.Value; + return this; + } + + static Expression ResolveComparison (ResolveContext rc, Expression expr, Expression instance) + { + if (expr is WildcardPattern) + return new EmptyExpression (expr.Type); + + return new Is (instance, expr, expr.Location).Resolve (rc); + } + + public override void EmitBranchable (EmitContext ec, Label target, bool on_true) + { + instance.Store (ec); + + base.EmitBranchable (ec, target, on_true); + } + } + + class PropertyPatternMember + { + public PropertyPatternMember (string name, Expression expr, Location loc) + { + Name = name; + Expr = expr; + Location = loc; + } + + public string Name { get; private set; } + public Expression Expr { get; private set; } + public Location Location { get; private set; } + } + + abstract class PatternExpression : Expression + { + protected PatternExpression (Location loc) + { + this.loc = loc; + } + + public override Expression CreateExpressionTree (ResolveContext ec) + { + throw new NotImplementedException (); + } + } + + abstract class ComplexPatternExpression : PatternExpression + { + protected Expression[] comparisons; + + protected ComplexPatternExpression (ATypeNameExpression typeExpresion, Location loc) + : base (loc) + { + TypeExpression = typeExpresion; + } + + public ATypeNameExpression TypeExpression { get; private set; } + + public override void Emit (EmitContext ec) + { + EmitBranchable (ec, ec.RecursivePatternLabel, false); + } + + public override void EmitBranchable (EmitContext ec, Label target, bool on_true) + { + if (comparisons != null) { + foreach (var comp in comparisons) { + comp.EmitBranchable (ec, target, false); + } + } + } + } + /// /// Implementation of the `as' operator. /// @@ -2315,6 +2721,96 @@ protected override Expression DoResolve (ResolveContext ec) return expr; } } + + public class DeclarationExpression : Expression, IMemoryLocation + { + LocalVariableReference lvr; + + public DeclarationExpression (FullNamedExpression variableType, LocalVariable variable) + { + VariableType = variableType; + Variable = variable; + this.loc = variable.Location; + } + + public LocalVariable Variable { get; set; } + public Expression Initializer { get; set; } + public FullNamedExpression VariableType { get; set; } + + public void AddressOf (EmitContext ec, AddressOp mode) + { + Variable.CreateBuilder (ec); + + if (Initializer != null) { + lvr.EmitAssign (ec, Initializer, false, false); + } + + lvr.AddressOf (ec, mode); + } + + protected override void CloneTo (CloneContext clonectx, Expression t) + { + var target = (DeclarationExpression) t; + + target.VariableType = (FullNamedExpression) VariableType.Clone (clonectx); + + if (Initializer != null) + target.Initializer = Initializer.Clone (clonectx); + } + + public override Expression CreateExpressionTree (ResolveContext rc) + { + rc.Report.Error (8046, loc, "An expression tree cannot contain a declaration expression"); + return null; + } + + bool DoResolveCommon (ResolveContext rc) + { + var var_expr = VariableType as VarExpr; + if (var_expr != null) { + type = InternalType.VarOutType; + } else { + type = VariableType.ResolveAsType (rc); + if (type == null) + return false; + } + + if (Initializer != null) { + Initializer = Initializer.Resolve (rc); + + if (var_expr != null && Initializer != null && var_expr.InferType (rc, Initializer)) { + type = var_expr.Type; + } + } + + Variable.Type = type; + lvr = new LocalVariableReference (Variable, loc); + + eclass = ExprClass.Variable; + return true; + } + + protected override Expression DoResolve (ResolveContext rc) + { + if (DoResolveCommon (rc)) + lvr.Resolve (rc); + + return this; + } + + public override Expression DoResolveLValue (ResolveContext rc, Expression right_side) + { + if (lvr == null && DoResolveCommon (rc)) + lvr.ResolveLValue (rc, right_side); + + return this; + } + + public override void Emit (EmitContext ec) + { + throw new NotImplementedException (); + } + } // // C# 2.0 Default value expression @@ -2968,11 +3464,16 @@ public Binary (Operator oper, Expression left, Expression right, bool isCompound } public Binary (Operator oper, Expression left, Expression right) + : this (oper, left, right, left.Location) + { + } + + public Binary (Operator oper, Expression left, Expression right, Location loc) { this.oper = oper; this.left = left; this.right = right; - this.loc = left.Location; + this.loc = loc; } #region Properties @@ -4704,7 +5205,15 @@ Expression ResolveEnumOperators (ResolveContext rc, bool lenum, bool renum, Type return expr; } - enum_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { enum_type }); + var nullable = rc.Module.PredefinedTypes.Nullable; + + // + // Don't try nullable version when nullable type is undefined + // + if (!nullable.IsDefined) + return null; + + enum_type = nullable.TypeSpec.MakeGenericType (rc.Module, new[] { enum_type }); } expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, true), false); @@ -6862,6 +7371,9 @@ public override void SetHasAddressTaken () void DoResolveBase (ResolveContext ec) { + eclass = ExprClass.Variable; + type = local_info.Type; + // // If we are referencing a variable from the external block // flag it for capturing @@ -6880,9 +7392,6 @@ void DoResolveBase (ResolveContext ec) storey.CaptureLocalVariable (ec, local_info); } } - - eclass = ExprClass.Variable; - type = local_info.Type; } protected override Expression DoResolve (ResolveContext ec) @@ -6890,6 +7399,14 @@ protected override Expression DoResolve (ResolveContext ec) local_info.SetIsUsed (); DoResolveBase (ec); + + if (local_info.Type == InternalType.VarOutType) { + ec.Report.Error (8048, loc, "Cannot use uninitialized variable `{0}'", + GetSignatureForError ()); + + type = InternalType.ErrorType; + } + return this; } @@ -7713,11 +8230,11 @@ public Arguments Arguments { } // - // Returns true for resolved `new S()' + // Returns true for resolved `new S()' when S does not declare parameterless constructor // - public bool IsDefaultStruct { + public bool IsGeneratedStructConstructor { get { - return arguments == null && type.IsStruct && GetType () == typeof (New); + return arguments == null && method == null && type.IsStruct && GetType () == typeof (New); } } @@ -7926,12 +8443,6 @@ protected override Expression DoResolve (ResolveContext ec) return null; } - // - // Any struct always defines parameterless constructor - // - if (type.IsStruct && arguments == null) - return this; - if (arguments != null) { arguments.Resolve (ec, out dynamic); } else { @@ -7950,46 +8461,14 @@ protected override Expression DoResolve (ResolveContext ec) return ret; } - bool DoEmitTypeParameter (EmitContext ec) + void DoEmitTypeParameter (EmitContext ec) { var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc); if (m == null) - return true; + return; var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type); - var tparam = (TypeParameterSpec) type; - - if (tparam.IsReferenceType) { - ec.Emit (OpCodes.Call, ctor_factory); - return true; - } - - // Allow DoEmit() to be called multiple times. - // We need to create a new LocalTemporary each time since - // you can't share LocalBuilders among ILGeneators. - LocalTemporary temp = new LocalTemporary (type); - - Label label_activator = ec.DefineLabel (); - Label label_end = ec.DefineLabel (); - - temp.AddressOf (ec, AddressOp.Store); - ec.Emit (OpCodes.Initobj, type); - - temp.Emit (ec); - ec.Emit (OpCodes.Box, type); - ec.Emit (OpCodes.Brfalse, label_activator); - - temp.AddressOf (ec, AddressOp.Store); - ec.Emit (OpCodes.Initobj, type); - temp.Emit (ec); - temp.Release (ec); - ec.Emit (OpCodes.Br_S, label_end); - - ec.MarkLabel (label_activator); - ec.Emit (OpCodes.Call, ctor_factory); - ec.MarkLabel (label_end); - return true; } // @@ -8021,7 +8500,7 @@ bool DoEmitTypeParameter (EmitContext ec) // public virtual bool Emit (EmitContext ec, IMemoryLocation target) { - bool is_value_type = TypeSpec.IsValueType (type); + bool is_value_type = type.IsStructOrEnum; VariableReference vr = target as VariableReference; if (target != null && is_value_type && (vr != null || method == null)) { @@ -8050,8 +8529,10 @@ public virtual bool Emit (EmitContext ec, IMemoryLocation target) } } - if (type is TypeParameterSpec) - return DoEmitTypeParameter (ec); + if (type is TypeParameterSpec) { + DoEmitTypeParameter (ec); + return true; + } ec.MarkCallEntry (loc); ec.Emit (OpCodes.Newobj, method); @@ -8061,7 +8542,7 @@ public virtual bool Emit (EmitContext ec, IMemoryLocation target) public override void Emit (EmitContext ec) { LocalTemporary v = null; - if (method == null && TypeSpec.IsValueType (type)) { + if (method == null && type.IsStructOrEnum) { // TODO: Use temporary variable from pool v = new LocalTemporary (type); } @@ -11884,6 +12365,10 @@ public override void Emit (EmitContext ec) // nothing, as we only exist to not do anything. } + public override void EmitBranchable (EmitContext ec, Label target, bool on_true) + { + } + public override void EmitSideEffect (EmitContext ec) { } @@ -12012,6 +12497,9 @@ public Expression Source { get { return source; } + set { + source = value; + } } public override bool ContainsEmitWithAwait () diff --git a/mcs/mcs/field.cs b/mcs/mcs/field.cs index 14890cc5f49..f184e14194f 100644 --- a/mcs/mcs/field.cs +++ b/mcs/mcs/field.cs @@ -642,9 +642,23 @@ bool CanBeVolatile () 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; } diff --git a/mcs/mcs/generic.cs b/mcs/mcs/generic.cs index 6b84a20297a..02f797ccc40 100644 --- a/mcs/mcs/generic.cs +++ b/mcs/mcs/generic.cs @@ -1336,16 +1336,22 @@ protected override void InitializeMemberCache (bool onlyTypes) foreach (var ta in targs) { var tps = ta as TypeParameterSpec; IList ifaces; + TypeSpec b_type; if (tps != null) { - var b_type = tps.GetEffectiveBase (); - if (b_type != null && b_type.BuiltinType != BuiltinTypeSpec.Type.Object && b_type.BuiltinType != BuiltinTypeSpec.Type.ValueType) - cache.AddBaseType (b_type); - + b_type = tps.GetEffectiveBase (); ifaces = tps.InterfacesDefined; } else { + b_type = ta; ifaces = ta.Interfaces; } + // + // Don't add base type which was inflated from base constraints but it's not valid + // in C# context + // + if (b_type != null && b_type.BuiltinType != BuiltinTypeSpec.Type.Object && b_type.BuiltinType != BuiltinTypeSpec.Type.ValueType && !b_type.IsStructOrEnum) + cache.AddBaseType (b_type); + if (ifaces != null) { foreach (var iface_type in ifaces) { cache.AddInterface (iface_type); @@ -2770,7 +2776,7 @@ class TypeInference // // Tracks successful rate of type inference // - int score = int.MaxValue; + int score; readonly Arguments arguments; readonly int arg_count; @@ -2843,12 +2849,12 @@ bool InferInPhases (ResolveContext ec, TypeInferenceContext tic, AParametersColl AnonymousMethodExpression am = a.Expr as AnonymousMethodExpression; if (am != null) { if (am.ExplicitTypeInference (tic, method_parameter)) - --score; + ++score; continue; } if (a.IsByRef) { - score -= tic.ExactInference (a.Type, method_parameter); + score += tic.ExactInference (a.Type, method_parameter); continue; } @@ -2856,14 +2862,14 @@ bool InferInPhases (ResolveContext ec, TypeInferenceContext tic, AParametersColl continue; if (TypeSpec.IsValueType (method_parameter)) { - score -= tic.LowerBoundInference (a.Type, method_parameter); + score += tic.LowerBoundInference (a.Type, method_parameter); continue; } // // Otherwise an output type inference is made // - score -= tic.OutputTypeInference (ec, a.Expr, method_parameter); + score += tic.OutputTypeInference (ec, a.Expr, method_parameter); } // @@ -2913,7 +2919,7 @@ bool DoSecondPhase (ResolveContext ec, TypeInferenceContext tic, TypeSpec[] meth if (arguments[i] == null) continue; - score -= tic.OutputTypeInference (ec, arguments[i].Expr, t_i); + score += tic.OutputTypeInference (ec, arguments[i].Expr, t_i); } } @@ -3020,7 +3026,7 @@ void AddToBounds (BoundInfo bound, int index, bool voidAllowed) // Some types cannot be used as type arguments // if ((bound.Type.Kind == MemberKind.Void && !voidAllowed) || bound.Type.IsPointer || bound.Type.IsSpecialRuntimeType || - bound.Type == InternalType.MethodGroup || bound.Type == InternalType.AnonymousMethod) + bound.Type == InternalType.MethodGroup || bound.Type == InternalType.AnonymousMethod || bound.Type == InternalType.VarOutType) return; var a = bounds [index]; @@ -3046,8 +3052,8 @@ bool AllTypesAreFixed (TypeSpec[] types) continue; } - if (TypeManager.IsGenericType (t)) - return AllTypesAreFixed (TypeManager.GetTypeArguments (t)); + if (t.IsGeneric && !AllTypesAreFixed (t.TypeArguments)) + return false; } return true; diff --git a/mcs/mcs/method.cs b/mcs/mcs/method.cs index 50d0df574d9..63ac088c195 100644 --- a/mcs/mcs/method.cs +++ b/mcs/mcs/method.cs @@ -1607,15 +1607,6 @@ protected override Expression DoResolve (ResolveContext ec) "`{0}': Struct constructors cannot call base constructors", caller_builder.GetSignatureForError ()); return this; } - } else { - // - // It is legal to have "this" initializers that take no arguments - // in structs - // - // struct D { public D (int a) : this () {} - // - if (ec.CurrentType.IsStruct && argument_list == null) - return this; } base_ctor = ConstructorLookup (ec, type, ref argument_list, loc); @@ -1777,12 +1768,6 @@ public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] protected override bool CheckBase () { if ((ModFlags & Modifiers.STATIC) != 0) { - if (!parameters.IsEmpty) { - Report.Error (132, Location, "`{0}': The static constructor must be parameterless", - GetSignatureForError ()); - return false; - } - if ((caching_flags & Flags.MethodOverloadsExist) != 0) Parent.MemberCache.CheckExistingMembersOverloads (this, parameters); @@ -1797,12 +1782,6 @@ protected override bool CheckBase () if ((caching_flags & Flags.MethodOverloadsExist) != 0) Parent.MemberCache.CheckExistingMembersOverloads (this, parameters); - if (Parent.PartialContainer.Kind == MemberKind.Struct && parameters.IsEmpty) { - Report.Error (568, Location, - "Structs cannot contain explicit parameterless constructors"); - return false; - } - CheckProtectedModifier (); return true; @@ -2722,6 +2701,9 @@ public enum OpType : byte { Implicit, Explicit, + // Pattern matching + Is, + // Just because of enum TOP }; @@ -2761,6 +2743,7 @@ static Operator () names [(int) OpType.AsURightShift] = new string [] { ">>>", "op_UnsignedRightShift" }; names [(int) OpType.Implicit] = new string [] { "implicit", "op_Implicit" }; names [(int) OpType.Explicit] = new string [] { "explicit", "op_Explicit" }; + names [(int) OpType.Is] = new string[] { "is", "op_Is" }; } public Operator (TypeDefinition parent, OpType type, FullNamedExpression ret_type, Modifiers mod_flags, ParametersCompiled parameters, diff --git a/mcs/mcs/module.cs b/mcs/mcs/module.cs index 3f9fca8a9a4..67aea10ee48 100644 --- a/mcs/mcs/module.cs +++ b/mcs/mcs/module.cs @@ -181,6 +181,7 @@ Method GenerateNumberMatcher () var system_convert = new MemberAccess (new QualifiedAliasMember ("global", "System", loc), "Convert", loc); + var expl_block = new ExplicitBlock (top_block, loc, loc); // // var converted = System.Convert.ChangeType (obj, System.Convert.GetTypeCode (value)); @@ -198,7 +199,7 @@ Method GenerateNumberMatcher () var changetype = new Invocation (new MemberAccess (system_convert, "ChangeType", loc), arguments_changetype); - top_block.AddStatement (new StatementExpression (new SimpleAssign (new LocalVariableReference (lv_converted, loc), changetype, loc))); + expl_block.AddStatement (new StatementExpression (new SimpleAssign (new LocalVariableReference (lv_converted, loc), changetype, loc))); // @@ -207,7 +208,13 @@ Method GenerateNumberMatcher () var equals_arguments = new Arguments (1); equals_arguments.Add (new Argument (top_block.GetParameterReference (1, loc))); var equals_invocation = new Invocation (new MemberAccess (new LocalVariableReference (lv_converted, loc), "Equals"), equals_arguments); - top_block.AddStatement (new Return (equals_invocation, loc)); + expl_block.AddStatement (new Return (equals_invocation, loc)); + + var catch_block = new ExplicitBlock (top_block, loc, loc); + catch_block.AddStatement (new Return (new BoolLiteral (Compiler.BuiltinTypes, false, loc), loc)); + top_block.AddStatement (new TryCatch (expl_block, new List () { + new Catch (catch_block, loc) + }, loc, false)); m.Define (); m.PrepareEmit (); diff --git a/mcs/mcs/namespace.cs b/mcs/mcs/namespace.cs index 0ff3b4a51aa..7fb83c19b2c 100644 --- a/mcs/mcs/namespace.cs +++ b/mcs/mcs/namespace.cs @@ -598,7 +598,21 @@ public static TypeSpec IsImportedTypeOverride (ModuleContainer module, TypeSpec public void RemoveContainer (TypeContainer tc) { - types.Remove (tc.MemberName.Basename); + IList found; + if (types.TryGetValue (tc.MemberName.Name, out found)) { + for (int i = 0; i < found.Count; ++i) { + if (tc.MemberName.Arity != found [i].Arity) + continue; + + if (found.Count == 1) + types.Remove (tc.MemberName.Name); + else + found.RemoveAt (i); + + break; + } + } + cached_types.Remove (tc.MemberName.Basename); } diff --git a/mcs/mcs/nullable.cs b/mcs/mcs/nullable.cs index a724b6f33f6..826c87ea870 100644 --- a/mcs/mcs/nullable.cs +++ b/mcs/mcs/nullable.cs @@ -1288,16 +1288,52 @@ public override void Emit (EmitContext ec) return; } - left.Emit (ec); - ec.Emit (OpCodes.Dup); + // + // Null check is done on original expression not after expression is converted to + // result type. This is in most cases same but when user conversion is involved + // we can end up in situation when use operator does the null handling which is + // not what the operator is supposed to do + // + var op_expr = left as UserCast; + if (op_expr != null) { + op_expr.Source.Emit (ec); + LocalTemporary temp; + + // TODO: More load kinds can be special cased + if (!(op_expr.Source is VariableReference)) { + temp = new LocalTemporary (op_expr.Source.Type); + temp.Store (ec); + temp.Emit (ec); + op_expr.Source = temp; + } else { + temp = null; + } + + var right_label = ec.DefineLabel (); + ec.Emit (OpCodes.Brfalse_S, right_label); + left.Emit (ec); + ec.Emit (OpCodes.Br, end_label); + ec.MarkLabel (right_label); - // Only to make verifier happy - if (left.Type.IsGenericParameter) - ec.Emit (OpCodes.Box, left.Type); + if (temp != null) + temp.Release (ec); + } else { + // + // Common case where expression is not modified before null check and + // we generate better/smaller code + // + left.Emit (ec); + ec.Emit (OpCodes.Dup); - ec.Emit (OpCodes.Brtrue, end_label); + // Only to make verifier happy + if (left.Type.IsGenericParameter) + ec.Emit (OpCodes.Box, left.Type); + + ec.Emit (OpCodes.Brtrue, end_label); + + ec.Emit (OpCodes.Pop); + } - ec.Emit (OpCodes.Pop); right.Emit (ec); ec.MarkLabel (end_label); diff --git a/mcs/mcs/parameter.cs b/mcs/mcs/parameter.cs index 8226acd64b7..3622ea24eea 100644 --- a/mcs/mcs/parameter.cs +++ b/mcs/mcs/parameter.cs @@ -1413,6 +1413,8 @@ public DefaultParameterValueExpression (Expression expr) public void Resolve (ResolveContext rc, Parameter p) { + var isPlayScript = rc.FileType == SourceFileType.PlayScript; + var expr = Resolve (rc); if (expr == null) { this.expr = ErrorExpression.Instance; @@ -1426,17 +1428,19 @@ public void Resolve (ResolveContext rc, Parameter p) return; // ActionScript allows * and Object types to have default values as well. - bool param_is_as_obj = rc.FileType == Mono.CSharp.SourceFileType.PlayScript && - (parameter_type.BuiltinType == Mono.CSharp.BuiltinTypeSpec.Type.Dynamic || - parameter_type.BuiltinType == Mono.CSharp.BuiltinTypeSpec.Type.Object); - - if (!(expr is Constant || expr is DefaultValueExpression || (expr is New && ((New) expr).IsDefaultStruct))) { - if (!param_is_as_obj) { - rc.Report.Error (1736, Location, - "The expression being assigned to optional parameter `{0}' must be a constant or default value", - p.Name); + bool param_is_as_obj = isPlayScript && + (parameter_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || + parameter_type.BuiltinType == BuiltinTypeSpec.Type.Object); + + if (!param_is_as_obj) { // PlayScript - see check above - tested via as/test-debug-UntypedParameterTest.as + if (!(expr is Constant || expr is DefaultValueExpression || (expr is New && ((New)expr).IsGeneratedStructConstructor))) { + if (!(expr is ErrorExpression)) { + rc.Report.Error (1736, Location, + "The expression being assigned to optional parameter `{0}' must be a constant or default value", + p.Name); - return; + return; + } } } diff --git a/mcs/mcs/ps-parser.jay b/mcs/mcs/ps-parser.jay index 8edfd4bbdc9..4ec68182b48 100644 --- a/mcs/mcs/ps-parser.jay +++ b/mcs/mcs/ps-parser.jay @@ -4198,11 +4198,61 @@ non_simple_argument $$ = new Argument ((Expression) $2, Argument.AType.Ref); lbag.AddLocation ($$, GetLocation ($1)); } + | REF declaration_expression + { + $$ = new Argument ((Expression) $2, Argument.AType.Ref); + } | OUT variable_reference { $$ = new Argument ((Expression) $2, Argument.AType.Out); lbag.AddLocation ($$, GetLocation ($1)); } + | OUT declaration_expression + { + $$ = new Argument ((Expression) $2, Argument.AType.Out); + } + ; + +declaration_expression + : OPEN_PARENS declaration_expression CLOSE_PARENS + { + $$ = new ParenthesizedExpression ((Expression) $2, GetLocation ($1)); + lbag.AddLocation ($$, GetLocation ($1), GetLocation ($3)); + } +/* + | CHECKED open_parens_any declaration_expression CLOSE_PARENS + { + $$ = new CheckedExpr ((Expression) $3, GetLocation ($1)); + lbag.AddLocation ($$, GetLocation ($2), GetLocation ($4)); + } + | UNCHECKED open_parens_any declaration_expression CLOSE_PARENS + { + $$ = new UnCheckedExpr ((Expression) $3, GetLocation ($1)); + lbag.AddLocation ($$, GetLocation ($2), GetLocation ($4)); + } +*/ + | variable_type identifier_inside_body + { + if (lang_version < LanguageVersion.V_6) + FeatureIsNotAvailable (GetLocation ($1), "declaration expression"); + + var lt = (LocatedToken) $2; + var lv = new LocalVariable (current_block, lt.Value, lt.Location); + current_block.AddLocalName (lv); + $$ = new DeclarationExpression ((FullNamedExpression) $1, lv); + } + | variable_type identifier_inside_body ASSIGN expression + { + if (lang_version < LanguageVersion.V_6) + FeatureIsNotAvailable (GetLocation ($1), "declaration expression"); + + var lt = (LocatedToken) $2; + var lv = new LocalVariable (current_block, lt.Value, lt.Location); + current_block.AddLocalName (lv); + $$ = new DeclarationExpression ((FullNamedExpression) $1, lv) { + Initializer = (Expression) $4 + }; + } ; variable_reference diff --git a/mcs/mcs/statement.cs b/mcs/mcs/statement.cs index c2a9a6847b3..df9349823b6 100644 --- a/mcs/mcs/statement.cs +++ b/mcs/mcs/statement.cs @@ -4957,6 +4957,8 @@ public Constant Converted { } } + public bool PatternMatching { get; set; } + public bool SectionStart { get; set; } public Label GetILLabel (EmitContext ec) @@ -4994,21 +4996,33 @@ public override bool Resolve (BlockContext bc) // Resolves the expression, reduces it to a literal if possible // and then converts it to the requested type. // - bool ResolveAndReduce (BlockContext rc) + bool ResolveAndReduce (BlockContext bc) { if (IsDefault) return true; - var c = label.ResolveLabelConstant (rc); + var switch_statement = bc.Switch; + + if (PatternMatching) { + label = new Is (switch_statement.ExpressionValue, label, loc).Resolve (bc); + return label != null; + } + + var c = label.ResolveLabelConstant (bc); if (c == null) return false; - if (rc.Switch.IsNullable && c is NullLiteral) { + if (switch_statement.IsNullable && c is NullLiteral) { converted = c; return true; } - converted = c.ImplicitConversionRequired (rc, rc.Switch.SwitchType); + if (switch_statement.IsPatternMatching) { + label = new Is (switch_statement.ExpressionValue, label, loc).Resolve (bc); + return true; + } + + converted = c.ImplicitConversionRequired (bc, switch_statement.SwitchType); return converted != null; } @@ -5235,12 +5249,24 @@ public bool IsNullable { } } + public bool IsPatternMatching { + get { + return new_expr == null && SwitchType != null; + } + } + public List RegisteredLabels { get { return case_labels; } } + public VariableReference ExpressionValue { + get { + return value; + } + } + // // Determines the governing type for a switch. The returned // expression might be the expression from the switch, or an @@ -5350,6 +5376,9 @@ public void RegisterLabel (BlockContext rc, SwitchLabel sl) return; } + if (sl.Converted == null) + return; + try { if (string_labels != null) { string string_value = sl.Converted.GetValue () as string; @@ -5358,7 +5387,7 @@ public void RegisterLabel (BlockContext rc, SwitchLabel sl) else string_labels.Add (string_value, sl); } else { - if (sl.Converted is NullLiteral) { + if (sl.Converted.IsNull) { case_null = sl; } else { labels.Add (sl.Converted.GetValueAsLong (), sl); @@ -5522,7 +5551,17 @@ public SwitchLabel FindLabel (Constant value) } } - return sl; + if (sl == null || sl.SectionStart) + return sl; + + // + // Always return section start, it simplifies handling of switch labels + // + for (int idx = case_labels.IndexOf (sl); ; --idx) { + var cs = case_labels [idx]; + if (cs.SectionStart) + return cs; + } } protected override bool DoFlowAnalysis (FlowAnalysisContext fc) @@ -5621,39 +5660,44 @@ public override bool Resolve (BlockContext ec) } } + Expression switch_expr; if (new_expr == null) { - if (Expr.Type != InternalType.ErrorType) { - ec.Report.Error (151, loc, - "A switch expression of type `{0}' cannot be converted to an integral type, bool, char, string, enum or nullable type", - Expr.Type.GetSignatureForError ()); - } + if (ec.Module.Compiler.Settings.Version != LanguageVersion.Experimental) { + if (Expr.Type != InternalType.ErrorType) { + ec.Report.Error (151, loc, + "A switch expression of type `{0}' cannot be converted to an integral type, bool, char, string, enum or nullable type", + Expr.Type.GetSignatureForError ()); + } - return false; - } + return false; + } - SwitchType = new_expr.Type; - if (SwitchType.IsNullableType) { - new_expr = unwrap = Nullable.Unwrap.Create (new_expr, true); - SwitchType = Nullable.NullableInfo.GetUnderlyingType (SwitchType); - } + switch_expr = Expr; + SwitchType = Expr.Type; + } else { + switch_expr = new_expr; + SwitchType = new_expr.Type; + if (SwitchType.IsNullableType) { + new_expr = unwrap = Nullable.Unwrap.Create (new_expr, true); + SwitchType = Nullable.NullableInfo.GetUnderlyingType (SwitchType); + } - if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.Bool && ec.Module.Compiler.Settings.Version == LanguageVersion.ISO_1) { - ec.Report.FeatureIsNotAvailable (ec.Module.Compiler, loc, "switch expression of boolean type"); - return false; - } + if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.Bool && ec.Module.Compiler.Settings.Version == LanguageVersion.ISO_1) { + ec.Report.FeatureIsNotAvailable (ec.Module.Compiler, loc, "switch expression of boolean type"); + return false; + } - if (block.Statements.Count == 0) - return true; + if (block.Statements.Count == 0) + return true; - if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.String) { - string_labels = new Dictionary (); - } else { - labels = new Dictionary (); + if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.String) { + string_labels = new Dictionary (); + } else { + labels = new Dictionary (); + } } - case_labels = new List (); - - var constant = new_expr as Constant; + var constant = switch_expr as Constant; // // Don't need extra variable for constant switch or switch with @@ -5663,7 +5707,7 @@ public override bool Resolve (BlockContext ec) // // Store switch expression for comparison purposes // - value = new_expr as VariableReference; + value = switch_expr as VariableReference; if (value == null && !HasOnlyDefaultSection ()) { var current_block = ec.CurrentBlock; ec.CurrentBlock = Block; @@ -5674,6 +5718,8 @@ public override bool Resolve (BlockContext ec) } } + case_labels = new List (); + Switch old_switch = ec.Switch; ec.Switch = this; var parent_los = ec.EnclosingLoopOrSwitch; @@ -5966,6 +6012,11 @@ void EmitShortSwitch (EmitContext ec) var constant = label.Converted; + if (constant == null) { + label.Label.EmitBranchable (ec, label.GetILLabel (ec), true); + continue; + } + if (equal_method != null) { value.Emit (ec); constant.Emit (ec); @@ -5991,6 +6042,11 @@ void EmitShortSwitch (EmitContext ec) void EmitDispatch (EmitContext ec) { + if (IsPatternMatching) { + EmitShortSwitch (ec); + return; + } + if (value == null) { // // Constant switch, we've already done the work if there is only 1 label @@ -6038,12 +6094,14 @@ protected override void DoEmit (EmitContext ec) if (value != null) { ec.Mark (loc); + + var switch_expr = new_expr ?? Expr; if (IsNullable) { unwrap.EmitCheck (ec); ec.Emit (OpCodes.Brfalse, nullLabel); - value.EmitAssign (ec, new_expr, false, false); - } else if (new_expr != value) { - value.EmitAssign (ec, new_expr, false, false); + value.EmitAssign (ec, switch_expr, false, false); + } else if (switch_expr != value) { + value.EmitAssign (ec, switch_expr, false, false); } diff --git a/mcs/mcs/typespec.cs b/mcs/mcs/typespec.cs index 97e6c6d13b0..c426e2bcde1 100644 --- a/mcs/mcs/typespec.cs +++ b/mcs/mcs/typespec.cs @@ -1512,6 +1512,7 @@ class InternalType : TypeSpec, ITypeDefinition public static readonly InternalType FakeInternalType = new InternalType (""); public static readonly InternalType Namespace = new InternalType (""); public static readonly InternalType ErrorType = new InternalType (""); + public static readonly InternalType VarOutType = new InternalType ("var out"); readonly string name; diff --git a/mcs/playc_tests/as/test-as-LogicalOr-02.as b/mcs/playc_tests/as/test-as-LogicalOr-02.as new file mode 100644 index 00000000000..1b42839cb4c --- /dev/null +++ b/mcs/playc_tests/as/test-as-LogicalOr-02.as @@ -0,0 +1,16 @@ +// Compiler options: -psstrict+ +package { + public class Foo { + public static function Main():int { + + var a:Number = 10; + var b:Number = 250; + var start:Boolean = false; + if ((a > 25) || (b > 200) || (start)) { + trace("the logical OR test passed"); // the logical OR test passed + return 0; + } + return 1; + } + } +} diff --git a/mcs/playc_tests/as/test-as-LogicalOr-03.as b/mcs/playc_tests/as/test-as-LogicalOr-03.as new file mode 100644 index 00000000000..b6c2a5f5396 --- /dev/null +++ b/mcs/playc_tests/as/test-as-LogicalOr-03.as @@ -0,0 +1,32 @@ +// Compiler options: -psstrict- +package { + public class Foo { + + static var fail:Boolean = false; + + static function fx1():Boolean { + trace("fx1 called"); + return true; + } + + static function fx2():Boolean { + trace("fx2 called"); + fail = true; + return true; + } + + // The following example demonstrates how using a function call as + // the second operand can lead to unexpected results. If the expression + // on the left of the operator evaluates to true, that result is returned + // without evaluating the expression on the right (the function fx2() + // is not called). + + public static function Main():int { + if (fx1() || fx2()) { + trace("IF statement entered"); + if (fail) return 1; + } + return 0; + } + } +} diff --git a/mcs/playc_tests/as/test-as-LogicalOr.as b/mcs/playc_tests/as/test-as-LogicalOr.as new file mode 100644 index 00000000000..df54f43498c --- /dev/null +++ b/mcs/playc_tests/as/test-as-LogicalOr.as @@ -0,0 +1,21 @@ +// Compiler options: -psstrict+ +package { + public class Foo { + public static function Main():int { + + var x:Boolean = false; + var y:Boolean = true; + + x ||= y; + trace (x); + if (!x) return 1; + + x = false; + x = x || y; + trace (x); + if (!x) return 1; + + return 0; + } + } +} diff --git a/mcs/playc_tests/as/test-as-Modulo.as b/mcs/playc_tests/as/test-as-Modulo.as new file mode 100644 index 00000000000..8f19141b1dc --- /dev/null +++ b/mcs/playc_tests/as/test-as-Modulo.as @@ -0,0 +1,21 @@ +// Compiler options: -psstrict+ +package { + public class Foo { + public static function Main():int { + + trace(12 % 5); // 2 + if (12 % 5 != 2) return 1; + + trace(-4 % 3); // -1 + if (-4 % 3 != -1) return 2; + + trace(-4 % -3); // -1 + if (-4 % -3 != -1) return 3; + + trace(4 % 4); // 0 + if (4 % 4 != 0) return 4; + + return 0; + } + } +} diff --git a/mcs/playc_tests/as/test-as-NewOperator.as b/mcs/playc_tests/as/test-as-NewOperator.as new file mode 100644 index 00000000000..e457c7874e8 --- /dev/null +++ b/mcs/playc_tests/as/test-as-NewOperator.as @@ -0,0 +1,26 @@ +// Compiler options: -psstrict+ +package { + + class Book { + public var bName:String; + public var bPrice:Number; + + public function Book(nameParam:String, priceParam:Number){ + bName = nameParam; + bPrice = priceParam; + } + } + + public class Foo { + public static function Main():int { + var book1:Book = new Book("Confederacy of Dunces", 19.95); + var book2:Book = new Book("The Floating Opera", 10.95); + trace(book1); // [object Book] + if (book1.bName != "Confederacy of Dunces") return 1; + if (book2.bPrice != 10.95) return 2; + trace(book1); // [object Book] + if (book1.toString() != "[object Book]") return 3; + return 0; + } + } +} diff --git a/mcs/playc_tests/as/test-as-ObjectInitializerOperator-01.as b/mcs/playc_tests/as/test-as-ObjectInitializerOperator-01.as new file mode 100644 index 00000000000..d442f3c4c14 --- /dev/null +++ b/mcs/playc_tests/as/test-as-ObjectInitializerOperator-01.as @@ -0,0 +1,25 @@ +// Compiler options: -psstrict+ +package { + public class Foo { + public static function Main():int { + + var object:Object = {}; + var object:Object = new Object(); + + var x:int = 0; + var account:Object = {name:"Adobe Systems, Inc.", address:"601 Townsend Street", city:"San Francisco", state:"California", zip:"94103", balance:"1000"}; + + for (var i:* in account) { + trace("account."+i+" = "+account[i]); + + x++; + if (x == 6) { + if (i != "balance") return 1; + if (account[i] != "1000") return 2; + } + } + + return 0; + } + } +} diff --git a/mcs/playc_tests/as/test-as-ObjectInitializerOperator-02.as b/mcs/playc_tests/as/test-as-ObjectInitializerOperator-02.as new file mode 100644 index 00000000000..d3204805fd9 --- /dev/null +++ b/mcs/playc_tests/as/test-as-ObjectInitializerOperator-02.as @@ -0,0 +1,32 @@ +// Compiler options: -psstrict- +package { + public class Foo { + public static function Main():int { + + // The following example shows how array and object initializers can + // be nested within each other: + + var person2:Object = {name:"Gina Vechio", children:["Ruby", "Chickie", "Puppa"]}; + + // The following code uses the information in the previous example + // and produces the same result using a constructor function: + + var person:Object = new Object(); + person.name = "Gina Vechio"; + person.children = new Array(); + person.children[0] = "Ruby"; + person.children[1] = "Chickie"; + person.children[2] = "Puppa"; + + // Thus person and person2 should contain identicial values + + if (person.name != person2.name) return 9; + + if (person.children[2] != person2.children[2]) return 1; + if (person.children[1] != person2.children[1]) return 2; + if (person.children[0] != person2.children[0]) return 3; + + return 0; + } + } +} diff --git a/mcs/playc_tests/as/test-as-Parentheses.as b/mcs/playc_tests/as/test-as-Parentheses.as new file mode 100644 index 00000000000..78ea2583720 --- /dev/null +++ b/mcs/playc_tests/as/test-as-Parentheses.as @@ -0,0 +1,21 @@ +// Compiler options: -psstrict- +package { + public class Foo { + public static function Main():int { + + trace((2 + 3) * (4 + 5)); // 45 + if ((2 + 3) * (4 + 5) != 45) return 1; + + trace(2 + (3 * (4 + 5))); // 29 + if (2 + (3 * (4 + 5)) != 29) return 2; + + trace(2 + (3 * 4) + 5); // 19 + if (2 + (3 * 4) + 5 != 19) return 3; + + trace(2 + (3 * 4) + 5); // 19 + if (2 + (3 * 4) + 5 != 19) return 4; + + return 0; + } + } +} diff --git a/mcs/playc_tests/as/test-as-Typeof.as b/mcs/playc_tests/as/test-as-Typeof.as new file mode 100644 index 00000000000..3196b244d47 --- /dev/null +++ b/mcs/playc_tests/as/test-as-Typeof.as @@ -0,0 +1,33 @@ +// Compiler options: -psstrict+ +package { + public class Foo { + public static function Main():int { + + trace(typeof Array); // object + trace(typeof Boolean); // boolean + trace(typeof Function); // function + trace(typeof int); + trace(typeof Number); + trace(typeof Object); + trace(typeof String); + trace(typeof uint); + trace(typeof XML); + trace(typeof XMLList); + //trace(typeof *); + + if ((typeof Array) == "object") return 1; + if ((typeof Boolean) == "boolean") return 2; + if ((typeof Function) == "function") return 3; + if ((typeof int) == "number") return 4; + if ((typeof Number) == "number") return 5; + if ((typeof Object) == "object") return 6; + if ((typeof String) == "string") return 7; + if ((typeof uint) == "number") return 8; + if ((typeof XML) == "xml") return 9; + if ((typeof XMLList) == "xml") return 10; + //if ((typeof *) == "undefined") return 11; + + return 0; + } + } +} diff --git a/mcs/playc_tests/play-il-net_4_5.xml b/mcs/playc_tests/play-il-net_4_5.xml index dcb48972bfc..aeb91ff469b 100644 --- a/mcs/playc_tests/play-il-net_4_5.xml +++ b/mcs/playc_tests/play-il-net_4_5.xml @@ -640,6 +640,70 @@ + + + + 86 + + + 7 + + + + + + + 20 + + + 26 + + + 59 + + + 7 + + + 7 + + + + + + + 86 + + + 7 + + + + + + + 54 + + + 7 + + + + + + + 22 + + + + + 145 + + + 7 + + + @@ -663,6 +727,36 @@ + + + + 436 + + + 7 + + + + + + + 934 + + + 7 + + + + + + + 58 + + + 7 + + + diff --git a/mcs/playc_tests/play-issues-net_4_5 b/mcs/playc_tests/play-issues-net_4_5 index 4c211da2e0e..589252982a8 100644 --- a/mcs/playc_tests/play-issues-net_4_5 +++ b/mcs/playc_tests/play-issues-net_4_5 @@ -4,6 +4,8 @@ # csXXXX.as : test case causes error # csXXXX.as IGNORE : adds test to ignore list +# Issue #80 - Typeof not returning the proper (string) values +./as/test-as-Typeof.as # Issue #62 - XML.attributes - Implement function - Currently System.NotImplementedException ./as/test-as-XML-Attributes-Access.as IGNORE diff --git a/mcs/tests/gtest-409.cs b/mcs/tests/gtest-409.cs index 2071b625c3a..2f5ea10ae8f 100644 --- a/mcs/tests/gtest-409.cs +++ b/mcs/tests/gtest-409.cs @@ -155,6 +155,11 @@ void Test_18 (bool b, Action a) var e = b ? () => { } : a; } + void Test_19 (int[,] table) + { + var x = 1 > 0 ? table[5, 1] : 0; + } + static void Helper (T arg) { } diff --git a/mcs/tests/gtest-623-lib.il b/mcs/tests/gtest-623-lib.il new file mode 100644 index 00000000000..25c5b72ca4f --- /dev/null +++ b/mcs/tests/gtest-623-lib.il @@ -0,0 +1,42 @@ +.assembly extern mscorlib +{ +} + +.assembly 'gtest-623-lib' +{ +} + +.module 'gtest-623-lib.dll' + + .class public sequential ansi sealed beforefieldinit S + extends [mscorlib]System.ValueType + implements I { + + .field public int32 Field + + .method public hidebysig specialname rtspecialname + instance default void '.ctor' () cil managed + { + ldarg.0 + ldc.i4.3 + stfld int32 S::Field + ret + } + + .method public final virtual hidebysig newslot + instance default int32 GetValue () cil managed + { + ldarg.0 + ldfld int32 S::Field + ret + } + } + + .class interface public auto ansi abstract I + { + + .method public virtual hidebysig newslot abstract + instance default int32 GetValue () cil managed + { + } + } diff --git a/mcs/tests/gtest-623.cs b/mcs/tests/gtest-623.cs new file mode 100644 index 00000000000..ce9b79d1bd1 --- /dev/null +++ b/mcs/tests/gtest-623.cs @@ -0,0 +1,24 @@ +// Compiler options: -r:gtest-623-lib.dll + +using System; + +public class C +{ + static bool Test () where T : struct, I + { + var t = new T (); + if (t.GetValue () != 3) + return false; + + return true; + } + + public static int Main () + { + if (!Test ()) + return 1; + + Console.WriteLine ("ok"); + return 0; + } +} \ No newline at end of file diff --git a/mcs/tests/gtest-624.cs b/mcs/tests/gtest-624.cs new file mode 100644 index 00000000000..0299d095e02 --- /dev/null +++ b/mcs/tests/gtest-624.cs @@ -0,0 +1,36 @@ +using System; + +class Model +{ + public int Value; +} + +class C1 +{ + public void Add (Func t) + { + } +} + +abstract class C2 +{ + public abstract void ApplyImpl (C1 c1) where U : TModel; +} + +class C3 : C2 +{ + public override void ApplyImpl (C1 c1) + { + c1.Add (t => t.Value); + } +} + +class Program +{ + static void Main () + { + var v1 = new C1 (); + var c3 = new C3 (); + c3.ApplyImpl (v1); + } +} diff --git a/mcs/tests/gtest-625.cs b/mcs/tests/gtest-625.cs new file mode 100644 index 00000000000..d733a809dc9 --- /dev/null +++ b/mcs/tests/gtest-625.cs @@ -0,0 +1,21 @@ +struct S +{ + public static bool operator true (S? S) + { + return true; + } + + public static bool operator false (S? S) + { + return true; + } +} + +class P +{ + static void Main () + { + if (new S? ()) { + } + } +} \ No newline at end of file diff --git a/mcs/tests/gtest-autoproperty-09.cs b/mcs/tests/gtest-autoproperty-09.cs index b6109d943c3..42c12e9add6 100644 --- a/mcs/tests/gtest-autoproperty-09.cs +++ b/mcs/tests/gtest-autoproperty-09.cs @@ -1,3 +1,4 @@ +// Compiler options: -langversion:experimental using System; struct S diff --git a/mcs/tests/gtest-autoproperty-10.cs b/mcs/tests/gtest-autoproperty-10.cs new file mode 100644 index 00000000000..036d9c3a43a --- /dev/null +++ b/mcs/tests/gtest-autoproperty-10.cs @@ -0,0 +1,17 @@ +// Compiler options: -langversion:experimental +struct S +{ + public decimal P { get; } = -3; +} + +class X +{ + public static int Main () + { + var s = new S (); + if (s.P != -3) + return 1; + + return 0; + } +} \ No newline at end of file diff --git a/mcs/tests/gtest-etree-01.cs b/mcs/tests/gtest-etree-01.cs index e538021cd0a..43f605e6b5b 100644 --- a/mcs/tests/gtest-etree-01.cs +++ b/mcs/tests/gtest-etree-01.cs @@ -210,6 +210,14 @@ public static implicit operator short (MyTypeImplicitOnly m) } } +struct StructWithUserConstructor +{ + public StructWithUserConstructor () + { + + } +} + class MemberAccessData { public bool BoolValue; @@ -2190,6 +2198,17 @@ void NewTest_7 () Assert (0, e.Compile ().Invoke ()); } + void NewTest_8 () + { + Expression> e = () => new DateTime (); + AssertNodeType (e, ExpressionType.New); + Assert (null, ((NewExpression)e.Body).Constructor, "default ctor"); + + Expression> e2 = () => new StructWithUserConstructor (); + AssertNodeType (e2, ExpressionType.New); + Assert ("Void .ctor()", ((NewExpression)e2.Body).Constructor.ToString (), "user ctor"); + } + void NotTest () { Expression> e = (bool a) => !a; diff --git a/mcs/tests/gtest-lambda-36.cs b/mcs/tests/gtest-lambda-36.cs new file mode 100644 index 00000000000..0d4d772c697 --- /dev/null +++ b/mcs/tests/gtest-lambda-36.cs @@ -0,0 +1,26 @@ +using System; + +class D +{ + public void S (Func ftu, Func ftuv) + { + } +} + +class Test +{ + static D Factory (V v) + { + return new D (); + } + + static void Main () + { + var danon = Factory (new { q = 5 }); + + danon.S ( + () => "x", + (l, str) => new { str } + ); + } +} \ No newline at end of file diff --git a/mcs/tests/gtest-optional-34.cs b/mcs/tests/gtest-optional-34.cs new file mode 100644 index 00000000000..bf865a7bbe9 --- /dev/null +++ b/mcs/tests/gtest-optional-34.cs @@ -0,0 +1,14 @@ +public struct S +{ + public S (double left = 0, double top = 0) + : this () + { + } +} + +class X +{ + public static void Main () + { + } +} \ No newline at end of file diff --git a/mcs/tests/known-issues-net_4_5 b/mcs/tests/known-issues-net_4_5 index 5f738216208..8e195f0d543 100644 --- a/mcs/tests/known-issues-net_4_5 +++ b/mcs/tests/known-issues-net_4_5 @@ -8,3 +8,7 @@ gtest-230.cs # IL Regresssion. gtest-409.cs IGNORE + +# +test-903.cs + diff --git a/mcs/tests/test-251.cs b/mcs/tests/test-251.cs index 7878999c1d1..3b2ffbaa9c4 100644 --- a/mcs/tests/test-251.cs +++ b/mcs/tests/test-251.cs @@ -1,3 +1,4 @@ +// Compiler options: -unsafe // // Tests the valid value types for volatile fields. // @@ -11,6 +12,9 @@ enum XX { A } +struct S { +} + class X { volatile byte a; volatile sbyte b; @@ -26,6 +30,9 @@ class X { 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 () {} } diff --git a/mcs/tests/test-898.cs b/mcs/tests/test-898.cs deleted file mode 100644 index 5b6940372fb..00000000000 --- a/mcs/tests/test-898.cs +++ /dev/null @@ -1,79 +0,0 @@ -// Compiler options: -unsafe - -using System; - -class BoolArrayWithByteValues -{ - - static int Foo (ref bool b) - { - bool b2 = true; - bool r; - r = b == true; - if (!r) - return 10; - - r = b == b2; - if (!r) - return 11; - - return 0; - } - - static unsafe bool Ptr () - { - bool rv; - - var arr = new byte [256]; - for (int i = 0; i < arr.Length; i++) - arr [i] = (byte) i; - fixed (byte* bptr = arr) { - rv = true; - for (int i = 0; i < arr.Length; i++) { - bool* boptr = (bool*)(bptr + i); - if (arr[i] > 0 && !*boptr) - rv = false; - System.Console.WriteLine ("#{0} = {1}", i, *boptr); - } - } - - return rv; - } - - static int Main() - { - var a = new bool[1]; - Buffer.SetByte (a, 0, 5); - - var b = true; - bool r; - r = a [0]; - if (!r) - return 1; - - r = a [0] == true; - if (!r) - return 2; - - r = a [0] == b; - if (!r) - return 3; - - r = a [0] != false; - if (!r) - return 4; - - r = a [0] != b; - if (r) - return 5; - - var res = Foo (ref a [0]); - if (res != 0) - return res; - - if (!Ptr ()) - return 6; - - return 0; - } -} \ No newline at end of file diff --git a/mcs/tests/test-903.cs b/mcs/tests/test-903.cs index 44513478a80..9da077d6f91 100644 --- a/mcs/tests/test-903.cs +++ b/mcs/tests/test-903.cs @@ -6,17 +6,37 @@ struct S class C { + public static int ConversionCalled; + public static implicit operator S (C c) { + ++ConversionCalled; +Console.WriteLine("ConversionCalled"); return new S (); } } class Program { - static void Main () + static C field; + + static int Main () { C c = new C (); var x = c ?? new S (); + + if (C.ConversionCalled != 1) + return 1; + + c = null; + x = c ?? new S (); + if (C.ConversionCalled != 1) + return 2; + + x = field ?? new S (); + if (C.ConversionCalled != 1) + return 3; + + return 0; } -} \ No newline at end of file +} diff --git a/mcs/tests/test-906.cs b/mcs/tests/test-906.cs new file mode 100644 index 00000000000..9a34e438773 --- /dev/null +++ b/mcs/tests/test-906.cs @@ -0,0 +1,76 @@ +// Compiler options: -langversion:experimental +using System; + +struct S1 +{ + public readonly int Value; + + public S1 () + { + Value = 17; + } +} + +struct S2 +{ + public readonly int Value = 23; +} + +struct S3 +{ + public readonly int Value = 11; + + public S3 () + { + Value = 5; + } +} + +struct S4 +{ + public readonly int Value = 11; + + public S4 (int v) + { + } +} + +struct S5 +{ + public readonly int Value = 7; + + public S5 (int v) + : this () + { + this.Value += v; + } +} + +class C +{ + static int Main () + { + var s = new S1 (); + if (s.Value != 17) + return 1; + + var s2 = new S2 (); + if (s2.Value != 23) + return 2; + + var s3 = new S3 (); + if (s3.Value != 5) + return 3; + + var s4 = new S4 (5); + if (s4.Value != 11) + return 4; + + var s5 = new S5 (2); + if (s5.Value != 9) + return 5; + + Console.WriteLine ("ok"); + return 0; + } +} \ No newline at end of file diff --git a/mcs/tests/test-907.cs b/mcs/tests/test-907.cs new file mode 100644 index 00000000000..0a832c91123 --- /dev/null +++ b/mcs/tests/test-907.cs @@ -0,0 +1,22 @@ +public enum Foo { One, Two }; + +class MainClass +{ + public static int Main () + { + const Foo foo = Foo.Two; + int obj; + + switch (foo) { + case Foo.One: + case Foo.Two: + obj = 2; + break; + } + + if (obj != 2) + return 1; + + return 0; + } +} diff --git a/mcs/tests/test-anon-172.cs b/mcs/tests/test-anon-172.cs new file mode 100644 index 00000000000..c316a1ba240 --- /dev/null +++ b/mcs/tests/test-anon-172.cs @@ -0,0 +1,30 @@ +using System; +using System.Reflection.Emit; +using System.Reflection; + +class MainClass +{ + public static int Main () + { + var dynMethod = new DynamicMethod ("Metoda", MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, + null, Type.EmptyTypes, typeof (MainClass), true); + var generator = dynMethod.GetILGenerator (); + + generator.Emit (OpCodes.Ldc_I4_7); + GenerateCodeCall (generator, (int a) => { + Console.WriteLine (a); + }); + + generator.Emit (OpCodes.Ret); + + var deleg = (Action)dynMethod.CreateDelegate (typeof (Action)); + deleg (); + return 0; + } + + static void GenerateCodeCall (ILGenerator generator, Action a) + { + generator.Emit (OpCodes.Call, a.Method); + } +} + diff --git a/mcs/tests/test-decl-expr-01.cs b/mcs/tests/test-decl-expr-01.cs new file mode 100644 index 00000000000..15e781dbf22 --- /dev/null +++ b/mcs/tests/test-decl-expr-01.cs @@ -0,0 +1,65 @@ +using System; + +class DeclarationExpression +{ + public static int Main () + { + Out (out int o); + if (o != 3) + return 1; + + if (Out (out int o1)) { + if (o1 != 3) + return 2; + } + + Out (out int o2 = 2); + if (o2 != 3) + return 3; + + Out (out var o3); + if (o3 != 3) + return 4; + + Ref (ref int r = 2); + if (r != 7) + return 5; + + Ref (ref ((var r2 = 3))); + if (r2 != 8) + return 6; + + Out2 (str: "b", v: out var o5); + if (o5 != 9) + return 7; + + Out3 (out var o6 = 9m); + if (o6.GetType () != typeof (decimal)) + return 8; + + Console.WriteLine ("ok"); + return 0; + } + + static bool Out (out int value) + { + value = 3; + return true; + } + + static bool Out2 (out int v, string str) + { + v = 9; + return true; + } + + static void Out3 (out T t) + { + t = default (T); + } + + static void Ref (ref int arg) + { + arg += 5; + } +} \ No newline at end of file diff --git a/mcs/tests/test-null-operator-010.cs b/mcs/tests/test-null-operator-010.cs new file mode 100644 index 00000000000..2d724034329 --- /dev/null +++ b/mcs/tests/test-null-operator-010.cs @@ -0,0 +1,41 @@ +using System; + +class Test +{ + static void Main () + { + Test_1 (""); + Test_1 (null); + + Test_2 (null); + Test_2 ("z"); + Test_2 (0); + Test_2 ((long?) -8); + + Test_3 (new int[1]); + Test_3 (new int[] { 5 }); + } + + static void Test_1 (T x) where T : class + { + x?.Call (); + } + + static void Test_2 (T x) + { + x?.Call (); + } + + static void Test_3 (T[] x) + { + x[0]?.Call (); + } +} + +static class Ext +{ + public static void Call (this T t) + { + Console.WriteLine (typeof (T)); + } +} diff --git a/mcs/tests/test-pattern-02.cs b/mcs/tests/test-pattern-02.cs index 9efe5d8c308..695775ec179 100644 --- a/mcs/tests/test-pattern-02.cs +++ b/mcs/tests/test-pattern-02.cs @@ -9,6 +9,11 @@ enum MyEnum : short class ConstantPattern { + static bool Generic (T t) where T : class + { + return t is default (T); + } + public static int Main () { bool b4 = false; @@ -62,6 +67,26 @@ public static int Main () if (!r4) return 12; + ConstantPattern o7 = new ConstantPattern (); + if (!(o7 is ConstantPattern)) + return 13; + + if (!(o7 is object)) + return 14; + + object o8 = true; + if (o8 is false) + return 15; + + if (!(o8 is true)) + return 16; + + if (Generic ("")) + return 17; + + if (!Generic (null)) + return 18; + Console.WriteLine ("ok"); return 0; } diff --git a/mcs/tests/test-pattern-03.cs b/mcs/tests/test-pattern-03.cs new file mode 100644 index 00000000000..c4793bdb9d3 --- /dev/null +++ b/mcs/tests/test-pattern-03.cs @@ -0,0 +1,14 @@ +// Compiler options: -langversion:experimental + +class WildcardPattern +{ + static int Main () + { + long? o = 1; + bool b = o is *; + if (!b) + return 1; + + return 0; + } +} \ No newline at end of file diff --git a/mcs/tests/test-pattern-04.cs b/mcs/tests/test-pattern-04.cs new file mode 100644 index 00000000000..dff391cde5a --- /dev/null +++ b/mcs/tests/test-pattern-04.cs @@ -0,0 +1,77 @@ +// Compiler options: -langversion:experimental + +using System; + +class RecursivePattern +{ + static int Main () + { + object o = null; + bool b = o is C1 (8); + if (b) + return 1; + + o = new C1 (); + b = o is C1 (-4); + if (b) + return 2; + + b = o is C1 (8); + if (!b) + return 3; + + b = o is C1 (C1 (9), C1 (8)); + if (b) + return 4; + + b = o is C1 (C1 (*), C1 (8)); + if (!b) + return 41; + + b = o is C1 (0); + if (b) + return 5; + + ValueType vt = new S (); + b = vt is S (null, 0); + if (b) + return 6; + + b = vt is S (8, 0); + if (b) + return 7; + + b = vt is S (8, 2); + if (!b) + return 8; + + Console.WriteLine ("ok"); + return 0; + } +} + +class C1 +{ + public static bool operator is (C1 c, out int x) + { + x = 8; + return true; + } + + public static bool operator is (C1 c, out C1 c2, out C1 c3) + { + c2 = null; + c3 = null; + return true; + } +} + +struct S +{ + public static bool operator is (S s, out int? x, out decimal d) + { + x = 8; + d = 2; + return true; + } +} \ No newline at end of file diff --git a/mcs/tests/test-pattern-05.cs b/mcs/tests/test-pattern-05.cs new file mode 100644 index 00000000000..7553acd6df0 --- /dev/null +++ b/mcs/tests/test-pattern-05.cs @@ -0,0 +1,39 @@ +// Compiler options: -langversion:experimental + +using System; + +class RecursiveNamedPattern +{ + public static int Main () + { + object o = new C (); + bool b = o is C (name2: "", name1: -2); + if (b) + return 1; + + b = o is C (name2: "n2", name1: -2); + if (!b) + return 2; + + b = o is C (); + if (b) + return 3; + + return 0; + } +} + +class C +{ + public static bool operator is (C c, out long name1, out string name2) + { + name1 = -2; + name2 = "n2"; + return true; + } + + public static bool operator is (C c) + { + return false; + } +} \ No newline at end of file diff --git a/mcs/tests/test-pattern-06.cs b/mcs/tests/test-pattern-06.cs new file mode 100644 index 00000000000..3b54b840acf --- /dev/null +++ b/mcs/tests/test-pattern-06.cs @@ -0,0 +1,68 @@ +// Compiler options: -langversion:experimental + +using System; + +class RecursiveNamedPattern +{ + public static int Main () + { + if (Switch_1 (null) != 4) + return 1; + + if (Switch_1 ("x") != 5) + return 2; + + if (Switch_1 (1) != 1) + return 3; + + if (Switch_1 (new C1 ()) != 3) + return 4; + + if (Switch_1 ((byte?) 1) != 1) + return 5; + + if (Switch_2 (new C1 ()) != 3) + return 10; + + if (Switch_2 (null) != 2) + return 11; + + Console.WriteLine ("ok"); + return 0; + } + + static int Switch_1 (object o) + { + switch (o) { + case 1: + return 1; + case C1 (3): + return 2; + case C1 (2): + return 3; + case null: + return 4; + default: + return 5; + } + } + + static int Switch_2 (C1 o) + { + switch (o) { + case null: + return 2; + } + + return 3; + } +} + +public class C1 +{ + public static bool operator is (C1 c1, out int i) + { + i = 2; + return true; + } +} diff --git a/mcs/tests/test-pattern-07.cs b/mcs/tests/test-pattern-07.cs new file mode 100644 index 00000000000..bc7dfda0a89 --- /dev/null +++ b/mcs/tests/test-pattern-07.cs @@ -0,0 +1,75 @@ +// Compiler options: -langversion:experimental + +using System; + +class PropertyPattern +{ + static int Main () + { + object o = new DateTime (2014, 8, 30); + + if (!(o is DateTime { Day is 30 })) + return 1; + + if (!(o is DateTime { Month is 8, Day is 30, Year is * })) + return 2; + + if (o is X { Field is 30 }) + return 3; + + object o2 = new X () { + Field = new Y () { + Prop = 'f' + } + }; + + bool res2 = o2 is X { Field is Y { Prop is 'f' }, Field is Y (4) }; + if (!res2) + return 4; + + res2 = o2 is X { Field is Y { Prop is 'g' } }; + if (res2) + return 5; + + object o3 = new X () { + Value = 5 + }; + + if (o3 is X { Value is 6 }) + return 6; + + if (!(o3 is X { Value is 5 })) + return 7; + + object o4 = new X () { + NullableValue = 4 + }; + + bool res3 = o4 is X { NullableValue is (byte) 4 }; + if (!res3) + return 8; + + Console.WriteLine("ok"); + return 0; + } +} + +class X +{ + public object Field { get; set; } + + public object Value { get; set; } + + public long? NullableValue { get; set; } +} + +class Y +{ + public char Prop { get; set; } + + public static bool operator is (Y y, out int x) + { + x = 4; + return true; + } +} diff --git a/mcs/tests/test-primary-ctor-01.cs b/mcs/tests/test-primary-ctor-01.cs index f2b2239fd4d..5b2eeaed8d5 100644 --- a/mcs/tests/test-primary-ctor-01.cs +++ b/mcs/tests/test-primary-ctor-01.cs @@ -1,3 +1,4 @@ +// Compiler options: -langversion:experimental class Simple(int arg) { int Property { get; } = arg; diff --git a/mcs/tests/test-primary-ctor-07.cs b/mcs/tests/test-primary-ctor-07.cs index 233cfd0d03c..79a1c2991e7 100644 --- a/mcs/tests/test-primary-ctor-07.cs +++ b/mcs/tests/test-primary-ctor-07.cs @@ -1,3 +1,5 @@ +// Compiler options: -langversion:experimental + using System; struct S (int x) @@ -14,6 +16,21 @@ static S () } } +struct S2 (int arg) +{ + public readonly int v = arg; +} + +struct S3 (string s = "arg") +{ + public readonly string V2 = s; + + public S3 (int i, string s = "arg2") + : this (s) + { + } +} + class X { public static int Main () @@ -24,6 +41,15 @@ public static int Main () if (new S ('x').y != 1) return 2; + if (new S2 (2).v != 2) + return 3; + + if (new S3 ("x").V2 != "x") + return 4; + + if (new S3 (0).V2 != "arg2") + return 5; + return 0; } } \ No newline at end of file diff --git a/mcs/tests/ver-il-net_4_5.xml b/mcs/tests/ver-il-net_4_5.xml index 91a4ae6f2bc..ca08bdcbbb1 100644 --- a/mcs/tests/ver-il-net_4_5.xml +++ b/mcs/tests/ver-il-net_4_5.xml @@ -2879,14 +2879,6 @@ 0 - - - 103 - - - 105 - - 118 @@ -2895,6 +2887,14 @@ 7 + + + 103 + + + 105 + + @@ -4725,7 +4725,7 @@ - 44 + 14 7 @@ -6790,10 +6790,10 @@ 86 - 235 + 203 - 114 + 84 20 @@ -7525,7 +7525,7 @@ - 16 + 14 @@ -7578,7 +7578,7 @@ - 57 + 27 @@ -7638,7 +7638,7 @@ - 57 + 27 @@ -12376,7 +12376,7 @@ - 38 + 8 7 @@ -12409,7 +12409,7 @@ - 51 + 21 7 @@ -14460,9 +14460,18 @@ + + 44 + 10 + + 2 + + + 11 + @@ -15204,7 +15213,7 @@ - 43 + 13 7 @@ -15664,7 +15673,7 @@ - 17 + 13 19 @@ -16647,7 +16656,7 @@ - 128 + 35 7 @@ -17469,7 +17478,7 @@ - 18 + 14 15 @@ -17642,7 +17651,7 @@ - 48 + 18 @@ -18073,7 +18082,7 @@ - 61 + 31 7 @@ -18921,7 +18930,7 @@ 26 - 54 + 24 18 @@ -19396,6 +19405,79 @@ + + + + 42 + + + 37 + + + 7 + + + + + + + 7 + + + + + 2 + + + 7 + + + + + 0 + + + 7 + + + + + 20 + + + 19 + + + 7 + + + + + 21 + + + 7 + + + + + + + 10 + + + 10 + + + + + 23 + + + 7 + + + @@ -20227,6 +20309,29 @@ 13 + + + 15 + + + + + + + 14 + + + 14 + + + + + 48 + + + 7 + + @@ -20280,18 +20385,18 @@ 2 - - 13 - - - 13 - 7 69 + + 13 + + + 13 + @@ -21529,6 +21634,16 @@ 12 + + + 2 + + + + + 140 + + @@ -27018,6 +27133,67 @@ + + + + 2 + + + 7 + + + + + 14 + + + 78 + + + 13 + + + 14 + + + 7 + + + + + 7 + + + 39 + + + 63 + + + 67 + + + 14 + + + + + 7 + + + 39 + + + 63 + + + 67 + + + 14 + + + @@ -29866,6 +30042,21 @@ + + + + 9 + + + + + 2 + + + 7 + + + @@ -30564,7 +30755,7 @@ - 44 + 14 22 @@ -32086,7 +32277,7 @@ - 355 + 352 7 @@ -46762,7 +46953,7 @@ - 149 + 146 7 @@ -50492,22 +50683,6 @@ - - - - 58 - - - 191 - - - 7 - - - 167 - - - @@ -50595,19 +50770,19 @@ - 18 + 30 7 - - 15 - 7 + + 155 + @@ -50633,6 +50808,57 @@ + + + + 10 + + + + + 9 + + + + + 17 + + + + + 10 + + + 9 + + + + + 22 + + + 8 + + + + + 161 + + + 7 + + + + + + + 37 + + + 7 + + + @@ -53580,17 +53806,15 @@ 35 + + 7 + 24 - - - 7 - - @@ -54734,6 +54958,22 @@ + + + + 133 + + + 19 + + + 8 + + + 7 + + + @@ -59850,7 +60090,7 @@ - 338 + 335 @@ -59970,7 +60210,7 @@ - 235 + 232 13 @@ -61094,7 +61334,7 @@ - 295 + 305 13 @@ -62696,6 +62936,14 @@ 13 + + + 162 + + + 13 + + 9 @@ -62706,14 +62954,6 @@ 33 - - - 162 - - - 13 - - @@ -65403,6 +65643,28 @@ + + + + 252 + + + 13 + + + 14 + + + 17 + + + 8 + + + 7 + + + @@ -67442,6 +67704,30 @@ + + + + 79 + + + 22 + + + 21 + + + 28 + + + 7 + + + + + 17 + + + @@ -68470,6 +68756,168 @@ + + + + 609 + + + 7 + + + + + 69 + + + + + 28 + + + + + + + 33 + + + 7 + + + + + + + 750 + + + 7 + + + + + 13 + + + 16 + + + 7 + + + + + 34 + + + + + + + 204 + + + 7 + + + + + 22 + + + 10 + + + 7 + + + + + + + 182 + + + 149 + + + 28 + + + 7 + + + + + 13 + + + 7 + + + + + 69 + + + + + + + 684 + + + 7 + + + + + 14 + + + 8 + + + 7 + + + + + 14 + + + 8 + + + 13 + + + 7 + + + + + 14 + + + 8 + + + + + 69 + + + + + 14 + + + 8 + + + @@ -68603,12 +69051,25 @@ - 69 + 180 7 + + + 8 + + + + + 9 + + + 8 + + diff --git a/mcs/tools/corcompare/mono-api-html/ApiDiff.cs b/mcs/tools/corcompare/mono-api-html/ApiDiff.cs index 6a7f39d90f3..b79dd7b886a 100644 --- a/mcs/tools/corcompare/mono-api-html/ApiDiff.cs +++ b/mcs/tools/corcompare/mono-api-html/ApiDiff.cs @@ -64,6 +64,11 @@ public static List IgnoreAdded { get { return ignoreAdded; } } + static List ignoreNew = new List (); + public static List IgnoreNew { + get { return ignoreNew; } + } + static List ignoreRemoved = new List (); public static List IgnoreRemoved { get { return ignoreRemoved; } @@ -83,11 +88,12 @@ public static int Main (string[] args) 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).", @@ -96,6 +102,9 @@ public static int Main (string[] args) { "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 } }; diff --git a/mcs/tools/corcompare/mono-api-html/ClassComparer.cs b/mcs/tools/corcompare/mono-api-html/ClassComparer.cs index bdf22fea489..d96613c3e8a 100644 --- a/mcs/tools/corcompare/mono-api-html/ClassComparer.cs +++ b/mcs/tools/corcompare/mono-api-html/ClassComparer.cs @@ -27,6 +27,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Xml.Linq; namespace Xamarin.ApiDiff { @@ -68,7 +69,10 @@ public void Compare (XElement source, XElement target) public override void Added (XElement target) { - Output.WriteLine ("

New Type {0}.{1}

", State.Namespace, target.Attribute ("name").Value); + string name = target.Attribute ("name").Value; + if (State.IgnoreNew.Any (re => re.IsMatch (name))) + return; + Output.WriteLine ("

New Type {0}.{1}

", State.Namespace, name); Output.WriteLine ("
");
 			State.Indent = 0;
 			AddedInner (target);
diff --git a/mcs/tools/corcompare/mono-api-html/NamespaceComparer.cs b/mcs/tools/corcompare/mono-api-html/NamespaceComparer.cs
index 7239385870e..427df66e6eb 100644
--- a/mcs/tools/corcompare/mono-api-html/NamespaceComparer.cs
+++ b/mcs/tools/corcompare/mono-api-html/NamespaceComparer.cs
@@ -26,6 +26,7 @@
 
 using System;
 using System.IO;
+using System.Linq;
 using System.Xml.Linq;
 
 namespace Xamarin.ApiDiff {
@@ -55,7 +56,11 @@ public override void SetContext (XElement current)
 
 		public override void Added (XElement target)
 		{
-			Output.WriteLine ("

New Namespace {0}

", target.Attribute ("name").Value); + string name = target.Attribute ("name").Value; + if (State.IgnoreNew.Any (re => re.IsMatch (name))) + return; + + Output.WriteLine ("

New Namespace {0}

", name); Output.WriteLine (); // list all new types foreach (var addedType in target.Element ("classes").Elements ("class")) diff --git a/mcs/tools/corcompare/mono-api-info.cs b/mcs/tools/corcompare/mono-api-info.cs index 2dc4bcebb3d..a689210b12b 100644 --- a/mcs/tools/corcompare/mono-api-info.cs +++ b/mcs/tools/corcompare/mono-api-info.cs @@ -545,6 +545,9 @@ static string GetClassType (TypeDefinition t) if (TypeHelper.IsDelegate(t)) return "delegate"; + if (t.IsPointer) + return "pointer"; + return "class"; } @@ -907,6 +910,8 @@ protected override void AddExtraData (XmlNode p, MemberReference memberDefenitio AddAttribute (p, "abstract", "true"); if (mbase.IsVirtual) AddAttribute (p, "virtual", "true"); + if (mbase.IsFinal && mbase.IsVirtual && mbase.IsReuseSlot) + AddAttribute (p, "sealed", "true"); if (mbase.IsStatic) AddAttribute (p, "static", "true"); diff --git a/mcs/tools/linker/Descriptors/System.xml b/mcs/tools/linker/Descriptors/System.xml index 181a3ebc36c..f70c020412d 100644 --- a/mcs/tools/linker/Descriptors/System.xml +++ b/mcs/tools/linker/Descriptors/System.xml @@ -13,6 +13,7 @@ + diff --git a/mcs/tools/mdoc/Makefile b/mcs/tools/mdoc/Makefile index e4ff1eed87c..3b7e698d604 100644 --- a/mcs/tools/mdoc/Makefile +++ b/mcs/tools/mdoc/Makefile @@ -90,9 +90,23 @@ cleanup: -rm -Rf Test/en.actual Test/html.actual -rm -f monodocer1.exe* +Test/DocTest-DropNS-classic-secondary.dll: + @echo $(value @) + $(CSCOMPILE) $(TEST_CSCFLAGS) -debug -unsafe -target:library -out:$@ Test/DocTest-DropNS-classic-secondary.cs + +Test/DocTest-DropNS-classic.dll: + @echo $(value @) + $(CSCOMPILE) $(TEST_CSCFLAGS) -debug -unsafe -target:library -out:$@ Test/DocTest-DropNS-classic.cs + +Test/DocTest-DropNS-unified.dll: + $(CSCOMPILE) $(TEST_CSCFLAGS) -debug -unsafe -target:library -out:$@ Test/DocTest-DropNS-unified.cs + Test/DocTest.dll: $(CSCOMPILE) $(TEST_CSCFLAGS) -debug -unsafe -target:library -out:$@ Test/DocTest.cs +Test/DocTest-InternalInterface.dll: + $(CSCOMPILE) $(TEST_CSCFLAGS) -debug -unsafe -target:library -out:$@ Test/DocTest-InternalInterface.cs + Test/DocTest.dll-v1: -rm -f Test/DocTest.cs cp Test/DocTest-v1.cs Test/DocTest.cs @@ -106,6 +120,42 @@ Test/DocTest.dll-v2: -rm -f Test/DocTest.dll $(MAKE) TEST_CSCFLAGS=$(TEST_CSCFLAGS) Test/DocTest.dll +check-monodocer-dropns-classic: $(PROGRAM) + # tests the simplest --dropns case, a single class where the root namespace was dropped. + -rm -Rf Test/en.actual + $(MAKE) Test/DocTest-DropNS-classic.dll + $(MONO) $(PROGRAM) update --exceptions=all -o Test/en.actual Test/DocTest-DropNS-classic.dll + $(MAKE) update-monodocer-dropns-unified + diff --exclude=.svn -rup Test/en.expected-dropns-classic-v1 Test/en.actual + +check-monodocer-dropns-classic-withsecondary: $(PROGRAM) + # tests case where a secondary assembly is included with a --dropns parameter + -rm -Rf Test/en.actual + $(MAKE) Test/DocTest-DropNS-classic.dll + $(MAKE) Test/DocTest-DropNS-classic-secondary.dll + $(MONO) $(PROGRAM) update --exceptions=all -o Test/en.actual Test/DocTest-DropNS-classic.dll Test/DocTest-DropNS-classic-secondary.dll + $(MAKE) update-monodocer-dropns-unified-withsecondary + diff --exclude=.svn -rup Test/en.expected-dropns-classic-withsecondary Test/en.actual + +update-monodocer-dropns-unified: $(PROGRAM) + $(MAKE) Test/DocTest-DropNS-unified.dll + $(MONO) $(PROGRAM) update --exceptions=all -o Test/en.actual Test/DocTest-DropNS-unified.dll --dropns Test/DocTest-DropNS-unified.dll=MyFramework + +update-monodocer-dropns-unified-withsecondary: $(PROGRAM) + $(MAKE) Test/DocTest-DropNS-unified.dll + $(MONO) $(PROGRAM) update --exceptions=all -o Test/en.actual Test/DocTest-DropNS-unified.dll Test/DocTest-DropNS-classic-secondary.dll --dropns Test/DocTest-DropNS-unified.dll=MyFramework + +update-monodocer-dropns-classic-secondary: $(PROGRAM) + $(MAKE) Test/DocTest-DropNS-classic-secondary.dll + $(MONO) $(PROGRAM) update --exceptions=all -o Test/en.actual Test/DocTest-DropNS-classic-secondary.dll + +check-monodocer-internal-interface: $(PROGRAM) + # Tests to make sure internal interfaces that are explicitly implemented are not documented + -rm -Rf Test/en.actual + $(MAKE) Test/DocTest-InternalInterface.dll + $(MONO) $(PROGRAM) update --exceptions=all -o Test/en.actual Test/DocTest-InternalInterface.dll + diff --exclude=.svn -rup Test/en.expected-internal-interface Test/en.actual + check-monodocer-update: $(PROGRAM) find Test/en.expected -name \*.xml -exec rm "{}" \; $(MAKE) Test/DocTest.dll-v1 @@ -262,8 +312,12 @@ check-doc-tools-update: check-monodocer-since-update \ check-monodocer-importecmadoc-update \ check-monodocer-importslashdoc-update \ check-monodocer-update \ + check-monodocer-dropns-classic \ + check-monodocer-dropns-classic-withsecondary \ + check-monodocer-internal-interface \ check-monodocer-delete-update \ check-mdoc-export-html-update \ check-mdoc-export-msxdoc-update \ - check-mdoc-validate-update + check-mdoc-validate-update + diff --git a/mcs/tools/mdoc/Mono.Documentation/monodocer.cs b/mcs/tools/mdoc/Mono.Documentation/monodocer.cs index 75a6d5ca63e..842a4ae439f 100644 --- a/mcs/tools/mdoc/Mono.Documentation/monodocer.cs +++ b/mcs/tools/mdoc/Mono.Documentation/monodocer.cs @@ -120,7 +120,7 @@ public static string GetTranslatedName(TypeReference t) { string typename = t.FullName; bool isInAssembly = MDocUpdater.IsInAssemblies (t.Module.Name); - if (isInAssembly && MDocUpdater.HasDroppedNamespace () && !typename.StartsWith ("System")) { + if (isInAssembly && !typename.StartsWith ("System") && MDocUpdater.HasDroppedNamespace (t)) { string nameWithDropped = string.Format ("{0}.{1}", MDocUpdater.droppedNamespace, typename); return nameWithDropped; } @@ -166,9 +166,30 @@ class MDocUpdater : MDocCommand HashSet forwardedTypes = new HashSet (); public static string droppedNamespace = string.Empty; - public static bool HasDroppedNamespace() { - return !string.IsNullOrWhiteSpace (droppedNamespace); + + public static bool HasDroppedNamespace(TypeDefinition forType) + { + return HasDroppedNamespace(forType.Module); + } + + public static bool HasDroppedNamespace(MemberReference forMember) + { + return HasDroppedNamespace(forMember.Module); + } + + public static bool HasDroppedNamespace(AssemblyDefinition forAssembly) + { + return HasDroppedNamespace(forAssembly.MainModule); } + + public static bool HasDroppedNamespace(ModuleDefinition forModule) + { + return !string.IsNullOrWhiteSpace (droppedNamespace) && droppedAssemblies.Any(da => da == forModule.Name); + } + + + static List droppedAssemblies = new List(); + public string PreserveTag { get; set; } public static MDocUpdater Instance { get; private set; } public static bool SwitchingToMagicTypes { get; private set; } @@ -236,8 +257,16 @@ public override void Run (IEnumerable args) "Only update documentation for {TYPE}.", v => types.Add (v) }, { "dropns=", - "Instructs the update process that {NAMESPACE} has been dropped, so that types and members will match existing documentation nodes.", - v => droppedNamespace = v }, + "When processing assembly {ASSEMBLY}, strip off leading namespace {PREFIX}:\n" + + " e.g. --dropns ASSEMBLY=PREFIX", + v => { + var parts = v.Split ('='); + if (parts.Length != 2) { Console.Error.WriteLine ("Invalid dropns input"); return; } + var assembly = Path.GetFileName (parts [0].Trim ()); + var prefix = parts [1].Trim(); + droppedAssemblies.Add (assembly); + droppedNamespace = prefix; + } }, { "ntypes", "If the new assembly is switching to 'magic types', then this switch should be defined.", v => SwitchingToMagicTypes = true }, @@ -580,7 +609,7 @@ public string DoUpdateType (TypeDefinition type, string basepath, string dest) nsname }; - if (MDocUpdater.HasDroppedNamespace ()) { + if (MDocUpdater.HasDroppedNamespace (type)) { // If dropping namespace, types may have moved into a couple of different places. var newSearchLocations = searchLocations.Union (new string[] { string.Format ("{0}.{1}", droppedNamespace, nsname), @@ -847,10 +876,10 @@ private void DoUpdateAssembly (AssemblyDefinition assembly, XmlElement index_typ // Add namespace and type nodes into the index file as needed AddIndexType (type, index_types); - + // Ensure the namespace index file exists string namespaceToUse = type.Namespace; - if (HasDroppedNamespace()) { + if (HasDroppedNamespace(assembly)) { namespaceToUse = string.Format ("{0}.{1}", droppedNamespace, namespaceToUse); } string onsdoc = DocUtils.PathCombine (dest, namespaceToUse + ".xml"); @@ -951,7 +980,7 @@ private static string GetTypeKind (TypeDefinition type) throw new ArgumentException ("Unknown kind for type: " + type.FullName); } - private static bool IsPublic (TypeDefinition type) + public static bool IsPublic (TypeDefinition type) { TypeDefinition decl = type; while (decl != null) { @@ -974,7 +1003,9 @@ private void CleanupFiles (string dest, HashSet goodfiles) XmlDocument doc = new XmlDocument (); doc.Load (typefile.FullName); XmlElement e = doc.SelectSingleNode("/Type") as XmlElement; - if (e != null && !no_assembly_versions && UpdateAssemblyVersions(e, GetAssemblyVersions(), false)) { + string assemblyName = doc.SelectSingleNode ("/Type/AssemblyInfo/AssemblyName").InnerText; + AssemblyDefinition assembly = assemblies.FirstOrDefault (a => a.Name.Name == assemblyName); + if (e != null && !no_assembly_versions && assembly != null && assemblyName != null && UpdateAssemblyVersions(e, assembly, GetAssemblyVersions(assemblyName), false)) { using (TextWriter writer = OpenWrite (typefile.FullName, FileMode.Truncate)) WriteXml(doc.DocumentElement, writer); goodfiles.Add (relTypeFile); @@ -1002,9 +1033,11 @@ private static TextWriter OpenWrite (string path, FileMode mode) return w; } - private string[] GetAssemblyVersions () + private string[] GetAssemblyVersions (string assemblyName) { - return (from a in assemblies select GetAssemblyVersion (a)).ToArray (); + return (from a in assemblies + where a.Name.Name == assemblyName + select GetAssemblyVersion (a)).ToArray (); } private static void CleanupIndexTypes (XmlElement index_types, HashSet goodfiles) @@ -1088,10 +1121,10 @@ public void DoUpdateType2 (string message, XmlDocument basefile, TypeDefinition // Deleted (or signature changed) if (oldmember2 == null) { - if (!no_assembly_versions && UpdateAssemblyVersions (oldmember, new string[]{ GetAssemblyVersion (type.Module.Assembly) }, false)) + if (!no_assembly_versions && UpdateAssemblyVersions (oldmember, type.Module.Assembly, new string[]{ GetAssemblyVersion (type.Module.Assembly) }, false)) continue; - DeleteMember ("Member Removed", output, oldmember, todelete); + DeleteMember ("Member Removed", output, oldmember, todelete, type); continue; } @@ -1101,7 +1134,7 @@ public void DoUpdateType2 (string message, XmlDocument basefile, TypeDefinition // ignore, already seen } else if (DefaultMemberComparer.Compare (oldmember, seenmembers [sig]) == 0) - DeleteMember ("Duplicate Member Found", output, oldmember, todelete); + DeleteMember ("Duplicate Member Found", output, oldmember, todelete, type); else Warning ("TODO: found a duplicate member '{0}', but it's not identical to the prior member found!", sig); continue; @@ -1131,6 +1164,27 @@ public void DoUpdateType2 (string message, XmlDocument basefile, TypeDefinition string sig = memberFormatters [0].GetDeclaration (m); if (sig == null) return false; if (seenmembers.ContainsKey(sig)) return false; + + // Verify that the member isn't an explicitly implemented + // member of an internal interface, in which case we shouldn't return true. + MethodDefinition methdef = null; + if (m is MethodDefinition) + methdef = m as MethodDefinition; + else if (m is PropertyDefinition) { + var prop = m as PropertyDefinition; + methdef = prop.GetMethod ?? prop.SetMethod; + } + + if (methdef != null) { + TypeReference iface; + MethodReference imethod; + + if (methdef.Overrides.Count == 1) { + DocUtils.GetInfoForExplicitlyImplementedMethod (methdef, out iface, out imethod); + if (!IsPublic (iface.Resolve ())) return false; + } + } + return true; }) .ToArray(); @@ -1232,7 +1286,7 @@ private string GetCodeSource (string lang, string file) return null; } - void DeleteMember (string reason, string output, XmlNode member, MyXmlNodeList todelete) + void DeleteMember (string reason, string output, XmlNode member, MyXmlNodeList todelete, TypeDefinition type) { string format = output != null ? "{0}: File='{1}'; Signature='{4}'" @@ -1245,7 +1299,7 @@ void DeleteMember (string reason, string output, XmlNode member, MyXmlNodeList t member.SelectSingleNode ("MemberSignature[@Language='C#']/@Value").Value); if (!delete && MemberDocsHaveUserContent (member)) { Warning ("Member deletions must be enabled with the --delete option."); - } else if (HasDroppedNamespace ()) { + } else if (HasDroppedNamespace (type)) { // if we're dropping the namespace, add the "classic style" var existingAttribute = member.Attributes ["apistyle"]; if (existingAttribute != null) { @@ -1258,7 +1312,7 @@ void DeleteMember (string reason, string output, XmlNode member, MyXmlNodeList t member.Attributes.Append (apistyleAttr); } - } else if (!HasDroppedNamespace () && member.Attributes ["apistyle"] != null && member.Attributes ["apistyle"].Value == "unified") { + } else if (!HasDroppedNamespace (type) && member.Attributes ["apistyle"] != null && member.Attributes ["apistyle"].Value == "unified") { // do nothing if there's an apistyle=new attribute and we haven't dropped the namespace } else if (!string.IsNullOrWhiteSpace (PreserveTag)) { // do nothing @@ -1400,10 +1454,11 @@ public void UpdateType (XmlElement root, TypeDefinition type) var node = WriteElementAttribute (root, element, "Language", f.Language, forceNewElement: true); var newnode = WriteElementAttribute (root, node, "Value", valueToUse); return newnode; - }); + }, + type); } - string assemblyInfoNodeFilter = MDocUpdater.HasDroppedNamespace () ? "[@apistyle='unified']" : "[not(@apistyle) or @apistyle='classic']"; + string assemblyInfoNodeFilter = MDocUpdater.HasDroppedNamespace (type) ? "[@apistyle='unified']" : "[not(@apistyle) or @apistyle='classic']"; AddXmlNode( root.SelectNodes ("AssemblyInfo" + assemblyInfoNodeFilter).Cast ().ToArray (), @@ -1412,12 +1467,13 @@ public void UpdateType (XmlElement root, TypeDefinition type) () => { XmlElement ass = WriteElement(root, "AssemblyInfo", forceNewElement:true); - if (MDocUpdater.HasDroppedNamespace ()) ass.SetAttribute ("apistyle", "unified"); + if (MDocUpdater.HasDroppedNamespace (type)) ass.SetAttribute ("apistyle", "unified"); return ass; - }); + }, + type); foreach(var ass in root.SelectNodes ("AssemblyInfo" + assemblyInfoNodeFilter).Cast ()) { @@ -1448,7 +1504,7 @@ public void UpdateType (XmlElement root, TypeDefinition type) } if (type.IsGenericType ()) { - MakeTypeParameters (root, type.GenericParameters, MDocUpdater.HasDroppedNamespace()); + MakeTypeParameters (root, type.GenericParameters, type, MDocUpdater.HasDroppedNamespace(type)); } else { ClearElement(root, "TypeParameters"); } @@ -1505,9 +1561,10 @@ public void UpdateType (XmlElement root, TypeDefinition type) MakeAttributes (root, GetCustomAttributes (type), type); if (DocUtils.IsDelegate (type)) { - MakeTypeParameters (root, type.GenericParameters, MDocUpdater.HasDroppedNamespace()); - MakeParameters(root, type.GetMethod("Invoke").Parameters); - MakeReturnValue(root, type.GetMethod("Invoke")); + MakeTypeParameters (root, type.GenericParameters, type, MDocUpdater.HasDroppedNamespace(type)); + var member = type.GetMethod ("Invoke"); + MakeParameters(root, member, member.Parameters); + MakeReturnValue(root, member); } DocsNodeInfo typeInfo = new DocsNodeInfo (WriteElement(root, "Docs"), type); @@ -1567,7 +1624,8 @@ private void UpdateMember (DocsNodeInfo info) var node = WriteElementAttribute (me, element, "Language", f.Language, forceNewElement:true); var newNode = WriteElementAttribute (me, node, "Value", valueToUse); return newNode; - }); + }, + mi); } @@ -1582,13 +1640,13 @@ private void UpdateMember (DocsNodeInfo info) MakeAttributes (me, GetCustomAttributes (mi), mi.DeclaringType); - MakeReturnValue(me, mi, MDocUpdater.HasDroppedNamespace()); + MakeReturnValue(me, mi, MDocUpdater.HasDroppedNamespace(mi)); if (mi is MethodReference) { MethodReference mb = (MethodReference) mi; if (mb.IsGenericMethod ()) - MakeTypeParameters (me, mb.GenericParameters, MDocUpdater.HasDroppedNamespace()); + MakeTypeParameters (me, mb.GenericParameters, mi, MDocUpdater.HasDroppedNamespace(mi)); } - MakeParameters(me, mi, MDocUpdater.HasDroppedNamespace()); + MakeParameters(me, mi, MDocUpdater.HasDroppedNamespace(mi)); string fieldValue; if (mi is FieldDefinition && GetFieldConstValue ((FieldDefinition)mi, out fieldValue)) @@ -1600,14 +1658,22 @@ private void UpdateMember (DocsNodeInfo info) UpdateExtensionMethods (me, info); } + static void AddXmlNode (XmlElement[] relevant, Func valueMatches, Action setValue, Func makeNewNode, MemberReference member) { + AddXmlNode (relevant, valueMatches, setValue, makeNewNode, member.Module); + } + + static void AddXmlNode (XmlElement[] relevant, Func valueMatches, Action setValue, Func makeNewNode, TypeDefinition type) { + AddXmlNode (relevant, valueMatches, setValue, makeNewNode, type.Module); + } + /// Adds an xml node, reusing the node if it's available /// The existing set of nodes /// Checks to see if the node's value matches what you're trying to write. /// Sets the node's value /// Creates a new node, if valueMatches returns false. - static void AddXmlNode (XmlElement[] relevant, Func valueMatches, Action setValue, Func makeNewNode) + static void AddXmlNode (XmlElement[] relevant, Func valueMatches, Action setValue, Func makeNewNode, ModuleDefinition module) { - bool shouldDuplicate = MDocUpdater.HasDroppedNamespace (); + bool shouldDuplicate = MDocUpdater.HasDroppedNamespace (module); var styleToUse = shouldDuplicate ? ApiStyle.Unified : ApiStyle.Classic; var existing = relevant; bool done = false; @@ -2164,7 +2230,7 @@ private static bool UpdateAssemblyVersions (XmlElement root, MemberReference mem TypeDefinition type = member as TypeDefinition; if (type == null) type = member.DeclaringType as TypeDefinition; - return UpdateAssemblyVersions(root, new string[]{ GetAssemblyVersion (type.Module.Assembly) }, add); + return UpdateAssemblyVersions(root, type.Module.Assembly, new string[]{ GetAssemblyVersion (type.Module.Assembly) }, add); } private static string GetAssemblyVersion (AssemblyDefinition assembly) @@ -2172,7 +2238,7 @@ private static string GetAssemblyVersion (AssemblyDefinition assembly) return assembly.Name.Version.ToString(); } - private static bool UpdateAssemblyVersions(XmlElement root, string[] assemblyVersions, bool add) + private static bool UpdateAssemblyVersions(XmlElement root, AssemblyDefinition assembly, string[] assemblyVersions, bool add) { XmlElement av = (XmlElement) root.SelectSingleNode ("AssemblyVersions"); if (av != null) { @@ -2182,14 +2248,14 @@ private static bool UpdateAssemblyVersions(XmlElement root, string[] assemblyVer string oldNodeFilter = "AssemblyInfo[not(@apistyle) or @apistyle='classic']"; string newNodeFilter = "AssemblyInfo[@apistyle='unified']"; - string thisNodeFilter = MDocUpdater.HasDroppedNamespace () ? newNodeFilter : oldNodeFilter; - string thatNodeFilter = MDocUpdater.HasDroppedNamespace () ? oldNodeFilter : newNodeFilter; + string thisNodeFilter = MDocUpdater.HasDroppedNamespace (assembly) ? newNodeFilter : oldNodeFilter; + string thatNodeFilter = MDocUpdater.HasDroppedNamespace (assembly) ? oldNodeFilter : newNodeFilter; XmlElement e = (XmlElement) root.SelectSingleNode (thisNodeFilter); if (e == null) { e = root.OwnerDocument.CreateElement("AssemblyInfo"); - if (MDocUpdater.HasDroppedNamespace ()) { + if (MDocUpdater.HasDroppedNamespace (assembly)) { e.SetAttribute ("apistyle", "unified"); } @@ -2197,7 +2263,7 @@ private static bool UpdateAssemblyVersions(XmlElement root, string[] assemblyVer } var thatNode = (XmlElement) root.SelectSingleNode (thatNodeFilter); - if (MDocUpdater.HasDroppedNamespace () && thatNode != null) { + if (MDocUpdater.HasDroppedNamespace (assembly) && thatNode != null) { // there's a classic node, we should add apistyles e.SetAttribute ("apistyle", "unified"); thatNode.SetAttribute ("apistyle", "classic"); @@ -2333,7 +2399,7 @@ static long ToInt64 (object value) return Convert.ToInt64 (value); } - private void MakeParameters (XmlElement root, IList parameters, bool shouldDuplicateWithNew=false) + private void MakeParameters (XmlElement root, MemberReference member, IList parameters, bool shouldDuplicateWithNew=false) { XmlElement e = WriteElement(root, "Parameters"); @@ -2382,13 +2448,14 @@ private void MakeParameters (XmlElement root, IList paramet MakeAttributes (pe, GetCustomAttributes (p.CustomAttributes, "")); return pe; - }); + }, + member); i++; } } - private void MakeTypeParameters (XmlElement root, IList typeParams, bool shouldDuplicateWithNew) + private void MakeTypeParameters (XmlElement root, IList typeParams, MemberReference member, bool shouldDuplicateWithNew) { if (typeParams == null || typeParams.Count == 0) { XmlElement f = (XmlElement) root.SelectSingleNode ("TypeParameters"); @@ -2450,18 +2517,19 @@ private void MakeTypeParameters (XmlElement root, IList typePa } return pe; - }); + }, + member); } } private void MakeParameters (XmlElement root, MemberReference mi, bool shouldDuplicateWithNew) { if (mi is MethodDefinition && ((MethodDefinition) mi).IsConstructor) - MakeParameters (root, ((MethodDefinition)mi).Parameters, shouldDuplicateWithNew); + MakeParameters (root, mi, ((MethodDefinition)mi).Parameters, shouldDuplicateWithNew); else if (mi is MethodDefinition) { MethodDefinition mb = (MethodDefinition) mi; IList parameters = mb.Parameters; - MakeParameters(root, parameters, shouldDuplicateWithNew); + MakeParameters(root, mi, parameters, shouldDuplicateWithNew); if (parameters.Count > 0 && DocUtils.IsExtensionMethod (mb)) { XmlElement p = (XmlElement) root.SelectSingleNode ("Parameters/Parameter[position()=1]"); p.SetAttribute ("RefType", "this"); @@ -2470,7 +2538,7 @@ private void MakeParameters (XmlElement root, MemberReference mi, bool shouldDup else if (mi is PropertyDefinition) { IList parameters = ((PropertyDefinition)mi).Parameters; if (parameters.Count > 0) - MakeParameters(root, parameters, shouldDuplicateWithNew); + MakeParameters(root, mi, parameters, shouldDuplicateWithNew); else return; } @@ -2498,7 +2566,8 @@ private void MakeReturnValue (XmlElement root, TypeReference type, IList GetUserImplementedInterfaces (TypeDefin if (!inheritedInterfaces.Contains (GetQualifiedTypeName (lookup))) userInterfaces.Add (iface); } - return userInterfaces; + return userInterfaces.Where (i => MDocUpdater.IsPublic (i.Resolve ())); } private static string GetQualifiedTypeName (TypeReference type) @@ -3217,7 +3286,7 @@ protected static MemberReference GetMember (TypeDefinition type, DocumentationMe // did not match ... if we're dropping the namespace, and the paramType has the dropped // namespace, we should see if it matches when added bool stillDoesntMatch = true; - if (MDocUpdater.HasDroppedNamespace() && paramType.StartsWith (MDocUpdater.droppedNamespace)) { + if (MDocUpdater.HasDroppedNamespace(type) && paramType.StartsWith (MDocUpdater.droppedNamespace)) { string withDroppedNs = string.Format ("{0}.{1}", MDocUpdater.droppedNamespace, xmlMemberType); stillDoesntMatch = withDroppedNs != paramType; @@ -3270,7 +3339,7 @@ protected static IEnumerable GetReflectionMembers (TypeDefiniti { // In case of dropping the namespace, we have to remove the dropped NS // so that docName will match what's in the assembly/type - if (MDocUpdater.HasDroppedNamespace () && docName.StartsWith(MDocUpdater.droppedNamespace + ".")) { + if (MDocUpdater.HasDroppedNamespace (type) && docName.StartsWith(MDocUpdater.droppedNamespace + ".")) { int droppedNsLength = MDocUpdater.droppedNamespace.Length; docName = docName.Substring (droppedNsLength + 1, docName.Length - droppedNsLength - 1); } @@ -4303,7 +4372,7 @@ protected override string GetTypeDeclaration (TypeDefinition type) buf.Append (full.GetName (type.BaseType).Substring ("class ".Length)); } bool first = true; - foreach (var name in type.Interfaces + foreach (var name in type.Interfaces.Where (i => MDocUpdater.IsPublic (i.Resolve ())) .Select (i => full.GetName (i)) .OrderBy (n => n)) { if (first) { diff --git a/mcs/tools/mdoc/Test/DocTest-DropNS-classic-secondary.cs b/mcs/tools/mdoc/Test/DocTest-DropNS-classic-secondary.cs new file mode 100644 index 00000000000..3f929d6a75c --- /dev/null +++ b/mcs/tools/mdoc/Test/DocTest-DropNS-classic-secondary.cs @@ -0,0 +1,9 @@ +namespace MyFramework.MyOtherNamespace { + ///Make sure the namespace in this assembly doesn't get 'dropped' + public class MyOtherClass { + public string MyProperty {get;set;} + public float Hello(int value) { + return 0.0f; + } + } +} diff --git a/mcs/tools/mdoc/Test/DocTest-DropNS-classic.cs b/mcs/tools/mdoc/Test/DocTest-DropNS-classic.cs new file mode 100644 index 00000000000..a279b0e85a7 --- /dev/null +++ b/mcs/tools/mdoc/Test/DocTest-DropNS-classic.cs @@ -0,0 +1,8 @@ +namespace MyFramework.MyNamespace { + public class MyClass { + public string MyProperty {get;set;} + public float Hello(int value) { + return 0.0f; + } + } +} diff --git a/mcs/tools/mdoc/Test/DocTest-DropNS-unified.cs b/mcs/tools/mdoc/Test/DocTest-DropNS-unified.cs new file mode 100644 index 00000000000..8ee5e8a6ffd --- /dev/null +++ b/mcs/tools/mdoc/Test/DocTest-DropNS-unified.cs @@ -0,0 +1,8 @@ +namespace MyNamespace { + public class MyClass { + public string MyProperty {get;set;} + public float Hello(int value) { + return 0.0f; + } + } +} diff --git a/mcs/tools/mdoc/Test/DocTest-InternalInterface.cs b/mcs/tools/mdoc/Test/DocTest-InternalInterface.cs new file mode 100644 index 00000000000..5d65c34c82c --- /dev/null +++ b/mcs/tools/mdoc/Test/DocTest-InternalInterface.cs @@ -0,0 +1,17 @@ +namespace MyNamespace { + internal interface MyInternalInterface { + bool Foo {get;set;} + string FooSet {set;} + void FooMeth (); + void BarMeth (); + } + + public class MyClass : MyInternalInterface { + public string Bar {get;set;} + public void BarMeth () {} // part of the interface, but publicly implemented + + string MyInternalInterface.FooSet {set {}} + bool MyInternalInterface.Foo {get;set;} + void MyInternalInterface.FooMeth () {} + } +} diff --git a/mcs/tools/mdoc/Test/en.expected-dropns-classic-v0/MyFramework.MyNamespace/MyClass.xml b/mcs/tools/mdoc/Test/en.expected-dropns-classic-v0/MyFramework.MyNamespace/MyClass.xml new file mode 100644 index 00000000000..1e0522f64f7 --- /dev/null +++ b/mcs/tools/mdoc/Test/en.expected-dropns-classic-v0/MyFramework.MyNamespace/MyClass.xml @@ -0,0 +1,67 @@ + + + + + DocTest-DropNS-classic + 0.0.0.0 + + + System.Object + + + + To be added. + To be added. + + + + + + Constructor + + 0.0.0.0 + + + + To be added. + To be added. + + + + + + Method + + 0.0.0.0 + + + System.Single + + + + + + To be added. + To be added. + To be added. + To be added. + + + + + + Property + + 0.0.0.0 + + + System.String + + + To be added. + To be added. + To be added. + + + + diff --git a/mcs/tools/mdoc/Test/en.expected-dropns-classic-v0/index.xml b/mcs/tools/mdoc/Test/en.expected-dropns-classic-v0/index.xml new file mode 100644 index 00000000000..4f7838baac6 --- /dev/null +++ b/mcs/tools/mdoc/Test/en.expected-dropns-classic-v0/index.xml @@ -0,0 +1,22 @@ + + + + + + System.Diagnostics.Debuggable(System.Diagnostics.DebuggableAttribute+DebuggingModes.IgnoreSymbolStoreSequencePoints) + + + System.Runtime.CompilerServices.RuntimeCompatibility(WrapNonExceptionThrows=true) + + + + + To be added. + To be added. + + + + + + DocTest-DropNS-classic + diff --git a/mcs/tools/mdoc/Test/en.expected-dropns-classic-v0/ns-MyFramework.MyNamespace.xml b/mcs/tools/mdoc/Test/en.expected-dropns-classic-v0/ns-MyFramework.MyNamespace.xml new file mode 100644 index 00000000000..74df75af20b --- /dev/null +++ b/mcs/tools/mdoc/Test/en.expected-dropns-classic-v0/ns-MyFramework.MyNamespace.xml @@ -0,0 +1,6 @@ + + + To be added. + To be added. + + diff --git a/mcs/tools/mdoc/Test/en.expected-dropns-classic-v1/MyFramework.MyNamespace/MyClass.xml b/mcs/tools/mdoc/Test/en.expected-dropns-classic-v1/MyFramework.MyNamespace/MyClass.xml new file mode 100644 index 00000000000..e3cda6d9d99 --- /dev/null +++ b/mcs/tools/mdoc/Test/en.expected-dropns-classic-v1/MyFramework.MyNamespace/MyClass.xml @@ -0,0 +1,80 @@ + + + + + DocTest-DropNS-classic + 0.0.0.0 + + + DocTest-DropNS-unified + 0.0.0.0 + + + System.Object + + + + To be added. + To be added. + + + + + + Constructor + + 0.0.0.0 + + + 0.0.0.0 + + + + To be added. + To be added. + + + + + + Method + + 0.0.0.0 + + + 0.0.0.0 + + + System.Single + + + + + + To be added. + To be added. + To be added. + To be added. + + + + + + Property + + 0.0.0.0 + + + 0.0.0.0 + + + System.String + + + To be added. + To be added. + To be added. + + + + diff --git a/mcs/tools/mdoc/Test/en.expected-dropns-classic-v1/index.xml b/mcs/tools/mdoc/Test/en.expected-dropns-classic-v1/index.xml new file mode 100644 index 00000000000..edacc723f54 --- /dev/null +++ b/mcs/tools/mdoc/Test/en.expected-dropns-classic-v1/index.xml @@ -0,0 +1,22 @@ + + + + + + System.Diagnostics.Debuggable(System.Diagnostics.DebuggableAttribute+DebuggingModes.IgnoreSymbolStoreSequencePoints) + + + System.Runtime.CompilerServices.RuntimeCompatibility(WrapNonExceptionThrows=true) + + + + + To be added. + To be added. + + + + + + DocTest-DropNS-classic + diff --git a/mcs/tools/mdoc/Test/en.expected-dropns-classic-v1/ns-MyFramework.MyNamespace.xml b/mcs/tools/mdoc/Test/en.expected-dropns-classic-v1/ns-MyFramework.MyNamespace.xml new file mode 100644 index 00000000000..74df75af20b --- /dev/null +++ b/mcs/tools/mdoc/Test/en.expected-dropns-classic-v1/ns-MyFramework.MyNamespace.xml @@ -0,0 +1,6 @@ + + + To be added. + To be added. + + diff --git a/mcs/tools/mdoc/Test/en.expected-dropns-classic-withsecondary/MyFramework.MyNamespace/MyClass.xml b/mcs/tools/mdoc/Test/en.expected-dropns-classic-withsecondary/MyFramework.MyNamespace/MyClass.xml new file mode 100644 index 00000000000..e3cda6d9d99 --- /dev/null +++ b/mcs/tools/mdoc/Test/en.expected-dropns-classic-withsecondary/MyFramework.MyNamespace/MyClass.xml @@ -0,0 +1,80 @@ + + + + + DocTest-DropNS-classic + 0.0.0.0 + + + DocTest-DropNS-unified + 0.0.0.0 + + + System.Object + + + + To be added. + To be added. + + + + + + Constructor + + 0.0.0.0 + + + 0.0.0.0 + + + + To be added. + To be added. + + + + + + Method + + 0.0.0.0 + + + 0.0.0.0 + + + System.Single + + + + + + To be added. + To be added. + To be added. + To be added. + + + + + + Property + + 0.0.0.0 + + + 0.0.0.0 + + + System.String + + + To be added. + To be added. + To be added. + + + + diff --git a/mcs/tools/mdoc/Test/en.expected-dropns-classic-withsecondary/MyFramework.MyOtherNamespace/MyOtherClass.xml b/mcs/tools/mdoc/Test/en.expected-dropns-classic-withsecondary/MyFramework.MyOtherNamespace/MyOtherClass.xml new file mode 100644 index 00000000000..a178fc47d6e --- /dev/null +++ b/mcs/tools/mdoc/Test/en.expected-dropns-classic-withsecondary/MyFramework.MyOtherNamespace/MyOtherClass.xml @@ -0,0 +1,67 @@ + + + + + DocTest-DropNS-classic-secondary + 0.0.0.0 + + + System.Object + + + + To be added. + To be added. + + + + + + Constructor + + 0.0.0.0 + + + + To be added. + To be added. + + + + + + Method + + 0.0.0.0 + + + System.Single + + + + + + To be added. + To be added. + To be added. + To be added. + + + + + + Property + + 0.0.0.0 + + + System.String + + + To be added. + To be added. + To be added. + + + + diff --git a/mcs/tools/mdoc/Test/en.expected-dropns-classic-withsecondary/index.xml b/mcs/tools/mdoc/Test/en.expected-dropns-classic-withsecondary/index.xml new file mode 100644 index 00000000000..d0fb593627f --- /dev/null +++ b/mcs/tools/mdoc/Test/en.expected-dropns-classic-withsecondary/index.xml @@ -0,0 +1,35 @@ + + + + + + System.Diagnostics.Debuggable(System.Diagnostics.DebuggableAttribute+DebuggingModes.IgnoreSymbolStoreSequencePoints) + + + System.Runtime.CompilerServices.RuntimeCompatibility(WrapNonExceptionThrows=true) + + + + + + + System.Diagnostics.Debuggable(System.Diagnostics.DebuggableAttribute+DebuggingModes.IgnoreSymbolStoreSequencePoints) + + + System.Runtime.CompilerServices.RuntimeCompatibility(WrapNonExceptionThrows=true) + + + + + To be added. + To be added. + + + + + + + + + Untitled + diff --git a/mcs/tools/mdoc/Test/en.expected-dropns-classic-withsecondary/ns-MyFramework.MyNamespace.xml b/mcs/tools/mdoc/Test/en.expected-dropns-classic-withsecondary/ns-MyFramework.MyNamespace.xml new file mode 100644 index 00000000000..74df75af20b --- /dev/null +++ b/mcs/tools/mdoc/Test/en.expected-dropns-classic-withsecondary/ns-MyFramework.MyNamespace.xml @@ -0,0 +1,6 @@ + + + To be added. + To be added. + + diff --git a/mcs/tools/mdoc/Test/en.expected-dropns-classic-withsecondary/ns-MyFramework.MyOtherNamespace.xml b/mcs/tools/mdoc/Test/en.expected-dropns-classic-withsecondary/ns-MyFramework.MyOtherNamespace.xml new file mode 100644 index 00000000000..8bdef1c7778 --- /dev/null +++ b/mcs/tools/mdoc/Test/en.expected-dropns-classic-withsecondary/ns-MyFramework.MyOtherNamespace.xml @@ -0,0 +1,6 @@ + + + To be added. + To be added. + + diff --git a/mcs/tools/mdoc/Test/en.expected-internal-interface/MyNamespace/MyClass.xml b/mcs/tools/mdoc/Test/en.expected-internal-interface/MyNamespace/MyClass.xml new file mode 100644 index 00000000000..614b7b7d59d --- /dev/null +++ b/mcs/tools/mdoc/Test/en.expected-internal-interface/MyNamespace/MyClass.xml @@ -0,0 +1,63 @@ + + + + + DocTest-InternalInterface + 0.0.0.0 + + + System.Object + + + + To be added. + To be added. + + + + + + Constructor + + 0.0.0.0 + + + + To be added. + To be added. + + + + + + Property + + 0.0.0.0 + + + System.String + + + To be added. + To be added. + To be added. + + + + + + Method + + 0.0.0.0 + + + System.Void + + + + To be added. + To be added. + + + + diff --git a/mcs/tools/mdoc/Test/en.expected-internal-interface/index.xml b/mcs/tools/mdoc/Test/en.expected-internal-interface/index.xml new file mode 100644 index 00000000000..5b49f3c71d2 --- /dev/null +++ b/mcs/tools/mdoc/Test/en.expected-internal-interface/index.xml @@ -0,0 +1,22 @@ + + + + + + System.Diagnostics.Debuggable(System.Diagnostics.DebuggableAttribute+DebuggingModes.IgnoreSymbolStoreSequencePoints) + + + System.Runtime.CompilerServices.RuntimeCompatibility(WrapNonExceptionThrows=true) + + + + + To be added. + To be added. + + + + + + DocTest-InternalInterface + diff --git a/mcs/tools/mdoc/Test/en.expected-internal-interface/ns-MyNamespace.xml b/mcs/tools/mdoc/Test/en.expected-internal-interface/ns-MyNamespace.xml new file mode 100644 index 00000000000..bd8d43168a3 --- /dev/null +++ b/mcs/tools/mdoc/Test/en.expected-internal-interface/ns-MyNamespace.xml @@ -0,0 +1,6 @@ + + + To be added. + To be added. + + diff --git a/mcs/tools/mkbundle/mkbundle.cs b/mcs/tools/mkbundle/mkbundle.cs index f13ce63d029..6e118995377 100755 --- a/mcs/tools/mkbundle/mkbundle.cs +++ b/mcs/tools/mkbundle/mkbundle.cs @@ -715,9 +715,14 @@ static int Execute (string cmdLine) if (use_dos2unix == null) { use_dos2unix = false; try { - var dos2unix = Process.Start ("dos2unix"); + var info = new ProcessStartInfo ("dos2unix"); + info.CreateNoWindow = true; + info.RedirectStandardInput = true; + info.UseShellExecute = false; + var dos2unix = Process.Start (info); dos2unix.StandardInput.WriteLine ("aaa"); dos2unix.StandardInput.WriteLine ("\u0004"); + dos2unix.StandardInput.Close (); dos2unix.WaitForExit (); if (dos2unix.ExitCode == 0) use_dos2unix = true; diff --git a/mcs/tools/security/Makefile b/mcs/tools/security/Makefile index c9baa67ccfe..ba771b51660 100644 --- a/mcs/tools/security/Makefile +++ b/mcs/tools/security/Makefile @@ -6,7 +6,7 @@ include ../../build/rules.make LOCAL_MCS_FLAGS = /lib:$(topdir)/class/lib/$(PROFILE) -r:Mono.Security.dll SECURITY_PROGRAMS = secutil.exe cert2spc.exe sn.exe makecert.exe chktrust.exe crlupdate.exe \ - signcode.exe setreg.exe certmgr.exe caspol.exe permview.exe mozroots.exe + signcode.exe setreg.exe certmgr.exe caspol.exe permview.exe mozroots.exe cert-sync.exe SECURITY_PROGRAMS_2_0 = httpcfg.exe HELPER_SOURCES = AssemblyInfo.cs $(topdir)/build/common/Consts.cs diff --git a/mcs/tools/security/cert-sync.cs b/mcs/tools/security/cert-sync.cs new file mode 100644 index 00000000000..44280675dd1 --- /dev/null +++ b/mcs/tools/security/cert-sync.cs @@ -0,0 +1,226 @@ +// +// cert-sync.cs: Import the root certificates from Linux SSL store into Mono +// +// Authors: +// Sebastien Pouliot +// Jo Shields +// +// Copyright (C) 2005 Novell, Inc (http://www.novell.com) +// Copyright (C) 2014 Xamarin, Inc (http://www.xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections; +using System.IO; +using System.Net; +using System.Reflection; +using System.Security.Cryptography; +using System.Text; + +using Mono.Security.X509; + +[assembly: AssemblyTitle ("Linux Cert Store Sync")] +[assembly: AssemblyDescription ("Synchronize local certs with certs from local Linux trust store.")] + +namespace Mono.Tools +{ + + class CertSync + { + + static string inputFile; + static bool quiet; + + static X509Certificate DecodeCertificate (string s) + { + byte[] rawdata = Convert.FromBase64String (s); + return new X509Certificate (rawdata); + } + + static Stream GetFile () + { + try { + if (inputFile != null) { + return File.OpenRead (inputFile); + } else { + return null; + } + } catch { + return null; + } + } + + static X509CertificateCollection DecodeCollection () + { + X509CertificateCollection roots = new X509CertificateCollection (); + StringBuilder sb = new StringBuilder (); + bool processing = false; + + using (Stream s = GetFile ()) { + if (s == null) { + WriteLine ("Couldn't retrieve the file using the supplied information."); + return null; + } + + StreamReader sr = new StreamReader (s); + while (true) { + string line = sr.ReadLine (); + if (line == null) + break; + + if (processing) { + if (line.StartsWith ("-----END CERTIFICATE-----")) { + processing = false; + X509Certificate root = DecodeCertificate (sb.ToString ()); + roots.Add (root); + + sb = new StringBuilder (); + continue; + } + sb.Append (line); + } else { + processing = line.StartsWith ("-----BEGIN CERTIFICATE-----"); + } + } + return roots; + } + } + + static int Process () + { + X509CertificateCollection roots = DecodeCollection (); + if (roots == null) { + return 1; + } else if (roots.Count == 0) { + WriteLine ("No certificates were found."); + return 0; + } + + X509Stores stores = (X509StoreManager.LocalMachine); + X509CertificateCollection trusted = stores.TrustedRoot.Certificates; + int additions = 0; + WriteLine ("I already trust {0}, your new list has {1}", trusted.Count, roots.Count); + foreach (X509Certificate root in roots) { + if (!trusted.Contains (root)) { + try { + stores.TrustedRoot.Import (root); + WriteLine ("Certificate added: {0}", root.SubjectName); + } catch { + WriteLine ("Warning: Could not import {0}"); + } + additions++; + } + } + if (additions > 0) + WriteLine ("{0} new root certificates were added to your trust store.", additions); + + X509CertificateCollection removed = new X509CertificateCollection (); + foreach (X509Certificate trust in trusted) { + if (!roots.Contains (trust)) { + removed.Add (trust); + } + } + if (removed.Count > 0) { + WriteLine ("{0} previously trusted certificates were removed.", removed.Count); + + foreach (X509Certificate old in removed) { + stores.TrustedRoot.Remove (old); + WriteLine ("Certificate removed: {0}", old.SubjectName); + } + } + WriteLine ("Import process completed."); + return 0; + } + + static string Thumbprint (string algorithm, X509Certificate certificate) + { + HashAlgorithm hash = HashAlgorithm.Create (algorithm); + byte[] digest = hash.ComputeHash (certificate.RawData); + return BitConverter.ToString (digest); + } + + static bool ParseOptions (string[] args) + { + if (args.Length < 1) + return false; + + for (int i = 0; i < args.Length - 1; i++) { + switch (args [i]) { + case "--quiet": + quiet = true; + break; + default: + WriteLine ("Unknown option '{0}'."); + return false; + } + } + inputFile = args [args.Length - 1]; + if (!File.Exists (inputFile)) { + WriteLine ("Unknown option or file not found '{0}'."); + return false; + } + return true; + } + + static void Header () + { + Console.WriteLine (new AssemblyInfo ().ToString ()); + } + + static void Help () + { + Console.WriteLine ("Usage: cert-sync [--quiet] system-ca-bundle.crt"); + Console.WriteLine ("Where system-ca-bundle.crt is in PEM format"); + } + + static void WriteLine (string str) + { + if (!quiet) + Console.WriteLine (str); + } + + static void WriteLine (string format, params object[] args) + { + if (!quiet) + Console.WriteLine (format, args); + } + + static int Main (string[] args) + { + try { + if (!ParseOptions (args)) { + Header (); + Help (); + return 1; + } + if (!quiet) { + Header (); + } + return Process (); + } catch (Exception e) { + // ignore quiet on exception + Console.WriteLine ("Error: {0}", e); + return 1; + } + } + } +} \ No newline at end of file diff --git a/mono-core.spec.in b/mono-core.spec.in index 0b7337d05d5..90d0b581219 100644 --- a/mono-core.spec.in +++ b/mono-core.spec.in @@ -4,6 +4,9 @@ %ifnarch %ix86 x86_64 %define llvm no +%endif + +%ifnarch %ix86 x86_64 s390x %define sgen no %endif @@ -16,10 +19,14 @@ Version: @VERSION@ Release: 0 Source0: mono-%{version}.tar.bz2 BuildRequires: bison +%if 0%{?suse_version} BuildRequires: fdupes +BuildRequires: xorg-x11-libX11-devel +%else +BuildRequires: libX11-devel +%endif BuildRequires: gcc-c++ BuildRequires: pkgconfig -BuildRequires: xorg-x11-libX11-devel BuildRequires: zlib-devel %ifnarch ia64 BuildRequires: valgrind-devel @@ -48,7 +55,9 @@ Conflicts: banshee < 1.0 Conflicts: f-spot < 0.4 Conflicts: helix-banshee < 1.0 Conflicts: mono-addins < 0.3.1 +%if 0%{?suse_version} Recommends: libgdiplus0 >= 2.6 +%endif %if %llvm == yes Recommends: libmono-llvm0 = %{version}-%{release} %endif @@ -92,6 +101,7 @@ export CFLAGS=" $RPM_OPT_FLAGS -fno-strict-aliasing" export PATH=/opt/novell/llvm-mono/bin:$PATH %endif %configure \ + --target=%{_host} \ --with-sgen=%{sgen} \ %if %llvm == yes --enable-loadedllvm \ @@ -104,6 +114,7 @@ export PATH=/opt/novell/llvm-mono/bin:$PATH --with-moonlight=no #make # We are not -jN safe! %{?jobs:-j%jobs} # We are now ! +make get-monolite-latest make %{?_smp_mflags} %install @@ -130,7 +141,9 @@ rm -f %buildroot%_prefix/lib/mono/2.0/cilc.exe* ln -s . %buildroot%_prefix%_prefix RPM_BUILD_ROOT=%buildroot%_prefix /usr/lib/rpm/brp-compress rm %buildroot%_prefix%_prefix +%if 0%{?suse_version} %fdupes %buildroot%_prefix +%endif %find_lang mcs %clean diff --git a/mono/arch/amd64/Makefile.am b/mono/arch/amd64/Makefile.am index 3c728263190..47daaaff699 100644 --- a/mono/arch/amd64/Makefile.am +++ b/mono/arch/amd64/Makefile.am @@ -1,7 +1,2 @@ - -AM_CPPFLAGS = $(GLIB_CFLAGS) -I$(top_srcdir) - -noinst_LTLIBRARIES = libmonoarch-amd64.la - -libmonoarch_amd64_la_SOURCES = tramp.c amd64-codegen.h +EXTRA_DIST = amd64-codegen.h diff --git a/mono/arch/amd64/tramp.c b/mono/arch/amd64/tramp.c deleted file mode 100644 index 6dbec93e859..00000000000 --- a/mono/arch/amd64/tramp.c +++ /dev/null @@ -1,1054 +0,0 @@ -/* - * Create trampolines to invoke arbitrary functions. - * - * Copyright (C) Ximian Inc. - * - * Author: - * Zalman Stern - * Based on code by: - * Paolo Molaro (lupus@ximian.com) - * Dietmar Maurer (dietmar@ximian.com) - * - * To understand this code, one will want to the calling convention section of the ABI sepc at: - * http://x86-64.org/abi.pdf - * and the AMD64 architecture docs found at amd.com . - */ - -#include "config.h" -#include -#include -#include "amd64-codegen.h" -#include "mono/metadata/class.h" -#include "mono/metadata/tabledefs.h" -#include "mono/interpreter/interp.h" -#include "mono/metadata/appdomain.h" -#include "mono/metadata/marshal.h" - -/* - * The resulting function takes the form: - * void func (void (*callme)(), void *retval, void *this_obj, stackval *arguments); - */ -#define FUNC_ADDR_POS 8 -#define RETVAL_POS 12 -#define THIS_POS 16 -#define ARGP_POS 20 -#define LOC_POS -4 - -#define ARG_SIZE sizeof (stackval) - -#define MAX_INT_ARG_REGS 6 -#define MAX_FLOAT_ARG_REGS 8 - -// TODO get these right. They are upper bounds anyway, so it doesn't much matter. -#define PUSH_INT_STACK_ARG_SIZE 16 -#define MOVE_INT_REG_ARG_SIZE 16 -#define PUSH_FLOAT_STACK_ARG_SIZE 16 -#define MOVE_FLOAT_REG_ARG_SIZE 16 -#define COPY_STRUCT_STACK_ARG_SIZE 16 - -/* Maps an argument number (starting at 0) to the register it is passed in (if it fits). - * E.g. int foo(int bar, int quux) has the foo arg in RDI and the quux arg in RSI - * There is no such map for floating point args as they go in XMM0-XMM7 in order and thus the - * index is the register number. - */ -static int int_arg_regs[] = { AMD64_RDI, AMD64_RSI, AMD64_RDX, AMD64_RCX, AMD64_R8, AMD64_R9 }; - -/* This next block of code resolves the ABI rules for passing structures in the argument registers. - * These basically amount to "Use up to two registers if they are all integer or all floating point. - * If the structure is bigger than two registers or would be in one integer register and one floating point, - * it is passed in memory instead. - * - * It is possible this code needs to be recursive to be correct in the case when one of the structure members - * is itself a structure. - * - * The 80-bit floating point stuff is ignored. - */ -typedef enum { - ARG_IN_MEMORY, - ARG_IN_INT_REGS, - ARG_IN_FLOAT_REGS -} struct_arg_type; - -static struct_arg_type compute_arg_type(MonoType *type) -{ - guint32 simpletype = type->type; - - switch (simpletype) { - case MONO_TYPE_BOOLEAN: - case MONO_TYPE_CHAR: - case MONO_TYPE_I1: - case MONO_TYPE_U1: - case MONO_TYPE_I2: - case MONO_TYPE_U2: - case MONO_TYPE_I4: - case MONO_TYPE_U4: - case MONO_TYPE_I: - case MONO_TYPE_U: - case MONO_TYPE_PTR: - case MONO_TYPE_SZARRAY: - case MONO_TYPE_CLASS: - case MONO_TYPE_OBJECT: - case MONO_TYPE_STRING: - case MONO_TYPE_I8: - return ARG_IN_INT_REGS; - break; - case MONO_TYPE_VALUETYPE: { - if (type->data.klass->enumtype) - return ARG_IN_INT_REGS; - return ARG_IN_MEMORY; - break; - } - case MONO_TYPE_R4: - case MONO_TYPE_R8: - return ARG_IN_FLOAT_REGS; - break; - default: - g_error ("Can't trampoline 0x%x", type->type); - } - - return ARG_IN_MEMORY; -} - -static struct_arg_type value_type_info(MonoClass *klass, int *native_size, int *regs_used, int *offset1, int *size1, int *offset2, int *size2) -{ - MonoMarshalType *info = mono_marshal_load_type_info (klass); - - *native_size = info->native_size; - - if (info->native_size > 8 || info->num_fields > 2) - { - *regs_used = 0; - *offset1 = -1; - *offset2 = -1; - return ARG_IN_MEMORY; - } - - if (info->num_fields == 1) - { - struct_arg_type result = compute_arg_type(info->fields[0].field->type); - if (result != ARG_IN_MEMORY) - { - *regs_used = 1; - *offset1 = info->fields[0].offset; - *size1 = mono_marshal_type_size (info->fields[0].field->type, info->fields[0].mspec, NULL, 1, 1); - } - else - { - *regs_used = 0; - *offset1 = -1; - } - - *offset2 = -1; - return result; - } - - struct_arg_type result1 = compute_arg_type(info->fields[0].field->type); - struct_arg_type result2 = compute_arg_type(info->fields[0].field->type); - - if (result1 == result2 && result1 != ARG_IN_MEMORY) - { - *regs_used = 2; - *offset1 = info->fields[0].offset; - *size1 = mono_marshal_type_size (info->fields[0].field->type, info->fields[0].mspec, NULL, 1, 1); - *offset2 = info->fields[1].offset; - *size2 = mono_marshal_type_size (info->fields[1].field->type, info->fields[1].mspec, NULL, 1, 1); - return result1; - } - - return ARG_IN_MEMORY; -} - -MonoPIFunc -mono_arch_create_trampoline (MonoMethodSignature *sig, gboolean string_ctor) -{ - unsigned char *p, *code_buffer; - guint32 stack_size = 0, code_size = 50; - guint32 arg_pos, simpletype; - int i; - static GHashTable *cache = NULL; - MonoPIFunc res; - - guint32 int_arg_regs_used = 0; - guint32 float_arg_regs_used = 0; - guint32 next_int_arg_reg = 0; - guint32 next_float_arg_reg = 0; - /* Indicates that the return value is filled in inside the called function. */ - int retval_implicit = 0; - char *arg_in_reg_bitvector; /* A set index by argument number saying if it is in a register - (integer or floating point according to type) */ - - if (!cache) - cache = g_hash_table_new ((GHashFunc)mono_signature_hash, - (GCompareFunc)mono_metadata_signature_equal); - - if ((res = (MonoPIFunc)g_hash_table_lookup (cache, sig))) - return res; - - if (sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->byref && !sig->ret->data.klass->enumtype) { - int_arg_regs_used++; - code_size += MOVE_INT_REG_ARG_SIZE; - } - - if (sig->hasthis) { - int_arg_regs_used++; - code_size += MOVE_INT_REG_ARG_SIZE; - } - - /* Run through stuff to calculate code size and argument bytes that will be pushed on stack (stack_size). */ - for (i = 0; i < sig->param_count; ++i) { - if (sig->params [i]->byref) - simpletype = MONO_TYPE_PTR; - else - simpletype = sig->params [i]->type; -enum_calc_size: - switch (simpletype) { - case MONO_TYPE_BOOLEAN: - case MONO_TYPE_CHAR: - case MONO_TYPE_I1: - case MONO_TYPE_U1: - case MONO_TYPE_I2: - case MONO_TYPE_U2: - case MONO_TYPE_I4: - case MONO_TYPE_U4: - case MONO_TYPE_I: - case MONO_TYPE_U: - case MONO_TYPE_PTR: - case MONO_TYPE_SZARRAY: - case MONO_TYPE_CLASS: - case MONO_TYPE_OBJECT: - case MONO_TYPE_STRING: - case MONO_TYPE_I8: - if (int_arg_regs_used++ > MAX_INT_ARG_REGS) { - stack_size += 8; - code_size += PUSH_INT_STACK_ARG_SIZE; - } - else - code_size += MOVE_INT_REG_ARG_SIZE; - break; - case MONO_TYPE_VALUETYPE: { - int size; - int arg_type; - int regs_used; - int offset1; - int size1; - int offset2; - int size2; - - if (sig->params [i]->data.klass->enumtype) { - simpletype = sig->params [i]->data.klass->enum_basetype->type; - goto enum_calc_size; - } - - arg_type = value_type_info(sig->params [i]->data.klass, &size, ®s_used, &offset1, &size1, &offset2, &size2); - if (arg_type == ARG_IN_INT_REGS && - (int_arg_regs_used + regs_used) <= MAX_INT_ARG_REGS) - { - code_size += MOVE_INT_REG_ARG_SIZE; - int_arg_regs_used += regs_used; - break; - } - - if (arg_type == ARG_IN_FLOAT_REGS && - (float_arg_regs_used + regs_used) <= MAX_FLOAT_ARG_REGS) - { - code_size += MOVE_FLOAT_REG_ARG_SIZE; - float_arg_regs_used += regs_used; - break; - } - - /* Else item is in memory. */ - - stack_size += size + 7; - stack_size &= ~7; - code_size += COPY_STRUCT_STACK_ARG_SIZE; - - break; - } - case MONO_TYPE_R4: - case MONO_TYPE_R8: - if (float_arg_regs_used++ > MAX_FLOAT_ARG_REGS) { - stack_size += 8; - code_size += PUSH_FLOAT_STACK_ARG_SIZE; - } - else - code_size += MOVE_FLOAT_REG_ARG_SIZE; - break; - default: - g_error ("Can't trampoline 0x%x", sig->params [i]->type); - } - } - /* - * FIXME: take into account large return values. - * (Comment carried over from IA32 code. Not sure what it means :-) - */ - - code_buffer = p = alloca (code_size); - - /* - * Standard function prolog. - */ - amd64_push_reg (p, AMD64_RBP); - amd64_mov_reg_reg (p, AMD64_RBP, AMD64_RSP, 8); - /* - * and align to 16 byte boundary... - */ - - if (sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->byref) { - MonoClass *klass = sig->ret->data.klass; - if (!klass->enumtype) { - retval_implicit = 1; - } - } - - if (sig->ret->byref || string_ctor || !(retval_implicit || sig->ret->type == MONO_TYPE_VOID)) { - /* Push the retval register so it is saved across the call. It will be addressed via RBP later. */ - amd64_push_reg (p, AMD64_RSI); - stack_size += 8; - } - - /* Ensure stack is 16 byte aligned when entering called function as required by calling convention. - * Getting this wrong results in a general protection fault on an SSE load or store somewhere in the - * code called under the trampoline. - */ - if ((stack_size & 15) != 0) - amd64_alu_reg_imm (p, X86_SUB, AMD64_RSP, 16 - (stack_size & 15)); - - /* - * On entry to generated function: - * RDI has target function address - * RSI has return value location address - * RDX has this pointer address - * RCX has the pointer to the args array. - * - * Inside the stub function: - * R10 holds the pointer to the args - * R11 holds the target function address. - * The return value address is pushed on the stack. - * The this pointer is moved into the first arg register at the start. - * - * Optimization note: we could keep the args pointer in RCX and then - * load over itself at the end. Ditto the callee addres could be left in RDI in some cases. - */ - - /* Move args pointer to temp register. */ - amd64_mov_reg_reg (p, AMD64_R10, AMD64_RCX, 8); - amd64_mov_reg_reg (p, AMD64_R11, AMD64_RDI, 8); - - /* First args register gets return value pointer, if need be. - * Note that "byref" equal true means the called function returns a pointer. - */ - if (retval_implicit) { - amd64_mov_reg_reg (p, int_arg_regs[next_int_arg_reg], AMD64_RSI, 8); - next_int_arg_reg++; - } - - /* this pointer goes in next args register. */ - if (sig->hasthis) { - amd64_mov_reg_reg (p, int_arg_regs[next_int_arg_reg], AMD64_RDX, 8); - next_int_arg_reg++; - } - - /* - * Generate code to handle arguments in registers. Stack arguments will happen in a loop after this. - */ - arg_in_reg_bitvector = (char *)alloca((sig->param_count + 7) / 8); - memset(arg_in_reg_bitvector, 0, (sig->param_count + 7) / 8); - - /* First, load all the arguments that are passed in registers into the appropriate registers. - * Below there is another loop to handle arguments passed on the stack. - */ - for (i = 0; i < sig->param_count; i++) { - arg_pos = ARG_SIZE * i; - - if (sig->params [i]->byref) - simpletype = MONO_TYPE_PTR; - else - simpletype = sig->params [i]->type; -enum_marshal: - switch (simpletype) { - case MONO_TYPE_BOOLEAN: - case MONO_TYPE_I1: - case MONO_TYPE_U1: - case MONO_TYPE_I2: - case MONO_TYPE_U2: - case MONO_TYPE_CHAR: - case MONO_TYPE_I4: - case MONO_TYPE_U4: - case MONO_TYPE_I: - case MONO_TYPE_U: - case MONO_TYPE_PTR: - case MONO_TYPE_OBJECT: - case MONO_TYPE_STRING: - case MONO_TYPE_SZARRAY: - case MONO_TYPE_I8: - case MONO_TYPE_U8: - case MONO_TYPE_CLASS: - if (next_int_arg_reg < MAX_INT_ARG_REGS) { - amd64_mov_reg_membase (p, int_arg_regs[next_int_arg_reg], AMD64_R10, arg_pos, 8); - next_int_arg_reg++; - arg_in_reg_bitvector[i >> 3] |= (1 << (i & 7)); - } - break; - case MONO_TYPE_R4: - if (next_float_arg_reg < MAX_FLOAT_ARG_REGS) { - amd64_movss_reg_membase (p, next_float_arg_reg, AMD64_R10, arg_pos); - next_float_arg_reg++; - arg_in_reg_bitvector[i >> 3] |= (1 << (i & 7)); - } - break; - case MONO_TYPE_R8: - if (next_float_arg_reg < MAX_FLOAT_ARG_REGS) { - amd64_movsd_reg_membase (p, next_float_arg_reg, AMD64_R10, arg_pos); - next_float_arg_reg++; - arg_in_reg_bitvector[i >> 3] |= (1 << (i & 7)); - } - break; - case MONO_TYPE_VALUETYPE: { - if (!sig->params [i]->data.klass->enumtype) { - int size; - int arg_type; - int regs_used; - int offset1; - int size1; - int offset2; - int size2; - - arg_type = value_type_info(sig->params [i]->data.klass, &size, ®s_used, &offset1, &size1, &offset2, &size2); - - if (arg_type == ARG_IN_INT_REGS && - (next_int_arg_reg + regs_used) <= MAX_INT_ARG_REGS) - { - amd64_mov_reg_membase (p, int_arg_regs[next_int_arg_reg], AMD64_R10, arg_pos + offset1, size1); - next_int_arg_reg++; - if (regs_used > 1) - { - amd64_mov_reg_membase (p, int_arg_regs[next_int_arg_reg], AMD64_R10, arg_pos + offset2, size2); - next_int_arg_reg++; - } - arg_in_reg_bitvector[i >> 3] |= (1 << (i & 7)); - break; - } - - if (arg_type == ARG_IN_FLOAT_REGS && - (next_float_arg_reg + regs_used) <= MAX_FLOAT_ARG_REGS) - { - if (size1 == 4) - amd64_movss_reg_membase (p, next_float_arg_reg, AMD64_R10, arg_pos + offset1); - else - amd64_movsd_reg_membase (p, next_float_arg_reg, AMD64_R10, arg_pos + offset1); - next_float_arg_reg++; - - if (regs_used > 1) - { - if (size2 == 4) - amd64_movss_reg_membase (p, next_float_arg_reg, AMD64_R10, arg_pos + offset2); - else - amd64_movsd_reg_membase (p, next_float_arg_reg, AMD64_R10, arg_pos + offset2); - next_float_arg_reg++; - } - arg_in_reg_bitvector[i >> 3] |= (1 << (i & 7)); - break; - } - - /* Structs in memory are handled in the next loop. */ - } else { - /* it's an enum value */ - simpletype = sig->params [i]->data.klass->enum_basetype->type; - goto enum_marshal; - } - break; - } - default: - g_error ("Can't trampoline 0x%x", sig->params [i]->type); - } - } - - /* Handle stack arguments, pushing the rightmost argument first. */ - for (i = sig->param_count; i > 0; --i) { - arg_pos = ARG_SIZE * (i - 1); - if (sig->params [i - 1]->byref) - simpletype = MONO_TYPE_PTR; - else - simpletype = sig->params [i - 1]->type; -enum_marshal2: - switch (simpletype) { - case MONO_TYPE_BOOLEAN: - case MONO_TYPE_I1: - case MONO_TYPE_U1: - case MONO_TYPE_I2: - case MONO_TYPE_U2: - case MONO_TYPE_CHAR: - case MONO_TYPE_I4: - case MONO_TYPE_U4: - case MONO_TYPE_I: - case MONO_TYPE_U: - case MONO_TYPE_PTR: - case MONO_TYPE_OBJECT: - case MONO_TYPE_STRING: - case MONO_TYPE_SZARRAY: - case MONO_TYPE_I8: - case MONO_TYPE_U8: - case MONO_TYPE_CLASS: - if ((arg_in_reg_bitvector[(i - 1) >> 3] & (1 << ((i - 1) & 7))) == 0) { - amd64_push_membase (p, AMD64_R10, arg_pos); - } - break; - case MONO_TYPE_R4: - if ((arg_in_reg_bitvector[(i - 1) >> 3] & (1 << ((i - 1) & 7))) == 0) { - amd64_push_membase (p, AMD64_R10, arg_pos); - } - break; - case MONO_TYPE_R8: - if ((arg_in_reg_bitvector[(i - 1) >> 3] & (1 << ((i - 1) & 7))) == 0) { - amd64_push_membase (p, AMD64_R10, arg_pos); - } - break; - case MONO_TYPE_VALUETYPE: - if (!sig->params [i - 1]->data.klass->enumtype) { - if ((arg_in_reg_bitvector[(i - 1) >> 3] & (1 << ((i - 1) & 7))) == 0) - { - int ss = mono_class_native_size (sig->params [i - 1]->data.klass, NULL); - ss += 7; - ss &= ~7; - - amd64_alu_reg_imm(p, X86_SUB, AMD64_RSP, ss); - /* Count register */ - amd64_mov_reg_imm(p, AMD64_RCX, ss); - /* Source register */ - amd64_lea_membase(p, AMD64_RSI, AMD64_R10, arg_pos); - /* Dest register */ - amd64_mov_reg_reg(p, AMD64_RDI, AMD64_RSP, 8); - - /* AMD64 calling convention guarantees direction flag is clear at call boundary. */ - x86_prefix(p, AMD64_REX(AMD64_REX_W)); - x86_prefix(p, X86_REP_PREFIX); - x86_movsb(p); - } - } else { - /* it's an enum value */ - simpletype = sig->params [i - 1]->data.klass->enum_basetype->type; - goto enum_marshal2; - } - break; - default: - g_error ("Can't trampoline 0x%x", sig->params [i - 1]->type); - } - } - - /* TODO: Set RAL to number of XMM registers used in case this is a varags function? */ - - /* - * Insert call to function - */ - amd64_call_reg (p, AMD64_R11); - - if (sig->ret->byref || string_ctor || !(retval_implicit || sig->ret->type == MONO_TYPE_VOID)) { - amd64_mov_reg_membase(p, AMD64_RSI, AMD64_RBP, -8, SIZEOF_VOID_P); - } - /* - * Handle retval. - * Small integer and pointer values are in EAX. - * Long integers are in EAX:EDX. - * FP values are on the FP stack. - */ - - if (sig->ret->byref || string_ctor) { - simpletype = MONO_TYPE_PTR; - } else { - simpletype = sig->ret->type; - } - enum_retvalue: - switch (simpletype) { - case MONO_TYPE_BOOLEAN: - case MONO_TYPE_I1: - case MONO_TYPE_U1: - amd64_mov_regp_reg (p, AMD64_RSI, X86_EAX, 1); - break; - case MONO_TYPE_CHAR: - case MONO_TYPE_I2: - case MONO_TYPE_U2: - amd64_mov_regp_reg (p, AMD64_RSI, X86_EAX, 2); - break; - case MONO_TYPE_I4: - case MONO_TYPE_U4: - case MONO_TYPE_I: - case MONO_TYPE_U: - case MONO_TYPE_CLASS: - case MONO_TYPE_OBJECT: - case MONO_TYPE_SZARRAY: - case MONO_TYPE_ARRAY: - case MONO_TYPE_STRING: - case MONO_TYPE_PTR: - amd64_mov_regp_reg (p, AMD64_RSI, X86_EAX, 8); - break; - case MONO_TYPE_R4: - amd64_movss_regp_reg (p, AMD64_RSI, AMD64_XMM0); - break; - case MONO_TYPE_R8: - amd64_movsd_regp_reg (p, AMD64_RSI, AMD64_XMM0); - break; - case MONO_TYPE_I8: - amd64_mov_regp_reg (p, AMD64_RSI, X86_EAX, 8); - break; - case MONO_TYPE_VALUETYPE: { - int size; - int arg_type; - int regs_used; - int offset1; - int size1; - int offset2; - int size2; - - if (sig->ret->data.klass->enumtype) { - simpletype = sig->ret->data.klass->enum_basetype->type; - goto enum_retvalue; - } - - arg_type = value_type_info(sig->params [i]->data.klass, &size, ®s_used, &offset1, &size1, &offset2, &size2); - - if (arg_type == ARG_IN_INT_REGS) - { - amd64_mov_membase_reg (p, AMD64_RSI, offset1, AMD64_RAX, size1); - if (regs_used > 1) - amd64_mov_membase_reg (p, AMD64_RSI, offset2, AMD64_RDX, size2); - break; - } - - if (arg_type == ARG_IN_FLOAT_REGS) - { - if (size1 == 4) - amd64_movss_membase_reg (p, AMD64_RSI, offset1, AMD64_XMM0); - else - amd64_movsd_membase_reg (p, AMD64_RSI, offset1, AMD64_XMM0); - - if (regs_used > 1) - { - if (size2 == 4) - amd64_movss_membase_reg (p, AMD64_RSI, offset2, AMD64_XMM1); - else - amd64_movsd_membase_reg (p, AMD64_RSI, offset2, AMD64_XMM1); - } - break; - } - - /* Else result should have been stored in place already. */ - break; - } - case MONO_TYPE_VOID: - break; - default: - g_error ("Can't handle as return value 0x%x", sig->ret->type); - } - - /* - * Standard epilog. - */ - amd64_leave (p); - amd64_ret (p); - - g_assert (p - code_buffer < code_size); - res = (MonoPIFunc)g_memdup (code_buffer, p - code_buffer); - - g_hash_table_insert (cache, sig, res); - - return res; -} - -/* - * Returns a pointer to a native function that can be used to - * call the specified method. - * The function created will receive the arguments according - * to the call convention specified in the method. - * This function works by creating a MonoInvocation structure, - * filling the fields in and calling ves_exec_method on it. - * Still need to figure out how to handle the exception stuff - * across the managed/unmanaged boundary. - */ -void * -mono_arch_create_method_pointer (MonoMethod *method) -{ - MonoMethodSignature *sig; - MonoJitInfo *ji; - unsigned char *p, *code_buffer; - guint32 simpletype; - gint32 local_size; - gint32 stackval_pos; - gint32 mono_invocation_pos; - int i, cpos; - int *vtbuf; - int *rbpoffsets; - int int_arg_regs_used = 0; - int float_arg_regs_used = 0; - int stacked_args_size = 0; /* bytes of register passed arguments pushed on stack for safe keeping. Used to get alignment right. */ - int next_stack_arg_rbp_offset = 16; - int retval_ptr_rbp_offset = 0; - int this_reg = -1; /* Remember register this ptr is in. */ - - /* - * If it is a static P/Invoke method, we can just return the pointer - * to the method implementation. - */ - if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL && ((MonoMethodPInvoke*) method)->addr) { - ji = g_new0 (MonoJitInfo, 1); - ji->method = method; - ji->code_size = 1; - ji->code_start = ((MonoMethodPInvoke*) method)->addr; - - mono_jit_info_table_add (mono_get_root_domain (), ji); - return ((MonoMethodPInvoke*) method)->addr; - } - - sig = method->signature; - - code_buffer = p = alloca (512); /* FIXME: check for overflows... */ - vtbuf = alloca (sizeof(int)*sig->param_count); - rbpoffsets = alloca (sizeof(int)*sig->param_count); - - - /* - * Standard function prolog. - */ - amd64_push_reg (p, AMD64_RBP); - amd64_mov_reg_reg (p, AMD64_RBP, AMD64_RSP, 8); - - /* If there is an implicit return value pointer in the first args reg, save it now so - * the result can be stored through the pointer at the end. - */ - if (sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->byref && !sig->ret->data.klass->enumtype) - { - amd64_push_reg (p, int_arg_regs[int_arg_regs_used]); - int_arg_regs_used++; - stacked_args_size += 8; - retval_ptr_rbp_offset = -stacked_args_size; - } - - /* - * If there is a this pointer, remember the number of the register it is in. - */ - if (sig->hasthis) { - this_reg = int_arg_regs[int_arg_regs_used++]; - } - - /* Put all arguments passed in registers on the stack. - * Record offsets from RBP to each argument. - */ - cpos = 0; - - for (i = 0; i < sig->param_count; i++) { - if (sig->params [i]->byref) - simpletype = MONO_TYPE_PTR; - else - simpletype = sig->params [i]->type; -enum_calc_size: - switch (simpletype) { - case MONO_TYPE_BOOLEAN: - case MONO_TYPE_CHAR: - case MONO_TYPE_I1: - case MONO_TYPE_U1: - case MONO_TYPE_I2: - case MONO_TYPE_U2: - case MONO_TYPE_I4: - case MONO_TYPE_U4: - case MONO_TYPE_I: - case MONO_TYPE_U: - case MONO_TYPE_PTR: - case MONO_TYPE_SZARRAY: - case MONO_TYPE_CLASS: - case MONO_TYPE_OBJECT: - case MONO_TYPE_STRING: - case MONO_TYPE_I8: - if (int_arg_regs_used < MAX_INT_ARG_REGS) { - amd64_push_reg (p, int_arg_regs[int_arg_regs_used]); - int_arg_regs_used++; - stacked_args_size += 8; - rbpoffsets[i] = -stacked_args_size; - } - else - { - rbpoffsets[i] = next_stack_arg_rbp_offset; - next_stack_arg_rbp_offset += 8; - } - break; - case MONO_TYPE_VALUETYPE: { - if (sig->params [i]->data.klass->enumtype) { - simpletype = sig->params [i]->data.klass->enum_basetype->type; - goto enum_calc_size; - } - else - { - int size; - int arg_type; - int regs_used; - int offset1; - int size1; - int offset2; - int size2; - - arg_type = value_type_info(sig->params [i]->data.klass, &size, ®s_used, &offset1, &size1, &offset2, &size2); - - if (arg_type == ARG_IN_INT_REGS && - (int_arg_regs_used + regs_used) <= MAX_INT_ARG_REGS) - { - amd64_alu_reg_imm (p, X86_SUB, AMD64_RSP, size); - stacked_args_size += size; - rbpoffsets[i] = stacked_args_size; - - amd64_mov_reg_membase (p, int_arg_regs[int_arg_regs_used], AMD64_RSP, offset1, size1); - int_arg_regs_used++; - if (regs_used > 1) - { - amd64_mov_reg_membase (p, int_arg_regs[int_arg_regs_used], AMD64_RSP, offset2, size2); - int_arg_regs_used++; - } - break; - } - - if (arg_type == ARG_IN_FLOAT_REGS && - (float_arg_regs_used + regs_used) <= MAX_FLOAT_ARG_REGS) - { - amd64_alu_reg_imm (p, X86_SUB, AMD64_RSP, size); - stacked_args_size += size; - rbpoffsets[i] = stacked_args_size; - - if (size1 == 4) - amd64_movss_reg_membase (p, float_arg_regs_used, AMD64_RSP, offset1); - else - amd64_movsd_reg_membase (p, float_arg_regs_used, AMD64_RSP, offset1); - float_arg_regs_used++; - - if (regs_used > 1) - { - if (size2 == 4) - amd64_movss_reg_membase (p, float_arg_regs_used, AMD64_RSP, offset2); - else - amd64_movsd_reg_membase (p, float_arg_regs_used, AMD64_RSP, offset2); - float_arg_regs_used++; - } - break; - } - - rbpoffsets[i] = next_stack_arg_rbp_offset; - next_stack_arg_rbp_offset += size; - } - break; - } - case MONO_TYPE_R4: - if (float_arg_regs_used < MAX_FLOAT_ARG_REGS) { - amd64_alu_reg_imm (p, X86_SUB, AMD64_RSP, 8); - amd64_movss_regp_reg (p, AMD64_RSP, float_arg_regs_used); - float_arg_regs_used++; - stacked_args_size += 8; - rbpoffsets[i] = -stacked_args_size; - } - else - { - rbpoffsets[i] = next_stack_arg_rbp_offset; - next_stack_arg_rbp_offset += 8; - } - break; - case MONO_TYPE_R8: - stacked_args_size += 8; - if (float_arg_regs_used < MAX_FLOAT_ARG_REGS) { - amd64_alu_reg_imm (p, X86_SUB, AMD64_RSP, 8); - amd64_movsd_regp_reg (p, AMD64_RSP, float_arg_regs_used); - float_arg_regs_used++; - stacked_args_size += 8; - rbpoffsets[i] = -stacked_args_size; - } - else - { - rbpoffsets[i] = next_stack_arg_rbp_offset; - next_stack_arg_rbp_offset += 8; - } - break; - default: - g_error ("Can't trampoline 0x%x", sig->params [i]->type); - } - } - - local_size = sizeof (MonoInvocation) + sizeof (stackval) * (sig->param_count + 1) + stacked_args_size; - - local_size += 15; - local_size &= ~15; - - stackval_pos = -local_size; - mono_invocation_pos = stackval_pos + sizeof (stackval) * (sig->param_count + 1); - - /* stacked_args_size has already been pushed onto the stack. Make room for the rest of it. */ - amd64_alu_reg_imm (p, X86_SUB, AMD64_RSP, local_size - stacked_args_size); - - /* Be careful not to trash any arg regs before saving this_reg to MonoInvocation structure below. */ - - /* - * Initialize MonoInvocation fields, first the ones known now. - */ - amd64_alu_reg_reg (p, X86_XOR, AMD64_RAX, AMD64_RAX); - amd64_mov_membase_reg (p, AMD64_RBP, (mono_invocation_pos + G_STRUCT_OFFSET (MonoInvocation, ex)), AMD64_RAX, SIZEOF_VOID_P); - amd64_mov_membase_reg (p, AMD64_RBP, (mono_invocation_pos + G_STRUCT_OFFSET (MonoInvocation, ex_handler)), AMD64_RAX, SIZEOF_VOID_P); - amd64_mov_membase_reg (p, AMD64_RBP, (mono_invocation_pos + G_STRUCT_OFFSET (MonoInvocation, parent)), AMD64_RAX, SIZEOF_VOID_P); - /* - * Set the method pointer. - */ - amd64_mov_membase_imm (p, AMD64_RBP, (mono_invocation_pos + G_STRUCT_OFFSET (MonoInvocation, method)), (long)method, SIZEOF_VOID_P); - - /* - * Handle this. - */ - if (sig->hasthis) - amd64_mov_membase_reg(p, AMD64_RBP, (mono_invocation_pos + G_STRUCT_OFFSET (MonoInvocation, obj)), this_reg, SIZEOF_VOID_P); - - /* - * Handle the arguments. stackval_pos is the offset from RBP of the stackval in the MonoInvocation args array . - * arg_pos is the offset from RBP to the incoming arg on the stack. - * We just call stackval_from_data to handle all the (nasty) issues.... - */ - amd64_lea_membase (p, AMD64_RAX, AMD64_RBP, stackval_pos); - amd64_mov_membase_reg (p, AMD64_RBP, (mono_invocation_pos + G_STRUCT_OFFSET (MonoInvocation, stack_args)), AMD64_RAX, SIZEOF_VOID_P); - for (i = 0; i < sig->param_count; ++i) { -/* Need to call stackval_from_data (MonoType *type, stackval *result, char *data, gboolean pinvoke); */ - amd64_mov_reg_imm (p, AMD64_R11, stackval_from_data); - amd64_mov_reg_imm (p, int_arg_regs[0], sig->params[i]); - amd64_lea_membase (p, int_arg_regs[1], AMD64_RBP, stackval_pos); - amd64_lea_membase (p, int_arg_regs[2], AMD64_RBP, rbpoffsets[i]); - amd64_mov_reg_imm (p, int_arg_regs[3], sig->pinvoke); - amd64_call_reg (p, AMD64_R11); - stackval_pos += sizeof (stackval); -#if 0 - /* fixme: alignment */ - if (sig->pinvoke) - arg_pos += mono_type_native_stack_size (sig->params [i], &align); - else - arg_pos += mono_type_stack_size (sig->params [i], &align); -#endif - } - - /* - * Handle the return value storage area. - */ - amd64_lea_membase (p, AMD64_RAX, AMD64_RBP, stackval_pos); - amd64_mov_membase_reg (p, AMD64_RBP, (mono_invocation_pos + G_STRUCT_OFFSET (MonoInvocation, retval)), AMD64_RAX, SIZEOF_VOID_P); - if (sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->byref) { - MonoClass *klass = sig->ret->data.klass; - if (!klass->enumtype) { - amd64_mov_reg_membase (p, AMD64_RCX, AMD64_RBP, retval_ptr_rbp_offset, SIZEOF_VOID_P); - amd64_mov_membase_reg (p, AMD64_RBP, stackval_pos, AMD64_RCX, SIZEOF_VOID_P); - } - } - - /* - * Call the method. - */ - amd64_lea_membase (p, int_arg_regs[0], AMD64_RBP, mono_invocation_pos); - amd64_mov_reg_imm (p, AMD64_R11, ves_exec_method); - amd64_call_reg (p, AMD64_R11); - - /* - * Move the return value to the proper place. - */ - amd64_lea_membase (p, AMD64_RAX, AMD64_RBP, stackval_pos); - if (sig->ret->byref) { - amd64_mov_reg_membase (p, AMD64_RAX, AMD64_RAX, 0, SIZEOF_VOID_P); - } else { - int simpletype = sig->ret->type; - enum_retvalue: - switch (sig->ret->type) { - case MONO_TYPE_VOID: - break; - case MONO_TYPE_BOOLEAN: - case MONO_TYPE_I1: - case MONO_TYPE_U1: - amd64_movzx_reg_membase (p, AMD64_RAX, AMD64_RAX, 0, 1); - break; - case MONO_TYPE_CHAR: - case MONO_TYPE_I2: - case MONO_TYPE_U2: - amd64_movzx_reg_membase (p, AMD64_RAX, AMD64_RAX, 0, 2); - break; - case MONO_TYPE_I4: - case MONO_TYPE_U4: - case MONO_TYPE_I: - case MONO_TYPE_U: - case MONO_TYPE_OBJECT: - case MONO_TYPE_STRING: - case MONO_TYPE_CLASS: - amd64_movzx_reg_membase (p, AMD64_RAX, AMD64_RAX, 0, 4); - break; - case MONO_TYPE_I8: - amd64_movzx_reg_membase (p, AMD64_RAX, AMD64_RAX, 0, 8); - break; - case MONO_TYPE_R4: - amd64_movss_regp_reg (p, AMD64_RAX, AMD64_XMM0); - break; - case MONO_TYPE_R8: - amd64_movsd_regp_reg (p, AMD64_RAX, AMD64_XMM0); - break; - case MONO_TYPE_VALUETYPE: { - int size; - int arg_type; - int regs_used; - int offset1; - int size1; - int offset2; - int size2; - - if (sig->ret->data.klass->enumtype) { - simpletype = sig->ret->data.klass->enum_basetype->type; - goto enum_retvalue; - } - - arg_type = value_type_info(sig->params [i]->data.klass, &size, ®s_used, &offset1, &size1, &offset2, &size2); - - if (arg_type == ARG_IN_INT_REGS) - { - if (regs_used > 1) - amd64_mov_membase_reg (p, AMD64_RAX, offset2, AMD64_RDX, size2); - amd64_mov_membase_reg (p, AMD64_RAX, offset1, AMD64_RAX, size1); - break; - } - - if (arg_type == ARG_IN_FLOAT_REGS) - { - if (size1 == 4) - amd64_movss_membase_reg (p, AMD64_RAX, offset1, AMD64_XMM0); - else - amd64_movsd_membase_reg (p, AMD64_RAX, offset1, AMD64_XMM0); - - if (regs_used > 1) - { - if (size2 == 4) - amd64_movss_membase_reg (p, AMD64_RAX, offset2, AMD64_XMM1); - else - amd64_movsd_membase_reg (p, AMD64_RAX, offset2, AMD64_XMM1); - } - break; - } - - /* Else result should have been stored in place already. IA32 code has a stackval_to_data call here, which - * looks wrong to me as the pointer in the stack val being converted is setup to point to the output area anyway. - * It all looks a bit suspect anyway. - */ - break; - } - default: - g_error ("Type 0x%x not handled yet in thunk creation", sig->ret->type); - break; - } - } - - /* - * Standard epilog. - */ - amd64_leave (p); - amd64_ret (p); - - g_assert (p - code_buffer < 512); - - ji = g_new0 (MonoJitInfo, 1); - ji->method = method; - ji->code_size = p - code_buffer; - ji->code_start = g_memdup (code_buffer, p - code_buffer); - - mono_jit_info_table_add (mono_get_root_domain (), ji); - - return ji->code_start; -} diff --git a/mono/arch/ppc/Makefile.am b/mono/arch/ppc/Makefile.am index 667ad258d73..9b209ef9400 100644 --- a/mono/arch/ppc/Makefile.am +++ b/mono/arch/ppc/Makefile.am @@ -1,7 +1 @@ -AM_CPPFLAGS = $(GLIB_CFLAGS) -I$(top_srcdir) - -noinst_LTLIBRARIES = libmonoarch-ppc.la - -libmonoarch_ppc_la_SOURCES = tramp.c ppc-codegen.h - -noinst_PROGRAMS = test +EXTRA_DIST = ppc-codegen.h \ No newline at end of file diff --git a/mono/arch/ppc/test.c b/mono/arch/ppc/test.c deleted file mode 100644 index c19358dcab0..00000000000 --- a/mono/arch/ppc/test.c +++ /dev/null @@ -1,35 +0,0 @@ -#include "ppc-codegen.h" -#include - -/* don't run the resulting program, it will destroy your computer, - * just objdump -d it to inspect we generated the correct assembler. - * On Mac OS X use otool[64] -v -t - */ - -int main() { - guint8 code [16000]; - guint8 *p = code; - guint8 *cp; - - printf (".text\n.align 4\n.globl main\n"); -#ifndef __APPLE__ - printf (".type main,@function\n"); -#endif - printf ("main:\n"); - - ppc_stwu (p, ppc_r1, -32, ppc_r1); - ppc_mflr (p, ppc_r0); - ppc_stw (p, ppc_r31, 28, ppc_r1); - ppc_or (p, ppc_r1, ppc_r2, ppc_r3); - ppc_mr (p, ppc_r31, ppc_r1); - ppc_lwz (p, ppc_r11, 0, ppc_r1); - ppc_mtlr (p, ppc_r0); - ppc_blr (p); - ppc_addi (p, ppc_r6, ppc_r6, 16); - - for (cp = code; cp < p; cp++) { - printf (".byte 0x%x\n", *cp); - } - - return 0; -} diff --git a/mono/arch/ppc/tramp.c b/mono/arch/ppc/tramp.c deleted file mode 100644 index 6bb1896255f..00000000000 --- a/mono/arch/ppc/tramp.c +++ /dev/null @@ -1,895 +0,0 @@ -/* - * Create trampolines to invoke arbitrary functions. - * - * Copyright (C) Radek Doulik - * - */ - -#include "config.h" -#include -#include -#include "ppc-codegen.h" -#include "mono/metadata/class.h" -#include "mono/metadata/tabledefs.h" -#include "mono/interpreter/interp.h" -#include "mono/metadata/appdomain.h" - -#ifdef NEED_MPROTECT -#include -#include /* for PAGESIZE */ -#ifndef PAGESIZE -#define PAGESIZE 4096 -#endif -#endif - -#define DEBUG(x) - -/* gpointer -fake_func (gpointer (*callme)(gpointer), stackval *retval, void *this_obj, stackval *arguments) -{ - guint32 i = 0xc002becd; - - callme = (gpointer) 0x100fabcd; - - *(gpointer*)retval = (gpointer)(*callme) (arguments [0].data.p, arguments [1].data.p, arguments [2].data.p); - *(gdouble*) retval = (gdouble)(*callme) (arguments [0].data.f); - - return (gpointer) (*callme) (((MonoType *)arguments [0]. data.p)->data.klass); -} */ - -#define MIN_CACHE_LINE 8 - -static void inline -flush_icache (guint8 *code, guint size) -{ - guint i; - guint8 *p; - - p = code; - for (i = 0; i < size; i += MIN_CACHE_LINE, p += MIN_CACHE_LINE) { - asm ("dcbst 0,%0;" : : "r"(p) : "memory"); - } - asm ("sync"); - p = code; - for (i = 0; i < size; i += MIN_CACHE_LINE, p += MIN_CACHE_LINE) { - asm ("icbi 0,%0; sync;" : : "r"(p) : "memory"); - } - asm ("sync"); - asm ("isync"); -} - -static void -disassemble (guint8 *code, int size) -{ - int i; - FILE *ofd; - const char *tmp = g_getenv("TMP"); - char *as_file; - char *o_file; - char *cmd; - - if (tmp == NULL) - tmp = "/tmp"; - as_file = g_strdup_printf ("%s/test.s", tmp); - - if (!(ofd = fopen (as_file, "w"))) - g_assert_not_reached (); - - fprintf (ofd, "tmp:\n"); - - for (i = 0; i < size; ++i) - fprintf (ofd, ".byte %d\n", (unsigned int) code [i]); - - fclose (ofd); -#ifdef __APPLE__ -#define DIS_CMD "otool -V -v -t" -#else -#define DIS_CMD "objdump -d" -#endif - o_file = g_strdup_printf ("%s/test.o", tmp); - cmd = g_strdup_printf ("as %s -o %s", as_file, o_file); - system (cmd); - g_free (cmd); - cmd = g_strdup_printf (DIS_CMD " %s", o_file); - system (cmd); - g_free (cmd); - g_free (o_file); - g_free (as_file); -} - - -#define NOT_IMPLEMENTED(x) \ - g_error ("FIXME: %s is not yet implemented. (trampoline)", x); - -#define PROLOG_INS 8 -#define CALL_INS 2 -#define EPILOG_INS 6 -#define FLOAT_REGS 8 -#define GENERAL_REGS 8 -#ifdef __APPLE__ -#define MINIMAL_STACK_SIZE 10 -#define ALWAYS_ON_STACK(s) s -#define FP_ALSO_IN_REG(s) s -#define RET_ADDR_OFFSET 8 -#define STACK_PARAM_OFFSET 24 -#else -#define MINIMAL_STACK_SIZE 5 -#define ALWAYS_ON_STACK(s) -#define FP_ALSO_IN_REG(s) s -#define ALIGN_DOUBLES -#define RET_ADDR_OFFSET 4 -#define STACK_PARAM_OFFSET 8 -#endif - -static void inline -add_general (guint *gr, guint *stack_size, guint *code_size, gboolean simple) -{ - if (simple) { - if (*gr >= GENERAL_REGS) { - *stack_size += 4; - *code_size += 8; /* load from stack, save on stack */ - } else { - ALWAYS_ON_STACK (*stack_size += 4); - *code_size += 4; /* load from stack */ - } - } else { - if (*gr >= GENERAL_REGS - 1) { - *stack_size += 8; -#ifdef ALIGN_DOUBLES - *stack_size += (*stack_size % 8); -#endif - *code_size += 16; /* 2x load from stack, 2x save to stack */ - } else { - ALWAYS_ON_STACK (*stack_size += 8); - *code_size += 8; /* 2x load from stack */ - } -#ifdef ALIGN_DOUBLES - if ((*gr) & 1) - (*gr) ++; -#endif - (*gr) ++; - } - (*gr) ++; -} - -static void inline -calculate_sizes (MonoMethodSignature *sig, guint *stack_size, guint *code_size, gboolean string_ctor, gboolean *use_memcpy) -{ - guint i, fr, gr; - guint32 simpletype; - - fr = gr = 0; - *stack_size = MINIMAL_STACK_SIZE*4; - *code_size = (PROLOG_INS + CALL_INS + EPILOG_INS)*4; - - if (sig->hasthis) { - add_general (&gr, stack_size, code_size, TRUE); - } - DEBUG(printf("params: %d\n", sig->param_count)); - for (i = 0; i < sig->param_count; ++i) { - DEBUG(printf("param %d: ", i)); - if (sig->params [i]->byref) { - DEBUG(printf("byref\n")); - add_general (&gr, stack_size, code_size, TRUE); - continue; - } - simpletype = sig->params [i]->type; - enum_calc_size: - switch (simpletype) { - case MONO_TYPE_BOOLEAN: - case MONO_TYPE_CHAR: - case MONO_TYPE_I1: - case MONO_TYPE_U1: - case MONO_TYPE_I2: - case MONO_TYPE_U2: - case MONO_TYPE_I4: - case MONO_TYPE_U4: - case MONO_TYPE_I: - case MONO_TYPE_U: - case MONO_TYPE_PTR: - case MONO_TYPE_CLASS: - case MONO_TYPE_OBJECT: - case MONO_TYPE_STRING: - add_general (&gr, stack_size, code_size, TRUE); - break; - case MONO_TYPE_SZARRAY: - add_general (&gr, stack_size, code_size, TRUE); - *code_size += 4; - break; - case MONO_TYPE_VALUETYPE: { - gint size; - if (sig->params [i]->data.klass->enumtype) { - simpletype = sig->params [i]->data.klass->enum_basetype->type; - goto enum_calc_size; - } - size = mono_class_value_size (sig->params [i]->data.klass, NULL); - if (size != 4) { - DEBUG(printf ("copy %d bytes struct on stack\n", - mono_class_value_size (sig->params [i]->data.klass, NULL))); - *use_memcpy = TRUE; - *code_size += 8*4; - *stack_size += (size + 3) & (~3); - if (gr > GENERAL_REGS) { - *code_size += 4; - *stack_size += 4; - } - } else { - DEBUG(printf ("load %d bytes struct\n", - mono_class_value_size (sig->params [i]->data.klass, NULL))); - add_general (&gr, stack_size, code_size, TRUE); - *code_size += 4; - } - break; - } - case MONO_TYPE_I8: - add_general (&gr, stack_size, code_size, FALSE); - break; - case MONO_TYPE_R4: - if (fr < 7) { - *code_size += 4; - fr ++; - FP_ALSO_IN_REG (gr ++); - ALWAYS_ON_STACK (*stack_size += 4); - } else { - NOT_IMPLEMENTED ("R4 arg"); - } - break; - case MONO_TYPE_R8: - if (fr < 7) { - *code_size += 4; - fr ++; - FP_ALSO_IN_REG (gr += 2); - ALWAYS_ON_STACK (*stack_size += 8); - } else { - NOT_IMPLEMENTED ("R8 arg"); - } - break; - default: - g_error ("Can't trampoline 0x%x", sig->params [i]->type); - } - } - - if (sig->ret->byref || string_ctor) { - *code_size += 8; - } else { - simpletype = sig->ret->type; -enum_retvalue: - switch (simpletype) { - case MONO_TYPE_BOOLEAN: - case MONO_TYPE_I1: - case MONO_TYPE_U1: - case MONO_TYPE_I2: - case MONO_TYPE_U2: - case MONO_TYPE_CHAR: - case MONO_TYPE_I4: - case MONO_TYPE_U4: - case MONO_TYPE_I: - case MONO_TYPE_U: - case MONO_TYPE_CLASS: - case MONO_TYPE_OBJECT: - case MONO_TYPE_R4: - case MONO_TYPE_R8: - case MONO_TYPE_SZARRAY: - case MONO_TYPE_ARRAY: - case MONO_TYPE_STRING: - *code_size += 8; - break; - case MONO_TYPE_I8: - *code_size += 12; - break; - case MONO_TYPE_VALUETYPE: - if (sig->ret->data.klass->enumtype) { - simpletype = sig->ret->data.klass->enum_basetype->type; - goto enum_retvalue; - } - *code_size += 2*4; - break; - case MONO_TYPE_VOID: - break; - default: - g_error ("Can't handle as return value 0x%x", sig->ret->type); - } - } - - if (*use_memcpy) { - *stack_size += 2*4; /* for r14, r15 */ - *code_size += 6*4; - if (sig->hasthis) { - *stack_size += 4; /* for r16 */ - *code_size += 4; - } - } - - /* align stack size to 16 */ - DEBUG (printf (" stack size: %d (%d)\n code size: %d\n", (*stack_size + 15) & ~15, *stack_size, *code_size)); - *stack_size = (*stack_size + 15) & ~15; -} - -static inline guint8 * -emit_prolog (guint8 *p, MonoMethodSignature *sig, guint stack_size) -{ - /* function prolog */ - ppc_stwu (p, ppc_r1, -stack_size, ppc_r1); /* sp <--- sp - stack_size, sp[0] <---- sp save sp, alloc stack */ - ppc_mflr (p, ppc_r0); /* r0 <--- LR */ - ppc_stw (p, ppc_r31, stack_size - 4, ppc_r1); /* sp[+4] <--- r31 save r31 */ - ppc_stw (p, ppc_r0, stack_size + RET_ADDR_OFFSET, ppc_r1); /* sp[-4] <--- LR save return address for "callme" */ - ppc_mr (p, ppc_r31, ppc_r1); /* r31 <--- sp */ - - return p; -} - -#define ARG_BASE ppc_r12 -#define ARG_SIZE sizeof (stackval) -#define SAVE_4_IN_GENERIC_REGISTER \ - if (gr < GENERAL_REGS) { \ - ppc_lwz (p, ppc_r3 + gr, i*ARG_SIZE, ARG_BASE); \ - gr ++; \ - ALWAYS_ON_STACK (stack_par_pos += 4); \ - } else { \ - ppc_lwz (p, ppc_r11, i*ARG_SIZE, ARG_BASE); \ - ppc_stw (p, ppc_r11, stack_par_pos, ppc_r1); \ - stack_par_pos += 4; \ - } -#define SAVE_4_VAL_IN_GENERIC_REGISTER \ - if (gr < GENERAL_REGS) { \ - ppc_lwz (p, ppc_r3 + gr, i*ARG_SIZE, ARG_BASE); \ - ppc_lwz (p, ppc_r3 + gr, 0, ppc_r3 + gr); \ - gr ++; \ - ALWAYS_ON_STACK (stack_par_pos += 4); \ - } else { \ - ppc_lwz (p, ppc_r11, i*ARG_SIZE, ARG_BASE); \ - ppc_lwz (p, ppc_r11, 0, ppc_r11); \ - ppc_stw (p, ppc_r11, stack_par_pos, ppc_r1); \ - stack_par_pos += 4; \ - } - -inline static guint8* -emit_save_parameters (guint8 *p, MonoMethodSignature *sig, guint stack_size, gboolean use_memcpy) -{ - guint i, fr, gr, stack_par_pos, struct_pos, cur_struct_pos; - guint32 simpletype; - - fr = gr = 0; - stack_par_pos = STACK_PARAM_OFFSET; - - ppc_stw (p, ppc_r4, stack_size - 12, ppc_r31); /* preserve "retval", sp[+8] */ - - if (use_memcpy) { - ppc_stw (p, ppc_r14, stack_size - 16, ppc_r31); /* save r14 */ - ppc_stw (p, ppc_r15, stack_size - 20, ppc_r31); /* save r15 */ - ppc_mr (p, ppc_r14, ppc_r3); /* keep "callme" in register */ - ppc_mr (p, ppc_r15, ppc_r6); /* keep "arguments" in register */ - } else { - ppc_mr (p, ppc_r12, ppc_r6); /* keep "arguments" in register */ - ppc_mr (p, ppc_r0, ppc_r3); /* keep "callme" in register */ - } - - if (sig->hasthis) { - if (use_memcpy) { - ppc_stw (p, ppc_r16, stack_size - 24, ppc_r31); /* save r16 */ - ppc_mr (p, ppc_r16, ppc_r5); - } else - ppc_mr (p, ppc_r3, ppc_r5); - gr ++; - ALWAYS_ON_STACK (stack_par_pos += 4); - } - - if (use_memcpy) { - cur_struct_pos = struct_pos = stack_par_pos; - for (i = 0; i < sig->param_count; ++i) { - if (sig->params [i]->byref) - continue; - if (sig->params [i]->type == MONO_TYPE_VALUETYPE && !sig->params [i]->data.klass->enumtype) { - gint size; - - size = mono_class_value_size (sig->params [i]->data.klass, NULL); - if (size != 4) { - /* call memcpy */ - ppc_addi (p, ppc_r3, ppc_r1, stack_par_pos); - ppc_lwz (p, ppc_r4, i*16, ppc_r15); - /* FIXME check if size > 0xffff */ - ppc_li (p, ppc_r5, size & 0xffff); - ppc_lis (p, ppc_r0, (guint32) memcpy >> 16); - ppc_ori (p, ppc_r0, ppc_r0, (guint32) memcpy & 0xffff); - ppc_mtlr (p, ppc_r0); - ppc_blrl (p); - stack_par_pos += (size + 3) & (~3); - } - } - } - - if (sig->hasthis) { - ppc_mr (p, ppc_r3, ppc_r16); - ppc_lwz (p, ppc_r16, stack_size - 24, ppc_r31); /* restore r16 */ - } - ppc_mr (p, ppc_r0, ppc_r14); - ppc_mr (p, ppc_r12, ppc_r15); - ppc_lwz (p, ppc_r14, stack_size - 16, ppc_r31); /* restore r14 */ - ppc_lwz (p, ppc_r15, stack_size - 20, ppc_r31); /* restore r15 */ - } - - if (sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->byref) { - MonoClass *klass = sig->ret->data.klass; - if (!klass->enumtype) { - gint size = mono_class_native_size (klass, NULL); - - DEBUG(printf ("retval value type size: %d\n", size)); - if (size > 8) { - ppc_lwz (p, ppc_r3, stack_size - 12, ppc_r31); - ppc_lwz (p, ppc_r3, 0, ppc_r3); - gr ++; - ALWAYS_ON_STACK (stack_par_pos += 4); - } else { - NOT_IMPLEMENTED ("retval valuetype <= 8 bytes"); - } - } - } - - for (i = 0; i < sig->param_count; ++i) { - if (sig->params [i]->byref) { - SAVE_4_IN_GENERIC_REGISTER; - continue; - } - simpletype = sig->params [i]->type; - enum_calc_size: - switch (simpletype) { - case MONO_TYPE_BOOLEAN: - case MONO_TYPE_I1: - case MONO_TYPE_U1: - case MONO_TYPE_I2: - case MONO_TYPE_U2: - case MONO_TYPE_CHAR: - case MONO_TYPE_I4: - case MONO_TYPE_U4: - case MONO_TYPE_I: - case MONO_TYPE_U: - case MONO_TYPE_PTR: - case MONO_TYPE_CLASS: - case MONO_TYPE_OBJECT: - case MONO_TYPE_STRING: - case MONO_TYPE_SZARRAY: - SAVE_4_IN_GENERIC_REGISTER; - break; - case MONO_TYPE_VALUETYPE: { - gint size; - if (sig->params [i]->data.klass->enumtype) { - simpletype = sig->params [i]->data.klass->enum_basetype->type; - goto enum_calc_size; - } - size = mono_class_value_size (sig->params [i]->data.klass, NULL); - if (size == 4) { - SAVE_4_VAL_IN_GENERIC_REGISTER; - } else { - if (gr < GENERAL_REGS) { - ppc_addi (p, ppc_r3 + gr, ppc_r1, cur_struct_pos); - gr ++; - } else { - ppc_lwz (p, ppc_r11, cur_struct_pos, ppc_r1); - ppc_stw (p, ppc_r11, stack_par_pos, ppc_r1); - stack_par_pos += 4; - } - cur_struct_pos += (size + 3) & (~3); - } - break; - } - case MONO_TYPE_I8: -DEBUG(printf("Mono_Type_i8. gr = %d, arg_base = %d\n", gr, ARG_BASE)); -#ifdef ALIGN_DOUBLES - if (gr & 1) - gr++; -#endif - if (gr < 7) { - ppc_lwz (p, ppc_r3 + gr, i*ARG_SIZE, ARG_BASE); - ppc_lwz (p, ppc_r3 + gr + 1, i*ARG_SIZE + 4, ARG_BASE); - ALWAYS_ON_STACK (stack_par_pos += 8); - } else if (gr == 7) { - ppc_lwz (p, ppc_r3 + gr, i*ARG_SIZE, ARG_BASE); - ppc_lwz (p, ppc_r11, i*ARG_SIZE + 4, ARG_BASE); - ppc_stw (p, ppc_r11, stack_par_pos + 4, ppc_r1); - stack_par_pos += 8; - } else { - ppc_lwz (p, ppc_r11, i*ARG_SIZE, ARG_BASE); - ppc_stw (p, ppc_r11, stack_par_pos, ppc_r1); - ppc_lwz (p, ppc_r11, i*ARG_SIZE + 4, ARG_BASE); - ppc_stw (p, ppc_r11, stack_par_pos + 4, ppc_r1); - stack_par_pos += 8; - } - gr += 2; - break; - case MONO_TYPE_R4: - if (fr < 7) { - ppc_lfs (p, ppc_f1 + fr, i*ARG_SIZE, ARG_BASE); - fr ++; - FP_ALSO_IN_REG (gr ++); - ALWAYS_ON_STACK (stack_par_pos += 4); - } else { - NOT_IMPLEMENTED ("r4 on stack"); - } - break; - case MONO_TYPE_R8: - if (fr < 7) { - ppc_lfd (p, ppc_f1 + fr, i*ARG_SIZE, ARG_BASE); - fr ++; - FP_ALSO_IN_REG (gr += 2); - ALWAYS_ON_STACK (stack_par_pos += 8); - } else { - NOT_IMPLEMENTED ("r8 on stack"); - } - break; - default: - g_error ("Can't trampoline 0x%x", sig->params [i]->type); - } - } - - return p; -} - -static inline guint8 * -alloc_code_memory (guint code_size) -{ - guint8 *p; - -#ifdef NEED_MPROTECT - p = g_malloc (code_size + PAGESIZE - 1); - - /* Align to a multiple of PAGESIZE, assumed to be a power of two */ - p = (char *)(((int) p + PAGESIZE-1) & ~(PAGESIZE-1)); -#else - p = g_malloc (code_size); -#endif - DEBUG (printf (" align: %p (%d)\n", p, (guint)p % 4)); - - return p; -} - -/* static MonoString* -mono_string_new_wrapper (const char *text) -{ - return text ? mono_string_new (mono_domain_get (), text) : NULL; -} */ - -static inline guint8 * -emit_call_and_store_retval (guint8 *p, MonoMethodSignature *sig, guint stack_size, gboolean string_ctor) -{ - guint32 simpletype; - - /* call "callme" */ - ppc_mtlr (p, ppc_r0); - ppc_blrl (p); - - /* get return value */ - if (sig->ret->byref || string_ctor) { - ppc_lwz (p, ppc_r9, stack_size - 12, ppc_r31); /* load "retval" address */ - ppc_stw (p, ppc_r3, 0, ppc_r9); /* save return value (r3) to "retval" */ - } else { - simpletype = sig->ret->type; -enum_retvalue: - switch (simpletype) { - case MONO_TYPE_BOOLEAN: - case MONO_TYPE_I1: - case MONO_TYPE_U1: - ppc_lwz (p, ppc_r9, stack_size - 12, ppc_r31); /* load "retval" address */ - ppc_stb (p, ppc_r3, 0, ppc_r9); /* save return value (r3) to "retval" */ - break; - case MONO_TYPE_I2: - case MONO_TYPE_U2: - case MONO_TYPE_CHAR: - ppc_lwz (p, ppc_r9, stack_size - 12, ppc_r31); /* load "retval" address */ - ppc_sth (p, ppc_r3, 0, ppc_r9); /* save return value (r3) to "retval" */ - break; - case MONO_TYPE_I4: - case MONO_TYPE_U4: - case MONO_TYPE_I: - case MONO_TYPE_U: - case MONO_TYPE_CLASS: - case MONO_TYPE_OBJECT: - case MONO_TYPE_SZARRAY: - case MONO_TYPE_ARRAY: - case MONO_TYPE_STRING: - ppc_lwz (p, ppc_r9, stack_size - 12, ppc_r31); /* load "retval" address */ - ppc_stw (p, ppc_r3, 0, ppc_r9); /* save return value (r3) to "retval" */ - break; - case MONO_TYPE_R4: - ppc_lwz (p, ppc_r9, stack_size - 12, ppc_r31); /* load "retval" address */ - ppc_stfs (p, ppc_f1, 0, ppc_r9); /* save return value (f1) to "retval" */ - break; - case MONO_TYPE_R8: - ppc_lwz (p, ppc_r9, stack_size - 12, ppc_r31); /* load "retval" address */ - ppc_stfd (p, ppc_f1, 0, ppc_r9); /* save return value (f1) to "retval" */ - break; - case MONO_TYPE_I8: - ppc_lwz (p, ppc_r9, stack_size - 12, ppc_r31); /* load "retval" address */ - ppc_stw (p, ppc_r3, 0, ppc_r9); /* save return value (r3) to "retval" */ - ppc_stw (p, ppc_r4, 4, ppc_r9); /* save return value (r3) to "retval" */ - break; - case MONO_TYPE_VALUETYPE: - if (sig->ret->data.klass->enumtype) { - simpletype = sig->ret->data.klass->enum_basetype->type; - goto enum_retvalue; - } - break; - case MONO_TYPE_VOID: - break; - default: - g_error ("Can't handle as return value 0x%x", sig->ret->type); - } - } - - return p; -} - -static inline guint8 * -emit_epilog (guint8 *p, MonoMethodSignature *sig, guint stack_size) -{ - /* function epilog */ - ppc_lwz (p, ppc_r11, 0, ppc_r1); /* r11 <--- sp[0] load backchain from caller's function */ - ppc_lwz (p, ppc_r0, RET_ADDR_OFFSET, ppc_r11); /* r0 <--- r11[4] load return address */ - ppc_mtlr (p, ppc_r0); /* LR <--- r0 set return address */ - ppc_lwz (p, ppc_r31, -4, ppc_r11); /* r31 <--- r11[-4] restore r31 */ - ppc_mr (p, ppc_r1, ppc_r11); /* sp <--- r11 restore stack */ - ppc_blr (p); /* return */ - - return p; -} - -MonoPIFunc -mono_arch_create_trampoline (MonoMethodSignature *sig, gboolean string_ctor) -{ - guint8 *p, *code_buffer; - guint stack_size, code_size; - gboolean use_memcpy = FALSE; - - DEBUG (printf ("\nPInvoke [start emiting]\n")); - calculate_sizes (sig, &stack_size, &code_size, string_ctor, &use_memcpy); - - p = code_buffer = alloc_code_memory (code_size); - p = emit_prolog (p, sig, stack_size); - p = emit_save_parameters (p, sig, stack_size, use_memcpy); - p = emit_call_and_store_retval (p, sig, stack_size, string_ctor); - p = emit_epilog (p, sig, stack_size); - - /* { - guchar *cp; - printf (".text\n.align 4\n.globl main\n.type main,@function\nmain:\n"); - for (cp = code_buffer; cp < p; cp++) { - printf (".byte 0x%x\n", *cp); - } - } */ - -#ifdef NEED_MPROTECT - if (mprotect (code_buffer, 1024, PROT_READ | PROT_WRITE | PROT_EXEC)) { - g_error ("Cannot mprotect trampoline\n"); - } -#endif - - DEBUG (printf ("emited code size: %d\n", p - code_buffer)); - flush_icache (code_buffer, p - code_buffer); - - DEBUG (printf ("PInvoke [end emiting]\n")); - - return (MonoPIFunc) code_buffer; - /* return fake_func; */ -} - - -#ifdef __APPLE__ -#define MINV_POS 40 /* MonoInvocation structure offset on stack - STACK_PARAM_OFFSET + 4 pointer args for stackval_from_data */ -#else -#define MINV_POS 8 /* MonoInvocation structure offset on stack */ -#endif -#define STACK_POS (MINV_POS - sizeof (stackval) * sig->param_count) -#define OBJ_POS 8 -#define TYPE_OFFSET (G_STRUCT_OFFSET (stackval, type)) - -/* - * Returns a pointer to a native function that can be used to - * call the specified method. - * The function created will receive the arguments according - * to the call convention specified in the method. - * This function works by creating a MonoInvocation structure, - * filling the fields in and calling ves_exec_method on it. - * Still need to figure out how to handle the exception stuff - * across the managed/unmanaged boundary. - */ -void * -mono_arch_create_method_pointer (MonoMethod *method) -{ - MonoMethodSignature *sig; - MonoJitInfo *ji; - guint8 *p, *code_buffer; - guint i, align = 0, code_size, stack_size, stackval_arg_pos, local_pos, local_start, reg_param = 0, stack_param, - cpos, vt_cur; - gint *vtbuf; - guint32 simpletype; - - code_size = 1024; - stack_size = 1024; - stack_param = 0; - - sig = mono_method_signature (method); - - p = code_buffer = g_malloc (code_size); - - DEBUG (printf ("\nDelegate [start emiting] %s\n", mono_method_get_name (method))); - - /* prolog */ - ppc_stwu (p, ppc_r1, -stack_size, ppc_r1); /* sp <--- sp - stack_size, sp[0] <---- sp save sp, alloc stack */ - ppc_mflr (p, ppc_r0); /* r0 <--- LR */ - ppc_stw (p, ppc_r31, stack_size - 4, ppc_r1); /* sp[+4] <--- r31 save r31 */ - ppc_stw (p, ppc_r0, stack_size + RET_ADDR_OFFSET, ppc_r1); /* sp[-4] <--- LR save return address for "callme" */ - ppc_mr (p, ppc_r31, ppc_r1); /* r31 <--- sp */ - - /* let's fill MonoInvocation */ - /* first zero some fields */ - ppc_li (p, ppc_r0, 0); - ppc_stw (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex)), ppc_r31); - ppc_stw (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex_handler)), ppc_r31); - ppc_stw (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, parent)), ppc_r31); - - /* set method pointer */ - ppc_lis (p, ppc_r0, (guint32) method >> 16); - ppc_ori (p, ppc_r0, ppc_r0, (guint32) method & 0xffff); - ppc_stw (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, method)), ppc_r31); - - local_start = local_pos = MINV_POS + sizeof (MonoInvocation) + (sig->param_count + 1) * sizeof (stackval); - - if (sig->hasthis) { - ppc_stw (p, ppc_r3, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, obj)), ppc_r31); - reg_param = 1; - } - - if (sig->param_count) { - gint save_count = MIN (8, sig->param_count + sig->hasthis); - for (i = reg_param; i < save_count; i ++) { - ppc_stw (p, ppc_r3 + i, local_pos, ppc_r31); - local_pos += 4; - DEBUG (printf ("save r%d\n", 4 + i)); - } - } - - /* prepare space for valuetypes */ - vt_cur = local_pos; - vtbuf = alloca (sizeof(int)*sig->param_count); - cpos = 0; - for (i = 0; i < sig->param_count; i++) { - MonoType *type = sig->params [i]; - vtbuf [i] = -1; - if (type->type == MONO_TYPE_VALUETYPE) { - MonoClass *klass = type->data.klass; - gint size; - - if (klass->enumtype) - continue; - size = mono_class_native_size (klass, &align); - cpos += align - 1; - cpos &= ~(align - 1); - vtbuf [i] = cpos; - cpos += size; - } - } - cpos += 3; - cpos &= ~3; - - local_pos += cpos; - - /* set MonoInvocation::stack_args */ - stackval_arg_pos = MINV_POS + sizeof (MonoInvocation); - ppc_addi (p, ppc_r0, ppc_r31, stackval_arg_pos); - ppc_stw (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, stack_args)), ppc_r31); - - /* add stackval arguments */ - for (i = 0; i < sig->param_count; ++i) { - if (reg_param < 8) { - ppc_addi (p, ppc_r5, ppc_r31, local_start + i*4); - reg_param ++; - } else { - ppc_addi (p, ppc_r5, stack_size + 8 + stack_param, ppc_r31); - stack_param ++; - } - ppc_lis (p, ppc_r3, (guint32) sig->params [i] >> 16); - - if (vtbuf [i] >= 0) { - ppc_addi (p, ppc_r4, ppc_r31, vt_cur); - ppc_stw (p, ppc_r4, stackval_arg_pos, ppc_r31); - ppc_addi (p, ppc_r4, ppc_r31, stackval_arg_pos); - ppc_lwz (p, ppc_r5, 0, ppc_r5); - vt_cur += vtbuf [i]; - } else { - ppc_addi (p, ppc_r4, ppc_r31, stackval_arg_pos); - } - ppc_ori (p, ppc_r3, ppc_r3, (guint32) sig->params [i] & 0xffff); - ppc_lis (p, ppc_r0, (guint32) stackval_from_data >> 16); - ppc_li (p, ppc_r6, sig->pinvoke); - ppc_ori (p, ppc_r0, ppc_r0, (guint32) stackval_from_data & 0xffff); - ppc_mtlr (p, ppc_r0); - ppc_blrl (p); - - stackval_arg_pos += sizeof (stackval); - } - - /* return value storage */ - if (sig->param_count) { - ppc_addi (p, ppc_r0, ppc_r31, stackval_arg_pos); - } - ppc_stw (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, retval)), ppc_r31); - - /* call ves_exec_method */ - ppc_lis (p, ppc_r0, (guint32) ves_exec_method >> 16); - ppc_addi (p, ppc_r3, ppc_r31, MINV_POS); - ppc_ori (p, ppc_r0, ppc_r0, (guint32) ves_exec_method & 0xffff); - ppc_mtlr (p, ppc_r0); - ppc_blrl (p); - - /* move retval from stackval to proper place (r3/r4/...) */ - if (sig->ret->byref) { - DEBUG (printf ("ret by ref\n")); - ppc_lwz (p, ppc_r3, stackval_arg_pos, ppc_r31); - } else { - enum_retvalue: - switch (sig->ret->type) { - case MONO_TYPE_VOID: - break; - case MONO_TYPE_BOOLEAN: - case MONO_TYPE_I1: - case MONO_TYPE_U1: - ppc_lbz (p, ppc_r3, stackval_arg_pos, ppc_r31); - break; - case MONO_TYPE_I2: - case MONO_TYPE_U2: - ppc_lhz (p, ppc_r3, stackval_arg_pos, ppc_r31); - break; - case MONO_TYPE_I4: - case MONO_TYPE_U4: - case MONO_TYPE_I: - case MONO_TYPE_U: - case MONO_TYPE_OBJECT: - case MONO_TYPE_STRING: - case MONO_TYPE_CLASS: - ppc_lwz (p, ppc_r3, stackval_arg_pos, ppc_r31); - break; - case MONO_TYPE_I8: - ppc_lwz (p, ppc_r3, stackval_arg_pos, ppc_r31); - ppc_lwz (p, ppc_r4, stackval_arg_pos + 4, ppc_r31); - break; - case MONO_TYPE_R4: - ppc_lfs (p, ppc_f1, stackval_arg_pos, ppc_r31); - break; - case MONO_TYPE_R8: - ppc_lfd (p, ppc_f1, stackval_arg_pos, ppc_r31); - break; - case MONO_TYPE_VALUETYPE: - if (sig->ret->data.klass->enumtype) { - simpletype = sig->ret->data.klass->enum_basetype->type; - goto enum_retvalue; - } - NOT_IMPLEMENTED ("value type as ret val from delegate"); - break; - default: - g_error ("Type 0x%x not handled yet in thunk creation", sig->ret->type); - break; - } - } - - /* epilog */ - ppc_lwz (p, ppc_r11, 0, ppc_r1); /* r11 <--- sp[0] load backchain from caller's function */ - ppc_lwz (p, ppc_r0, RET_ADDR_OFFSET, ppc_r11); /* r0 <--- r11[4] load return address */ - ppc_mtlr (p, ppc_r0); /* LR <--- r0 set return address */ - ppc_lwz (p, ppc_r31, -4, ppc_r11); /* r31 <--- r11[-4] restore r31 */ - ppc_mr (p, ppc_r1, ppc_r11); /* sp <--- r11 restore stack */ - ppc_blr (p); /* return */ - - DEBUG (printf ("emited code size: %d\n", p - code_buffer)); - DEBUG (disassemble (code_buffer, p - code_buffer)); - flush_icache (code_buffer, p - code_buffer); - - DEBUG (printf ("Delegate [end emiting]\n")); - - ji = g_new0 (MonoJitInfo, 1); - ji->method = method; - ji->code_size = p - code_buffer; - ji->code_start = code_buffer; - - mono_jit_info_table_add (mono_get_root_domain (), ji); - - return ji->code_start; -} diff --git a/mono/arch/unknown.c b/mono/arch/unknown.c deleted file mode 100644 index d865299001c..00000000000 --- a/mono/arch/unknown.c +++ /dev/null @@ -1,18 +0,0 @@ -#include "mono/interpreter/interp.h" -#ifdef NO_PORT -MonoPIFunc -mono_create_trampoline (MonoMethodSignature *sig, gboolean string_ctor) -{ - g_error ("Unsupported arch"); - return NULL; -} - -void * -mono_create_method_pointer (MonoMethod *method) -{ - g_error ("Unsupported arch"); - return NULL; -} - -#endif - diff --git a/mono/arch/x86/Makefile.am b/mono/arch/x86/Makefile.am index e88506e4cd8..bab0f9e54d6 100644 --- a/mono/arch/x86/Makefile.am +++ b/mono/arch/x86/Makefile.am @@ -1,5 +1 @@ -AM_CPPFLAGS = $(GLIB_CFLAGS) -I$(top_srcdir) - -noinst_LTLIBRARIES = libmonoarch-x86.la - -libmonoarch_x86_la_SOURCES = tramp.c x86-codegen.h +EXTRA_DIST = x86-codegen.h \ No newline at end of file diff --git a/mono/arch/x86/test.c b/mono/arch/x86/test.c deleted file mode 100644 index 3511e8fdaf0..00000000000 --- a/mono/arch/x86/test.c +++ /dev/null @@ -1,225 +0,0 @@ -#include "x86-codegen.h" -#include - -/* don't run the resulting program, it will destroy your computer, - * just objdump -d it to inspect we generated the correct assembler. - */ - -int main() { - unsigned char code [16000]; - unsigned char *p = code; - unsigned char *target, *start, *end; - unsigned long mem_addr = 0xdeadbeef; - int size, i; - - printf (".text\n.align 4\n.globl main\n.type main,@function\nmain:\n"); - - x86_prolog (p, 16, X86_CALLER_REGS); - - x86_cmpxchg_reg_reg (p, X86_EAX, X86_EBP); - x86_cmpxchg_membase_reg (p, X86_EAX, 12, X86_EBP); - - x86_xchg_reg_reg (p, X86_EAX, X86_EBP, 4); - x86_xchg_reg_reg (p, X86_EAX, X86_EBP, 1); // FIXME? - x86_xchg_membase_reg (p, X86_EAX, 12, X86_EBP, 4); - x86_xchg_membase_reg (p, X86_EAX, 12, X86_EBP, 2); - x86_xchg_membase_reg (p, X86_EAX, 12, X86_EBX, 1); // FIXME? - - x86_inc_reg (p, X86_EAX); - x86_inc_mem (p, mem_addr); - x86_inc_membase (p, X86_ESP, 4); - - x86_nop (p); - x86_nop (p); - - x86_dec_reg (p, X86_EAX); - x86_dec_reg (p, X86_ECX); - x86_dec_mem (p, mem_addr); - x86_dec_membase (p, X86_ESP, 4); - - x86_not_reg (p, X86_EDX); - x86_not_reg (p, X86_ECX); - x86_not_mem (p, mem_addr); - x86_not_membase (p, X86_ESP, 4); - x86_not_membase (p, X86_ESP, 0x4444444); - x86_not_membase (p, X86_EBP, 0x4444444); - x86_not_membase (p, X86_ECX, 0x4444444); - x86_not_membase (p, X86_EDX, 0); - x86_not_membase (p, X86_EBP, 0); - - x86_neg_reg (p, X86_EAX); - x86_neg_reg (p, X86_ECX); - x86_neg_mem (p, mem_addr); - x86_neg_membase (p, X86_ESP, 8); - - x86_alu_reg_imm (p, X86_ADD, X86_EAX, 5); - x86_alu_reg_imm (p, X86_ADD, X86_EBX, -10); - x86_alu_reg_imm (p, X86_SUB, X86_EDX, 7); - x86_alu_reg_imm (p, X86_OR, X86_ESP, 0xffffedaf); - x86_alu_reg_imm (p, X86_CMP, X86_ECX, 1); - x86_alu_mem_imm (p, X86_ADC, mem_addr, 2); - x86_alu_membase_imm (p, X86_ADC, X86_ESP, -4, 4); - x86_alu_membase_imm (p, X86_ADC, X86_ESP, -12, 0xffffedaf); - - x86_alu_mem_reg (p, X86_SUB, mem_addr, X86_EDX); - x86_alu_reg_reg (p, X86_ADD, X86_EAX, X86_EBX); - x86_alu_reg_mem (p, X86_ADD, X86_EAX, mem_addr); - x86_alu_reg_imm (p, X86_ADD, X86_EAX, 0xdeadbeef); - x86_alu_reg_membase (p, X86_XOR, X86_EDX, X86_ESP, 4); - x86_alu_membase_reg (p, X86_XOR, X86_EBP, 8, X86_ESI); - - x86_test_reg_imm (p, X86_EAX, 16); - x86_test_reg_imm (p, X86_EDX, -16); - x86_test_mem_imm (p, mem_addr, 1); - x86_test_membase_imm (p, X86_EBP, 8, 1); - - x86_test_reg_reg (p, X86_EAX, X86_EDX); - x86_test_mem_reg (p, mem_addr, X86_EDX); - x86_test_membase_reg (p, X86_ESI, 4, X86_EDX); - - x86_shift_reg_imm (p, X86_SHL, X86_EAX, 1); - x86_shift_reg_imm (p, X86_SHL, X86_EDX, 2); - - x86_shift_mem_imm (p, X86_SHL, mem_addr, 2); - x86_shift_membase_imm (p, X86_SHLR, X86_EBP, 8, 4); - - /* - * Shift by CL - */ - x86_shift_reg (p, X86_SHL, X86_EAX); - x86_shift_mem (p, X86_SHL, mem_addr); - - x86_mul_reg (p, X86_EAX, 0); - x86_mul_reg (p, X86_EAX, 1); - x86_mul_membase (p, X86_EBP, 8, 1); - - x86_imul_reg_reg (p, X86_EBX, X86_EDX); - x86_imul_reg_membase (p, X86_EBX, X86_EBP, 12); - - x86_imul_reg_reg_imm (p, X86_EBX, X86_EDX, 10); - x86_imul_reg_mem_imm (p, X86_EBX, mem_addr, 20); - x86_imul_reg_membase_imm (p, X86_EBX, X86_EBP, 16, 300); - - x86_div_reg (p, X86_EDX, 0); - x86_div_reg (p, X86_EDX, 1); - x86_div_mem (p, mem_addr, 1); - x86_div_membase (p, X86_ESI, 4, 1); - - x86_mov_mem_reg (p, mem_addr, X86_EAX, 4); - x86_mov_mem_reg (p, mem_addr, X86_EAX, 2); - x86_mov_mem_reg (p, mem_addr, X86_EAX, 1); - x86_mov_membase_reg (p, X86_EBP, 4, X86_EAX, 1); - - x86_mov_regp_reg (p, X86_EAX, X86_EAX, 4); - x86_mov_membase_reg (p, X86_EAX, 0, X86_EAX, 4); - x86_mov_reg_membase (p, X86_EAX, X86_EAX, 0, 4); - x86_mov_reg_memindex (p, X86_ECX, X86_EAX, 34, X86_EDX, 2, 4); - x86_mov_reg_memindex (p, X86_ECX, X86_NOBASEREG, 34, X86_EDX, 2, 4); - x86_mov_memindex_reg (p, X86_EAX, X86_EAX, 0, X86_EDX, 2, 4); - x86_mov_reg_reg (p, X86_EAX, X86_EAX, 1); - x86_mov_reg_reg (p, X86_EAX, X86_EAX, 4); - x86_mov_reg_mem (p, X86_EAX, mem_addr, 4); - - x86_mov_reg_imm (p, X86_EAX, 10); - x86_mov_mem_imm (p, mem_addr, 54, 4); - x86_mov_mem_imm (p, mem_addr, 54, 1); - - x86_lea_mem (p, X86_EDX, mem_addr); - /* test widen */ - x86_widen_memindex (p, X86_EDX, X86_ECX, 0, X86_EBX, 2, 1, 0); - - x86_cdq (p); - x86_wait (p); - - x86_fp_op_mem (p, X86_FADD, mem_addr, 1); - x86_fp_op_mem (p, X86_FSUB, mem_addr, 0); - x86_fp_op (p, X86_FSUB, 2); - x86_fp_op_reg (p, X86_FMUL, 1, 0); - x86_fstp (p, 2); - x86_fcompp (p); - x86_fnstsw (p); - x86_fnstcw (p, mem_addr); - x86_fnstcw_membase (p, X86_ESP, -8); - - x86_fldcw_membase (p, X86_ESP, -8); - x86_fchs (p); - x86_frem (p); - x86_fxch (p, 3); - x86_fcomip (p, 3); - x86_fld_membase (p, X86_ESP, -8, 1); - x86_fld_membase (p, X86_ESP, -8, 0); - x86_fld80_membase (p, X86_ESP, -8); - x86_fild_membase (p, X86_ESP, -8, 1); - x86_fild_membase (p, X86_ESP, -8, 0); - x86_fld_reg (p, 4); - x86_fldz (p); - x86_fld1 (p); - - x86_fst (p, mem_addr, 1, 0); - x86_fst (p, mem_addr, 1, 1); - x86_fst (p, mem_addr, 0, 1); - - x86_fist_pop_membase (p, X86_EDX, 4, 1); - x86_fist_pop_membase (p, X86_EDX, 4, 0); - - x86_push_reg (p, X86_EBX); - x86_push_membase (p, X86_EBP, 8); - x86_push_imm (p, -1); - x86_pop_reg (p, X86_EBX); - - x86_pushad (p); - x86_pushfd (p); - x86_popfd (p); - x86_popad (p); - - target = p; - - start = p; - x86_jump32 (p, mem_addr); - x86_patch (start, target); - start = p; - x86_jump8 (p, 12); - x86_patch (start, target); - x86_jump_reg (p, X86_EAX); - x86_jump_membase (p, X86_EDX, 16); - - x86_jump_code (p, target); - - x86_branch8 (p, X86_CC_EQ, 54, 1); - x86_branch32 (p, X86_CC_LT, 54, 0); - x86_branch (p, X86_CC_GT, target, 0); - x86_branch_disp (p, X86_CC_NE, -4, 0); - - x86_set_reg (p, X86_CC_EQ, X86_EAX, 0); - x86_set_membase (p, X86_CC_LE, X86_EBP, -8, 0); - - x86_call_code (p, printf); - x86_call_reg (p, X86_ECX); - - x86_sahf (p); - - x86_fsin (p); - x86_fcos (p); - x86_fabs (p); - x86_fpatan (p); - x86_fprem (p); - x86_fprem1 (p); - x86_frndint (p); - x86_fsqrt (p); - x86_fptan (p); - - x86_leave (p); - x86_ret (p); - x86_ret_imm (p, 24); - - x86_cmov_reg (p, X86_CC_GT, 1, X86_EAX, X86_EDX); - x86_cmov_membase (p, X86_CC_GT, 0, X86_EAX, X86_EDX, -4); - - x86_nop (p); - x86_epilog (p, X86_CALLER_REGS); - - size = p-code; - for (i = 0; i < size; ++i) - printf (".byte %d\n", (unsigned int) code [i]); - return 0; -} diff --git a/mono/arch/x86/tramp.c b/mono/arch/x86/tramp.c deleted file mode 100644 index fab5a55325f..00000000000 --- a/mono/arch/x86/tramp.c +++ /dev/null @@ -1,545 +0,0 @@ -/* - * Create trampolines to invoke arbitrary functions. - * - * Copyright (C) Ximian Inc. - * - * Authors: - * Paolo Molaro (lupus@ximian.com) - * Dietmar Maurer (dietmar@ximian.com) - * - */ - -#include "config.h" -#include -#include -#include "x86-codegen.h" -#include "mono/metadata/class.h" -#include "mono/metadata/tabledefs.h" -#include "mono/interpreter/interp.h" -#include "mono/metadata/appdomain.h" -#include "mono/metadata/marshal.h" - -/* - * The resulting function takes the form: - * void func (void (*callme)(), void *retval, void *this_obj, stackval *arguments); - */ -#define FUNC_ADDR_POS 8 -#define RETVAL_POS 12 -#define THIS_POS 16 -#define ARGP_POS 20 -#define LOC_POS -4 - -#define ARG_SIZE sizeof (stackval) - -MonoPIFunc -mono_arch_create_trampoline (MonoMethodSignature *sig, gboolean string_ctor) -{ - unsigned char *p, *code_buffer; - guint32 stack_size = 0, code_size = 50; - guint32 arg_pos, simpletype; - int i, stringp; - static GHashTable *cache = NULL; - MonoPIFunc res; - - if (!cache) - cache = g_hash_table_new ((GHashFunc)mono_signature_hash, - (GCompareFunc)mono_metadata_signature_equal); - - if ((res = (MonoPIFunc)g_hash_table_lookup (cache, sig))) - return res; - - if (sig->hasthis) { - stack_size += sizeof (gpointer); - code_size += 10; - } - - if (sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->byref && !sig->ret->data.klass->enumtype) { - stack_size += sizeof (gpointer); - code_size += 5; - } - - for (i = 0; i < sig->param_count; ++i) { - if (sig->params [i]->byref) { - stack_size += sizeof (gpointer); - code_size += 20; - continue; - } - simpletype = sig->params [i]->type; -enum_calc_size: - switch (simpletype) { - case MONO_TYPE_BOOLEAN: - case MONO_TYPE_CHAR: - case MONO_TYPE_I1: - case MONO_TYPE_U1: - case MONO_TYPE_I2: - case MONO_TYPE_U2: - case MONO_TYPE_I4: - case MONO_TYPE_U4: - case MONO_TYPE_I: - case MONO_TYPE_U: - case MONO_TYPE_PTR: - case MONO_TYPE_SZARRAY: - case MONO_TYPE_CLASS: - case MONO_TYPE_OBJECT: - case MONO_TYPE_STRING: - stack_size += 4; - code_size += i < 10 ? 5 : 8; - break; - case MONO_TYPE_VALUETYPE: { - int size; - if (sig->params [i]->data.klass->enumtype) { - simpletype = sig->params [i]->data.klass->enum_basetype->type; - goto enum_calc_size; - } - if ((size = mono_class_native_size (sig->params [i]->data.klass, NULL)) != 4) { - stack_size += size + 3; - stack_size &= ~3; - code_size += 32; - } else { - stack_size += 4; - code_size += i < 10 ? 5 : 8; - } - break; - } - case MONO_TYPE_I8: - stack_size += 8; - code_size += i < 10 ? 5 : 8; - break; - case MONO_TYPE_R4: - stack_size += 4; - code_size += i < 10 ? 10 : 13; - break; - case MONO_TYPE_R8: - stack_size += 8; - code_size += i < 10 ? 7 : 10; - break; - default: - g_error ("Can't trampoline 0x%x", sig->params [i]->type); - } - } - /* - * FIXME: take into account large return values. - */ - - code_buffer = p = alloca (code_size); - - /* - * Standard function prolog. - */ - x86_push_reg (p, X86_EBP); - x86_mov_reg_reg (p, X86_EBP, X86_ESP, 4); - /* - * and align to 16 byte boundary... - */ - stack_size += 15; - stack_size &= ~15; - - if (stack_size) - x86_alu_reg_imm (p, X86_SUB, X86_ESP, stack_size); - - /* - * EDX has the pointer to the args. - */ - x86_mov_reg_membase (p, X86_EDX, X86_EBP, ARGP_POS, 4); - - /* - * Push arguments in reverse order. - */ - stringp = 0; - for (i = sig->param_count; i; --i) { - arg_pos = ARG_SIZE * (i - 1); - if (sig->params [i - 1]->byref) { - x86_push_membase (p, X86_EDX, arg_pos); - continue; - } - simpletype = sig->params [i - 1]->type; -enum_marshal: - switch (simpletype) { - case MONO_TYPE_BOOLEAN: - case MONO_TYPE_I1: - case MONO_TYPE_U1: - case MONO_TYPE_I2: - case MONO_TYPE_U2: - case MONO_TYPE_CHAR: - case MONO_TYPE_I4: - case MONO_TYPE_U4: - case MONO_TYPE_I: - case MONO_TYPE_U: - case MONO_TYPE_PTR: - case MONO_TYPE_OBJECT: - case MONO_TYPE_STRING: - x86_push_membase (p, X86_EDX, arg_pos); - break; - case MONO_TYPE_R4: - x86_alu_reg_imm (p, X86_SUB, X86_ESP, 4); - x86_fld_membase (p, X86_EDX, arg_pos, TRUE); - x86_fst_membase (p, X86_ESP, 0, FALSE, TRUE); - break; - case MONO_TYPE_CLASS: - x86_push_membase (p, X86_EDX, arg_pos); - break; - case MONO_TYPE_SZARRAY: - x86_push_membase (p, X86_EDX, arg_pos); - break; - case MONO_TYPE_VALUETYPE: - if (!sig->params [i - 1]->data.klass->enumtype) { - int size = mono_class_native_size (sig->params [i - 1]->data.klass, NULL); - if (size == 4) { - /* it's a structure that fits in 4 bytes, need to push the value pointed to */ - x86_mov_reg_membase (p, X86_EAX, X86_EDX, arg_pos, 4); - x86_push_regp (p, X86_EAX); - } else { - int ss = size; - ss += 3; - ss &= ~3; - - x86_alu_reg_imm (p, X86_SUB, X86_ESP, ss); - x86_push_imm (p, size); - x86_push_membase (p, X86_EDX, arg_pos); - x86_lea_membase (p, X86_EAX, X86_ESP, 2*4); - x86_push_reg (p, X86_EAX); - x86_mov_reg_imm (p, X86_EAX, memcpy); - x86_call_reg (p, X86_EAX); - x86_alu_reg_imm (p, X86_ADD, X86_ESP, 12); - /* memcpy might clobber EDX so restore it */ - x86_mov_reg_membase (p, X86_EDX, X86_EBP, ARGP_POS, 4); - } - } else { - /* it's an enum value */ - simpletype = sig->params [i - 1]->data.klass->enum_basetype->type; - goto enum_marshal; - } - break; - case MONO_TYPE_I8: - case MONO_TYPE_U8: - case MONO_TYPE_R8: - x86_push_membase (p, X86_EDX, arg_pos + 4); - x86_push_membase (p, X86_EDX, arg_pos); - break; - default: - g_error ("Can't trampoline 0x%x", sig->params [i - 1]->type); - } - } - - if (sig->hasthis) { - if (sig->call_convention != MONO_CALL_THISCALL) { - x86_mov_reg_membase (p, X86_EDX, X86_EBP, THIS_POS, 4); - x86_push_reg (p, X86_EDX); - } else { - x86_mov_reg_membase (p, X86_ECX, X86_EBP, THIS_POS, 4); - } - } - - if (sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->byref) { - MonoClass *klass = sig->ret->data.klass; - if (!klass->enumtype) { - x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4); - x86_push_membase (p, X86_ECX, 0); - } - } - - /* - * Insert call to function - */ - x86_mov_reg_membase (p, X86_EDX, X86_EBP, FUNC_ADDR_POS, 4); - x86_call_reg (p, X86_EDX); - - /* - * Handle retval. - * Small integer and pointer values are in EAX. - * Long integers are in EAX:EDX. - * FP values are on the FP stack. - */ - - if (sig->ret->byref || string_ctor) { - x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4); - x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4); - } else { - simpletype = sig->ret->type; - enum_retvalue: - switch (simpletype) { - case MONO_TYPE_BOOLEAN: - case MONO_TYPE_I1: - case MONO_TYPE_U1: - x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4); - x86_mov_regp_reg (p, X86_ECX, X86_EAX, 1); - break; - case MONO_TYPE_CHAR: - case MONO_TYPE_I2: - case MONO_TYPE_U2: - x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4); - x86_mov_regp_reg (p, X86_ECX, X86_EAX, 2); - break; - case MONO_TYPE_I4: - case MONO_TYPE_U4: - case MONO_TYPE_I: - case MONO_TYPE_U: - case MONO_TYPE_CLASS: - case MONO_TYPE_OBJECT: - case MONO_TYPE_SZARRAY: - case MONO_TYPE_ARRAY: - x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4); - x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4); - break; - case MONO_TYPE_STRING: - x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4); - x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4); - break; - case MONO_TYPE_R4: - x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4); - x86_fst_membase (p, X86_ECX, 0, FALSE, TRUE); - break; - case MONO_TYPE_R8: - x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4); - x86_fst_membase (p, X86_ECX, 0, TRUE, TRUE); - break; - case MONO_TYPE_I8: - x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4); - x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4); - x86_mov_membase_reg (p, X86_ECX, 4, X86_EDX, 4); - break; - case MONO_TYPE_VALUETYPE: - if (sig->ret->data.klass->enumtype) { - simpletype = sig->ret->data.klass->enum_basetype->type; - goto enum_retvalue; - } - case MONO_TYPE_VOID: - break; - default: - g_error ("Can't handle as return value 0x%x", sig->ret->type); - } - } - - /* - * Standard epilog. - */ - x86_leave (p); - x86_ret (p); - - g_assert (p - code_buffer < code_size); - res = (MonoPIFunc)g_memdup (code_buffer, p - code_buffer); - - g_hash_table_insert (cache, sig, res); - - return res; -} - -#define MINV_POS (- sizeof (MonoInvocation)) -#define STACK_POS (MINV_POS - sizeof (stackval) * sig->param_count) -#define TYPE_OFFSET (G_STRUCT_OFFSET (stackval, type)) - -/* - * Returns a pointer to a native function that can be used to - * call the specified method. - * The function created will receive the arguments according - * to the call convention specified in the method. - * This function works by creating a MonoInvocation structure, - * filling the fields in and calling ves_exec_method on it. - * Still need to figure out how to handle the exception stuff - * across the managed/unmanaged boundary. - */ -void * -mono_arch_create_method_pointer (MonoMethod *method) -{ - MonoMethodSignature *sig; - MonoJitInfo *ji; - unsigned char *p, *code_buffer; - gint32 local_size; - gint32 stackval_pos, arg_pos = 8; - int i, size, align, cpos; - int *vtbuf; - - sig = method->signature; - - code_buffer = p = alloca (512); /* FIXME: check for overflows... */ - vtbuf = alloca (sizeof(int)*sig->param_count); - - local_size = sizeof (MonoInvocation) + sizeof (stackval) * (sig->param_count + 1); - - local_size += 7; - local_size &= ~7; - - stackval_pos = -local_size; - - cpos = 0; - for (i = 0; i < sig->param_count; i++) { - MonoType *type = sig->params [i]; - vtbuf [i] = -1; - if (type->type == MONO_TYPE_VALUETYPE) { - MonoClass *klass = type->data.klass; - if (klass->enumtype) - continue; - size = mono_class_native_size (klass, &align); - cpos += align - 1; - cpos &= ~(align - 1); - vtbuf [i] = cpos; - cpos += size; - } - } - - cpos += 7; - cpos &= ~7; - - local_size += cpos; - - /* - * Standard function prolog. - */ - x86_push_reg (p, X86_EBP); - x86_mov_reg_reg (p, X86_EBP, X86_ESP, 4); - x86_alu_reg_imm (p, X86_SUB, X86_ESP, local_size); - - /* - * Initialize MonoInvocation fields, first the ones known now. - */ - x86_mov_reg_imm (p, X86_EAX, 0); - x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex)), X86_EAX, 4); - x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex_handler)), X86_EAX, 4); - x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, parent)), X86_EAX, 4); - /* - * Set the method pointer. - */ - x86_mov_membase_imm (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, method)), (int)method, 4); - - if (sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->byref && !sig->ret->data.klass->enumtype) - arg_pos += 4; - - /* - * Handle this. - */ - if (sig->hasthis) { - if (sig->call_convention != MONO_CALL_THISCALL) { - /* - * Grab it from the stack, otherwise it's already in ECX. - */ - x86_mov_reg_membase (p, X86_ECX, X86_EBP, arg_pos, 4); - arg_pos += 4; - } - x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, obj)), X86_ECX, 4); - } - /* - * Handle the arguments. stackval_pos is the posset of the stackval array from EBP. - * arg_pos is the offset from EBP to the incoming arg on the stack. - * We just call stackval_from_data to handle all the (nasty) issues.... - */ - x86_lea_membase (p, X86_EAX, X86_EBP, stackval_pos); - x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, stack_args)), X86_EAX, 4); - for (i = 0; i < sig->param_count; ++i) { - if (vtbuf [i] >= 0) { - x86_lea_membase (p, X86_EAX, X86_EBP, - local_size + vtbuf [i]); - x86_mov_membase_reg (p, X86_EBP, stackval_pos, X86_EAX, 4); - } - x86_mov_reg_imm (p, X86_ECX, stackval_from_data); - x86_lea_membase (p, X86_EDX, X86_EBP, arg_pos); - x86_lea_membase (p, X86_EAX, X86_EBP, stackval_pos); - x86_push_imm (p, sig->pinvoke); - x86_push_reg (p, X86_EDX); - x86_push_reg (p, X86_EAX); - x86_push_imm (p, sig->params [i]); - x86_call_reg (p, X86_ECX); - x86_alu_reg_imm (p, X86_SUB, X86_ESP, 16); - stackval_pos += sizeof (stackval); - /* fixme: alignment */ - if (sig->pinvoke) - arg_pos += mono_type_native_stack_size (sig->params [i], &align); - else - arg_pos += mono_type_stack_size (sig->params [i], &align); - } - - /* - * Handle the return value storage area. - */ - x86_lea_membase (p, X86_EAX, X86_EBP, stackval_pos); - x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, retval)), X86_EAX, 4); - if (sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->byref) { - MonoClass *klass = sig->ret->data.klass; - if (!klass->enumtype) { - x86_mov_reg_membase (p, X86_ECX, X86_EBP, 8, 4); - x86_mov_membase_reg (p, X86_EBP, stackval_pos, X86_ECX, 4); - } - } - - /* - * Call the method. - */ - x86_lea_membase (p, X86_EAX, X86_EBP, MINV_POS); - x86_push_reg (p, X86_EAX); - x86_mov_reg_imm (p, X86_EDX, ves_exec_method); - x86_call_reg (p, X86_EDX); - - /* - * Move the return value to the proper place. - */ - x86_lea_membase (p, X86_EAX, X86_EBP, stackval_pos); - if (sig->ret->byref) { - x86_mov_reg_membase (p, X86_EAX, X86_EAX, 0, 4); - } else { - int simpletype = sig->ret->type; - enum_retvalue: - switch (sig->ret->type) { - case MONO_TYPE_VOID: - break; - case MONO_TYPE_BOOLEAN: - case MONO_TYPE_I1: - case MONO_TYPE_U1: - x86_mov_reg_membase (p, X86_EAX, X86_EAX, 0, 1); - break; - case MONO_TYPE_CHAR: - case MONO_TYPE_I2: - case MONO_TYPE_U2: - x86_mov_reg_membase (p, X86_EAX, X86_EAX, 0, 2); - break; - case MONO_TYPE_I4: - case MONO_TYPE_U4: - case MONO_TYPE_I: - case MONO_TYPE_U: - case MONO_TYPE_OBJECT: - case MONO_TYPE_STRING: - case MONO_TYPE_CLASS: - x86_mov_reg_membase (p, X86_EAX, X86_EAX, 0, 4); - break; - case MONO_TYPE_I8: - x86_mov_reg_membase (p, X86_EDX, X86_EAX, 4, 4); - x86_mov_reg_membase (p, X86_EAX, X86_EAX, 0, 4); - break; - case MONO_TYPE_R8: - x86_fld_membase (p, X86_EAX, 0, TRUE); - break; - case MONO_TYPE_VALUETYPE: - if (sig->ret->data.klass->enumtype) { - simpletype = sig->ret->data.klass->enum_basetype->type; - goto enum_retvalue; - } - - x86_push_imm (p, sig->pinvoke); - x86_push_membase (p, X86_EBP, stackval_pos); - x86_push_reg (p, X86_EAX); - x86_push_imm (p, sig->ret); - x86_mov_reg_imm (p, X86_ECX, stackval_to_data); - x86_call_reg (p, X86_ECX); - x86_alu_reg_imm (p, X86_SUB, X86_ESP, 16); - - break; - default: - g_error ("Type 0x%x not handled yet in thunk creation", sig->ret->type); - break; - } - } - - /* - * Standard epilog. - */ - x86_leave (p); - x86_ret (p); - - g_assert (p - code_buffer < 512); - - ji = g_new0 (MonoJitInfo, 1); - ji->method = method; - ji->code_size = p - code_buffer; - ji->code_start = g_memdup (code_buffer, p - code_buffer); - - mono_jit_info_table_add (mono_get_root_domain (), ji); - - return ji->code_start; -} diff --git a/mono/dis/Makefile.am b/mono/dis/Makefile.am index fd581ff5514..0a6e86d0c0c 100644 --- a/mono/dis/Makefile.am +++ b/mono/dis/Makefile.am @@ -4,7 +4,6 @@ if HOST_WIN32 export HOST_CC endif -if JIT_SUPPORTED if !SHARED_MONO static_libs= \ $(top_builddir)/mono/metadata/libmonoruntime-static.la \ @@ -17,9 +16,6 @@ runtime_lib=../mini/$(LIBMONO_LA) $(static_libs) else runtime_lib=../mini/$(LIBMONO_LA) endif -else -runtime_lib=../interpreter/libmint.la -endif if DISABLE_EXECUTABLES bin_PROGRAMS = diff --git a/mono/dis/dump.c b/mono/dis/dump.c index 2b3a4851de0..391ec7fbc77 100755 --- a/mono/dis/dump.c +++ b/mono/dis/dump.c @@ -566,6 +566,7 @@ dump_table_method (MonoImage *m) current_type = 1; last_m = first_m = 1; for (i = 1; i <= t->rows; i++){ + MonoError error; guint32 cols [MONO_METHOD_SIZE]; char *sig, *impl_flags; const char *sigblob; @@ -583,13 +584,17 @@ dump_table_method (MonoImage *m) mono_metadata_string_heap (m, mono_metadata_decode_row_col (td, current_type - 2, MONO_TYPEDEF_NAME))); first_m = last_m; type_container = mono_metadata_load_generic_params (m, MONO_TOKEN_TYPE_DEF | (current_type - 1), NULL); - if (type_container) - mono_metadata_load_generic_param_constraints (m, MONO_TOKEN_TYPE_DEF | (current_type - 1), type_container); + if (type_container) { + mono_metadata_load_generic_param_constraints_checked (m, MONO_TOKEN_TYPE_DEF | (current_type - 1), type_container, &error); + g_assert (mono_error_ok (&error)); /*FIXME don't swallow the error message*/ + } } method_container = mono_metadata_load_generic_params (m, MONO_TOKEN_METHOD_DEF | i, type_container); - if (method_container) - mono_metadata_load_generic_param_constraints (m, MONO_TOKEN_METHOD_DEF | i, method_container); + if (method_container) { + mono_metadata_load_generic_param_constraints_checked (m, MONO_TOKEN_METHOD_DEF | i, method_container, &error); + g_assert (mono_error_ok (&error)); /*FIXME don't swallow the error message*/ + } mono_metadata_decode_table_row (m, MONO_TABLE_METHOD, i - 1, cols, MONO_METHOD_SIZE); sigblob = mono_metadata_blob_heap (m, cols [MONO_METHOD_SIGNATURE]); mono_metadata_decode_blob_size (sigblob, &sigblob); diff --git a/mono/dis/get.c b/mono/dis/get.c index 34f87b0c8ad..a3f2e7b9cac 100755 --- a/mono/dis/get.c +++ b/mono/dis/get.c @@ -889,11 +889,14 @@ dis_stringify_method_signature_full (MonoImage *m, MonoMethodSignature *method, method_name = mono_metadata_string_heap (m, cols [MONO_METHOD_NAME]); param_index = cols [MONO_METHOD_PARAMLIST]; if (!method) { + MonoError error; const char *sig = mono_metadata_blob_heap (m, cols [MONO_METHOD_SIGNATURE]); container = mono_metadata_load_generic_params (m, MONO_TOKEN_METHOD_DEF | methoddef_row, container); - if (container) - mono_metadata_load_generic_param_constraints (m, MONO_TOKEN_METHOD_DEF | methoddef_row, container); + if (container) { + mono_metadata_load_generic_param_constraints_checked (m, MONO_TOKEN_METHOD_DEF | methoddef_row, container, &error); + g_assert (mono_error_ok (&error)); /*FIXME don't swallow the error message*/ + } mono_metadata_decode_blob_size (sig, &sig); method = mono_metadata_parse_method_signature_full (m, container, methoddef_row, sig, &sig); diff --git a/mono/dis/main.c b/mono/dis/main.c index 42d735b0f75..b56da24c35a 100644 --- a/mono/dis/main.c +++ b/mono/dis/main.c @@ -854,10 +854,13 @@ dis_method_list (const char *klass_name, MonoImage *m, guint32 start, guint32 en mono_metadata_decode_blob_size (sig, &sig); container = mono_metadata_load_generic_params (m, MONO_TOKEN_METHOD_DEF | (i + 1), type_container); - if (container) - mono_metadata_load_generic_param_constraints (m, MONO_TOKEN_METHOD_DEF | (i + 1), container); - else + if (container) { + MonoError error; + mono_metadata_load_generic_param_constraints_checked (m, MONO_TOKEN_METHOD_DEF | (i + 1), container, &error); + g_assert (mono_error_ok (&error)); /*FIXME don't swallow the error message*/ + } else { container = type_container; + } ms = mono_metadata_parse_method_signature_full (m, container, i + 1, sig, &sig); if (ms != NULL){ @@ -1181,8 +1184,11 @@ dis_type (MonoImage *m, int n, int is_nested, int forward) } container = mono_metadata_load_generic_params (m, MONO_TOKEN_TYPE_DEF | (n + 1), NULL); - if (container) - mono_metadata_load_generic_param_constraints (m, MONO_TOKEN_TYPE_DEF | (n + 1), container); + if (container) { + MonoError error; + mono_metadata_load_generic_param_constraints_checked (m, MONO_TOKEN_TYPE_DEF | (n + 1), container, &error); + g_assert (mono_error_ok (&error)); /*FIXME don't swallow the error message*/ + } esname = get_escaped_name (name); if ((cols [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_CLASS_SEMANTIC_MASK) == TYPE_ATTRIBUTE_CLASS){ diff --git a/mono/io-layer/handles.c b/mono/io-layer/handles.c index 8cd74e9ff36..5e706fb7280 100644 --- a/mono/io-layer/handles.c +++ b/mono/io-layer/handles.c @@ -29,6 +29,9 @@ # include #endif #include +#ifdef HAVE_SYS_RESOURCE_H +# include +#endif #include #include @@ -213,6 +216,21 @@ static void handle_cleanup (void) 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: * @@ -223,8 +241,8 @@ wapi_init (void) { 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); @@ -266,6 +284,7 @@ wapi_init (void) _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 @@ -1841,65 +1860,6 @@ void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd) } } - 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//fd/ but ignore - * /proc//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) { diff --git a/mono/io-layer/handles.h b/mono/io-layer/handles.h index 04444d0ae82..31cab7bdb94 100644 --- a/mono/io-layer/handles.h +++ b/mono/io-layer/handles.h @@ -20,6 +20,8 @@ extern gboolean DuplicateHandle (gpointer srcprocess, gpointer src, gpointer tar extern void wapi_init (void); extern void wapi_cleanup (void); +int wapi_getdtablesize (void); + G_END_DECLS #endif /* _WAPI_HANDLES_H_ */ diff --git a/mono/io-layer/io-layer.h b/mono/io-layer/io-layer.h index 394799bc86c..6b21f056ca2 100755 --- a/mono/io-layer/io-layer.h +++ b/mono/io-layer/io-layer.h @@ -21,9 +21,9 @@ * Declare as __GetProcessId for unsupported targets. */ #define GetProcessId __GetProcessId #endif -#include #include #include +#include /* * The mingw version says: * /usr/i686-pc-mingw32/sys-root/mingw/include/ws2tcpip.h:38:2: error: #error "ws2tcpip.h is not compatible with winsock.h. Include winsock2.h instead." diff --git a/mono/io-layer/io.c b/mono/io-layer/io.c index 169cb07617a..03672d4197e 100644 --- a/mono/io-layer/io.c +++ b/mono/io-layer/io.c @@ -3904,7 +3904,7 @@ GetLogicalDriveStrings_Mtab (guint32 len, gunichar2 *buf) } #endif -#if (defined(HAVE_STATVFS) || defined(HAVE_STATFS)) && !defined(PLATFORM_ANDROID) +#if defined(HAVE_STATVFS) || defined(HAVE_STATFS) gboolean GetDiskFreeSpaceEx(const gunichar2 *path_name, WapiULargeInteger *free_bytes_avail, WapiULargeInteger *total_number_of_bytes, WapiULargeInteger *total_number_of_free_bytes) @@ -3943,7 +3943,11 @@ gboolean GetDiskFreeSpaceEx(const gunichar2 *path_name, WapiULargeInteger *free_ block_size = fsstat.f_frsize; #elif defined(HAVE_STATFS) ret = statfs (utf8_path_name, &fsstat); +#if defined (MNT_RDONLY) isreadonly = ((fsstat.f_flags & MNT_RDONLY) == MNT_RDONLY); +#elif defined (MS_RDONLY) + isreadonly = ((fsstat.f_flags & MS_RDONLY) == MS_RDONLY); +#endif block_size = fsstat.f_bsize; #endif } while(ret == -1 && errno == EINTR); diff --git a/mono/io-layer/process-private.h b/mono/io-layer/process-private.h index c3e6988732d..1da7f472f00 100644 --- a/mono/io-layer/process-private.h +++ b/mono/io-layer/process-private.h @@ -16,18 +16,24 @@ /* 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 @@ -42,8 +48,7 @@ struct MonoProcess { 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; }; @@ -52,8 +57,6 @@ struct MonoProcess { /* * _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 { @@ -62,12 +65,13 @@ 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_ */ diff --git a/mono/io-layer/processes.c b/mono/io-layer/processes.c index c65bf23813c..3c0531f3de0 100644 --- a/mono/io-layer/processes.c +++ b/mono/io-layer/processes.c @@ -86,7 +86,7 @@ * 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; @@ -142,22 +142,25 @@ static volatile gint32 mono_processes_cleaning_up = 0; 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; @@ -169,7 +172,7 @@ static gboolean is_pid_valid (pid_t pid) 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); @@ -178,7 +181,8 @@ static gboolean is_pid_valid (pid_t pid) 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; @@ -233,42 +237,6 @@ utf16_concat (const gunichar2 *first, ...) 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 }; @@ -279,7 +247,7 @@ static const gunichar2 *utf16_quote = utf16_quote_bytes; void print_utf16 (gunichar2 *str) { - gchar *res; + char *res; res = g_utf16_to_utf8 (str, -1, NULL, NULL, NULL); g_print ("%s\n", res); @@ -288,7 +256,8 @@ print_utf16 (gunichar2 *str) #endif /* Implemented as just a wrapper around CreateProcess () */ -gboolean ShellExecuteEx (WapiShellExecuteInfo *sei) +gboolean +ShellExecuteEx (WapiShellExecuteInfo *sei) { gboolean ret; WapiProcessInformation process_info; @@ -299,13 +268,12 @@ gboolean ShellExecuteEx (WapiShellExecuteInfo *sei) * 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 @@ -313,9 +281,9 @@ gboolean ShellExecuteEx (WapiShellExecuteInfo *sei) * 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, @@ -346,7 +314,7 @@ gboolean ShellExecuteEx (WapiShellExecuteInfo *sei) 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; @@ -370,7 +338,7 @@ gboolean ShellExecuteEx (WapiShellExecuteInfo *sei) 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; } @@ -378,7 +346,7 @@ gboolean ShellExecuteEx (WapiShellExecuteInfo *sei) 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; @@ -388,17 +356,16 @@ gboolean ShellExecuteEx (WapiShellExecuteInfo *sei) 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) @@ -505,17 +472,18 @@ is_managed_binary (const gchar *filename) 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); @@ -535,17 +503,15 @@ is_executable (const char *prog) } 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] = '/'; - } } } @@ -557,11 +523,12 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, 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; @@ -570,10 +537,9 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, 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. @@ -610,7 +576,7 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, goto free_strings; } - switchDirectorySeparators(cmd); + switch_dir_separators(cmd); } if (cmdline != NULL) { @@ -633,13 +599,13 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, } /* 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 @@ -684,7 +650,7 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, args_after_prog = args; } else { - gchar *token = NULL; + char *token = NULL; char quote; /* Dig out the first token from args, taking quotation @@ -747,7 +713,7 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, /* 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 @@ -770,7 +736,6 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, SetLastError (ERROR_FILE_NOT_FOUND); goto free_strings; } - } else { char *curdir = g_get_current_dir (); @@ -846,7 +811,7 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, } 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); @@ -873,8 +838,7 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, 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); @@ -895,7 +859,7 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, * 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 */ @@ -910,7 +874,7 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, /* +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 @@ -926,14 +890,13 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, } } } 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 @@ -945,18 +908,6 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, 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 */ @@ -1000,20 +951,17 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, } /* 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 */ @@ -1030,9 +978,8 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, } /* 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); @@ -1057,7 +1004,6 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, _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); @@ -1091,27 +1037,20 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, } 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); @@ -1119,98 +1058,39 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, /* 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); @@ -1218,273 +1098,60 @@ static void process_set_current (void) 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); @@ -1493,37 +1160,34 @@ static gboolean process_open_compare (gpointer handle, gpointer 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, @@ -1534,34 +1198,31 @@ gpointer OpenProcess (guint32 req_access G_GNUC_UNUSED, gboolean inherit G_GNUC_ /* 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 */ @@ -1573,12 +1234,11 @@ gboolean GetExitCodeProcess (gpointer process, guint32 *code) } } - 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 @@ -1589,53 +1249,46 @@ gboolean GetExitCodeProcess (gpointer process, guint32 *code) */ 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 ()) { @@ -1655,18 +1308,18 @@ gboolean GetProcessTimes (gpointer process, WapiFileTime *create_time, 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) @@ -1843,9 +1496,9 @@ static GSList *load_modules (FILE *fp) { 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; @@ -1959,7 +1612,7 @@ static GSList *load_modules (FILE *fp) } #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; @@ -2006,13 +1659,13 @@ static FILE * 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); @@ -2027,8 +1680,7 @@ open_process_map (int pid, const char *mode) 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 @@ -2037,7 +1689,7 @@ gboolean EnumProcessModules (gpointer process, gpointer *modules, 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 @@ -2048,72 +1700,76 @@ gboolean EnumProcessModules (gpointer process, gpointer *modules, * 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//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//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//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]; @@ -2127,10 +1783,10 @@ static gchar *get_process_name_from_proc (pid_t pid) #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); @@ -2239,7 +1895,7 @@ static gchar *get_process_name_from_proc (pid_t 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) { @@ -2266,11 +1922,11 @@ static gchar *get_process_name_from_proc (pid_t pid) * 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)); @@ -2296,15 +1952,15 @@ wapi_process_set_cli_launcher (char *path) 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) @@ -2314,31 +1970,27 @@ static guint32 get_module_name (gpointer process, gpointer module, 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); @@ -2346,10 +1998,10 @@ static guint32 get_module_name (gpointer process, gpointer module, /* Look up the address in /proc//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 { @@ -2357,47 +2009,45 @@ static guint32 get_module_name (gpointer process, gpointer module, * 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); @@ -2405,7 +2055,7 @@ static guint32 get_module_name (gpointer process, gpointer module, if (procname == NULL) { /* bugger */ g_free (procname_ext); - return(0); + return 0; } len = (bytes / 2); @@ -2427,29 +2077,31 @@ static guint32 get_module_name (gpointer process, gpointer module, 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; @@ -2459,37 +2111,31 @@ gboolean GetModuleInformation (gpointer process, gpointer module, 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//maps */ if ((fp = open_process_map (pid, "r")) == NULL) { @@ -2497,22 +2143,22 @@ gboolean GetModuleInformation (gpointer process, gpointer module, * 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; @@ -2520,94 +2166,79 @@ gboolean GetModuleInformation (gpointer process, gpointer module, } 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; } @@ -2639,19 +2270,16 @@ guint32 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; } @@ -2699,20 +2327,17 @@ gboolean 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; } @@ -2796,6 +2421,12 @@ mono_processes_cleanup (void) 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) { @@ -2807,6 +2438,10 @@ mono_processes_cleanup (void) /* 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) { @@ -2857,12 +2492,14 @@ mono_processes_cleanup (void) 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 (); } @@ -2874,9 +2511,7 @@ MONO_SIGNAL_HANDLER_FUNC (static, mono_sigchld_signal_handler, (int _dummy, sigi 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); @@ -2888,9 +2523,7 @@ MONO_SIGNAL_HANDLER_FUNC (static, mono_sigchld_signal_handler, (int _dummy, sigi 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) { @@ -2905,14 +2538,13 @@ MONO_SIGNAL_HANDLER_FUNC (static, mono_sigchld_signal_handler, (int _dummy, sigi 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; @@ -2925,23 +2557,15 @@ static void process_add_sigchld_handler (void) #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. */ @@ -2949,8 +2573,8 @@ static guint32 process_wait (gpointer handle, guint32 timeout, gboolean alertabl 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; } @@ -2968,48 +2592,33 @@ static guint32 process_wait (gpointer handle, guint32 timeout, gboolean alertabl /* 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) { @@ -3022,14 +2631,8 @@ static guint32 process_wait (gpointer handle, guint32 timeout, gboolean alertabl 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; } @@ -3042,11 +2645,10 @@ static guint32 process_wait (gpointer handle, guint32 timeout, gboolean alertabl 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; @@ -3054,7 +2656,7 @@ static guint32 process_wait (gpointer handle, guint32 timeout, gboolean alertabl 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 (); diff --git a/mono/io-layer/processes.h b/mono/io-layer/processes.h index 8e4c0aa558b..c2b78d44387 100644 --- a/mono/io-layer/processes.h +++ b/mono/io-layer/processes.h @@ -10,6 +10,9 @@ #ifndef _WAPI_PROCESSES_H_ #define _WAPI_PROCESSES_H_ +#ifdef HAVE_UNISTD_H +#include +#endif #include #include @@ -188,8 +191,6 @@ extern gboolean CreateProcessWithLogonW (const gunichar2 *username, 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); diff --git a/mono/io-layer/shared.c b/mono/io-layer/shared.c index 1800f9b74a7..f8539039cad 100644 --- a/mono/io-layer/shared.c +++ b/mono/io-layer/shared.c @@ -44,8 +44,6 @@ static mono_mutex_t noshm_sems[_WAPI_SHARED_SEM_COUNT]; -gboolean _wapi_shm_disabled = TRUE; - static gpointer wapi_storage [16]; static void @@ -152,12 +150,13 @@ _wapi_shm_detach (_wapi_shm_t type) } 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 @@ -167,6 +166,8 @@ _wapi_shm_enabled (void) #define USE_SHM 1 #endif +static gboolean _wapi_shm_disabled = TRUE; + static gchar * _wapi_shm_base_name (_wapi_shm_t type) { @@ -404,7 +405,7 @@ _wapi_shm_file_open (const gchar *filename, guint32 wanted_size) } gboolean -_wapi_shm_enabled (void) +_wapi_shm_enabled_internal (void) { static gboolean env_checked; diff --git a/mono/io-layer/shared.h b/mono/io-layer/shared.h index b175b6e306b..5f66a732e6d 100644 --- a/mono/io-layer/shared.h +++ b/mono/io-layer/shared.h @@ -17,15 +17,23 @@ typedef enum { 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_ */ diff --git a/mono/io-layer/wapi-private.h b/mono/io-layer/wapi-private.h index f982d860607..34de2f0fd99 100644 --- a/mono/io-layer/wapi-private.h +++ b/mono/io-layer/wapi-private.h @@ -42,8 +42,7 @@ typedef enum { 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) @@ -136,6 +135,7 @@ struct _WapiHandleUnshared struct _WapiHandle_sem sem; struct _WapiHandle_socket sock; struct _WapiHandle_thread thread; + struct _WapiHandle_process process; struct _WapiHandle_shared_ref shared; } u; }; @@ -149,7 +149,6 @@ struct _WapiHandleShared union { - struct _WapiHandle_process process; struct _WapiHandle_namedmutex namedmutex; struct _WapiHandle_namedsem namedsem; struct _WapiHandle_namedevent namedevent; diff --git a/mono/metadata/Makefile.am b/mono/metadata/Makefile.am index f0c175f08e3..335484ae676 100644 --- a/mono/metadata/Makefile.am +++ b/mono/metadata/Makefile.am @@ -124,6 +124,7 @@ common_sources = \ icall.c \ icall-def.h \ image.c \ + jit-info.c \ loader.c \ locales.c \ locales.h \ @@ -222,9 +223,6 @@ sgen_sources = \ sgen-gc.c \ sgen-internal.c \ sgen-marksweep.c \ - sgen-marksweep-fixed.c \ - sgen-marksweep-par.c \ - sgen-marksweep-fixed-par.c \ sgen-los.c \ sgen-protocol.c \ sgen-bridge.c \ @@ -239,6 +237,8 @@ sgen_sources = \ sgen-archdep.h \ sgen-cardtable.c \ sgen-cardtable.h \ + sgen-pointer-queue.c \ + sgen-pointer-queue.h \ sgen-pinning.c \ sgen-pinning.h \ sgen-pinning-stats.c \ @@ -269,7 +269,8 @@ sgen_sources = \ sgen-layout-stats.c \ sgen-layout-stats.h \ sgen-qsort.c \ - sgen-qsort.h + sgen-qsort.h \ + sgen-tagged-pointer.h libmonoruntime_la_SOURCES = $(common_sources) $(gc_dependent_sources) $(null_gc_sources) $(boehm_sources) libmonoruntime_la_CFLAGS = $(BOEHM_DEFINES) diff --git a/mono/metadata/appdomain.c b/mono/metadata/appdomain.c index 45b9a606ab6..c46bdfa2db4 100644 --- a/mono/metadata/appdomain.c +++ b/mono/metadata/appdomain.c @@ -2415,6 +2415,7 @@ mono_domain_try_unload (MonoDomain *domain, MonoObject **exc) unload_data *thread_data; MonoNativeThreadId tid; MonoDomain *caller_domain = mono_domain_get (); + char *name; /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, GetCurrentThreadId ()); */ @@ -2466,7 +2467,10 @@ mono_domain_try_unload (MonoDomain *domain, MonoObject **exc) thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)unload_thread_main, thread_data, 0, CREATE_SUSPENDED, &tid); if (thread_handle == NULL) return; + name = g_strdup_printf ("Unload thread for domain %x", domain); + mono_thread_info_set_name (tid, name); mono_thread_info_resume (tid); + g_free (name); /* Wait for the thread */ while (!thread_data->done && WaitForSingleObjectEx (thread_handle, INFINITE, TRUE) == WAIT_IO_COMPLETION) { diff --git a/mono/metadata/boehm-gc.c b/mono/metadata/boehm-gc.c index 3320820f877..090f2f7a1dc 100644 --- a/mono/metadata/boehm-gc.c +++ b/mono/metadata/boehm-gc.c @@ -753,7 +753,7 @@ create_allocator (int atype, int tls_key) 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); @@ -1291,6 +1291,18 @@ mono_gc_get_los_limit (void) 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) { diff --git a/mono/metadata/class-internals.h b/mono/metadata/class-internals.h index ab4a5cb5789..2bf904143f1 100644 --- a/mono/metadata/class-internals.h +++ b/mono/metadata/class-internals.h @@ -208,8 +208,8 @@ enum { 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, @@ -1228,13 +1228,9 @@ MONO_API MonoGenericContainer * mono_metadata_load_generic_params (MonoImage *image, guint32 token, MonoGenericContainer *parent_container); -MONO_API void -mono_metadata_load_generic_param_constraints (MonoImage *image, guint32 token, - MonoGenericContainer *container); - -gboolean -mono_metadata_load_generic_param_constraints_full (MonoImage *image, guint32 token, - MonoGenericContainer *container) MONO_INTERNAL; +MONO_API gboolean +mono_metadata_load_generic_param_constraints_checked (MonoImage *image, guint32 token, + MonoGenericContainer *container, MonoError *error); MonoMethodSignature* mono_create_icall_signature (const char *sigstr) MONO_INTERNAL; @@ -1298,7 +1294,7 @@ MONO_API gboolean mono_class_is_valid_enum (MonoClass *klass); MonoType * -mono_type_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *context) MONO_INTERNAL; +mono_type_get_checked (MonoImage *image, guint32 type_token, MonoGenericContext *context, MonoError *error) MONO_INTERNAL; gboolean mono_generic_class_is_generic_type_definition (MonoGenericClass *gklass) MONO_INTERNAL; @@ -1386,4 +1382,16 @@ mono_class_get_methods_by_name (MonoClass *klass, const char *name, guint32 bfla char* mono_class_full_name (MonoClass *klass) MONO_INTERNAL; +MonoClass* +mono_class_inflate_generic_class_checked (MonoClass *gklass, MonoGenericContext *context, MonoError *error) MONO_INTERNAL; + +MonoClass * +mono_class_get_checked (MonoImage *image, guint32 type_token, MonoError *error) MONO_INTERNAL; + +MonoClass * +mono_class_get_and_inflate_typespec_checked (MonoImage *image, guint32 type_token, MonoGenericContext *context, MonoError *error) MONO_INTERNAL; + +MonoClass * +mono_class_from_name_case_checked (MonoImage *image, const char* name_space, const char *name, MonoError *error) MONO_INTERNAL; + #endif /* __MONO_METADATA_CLASS_INTERBALS_H__ */ diff --git a/mono/metadata/class.c b/mono/metadata/class.c index d438803266c..e9ff58249ef 100644 --- a/mono/metadata/class.c +++ b/mono/metadata/class.c @@ -52,6 +52,9 @@ gboolean mono_print_vtable = FALSE; guint32 inflated_classes, inflated_classes_size, inflated_methods_size; guint32 classes_size, class_ext_size; +/* Low level lock which protects data structures in this module */ +static mono_mutex_t classes_mutex; + /* Function supplied by the runtime to find classes by name using information from the AOT file */ static MonoGetClassFromName get_class_from_name = NULL; @@ -100,6 +103,18 @@ static int record_gclass_instantiation; static GSList *gclass_recorded_list; typedef gboolean (*gclass_record_func) (MonoClass*, void*); +static inline void +classes_lock (void) +{ + mono_locks_acquire (&classes_mutex, ClassesLock); +} + +static inline void +classes_unlock (void) +{ + mono_locks_release (&classes_mutex, ClassesLock); +} + /* * LOCKING: loader lock must be held until pairing disable_gclass_recording is called. */ @@ -151,59 +166,60 @@ MonoClass * mono_class_from_typeref (MonoImage *image, guint32 type_token) { MonoError error; + MonoClass *class = mono_class_from_typeref_checked (image, type_token, &error); + g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/ + return class; +} + +MonoClass * +mono_class_from_typeref_checked (MonoImage *image, guint32 type_token, MonoError *error) +{ guint32 cols [MONO_TYPEREF_SIZE]; MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEREF]; guint32 idx; const char *name, *nspace; - MonoClass *res; + MonoClass *res = NULL; MonoImage *module; - if (!mono_verifier_verify_typeref_row (image, (type_token & 0xffffff) - 1, &error)) { - mono_trace_warning (MONO_TRACE_TYPE, "Failed to resolve typeref from %s due to '%s'", image->name, mono_error_get_message (&error)); + mono_error_init (error); + + if (!mono_verifier_verify_typeref_row (image, (type_token & 0xffffff) - 1, error)) return NULL; - } mono_metadata_decode_row (t, (type_token&0xffffff)-1, cols, MONO_TYPEREF_SIZE); name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]); nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]); - idx = cols [MONO_TYPEREF_SCOPE] >> MONO_RESOLTION_SCOPE_BITS; - switch (cols [MONO_TYPEREF_SCOPE] & MONO_RESOLTION_SCOPE_MASK) { - case MONO_RESOLTION_SCOPE_MODULE: + idx = cols [MONO_TYPEREF_SCOPE] >> MONO_RESOLUTION_SCOPE_BITS; + switch (cols [MONO_TYPEREF_SCOPE] & MONO_RESOLUTION_SCOPE_MASK) { + case MONO_RESOLUTION_SCOPE_MODULE: /* LAMESPEC The spec says that a null module resolution scope should go through the exported type table. This is not the observed behavior of existing implementations. The defacto behavior is that it's just a typedef in disguise. */ /* a typedef in disguise */ - return mono_class_from_name (image, nspace, name); - case MONO_RESOLTION_SCOPE_MODULEREF: + res = mono_class_from_name (image, nspace, name); /*FIXME proper error handling*/ + goto done; + + case MONO_RESOLUTION_SCOPE_MODULEREF: module = mono_image_load_module (image, idx); if (module) - return mono_class_from_name (module, nspace, name); - else { - char *msg = g_strdup_printf ("%s%s%s", nspace, nspace [0] ? "." : "", name); - char *human_name; - - human_name = mono_stringify_assembly_name (&image->assembly->aname); - mono_loader_set_error_type_load (msg, human_name); - g_free (msg); - g_free (human_name); - - return NULL; - } - case MONO_RESOLTION_SCOPE_TYPEREF: { + res = mono_class_from_name (module, nspace, name); /*FIXME proper error handling*/ + goto done; + + case MONO_RESOLUTION_SCOPE_TYPEREF: { MonoClass *enclosing; GList *tmp; if (idx == mono_metadata_token_index (type_token)) { - mono_loader_set_error_bad_image (g_strdup_printf ("Image %s with self-referencing typeref token %08x.", image->name, type_token)); + mono_error_set_bad_image (error, image, "Image with self-referencing typeref token %08x.", type_token); return NULL; } - enclosing = mono_class_from_typeref (image, MONO_TOKEN_TYPE_REF | idx); - if (!enclosing) + enclosing = mono_class_from_typeref_checked (image, MONO_TOKEN_TYPE_REF | idx, error); + if (!mono_error_ok (error)) return NULL; if (enclosing->nested_classes_inited && enclosing->ext) { @@ -221,28 +237,21 @@ mono_class_from_typeref (MonoImage *image, guint32 type_token) guint32 string_offset = mono_metadata_decode_row_col (&enclosing->image->tables [MONO_TABLE_TYPEDEF], class_nested - 1, MONO_TYPEDEF_NAME); const char *nname = mono_metadata_string_heap (enclosing->image, string_offset); - if (strcmp (nname, name) == 0) { - MonoClass *res = mono_class_create_from_typedef (enclosing->image, MONO_TOKEN_TYPE_DEF | class_nested, &error); - if (!mono_error_ok (&error)) { - mono_loader_set_error_from_mono_error (&error); - mono_error_cleanup (&error); /*FIXME don't swallow error message.*/ - return NULL; - } - return res; - } + if (strcmp (nname, name) == 0) + return mono_class_create_from_typedef (enclosing->image, MONO_TOKEN_TYPE_DEF | class_nested, error); i = mono_metadata_nesting_typedef (enclosing->image, enclosing->type_token, i + 1); } } g_warning ("TypeRef ResolutionScope not yet handled (%d) for %s.%s in image %s", idx, nspace, name, image->name); - return NULL; + goto done; } - case MONO_RESOLTION_SCOPE_ASSEMBLYREF: + case MONO_RESOLUTION_SCOPE_ASSEMBLYREF: break; } if (idx > image->tables [MONO_TABLE_ASSEMBLYREF].rows) { - mono_loader_set_error_bad_image (g_strdup_printf ("Image %s with invalid assemblyref token %08x.", image->name, idx)); + mono_error_set_bad_image (error, image, "Image with invalid assemblyref token %08x.", idx); return NULL; } @@ -257,13 +266,20 @@ mono_class_from_typeref (MonoImage *image, guint32 type_token) mono_assembly_get_assemblyref (image, idx - 1, &aname); human_name = mono_stringify_assembly_name (&aname); - mono_loader_set_error_assembly_load (human_name, image->assembly ? image->assembly->ref_only : FALSE); - g_free (human_name); - + mono_error_set_assembly_load_simple (error, human_name, image->assembly ? image->assembly->ref_only : FALSE); return NULL; } - return mono_class_from_name (image->references [idx - 1]->image, nspace, name); + res = mono_class_from_name (image->references [idx - 1]->image, nspace, name); + +done: + /* Generic case, should be avoided for when a better error is possible. */ + if (!res && mono_error_ok (error)) { + char *name = mono_class_name_from_token (image, type_token); + char *assembly = mono_assembly_name_from_token (image, type_token); + mono_error_set_type_load_name (error, name, assembly, "Could not resolve type with token %08x", type_token); + } + return res; } @@ -878,7 +894,7 @@ mono_class_inflate_generic_type_no_copy (MonoImage *image, MonoType *type, MonoG return inflated; } -static MonoClass* +MonoClass* mono_class_inflate_generic_class_checked (MonoClass *gklass, MonoGenericContext *context, MonoError *error) { MonoClass *res; @@ -1243,7 +1259,7 @@ mono_method_set_generic_container (MonoMethod *method, MonoGenericContainer* con * in a separate function since it is cheaper than calling mono_class_setup_fields. */ static MonoType* -mono_class_find_enum_basetype (MonoClass *class) +mono_class_find_enum_basetype (MonoClass *class, MonoError *error) { MonoGenericContainer *container = NULL; MonoImage *m = class->image; @@ -1252,6 +1268,8 @@ mono_class_find_enum_basetype (MonoClass *class) g_assert (class->enumtype); + mono_error_init (error); + if (class->generic_container) container = class->generic_container; else if (class->generic_class) { @@ -1276,27 +1294,41 @@ mono_class_find_enum_basetype (MonoClass *class) if (cols [MONO_FIELD_FLAGS] & FIELD_ATTRIBUTE_STATIC) //no need to decode static fields continue; - if (!mono_verifier_verify_field_signature (class->image, cols [MONO_FIELD_SIGNATURE], NULL)) - return NULL; + if (!mono_verifier_verify_field_signature (class->image, cols [MONO_FIELD_SIGNATURE], NULL)) { + mono_error_set_bad_image (error, class->image, "Invalid field signature %x", cols [MONO_FIELD_SIGNATURE]); + goto fail; + } sig = mono_metadata_blob_heap (m, cols [MONO_FIELD_SIGNATURE]); mono_metadata_decode_value (sig, &sig); /* FIELD signature == 0x06 */ - if (*sig != 0x06) - return NULL; + if (*sig != 0x06) { + mono_error_set_bad_image (error, class->image, "Invalid field signature %x, expected 0x6 but got %x", cols [MONO_FIELD_SIGNATURE], *sig); + goto fail; + } ftype = mono_metadata_parse_type_full (m, container, MONO_PARSE_FIELD, cols [MONO_FIELD_FLAGS], sig + 1, &sig); - if (!ftype) - return NULL; + if (!ftype) { + if (mono_loader_get_last_error ()) /*FIXME plug the above to not leak errors*/ + mono_error_set_from_loader_error (error); + else + mono_error_set_bad_image (error, class->image, "Could not parse type for field signature %x", cols [MONO_FIELD_SIGNATURE]); + goto fail; + } if (class->generic_class) { //FIXME do we leak here? - ftype = mono_class_inflate_generic_type (ftype, mono_class_get_context (class)); + ftype = mono_class_inflate_generic_type_checked (ftype, mono_class_get_context (class), error); + if (!mono_error_ok (error)) + goto fail; ftype->attrs = cols [MONO_FIELD_FLAGS]; } return ftype; } + mono_error_set_type_load_class (error, class, "Could not find base type"); +fail: + g_assert (!mono_loader_get_last_error ()); return NULL; } @@ -1610,6 +1642,10 @@ mono_class_setup_fields (MonoClass *class) mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Invalid negative field offset %d for %s", field->offset, field->name)); break; } + if (class->generic_container) { + mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Generic class cannot have explicit layout.")); + break; + } } } @@ -1907,7 +1943,9 @@ mono_class_layout_fields (MonoClass *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; @@ -1920,7 +1958,6 @@ mono_class_layout_fields (MonoClass *class) * 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) @@ -1950,6 +1987,43 @@ mono_class_layout_fields (MonoClass *class) */ 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; + + // FIXME: Too much code does this +#if 0 + 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); + } +#endif + } + 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; @@ -1957,6 +2031,7 @@ mono_class_layout_fields (MonoClass *class) } break; } + } if (layout != TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) { /* @@ -2030,7 +2105,7 @@ create_array_method (MonoClass *class, const char *name, MonoMethodSignature *si * mono_class_setup_methods: * @class: a class * - * Initializes the 'methods' array in the klass. + * Initializes the 'methods' array in CLASS. * Calling this method should be avoided if possible since it allocates a lot * of long-living MonoMethod structures. * Methods belonging to an interface are assigned a sequential slot starting @@ -2041,19 +2116,12 @@ create_array_method (MonoClass *class, const char *name, MonoMethodSignature *si void mono_class_setup_methods (MonoClass *class) { - int i; + int i, count; MonoMethod **methods; if (class->methods) return; - mono_loader_lock (); - - if (class->methods) { - mono_loader_unlock (); - return; - } - if (class->generic_class) { MonoError error; MonoClass *gklass = class->generic_class->container_class; @@ -2062,17 +2130,16 @@ mono_class_setup_methods (MonoClass *class) if (!gklass->exception_type) mono_class_setup_methods (gklass); if (gklass->exception_type) { - /*FIXME make exception_data less opaque so it's possible to dup it here*/ + /* FIXME make exception_data less opaque so it's possible to dup it here */ mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Generic type definition failed to load")); - mono_loader_unlock (); return; } /* The + 1 makes this always non-NULL to pass the check in mono_class_setup_methods () */ - class->method.count = gklass->method.count; - methods = mono_class_alloc0 (class, sizeof (MonoMethod*) * (class->method.count + 1)); + count = gklass->method.count; + methods = mono_class_alloc0 (class, sizeof (MonoMethod*) * (count + 1)); - for (i = 0; i < class->method.count; i++) { + for (i = 0; i < count; i++) { methods [i] = mono_class_inflate_generic_method_full_checked ( gklass->methods [i], class, mono_class_get_context (class), &error); if (!mono_error_ok (&error)) { @@ -2081,7 +2148,6 @@ mono_class_setup_methods (MonoClass *class) g_free (method); mono_error_cleanup (&error); - mono_loader_unlock (); return; } } @@ -2092,18 +2158,18 @@ mono_class_setup_methods (MonoClass *class) int count_generic = 0, first_generic = 0; int method_num = 0; - class->method.count = 3 + (class->rank > 1? 2: 1); + count = 3 + (class->rank > 1? 2: 1); mono_class_setup_interfaces (class, &error); g_assert (mono_error_ok (&error)); /*FIXME can this fail for array types?*/ if (class->interface_count) { count_generic = generic_array_methods (class); - first_generic = class->method.count; - class->method.count += class->interface_count * count_generic; + first_generic = count; + count += class->interface_count * count_generic; } - methods = mono_class_alloc0 (class, sizeof (MonoMethod*) * class->method.count); + methods = mono_class_alloc0 (class, sizeof (MonoMethod*) * count); sig = mono_metadata_signature_alloc (class->image, class->rank); sig->ret = &mono_defaults.void_class->byval_arg; @@ -2157,8 +2223,9 @@ mono_class_setup_methods (MonoClass *class) for (i = 0; i < class->interface_count; i++) setup_generic_array_ifaces (class, class->interfaces [i], methods, first_generic + i * count_generic); } else { - methods = mono_class_alloc (class, sizeof (MonoMethod*) * class->method.count); - for (i = 0; i < class->method.count; ++i) { + count = class->method.count; + methods = mono_class_alloc (class, sizeof (MonoMethod*) * count); + for (i = 0; i < count; ++i) { int idx = mono_metadata_translate_token_index (class->image, MONO_TABLE_METHOD, class->method.first + i + 1); methods [i] = mono_get_method (class->image, MONO_TOKEN_METHOD_DEF | idx, class); } @@ -2167,18 +2234,24 @@ mono_class_setup_methods (MonoClass *class) if (MONO_CLASS_IS_INTERFACE (class)) { int slot = 0; /*Only assign slots to virtual methods as interfaces are allowed to have static methods.*/ - for (i = 0; i < class->method.count; ++i) { + for (i = 0; i < count; ++i) { if (methods [i]->flags & METHOD_ATTRIBUTE_VIRTUAL) methods [i]->slot = slot++; } } - /* Needed because of the double-checking locking pattern */ - mono_memory_barrier (); + mono_image_lock (class->image); - class->methods = methods; + if (!class->methods) { + class->method.count = count; - mono_loader_unlock (); + /* Needed because of the double-checking locking pattern */ + mono_memory_barrier (); + + class->methods = methods; + } + + mono_image_unlock (class->image); } /* @@ -2296,7 +2369,13 @@ mono_class_get_vtable_size (MonoClass *klass) return klass->vtable_size; } -/*This method can fail the class.*/ +/* + * mono_class_setup_properties: + * + * Initialize class->ext.property and class->ext.properties. + * + * This method can fail the class. + */ static void mono_class_setup_properties (MonoClass *class) { @@ -2305,19 +2384,11 @@ mono_class_setup_properties (MonoClass *class) MonoTableInfo *msemt = &class->image->tables [MONO_TABLE_METHODSEMANTICS]; MonoProperty *properties; guint32 last; + int first, count; if (class->ext && class->ext->properties) return; - mono_loader_lock (); - - if (class->ext && class->ext->properties) { - mono_loader_unlock (); - return; - } - - mono_class_alloc_ext (class); - if (class->generic_class) { MonoClass *gklass = class->generic_class->container_class; @@ -2325,15 +2396,12 @@ mono_class_setup_properties (MonoClass *class) mono_class_setup_properties (gklass); if (gklass->exception_type) { mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Generic type definition failed to load")); - mono_loader_unlock (); return; } - class->ext->property = gklass->ext->property; + properties = mono_class_new0 (class, MonoProperty, gklass->ext->property.count + 1); - properties = mono_class_new0 (class, MonoProperty, class->ext->property.count + 1); - - for (i = 0; i < class->ext->property.count; i++) { + for (i = 0; i < gklass->ext->property.count; i++) { MonoProperty *prop = &properties [i]; *prop = gklass->ext->properties [i]; @@ -2347,20 +2415,19 @@ mono_class_setup_properties (MonoClass *class) prop->parent = class; } + + first = gklass->ext->property.first; + count = gklass->ext->property.count; } else { - int first = mono_metadata_properties_from_typedef (class->image, mono_metadata_token_index (class->type_token) - 1, &last); - int count = last - first; + first = mono_metadata_properties_from_typedef (class->image, mono_metadata_token_index (class->type_token) - 1, &last); + count = last - first; if (count) { mono_class_setup_methods (class); - if (class->exception_type) { - mono_loader_unlock (); + if (class->exception_type) return; - } } - class->ext->property.first = first; - class->ext->property.count = count; properties = mono_class_alloc0 (class, sizeof (MonoProperty) * count); for (i = first; i < last; ++i) { mono_metadata_decode_table_row (class->image, MONO_TABLE_PROPERTY, i, cols, MONO_PROPERTY_SIZE); @@ -2393,13 +2460,27 @@ mono_class_setup_properties (MonoClass *class) } } } - /*Flush any pending writes as we do double checked locking on class->properties */ + + mono_class_alloc_ext (class); + + mono_image_lock (class->image); + + if (class->ext->properties) { + /* We leak 'properties' which was allocated from the image mempool */ + mono_image_unlock (class->image); + return; + } + + class->ext->property.first = first; + class->ext->property.count = count; + + /* Flush any pending writes as we do double checked locking on class->ext->properties */ mono_memory_barrier (); /* Leave this assignment as the last op in the function */ class->ext->properties = properties; - mono_loader_unlock (); + mono_image_unlock (class->image); } static MonoMethod** @@ -2433,34 +2514,26 @@ mono_class_setup_events (MonoClass *class) if (class->ext && class->ext->events) return; - mono_loader_lock (); - - if (class->ext && class->ext->events) { - mono_loader_unlock (); - return; - } - - mono_class_alloc_ext (class); - 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) { mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Generic type definition failed to load")); - mono_loader_unlock (); return; } - class->ext->event = gklass->ext->event; - class->ext->events = mono_class_new0 (class, MonoEvent, class->ext->event.count); + first = gklass->ext->event.first; + count = gklass->ext->event.count; - if (class->ext->event.count) + events = mono_class_new0 (class, MonoEvent, count); + + if (count) context = mono_class_get_context (class); - for (i = 0; i < class->ext->event.count; i++) { - MonoEvent *event = &class->ext->events [i]; + for (i = 0; i < count; i++) { + MonoEvent *event = &events [i]; MonoEvent *gevent = &gklass->ext->events [i]; event->parent = class; @@ -2473,89 +2546,97 @@ mono_class_setup_events (MonoClass *class) #endif event->attrs = gevent->attrs; } + } else { + first = mono_metadata_events_from_typedef (class->image, mono_metadata_token_index (class->type_token) - 1, &last); + count = last - first; - mono_loader_unlock (); - return; - } - - first = mono_metadata_events_from_typedef (class->image, mono_metadata_token_index (class->type_token) - 1, &last); - count = last - first; - - if (count) { - mono_class_setup_methods (class); - if (class->exception_type) { - mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Generic type definition failed to load")); - mono_loader_unlock (); - return; + if (count) { + mono_class_setup_methods (class); + if (class->exception_type) { + mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Generic type definition failed to load")); + return; + } } - } - class->ext->event.first = first; - class->ext->event.count = count; - events = mono_class_alloc0 (class, sizeof (MonoEvent) * class->ext->event.count); - for (i = first; i < last; ++i) { - MonoEvent *event = &events [i - first]; - mono_metadata_decode_table_row (class->image, MONO_TABLE_EVENT, i, cols, MONO_EVENT_SIZE); - event->parent = class; - event->attrs = cols [MONO_EVENT_FLAGS]; - event->name = mono_metadata_string_heap (class->image, cols [MONO_EVENT_NAME]); + events = mono_class_alloc0 (class, sizeof (MonoEvent) * count); + for (i = first; i < last; ++i) { + MonoEvent *event = &events [i - first]; - startm = mono_metadata_methods_from_event (class->image, i, &endm); - for (j = startm; j < endm; ++j) { - MonoMethod *method; + mono_metadata_decode_table_row (class->image, MONO_TABLE_EVENT, i, cols, MONO_EVENT_SIZE); + event->parent = class; + event->attrs = cols [MONO_EVENT_FLAGS]; + event->name = mono_metadata_string_heap (class->image, cols [MONO_EVENT_NAME]); - mono_metadata_decode_row (msemt, j, cols, MONO_METHOD_SEMA_SIZE); + startm = mono_metadata_methods_from_event (class->image, i, &endm); + for (j = startm; j < endm; ++j) { + MonoMethod *method; - if (class->image->uncompressed_metadata) - /* It seems like the MONO_METHOD_SEMA_METHOD column needs no remapping */ - method = mono_get_method (class->image, MONO_TOKEN_METHOD_DEF | cols [MONO_METHOD_SEMA_METHOD], class); - else - method = class->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - class->method.first]; + mono_metadata_decode_row (msemt, j, cols, MONO_METHOD_SEMA_SIZE); - switch (cols [MONO_METHOD_SEMA_SEMANTICS]) { - case METHOD_SEMANTIC_ADD_ON: - event->add = method; - break; - case METHOD_SEMANTIC_REMOVE_ON: - event->remove = method; - break; - case METHOD_SEMANTIC_FIRE: - event->raise = method; - break; - case METHOD_SEMANTIC_OTHER: { + if (class->image->uncompressed_metadata) + /* It seems like the MONO_METHOD_SEMA_METHOD column needs no remapping */ + method = mono_get_method (class->image, MONO_TOKEN_METHOD_DEF | cols [MONO_METHOD_SEMA_METHOD], class); + else + method = class->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - class->method.first]; + + switch (cols [MONO_METHOD_SEMA_SEMANTICS]) { + case METHOD_SEMANTIC_ADD_ON: + event->add = method; + break; + case METHOD_SEMANTIC_REMOVE_ON: + event->remove = method; + break; + case METHOD_SEMANTIC_FIRE: + event->raise = method; + break; + case METHOD_SEMANTIC_OTHER: { #ifndef MONO_SMALL_CONFIG - int n = 0; - - if (event->other == NULL) { - event->other = g_new0 (MonoMethod*, 2); - } else { - while (event->other [n]) - n++; - event->other = g_realloc (event->other, (n + 2) * sizeof (MonoMethod*)); - } - event->other [n] = method; - /* NULL terminated */ - event->other [n + 1] = NULL; + int n = 0; + + if (event->other == NULL) { + event->other = g_new0 (MonoMethod*, 2); + } else { + while (event->other [n]) + n++; + event->other = g_realloc (event->other, (n + 2) * sizeof (MonoMethod*)); + } + event->other [n] = method; + /* NULL terminated */ + event->other [n + 1] = NULL; #endif - break; - } - default: - break; + break; + } + default: + break; + } } } } - /*Flush any pending writes as we do double checked locking on class->properties */ + + mono_class_alloc_ext (class); + + mono_image_lock (class->image); + + if (class->ext->events) { + mono_image_unlock (class->image); + return; + } + + class->ext->event.first = first; + class->ext->event.count = count; + + /* Flush any pending writes as we do double checked locking on class->ext.events */ mono_memory_barrier (); /* Leave this assignment as the last op in the function */ class->ext->events = events; - mono_loader_unlock (); + mono_image_unlock (class->image); } /* * Global pool of interface IDs, represented as a bitset. - * LOCKING: this is supposed to be accessed with the loader lock held. + * LOCKING: Protected by the classes lock. */ static MonoBitSet *global_interface_bitset = NULL; @@ -2570,18 +2651,18 @@ static MonoBitSet *global_interface_bitset = NULL; void mono_unload_interface_ids (MonoBitSet *bitset) { - mono_loader_lock (); + classes_lock (); mono_bitset_sub (global_interface_bitset, bitset); - mono_loader_unlock (); + classes_unlock (); } void mono_unload_interface_id (MonoClass *class) { if (global_interface_bitset && class->interface_id) { - mono_loader_lock (); + classes_lock (); mono_bitset_clear (global_interface_bitset, class->interface_id); - mono_loader_unlock (); + classes_unlock (); } } @@ -2591,7 +2672,7 @@ mono_unload_interface_id (MonoClass *class) * * Assign a unique integer ID to the interface represented by @class. * The ID will positive and as small as possible. - * LOCKING: this is supposed to be called with the loader lock held. + * LOCKING: Acquires the classes lock. * Returns: the new ID. */ static guint @@ -2601,6 +2682,8 @@ mono_get_unique_iid (MonoClass *class) g_assert (MONO_CLASS_IS_INTERFACE (class)); + classes_lock (); + if (!global_interface_bitset) { global_interface_bitset = mono_bitset_new (128, 0); } @@ -2628,6 +2711,8 @@ mono_get_unique_iid (MonoClass *class) mono_bitset_set (class->image->interface_bitset, iid); } + classes_unlock (); + #ifndef MONO_SMALL_CONFIG if (mono_print_vtable) { int generic_id; @@ -5060,14 +5145,11 @@ mono_class_init (MonoClass *class) } else { class->vtable_size = szarray_vtable_size[slot]; } - class->has_finalize_inited = TRUE; } else if (class->generic_class && !MONO_CLASS_IS_INTERFACE (class)) { MonoClass *gklass = class->generic_class->container_class; /* Generic instance case */ class->ghcimpl = gklass->ghcimpl; - class->has_finalize = mono_class_has_finalizer (gklass); - class->has_finalize_inited = TRUE; class->has_cctor = gklass->has_cctor; mono_class_setup_vtable (gklass); @@ -5184,55 +5266,61 @@ mono_class_init (MonoClass *class) gboolean mono_class_has_finalizer (MonoClass *klass) { - if (!klass->has_finalize_inited) { - MonoClass *class = klass; + MonoClass *class = klass; + gboolean has_finalize = FALSE; - mono_loader_lock (); + if (klass->has_finalize_inited) + return klass->has_finalize; - /* Interfaces and valuetypes are not supposed to have finalizers */ - if (!(MONO_CLASS_IS_INTERFACE (class) || class->valuetype)) { - MonoMethod *cmethod = NULL; + /* Interfaces and valuetypes are not supposed to have finalizers */ + if (!(MONO_CLASS_IS_INTERFACE (class) || class->valuetype)) { + MonoMethod *cmethod = NULL; - if (class->parent && class->parent->has_finalize) { - class->has_finalize = 1; - } else { - if (class->parent) { - /* - * Can't search in metadata for a method named Finalize, because that - * ignores overrides. - */ - mono_class_setup_vtable (class); - if (class->exception_type || mono_loader_get_last_error ()) - goto leave; + if (class->rank == 1 && class->byval_arg.type == MONO_TYPE_SZARRAY) { + } else if (class->generic_class) { + MonoClass *gklass = class->generic_class->container_class; + + has_finalize = mono_class_has_finalizer (gklass); + } else if (class->parent && class->parent->has_finalize) { + has_finalize = TRUE; + } else { + if (class->parent) { + /* + * Can't search in metadata for a method named Finalize, because that + * ignores overrides. + */ + mono_class_setup_vtable (class); + if (class->exception_type || mono_loader_get_last_error ()) + cmethod = NULL; + else cmethod = class->vtable [finalize_slot]; - } + } - if (cmethod) { - g_assert (class->vtable_size > finalize_slot); + if (cmethod) { + g_assert (class->vtable_size > finalize_slot); - class->has_finalize = 0; - if (class->parent) { - if (cmethod->is_inflated) - cmethod = ((MonoMethodInflated*)cmethod)->declaring; - if (cmethod != default_finalize) { - class->has_finalize = 1; - } - } + if (class->parent) { + if (cmethod->is_inflated) + cmethod = ((MonoMethodInflated*)cmethod)->declaring; + if (cmethod != default_finalize) + has_finalize = TRUE; } } } + } + + mono_image_lock (klass->image); + + if (!klass->has_finalize_inited) { + klass->has_finalize = has_finalize ? 1 : 0; mono_memory_barrier (); klass->has_finalize_inited = TRUE; - - mono_loader_unlock (); } - return klass->has_finalize; + mono_image_unlock (klass->image); - leave: - mono_loader_unlock (); - return FALSE; + return klass->has_finalize; } gboolean @@ -5653,10 +5741,12 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError class->byval_arg.data.klass = class; class->byval_arg.type = MONO_TYPE_CLASS; } - parent = mono_class_get_full (image, parent_token, context); + parent = mono_class_get_checked (image, parent_token, error); + if (parent && context) /* Always inflate */ + parent = mono_class_inflate_generic_class_checked (parent, context, error); if (parent == NULL) { - mono_class_set_failure_from_loader_error (class, error, g_strdup_printf ("Could not load parent, token is %x", parent_token)); + mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup (mono_error_get_message (error))); goto parent_failure; } @@ -5755,11 +5845,11 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError } if (class->enumtype) { - MonoType *enum_basetype = mono_class_find_enum_basetype (class); + MonoType *enum_basetype = mono_class_find_enum_basetype (class, error); if (!enum_basetype) { /*set it to a default value as the whole runtime can't handle this to be null*/ class->cast_class = class->element_class = mono_defaults.int32_class; - mono_class_set_failure_and_error (class, error, "Could not enum basetype"); + mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup (mono_error_get_message (error))); mono_loader_unlock (); mono_profiler_class_loaded (class, MONO_PROFILE_FAILED); g_assert (!mono_loader_get_last_error ()); @@ -5773,8 +5863,8 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError * We must do this after the class has been constructed to make certain recursive scenarios * work. */ - if (class->generic_container && !mono_metadata_load_generic_param_constraints_full (image, type_token, class->generic_container)){ - mono_class_set_failure_from_loader_error (class, error, g_strdup ("Could not load generic parameter constraints")); + if (class->generic_container && !mono_metadata_load_generic_param_constraints_checked (image, type_token, class->generic_container, error)) { + mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Could not load generic parameter constrains due to %s", mono_error_get_message (error))); mono_loader_unlock (); mono_profiler_class_loaded (class, MONO_PROFILE_FAILED); g_assert (!mono_loader_get_last_error ()); @@ -6075,7 +6165,7 @@ set_anon_gparam_class (MonoGenericParam *param, gboolean is_mvar, MonoClass *kla } ht = is_mvar ? image->mvar_cache_slow : image->var_cache_slow; if (!ht) { - mono_loader_lock (); + mono_image_lock (image); ht = is_mvar ? image->mvar_cache_slow : image->var_cache_slow; if (!ht) { ht = g_hash_table_new (NULL, NULL); @@ -6085,7 +6175,7 @@ set_anon_gparam_class (MonoGenericParam *param, gboolean is_mvar, MonoClass *kla else image->var_cache_slow = ht; } - mono_loader_unlock (); + mono_image_unlock (image); } g_hash_table_insert (ht, GINT_TO_POINTER (n), klass); @@ -6327,23 +6417,20 @@ mono_class_from_mono_type (MonoType *type) static MonoType * mono_type_retrieve_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context, gboolean *did_inflate, MonoError *error) { - MonoType *t = mono_type_create_from_typespec (image, type_spec); + MonoType *t = mono_type_create_from_typespec_checked (image, type_spec, error); - mono_error_init (error); *did_inflate = FALSE; - if (!t) { - char *name = mono_class_name_from_token (image, type_spec); - char *assembly = mono_assembly_name_from_token (image, type_spec); - mono_error_set_type_load_name (error, name, assembly, "Could not resolve typespec token %08x", type_spec); + if (!t) return NULL; - } if (context && (context->class_inst || context->method_inst)) { MonoType *inflated = inflate_generic_type (NULL, t, context, error); - if (!mono_error_ok (error)) + if (!mono_error_ok (error)) { + g_assert (!mono_loader_get_last_error ()); return NULL; + } if (inflated) { t = inflated; @@ -6837,11 +6924,17 @@ mono_class_get_field_default_value (MonoClassField *field, MonoTypeEnum *def_typ g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT); if (!klass->ext || !klass->ext->field_def_values) { - mono_loader_lock (); + MonoFieldDefaultValue *def_values; + mono_class_alloc_ext (klass); + + def_values = mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * klass->field.count); + + mono_image_lock (klass->image); + mono_memory_barrier (); if (!klass->ext->field_def_values) - klass->ext->field_def_values = mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * klass->field.count); - mono_loader_unlock (); + klass->ext->field_def_values = def_values; + mono_image_unlock (klass->image); } field_index = mono_field_get_index (field); @@ -7050,18 +7143,18 @@ mono_assembly_name_from_token (MonoImage *image, guint32 type_token) } mono_metadata_decode_row (t, idx-1, cols, MONO_TYPEREF_SIZE); - idx = cols [MONO_TYPEREF_SCOPE] >> MONO_RESOLTION_SCOPE_BITS; - switch (cols [MONO_TYPEREF_SCOPE] & MONO_RESOLTION_SCOPE_MASK) { - case MONO_RESOLTION_SCOPE_MODULE: + idx = cols [MONO_TYPEREF_SCOPE] >> MONO_RESOLUTION_SCOPE_BITS; + switch (cols [MONO_TYPEREF_SCOPE] & MONO_RESOLUTION_SCOPE_MASK) { + case MONO_RESOLUTION_SCOPE_MODULE: /* FIXME: */ return g_strdup (""); - case MONO_RESOLTION_SCOPE_MODULEREF: + case MONO_RESOLUTION_SCOPE_MODULEREF: /* FIXME: */ return g_strdup (""); - case MONO_RESOLTION_SCOPE_TYPEREF: + case MONO_RESOLUTION_SCOPE_TYPEREF: /* FIXME: */ return g_strdup (""); - case MONO_RESOLTION_SCOPE_ASSEMBLYREF: + case MONO_RESOLUTION_SCOPE_ASSEMBLYREF: mono_assembly_get_assemblyref (image, idx - 1, &aname); return mono_stringify_assembly_name (&aname); default: @@ -7084,6 +7177,7 @@ mono_assembly_name_from_token (MonoImage *image, guint32 type_token) * @image: the image where the class resides * @type_token: the token for the class * @context: the generic context used to evaluate generic instantiations in + * @deprecated: Functions that expose MonoGenericContext are going away in mono 4.0 * * Returns: the MonoClass that represents @type_token in @image */ @@ -7091,49 +7185,79 @@ MonoClass * mono_class_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *context) { MonoError error; + MonoClass *class; + class = mono_class_get_checked (image, type_token, &error); + + if (class && context && mono_metadata_token_table (type_token) == MONO_TABLE_TYPESPEC) + class = mono_class_inflate_generic_class_checked (class, context, &error); + + if (!class) { + mono_loader_set_error_from_mono_error (&error); + mono_error_cleanup (&error); /*FIXME don't swallow this error */ + } + return class; +} + + +MonoClass * +mono_class_get_and_inflate_typespec_checked (MonoImage *image, guint32 type_token, MonoGenericContext *context, MonoError *error) +{ + MonoClass *class; + + mono_error_init (error); + class = mono_class_get_checked (image, type_token, error); + + if (class && context && mono_metadata_token_table (type_token) == MONO_TABLE_TYPESPEC) + class = mono_class_inflate_generic_class_checked (class, context, error); + + return class; +} +/** + * mono_class_get_checked: + * @image: the image where the class resides + * @type_token: the token for the class + * @error: error object to return any error + * + * Returns: the MonoClass that represents @type_token in @image + */ +MonoClass * +mono_class_get_checked (MonoImage *image, guint32 type_token, MonoError *error) +{ MonoClass *class = NULL; + mono_error_init (error); + if (image_is_dynamic (image)) { int table = mono_metadata_token_table (type_token); if (table != MONO_TABLE_TYPEDEF && table != MONO_TABLE_TYPEREF && table != MONO_TABLE_TYPESPEC) { - mono_loader_set_error_bad_image (g_strdup ("Bad type token.")); + mono_error_set_bad_image (error, image,"Bad token table for dynamic image: %x", table); return NULL; } - return mono_lookup_dynamic_token (image, type_token, context); + class = mono_lookup_dynamic_token (image, type_token, NULL); /*FIXME proper error handling*/ + goto done; } switch (type_token & 0xff000000){ case MONO_TOKEN_TYPE_DEF: - class = mono_class_create_from_typedef (image, type_token, &error); - if (!mono_error_ok (&error)) { - mono_loader_set_error_from_mono_error (&error); - /*FIXME don't swallow the error message*/ - mono_error_cleanup (&error); - return NULL; - } + class = mono_class_create_from_typedef (image, type_token, error); break; case MONO_TOKEN_TYPE_REF: - class = mono_class_from_typeref (image, type_token); + class = mono_class_from_typeref_checked (image, type_token, error); break; case MONO_TOKEN_TYPE_SPEC: - class = mono_class_create_from_typespec (image, type_token, context, &error); - if (!mono_error_ok (&error)) { - /*FIXME don't swallow the error message*/ - mono_error_cleanup (&error); - } + class = mono_class_create_from_typespec (image, type_token, NULL, error); break; default: - g_warning ("unknown token type %x", type_token & 0xff000000); - g_assert_not_reached (); + mono_error_set_bad_image (error, image, "Unknown type token %x", type_token & 0xff000000); } - if (!class){ +done: + /* Generic case, should be avoided for when a better error is possible. */ + if (!class && mono_error_ok (error)) { char *name = mono_class_name_from_token (image, type_token); char *assembly = mono_assembly_name_from_token (image, type_token); - mono_loader_set_error_type_load (name, assembly); - g_free (name); - g_free (assembly); + mono_error_set_type_load_name (error, name, assembly, "Could not resolve type with token %08x", type_token); } return class; @@ -7141,42 +7265,44 @@ mono_class_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *c /** - * mono_type_get_full: + * mono_type_get_checked: * @image: the image where the type resides * @type_token: the token for the type * @context: the generic context used to evaluate generic instantiations in + * @error: Error handling context * * This functions exists to fullfill the fact that sometimes it's desirable to have access to the * * Returns: the MonoType that represents @type_token in @image */ MonoType * -mono_type_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *context) +mono_type_get_checked (MonoImage *image, guint32 type_token, MonoGenericContext *context, MonoError *error) { - MonoError error; MonoType *type = NULL; gboolean inflated = FALSE; + mono_error_init (error); + //FIXME: this will not fix the very issue for which mono_type_get_full exists -but how to do it then? if (image_is_dynamic (image)) return mono_class_get_type (mono_lookup_dynamic_token (image, type_token, context)); if ((type_token & 0xff000000) != MONO_TOKEN_TYPE_SPEC) { - MonoClass *class = mono_class_get_full (image, type_token, context); - return class ? mono_class_get_type (class) : NULL; - } + MonoClass *class = mono_class_get_checked (image, type_token, error); - type = mono_type_retrieve_from_typespec (image, type_token, context, &inflated, &error); + if (!class) { + g_assert (!mono_loader_get_last_error ()); + return NULL; + } - if (!mono_error_ok (&error)) { - /*FIXME don't swalloc the error message.*/ - char *name = mono_class_name_from_token (image, type_token); - char *assembly = mono_assembly_name_from_token (image, type_token); + g_assert (class); + return mono_class_get_type (class); + } - g_warning ("Error loading type %s from %s due to %s", name, assembly, mono_error_get_message (&error)); + type = mono_type_retrieve_from_typespec (image, type_token, context, &inflated, error); - mono_error_cleanup (&error); - mono_loader_set_error_type_load (name, assembly); + if (!type) { + g_assert (!mono_loader_get_last_error ()); return NULL; } @@ -7336,6 +7462,7 @@ find_nocase (gpointer key, gpointer value, gpointer user_data) * @image: The MonoImage where the type is looked up in * @name_space: the type namespace * @name: the type short name. + * @deprecated: use the _checked variant * * Obtains a MonoClass with a given namespace and a given name which * is located in the given MonoImage. The namespace and name @@ -7343,6 +7470,15 @@ find_nocase (gpointer key, gpointer value, gpointer user_data) */ MonoClass * mono_class_from_name_case (MonoImage *image, const char* name_space, const char *name) +{ + MonoError error; + MonoClass *res = mono_class_from_name_case_checked (image, name_space, name, &error); + g_assert (!mono_error_ok (&error)); + return res; +} + +MonoClass * +mono_class_from_name_case_checked (MonoImage *image, const char* name_space, const char *name, MonoError *error) { MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEDEF]; guint32 cols [MONO_TYPEDEF_SIZE]; @@ -7350,6 +7486,8 @@ mono_class_from_name_case (MonoImage *image, const char* name_space, const char const char *nspace; guint32 i, visib; + mono_error_init (error); + if (image_is_dynamic (image)) { guint32 token = 0; FindUserData user_data; @@ -7378,7 +7516,7 @@ mono_class_from_name_case (MonoImage *image, const char* name_space, const char mono_image_unlock (image); if (token) - return mono_class_get (image, MONO_TOKEN_TYPE_DEF | token); + return mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF | token, error); else return NULL; @@ -7397,7 +7535,7 @@ mono_class_from_name_case (MonoImage *image, const char* name_space, const char n = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]); nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]); if (mono_utf8_strcasecmp (n, name) == 0 && mono_utf8_strcasecmp (nspace, name_space) == 0) - return mono_class_get (image, MONO_TOKEN_TYPE_DEF | i); + return mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF | i, error); } return NULL; } @@ -8271,26 +8409,34 @@ mono_ldtoken (MonoImage *image, guint32 token, MonoClass **handle_class, case MONO_TOKEN_TYPE_DEF: case MONO_TOKEN_TYPE_REF: case MONO_TOKEN_TYPE_SPEC: { + MonoError error; MonoType *type; if (handle_class) *handle_class = mono_defaults.typehandle_class; - type = mono_type_get_full (image, token, context); - if (!type) + type = mono_type_get_checked (image, token, context, &error); + if (!type) { + mono_loader_set_error_from_mono_error (&error); + mono_error_cleanup (&error); /* FIXME Don't swallow the error */ return NULL; + } mono_class_init (mono_class_from_mono_type (type)); /* We return a MonoType* as handle */ return type; } case MONO_TOKEN_FIELD_DEF: { MonoClass *class; + MonoError error; guint32 type = mono_metadata_typedef_from_field (image, mono_metadata_token_index (token)); if (!type) return NULL; if (handle_class) *handle_class = mono_defaults.fieldhandle_class; - class = mono_class_get_full (image, MONO_TOKEN_TYPE_DEF | type, context); - if (!class) + class = mono_class_get_and_inflate_typespec_checked (image, MONO_TOKEN_TYPE_DEF | type, context, &error); + if (!class) { + mono_loader_set_error_from_mono_error (&error); + mono_error_cleanup (&error); /* FIXME Don't swallow the error */ return NULL; + } mono_class_init (class); return mono_class_get_field (class, token); } @@ -8878,6 +9024,58 @@ mono_class_get_interfaces (MonoClass* klass, gpointer *iter) return NULL; } +static void +setup_nested_types (MonoClass *klass) +{ + MonoError error; + GList *classes, *nested_classes, *l; + int i; + + if (klass->nested_classes_inited) + return; + + if (!klass->type_token) + klass->nested_classes_inited = TRUE; + + i = mono_metadata_nesting_typedef (klass->image, klass->type_token, 1); + classes = NULL; + while (i) { + MonoClass* nclass; + guint32 cols [MONO_NESTED_CLASS_SIZE]; + mono_metadata_decode_row (&klass->image->tables [MONO_TABLE_NESTEDCLASS], i - 1, cols, MONO_NESTED_CLASS_SIZE); + nclass = mono_class_create_from_typedef (klass->image, MONO_TOKEN_TYPE_DEF | cols [MONO_NESTED_CLASS_NESTED], &error); + if (!mono_error_ok (&error)) { + /*FIXME don't swallow the error message*/ + mono_error_cleanup (&error); + + i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1); + continue; + } + + classes = g_list_prepend (classes, nclass); + + i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1); + } + + mono_class_alloc_ext (klass); + + nested_classes = NULL; + for (l = classes; l; l = l->next) + nested_classes = g_list_prepend_image (klass->image, nested_classes, l->data); + g_list_free (classes); + + mono_image_lock (klass->image); + + mono_memory_barrier (); + if (!klass->nested_classes_inited) { + klass->ext->nested_classes = nested_classes; + mono_memory_barrier (); + klass->nested_classes_inited = TRUE; + } + + mono_image_unlock (klass->image); +} + /** * mono_class_get_nested_types * @klass: the MonoClass to act on @@ -8894,40 +9092,12 @@ mono_class_get_interfaces (MonoClass* klass, gpointer *iter) MonoClass* mono_class_get_nested_types (MonoClass* klass, gpointer *iter) { - MonoError error; GList *item; - int i; if (!iter) return NULL; - if (!klass->nested_classes_inited) { - if (!klass->type_token) - klass->nested_classes_inited = TRUE; - mono_loader_lock (); - if (!klass->nested_classes_inited) { - i = mono_metadata_nesting_typedef (klass->image, klass->type_token, 1); - while (i) { - MonoClass* nclass; - guint32 cols [MONO_NESTED_CLASS_SIZE]; - mono_metadata_decode_row (&klass->image->tables [MONO_TABLE_NESTEDCLASS], i - 1, cols, MONO_NESTED_CLASS_SIZE); - nclass = mono_class_create_from_typedef (klass->image, MONO_TOKEN_TYPE_DEF | cols [MONO_NESTED_CLASS_NESTED], &error); - if (!mono_error_ok (&error)) { - /*FIXME don't swallow the error message*/ - mono_error_cleanup (&error); - - i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1); - continue; - } - mono_class_alloc_ext (klass); - klass->ext->nested_classes = g_list_prepend_image (klass->image, klass->ext->nested_classes, nclass); - - i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1); - } - } - mono_memory_barrier (); - klass->nested_classes_inited = TRUE; - mono_loader_unlock (); - } + if (!klass->nested_classes_inited) + setup_nested_types (klass); if (!*iter) { /* start from the first */ @@ -9068,15 +9238,19 @@ mono_field_get_rva (MonoClassField *field) guint32 rva; int field_index; MonoClass *klass = field->parent; + MonoFieldDefaultValue *field_def_values; g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA); if (!klass->ext || !klass->ext->field_def_values) { - mono_loader_lock (); mono_class_alloc_ext (klass); + + field_def_values = mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * klass->field.count); + + mono_image_lock (klass->image); if (!klass->ext->field_def_values) - klass->ext->field_def_values = mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * klass->field.count); - mono_loader_unlock (); + klass->ext->field_def_values = field_def_values; + mono_image_unlock (klass->image); } field_index = mono_field_get_index (field); @@ -9397,6 +9571,8 @@ mono_class_get_exception_data (MonoClass *klass) void mono_classes_init (void) { + mono_mutex_init (&classes_mutex); + mono_counters_register ("Inflated methods size", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_methods_size); mono_counters_register ("Inflated classes", @@ -9420,6 +9596,7 @@ mono_classes_cleanup (void) if (global_interface_bitset) mono_bitset_free (global_interface_bitset); global_interface_bitset = NULL; + mono_mutex_destroy (&classes_mutex); } /** @@ -10024,15 +10201,22 @@ mono_class_setup_interface_id (MonoClass *class) * mono_class_alloc_ext: * * Allocate klass->ext if not already done. - * LOCKING: Assumes the loader lock is held. */ void mono_class_alloc_ext (MonoClass *klass) { - if (!klass->ext) { - klass->ext = mono_class_alloc0 (klass, sizeof (MonoClassExt)); - class_ext_size += sizeof (MonoClassExt); - } + MonoClassExt *ext; + + if (klass->ext) + return; + + ext = mono_class_alloc0 (klass, sizeof (MonoClassExt)); + mono_image_lock (klass->image); + mono_memory_barrier (); + if (!klass->ext) + klass->ext = ext; + class_ext_size += sizeof (MonoClassExt); + mono_image_unlock (klass->image); } /* @@ -10045,53 +10229,62 @@ mono_class_alloc_ext (MonoClass *klass) void mono_class_setup_interfaces (MonoClass *klass, MonoError *error) { - int i; + int i, interface_count; + MonoClass **interfaces; mono_error_init (error); if (klass->interfaces_inited) return; - mono_loader_lock (); - - if (klass->interfaces_inited) { - mono_loader_unlock (); - return; - } - if (klass->rank == 1 && klass->byval_arg.type != MONO_TYPE_ARRAY) { MonoType *args [1]; /* generic IList, ICollection, IEnumerable */ - klass->interface_count = mono_defaults.generic_ireadonlylist_class ? 2 : 1; - klass->interfaces = mono_image_alloc0 (klass->image, sizeof (MonoClass*) * klass->interface_count); + interface_count = mono_defaults.generic_ireadonlylist_class ? 2 : 1; + interfaces = mono_image_alloc0 (klass->image, sizeof (MonoClass*) * interface_count); args [0] = &klass->element_class->byval_arg; - klass->interfaces [0] = mono_class_bind_generic_parameters ( + interfaces [0] = mono_class_bind_generic_parameters ( mono_defaults.generic_ilist_class, 1, args, FALSE); - if (klass->interface_count > 1) - klass->interfaces [1] = mono_class_bind_generic_parameters ( + if (interface_count > 1) + interfaces [1] = mono_class_bind_generic_parameters ( mono_defaults.generic_ireadonlylist_class, 1, args, FALSE); } else if (klass->generic_class) { MonoClass *gklass = klass->generic_class->container_class; - klass->interface_count = gklass->interface_count; - klass->interfaces = mono_class_new0 (klass, MonoClass *, klass->interface_count); - for (i = 0; i < klass->interface_count; i++) { - klass->interfaces [i] = mono_class_inflate_generic_class_checked (gklass->interfaces [i], mono_generic_class_get_context (klass->generic_class), error); + mono_class_setup_interfaces (gklass, error); + if (!mono_error_ok (error)) { + mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Could not setup the interfaces")); + return; + } + + interface_count = gklass->interface_count; + interfaces = mono_class_new0 (klass, MonoClass *, interface_count); + for (i = 0; i < interface_count; i++) { + interfaces [i] = mono_class_inflate_generic_class_checked (gklass->interfaces [i], mono_generic_class_get_context (klass->generic_class), error); if (!mono_error_ok (error)) { mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Could not setup the interfaces")); - klass->interfaces = NULL; return; } } + } else { + interface_count = 0; + interfaces = NULL; } - mono_memory_barrier (); + mono_image_lock (klass->image); - klass->interfaces_inited = TRUE; + if (!klass->interfaces_inited) { + klass->interface_count = interface_count; + klass->interfaces = interfaces; - mono_loader_unlock (); + mono_memory_barrier (); + + klass->interfaces_inited = TRUE; + } + + mono_image_unlock (klass->image); } static void diff --git a/mono/metadata/class.h b/mono/metadata/class.h index a65bd4565e9..d9f315139b1 100644 --- a/mono/metadata/class.h +++ b/mono/metadata/class.h @@ -4,6 +4,7 @@ #include #include #include +#include MONO_BEGIN_DECLS @@ -37,6 +38,9 @@ mono_class_get_method_from_name_flags (MonoClass *klass, const char *name, int p MONO_API MonoClass * mono_class_from_typeref (MonoImage *image, uint32_t type_token); +MONO_API MonoClass * +mono_class_from_typeref_checked (MonoImage *image, uint32_t type_token, MonoError *error); + MONO_API MonoClass * mono_class_from_generic_parameter (MonoGenericParam *param, MonoImage *image, mono_bool is_mvar); diff --git a/mono/metadata/console-unix.c b/mono/metadata/console-unix.c index 6a70b350085..dffba190e31 100644 --- a/mono/metadata/console-unix.c +++ b/mono/metadata/console-unix.c @@ -277,7 +277,7 @@ mono_console_handle_async_ops (void) 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; @@ -295,7 +295,7 @@ MONO_SIGNAL_HANDLER_FUNC (static, sigint_handler, (int signo)) 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. @@ -308,10 +308,10 @@ MONO_SIGNAL_HANDLER_FUNC (static, sigcont_handler, (int signo, void *the_siginfo 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) @@ -321,7 +321,7 @@ MONO_SIGNAL_HANDLER_FUNC (static, sigwinch_handler, (int signo, void *the_siginf 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); } /* diff --git a/mono/metadata/culture-info-tables.h b/mono/metadata/culture-info-tables.h index 5df6721ed4d..bdbeb1daf6b 100644 --- a/mono/metadata/culture-info-tables.h +++ b/mono/metadata/culture-info-tables.h @@ -223,7 +223,7 @@ static const DateTimeFormatEntry datetime_format_entries [] = { {3943, 2309, 323, 331, 44, 55, 0, 0, {0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0}, {36041, 36052, 13523, 36063, 36074, 36081, 36090, 36103, 36110, 36123, 36136, 36149, 0}, {36041, 36052, 13523, 36063, 36074, 36081, 36090, 36103, 36110, 36123, 36136, 36149, 0}, {36041, 36052, 13523, 36063, 36074, 36081, 36090, 36103, 36110, 36123, 36136, 36149, 0}, {36041, 36052, 13523, 36063, 36074, 36081, 36090, 36103, 36110, 36123, 36136, 36149, 0}, 0, 6, 2541, 241, {2309,1236,1210,0,0,0,0,0,0,0,0,0,0,0},{3943,254,0,0,0,0,0,0},{331,274,35,0,0,0,0,0,0,0,0,0},{323,280,23,0,0,0,0,0,0}}, {1344, 2927, 323, 331, 1375, 1391, 1404, 1411, {1418, 1428, 1438, 1448, 1458, 1468, 1478}, {34903, 34910, 34917, 34924, 34931, 34938, 34945}, {1537, 1541, 1545, 1549, 1553, 1557, 1561}, {1655, 1660, 1665, 1670, 1675, 1680, 1685, 1690, 1695, 1700, 1706, 1712, 0}, {1655, 1660, 1665, 1670, 1675, 1680, 1685, 1690, 1695, 1700, 1706, 1712, 0}, {1655, 1660, 1665, 1670, 1675, 1680, 1685, 1690, 1695, 1700, 1706, 1712, 0}, {1655, 1660, 1665, 1670, 1675, 1680, 1685, 1690, 1695, 1700, 1706, 1712, 0}, 0, 0, 239, 241, {2927,1229,14,1765,1779,1366,1736,1210,0,0,0,0,0,0},{1344,36162,36189,2543,0,0,0,0},{331,274,0,0,0,0,0,0,0,0,0,0},{323,280,0,0,0,0,0,0,0}}, {2568, 2587, 280, 274, 1906, 1916, 2598, 2604, {2611, 2619, 2626, 2635, 2644, 2655, 2663}, {2671, 2674, 2677, 2680, 2683, 2686, 2689}, {2018, 2403, 2692, 2403, 2692, 2409, 2018}, {2694, 2701, 2709, 2715, 2721, 2725, 2730, 2735, 2742, 2752, 2760, 2769, 0}, {2694, 2701, 2709, 2715, 2721, 2725, 2730, 2735, 2742, 2752, 2760, 2769, 0}, {2778, 2782, 2786, 2791, 2721, 2795, 2799, 2803, 2807, 2811, 2815, 2819, 0}, {2778, 2782, 2786, 2791, 2721, 2795, 2799, 2803, 2807, 2811, 2815, 2819, 0}, 2, 1, 754, 241, {2587,1245,2835,35120,2843,1210,0,0,0,0,0,0,0,0},{2568,1882,35130,0,0,0,0,0},{274,331,8214,8204,2862,8237,8242,8223,8229,0,0,0},{280,323,8274,8287,2887,2873,2902,0,0}}, - {2909, 14812, 2936, 2947, 1906, 352, 7992, 21969, {3719, 3726, 3733, 3741, 3751, 3760, 3767}, {3776, 3780, 3784, 3788, 3792, 3796, 3800}, {2018, 2403, 2405, 3804, 2405, 2409, 2018}, {3806, 3814, 3823, 2715, 3829, 3833, 3838, 2735, 2742, 3843, 2760, 3851, 0}, {3806, 3814, 3823, 2715, 3829, 3833, 3838, 2735, 2742, 3843, 2760, 3851, 0}, {2778, 2782, 3860, 2791, 3829, 2795, 2799, 2803, 2807, 3864, 2815, 3868, 0}, {2778, 2782, 3860, 2791, 3829, 2795, 2799, 2803, 2807, 3864, 2815, 3868, 0}, 0, 0, 239, 241, {14812,1221,14,2835,1210,0,0,0,0,0,0,0,0,0},{2909,3672,0,0,0,0,0,0},{2947,35,274,331,0,0,0,0,0,0,0,0},{2936,23,280,323,0,0,0,0,0}}, + {2909, 14812, 2936, 2947, 1906, 352, 7213, 7218, {3719, 3726, 3733, 3741, 3751, 3760, 3767}, {3776, 3780, 3784, 3788, 3792, 3796, 3800}, {2018, 2403, 2405, 3804, 2405, 2409, 2018}, {3806, 3814, 3823, 2715, 3829, 3833, 3838, 2735, 2742, 3843, 2760, 3851, 0}, {3806, 3814, 3823, 2715, 3829, 3833, 3838, 2735, 2742, 3843, 2760, 3851, 0}, {2778, 2782, 3860, 2791, 3829, 2795, 2799, 2803, 2807, 3864, 2815, 3868, 0}, {2778, 2782, 3860, 2791, 3829, 2795, 2799, 2803, 2807, 3864, 2815, 3868, 0}, 0, 0, 239, 241, {14812,1221,14,2835,1210,0,0,0,0,0,0,0,0,0},{2909,3672,0,0,0,0,0,0},{2947,35,274,331,0,0,0,0,0,0,0,0},{2936,23,280,323,0,0,0,0,0}}, {4342, 243, 23, 35, 947, 3985, 962, 968, {3997, 4005, 4011, 4018, 4029, 4036, 4044}, {4052, 4057, 4062, 4067, 4073, 4078, 4083}, {2692, 2411, 2403, 2403, 4089, 4091, 2018}, {4093, 4099, 4107, 4113, 4119, 4124, 4130, 4136, 4143, 4154, 4162, 4172, 0}, {4182, 4188, 4196, 1102, 4202, 4207, 4213, 4219, 4226, 1140, 4237, 4247, 0}, {4257, 4262, 4062, 4267, 4272, 4277, 4282, 4287, 4292, 4298, 4303, 4308, 0}, {4257, 4262, 4062, 4267, 4272, 4277, 4282, 4287, 4292, 4298, 4303, 4308, 0}, 0, 1, 239, 241, {243,14,1229,1236,1210,0,0,0,0,0,0,0,0,0},{4313,4342,4369,0,0,0,0,0},{35,2947,331,274,0,0,0,0,0,0,0,0},{23,2936,323,280,0,0,0,0,0}}, {36205, 243, 280, 274, 1906, 352, 1924, 1927, {4874, 4883, 4889, 4895, 4904, 4910, 4919}, {4926, 4931, 4936, 4941, 4946, 4951, 4956}, {2692, 2411, 2403, 2403, 4089, 4091, 2018}, {4961, 4969, 4978, 4983, 4989, 4993, 4998, 5006, 5012, 5022, 1148, 5030, 0}, {4961, 4969, 4978, 4983, 4989, 4993, 4998, 5006, 5012, 5022, 1148, 5030, 0}, {5040, 5046, 4978, 5053, 4989, 4993, 5058, 5006, 5064, 1195, 1200, 5070, 0}, {5040, 5046, 4978, 5053, 4989, 4993, 5058, 5006, 5064, 1195, 1200, 5070, 0}, 2, 1, 239, 241, {243,14,1245,1236,1210,0,0,0,0,0,0,0,0,0},{4857,5076,3672,0,0,0,0,0},{274,331,5085,5091,5101,0,0,0,0,0,0,0},{280,323,0,0,0,0,0,0,0}}, {1882, 2261, 323, 331, 1906, 11991, 36228, 36238, {9068, 9077, 9089, 9096, 9104, 9114, 9120}, {9127, 9131, 9135, 9139, 9143, 9148, 9152}, {0, 0, 0, 0, 0, 0, 0}, {2413, 2420, 15113, 2434, 2440, 2444, 2449, 11959, 36246, 36256, 36264, 36273, 0}, {2413, 2420, 15113, 2434, 2440, 2444, 2449, 11959, 36246, 36256, 36264, 36273, 0}, {2497, 2501, 2505, 2509, 2440, 2513, 2517, 11966, 2525, 2529, 2533, 2537, 0}, {2497, 2501, 2505, 2509, 2440, 2513, 2517, 11966, 2525, 2529, 2533, 2537, 0}, 0, 1, 754, 241, {2261,2843,1895,2587,9640,1245,11970,1210,0,0,0,0,0,0},{1882,2554,2568,0,0,0,0,0},{331,274,0,0,0,0,0,0,0,0,0,0},{323,280,0,0,0,0,0,0,0}}, diff --git a/mono/metadata/decimal.c b/mono/metadata/decimal.c index 39d226d3b25..3bbd0058032 100644 --- a/mono/metadata/decimal.c +++ b/mono/metadata/decimal.c @@ -577,7 +577,7 @@ my_g_bit_nth_msf (gsize mask) if (_BitScanReverse (&bIndex, mask)) return bIndex; return -1; -#elif defined(__x86_64__) && defined(_MSC_VER) +#elif defined(_M_X64) && defined(_MSC_VER) unsigned long bIndex = 0; if (_BitScanReverse64 (&bIndex, mask)) return bIndex; @@ -597,7 +597,7 @@ my_g_bit_nth_msf (gsize mask) i = sizeof (gsize) * 8; while (i > 0) { i --; - if (mask & (1UL << i)) + if (mask & (1ULL << i)) return i; } return -1; diff --git a/mono/metadata/domain-internals.h b/mono/metadata/domain-internals.h index 119f173dd09..065e0458fa2 100644 --- a/mono/metadata/domain-internals.h +++ b/mono/metadata/domain-internals.h @@ -175,6 +175,7 @@ typedef struct typedef struct { guint32 stack_size; + guint32 epilog_size; } MonoArchEHJitInfo; typedef struct { @@ -187,6 +188,14 @@ typedef struct { 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 @@ -455,6 +464,19 @@ mono_cleanup (void) MONO_INTERNAL; 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; diff --git a/mono/metadata/domain.c b/mono/metadata/domain.c old mode 100644 new mode 100755 index b1b912f4e9b..e30c0345c0a --- a/mono/metadata/domain.c +++ b/mono/metadata/domain.c @@ -116,8 +116,6 @@ typedef struct { 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[] = { @@ -160,876 +158,16 @@ gint32 mono_domain_get_tls_offset (void) { int offset = -1; + +#ifdef HOST_WIN32 + if (appdomain_thread_id) + offset = appdomain_thread_id; +#else MONO_THREAD_VAR_OFFSET (tls_appdomain, offset); -/* __asm ("jmp 1f; .section writetext, \"awx\"; 1: movl $tls_appdomain@ntpoff, %0; jmp 2f; .previous; 2:" - : "=r" (offset));*/ +#endif 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))) @@ -1302,7 +440,7 @@ mono_domain_create (void) 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); @@ -2094,9 +1232,9 @@ mono_domain_free (MonoDomain *domain, gboolean force) */ 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); diff --git a/mono/metadata/exception.c b/mono/metadata/exception.c index 24bfd6ed5ba..cf42445fa78 100644 --- a/mono/metadata/exception.c +++ b/mono/metadata/exception.c @@ -87,10 +87,12 @@ mono_exception_from_name_domain (MonoDomain *domain, MonoImage *image, MonoException * mono_exception_from_token (MonoImage *image, guint32 token) { + MonoError error; MonoClass *klass; MonoObject *o; - klass = mono_class_get (image, token); + klass = mono_class_get_checked (image, token, &error); + g_assert (mono_error_ok (&error)); /* FIXME handle the error. */ o = mono_object_new (mono_domain_get (), klass); g_assert (o != NULL); @@ -197,7 +199,9 @@ MonoException * mono_exception_from_token_two_strings (MonoImage *image, guint32 token, MonoString *a1, MonoString *a2) { - MonoClass *klass = mono_class_get (image, token); + MonoError error; + MonoClass *klass = mono_class_get_checked (image, token, &error); + g_assert (mono_error_ok (&error)); /* FIXME handle the error. */ return create_exception_two_strings (klass, a1, a2); } diff --git a/mono/metadata/gc-internal.h b/mono/metadata/gc-internal.h index f2e59acb844..7b8836363f8 100644 --- a/mono/metadata/gc-internal.h +++ b/mono/metadata/gc-internal.h @@ -13,7 +13,6 @@ #include #include #include -#include #include typedef struct { @@ -21,14 +20,7 @@ typedef struct { int major_gc_count; long long minor_gc_time; long long major_gc_time; -#ifdef HEAVY_STATISTICS - unsigned long long gray_queue_section_alloc; - unsigned long long gray_queue_section_free; - unsigned long long gray_queue_enqueue_fast_path; - unsigned long long gray_queue_dequeue_fast_path; - unsigned long long gray_queue_enqueue_slow_path; - unsigned long long gray_queue_dequeue_slow_path; -#endif + long long major_gc_time_concurrent; } GCStats; #define mono_domain_finalizers_lock(domain) mono_mutex_lock (&(domain)->finalizable_objects_hash_lock); @@ -337,6 +329,8 @@ void mono_gc_set_skip_thread (gboolean skip) MONO_INTERNAL; */ 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; diff --git a/mono/metadata/gc.c b/mono/metadata/gc.c index 03b182b99f4..4e025385b76 100644 --- a/mono/metadata/gc.c +++ b/mono/metadata/gc.c @@ -1154,14 +1154,7 @@ mono_gc_init (void) mono_counters_register ("Major GC collections", MONO_COUNTER_GC | MONO_COUNTER_INT, &gc_stats.major_gc_count); mono_counters_register ("Minor GC time", MONO_COUNTER_GC | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &gc_stats.minor_gc_time); mono_counters_register ("Major GC time", MONO_COUNTER_GC | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &gc_stats.major_gc_time); -#ifdef HEAVY_STATISTICS - mono_counters_register ("Gray Queue alloc section", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &gc_stats.gray_queue_section_alloc); - mono_counters_register ("Gray Queue free section", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &gc_stats.gray_queue_section_free); - mono_counters_register ("Gray Queue enqueue fast path", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &gc_stats.gray_queue_enqueue_fast_path); - mono_counters_register ("Gray Queue dequeue fast path", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &gc_stats.gray_queue_dequeue_fast_path); - mono_counters_register ("Gray Queue enqueue slow path", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &gc_stats.gray_queue_enqueue_slow_path); - mono_counters_register ("Gray Queue dequeue slow path", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &gc_stats.gray_queue_dequeue_slow_path); -#endif + mono_counters_register ("Major GC time concurrent", MONO_COUNTER_GC | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &gc_stats.major_gc_time_concurrent); mono_gc_base_init (); @@ -1231,7 +1224,7 @@ mono_gc_cleanup (void) 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; diff --git a/mono/metadata/icall-def.h b/mono/metadata/icall-def.h index 103eb3c4230..257b8332f5f 100644 --- a/mono/metadata/icall-def.h +++ b/mono/metadata/icall-def.h @@ -797,6 +797,7 @@ ICALL(STRING_8a, "GetLOSLimit", ves_icall_System_String_GetLOSLimit) 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) diff --git a/mono/metadata/icall.c b/mono/metadata/icall.c index ddec8e43053..763b2f638bf 100644 --- a/mono/metadata/icall.c +++ b/mono/metadata/icall.c @@ -907,11 +907,12 @@ ves_icall_System_Runtime_CompilerServices_RuntimeHelpers_RunClassConstructor (Mo ICALL_EXPORT void ves_icall_System_Runtime_CompilerServices_RuntimeHelpers_RunModuleConstructor (MonoImage *image) { - MONO_ARCH_SAVE_REGS; + MonoError error; mono_image_check_for_module_cctor (image); if (image->has_module_cctor) { - MonoClass *module_klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | 1); + MonoClass *module_klass = mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF | 1, &error); + mono_error_raise_exception (&error); /*It's fine to raise the exception here*/ mono_runtime_class_init (mono_class_vtable_full (mono_domain_get (), module_klass, TRUE)); } @@ -1673,8 +1674,7 @@ ves_icall_System_Reflection_FieldInfo_GetTypeModifiers (MonoReflectionField *fie { MonoError error; MonoType *type = mono_field_get_type_checked (field->field, &error); - if (!mono_error_ok (&error)) - mono_error_raise_exception (&error); + mono_error_raise_exception (&error); return type_array_from_modifiers (field->field->parent->image, type, optional); } @@ -5161,21 +5161,16 @@ mono_module_get_types (MonoDomain *domain, MonoImage *image, MonoArray **excepti attrs = mono_metadata_decode_row_col (tdef, i, MONO_TYPEDEF_FLAGS); visibility = attrs & TYPE_ATTRIBUTE_VISIBILITY_MASK; if (!exportedOnly || (visibility == TYPE_ATTRIBUTE_PUBLIC || visibility == TYPE_ATTRIBUTE_NESTED_PUBLIC)) { - klass = mono_class_get (image, (i + 1) | MONO_TOKEN_TYPE_DEF); + MonoError error; + klass = mono_class_get_checked (image, (i + 1) | MONO_TOKEN_TYPE_DEF, &error); + g_assert (!mono_loader_get_last_error ()); /* Plug any leaks */ + if (klass) { mono_array_setref (res, count, mono_type_get_object (domain, &klass->byval_arg)); } else { - MonoLoaderError *error; - MonoException *ex; - - error = mono_loader_get_last_error (); - g_assert (error != NULL); - - ex = mono_loader_error_prepare_exception (error); + MonoException *ex = mono_error_convert_to_exception (&error); mono_array_setref (*exceptions, count, ex); } - if (mono_loader_get_last_error ()) - mono_loader_clear_error (); count++; } } @@ -5266,7 +5261,7 @@ ves_icall_System_Reflection_Assembly_GetTypes (MonoReflectionAssembly *assembly, mono_loader_clear_error (); exl = mono_array_new (domain, mono_defaults.exception_class, length); - /* Types for which mono_class_get () succeeded */ + /* Types for which mono_class_get_checked () succeeded */ for (i = 0, tmp = list; tmp; i++, tmp = tmp->next) { MonoException *exc = mono_class_get_exception_for_failure (tmp->data); mono_array_setref (exl, i, exc); @@ -5321,6 +5316,7 @@ ves_icall_System_Reflection_AssemblyName_ParseName (MonoReflectionAssemblyName * ICALL_EXPORT MonoReflectionType* ves_icall_System_Reflection_Module_GetGlobalType (MonoReflectionModule *module) { + MonoError error; MonoDomain *domain = mono_object_domain (module); MonoClass *klass; @@ -5332,7 +5328,8 @@ ves_icall_System_Reflection_Module_GetGlobalType (MonoReflectionModule *module) /* These images do not have a global type */ return NULL; - klass = mono_class_get (module->image, 1 | MONO_TOKEN_TYPE_DEF); + klass = mono_class_get_checked (module->image, 1 | MONO_TOKEN_TYPE_DEF, &error); + mono_error_raise_exception (&error); return mono_type_get_object (domain, &klass->byval_arg); } @@ -5442,19 +5439,20 @@ init_generic_context_from_args (MonoGenericContext *context, MonoArray *type_arg } ICALL_EXPORT MonoType* -ves_icall_System_Reflection_Module_ResolveTypeToken (MonoImage *image, guint32 token, MonoArray *type_args, MonoArray *method_args, MonoResolveTokenError *error) +ves_icall_System_Reflection_Module_ResolveTypeToken (MonoImage *image, guint32 token, MonoArray *type_args, MonoArray *method_args, MonoResolveTokenError *resolve_error) { MonoClass *klass; int table = mono_metadata_token_table (token); int index = mono_metadata_token_index (token); MonoGenericContext context; + MonoError error; - *error = ResolveTokenError_Other; + *resolve_error = ResolveTokenError_Other; /* Validate token */ if ((table != MONO_TABLE_TYPEDEF) && (table != MONO_TABLE_TYPEREF) && (table != MONO_TABLE_TYPESPEC)) { - *error = ResolveTokenError_BadTable; + *resolve_error = ResolveTokenError_BadTable; return NULL; } @@ -5470,15 +5468,15 @@ ves_icall_System_Reflection_Module_ResolveTypeToken (MonoImage *image, guint32 t } if ((index <= 0) || (index > image->tables [table].rows)) { - *error = ResolveTokenError_OutOfRange; + *resolve_error = ResolveTokenError_OutOfRange; return NULL; } init_generic_context_from_args (&context, type_args, method_args); - klass = mono_class_get_full (image, token, &context); - - if (mono_loader_get_last_error ()) - mono_raise_exception (mono_loader_error_prepare_exception (mono_loader_get_last_error ())); + klass = mono_class_get_checked (image, token, &error); + if (klass) + klass = mono_class_inflate_generic_class_checked (klass, &context, &error); + mono_error_raise_exception (&error); if (klass) return &klass->byval_arg; @@ -7415,6 +7413,8 @@ ves_icall_System_Char_GetDataTablePointers (int category_data_version, /* * We return NULL for no modifiers so the corlib code can return Type.EmptyTypes * and avoid useless allocations. + * + * MAY THROW */ static MonoArray* type_array_from_modifiers (MonoImage *image, MonoType *type, int optional) @@ -7431,7 +7431,9 @@ type_array_from_modifiers (MonoImage *image, MonoType *type, int optional) count = 0; for (i = 0; i < type->num_mods; ++i) { if ((optional && !type->modifiers [i].required) || (!optional && type->modifiers [i].required)) { - MonoClass *klass = mono_class_get (image, type->modifiers [i].token); + MonoError error; + MonoClass *klass = mono_class_get_checked (image, type->modifiers [i].token, &error); + mono_error_raise_exception (&error); /* this is safe, no cleanup needed on callers */ mono_array_setref (res, count, mono_type_get_object (mono_domain_get (), &klass->byval_arg)); count++; } diff --git a/mono/metadata/jit-info.c b/mono/metadata/jit-info.c new file mode 100644 index 00000000000..cc0b76622fb --- /dev/null +++ b/mono/metadata/jit-info.c @@ -0,0 +1,946 @@ +/* + * 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 +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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; + } +} diff --git a/mono/metadata/loader.c b/mono/metadata/loader.c index 7cbc0810c00..f7dc1497a01 100644 --- a/mono/metadata/loader.c +++ b/mono/metadata/loader.c @@ -395,9 +395,9 @@ find_cached_memberref_sig (MonoImage *image, guint32 sig_idx) { gpointer res; - mono_loader_lock (); + mono_image_lock (image); res = g_hash_table_lookup (image->memberref_signatures, GUINT_TO_POINTER (sig_idx)); - mono_loader_unlock (); + mono_image_unlock (image); return res; } @@ -407,7 +407,7 @@ cache_memberref_sig (MonoImage *image, guint32 sig_idx, gpointer sig) { gpointer prev_sig; - mono_loader_lock (); + mono_image_lock (image); prev_sig = g_hash_table_lookup (image->memberref_signatures, GUINT_TO_POINTER (sig_idx)); if (prev_sig) { /* Somebody got in before us */ @@ -418,8 +418,7 @@ cache_memberref_sig (MonoImage *image, guint32 sig_idx, gpointer sig) /* An approximation based on glib 2.18 */ memberref_sig_cache_size += sizeof (gpointer) * 4; } - - mono_loader_unlock (); + mono_image_unlock (image); return sig; } @@ -437,6 +436,7 @@ field_from_memberref (MonoImage *image, guint32 token, MonoClass **retklass, const char *fname; const char *ptr; guint32 idx = mono_metadata_token_index (token); + MonoError error; mono_metadata_decode_row (&tables [MONO_TABLE_MEMBERREF], idx-1, cols, MONO_MEMBERREF_SIZE); nindex = cols [MONO_MEMBERREF_CLASS] >> MONO_MEMBERREF_PARENT_BITS; @@ -452,15 +452,29 @@ field_from_memberref (MonoImage *image, guint32 token, MonoClass **retklass, switch (class) { case MONO_MEMBERREF_PARENT_TYPEDEF: class_table = MONO_TOKEN_TYPE_DEF; - klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | nindex); + klass = mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF | nindex, &error); + if (!mono_error_ok (&error)) { + /*FIXME don't swallow the error message*/ + mono_error_cleanup (&error); + } + break; case MONO_MEMBERREF_PARENT_TYPEREF: class_table = MONO_TOKEN_TYPE_REF; - klass = mono_class_from_typeref (image, MONO_TOKEN_TYPE_REF | nindex); + klass = mono_class_from_typeref_checked (image, MONO_TOKEN_TYPE_REF | nindex, &error); + if (!mono_error_ok (&error)) { + /*FIXME don't swallow the error message*/ + mono_error_cleanup (&error); + } + break; case MONO_MEMBERREF_PARENT_TYPESPEC: class_table = MONO_TOKEN_TYPE_SPEC; - klass = mono_class_get_full (image, MONO_TOKEN_TYPE_SPEC | nindex, context); + klass = mono_class_get_and_inflate_typespec_checked (image, MONO_TOKEN_TYPE_SPEC | nindex, context, &error); + if (!mono_error_ok (&error)) { + /*FIXME don't swallow the error message*/ + mono_error_cleanup (&error); + } break; default: /*FIXME this must set a loader error!*/ @@ -513,6 +527,7 @@ MonoClassField* mono_field_from_token (MonoImage *image, guint32 token, MonoClass **retklass, MonoGenericContext *context) { + MonoError error; MonoClass *k; guint32 type; MonoClassField *field; @@ -543,9 +558,12 @@ mono_field_from_token (MonoImage *image, guint32 token, MonoClass **retklass, type = mono_metadata_typedef_from_field (image, mono_metadata_token_index (token)); if (!type) return NULL; - k = mono_class_get (image, MONO_TOKEN_TYPE_DEF | type); - if (!k) + k = mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF | type, &error); + if (!k) { + mono_loader_set_error_from_mono_error (&error); + mono_error_cleanup (&error); /*FIXME don't swallow the error message*/ return NULL; + } mono_class_init (k); if (retklass) *retklass = k; @@ -941,6 +959,7 @@ method_from_memberref (MonoImage *image, guint32 idx, MonoGenericContext *typesp const char *mname; MonoMethodSignature *sig; const char *ptr; + MonoError error; mono_metadata_decode_row (&tables [MONO_TABLE_MEMBERREF], idx-1, cols, 3); nindex = cols [MONO_MEMBERREF_CLASS] >> MONO_MEMBERREF_PARENT_BITS; @@ -960,12 +979,10 @@ method_from_memberref (MonoImage *image, guint32 idx, MonoGenericContext *typesp switch (class) { case MONO_MEMBERREF_PARENT_TYPEREF: - klass = mono_class_from_typeref (image, MONO_TOKEN_TYPE_REF | nindex); + klass = mono_class_from_typeref_checked (image, MONO_TOKEN_TYPE_REF | nindex, &error); if (!klass) { - char *name = mono_class_name_from_token (image, MONO_TOKEN_TYPE_REF | nindex); - g_warning ("Missing method %s in assembly %s, type %s", mname, image->name, name); - mono_loader_set_error_type_load (name, image->assembly_name); - g_free (name); + mono_loader_set_error_from_mono_error (&error); + mono_error_cleanup (&error); /* FIXME Don't swallow the error */ return NULL; } break; @@ -973,22 +990,18 @@ method_from_memberref (MonoImage *image, guint32 idx, MonoGenericContext *typesp /* * Parse the TYPESPEC in the parent's context. */ - klass = mono_class_get_full (image, MONO_TOKEN_TYPE_SPEC | nindex, typespec_context); + klass = mono_class_get_and_inflate_typespec_checked (image, MONO_TOKEN_TYPE_SPEC | nindex, typespec_context, &error); if (!klass) { - char *name = mono_class_name_from_token (image, MONO_TOKEN_TYPE_SPEC | nindex); - g_warning ("Missing method %s in assembly %s, type %s", mname, image->name, name); - mono_loader_set_error_type_load (name, image->assembly_name); - g_free (name); + mono_loader_set_error_from_mono_error (&error); + mono_error_cleanup (&error); /*FIXME don't swallow the error message*/ return NULL; } break; case MONO_MEMBERREF_PARENT_TYPEDEF: - klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | nindex); + klass = mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF | nindex, &error); if (!klass) { - char *name = mono_class_name_from_token (image, MONO_TOKEN_TYPE_DEF | nindex); - g_warning ("Missing method %s in assembly %s, type %s", mname, image->name, name); - mono_loader_set_error_type_load (name, image->assembly_name); - g_free (name); + mono_loader_set_error_from_mono_error (&error); + mono_error_cleanup (&error); /*FIXME don't swallow the error message*/ return NULL; } break; @@ -1230,27 +1243,29 @@ mono_dllmap_insert (MonoImage *assembly, const char *dll, const char *func, cons mono_loader_init (); - mono_loader_lock (); - if (!assembly) { entry = g_malloc0 (sizeof (MonoDllMap)); entry->dll = dll? g_strdup (dll): NULL; entry->target = tdll? g_strdup (tdll): NULL; entry->func = func? g_strdup (func): NULL; entry->target_func = tfunc? g_strdup (tfunc): NULL; + + mono_loader_lock (); entry->next = global_dll_map; global_dll_map = entry; + mono_loader_unlock (); } else { entry = mono_image_alloc0 (assembly, sizeof (MonoDllMap)); entry->dll = dll? mono_image_strdup (assembly, dll): NULL; entry->target = tdll? mono_image_strdup (assembly, tdll): NULL; entry->func = func? mono_image_strdup (assembly, func): NULL; entry->target_func = tfunc? mono_image_strdup (assembly, tfunc): NULL; + + mono_image_lock (assembly); entry->next = assembly->dll_map; assembly->dll_map = entry; + mono_image_unlock (assembly); } - - mono_loader_unlock (); } static void @@ -1369,14 +1384,14 @@ mono_lookup_pinvoke_call (MonoMethod *method, const char **exc_class, const char mono_dllmap_lookup (image, orig_scope, import, &new_scope, &import); if (!module) { - mono_loader_lock (); + mono_image_lock (image); if (!image->pinvoke_scopes) { image->pinvoke_scopes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); image->pinvoke_scope_filenames = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); } module = g_hash_table_lookup (image->pinvoke_scopes, new_scope); found_name = g_hash_table_lookup (image->pinvoke_scope_filenames, new_scope); - mono_loader_unlock (); + mono_image_unlock (image); if (module) cached = TRUE; if (found_name) @@ -1542,12 +1557,12 @@ mono_lookup_pinvoke_call (MonoMethod *method, const char **exc_class, const char if (!cached) { mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT, "DllImport loaded library '%s'.", found_name); - mono_loader_lock (); + mono_image_lock (image); if (!g_hash_table_lookup (image->pinvoke_scopes, new_scope)) { g_hash_table_insert (image->pinvoke_scopes, g_strdup (new_scope), module); g_hash_table_insert (image->pinvoke_scope_filenames, g_strdup (new_scope), g_strdup (found_name)); } - mono_loader_unlock (); + mono_image_unlock (image); } mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT, @@ -1676,6 +1691,7 @@ static MonoMethod * mono_get_method_from_token (MonoImage *image, guint32 token, MonoClass *klass, MonoGenericContext *context, gboolean *used_context) { + MonoError error; MonoMethod *result; int table = mono_metadata_token_table (token); int idx = mono_metadata_token_index (token); @@ -1717,6 +1733,18 @@ mono_get_method_from_token (MonoImage *image, guint32 token, MonoClass *klass, return NULL; } + if (!klass) { + guint32 type = mono_metadata_typedef_from_method (image, token); + if (!type) + return NULL; + klass = mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF | type, &error); + if (klass == NULL) { + mono_loader_set_error_from_mono_error (&error); + mono_error_cleanup (&error); /*FIXME don't swallow the error message*/ + return NULL; + } + } + mono_metadata_decode_row (&image->tables [MONO_TABLE_METHOD], idx - 1, cols, 6); if ((cols [2] & METHOD_ATTRIBUTE_PINVOKE_IMPL) || @@ -1729,15 +1757,6 @@ mono_get_method_from_token (MonoImage *image, guint32 token, MonoClass *klass, mono_stats.method_count ++; - if (!klass) { /*FIXME put this before the image alloc*/ - guint32 type = mono_metadata_typedef_from_method (image, token); - if (!type) - return NULL; - klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | type); - if (klass == NULL) - return NULL; - } - result->slot = -1; result->klass = klass; result->flags = cols [2]; @@ -1758,11 +1777,15 @@ mono_get_method_from_token (MonoImage *image, guint32 token, MonoClass *klass, if (*sig & 0x10) generic_container = mono_metadata_load_generic_params (image, token, container); if (generic_container) { + MonoError error; result->is_generic = TRUE; generic_container->owner.method = result; /*FIXME put this before the image alloc*/ - if (!mono_metadata_load_generic_param_constraints_full (image, token, generic_container)) + if (!mono_metadata_load_generic_param_constraints_checked (image, token, generic_container, &error)) { + mono_loader_set_error_from_mono_error (&error); + mono_error_cleanup (&error); /*FIXME don't swallow the error message*/ return NULL; + } container = generic_container; } @@ -1917,17 +1940,11 @@ MonoMethod * mono_get_method_constrained_with_method (MonoImage *image, MonoMethod *method, MonoClass *constrained_class, MonoGenericContext *context) { - MonoMethod *result; - g_assert (method); - mono_loader_lock (); - - result = get_method_constrained (image, method, constrained_class, context); - - mono_loader_unlock (); - return result; + return get_method_constrained (image, method, constrained_class, context); } + /** * mono_get_method_constrained: * @@ -1943,17 +1960,12 @@ mono_get_method_constrained (MonoImage *image, guint32 token, MonoClass *constra { MonoMethod *result; - mono_loader_lock (); - *cil_method = mono_get_method_from_token (image, token, NULL, context, NULL); - if (!*cil_method) { - mono_loader_unlock (); + if (!*cil_method) return NULL; - } result = get_method_constrained (image, *cil_method, constrained_class, context); - mono_loader_unlock (); return result; } @@ -2266,6 +2278,18 @@ mono_stack_walk_no_il (MonoStackWalk func, gpointer user_data) mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (stack_walk_adapter, NULL, MONO_UNWIND_DEFAULT, &ud); } +/* + * mono_stack_walk_async_safe: + * + * Async safe version callable from signal handlers. + */ +void +mono_stack_walk_async_safe (MonoStackWalk func, gpointer user_data) +{ + StackWalkUserData ud = { func, user_data }; + mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (stack_walk_adapter, NULL, MONO_UNWIND_NONE, &ud); +} + static gboolean last_managed (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data) { @@ -2370,7 +2394,7 @@ mono_method_signature_checked (MonoMethod *m, MonoError *error) const char *sig; gboolean can_cache_signature; MonoGenericContainer *container; - MonoMethodSignature *signature = NULL; + MonoMethodSignature *signature = NULL, *sig2; guint32 sig_offset; /* We need memory barriers below because of the double-checked locking pattern */ @@ -2380,34 +2404,31 @@ mono_method_signature_checked (MonoMethod *m, MonoError *error) if (m->signature) return m->signature; - mono_loader_lock (); - - if (m->signature) { - mono_loader_unlock (); - return m->signature; - } + img = m->klass->image; if (m->is_inflated) { MonoMethodInflated *imethod = (MonoMethodInflated *) m; /* the lock is recursive */ signature = mono_method_signature (imethod->declaring); signature = inflate_generic_signature_checked (imethod->declaring->klass->image, signature, mono_method_get_context (m), error); - if (!mono_error_ok (error)) { - mono_loader_unlock (); + if (!mono_error_ok (error)) return NULL; - } inflated_signatures_size += mono_metadata_signature_size (signature); + mono_image_lock (img); + mono_memory_barrier (); - m->signature = signature; - mono_loader_unlock (); + if (!m->signature) + m->signature = signature; + + mono_image_unlock (img); + return m->signature; } g_assert (mono_metadata_token_table (m->token) == MONO_TABLE_METHOD); idx = mono_metadata_token_index (m->token); - img = m->klass->image; sig = mono_metadata_blob_heap (img, sig_offset = mono_metadata_decode_row_col (&img->tables [MONO_TABLE_METHOD], idx - 1, MONO_METHOD_SIGNATURE)); @@ -2424,28 +2445,33 @@ mono_method_signature_checked (MonoMethod *m, MonoError *error) if (mono_metadata_method_has_param_attrs (img, idx)) can_cache_signature = FALSE; - if (can_cache_signature) + if (can_cache_signature) { + mono_image_lock (img); signature = g_hash_table_lookup (img->method_signatures, sig); + mono_image_unlock (img); + } if (!signature) { const char *sig_body; /*TODO we should cache the failure result somewhere*/ - if (!mono_verifier_verify_method_signature (img, sig_offset, error)) { - mono_loader_unlock (); + if (!mono_verifier_verify_method_signature (img, sig_offset, error)) return NULL; - } size = mono_metadata_decode_blob_size (sig, &sig_body); signature = mono_metadata_parse_method_signature_full (img, container, idx, sig_body, NULL); if (!signature) { mono_error_set_from_loader_error (error); - mono_loader_unlock (); return NULL; } - if (can_cache_signature) - g_hash_table_insert (img->method_signatures, (gpointer)sig, signature); + if (can_cache_signature) { + mono_image_lock (img); + sig2 = g_hash_table_lookup (img->method_signatures, sig); + if (!sig2) + g_hash_table_insert (img->method_signatures, (gpointer)sig, signature); + mono_image_unlock (img); + } signatures_size += mono_metadata_signature_size (signature); } @@ -2453,17 +2479,14 @@ mono_method_signature_checked (MonoMethod *m, MonoError *error) /* Verify metadata consistency */ if (signature->generic_param_count) { if (!container || !container->is_method) { - mono_loader_unlock (); mono_error_set_method_load (error, m->klass, m->name, "Signature claims method has generic parameters, but generic_params table says it doesn't for method 0x%08x from image %s", idx, img->name); return NULL; } if (container->type_argc != signature->generic_param_count) { - mono_loader_unlock (); mono_error_set_method_load (error, m->klass, m->name, "Inconsistent generic parameter count. Signature says %d, generic_params table says %d for method 0x%08x from image %s", signature->generic_param_count, container->type_argc, idx, img->name); return NULL; } } else if (container && container->is_method && container->type_argc) { - mono_loader_unlock (); mono_error_set_method_load (error, m->klass, m->name, "generic_params table claims method has generic parameters, but signature says it doesn't for method 0x%08x from image %s", idx, img->name); return NULL; } @@ -2494,17 +2517,20 @@ mono_method_signature_checked (MonoMethod *m, MonoError *error) case PINVOKE_ATTRIBUTE_CALL_CONV_GENERIC: case PINVOKE_ATTRIBUTE_CALL_CONV_GENERICINST: default: - mono_loader_unlock (); mono_error_set_method_load (error, m->klass, m->name, "unsupported calling convention : 0x%04x for method 0x%08x from image %s", piinfo->piflags, idx, img->name); return NULL; } signature->call_convention = conv; } + mono_image_lock (img); + mono_memory_barrier (); - m->signature = signature; + if (!m->signature) + m->signature = signature; + + mono_image_unlock (img); - mono_loader_unlock (); return m->signature; } @@ -2561,26 +2587,32 @@ mono_method_get_header (MonoMethod *method) if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) || (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) || (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) return NULL; + img = method->klass->image; + if (method->is_inflated) { MonoMethodInflated *imethod = (MonoMethodInflated *) method; - MonoMethodHeader *header; + MonoMethodHeader *header, *iheader; - mono_loader_lock (); + header = mono_method_get_header (imethod->declaring); + if (!header) + return NULL; + + iheader = inflate_generic_header (header, mono_method_get_context (method)); + mono_metadata_free_mh (header); + + mono_image_lock (img); if (imethod->header) { - mono_loader_unlock (); + mono_metadata_free_mh (iheader); + mono_image_unlock (img); return imethod->header; } - header = mono_method_get_header (imethod->declaring); - if (!header) { - mono_loader_unlock (); - return NULL; - } + mono_memory_barrier (); + imethod->header = iheader; + + mono_image_unlock (img); - imethod->header = inflate_generic_header (header, mono_method_get_context (method)); - mono_loader_unlock (); - mono_metadata_free_mh (header); return imethod->header; } @@ -2596,7 +2628,6 @@ mono_method_get_header (MonoMethod *method) */ g_assert (mono_metadata_token_table (method->token) == MONO_TABLE_METHOD); idx = mono_metadata_token_index (method->token); - img = method->klass->image; rva = mono_metadata_decode_row_col (&img->tables [MONO_TABLE_METHOD], idx - 1, MONO_METHOD_RVA); if (!mono_verifier_verify_method_header (img, rva, NULL)) @@ -2630,7 +2661,8 @@ mono_method_get_flags (MonoMethod *method, guint32 *iflags) * Find the method index in the metadata methodDef table. */ guint32 -mono_method_get_index (MonoMethod *method) { +mono_method_get_index (MonoMethod *method) +{ MonoClass *klass = method->klass; int i; @@ -2654,4 +2686,3 @@ mono_method_get_index (MonoMethod *method) { } return 0; } - diff --git a/mono/metadata/loader.h b/mono/metadata/loader.h index b159dee727a..ae0ca441773 100644 --- a/mono/metadata/loader.h +++ b/mono/metadata/loader.h @@ -90,6 +90,9 @@ mono_stack_walk (MonoStackWalk func, void* user_data); MONO_API void mono_stack_walk_no_il (MonoStackWalk func, void* user_data); +MONO_API void +mono_stack_walk_async_safe (MonoStackWalk func, void* user_data); + MONO_END_DECLS #endif diff --git a/mono/metadata/marshal.c b/mono/metadata/marshal.c index 88bbaeb7a02..0c8fe33f219 100644 --- a/mono/metadata/marshal.c +++ b/mono/metadata/marshal.c @@ -2739,6 +2739,7 @@ mono_wrapper_info_create (MonoMethodBuilder *mb, WrapperSubtype subtype) static MonoClass* get_wrapper_target_class (MonoImage *image) { + MonoError error; MonoClass *klass; /* @@ -2754,10 +2755,12 @@ get_wrapper_target_class (MonoImage *image) * To avoid these problems, we put the wrappers into the class of * the image. */ - if (image_is_dynamic (image)) + if (image_is_dynamic (image)) { klass = ((MonoDynamicImage*)image)->wrappers_type; - else - klass = mono_class_get (image, mono_metadata_make_token (MONO_TABLE_TYPEDEF, 1)); + } else { + klass = mono_class_get_checked (image, mono_metadata_make_token (MONO_TABLE_TYPEDEF, 1), &error); + g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */ + } g_assert (klass); return klass; @@ -9490,8 +9493,9 @@ mono_marshal_set_callconv_from_modopt (MonoMethod *method, MonoMethodSignature * /* Why is this a modopt ? */ if (sig->ret && sig->ret->num_mods) { for (i = 0; i < sig->ret->num_mods; ++i) { - MonoClass *cmod_class = mono_class_get (method->klass->image, sig->ret->modifiers [i].token); - g_assert (cmod_class); + MonoError error; + MonoClass *cmod_class = mono_class_get_checked (method->klass->image, sig->ret->modifiers [i].token, &error); + g_assert (mono_error_ok (&error)); if ((cmod_class->image == mono_defaults.corlib) && !strcmp (cmod_class->name_space, "System.Runtime.CompilerServices")) { if (!strcmp (cmod_class->name, "CallConvCdecl")) csig->call_convention = MONO_CALL_C; diff --git a/mono/metadata/metadata-internals.h b/mono/metadata/metadata-internals.h index c577c64e278..c738d53654e 100644 --- a/mono/metadata/metadata-internals.h +++ b/mono/metadata/metadata-internals.h @@ -228,7 +228,7 @@ struct _MonoImage { MonoConcurrentHashTable *field_cache; /*protected by the image lock*/ /* indexed by typespec tokens. */ - GHashTable *typespec_cache; + GHashTable *typespec_cache; /* protected by the image lock */ /* indexed by token */ GHashTable *memberref_signatures; GHashTable *helper_signatures; @@ -317,6 +317,7 @@ struct _MonoImage { MonoDllMap *dll_map; /* interfaces IDs from this image */ + /* protected by the classes lock */ MonoBitSet *interface_bitset; /* when the image is being closed, this is abused as a list of @@ -528,7 +529,13 @@ struct _MonoMethodSignature { * Doesn't really belong here. */ typedef struct { + /* + * Enable aot caching for applications whose main assemblies are in + * this list. + */ + GSList *apps; GSList *assemblies; + char *aot_options; } MonoAotCacheConfig; #define MONO_SIZEOF_METHOD_SIGNATURE (sizeof (struct _MonoMethodSignature) - MONO_ZERO_LEN_ARRAY * SIZEOF_VOID_P) @@ -794,6 +801,8 @@ MonoMethod *mono_get_method_constrained_with_method (MonoImage *image, MonoMetho void mono_type_set_alignment (MonoTypeEnum type, int align) MONO_INTERNAL; MonoAotCacheConfig *mono_get_aot_cache_config (void) MONO_INTERNAL; +MonoType * +mono_type_create_from_typespec_checked (MonoImage *image, guint32 type_spec, MonoError *error) MONO_INTERNAL; #endif /* __MONO_METADATA_INTERNALS_H__ */ diff --git a/mono/metadata/metadata.c b/mono/metadata/metadata.c index 091ab5046e3..6b598020f03 100644 --- a/mono/metadata/metadata.c +++ b/mono/metadata/metadata.c @@ -3200,11 +3200,15 @@ do_mono_metadata_parse_type (MonoType *type, MonoImage *m, MonoGenericContainer case MONO_TYPE_CLASS: { guint32 token; MonoClass *class; + MonoError error; token = mono_metadata_parse_typedef_or_ref (m, ptr, &ptr); - class = mono_class_get (m, token); + class = mono_class_get_checked (m, token, &error); type->data.klass = class; - if (!class) + if (!class) { + mono_loader_set_error_from_mono_error (&error); + mono_error_cleanup (&error); /*FIXME don't swallow the error message*/ return FALSE; + } if (!compare_type_literals (class->byval_arg.type, type->type)) return FALSE; break; @@ -3377,7 +3381,16 @@ parse_section_data (MonoImage *m, int *num_clauses, const unsigned char *ptr) if (ec->flags == MONO_EXCEPTION_CLAUSE_FILTER) { ec->data.filter_offset = tof_value; } else if (ec->flags == MONO_EXCEPTION_CLAUSE_NONE) { - ec->data.catch_class = tof_value? mono_class_get (m, tof_value): 0; + ec->data.catch_class = NULL; + if (tof_value) { + MonoError error; + ec->data.catch_class = mono_class_get_checked (m, tof_value, &error); + if (!mono_error_ok (&error)) { + mono_error_cleanup (&error); /* FIXME don't swallow the error */ + g_free (clauses); + return NULL; + } + } } else { ec->data.catch_class = NULL; } @@ -3480,7 +3493,7 @@ mono_method_get_header_summary (MonoMethod *method, MonoMethodHeaderSummary *sum MonoMethodHeader * mono_metadata_parse_mh_full (MonoImage *m, MonoGenericContainer *container, const char *ptr) { - MonoMethodHeader *mh; + MonoMethodHeader *mh = NULL; unsigned char flags = *(const unsigned char *) ptr; unsigned char format = flags & METHOD_HEADER_FORMAT_MASK; guint16 fat_flags; @@ -3536,11 +3549,11 @@ mono_metadata_parse_mh_full (MonoImage *m, MonoGenericContainer *container, cons if (local_var_sig_tok) { int idx = (local_var_sig_tok & 0xffffff)-1; if (idx >= t->rows || idx < 0) - return NULL; + goto fail; mono_metadata_decode_row (t, idx, cols, 1); if (!mono_verifier_verify_standalone_signature (m, cols [MONO_STAND_ALONE_SIGNATURE], NULL)) - return NULL; + goto fail; } if (fat_flags & METHOD_HEADER_MORE_SECTS) clauses = parse_section_data (m, &num_clauses, (const unsigned char*)ptr); @@ -3559,11 +3572,8 @@ mono_metadata_parse_mh_full (MonoImage *m, MonoGenericContainer *container, cons for (i = 0; i < len; ++i) { mh->locals [i] = mono_metadata_parse_type_internal (m, container, MONO_PARSE_LOCAL, 0, TRUE, locals_ptr, &locals_ptr); - if (!mh->locals [i]) { - g_free (clauses); - g_free (mh); - return NULL; - } + if (!mh->locals [i]) + goto fail; } } else { mh = g_malloc0 (MONO_SIZEOF_METHOD_HEADER + num_clauses * sizeof (MonoExceptionClause)); @@ -3581,6 +3591,11 @@ mono_metadata_parse_mh_full (MonoImage *m, MonoGenericContainer *container, cons mh->num_clauses = num_clauses; } return mh; +fail: + g_free (clauses); + g_free (mh); + return NULL; + } /* @@ -4042,15 +4057,19 @@ mono_metadata_interfaces_from_typedef_full (MonoImage *meta, guint32 index, Mono pos = start; while (pos < tdef->rows) { + MonoError error; MonoClass *iface; mono_metadata_decode_row (tdef, pos, cols, MONO_INTERFACEIMPL_SIZE); if (cols [MONO_INTERFACEIMPL_CLASS] != loc.idx) break; - iface = mono_class_get_full ( - meta, mono_metadata_token_from_dor (cols [MONO_INTERFACEIMPL_INTERFACE]), context); - if (iface == NULL) + iface = mono_class_get_and_inflate_typespec_checked ( + meta, mono_metadata_token_from_dor (cols [MONO_INTERFACEIMPL_INTERFACE]), context, &error); + if (iface == NULL) { + mono_loader_set_error_from_mono_error (&error); + mono_error_cleanup (&error); /* FIXME Don't swallow the error */ return FALSE; + } result [pos - start] = iface; ++pos; } @@ -5279,12 +5298,26 @@ mono_metadata_implmap_from_method (MonoImage *meta, guint32 method_idx) /** * @image: context where the image is created * @type_spec: typespec token + * @deprecated use mono_type_create_from_typespec_checked that has proper error handling * * Creates a MonoType representing the TypeSpec indexed by the @type_spec * token. */ MonoType * mono_type_create_from_typespec (MonoImage *image, guint32 type_spec) +{ + MonoError error; + MonoType *type = mono_type_create_from_typespec_checked (image, type_spec, &error); + if (!type) { + mono_loader_set_error_from_mono_error (&error); + mono_error_cleanup (&error); /* FIXME don't swallow error*/ + } + return type; +} + +MonoType * +mono_type_create_from_typespec_checked (MonoImage *image, guint32 type_spec, MonoError *error) + { guint32 idx = mono_metadata_token_index (type_spec); MonoTableInfo *t; @@ -5293,13 +5326,13 @@ mono_type_create_from_typespec (MonoImage *image, guint32 type_spec) guint32 len; MonoType *type, *type2; - mono_loader_lock (); + mono_error_init (error); + mono_image_lock (image); type = g_hash_table_lookup (image->typespec_cache, GUINT_TO_POINTER (type_spec)); - if (type) { - mono_loader_unlock (); + mono_image_unlock (image); + if (type) return type; - } t = &image->tables [MONO_TABLE_TYPESPEC]; @@ -5307,7 +5340,7 @@ mono_type_create_from_typespec (MonoImage *image, guint32 type_spec) ptr = mono_metadata_blob_heap (image, cols [MONO_TYPESPEC_SIGNATURE]); if (!mono_verifier_verify_typespec_signature (image, cols [MONO_TYPESPEC_SIGNATURE], type_spec, NULL)) { - mono_loader_unlock (); + mono_error_set_bad_image (error, image, "Could not verify type spec %08x.", type_spec); return NULL; } @@ -5315,24 +5348,26 @@ mono_type_create_from_typespec (MonoImage *image, guint32 type_spec) type = mono_metadata_parse_type_internal (image, NULL, MONO_PARSE_TYPE, 0, TRUE, ptr, &ptr); if (!type) { - mono_loader_unlock (); + if (mono_loader_get_last_error ()) + mono_error_set_from_loader_error (error); + else + mono_error_set_bad_image (error, image, "Could not parse type spec %08x.", type_spec); return NULL; } - type2 = g_hash_table_lookup (image->typespec_cache, GUINT_TO_POINTER (type_spec)); - - if (type2) { - mono_loader_unlock (); - return type2; - } - type2 = mono_metadata_type_dup (image, type); - g_hash_table_insert (image->typespec_cache, GUINT_TO_POINTER (type_spec), type2); mono_metadata_free_type (type); - mono_loader_unlock (); + mono_image_lock (image); + type = g_hash_table_lookup (image->typespec_cache, GUINT_TO_POINTER (type_spec)); + /* We might leak some data in the image mempool if found */ + if (!type) { + g_hash_table_insert (image->typespec_cache, GUINT_TO_POINTER (type_spec), type2); + type = type2; + } + mono_image_unlock (image); - return type2; + return type; } @@ -5779,7 +5814,7 @@ mono_guid_to_string (const guint8 *guid) } static gboolean -get_constraints (MonoImage *image, int owner, MonoClass ***constraints, MonoGenericContainer *container) +get_constraints (MonoImage *image, int owner, MonoClass ***constraints, MonoGenericContainer *container, MonoError *error) { MonoTableInfo *tdef = &image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT]; guint32 cols [MONO_GENPARCONSTRAINT_SIZE]; @@ -5788,13 +5823,15 @@ get_constraints (MonoImage *image, int owner, MonoClass ***constraints, MonoGene GSList *cons = NULL, *tmp; MonoGenericContext *context = &container->context; + mono_error_init (error); + *constraints = NULL; found = 0; for (i = 0; i < tdef->rows; ++i) { mono_metadata_decode_row (tdef, i, cols, MONO_GENPARCONSTRAINT_SIZE); if (cols [MONO_GENPARCONSTRAINT_GENERICPAR] == owner) { token = mono_metadata_token_from_dor (cols [MONO_GENPARCONSTRAINT_CONSTRAINT]); - klass = mono_class_get_full (image, token, context); + klass = mono_class_get_and_inflate_typespec_checked (image, token, context, error); if (!klass) { g_slist_free (cons); return FALSE; @@ -5873,40 +5910,24 @@ mono_metadata_has_generic_params (MonoImage *image, guint32 token) * Memory is allocated from IMAGE's mempool. */ gboolean -mono_metadata_load_generic_param_constraints_full (MonoImage *image, guint32 token, - MonoGenericContainer *container) +mono_metadata_load_generic_param_constraints_checked (MonoImage *image, guint32 token, + MonoGenericContainer *container, MonoError *error) { guint32 start_row, i, owner; + mono_error_init (error); + if (! (start_row = mono_metadata_get_generic_param_row (image, token, &owner))) return TRUE; for (i = 0; i < container->type_argc; i++) { - if (!get_constraints (image, start_row + i, &mono_generic_container_get_param_info (container, i)->constraints, container)) + if (!get_constraints (image, start_row + i, &mono_generic_container_get_param_info (container, i)->constraints, container, error)) { + g_assert (!mono_loader_get_last_error ()); return FALSE; + } } return TRUE; } -/* - * mono_metadata_load_generic_param_constraints: - * - * @image: metadata context - * @token: metadata token to load the contraints, can be methodef or typedef. - * @container: generic container to load into. - * - * Load the generic parameter constraints for the newly created generic type or method - * represented by @token and @container. The @container is the new container which has - * been returned by a call to mono_metadata_load_generic_params() with this @token. - * Memory is allocated from IMAGE's mempool. - */ -void -mono_metadata_load_generic_param_constraints (MonoImage *image, guint32 token, - MonoGenericContainer *container) -{ - mono_metadata_load_generic_param_constraints_full (image, token, container); - /*FIXME this function can potentially exit with a pending loader error and cause all sort of havok */ -} - /* * mono_metadata_load_generic_params: * diff --git a/mono/metadata/mono-config.c b/mono/metadata/mono-config.c index ac148b08d6f..c9e9e030b8c 100644 --- a/mono/metadata/mono-config.c +++ b/mono/metadata/mono-config.c @@ -371,6 +371,14 @@ aot_cache_start (gpointer user_data, config = mono_get_aot_cache_config (); + /* Per-app configuration */ + for (i = 0; attribute_names [i]; ++i) { + if (!strcmp (attribute_names [i], "app")) { + config->apps = g_slist_prepend (config->apps, g_strdup (attribute_values [i])); + } + } + + /* Global configuration */ for (i = 0; attribute_names [i]; ++i) { if (!strcmp (attribute_names [i], "assemblies")) { char **parts, **ptr; @@ -382,6 +390,8 @@ aot_cache_start (gpointer user_data, config->assemblies = g_slist_prepend (config->assemblies, g_strdup (part)); } g_strfreev (parts); + } else if (!strcmp (attribute_names [i], "options")) { + config->aot_options = g_strdup (attribute_values [i]); } } } diff --git a/mono/metadata/mono-wsq.c b/mono/metadata/mono-wsq.c index 7a9d2258d12..859fb69c55b 100644 --- a/mono/metadata/mono-wsq.c +++ b/mono/metadata/mono-wsq.c @@ -24,6 +24,7 @@ struct _MonoWSQ { volatile gint tail; MonoArray *queue; gint32 mask; + gint32 suspended; MonoSemType lock; }; @@ -61,6 +62,7 @@ mono_wsq_create () 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); @@ -72,6 +74,12 @@ mono_wsq_create () return wsq; } +gboolean +mono_wsq_suspend (MonoWSQ *wsq) +{ + return InterlockedCompareExchange (&wsq->suspended, 1, 0) == 0; +} + void mono_wsq_destroy (MonoWSQ *wsq) { @@ -112,6 +120,11 @@ mono_wsq_local_push (void *obj) 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); diff --git a/mono/metadata/mono-wsq.h b/mono/metadata/mono-wsq.h index 7208dadb6b9..ccb064d4f18 100644 --- a/mono/metadata/mono-wsq.h +++ b/mono/metadata/mono-wsq.h @@ -20,6 +20,7 @@ gboolean mono_wsq_local_push (void *obj) MONO_INTERNAL; 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 diff --git a/mono/metadata/object.c b/mono/metadata/object.c index daa72aec6f2..b9abf073f05 100644 --- a/mono/metadata/object.c +++ b/mono/metadata/object.c @@ -287,8 +287,19 @@ mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception) if (!klass->image->checked_module_cctor) { mono_image_check_for_module_cctor (klass->image); if (klass->image->has_module_cctor) { - MonoClass *module_klass = mono_class_get (klass->image, MONO_TOKEN_TYPE_DEF | 1); - MonoVTable *module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception); + MonoError error; + MonoClass *module_klass; + MonoVTable *module_vtable; + + module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, &error); + if (!module_klass) { + exc = mono_error_convert_to_exception (&error); + if (raise_exception) + mono_raise_exception (exc); + return exc; + } + + module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception); if (!module_vtable) return NULL; exc = mono_runtime_class_init_full (module_vtable, raise_exception); @@ -4596,9 +4607,11 @@ mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *p MonoObject * mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token) { + MonoError error; MonoClass *class; - class = mono_class_get (image, token); + class = mono_class_get_checked (image, token, &error); + g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */ return mono_object_new (domain, class); } @@ -5028,10 +5041,10 @@ mono_string_new_size (MonoDomain *domain, gint32 len) 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); diff --git a/mono/metadata/process.c b/mono/metadata/process.c index c9e0f8bf63b..d7cc110aec6 100644 --- a/mono/metadata/process.c +++ b/mono/metadata/process.c @@ -23,18 +23,7 @@ #include #include #include -#ifndef HAVE_GETPROCESSID -#if defined(_MSC_VER) || defined(HAVE_WINTERNL_H) -#include -#ifndef NT_SUCCESS -#define NT_SUCCESS(status) ((NTSTATUS) (status) >= 0) -#endif /* !NT_SUCCESS */ -#else /* ! (defined(_MSC_VER) || defined(HAVE_WINTERNL_H)) */ -#include -#include -#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 #define LOGDEBUG(...) @@ -60,11 +49,12 @@ HANDLE ves_icall_System_Diagnostics_Process_GetProcess_internal (guint32 pid) 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, @@ -525,76 +515,6 @@ complete_path (const gunichar2 *appname, gchar **completed) 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}; @@ -891,14 +811,33 @@ MonoString *ves_icall_System_Diagnostics_Process_ProcessName_internal (HANDLE pr /* 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); @@ -926,6 +865,7 @@ MonoArray *ves_icall_System_Diagnostics_Process_GetProcesses_internal (void) pids = NULL; return procs; +#endif } MonoBoolean ves_icall_System_Diagnostics_Process_GetWorkingSet_internal (HANDLE process, guint32 *min, guint32 *max) diff --git a/mono/metadata/profiler-private.h b/mono/metadata/profiler-private.h index 18ec96b7aea..ed8a32f44fe 100644 --- a/mono/metadata/profiler-private.h +++ b/mono/metadata/profiler-private.h @@ -77,5 +77,8 @@ void mono_profiler_code_buffer_new (gpointer buffer, int size, MonoProfilerCodeB void mono_profiler_runtime_initialized (void) MONO_INTERNAL; +int64_t mono_profiler_get_sampling_rate (void) MONO_INTERNAL; +MonoProfileSamplingMode mono_profiler_get_sampling_mode (void) MONO_INTERNAL; + #endif /* __MONO_PROFILER_PRIVATE_H__ */ diff --git a/mono/metadata/profiler.c b/mono/metadata/profiler.c index 53f8ff0c907..dccf0930711 100644 --- a/mono/metadata/profiler.c +++ b/mono/metadata/profiler.c @@ -273,6 +273,28 @@ mono_profiler_install_monitor (MonoProfileMonitorFunc callback) prof_list->monitor_event_cb = callback; } +static MonoProfileSamplingMode sampling_mode = MONO_PROFILER_STAT_MODE_PROCESS; +static int64_t sampling_frequency = 1000; //1ms + +/** + * mono_profiler_set_statistical_mode: + * @mode the sampling mode used. + * @sample_frequency_is_us the sampling frequency in microseconds. + * + * Set the sampling parameters for the profiler. Sampling mode affects the effective sampling rate as in samples/s you'll witness. + * The default sampling mode is process mode, which only reports samples when there's activity in the process. + * + * Sampling frequency should be interpreted as a suggestion that can't always be honored due to how most kernels expose alarms. + * + * Said that, when using statistical sampling, always assume variable rate sampling as all sort of external factors can interfere. + */ +void +mono_profiler_set_statistical_mode (MonoProfileSamplingMode mode, int64_t sampling_frequency_is_us) +{ + sampling_mode = mode; + sampling_frequency = sampling_frequency_is_us; +} + void mono_profiler_install_statistical (MonoProfileStatFunc callback) { @@ -281,6 +303,18 @@ mono_profiler_install_statistical (MonoProfileStatFunc callback) prof_list->statistical_cb = callback; } +int64_t +mono_profiler_get_sampling_rate (void) +{ + return sampling_frequency; +} + +MonoProfileSamplingMode +mono_profiler_get_sampling_mode (void) +{ + return sampling_mode; +} + void mono_profiler_install_statistical_call_chain (MonoProfileStatCallChainFunc callback, int call_chain_depth, MonoProfilerCallChainStrategy call_chain_strategy) { if (!prof_list) diff --git a/mono/metadata/profiler.h b/mono/metadata/profiler.h index c7b8f6d8a88..408cac8ba31 100644 --- a/mono/metadata/profiler.h +++ b/mono/metadata/profiler.h @@ -193,6 +193,15 @@ MONO_API void mono_profiler_install_iomap (MonoProfileIomapFunc callback); MONO_API void mono_profiler_load (const char *desc); +typedef enum { + /* Elapsed time is tracked by user+kernel time of the process - this is the default*/ + MONO_PROFILER_STAT_MODE_PROCESS = 0, + /* Elapsed time is tracked by wallclock time */ + MONO_PROFILER_STAT_MODE_REAL = 1, +} MonoProfileSamplingMode; + +MONO_API void mono_profiler_set_statistical_mode (MonoProfileSamplingMode mode, int64_t sampling_frequency_is_us); + MONO_END_DECLS #endif /* __MONO_PROFILER_H__ */ diff --git a/mono/metadata/reflection.c b/mono/metadata/reflection.c index 3691da1b5dd..6614b01e1e9 100644 --- a/mono/metadata/reflection.c +++ b/mono/metadata/reflection.c @@ -1702,8 +1702,10 @@ fieldref_encode_signature (MonoDynamicImage *assembly, MonoImage *field_image, M if (type->num_mods) { for (i = 0; i < type->num_mods; ++i) { if (field_image) { - MonoClass *class = mono_class_get (field_image, type->modifiers [i].token); - g_assert (class); + MonoError error; + MonoClass *class = mono_class_get_checked (field_image, type->modifiers [i].token, &error); + g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */ + token = mono_image_typedef_or_ref (assembly, &class->byval_arg); } else { token = type->modifiers [i].token; @@ -2254,8 +2256,8 @@ resolution_scope_from_image (MonoDynamicImage *assembly, MonoImage *image) values = table->values + token * MONO_MODULEREF_SIZE; values [MONO_MODULEREF_NAME] = string_heap_insert (&assembly->sheap, image->module_name); - token <<= MONO_RESOLTION_SCOPE_BITS; - token |= MONO_RESOLTION_SCOPE_MODULEREF; + token <<= MONO_RESOLUTION_SCOPE_BITS; + token |= MONO_RESOLUTION_SCOPE_MODULEREF; g_hash_table_insert (assembly->handleref, image, GUINT_TO_POINTER (token)); return token; @@ -2297,8 +2299,8 @@ resolution_scope_from_image (MonoDynamicImage *assembly, MonoImage *image) } else { values [MONO_ASSEMBLYREF_PUBLIC_KEY] = 0; } - token <<= MONO_RESOLTION_SCOPE_BITS; - token |= MONO_RESOLTION_SCOPE_ASSEMBLYREF; + token <<= MONO_RESOLUTION_SCOPE_BITS; + token |= MONO_RESOLUTION_SCOPE_ASSEMBLYREF; g_hash_table_insert (assembly->handleref, image, GUINT_TO_POINTER (token)); return token; } @@ -2388,7 +2390,7 @@ mono_image_typedef_or_ref_full (MonoDynamicImage *assembly, MonoType *type, gboo enclosing = mono_image_typedef_or_ref_full (assembly, &klass->nested_in->byval_arg, FALSE); /* get the typeref idx of the enclosing type */ enclosing >>= MONO_TYPEDEFORREF_BITS; - scope = (enclosing << MONO_RESOLTION_SCOPE_BITS) | MONO_RESOLTION_SCOPE_TYPEREF; + scope = (enclosing << MONO_RESOLUTION_SCOPE_BITS) | MONO_RESOLUTION_SCOPE_TYPEREF; } else { scope = resolution_scope_from_image (assembly, klass->image); } @@ -3798,7 +3800,9 @@ mono_image_fill_export_table_from_module (MonoDomain *domain, MonoReflectionModu t = &image->tables [MONO_TABLE_TYPEDEF]; for (i = 0; i < t->rows; ++i) { - MonoClass *klass = mono_class_get (image, mono_metadata_make_token (MONO_TABLE_TYPEDEF, i + 1)); + MonoError error; + MonoClass *klass = mono_class_get_checked (image, mono_metadata_make_token (MONO_TABLE_TYPEDEF, i + 1), &error); + g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */ if (klass->flags & TYPE_ATTRIBUTE_PUBLIC) mono_image_fill_export_table_from_class (domain, klass, module_index, 0, assembly); @@ -3820,8 +3824,8 @@ add_exported_type (MonoReflectionAssemblyBuilder *assemblyb, MonoDynamicImage *a forwarder = FALSE; } else { scope = resolution_scope_from_image (assembly, klass->image); - g_assert ((scope & MONO_RESOLTION_SCOPE_MASK) == MONO_RESOLTION_SCOPE_ASSEMBLYREF); - scope_idx = scope >> MONO_RESOLTION_SCOPE_BITS; + g_assert ((scope & MONO_RESOLUTION_SCOPE_MASK) == MONO_RESOLUTION_SCOPE_ASSEMBLYREF); + scope_idx = scope >> MONO_RESOLUTION_SCOPE_BITS; impl = (scope_idx << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_ASSEMBLYREF; } @@ -7487,10 +7491,13 @@ mono_reflection_get_type_internal (MonoImage *rootimage, MonoImage* image, MonoT if (!image) image = mono_defaults.corlib; - if (ignorecase) - klass = mono_class_from_name_case (image, info->name_space, info->name); - else + if (ignorecase) { + MonoError error; + klass = mono_class_from_name_case_checked (image, info->name_space, info->name, &error); + g_assert (mono_error_ok (&error)); /* FIXME Don't swallow the error */ + } else { klass = mono_class_from_name (image, info->name_space, info->name); + } if (!klass) return NULL; for (mod = info->nested; mod; mod = mod->next) { @@ -7501,14 +7508,52 @@ mono_reflection_get_type_internal (MonoImage *rootimage, MonoImage* image, MonoT mono_class_init (parent); while ((klass = mono_class_get_nested_types (parent, &iter))) { - if (ignorecase) { - if (mono_utf8_strcasecmp (klass->name, mod->data) == 0) - break; + char *lastp; + char *nested_name, *nested_nspace; + gboolean match = TRUE; + + lastp = strrchr (mod->data, '.'); + if (lastp) { + /* Nested classes can have namespaces */ + int nspace_len; + + nested_name = g_strdup (lastp + 1); + nspace_len = lastp - (char*)mod->data; + nested_nspace = g_malloc (nspace_len + 1); + memcpy (nested_nspace, mod->data, nspace_len); + nested_nspace [nspace_len] = '\0'; + } else { - if (strcmp (klass->name, mod->data) == 0) - break; + nested_name = mod->data; + nested_nspace = NULL; + } + + if (nested_nspace) { + if (ignorecase) { + if (!(klass->name_space && mono_utf8_strcasecmp (klass->name_space, nested_nspace) == 0)) + match = FALSE; + } else { + if (!(klass->name_space && strcmp (klass->name_space, nested_nspace) == 0)) + match = FALSE; + } + } + if (match) { + if (ignorecase) { + if (mono_utf8_strcasecmp (klass->name, nested_name) != 0) + match = FALSE; + } else { + if (strcmp (klass->name, nested_name) != 0) + match = FALSE; + } } + if (lastp) { + g_free (nested_name); + g_free (nested_nspace); + } + if (match) + break; } + if (!klass) break; } @@ -7757,12 +7802,15 @@ mono_reflection_get_token (MonoObject *obj) 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) { @@ -9970,7 +10018,7 @@ mono_reflection_setup_internal_class (MonoReflectionTypeBuilder *tb) mono_class_set_ref_info (klass, tb); - /* Put into cache so mono_class_get () will find it. + /* Put into cache so mono_class_get_checked () will find it. Skip nested types as those should not be available on the global scope. */ if (!tb->nesting_type) mono_image_add_to_name_cache (klass->image, klass->name_space, klass->name, tb->table_idx); diff --git a/mono/metadata/row-indexes.h b/mono/metadata/row-indexes.h index 4b4ca6dbc96..74fbf6b35c5 100644 --- a/mono/metadata/row-indexes.h +++ b/mono/metadata/row-indexes.h @@ -419,6 +419,16 @@ enum { MONO_CUSTOM_ATTR_TYPE_MASK = 7 }; +enum { + MONO_RESOLUTION_SCOPE_MODULE, + MONO_RESOLUTION_SCOPE_MODULEREF, + MONO_RESOLUTION_SCOPE_ASSEMBLYREF, + MONO_RESOLUTION_SCOPE_TYPEREF, + MONO_RESOLUTION_SCOPE_BITS = 2, + MONO_RESOLUTION_SCOPE_MASK = 3 +}; + +/* Kept for compatibility since this is a public header file */ enum { MONO_RESOLTION_SCOPE_MODULE, MONO_RESOLTION_SCOPE_MODULEREF, diff --git a/mono/metadata/security.c b/mono/metadata/security.c index c61eab99f7b..65a562da72c 100644 --- a/mono/metadata/security.c +++ b/mono/metadata/security.c @@ -701,9 +701,10 @@ IsUserProtected (gunichar2 *path) gboolean success = FALSE; PACL pDACL = NULL; PSID pEveryoneSid = NULL; + PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL; DWORD dwRes = GetNamedSecurityInfoW (path, SE_FILE_OBJECT, - DACL_SECURITY_INFORMATION, NULL, NULL, &pDACL, NULL, NULL); + DACL_SECURITY_INFORMATION, NULL, NULL, &pDACL, NULL, &pSecurityDescriptor); if (dwRes != ERROR_SUCCESS) return FALSE; @@ -720,8 +721,8 @@ IsUserProtected (gunichar2 *path) /* Note: we don't need to check our own access - we'll know soon enough when reading the file */ - if (pDACL) - LocalFree (pDACL); + if (pSecurityDescriptor) + LocalFree (pSecurityDescriptor); return success; } diff --git a/mono/metadata/sgen-alloc.c b/mono/metadata/sgen-alloc.c index d9a52e9b195..368388a5dab 100644 --- a/mono/metadata/sgen-alloc.c +++ b/mono/metadata/sgen-alloc.c @@ -189,9 +189,12 @@ mono_gc_alloc_obj_nolock (MonoVTable *vtable, size_t size) 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); @@ -207,7 +210,7 @@ mono_gc_alloc_obj_nolock (MonoVTable *vtable, size_t 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 (); } @@ -229,8 +232,8 @@ mono_gc_alloc_obj_nolock (MonoVTable *vtable, size_t size) * 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 */ @@ -247,6 +250,7 @@ mono_gc_alloc_obj_nolock (MonoVTable *vtable, size_t size) * 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 ())) @@ -287,20 +291,30 @@ mono_gc_alloc_obj_nolock (MonoVTable *vtable, size_t size) available_in_tlab = (int)(TLAB_REAL_END - TLAB_NEXT);//We'll never have tlabs > 2Gb if (size > tlab_size || available_in_tlab > SGEN_MAX_NURSERY_WASTE) { /* Allocate directly from the nursery */ - do { - p = sgen_nursery_alloc (size); - if (!p) { - sgen_ensure_free_space (size); - if (degraded_mode) - return alloc_degraded (vtable, size, FALSE); - else - p = sgen_nursery_alloc (size); - } - } while (!p); + p = sgen_nursery_alloc (size); if (!p) { - // no space left - g_assert (0); + /* + * We couldn't allocate from the nursery, so we try + * collecting. Even after the collection, we might + * still not have enough memory to allocate the + * object. The reason will most likely be that we've + * run out of memory, but there is the theoretical + * possibility that other threads might have consumed + * the freed up memory ahead of us, so doing another + * collection and trying again might actually help. + * Of course the same thing might happen again. + * + * Ideally we'd like to detect that case and loop (if + * we always loop we will loop endlessly in the case of + * OOM). What we do here is give up right away. + */ + sgen_ensure_free_space (real_size); + if (degraded_mode) + return alloc_degraded (vtable, size, FALSE); + else + p = sgen_nursery_alloc (size); } + SGEN_ASSERT (0, p, "Out of memory"); zero_tlab_if_necessary (p, size); } else { @@ -309,21 +323,16 @@ mono_gc_alloc_obj_nolock (MonoVTable *vtable, size_t size) SGEN_LOG (3, "Retire TLAB: %p-%p [%ld]", TLAB_START, TLAB_REAL_END, (long)(TLAB_REAL_END - TLAB_NEXT - size)); sgen_nursery_retire_region (p, available_in_tlab); - do { - p = sgen_nursery_alloc_range (tlab_size, size, &alloc_size); - if (!p) { - sgen_ensure_free_space (tlab_size); - if (degraded_mode) - return alloc_degraded (vtable, size, FALSE); - else - p = sgen_nursery_alloc_range (tlab_size, size, &alloc_size); - } - } while (!p); - + p = sgen_nursery_alloc_range (tlab_size, size, &alloc_size); if (!p) { - // no space left - g_assert (0); + /* See comment above in similar case. */ + sgen_ensure_free_space (tlab_size); + if (degraded_mode) + return alloc_degraded (vtable, size, FALSE); + else + p = sgen_nursery_alloc_range (tlab_size, size, &alloc_size); } + SGEN_ASSERT (0, p, "Out of memory"); /* Allocate a new TLAB from the current nursery fragment */ TLAB_START = (char*)p; @@ -347,13 +356,14 @@ mono_gc_alloc_obj_nolock (MonoVTable *vtable, size_t size) 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); @@ -370,12 +380,15 @@ mono_gc_try_alloc_obj_nolock (MonoVTable *vtable, size_t size) 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)) { @@ -440,6 +453,7 @@ mono_gc_try_alloc_obj_nolock (MonoVTable *vtable, size_t 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 ())) @@ -887,7 +901,7 @@ create_allocator (int atype) /* * a string allocator method takes the args: (vtable, len) * - * bytes = sizeof (MonoString) + ((len + 1) * 2) + * bytes = offsetof (MonoString, chars) + ((len + 1) * 2) * * condition: * @@ -895,11 +909,11 @@ create_allocator (int atype) * * 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); @@ -911,7 +925,7 @@ create_allocator (int atype) 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 { diff --git a/mono/metadata/sgen-archdep.h b/mono/metadata/sgen-archdep.h index b86ec318c7c..420dc96e47d 100644 --- a/mono/metadata/sgen-archdep.h +++ b/mono/metadata/sgen-archdep.h @@ -21,7 +21,14 @@ #ifndef __MONO_SGENARCHDEP_H__ #define __MONO_SGENARCHDEP_H__ -#include +#include + +/* + * 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) @@ -35,35 +42,23 @@ #elif defined(TARGET_X86) -#include - #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 - #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 @@ -99,39 +94,9 @@ /* 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 - #ifdef __linux__ #define REDZONE_SIZE 0 #elif defined(__APPLE__) @@ -142,12 +107,6 @@ #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 @@ -155,23 +114,12 @@ #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 - #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__) diff --git a/mono/metadata/sgen-cardtable.c b/mono/metadata/sgen-cardtable.c index aab3bcb6153..6dd91e24442 100644 --- a/mono/metadata/sgen-cardtable.c +++ b/mono/metadata/sgen-cardtable.c @@ -455,6 +455,9 @@ sgen_card_table_finish_scan_remsets (void *start_nursery, void *end_nursery, Sge guint8* mono_gc_get_card_table (int *shift_bits, gpointer *mask) { +#ifndef MANAGED_WBARRIER + return NULL; +#else if (!sgen_cardtable) return NULL; @@ -466,6 +469,7 @@ mono_gc_get_card_table (int *shift_bits, gpointer *mask) #endif return sgen_cardtable; +#endif } gboolean @@ -475,22 +479,6 @@ mono_gc_card_table_nursery_check (void) } #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) { @@ -683,9 +671,9 @@ sgen_cardtable_scan_object (char *obj, mword block_obj_size, guint8 *cards, gboo HEAVY_STAT (++bloby_objects); if (cards) { if (sgen_card_table_is_range_marked (cards, (mword)obj, block_obj_size)) - sgen_get_current_object_ops ()->scan_object (obj, queue); + sgen_get_current_object_ops ()->scan_object (obj, sgen_obj_get_descriptor (obj), queue); } else if (sgen_card_table_region_begin_scanning ((mword)obj, block_obj_size)) { - sgen_get_current_object_ops ()->scan_object (obj, queue); + sgen_get_current_object_ops ()->scan_object (obj, sgen_obj_get_descriptor (obj), queue); } binary_protocol_card_scan (obj, sgen_safe_object_get_size ((MonoObject*)obj)); diff --git a/mono/metadata/sgen-conf.h b/mono/metadata/sgen-conf.h index 009d0f66ee2..babee94026e 100644 --- a/mono/metadata/sgen-conf.h +++ b/mono/metadata/sgen-conf.h @@ -41,6 +41,12 @@ typedef guint64 mword; */ // #define HEAVY_STATISTICS +#ifdef HEAVY_STATISTICS +#define HEAVY_STAT(x) x +#else +#define HEAVY_STAT(x) +#endif + /* * Define this to allow the user to change the nursery size by * specifying its value in the MONO_GC_PARAMS environmental diff --git a/mono/metadata/sgen-copy-object.h b/mono/metadata/sgen-copy-object.h index dec0d073fe0..21331c18f06 100644 --- a/mono/metadata/sgen-copy-object.h +++ b/mono/metadata/sgen-copy-object.h @@ -18,6 +18,9 @@ * License 2.0 along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "mono/utils/mono-compiler.h" + extern long long stat_copy_object_called_nursery; extern long long stat_objects_copied_nursery; @@ -31,13 +34,9 @@ extern long long stat_slots_allocated_in_vain; * This function can be used even if the vtable of obj is not valid * anymore, which is the case in the parallel collector. */ -static inline void +static MONO_ALWAYS_INLINE void par_copy_object_no_checks (char *destination, MonoVTable *vt, void *obj, mword objsize, SgenGrayQueue *queue) { -#ifdef __GNUC__ - static const void *copy_labels [] = { &&LAB_0, &&LAB_1, &&LAB_2, &&LAB_3, &&LAB_4, &&LAB_5, &&LAB_6, &&LAB_7, &&LAB_8 }; -#endif - SGEN_ASSERT (9, vt->klass->inited, "vtable %p for class %s:%s was not initialized", vt, vt->klass->name_space, vt->klass->name); SGEN_LOG (9, " (to %p, %s size: %lu)", destination, ((MonoObject*)obj)->vtable->klass->name, (unsigned long)objsize); binary_protocol_copy (obj, destination, vt, objsize); @@ -50,35 +49,8 @@ par_copy_object_no_checks (char *destination, MonoVTable *vt, void *obj, mword o } #endif -#ifdef __GNUC__ - if (objsize <= sizeof (gpointer) * 8) { - mword *dest = (mword*)destination; - goto *copy_labels [objsize / sizeof (gpointer)]; - LAB_8: - (dest) [7] = ((mword*)obj) [7]; - LAB_7: - (dest) [6] = ((mword*)obj) [6]; - LAB_6: - (dest) [5] = ((mword*)obj) [5]; - LAB_5: - (dest) [4] = ((mword*)obj) [4]; - LAB_4: - (dest) [3] = ((mword*)obj) [3]; - LAB_3: - (dest) [2] = ((mword*)obj) [2]; - LAB_2: - (dest) [1] = ((mword*)obj) [1]; - LAB_1: - ; - LAB_0: - ; - } else { - /*can't trust memcpy doing word copies */ - mono_gc_memmove_aligned (destination + sizeof (mword), (char*)obj + sizeof (mword), objsize - sizeof (mword)); - } -#else - mono_gc_memmove_aligned (destination + sizeof (mword), (char*)obj + sizeof (mword), objsize - sizeof (mword)); -#endif + memcpy (destination + sizeof (mword), (char*)obj + sizeof (mword), objsize - sizeof (mword)); + /* adjust array->bounds */ SGEN_ASSERT (9, vt->gc_descr, "vtable %p for class %s:%s has no gc descriptor", vt, vt->klass->name_space, vt->klass->name); @@ -92,18 +64,14 @@ par_copy_object_no_checks (char *destination, MonoVTable *vt, void *obj, mword o obj = destination; if (queue) { SGEN_LOG (9, "Enqueuing gray object %p (%s)", obj, sgen_safe_name (obj)); - GRAY_OBJECT_ENQUEUE (queue, obj); + GRAY_OBJECT_ENQUEUE (queue, obj, sgen_vtable_get_descriptor (vt)); } } /* * This can return OBJ itself on OOM. */ -#ifdef _MSC_VER -static __declspec(noinline) void* -#else -static G_GNUC_UNUSED void* __attribute__((noinline)) -#endif +static MONO_NEVER_INLINE void* copy_object_no_checks (void *obj, SgenGrayQueue *queue) { MonoVTable *vt = ((MonoObject*)obj)->vtable; diff --git a/mono/metadata/sgen-debug.c b/mono/metadata/sgen-debug.c index 1387676c758..113078c1839 100644 --- a/mono/metadata/sgen-debug.c +++ b/mono/metadata/sgen-debug.c @@ -174,7 +174,8 @@ static gboolean missing_remsets; static void check_consistency_callback (char *start, size_t size, void *dummy) { - GCVTable *vt = (GCVTable*)LOAD_VTABLE (start); + MonoVTable *vt = (MonoVTable*)LOAD_VTABLE (start); + mword desc = sgen_vtable_get_descriptor (vt); SGEN_LOG (8, "Scanning object %p, vtable: %p (%s)", start, vt, vt->klass->name); #include "sgen-scan-object.h" @@ -230,7 +231,8 @@ static void check_mod_union_callback (char *start, size_t size, void *dummy) { gboolean in_los = (gboolean) (size_t) dummy; - GCVTable *vt = (GCVTable*)LOAD_VTABLE (start); + MonoVTable *vt = (MonoVTable*)LOAD_VTABLE (start); + mword desc = sgen_vtable_get_descriptor (vt); guint8 *cards; SGEN_LOG (8, "Scanning object %p, vtable: %p (%s)", start, vt, vt->klass->name); @@ -269,6 +271,8 @@ sgen_check_mod_union_consistency (void) static void check_major_refs_callback (char *start, size_t size, void *dummy) { + mword desc = sgen_obj_get_descriptor (start); + #include "sgen-scan-object.h" } @@ -296,9 +300,13 @@ sgen_check_major_refs (void) void check_object (char *start) { + mword desc; + if (!start) return; + desc = sgen_obj_get_descriptor (start); + #include "sgen-scan-object.h" } @@ -425,6 +433,7 @@ static void verify_object_pointers_callback (char *start, size_t size, void *data) { gboolean allow_missing_pinned = (gboolean) (size_t) data; + mword desc = sgen_obj_get_descriptor (start); #include "sgen-scan-object.h" } @@ -548,6 +557,7 @@ static void check_marked_callback (char *start, size_t size, void *dummy) { gboolean is_los = (gboolean) (size_t) dummy; + mword desc; if (is_los) { if (!sgen_los_object_is_pinned (start)) @@ -557,6 +567,8 @@ check_marked_callback (char *start, size_t size, void *dummy) return; } + desc = sgen_obj_get_descriptor (start); + #include "sgen-scan-object.h" } @@ -608,6 +620,7 @@ scan_object_for_specific_ref (char *start, MonoObject *key) start = forwarded; if (scan_object_for_specific_ref_precise) { + mword desc = sgen_obj_get_descriptor (start); #include "sgen-scan-object.h" } else { mword *words = (mword*)start; @@ -896,7 +909,9 @@ check_reference_for_xdomain (gpointer *ptr, char *obj, MonoDomain *domain) static void scan_object_for_xdomain_refs (char *start, mword size, void *data) { - MonoDomain *domain = ((MonoObject*)start)->vtable->domain; + MonoVTable *vt = (MonoVTable*)SGEN_LOAD_VTABLE (start); + MonoDomain *domain = vt->domain; + mword desc = sgen_vtable_get_descriptor (vt); #include "sgen-scan-object.h" } diff --git a/mono/metadata/sgen-descriptor.c b/mono/metadata/sgen-descriptor.c index c578a91cfb2..6da8f7290d9 100644 --- a/mono/metadata/sgen-descriptor.c +++ b/mono/metadata/sgen-descriptor.c @@ -43,6 +43,7 @@ #define _XOPEN_SOURCE #endif +#include "utils/mono-counters.h" #include "metadata/sgen-gc.h" #define MAX_USER_DESCRIPTORS 16 @@ -58,6 +59,9 @@ static MonoGCRootMarkFunc user_descriptors [MAX_USER_DESCRIPTORS]; static int user_descriptors_next = 0; static void *all_ref_root_descrs [32]; +#ifdef HEAVY_STATISTICS +static long long stat_scanned_count_per_descriptor [DESC_TYPE_MAX]; +#endif static int alloc_complex_descriptor (gsize *bitmap, int numbits) @@ -348,4 +352,28 @@ sgen_get_user_descriptor_func (mword desc) return user_descriptors [desc >> ROOT_DESC_TYPE_SHIFT]; } +#ifdef HEAVY_STATISTICS +void +sgen_descriptor_count_scanned_object (mword desc) +{ + int type = desc & 7; + SGEN_ASSERT (0, type, "Descriptor type can't be zero"); + ++stat_scanned_count_per_descriptor [type - 1]; +} +#endif + +void +sgen_init_descriptors (void) +{ +#ifdef HEAVY_STATISTICS + mono_counters_register ("# scanned RUN_LENGTH", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_scanned_count_per_descriptor [DESC_TYPE_RUN_LENGTH - 1]); + mono_counters_register ("# scanned SMALL_BITMAP", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_scanned_count_per_descriptor [DESC_TYPE_SMALL_BITMAP - 1]); + mono_counters_register ("# scanned COMPLEX", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_scanned_count_per_descriptor [DESC_TYPE_COMPLEX - 1]); + mono_counters_register ("# scanned VECTOR", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_scanned_count_per_descriptor [DESC_TYPE_VECTOR - 1]); + mono_counters_register ("# scanned LARGE_BITMAP", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_scanned_count_per_descriptor [DESC_TYPE_LARGE_BITMAP - 1]); + mono_counters_register ("# scanned COMPLEX_ARR", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_scanned_count_per_descriptor [DESC_TYPE_COMPLEX_ARR - 1]); + mono_counters_register ("# scanned COMPLEX_PTRFREE", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_scanned_count_per_descriptor [DESC_TYPE_COMPLEX_PTRFREE - 1]); +#endif +} + #endif diff --git a/mono/metadata/sgen-descriptor.h b/mono/metadata/sgen-descriptor.h index 366c7667778..c06354dd958 100644 --- a/mono/metadata/sgen-descriptor.h +++ b/mono/metadata/sgen-descriptor.h @@ -82,13 +82,14 @@ enum { * copy_object_no_checks(), without having to fetch the * object's class. */ - DESC_TYPE_RUN_LENGTH = 1, /* 16 bits aligned byte size | 1-3 (offset, numptr) bytes tuples */ - DESC_TYPE_SMALL_BITMAP, /* 16 bits aligned byte size | 16-48 bit bitmap */ - DESC_TYPE_COMPLEX, /* index for bitmap into complex_descriptors */ - DESC_TYPE_VECTOR, /* 10 bits element size | 1 bit kind | 2 bits desc | element desc */ - DESC_TYPE_LARGE_BITMAP, /* | 29-61 bitmap bits */ - DESC_TYPE_COMPLEX_ARR, /* index for bitmap into complex_descriptors */ - DESC_TYPE_COMPLEX_PTRFREE, /*Nothing, used to encode large ptr objects. */ + DESC_TYPE_RUN_LENGTH = 1, /* 16 bits aligned byte size | 1-3 (offset, numptr) bytes tuples */ + DESC_TYPE_SMALL_BITMAP = 2, /* 16 bits aligned byte size | 16-48 bit bitmap */ + DESC_TYPE_COMPLEX = 3, /* index for bitmap into complex_descriptors */ + DESC_TYPE_VECTOR = 4, /* 10 bits element size | 1 bit kind | 2 bits desc | element desc */ + DESC_TYPE_LARGE_BITMAP = 5, /* | 29-61 bitmap bits */ + DESC_TYPE_COMPLEX_ARR = 6, /* index for bitmap into complex_descriptors */ + DESC_TYPE_COMPLEX_PTRFREE = 7, /*Nothing, used to encode large ptr objects. */ + DESC_TYPE_MAX = 7, /* values for array kind */ DESC_TYPE_V_SZARRAY = 0, /*vector with no bounds data */ DESC_TYPE_V_ARRAY = 1, /* array with bounds data */ @@ -117,6 +118,11 @@ gsize* sgen_get_complex_descriptor (mword desc) MONO_INTERNAL; void* sgen_get_complex_descriptor_bitmap (mword desc) MONO_INTERNAL; MonoGCRootMarkFunc sgen_get_user_descriptor_func (mword desc) MONO_INTERNAL; +void sgen_init_descriptors (void) MONO_INTERNAL; + +#ifdef HEAVY_STATISTICS +void sgen_descriptor_count_scanned_object (mword desc) MONO_INTERNAL; +#endif static inline gboolean sgen_gc_descr_has_references (mword desc) @@ -168,8 +174,6 @@ sgen_gc_descr_has_references (mword desc) void **_objptr = (void**)(obj); \ _objptr += ((desc) >> 16) & 0xff; \ _objptr_end = _objptr + (((desc) >> 24) & 0xff); \ - HANDLE_PTR (_objptr, (obj)); \ - _objptr ++; \ while (_objptr < _objptr_end) { \ HANDLE_PTR (_objptr, (obj)); \ _objptr++; \ @@ -183,20 +187,13 @@ sgen_gc_descr_has_references (mword desc) void **_objptr = (void**)(obj); \ gsize _bmap = (desc) >> 16; \ _objptr += OBJECT_HEADER_WORDS; \ - { \ - int _index = GNUC_BUILTIN_CTZ (_bmap); \ - _objptr += _index; \ - _bmap >>= (_index + 1); \ - HANDLE_PTR (_objptr, (obj)); \ - _objptr ++; \ - } \ - while (_bmap) { \ + do { \ int _index = GNUC_BUILTIN_CTZ (_bmap); \ _objptr += _index; \ _bmap >>= (_index + 1); \ HANDLE_PTR (_objptr, (obj)); \ _objptr ++; \ - } \ + } while (_bmap); \ } while (0) #else #define OBJ_BITMAP_FOREACH_PTR(desc,obj) do { \ @@ -258,15 +255,16 @@ sgen_gc_descr_has_references (mword desc) } while (0) /* this one is untested */ -#define OBJ_COMPLEX_ARR_FOREACH_PTR(vt,obj) do { \ +#define OBJ_COMPLEX_ARR_FOREACH_PTR(desc,obj) do { \ /* there are pointers */ \ - gsize *mbitmap_data = sgen_get_complex_descriptor ((vt)->desc); \ + GCVTable *vt = (GCVTable*)SGEN_LOAD_VTABLE (obj); \ + gsize *mbitmap_data = sgen_get_complex_descriptor ((desc)); \ gsize mbwords = (*mbitmap_data++) - 1; \ gsize el_size = mono_array_element_size (vt->klass); \ char *e_start = (char*)(obj) + G_STRUCT_OFFSET (MonoArray, vector); \ char *e_end = e_start + el_size * mono_array_length_fast ((MonoArray*)(obj)); \ if (0) \ - g_print ("found %d at %p (0x%zx): %s.%s\n", mbwords, (obj), (vt)->desc, vt->klass->name_space, vt->klass->name); \ + g_print ("found %d at %p (0x%zx): %s.%s\n", mbwords, (obj), (desc), (vt)->klass->name_space, (vt)->klass->name); \ while (e_start < e_end) { \ void **_objptr = (void**)e_start; \ gsize *bitmap_data = mbitmap_data; \ diff --git a/mono/metadata/sgen-gc.c b/mono/metadata/sgen-gc.c index 8e1d05e1663..c9a0792c519 100644 --- a/mono/metadata/sgen-gc.c +++ b/mono/metadata/sgen-gc.c @@ -285,12 +285,12 @@ static gboolean do_scan_starts_check = FALSE; * GC.Collect(). */ static gboolean allow_synchronous_major = TRUE; -static gboolean nursery_collection_is_parallel = FALSE; static gboolean disable_minor_collections = FALSE; static gboolean disable_major_collections = FALSE; 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; @@ -347,6 +347,14 @@ static long long time_major_los_sweep = 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); + +static SGEN_TV_DECLARE (last_minor_collection_start_tv); +static SGEN_TV_DECLARE (last_minor_collection_end_tv); + int gc_debug_level = 0; FILE* gc_debug_file; @@ -387,6 +395,12 @@ safe_name (void* obj) 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* @@ -597,8 +611,7 @@ gray_queue_redirect (SgenGrayQueue *queue) } if (wake) { - g_assert (concurrent_collection_in_progress || - (current_collection_generation == GENERATION_OLD && major_collector.is_parallel)); + g_assert (concurrent_collection_in_progress); if (sgen_workers_have_started ()) { sgen_workers_wake_up_all (); } else { @@ -627,10 +640,14 @@ sgen_scan_area_with_callback (char *start, char *end, IterateObjectCallbackFunc 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; } @@ -689,8 +706,10 @@ clear_domain_process_object (char *obj, MonoDomain *domain) 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 @@ -857,36 +876,29 @@ sgen_add_to_global_remset (gpointer ptr, gpointer obj) * Scan objects in the gray stack until the stack is empty. This should be called * frequently after each object is copied, to achieve better locality and cache * usage. + * + * max_objs is the maximum number of objects to scan, or -1 to scan until the stack is + * empty. */ gboolean sgen_drain_gray_stack (int max_objs, ScanCopyContext ctx) { - char *obj; ScanObjectFunc scan_func = ctx.scan_func; GrayQueue *queue = ctx.queue; - if (max_objs == -1) { - for (;;) { - GRAY_OBJECT_DEQUEUE (queue, &obj); + do { + int i; + for (i = 0; i != max_objs; ++i) { + char *obj; + mword desc; + GRAY_OBJECT_DEQUEUE (queue, &obj, &desc); if (!obj) return TRUE; SGEN_LOG (9, "Precise gray object scan %p (%s)", obj, safe_name (obj)); - scan_func (obj, queue); + scan_func (obj, desc, queue); } - } else { - int i; - - do { - for (i = 0; i != max_objs; ++i) { - GRAY_OBJECT_DEQUEUE (queue, &obj); - if (!obj) - return TRUE; - SGEN_LOG (9, "Precise gray object scan %p (%s)", obj, safe_name (obj)); - scan_func (obj, queue); - } - } while (max_objs < 0); - return FALSE; - } + } while (max_objs < 0); + return FALSE; } /* @@ -900,8 +912,8 @@ static int pin_objects_from_nursery_pin_queue (ScanCopyContext ctx) { GCMemSection *section = nursery_section; - void **start = section->pin_queue_start; - void **end = start + section->pin_queue_num_entries; + void **start = sgen_pinning_get_entry (section->pin_queue_first_entry); + void **end = sgen_pinning_get_entry (section->pin_queue_last_entry); void *start_nursery = section->data; void *end_nursery = section->next_data; void *last = NULL; @@ -919,6 +931,7 @@ pin_objects_from_nursery_pin_queue (ScanCopyContext ctx) while (start < end) { void *obj_to_pin = NULL; size_t obj_to_pin_size = 0; + mword desc; addr = *start; @@ -988,6 +1001,11 @@ pin_objects_from_nursery_pin_queue (ScanCopyContext ctx) } /* 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); @@ -1013,8 +1031,9 @@ pin_objects_from_nursery_pin_queue (ScanCopyContext ctx) /* * Finally - pin the object! */ + desc = sgen_obj_get_descriptor_safe (obj_to_pin); if (scan_func) { - scan_func (obj_to_pin, queue); + scan_func (obj_to_pin, desc, queue); } else { SGEN_LOG (4, "Pinned object %p, vtable %p (%s), count %d\n", obj_to_pin, *(void**)obj_to_pin, safe_name (obj_to_pin), count); @@ -1033,7 +1052,7 @@ pin_objects_from_nursery_pin_queue (ScanCopyContext ctx) #endif pin_object (obj_to_pin); - GRAY_OBJECT_ENQUEUE (queue, obj_to_pin); + GRAY_OBJECT_ENQUEUE (queue, obj_to_pin, desc); if (G_UNLIKELY (do_pin_stats)) sgen_pin_stats_register_object (obj_to_pin, obj_to_pin_size); definitely_pinned [count] = obj_to_pin; @@ -1061,13 +1080,11 @@ pin_objects_in_nursery (ScanCopyContext ctx) { size_t reduced_to; - if (!nursery_section->pin_queue_num_entries) + if (nursery_section->pin_queue_first_entry == nursery_section->pin_queue_last_entry) return; reduced_to = pin_objects_from_nursery_pin_queue (ctx); - nursery_section->pin_queue_num_entries = reduced_to; - if (!reduced_to) - nursery_section->pin_queue_start = NULL; + nursery_section->pin_queue_last_entry = nursery_section->pin_queue_first_entry + reduced_to; } @@ -1076,20 +1093,13 @@ sgen_pin_object (void *object, GrayQueue *queue) { g_assert (!concurrent_collection_in_progress); - if (sgen_collection_is_parallel ()) { - LOCK_PIN_QUEUE; - /*object arrives pinned*/ - sgen_pin_stage_ptr (object); - ++objects_pinned ; - UNLOCK_PIN_QUEUE; - } else { - SGEN_PIN_OBJECT (object); - sgen_pin_stage_ptr (object); - ++objects_pinned; - if (G_UNLIKELY (do_pin_stats)) - sgen_pin_stats_register_object (object, safe_object_get_size (object)); - } - GRAY_OBJECT_ENQUEUE (queue, object); + SGEN_PIN_OBJECT (object); + sgen_pin_stage_ptr (object); + ++objects_pinned; + if (G_UNLIKELY (do_pin_stats)) + sgen_pin_stats_register_object (object, safe_object_get_size (object)); + + GRAY_OBJECT_ENQUEUE (queue, object, sgen_obj_get_descriptor_safe (object)); binary_protocol_pin (object, (gpointer)LOAD_VTABLE (object), safe_object_get_size (object)); #ifdef ENABLE_DTRACE @@ -1109,7 +1119,7 @@ sgen_parallel_pin_or_update (void **ptr, void *obj, MonoVTable *vt, SgenGrayQueu gboolean major_pinned = FALSE; if (sgen_ptr_in_nursery (obj)) { - if (SGEN_CAS_PTR (obj, (void*)((mword)vt | SGEN_PINNED_BIT), vt) == vt) { + if (SGEN_CAS_PTR (obj, SGEN_POINTER_TAG_PINNED (vt), vt) == vt) { sgen_pin_object (obj, queue); break; } @@ -1120,13 +1130,13 @@ sgen_parallel_pin_or_update (void **ptr, void *obj, MonoVTable *vt, SgenGrayQueu vtable_word = *(mword*)obj; /*someone else forwarded it, update the pointer and bail out*/ - if (vtable_word & SGEN_FORWARDED_BIT) { - *ptr = (void*)(vtable_word & ~SGEN_VTABLE_BITS_MASK); + if (SGEN_POINTER_IS_TAGGED_FORWARDED (vtable_word)) { + *ptr = SGEN_POINTER_UNTAG_VTABLE (vtable_word); break; } /*someone pinned it, nothing to do.*/ - if (vtable_word & SGEN_PINNED_BIT || major_pinned) + if (SGEN_POINTER_IS_TAGGED_PINNED (vtable_word) || major_pinned) break; } } @@ -1264,7 +1274,8 @@ unpin_objects_from_queue (SgenGrayQueue *queue) { for (;;) { char *addr; - GRAY_OBJECT_DEQUEUE (queue, &addr); + mword desc; + GRAY_OBJECT_DEQUEUE (queue, &addr, &desc); if (!addr) break; g_assert (SGEN_OBJECT_IS_PINNED (addr)); @@ -1735,6 +1746,8 @@ finish_gray_stack (int generation, GrayQueue *queue) } g_assert (sgen_gray_object_queue_is_empty (queue)); + + sgen_gray_object_queue_trim_free_list (queue); } void @@ -1899,9 +1912,6 @@ sgen_register_moved_object (void *obj, void *destination) { g_assert (mono_profiler_events & MONO_PROFILE_GC_MOVES); - /* FIXME: handle this for parallel collector */ - g_assert (!sgen_collection_is_parallel ()); - if (moved_objects_idx == MOVED_OBJECTS_NUM) { mono_profiler_gc_moves (moved_objects, moved_objects_idx); moved_objects_idx = 0; @@ -1918,6 +1928,8 @@ init_stats (void) 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); @@ -1992,19 +2004,6 @@ sgen_set_pinned_from_failed_allocation (mword objsize) bytes_pinned_from_failed_allocation += objsize; } -gboolean -sgen_collection_is_parallel (void) -{ - switch (current_collection_generation) { - case GENERATION_NURSERY: - return nursery_collection_is_parallel; - case GENERATION_OLD: - return major_collector.is_parallel; - default: - g_error ("Invalid current generation %d", current_collection_generation); - } -} - gboolean sgen_collection_is_concurrent (void) { @@ -2075,19 +2074,13 @@ job_scan_thread_data (WorkerData *worker_data, void *job_data_untyped) sgen_free_internal_dynamic (job_data, sizeof (ScanThreadDataJobData), INTERNAL_MEM_WORKER_JOB_DATA); } -typedef struct -{ - FinalizeReadyEntry *list; -} ScanFinalizerEntriesJobData; - static void job_scan_finalizer_entries (WorkerData *worker_data, void *job_data_untyped) { - ScanFinalizerEntriesJobData *job_data = job_data_untyped; + FinalizeReadyEntry *list = job_data_untyped; ScanCopyContext ctx = { NULL, current_object_ops.copy_or_mark_object, sgen_workers_get_job_gray_queue (worker_data) }; - scan_finalizer_entries (job_data->list, ctx); - sgen_free_internal_dynamic (job_data, sizeof (ScanFinalizerEntriesJobData), INTERNAL_MEM_WORKER_JOB_DATA); + scan_finalizer_entries (list, ctx); } static void @@ -2123,6 +2116,9 @@ verify_nursery (void) 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 (); @@ -2151,6 +2147,10 @@ verify_nursery (void) 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; } @@ -2192,7 +2192,7 @@ check_nursery_is_clean (void) static void init_gray_queue (void) { - if (sgen_collection_is_parallel () || sgen_collection_is_concurrent ()) { + if (sgen_collection_is_concurrent ()) { sgen_workers_init_distribute_gray_queue (); sgen_gray_object_queue_init_with_alloc_prepare (&gray_queue, NULL, gray_queue_redirect, sgen_workers_get_distribute_section_gray_queue ()); @@ -2201,13 +2201,6 @@ init_gray_queue (void) } } -static void -pin_stage_object_callback (char *obj, size_t size, void *data) -{ - sgen_pin_stage_ptr (obj); - /* FIXME: do pin stats if enabled */ -} - /* * Collect objects in the nursery. Returns whether to trigger a major * collection. @@ -2220,18 +2213,18 @@ collect_nursery (SgenGrayQueue *unpin_queue, gboolean finish_up_concurrent_mark) char *nursery_next; FinishRememberedSetScanJobData *frssjd; ScanFromRegisteredRootsJobData *scrrjd_normal, *scrrjd_wbarrier; - ScanFinalizerEntriesJobData *sfejd_fin_ready, *sfejd_critical_fin; ScanThreadDataJobData *stdjd; mword fragment_total; ScanCopyContext ctx; - TV_DECLARE (all_atv); - TV_DECLARE (all_btv); TV_DECLARE (atv); TV_DECLARE (btv); if (disable_minor_collections) return TRUE; + TV_GETTIME (last_minor_collection_start_tv); + atv = last_minor_collection_start_tv; + MONO_GC_BEGIN (GENERATION_NURSERY); binary_protocol_collection_begin (gc_stats.minor_gc_count, GENERATION_NURSERY); @@ -2242,11 +2235,8 @@ collect_nursery (SgenGrayQueue *unpin_queue, gboolean finish_up_concurrent_mark) #endif current_collection_generation = GENERATION_NURSERY; - if (sgen_collection_is_parallel ()) - current_object_ops = sgen_minor_collector.parallel_ops; - else - current_object_ops = sgen_minor_collector.serial_ops; - + current_object_ops = sgen_minor_collector.serial_ops; + reset_pinned_from_failed_allocation (); check_scan_starts (); @@ -2264,9 +2254,6 @@ collect_nursery (SgenGrayQueue *unpin_queue, gboolean finish_up_concurrent_mark) g_assert (nursery_section->size >= max_garbage_amount); /* world must be stopped already */ - TV_GETTIME (all_atv); - atv = all_atv; - TV_GETTIME (btv); time_minor_pre_collection_fragment_clear += TV_ELAPSED (atv, btv); @@ -2297,9 +2284,9 @@ collect_nursery (SgenGrayQueue *unpin_queue, gboolean finish_up_concurrent_mark) mono_profiler_gc_event (MONO_GC_EVENT_MARK_START, 0); pin_from_roots (sgen_get_nursery_start (), nursery_next, WORKERS_DISTRIBUTE_GRAY_QUEUE); /* pin cemented objects */ - sgen_cement_iterate (pin_stage_object_callback, NULL); + sgen_pin_cemented_objects (); /* identify pinned objects */ - sgen_optimize_pin_queue (0); + sgen_optimize_pin_queue (); sgen_pinning_setup_section (nursery_section); ctx.scan_func = NULL; ctx.copy_func = NULL; @@ -2336,12 +2323,11 @@ collect_nursery (SgenGrayQueue *unpin_queue, gboolean finish_up_concurrent_mark) MONO_GC_CHECKPOINT_4 (GENERATION_NURSERY); - if (!sgen_collection_is_parallel ()) { - ctx.scan_func = current_object_ops.scan_object; - ctx.copy_func = NULL; - ctx.queue = &gray_queue; - sgen_drain_gray_stack (-1, ctx); - } + /* FIXME: why is this here? */ + ctx.scan_func = current_object_ops.scan_object; + ctx.copy_func = NULL; + ctx.queue = &gray_queue; + sgen_drain_gray_stack (-1, ctx); if (mono_profiler_get_events () & MONO_PROFILE_GC_ROOTS) report_registered_roots (); @@ -2386,19 +2372,11 @@ collect_nursery (SgenGrayQueue *unpin_queue, gboolean finish_up_concurrent_mark) MONO_GC_CHECKPOINT_7 (GENERATION_NURSERY); - g_assert (!sgen_collection_is_parallel () && !sgen_collection_is_concurrent ()); - - if (sgen_collection_is_parallel () || sgen_collection_is_concurrent ()) - g_assert (sgen_gray_object_queue_is_empty (&gray_queue)); + g_assert (!sgen_collection_is_concurrent ()); /* Scan the list of objects ready for finalization. If */ - sfejd_fin_ready = sgen_alloc_internal_dynamic (sizeof (ScanFinalizerEntriesJobData), INTERNAL_MEM_WORKER_JOB_DATA, TRUE); - sfejd_fin_ready->list = fin_ready_list; - sgen_workers_enqueue_job (job_scan_finalizer_entries, sfejd_fin_ready); - - sfejd_critical_fin = sgen_alloc_internal_dynamic (sizeof (ScanFinalizerEntriesJobData), INTERNAL_MEM_WORKER_JOB_DATA, TRUE); - sfejd_critical_fin->list = critical_fin_list; - sgen_workers_enqueue_job (job_scan_finalizer_entries, sfejd_critical_fin); + sgen_workers_enqueue_job (job_scan_finalizer_entries, fin_ready_list); + sgen_workers_enqueue_job (job_scan_finalizer_entries, critical_fin_list); MONO_GC_CHECKPOINT_8 (GENERATION_NURSERY); @@ -2418,7 +2396,7 @@ collect_nursery (SgenGrayQueue *unpin_queue, gboolean finish_up_concurrent_mark) sgen_workers_reset_data (); if (objects_pinned) { - sgen_optimize_pin_queue (0); + sgen_optimize_pin_queue (); sgen_pinning_setup_section (nursery_section); } @@ -2427,9 +2405,7 @@ collect_nursery (SgenGrayQueue *unpin_queue, gboolean finish_up_concurrent_mark) * next allocations. */ mono_profiler_gc_event (MONO_GC_EVENT_RECLAIM_START, 0); - fragment_total = sgen_build_nursery_fragments (nursery_section, - nursery_section->pin_queue_start, nursery_section->pin_queue_num_entries, - unpin_queue); + fragment_total = sgen_build_nursery_fragments (nursery_section, unpin_queue); if (!fragment_total) degraded_mode = 1; @@ -2446,8 +2422,8 @@ collect_nursery (SgenGrayQueue *unpin_queue, gboolean finish_up_concurrent_mark) major_collector.finish_nursery_collection (); - TV_GETTIME (all_btv); - gc_stats.minor_gc_time += TV_ELAPSED (all_atv, all_btv); + TV_GETTIME (last_minor_collection_end_tv); + gc_stats.minor_gc_time += TV_ELAPSED (last_minor_collection_start_tv, last_minor_collection_end_tv); if (heap_dump_file) dump_heap ("minor", gc_stats.minor_gc_count - 1, NULL); @@ -2489,7 +2465,11 @@ collect_nursery (SgenGrayQueue *unpin_queue, gboolean finish_up_concurrent_mark) static void scan_nursery_objects_callback (char *obj, size_t size, ScanCopyContext *ctx) { - ctx->scan_func (obj, ctx->queue); + /* + * This is called on all objects in the nursery, including pinned ones, so we need + * to use sgen_obj_get_descriptor_safe(), which masks out the vtable tag bits. + */ + ctx->scan_func (obj, sgen_obj_get_descriptor_safe (obj), ctx->queue); } static void @@ -2514,7 +2494,6 @@ major_copy_or_mark_from_roots (size_t *old_next_pin_slot, gboolean finish_up_con GCRootReport root_report = { 0 }; ScanFromRegisteredRootsJobData *scrrjd_normal, *scrrjd_wbarrier; ScanThreadDataJobData *stdjd; - ScanFinalizerEntriesJobData *sfejd_fin_ready, *sfejd_critical_fin; ScanCopyContext ctx; if (concurrent_collection_in_progress) { @@ -2577,14 +2556,14 @@ major_copy_or_mark_from_roots (size_t *old_next_pin_slot, gboolean finish_up_con * * FIXME: We could evict now! */ - sgen_cement_iterate (pin_stage_object_callback, NULL); + sgen_pin_cemented_objects (); } if (!concurrent_collection_in_progress) sgen_cement_reset (); } - sgen_optimize_pin_queue (0); + sgen_optimize_pin_queue (); /* * The concurrent collector doesn't move objects, neither on @@ -2617,7 +2596,7 @@ major_copy_or_mark_from_roots (size_t *old_next_pin_slot, gboolean finish_up_con SGEN_LOG (6, "Pinning from large objects"); for (bigobj = los_object_list; bigobj; bigobj = bigobj->next) { size_t dummy; - if (sgen_find_optimized_pin_queue_area (bigobj->data, (char*)bigobj->data + sgen_los_object_size (bigobj), &dummy)) { + if (sgen_find_optimized_pin_queue_area (bigobj->data, (char*)bigobj->data + sgen_los_object_size (bigobj), &dummy, &dummy)) { binary_protocol_pin (bigobj->data, (gpointer)LOAD_VTABLE (bigobj->data), safe_object_get_size (((MonoObject*)(bigobj->data)))); #ifdef ENABLE_DTRACE @@ -2633,7 +2612,7 @@ major_copy_or_mark_from_roots (size_t *old_next_pin_slot, gboolean finish_up_con } sgen_los_pin_object (bigobj->data); if (SGEN_OBJECT_HAS_REFERENCES (bigobj->data)) - GRAY_OBJECT_ENQUEUE (WORKERS_DISTRIBUTE_GRAY_QUEUE, bigobj->data); + GRAY_OBJECT_ENQUEUE (WORKERS_DISTRIBUTE_GRAY_QUEUE, bigobj->data, sgen_obj_get_descriptor (bigobj->data)); if (G_UNLIKELY (do_pin_stats)) sgen_pin_stats_register_object ((char*) bigobj->data, safe_object_get_size ((MonoObject*) bigobj->data)); SGEN_LOG (6, "Marked large object %p (%s) size: %lu from roots", bigobj->data, safe_name (bigobj->data), (unsigned long)sgen_los_object_size (bigobj)); @@ -2692,11 +2671,6 @@ major_copy_or_mark_from_roots (size_t *old_next_pin_slot, gboolean finish_up_con main_gc_thread = mono_native_thread_self (); #endif - if (!concurrent_collection_in_progress && major_collector.is_parallel) { - sgen_workers_start_all_workers (); - sgen_workers_start_marking (); - } - if (mono_profiler_get_events () & MONO_PROFILE_GC_ROOTS) report_registered_roots (); TV_GETTIME (atv); @@ -2738,13 +2712,8 @@ major_copy_or_mark_from_roots (size_t *old_next_pin_slot, gboolean finish_up_con report_finalizer_roots (); /* scan the list of objects ready for finalization */ - sfejd_fin_ready = sgen_alloc_internal_dynamic (sizeof (ScanFinalizerEntriesJobData), INTERNAL_MEM_WORKER_JOB_DATA, TRUE); - sfejd_fin_ready->list = fin_ready_list; - sgen_workers_enqueue_job (job_scan_finalizer_entries, sfejd_fin_ready); - - sfejd_critical_fin = sgen_alloc_internal_dynamic (sizeof (ScanFinalizerEntriesJobData), INTERNAL_MEM_WORKER_JOB_DATA, TRUE); - sfejd_critical_fin->list = critical_fin_list; - sgen_workers_enqueue_job (job_scan_finalizer_entries, sfejd_critical_fin); + sgen_workers_enqueue_job (job_scan_finalizer_entries, fin_ready_list); + sgen_workers_enqueue_job (job_scan_finalizer_entries, critical_fin_list); if (scan_mod_union) { g_assert (finish_up_concurrent_mark); @@ -2825,7 +2794,7 @@ wait_for_workers_to_finish (void) static void join_workers (void) { - if (concurrent_collection_in_progress || major_collector.is_parallel) { + if (concurrent_collection_in_progress) { gray_queue_redirect (&gray_queue); sgen_workers_join (); } @@ -2846,7 +2815,7 @@ major_finish_collection (const char *reason, size_t old_next_pin_slot, gboolean TV_GETTIME (btv); - if (concurrent_collection_in_progress || major_collector.is_parallel) + if (concurrent_collection_in_progress) join_workers (); if (concurrent_collection_in_progress) { @@ -2887,9 +2856,21 @@ major_finish_collection (const char *reason, size_t old_next_pin_slot, gboolean if (objects_pinned) { g_assert (!concurrent_collection_in_progress); - /*This is slow, but we just OOM'd*/ + /* + * This is slow, but we just OOM'd. + * + * See comment at `sgen_pin_queue_clear_discarded_entries` for how the pin + * queue is laid out at this point. + */ sgen_pin_queue_clear_discarded_entries (nursery_section, old_next_pin_slot); - sgen_optimize_pin_queue (0); + /* + * We need to reestablish all pinned nursery objects in the pin queue + * because they're needed for fragment creation. Unpinning happens by + * walking the whole queue, so it's not necessary to reestablish where major + * heap block pins are - all we care is that they're still in there + * somewhere. + */ + sgen_optimize_pin_queue (); sgen_find_section_pin_queue_start_end (nursery_section); objects_pinned = 0; } @@ -2945,7 +2926,7 @@ major_finish_collection (const char *reason, size_t old_next_pin_slot, gboolean * pinned objects as we go, memzero() the empty fragments so they are ready for the * next allocations. */ - if (!sgen_build_nursery_fragments (nursery_section, nursery_section->pin_queue_start, nursery_section->pin_queue_num_entries, NULL)) + if (!sgen_build_nursery_fragments (nursery_section, NULL)) degraded_mode = 1; /* prepare the pin queue for the next collection */ @@ -2997,8 +2978,8 @@ major_finish_collection (const char *reason, size_t old_next_pin_slot, gboolean static gboolean major_do_collection (const char *reason) { - TV_DECLARE (all_atv); - TV_DECLARE (all_btv); + TV_DECLARE (time_start); + TV_DECLARE (time_end); size_t old_next_pin_slot; if (disable_major_collections) @@ -3010,13 +2991,13 @@ major_do_collection (const char *reason) } /* world must be stopped already */ - TV_GETTIME (all_atv); + TV_GETTIME (time_start); major_start_collection (FALSE, &old_next_pin_slot); major_finish_collection (reason, old_next_pin_slot, FALSE); - TV_GETTIME (all_btv); - gc_stats.major_gc_time += TV_ELAPSED (all_atv, all_btv); + TV_GETTIME (time_end); + gc_stats.major_gc_time += TV_ELAPSED (time_start, time_end); /* FIXME: also report this to the user, preferably in gc-end. */ if (major_collector.get_and_reset_num_major_objects_marked) @@ -3028,11 +3009,16 @@ major_do_collection (const char *reason) static void major_start_concurrent_collection (const char *reason) { + TV_DECLARE (time_start); + TV_DECLARE (time_end); long long num_objects_marked; if (disable_major_collections) return; + TV_GETTIME (time_start); + SGEN_TV_GETTIME (time_major_conc_collection_start); + num_objects_marked = major_collector.get_and_reset_num_major_objects_marked (); g_assert (num_objects_marked == 0); @@ -3048,15 +3034,22 @@ major_start_concurrent_collection (const char *reason) num_objects_marked = major_collector.get_and_reset_num_major_objects_marked (); MONO_GC_CONCURRENT_START_END (GENERATION_OLD, num_objects_marked); + TV_GETTIME (time_end); + gc_stats.major_gc_time += TV_ELAPSED (time_start, time_end); + current_collection_generation = -1; } static gboolean major_update_or_finish_concurrent_collection (gboolean force_finish) { + TV_DECLARE (total_start); + TV_DECLARE (total_end); SgenGrayQueue unpin_queue; memset (&unpin_queue, 0, sizeof (unpin_queue)); + TV_GETTIME (total_start); + MONO_GC_CONCURRENT_UPDATE_FINISH_BEGIN (GENERATION_OLD, major_collector.get_and_reset_num_major_objects_marked ()); binary_protocol_concurrent_update_finish (); @@ -3067,6 +3060,10 @@ major_update_or_finish_concurrent_collection (gboolean force_finish) sgen_los_update_cardtable_mod_union (); MONO_GC_CONCURRENT_UPDATE_END (GENERATION_OLD, major_collector.get_and_reset_num_major_objects_marked ()); + + TV_GETTIME (total_end); + gc_stats.major_gc_time += TV_ELAPSED (total_start, total_end); + return FALSE; } @@ -3078,6 +3075,9 @@ major_update_or_finish_concurrent_collection (gboolean force_finish) */ wait_for_workers_to_finish (); + SGEN_TV_GETTIME (time_major_conc_collection_end); + gc_stats.major_gc_time_concurrent += SGEN_TV_ELAPSED (time_major_conc_collection_start, time_major_conc_collection_end); + major_collector.update_cardtable_mod_union (); sgen_los_update_cardtable_mod_union (); @@ -3097,6 +3097,9 @@ major_update_or_finish_concurrent_collection (gboolean force_finish) MONO_GC_CONCURRENT_FINISH_END (GENERATION_OLD, major_collector.get_and_reset_num_major_objects_marked ()); + TV_GETTIME (total_end); + gc_stats.major_gc_time += TV_ELAPSED (total_start, total_end) - TV_ELAPSED (last_minor_collection_start_tv, last_minor_collection_end_tv); + current_collection_generation = -1; return TRUE; @@ -3153,6 +3156,8 @@ void 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; @@ -3175,6 +3180,8 @@ sgen_perform_collection (size_t requested_size, int generation_to_collect, const 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; @@ -3254,6 +3261,9 @@ sgen_perform_collection (size_t requested_size, int generation_to_collect, const 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); @@ -3835,11 +3845,11 @@ sgen_thread_register (SgenThreadInfo* info, void *addr) binary_protocol_thread_register ((gpointer)mono_thread_info_get_tid (info)); /* On win32, stack_start_limit should be 0, since the stack can grow dynamically */ -#ifndef HOST_WIN32 mono_thread_info_get_stack_bounds (&staddr, &stsize); -#endif if (staddr) { +#ifndef HOST_WIN32 info->stack_start_limit = staddr; +#endif info->stack_end = staddr + stsize; } else { gsize stack_bottom = (gsize)addr; @@ -4272,6 +4282,8 @@ typedef struct { static void collect_references (HeapWalkInfo *hwi, char *start, size_t size) { + mword desc = sgen_obj_get_descriptor (start); + #include "sgen-scan-object.h" } @@ -4366,6 +4378,25 @@ mono_gc_get_los_limit (void) 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) { @@ -4547,7 +4578,6 @@ mono_gc_base_init (void) char *minor_collector_opt = NULL; size_t max_heap = 0; size_t soft_limit = 0; - int num_workers; int result; int dummy; gboolean debug_print_allowance = FALSE; @@ -4617,6 +4647,8 @@ mono_gc_base_init (void) sgen_init_fin_weak_hash (); sgen_init_stw (); sgen_init_hash_table (); + sgen_init_descriptors (); + sgen_init_gray_queues (); sgen_register_fixed_internal_mem_type (INTERNAL_MEM_SECTION, SGEN_SIZEOF_GC_MEM_SECTION); sgen_register_fixed_internal_mem_type (INTERNAL_MEM_FINALIZE_READY_ENTRY, sizeof (FinalizeReadyEntry)); @@ -4667,12 +4699,6 @@ mono_gc_base_init (void) if (!major_collector_opt || !strcmp (major_collector_opt, "marksweep")) { use_marksweep_major: sgen_marksweep_init (&major_collector); - } else if (!major_collector_opt || !strcmp (major_collector_opt, "marksweep-fixed")) { - sgen_marksweep_fixed_init (&major_collector); - } else if (!major_collector_opt || !strcmp (major_collector_opt, "marksweep-par")) { - sgen_marksweep_par_init (&major_collector); - } else if (!major_collector_opt || !strcmp (major_collector_opt, "marksweep-fixed-par")) { - sgen_marksweep_fixed_par_init (&major_collector); } else if (!major_collector_opt || !strcmp (major_collector_opt, "marksweep-conc")) { sgen_marksweep_conc_init (&major_collector); } else { @@ -4680,16 +4706,6 @@ mono_gc_base_init (void) goto use_marksweep_major; } - if (have_split_nursery && major_collector.is_parallel) { - sgen_env_var_error (MONO_GC_PARAMS_NAME, "Disabling split minor collector.", "`minor=split` is not supported with the parallel collector yet."); - have_split_nursery = FALSE; - } - - num_workers = mono_cpu_count (); - g_assert (num_workers > 0); - if (num_workers > 16) - num_workers = 16; - ///* Keep this the default for now */ /* Precise marking is broken on all supported targets. Disable until fixed. */ conservative_stack_mark = TRUE; @@ -4731,26 +4747,6 @@ mono_gc_base_init (void) } continue; } - if (g_str_has_prefix (opt, "workers=")) { - long val; - char *endptr; - if (!major_collector.is_parallel) { - sgen_env_var_error (MONO_GC_PARAMS_NAME, "Ignoring.", "The `workers` option can only be used for parallel collectors."); - continue; - } - opt = strchr (opt, '=') + 1; - val = strtol (opt, &endptr, 10); - if (!*opt || *endptr) { - sgen_env_var_error (MONO_GC_PARAMS_NAME, "Ignoring.", "Cannot parse the `workers` option value."); - continue; - } - if (val <= 0 || val > 16) { - sgen_env_var_error (MONO_GC_PARAMS_NAME, "Using default value.", "The number of `workers` must be in the range 1 to 16."); - continue; - } - num_workers = (int)val; - continue; - } if (g_str_has_prefix (opt, "stack-mark=")) { opt = strchr (opt, '=') + 1; if (!strcmp (opt, "precise")) { @@ -4841,10 +4837,6 @@ mono_gc_base_init (void) } if (!strcmp (opt, "cementing")) { - if (major_collector.is_parallel) { - sgen_env_var_error (MONO_GC_PARAMS_NAME, "Ignoring.", "`cementing` is not supported for the parallel major collector."); - continue; - } cement_enabled = TRUE; continue; } @@ -4868,7 +4860,7 @@ mono_gc_base_init (void) fprintf (stderr, " max-heap-size=N (where N is an integer, possibly with a k, m or a g suffix)\n"); fprintf (stderr, " soft-heap-limit=n (where N is an integer, possibly with a k, m or a g suffix)\n"); fprintf (stderr, " nursery-size=N (where N is an integer, possibly with a k, m or a g suffix)\n"); - fprintf (stderr, " major=COLLECTOR (where COLLECTOR is `marksweep', `marksweep-conc', `marksweep-par', 'marksweep-fixed' or 'marksweep-fixed-par')\n"); + fprintf (stderr, " major=COLLECTOR (where COLLECTOR is `marksweep', `marksweep-conc', `marksweep-par')\n"); fprintf (stderr, " minor=COLLECTOR (where COLLECTOR is `simple' or `split')\n"); fprintf (stderr, " wbarrier=WBARRIER (where WBARRIER is `remset' or `cardtable')\n"); fprintf (stderr, " stack-mark=MARK-METHOD (where MARK-METHOD is 'precise' or 'conservative')\n"); @@ -4889,12 +4881,8 @@ mono_gc_base_init (void) g_strfreev (opts); } - if (major_collector.is_parallel) { - cement_enabled = FALSE; - sgen_workers_init (num_workers); - } else if (major_collector.is_concurrent) { + if (major_collector.is_concurrent) sgen_workers_init (1); - } if (major_collector_opt) g_free (major_collector_opt); @@ -4920,11 +4908,7 @@ mono_gc_base_init (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; @@ -5011,6 +4995,10 @@ mono_gc_base_init (void) *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); @@ -5040,6 +5028,7 @@ mono_gc_base_init (void) fprintf (stderr, " print-pinning\n"); fprintf (stderr, " heap-dump=\n"); fprintf (stderr, " binary-protocol=[:]\n"); + fprintf (stderr, " nursery-canaries\n"); sgen_bridge_print_gc_debug_usage (); fprintf (stderr, "\n"); @@ -5049,18 +5038,6 @@ mono_gc_base_init (void) g_strfreev (opts); } - if (major_collector.is_parallel) { - if (heap_dump_file) { - sgen_env_var_error (MONO_GC_DEBUG_NAME, "Disabling.", "Cannot do `heap-dump` with the parallel collector."); - fclose (heap_dump_file); - heap_dump_file = NULL; - } - if (do_pin_stats) { - sgen_env_var_error (MONO_GC_DEBUG_NAME, "Disabling.", "`print-pinning` is not supported with the parallel collector."); - do_pin_stats = FALSE; - } - } - if (major_collector.post_param_init) major_collector.post_param_init (&major_collector); @@ -5432,4 +5409,8 @@ mono_gc_register_finalizer_callbacks (MonoGCFinalizerCallbacks *callbacks) fin_callbacks = *callbacks; } + + + + #endif /* HAVE_SGEN_GC */ diff --git a/mono/metadata/sgen-gc.h b/mono/metadata/sgen-gc.h index 41a7151ba29..0fa76130411 100644 --- a/mono/metadata/sgen-gc.h +++ b/mono/metadata/sgen-gc.h @@ -144,8 +144,8 @@ struct _GCMemSection { */ char **scan_starts; /* in major collections indexes in the pin_queue for objects that pin this section */ - void **pin_queue_start; - size_t pin_queue_num_entries; + size_t pin_queue_first_entry; + size_t pin_queue_last_entry; size_t num_scan_start; }; @@ -190,14 +190,10 @@ extern LOCK_DECLARE (sgen_interruption_mutex); #endif #ifdef HEAVY_STATISTICS -#define HEAVY_STAT(x) x - extern long long stat_objects_alloced_degraded; extern long long stat_bytes_alloced_degraded; extern long long stat_copy_object_called_major; extern long long stat_objects_copied_major; -#else -#define HEAVY_STAT(x) #endif #define SGEN_ASSERT(level, a, ...) do { \ @@ -323,77 +319,42 @@ typedef struct { * The values are already shifted. * The forwarding address is stored in the sync block. */ -#define SGEN_FORWARDED_BIT 1 -#define SGEN_PINNED_BIT 2 + #define SGEN_VTABLE_BITS_MASK 0x3 +#include "sgen-tagged-pointer.h" + +#define SGEN_POINTER_IS_TAGGED_FORWARDED(p) SGEN_POINTER_IS_TAGGED_1((p)) +#define SGEN_POINTER_TAG_FORWARDED(p) SGEN_POINTER_TAG_1((p)) + +#define SGEN_POINTER_IS_TAGGED_PINNED(p) SGEN_POINTER_IS_TAGGED_2((p)) +#define SGEN_POINTER_TAG_PINNED(p) SGEN_POINTER_TAG_2((p)) + +#define SGEN_POINTER_UNTAG_VTABLE(p) SGEN_POINTER_UNTAG_12((p)) + /* returns NULL if not forwarded, or the forwarded address */ -#define SGEN_OBJECT_IS_FORWARDED(obj) (((mword*)(obj))[0] & SGEN_FORWARDED_BIT ? (void*)(((mword*)(obj))[0] & ~SGEN_VTABLE_BITS_MASK) : NULL) -#define SGEN_OBJECT_IS_PINNED(obj) (((mword*)(obj))[0] & SGEN_PINNED_BIT) +#define SGEN_VTABLE_IS_FORWARDED(vtable) (SGEN_POINTER_IS_TAGGED_FORWARDED ((vtable)) ? SGEN_POINTER_UNTAG_VTABLE ((vtable)) : NULL) +#define SGEN_OBJECT_IS_FORWARDED(obj) (SGEN_VTABLE_IS_FORWARDED (((mword*)(obj))[0])) + +#define SGEN_VTABLE_IS_PINNED(vtable) SGEN_POINTER_IS_TAGGED_PINNED ((vtable)) +#define SGEN_OBJECT_IS_PINNED(obj) (SGEN_VTABLE_IS_PINNED (((mword*)(obj))[0])) /* set the forwarded address fw_addr for object obj */ #define SGEN_FORWARD_OBJECT(obj,fw_addr) do { \ - ((mword*)(obj))[0] = (mword)(fw_addr) | SGEN_FORWARDED_BIT; \ + *(void**)(obj) = SGEN_POINTER_TAG_FORWARDED ((fw_addr)); \ } while (0) #define SGEN_PIN_OBJECT(obj) do { \ - ((mword*)(obj))[0] |= SGEN_PINNED_BIT; \ + *(void**)(obj) = SGEN_POINTER_TAG_PINNED (*(void**)(obj)); \ } while (0) #define SGEN_UNPIN_OBJECT(obj) do { \ - ((mword*)(obj))[0] &= ~SGEN_PINNED_BIT; \ + *(void**)(obj) = SGEN_POINTER_UNTAG_2 (*(void**)(obj)); \ } while (0) /* * Since we set bits in the vtable, use the macro to load it from the pointer to * an object that is potentially pinned. */ -#define SGEN_LOAD_VTABLE(addr) ((*(mword*)(addr)) & ~SGEN_VTABLE_BITS_MASK) - -static inline MONO_ALWAYS_INLINE void -GRAY_OBJECT_ENQUEUE (SgenGrayQueue *queue, char* obj) -{ -#if defined(SGEN_GRAY_OBJECT_ENQUEUE) || SGEN_MAX_DEBUG_LEVEL >= 9 - sgen_gray_object_enqueue (queue, obj); -#else - if (G_UNLIKELY (!queue->first || queue->cursor == GRAY_LAST_CURSOR_POSITION (queue->first))) { - sgen_gray_object_enqueue (queue, obj); - } else { - HEAVY_STAT (gc_stats.gray_queue_enqueue_fast_path ++); - - *++queue->cursor = obj; -#ifdef SGEN_HEAVY_BINARY_PROTOCOL - binary_protocol_gray_enqueue (queue, queue->cursor, obj); -#endif - } - - PREFETCH (obj); -#endif -} - -static inline MONO_ALWAYS_INLINE void -GRAY_OBJECT_DEQUEUE (SgenGrayQueue *queue, char** obj) -{ -#if defined(SGEN_GRAY_OBJECT_ENQUEUE) || SGEN_MAX_DEBUG_LEVEL >= 9 - *obj = sgen_gray_object_enqueue (queue); -#else - if (!queue->first) { - HEAVY_STAT (gc_stats.gray_queue_dequeue_fast_path ++); - - *obj = NULL; -#ifdef SGEN_HEAVY_BINARY_PROTOCOL - binary_protocol_gray_dequeue (queue, queue->cursor, *obj); -#endif - } else if (G_UNLIKELY (queue->cursor == GRAY_FIRST_CURSOR_POSITION (queue->first))) { - *obj = sgen_gray_object_dequeue (queue); - } else { - HEAVY_STAT (gc_stats.gray_queue_dequeue_fast_path ++); - - *obj = *queue->cursor--; -#ifdef SGEN_HEAVY_BINARY_PROTOCOL - binary_protocol_gray_dequeue (queue, queue->cursor + 1, *obj); -#endif - } -#endif -} +#define SGEN_LOAD_VTABLE(addr) SGEN_POINTER_UNTAG_12 (*(void**)(addr)) /* List of what each bit on of the vtable gc bits means. @@ -500,7 +461,7 @@ struct _ObjectList { }; typedef void (*CopyOrMarkObjectFunc) (void**, SgenGrayQueue*); -typedef void (*ScanObjectFunc) (char*, SgenGrayQueue*); +typedef void (*ScanObjectFunc) (char *obj, mword desc, SgenGrayQueue*); typedef void (*ScanVTypeFunc) (char*, mword desc, SgenGrayQueue* BINARY_PROTOCOL_ARG (size_t size)); typedef struct @@ -525,10 +486,6 @@ void sgen_free_internal (void *addr, int type) MONO_INTERNAL; void* sgen_alloc_internal_dynamic (size_t size, int type, gboolean assert_on_failure) MONO_INTERNAL; void sgen_free_internal_dynamic (void *addr, size_t size, int type) MONO_INTERNAL; -void** sgen_find_optimized_pin_queue_area (void *start, void *end, size_t *num) MONO_INTERNAL; -void sgen_find_section_pin_queue_start_end (GCMemSection *section) MONO_INTERNAL; -void sgen_pin_objects_in_section (GCMemSection *section, ScanCopyContext ctx) MONO_INTERNAL; - void sgen_pin_stats_register_object (char *obj, size_t size); void sgen_pin_stats_register_global_remset (char *obj); void sgen_pin_stats_print_class_stats (void); @@ -537,7 +494,6 @@ void sgen_sort_addresses (void **array, size_t size) MONO_INTERNAL; void sgen_add_to_global_remset (gpointer ptr, gpointer obj) MONO_INTERNAL; int sgen_get_current_collection_generation (void) MONO_INTERNAL; -gboolean sgen_collection_is_parallel (void) MONO_INTERNAL; gboolean sgen_collection_is_concurrent (void) MONO_INTERNAL; gboolean sgen_concurrent_collection_in_progress (void) MONO_INTERNAL; @@ -600,7 +556,7 @@ static inline gboolean sgen_nursery_is_to_space (char *object) { size_t idx = (object - sgen_nursery_start) >> SGEN_TO_SPACE_GRANULE_BITS; - size_t byte = idx / 8; + size_t byte = idx >> 3; size_t bit = idx & 0x7; SGEN_ASSERT (4, sgen_ptr_in_nursery (object), "object %p is not in nursery [%p - %p]", object, sgen_get_nursery_start (), sgen_get_nursery_end ()); @@ -634,10 +590,8 @@ typedef struct { gboolean is_split; char* (*alloc_for_promotion) (MonoVTable *vtable, char *obj, size_t objsize, gboolean has_references); - char* (*par_alloc_for_promotion) (MonoVTable *vtable, char *obj, size_t objsize, gboolean has_references); SgenObjectOperations serial_ops; - SgenObjectOperations parallel_ops; void (*prepare_to_space) (char *to_space_bitmap, size_t space_bitmap_size); void (*clear_fragments) (void); @@ -671,7 +625,6 @@ typedef enum { typedef struct _SgenMajorCollector SgenMajorCollector; struct _SgenMajorCollector { size_t section_size; - gboolean is_parallel; gboolean is_concurrent; gboolean supports_cardtable; gboolean sweeps_lazily; @@ -697,7 +650,6 @@ struct _SgenMajorCollector { SgenObjectOperations major_concurrent_ops; void* (*alloc_object) (MonoVTable *vtable, size_t size, gboolean has_references); - void* (*par_alloc_object) (MonoVTable *vtable, size_t size, gboolean has_references); void (*free_pinned_object) (char *obj, size_t size); void (*iterate_objects) (IterateObjectsFlags flags, IterateObjectCallbackFunc callback, void *data); void (*free_non_pinned_object) (char *obj, size_t size); @@ -775,7 +727,7 @@ slow_object_get_size (MonoVTable *vtable, MonoObject* o) * 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); @@ -791,6 +743,27 @@ slow_object_get_size (MonoVTable *vtable, MonoObject* o) } } +static inline mword +sgen_vtable_get_descriptor (MonoVTable *vtable) +{ + return (mword)vtable->gc_descr; +} + +static inline mword +sgen_obj_get_descriptor (char *obj) +{ + MonoVTable *vtable = ((MonoObject*)obj)->vtable; + SGEN_ASSERT (0, !SGEN_POINTER_IS_TAGGED_1_OR_2 (vtable), "Object can't be tagged"); + return sgen_vtable_get_descriptor (vtable); +} + +static inline mword +sgen_obj_get_descriptor_safe (char *obj) +{ + MonoVTable *vtable = (MonoVTable*)SGEN_LOAD_VTABLE (obj); + return sgen_vtable_get_descriptor (vtable); +} + /* * This function can be called on an object whose first word, the * vtable field, is not intact. This is necessary for the parallel @@ -805,7 +778,7 @@ sgen_par_object_get_size (MonoVTable *vtable, MonoObject* o) 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; @@ -834,6 +807,22 @@ sgen_safe_object_get_size (MonoObject *obj) 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; @@ -985,7 +974,7 @@ gboolean sgen_los_object_is_pinned (char *obj) MONO_INTERNAL; void sgen_clear_nursery_fragments (void) MONO_INTERNAL; void sgen_nursery_allocator_prepare_for_pinning (void) MONO_INTERNAL; void sgen_nursery_allocator_set_nursery_bounds (char *nursery_start, char *nursery_end) MONO_INTERNAL; -mword sgen_build_nursery_fragments (GCMemSection *nursery_section, void **start, size_t num_entries, SgenGrayQueue *unpin_queue) MONO_INTERNAL; +mword sgen_build_nursery_fragments (GCMemSection *nursery_section, SgenGrayQueue *unpin_queue) MONO_INTERNAL; void sgen_init_nursery_allocator (void) MONO_INTERNAL; void sgen_nursery_allocator_init_heavy_stats (void) MONO_INTERNAL; void sgen_alloc_init_heavy_stats (void) MONO_INTERNAL; @@ -1000,7 +989,6 @@ void sgen_nursery_alloc_prepare_for_minor (void) MONO_INTERNAL; void sgen_nursery_alloc_prepare_for_major (void) MONO_INTERNAL; char* sgen_alloc_for_promotion (char *obj, size_t objsize, gboolean has_references) MONO_INTERNAL; -char* sgen_par_alloc_for_promotion (char *obj, size_t objsize, gboolean has_references) MONO_INTERNAL; /* TLS Data */ @@ -1168,6 +1156,37 @@ void sgen_env_var_error (const char *env_var, const char *fallback, const char * 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__ */ diff --git a/mono/metadata/sgen-gray.c b/mono/metadata/sgen-gray.c index 2393cbabb14..247608751fe 100644 --- a/mono/metadata/sgen-gray.c +++ b/mono/metadata/sgen-gray.c @@ -25,6 +25,15 @@ #include "utils/mono-counters.h" #include "sgen-protocol.h" +#ifdef HEAVY_STATISTICS +unsigned long long stat_gray_queue_section_alloc; +unsigned long long stat_gray_queue_section_free; +unsigned long long stat_gray_queue_enqueue_fast_path; +unsigned long long stat_gray_queue_dequeue_fast_path; +unsigned long long stat_gray_queue_enqueue_slow_path; +unsigned long long stat_gray_queue_dequeue_slow_path; +#endif + #define GRAY_QUEUE_LENGTH_LIMIT 64 #ifdef SGEN_CHECK_GRAY_OBJECT_SECTIONS @@ -46,7 +55,7 @@ sgen_gray_object_alloc_queue_section (SgenGrayQueue *queue) { GrayQueueSection *section; - HEAVY_STAT (gc_stats.gray_queue_section_alloc ++); + HEAVY_STAT (stat_gray_queue_section_alloc ++); if (queue->alloc_prepare_func) queue->alloc_prepare_func (queue); @@ -69,13 +78,13 @@ sgen_gray_object_alloc_queue_section (SgenGrayQueue *queue) /* Link it with the others */ section->next = queue->first; queue->first = section; - queue->cursor = (char**)section->objects - 1; + queue->cursor = section->entries - 1; } void sgen_gray_object_free_queue_section (GrayQueueSection *section) { - HEAVY_STAT (gc_stats.gray_queue_section_free ++); + HEAVY_STAT (stat_gray_queue_section_free ++); STATE_TRANSITION (section, GRAY_QUEUE_SECTION_STATE_FLOATING, GRAY_QUEUE_SECTION_STATE_FREED); sgen_free_internal (section, INTERNAL_MEM_GRAY_QUEUE); @@ -88,9 +97,11 @@ sgen_gray_object_free_queue_section (GrayQueueSection *section) */ void -sgen_gray_object_enqueue (SgenGrayQueue *queue, char *obj) +sgen_gray_object_enqueue (SgenGrayQueue *queue, char *obj, mword desc) { - HEAVY_STAT (gc_stats.gray_queue_enqueue_slow_path ++); + GrayQueueEntry entry = { obj, desc }; + + HEAVY_STAT (stat_gray_queue_enqueue_slow_path ++); SGEN_ASSERT (9, obj, "enqueueing a null object"); //sgen_check_objref (obj); @@ -110,33 +121,35 @@ sgen_gray_object_enqueue (SgenGrayQueue *queue, char *obj) } STATE_ASSERT (queue->first, GRAY_QUEUE_SECTION_STATE_ENQUEUED); SGEN_ASSERT (9, queue->cursor <= GRAY_LAST_CURSOR_POSITION (queue->first), "gray queue %p overflow, first %p, cursor %p", queue, queue->first, queue->cursor); - *++queue->cursor = obj; + *++queue->cursor = entry; #ifdef SGEN_HEAVY_BINARY_PROTOCOL binary_protocol_gray_enqueue (queue, queue->cursor, obj); #endif } -char* +GrayQueueEntry sgen_gray_object_dequeue (SgenGrayQueue *queue) { - char *obj; + GrayQueueEntry entry; - HEAVY_STAT (gc_stats.gray_queue_dequeue_slow_path ++); + HEAVY_STAT (stat_gray_queue_dequeue_slow_path ++); - if (sgen_gray_object_queue_is_empty (queue)) - return NULL; + if (sgen_gray_object_queue_is_empty (queue)) { + entry.obj = NULL; + return entry; + } STATE_ASSERT (queue->first, GRAY_QUEUE_SECTION_STATE_ENQUEUED); - SGEN_ASSERT (9, queue->cursor >= (char**)queue->first->objects, "gray queue %p underflow, first %p, cursor %d", queue, queue->first, queue->cursor); + SGEN_ASSERT (9, queue->cursor >= GRAY_FIRST_CURSOR_POSITION (queue->first), "gray queue %p underflow, first %p, cursor %d", queue, queue->first, queue->cursor); - obj = *queue->cursor--; + entry = *queue->cursor--; #ifdef SGEN_HEAVY_BINARY_PROTOCOL binary_protocol_gray_dequeue (queue, queue->cursor + 1, obj); #endif - if (G_UNLIKELY (queue->cursor == (char**)queue->first->objects - 1)) { + if (G_UNLIKELY (queue->cursor < GRAY_FIRST_CURSOR_POSITION (queue->first))) { GrayQueueSection *section = queue->first; queue->first = section->next; section->next = queue->free_list; @@ -144,10 +157,10 @@ sgen_gray_object_dequeue (SgenGrayQueue *queue) STATE_TRANSITION (section, GRAY_QUEUE_SECTION_STATE_ENQUEUED, GRAY_QUEUE_SECTION_STATE_FREE_LIST); queue->free_list = section; - queue->cursor = queue->first ? (char**)queue->first->objects + queue->first->size - 1 : NULL; + queue->cursor = queue->first ? queue->first->entries + queue->first->size - 1 : NULL; } - return obj; + return entry; } GrayQueueSection* @@ -162,9 +175,9 @@ sgen_gray_object_dequeue_section (SgenGrayQueue *queue) queue->first = section->next; section->next = NULL; - section->size = queue->cursor - (char**)section->objects + 1; + section->size = queue->cursor - section->entries + 1; - queue->cursor = queue->first ? (char**)queue->first->objects + queue->first->size - 1 : NULL; + queue->cursor = queue->first ? queue->first->entries + queue->first->size - 1 : NULL; STATE_TRANSITION (section, GRAY_QUEUE_SECTION_STATE_ENQUEUED, GRAY_QUEUE_SECTION_STATE_FLOATING); @@ -177,36 +190,25 @@ sgen_gray_object_enqueue_section (SgenGrayQueue *queue, GrayQueueSection *sectio STATE_TRANSITION (section, GRAY_QUEUE_SECTION_STATE_FLOATING, GRAY_QUEUE_SECTION_STATE_ENQUEUED); if (queue->first) - queue->first->size = queue->cursor - (char**)queue->first->objects + 1; + queue->first->size = queue->cursor - queue->first->entries + 1; section->next = queue->first; queue->first = section; - queue->cursor = (char**)queue->first->objects + queue->first->size - 1; + queue->cursor = queue->first->entries + queue->first->size - 1; #ifdef SGEN_CHECK_GRAY_OBJECT_ENQUEUE if (queue->enqueue_check_func) { int i; for (i = 0; i < section->size; ++i) - queue->enqueue_check_func (section->objects [i]); + queue->enqueue_check_func (section->entries [i].obj); } #endif } void -sgen_gray_object_queue_init (SgenGrayQueue *queue, GrayQueueEnqueueCheckFunc enqueue_check_func) +sgen_gray_object_queue_trim_free_list (SgenGrayQueue *queue) { GrayQueueSection *section, *next; - int i; - - g_assert (sgen_gray_object_queue_is_empty (queue)); - - queue->alloc_prepare_func = NULL; - queue->alloc_prepare_data = NULL; -#ifdef SGEN_CHECK_GRAY_OBJECT_ENQUEUE - queue->enqueue_check_func = enqueue_check_func; -#endif - - /* Free the extra sections allocated during the last collection */ - i = 0; + int i = 0; for (section = queue->free_list; section && i < GRAY_QUEUE_LENGTH_LIMIT - 1; section = section->next) { STATE_ASSERT (section, GRAY_QUEUE_SECTION_STATE_FREE_LIST); i ++; @@ -221,6 +223,21 @@ sgen_gray_object_queue_init (SgenGrayQueue *queue, GrayQueueEnqueueCheckFunc enq } } +void +sgen_gray_object_queue_init (SgenGrayQueue *queue, GrayQueueEnqueueCheckFunc enqueue_check_func) +{ + g_assert (sgen_gray_object_queue_is_empty (queue)); + + queue->alloc_prepare_func = NULL; + queue->alloc_prepare_data = NULL; +#ifdef SGEN_CHECK_GRAY_OBJECT_ENQUEUE + queue->enqueue_check_func = enqueue_check_func; +#endif + + /* Free the extra sections allocated during the last collection */ + sgen_gray_object_queue_trim_free_list (queue); +} + static void invalid_prepare_func (SgenGrayQueue *queue) { @@ -338,11 +355,23 @@ sgen_section_gray_queue_enqueue (SgenSectionGrayQueue *queue, GrayQueueSection * if (queue->enqueue_check_func) { int i; for (i = 0; i < section->size; ++i) - queue->enqueue_check_func (section->objects [i]); + queue->enqueue_check_func (section->entries [i].obj); } #endif unlock_section_queue (queue); } +void +sgen_init_gray_queues (void) +{ +#ifdef HEAVY_STATISTICS + mono_counters_register ("Gray Queue alloc section", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_gray_queue_section_alloc); + mono_counters_register ("Gray Queue free section", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_gray_queue_section_free); + mono_counters_register ("Gray Queue enqueue fast path", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_gray_queue_enqueue_fast_path); + mono_counters_register ("Gray Queue dequeue fast path", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_gray_queue_dequeue_fast_path); + mono_counters_register ("Gray Queue enqueue slow path", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_gray_queue_enqueue_slow_path); + mono_counters_register ("Gray Queue dequeue slow path", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_gray_queue_dequeue_slow_path); +#endif +} #endif diff --git a/mono/metadata/sgen-gray.h b/mono/metadata/sgen-gray.h index 2dfea35a146..c0ccd616bd7 100644 --- a/mono/metadata/sgen-gray.h +++ b/mono/metadata/sgen-gray.h @@ -48,7 +48,14 @@ * array and another 1 for the actual value in the array. */ -#define SGEN_GRAY_QUEUE_SECTION_SIZE (128 - 3) +/* SGEN_GRAY_QUEUE_HEADER_SIZE is number of machine words */ +#ifdef SGEN_CHECK_GRAY_OBJECT_SECTIONS +#define SGEN_GRAY_QUEUE_HEADER_SIZE 4 +#else +#define SGEN_GRAY_QUEUE_HEADER_SIZE 2 +#endif + +#define SGEN_GRAY_QUEUE_SECTION_SIZE (128 - SGEN_GRAY_QUEUE_HEADER_SIZE) #ifdef SGEN_CHECK_GRAY_OBJECT_SECTIONS typedef enum { @@ -59,6 +66,12 @@ typedef enum { } GrayQueueSectionState; #endif +typedef struct _GrayQueueEntry GrayQueueEntry; +struct _GrayQueueEntry { + char *obj; + mword desc; +}; + /* * This is a stack now instead of a queue, so the most recently added items are removed * first, improving cache locality, and keeping the stack size manageable. @@ -75,7 +88,7 @@ struct _GrayQueueSection { #endif int size; GrayQueueSection *next; - char *objects [SGEN_GRAY_QUEUE_SECTION_SIZE]; + GrayQueueEntry entries [SGEN_GRAY_QUEUE_SECTION_SIZE]; }; typedef struct _SgenGrayQueue SgenGrayQueue; @@ -84,7 +97,7 @@ typedef void (*GrayQueueAllocPrepareFunc) (SgenGrayQueue*); typedef void (*GrayQueueEnqueueCheckFunc) (char*); struct _SgenGrayQueue { - char **cursor; + GrayQueueEntry *cursor; GrayQueueSection *first; GrayQueueSection *free_list; GrayQueueAllocPrepareFunc alloc_prepare_func; @@ -105,13 +118,25 @@ struct _SgenSectionGrayQueue { #endif }; -#define GRAY_LAST_CURSOR_POSITION(s) ((char**)(s)->objects + SGEN_GRAY_QUEUE_SECTION_SIZE - 1) -#define GRAY_FIRST_CURSOR_POSITION(s) ((char**)(s)->objects) +#define GRAY_LAST_CURSOR_POSITION(s) ((s)->entries + SGEN_GRAY_QUEUE_SECTION_SIZE - 1) +#define GRAY_FIRST_CURSOR_POSITION(s) ((s)->entries) + +#ifdef HEAVY_STATISTICS +extern unsigned long long stat_gray_queue_section_alloc; +extern unsigned long long stat_gray_queue_section_free; +extern unsigned long long stat_gray_queue_enqueue_fast_path; +extern unsigned long long stat_gray_queue_dequeue_fast_path; +extern unsigned long long stat_gray_queue_enqueue_slow_path; +extern unsigned long long stat_gray_queue_dequeue_slow_path; +#endif + +void sgen_init_gray_queues (void) MONO_INTERNAL; -void sgen_gray_object_enqueue (SgenGrayQueue *queue, char *obj) MONO_INTERNAL; -char* sgen_gray_object_dequeue (SgenGrayQueue *queue) MONO_INTERNAL; +void sgen_gray_object_enqueue (SgenGrayQueue *queue, char *obj, mword desc) MONO_INTERNAL; +GrayQueueEntry sgen_gray_object_dequeue (SgenGrayQueue *queue) MONO_INTERNAL; GrayQueueSection* sgen_gray_object_dequeue_section (SgenGrayQueue *queue) MONO_INTERNAL; void sgen_gray_object_enqueue_section (SgenGrayQueue *queue, GrayQueueSection *section) MONO_INTERNAL; +void sgen_gray_object_queue_trim_free_list (SgenGrayQueue *queue) MONO_INTERNAL; void sgen_gray_object_queue_init (SgenGrayQueue *queue, GrayQueueEnqueueCheckFunc enqueue_check_func) MONO_INTERNAL; void sgen_gray_object_queue_init_invalid (SgenGrayQueue *queue) MONO_INTERNAL; void sgen_gray_object_queue_init_with_alloc_prepare (SgenGrayQueue *queue, GrayQueueEnqueueCheckFunc enqueue_check_func, @@ -133,4 +158,58 @@ sgen_gray_object_queue_is_empty (SgenGrayQueue *queue) return queue->first == NULL; } +static inline MONO_ALWAYS_INLINE void +GRAY_OBJECT_ENQUEUE (SgenGrayQueue *queue, char* obj, mword desc) +{ +#if SGEN_MAX_DEBUG_LEVEL >= 9 + sgen_gray_object_enqueue (queue, obj, desc); +#else + if (G_UNLIKELY (!queue->first || queue->cursor == GRAY_LAST_CURSOR_POSITION (queue->first))) { + sgen_gray_object_enqueue (queue, obj, desc); + } else { + GrayQueueEntry entry = { obj, desc }; + + HEAVY_STAT (stat_gray_queue_enqueue_fast_path ++); + + *++queue->cursor = entry; +#ifdef SGEN_HEAVY_BINARY_PROTOCOL + binary_protocol_gray_enqueue (queue, queue->cursor, obj); +#endif + } +#endif +} + +static inline MONO_ALWAYS_INLINE void +GRAY_OBJECT_DEQUEUE (SgenGrayQueue *queue, char** obj, mword *desc) +{ + GrayQueueEntry entry; +#if SGEN_MAX_DEBUG_LEVEL >= 9 + entry = sgen_gray_object_enqueue (queue); + *obj = entry.obj; + *desc = entry.desc; +#else + if (!queue->first) { + HEAVY_STAT (stat_gray_queue_dequeue_fast_path ++); + + *obj = NULL; +#ifdef SGEN_HEAVY_BINARY_PROTOCOL + binary_protocol_gray_dequeue (queue, queue->cursor, *obj); +#endif + } else if (G_UNLIKELY (queue->cursor == GRAY_FIRST_CURSOR_POSITION (queue->first))) { + entry = sgen_gray_object_dequeue (queue); + *obj = entry.obj; + *desc = entry.desc; + } else { + HEAVY_STAT (stat_gray_queue_dequeue_fast_path ++); + + entry = *queue->cursor--; + *obj = entry.obj; + *desc = entry.desc; +#ifdef SGEN_HEAVY_BINARY_PROTOCOL + binary_protocol_gray_dequeue (queue, queue->cursor + 1, *obj); +#endif + } +#endif +} + #endif diff --git a/mono/metadata/sgen-internal.c b/mono/metadata/sgen-internal.c index 37ac5c6f329..333f8c3ee41 100644 --- a/mono/metadata/sgen-internal.c +++ b/mono/metadata/sgen-internal.c @@ -23,21 +23,53 @@ #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" /* keep each size a multiple of ALLOC_ALIGN */ +#if SIZEOF_VOID_P == 4 static const int allocator_sizes [] = { 8, 16, 24, 32, 40, 48, 64, 80, - 96, 128, 160, 192, 224, 248, 320, 384, - 448, 528, 584, 680, 816, 1088, 1360, 2040, - 2336, 2728, 3272, 4088, 5456, 8184 }; + 96, 128, 160, 192, 224, 248, 296, 320, + 384, 448, 504, 528, 584, 680, 816, 1088, + 1360, 2044, 2336, 2728, 3272, 4092, 5456, 8188 }; +#else +static const int allocator_sizes [] = { + 8, 16, 24, 32, 40, 48, 64, 80, + 96, 128, 160, 192, 224, 248, 320, 328, + 384, 448, 528, 584, 680, 816, 1016, 1088, + 1360, 2040, 2336, 2728, 3272, 4088, 5456, 8184 }; +#endif #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. @@ -67,6 +99,7 @@ sgen_register_fixed_internal_mem_type (int type, size_t size) 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); @@ -135,6 +168,10 @@ sgen_alloc_internal_dynamic (size_t size, int type, gboolean assert_on_failure) } 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)); @@ -154,7 +191,7 @@ sgen_free_internal_dynamic (void *addr, size_t size, int 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); } @@ -162,10 +199,18 @@ sgen_free_internal_dynamic (void *addr, size_t size, int 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); @@ -185,7 +230,7 @@ sgen_free_internal (void *addr, int type) 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]; @@ -211,22 +256,37 @@ sgen_dump_internal_mem_usage (FILE *heap_dump_file) 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 diff --git a/mono/metadata/sgen-los.c b/mono/metadata/sgen-los.c index 1e38006cac7..8e823b05537 100644 --- a/mono/metadata/sgen-los.c +++ b/mono/metadata/sgen-los.c @@ -336,13 +336,13 @@ sgen_los_alloc_large_inner (MonoVTable *vtable, size_t size) g_assert ((size & 1) == 0); /* - * size + sizeof (LOSObject) <= SIZE_MAX - (mono_pagesize () - 1) + * size + sizeof (LOSObject) <= SSIZE_MAX - (mono_pagesize () - 1) * * therefore: * - * size <= SIZE_MAX - (mono_pagesize () - 1) - sizeof (LOSObject) + * size <= SSIZE_MAX - (mono_pagesize () - 1) - sizeof (LOSObject) */ - if (size > SIZE_MAX - (mono_pagesize () - 1) - sizeof (LOSObject)) + if (size > SSIZE_MAX - (mono_pagesize () - 1) - sizeof (LOSObject)) return NULL; #ifdef LOS_DUMMY diff --git a/mono/metadata/sgen-major-scan-object.h b/mono/metadata/sgen-major-scan-object.h index a4674a2139d..14b11317096 100644 --- a/mono/metadata/sgen-major-scan-object.h +++ b/mono/metadata/sgen-major-scan-object.h @@ -37,12 +37,23 @@ extern long long stat_scan_object_called_major; #define CONCURRENT_NAME(x) x #endif +/* + * FIXME: We use the same scanning function in the concurrent collector whether we scan + * during the starting/finishing collection pause (with the world stopped) or from the + * concurrent worker thread. + * + * As long as the world is stopped, we should just follow pointers into the nursery and + * evict if possible. In that case we also don't need the ALWAYS_ADD_TO_GLOBAL_REMSET case, + * which only seems to make sense for when the world is stopped, in which case we only need + * it because we don't follow into the nursery. + */ + #undef HANDLE_PTR #define HANDLE_PTR(ptr,obj) do { \ void *__old = *(ptr); \ - void *__copy; \ SGEN_OBJECT_LAYOUT_STATISTICS_MARK_BITMAP ((obj), (ptr)); \ if (__old && FOLLOW_OBJECT (__old)) { \ + void *__copy; \ PREFETCH_DYNAMIC_HEAP (__old); \ CONCURRENT_NAME (major_copy_or_mark_object) ((ptr), __old, queue); \ __copy = *(ptr); \ @@ -56,10 +67,14 @@ extern long long stat_scan_object_called_major; } while (0) static void -CONCURRENT_NAME (major_scan_object) (char *start, SgenGrayQueue *queue) +CONCURRENT_NAME (major_scan_object) (char *start, mword desc, SgenGrayQueue *queue) { SGEN_OBJECT_LAYOUT_STATISTICS_DECLARE_BITMAP; +#ifdef HEAVY_STATISTICS + sgen_descriptor_count_scanned_object (desc); +#endif + #define SCAN_OBJECT_PROTOCOL #include "sgen-scan-object.h" diff --git a/mono/metadata/sgen-marksweep-fixed-par.c b/mono/metadata/sgen-marksweep-fixed-par.c deleted file mode 100644 index 7c03e5b1728..00000000000 --- a/mono/metadata/sgen-marksweep-fixed-par.c +++ /dev/null @@ -1,25 +0,0 @@ -#include "config.h" - -#ifdef HAVE_SGEN_GC - -#ifndef DISABLE_SGEN_MAJOR_MARKSWEEP_FIXED_PAR - -#define SGEN_PARALLEL_MARK -#define FIXED_HEAP - -#include "sgen-marksweep.c" - -#else - -#include "metadata/sgen-gc.h" - -void -sgen_marksweep_fixed_par_init (SgenMajorCollector *collector) -{ - fprintf (stderr, "Error: Mono was configured using --enable-minimal=sgen_marksweep_fixed_par.\n"); - exit (1); -} - -#endif - -#endif diff --git a/mono/metadata/sgen-marksweep-fixed.c b/mono/metadata/sgen-marksweep-fixed.c deleted file mode 100644 index 3d08895bce7..00000000000 --- a/mono/metadata/sgen-marksweep-fixed.c +++ /dev/null @@ -1,24 +0,0 @@ -#include "config.h" - -#ifdef HAVE_SGEN_GC - -#ifndef DISABLE_SGEN_MAJOR_MARKSWEEP_FIXED - -#define FIXED_HEAP - -#include "sgen-marksweep.c" - -#else - -#include "metadata/sgen-gc.h" - -void -sgen_marksweep_fixed_init (SgenMajorCollector *collector) -{ - fprintf (stderr, "Error: Mono was configured using --enable-minimal=sgen_marksweep_fixed.\n"); - exit (1); -} - -#endif - -#endif diff --git a/mono/metadata/sgen-marksweep-par.c b/mono/metadata/sgen-marksweep-par.c deleted file mode 100644 index 5bc7805c870..00000000000 --- a/mono/metadata/sgen-marksweep-par.c +++ /dev/null @@ -1,24 +0,0 @@ -#include "config.h" - -#ifdef HAVE_SGEN_GC - -#ifndef DISABLE_SGEN_MAJOR_MARKSWEEP_PAR - -#define SGEN_PARALLEL_MARK - -#include "sgen-marksweep.c" - -#else - -#include "metadata/sgen-gc.h" - -void -sgen_marksweep_par_init (SgenMajorCollector *collector) -{ - fprintf (stderr, "Error: Mono was configured using --enable-minimal=sgen_marksweep_par.\n"); - exit (1); -} - -#endif /* DISABLE_SGEN_MAJOR_MARKSWEEP_PAR */ - -#endif diff --git a/mono/metadata/sgen-marksweep.c b/mono/metadata/sgen-marksweep.c index d3093385805..dfe7504242f 100644 --- a/mono/metadata/sgen-marksweep.c +++ b/mono/metadata/sgen-marksweep.c @@ -40,20 +40,16 @@ #include "metadata/sgen-memory-governor.h" #include "metadata/sgen-layout-stats.h" #include "metadata/gc-internal.h" +#include "metadata/sgen-pointer-queue.h" +#include "metadata/sgen-pinning.h" -#if !defined(SGEN_PARALLEL_MARK) && !defined(FIXED_HEAP) #define SGEN_HAVE_CONCURRENT_MARK -#endif #define MS_BLOCK_SIZE (16*1024) #define MS_BLOCK_SIZE_SHIFT 14 #define MAJOR_SECTION_SIZE MS_BLOCK_SIZE #define CARDS_PER_BLOCK (MS_BLOCK_SIZE / CARD_SIZE_IN_BYTES) -#ifdef FIXED_HEAP -#define MS_DEFAULT_HEAP_NUM_BLOCKS (32 * 1024) /* 512 MB */ -#endif - /* * Don't allocate single blocks, but alloc a contingent of this many * blocks in one swoop. This must be a power of two. @@ -65,11 +61,7 @@ * of a block is the MSBlockHeader, then opional padding, then come * the objects, so this must be >= sizeof (MSBlockHeader). */ -#ifdef FIXED_HEAP -#define MS_BLOCK_SKIP 0 -#else #define MS_BLOCK_SKIP 16 -#endif #define MS_BLOCK_FREE (MS_BLOCK_SIZE - MS_BLOCK_SKIP) @@ -83,55 +75,36 @@ typedef struct _MSBlockInfo MSBlockInfo; struct _MSBlockInfo { int obj_size; int obj_size_index; - size_t pin_queue_num_entries; unsigned int pinned : 1; unsigned int has_references : 1; unsigned int has_pinned : 1; /* means cannot evacuate */ unsigned int is_to_space : 1; unsigned int swept : 1; -#ifdef FIXED_HEAP - unsigned int used : 1; - unsigned int zeroed : 1; -#endif - MSBlockInfo *next; char *block; void **free_list; MSBlockInfo *next_free; - void **pin_queue_start; + size_t pin_queue_first_entry; + size_t pin_queue_last_entry; #ifdef SGEN_HAVE_CONCURRENT_MARK guint8 *cardtable_mod_union; #endif mword mark_words [MS_NUM_MARK_WORDS]; }; -#ifdef FIXED_HEAP -static mword ms_heap_num_blocks = MS_DEFAULT_HEAP_NUM_BLOCKS; - -static char *ms_heap_start; -static char *ms_heap_end; - -#define MS_PTR_IN_SMALL_MAJOR_HEAP(p) ((char*)(p) >= ms_heap_start && (char*)(p) < ms_heap_end) - -/* array of all all block infos in the system */ -static MSBlockInfo *block_infos; -#endif +#define MS_BLOCK_FOR_BLOCK_INFO(b) ((b)->block) -#define MS_BLOCK_OBJ(b,i) ((b)->block + MS_BLOCK_SKIP + (b)->obj_size * (i)) -#define MS_BLOCK_OBJ_FOR_SIZE(b,i,obj_size) ((b)->block + MS_BLOCK_SKIP + (obj_size) * (i)) +#define MS_BLOCK_OBJ(b,i) (MS_BLOCK_FOR_BLOCK_INFO(b) + MS_BLOCK_SKIP + (b)->obj_size * (i)) +#define MS_BLOCK_OBJ_FOR_SIZE(b,i,obj_size) (MS_BLOCK_FOR_BLOCK_INFO(b) + MS_BLOCK_SKIP + (obj_size) * (i)) #define MS_BLOCK_DATA_FOR_OBJ(o) ((char*)((mword)(o) & ~(mword)(MS_BLOCK_SIZE - 1))) -#ifdef FIXED_HEAP -#define MS_BLOCK_FOR_OBJ(o) (&block_infos [(mword)((char*)(o) - ms_heap_start) >> MS_BLOCK_SIZE_SHIFT]) -#else typedef struct { MSBlockInfo *info; } MSBlockHeader; #define MS_BLOCK_FOR_OBJ(o) (((MSBlockHeader*)MS_BLOCK_DATA_FOR_OBJ ((o)))->info) -#endif /* object index will always be small */ -#define MS_BLOCK_OBJ_INDEX(o,b) ((int)(((char*)(o) - ((b)->block + MS_BLOCK_SKIP)) / (b)->obj_size)) +#define MS_BLOCK_OBJ_INDEX(o,b) ((int)(((char*)(o) - (MS_BLOCK_FOR_BLOCK_INFO(b) + MS_BLOCK_SKIP)) / (b)->obj_size)) //casting to int is fine since blocks are 32k #define MS_CALC_MARK_BIT(w,b,o) do { \ @@ -163,7 +136,7 @@ typedef struct { } \ } while (1) -#define MS_OBJ_ALLOCED(o,b) (*(void**)(o) && (*(char**)(o) < (b)->block || *(char**)(o) >= (b)->block + MS_BLOCK_SIZE)) +#define MS_OBJ_ALLOCED(o,b) (*(void**)(o) && (*(char**)(o) < MS_BLOCK_FOR_BLOCK_INFO (b) || *(char**)(o) >= MS_BLOCK_FOR_BLOCK_INFO (b) + MS_BLOCK_SIZE)) #define MS_BLOCK_OBJ_SIZE_FACTOR (sqrt (2.0)) @@ -182,12 +155,6 @@ static int fast_block_obj_size_indexes [MS_NUM_FAST_BLOCK_OBJ_SIZE_INDEXES]; #define MS_BLOCK_TYPE_MAX 4 -#ifdef SGEN_PARALLEL_MARK -static LOCK_DECLARE (ms_block_list_mutex); -#define LOCK_MS_BLOCK_LIST mono_mutex_lock (&ms_block_list_mutex) -#define UNLOCK_MS_BLOCK_LIST mono_mutex_unlock (&ms_block_list_mutex) -#endif - static gboolean *evacuate_block_obj_sizes; static float evacuation_threshold = 0.666f; #ifdef SGEN_HAVE_CONCURRENT_MARK @@ -202,33 +169,28 @@ static gboolean have_swept; static gboolean concurrent_mark; #endif +#define BLOCK_IS_TAGGED_HAS_REFERENCES(bl) SGEN_POINTER_IS_TAGGED_1 ((bl)) +#define BLOCK_TAG_HAS_REFERENCES(bl) SGEN_POINTER_TAG_1 ((bl)) +#define BLOCK_UNTAG_HAS_REFERENCES(bl) SGEN_POINTER_UNTAG_1 ((bl)) + +#define BLOCK_TAG(bl) ((bl)->has_references ? BLOCK_TAG_HAS_REFERENCES ((bl)) : (bl)) + /* all allocated blocks in the system */ -static MSBlockInfo *all_blocks; +static SgenPointerQueue allocated_blocks; -#ifdef FIXED_HEAP -/* non-allocated block free-list */ -static MSBlockInfo *empty_blocks = NULL; -#else /* non-allocated block free-list */ static void *empty_blocks = NULL; static size_t num_empty_blocks = 0; -#endif -#define FOREACH_BLOCK(bl) for ((bl) = all_blocks; (bl); (bl) = (bl)->next) { -#define END_FOREACH_BLOCK } +#define FOREACH_BLOCK(bl) { size_t __index; for (__index = 0; __index < allocated_blocks.next_slot; ++__index) { (bl) = BLOCK_UNTAG_HAS_REFERENCES (allocated_blocks.data [__index]); +#define FOREACH_BLOCK_HAS_REFERENCES(bl,hr) { size_t __index; for (__index = 0; __index < allocated_blocks.next_slot; ++__index) { (bl) = allocated_blocks.data [__index]; (hr) = BLOCK_IS_TAGGED_HAS_REFERENCES ((bl)); (bl) = BLOCK_UNTAG_HAS_REFERENCES ((bl)); +#define END_FOREACH_BLOCK } } +#define DELETE_BLOCK_IN_FOREACH() (allocated_blocks.data [__index] = NULL) static size_t num_major_sections = 0; /* one free block list for each block object size */ static MSBlockInfo **free_block_lists [MS_BLOCK_TYPE_MAX]; -#ifdef SGEN_PARALLEL_MARK -#ifdef HAVE_KW_THREAD -static __thread MSBlockInfo ***workers_free_block_lists; -#else -static MonoNativeTlsKey workers_free_block_lists_key; -#endif -#endif - static long long stat_major_blocks_alloced = 0; static long long stat_major_blocks_freed = 0; static long long stat_major_blocks_lazy_swept = 0; @@ -264,55 +226,12 @@ ms_find_block_obj_size_index (size_t size) #define FREE_BLOCKS_FROM(lists,p,r) (lists [((p) ? MS_BLOCK_FLAG_PINNED : 0) | ((r) ? MS_BLOCK_FLAG_REFS : 0)]) #define FREE_BLOCKS(p,r) (FREE_BLOCKS_FROM (free_block_lists, (p), (r))) -#ifdef SGEN_PARALLEL_MARK -#ifdef HAVE_KW_THREAD -#define FREE_BLOCKS_LOCAL(p,r) (FREE_BLOCKS_FROM (workers_free_block_lists, (p), (r))) -#else -#define FREE_BLOCKS_LOCAL(p,r) (FREE_BLOCKS_FROM (((MSBlockInfo***)(mono_native_tls_get_value (workers_free_block_lists_key))), (p), (r))) -#endif -#else -//#define FREE_BLOCKS_LOCAL(p,r) (FREE_BLOCKS_FROM (free_block_lists, (p), (r))) -#endif #define MS_BLOCK_OBJ_SIZE_INDEX(s) \ (((s)+7)>>3 < MS_NUM_FAST_BLOCK_OBJ_SIZE_INDEXES ? \ fast_block_obj_size_indexes [((s)+7)>>3] : \ ms_find_block_obj_size_index ((s))) -#ifdef FIXED_HEAP -static void* -major_alloc_heap (mword nursery_size, mword nursery_align, int the_nursery_bits) -{ - char *nursery_start; - mword major_heap_size = ms_heap_num_blocks * MS_BLOCK_SIZE; - mword alloc_size = nursery_size + major_heap_size; - mword i; - - g_assert (ms_heap_num_blocks > 0); - g_assert (nursery_size % MS_BLOCK_SIZE == 0); - if (nursery_align) - g_assert (nursery_align % MS_BLOCK_SIZE == 0); - - nursery_start = sgen_alloc_os_memory_aligned (alloc_size, nursery_align ? nursery_align : MS_BLOCK_SIZE, SGEN_ALLOC_HEAP | SGEN_ALLOC_ACTIVATE, "heap"); - ms_heap_start = nursery_start + nursery_size; - ms_heap_end = ms_heap_start + major_heap_size; - - block_infos = sgen_alloc_internal_dynamic (sizeof (MSBlockInfo) * ms_heap_num_blocks, INTERNAL_MEM_MS_BLOCK_INFO, TRUE); - - for (i = 0; i < ms_heap_num_blocks; ++i) { - block_infos [i].block = ms_heap_start + i * MS_BLOCK_SIZE; - if (i < ms_heap_num_blocks - 1) - block_infos [i].next_free = &block_infos [i + 1]; - else - block_infos [i].next_free = NULL; - block_infos [i].zeroed = TRUE; - } - - empty_blocks = &block_infos [0]; - - return nursery_start; -} -#else static void* major_alloc_heap (mword nursery_size, mword nursery_align, int the_nursery_bits) { @@ -324,44 +243,13 @@ major_alloc_heap (mword nursery_size, mword nursery_align, int the_nursery_bits) return start; } -#endif static void update_heap_boundaries_for_block (MSBlockInfo *block) { - sgen_update_heap_boundaries ((mword)block->block, (mword)block->block + MS_BLOCK_SIZE); + sgen_update_heap_boundaries ((mword)MS_BLOCK_FOR_BLOCK_INFO (block), (mword)MS_BLOCK_FOR_BLOCK_INFO (block) + MS_BLOCK_SIZE); } -#ifdef FIXED_HEAP -static MSBlockInfo* -ms_get_empty_block (void) -{ - MSBlockInfo *block; - - g_assert (empty_blocks); - - do { - block = empty_blocks; - } while (SGEN_CAS_PTR ((gpointer*)&empty_blocks, block->next_free, block) != block); - - block->used = TRUE; - - if (!block->zeroed) - memset (block->block, 0, MS_BLOCK_SIZE); - - return block; -} - -static void -ms_free_block (MSBlockInfo *block) -{ - block->next_free = empty_blocks; - empty_blocks = block; - block->used = FALSE; - block->zeroed = FALSE; - sgen_memgov_release_space (MS_BLOCK_SIZE, SPACE_MAJOR); -} -#else static void* ms_get_empty_block (void) { @@ -440,7 +328,6 @@ ms_free_block (void *block) SGEN_ATOMIC_ADD_P (num_empty_blocks, 1); } -#endif //#define MARKSWEEP_CONSISTENCY_CHECK @@ -459,30 +346,19 @@ check_block_free_list (MSBlockInfo *block, int size, gboolean pinned) if (block->swept) g_assert (block->free_list); -#ifdef FIXED_HEAP - /* the block must not be in the empty_blocks list */ - for (b = empty_blocks; b; b = b->next_free) - g_assert (b != block); -#endif - /* the block must be in the all_blocks list */ - for (b = all_blocks; b; b = b->next) { - if (b == block) - break; - } - g_assert (b == block); + /* the block must be in the allocated_blocks array */ + g_assert (sgen_pointer_queue_find (&allocated_blocks, BLOCK_TAG (block)) != (size_t)-1); } } static void check_empty_blocks (void) { -#ifndef FIXED_HEAP void *p; size_t i = 0; for (p = empty_blocks; p; p = *(void**)p) ++i; g_assert (i == num_empty_blocks); -#endif } static void @@ -497,10 +373,8 @@ consistency_check (void) int num_free = 0; void **free; -#ifndef FIXED_HEAP /* check block header */ g_assert (((MSBlockHeader*)block->block)->info == block); -#endif /* count number of free slots */ for (i = 0; i < count; ++i) { @@ -540,12 +414,7 @@ ms_alloc_block (int size_index, gboolean pinned, gboolean has_references) int size = block_obj_sizes [size_index]; int count = MS_BLOCK_FREE / size; MSBlockInfo *info; -#ifdef SGEN_PARALLEL_MARK - MSBlockInfo *next; -#endif -#ifndef FIXED_HEAP MSBlockHeader *header; -#endif MSBlockInfo **free_blocks = FREE_BLOCKS (pinned, has_references); char *obj_start; int i; @@ -553,11 +422,7 @@ ms_alloc_block (int size_index, gboolean pinned, gboolean has_references) if (!sgen_memgov_try_alloc_space (MS_BLOCK_SIZE, SPACE_MAJOR)) return FALSE; -#ifdef FIXED_HEAP - info = ms_get_empty_block (); -#else info = sgen_alloc_internal (INTERNAL_MEM_MS_BLOCK_INFO); -#endif SGEN_ASSERT (9, count >= 2, "block with %d objects, it must hold at least 2", count); @@ -574,12 +439,10 @@ ms_alloc_block (int size_index, gboolean pinned, gboolean has_references) */ info->is_to_space = (sgen_get_current_collection_generation () == GENERATION_OLD); info->swept = 1; -#ifndef FIXED_HEAP info->block = ms_get_empty_block (); header = (MSBlockHeader*) info->block; header->info = info; -#endif #ifdef SGEN_HAVE_CONCURRENT_MARK info->cardtable_mod_union = NULL; #endif @@ -587,7 +450,7 @@ ms_alloc_block (int size_index, gboolean pinned, gboolean has_references) update_heap_boundaries_for_block (info); /* build free list */ - obj_start = info->block + MS_BLOCK_SKIP; + obj_start = MS_BLOCK_FOR_BLOCK_INFO (info) + MS_BLOCK_SKIP; info->free_list = (void**)obj_start; /* we're skipping the last one - it must be nulled */ for (i = 0; i < count - 1; ++i) { @@ -598,21 +461,10 @@ ms_alloc_block (int size_index, gboolean pinned, gboolean has_references) /* the last one */ *(void**)obj_start = NULL; -#ifdef SGEN_PARALLEL_MARK - do { - next = info->next_free = free_blocks [size_index]; - } while (SGEN_CAS_PTR ((void**)&free_blocks [size_index], info, next) != next); - - do { - next = info->next = all_blocks; - } while (SGEN_CAS_PTR ((void**)&all_blocks, info, next) != next); -#else info->next_free = free_blocks [size_index]; free_blocks [size_index] = info; - info->next = all_blocks; - all_blocks = info; -#endif + sgen_pointer_queue_add (&allocated_blocks, BLOCK_TAG (info)); ++num_major_sections; return TRUE; @@ -624,7 +476,7 @@ obj_is_from_pinned_alloc (char *ptr) MSBlockInfo *block; FOREACH_BLOCK (block) { - if (ptr >= block->block && ptr <= block->block + MS_BLOCK_SIZE) + if (ptr >= MS_BLOCK_FOR_BLOCK_INFO (block) && ptr <= MS_BLOCK_FOR_BLOCK_INFO (block) + MS_BLOCK_SIZE) return block->pinned; } END_FOREACH_BLOCK; return FALSE; @@ -656,86 +508,6 @@ unlink_slot_from_free_list_uncontested (MSBlockInfo **free_blocks, int size_inde return obj; } -#ifdef SGEN_PARALLEL_MARK -static gboolean -try_remove_block_from_free_list (MSBlockInfo *block, MSBlockInfo **free_blocks, int size_index) -{ - /* - * No more free slots in the block, so try to free the block. - * Don't try again if we don't succeed - another thread will - * already have done it. - */ - MSBlockInfo *next_block = block->next_free; - if (SGEN_CAS_PTR ((void**)&free_blocks [size_index], next_block, block) == block) { - /* - void *old = SGEN_CAS_PTR ((void**)&block->next_free, NULL, next_block); - g_assert (old == next_block); - */ - block->next_free = NULL; - return TRUE; - } - return FALSE; -} - -static void* -alloc_obj_par (MonoVTable *vtable, int size, gboolean pinned, gboolean has_references) -{ - int size_index = MS_BLOCK_OBJ_SIZE_INDEX (size); - MSBlockInfo **free_blocks_local = FREE_BLOCKS_LOCAL (pinned, has_references); - MSBlockInfo *block; - void *obj; - -#ifdef SGEN_HAVE_CONCURRENT_MARK - if (concurrent_mark) - g_assert_not_reached (); -#endif - - SGEN_ASSERT (9, current_collection_generation == GENERATION_OLD, "old gen parallel allocator called from a %d collection", current_collection_generation); - - if (free_blocks_local [size_index]) { - get_slot: - obj = unlink_slot_from_free_list_uncontested (free_blocks_local, size_index); - } else { - MSBlockInfo **free_blocks = FREE_BLOCKS (pinned, has_references); - - get_block: - block = free_blocks [size_index]; - if (block) { - if (!try_remove_block_from_free_list (block, free_blocks, size_index)) - goto get_block; - - g_assert (block->next_free == NULL); - g_assert (block->free_list); - block->next_free = free_blocks_local [size_index]; - free_blocks_local [size_index] = block; - - goto get_slot; - } else { - gboolean success; - - LOCK_MS_BLOCK_LIST; - success = ms_alloc_block (size_index, pinned, has_references); - UNLOCK_MS_BLOCK_LIST; - - if (G_UNLIKELY (!success)) - return NULL; - - goto get_block; - } - } - - *(MonoVTable**)obj = vtable; - - return obj; -} - -static void* -major_par_alloc_object (MonoVTable *vtable, size_t size, gboolean has_references) -{ - return alloc_obj_par (vtable, size, FALSE, has_references); -} -#endif - static void* alloc_obj (MonoVTable *vtable, size_t size, gboolean pinned, gboolean has_references) { @@ -743,11 +515,6 @@ alloc_obj (MonoVTable *vtable, size_t size, gboolean pinned, gboolean has_refere MSBlockInfo **free_blocks = FREE_BLOCKS (pinned, has_references); void *obj; -#ifdef SGEN_PARALLEL_MARK - SGEN_ASSERT (9, current_collection_generation == GENERATION_OLD, "old gen parallel allocator called from a %d collection", current_collection_generation); - -#endif - if (!free_blocks [size_index]) { if (G_UNLIKELY (!ms_alloc_block (size_index, pinned, has_references))) return NULL; @@ -859,24 +626,16 @@ major_is_object_live (char *obj) { MSBlockInfo *block; int word, bit; -#ifndef FIXED_HEAP mword objsize; -#endif if (sgen_ptr_in_nursery (obj)) return FALSE; -#ifdef FIXED_HEAP - /* LOS */ - if (!MS_PTR_IN_SMALL_MAJOR_HEAP (obj)) - return FALSE; -#else objsize = SGEN_ALIGN_UP (sgen_safe_object_get_size ((MonoObject*)obj)); /* LOS */ if (objsize > SGEN_MAX_SMALL_OBJ_SIZE) return FALSE; -#endif /* now we know it's in a major block */ block = MS_BLOCK_FOR_OBJ (obj); @@ -891,7 +650,7 @@ major_ptr_is_in_non_pinned_space (char *ptr, char **start) MSBlockInfo *block; FOREACH_BLOCK (block) { - if (ptr >= block->block && ptr <= block->block + MS_BLOCK_SIZE) { + if (ptr >= MS_BLOCK_FOR_BLOCK_INFO (block) && ptr <= MS_BLOCK_FOR_BLOCK_INFO (block) + MS_BLOCK_SIZE) { int count = MS_BLOCK_FREE / block->obj_size; int i; @@ -952,7 +711,7 @@ major_is_valid_object (char *object) int idx; char *obj; - if ((block->block > object) || ((block->block + MS_BLOCK_SIZE) <= object)) + if ((MS_BLOCK_FOR_BLOCK_INFO (block) > object) || ((MS_BLOCK_FOR_BLOCK_INFO (block) + MS_BLOCK_SIZE) <= object)) continue; idx = MS_BLOCK_OBJ_INDEX (object, block); @@ -979,11 +738,11 @@ major_describe_pointer (char *ptr) int w, b; gboolean marked; - if ((block->block > ptr) || ((block->block + MS_BLOCK_SIZE) <= ptr)) + if ((MS_BLOCK_FOR_BLOCK_INFO (block) > ptr) || ((MS_BLOCK_FOR_BLOCK_INFO (block) + MS_BLOCK_SIZE) <= ptr)) continue; SGEN_LOG (0, "major-ptr (block %p sz %d pin %d ref %d)\n", - block->block, block->obj_size, block->pinned, block->has_references); + MS_BLOCK_FOR_BLOCK_INFO (block), block->obj_size, block->pinned, block->has_references); idx = MS_BLOCK_OBJ_INDEX (ptr, block); obj = (char*)MS_BLOCK_OBJ (block, idx); @@ -1061,7 +820,7 @@ major_dump_heap (FILE *heap_dump_file) start = i; } else { if (start >= 0) { - sgen_dump_occupied (MS_BLOCK_OBJ (block, start), MS_BLOCK_OBJ (block, i), block->block); + sgen_dump_occupied (MS_BLOCK_OBJ (block, start), MS_BLOCK_OBJ (block, i), MS_BLOCK_FOR_BLOCK_INFO (block)); start = -1; } } @@ -1073,30 +832,30 @@ major_dump_heap (FILE *heap_dump_file) #define LOAD_VTABLE SGEN_LOAD_VTABLE -#define MS_MARK_OBJECT_AND_ENQUEUE_CHECKED(obj,block,queue) do { \ +#define MS_MARK_OBJECT_AND_ENQUEUE_CHECKED(obj,desc,block,queue) do { \ int __word, __bit; \ MS_CALC_MARK_BIT (__word, __bit, (obj)); \ if (!MS_MARK_BIT ((block), __word, __bit) && MS_OBJ_ALLOCED ((obj), (block))) { \ MS_SET_MARK_BIT ((block), __word, __bit); \ if ((block)->has_references) \ - GRAY_OBJECT_ENQUEUE ((queue), (obj)); \ + GRAY_OBJECT_ENQUEUE ((queue), (obj), (desc)); \ binary_protocol_mark ((obj), (gpointer)LOAD_VTABLE ((obj)), sgen_safe_object_get_size ((MonoObject*)(obj))); \ INC_NUM_MAJOR_OBJECTS_MARKED (); \ } \ } while (0) -#define MS_MARK_OBJECT_AND_ENQUEUE(obj,block,queue) do { \ +#define MS_MARK_OBJECT_AND_ENQUEUE(obj,desc,block,queue) do { \ int __word, __bit; \ MS_CALC_MARK_BIT (__word, __bit, (obj)); \ SGEN_ASSERT (9, MS_OBJ_ALLOCED ((obj), (block)), "object %p not allocated", obj); \ if (!MS_MARK_BIT ((block), __word, __bit)) { \ MS_SET_MARK_BIT ((block), __word, __bit); \ if ((block)->has_references) \ - GRAY_OBJECT_ENQUEUE ((queue), (obj)); \ + GRAY_OBJECT_ENQUEUE ((queue), (obj), (desc)); \ binary_protocol_mark ((obj), (gpointer)LOAD_VTABLE ((obj)), sgen_safe_object_get_size ((MonoObject*)(obj))); \ INC_NUM_MAJOR_OBJECTS_MARKED (); \ } \ } while (0) -#define MS_PAR_MARK_OBJECT_AND_ENQUEUE(obj,block,queue) do { \ +#define MS_PAR_MARK_OBJECT_AND_ENQUEUE(obj,desc,block,queue) do { \ int __word, __bit; \ gboolean __was_marked; \ SGEN_ASSERT (9, MS_OBJ_ALLOCED ((obj), (block)), "object %p not allocated", obj); \ @@ -1104,7 +863,7 @@ major_dump_heap (FILE *heap_dump_file) MS_PAR_SET_MARK_BIT (__was_marked, (block), __word, __bit); \ if (!__was_marked) { \ if ((block)->has_references) \ - GRAY_OBJECT_ENQUEUE ((queue), (obj)); \ + GRAY_OBJECT_ENQUEUE ((queue), (obj), (desc)); \ binary_protocol_mark ((obj), (gpointer)LOAD_VTABLE ((obj)), sgen_safe_object_get_size ((MonoObject*)(obj))); \ INC_NUM_MAJOR_OBJECTS_MARKED (); \ } \ @@ -1122,170 +881,11 @@ pin_major_object (char *obj, SgenGrayQueue *queue) block = MS_BLOCK_FOR_OBJ (obj); block->has_pinned = TRUE; - MS_MARK_OBJECT_AND_ENQUEUE (obj, block, queue); + MS_MARK_OBJECT_AND_ENQUEUE (obj, sgen_obj_get_descriptor (obj), block, queue); } #include "sgen-major-copy-object.h" -#ifdef SGEN_PARALLEL_MARK -static void -major_copy_or_mark_object (void **ptr, void *obj, SgenGrayQueue *queue) -{ - mword objsize; - MSBlockInfo *block; - MonoVTable *vt; - - HEAVY_STAT (++stat_copy_object_called_major); - - SGEN_ASSERT (9, obj, "null object from pointer %p", ptr); - SGEN_ASSERT (9, current_collection_generation == GENERATION_OLD, "old gen parallel allocator called from a %d collection", current_collection_generation); - - if (sgen_ptr_in_nursery (obj)) { - int word, bit; - gboolean has_references; - void *destination; - mword vtable_word = *(mword*)obj; - vt = (MonoVTable*)(vtable_word & ~SGEN_VTABLE_BITS_MASK); - - if (vtable_word & SGEN_FORWARDED_BIT) { - *ptr = (void*)vt; - return; - } - - if (vtable_word & SGEN_PINNED_BIT) - return; - - /* An object in the nursery To Space has already been copied and grayed. Nothing to do. */ - if (sgen_nursery_is_to_space (obj)) - return; - - HEAVY_STAT (++stat_objects_copied_major); - - do_copy_object: - objsize = SGEN_ALIGN_UP (sgen_par_object_get_size (vt, (MonoObject*)obj)); - has_references = SGEN_VTABLE_HAS_REFERENCES (vt); - - destination = sgen_minor_collector.par_alloc_for_promotion (vt, obj, objsize, has_references); - if (G_UNLIKELY (!destination)) { - if (!sgen_ptr_in_nursery (obj)) { - int size_index; - block = MS_BLOCK_FOR_OBJ (obj); - size_index = block->obj_size_index; - evacuate_block_obj_sizes [size_index] = FALSE; - } - - sgen_parallel_pin_or_update (ptr, obj, vt, queue); - sgen_set_pinned_from_failed_allocation (objsize); - return; - } - - if (SGEN_CAS_PTR (obj, (void*)((mword)destination | SGEN_FORWARDED_BIT), vt) == vt) { - gboolean was_marked; - - par_copy_object_no_checks (destination, vt, obj, objsize, has_references ? queue : NULL); - obj = destination; - *ptr = obj; - - /* - * FIXME: If we make major_alloc_object() give - * us the block info, too, we won't have to - * re-fetch it here. - * - * FIXME (2): We should rework this to avoid all those nursery checks. - */ - /* - * For the split nursery allocator the object - * might still be in the nursery despite - * having being promoted, in which case we - * can't mark it. - */ - if (!sgen_ptr_in_nursery (obj)) { - block = MS_BLOCK_FOR_OBJ (obj); - MS_CALC_MARK_BIT (word, bit, obj); - SGEN_ASSERT (9, !MS_MARK_BIT (block, word, bit), "object %p already marked", obj); - MS_PAR_SET_MARK_BIT (was_marked, block, word, bit); - binary_protocol_mark (obj, vt, sgen_safe_object_get_size ((MonoObject*)obj)); - } - } else { - /* - * FIXME: We have allocated destination, but - * we cannot use it. Give it back to the - * allocator. - */ - *(void**)destination = NULL; - - vtable_word = *(mword*)obj; - g_assert (vtable_word & SGEN_FORWARDED_BIT); - - obj = (void*)(vtable_word & ~SGEN_VTABLE_BITS_MASK); - - *ptr = obj; - - HEAVY_STAT (++stat_slots_allocated_in_vain); - } - } else { -#ifdef FIXED_HEAP - if (MS_PTR_IN_SMALL_MAJOR_HEAP (obj)) -#else - mword vtable_word = *(mword*)obj; - vt = (MonoVTable*)(vtable_word & ~SGEN_VTABLE_BITS_MASK); - - /* see comment in the non-parallel version below */ - if (vtable_word & SGEN_FORWARDED_BIT) { - *ptr = (void*)vt; - return; - } - objsize = SGEN_ALIGN_UP (sgen_par_object_get_size (vt, (MonoObject*)obj)); - - if (objsize <= SGEN_MAX_SMALL_OBJ_SIZE) -#endif - { - int size_index; - - block = MS_BLOCK_FOR_OBJ (obj); - size_index = block->obj_size_index; - - if (!block->has_pinned && evacuate_block_obj_sizes [size_index]) { - if (block->is_to_space) - return; - -#ifdef FIXED_HEAP - { - mword vtable_word = *(mword*)obj; - vt = (MonoVTable*)(vtable_word & ~SGEN_VTABLE_BITS_MASK); - - if (vtable_word & SGEN_FORWARDED_BIT) { - *ptr = (void*)vt; - return; - } - } -#endif - - HEAVY_STAT (++stat_major_objects_evacuated); - goto do_copy_object; - } - - MS_PAR_MARK_OBJECT_AND_ENQUEUE (obj, block, queue); - } else { - LOSObject *bigobj = sgen_los_header_for_object (obj); - mword size_word = bigobj->size; -#ifdef FIXED_HEAP - mword vtable_word = *(mword*)obj; - vt = (MonoVTable*)(vtable_word & ~SGEN_VTABLE_BITS_MASK); -#endif - if (size_word & 1) - return; - binary_protocol_pin (obj, vt, sgen_safe_object_get_size ((MonoObject*)obj)); - if (SGEN_CAS_PTR ((void*)&bigobj->size, (void*)(size_word | 1), (void*)size_word) == (void*)size_word) { - if (SGEN_VTABLE_HAS_REFERENCES (vt)) - GRAY_OBJECT_ENQUEUE (queue, obj); - } else { - g_assert (sgen_los_object_is_pinned (obj)); - } - } - } -} -#else #ifdef SGEN_HAVE_CONCURRENT_MARK static void major_copy_or_mark_object_concurrent (void **ptr, void *obj, SgenGrayQueue *queue) @@ -1293,18 +893,13 @@ major_copy_or_mark_object_concurrent (void **ptr, void *obj, SgenGrayQueue *queu g_assert (!SGEN_OBJECT_IS_FORWARDED (obj)); if (!sgen_ptr_in_nursery (obj)) { -#ifdef FIXED_HEAP - if (MS_PTR_IN_SMALL_MAJOR_HEAP (obj)) -#else mword objsize; objsize = SGEN_ALIGN_UP (sgen_safe_object_get_size ((MonoObject*)obj)); - if (objsize <= SGEN_MAX_SMALL_OBJ_SIZE) -#endif - { + if (objsize <= SGEN_MAX_SMALL_OBJ_SIZE) { MSBlockInfo *block = MS_BLOCK_FOR_OBJ (obj); - MS_MARK_OBJECT_AND_ENQUEUE (obj, block, queue); + MS_MARK_OBJECT_AND_ENQUEUE (obj, sgen_obj_get_descriptor (obj), block, queue); } else { if (sgen_los_object_is_pinned (obj)) return; @@ -1318,7 +913,7 @@ major_copy_or_mark_object_concurrent (void **ptr, void *obj, SgenGrayQueue *queu sgen_los_pin_object (obj); if (SGEN_OBJECT_HAS_REFERENCES (obj)) - GRAY_OBJECT_ENQUEUE (queue, obj); + GRAY_OBJECT_ENQUEUE (queue, obj, sgen_obj_get_descriptor (obj)); INC_NUM_MAJOR_OBJECTS_MARKED (); } } @@ -1362,7 +957,7 @@ major_copy_or_mark_object (void **ptr, void *obj, SgenGrayQueue *queue) block = MS_BLOCK_FOR_OBJ (obj); size_index = block->obj_size_index; evacuate_block_obj_sizes [size_index] = FALSE; - MS_MARK_OBJECT_AND_ENQUEUE (obj, block, queue); + MS_MARK_OBJECT_AND_ENQUEUE (obj, sgen_obj_get_descriptor (obj), block, queue); } return; } @@ -1390,9 +985,6 @@ major_copy_or_mark_object (void **ptr, void *obj, SgenGrayQueue *queue) } } else { char *forwarded; -#ifdef FIXED_HEAP - if (MS_PTR_IN_SMALL_MAJOR_HEAP (obj)) -#else mword objsize; /* @@ -1410,9 +1002,7 @@ major_copy_or_mark_object (void **ptr, void *obj, SgenGrayQueue *queue) objsize = SGEN_ALIGN_UP (sgen_safe_object_get_size ((MonoObject*)obj)); - if (objsize <= SGEN_MAX_SMALL_OBJ_SIZE) -#endif - { + if (objsize <= SGEN_MAX_SMALL_OBJ_SIZE) { int size_index; gboolean evacuate; @@ -1420,20 +1010,6 @@ major_copy_or_mark_object (void **ptr, void *obj, SgenGrayQueue *queue) size_index = block->obj_size_index; evacuate = evacuate_block_obj_sizes [size_index]; -#ifdef FIXED_HEAP - /* - * We could also check for !block->has_pinned - * here, but it would only make an uncommon case - * faster, namely objects that are in blocks - * whose slot sizes are evacuated but which have - * pinned objects. - */ - if (evacuate && (forwarded = SGEN_OBJECT_IS_FORWARDED (obj))) { - *ptr = forwarded; - return; - } -#endif - if (evacuate && !block->has_pinned) { g_assert (!SGEN_OBJECT_IS_PINNED (obj)); if (block->is_to_space) @@ -1441,7 +1017,7 @@ major_copy_or_mark_object (void **ptr, void *obj, SgenGrayQueue *queue) HEAVY_STAT (++stat_major_objects_evacuated); goto do_copy_object; } else { - MS_MARK_OBJECT_AND_ENQUEUE (obj, block, queue); + MS_MARK_OBJECT_AND_ENQUEUE (obj, sgen_obj_get_descriptor (obj), block, queue); } } else { if (sgen_los_object_is_pinned (obj)) @@ -1457,11 +1033,10 @@ major_copy_or_mark_object (void **ptr, void *obj, SgenGrayQueue *queue) sgen_los_pin_object (obj); if (SGEN_OBJECT_HAS_REFERENCES (obj)) - GRAY_OBJECT_ENQUEUE (queue, obj); + GRAY_OBJECT_ENQUEUE (queue, obj, sgen_obj_get_descriptor (obj)); } } } -#endif static void major_copy_or_mark_object_canonical (void **ptr, SgenGrayQueue *queue) @@ -1475,6 +1050,7 @@ major_copy_or_mark_object_concurrent_canonical (void **ptr, SgenGrayQueue *queue { major_copy_or_mark_object_concurrent (ptr, *ptr, queue); } +#endif static long long major_get_and_reset_num_major_objects_marked (void) @@ -1487,7 +1063,6 @@ major_get_and_reset_num_major_objects_marked (void) return 0; #endif } -#endif #include "sgen-major-scan-object.h" @@ -1500,20 +1075,25 @@ major_get_and_reset_num_major_objects_marked (void) static void mark_pinned_objects_in_block (MSBlockInfo *block, SgenGrayQueue *queue) { - int i; + void **entry, **end; int last_index = -1; - if (!block->pin_queue_num_entries) + if (block->pin_queue_first_entry == block->pin_queue_last_entry) return; block->has_pinned = TRUE; - for (i = 0; i < block->pin_queue_num_entries; ++i) { - int index = MS_BLOCK_OBJ_INDEX (block->pin_queue_start [i], block); - SGEN_ASSERT (9, index >= 0 && index < MS_BLOCK_FREE / block->obj_size, "invalid object %p index %d max-index %d", block->pin_queue_start [i], index, MS_BLOCK_FREE / block->obj_size); + entry = sgen_pinning_get_entry (block->pin_queue_first_entry); + end = sgen_pinning_get_entry (block->pin_queue_last_entry); + + for (; entry < end; ++entry) { + int index = MS_BLOCK_OBJ_INDEX (*entry, block); + char *obj; + SGEN_ASSERT (9, index >= 0 && index < MS_BLOCK_FREE / block->obj_size, "invalid object %p index %d max-index %d", *entry, index, MS_BLOCK_FREE / block->obj_size); if (index == last_index) continue; - MS_MARK_OBJECT_AND_ENQUEUE_CHECKED (MS_BLOCK_OBJ (block, index), block, queue); + obj = MS_BLOCK_OBJ (block, index); + MS_MARK_OBJECT_AND_ENQUEUE_CHECKED (obj, sgen_obj_get_descriptor (obj), block, queue); last_index = index; } } @@ -1620,7 +1200,7 @@ static void ms_sweep (void) { int i; - MSBlockInfo **iter; + MSBlockInfo *block; /* statistics for evacuation */ int *slots_available = alloca (sizeof (int) * num_block_obj_sizes); @@ -1644,9 +1224,7 @@ ms_sweep (void) } /* traverse all blocks, free and zero unmarked objects */ - iter = &all_blocks; - while (*iter) { - MSBlockInfo *block = *iter; + FOREACH_BLOCK (block) { int count; gboolean have_live = FALSE; gboolean has_pinned; @@ -1691,8 +1269,6 @@ ms_sweep (void) slots_available [obj_size_index] += count; } - iter = &block->next; - /* * If there are free slots in the block, add * the block to the corresponding free list. @@ -1710,20 +1286,16 @@ ms_sweep (void) * Blocks without live objects are removed from the * block list and freed. */ - *iter = block->next; + DELETE_BLOCK_IN_FOREACH (); binary_protocol_empty (MS_BLOCK_OBJ (block, 0), (char*)MS_BLOCK_OBJ (block, count) - (char*)MS_BLOCK_OBJ (block, 0)); -#ifdef FIXED_HEAP - ms_free_block (block); -#else ms_free_block (block->block); - sgen_free_internal (block, INTERNAL_MEM_MS_BLOCK_INFO); -#endif --num_major_sections; } - } + } END_FOREACH_BLOCK; + sgen_pointer_queue_remove_nulls (&allocated_blocks); for (i = 0; i < num_block_obj_sizes; ++i) { float usage = (float)slots_used [i] / (float)slots_available [i]; @@ -1869,18 +1441,13 @@ major_start_major_collection (void) // Sweep all unswept blocks if (lazy_sweep) { - MSBlockInfo **iter; + MSBlockInfo *block; MONO_GC_SWEEP_BEGIN (GENERATION_OLD, TRUE); - iter = &all_blocks; - while (*iter) { - MSBlockInfo *block = *iter; - + FOREACH_BLOCK (block) { sweep_block (block, TRUE); - - iter = &block->next; - } + } END_FOREACH_BLOCK; MONO_GC_SWEEP_END (GENERATION_OLD, TRUE); } @@ -1891,7 +1458,7 @@ major_finish_major_collection (void) { } -#if !defined(FIXED_HEAP) && SIZEOF_VOID_P != 8 +#if SIZEOF_VOID_P != 8 static int compare_pointers (const void *va, const void *vb) { char *a = *(char**)va, *b = *(char**)vb; @@ -1906,7 +1473,6 @@ compare_pointers (const void *va, const void *vb) { static void major_have_computer_minor_collection_allowance (void) { -#ifndef FIXED_HEAP size_t section_reserve = sgen_get_minor_collection_allowance () / MS_BLOCK_SIZE; g_assert (have_swept); @@ -2056,7 +1622,6 @@ major_have_computer_minor_collection_allowance (void) ++stat_major_blocks_freed_individual; #endif } -#endif } static void @@ -2065,8 +1630,8 @@ major_find_pin_queue_start_ends (SgenGrayQueue *queue) MSBlockInfo *block; FOREACH_BLOCK (block) { - block->pin_queue_start = sgen_find_optimized_pin_queue_area (block->block + MS_BLOCK_SKIP, block->block + MS_BLOCK_SIZE, - &block->pin_queue_num_entries); + sgen_find_optimized_pin_queue_area (MS_BLOCK_FOR_BLOCK_INFO (block) + MS_BLOCK_SKIP, MS_BLOCK_FOR_BLOCK_INFO (block) + MS_BLOCK_SIZE, + &block->pin_queue_first_entry, &block->pin_queue_last_entry); } END_FOREACH_BLOCK; } @@ -2117,17 +1682,6 @@ get_num_major_sections (void) static gboolean major_handle_gc_param (const char *opt) { -#ifdef FIXED_HEAP - if (g_str_has_prefix (opt, "major-heap-size=")) { - const char *arg = strchr (opt, '=') + 1; - size_t size; - if (!mono_gc_parse_environment_string_extract_number (arg, &size)) - return FALSE; - ms_heap_num_blocks = (size + MS_BLOCK_SIZE - 1) / MS_BLOCK_SIZE; - g_assert (ms_heap_num_blocks > 0); - return TRUE; - } else -#endif if (g_str_has_prefix (opt, "evacuation-threshold=")) { const char *arg = strchr (opt, '=') + 1; int percentage = atoi (arg); @@ -2153,9 +1707,6 @@ major_print_gc_param_usage (void) { fprintf (stderr, "" -#ifdef FIXED_HEAP - " major-heap-size=N (where N is an integer, possibly with a k, m or a g suffix)\n" -#endif " evacuation-threshold=P (where P is a percentage, an integer in 0-100)\n" " (no-)lazy-sweep\n" ); @@ -2165,10 +1716,11 @@ static void major_iterate_live_block_ranges (sgen_cardtable_block_callback callback) { MSBlockInfo *block; + gboolean has_references; - FOREACH_BLOCK (block) { - if (block->has_references) - callback ((mword)block->block, MS_BLOCK_SIZE); + FOREACH_BLOCK_HAS_REFERENCES (block, has_references) { + if (has_references) + callback ((mword)MS_BLOCK_FOR_BLOCK_INFO (block), MS_BLOCK_SIZE); } END_FOREACH_BLOCK; } @@ -2232,6 +1784,7 @@ static void major_scan_card_table (gboolean mod_union, SgenGrayQueue *queue) { MSBlockInfo *block; + gboolean has_references; ScanObjectFunc scan_func = sgen_get_current_object_ops ()->scan_object; #ifdef SGEN_HAVE_CONCURRENT_MARK @@ -2241,15 +1794,15 @@ major_scan_card_table (gboolean mod_union, SgenGrayQueue *queue) g_assert (!mod_union); #endif - FOREACH_BLOCK (block) { + FOREACH_BLOCK_HAS_REFERENCES (block, has_references) { int block_obj_size; char *block_start; - if (!block->has_references) + if (!has_references) continue; block_obj_size = block->obj_size; - block_start = block->block; + block_start = MS_BLOCK_FOR_BLOCK_INFO (block); if (block_obj_size >= CARD_SIZE_IN_BYTES) { guint8 *cards; @@ -2377,7 +1930,7 @@ major_scan_card_table (gboolean mod_union, SgenGrayQueue *queue) } HEAVY_STAT (++scanned_objects); - scan_func (obj, queue); + scan_func (obj, sgen_obj_get_descriptor (obj), queue); next_small: obj += block_obj_size; } @@ -2392,14 +1945,15 @@ static void major_count_cards (long long *num_total_cards, long long *num_marked_cards) { MSBlockInfo *block; + gboolean has_references; long long total_cards = 0; long long marked_cards = 0; - FOREACH_BLOCK (block) { - guint8 *cards = sgen_card_table_get_card_scan_address ((mword) block->block); + FOREACH_BLOCK_HAS_REFERENCES (block, has_references) { + guint8 *cards = sgen_card_table_get_card_scan_address ((mword) MS_BLOCK_FOR_BLOCK_INFO (block)); int i; - if (!block->has_references) + if (!has_references) continue; total_cards += CARDS_PER_BLOCK; @@ -2423,7 +1977,7 @@ update_cardtable_mod_union (void) size_t num_cards; block->cardtable_mod_union = sgen_card_table_update_mod_union (block->cardtable_mod_union, - block->block, MS_BLOCK_SIZE, &num_cards); + MS_BLOCK_FOR_BLOCK_INFO (block), MS_BLOCK_SIZE, &num_cards); SGEN_ASSERT (0, num_cards == CARDS_PER_BLOCK, "Number of cards calculation is wrong"); } END_FOREACH_BLOCK; @@ -2433,7 +1987,7 @@ static guint8* major_get_cardtable_mod_union_for_object (char *obj) { MSBlockInfo *block = MS_BLOCK_FOR_OBJ (obj); - return &block->cardtable_mod_union [(obj - (char*)sgen_card_table_align_pointer (block->block)) >> CARD_BITS]; + return &block->cardtable_mod_union [(obj - (char*)sgen_card_table_align_pointer (MS_BLOCK_FOR_BLOCK_INFO (block))) >> CARD_BITS]; } #endif @@ -2445,49 +1999,6 @@ alloc_free_block_lists (MSBlockInfo ***lists) lists [i] = sgen_alloc_internal_dynamic (sizeof (MSBlockInfo*) * num_block_obj_sizes, INTERNAL_MEM_MS_TABLES, TRUE); } -#ifdef SGEN_PARALLEL_MARK -static void* -major_alloc_worker_data (void) -{ - /* FIXME: free this when the workers come down */ - MSBlockInfo ***lists = malloc (sizeof (MSBlockInfo**) * MS_BLOCK_TYPE_MAX); - alloc_free_block_lists (lists); - return lists; -} - -static void -major_init_worker_thread (void *data) -{ - MSBlockInfo ***lists = data; - int i; - - g_assert (lists && lists != free_block_lists); - for (i = 0; i < MS_BLOCK_TYPE_MAX; ++i) { - int j; - for (j = 0; j < num_block_obj_sizes; ++j) - g_assert (!lists [i][j]); - } - -#ifdef HAVE_KW_THREAD - workers_free_block_lists = data; -#else - mono_native_tls_set_value (workers_free_block_lists_key, data); -#endif -} - -static void -major_reset_worker_data (void *data) -{ - MSBlockInfo ***lists = data; - int i; - for (i = 0; i < MS_BLOCK_TYPE_MAX; ++i) { - int j; - for (j = 0; j < num_block_obj_sizes; ++j) - lists [i][j] = NULL; - } -} -#endif - #undef pthread_create static void @@ -2500,29 +2011,12 @@ post_param_init (SgenMajorCollector *collector) static void sgen_marksweep_init_internal (SgenMajorCollector *collector, gboolean is_concurrent) #else // SGEN_HAVE_CONCURRENT_MARK -#ifdef SGEN_PARALLEL_MARK -#ifdef FIXED_HEAP -void -sgen_marksweep_fixed_par_init (SgenMajorCollector *collector) -#else // FIXED_HEAP -void -sgen_marksweep_par_init (SgenMajorCollector *collector) -#endif // FIXED_HEAP -#else // SGEN_PARALLEL_MARK -#ifdef FIXED_HEAP -void -sgen_marksweep_fixed_init (SgenMajorCollector *collector) -#else // FIXED_HEAP #error unknown configuration -#endif // FIXED_HEAP -#endif // SGEN_PARALLEL_MARK #endif // SGEN_HAVE_CONCURRENT_MARK { int i; -#ifndef FIXED_HEAP sgen_register_fixed_internal_mem_type (INTERNAL_MEM_MS_BLOCK_INFO, sizeof (MSBlockInfo)); -#endif num_block_obj_sizes = ms_calculate_block_obj_sizes (MS_BLOCK_OBJ_SIZE_FACTOR, NULL); block_obj_sizes = sgen_alloc_internal_dynamic (sizeof (int) * num_block_obj_sizes, INTERNAL_MEM_MS_TABLES, TRUE); @@ -2548,10 +2042,6 @@ sgen_marksweep_fixed_init (SgenMajorCollector *collector) for (i = 0; i < MS_NUM_FAST_BLOCK_OBJ_SIZE_INDEXES * 8; ++i) g_assert (MS_BLOCK_OBJ_SIZE_INDEX (i) == ms_find_block_obj_size_index (i)); -#ifdef SGEN_PARALLEL_MARK - LOCK_INIT (ms_block_list_mutex); -#endif - mono_counters_register ("# major blocks allocated", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_major_blocks_alloced); mono_counters_register ("# major blocks freed", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_major_blocks_freed); mono_counters_register ("# major blocks lazy swept", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_major_blocks_lazy_swept); @@ -2563,33 +2053,20 @@ sgen_marksweep_fixed_init (SgenMajorCollector *collector) mono_counters_register ("# major blocks allocated less ideally", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_major_blocks_alloced_less_ideal); #endif -#ifdef SGEN_PARALLEL_MARK -#ifndef HAVE_KW_THREAD - mono_native_tls_alloc (&workers_free_block_lists_key, NULL); -#endif -#endif - collector->section_size = MAJOR_SECTION_SIZE; -#ifdef SGEN_PARALLEL_MARK - collector->is_parallel = TRUE; - collector->alloc_worker_data = major_alloc_worker_data; - collector->init_worker_thread = major_init_worker_thread; - collector->reset_worker_data = major_reset_worker_data; -#else - collector->is_parallel = FALSE; -#endif + #ifdef SGEN_HAVE_CONCURRENT_MARK concurrent_mark = is_concurrent; if (is_concurrent) { collector->is_concurrent = TRUE; collector->want_synchronous_collection = &want_evacuation; - collector->get_and_reset_num_major_objects_marked = major_get_and_reset_num_major_objects_marked; } else #endif { collector->is_concurrent = FALSE; collector->want_synchronous_collection = NULL; } + collector->get_and_reset_num_major_objects_marked = major_get_and_reset_num_major_objects_marked; collector->supports_cardtable = TRUE; collector->have_swept = &have_swept; @@ -2600,9 +2077,6 @@ sgen_marksweep_fixed_init (SgenMajorCollector *collector) collector->alloc_degraded = major_alloc_degraded; collector->alloc_object = major_alloc_object; -#ifdef SGEN_PARALLEL_MARK - collector->par_alloc_object = major_par_alloc_object; -#endif collector->free_pinned_object = free_pinned_object; collector->iterate_objects = major_iterate_objects; collector->free_non_pinned_object = major_free_non_pinned_object; diff --git a/mono/metadata/sgen-memory-governor.c b/mono/metadata/sgen-memory-governor.c index 448ebef3f05..5d17a0d721c 100644 --- a/mono/metadata/sgen-memory-governor.c +++ b/mono/metadata/sgen-memory-governor.c @@ -48,6 +48,7 @@ static double save_target_ratio = SGEN_DEFAULT_SAVE_TARGET_RATIO; /**/ static mword allocated_heap; static mword total_alloc = 0; +static mword total_alloc_max = 0; /* GC triggers. */ @@ -72,21 +73,13 @@ static mword last_collection_los_memory_alloced; 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); @@ -102,32 +95,16 @@ sgen_memgov_try_calculate_minor_collection_allowance (gboolean overwrite) 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) @@ -311,6 +288,7 @@ sgen_alloc_os_memory (size_t size, SgenAllocFlags flags, const char *assert_desc 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; } @@ -329,6 +307,7 @@ sgen_alloc_os_memory_aligned (size_t size, mword alignment, SgenAllocFlags flags 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; } @@ -345,6 +324,7 @@ sgen_free_os_memory (void *addr, size_t size, SgenAllocFlags flags) 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 @@ -392,6 +372,9 @@ sgen_memgov_init (size_t max_heap, size_t soft_limit, gboolean debug_allowance, 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; diff --git a/mono/metadata/sgen-minor-copy-object.h b/mono/metadata/sgen-minor-copy-object.h index 782bbdf8de2..c18e49f16dd 100644 --- a/mono/metadata/sgen-minor-copy-object.h +++ b/mono/metadata/sgen-minor-copy-object.h @@ -21,10 +21,11 @@ #define collector_pin_object(obj, queue) sgen_pin_object (obj, queue); #define COLLECTOR_SERIAL_ALLOC_FOR_PROMOTION alloc_for_promotion -#define COLLECTOR_PARALLEL_ALLOC_FOR_PROMOTION par_alloc_for_promotion extern long long stat_nursery_copy_object_failed_to_space; /* from sgen-gc.c */ +#include "mono/utils/mono-compiler.h" + #include "sgen-copy-object.h" /* @@ -47,11 +48,7 @@ extern long long stat_nursery_copy_object_failed_to_space; /* from sgen-gc.c */ * copy_object could be made into a macro once debugged (use inline for now). */ -#ifdef _MSC_VER -static __forceinline void -#else -static inline void __attribute__((always_inline)) -#endif +static MONO_ALWAYS_INLINE void SERIAL_COPY_OBJECT (void **obj_slot, SgenGrayQueue *queue) { char *forwarded; @@ -107,11 +104,7 @@ SERIAL_COPY_OBJECT (void **obj_slot, SgenGrayQueue *queue) * * Similar to SERIAL_COPY_OBJECT, but assumes that OBJ_SLOT is part of an object, so it handles global remsets as well. */ -#ifdef _MSC_VER -static __forceinline void -#else -static inline void __attribute__((always_inline)) -#endif +static MONO_ALWAYS_INLINE void SERIAL_COPY_OBJECT_FROM_OBJ (void **obj_slot, SgenGrayQueue *queue) { char *forwarded; @@ -217,88 +210,6 @@ SERIAL_COPY_OBJECT_FROM_OBJ (void **obj_slot, SgenGrayQueue *queue) #endif } -static void -PARALLEL_COPY_OBJECT (void **obj_slot, SgenGrayQueue *queue) -{ - char *obj = *obj_slot; - mword vtable_word, objsize; - MonoVTable *vt; - void *destination; - gboolean has_references; - - SGEN_ASSERT (9, current_collection_generation == GENERATION_NURSERY, "calling minor-par-copy from a %d generation collection", current_collection_generation); - - HEAVY_STAT (++stat_copy_object_called_nursery); - - if (!sgen_ptr_in_nursery (obj)) { - HEAVY_STAT (++stat_nursery_copy_object_failed_from_space); - return; - } - - vtable_word = *(mword*)obj; - vt = (MonoVTable*)(vtable_word & ~SGEN_VTABLE_BITS_MASK); - - /* - * Before we can copy the object we must make sure that we are - * allowed to, i.e. that the object not pinned, not already - * forwarded and not in the nursery To Space. - */ - - if (vtable_word & SGEN_FORWARDED_BIT) { - HEAVY_STAT (++stat_nursery_copy_object_failed_forwarded); - *obj_slot = vt; - return; - } - if (vtable_word & SGEN_PINNED_BIT) { - HEAVY_STAT (++stat_nursery_copy_object_failed_pinned); - return; - } - - if (sgen_nursery_is_to_space (obj)) { - HEAVY_STAT (++stat_nursery_copy_object_failed_to_space); - return; - } - - HEAVY_STAT (++stat_objects_copied_nursery); - - objsize = SGEN_ALIGN_UP (sgen_par_object_get_size (vt, (MonoObject*)obj)); - has_references = SGEN_VTABLE_HAS_REFERENCES (vt); - - destination = COLLECTOR_PARALLEL_ALLOC_FOR_PROMOTION (vt, obj, objsize, has_references); - - if (G_UNLIKELY (!destination)) { - sgen_parallel_pin_or_update (obj_slot, obj, vt, queue); - return; - } - - *(MonoVTable**)destination = vt; - - if (SGEN_CAS_PTR ((void*)obj, (void*)((mword)destination | SGEN_FORWARDED_BIT), vt) == vt) { - par_copy_object_no_checks (destination, vt, obj, objsize, has_references ? queue : NULL); - obj = destination; - *obj_slot = obj; - } else { - /* FIXME: unify with code in major_copy_or_mark_object() */ - - /* FIXME: Give destination back to the allocator. */ - /*The major collector only needs the first word zeroed and nursery requires all bits to be. */ - if (!sgen_ptr_in_nursery (destination)) - *(void**)destination = NULL; - else - memset (destination, 0, objsize); - - vtable_word = *(mword*)obj; - g_assert (vtable_word & SGEN_FORWARDED_BIT); - - obj = (void*)(vtable_word & ~SGEN_VTABLE_BITS_MASK); - - *obj_slot = obj; - - HEAVY_STAT (++stat_slots_allocated_in_vain); - } -} - #define FILL_MINOR_COLLECTOR_COPY_OBJECT(collector) do { \ (collector)->serial_ops.copy_or_mark_object = SERIAL_COPY_OBJECT; \ - (collector)->parallel_ops.copy_or_mark_object = PARALLEL_COPY_OBJECT; \ } while (0) diff --git a/mono/metadata/sgen-minor-scan-object.h b/mono/metadata/sgen-minor-scan-object.h index 7a34dfd4ac3..3cff269a7da 100644 --- a/mono/metadata/sgen-minor-scan-object.h +++ b/mono/metadata/sgen-minor-scan-object.h @@ -24,70 +24,15 @@ extern long long stat_scan_object_called_nursery; #if defined(SGEN_SIMPLE_NURSERY) #define SERIAL_SCAN_OBJECT simple_nursery_serial_scan_object #define SERIAL_SCAN_VTYPE simple_nursery_serial_scan_vtype -#define PARALLEL_SCAN_OBJECT simple_nursery_parallel_scan_object -#define PARALLEL_SCAN_VTYPE simple_nursery_parallel_scan_vtype #elif defined (SGEN_SPLIT_NURSERY) #define SERIAL_SCAN_OBJECT split_nursery_serial_scan_object #define SERIAL_SCAN_VTYPE split_nursery_serial_scan_vtype -#define PARALLEL_SCAN_OBJECT split_nursery_parallel_scan_object -#define PARALLEL_SCAN_VTYPE split_nursery_parallel_scan_vtype #else #error "Please define GC_CONF_NAME" #endif -#undef HANDLE_PTR -#define HANDLE_PTR(ptr,obj) do { \ - void *__old = *(ptr); \ - void *__copy; \ - SGEN_OBJECT_LAYOUT_STATISTICS_MARK_BITMAP ((obj), (ptr)); \ - if (__old) { \ - PARALLEL_COPY_OBJECT ((ptr), queue); \ - __copy = *(ptr); \ - SGEN_COND_LOG (9, __old != __copy, "Overwrote field at %p with %p (was: %p)", (ptr), *(ptr), __old); \ - if (G_UNLIKELY (sgen_ptr_in_nursery (__copy) && !sgen_ptr_in_nursery ((ptr)))) \ - sgen_add_to_global_remset ((ptr), __copy); \ - } \ - } while (0) - -/* - * Scan the object pointed to by @start for references to - * other objects between @from_start and @from_end and copy - * them to the gray_objects area. - */ -static void -PARALLEL_SCAN_OBJECT (char *start, SgenGrayQueue *queue) -{ - SGEN_OBJECT_LAYOUT_STATISTICS_DECLARE_BITMAP; - -#define SCAN_OBJECT_PROTOCOL -#include "sgen-scan-object.h" - - SGEN_OBJECT_LAYOUT_STATISTICS_COMMIT_BITMAP; - HEAVY_STAT (++stat_scan_object_called_nursery); -} - -/* - * scan_vtype: - * - * Scan the valuetype pointed to by START, described by DESC for references to - * other objects between @from_start and @from_end and copy them to the gray_objects area. - * Returns a pointer to the end of the object. - */ -static void -PARALLEL_SCAN_VTYPE (char *start, mword desc, SgenGrayQueue *queue BINARY_PROTOCOL_ARG (size_t size)) -{ - SGEN_OBJECT_LAYOUT_STATISTICS_DECLARE_BITMAP; - - /* The descriptors include info about the MonoObject header as well */ - start -= sizeof (MonoObject); - -#define SCAN_OBJECT_NOVTABLE -#define SCAN_OBJECT_PROTOCOL -#include "sgen-scan-object.h" -} - #undef HANDLE_PTR /* Global remsets are handled in SERIAL_COPY_OBJECT_FROM_OBJ */ #define HANDLE_PTR(ptr,obj) do { \ @@ -100,10 +45,14 @@ PARALLEL_SCAN_VTYPE (char *start, mword desc, SgenGrayQueue *queue BINARY_PROTOC } while (0) static void -SERIAL_SCAN_OBJECT (char *start, SgenGrayQueue *queue) +SERIAL_SCAN_OBJECT (char *start, mword desc, SgenGrayQueue *queue) { SGEN_OBJECT_LAYOUT_STATISTICS_DECLARE_BITMAP; +#ifdef HEAVY_STATISTICS + sgen_descriptor_count_scanned_object (desc); +#endif + #define SCAN_OBJECT_PROTOCOL #include "sgen-scan-object.h" @@ -125,8 +74,6 @@ SERIAL_SCAN_VTYPE (char *start, mword desc, SgenGrayQueue *queue BINARY_PROTOCOL } #define FILL_MINOR_COLLECTOR_SCAN_OBJECT(collector) do { \ - (collector)->parallel_ops.scan_object = PARALLEL_SCAN_OBJECT; \ - (collector)->parallel_ops.scan_vtype = PARALLEL_SCAN_VTYPE; \ (collector)->serial_ops.scan_object = SERIAL_SCAN_OBJECT; \ (collector)->serial_ops.scan_vtype = SERIAL_SCAN_VTYPE; \ } while (0) diff --git a/mono/metadata/sgen-new-bridge.c b/mono/metadata/sgen-new-bridge.c index d07203db4d1..51b00e96695 100644 --- a/mono/metadata/sgen-new-bridge.c +++ b/mono/metadata/sgen-new-bridge.c @@ -652,6 +652,7 @@ dfs1 (HashEntry *obj_entry) if (obj_entry) { /* obj_entry needs to be expanded */ src = dyn_array_ptr_pop (&dfs_stack); + if (src) g_assert (!src->v.dfs1.forwarded_to); @@ -664,6 +665,7 @@ dfs1 (HashEntry *obj_entry) if (!obj_entry->v.dfs1.is_visited) { int num_links = 0; + mword desc = sgen_obj_get_descriptor (start); obj_entry->v.dfs1.is_visited = 1; diff --git a/mono/metadata/sgen-nursery-allocator.c b/mono/metadata/sgen-nursery-allocator.c index 3d422e6b7b8..75297a7e1b1 100644 --- a/mono/metadata/sgen-nursery-allocator.c +++ b/mono/metadata/sgen-nursery-allocator.c @@ -71,6 +71,7 @@ #include "metadata/sgen-archdep.h" #include "metadata/sgen-bridge.h" #include "metadata/sgen-memory-governor.h" +#include "metadata/sgen-pinning.h" #include "metadata/mono-gc.h" #include "metadata/method-builder.h" #include "metadata/profiler-private.h" @@ -747,12 +748,12 @@ fragment_list_reverse (SgenFragmentAllocator *allocator) } mword -sgen_build_nursery_fragments (GCMemSection *nursery_section, void **start, size_t num_entries, SgenGrayQueue *unpin_queue) +sgen_build_nursery_fragments (GCMemSection *nursery_section, SgenGrayQueue *unpin_queue) { char *frag_start, *frag_end; size_t frag_size; - size_t i = 0; SgenFragment *frags_ranges; + void **pin_start, **pin_entry, **pin_end; #ifdef NALLOC_DEBUG reset_alloc_records (); @@ -769,26 +770,30 @@ sgen_build_nursery_fragments (GCMemSection *nursery_section, void **start, size_ /* clear scan starts */ memset (nursery_section->scan_starts, 0, nursery_section->num_scan_start * sizeof (gpointer)); - while (i < num_entries || frags_ranges) { + pin_start = pin_entry = sgen_pinning_get_entry (nursery_section->pin_queue_first_entry); + pin_end = sgen_pinning_get_entry (nursery_section->pin_queue_last_entry); + + while (pin_entry < pin_end || frags_ranges) { char *addr0, *addr1; size_t size; SgenFragment *last_frag = NULL; addr0 = addr1 = sgen_nursery_end; - if (i < num_entries) - addr0 = start [i]; + if (pin_entry < pin_end) + addr0 = *pin_entry; if (frags_ranges) addr1 = frags_ranges->fragment_start; if (addr0 < addr1) { if (unpin_queue) - GRAY_OBJECT_ENQUEUE (unpin_queue, addr0); + 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; + ++pin_entry; } else { frag_end = addr1; size = frags_ranges->fragment_next - addr1; @@ -808,7 +813,7 @@ sgen_build_nursery_fragments (GCMemSection *nursery_section, void **start, size_ frag_size = size; #ifdef NALLOC_DEBUG - add_alloc_record (start [i], frag_size, PINNING); + add_alloc_record (*pin_entry, frag_size, PINNING); #endif frag_start = frag_end + frag_size; } @@ -829,9 +834,10 @@ sgen_build_nursery_fragments (GCMemSection *nursery_section, void **start, size_ sgen_minor_collector.build_fragments_finish (&mutator_allocator); if (!unmask (mutator_allocator.alloc_head)) { - SGEN_LOG (1, "Nursery fully pinned (%zd)", num_entries); - for (i = 0; i < num_entries; ++i) { - SGEN_LOG (3, "Bastard pinning obj %p (%s), size: %zd", start [i], sgen_safe_name (start [i]), sgen_safe_object_get_size (start [i])); + SGEN_LOG (1, "Nursery fully pinned"); + for (pin_entry = pin_start; pin_entry < pin_end; ++pin_entry) { + void *p = *pin_entry; + SGEN_LOG (3, "Bastard pinning obj %p (%s), size: %zd", p, sgen_safe_name (p), sgen_safe_object_get_size (p)); } } return fragment_total; @@ -871,7 +877,7 @@ sgen_can_alloc_size (size_t size) 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); diff --git a/mono/metadata/sgen-old-bridge.c b/mono/metadata/sgen-old-bridge.c index 42a588164df..4e2ba7b84d7 100644 --- a/mono/metadata/sgen-old-bridge.c +++ b/mono/metadata/sgen-old-bridge.c @@ -521,10 +521,12 @@ dfs1 (HashEntry *obj_entry) obj_entry = dyn_array_ptr_pop (&dfs_stack); if (obj_entry) { + mword desc; src = dyn_array_ptr_pop (&dfs_stack); obj = obj_entry->obj; start = (char*)obj; + desc = sgen_obj_get_descriptor (start); if (src) { //g_print ("link %s -> %s\n", sgen_safe_name (src->obj), sgen_safe_name (obj)); diff --git a/mono/metadata/sgen-os-posix.c b/mono/metadata/sgen-os-posix.c index 909b8382c81..55acf5137c3 100644 --- a/mono/metadata/sgen-os-posix.c +++ b/mono/metadata/sgen-os-posix.c @@ -56,17 +56,30 @@ suspend_thread (SgenThreadInfo *info, void *context) #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) { @@ -74,7 +87,7 @@ suspend_thread (SgenThreadInfo *info, void *context) #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)); } @@ -122,7 +135,7 @@ suspend_thread (SgenThreadInfo *info, void *context) } /* 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 @@ -131,19 +144,19 @@ MONO_SIGNAL_HANDLER_FUNC (static, suspend_handler, (int sig, siginfo_t *siginfo, * 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; diff --git a/mono/metadata/sgen-pinning.c b/mono/metadata/sgen-pinning.c index 523c7737b14..c895d7471ea 100644 --- a/mono/metadata/sgen-pinning.c +++ b/mono/metadata/sgen-pinning.c @@ -25,10 +25,9 @@ #include "metadata/sgen-gc.h" #include "metadata/sgen-pinning.h" #include "metadata/sgen-protocol.h" +#include "metadata/sgen-pointer-queue.h" -static void** pin_queue; -static size_t pin_queue_size = 0; -static size_t next_pin_slot = 0; +static SgenPointerQueue pin_queue; static size_t last_num_pinned = 0; #define PIN_HASH_SIZE 1024 @@ -43,20 +42,8 @@ sgen_init_pinning (void) void sgen_finish_pinning (void) { - last_num_pinned = next_pin_slot; - next_pin_slot = 0; -} - -static void -realloc_pin_queue (void) -{ - size_t new_size = pin_queue_size? pin_queue_size + pin_queue_size/2: 1024; - void **new_pin = sgen_alloc_internal_dynamic (sizeof (void*) * new_size, INTERNAL_MEM_PIN_QUEUE, TRUE); - memcpy (new_pin, pin_queue, sizeof (void*) * next_pin_slot); - sgen_free_internal_dynamic (pin_queue, sizeof (void*) * pin_queue_size, INTERNAL_MEM_PIN_QUEUE); - pin_queue = new_pin; - pin_queue_size = new_size; - SGEN_LOG (4, "Reallocated pin queue to size: %zd", new_size); + last_num_pinned = pin_queue.next_slot; + sgen_pointer_queue_clear (&pin_queue); } void @@ -69,71 +56,92 @@ sgen_pin_stage_ptr (void *ptr) pin_hash_filter [hash_idx] = ptr; - if (next_pin_slot >= pin_queue_size) - realloc_pin_queue (); - - pin_queue [next_pin_slot++] = ptr; + sgen_pointer_queue_add (&pin_queue, ptr); } -static size_t -optimized_pin_queue_search (void *addr) +gboolean +sgen_find_optimized_pin_queue_area (void *start, void *end, size_t *first_out, size_t *last_out) { - size_t first = 0, last = next_pin_slot; - while (first < last) { - size_t middle = first + ((last - first) >> 1); - if (addr <= pin_queue [middle]) - last = middle; - else - first = middle + 1; - } - g_assert (first == last); - return first; + size_t first = sgen_pointer_queue_search (&pin_queue, start); + size_t last = sgen_pointer_queue_search (&pin_queue, end); + SGEN_ASSERT (0, last == pin_queue.next_slot || pin_queue.data [last] >= end, "Pin queue search gone awry"); + *first_out = first; + *last_out = last; + return first != last; } void** -sgen_find_optimized_pin_queue_area (void *start, void *end, size_t *num) +sgen_pinning_get_entry (size_t index) { - size_t first, last; - first = optimized_pin_queue_search (start); - last = optimized_pin_queue_search (end); - *num = last - first; - if (first == last) - return NULL; - return pin_queue + first; + SGEN_ASSERT (0, index <= pin_queue.next_slot, "Pin queue entry out of range"); + return &pin_queue.data [index]; } void sgen_find_section_pin_queue_start_end (GCMemSection *section) { SGEN_LOG (6, "Pinning from section %p (%p-%p)", section, section->data, section->end_data); - section->pin_queue_start = sgen_find_optimized_pin_queue_area (section->data, section->end_data, §ion->pin_queue_num_entries); - SGEN_LOG (6, "Found %zd pinning addresses in section %p", section->pin_queue_num_entries, section); + + sgen_find_optimized_pin_queue_area (section->data, section->end_data, + §ion->pin_queue_first_entry, §ion->pin_queue_last_entry); + + SGEN_LOG (6, "Found %zd pinning addresses in section %p", + section->pin_queue_last_entry - section->pin_queue_first_entry, section); } /*This will setup the given section for the while pin queue. */ void sgen_pinning_setup_section (GCMemSection *section) { - section->pin_queue_start = pin_queue; - section->pin_queue_num_entries = next_pin_slot; + section->pin_queue_first_entry = 0; + section->pin_queue_last_entry = pin_queue.next_slot; } void sgen_pinning_trim_queue_to_section (GCMemSection *section) { - next_pin_slot = section->pin_queue_num_entries; + SGEN_ASSERT (0, section->pin_queue_first_entry == 0, "Pin queue trimming assumes the whole pin queue is used by the nursery"); + pin_queue.next_slot = section->pin_queue_last_entry; } +/* + * This is called when we've run out of memory during a major collection. + * + * After collecting potential pin entries and sorting the array, this is what it looks like: + * + * +--------------------+---------------------------------------------+--------------------+ + * | major heap entries | nursery entries | major heap entries | + * +--------------------+---------------------------------------------+--------------------+ + * + * Of course there might not be major heap entries before and/or after the nursery entries, + * depending on where the major heap sections are in the address space, and whether there + * were any potential pointers there. + * + * When we pin nursery objects, we compact the nursery part of the pin array, which leaves + * discarded entries after the ones that actually pointed to nursery objects: + * + * +--------------------+-----------------+---------------------------+--------------------+ + * | major heap entries | nursery entries | discarded nursery entries | major heap entries | + * +--------------------+-----------------+---------------------------+--------------------+ + * + * When, due to being out of memory, we late pin more objects, the pin array looks like + * this: + * + * +--------------------+-----------------+---------------------------+--------------------+--------------+ + * | major heap entries | nursery entries | discarded nursery entries | major heap entries | late entries | + * +--------------------+-----------------+---------------------------+--------------------+--------------+ + * + * This function gets rid of the discarded nursery entries by nulling them out. Note that + * we can late pin objects not only in the nursery but also in the major heap, which happens + * when evacuation fails. + */ void sgen_pin_queue_clear_discarded_entries (GCMemSection *section, size_t max_pin_slot) { - void **start = section->pin_queue_start + section->pin_queue_num_entries; - void **end = pin_queue + max_pin_slot; + void **start = sgen_pinning_get_entry (section->pin_queue_last_entry); + void **end = sgen_pinning_get_entry (max_pin_slot); void *addr; - if (!start) - return; - for (; start < end; ++start) { addr = *start; if ((char*)addr < section->data || (char*)addr > section->end_data) @@ -144,30 +152,15 @@ sgen_pin_queue_clear_discarded_entries (GCMemSection *section, size_t max_pin_sl /* reduce the info in the pin queue, removing duplicate pointers and sorting them */ void -sgen_optimize_pin_queue (size_t start_slot) +sgen_optimize_pin_queue (void) { - void **start, **cur, **end; - /* sort and uniq pin_queue: we just sort and we let the rest discard multiple values */ - /* it may be better to keep ranges of pinned memory instead of individually pinning objects */ - SGEN_LOG (5, "Sorting pin queue, size: %zd", next_pin_slot); - if ((next_pin_slot - start_slot) > 1) - sgen_sort_addresses (pin_queue + start_slot, next_pin_slot - start_slot); - start = cur = pin_queue + start_slot; - end = pin_queue + next_pin_slot; - while (cur < end) { - *start = *cur++; - while (*start == *cur && cur < end) - cur++; - start++; - }; - next_pin_slot = start - pin_queue; - SGEN_LOG (5, "Pin queue reduced to size: %zd", next_pin_slot); + sgen_pointer_queue_sort_uniq (&pin_queue); } size_t sgen_get_pinned_count (void) { - return next_pin_slot; + return pin_queue.next_slot; } void @@ -176,8 +169,9 @@ sgen_dump_pin_queue (void) int i; for (i = 0; i < last_num_pinned; ++i) { - SGEN_LOG (3, "Bastard pinning obj %p (%s), size: %zd", pin_queue [i], sgen_safe_name (pin_queue [i]), sgen_safe_object_get_size (pin_queue [i])); - } + void *ptr = pin_queue.data [i]; + SGEN_LOG (3, "Bastard pinning obj %p (%s), size: %zd", ptr, sgen_safe_name (ptr), sgen_safe_object_get_size (ptr)); + } } typedef struct _CementHashEntry CementHashEntry; @@ -311,7 +305,7 @@ sgen_cement_lookup_or_register (char *obj) } void -sgen_cement_iterate (IterateObjectCallbackFunc callback, void *callback_data) +sgen_pin_cemented_objects (void) { int i; for (i = 0; i < SGEN_CEMENT_HASH_SIZE; ++i) { @@ -320,7 +314,8 @@ sgen_cement_iterate (IterateObjectCallbackFunc callback, void *callback_data) SGEN_ASSERT (5, cement_hash [i].count >= SGEN_CEMENT_THRESHOLD, "Cementing hash inconsistent"); - callback (cement_hash [i].obj, 0, callback_data); + sgen_pin_stage_ptr (cement_hash [i].obj); + /* FIXME: do pin stats if enabled */ } } diff --git a/mono/metadata/sgen-pinning.h b/mono/metadata/sgen-pinning.h index ef41df24d2f..9a2dcbb2c57 100644 --- a/mono/metadata/sgen-pinning.h +++ b/mono/metadata/sgen-pinning.h @@ -28,7 +28,7 @@ enum { }; void sgen_pin_stage_ptr (void *ptr) MONO_INTERNAL; -void sgen_optimize_pin_queue (size_t start_slot) MONO_INTERNAL; +void sgen_optimize_pin_queue (void) MONO_INTERNAL; void sgen_init_pinning (void) MONO_INTERNAL; void sgen_finish_pinning (void) MONO_INTERNAL; void sgen_pin_queue_clear_discarded_entries (GCMemSection *section, size_t max_pin_slot) MONO_INTERNAL; @@ -38,6 +38,11 @@ void sgen_pinning_trim_queue_to_section (GCMemSection *section) MONO_INTERNAL; void sgen_dump_pin_queue (void) MONO_INTERNAL; +gboolean sgen_find_optimized_pin_queue_area (void *start, void *end, size_t *first_out, size_t *last_out) MONO_INTERNAL; +void sgen_find_section_pin_queue_start_end (GCMemSection *section) MONO_INTERNAL; +void** sgen_pinning_get_entry (size_t index) MONO_INTERNAL; +void sgen_pin_objects_in_section (GCMemSection *section, ScanCopyContext ctx) MONO_INTERNAL; + /* Pinning stats */ void sgen_pin_stats_register_address (char *addr, int pin_type) MONO_INTERNAL; @@ -53,7 +58,7 @@ void sgen_cement_concurrent_start (void) MONO_INTERNAL; void sgen_cement_concurrent_finish (void) MONO_INTERNAL; gboolean sgen_cement_lookup (char *obj) MONO_INTERNAL; gboolean sgen_cement_lookup_or_register (char *obj) MONO_INTERNAL; -void sgen_cement_iterate (IterateObjectCallbackFunc callback, void *callback_data) MONO_INTERNAL; +void sgen_pin_cemented_objects (void) MONO_INTERNAL; void sgen_cement_clear_below_threshold (void) MONO_INTERNAL; #endif diff --git a/mono/metadata/sgen-pointer-queue.c b/mono/metadata/sgen-pointer-queue.c index fe491605d52..3c1d8fb6c61 100644 --- a/mono/metadata/sgen-pointer-queue.c +++ b/mono/metadata/sgen-pointer-queue.c @@ -64,6 +64,27 @@ sgen_pointer_queue_search (SgenPointerQueue *queue, void *addr) return first; } +/* + * Removes all NULL pointers from the queue. + */ +void +sgen_pointer_queue_remove_nulls (SgenPointerQueue *queue) +{ + void **start, **cur, **end; + start = cur = queue->data; + end = queue->data + queue->next_slot; + while (cur < end) { + if (*cur) + *start++ = *cur++; + else + ++cur; + } + queue->next_slot = start - queue->data; +} + +/* + * Sorts the pointers in the queue, then removes duplicates. + */ void sgen_pointer_queue_sort_uniq (SgenPointerQueue *queue) { @@ -77,7 +98,7 @@ sgen_pointer_queue_sort_uniq (SgenPointerQueue *queue) end = queue->data + queue->next_slot; while (cur < end) { *start = *cur++; - while (*start == *cur && cur < end) + while (cur < end && *start == *cur) cur++; start++; }; @@ -85,4 +106,18 @@ sgen_pointer_queue_sort_uniq (SgenPointerQueue *queue) SGEN_LOG (5, "Pointer queue reduced to size: %lu", queue->next_slot); } +/* + * Does a linear search through the pointer queue to find `ptr`. Returns the index if + * found, otherwise (size_t)-1. + */ +size_t +sgen_pointer_queue_find (SgenPointerQueue *queue, void *ptr) +{ + size_t i; + for (i = 0; i < queue->next_slot; ++i) + if (queue->data [i] == ptr) + return i; + return (size_t)-1; +} + #endif diff --git a/mono/metadata/sgen-pointer-queue.h b/mono/metadata/sgen-pointer-queue.h index 031870f1285..d972f3cc92e 100644 --- a/mono/metadata/sgen-pointer-queue.h +++ b/mono/metadata/sgen-pointer-queue.h @@ -28,7 +28,9 @@ typedef struct { void sgen_pointer_queue_add (SgenPointerQueue *queue, void *ptr) MONO_INTERNAL; void sgen_pointer_queue_clear (SgenPointerQueue *queue) MONO_INTERNAL; +void sgen_pointer_queue_remove_nulls (SgenPointerQueue *queue) MONO_INTERNAL; void sgen_pointer_queue_sort_uniq (SgenPointerQueue *queue) MONO_INTERNAL; size_t sgen_pointer_queue_search (SgenPointerQueue *queue, void *addr) MONO_INTERNAL; +size_t sgen_pointer_queue_find (SgenPointerQueue *queue, void *ptr) MONO_INTERNAL; #endif diff --git a/mono/metadata/sgen-scan-object.h b/mono/metadata/sgen-scan-object.h index 7cbe57a6c83..ad569dda359 100644 --- a/mono/metadata/sgen-scan-object.h +++ b/mono/metadata/sgen-scan-object.h @@ -23,7 +23,12 @@ * object must be given in the variable "char* start". Afterwards, * "start" will point to the start of the next object, if the scanned * object contained references. If not, the value of "start" should - * be considered undefined after executing this code. + * be considered undefined after executing this code. The object's + * GC descriptor must be in the variable "mword desc". + * + * The macro `HANDLE_PTR` will be invoked for every reference encountered while scanning the + * object. It is called with two parameters: The pointer to the reference (not the + * reference itself!) as well as the pointer to the scanned object. * * Modifiers (automatically undefined): * @@ -40,17 +45,8 @@ { #ifndef SCAN_OBJECT_NOVTABLE - GCVTable *vt; - mword desc; - - vt = (GCVTable*)SGEN_LOAD_VTABLE (start); - //type = vt->desc & 0x7; - - /* gcc should be smart enough to remove the bounds check, but it isn't:( */ - desc = vt->desc; - #if defined(SGEN_HEAVY_BINARY_PROTOCOL) && defined(SCAN_OBJECT_PROTOCOL) - binary_protocol_scan_begin (start, vt, sgen_safe_object_get_size ((MonoObject*)start)); + binary_protocol_scan_begin (start, SGEN_LOAD_VTABLE (start), sgen_safe_object_get_size ((MonoObject*)start)); #endif #else #if defined(SGEN_HEAVY_BINARY_PROTOCOL) && defined(SCAN_OBJECT_PROTOCOL) @@ -97,7 +93,7 @@ #ifndef SCAN_OBJECT_NOVTABLE case DESC_TYPE_COMPLEX_ARR: /* this is an array of complex structs */ -#define SCAN OBJ_COMPLEX_ARR_FOREACH_PTR (vt, start) +#define SCAN OBJ_COMPLEX_ARR_FOREACH_PTR (desc, start) #ifndef SCAN_OBJECT_NOSCAN SCAN; #endif diff --git a/mono/metadata/sgen-simple-nursery.c b/mono/metadata/sgen-simple-nursery.c index f2f7066c301..2cfb9d3211c 100644 --- a/mono/metadata/sgen-simple-nursery.c +++ b/mono/metadata/sgen-simple-nursery.c @@ -35,12 +35,6 @@ alloc_for_promotion (MonoVTable *vtable, char *obj, size_t objsize, gboolean has return major_collector.alloc_object (vtable, objsize, has_references); } -static inline char* -par_alloc_for_promotion (MonoVTable *vtable, char *obj, size_t objsize, gboolean has_references) -{ - return major_collector.par_alloc_object (vtable, objsize, has_references); -} - static SgenFragment* build_fragments_get_exclude_head (void) { @@ -79,7 +73,6 @@ init_nursery (SgenFragmentAllocator *allocator, char *start, char *end) #define SGEN_SIMPLE_NURSERY #define SERIAL_COPY_OBJECT simple_nursery_serial_copy_object -#define PARALLEL_COPY_OBJECT simple_nursery_parallel_copy_object #define SERIAL_COPY_OBJECT_FROM_OBJ simple_nursery_serial_copy_object_from_obj #include "sgen-minor-copy-object.h" @@ -91,7 +84,6 @@ sgen_simple_nursery_init (SgenMinorCollector *collector) collector->is_split = FALSE; collector->alloc_for_promotion = alloc_for_promotion; - collector->par_alloc_for_promotion = par_alloc_for_promotion; collector->prepare_to_space = prepare_to_space; collector->clear_fragments = clear_fragments; diff --git a/mono/metadata/sgen-split-nursery.c b/mono/metadata/sgen-split-nursery.c index 1f62d14b703..87cc412c672 100644 --- a/mono/metadata/sgen-split-nursery.c +++ b/mono/metadata/sgen-split-nursery.c @@ -145,8 +145,6 @@ static AgeAllocationBuffer age_alloc_buffers [MAX_AGE]; /* The collector allocs from here. */ static SgenFragmentAllocator collector_allocator; -static LOCK_DECLARE (par_alloc_buffer_refill_mutex); - static inline int get_object_age (char *object) { @@ -292,82 +290,6 @@ alloc_for_promotion (MonoVTable *vtable, char *obj, size_t objsize, gboolean has return p; } -static char* -par_alloc_for_promotion_slow_path (int age, size_t objsize) -{ - char *p; - size_t allocated_size; - size_t aligned_objsize = (size_t)align_up (objsize, SGEN_TO_SPACE_GRANULE_BITS); - - mono_mutex_lock (&par_alloc_buffer_refill_mutex); - -restart: - p = age_alloc_buffers [age].next; - if (G_LIKELY (p + objsize <= age_alloc_buffers [age].end)) { - if (SGEN_CAS_PTR ((void*)&age_alloc_buffers [age].next, p + objsize, p) != p) - goto restart; - } else { - /* Reclaim remaining space - if we OOMd the nursery nothing to see here. */ - char *end = age_alloc_buffers [age].end; - if (end) { - do { - p = age_alloc_buffers [age].next; - } while (SGEN_CAS_PTR ((void*)&age_alloc_buffers [age].next, end, p) != p); - sgen_clear_range (p, end); - } - - /* By setting end to NULL we make sure no other thread can advance while we're updating.*/ - age_alloc_buffers [age].end = NULL; - STORE_STORE_FENCE; - - p = sgen_fragment_allocator_par_range_alloc ( - &collector_allocator, - MAX (aligned_objsize, AGE_ALLOC_BUFFER_DESIRED_SIZE), - MAX (aligned_objsize, AGE_ALLOC_BUFFER_MIN_SIZE), - &allocated_size); - if (p) { - set_age_in_range (p, p + allocated_size, age); - age_alloc_buffers [age].next = p + objsize; - STORE_STORE_FENCE; /* Next must arrive before the new value for next. */ - age_alloc_buffers [age].end = p + allocated_size; - } - } - - mono_mutex_unlock (&par_alloc_buffer_refill_mutex); - return p; -} - -static inline char* -par_alloc_for_promotion (MonoVTable *vtable, char *obj, size_t objsize, gboolean has_references) -{ - char *p; - int age; - - age = get_object_age (obj); - if (age >= promote_age) - return major_collector.par_alloc_object (vtable, objsize, has_references); - -restart: - p = age_alloc_buffers [age].next; - - LOAD_LOAD_FENCE; /* The read of ->next must happen before ->end */ - - if (G_LIKELY (p + objsize <= age_alloc_buffers [age].end)) { - if (SGEN_CAS_PTR ((void*)&age_alloc_buffers [age].next, p + objsize, p) != p) - goto restart; - } else { - p = par_alloc_for_promotion_slow_path (age, objsize); - - /* Have we failed to promote to the nursery, lets just evacuate it to old gen. */ - if (!p) - return major_collector.par_alloc_object (vtable, objsize, has_references); - } - - *(MonoVTable**)p = vtable; - - return p; -} - static char* minor_alloc_for_promotion (MonoVTable *vtable, char *obj, size_t objsize, gboolean has_references) { @@ -380,18 +302,6 @@ minor_alloc_for_promotion (MonoVTable *vtable, char *obj, size_t objsize, gboole return alloc_for_promotion (vtable, obj, objsize, has_references); } -static char* -minor_par_alloc_for_promotion (MonoVTable *vtable, char *obj, size_t objsize, gboolean has_references) -{ - /* - We only need to check for a non-nursery object if we're doing a major collection. - */ - if (!sgen_ptr_in_nursery (obj)) - return major_collector.par_alloc_object (vtable, objsize, has_references); - - return par_alloc_for_promotion (vtable, obj, objsize, has_references); -} - static SgenFragment* build_fragments_get_exclude_head (void) { @@ -522,7 +432,6 @@ print_gc_param_usage (void) #define SGEN_SPLIT_NURSERY #define SERIAL_COPY_OBJECT split_nursery_serial_copy_object -#define PARALLEL_COPY_OBJECT split_nursery_parallel_copy_object #define SERIAL_COPY_OBJECT_FROM_OBJ split_nursery_serial_copy_object_from_obj #include "sgen-minor-copy-object.h" @@ -534,7 +443,6 @@ sgen_split_nursery_init (SgenMinorCollector *collector) collector->is_split = TRUE; collector->alloc_for_promotion = minor_alloc_for_promotion; - collector->par_alloc_for_promotion = minor_par_alloc_for_promotion; collector->prepare_to_space = prepare_to_space; collector->clear_fragments = clear_fragments; @@ -547,7 +455,6 @@ sgen_split_nursery_init (SgenMinorCollector *collector) FILL_MINOR_COLLECTOR_COPY_OBJECT (collector); FILL_MINOR_COLLECTOR_SCAN_OBJECT (collector); - LOCK_INIT (par_alloc_buffer_refill_mutex); } diff --git a/mono/metadata/sgen-stw.c b/mono/metadata/sgen-stw.c index 5a2ab0e9687..2a9bf34788c 100644 --- a/mono/metadata/sgen-stw.c +++ b/mono/metadata/sgen-stw.c @@ -52,7 +52,7 @@ align_pointer (void *ptr) #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 diff --git a/mono/metadata/sgen-tagged-pointer.h b/mono/metadata/sgen-tagged-pointer.h new file mode 100644 index 00000000000..fc065f7f96b --- /dev/null +++ b/mono/metadata/sgen-tagged-pointer.h @@ -0,0 +1,34 @@ +/* + * sgen-tagged-pointer.h: Macros for tagging and untagging pointers. + * + * 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_SGEN_TAGGED_POINTER_H__ +#define __MONO_SGEN_TAGGED_POINTER_H__ + +#define SGEN_POINTER_IS_TAGGED_1(p) ((mword)(p) & 1) +#define SGEN_POINTER_TAG_1(p) ((void*)((mword)(p) | 1)) +#define SGEN_POINTER_UNTAG_1(p) ((void*)((mword)(p) & ~1)) + +#define SGEN_POINTER_IS_TAGGED_2(p) ((mword)(p) & 2) +#define SGEN_POINTER_TAG_2(p) ((void*)((mword)(p) | 2)) +#define SGEN_POINTER_UNTAG_2(p) ((void*)((mword)(p) & ~2)) + +#define SGEN_POINTER_IS_TAGGED_1_OR_2(p) ((mword)(p) & 3) +#define SGEN_POINTER_UNTAG_12(p) ((void*)((mword)(p) & ~3)) + +#endif diff --git a/mono/metadata/sgen-tarjan-bridge.c b/mono/metadata/sgen-tarjan-bridge.c index 59013f70124..5c6525e9ec7 100644 --- a/mono/metadata/sgen-tarjan-bridge.c +++ b/mono/metadata/sgen-tarjan-bridge.c @@ -661,6 +661,7 @@ push_all (ScanData *data) { MonoObject *obj = data->obj; char *start = (char*)obj; + mword desc = sgen_obj_get_descriptor (start); #if DUMP_GRAPH printf ("**scanning %p %s\n", obj, safe_name_bridge (obj)); @@ -712,6 +713,7 @@ compute_low (ScanData *data) { MonoObject *obj = data->obj; char *start = (char*)obj; + mword desc = sgen_obj_get_descriptor (start); #include "sgen-scan-object.h" } diff --git a/mono/metadata/sgen-workers.c b/mono/metadata/sgen-workers.c index b3eebb02d9c..2d48745762b 100644 --- a/mono/metadata/sgen-workers.c +++ b/mono/metadata/sgen-workers.c @@ -140,7 +140,7 @@ workers_wait (void) static gboolean collection_needs_workers (void) { - return sgen_collection_is_parallel () || sgen_collection_is_concurrent (); + return sgen_collection_is_concurrent (); } void @@ -243,9 +243,9 @@ workers_steal (WorkerData *data, WorkerData *victim_data, gboolean lock) n -= m; sgen_gray_object_alloc_queue_section (queue); - memcpy (queue->first->objects, + memcpy (queue->first->entries, victim_data->stealable_stack + victim_data->stealable_stack_fill - num + n, - sizeof (char*) * m); + sizeof (GrayQueueEntry) * m); queue->first->size = m; /* @@ -253,10 +253,10 @@ workers_steal (WorkerData *data, WorkerData *victim_data, gboolean lock) * Doing so trigger "assert not reached" in sgen-scan-object.h : we use the queue->cursor * to compute the size of the first section during section allocation (via alloc_prepare_func * -> workers_gray_queue_share_redirect -> sgen_gray_object_dequeue_section) which will be then - * set to 0, because queue->cursor is still pointing to queue->first->objects [-1], thus + * set to 0, because queue->cursor is still pointing to queue->first->entries [-1], thus * losing objects in the gray queue. */ - queue->cursor = (char**)queue->first->objects + queue->first->size - 1; + queue->cursor = queue->first->entries + queue->first->size - 1; } victim_data->stealable_stack_fill -= num; @@ -301,7 +301,7 @@ workers_get_work (WorkerData *data) * distribute gray queue. */ major = sgen_get_major_collector (); - if (major->is_concurrent || major->is_parallel) { + if (major->is_concurrent) { GrayQueueSection *section = sgen_section_gray_queue_dequeue (&workers_distribute_gray_queue); if (section) { sgen_gray_object_enqueue_section (&data->private_gray_queue, section); @@ -338,8 +338,8 @@ workers_gray_queue_share_redirect (SgenGrayQueue *queue) int num = MIN (section->size, STEALABLE_STACK_SIZE - data->stealable_stack_fill); memcpy (data->stealable_stack + data->stealable_stack_fill, - section->objects + section->size - num, - sizeof (char*) * num); + section->entries + section->size - num, + sizeof (GrayQueueEntry) * num); section->size -= num; data->stealable_stack_fill += num; @@ -441,7 +441,7 @@ sgen_workers_init_distribute_gray_queue (void) if (!collection_needs_workers ()) return; - init_distribute_gray_queue (sgen_get_major_collector ()->is_concurrent || sgen_get_major_collector ()->is_parallel); + init_distribute_gray_queue (sgen_get_major_collector ()->is_concurrent); } void @@ -449,7 +449,7 @@ sgen_workers_init (int num_workers) { int i; - if (!sgen_get_major_collector ()->is_parallel && !sgen_get_major_collector ()->is_concurrent) + if (!sgen_get_major_collector ()->is_concurrent) return; //g_print ("initing %d workers\n", num_workers); @@ -462,7 +462,7 @@ sgen_workers_init (int num_workers) MONO_SEM_INIT (&workers_waiting_sem, 0); MONO_SEM_INIT (&workers_done_sem, 0); - init_distribute_gray_queue (sgen_get_major_collector ()->is_concurrent || sgen_get_major_collector ()->is_parallel); + init_distribute_gray_queue (sgen_get_major_collector ()->is_concurrent); if (sgen_get_major_collector ()->alloc_worker_data) workers_gc_thread_major_collector_data = sgen_get_major_collector ()->alloc_worker_data (); diff --git a/mono/metadata/sgen-workers.h b/mono/metadata/sgen-workers.h index 9070623673f..d13c4609674 100644 --- a/mono/metadata/sgen-workers.h +++ b/mono/metadata/sgen-workers.h @@ -34,7 +34,7 @@ struct _WorkerData { mono_mutex_t stealable_stack_mutex; volatile int stealable_stack_fill; - char *stealable_stack [STEALABLE_STACK_SIZE]; + GrayQueueEntry stealable_stack [STEALABLE_STACK_SIZE]; }; typedef void (*JobFunc) (WorkerData *worker_data, void *job_data); diff --git a/mono/metadata/socket-io.c b/mono/metadata/socket-io.c index cbce0f77269..949164e5548 100644 --- a/mono/metadata/socket-io.c +++ b/mono/metadata/socket-io.c @@ -20,12 +20,6 @@ #include #include #include -#ifdef HAVE_UNISTD_H -#include -#endif -#include - -#include #ifdef HOST_WIN32 #include #else @@ -36,6 +30,12 @@ #include #include #endif +#ifdef HAVE_UNISTD_H +#include +#endif +#include + +#include #include #include diff --git a/mono/metadata/string-icalls.c b/mono/metadata/string-icalls.c index 0927141e792..22b1fbbbdb4 100644 --- a/mono/metadata/string-icalls.c +++ b/mono/metadata/string-icalls.c @@ -65,5 +65,12 @@ ves_icall_System_String_GetLOSLimit (void) { 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); +} + diff --git a/mono/metadata/string-icalls.h b/mono/metadata/string-icalls.h index a0b831a1e20..33bcf80378b 100644 --- a/mono/metadata/string-icalls.h +++ b/mono/metadata/string-icalls.h @@ -30,4 +30,7 @@ ves_icall_System_String_InternalIsInterned (MonoString *str) MONO_INTERNAL; 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_ */ diff --git a/mono/metadata/threadpool.c b/mono/metadata/threadpool.c index 39ade54daa1..36514cc6ea8 100644 --- a/mono/metadata/threadpool.c +++ b/mono/metadata/threadpool.c @@ -41,6 +41,7 @@ #include #endif #include +#include #ifdef HAVE_SYS_SOCKET_H #include #endif @@ -62,13 +63,6 @@ #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 */ @@ -83,6 +77,12 @@ enum { 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 @@ -127,12 +127,10 @@ typedef struct { 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; @@ -148,6 +146,7 @@ static void threadpool_init (ThreadPool *tp, int min_threads, int max_threads, v 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); @@ -159,10 +158,17 @@ static MonoClass *async_call_klass; 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; @@ -656,6 +662,16 @@ mono_async_invoke (ThreadPool *tp, MonoAsyncResult *ares) 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; } @@ -757,21 +773,135 @@ signal_handler (int signo) } #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; @@ -791,26 +921,44 @@ monitor_thread (gpointer unused) 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); } } } @@ -857,6 +1005,10 @@ mono_thread_pool_init (void) 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)); @@ -878,6 +1030,10 @@ mono_thread_pool_init (void) signal (SIGALRM, signal_handler); alarm (2); #endif + + MONO_SEM_INIT (&monitor_sem, 0); + monitor_state = MONITOR_STATE_AWAKE; + monitor_njobs = 0; } static MonoAsyncResult * @@ -1004,6 +1160,14 @@ mono_thread_pool_cleanup (void) 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); @@ -1014,6 +1178,8 @@ mono_thread_pool_cleanup (void) mono_mutex_unlock (&wsqs_lock); MONO_SEM_DESTROY (&async_tp.new_job); } + + MONO_SEM_DESTROY (&monitor_sem); } static gboolean @@ -1021,6 +1187,7 @@ threadpool_start_thread (ThreadPool *tp) { 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) { @@ -1028,7 +1195,13 @@ threadpool_start_thread (ThreadPool *tp) #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; } } @@ -1043,6 +1216,13 @@ pulse_on_new_job (ThreadPool *tp) 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) { @@ -1058,7 +1238,6 @@ threadpool_append_job (ThreadPool *tp, MonoObject *ar) static void threadpool_append_jobs (ThreadPool *tp, MonoObject **jobs, gint njobs) { - static int job_counter; MonoObject *ar; gint i; @@ -1067,7 +1246,8 @@ threadpool_append_jobs (ThreadPool *tp, MonoObject **jobs, gint njobs) 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 @@ -1078,14 +1258,18 @@ threadpool_append_jobs (ThreadPool *tp, MonoObject **jobs, gint njobs) } } + 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); @@ -1096,6 +1280,10 @@ threadpool_append_jobs (ThreadPool *tp, MonoObject **jobs, gint njobs) 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); } @@ -1309,84 +1497,6 @@ dequeue_or_steal (ThreadPool *tp, gpointer *data, MonoWSQ *local_wsq) 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) { @@ -1513,8 +1623,6 @@ async_invoke_thread (gpointer data) 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); @@ -1541,8 +1649,12 @@ async_invoke_thread (gpointer 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) { @@ -1608,6 +1720,16 @@ async_invoke_thread (gpointer data) 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; } } diff --git a/mono/metadata/threads-types.h b/mono/metadata/threads-types.h index 6aeca4acf5e..860bb5b67e9 100644 --- a/mono/metadata/threads-types.h +++ b/mono/metadata/threads-types.h @@ -40,8 +40,6 @@ typedef enum { ThreadApartmentState_Unknown = 0x00000002 } MonoThreadApartmentState; -typedef void (*MonoThreadNotifyPendingExcFunc) (void); - #define SPECIAL_STATIC_NONE 0 #define SPECIAL_STATIC_THREAD 1 #define SPECIAL_STATIC_CONTEXT 2 @@ -54,6 +52,8 @@ typedef LPTHREAD_START_ROUTINE WapiThreadStart; typedef struct _MonoInternalThread MonoInternalThread; typedef void (*MonoThreadCleanupFunc) (MonoInternalThread* thread); +/* INFO has type MonoThreadInfo* */ +typedef void (*MonoThreadNotifyPendingExcFunc) (gpointer info); MonoInternalThread* mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size) MONO_INTERNAL; diff --git a/mono/metadata/threads.c b/mono/metadata/threads.c index a0e5f8469d6..de4917ce08d 100644 --- a/mono/metadata/threads.c +++ b/mono/metadata/threads.c @@ -30,9 +30,6 @@ #include #include #include -#ifndef HOST_WIN32 -#include -#endif #include #include #include @@ -1210,12 +1207,16 @@ mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, g { LOCK_THREAD (this_obj); - if (this_obj->flags & MONO_THREAD_FLAG_NAME_SET) { + if ((this_obj->flags & MONO_THREAD_FLAG_NAME_SET) && !this_obj->threadpool_thread) { UNLOCK_THREAD (this_obj); mono_raise_exception (mono_get_exception_invalid_operation ("Thread.Name can only be set once.")); return; } + if (this_obj->name) { + g_free (this_obj->name); + this_obj->name_len = 0; + } if (name) { this_obj->name = g_new (gunichar2, mono_string_length (name)); memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2); @@ -2028,12 +2029,12 @@ static void signal_thread_state_change (MonoInternalThread *thread) * functions in the io-layer until the signal handler calls QueueUserAPC which will * make it return. */ - wait_handle = wapi_prepare_interrupt_thread (thread->handle); + wait_handle = mono_thread_info_prepare_interrupt (thread->handle); /* fixme: store the state somewhere */ mono_thread_kill (thread, mono_thread_get_abort_signal ()); - wapi_finish_interrupt_thread (wait_handle); + mono_thread_info_finish_interrupt (wait_handle); #endif /* HOST_WIN32 */ } @@ -2956,9 +2957,7 @@ void mono_thread_manage (void) * to get correct user and system times from getrusage/wait/time(1)). * This could be removed if we avoid pthread_detach() and use pthread_join(). */ -#ifndef HOST_WIN32 mono_thread_info_yield (); -#endif } static void terminate_thread (gpointer key, gpointer value, gpointer user) @@ -3265,14 +3264,19 @@ mono_threads_perform_thread_dump (void) printf ("Full thread dump:\n"); - /* - * Make a copy of the hashtable since we can't do anything with - * threads while threads_mutex is held. - */ + /* We take the loader lock and the root domain lock as to increase our odds of not deadlocking if + something needs then in the process. + */ + mono_loader_lock (); + mono_domain_lock (mono_get_root_domain ()); + mono_threads_lock (); mono_g_hash_table_foreach (threads, dump_thread, NULL); mono_threads_unlock (); + mono_domain_unlock (mono_get_root_domain ()); + mono_loader_unlock (); + thread_dump_requested = FALSE; } @@ -4110,10 +4114,8 @@ static MonoException* mono_thread_execute_interruption (MonoInternalThread *thre WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE); #endif InterlockedDecrement (&thread_interruption_requested); -#ifndef HOST_WIN32 /* Clear the interrupted flag of the thread so it can wait again */ - wapi_clear_interruption (); -#endif + mono_thread_info_clear_interruption (); } if ((thread->state & ThreadState_AbortRequested) != 0) { @@ -4195,7 +4197,7 @@ mono_thread_request_interruption (gboolean running_managed) if (mono_thread_notify_pending_exc_fn && !running_managed) /* The JIT will notify the thread about the interruption */ /* This shouldn't take any locks */ - mono_thread_notify_pending_exc_fn (); + mono_thread_notify_pending_exc_fn (NULL); /* this will awake the thread if it is in WaitForSingleObject or similar */ @@ -4203,7 +4205,7 @@ mono_thread_request_interruption (gboolean running_managed) #ifdef HOST_WIN32 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, (ULONG_PTR)NULL); #else - wapi_self_interrupt (); + mono_thread_info_self_interrupt (); #endif return NULL; } @@ -4236,9 +4238,8 @@ mono_thread_resume_interruption (void) return NULL; InterlockedIncrement (&thread_interruption_requested); -#ifndef HOST_WIN32 - wapi_self_interrupt (); -#endif + mono_thread_info_self_interrupt (); + return mono_thread_execute_interruption (thread); } @@ -4555,9 +4556,7 @@ abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, MonoException *exc = mono_thread_request_interruption (can_raise_exception); if (exc) mono_raise_exception (exc); -#ifndef HOST_WIN32 - wapi_interrupt_thread (thread->handle); -#endif + mono_thread_info_interrupt (thread->handle); return; } @@ -4596,14 +4595,15 @@ abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, * functions in the io-layer until the signal handler calls QueueUserAPC which will * make it return. */ -#ifndef HOST_WIN32 gpointer interrupt_handle; - interrupt_handle = wapi_prepare_interrupt_thread (thread->handle); -#endif + + if (mono_thread_notify_pending_exc_fn) + /* The JIT will notify the thread about the interruption */ + mono_thread_notify_pending_exc_fn (info); + + interrupt_handle = mono_thread_info_prepare_interrupt (thread->handle); mono_thread_info_finish_suspend_and_resume (info); -#ifndef HOST_WIN32 - wapi_finish_interrupt_thread (interrupt_handle); -#endif + mono_thread_info_finish_interrupt (interrupt_handle); } /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/ } @@ -4656,21 +4656,18 @@ suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt) if (running_managed && !protected_wrapper) { transition_to_suspended (thread, info); } else { -#ifndef HOST_WIN32 gpointer interrupt_handle; -#endif if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0) InterlockedIncrement (&thread_interruption_requested); -#ifndef HOST_WIN32 if (interrupt) - interrupt_handle = wapi_prepare_interrupt_thread (thread->handle); -#endif + interrupt_handle = mono_thread_info_prepare_interrupt (thread->handle); + if (mono_thread_notify_pending_exc_fn && !running_managed) + /* The JIT will notify the thread about the interruption */ + mono_thread_notify_pending_exc_fn (info); mono_thread_info_finish_suspend_and_resume (info); -#ifndef HOST_WIN32 if (interrupt) - wapi_finish_interrupt_thread (interrupt_handle); -#endif + mono_thread_info_finish_interrupt (interrupt_handle); UNLOCK_THREAD (thread); } } diff --git a/mono/metadata/verify.c b/mono/metadata/verify.c index 50781a4bbf4..95bde8efbc5 100644 --- a/mono/metadata/verify.c +++ b/mono/metadata/verify.c @@ -1004,11 +1004,13 @@ verifier_load_type (VerifyContext *ctx, int token, const char *opcode) { MonoClass *class = mono_method_get_wrapper_data (ctx->method, (guint32)token); type = class ? &class->byval_arg : NULL; } else { + MonoError error; if (!IS_TYPE_DEF_OR_REF_OR_SPEC (token) || !token_bounds_check (ctx->image, token)) { ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid type token 0x%08x at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE); return NULL; } - type = mono_type_get_full (ctx->image, token, ctx->generic_context); + type = mono_type_get_checked (ctx->image, token, ctx->generic_context, &error); + mono_error_cleanup (&error); /*FIXME don't swallow the error */ } if (!type || mono_loader_get_last_error ()) { diff --git a/mono/mini/Makefile.am.in b/mono/mini/Makefile.am.in index f928eec806d..d43605ce620 100755 --- a/mono/mini/Makefile.am.in +++ b/mono/mini/Makefile.am.in @@ -83,8 +83,6 @@ libmonoldflags=$(monoldflags) -version-info 1:0:0 endif endif -if JIT_SUPPORTED - if SUPPORT_SGEN sgen_binaries = mono-sgen sgen_libraries = libmonosgen-2.0.la @@ -166,8 +164,6 @@ libmono_llvm_la_LIBADD += $(top_builddir)/mono/mini/libmonoboehm-$(API_VER).la $ endif endif -endif - mono_boehm_SOURCES = \ main.c @@ -195,6 +191,8 @@ buildver-boehm.h: libmini-static.la $(monodir)/mono/metadata/libmonoruntime-stat 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 @@ -204,6 +202,8 @@ buildver-sgen.h: libmini-static.la $(monodir)/mono/metadata/libmonoruntimesgen-s 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) @@ -344,6 +344,7 @@ sparc_sources = \ s390x_sources = \ mini-s390x.c \ mini-s390x.h \ + support-s390x.h \ exceptions-s390x.c \ tramp-s390x.c @@ -726,11 +727,7 @@ clean-local: 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 \ diff --git a/mono/mini/aot-compiler.c b/mono/mini/aot-compiler.c index 3c805ddae8c..44812084153 100644 --- a/mono/mini/aot-compiler.c +++ b/mono/mini/aot-compiler.c @@ -10,17 +10,6 @@ * Copyright 2011 Xamarin Inc (http://www.xamarin.com) */ -/* Remaining AOT-only work: - * - optimize the trampolines, generate more code in the arch files. - * - make things more consistent with how elf works, for example, use ELF - * relocations. - * Remaining generics sharing work: - * - optimize the size of the data which is encoded. - * - optimize the runtime loading of data: - * - the trampoline code calls mono_jit_info_table_find () to find the rgctx, - * which loads the debugging+exception handling info for the method. This is a - * huge waste of time and code, since the rgctx structure is currently empty. - */ #include "config.h" #include #ifdef HAVE_UNISTD_H @@ -42,7 +31,6 @@ #include #include - #include #include #include @@ -136,6 +124,7 @@ typedef struct MonoAotOptions { gboolean use_trampolines_page; gboolean no_instances; gboolean gnu_asm; + gboolean llvm; int nthreads; int ntrampolines; int nrgctx_trampolines; @@ -149,6 +138,7 @@ typedef struct MonoAotOptions { char *mtriple; char *llvm_path; char *instances_logfile_path; + char *logfile; } MonoAotOptions; typedef struct MonoAotStats { @@ -244,6 +234,7 @@ typedef struct MonoAotCompile { int objc_selector_index, objc_selector_index_2; GPtrArray *objc_selectors; GHashTable *objc_selector_to_index; + FILE *logfile; FILE *instances_logfile; } MonoAotCompile; @@ -303,6 +294,38 @@ get_patch_name (int info) static char* get_plt_entry_debug_sym (MonoAotCompile *acfg, MonoJumpInfo *ji, GHashTable *cache); +static void +aot_printf (MonoAotCompile *acfg, const gchar *format, ...) +{ + FILE *output; + va_list args; + + if (acfg->logfile) + output = acfg->logfile; + else + output = stdout; + + va_start (args, format); + vfprintf (output, format, args); + va_end (args); +} + +static void +aot_printerrf (MonoAotCompile *acfg, const gchar *format, ...) +{ + FILE *output; + va_list args; + + if (acfg->logfile) + output = acfg->logfile; + else + output = stderr; + + va_start (args, format); + vfprintf (output, format, args); + va_end (args); +} + /* Wrappers around the image writer functions */ static inline void @@ -667,6 +690,10 @@ arch_init (MonoAotCompile *acfg) acfg->llvm_label_prefix = ""; acfg->user_symbol_prefix = ""; +#if defined(TARGET_X86) + g_string_append (acfg->llc_args, " -march=x86 -mattr=sse4.1"); +#endif + #if defined(TARGET_AMD64) g_string_append (acfg->llc_args, " -march=x86-64 -mattr=sse4.1"); #endif @@ -1235,6 +1262,11 @@ arch_emit_specific_trampoline_pages (MonoAotCompile *acfg) g_assert (code - buf == 8); emit_bytes (acfg, buf, code - buf); } + + acfg->tramp_page_code_offsets [MONO_AOT_TRAMP_SPECIFIC] = 16; + acfg->tramp_page_code_offsets [MONO_AOT_TRAMP_STATIC_RGCTX] = 16; + acfg->tramp_page_code_offsets [MONO_AOT_TRAMP_IMT_THUNK] = 72; + acfg->tramp_page_code_offsets [MONO_AOT_TRAMP_GSHAREDVT_ARG] = 16; #elif defined(TARGET_ARM64) arm64_emit_specific_trampoline_pages (acfg); #endif @@ -2299,7 +2331,9 @@ find_typespec_for_class (MonoAotCompile *acfg, MonoClass *klass) if (!acfg->typespec_classes) { acfg->typespec_classes = mono_mempool_alloc0 (acfg->mempool, sizeof (MonoClass*) * len); for (i = 0; i < len; ++i) { - acfg->typespec_classes [i] = mono_class_get_full (acfg->image, MONO_TOKEN_TYPE_SPEC | (i + 1), NULL); + MonoError error; + acfg->typespec_classes [i] = mono_class_get_and_inflate_typespec_checked (acfg->image, MONO_TOKEN_TYPE_SPEC | (i + 1), NULL, &error); + g_assert (mono_error_ok (&error)); /* FIXME error handling */ } } for (i = 0; i < len; ++i) { @@ -3113,7 +3147,7 @@ add_extra_method_with_depth (MonoAotCompile *acfg, MonoMethod *method, int depth method = mini_get_shared_method (method); if (acfg->aot_opts.log_generics) - printf ("%*sAdding method %s.\n", depth, "", mono_method_full_name (method, TRUE)); + aot_printf (acfg, "%*sAdding method %s.\n", depth, "", mono_method_full_name (method, TRUE)); add_method_full (acfg, method, TRUE, depth); } @@ -3330,8 +3364,9 @@ add_wrappers (MonoAotCompile *acfg) 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 @@ -3503,14 +3538,15 @@ add_wrappers (MonoAotCompile *acfg) /* delegate-invoke wrappers */ for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPEDEF].rows; ++i) { + MonoError error; MonoClass *klass; MonoCustomAttrInfo *cattr; token = MONO_TOKEN_TYPE_DEF | (i + 1); - klass = mono_class_get (acfg->image, token); + klass = mono_class_get_checked (acfg->image, token, &error); if (!klass) { - mono_loader_clear_error (); + mono_error_cleanup (&error); continue; } @@ -3591,13 +3627,14 @@ add_wrappers (MonoAotCompile *acfg) /* array access wrappers */ for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPESPEC].rows; ++i) { + MonoError error; MonoClass *klass; token = MONO_TOKEN_TYPE_SPEC | (i + 1); - klass = mono_class_get (acfg->image, token); + klass = mono_class_get_checked (acfg->image, token, &error); if (!klass) { - mono_loader_clear_error (); + mono_error_cleanup (&error); continue; } @@ -3774,13 +3811,14 @@ add_wrappers (MonoAotCompile *acfg) /* StructureToPtr/PtrToStructure wrappers */ for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPEDEF].rows; ++i) { + MonoError error; MonoClass *klass; token = MONO_TOKEN_TYPE_DEF | (i + 1); - klass = mono_class_get (acfg->image, token); + klass = mono_class_get_checked (acfg->image, token, &error); if (!klass) { - mono_loader_clear_error (); + mono_error_cleanup (&error); continue; } @@ -3821,7 +3859,7 @@ is_vt_inst (MonoGenericInst *inst) for (i = 0; i < inst->type_argc; ++i) { MonoType *t = inst->type_argv [i]; - if (t->type == MONO_TYPE_VALUETYPE) + if (MONO_TYPE_ISSTRUCT (t) || t->type == MONO_TYPE_VALUETYPE) return TRUE; } return FALSE; @@ -3929,7 +3967,7 @@ add_generic_class_with_depth (MonoAotCompile *acfg, MonoClass *klass, int depth, return; if (acfg->aot_opts.log_generics) - printf ("%*sAdding generic instance %s [%s].\n", depth, "", mono_type_full_name (&klass->byval_arg), ref); + aot_printf (acfg, "%*sAdding generic instance %s [%s].\n", depth, "", mono_type_full_name (&klass->byval_arg), ref); g_hash_table_insert (acfg->ginst_hash, klass, klass); @@ -3979,7 +4017,7 @@ add_generic_class_with_depth (MonoAotCompile *acfg, MonoClass *klass, int depth, method = mono_marshal_get_delegate_invoke (method, NULL); if (acfg->aot_opts.log_generics) - printf ("%*sAdding method %s.\n", depth, "", mono_method_full_name (method, TRUE)); + aot_printf (acfg, "%*sAdding method %s.\n", depth, "", mono_method_full_name (method, TRUE)); add_method (acfg, method); } @@ -4239,13 +4277,14 @@ add_generic_instances (MonoAotCompile *acfg) } for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPESPEC].rows; ++i) { + MonoError error; MonoClass *klass; token = MONO_TOKEN_TYPE_SPEC | (i + 1); - klass = mono_class_get (acfg->image, token); + klass = mono_class_get_checked (acfg->image, token, &error); if (!klass || klass->rank) { - mono_loader_clear_error (); + mono_error_cleanup (&error); continue; } @@ -4833,13 +4872,14 @@ get_debug_sym (MonoMethod *method, const char *prefix, GHashTable *cache) char *name1, *name2, *cached; int i, j, len, count; + name1 = mono_method_full_name (method, TRUE); + #ifdef TARGET_MACH // This is so that we don't accidentally create a local symbol (which starts with 'L') - if (!prefix || !*prefix) + if ((!prefix || !*prefix) && name1 [0] == 'L') prefix = "_"; #endif - name1 = mono_method_full_name (method, TRUE); len = strlen (name1); name2 = malloc (strlen (prefix) + len + 16); memcpy (name2, prefix, strlen (prefix)); @@ -4962,7 +5002,9 @@ encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR: case MONO_PATCH_INFO_JIT_TLS_ID: case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR: + break; case MONO_PATCH_INFO_CASTCLASS_CACHE: + encode_value (patch_info->data.index, p, &p); break; case MONO_PATCH_INFO_METHOD_REL: encode_value ((gint)patch_info->data.offset, p, &p); @@ -5333,18 +5375,7 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg) encoded = mono_unwind_ops_encode (cfg->unwind_ops, &encoded_len); unwind_desc = get_unwind_info_offset (acfg, encoded, encoded_len); - g_assert (unwind_desc < 0xffff); - if (cfg->has_unwind_info_for_epilog) { - /* - * The lower 16 bits identify the unwind descriptor, the upper 16 bits contain the offset of - * the start of the epilog from the end of the method. - */ - g_assert (cfg->code_size - cfg->epilog_begin < 0xffff); - encode_value (((cfg->code_size - cfg->epilog_begin) << 16) | unwind_desc, p, &p); - g_free (encoded); - } else { - encode_value (unwind_desc, p, &p); - } + encode_value (unwind_desc, p, &p); } else { encode_value (jinfo->unwind_info, p, &p); } @@ -5443,6 +5474,7 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg) eh_info = mono_jit_info_get_arch_eh_info (jinfo); encode_value (eh_info->stack_size, p, &p); + encode_value (eh_info->epilog_size, p, &p); } if (jinfo->has_generic_jit_info) { @@ -5576,14 +5608,15 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg) static guint32 emit_klass_info (MonoAotCompile *acfg, guint32 token) { - MonoClass *klass = mono_class_get (acfg->image, token); + MonoError error; + MonoClass *klass = mono_class_get_checked (acfg->image, token, &error); guint8 *p, *buf; int i, buf_size, res; gboolean no_special_static, cant_encode; gpointer iter = NULL; if (!klass) { - mono_loader_clear_error (); + mono_error_cleanup (&error); buf_size = 16; @@ -5737,41 +5770,16 @@ emit_plt (MonoAotCompile *acfg) 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); @@ -5811,9 +5819,6 @@ emit_plt (MonoAotCompile *acfg) 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; @@ -6361,10 +6366,14 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts) opts->instances_logfile_path = g_strdup (arg + strlen ("log-instances=")); } else if (str_begins_with (arg, "log-instances")) { opts->log_instances = TRUE; + } else if (str_begins_with (arg, "internal-logfile=")) { + opts->logfile = g_strdup (arg + strlen ("internal-logfile=")); } else if (str_begins_with (arg, "mtriple=")) { opts->mtriple = g_strdup (arg + strlen ("mtriple=")); } else if (str_begins_with (arg, "llvm-path=")) { opts->llvm_path = g_strdup (arg + strlen ("llvm-path=")); + } else if (!strcmp (arg, "llvm")) { + opts->llvm = TRUE; } else if (str_begins_with (arg, "readonly-value=")) { add_readonly_value (opts, arg + strlen ("readonly-value=")); } else if (str_begins_with (arg, "info")) { @@ -6422,9 +6431,10 @@ add_token_info_hash (gpointer key, gpointer value, gpointer user_data) { 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); @@ -6552,6 +6562,7 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method) gboolean skip; int index, depth; MonoMethod *wrapped; + JitFlags flags; if (acfg->aot_opts.metadata_only) return; @@ -6596,7 +6607,12 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method) * the runtime will not see AOT methods during AOT compilation,so it * does not need to support them by creating a fake GOT etc. */ - cfg = mini_method_compile (method, acfg->opts, mono_get_root_domain (), acfg->aot_opts.full_aot ? (JIT_FLAG_AOT|JIT_FLAG_FULL_AOT) : (JIT_FLAG_AOT), 0); + flags = JIT_FLAG_AOT; + if (acfg->aot_opts.full_aot) + flags |= JIT_FLAG_FULL_AOT; + if (acfg->llvm) + flags |= JIT_FLAG_LLVM; + cfg = mini_method_compile (method, acfg->opts, mono_get_root_domain (), flags, 0); mono_loader_clear_error (); if (cfg->exception_type == MONO_EXCEPTION_GENERIC_SHARING_FAILED) { @@ -6637,6 +6653,8 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method) 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. @@ -6975,6 +6993,21 @@ mono_aot_get_method_name (MonoCompile *cfg) 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) { @@ -7024,7 +7057,7 @@ mono_aot_patch_info_dup (MonoJumpInfo* ji) * Emit the LLVM code into an LLVM bytecode file, and compile it using the LLVM * tools. */ -static void +static gboolean emit_llvm_file (MonoAotCompile *acfg) { char *command, *opts, *tempbc; @@ -7070,7 +7103,7 @@ emit_llvm_file (MonoAotCompile *acfg) tempbc = g_strdup_printf ("%s.bc", acfg->tmpbasename); - mono_llvm_emit_aot_module (tempbc, acfg->final_got_size); + mono_llvm_emit_aot_module (tempbc, g_path_get_basename (acfg->image->name), acfg->final_got_size); g_free (tempbc); /* @@ -7104,10 +7137,9 @@ emit_llvm_file (MonoAotCompile *acfg) opts = g_strdup ("-targetlibinfo -no-aa -basicaa -notti -instcombine -simplifycfg -sroa -domtree -early-cse -lazy-value-info -correlated-propagation -simplifycfg -instcombine -simplifycfg -reassociate -domtree -loops -loop-simplify -lcssa -loop-rotate -licm -lcssa -loop-unswitch -instcombine -scalar-evolution -loop-simplify -lcssa -indvars -loop-idiom -loop-deletion -loop-unroll -memdep -gvn -memdep -memcpyopt -sccp -instcombine -lazy-value-info -correlated-propagation -domtree -memdep -adce -simplifycfg -instcombine -strip-dead-prototypes -domtree -verify"); #if 1 command = g_strdup_printf ("%sopt -f %s -o \"%s.opt.bc\" \"%s.bc\"", acfg->aot_opts.llvm_path, opts, acfg->tmpbasename, acfg->tmpbasename); - printf ("Executing opt: %s\n", command); - if (system (command) != 0) { - exit (1); - } + aot_printf (acfg, "Executing opt: %s\n", command); + if (system (command) != 0) + return FALSE; #endif g_free (opts); @@ -7133,11 +7165,11 @@ emit_llvm_file (MonoAotCompile *acfg) command = g_strdup_printf ("%sllc %s -disable-gnu-eh-frame -enable-mono-eh-frame -o \"%s\" \"%s.opt.bc\"", acfg->aot_opts.llvm_path, acfg->llc_args->str, acfg->tmpfname, acfg->tmpbasename); - printf ("Executing llc: %s\n", command); + aot_printf (acfg, "Executing llc: %s\n", command); - if (system (command) != 0) { - exit (1); - } + if (system (command) != 0) + return FALSE; + return TRUE; } #endif @@ -7810,10 +7842,11 @@ emit_class_name_table (MonoAotCompile *acfg) for (i = 0; i < table_size; ++i) g_ptr_array_add (table, NULL); for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPEDEF].rows; ++i) { + MonoError error; token = MONO_TOKEN_TYPE_DEF | (i + 1); - klass = mono_class_get (acfg->image, token); + klass = mono_class_get_checked (acfg->image, token, &error); if (!klass) { - mono_loader_clear_error (); + mono_error_cleanup (&error); continue; } full_name = mono_type_get_name_full (mono_class_get_type (klass), MONO_TYPE_NAME_FORMAT_FULL_NAME); @@ -8381,7 +8414,7 @@ emit_dwarf_info (MonoAotCompile *acfg) #endif } -static void +static gboolean collect_methods (MonoAotCompile *acfg) { int mindex, i; @@ -8395,9 +8428,9 @@ collect_methods (MonoAotCompile *acfg) method = mono_get_method (acfg->image, token, NULL); if (!method) { - printf ("Failed to load method 0x%x from '%s'.\n", token, image->name); - printf ("Run with MONO_LOG_LEVEL=debug for more information.\n"); - exit (1); + aot_printerrf (acfg, "Failed to load method 0x%x from '%s'.\n", token, image->name); + aot_printerrf (acfg, "Run with MONO_LOG_LEVEL=debug for more information.\n"); + return FALSE; } /* Load all methods eagerly to skip the slower lazy loading code */ @@ -8461,6 +8494,7 @@ collect_methods (MonoAotCompile *acfg) if (acfg->aot_opts.full_aot) add_wrappers (acfg); + return TRUE; } static void @@ -8573,9 +8607,9 @@ compile_asm (MonoAotCompile *acfg) #endif if (acfg->aot_opts.asm_only) { - printf ("Output file: '%s'.\n", acfg->tmpfname); + aot_printf (acfg, "Output file: '%s'.\n", acfg->tmpfname); if (acfg->aot_opts.static_link) - printf ("Linking symbol: '%s'.\n", acfg->static_linking_symbol); + aot_printf (acfg, "Linking symbol: '%s'.\n", acfg->static_linking_symbol); return 0; } @@ -8588,7 +8622,7 @@ compile_asm (MonoAotCompile *acfg) objfile = g_strdup_printf ("%s.o", acfg->tmpfname); } command = g_strdup_printf ("%s%s %s %s -o %s %s", tool_prefix, AS_NAME, AS_OPTIONS, acfg->as_args ? acfg->as_args->str : "", objfile, acfg->tmpfname); - printf ("Executing the native assembler: %s\n", command); + aot_printf (acfg, "Executing the native assembler: %s\n", command); if (system (command) != 0) { g_free (command); g_free (objfile); @@ -8598,8 +8632,8 @@ compile_asm (MonoAotCompile *acfg) g_free (command); if (acfg->aot_opts.static_link) { - printf ("Output file: '%s'.\n", objfile); - printf ("Linking symbol: '%s'.\n", acfg->static_linking_symbol); + aot_printf (acfg, "Output file: '%s'.\n", objfile); + aot_printf (acfg, "Linking symbol: '%s'.\n", acfg->static_linking_symbol); g_free (objfile); return 0; } @@ -8616,7 +8650,7 @@ compile_asm (MonoAotCompile *acfg) #else command = g_strdup_printf ("%sld %s -shared -o %s %s.o", tool_prefix, LD_OPTIONS, tmp_outfile_name, acfg->tmpfname); #endif - printf ("Executing the native linker: %s\n", command); + aot_printf (acfg, "Executing the native linker: %s\n", command); if (system (command) != 0) { g_free (tmp_outfile_name); g_free (outfile_name); @@ -8638,7 +8672,7 @@ compile_asm (MonoAotCompile *acfg) * happens a lot in emit_and_reloc_code (), so we need to get rid of them. */ command = g_strdup_printf ("%sstrip --strip-symbol=\\$a --strip-symbol=\\$d %s", tool_prefix, tmp_outfile_name); - printf ("Stripping the binary: %s\n", command); + aot_printf (acfg, "Stripping the binary: %s\n", command); if (system (command) != 0) { g_free (tmp_outfile_name); g_free (outfile_name); @@ -8652,7 +8686,7 @@ compile_asm (MonoAotCompile *acfg) #if defined(TARGET_MACH) command = g_strdup_printf ("dsymutil %s", outfile_name); - printf ("Executing dsymutil: %s\n", command); + aot_printf (acfg, "Executing dsymutil: %s\n", command); if (system (command) != 0) { return 1; } @@ -8666,7 +8700,7 @@ compile_asm (MonoAotCompile *acfg) g_free (objfile); if (acfg->aot_opts.save_temps) - printf ("Retained input file.\n"); + aot_printf (acfg, "Retained input file.\n"); else unlink (acfg->tmpfname); @@ -8692,7 +8726,7 @@ acfg_create (MonoAssembly *ass, guint32 opts) 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 (); @@ -8771,15 +8805,6 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) TV_DECLARE (atv); TV_DECLARE (btv); -#if !defined(MONO_ARCH_GSHAREDVT_SUPPORTED) || !defined(ENABLE_GSHAREDVT) - if (opts & MONO_OPT_GSHAREDVT) { - fprintf (stderr, "-O=gsharedvt not supported on this platform.\n"); - exit (1); - } -#endif - - printf ("Mono Ahead of Time compiler - compiling assembly %s\n", image->name); - acfg = acfg_create (ass, opts); memset (&acfg->aot_opts, 0, sizeof (acfg->aot_opts)); @@ -8796,21 +8821,34 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) mono_aot_parse_options (aot_options, &acfg->aot_opts); + if (acfg->aot_opts.logfile) { + acfg->logfile = fopen (acfg->aot_opts.logfile, "a+"); + } + if (acfg->aot_opts.static_link) acfg->aot_opts.autoreg = TRUE; //acfg->aot_opts.print_skipped_methods = TRUE; +#if !defined(MONO_ARCH_GSHAREDVT_SUPPORTED) || !defined(ENABLE_GSHAREDVT) + if (opts & MONO_OPT_GSHAREDVT) { + aot_printerrf (acfg, "-O=gsharedvt not supported on this platform.\n"); + return 1; + } +#endif + + aot_printf (acfg, "Mono Ahead of Time compiler - compiling assembly %s\n", image->name); + #ifndef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES if (acfg->aot_opts.full_aot) { - printf ("--aot=full is not supported on this platform.\n"); + aot_printerrf (acfg, "--aot=full is not supported on this platform.\n"); return 1; } #endif if (acfg->aot_opts.direct_pinvoke && !acfg->aot_opts.static_link) { - fprintf (stderr, "The 'direct-pinvoke' AOT option also requires the 'static' AOT option.\n"); - exit (1); + aot_printerrf (acfg, "The 'direct-pinvoke' AOT option also requires the 'static' AOT option.\n"); + return 1; } if (acfg->aot_opts.static_link) @@ -8823,21 +8861,23 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) opt->gen_seq_points = TRUE; if (!mono_debug_enabled ()) { - fprintf (stderr, "The soft-debug AOT option requires the --debug option.\n"); + aot_printerrf (acfg, "The soft-debug AOT option requires the --debug option.\n"); return 1; } acfg->flags |= MONO_AOT_FILE_FLAG_DEBUG; } - if (mono_use_llvm) { + if (mono_use_llvm || acfg->aot_opts.llvm) { acfg->llvm = TRUE; acfg->aot_opts.asm_writer = TRUE; acfg->flags |= MONO_AOT_FILE_FLAG_WITH_LLVM; if (acfg->aot_opts.soft_debug) { - fprintf (stderr, "The 'soft-debug' option is not supported when compiling with LLVM.\n"); - exit (1); + aot_printerrf (acfg, "The 'soft-debug' option is not supported when compiling with LLVM.\n"); + return 1; } + + mini_llvm_init (); } if (acfg->aot_opts.full_aot) @@ -8846,8 +8886,8 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) if (acfg->aot_opts.instances_logfile_path) { acfg->instances_logfile = fopen (acfg->aot_opts.instances_logfile_path, "w"); if (!acfg->instances_logfile) { - fprintf (stderr, "Unable to create logfile: '%s'.\n", acfg->aot_opts.instances_logfile_path); - exit (1); + aot_printerrf (acfg, "Unable to create logfile: '%s'.\n", acfg->aot_opts.instances_logfile_path); + return 1; } } @@ -8893,7 +8933,9 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) mono_set_partial_sharing_supported (TRUE); */ - collect_methods (acfg); + res = collect_methods (acfg); + if (!res) + return 1; acfg->cfgs_size = acfg->methods->len + 32; acfg->cfgs = g_new0 (MonoCompile*, acfg->cfgs_size); @@ -8945,6 +8987,8 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) #ifdef ENABLE_LLVM if (acfg->llvm) { + gboolean res; + if (acfg->aot_opts.asm_only) { if (acfg->aot_opts.outfile) { acfg->tmpfname = g_strdup_printf ("%s", acfg->aot_opts.outfile); @@ -8958,7 +9002,9 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) acfg->tmpfname = g_strdup_printf ("%s.s", acfg->tmpbasename); } - emit_llvm_file (acfg); + res = emit_llvm_file (acfg); + if (!res) + return 1; } #endif @@ -8976,7 +9022,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) acfg->fp = fopen (tmp_outfile_name, "w"); if (!acfg->fp) { - printf ("Unable to create temporary file '%s': %s\n", tmp_outfile_name, strerror (errno)); + aot_printf (acfg, "Unable to create temporary file '%s': %s\n", tmp_outfile_name, strerror (errno)); return 1; } @@ -9000,7 +9046,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) } } if (acfg->fp == 0) { - fprintf (stderr, "Unable to open file '%s': %s\n", acfg->tmpfname, strerror (errno)); + aot_printerrf (acfg, "Unable to open file '%s': %s\n", acfg->tmpfname, strerror (errno)); return 1; } acfg->w = img_writer_create (acfg->fp, FALSE); @@ -9037,7 +9083,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) if (!acfg->aot_opts.nodebug || acfg->aot_opts.dwarf_debug) { if (acfg->aot_opts.dwarf_debug && !mono_debug_enabled ()) { - fprintf (stderr, "The dwarf AOT option requires the --debug option.\n"); + aot_printerrf (acfg, "The dwarf AOT option requires the --debug option.\n"); return 1; } acfg->dwarf = mono_dwarf_writer_create (acfg->w, NULL, 0, FALSE, !acfg->gas_line_numbers); @@ -9125,7 +9171,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) all_sizes = acfg->stats.code_size + acfg->stats.info_size + acfg->stats.ex_info_size + acfg->stats.unwind_info_size + acfg->stats.class_info_size + acfg->stats.got_info_size + acfg->stats.offsets_size + acfg->stats.plt_size; - printf ("Code: %d(%d%%) Info: %d(%d%%) Ex Info: %d(%d%%) Unwind Info: %d(%d%%) Class Info: %d(%d%%) PLT: %d(%d%%) GOT Info: %d(%d%%) Offsets: %d(%d%%) GOT: %d\n", + aot_printf (acfg, "Code: %d(%d%%) Info: %d(%d%%) Ex Info: %d(%d%%) Unwind Info: %d(%d%%) Class Info: %d(%d%%) PLT: %d(%d%%) GOT Info: %d(%d%%) Offsets: %d(%d%%) GOT: %d\n", acfg->stats.code_size, acfg->stats.code_size * 100 / all_sizes, acfg->stats.info_size, acfg->stats.info_size * 100 / all_sizes, acfg->stats.ex_info_size, acfg->stats.ex_info_size * 100 / all_sizes, @@ -9135,19 +9181,19 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) acfg->stats.got_info_size, acfg->stats.got_info_size * 100 / all_sizes, acfg->stats.offsets_size, acfg->stats.offsets_size * 100 / all_sizes, (int)(acfg->got_offset * sizeof (gpointer))); - printf ("Compiled: %d/%d (%d%%)%s, No GOT slots: %d (%d%%), Direct calls: %d (%d%%)\n", + aot_printf (acfg, "Compiled: %d/%d (%d%%)%s, No GOT slots: %d (%d%%), Direct calls: %d (%d%%)\n", acfg->stats.ccount, acfg->stats.mcount, acfg->stats.mcount ? (acfg->stats.ccount * 100) / acfg->stats.mcount : 100, llvm_stats_msg, acfg->stats.methods_without_got_slots, acfg->stats.mcount ? (acfg->stats.methods_without_got_slots * 100) / acfg->stats.mcount : 100, acfg->stats.direct_calls, acfg->stats.all_calls ? (acfg->stats.direct_calls * 100) / acfg->stats.all_calls : 100); if (acfg->stats.genericcount) - printf ("%d methods are generic (%d%%)\n", acfg->stats.genericcount, acfg->stats.mcount ? (acfg->stats.genericcount * 100) / acfg->stats.mcount : 100); + aot_printf (acfg, "%d methods are generic (%d%%)\n", acfg->stats.genericcount, acfg->stats.mcount ? (acfg->stats.genericcount * 100) / acfg->stats.mcount : 100); if (acfg->stats.abscount) - printf ("%d methods contain absolute addresses (%d%%)\n", acfg->stats.abscount, acfg->stats.mcount ? (acfg->stats.abscount * 100) / acfg->stats.mcount : 100); + aot_printf (acfg, "%d methods contain absolute addresses (%d%%)\n", acfg->stats.abscount, acfg->stats.mcount ? (acfg->stats.abscount * 100) / acfg->stats.mcount : 100); if (acfg->stats.lmfcount) - printf ("%d methods contain lmf pointers (%d%%)\n", acfg->stats.lmfcount, acfg->stats.mcount ? (acfg->stats.lmfcount * 100) / acfg->stats.mcount : 100); + aot_printf (acfg, "%d methods contain lmf pointers (%d%%)\n", acfg->stats.lmfcount, acfg->stats.mcount ? (acfg->stats.lmfcount * 100) / acfg->stats.mcount : 100); if (acfg->stats.ocount) - printf ("%d methods have other problems (%d%%)\n", acfg->stats.ocount, acfg->stats.mcount ? (acfg->stats.ocount * 100) / acfg->stats.mcount : 100); + aot_printf (acfg, "%d methods have other problems (%d%%)\n", acfg->stats.ocount, acfg->stats.mcount ? (acfg->stats.ocount * 100) / acfg->stats.mcount : 100); TV_GETTIME (atv); res = img_writer_emit_writeout (acfg->w); @@ -9159,7 +9205,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) int err = rename (tmp_outfile_name, outfile_name); if (err) { - printf ("Unable to rename '%s' to '%s': %s\n", tmp_outfile_name, outfile_name, strerror (errno)); + aot_printf (acfg, "Unable to rename '%s' to '%s': %s\n", tmp_outfile_name, outfile_name, strerror (errno)); return 1; } } else { @@ -9175,13 +9221,13 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) if (acfg->aot_opts.stats) { int i; - printf ("GOT slot distribution:\n"); + aot_printf (acfg, "GOT slot distribution:\n"); for (i = 0; i < MONO_PATCH_INFO_NONE; ++i) if (acfg->stats.got_slot_types [i]) - printf ("\t%s: %d (%d)\n", get_patch_name (i), acfg->stats.got_slot_types [i], acfg->stats.got_slot_info_sizes [i]); + aot_printf (acfg, "\t%s: %d (%d)\n", get_patch_name (i), acfg->stats.got_slot_types [i], acfg->stats.got_slot_info_sizes [i]); } - printf ("JIT time: %d ms, Generation time: %d ms, Assembly+Link time: %d ms.\n", acfg->stats.jit_time / 1000, acfg->stats.gen_time / 1000, acfg->stats.link_time / 1000); + aot_printf (acfg, "JIT time: %d ms, Generation time: %d ms, Assembly+Link time: %d ms.\n", acfg->stats.jit_time / 1000, acfg->stats.gen_time / 1000, acfg->stats.link_time / 1000); acfg_free (acfg); diff --git a/mono/mini/aot-runtime.c b/mono/mini/aot-runtime.c index f484f18364b..97d22706db0 100644 --- a/mono/mini/aot-runtime.c +++ b/mono/mini/aot-runtime.c @@ -176,6 +176,8 @@ static GHashTable *ji_to_amodule; */ static gboolean enable_aot_cache = FALSE; +static gboolean mscorlib_aot_loaded; + /* For debugging */ static gint32 mono_last_aot_method = -1; @@ -403,6 +405,7 @@ decode_generic_context (MonoAotModule *module, MonoGenericContext *ctx, guint8 * static MonoClass* decode_klass_ref (MonoAotModule *module, guint8 *buf, guint8 **endbuf) { + MonoError error; MonoImage *image; MonoClass *klass = NULL, *eklass; guint32 token, rank, idx; @@ -421,21 +424,24 @@ decode_klass_ref (MonoAotModule *module, guint8 *buf, guint8 **endbuf) image = load_image (module, 0, TRUE); if (!image) return NULL; - klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF + idx); + klass = mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF + idx, &error); + g_assert (mono_error_ok (&error)); break; case MONO_AOT_TYPEREF_TYPEDEF_INDEX_IMAGE: idx = decode_value (p, &p); image = load_image (module, decode_value (p, &p), TRUE); if (!image) return NULL; - klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF + idx); + klass = mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF + idx, &error); + g_assert (mono_error_ok (&error)); break; case MONO_AOT_TYPEREF_TYPESPEC_TOKEN: token = decode_value (p, &p); image = module->assembly->image; if (!image) return NULL; - klass = mono_class_get (image, token); + klass = mono_class_get_checked (image, token, &error); + g_assert (mono_error_ok (&error)); break; case MONO_AOT_TYPEREF_GINST: { MonoClass *gclass; @@ -1374,13 +1380,15 @@ aot_cache_load_module (MonoAssembly *assembly, char **aot_name) { MonoAotCacheConfig *config; GSList *l; - char *fname, *tmp2, *aot_options; + char *fname, *tmp2, *aot_options, *failure_fname; const char *home; MonoDl *module; gboolean res; gint exit_status; char *hash; int pid; + gboolean enabled; + FILE *failure_file; *aot_name = NULL; @@ -1389,13 +1397,34 @@ aot_cache_load_module (MonoAssembly *assembly, char **aot_name) /* Check in the list of assemblies enabled for aot caching */ config = mono_get_aot_cache_config (); - for (l = config->assemblies; l; l = l->next) { - char *n = l->data; - if (!strcmp (assembly->aname.name, n)) - break; + enabled = FALSE; + if (config->apps) { + MonoDomain *domain = mono_domain_get (); + MonoAssembly *entry_assembly = domain->entry_assembly; + + // FIXME: This cannot be used for mscorlib during startup, since entry_assembly is not set yet + for (l = config->apps; l; l = l->next) { + char *n = l->data; + + if ((entry_assembly && !strcmp (entry_assembly->aname.name, n)) || (!entry_assembly && !strcmp (assembly->aname.name, n))) + break; + } + if (l) + enabled = TRUE; } - if (!l) + + if (!enabled) { + for (l = config->assemblies; l; l = l->next) { + char *n = l->data; + + if (!strcmp (assembly->aname.name, n)) + break; + } + if (l) + enabled = TRUE; + } + if (!enabled) return NULL; if (!cache_dir) { @@ -1423,21 +1452,38 @@ aot_cache_load_module (MonoAssembly *assembly, char **aot_name) mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT: loading from cache: '%s'.", fname); module = mono_dl_open (fname, MONO_DL_LAZY, NULL); - if (module) + if (module) { + mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT: found in cache: '%s'.", fname); return module; + } - mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT: not found."); - - if (!strcmp (assembly->aname.name, "mscorlib") && !mono_defaults.corlib) - /* Can't AOT this during startup */ + if (!strcmp (assembly->aname.name, "mscorlib") && !mscorlib_aot_loaded) + /* + * Can't AOT this during startup, so we AOT it when called later from + * mono_aot_get_method (). + */ return NULL; + mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT: not found."); + /* Only AOT one assembly per run to avoid slowing down execution too much */ if (cache_count > 0) return NULL; cache_count ++; - mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT: compiling assembly '%s'... ", assembly->image->name); + /* Check for previous failure */ + failure_fname = g_strdup_printf ("%s.failure", fname); + failure_file = fopen (failure_fname, "r"); + if (failure_file) { + mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT: assembly '%s' previously failed to compile '%s' ('%s')... ", assembly->image->name, fname, failure_fname); + g_free (failure_fname); + return NULL; + } else { + g_free (failure_fname); + fclose (failure_file); + } + + mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT: compiling assembly '%s', logfile: '%s.log'... ", assembly->image->name, fname); /* * We need to invoke the AOT compiler here. There are multiple approaches: @@ -1448,16 +1494,18 @@ aot_cache_load_module (MonoAssembly *assembly, char **aot_name) * - fork a new process and do the work there. */ if (in_process) { - FILE *logfile; - char *logfile_name; - - logfile_name = g_strdup_printf ("%s/aot.log", cache_dir); - logfile = fopen (logfile_name, "a+"); - - aot_options = g_strdup_printf ("outfile=%s", fname); + aot_options = g_strdup_printf ("outfile=%s,internal-logfile=%s.log%s%s", fname, fname, config->aot_options ? "," : "", config->aot_options ? config->aot_options : ""); /* Maybe due this in another thread ? */ res = mono_compile_assembly (assembly, mono_parse_default_optimizations (NULL), aot_options); - // FIXME: Cache failures + if (res) { + mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT: compilation failed."); + failure_fname = g_strdup_printf ("%s.failure", fname); + failure_file = fopen (failure_fname, "a+"); + fclose (failure_file); + g_free (failure_fname); + } else { + mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT: compilation succeeded."); + } } else { /* * - Avoid waiting for the aot process to finish ? @@ -1705,10 +1753,6 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data) if (mono_security_cas_enabled ()) return; - if (enable_aot_cache && !strcmp (assembly->aname.name, "mscorlib") && !mono_defaults.corlib && !mono_aot_only) - /* Loaded later from mono_aot_get_method () */ - return; - mono_aot_lock (); if (static_aot_modules) info = g_hash_table_lookup (static_aot_modules, assembly->aname.name); @@ -2064,9 +2108,7 @@ mono_aot_init (void) if (g_getenv ("MONO_LASTAOT")) mono_last_aot_method = atoi (g_getenv ("MONO_LASTAOT")); -#ifdef ENABLE_AOT_CACHE aot_cache_init (); -#endif } void @@ -2258,8 +2300,11 @@ mono_aot_get_class_from_name (MonoImage *image, const char *name_space, const ch name_space2 = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]); if (!strcmp (name, name2) && !strcmp (name_space, name_space2)) { + MonoError error; amodule_unlock (amodule); - *klass = mono_class_get (image, token); + *klass = mono_class_get_checked (image, token, &error); + if (!mono_error_ok (&error)) + mono_error_cleanup (&error); /* FIXME don't swallow the error */ /* Add to cache */ if (*klass) { @@ -2299,7 +2344,8 @@ static MonoJitInfo* 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; @@ -2410,20 +2456,17 @@ decode_llvm_mono_eh_frame (MonoAotModule *amodule, MonoDomain *domain, * 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 */ @@ -2499,7 +2542,8 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain, { 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; @@ -2511,15 +2555,15 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain, 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); @@ -2527,13 +2571,16 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain, } 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; @@ -2543,10 +2590,12 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain, 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; @@ -2579,17 +2628,16 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain, } } - 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]; @@ -2616,25 +2664,11 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain, 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; @@ -2659,6 +2693,7 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain, eh_info = mono_jit_info_get_arch_eh_info (jinfo); eh_info->stack_size = decode_value (p, &p); + eh_info->epilog_size = decode_value (p, &p); } if (async) { @@ -2818,8 +2853,7 @@ mono_aot_get_unwind_info (MonoJitInfo *ji, guint32 *unwind_info_len) mono_aot_unlock (); } - /* The upper 16 bits of ji->unwind_info might contain the epilog offset */ - p = amodule->unwind_info + (ji->unwind_info & 0xffff); + p = amodule->unwind_info + ji->unwind_info; *unwind_info_len = decode_value (p, &p); return p; } @@ -3240,9 +3274,11 @@ decode_patch (MonoAotModule *aot_module, MonoMemPool *mp, MonoJumpInfo *ji, guin case MONO_PATCH_INFO_MONITOR_ENTER: case MONO_PATCH_INFO_MONITOR_EXIT: case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR: - case MONO_PATCH_INFO_CASTCLASS_CACHE: case MONO_PATCH_INFO_JIT_TLS_ID: break; + case MONO_PATCH_INFO_CASTCLASS_CACHE: + ji->data.index = decode_value (p, &p); + break; case MONO_PATCH_INFO_RGCTX_FETCH: { gboolean res; MonoJumpInfoRgctxEntry *entry; @@ -3429,8 +3465,12 @@ load_method (MonoDomain *domain, MonoAotModule *amodule, MonoImage *image, MonoM MonoJitInfo *jinfo = NULL; guint8 *code, *info; - if (mono_profiler_get_events () & MONO_PROFILE_ENTER_LEAVE) + if (mono_profiler_get_events () & MONO_PROFILE_ENTER_LEAVE) { + if (mono_aot_only) + /* The caller cannot handle this */ + g_assert_not_reached (); return NULL; + } if ((domain != mono_get_root_domain ()) && (!(amodule->info.opts & MONO_OPT_SHARED))) /* Non shared AOT code can't be used in other appdomains */ @@ -3761,10 +3801,13 @@ mono_aot_get_method (MonoDomain *domain, MonoMethod *method) MonoAotModule *amodule = klass->image->aot_module; guint8 *code; - if (enable_aot_cache && !amodule && klass->image == mono_defaults.corlib) { + if (enable_aot_cache && !amodule && domain->entry_assembly && klass->image == mono_defaults.corlib) { /* This cannot be AOTed during startup, so do it now */ - load_aot_module (klass->image->assembly, NULL); - amodule = klass->image->aot_module; + if (!mscorlib_aot_loaded) { + mscorlib_aot_loaded = TRUE; + load_aot_module (klass->image->assembly, NULL); + amodule = klass->image->aot_module; + } } if (!amodule) @@ -4433,13 +4476,6 @@ mono_aot_get_trampoline (const char *name) #include static TrampolinePage* trampoline_pages [MONO_AOT_TRAMP_NUM]; -/* these sizes are for ARM code, parametrize if porting to other architectures (see arch_emit_specific_trampoline_pages) - * trampoline size is assumed to be 8 bytes below as well (8 is the minimum for 32 bit archs, since we need to store - * two pointers for trampoline in the data page). - * the minimum for the common code must be at least sizeof(TrampolinePage), since we store the page info at the - * beginning of the data page. - */ -static const int trampolines_pages_code_offsets [MONO_AOT_TRAMP_NUM] = {16, 16, 72, 16}; static unsigned char* get_new_trampoline_from_page (int tramp_type) @@ -4528,11 +4564,7 @@ get_new_trampoline_from_page (int tramp_type) page = (TrampolinePage*)addr; page->next = trampoline_pages [tramp_type]; trampoline_pages [tramp_type] = page; -#ifdef TARGET_ARM64 page->trampolines = (void*)(taddr + amodule->info.tramp_page_code_offsets [tramp_type]); -#else - page->trampolines = (void*)(taddr + trampolines_pages_code_offsets [tramp_type]); -#endif page->trampolines_end = (void*)(taddr + psize - 64); code = page->trampolines; page->trampolines += specific_trampoline_size; diff --git a/mono/mini/branch-opts.c b/mono/mini/branch-opts.c index 44a78aa476b..2be95e73642 100644 --- a/mono/mini/branch-opts.c +++ b/mono/mini/branch-opts.c @@ -1299,7 +1299,7 @@ mono_optimize_branches (MonoCompile *cfg) /* 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); diff --git a/mono/mini/cpu-amd64.md b/mono/mini/cpu-amd64.md old mode 100644 new mode 100755 index bb6f32f9e6b..be535210a6d --- a/mono/mini/cpu-amd64.md +++ b/mono/mini/cpu-amd64.md @@ -114,7 +114,7 @@ cgt: dest:c len:8 cgt.un: dest:c len:8 clt: dest:c len:8 clt.un: dest:c len:8 -localloc: dest:i src1:i len:84 +localloc: dest:i src1:i len:96 compare: src1:i src2:i len:3 lcompare: src1:i src2:i len:3 icompare: src1:i src2:i len:3 @@ -511,7 +511,7 @@ vcall2_membase: src1:b len:64 clob:c dyn_call: src1:i src2:i len:64 clob:c nacl:128 -localloc_imm: dest:i len:84 +localloc_imm: dest:i len:96 load_mem: dest:i len:16 loadi8_mem: dest:i len:16 diff --git a/mono/mini/cpu-arm.md b/mono/mini/cpu-arm.md index 431936113c3..b31b368ec78 100644 --- a/mono/mini/cpu-arm.md +++ b/mono/mini/cpu-arm.md @@ -211,7 +211,7 @@ sbb_imm: dest:i src1:i len:12 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 diff --git a/mono/mini/cpu-arm64.md b/mono/mini/cpu-arm64.md index 7d9e40b2266..f45b72123aa 100644 --- a/mono/mini/cpu-arm64.md +++ b/mono/mini/cpu-arm64.md @@ -321,9 +321,9 @@ icompare_imm: src1:i len:12 long_conv_to_ovf_i4_2: dest:i src1:i src2:i len:36 -vcall2: len:32 clob:c -vcall2_reg: src1:i len:32 clob:c -vcall2_membase: src1:b len:32 clob:c +vcall2: len:40 clob:c +vcall2_reg: src1:i len:40 clob:c +vcall2_membase: src1:b len:40 clob:c dyn_call: src1:i src2:i len:120 clob:c # This is different from the original JIT opcodes diff --git a/mono/mini/cpu-s390x.md b/mono/mini/cpu-s390x.md index b3dce352ec6..2eee2e4e57d 100644 --- a/mono/mini/cpu-s390x.md +++ b/mono/mini/cpu-s390x.md @@ -283,6 +283,7 @@ long_xor: dest:i src1:i src2:i len:8 long_neg: dest:i src1:i len:6 long_not: dest:i src1:i len:12 long_rem: dest:i src1:i src2:i len:12 +long_rem_imm: dest:i src1:i src2:i len:12 long_rem_un: dest:i src1:i src2:i len:16 long_shl: dest:i src1:i src2:i len:14 long_shl_imm: dest:i src1:i len:14 diff --git a/mono/mini/debugger-agent.c b/mono/mini/debugger-agent.c index 59194301869..63e39501fe1 100644 --- a/mono/mini/debugger-agent.c +++ b/mono/mini/debugger-agent.c @@ -289,7 +289,7 @@ typedef struct { #define HEADER_LENGTH 11 #define MAJOR_VERSION 2 -#define MINOR_VERSION 36 +#define MINOR_VERSION 37 typedef enum { CMD_SET_VM = 1, @@ -403,7 +403,8 @@ typedef enum { INVOKE_FLAG_DISABLE_BREAKPOINTS = 1, INVOKE_FLAG_SINGLE_THREADED = 2, INVOKE_FLAG_RETURN_OUT_THIS = 4, - INVOKE_FLAG_RETURN_OUT_ARGS = 8 + INVOKE_FLAG_RETURN_OUT_ARGS = 8, + INVOKE_FLAG_VIRTUAL = 16 } InvokeFlags; typedef enum { @@ -2776,9 +2777,6 @@ notify_thread (gpointer key, gpointer value, gpointer user_data) #endif /* This is _not_ equivalent to ves_icall_System_Threading_Thread_Abort () */ -#ifdef HOST_WIN32 - QueueUserAPC (notify_thread_apc, thread->handle, (ULONG_PTR)NULL); -#else if (mono_thread_info_new_interrupt_enabled ()) { MonoThreadInfo *info; MonoJitInfo *ji; @@ -2798,6 +2796,10 @@ notify_thread (gpointer key, gpointer value, gpointer user_data) mono_thread_info_finish_suspend_and_resume (info); } } else { +#ifdef HOST_WIN32 + // FIXME: Remove this since new interrupt is used on win32 now + QueueUserAPC (notify_thread_apc, thread->handle, (ULONG_PTR)NULL); +#else res = mono_thread_kill (thread, mono_thread_get_abort_signal ()); if (res) { DEBUG(1, fprintf (log_file, "[%p] mono_thread_kill () failed for %p: %d...\n", (gpointer)GetCurrentThreadId (), (gpointer)tid, res)); @@ -2806,8 +2808,8 @@ notify_thread (gpointer key, gpointer value, gpointer user_data) */ tls->terminated = TRUE; } - } #endif + } } static void @@ -6564,6 +6566,12 @@ do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke, guint8 return ERR_INVALID_ARGUMENT; } m = mono_object_get_virtual_method (this, m); + } else if (invoke->flags & INVOKE_FLAG_VIRTUAL) { + if (!this) { + DEBUG (1, fprintf (log_file, "[%p] Error: invoke with INVOKE_FLAG_VIRTUAL flag set without this argument.\n", (gpointer)GetCurrentThreadId ())); + return ERR_INVALID_ARGUMENT; + } + m = mono_object_get_virtual_method (this, m); } DEBUG (1, fprintf (log_file, "[%p] Invoking method '%s' on receiver '%s'.\n", (gpointer)GetCurrentThreadId (), mono_method_full_name (m, TRUE), this ? this->vtable->klass->name : "")); diff --git a/mono/mini/decompose.c b/mono/mini/decompose.c index 07242d86138..f29e913acf9 100644 --- a/mono/mini/decompose.c +++ b/mono/mini/decompose.c @@ -470,7 +470,7 @@ mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins) } #endif MONO_EMIT_NEW_BIALU (cfg, ins->opcode, ins->dreg, ins->sreg1, ins->sreg2); - ins->opcode = OP_NOP; + NULLIFY_INS (ins); } else { emulate = TRUE; } @@ -486,6 +486,9 @@ mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins) ins->opcode = OP_ICONST; MONO_INST_NULLIFY_SREGS (ins); ins->inst_c0 = 0; +#if __s390__ + } +#else } else if ((ins->inst_imm > 0) && (ins->inst_imm < (1LL << 32)) && (power != -1)) { gboolean is_long = ins->opcode == OP_LREM_IMM; int compensator_reg = alloc_ireg (cfg); @@ -497,12 +500,12 @@ mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins) 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); @@ -511,6 +514,7 @@ mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins) NULLIFY_INS (ins); } +#endif break; } @@ -980,7 +984,7 @@ mono_decompose_long_opts (MonoCompile *cfg) 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: @@ -998,7 +1002,7 @@ mono_decompose_long_opts (MonoCompile *cfg) 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; @@ -1012,7 +1016,7 @@ mono_decompose_long_opts (MonoCompile *cfg) 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: @@ -1034,7 +1038,7 @@ mono_decompose_long_opts (MonoCompile *cfg) 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: @@ -1066,7 +1070,7 @@ mono_decompose_long_opts (MonoCompile *cfg) 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; } @@ -1085,7 +1089,7 @@ mono_decompose_long_opts (MonoCompile *cfg) 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; @@ -1099,7 +1103,7 @@ mono_decompose_long_opts (MonoCompile *cfg) 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: @@ -1121,7 +1125,7 @@ mono_decompose_long_opts (MonoCompile *cfg) 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: @@ -1330,18 +1334,18 @@ mono_decompose_vtype_opts (MonoCompile *cfg) 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); @@ -1367,12 +1371,19 @@ mono_decompose_vtype_opts (MonoCompile *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. diff --git a/mono/mini/driver.c b/mono/mini/driver.c index 2929e813a4d..c6c8e20628c 100644 --- a/mono/mini/driver.c +++ b/mono/mini/driver.c @@ -408,8 +408,7 @@ mini_regression_step (MonoImage *image, int verbose, int *total_run, int *total, } 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, ", @@ -1903,6 +1902,14 @@ mono_main (int argc, char* argv[]) 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); + } + mono_set_defaults (mini_verbose, opt); domain = mini_init (argv [i], forced_version); @@ -1968,11 +1975,6 @@ mono_main (int argc, char* argv[]) break; } - /* Parse gac loading options before loading assemblies. */ - if (mono_compile_aot || action == DO_EXEC || action == DO_DEBUGGER) { - mono_config_parse (config_file); - } - #ifdef MONO_JIT_INFO_TABLE_TEST if (test_jit_info_table) jit_info_table_test (domain); diff --git a/mono/mini/dwarfwriter.c b/mono/mini/dwarfwriter.c index 9f68a62683e..67585763b69 100644 --- a/mono/mini/dwarfwriter.c +++ b/mono/mini/dwarfwriter.c @@ -1376,6 +1376,7 @@ static const guint8 *token_handler_ip; static char* token_handler (MonoDisHelper *dh, MonoMethod *method, guint32 token) { + MonoError error; char *res, *desc; MonoMethod *cmethod; MonoClass *klass; @@ -1389,10 +1390,12 @@ token_handler (MonoDisHelper *dh, MonoMethod *method, guint32 token) case CEE_ISINST: case CEE_CASTCLASS: case CEE_LDELEMA: - if (method->wrapper_type) + if (method->wrapper_type) { klass = data; - else - klass = mono_class_get_full (method->klass->image, token, NULL); + } else { + klass = mono_class_get_checked (method->klass->image, token, &error); + g_assert (mono_error_ok (&error)); /* FIXME error handling */ + } res = g_strdup_printf ("<%s>", klass->name); break; case CEE_NEWOBJ: diff --git a/mono/mini/exceptions-amd64.c b/mono/mini/exceptions-amd64.c index 2a253a8cef8..a0865b7e2b6 100644 --- a/mono/mini/exceptions-amd64.c +++ b/mono/mini/exceptions-amd64.c @@ -45,7 +45,7 @@ LPTOP_LEVEL_EXCEPTION_FILTER mono_old_win_toplevel_exception_filter; void *mono_win_vectored_exception_handle; #define W32_SEH_HANDLE_EX(_ex) \ - if (_ex##_handler) _ex##_handler(0, ep, sctx) + if (_ex##_handler) _ex##_handler(0, ep, ctx) static LONG CALLBACK seh_unhandled_exception_filter(EXCEPTION_POINTERS* ep) { @@ -68,7 +68,6 @@ static LONG CALLBACK seh_vectored_exception_handler(EXCEPTION_POINTERS* ep) { EXCEPTION_RECORD* er; CONTEXT* ctx; - MonoContext* sctx; LONG res; MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id); @@ -81,22 +80,6 @@ static LONG CALLBACK seh_vectored_exception_handler(EXCEPTION_POINTERS* ep) er = ep->ExceptionRecord; ctx = ep->ContextRecord; - sctx = g_malloc(sizeof(MonoContext)); - - /* Copy Win32 context to UNIX style context */ - sctx->rax = ctx->Rax; - sctx->rbx = ctx->Rbx; - sctx->rcx = ctx->Rcx; - sctx->rdx = ctx->Rdx; - sctx->rbp = ctx->Rbp; - sctx->rsp = ctx->Rsp; - sctx->rsi = ctx->Rsi; - sctx->rdi = ctx->Rdi; - sctx->rip = ctx->Rip; - sctx->r12 = ctx->R12; - sctx->r13 = ctx->R13; - sctx->r14 = ctx->R14; - sctx->r15 = ctx->R15; switch (er->ExceptionCode) { case EXCEPTION_ACCESS_VIOLATION: @@ -126,30 +109,8 @@ static LONG CALLBACK seh_vectored_exception_handler(EXCEPTION_POINTERS* ep) * can correctly chain the exception. */ res = EXCEPTION_CONTINUE_SEARCH; - } else { - /* Copy context back */ - /* Nonvolatile */ - ctx->Rsp = sctx->rsp; - ctx->Rdi = sctx->rdi; - ctx->Rsi = sctx->rsi; - ctx->Rbx = sctx->rbx; - ctx->Rbp = sctx->rbp; - ctx->R12 = sctx->r12; - ctx->R13 = sctx->r13; - ctx->R14 = sctx->r14; - ctx->R15 = sctx->r15; - ctx->Rip = sctx->rip; - - /* Volatile But should not matter?*/ - ctx->Rax = sctx->rax; - ctx->Rcx = sctx->rcx; - ctx->Rdx = sctx->rdx; } - /* TODO: Find right place to free this in stack overflow case */ - if (er->ExceptionCode != EXCEPTION_STACK_OVERFLOW) - g_free (sctx); - return res; } @@ -591,7 +552,7 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, guint8 *cfa; guint32 unwind_info_len; guint8 *unwind_info; - guint8 *epilog; + guint8 *epilog = NULL; frame->type = FRAME_TYPE_MANAGED; @@ -604,7 +565,9 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, printf ("%s %p %p\n", ji->d.method->name, ji->code_start, ip); mono_print_unwind_info (unwind_info, unwind_info_len); */ - epilog = (guint8*)ji->code_start + ji->code_size - (ji->unwind_info >> 16); + /* LLVM compiled code doesn't have this info */ + if (ji->has_arch_eh_info) + epilog = (guint8*)ji->code_start + ji->code_size - mono_jinfo_get_epilog_size (ji); regs [AMD64_RAX] = new_ctx->rax; regs [AMD64_RBX] = new_ctx->rbx; @@ -622,7 +585,7 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, mono_unwind_frame (unwind_info, unwind_info_len, ji->code_start, (guint8*)ji->code_start + ji->code_size, - ip, &epilog, regs, MONO_MAX_IREGS + 1, + ip, epilog ? &epilog : NULL, regs, MONO_MAX_IREGS + 1, save_locations, MONO_MAX_IREGS, &cfa); new_ctx->rax = regs [AMD64_RAX]; @@ -645,12 +608,6 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, /* Adjust IP */ new_ctx->rip --; -#ifndef MONO_AMD64_NO_PUSHES - /* Pop arguments off the stack */ - if (ji->has_arch_eh_info) - new_ctx->rsp += mono_jit_info_get_arch_eh_info (ji)->stack_size; -#endif - return TRUE; } else if (*lmf) { guint64 rip; @@ -841,6 +798,8 @@ mono_arch_ip_from_context (void *sigctx) ucontext_t *ctx = (ucontext_t*)sigctx; return (gpointer)UCONTEXT_REG_RIP (ctx); +#elif defined(HOST_WIN32) + return ((CONTEXT*)sigctx)->Rip; #else MonoContext *ctx = sigctx; return (gpointer)ctx->rip; @@ -1062,10 +1021,17 @@ static gpointer throw_pending_exception; * exception. */ void -mono_arch_notify_pending_exc (void) +mono_arch_notify_pending_exc (MonoThreadInfo *info) { MonoLMF *lmf = mono_get_lmf (); + if (!info) { + lmf = mono_get_lmf (); + } else { + g_assert (info->suspend_state.valid); + lmf = info->suspend_state.unwind_data [MONO_UNWIND_DATA_LMF]; + } + if (!lmf) /* Not yet started */ return; diff --git a/mono/mini/exceptions-arm.c b/mono/mini/exceptions-arm.c index d7fd3318f3d..e39248ceda1 100644 --- a/mono/mini/exceptions-arm.c +++ b/mono/mini/exceptions-arm.c @@ -36,6 +36,7 @@ #include "mini.h" #include "mini-arm.h" #include "mono/utils/mono-sigcontext.h" +#include "mono/utils/mono-compiler.h" /* * arch_get_restore_context: @@ -536,10 +537,7 @@ handle_signal_exception (gpointer obj) * This works around a gcc 4.5 bug: * https://bugs.launchpad.net/ubuntu/+source/gcc-4.5/+bug/721531 */ -#if defined(__GNUC__) -__attribute__((noinline)) -#endif -static gpointer +static MONO_NEVER_INLINE gpointer get_handle_signal_exception_addr (void) { return handle_signal_exception; diff --git a/mono/mini/exceptions-x86.c b/mono/mini/exceptions-x86.c old mode 100644 new mode 100755 index d335d7ea5c6..615b3f2371f --- a/mono/mini/exceptions-x86.c +++ b/mono/mini/exceptions-x86.c @@ -49,7 +49,7 @@ extern int (*gUnhandledExceptionHandler)(EXCEPTION_POINTERS*); #endif #define W32_SEH_HANDLE_EX(_ex) \ - if (_ex##_handler) _ex##_handler(0, ep, sctx) + if (_ex##_handler) _ex##_handler(0, ep, ctx) LONG CALLBACK seh_unhandled_exception_filter(EXCEPTION_POINTERS* ep) { @@ -189,7 +189,6 @@ LONG CALLBACK seh_vectored_exception_handler(EXCEPTION_POINTERS* ep) { EXCEPTION_RECORD* er; CONTEXT* ctx; - struct sigcontext* sctx; LONG res; MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id); @@ -202,22 +201,10 @@ LONG CALLBACK seh_vectored_exception_handler(EXCEPTION_POINTERS* ep) er = ep->ExceptionRecord; ctx = ep->ContextRecord; - sctx = g_malloc(sizeof(struct sigcontext)); - - /* Copy Win32 context to UNIX style context */ - sctx->eax = ctx->Eax; - sctx->ebx = ctx->Ebx; - sctx->ecx = ctx->Ecx; - sctx->edx = ctx->Edx; - sctx->ebp = ctx->Ebp; - sctx->esp = ctx->Esp; - sctx->esi = ctx->Esi; - sctx->edi = ctx->Edi; - sctx->eip = ctx->Eip; switch (er->ExceptionCode) { case EXCEPTION_STACK_OVERFLOW: - win32_handle_stack_overflow (ep, sctx); + win32_handle_stack_overflow (ep, ctx); break; case EXCEPTION_ACCESS_VIOLATION: W32_SEH_HANDLE_EX(segv); @@ -246,23 +233,8 @@ LONG CALLBACK seh_vectored_exception_handler(EXCEPTION_POINTERS* ep) * can correctly chain the exception. */ res = EXCEPTION_CONTINUE_SEARCH; - } else { - /* Copy context back */ - ctx->Eax = sctx->eax; - ctx->Ebx = sctx->ebx; - ctx->Ecx = sctx->ecx; - ctx->Edx = sctx->edx; - ctx->Ebp = sctx->ebp; - ctx->Esp = sctx->esp; - ctx->Esi = sctx->esi; - ctx->Edi = sctx->edi; - ctx->Eip = sctx->eip; } - /* TODO: Find right place to free this in stack overflow case */ - if (er->ExceptionCode != EXCEPTION_STACK_OVERFLOW) - g_free (sctx); - return res; } @@ -278,8 +250,9 @@ void win32_seh_init() void win32_seh_cleanup() { - if (mono_old_win_toplevel_exception_filter) SetUnhandledExceptionFilter(mono_old_win_toplevel_exception_filter); - RemoveVectoredExceptionHandler (seh_unhandled_exception_filter); + if (mono_old_win_toplevel_exception_filter) + SetUnhandledExceptionFilter(mono_old_win_toplevel_exception_filter); + RemoveVectoredExceptionHandler (mono_win_vectored_exception_handle); } void win32_seh_set_handler(int type, MonoW32ExceptionHandler handler) @@ -835,29 +808,6 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, /* Adjust IP */ new_ctx->eip --; - -#ifndef MONO_X86_NO_PUSHES - /* Pop arguments off the stack */ - if (ji->has_arch_eh_info) { - int stack_size; - - stack_size = mono_jit_info_get_arch_eh_info (ji)->stack_size; - - if (stack_size) { -#ifdef ENABLE_LLVM - MonoJitInfo *caller_ji; - - caller_ji = mini_jit_info_table_find (domain, (char*)new_ctx->eip, NULL); - /* LLVM doesn't push the arguments */ - if (caller_ji && !caller_ji->from_llvm) - new_ctx->esp += stack_size; -#else - new_ctx->esp += stack_size; -#endif - } - } -#endif - return TRUE; } else if (*lmf) { @@ -952,15 +902,15 @@ mono_arch_ip_from_context (void *sigctx) #if defined(__native_client__) printf("WARNING: mono_arch_ip_from_context() called!\n"); return (NULL); -#else -#ifdef MONO_ARCH_USE_SIGACTION +#elif defined(MONO_ARCH_USE_SIGACTION) ucontext_t *ctx = (ucontext_t*)sigctx; return (gpointer)UCONTEXT_REG_EIP (ctx); +#elif defined(HOST_WIN32) + return ((CONTEXT*)sigctx)->Eip; #else struct sigcontext *ctx = sigctx; return (gpointer)ctx->SC_EIP; #endif -#endif /* __native_client__ */ } /* diff --git a/mono/mini/generics.cs b/mono/mini/generics.cs index cdf7b36ef68..f350710c76e 100644 --- a/mono/mini/generics.cs +++ b/mono/mini/generics.cs @@ -913,6 +913,7 @@ public Type getInstance() { } } + [Category ("GSHAREDVT")] static int test_0_synchronized_gshared () { var c = new SyncClass (); if (c.getInstance () != typeof (string)) @@ -1088,6 +1089,36 @@ public static int test_0_delegate_callvirt_fullaot () { var s = f2 (f); return s == "A" ? 0 : 1; } + + public interface ICovariant + { + } + + // Deleting the `out` modifier from this line stop the problem + public interface IExtCovariant : ICovariant + { + } + + public class Sample : ICovariant + { + } + + public interface IMyInterface + { + } + + public static int test_0_variant_cast_cache () { + object covariant = new Sample(); + + var foo = (ICovariant)(covariant); + + try { + var extCovariant = (IExtCovariant)covariant; + return 1; + } catch { + return 0; + } + } } #if !MOBILE diff --git a/mono/mini/gshared.cs b/mono/mini/gshared.cs index 27149e9085d..d0ee4fac40d 100644 --- a/mono/mini/gshared.cs +++ b/mono/mini/gshared.cs @@ -944,6 +944,47 @@ public static int test_0_virtual_generic () { return 0; } + public interface IFace1 { + void m1 (); + void m2 (); + void m3 (); + void m4 (); + void m5 (); + } + + public class ClassIFace : IFace1 { + public void m1 () { + } + public void m2 () { + } + public void m3 () { + } + public void m4 () { + } + public void m5 () { + } + } + + interface IFaceIFaceCall { + void call (IFace1 iface); + } + + class MakeIFaceCall : IFaceIFaceCall { + public void call (IFace1 iface) { + iface.m1 (); + } + } + + // Check normal interface calls from gsharedvt call to fully instantiated methods + public static int test_0_instatiated_iface_call () { + ClassIFace c1 = new ClassIFace (); + + IFaceIFaceCall c = new MakeIFaceCall (); + + c.call (c1); + return 0; + } + [MethodImplAttribute (MethodImplOptions.NoInlining)] static string to_string(T t, T2 t2) { return t.ToString (); diff --git a/mono/mini/jit-icalls.c b/mono/mini/jit-icalls.c index 8c7c00c8322..fcfcf4f3cd1 100644 --- a/mono/mini/jit-icalls.c +++ b/mono/mini/jit-icalls.c @@ -17,7 +17,7 @@ #endif #include "jit-icalls.h" - +#include void* mono_ldftn (MonoMethod *method) { @@ -1022,9 +1022,9 @@ mono_helper_ldstr_mscorlib (guint32 idx) MonoObject* mono_helper_newobj_mscorlib (guint32 idx) { - MonoClass *klass = mono_class_get (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx); - - g_assert (klass); + MonoError error; + MonoClass *klass = mono_class_get_checked (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx, &error); + mono_error_raise_exception (&error); return mono_object_new (mono_domain_get (), klass); } diff --git a/mono/mini/liveness.c b/mono/mini/liveness.c index a5cbabb53a5..5f304b390fd 100644 --- a/mono/mini/liveness.c +++ b/mono/mini/liveness.c @@ -812,9 +812,7 @@ update_liveness2 (MonoCompile *cfg, MonoInst *ins, gboolean set_volatile, int in /* 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; } diff --git a/mono/mini/method-to-ir.c b/mono/mini/method-to-ir.c old mode 100644 new mode 100755 index 27f26a14a76..9a78a549a31 --- a/mono/mini/method-to-ir.c +++ b/mono/mini/method-to-ir.c @@ -71,49 +71,35 @@ #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) @@ -126,6 +112,16 @@ 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)) @@ -138,6 +134,9 @@ int mono_op_to_op_imm_noemul (int opcode); MONO_API MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args); +static int inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, + guchar *ip, guint real_offset, gboolean inline_always, MonoBasicBlock **out_cbb); + /* helper methods signatures */ static MonoMethodSignature *helper_sig_class_init_trampoline; static MonoMethodSignature *helper_sig_domain_get; @@ -194,14 +193,6 @@ const gint8 ins_sreg_counts[] = { (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) { @@ -367,6 +358,60 @@ mono_create_helper_signatures (void) 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 (int i) { ldarg.0; box T; } @@ -378,16 +423,10 @@ mono_create_helper_signatures (void) 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)) { \ @@ -4045,8 +4084,7 @@ mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass * return FALSE; } -// FIXME: This doesn't work yet (class libs tests fail?) -#define is_complex_isinst(klass) (TRUE || (klass->flags & TYPE_ATTRIBUTE_INTERFACE) || klass->rank || mono_class_is_nullable (klass) || mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_SEALED) || klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR) +#define is_complex_isinst(klass) ((klass->flags & TYPE_ATTRIBUTE_INTERFACE) || klass->rank || mono_class_is_nullable (klass) || mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_SEALED) || klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR) static MonoInst* emit_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args, MonoBasicBlock **out_bblock) @@ -4063,16 +4101,77 @@ emit_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args, return res; } +static MonoInst* +emit_castclass_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass, MonoBasicBlock **out_bblock) +{ + MonoInst *args [3]; + int idx; + + /* obj */ + args [0] = obj; + + /* klass */ + EMIT_NEW_CLASSCONST (cfg, args [1], klass); + + /* inline cache*/ + if (cfg->compile_aot) { + /* Each CASTCLASS_CACHE patch needs a unique index which identifies the call site */ + cfg->castclass_cache_index ++; + idx = (cfg->method_index << 16) | cfg->castclass_cache_index; + EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx)); + } else { + EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer))); + } + + /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/ + + return emit_castclass_with_cache (cfg, klass, args, out_bblock); +} + /* * Returns NULL and set the cfg exception on error. */ static MonoInst* -handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used) +handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, guint8 *ip, MonoBasicBlock **out_bb, int *inline_costs) { MonoBasicBlock *is_null_bb; int obj_reg = src->dreg; int vtable_reg = alloc_preg (cfg); - MonoInst *klass_inst = NULL; + int context_used; + MonoInst *klass_inst = NULL, *res; + MonoBasicBlock *bblock; + + *out_bb = cfg->cbb; + + context_used = mini_class_check_context_used (cfg, klass); + + if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) { + res = emit_castclass_with_cache_nonshared (cfg, src, klass, &bblock); + (*inline_costs) += 2; + *out_bb = cfg->cbb; + return res; + } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) { + MonoMethod *mono_castclass; + MonoInst *iargs [1]; + int costs; + + mono_castclass = mono_marshal_get_castclass (klass); + iargs [0] = src; + + save_cast_details (cfg, klass, src->dreg, TRUE, &bblock); + costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), + iargs, ip, cfg->real_offset, TRUE, &bblock); + reset_cast_details (cfg); + CHECK_CFG_EXCEPTION; + g_assert (costs > 0); + + cfg->real_offset += 5; + + (*inline_costs) += costs; + + *out_bb = cfg->cbb; + return src; + } if (context_used) { MonoInst *args [3]; @@ -4137,7 +4236,12 @@ handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context reset_cast_details (cfg); + *out_bb = cfg->cbb; + return src; + +exception_exit: + return NULL; } /* @@ -4662,6 +4766,8 @@ mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method) int i; #endif + if (cfg->disable_inline) + return FALSE; if (cfg->generic_sharing_context) return FALSE; @@ -4766,6 +4872,9 @@ mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method) } #endif + if (g_list_find (cfg->dont_inline, method)) + return FALSE; + return TRUE; } @@ -5976,9 +6085,14 @@ emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init) } } +/* + * 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; @@ -5995,7 +6109,7 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, 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); @@ -6071,11 +6185,12 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, 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; @@ -6091,6 +6206,7 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, 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) { @@ -6145,6 +6261,8 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, cfg->cbb = ebblock; } + *out_cbb = cfg->cbb; + if (rvar) { /* * If the inlined method contains only a throw, then the ret var is not @@ -6201,7 +6319,7 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, #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 @@ -6338,6 +6456,7 @@ mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klas static inline MonoClass* mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context) { + MonoError error; MonoClass *klass; if (method->wrapper_type != MONO_WRAPPER_NONE) { @@ -6345,7 +6464,8 @@ mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context) if (context) klass = mono_class_inflate_generic_class (klass, context); } else { - klass = mono_class_get_full (method->klass->image, token, context); + klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error); + mono_error_cleanup (&error); /* FIXME don't swallow the error */ } if (klass) mono_class_init (klass); @@ -6621,7 +6741,7 @@ emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *en emit_init_local (cfg, local, type, TRUE); return ip + 6; } -load_error: + exception_exit: return NULL; } @@ -6818,6 +6938,90 @@ create_magic_tls_access (MonoCompile *cfg, MonoClassField *tls_field, MonoInst * 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: * @@ -6825,7 +7029,7 @@ create_magic_tls_access (MonoCompile *cfg, MonoClassField *tls_field, MonoInst * */ 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; @@ -6855,13 +7059,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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; @@ -6990,7 +7194,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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) @@ -7918,7 +8122,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b } 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 ()) @@ -8345,8 +8549,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b /* 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; @@ -8358,10 +8561,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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 */ @@ -8432,6 +8634,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b cmethod, MONO_RGCTX_INFO_METHOD); /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */ vtable_arg = NULL; + } else if ((cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !imt_arg) { + /* This can happen when we call a fully instantiated iface method */ + imt_arg = emit_get_rgctx_method (cfg, context_used, + cmethod, MONO_RGCTX_INFO_METHOD); + vtable_arg = NULL; } } @@ -8467,10 +8674,14 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b } /* Generic sharing */ - /* FIXME: only do this for generic methods if - they are not shared! */ + + /* + * Use this if the callee is gsharedvt sharable too, since + * at runtime we might find an instantiation so the call cannot + * be patched (the 'no_patch' code path in mini-trampolines.c). + */ if (context_used && !imt_arg && !array_rank && !delegate_invoke && - (!mono_method_is_generic_sharable (cmethod, TRUE) || + (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) || !mono_class_generic_sharing_enabled (cmethod->klass)) && (!virtual || MONO_METHOD_IS_FINAL (cmethod) || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) { @@ -9140,7 +9351,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0); ins->sreg2 = -1; - sp [1]->opcode = OP_NOP; + NULLIFY_INS (sp [1]); } } @@ -9201,7 +9412,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b /* 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)); @@ -9518,27 +9729,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b } */ - 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); @@ -9552,8 +9742,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b ((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); @@ -9594,8 +9782,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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); @@ -9618,8 +9804,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b /* 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); @@ -9663,58 +9847,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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) { @@ -9722,9 +9856,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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; @@ -9740,58 +9874,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b if (sp [0]->type != STACK_OBJ) UNVERIFIED; - context_used = mini_class_check_context_used (cfg, klass); - - if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) { - MonoInst *args [3]; - - /* obj */ - args [0] = *sp; - - /* klass */ - EMIT_NEW_CLASSCONST (cfg, args [1], klass); - - /* inline cache*/ - if (cfg->compile_aot) - EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, NULL); - else - EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer))); - - /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/ - - *sp++ = emit_castclass_with_cache (cfg, klass, args, &bblock); - ip += 5; - inline_costs += 2; - } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) { - MonoMethod *mono_castclass; - MonoInst *iargs [1]; - int costs; - - mono_castclass = mono_marshal_get_castclass (klass); - iargs [0] = sp [0]; - - 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); - reset_cast_details (cfg); - CHECK_CFG_EXCEPTION; - g_assert (costs > 0); - - ip += 5; - cfg->real_offset += 5; - bblock = cfg->cbb; - - *sp++ = iargs [0]; + ins = handle_castclass (cfg, klass, *sp, ip, &bblock, &inline_costs); + CHECK_CFG_EXCEPTION; - inline_costs += costs; - } - else { - ins = handle_castclass (cfg, klass, *sp, context_used); - CHECK_CFG_EXCEPTION; - bblock = cfg->cbb; - *sp ++ = ins; - ip += 5; - } + *sp ++ = ins; + ip += 5; break; case CEE_ISINST: { CHECK_STACK (1); @@ -9833,13 +9920,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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]; @@ -9855,6 +9941,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b break; } case CEE_UNBOX_ANY: { + MonoInst *res, *addr; + CHECK_STACK (1); --sp; CHECK_OPSIZE (5); @@ -9867,83 +9955,23 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b context_used = mini_class_check_context_used (cfg, klass); if (mini_is_gsharedvt_klass (cfg, klass)) { - *sp = handle_unbox_gsharedvt (cfg, klass, *sp, &bblock); - sp ++; - - ip += 5; + res = handle_unbox_gsharedvt (cfg, klass, *sp, &bblock); + inline_costs += 2; + } else if (generic_class_is_reference_type (cfg, klass)) { + res = handle_castclass (cfg, klass, *sp, ip, &bblock, &inline_costs); + CHECK_CFG_EXCEPTION; + } else if (mono_class_is_nullable (klass)) { + res = handle_unbox_nullable (cfg, *sp, klass, context_used); + } else { + addr = handle_unbox (cfg, klass, sp, context_used); + /* LDOBJ */ + EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0); + res = ins; inline_costs += 2; - break; - } - - if (generic_class_is_reference_type (cfg, klass)) { - /* CASTCLASS FIXME kill this huge slice of duplicated code*/ - if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) { - MonoInst *args [3]; - - /* obj */ - args [0] = *sp; - - /* klass */ - EMIT_NEW_CLASSCONST (cfg, args [1], klass); - - /* inline cache*/ - /*FIXME AOT support*/ - if (cfg->compile_aot) - EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, NULL); - else - EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer))); - - /* The wrapper doesn't inline well so the bloat of inlining doesn't pay off. */ - *sp++ = emit_castclass_with_cache (cfg, klass, args, &bblock); - ip += 5; - inline_costs += 2; - } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) { - MonoMethod *mono_castclass; - MonoInst *iargs [1]; - int costs; - - mono_castclass = mono_marshal_get_castclass (klass); - iargs [0] = sp [0]; - - costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), - iargs, ip, cfg->real_offset, dont_inline, TRUE); - CHECK_CFG_EXCEPTION; - g_assert (costs > 0); - - ip += 5; - cfg->real_offset += 5; - bblock = cfg->cbb; - - *sp++ = iargs [0]; - inline_costs += costs; - } else { - ins = handle_castclass (cfg, klass, *sp, context_used); - CHECK_CFG_EXCEPTION; - bblock = cfg->cbb; - *sp ++ = ins; - ip += 5; - } - break; - } - - if (mono_class_is_nullable (klass)) { - ins = handle_unbox_nullable (cfg, *sp, klass, context_used); - *sp++= ins; - ip += 5; - break; } - /* UNBOX */ - ins = handle_unbox (cfg, klass, sp, context_used); - *sp = ins; - + *sp ++ = res; ip += 5; - - /* LDOBJ */ - EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0); - *sp++ = ins; - - inline_costs += 2; break; } case CEE_BOX: { @@ -10133,7 +10161,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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)) @@ -10194,12 +10222,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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 { @@ -10258,9 +10285,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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; @@ -10943,7 +10969,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b MONO_INST_NEW (cfg, ins, *ip); --sp; CHECK_OPSIZE (5); - klass = mono_class_get_full (image, read32 (ip + 1), generic_context); + klass = mono_class_get_and_inflate_typespec_checked (image, read32 (ip + 1), generic_context, &error); + mono_error_cleanup (&error); /* FIXME don't swallow the error */ CHECK_TYPELOAD (klass); mono_class_init (klass); @@ -10983,7 +11010,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b MONO_INST_NEW (cfg, ins, *ip); --sp; CHECK_OPSIZE (5); - klass = mono_class_get_full (image, read32 (ip + 1), generic_context); + klass = mono_class_get_and_inflate_typespec_checked (image, read32 (ip + 1), generic_context, &error); + mono_error_cleanup (&error); /* FIXME don't swallow the error */ CHECK_TYPELOAD (klass); mono_class_init (klass); @@ -11106,10 +11134,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b tclass, MONO_RGCTX_INFO_REFLECTION_TYPE); } else if (cfg->compile_aot) { if (method->wrapper_type) { - if (mono_class_get (tclass->image, tclass->type_token) == tclass && !generic_context) { + mono_error_init (&error); //got to do it since there are multiple conditionals below + if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) { /* Special case for static synchronized wrappers */ EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context); } else { + mono_error_cleanup (&error); /* FIXME don't swallow the error */ /* FIXME: n is not a normal token */ DISABLE_AOT (cfg); EMIT_NEW_PCONST (cfg, ins, NULL); @@ -11593,7 +11623,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b } case CEE_MONO_JIT_ATTACH: { MonoInst *args [16], *domain_ins; - MonoInst *ad_ins, *lmf_ins; + MonoInst *ad_ins, *jit_tls_ins; MonoBasicBlock *next_bb = NULL, *call_bb = NULL; cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL); @@ -11601,15 +11631,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b EMIT_NEW_PCONST (cfg, ins, NULL); MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg); -#if TARGET_WIN32 - ad_ins = NULL; - lmf_ins = NULL; -#else ad_ins = mono_get_domain_intrinsic (cfg); - lmf_ins = mono_get_lmf_intrinsic (cfg); -#endif + jit_tls_ins = mono_get_jit_tls_intrinsic (cfg); - if (MONO_ARCH_HAVE_TLS_GET && ad_ins && lmf_ins) { + if (MONO_ARCH_HAVE_TLS_GET && ad_ins && jit_tls_ins) { NEW_BBLOCK (cfg, next_bb); NEW_BBLOCK (cfg, call_bb); @@ -11623,8 +11648,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg); MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb); - MONO_ADD_INS (cfg->cbb, lmf_ins); - MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, lmf_ins->dreg, 0); + MONO_ADD_INS (cfg->cbb, jit_tls_ins); + MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0); MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb); MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb); @@ -11722,9 +11747,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b * 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; @@ -11749,7 +11774,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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)) @@ -11973,7 +11998,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b * 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); @@ -12155,19 +12180,25 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b guint32 val; int ialign; - GSHAREDVT_FAILURE (*ip); - CHECK_STACK_OVF (1); CHECK_OPSIZE (6); token = read32 (ip + 2); if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) { - MonoType *type = mono_type_create_from_typespec (image, token); + MonoType *type = mono_type_create_from_typespec_checked (image, token, &error); + mono_error_cleanup (&error); /* FIXME don't swallow the error */ + if (!type) + UNVERIFIED; + val = mono_type_size (type, &ialign); } else { - MonoClass *klass = mono_class_get_full (image, token, generic_context); + MonoClass *klass = mono_class_get_and_inflate_typespec_checked (image, token, generic_context, &error); + mono_error_cleanup (&error); /* FIXME don't swallow the error */ CHECK_TYPELOAD (klass); mono_class_init (klass); val = mono_type_size (&klass->byval_arg, &ialign); + + if (mini_is_gsharedvt_klass (cfg, klass)) + GSHAREDVT_FAILURE (*ip); } EMIT_NEW_ICONST (cfg, ins, val); *sp++= ins; @@ -12332,9 +12363,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b } } - g_slist_free (class_inits); - dont_inline = g_list_remove (dont_inline, method); - if (inline_costs < 0) { char *mname; @@ -12343,29 +12371,17 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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; @@ -12373,9 +12389,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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 diff --git a/mono/mini/mini-amd64.c b/mono/mini/mini-amd64.c old mode 100644 new mode 100755 index 3cefc22c87d..a809de49e05 --- a/mono/mini/mini-amd64.c +++ b/mono/mini/mini-amd64.c @@ -85,12 +85,8 @@ static int breakpoint_fault_size; /* The size of the single step instruction causing the actual fault */ static int single_step_fault_size; -#ifdef HOST_WIN32 -/* On Win64 always reserve first 32 bytes for first four arguments */ -#define ARGS_OFFSET 48 -#else +/* Offset between fp and the first argument in the callee */ #define ARGS_OFFSET 16 -#endif #define GP_SCRATCH_REG AMD64_R11 /* @@ -940,6 +936,11 @@ get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSign gr = 0; fr = 0; +#ifdef HOST_WIN32 + /* Reserve space where the callee can save the argument registers */ + stack_size = 4 * sizeof (mgreg_t); +#endif + /* return value */ { ret_type = mini_type_get_underlying_type (gsctx, sig->ret); @@ -1107,6 +1108,7 @@ get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSign add_valuetype (gsctx, sig, ainfo, sig->params [i], FALSE, &gr, &fr, &stack_size); break; case MONO_TYPE_U8: + case MONO_TYPE_I8: add_general (&gr, &stack_size, ainfo); break; @@ -1129,19 +1131,6 @@ get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSign add_general (&gr, &stack_size, &cinfo->sig_cookie); } -#ifdef HOST_WIN32 - // There always is 32 bytes reserved on the stack when calling on Winx64 - stack_size += 0x20; -#endif - -#ifndef MONO_AMD64_NO_PUSHES - if (stack_size & 0x8) { - /* The AMD64 ABI requires each stack frame to be 16 byte aligned */ - cinfo->need_stack_align = TRUE; - stack_size += 8; - } -#endif - cinfo->stack_usage = stack_size; cinfo->reg_usage = gr; cinfo->freg_usage = fr; @@ -1407,10 +1396,6 @@ mono_arch_compute_omit_fp (MonoCompile *cfg) cfg->arch.omit_fp = FALSE; #endif -#ifdef HOST_WIN32 - cfg->arch.omit_fp = FALSE; -#endif - if (cfg->disable_omit_fp) cfg->arch.omit_fp = FALSE; @@ -1991,19 +1976,6 @@ mono_arch_create_vars (MonoCompile *cfg) cfg->arch.ss_trigger_page_var = ins; } -#ifdef MONO_AMD64_NO_PUSHES - /* - * When this is set, we pass arguments on the stack by moves, and by allocating - * a bigger stack frame, instead of pushes. - * Pushes complicate exception handling because the arguments on the stack have - * to be popped each time a frame is unwound. They also make fp elimination - * impossible. - * FIXME: This doesn't work inside filter/finally clauses, since those execute - * on a new frame which doesn't include a param area. - */ - cfg->arch.no_pushes = TRUE; -#endif - if (cfg->method->save_lmf) cfg->create_lmf_var = TRUE; @@ -2014,10 +1986,6 @@ mono_arch_create_vars (MonoCompile *cfg) cfg->lmf_ir_mono_lmf = TRUE; #endif } - -#ifndef MONO_AMD64_NO_PUSHES - cfg->arch_eh_jit_info = 1; -#endif } static void @@ -2079,7 +2047,6 @@ arg_storage_to_load_membase (ArgStorage storage) static void emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo) { - MonoInst *arg; MonoMethodSignature *tmp_sig; int sig_reg; @@ -2102,13 +2069,7 @@ emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo) sig_reg = mono_alloc_ireg (cfg); MONO_EMIT_NEW_SIGNATURECONST (cfg, sig_reg, tmp_sig); - if (cfg->arch.no_pushes) { - MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, AMD64_RSP, cinfo->sig_cookie.offset, sig_reg); - } else { - MONO_INST_NEW (cfg, arg, OP_X86_PUSH); - arg->sreg1 = sig_reg; - MONO_ADD_INS (cfg->cbb, arg); - } + MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, AMD64_RSP, cinfo->sig_cookie.offset, sig_reg); } static inline LLVMArgStorage @@ -2245,43 +2206,36 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) return; } - if (cinfo->need_stack_align) { - if (!cfg->arch.no_pushes) - MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUB_IMM, X86_ESP, X86_ESP, 8); - } - /* * Emit all arguments which are passed on the stack to prevent register * allocation problems. */ - if (cfg->arch.no_pushes) { - for (i = 0; i < n; ++i) { - MonoType *t; - ainfo = cinfo->args + i; + for (i = 0; i < n; ++i) { + MonoType *t; + ainfo = cinfo->args + i; - in = call->args [i]; + in = call->args [i]; - if (sig->hasthis && i == 0) - t = &mono_defaults.object_class->byval_arg; - else - t = sig->params [i - sig->hasthis]; + if (sig->hasthis && i == 0) + t = &mono_defaults.object_class->byval_arg; + else + t = sig->params [i - sig->hasthis]; - if (ainfo->storage == ArgOnStack && !MONO_TYPE_ISSTRUCT (t) && !call->tail_call) { - if (!t->byref) { - if (t->type == MONO_TYPE_R4) - MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, AMD64_RSP, ainfo->offset, in->dreg); - else if (t->type == MONO_TYPE_R8) - MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, AMD64_RSP, ainfo->offset, in->dreg); - else - MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, AMD64_RSP, ainfo->offset, in->dreg); - } else { + if (ainfo->storage == ArgOnStack && !MONO_TYPE_ISSTRUCT (t) && !call->tail_call) { + if (!t->byref) { + if (t->type == MONO_TYPE_R4) + MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, AMD64_RSP, ainfo->offset, in->dreg); + else if (t->type == MONO_TYPE_R8) + MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, AMD64_RSP, ainfo->offset, in->dreg); + else MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, AMD64_RSP, ainfo->offset, in->dreg); - } - if (cfg->compute_gc_maps) { - MonoInst *def; + } else { + MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, AMD64_RSP, ainfo->offset, in->dreg); + } + if (cfg->compute_gc_maps) { + MonoInst *def; - EMIT_NEW_GC_PARAM_SLOT_LIVENESS_DEF (cfg, def, ainfo->offset, t); - } + EMIT_NEW_GC_PARAM_SLOT_LIVENESS_DEF (cfg, def, ainfo->offset, t); } } } @@ -2358,27 +2312,6 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) arg->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo)); memcpy (arg->inst_p1, ainfo, sizeof (ArgInfo)); - MONO_ADD_INS (cfg->cbb, arg); - } - } else { - if (cfg->arch.no_pushes) { - /* Already done */ - } else { - MONO_INST_NEW (cfg, arg, OP_X86_PUSH); - arg->sreg1 = in->dreg; - if (!sig->params [i - sig->hasthis]->byref) { - if (sig->params [i - sig->hasthis]->type == MONO_TYPE_R4) { - MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUB_IMM, X86_ESP, X86_ESP, 8); - arg->opcode = OP_STORER4_MEMBASE_REG; - arg->inst_destbasereg = X86_ESP; - arg->inst_offset = 0; - } else if (sig->params [i - sig->hasthis]->type == MONO_TYPE_R8) { - MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUB_IMM, X86_ESP, X86_ESP, 8); - arg->opcode = OP_STORER8_MEMBASE_REG; - arg->inst_destbasereg = X86_ESP; - arg->inst_offset = 0; - } - } MONO_ADD_INS (cfg->cbb, arg); } } @@ -2441,12 +2374,6 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) } } -#ifdef HOST_WIN32 - if (call->inst.opcode != OP_TAILCALL) { - MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUB_IMM, X86_ESP, X86_ESP, 0x20); - } -#endif - if (cfg->method->save_lmf) { MONO_INST_NEW (cfg, arg, OP_AMD64_SAVE_SP_TO_LMF); MONO_ADD_INS (cfg->cbb, arg); @@ -2494,8 +2421,6 @@ mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src) MonoInst *vtaddr, *load; vtaddr = mono_compile_create_var (cfg, &ins->klass->byval_arg, OP_LOCAL); - g_assert (!cfg->arch.no_pushes); - MONO_INST_NEW (cfg, load, OP_LDADDR); cfg->has_indirection = TRUE; load->inst_p0 = vtaddr; @@ -2514,42 +2439,19 @@ mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src) MONO_ADD_INS (cfg->cbb, arg); mono_call_inst_add_outarg_reg (cfg, call, arg->dreg, ainfo->pair_regs [0], FALSE); } else { - MONO_INST_NEW (cfg, arg, OP_X86_PUSH); - arg->sreg1 = load->dreg; - MONO_ADD_INS (cfg->cbb, arg); + MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, AMD64_RSP, ainfo->offset, load->dreg); } } else { if (size == 8) { - if (cfg->arch.no_pushes) { - int dreg = mono_alloc_ireg (cfg); + int dreg = mono_alloc_ireg (cfg); - MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, 0); - MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, AMD64_RSP, ainfo->offset, dreg); - } else { - /* Can't use this for < 8 since it does an 8 byte memory load */ - MONO_INST_NEW (cfg, arg, OP_X86_PUSH_MEMBASE); - arg->inst_basereg = src->dreg; - arg->inst_offset = 0; - MONO_ADD_INS (cfg->cbb, arg); - } + MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, 0); + MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, AMD64_RSP, ainfo->offset, dreg); } else if (size <= 40) { - if (cfg->arch.no_pushes) { - mini_emit_memcpy (cfg, AMD64_RSP, ainfo->offset, src->dreg, 0, size, 4); - } else { - MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUB_IMM, X86_ESP, X86_ESP, ALIGN_TO (size, 8)); - mini_emit_memcpy (cfg, X86_ESP, 0, src->dreg, 0, size, 4); - } + mini_emit_memcpy (cfg, AMD64_RSP, ainfo->offset, src->dreg, 0, size, 4); } else { - if (cfg->arch.no_pushes) { - // FIXME: Code growth - mini_emit_memcpy (cfg, AMD64_RSP, ainfo->offset, src->dreg, 0, size, 4); - } else { - MONO_INST_NEW (cfg, arg, OP_X86_PUSH_OBJ); - arg->inst_basereg = src->dreg; - arg->inst_offset = 0; - arg->inst_imm = size; - MONO_ADD_INS (cfg->cbb, arg); - } + // FIXME: Code growth + mini_emit_memcpy (cfg, AMD64_RSP, ainfo->offset, src->dreg, 0, size, 4); } if (cfg->compute_gc_maps) { @@ -3461,7 +3363,7 @@ mono_emit_stack_alloc (MonoCompile *cfg, guchar *code, MonoInst* tree) amd64_alu_reg_reg (code, X86_XOR, AMD64_RAX, AMD64_RAX); amd64_lea_membase (code, AMD64_RDI, AMD64_RSP, offset); - if (cfg->param_area && cfg->arch.no_pushes) + if (cfg->param_area) amd64_alu_reg_imm (code, X86_ADD, AMD64_RDI, cfg->param_area); amd64_cld (code); #if defined(__default_codegen__) @@ -4771,8 +4673,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, call->fptr, FALSE); ins->flags |= MONO_INST_GC_CALLSITE; ins->backend.pc_offset = code - cfg->native_code; - if (call->stack_usage && !CALLCONV_IS_STDCALL (call->signature->call_convention) && !cfg->arch.no_pushes) - amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, call->stack_usage); code = emit_move_return_value (cfg, ins, code); break; case OP_FCALL_REG: @@ -4821,8 +4721,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) amd64_call_reg (code, ins->sreg1); ins->flags |= MONO_INST_GC_CALLSITE; ins->backend.pc_offset = code - cfg->native_code; - if (call->stack_usage && !CALLCONV_IS_STDCALL (call->signature->call_convention) && !cfg->arch.no_pushes) - amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, call->stack_usage); code = emit_move_return_value (cfg, ins, code); break; case OP_FCALL_MEMBASE: @@ -4836,8 +4734,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) amd64_call_membase (code, ins->sreg1, ins->inst_offset); ins->flags |= MONO_INST_GC_CALLSITE; ins->backend.pc_offset = code - cfg->native_code; - if (call->stack_usage && !CALLCONV_IS_STDCALL (call->signature->call_convention) && !cfg->arch.no_pushes) - amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, call->stack_usage); code = emit_move_return_value (cfg, ins, code); break; case OP_DYN_CALL: { @@ -4875,22 +4771,22 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; } case OP_X86_PUSH: - g_assert (!cfg->arch.no_pushes); + g_assert_not_reached (); amd64_push_reg (code, ins->sreg1); break; case OP_X86_PUSH_IMM: - g_assert (!cfg->arch.no_pushes); + g_assert_not_reached (); g_assert (amd64_is_imm32 (ins->inst_imm)); amd64_push_imm (code, ins->inst_imm); break; case OP_X86_PUSH_MEMBASE: - g_assert (!cfg->arch.no_pushes); + g_assert_not_reached (); amd64_push_membase (code, ins->inst_basereg, ins->inst_offset); break; case OP_X86_PUSH_OBJ: { int size = ALIGN_TO (ins->inst_imm, 8); - g_assert (!cfg->arch.no_pushes); + g_assert_not_reached (); amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, size); amd64_push_reg (code, AMD64_RDI); @@ -4925,7 +4821,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) amd64_alu_reg_imm (code, X86_AND, ins->sreg1, ~(MONO_ARCH_FRAME_ALIGNMENT - 1)); code = mono_emit_stack_alloc (cfg, code, ins); amd64_mov_reg_reg (code, ins->dreg, AMD64_RSP, 8); - if (cfg->param_area && cfg->arch.no_pushes) + if (cfg->param_area) amd64_alu_reg_imm (code, X86_ADD, ins->dreg, cfg->param_area); break; case OP_LOCALLOC_IMM: { @@ -4953,7 +4849,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, size); amd64_mov_reg_reg (code, ins->dreg, AMD64_RSP, 8); } - if (cfg->param_area && cfg->arch.no_pushes) + if (cfg->param_area) amd64_alu_reg_imm (code, X86_ADD, ins->dreg, cfg->param_area); break; } @@ -4991,7 +4887,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) if ((MONO_BBLOCK_IS_IN_REGION (bb, MONO_REGION_FINALLY) || MONO_BBLOCK_IS_IN_REGION (bb, MONO_REGION_FINALLY)) && - cfg->param_area && cfg->arch.no_pushes) { + cfg->param_area) { amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, ALIGN_TO (cfg->param_area, MONO_ARCH_FRAME_ALIGNMENT)); } break; @@ -6521,7 +6417,7 @@ mono_arch_emit_prolog (MonoCompile *cfg) 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); @@ -6593,7 +6489,7 @@ mono_arch_emit_prolog (MonoCompile *cfg) /* The param area is always at offset 0 from sp */ /* This needs to be allocated here, since it has to come after the spill area */ - if (cfg->arch.no_pushes && cfg->param_area) { + if (cfg->param_area) { if (cfg->arch.omit_fp) // FIXME: g_assert_not_reached (); @@ -7076,7 +6972,6 @@ mono_arch_emit_epilog (MonoCompile *cfg) 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; @@ -8278,49 +8173,15 @@ mono_arch_context_set_int_reg (MonoContext *ctx, int reg, mgreg_t val) } } -/*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)) @@ -8425,8 +8286,11 @@ gboolean mono_arch_is_breakpoint_event (void *info, void *sigctx) { #ifdef HOST_WIN32 - EXCEPTION_RECORD* einfo = (EXCEPTION_RECORD*)info; - return FALSE; + EXCEPTION_RECORD* einfo = ((EXCEPTION_POINTERS*)info)->ExceptionRecord; + if (einfo->ExceptionCode == EXCEPTION_ACCESS_VIOLATION && (gpointer)einfo->ExceptionInformation [1] == bp_trigger_page) + return TRUE; + else + return FALSE; #else siginfo_t* sinfo = (siginfo_t*) info; /* Sometimes the address is off by 4 */ @@ -8486,8 +8350,11 @@ gboolean mono_arch_is_single_step_event (void *info, void *sigctx) { #ifdef HOST_WIN32 - EXCEPTION_RECORD* einfo = (EXCEPTION_RECORD*)info; - return FALSE; + EXCEPTION_RECORD* einfo = ((EXCEPTION_POINTERS*)info)->ExceptionRecord; + if (einfo->ExceptionCode == EXCEPTION_ACCESS_VIOLATION && (gpointer)einfo->ExceptionInformation [1] == ss_trigger_page) + return TRUE; + else + return FALSE; #else siginfo_t* sinfo = (siginfo_t*) info; /* Sometimes the address is off by 4 */ diff --git a/mono/mini/mini-amd64.h b/mono/mini/mini-amd64.h old mode 100644 new mode 100755 index b7c974e3acd..ebd2638727b --- a/mono/mini/mini-amd64.h +++ b/mono/mini/mini-amd64.h @@ -33,7 +33,7 @@ void amd64_nacl_membase_handler (guint8** code, gint8 basereg, gint32 offset, gi #include #endif - +#if !defined(_MSC_VER) /* sigcontext surrogate */ struct sigcontext { guint64 eax; @@ -46,6 +46,7 @@ struct sigcontext { guint64 edi; guint64 eip; }; +#endif typedef void (* MonoW32ExceptionHandler) (int _dummy, EXCEPTION_POINTERS *info, void *context); void win32_seh_init(void); @@ -191,7 +192,7 @@ typedef struct MonoCompileArch { gint32 stack_alloc_size; gint32 sp_fp_offset; guint32 saved_iregs; - gboolean omit_fp, omit_fp_computed, no_pushes; + gboolean omit_fp, omit_fp_computed; gpointer cinfo; gint32 async_point_count; gpointer vret_addr_loc; @@ -275,74 +276,18 @@ typedef struct { #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 - -#endif /* __FreeBSD__ */ +#if !defined(__linux__) +#define MONO_ARCH_NOMAP32BIT 1 +#endif #ifdef HOST_WIN32 #define MONO_AMD64_ARG_REG1 AMD64_RCX #define MONO_AMD64_ARG_REG2 AMD64_RDX +#define MONO_AMD64_ARG_REG3 AMD64_R8 #else #define MONO_AMD64_ARG_REG1 AMD64_RDI #define MONO_AMD64_ARG_REG2 AMD64_RSI +#define MONO_AMD64_ARG_REG3 AMD64_RDX #endif #define MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS @@ -352,7 +297,6 @@ typedef struct { #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 @@ -373,35 +317,25 @@ typedef struct { #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 -#if !defined(HOST_WIN32) #define MONO_ARCH_MONITOR_OBJECT_REG MONO_AMD64_ARG_REG1 -#endif #define MONO_ARCH_HAVE_GET_TRAMPOLINES 1 #define MONO_ARCH_AOT_SUPPORTED 1 -#if !defined( HOST_WIN32 ) && !defined( __native_client__ ) +#if !defined( __native_client__ ) #define MONO_ARCH_SOFT_DEBUG_SUPPORTED 1 #endif -#if !defined(HOST_WIN32) || defined(__sun) #define MONO_ARCH_ENABLE_MONITOR_IL_FASTPATH 1 -#endif #define MONO_ARCH_SUPPORT_TASKLETS 1 -#ifndef HOST_WIN32 -#define MONO_AMD64_NO_PUSHES 1 -#endif - #define MONO_ARCH_GSHARED_SUPPORTED 1 #define MONO_ARCH_DYN_CALL_SUPPORTED 1 #define MONO_ARCH_DYN_CALL_PARAM_AREA 0 #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 diff --git a/mono/mini/mini-arm.c b/mono/mini/mini-arm.c index b644d7dca7a..7e7c5937b97 100644 --- a/mono/mini/mini-arm.c +++ b/mono/mini/mini-arm.c @@ -247,9 +247,32 @@ emit_big_add (guint8 *code, int dreg, int sreg, int imm) ARM_ADD_REG_IMM (code, dreg, sreg, imm8, rot_amount); return code; } - g_assert (dreg != sreg); - code = mono_arm_emit_load_imm (code, dreg, imm); - ARM_ADD_REG_REG (code, dreg, dreg, sreg); + if (dreg == sreg) { + code = mono_arm_emit_load_imm (code, ARMREG_IP, imm); + ARM_ADD_REG_REG (code, dreg, sreg, ARMREG_IP); + } else { + code = mono_arm_emit_load_imm (code, dreg, imm); + ARM_ADD_REG_REG (code, dreg, dreg, sreg); + } + return code; +} + +/* If dreg == sreg, this clobbers IP */ +static guint8* +emit_sub_imm (guint8 *code, int dreg, int sreg, int imm) +{ + int imm8, rot_amount; + if ((imm8 = mono_arm_is_rotated_imm8 (imm, &rot_amount)) >= 0) { + ARM_SUB_REG_IMM (code, dreg, sreg, imm8, rot_amount); + return code; + } + if (dreg == sreg) { + code = mono_arm_emit_load_imm (code, ARMREG_IP, imm); + ARM_SUB_REG_REG (code, dreg, sreg, ARMREG_IP); + } else { + code = mono_arm_emit_load_imm (code, dreg, imm); + ARM_SUB_REG_REG (code, dreg, dreg, sreg); + } return code; } @@ -4945,15 +4968,9 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; } case OP_LOCALLOC: { - /* keep alignment */ - int alloca_waste = cfg->param_area; - alloca_waste += 7; - alloca_waste &= ~7; /* round the size to 8 bytes */ ARM_ADD_REG_IMM8 (code, ins->dreg, ins->sreg1, 7); ARM_BIC_REG_IMM8 (code, ins->dreg, ins->dreg, 7); - if (alloca_waste) - ARM_ADD_REG_IMM8 (code, ins->dreg, ins->dreg, alloca_waste); ARM_SUB_REG_REG (code, ARMREG_SP, ARMREG_SP, ins->dreg); /* memzero the area: dreg holds the size, sp is the pointer */ if (ins->flags & MONO_INST_INIT) { @@ -4969,7 +4986,9 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) ARM_B_COND (code, ARMCOND_GE, 0); arm_patch (code - 4, start_loop); } - ARM_ADD_REG_IMM8 (code, ins->dreg, ARMREG_SP, alloca_waste); + ARM_MOV_REG_REG (code, ins->dreg, ARMREG_SP); + if (cfg->param_area) + code = emit_sub_imm (code, ARMREG_SP, ARMREG_SP, ALIGN_TO (cfg->param_area, MONO_ARCH_FRAME_ALIGNMENT)); break; } case OP_DYN_CALL: { @@ -6929,6 +6948,26 @@ mono_arch_get_trampolines (gboolean aot) 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: diff --git a/mono/mini/mini-arm.h b/mono/mini/mini-arm.h index 7c3fd9ad041..f22514b61ef 100644 --- a/mono/mini/mini-arm.h +++ b/mono/mini/mini-arm.h @@ -256,7 +256,6 @@ typedef struct MonoCompileArch { #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) @@ -267,7 +266,6 @@ typedef struct MonoCompileArch { #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 @@ -284,6 +282,7 @@ typedef struct MonoCompileArch { #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 diff --git a/mono/mini/mini-codegen.c b/mono/mini/mini-codegen.c index 66eb8fcdcf2..f4bdecb727a 100644 --- a/mono/mini/mini-codegen.c +++ b/mono/mini/mini-codegen.c @@ -1173,6 +1173,8 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb) * 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)) { @@ -1198,12 +1200,14 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb) #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) diff --git a/mono/mini/mini-exceptions.c b/mono/mini/mini-exceptions.c index 7659466cd24..db4a1ce4b0c 100644 --- a/mono/mini/mini-exceptions.c +++ b/mono/mini/mini-exceptions.c @@ -2227,8 +2227,8 @@ print_stack_frame_to_string (StackFrameInfo *frame, MonoContext *ctx, gpointer d 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 @@ -2759,6 +2759,16 @@ mono_jinfo_get_unwind_info (MonoJitInfo *ji, guint32 *unwind_info_len) if (ji->from_aot) return mono_aot_get_unwind_info (ji, unwind_info_len); else - /* The upper 16 bits of ji->unwind_info might contain the epilog offset */ - return mono_get_cached_unwind_info (ji->unwind_info & 0xffff, unwind_info_len); + return mono_get_cached_unwind_info (ji->unwind_info, unwind_info_len); +} + +int +mono_jinfo_get_epilog_size (MonoJitInfo *ji) +{ + MonoArchEHJitInfo *info; + + info = mono_jit_info_get_arch_eh_info (ji); + g_assert (info); + + return info->epilog_size; } diff --git a/mono/mini/mini-ia64.h b/mono/mini/mini-ia64.h index d419bc26c72..15bb596d414 100644 --- a/mono/mini/mini-ia64.h +++ b/mono/mini/mini-ia64.h @@ -115,6 +115,5 @@ unw_dyn_region_info_t* mono_ia64_create_unwind_region (Ia64CodegenState *code); #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__ */ diff --git a/mono/mini/mini-llvm-cpp.cpp b/mono/mini/mini-llvm-cpp.cpp index 7560fcf012b..bf5e16f8fac 100644 --- a/mono/mini/mini-llvm-cpp.cpp +++ b/mono/mini/mini-llvm-cpp.cpp @@ -60,10 +60,6 @@ #include "mini-llvm-cpp.h" -#define LLVM_CHECK_VERSION(major,minor) \ - ((LLVM_MAJOR_VERSION > (major)) || \ - ((LLVM_MAJOR_VERSION == (major)) && (LLVM_MINOR_VERSION >= (minor)))) - // extern "C" void LLVMInitializeARMTargetInfo(); // extern "C" void LLVMInitializeARMTarget (); // extern "C" void LLVMInitializeARMTargetMC (); @@ -606,7 +602,6 @@ mono_llvm_create_ee (LLVMModuleProviderRef MP, AllocCodeMemoryCb *alloc_cb, Func // EngineBuilder no longer has a copy assignment operator (?) std::unique_ptr Owner(unwrap(MP)); EngineBuilder b (std::move(Owner)); - EngineBuilder &eb = b; #ifdef TARGET_AMD64 ExecutionEngine *EE = b.setJITMemoryManager (mono_mm).setTargetOptions (opts).setAllocateGVsWithCode (true).setMCPU (cpu_name).setCodeModel (CodeModel::Large).create (); #else diff --git a/mono/mini/mini-llvm.c b/mono/mini/mini-llvm.c index df6de20bab4..a28570344ef 100644 --- a/mono/mini/mini-llvm.c +++ b/mono/mini/mini-llvm.c @@ -7,9 +7,12 @@ #include "mini.h" #include +#include #include #include #include +#include +#include #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS @@ -35,10 +38,13 @@ typedef struct { 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; LLVMTypeRef ptr_type; + GPtrArray *subprogram_mds; MonoEERef *mono_ee; LLVMExecutionEngineRef ee; } MonoLLVMModule; @@ -96,7 +102,8 @@ typedef struct { int *pindexes; LLVMValueRef imt_rgctx_loc; GHashTable *llvm_types; - + LLVMValueRef dbg_md; + MonoDebugMethodInfo *minfo; char temp_name [32]; } EmitContext; @@ -206,6 +213,10 @@ static const char *memcpy_func_name; static void init_jit_module (MonoDomain *domain); +static void emit_dbg_loc (EmitContext *ctx, LLVMBuilderRef builder, const unsigned char *cil_code); +static LLVMValueRef emit_dbg_subprogram (EmitContext *ctx, MonoCompile *cfg, LLVMValueRef method, const char *name); +static void emit_dbg_info (MonoLLVMModule *lmodule, const char *filename, const char *cu_name); + /* * IntPtrType: * @@ -417,6 +428,7 @@ type_is_unsigned (EmitContext *ctx, MonoType *t) switch (t->type) { case MONO_TYPE_U1: case MONO_TYPE_U2: + case MONO_TYPE_CHAR: case MONO_TYPE_U4: case MONO_TYPE_U8: return TRUE; @@ -434,7 +446,12 @@ static LLVMTypeRef type_to_llvm_arg_type (EmitContext *ctx, MonoType *t) { LLVMTypeRef ptype = type_to_llvm_type (ctx, t); - + + /* + * This works on all abis except arm64/ios which passes multiple + * arguments in one stack slot. + */ +#ifndef TARGET_ARM64 if (ptype == LLVMInt8Type () || ptype == LLVMInt16Type ()) { /* * LLVM generates code which only sets the lower bits, while JITted @@ -442,6 +459,7 @@ type_to_llvm_arg_type (EmitContext *ctx, MonoType *t) */ ptype = LLVMInt32Type (); } +#endif return ptype; } @@ -1272,6 +1290,7 @@ get_plt_entry (EmitContext *ctx, LLVMTypeRef llvm_sig, MonoJumpInfoType type, gc { char *callee_name = mono_aot_get_plt_symbol (type, data); LLVMValueRef callee; + MonoJumpInfo *ji = NULL; if (!callee_name) return NULL; @@ -1290,6 +1309,14 @@ get_plt_entry (EmitContext *ctx, LLVMTypeRef llvm_sig, MonoJumpInfoType type, gc 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; } @@ -1805,7 +1832,7 @@ emit_entry_bb (EmitContext *ctx, LLVMBuilderRef builder) ctx->values [reg] = LLVMBuildLoad (builder, ctx->addresses [reg], ""); } } else { - ctx->values [reg] = convert (ctx, ctx->values [reg], llvm_type_to_stack_type (type_to_llvm_type (ctx, sig->params [i]))); + ctx->values [reg] = convert_full (ctx, ctx->values [reg], llvm_type_to_stack_type (type_to_llvm_type (ctx, sig->params [i])), type_is_unsigned (ctx, sig->params [i])); } } @@ -2327,6 +2354,8 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb) char *dname = NULL; char dname_buf [128]; + emit_dbg_loc (ctx, builder, ins->cil_code); + nins ++; if (nins > 5000 && builder == starting_builder) { /* some steps in llc are non-linear in the size of basic blocks, see #5714 */ @@ -3156,7 +3185,7 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb) index = LLVMConstInt (LLVMInt32Type (), ins->inst_offset / size, FALSE); addr = LLVMBuildGEP (builder, convert (ctx, values [ins->inst_destbasereg], LLVMPointerType (t, 0)), &index, 1, ""); } - emit_store (ctx, bb, &builder, size, convert (ctx, LLVMConstInt (IntPtrType (), ins->inst_imm, FALSE), t), addr, is_volatile); + emit_store (ctx, bb, &builder, size, convert (ctx, LLVMConstInt (IntPtrType (), ins->inst_imm, FALSE), t), convert (ctx, addr, LLVMPointerType (t, 0)), is_volatile); break; } @@ -4226,8 +4255,10 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb) if (!has_terminator && bb->next_bb && (bb == cfg->bb_entry || bb->in_count > 0)) LLVMBuildBr (builder, get_bb (ctx, bb->next_bb)); - if (bb == cfg->bb_exit && sig->ret->type == MONO_TYPE_VOID) + if (bb == cfg->bb_exit && sig->ret->type == MONO_TYPE_VOID) { + emit_dbg_loc (ctx, builder, cfg->header->code + cfg->header->code_size - 1); LLVMBuildRetVoid (builder); + } if (bb == cfg->bb_entry) ctx->last_alloca = LLVMGetLastInstruction (get_bb (ctx, cfg->bb_entry)); @@ -4465,6 +4496,12 @@ mono_llvm_emit_method (MonoCompile *cfg) } g_free (names); + // See emit_dbg_info () + if (FALSE && cfg->compile_aot && mono_debug_enabled ()) { + ctx->minfo = mono_debug_lookup_method (cfg->method); + ctx->dbg_md = emit_dbg_subprogram (ctx, cfg, method, method_name); + } + max_block_num = 0; for (bb = cfg->bb_entry; bb; bb = bb->next_bb) max_block_num = MAX (max_block_num, bb->block_num); @@ -4675,6 +4712,9 @@ mono_llvm_emit_method (MonoCompile *cfg) /* 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: @@ -5331,16 +5371,19 @@ mono_llvm_create_aot_module (const char *got_symbol) 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); } /* * Emit the aot module into the LLVM bitcode file FILENAME. */ void -mono_llvm_emit_aot_module (const char *filename, int got_size) +mono_llvm_emit_aot_module (const char *filename, const char *cu_name, int got_size) { LLVMTypeRef got_type; LLVMValueRef real_got; + MonoLLVMModule *module = &aot_module; /* * Create the real got variable and replace all uses of the dummy variable with @@ -5359,6 +5402,28 @@ mono_llvm_emit_aot_module (const char *filename, int got_size) LLVMDeleteGlobal (aot_module.got_var); emit_llvm_used (&aot_module); + emit_dbg_info (&aot_module, filename, cu_name); + + /* 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); + /* The types might not match because the caller might pass an rgctx */ + if (lmethod && LLVMTypeOf (callee) == LLVMTypeOf (lmethod)) { + mono_llvm_replace_uses_of (callee, lmethod); + mono_aot_mark_unused_llvm_plt_entry (ji); + } + } + } + } #if 0 { @@ -5373,6 +5438,221 @@ mono_llvm_emit_aot_module (const char *filename, int got_size) LLVMWriteBitcodeToFile (aot_module.module, filename); } + +static LLVMValueRef +md_string (const char *s) +{ + return LLVMMDString (s, strlen (s)); +} + +/* Debugging support */ + +static void +emit_dbg_info (MonoLLVMModule *lmodule, const char *filename, const char *cu_name) +{ + LLVMModuleRef module = lmodule->module; + LLVMValueRef args [16], cu_args [16], cu, ver; + int n_cuargs; + char *build_info, *s, *dir; + + // + // FIXME: This cannot be enabled, since the AOT compiler also emits dwarf info, + // and the abbrev indexes will not be correct since llvm has added its own + // abbrevs. + // + return; + + /* + * Emit dwarf info in the form of LLVM metadata. There is some + * out-of-date documentation at: + * http://llvm.org/docs/SourceLevelDebugging.html + * but most of this was gathered from the llvm and + * clang sources. + */ + + n_cuargs = 0; + cu_args [n_cuargs ++] = LLVMConstInt (LLVMInt32Type (), DW_TAG_compile_unit, FALSE); + /* CU name/compilation dir */ + dir = g_path_get_dirname (filename); + args [0] = LLVMMDString (cu_name, strlen (cu_name)); + args [1] = LLVMMDString (dir, strlen (dir)); + cu_args [n_cuargs ++] = LLVMMDNode (args, 2); + g_free (dir); + /* Language */ + cu_args [n_cuargs ++] = LLVMConstInt (LLVMInt32Type (), DW_LANG_C99, FALSE); + /* Producer */ + build_info = mono_get_runtime_build_info (); + s = g_strdup_printf ("Mono AOT Compiler %s (LLVM)", build_info); + cu_args [n_cuargs ++] = LLVMMDString (s, strlen (s)); + g_free (build_info); + /* Optimized */ + cu_args [n_cuargs ++] = LLVMConstInt (LLVMInt32Type (), 1, FALSE); + /* Flags */ + cu_args [n_cuargs ++] = LLVMMDString ("", strlen ("")); + /* Runtime version */ + cu_args [n_cuargs ++] = LLVMConstInt (LLVMInt32Type (), 0, FALSE); + /* Enums */ + cu_args [n_cuargs ++] = LLVMMDNode (args, 0); + cu_args [n_cuargs ++] = LLVMMDNode (args, 0); + /* Subprograms */ + if (lmodule->subprogram_mds) { + LLVMValueRef *mds; + int i; + + mds = g_new0 (LLVMValueRef, lmodule->subprogram_mds->len); + for (i = 0; i < lmodule->subprogram_mds->len; ++i) + mds [i] = g_ptr_array_index (lmodule->subprogram_mds, i); + cu_args [n_cuargs ++] = LLVMMDNode (mds, lmodule->subprogram_mds->len); + } else { + cu_args [n_cuargs ++] = LLVMMDNode (args, 0); + } + /* GVs */ + cu_args [n_cuargs ++] = LLVMMDNode (args, 0); + /* Imported modules */ + cu_args [n_cuargs ++] = LLVMMDNode (args, 0); + /* SplitName */ + cu_args [n_cuargs ++] = LLVMMDString ("", strlen ("")); + /* DebugEmissionKind = FullDebug */ + cu_args [n_cuargs ++] = LLVMConstInt (LLVMInt32Type (), 1, FALSE); + cu = LLVMMDNode (cu_args, n_cuargs); + LLVMAddNamedMetadataOperand (module, "llvm.dbg.cu", cu); + + args [0] = LLVMConstInt (LLVMInt32Type (), 1, FALSE); + args [1] = LLVMMDString ("Dwarf Version", strlen ("Dwarf Version")); + args [2] = LLVMConstInt (LLVMInt32Type (), 2, FALSE); + ver = LLVMMDNode (args, 3); + LLVMAddNamedMetadataOperand (module, "llvm.module.flags", ver); + + args [0] = LLVMConstInt (LLVMInt32Type (), 1, FALSE); + args [1] = LLVMMDString ("Debug Info Version", strlen ("Debug Info Version")); + args [2] = LLVMConstInt (LLVMInt32Type (), 1, FALSE); + ver = LLVMMDNode (args, 3); + LLVMAddNamedMetadataOperand (module, "llvm.module.flags", ver); +} + +static LLVMValueRef +emit_dbg_subprogram (EmitContext *ctx, MonoCompile *cfg, LLVMValueRef method, const char *name) +{ + MonoLLVMModule *module = ctx->lmodule; + MonoDebugMethodInfo *minfo = ctx->minfo; + char *source_file, *dir, *filename; + LLVMValueRef md, args [16], ctx_args [16], md_args [64], type_args [16], ctx_md, type_md; + int n_il_offsets; + int *il_offsets; + int *line_numbers; + + if (!minfo) + return NULL; + + mono_debug_symfile_get_line_numbers_full (minfo, &source_file, NULL, &n_il_offsets, &il_offsets, &line_numbers, NULL, NULL, NULL, NULL); + if (!source_file) + source_file = g_strdup (""); + dir = g_path_get_dirname (source_file); + filename = g_path_get_basename (source_file); + + ctx_args [0] = LLVMConstInt (LLVMInt32Type (), 0x29, FALSE); + args [0] = md_string (filename); + args [1] = md_string (dir); + ctx_args [1] = LLVMMDNode (args, 2); + ctx_md = LLVMMDNode (ctx_args, 2); + + type_args [0] = LLVMConstInt (LLVMInt32Type (), DW_TAG_subroutine_type, FALSE); + type_args [1] = NULL; + type_args [2] = NULL; + type_args [3] = LLVMMDString ("", 0); + type_args [4] = LLVMConstInt (LLVMInt32Type (), 0, FALSE); + type_args [5] = LLVMConstInt (LLVMInt64Type (), 0, FALSE); + type_args [6] = LLVMConstInt (LLVMInt64Type (), 0, FALSE); + type_args [7] = LLVMConstInt (LLVMInt64Type (), 0, FALSE); + type_args [8] = LLVMConstInt (LLVMInt32Type (), 0, FALSE); + type_args [9] = NULL; + type_args [10] = NULL; + type_args [11] = LLVMConstInt (LLVMInt32Type (), 0, FALSE); + type_args [12] = NULL; + type_args [13] = NULL; + type_args [14] = NULL; + type_md = LLVMMDNode (type_args, 14); + + /* http://llvm.org/docs/SourceLevelDebugging.html#subprogram-descriptors */ + md_args [0] = LLVMConstInt (LLVMInt32Type (), DW_TAG_subprogram, FALSE); + /* Source directory + file pair */ + args [0] = md_string (filename); + args [1] = md_string (dir); + md_args [1] = LLVMMDNode (args ,2); + md_args [2] = ctx_md; + md_args [3] = md_string (cfg->method->name); + md_args [4] = md_string (name); + md_args [5] = md_string (name); + /* Line number */ + if (n_il_offsets) + md_args [6] = LLVMConstInt (LLVMInt32Type (), line_numbers [0], FALSE); + else + md_args [6] = LLVMConstInt (LLVMInt32Type (), 1, FALSE); + /* Type */ + md_args [7] = type_md; + /* static */ + md_args [8] = LLVMConstInt (LLVMInt1Type (), 0, FALSE); + /* not extern */ + md_args [9] = LLVMConstInt (LLVMInt1Type (), 1, FALSE); + /* Virtuality */ + md_args [10] = LLVMConstInt (LLVMInt32Type (), 0, FALSE); + /* Index into a virtual function */ + md_args [11] = NULL; + md_args [12] = NULL; + /* Flags */ + md_args [13] = LLVMConstInt (LLVMInt1Type (), 0, FALSE); + /* isOptimized */ + md_args [14] = LLVMConstInt (LLVMInt1Type (), 1, FALSE); + /* Pointer to LLVM function */ + md_args [15] = method; + /* Function template parameter */ + md_args [16] = NULL; + /* Function declaration descriptor */ + md_args [17] = NULL; + /* List of function variables */ + md_args [18] = LLVMMDNode (args, 0); + /* Line number */ + md_args [19] = LLVMConstInt (LLVMInt32Type (), 1, FALSE); + md = LLVMMDNode (md_args, 20); + + if (!module->subprogram_mds) + module->subprogram_mds = g_ptr_array_new (); + g_ptr_array_add (module->subprogram_mds, md); + + g_free (dir); + g_free (filename); + g_free (source_file); + g_free (il_offsets); + g_free (line_numbers); + + return md; +} + +static void +emit_dbg_loc (EmitContext *ctx, LLVMBuilderRef builder, const unsigned char *cil_code) +{ + MonoCompile *cfg = ctx->cfg; + + if (ctx->minfo && cil_code && cil_code >= cfg->header->code && cil_code < cfg->header->code + cfg->header->code_size) { + MonoDebugSourceLocation *loc; + LLVMValueRef loc_md, md_args [16]; + int nmd_args; + + loc = mono_debug_symfile_lookup_location (ctx->minfo, cil_code - cfg->header->code); + + if (loc) { + nmd_args = 0; + md_args [nmd_args ++] = LLVMConstInt (LLVMInt32Type (), loc->row, FALSE); + md_args [nmd_args ++] = LLVMConstInt (LLVMInt32Type (), loc->column, FALSE); + md_args [nmd_args ++] = ctx->dbg_md; + md_args [nmd_args ++] = NULL; + loc_md = LLVMMDNode (md_args, nmd_args); + LLVMSetCurrentDebugLocation (builder, loc_md); + mono_debug_symfile_free_location (loc); + } + } +} + /* DESIGN: - Emit LLVM IR from the mono IR using the LLVM C API. diff --git a/mono/mini/mini-llvm.h b/mono/mini/mini-llvm.h index 541ae3dd390..644b9b392dc 100644 --- a/mono/mini/mini-llvm.h +++ b/mono/mini/mini-llvm.h @@ -16,7 +16,7 @@ typedef void (*MonoLLVMVoidFunc)(void); typedef void (*MonoLLVMCFGFunc)(MonoCompile *cfg); typedef void (*MonoLLVMEmitCallFunc)(MonoCompile *cfg, MonoCallInst *call); typedef void (*MonoLLVMCreateAotFunc)(const char *got_symbol); -typedef void (*MonoLLVMEmitAotFunc)(const char *filename, int got_size); +typedef void (*MonoLLVMEmitAotFunc)(const char *filename, const char *cu_name, int got_size); typedef void (*MonoLLVMFreeDomainFunc)(MonoDomain *domain); static MonoLLVMVoidFunc mono_llvm_init_fptr; @@ -60,10 +60,10 @@ mono_llvm_create_aot_module (const char *got_symbol) } void -mono_llvm_emit_aot_module (const char *filename, int got_size) +mono_llvm_emit_aot_module (const char *filename, const char *cu_name, int got_size) { g_assert (mono_llvm_emit_aot_module_fptr); - mono_llvm_emit_aot_module_fptr (filename, got_size); + mono_llvm_emit_aot_module_fptr (filename, cu_name, got_size); } void diff --git a/mono/mini/mini-mips.h b/mono/mini/mini-mips.h index c94f7c898f3..d8d769130c4 100644 --- a/mono/mini/mini-mips.h +++ b/mono/mini/mini-mips.h @@ -268,7 +268,6 @@ typedef struct MonoCompileArch { #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 @@ -280,8 +279,6 @@ typedef struct MonoCompileArch { #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) diff --git a/mono/mini/mini-posix.c b/mono/mini/mini-posix.c index d26b4af4e92..5831d0976b6 100644 --- a/mono/mini/mini-posix.c +++ b/mono/mini/mini-posix.c @@ -25,6 +25,8 @@ #ifdef HAVE_SYS_SYSCALL_H #include #endif +#include + #include #include @@ -55,6 +57,7 @@ #include #include #include +#include #include "mini.h" #include @@ -81,7 +84,7 @@ mono_runtime_shutdown_stat_profiler (void) gboolean -SIG_HANDLER_SIGNATURE (mono_chain_signal) +MONO_SIG_HANDLER_SIGNATURE (mono_chain_signal) { return FALSE; } @@ -173,19 +176,17 @@ free_saved_signal_handlers (void) * 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; @@ -193,29 +194,28 @@ SIG_HANDLER_SIGNATURE (mono_chain_signal) 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 */ @@ -299,9 +299,9 @@ SIG_HANDLER_FUNC (static, sigusr1_signal_handler) #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; @@ -309,12 +309,43 @@ SIG_HANDLER_FUNC (static, sigprof_signal_handler) #else -SIG_HANDLER_FUNC (static, sigprof_signal_handler) +static int +get_stage2_signal_handler (void) +{ +#if defined(PLATFORM_ANDROID) + return SIGINFO; +#elif !defined (SIGRTMIN) +#ifdef SIGUSR2 + return SIGUSR2; +#else + return -1; +#endif /* SIGUSR2 */ +#else + static int prof2_signum = -1; + int i; + if (prof2_signum != -1) + return prof2_signum; + /* we try to avoid SIGRTMIN and any one that might have been set already */ + for (i = SIGRTMIN + 2; i < SIGRTMAX; ++i) { + struct sigaction sinfo; + sigaction (i, NULL, &sinfo); + if (sinfo.sa_handler == SIG_DFL && (void*)sinfo.sa_sigaction == (void*)SIG_DFL) { + prof2_signum = i; + return i; + } + } + /* fallback to the old way */ + return SIGRTMIN + 2; +#endif +} + + +static void +per_thread_profiler_hit (void *ctx) { int call_chain_depth = mono_profiler_stat_get_call_chain_depth (); MonoProfilerCallChainStrategy call_chain_strategy = mono_profiler_stat_get_call_chain_strategy (); - GET_CONTEXT; - + if (call_chain_depth == 0) { mono_profiler_stat_hit (mono_arch_ip_from_context (ctx), ctx); } else { @@ -381,18 +412,45 @@ SIG_HANDLER_FUNC (static, sigprof_signal_handler) mono_profiler_stat_call_chain (current_frame_index, & ips [0], ctx); } +} - mono_chain_signal (SIG_HANDLER_PARAMS); +MONO_SIG_HANDLER_FUNC (static, sigprof_stage2_signal_handler) +{ + MONO_SIG_HANDLER_GET_CONTEXT; + + per_thread_profiler_hit (ctx); + + mono_chain_signal (MONO_SIG_HANDLER_PARAMS); +} + +MONO_SIG_HANDLER_FUNC (static, sigprof_signal_handler) +{ + MonoThreadInfo *info; + int old_errno = errno; + int hp_save_index = mono_hazard_pointer_save_for_signal_handler (); + MONO_SIG_HANDLER_GET_CONTEXT; + + FOREACH_THREAD_SAFE (info) { + if (mono_thread_info_get_tid (info) == mono_native_thread_id_get ()) + continue; + mono_threads_pthread_kill (info, get_stage2_signal_handler ()); + } END_FOREACH_THREAD_SAFE; + + per_thread_profiler_hit (ctx); + + mono_hazard_pointer_restore_for_signal_handler (hp_save_index); + errno = old_errno; + + 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 (); @@ -415,16 +473,16 @@ SIG_HANDLER_FUNC (static, sigquit_signal_handler) 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 @@ -604,6 +662,30 @@ mono_runtime_shutdown_stat_profiler (void) #endif } +#ifdef ITIMER_PROF +static int +get_itimer_mode (void) +{ + switch (mono_profiler_get_sampling_mode ()) { + case MONO_PROFILER_STAT_MODE_PROCESS: return ITIMER_PROF; + case MONO_PROFILER_STAT_MODE_REAL: return ITIMER_REAL; + } + g_assert_not_reached (); + return 0; +} + +static int +get_itimer_signal (void) +{ + switch (mono_profiler_get_sampling_mode ()) { + case MONO_PROFILER_STAT_MODE_PROCESS: return SIGPROF; + case MONO_PROFILER_STAT_MODE_REAL: return SIGALRM; + } + g_assert_not_reached (); + return 0; +} +#endif + void mono_runtime_setup_stat_profiler (void) { @@ -648,14 +730,15 @@ mono_runtime_setup_stat_profiler (void) return; #endif - itval.it_interval.tv_usec = 999; + itval.it_interval.tv_usec = (1000000 / mono_profiler_get_sampling_rate ()) - 1; itval.it_interval.tv_sec = 0; itval.it_value = itval.it_interval; - setitimer (ITIMER_PROF, &itval, NULL); if (inited) return; inited = 1; - add_signal_handler (SIGPROF, sigprof_signal_handler); + add_signal_handler (get_itimer_signal (), sigprof_signal_handler); + add_signal_handler (get_stage2_signal_handler (), sigprof_stage2_signal_handler); + setitimer (get_itimer_mode (), &itval, NULL); #endif } diff --git a/mono/mini/mini-ppc.h b/mono/mini/mini-ppc.h index c3025a712e0..4b39b7ac223 100644 --- a/mono/mini/mini-ppc.h +++ b/mono/mini/mini-ppc.h @@ -182,7 +182,6 @@ typedef struct MonoCompileArch { #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 @@ -192,7 +191,6 @@ typedef struct MonoCompileArch { #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) diff --git a/mono/mini/mini-s390x.c b/mono/mini/mini-s390x.c index 435ef2904a4..d84c87860d1 100644 --- a/mono/mini/mini-s390x.c +++ b/mono/mini/mini-s390x.c @@ -624,7 +624,7 @@ indent (int diff) { if (diff < 0) indent_level += diff; v = indent_level; - printf("%p [%3d] ",pthread_self(),v); + printf("%p [%3d] ",(void *)pthread_self(),v); while (v-- > 0) { printf (". "); } @@ -2798,6 +2798,7 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb) case OP_IREM_UN_IMM: case OP_LAND_IMM: case OP_LOR_IMM: + case OP_LREM_IMM: case OP_LXOR_IMM: case OP_LOCALLOC_IMM: mono_decompose_op_imm (cfg, bb, ins); @@ -3312,6 +3313,17 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_lgr (code, ins->dreg, s390_r0); break; } + case OP_LREM_IMM: { + if (s390_is_imm16 (ins->inst_imm)) { + s390_lghi (code, s390_r13, ins->inst_imm); + } else { + s390_lgfi (code, s390_r13, ins->inst_imm); + } + s390_lgr (code, s390_r0, ins->sreg1); + s390_dsgr (code, s390_r0, s390_r13); + s390_lgfr (code, ins->dreg, s390_r0); + } + break; case OP_LREM_UN: { s390_lgr (code, s390_r1, ins->sreg1); s390_lghi (code, s390_r0, 0); @@ -5735,9 +5747,35 @@ mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_targe /*------------------------------------------------------------------*/ gpointer -mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method, int offset, gboolean load_imt_reg) +mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method, + int offset, gboolean load_imt_reg) { - return NULL; + guint8 *code, *start; + int size = 20; + + start = code = mono_global_codeman_reserve (size); + + /* + * Replace the "this" argument with the target + */ + s390_lgr (code, s390_r1, s390_r2); + s390_lg (code, s390_r2, s390_r1, 0, MONO_STRUCT_OFFSET(MonoDelegate, target)); + + /* + * Load the IMT register, if needed + */ + if (load_imt_reg) { + s390_lg (code, MONO_ARCH_IMT_REG, s390_r2, 0, MONO_STRUCT_OFFSET(MonoDelegate, method)); + } + + /* + * Load the vTable + */ + s390_lg (code, s390_r1, s390_r2, 0, MONO_STRUCT_OFFSET(MonoObject, vtable)); + s390_agfi(code, s390_r1, offset); + s390_br (code, s390_r1); + + return(start); } /*========================= End of Function ========================*/ @@ -5833,7 +5871,7 @@ mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, s390_lg (code, s390_r1, 0, s390_r1, 0); } s390_br (code, s390_r1); - target = S390_RELATIVE(code, item->jmp_code); + target = (gint64) S390_RELATIVE(code, item->jmp_code); s390_patch_rel(item->jmp_code+2, target); S390_SET (code, s390_r1, fail_tramp); s390_br (code, s390_r1); @@ -5863,7 +5901,7 @@ mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, if (item->jmp_code) { if (item->check_target_idx) { gint64 offset; - offset = S390_RELATIVE(imt_entries [item->check_target_idx]->code_target, + offset = (gint64) S390_RELATIVE(imt_entries [item->check_target_idx]->code_target, item->jmp_code); s390_patch_rel ((guchar *) item->jmp_code + 2, (guint64) offset); } @@ -5932,7 +5970,7 @@ mono_arch_get_cie_program (void) { GSList *l = NULL; - mono_add_unwind_op_def_cfa (l, NULL, NULL, STK_BASE, 0); + mono_add_unwind_op_def_cfa (l, 0, 0, STK_BASE, 0); return(l); } diff --git a/mono/mini/mini-s390x.h b/mono/mini/mini-s390x.h index 50b74c51fd9..b40425c6478 100644 --- a/mono/mini/mini-s390x.h +++ b/mono/mini/mini-s390x.h @@ -53,8 +53,6 @@ typedef struct #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 diff --git a/mono/mini/mini-sparc.c b/mono/mini/mini-sparc.c old mode 100644 new mode 100755 index 3b95fd97033..21c2b0cda1b --- a/mono/mini/mini-sparc.c +++ b/mono/mini/mini-sparc.c @@ -4354,7 +4354,7 @@ mono_arch_tls_init (void) } - jit_tls = pthread_getspecific (mono_get_jit_tls_key ()); + jit_tls = mono_get_jit_tls (); #ifdef MONO_SPARC_THR_TLS thr_setspecific (lmf_addr_key, &jit_tls->lmf); diff --git a/mono/mini/mini-sparc.h b/mono/mini/mini-sparc.h index 4b947784558..ab8e452b70e 100644 --- a/mono/mini/mini-sparc.h +++ b/mono/mini/mini-sparc.h @@ -112,8 +112,6 @@ void mono_arch_tls_init (void); #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) diff --git a/mono/mini/mini-trampolines.c b/mono/mini/mini-trampolines.c index f65dab8c1e7..d8f1e4298e9 100644 --- a/mono/mini/mini-trampolines.c +++ b/mono/mini/mini-trampolines.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "mini.h" @@ -140,18 +141,15 @@ mono_create_static_rgctx_trampoline (MonoMethod *m, gpointer addr) /* * Either IMPL_METHOD or AOT_ADDR will be set on return. - */ -static gpointer* -#ifdef __GNUC__ -/* + * + * MONO_NEVER_INLINE : * This works against problems when compiling with gcc 4.6 on arm. The 'then' part of * this line gets executed, even when the condition is false: * if (impl && mono_method_needs_static_rgctx_invoke (impl, FALSE)) * *need_rgctx_tramp = TRUE; */ -__attribute__ ((noinline)) -#endif - mono_convert_imt_slot_to_vtable_slot (gpointer* slot, mgreg_t *regs, guint8 *code, MonoMethod *method, gboolean lookup_aot, MonoMethod **impl_method, gboolean *need_rgctx_tramp, gboolean *variance_used, gpointer *aot_addr) +static MONO_NEVER_INLINE gpointer* +mono_convert_imt_slot_to_vtable_slot (gpointer* slot, mgreg_t *regs, guint8 *code, MonoMethod *method, gboolean lookup_aot, MonoMethod **impl_method, gboolean *need_rgctx_tramp, gboolean *variance_used, gpointer *aot_addr) { MonoObject *this_argument = mono_arch_get_this_arg_from_call (regs, code); MonoVTable *vt = this_argument->vtable; @@ -730,10 +728,6 @@ mono_vcall_trampoline (mgreg_t *regs, guint8 *code, int slot, guint8 *tramp) * 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. diff --git a/mono/mini/mini-windows.c b/mono/mini/mini-windows.c index c43b1d0102f..9488ac895d9 100644 --- a/mono/mini/mini-windows.c +++ b/mono/mini/mini-windows.c @@ -79,7 +79,7 @@ mono_runtime_cleanup_handlers (void) * 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; @@ -123,7 +123,7 @@ mono_runtime_setup_stat_profiler (void) if (timeBeginPeriod (1) != TIMERR_NOERROR) return; - if ((win32_timer = timeSetEvent (1, 0, win32_time_proc, 0, TIME_PERIODIC)) == 0) { + if ((win32_timer = timeSetEvent (1, 0, (LPTIMECALLBACK)win32_time_proc, (DWORD_PTR)NULL, TIME_PERIODIC)) == 0) { timeEndPeriod (1); return; } @@ -137,7 +137,65 @@ mono_runtime_shutdown_stat_profiler (void) gboolean mono_thread_state_init_from_handle (MonoThreadUnwindState *tctx, MonoThreadInfo *info) { - g_error ("Windows systems haven't been ported to support mono_thread_state_init_from_handle"); - return FALSE; + DWORD id = mono_thread_info_get_tid (info); + HANDLE handle; + CONTEXT context; + DWORD result; + MonoContext *ctx; + MonoJitTlsData *jit_tls; + void *domain; + MonoLMF *lmf = NULL; + gpointer *addr; + + tctx->valid = FALSE; + tctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = NULL; + tctx->unwind_data [MONO_UNWIND_DATA_LMF] = NULL; + tctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = NULL; + + g_assert (id != GetCurrentThreadId ()); + + handle = OpenThread (THREAD_ALL_ACCESS, FALSE, id); + g_assert (handle); + + context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL; + + if (!GetThreadContext (handle, &context)) { + CloseHandle (handle); + return FALSE; + } + + g_assert (context.ContextFlags & CONTEXT_INTEGER); + g_assert (context.ContextFlags & CONTEXT_CONTROL); + + ctx = &tctx->ctx; + + memset (ctx, 0, sizeof (MonoContext)); + mono_sigctx_to_monoctx (&context, ctx); + + /* mono_set_jit_tls () sets this */ + jit_tls = mono_thread_info_tls_get (info, TLS_KEY_JIT_TLS); + /* SET_APPDOMAIN () sets this */ + domain = mono_thread_info_tls_get (info, TLS_KEY_DOMAIN); + + /*Thread already started to cleanup, can no longer capture unwind state*/ + if (!jit_tls || !domain) + return FALSE; + + /* + * The current LMF address is kept in a separate TLS variable, and its hard to read its value without + * arch-specific code. But the address of the TLS variable is stored in another TLS variable which + * can be accessed through MonoThreadInfo. + */ + /* mono_set_lmf_addr () sets this */ + addr = mono_thread_info_tls_get (info, TLS_KEY_LMF_ADDR); + if (addr) + lmf = *addr; + + tctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = domain; + tctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = jit_tls; + tctx->unwind_data [MONO_UNWIND_DATA_LMF] = lmf; + tctx->valid = TRUE; + + return TRUE; } diff --git a/mono/mini/mini-x86.c b/mono/mini/mini-x86.c index c7931e328ff..05b72c05f6b 100644 --- a/mono/mini/mini-x86.c +++ b/mono/mini/mini-x86.c @@ -1217,10 +1217,6 @@ mono_arch_create_vars (MonoCompile *cfg) cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG); } -#ifdef MONO_X86_NO_PUSHES - cfg->arch.no_pushes = TRUE; -#endif - if (cfg->method->save_lmf) { cfg->create_lmf_var = TRUE; cfg->lmf_ir = TRUE; @@ -1279,17 +1275,9 @@ emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo) if (cfg->compile_aot) { sig_reg = mono_alloc_ireg (cfg); MONO_EMIT_NEW_SIGNATURECONST (cfg, sig_reg, tmp_sig); - if (cfg->arch.no_pushes) { - MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, X86_ESP, cinfo->sig_cookie.offset, sig_reg); - } else { - MONO_EMIT_NEW_UNALU (cfg, OP_X86_PUSH, -1, sig_reg); - } + MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, X86_ESP, cinfo->sig_cookie.offset, sig_reg); } else { - if (cfg->arch.no_pushes) { - MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, X86_ESP, cinfo->sig_cookie.offset, tmp_sig); - } else { - MONO_EMIT_NEW_BIALU_IMM (cfg, OP_X86_PUSH_IMM, -1, -1, tmp_sig); - } + MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, X86_ESP, cinfo->sig_cookie.offset, tmp_sig); } } @@ -1415,7 +1403,7 @@ emit_gc_param_slot_def (MonoCompile *cfg, int sp_offset, MonoType *t) MonoInst *def; /* Needs checking if the feature will be enabled again */ - g_assert (!cfg->arch.no_pushes); + g_assert_not_reached (); /* On x86, the offsets are from the sp value before the start of the call sequence */ if (t == NULL) @@ -1444,19 +1432,6 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG)) sentinelpos = sig->sentinelpos + (sig->hasthis ? 1 : 0); - if (cinfo->need_stack_align && !cfg->arch.no_pushes) { - MONO_INST_NEW (cfg, arg, OP_SUB_IMM); - arg->dreg = X86_ESP; - arg->sreg1 = X86_ESP; - arg->inst_imm = cinfo->stack_align_amount; - MONO_ADD_INS (cfg->cbb, arg); - for (i = 0; i < cinfo->stack_align_amount; i += sizeof (mgreg_t)) { - sp_offset += 4; - - emit_gc_param_slot_def (cfg, sp_offset, NULL); - } - } - if (sig_ret && MONO_TYPE_ISSTRUCT (sig_ret)) { if (cinfo->ret.storage == ArgValuetypeInReg) { /* @@ -1465,6 +1440,10 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) * 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); } @@ -1475,7 +1454,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) /* Handle the case where there are no implicit arguments */ if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sentinelpos)) { emit_sig_cookie (cfg, call, cinfo); - sp_offset = (cfg->arch.no_pushes) ? cinfo->sig_cookie.offset : (sp_offset + 4); + sp_offset = cinfo->sig_cookie.offset; emit_gc_param_slot_def (cfg, sp_offset, NULL); } @@ -1487,23 +1466,15 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) if (cinfo->vtype_retaddr && cinfo->vret_arg_index == 1 && i == 0) { MonoInst *vtarg; + /* Push the vret arg before the first argument */ - if (cfg->arch.no_pushes) { - MONO_INST_NEW (cfg, vtarg, OP_STORE_MEMBASE_REG); - vtarg->type = STACK_MP; - vtarg->inst_destbasereg = X86_ESP; - vtarg->sreg1 = call->vret_var->dreg; - vtarg->inst_offset = cinfo->ret.offset; - MONO_ADD_INS (cfg->cbb, vtarg); - sp_offset = cinfo->ret.offset; - } else { - MONO_INST_NEW (cfg, vtarg, OP_X86_PUSH); - vtarg->type = STACK_MP; - vtarg->sreg1 = call->vret_var->dreg; - MONO_ADD_INS (cfg->cbb, vtarg); - sp_offset += 4; - } - emit_gc_param_slot_def (cfg, sp_offset, NULL); + MONO_INST_NEW (cfg, vtarg, OP_STORE_MEMBASE_REG); + vtarg->type = STACK_MP; + vtarg->inst_destbasereg = X86_ESP; + vtarg->sreg1 = call->vret_var->dreg; + vtarg->inst_offset = cinfo->ret.offset; + MONO_ADD_INS (cfg->cbb, vtarg); + emit_gc_param_slot_def (cfg, cinfo->ret.offset, NULL); } if (i >= sig->hasthis) @@ -1555,8 +1526,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) MONO_ADD_INS (cfg->cbb, arg); if (ainfo->storage != ArgValuetypeInReg) { - sp_offset = (cfg->arch.no_pushes) ? ainfo->offset : (sp_offset + size); - emit_gc_param_slot_def (cfg, sp_offset, orig_type); + emit_gc_param_slot_def (cfg, ainfo->offset, orig_type); } } } else { @@ -1564,47 +1534,21 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) case ArgOnStack: if (!t->byref) { if (t->type == MONO_TYPE_R4) { - if (cfg->arch.no_pushes) { - MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, X86_ESP, ainfo->offset, in->dreg); - } else { - MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUB_IMM, X86_ESP, X86_ESP, 4); - MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, X86_ESP, 0, in->dreg); - } + MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, X86_ESP, ainfo->offset, in->dreg); argsize = 4; } else if (t->type == MONO_TYPE_R8) { - if (cfg->arch.no_pushes) { - MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, X86_ESP, ainfo->offset, in->dreg); - } else { - MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUB_IMM, X86_ESP, X86_ESP, 8); - MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, X86_ESP, 0, in->dreg); - } + MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, X86_ESP, ainfo->offset, in->dreg); argsize = 8; } else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_U8) { - if (cfg->arch.no_pushes) { - MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, X86_ESP, ainfo->offset + 4, in->dreg + 2); - MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, X86_ESP, ainfo->offset, in->dreg + 1); - } else { - MONO_EMIT_NEW_UNALU (cfg, OP_X86_PUSH, -1, in->dreg + 2); - MONO_EMIT_NEW_UNALU (cfg, OP_X86_PUSH, -1, in->dreg + 1); - sp_offset += 4; - } + MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, X86_ESP, ainfo->offset + 4, in->dreg + 2); + MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, X86_ESP, ainfo->offset, in->dreg + 1); argsize = 4; } else { - if (cfg->arch.no_pushes) { - MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, X86_ESP, ainfo->offset, in->dreg); - } else { - arg->opcode = OP_X86_PUSH; - MONO_ADD_INS (cfg->cbb, arg); - } + MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, X86_ESP, ainfo->offset, in->dreg); argsize = 4; } } else { - if (cfg->arch.no_pushes) { - MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, X86_ESP, ainfo->offset, in->dreg); - } else { - arg->opcode = OP_X86_PUSH; - MONO_ADD_INS (cfg->cbb, arg); - } + MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, X86_ESP, ainfo->offset, in->dreg); argsize = 4; } break; @@ -1618,8 +1562,6 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) g_assert_not_reached (); } - sp_offset = (cfg->arch.no_pushes) ? ainfo->offset : (sp_offset + argsize); - if (cfg->compute_gc_maps) { if (argsize == 4) { /* FIXME: The == STACK_OBJ check might be fragile ? */ @@ -1627,20 +1569,16 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) /* this */ if (call->need_unbox_trampoline) /* The unbox trampoline transforms this into a managed pointer */ - emit_gc_param_slot_def (cfg, sp_offset, &mono_defaults.int_class->this_arg); + emit_gc_param_slot_def (cfg, ainfo->offset, &mono_defaults.int_class->this_arg); else - emit_gc_param_slot_def (cfg, sp_offset, &mono_defaults.object_class->byval_arg); + emit_gc_param_slot_def (cfg, ainfo->offset, &mono_defaults.object_class->byval_arg); } else { - emit_gc_param_slot_def (cfg, sp_offset, orig_type); + emit_gc_param_slot_def (cfg, ainfo->offset, orig_type); } } else { /* i8/r8 */ - for (j = 0; j < argsize; j += 4) { - if (cfg->arch.no_pushes) - emit_gc_param_slot_def (cfg, sp_offset + j, NULL); - else - emit_gc_param_slot_def (cfg, sp_offset - j, NULL); - } + for (j = 0; j < argsize; j += 4) + emit_gc_param_slot_def (cfg, ainfo->offset + j, NULL); } } } @@ -1648,8 +1586,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sentinelpos)) { /* Emit the signature cookie just before the implicit arguments */ emit_sig_cookie (cfg, call, cinfo); - sp_offset = (cfg->arch.no_pushes) ? cinfo->sig_cookie.offset : (sp_offset + 4); - emit_gc_param_slot_def (cfg, sp_offset, NULL); + emit_gc_param_slot_def (cfg, cinfo->sig_cookie.offset, NULL); } } @@ -1669,29 +1606,13 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->ret.reg, FALSE); } else if (cinfo->vtype_retaddr && cinfo->vret_arg_index == 0) { - if (cfg->arch.no_pushes) { - MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, X86_ESP, cinfo->ret.offset, call->vret_var->dreg); - sp_offset = cinfo->ret.offset; - } else { - MonoInst *vtarg; - MONO_INST_NEW (cfg, vtarg, OP_X86_PUSH); - vtarg->type = STACK_MP; - vtarg->sreg1 = call->vret_var->dreg; - MONO_ADD_INS (cfg->cbb, vtarg); - sp_offset += 4; - } - emit_gc_param_slot_def (cfg, sp_offset, NULL); + MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, X86_ESP, cinfo->ret.offset, call->vret_var->dreg); + emit_gc_param_slot_def (cfg, cinfo->ret.offset, NULL); } - - /* if the function returns a struct on stack, the called method already does a ret $0x4 */ - if (!cfg->arch.no_pushes) - cinfo->stack_usage -= cinfo->callee_stack_pop; } call->stack_usage = cinfo->stack_usage; call->stack_align_amount = cinfo->stack_align_amount; - if (!cfg->arch.no_pushes) - cfg->arch.param_area_size = MAX (cfg->arch.param_area_size, sp_offset); } void @@ -1699,7 +1620,6 @@ mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src) { MonoCallInst *call = (MonoCallInst*)ins->inst_p0; ArgInfo *ainfo = ins->inst_p1; - MonoInst *arg; int size = ins->backend.size; if (ainfo->storage == ArgValuetypeInReg) { @@ -1723,42 +1643,16 @@ mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src) else { if (cfg->gsharedvt && mini_is_gsharedvt_klass (cfg, ins->klass)) { /* Pass by addr */ - if (cfg->arch.no_pushes) { - MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, X86_ESP, ainfo->offset, src->dreg); - } else { - MONO_INST_NEW (cfg, arg, OP_X86_PUSH); - arg->sreg1 = src->dreg; - MONO_ADD_INS (cfg->cbb, arg); - } + MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, X86_ESP, ainfo->offset, src->dreg); } else if (size <= 4) { - if (cfg->arch.no_pushes) { - int dreg = mono_alloc_ireg (cfg); - MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, 0); - MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, X86_ESP, ainfo->offset, dreg); - } else { - MONO_INST_NEW (cfg, arg, OP_X86_PUSH_MEMBASE); - arg->sreg1 = src->dreg; - MONO_ADD_INS (cfg->cbb, arg); - } + int dreg = mono_alloc_ireg (cfg); + MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, 0); + MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, X86_ESP, ainfo->offset, dreg); } else if (size <= 20) { - if (cfg->arch.no_pushes) { - mini_emit_memcpy (cfg, X86_ESP, ainfo->offset, src->dreg, 0, size, 4); - } else { - MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUB_IMM, X86_ESP, X86_ESP, ALIGN_TO (size, 4)); - mini_emit_memcpy (cfg, X86_ESP, 0, src->dreg, 0, size, 4); - } + mini_emit_memcpy (cfg, X86_ESP, ainfo->offset, src->dreg, 0, size, 4); } else { - if (cfg->arch.no_pushes) { - // FIXME: Code growth - mini_emit_memcpy (cfg, X86_ESP, ainfo->offset, src->dreg, 0, size, 4); - } else { - MONO_INST_NEW (cfg, arg, OP_X86_PUSH_OBJ); - arg->inst_basereg = src->dreg; - arg->inst_offset = 0; - arg->inst_imm = size; - - MONO_ADD_INS (cfg->cbb, arg); - } + // FIXME: Code growth + mini_emit_memcpy (cfg, X86_ESP, ainfo->offset, src->dreg, 0, size, 4); } } } @@ -2301,7 +2195,7 @@ mono_emit_stack_alloc (MonoCompile *cfg, guchar *code, MonoInst* tree) x86_push_reg (code, X86_EDI); x86_mov_reg_imm (code, X86_ECX, (0x1000 >> 2)); x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EAX); - if (cfg->param_area && cfg->arch.no_pushes) + if (cfg->param_area) x86_lea_membase (code, X86_EDI, X86_ESP, 12 + ALIGN_TO (cfg->param_area, MONO_ARCH_FRAME_ALIGNMENT)); else x86_lea_membase (code, X86_EDI, X86_ESP, 12); @@ -2351,7 +2245,7 @@ mono_emit_stack_alloc (MonoCompile *cfg, guchar *code, MonoInst* tree) x86_mov_reg_reg (code, X86_ECX, sreg, 4); x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EAX); - if (cfg->param_area && cfg->arch.no_pushes) + if (cfg->param_area) x86_lea_membase (code, X86_EDI, X86_ESP, offset + ALIGN_TO (cfg->param_area, MONO_ARCH_FRAME_ALIGNMENT)); else x86_lea_membase (code, X86_EDI, X86_ESP, offset); @@ -3396,65 +3290,13 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } ins->flags |= MONO_INST_GC_CALLSITE; ins->backend.pc_offset = code - cfg->native_code; - if (call->stack_usage && !CALLCONV_IS_STDCALL (call->signature) && !cfg->arch.no_pushes) { - /* a pop is one byte, while an add reg, imm is 3. So if there are 4 or 8 - * bytes to pop, we want to use pops. GCC does this (note it won't happen - * for P4 or i686 because gcc will avoid using pop push at all. But we aren't - * smart enough to do that optimization yet - * - * It turns out that on my P4, doing two pops for 8 bytes on the stack makes - * mcs botstrap slow down. However, doing 1 pop for 4 bytes creates a small, - * (most likely from locality benefits). People with other processors should - * check on theirs to see what happens. - */ - if (call->stack_usage == 4) { - /* we want to use registers that won't get used soon, so use - * ecx, as eax will get allocated first. edx is used by long calls, - * so we can't use that. - */ - - x86_pop_reg (code, X86_ECX); - } else { - x86_alu_reg_imm (code, X86_ADD, X86_ESP, call->stack_usage); - } - } else if (cinfo->callee_stack_pop && cfg->arch.no_pushes) { + if (cinfo->callee_stack_pop) { /* Have to compensate for the stack space popped by the callee */ x86_alu_reg_imm (code, X86_SUB, X86_ESP, cinfo->callee_stack_pop); } code = emit_move_return_value (cfg, ins, code); break; } - case OP_X86_PUSH: - g_assert (!cfg->arch.no_pushes); - x86_push_reg (code, ins->sreg1); - break; - case OP_X86_PUSH_IMM: - g_assert (!cfg->arch.no_pushes); - x86_push_imm (code, ins->inst_imm); - break; - case OP_X86_PUSH_MEMBASE: - g_assert (!cfg->arch.no_pushes); - x86_push_membase (code, ins->inst_basereg, ins->inst_offset); - break; - case OP_X86_PUSH_OBJ: - g_assert (!cfg->arch.no_pushes); - x86_alu_reg_imm (code, X86_SUB, X86_ESP, ins->inst_imm); - x86_push_reg (code, X86_EDI); - x86_push_reg (code, X86_ESI); - x86_push_reg (code, X86_ECX); - if (ins->inst_offset) - x86_lea_membase (code, X86_ESI, ins->inst_basereg, ins->inst_offset); - else - x86_mov_reg_reg (code, X86_ESI, ins->inst_basereg, 4); - x86_lea_membase (code, X86_EDI, X86_ESP, 12); - x86_mov_reg_imm (code, X86_ECX, (ins->inst_imm >> 2)); - x86_cld (code); - x86_prefix (code, X86_REP_PREFIX); - x86_movsd (code); - x86_pop_reg (code, X86_ECX); - x86_pop_reg (code, X86_ESI); - x86_pop_reg (code, X86_EDI); - break; case OP_X86_LEA: x86_lea_memindex (code, ins->dreg, ins->sreg1, ins->inst_imm, ins->sreg2, ins->backend.shift_amount); break; @@ -3470,8 +3312,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) x86_alu_reg_imm (code, X86_AND, ins->sreg1, ~(MONO_ARCH_LOCALLOC_ALIGNMENT - 1)); code = mono_emit_stack_alloc (cfg, code, ins); x86_mov_reg_reg (code, ins->dreg, X86_ESP, 4); - if (cfg->param_area && cfg->arch.no_pushes) - x86_alu_reg_imm (code, X86_ADD, ins->dreg, ALIGN_TO (cfg->param_area, MONO_ARCH_FRAME_ALIGNMENT)); + if (cfg->param_area) + x86_alu_reg_imm (code, X86_ADD, ins->dreg, ALIGN_TO (cfg->param_area, MONO_ARCH_FRAME_ALIGNMENT)); break; case OP_LOCALLOC_IMM: { guint32 size = ins->inst_imm; @@ -3488,8 +3330,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) x86_alu_reg_imm (code, X86_SUB, X86_ESP, size); x86_mov_reg_reg (code, ins->dreg, X86_ESP, 4); } - if (cfg->param_area && cfg->arch.no_pushes) - x86_alu_reg_imm (code, X86_ADD, ins->dreg, ALIGN_TO (cfg->param_area, MONO_ARCH_FRAME_ALIGNMENT)); + if (cfg->param_area) + x86_alu_reg_imm (code, X86_ADD, ins->dreg, ALIGN_TO (cfg->param_area, MONO_ARCH_FRAME_ALIGNMENT)); break; } case OP_THROW: { @@ -3520,9 +3362,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_START_HANDLER: { MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region); x86_mov_membase_reg (code, spvar->inst_basereg, spvar->inst_offset, X86_ESP, 4); - if (cfg->param_area && cfg->arch.no_pushes) { + if (cfg->param_area) x86_alu_reg_imm (code, X86_SUB, X86_ESP, ALIGN_TO (cfg->param_area, MONO_ARCH_FRAME_ALIGNMENT)); - } break; } case OP_ENDFINALLY: { @@ -5347,10 +5188,8 @@ mono_arch_emit_prolog (MonoCompile *cfg) cfg->frame_reg = X86_ESP; } - if (cfg->arch.no_pushes) { - cfg->stack_offset += cfg->param_area; - cfg->stack_offset = ALIGN_TO (cfg->stack_offset, MONO_ARCH_FRAME_ALIGNMENT); - } + cfg->stack_offset += cfg->param_area; + cfg->stack_offset = ALIGN_TO (cfg->stack_offset, MONO_ARCH_FRAME_ALIGNMENT); alloc_size = cfg->stack_offset; pos = 0; diff --git a/mono/mini/mini-x86.h b/mono/mini/mini-x86.h index 05b977c547a..f6ddc930427 100644 --- a/mono/mini/mini-x86.h +++ b/mono/mini/mini-x86.h @@ -74,8 +74,6 @@ struct sigcontext { #endif /* HAVE_WORKING_SIGALTSTACK */ #endif /* !HOST_WIN32 */ -/* #define MONO_X86_NO_PUSHES 1 */ - #define MONO_ARCH_SUPPORT_TASKLETS 1 #ifndef DISABLE_SIMD @@ -169,7 +167,6 @@ struct MonoLMF { typedef struct { gboolean need_stack_frame_inited; gboolean need_stack_frame; - gboolean no_pushes; int sp_fp_offset, param_area_size; } MonoCompileArch; @@ -220,7 +217,6 @@ typedef struct { #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 @@ -249,7 +245,6 @@ typedef struct { #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 diff --git a/mono/mini/mini.c b/mono/mini/mini.c old mode 100644 new mode 100755 index 03e0eb7f8b3..dd40298565b --- a/mono/mini/mini.c +++ b/mono/mini/mini.c @@ -711,17 +711,22 @@ mono_debug_count (void) { 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; } @@ -1241,7 +1246,7 @@ mono_compile_create_var_for_vreg (MonoCompile *cfg, MonoType *type, int opcode, 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)); @@ -2629,17 +2634,20 @@ MONO_FAST_TLS_DECLARE(mono_lmf); #endif #endif -MonoNativeTlsKey -mono_get_jit_tls_key (void) -{ - return mono_jit_tls_id; -} - gint32 mono_get_jit_tls_offset (void) { int offset; + +#ifdef HOST_WIN32 + if (mono_jit_tls_id) + offset = mono_jit_tls_id; + else + /* FIXME: Happens during startup */ + offset = -1; +#else MONO_THREAD_VAR_OFFSET (mono_jit_tls, offset); +#endif return offset; } @@ -2952,11 +2960,7 @@ mini_get_tls_offset (MonoTlsKey key) offset = mono_thread_get_tls_offset (); break; case TLS_KEY_JIT_TLS: -#ifdef HOST_WIN32 - offset = mono_get_jit_tls_key (); -#else offset = mono_get_jit_tls_offset (); -#endif break; case TLS_KEY_DOMAIN: offset = mono_domain_get_tls_offset (); @@ -3240,9 +3244,10 @@ mono_patch_info_hash (gconstpointer data) case MONO_PATCH_INFO_JIT_TLS_ID: case MONO_PATCH_INFO_MONITOR_ENTER: case MONO_PATCH_INFO_MONITOR_EXIT: - case MONO_PATCH_INFO_CASTCLASS_CACHE: case MONO_PATCH_INFO_GOT_OFFSET: return (ji->type << 8); + case MONO_PATCH_INFO_CASTCLASS_CACHE: + return (ji->type << 8) | (ji->data.index); case MONO_PATCH_INFO_SWITCH: return (ji->type << 8) | ji->data.table->table_size; case MONO_PATCH_INFO_GSHAREDVT_METHOD: @@ -3307,6 +3312,8 @@ mono_patch_info_equal (gconstpointer ka, gconstpointer kb) return ji1->data.gsharedvt_method->method == ji2->data.gsharedvt_method->method; case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE: return ji1->data.del_tramp->klass == ji2->data.del_tramp->klass && ji1->data.del_tramp->method == ji2->data.del_tramp->method && ji1->data.del_tramp->virtual == ji2->data.del_tramp->virtual; + case MONO_PATCH_INFO_CASTCLASS_CACHE: + return ji1->data.index == ji2->data.index; default: if (ji1->data.target != ji2->data.target) return 0; @@ -4327,18 +4334,15 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile) 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; @@ -4352,8 +4356,11 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile) 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 && !(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) { @@ -4368,34 +4375,25 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile) ++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; @@ -4405,8 +4403,6 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile) MonoGenericJitInfo *gi; GSList *loclist = NULL; - jinfo->has_generic_jit_info = 1; - gi = mono_jit_info_get_generic_jit_info (jinfo); g_assert (gi); @@ -4480,7 +4476,6 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile) 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; @@ -4509,19 +4504,14 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile) 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)); @@ -4651,16 +4641,13 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile) unwind_desc = mono_cache_unwind_info (unwind_info, info_len); if (cfg->has_unwind_info_for_epilog) { - /* - * The lower 16 bits identify the unwind descriptor, the upper 16 bits contain the offset of - * the start of the epilog from the end of the method. - */ - g_assert (unwind_desc < 0xffff); - g_assert (cfg->code_size - cfg->epilog_begin < 0xffff); - jinfo->unwind_info = ((cfg->code_size - cfg->epilog_begin) << 16) | unwind_desc; - } else { - jinfo->unwind_info = unwind_desc; + MonoArchEHJitInfo *info; + + info = mono_jit_info_get_arch_eh_info (jinfo); + g_assert (info); + info->epilog_size = cfg->code_size - cfg->epilog_begin; } + jinfo->unwind_info = unwind_desc; g_free (unwind_info); } else { jinfo->unwind_info = cfg->used_int_regs; @@ -4935,6 +4922,11 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl gboolean run_cctors = (flags & JIT_FLAG_RUN_CCTORS) ? 1 : 0; gboolean compile_aot = (flags & JIT_FLAG_AOT) ? 1 : 0; gboolean full_aot = (flags & JIT_FLAG_FULL_AOT) ? 1 : 0; +#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) @@ -4976,7 +4968,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl } #ifdef ENABLE_LLVM - try_llvm = mono_use_llvm; + try_llvm = mono_use_llvm || llvm; #endif restart_compile: @@ -5048,6 +5040,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl 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; @@ -5084,9 +5077,8 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl { static gboolean inited; - if (!inited) { + if (!inited) inited = TRUE; - } /* * Check for methods which cannot be compiled by LLVM early, to avoid @@ -5162,8 +5154,12 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl 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; @@ -5174,7 +5170,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl } 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; } } @@ -5281,7 +5277,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl /* 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) { @@ -6738,14 +6734,12 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec 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)); @@ -6763,12 +6757,12 @@ SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler) #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; } } @@ -6776,10 +6770,10 @@ SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler) 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"); @@ -6790,13 +6784,15 @@ SIG_HANDLER_FUNC (, mono_sigill_signal_handler) #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)) { @@ -6818,11 +6814,11 @@ SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler) /* 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; } } @@ -6855,7 +6851,7 @@ SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler) 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); @@ -6863,13 +6859,13 @@ SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler) #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; } } @@ -6878,10 +6874,10 @@ SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler) #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)."); @@ -7274,6 +7270,43 @@ mini_free_jit_domain_info (MonoDomain *domain) domain->runtime_info = NULL; } +#ifdef ENABLE_LLVM +static gboolean +llvm_init_inner (void) +{ + if (!mono_llvm_load (NULL)) + return FALSE; + + mono_llvm_init (); + return TRUE; +} +#endif + +/* + * mini_llvm_init: + * + * Load and initialize LLVM support. + * Return TRUE on success. + */ +gboolean +mini_llvm_init (void) +{ +#ifdef ENABLE_LLVM + static gboolean llvm_inited; + static gboolean init_result; + + mono_loader_lock_if_inited (); + if (!llvm_inited) { + init_result = llvm_init_inner (); + llvm_inited = TRUE; + } + mono_loader_unlock_if_inited (); + return init_result; +#else + return FALSE; +#endif +} + MonoDomain * mini_init (const char *filename, const char *runtime_version) { @@ -7394,13 +7427,8 @@ mini_init (const char *filename, const char *runtime_version) mono_threads_install_cleanup (mini_thread_cleanup); #ifdef MONO_ARCH_HAVE_NOTIFY_PENDING_EXC - // This is experimental code so provide an env var to switch it off - if (g_getenv ("MONO_DISABLE_PENDING_EXCEPTIONS")) { - printf ("MONO_DISABLE_PENDING_EXCEPTIONS env var set.\n"); - } else { - check_for_pending_exc = FALSE; - mono_threads_install_notify_pending_exc (mono_arch_notify_pending_exc); - } + check_for_pending_exc = FALSE; + mono_threads_install_notify_pending_exc ((MonoThreadNotifyPendingExcFunc)mono_arch_notify_pending_exc); #endif #define JIT_TRAMPOLINES_WORK @@ -7937,6 +7965,8 @@ mono_precompile_assembly (MonoAssembly *ass, void *user_data) 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) { diff --git a/mono/mini/mini.h b/mono/mini/mini.h old mode 100644 new mode 100755 index cccdc095616..658f2701c60 --- a/mono/mini/mini.h +++ b/mono/mini/mini.h @@ -31,6 +31,7 @@ #include #include #include +#include #define MONO_BREAKPOINT_ARRAY_SIZE 64 @@ -53,19 +54,6 @@ #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) @@ -95,14 +83,6 @@ #define COMPILE_SOFT_FLOAT(cfg) (0) #endif -#ifdef ENABLE_LLVM -#define LLVM_CHECK_VERSION(major,minor) \ - ((LLVM_MAJOR_VERSION > (major)) || \ - ((LLVM_MAJOR_VERSION == (major)) && (LLVM_MINOR_VERSION >= (minor)))) -#else -#define LLVM_CHECK_VERSION(major,minor) 0 -#endif - #define NOT_IMPLEMENTED do { g_assert_not_reached (); } while (0) /* for 32 bit systems */ @@ -123,7 +103,7 @@ #endif /* Version number of the AOT file format */ -#define MONO_AOT_FILE_VERSION 101 +#define MONO_AOT_FILE_VERSION 103 //TODO: This is x86/amd64 specific. #define mono_simd_shuffle_mask(a,b,c,d) ((a) | ((b) << 2) | ((c) << 4) | ((d) << 6)) @@ -851,6 +831,8 @@ struct MonoCallInst { * 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 */ @@ -956,6 +938,14 @@ enum { #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, @@ -1237,6 +1227,7 @@ struct MonoJumpInfo { #else int offset; #endif + int index; MonoBasicBlock *bb; MonoInst *inst; MonoMethod *method; @@ -1320,7 +1311,9 @@ typedef enum { /* Whenever this is an AOT compilation */ JIT_FLAG_AOT = (1 << 1), /* Whenever this is a full AOT compilation */ - JIT_FLAG_FULL_AOT = (1 << 2) + JIT_FLAG_FULL_AOT = (1 << 2), + /* Whenever to compile with LLVM */ + JIT_FLAG_LLVM = (1 << 3), } JitFlags; /* Bit-fields in the MonoBasicBlock.region */ @@ -1423,8 +1416,6 @@ typedef struct { MonoGenericSharingContext gsctx; MonoGenericContext *gsctx_context; - gboolean gsharedvt; - MonoGSharedVtMethodInfo *gsharedvt_info; /* Points to the gsharedvt locals area at runtime */ @@ -1521,6 +1512,9 @@ typedef struct { 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; @@ -1537,6 +1531,8 @@ typedef struct { guint32 encoded_unwind_ops_len; GSList* unwind_ops; + GList* dont_inline; + /* Fields used by the local reg allocator */ void* reginfo; int reginfo_len; @@ -1611,6 +1607,7 @@ typedef struct { /* Symbol used to refer to this method in generated assembly */ char *asm_symbol; char *llvm_method_name; + int castclass_cache_index; MonoJitExceptionInfo *llvm_ex_info; guint32 llvm_ex_info_len; @@ -2026,7 +2023,6 @@ MONO_API void mono_print_method_from_ip (void *ip); 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; @@ -2052,7 +2048,6 @@ void mono_set_lmf (MonoLMF *lmf) MONO_INTERNAL; MonoJitTlsData* mono_get_jit_tls (void) MONO_INTERNAL; MONO_API MonoDomain *mono_jit_thread_attach (MonoDomain *domain); MONO_API void mono_jit_set_domain (MonoDomain *domain); -MonoNativeTlsKey mono_get_jit_tls_key (void) MONO_INTERNAL; gint32 mono_get_jit_tls_offset (void) MONO_INTERNAL; gint32 mono_get_lmf_tls_offset (void) MONO_INTERNAL; gint32 mono_get_lmf_addr_tls_offset (void) MONO_INTERNAL; @@ -2171,6 +2166,8 @@ guint32 mono_aot_method_hash (MonoMethod *method) 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; @@ -2197,10 +2194,12 @@ void mono_llvm_cleanup (void) MONO_LLVM_INTERNAL; void mono_llvm_emit_method (MonoCompile *cfg) MONO_LLVM_INTERNAL; void mono_llvm_emit_call (MonoCompile *cfg, MonoCallInst *call) MONO_LLVM_INTERNAL; void mono_llvm_create_aot_module (const char *got_symbol) MONO_LLVM_INTERNAL; -void mono_llvm_emit_aot_module (const char *filename, int got_size) MONO_LLVM_INTERNAL; +void mono_llvm_emit_aot_module (const char *filename, const char *cu_name, int got_size) MONO_LLVM_INTERNAL; void mono_llvm_check_method_supported (MonoCompile *cfg) MONO_LLVM_INTERNAL; void mono_llvm_free_domain_info (MonoDomain *domain) MONO_LLVM_INTERNAL; +gboolean mini_llvm_init (void); + gboolean mono_method_blittable (MonoMethod *method) MONO_INTERNAL; gboolean mono_method_same_domain (MonoJitInfo *caller, MonoJitInfo *callee) MONO_INTERNAL; @@ -2290,7 +2289,7 @@ void mono_tramp_info_register (MonoTrampInfo *info) MONO_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; @@ -2462,7 +2461,7 @@ void mono_arch_emit_imt_argument (MonoCompile *cfg, MonoCallInst MonoMethod* mono_arch_find_imt_method (mgreg_t *regs, guint8 *code) MONO_INTERNAL; MonoVTable* mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code) MONO_INTERNAL; gpointer mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count, gpointer fail_tramp) MONO_INTERNAL; -void mono_arch_notify_pending_exc (void) MONO_INTERNAL; +void mono_arch_notify_pending_exc (MonoThreadInfo *info) MONO_INTERNAL; guint8* mono_arch_get_call_target (guint8 *code) MONO_INTERNAL; guint32 mono_arch_get_plt_info_offset (guint8 *plt_entry, mgreg_t *regs, guint8 *code) MONO_INTERNAL; GSList *mono_arch_get_trampolines (gboolean aot) MONO_INTERNAL; @@ -2511,6 +2510,7 @@ typedef gboolean (*MonoExceptionFrameWalk) (MonoMethod *method, gpointer ip gboolean mono_exception_walk_trace (MonoException *ex, MonoExceptionFrameWalk func, gpointer user_data); void mono_restore_context (MonoContext *ctx) MONO_INTERNAL; guint8* mono_jinfo_get_unwind_info (MonoJitInfo *ji, guint32 *unwind_info_len) MONO_INTERNAL; +int mono_jinfo_get_epilog_size (MonoJitInfo *ji) MONO_INTERNAL; gboolean mono_find_jit_info_ext (MonoDomain *domain, MonoJitTlsData *jit_tls, @@ -2815,52 +2815,12 @@ void mono_cross_helpers_run (void) MONO_INTERNAL; /* * Signal handling */ -#ifdef MONO_GET_CONTEXT -#define GET_CONTEXT MONO_GET_CONTEXT -#endif - -#ifndef GET_CONTEXT -#ifdef HOST_WIN32 -#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 diff --git a/mono/mini/ssa.c b/mono/mini/ssa.c index 801826b96e8..160db5fec57 100644 --- a/mono/mini/ssa.c +++ b/mono/mini/ssa.c @@ -26,10 +26,8 @@ //#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 { @@ -530,8 +528,7 @@ mono_ssa_remove (MonoCompile *cfg) } } - ins->opcode = OP_NOP; - ins->dreg = -1; + NULLIFY_INS (ins); } } } @@ -1287,12 +1284,10 @@ mono_ssa_deadce (MonoCompile *cfg) 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; @@ -1300,8 +1295,7 @@ mono_ssa_deadce (MonoCompile *cfg) 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) { diff --git a/mono/mini/support-s390x.h b/mono/mini/support-s390x.h index 62edcc4e7e9..f93dc88c0c6 100644 --- a/mono/mini/support-s390x.h +++ b/mono/mini/support-s390x.h @@ -4,8 +4,12 @@ #define S390_SET(loc, dr, v) \ do { \ guint64 val = (guint64) v; \ - if (s390_is_uimm16(val)) { \ + if (s390_is_imm16(val)) { \ + s390_lghi(loc, dr, val); \ + } else if (s390_is_uimm16(val)) { \ s390_llill(loc, dr, val); \ + } else if (s390_is_imm32(val)) { \ + s390_lgfi(loc, dr, val); \ } else if (s390_is_uimm32(val)) { \ s390_llilf(loc, dr, val); \ } else { \ diff --git a/mono/mini/tramp-amd64.c b/mono/mini/tramp-amd64.c old mode 100644 new mode 100755 index 9ba8502250f..cfc14ee2a4e --- a/mono/mini/tramp-amd64.c +++ b/mono/mini/tramp-amd64.c @@ -522,7 +522,7 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf amd64_mov_reg_imm (code, AMD64_R11, 0); amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, 0, 8); } else { - amd64_mov_reg_imm (code, AMD64_RDI, tramp_type); + amd64_mov_reg_imm (code, MONO_AMD64_ARG_REG1, tramp_type); amd64_mov_reg_imm (code, AMD64_R11, stack_unaligned); amd64_call_reg (code, AMD64_R11); } @@ -946,8 +946,6 @@ mono_arch_create_generic_class_init_trampoline (MonoTrampInfo **info, gboolean a return buf; } -#ifdef MONO_ARCH_MONITOR_OBJECT_REG - gpointer mono_arch_create_monitor_enter_trampoline (MonoTrampInfo **info, gboolean aot) { @@ -958,8 +956,11 @@ mono_arch_create_monitor_enter_trampoline (MonoTrampInfo **info, gboolean aot) int owner_offset, nest_offset, dummy; MonoJumpInfo *ji = NULL; GSList *unwind_ops = NULL; + int obj_reg = MONO_AMD64_ARG_REG1; + int sync_reg = MONO_AMD64_ARG_REG2; + int tid_reg = MONO_AMD64_ARG_REG3; - g_assert (MONO_ARCH_MONITOR_OBJECT_REG == AMD64_RDI); + g_assert (MONO_ARCH_MONITOR_OBJECT_REG == obj_reg); mono_monitor_threads_sync_members_offset (&owner_offset, &nest_offset, &dummy); g_assert (MONO_THREADS_SYNC_MEMBER_SIZE (owner_offset) == sizeof (gpointer)); @@ -974,50 +975,51 @@ mono_arch_create_monitor_enter_trampoline (MonoTrampInfo **info, gboolean aot) unwind_ops = mono_arch_get_cie_program (); if (!aot && mono_thread_get_tls_offset () != -1) { - /* MonoObject* obj is in RDI */ + /* MonoObject* obj is in obj_reg */ /* is obj null? */ - amd64_test_reg_reg (code, AMD64_RDI, AMD64_RDI); + amd64_test_reg_reg (code, obj_reg, obj_reg); /* if yes, jump to actual trampoline */ jump_obj_null = code; amd64_branch8 (code, X86_CC_Z, -1, 1); - /* load obj->synchronization to RCX */ - amd64_mov_reg_membase (code, AMD64_RCX, AMD64_RDI, MONO_STRUCT_OFFSET (MonoObject, synchronisation), 8); + /* load obj->synchronization to sync_reg */ + amd64_mov_reg_membase (code, sync_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, synchronisation), 8); if (mono_gc_is_moving ()) { /*if bit zero is set it's a thin hash*/ /*FIXME use testb encoding*/ - amd64_test_reg_imm (code, AMD64_RCX, 0x01); + amd64_test_reg_imm (code, sync_reg, 0x01); jump_sync_thin_hash = code; amd64_branch8 (code, X86_CC_NE, -1, 1); /*clear bits used by the gc*/ - amd64_alu_reg_imm (code, X86_AND, AMD64_RCX, ~0x3); + amd64_alu_reg_imm (code, X86_AND, sync_reg, ~0x3); } /* is synchronization null? */ - amd64_test_reg_reg (code, AMD64_RCX, AMD64_RCX); + amd64_test_reg_reg (code, sync_reg, sync_reg); /* if yes, jump to actual trampoline */ jump_sync_null = code; amd64_branch8 (code, X86_CC_Z, -1, 1); - /* load MonoInternalThread* into RDX */ - code = mono_amd64_emit_tls_get (code, AMD64_RDX, mono_thread_get_tls_offset ()); - /* load TID into RDX */ - amd64_mov_reg_membase (code, AMD64_RDX, AMD64_RDX, MONO_STRUCT_OFFSET (MonoInternalThread, tid), 8); + /* load MonoInternalThread* into tid_reg */ + code = mono_amd64_emit_tls_get (code, tid_reg, mono_thread_get_tls_offset ()); + /* load TID into tid_reg */ + amd64_mov_reg_membase (code, tid_reg, tid_reg, MONO_STRUCT_OFFSET (MonoInternalThread, tid), 8); /* is synchronization->owner null? */ - amd64_alu_membase_imm_size (code, X86_CMP, AMD64_RCX, owner_offset, 0, 8); + amd64_alu_membase_imm_size (code, X86_CMP, sync_reg, owner_offset, 0, 8); /* if not, jump to next case */ jump_tid = code; amd64_branch8 (code, X86_CC_NZ, -1, 1); /* if yes, try a compare-exchange with the TID */ + g_assert (tid_reg != X86_EAX); /* zero RAX */ amd64_alu_reg_reg (code, X86_XOR, AMD64_RAX, AMD64_RAX); /* compare and exchange */ amd64_prefix (code, X86_LOCK_PREFIX); - amd64_cmpxchg_membase_reg_size (code, AMD64_RCX, owner_offset, AMD64_RDX, 8); + amd64_cmpxchg_membase_reg_size (code, sync_reg, owner_offset, tid_reg, 8); /* if not successful, jump to actual trampoline */ jump_cmpxchg_failed = code; amd64_branch8 (code, X86_CC_NZ, -1, 1); @@ -1027,12 +1029,12 @@ mono_arch_create_monitor_enter_trampoline (MonoTrampInfo **info, gboolean aot) /* next case: synchronization->owner is not null */ x86_patch (jump_tid, code); /* is synchronization->owner == TID? */ - amd64_alu_membase_reg_size (code, X86_CMP, AMD64_RCX, owner_offset, AMD64_RDX, 8); + amd64_alu_membase_reg_size (code, X86_CMP, sync_reg, owner_offset, tid_reg, 8); /* if not, jump to actual trampoline */ jump_other_owner = code; amd64_branch8 (code, X86_CC_NZ, -1, 1); /* if yes, increment nest */ - amd64_inc_membase_size (code, AMD64_RCX, nest_offset, 4); + amd64_inc_membase_size (code, sync_reg, nest_offset, 4); /* return */ amd64_ret (code); @@ -1045,9 +1047,8 @@ mono_arch_create_monitor_enter_trampoline (MonoTrampInfo **info, gboolean aot) } /* jump to the actual trampoline */ -#if MONO_AMD64_ARG_REG1 != AMD64_RDI - amd64_mov_reg_reg (code, MONO_AMD64_ARG_REG1, AMD64_RDI); -#endif + if (MONO_AMD64_ARG_REG1 != obj_reg) + amd64_mov_reg_reg (code, MONO_AMD64_ARG_REG1, obj_reg, sizeof (mgreg_t)); if (aot) { code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "specific_trampoline_monitor_enter"); @@ -1081,8 +1082,10 @@ mono_arch_create_monitor_exit_trampoline (MonoTrampInfo **info, gboolean aot) int owner_offset, nest_offset, entry_count_offset; MonoJumpInfo *ji = NULL; GSList *unwind_ops = NULL; + int obj_reg = MONO_AMD64_ARG_REG1; + int sync_reg = MONO_AMD64_ARG_REG2; - g_assert (MONO_ARCH_MONITOR_OBJECT_REG == AMD64_RDI); + g_assert (obj_reg == MONO_ARCH_MONITOR_OBJECT_REG); mono_monitor_threads_sync_members_offset (&owner_offset, &nest_offset, &entry_count_offset); g_assert (MONO_THREADS_SYNC_MEMBER_SIZE (owner_offset) == sizeof (gpointer)); @@ -1099,63 +1102,63 @@ mono_arch_create_monitor_exit_trampoline (MonoTrampInfo **info, gboolean aot) unwind_ops = mono_arch_get_cie_program (); if (!aot && mono_thread_get_tls_offset () != -1) { - /* MonoObject* obj is in RDI */ + /* MonoObject* obj is in obj_reg */ /* is obj null? */ - amd64_test_reg_reg (code, AMD64_RDI, AMD64_RDI); + amd64_test_reg_reg (code, obj_reg, obj_reg); /* if yes, jump to actual trampoline */ jump_obj_null = code; amd64_branch8 (code, X86_CC_Z, -1, 1); /* load obj->synchronization to RCX */ - amd64_mov_reg_membase (code, AMD64_RCX, AMD64_RDI, MONO_STRUCT_OFFSET (MonoObject, synchronisation), 8); + amd64_mov_reg_membase (code, sync_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, synchronisation), 8); if (mono_gc_is_moving ()) { /*if bit zero is set it's a thin hash*/ /*FIXME use testb encoding*/ - amd64_test_reg_imm (code, AMD64_RCX, 0x01); + amd64_test_reg_imm (code, sync_reg, 0x01); jump_sync_thin_hash = code; amd64_branch8 (code, X86_CC_NE, -1, 1); /*clear bits used by the gc*/ - amd64_alu_reg_imm (code, X86_AND, AMD64_RCX, ~0x3); + amd64_alu_reg_imm (code, X86_AND, sync_reg, ~0x3); } /* is synchronization null? */ - amd64_test_reg_reg (code, AMD64_RCX, AMD64_RCX); + amd64_test_reg_reg (code, sync_reg, sync_reg); /* if yes, jump to actual trampoline */ jump_sync_null = code; amd64_branch8 (code, X86_CC_Z, -1, 1); /* next case: synchronization is not null */ - /* load MonoInternalThread* into RDX */ - code = mono_amd64_emit_tls_get (code, AMD64_RDX, mono_thread_get_tls_offset ()); - /* load TID into RDX */ - amd64_mov_reg_membase (code, AMD64_RDX, AMD64_RDX, MONO_STRUCT_OFFSET (MonoInternalThread, tid), 8); + /* load MonoInternalThread* into RAX */ + code = mono_amd64_emit_tls_get (code, AMD64_RAX, mono_thread_get_tls_offset ()); + /* load TID into RAX */ + amd64_mov_reg_membase (code, AMD64_RAX, AMD64_RAX, MONO_STRUCT_OFFSET (MonoInternalThread, tid), 8); /* is synchronization->owner == TID */ - amd64_alu_membase_reg_size (code, X86_CMP, AMD64_RCX, owner_offset, AMD64_RDX, 8); + amd64_alu_membase_reg_size (code, X86_CMP, sync_reg, owner_offset, AMD64_RAX, 8); /* if no, jump to actual trampoline */ jump_not_owned = code; amd64_branch8 (code, X86_CC_NZ, -1, 1); /* next case: synchronization->owner == TID */ /* is synchronization->nest == 1 */ - amd64_alu_membase_imm_size (code, X86_CMP, AMD64_RCX, nest_offset, 1, 4); + amd64_alu_membase_imm_size (code, X86_CMP, sync_reg, nest_offset, 1, 4); /* if not, jump to next case */ jump_next = code; amd64_branch8 (code, X86_CC_NZ, -1, 1); /* if yes, is synchronization->entry_count zero? */ - amd64_alu_membase_imm_size (code, X86_CMP, AMD64_RCX, entry_count_offset, 0, 4); + amd64_alu_membase_imm_size (code, X86_CMP, sync_reg, entry_count_offset, 0, 4); /* if not, jump to actual trampoline */ jump_have_waiters = code; amd64_branch8 (code, X86_CC_NZ, -1 , 1); /* if yes, set synchronization->owner to null and return */ - amd64_mov_membase_imm (code, AMD64_RCX, owner_offset, 0, 8); + amd64_mov_membase_imm (code, sync_reg, owner_offset, 0, 8); amd64_ret (code); /* next case: synchronization->nest is not 1 */ x86_patch (jump_next, code); /* decrease synchronization->nest and return */ - amd64_dec_membase_size (code, AMD64_RCX, nest_offset, 4); + amd64_dec_membase_size (code, sync_reg, nest_offset, 4); amd64_ret (code); x86_patch (jump_obj_null, code); @@ -1165,9 +1168,8 @@ mono_arch_create_monitor_exit_trampoline (MonoTrampInfo **info, gboolean aot) } /* jump to the actual trampoline */ -#if MONO_AMD64_ARG_REG1 != AMD64_RDI - amd64_mov_reg_reg (code, MONO_AMD64_ARG_REG1, AMD64_RDI); -#endif + if (MONO_AMD64_ARG_REG1 != obj_reg) + amd64_mov_reg_reg (code, MONO_AMD64_ARG_REG1, obj_reg, sizeof (mgreg_t)); if (aot) { code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "specific_trampoline_monitor_exit"); @@ -1187,7 +1189,6 @@ mono_arch_create_monitor_exit_trampoline (MonoTrampInfo **info, gboolean aot) return buf; } -#endif void mono_arch_invalidate_method (MonoJitInfo *ji, void *func, gpointer func_arg) @@ -1226,18 +1227,18 @@ mono_arch_create_handler_block_trampoline (MonoTrampInfo **info, gboolean aot) /* This trampoline restore the call chain of the handler block then jumps into the code that deals with it. */ - if (mono_get_jit_tls_offset () != -1) { - code = mono_amd64_emit_tls_get (code, AMD64_RDI, mono_get_jit_tls_offset ()); - amd64_mov_reg_membase (code, AMD64_RDI, AMD64_RDI, MONO_STRUCT_OFFSET (MonoJitTlsData, handler_block_return_address), 8); + code = mono_amd64_emit_tls_get (code, MONO_AMD64_ARG_REG1, mono_get_jit_tls_offset ()); + amd64_mov_reg_membase (code, MONO_AMD64_ARG_REG1, MONO_AMD64_ARG_REG1, MONO_STRUCT_OFFSET (MonoJitTlsData, handler_block_return_address), 8); /* Simulate a call */ amd64_push_reg (code, AMD64_RAX); amd64_jump_code (code, tramp); } else { /*Slow path uses a c helper*/ - amd64_mov_reg_reg (code, AMD64_RDI, AMD64_RSP, 8); + amd64_mov_reg_reg (code, MONO_AMD64_ARG_REG1, AMD64_RSP, 8); amd64_mov_reg_imm (code, AMD64_RAX, tramp); amd64_push_reg (code, AMD64_RAX); + amd64_push_reg (code, AMD64_RAX); amd64_jump_code (code, handler_block_trampoline_helper); } diff --git a/mono/mini/tramp-arm.c b/mono/mini/tramp-arm.c index bb500a7c0f5..f9e651093b4 100644 --- a/mono/mini/tramp-arm.c +++ b/mono/mini/tramp-arm.c @@ -505,17 +505,21 @@ mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_ty 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, @@ -894,6 +898,59 @@ mono_arch_create_generic_class_init_trampoline (MonoTrampInfo **info, gboolean a 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* @@ -944,6 +1001,13 @@ mono_arch_get_nullified_class_init_trampoline (MonoTrampInfo **info) 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 */ diff --git a/mono/mini/unwind.c b/mono/mini/unwind.c index 31024bfee0f..d6710939787 100644 --- a/mono/mini/unwind.c +++ b/mono/mini/unwind.c @@ -349,9 +349,10 @@ mono_unwind_ops_encode (GSList *unwind_ops, guint32 *out_len) 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; @@ -443,7 +444,6 @@ mono_unwind_ops_encode (GSList *unwind_ops, guint32 *out_len) *out_len = p - buf; res = g_malloc (p - buf); memcpy (res, buf, p - buf); - g_free (buf); return res; } @@ -498,6 +498,8 @@ mono_unwind_frame (guint8 *unwind_info, guint32 unwind_info_len, 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; diff --git a/mono/mini/wapihandles.c b/mono/mini/wapihandles.c index c2a31ce1ea3..7bda38843ef 100644 --- a/mono/mini/wapihandles.c +++ b/mono/mini/wapihandles.c @@ -3,7 +3,7 @@ #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) { @@ -42,7 +42,6 @@ static const gchar *thread_details (struct _WapiHandleShared *handle); 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 @@ -58,7 +57,7 @@ static const gchar * (*details[])(struct _WapiHandleShared *)= unshared_details, /* event */ unshared_details, /* socket */ unshared_details, /* find */ - process_details, + unshared_details, /* process */ unshared_details, /* pipe */ namedmutex_details, namedsem_details, @@ -191,20 +190,6 @@ static const gchar *namedevent_details (struct _WapiHandleShared *handle) 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) { diff --git a/mono/mini/xdebug.c b/mono/mini/xdebug.c index 9e415ca3390..167b2b9e2b7 100644 --- a/mono/mini/xdebug.c +++ b/mono/mini/xdebug.c @@ -51,6 +51,8 @@ #include "image-writer.h" #include "dwarfwriter.h" +#include "mono/utils/mono-compiler.h" + #define USE_GDB_JIT_INTERFACE /* The recommended gdb macro is: */ @@ -95,15 +97,8 @@ struct jit_descriptor struct jit_code_entry *first_entry; }; - -#ifdef _MSC_VER -#define MONO_NOINLINE __declspec (noinline) -#else -#define MONO_NOINLINE __attribute__((noinline)) -#endif - /* GDB puts a breakpoint in this function. */ -void MONO_NOINLINE __jit_debug_register_code(void); +void MONO_NEVER_INLINE __jit_debug_register_code(void); #if !defined(MONO_LLVM_LOADED) && defined(ENABLE_LLVM) && !defined(MONO_CROSS_COMPILE) @@ -114,7 +109,7 @@ extern struct jit_descriptor __jit_debug_descriptor; #else /* gcc seems to inline/eliminate calls to noinline functions, thus the asm () */ -void MONO_NOINLINE __jit_debug_register_code(void) { +void MONO_NEVER_INLINE __jit_debug_register_code(void) { #if defined(__GNUC__) asm (""); #endif diff --git a/mono/monograph/Makefile.am b/mono/monograph/Makefile.am index 585b5641829..25555809f1d 100644 --- a/mono/monograph/Makefile.am +++ b/mono/monograph/Makefile.am @@ -3,7 +3,6 @@ if HOST_WIN32 export HOST_CC endif -if JIT_SUPPORTED if DISABLE_EXECUTABLES runtime_lib=../mini/$(LIBMONO_LA) $(static_libs) else @@ -20,9 +19,6 @@ else runtime_lib=../mini/$(LIBMONO_LA) endif endif -else -runtime_lib=../interpreter/libmint.la -endif if DISABLE_EXECUTABLES bin_PROGRAMS = diff --git a/mono/profiler/Makefile.am b/mono/profiler/Makefile.am index 25bb9b51f70..b0d1e2f77de 100644 --- a/mono/profiler/Makefile.am +++ b/mono/profiler/Makefile.am @@ -11,7 +11,6 @@ AM_CPPFLAGS = \ 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 @@ -22,7 +21,6 @@ libmono_profiler_log_la_LDFLAGS = -avoid-version endif endif endif -endif if HAVE_OPROFILE # Do something that uses OPROFILE_CFLAGS and OPROFILE_LIBS diff --git a/mono/profiler/perf_event.h b/mono/profiler/perf_event.h index 057bf22a832..3137aea7980 100644 --- a/mono/profiler/perf_event.h +++ b/mono/profiler/perf_event.h @@ -18,6 +18,8 @@ #include #include +#include "mono/utils/mono-compiler.h" + /* * User-space ABI bits: */ @@ -1004,7 +1006,7 @@ static inline void perf_fetch_caller_regs(struct pt_regs *regs) perf_arch_fetch_caller_regs(regs, CALLER_ADDR0); } -static __always_inline void +static MONO_ALWAYS_INLINE void perf_sw_event(u32 event_id, u64 nr, int nmi, struct pt_regs *regs, u64 addr) { struct pt_regs hot_regs; diff --git a/mono/profiler/proflog.c b/mono/profiler/proflog.c index 9021a00b24d..edf903a7442 100644 --- a/mono/profiler/proflog.c +++ b/mono/profiler/proflog.c @@ -90,6 +90,7 @@ static int do_mono_sample = 0; static int in_shutdown = 0; static int do_debug = 0; static int do_counters = 0; +static MonoProfileSamplingMode sampling_mode = MONO_PROFILER_STAT_MODE_PROCESS; /* For linux compile with: * gcc -fPIC -shared -o libmono-profiler-log.so proflog.c utils.c -Wall -g -lz `pkg-config --cflags --libs mono-2` @@ -831,10 +832,13 @@ walk_stack (MonoMethod *method, int32_t native_offset, int32_t il_offset, mono_b * event, hence the collect_bt/emit_bt split. */ static void -collect_bt (FrameData *data) +collect_bt (FrameData *data, gboolean async_safe) { data->count = 0; - mono_stack_walk_no_il (walk_stack, data); + if (async_safe) + mono_stack_walk_async_safe (walk_stack, data); + else + mono_stack_walk_no_il (walk_stack, data); } static void @@ -867,7 +871,7 @@ gc_alloc (MonoProfiler *prof, MonoObject *obj, MonoClass *klass) len += 7; len &= ~7; if (do_bt) - collect_bt (&data); + collect_bt (&data, FALSE); logbuffer = ensure_logbuf (32 + MAX_FRAMES * 8); now = current_time (); ENTER_LOG (logbuffer, "gcalloc"); @@ -1132,7 +1136,7 @@ throw_exc (MonoProfiler *prof, MonoObject *object) FrameData data; LogBuffer *logbuffer; if (do_bt) - collect_bt (&data); + collect_bt (&data, FALSE); logbuffer = ensure_logbuf (16 + MAX_FRAMES * 8); now = current_time (); ENTER_LOG (logbuffer, "throw"); @@ -1168,7 +1172,7 @@ monitor_event (MonoProfiler *profiler, MonoObject *object, MonoProfilerMonitorEv FrameData data; LogBuffer *logbuffer; if (do_bt) - collect_bt (&data); + collect_bt (&data, FALSE); logbuffer = ensure_logbuf (16 + MAX_FRAMES * 8); now = current_time (); ENTER_LOG (logbuffer, "monitor"); @@ -1230,7 +1234,7 @@ mono_sample_hit (MonoProfiler *profiler, unsigned char *ip, void *context) if (in_shutdown) return; now = current_time (); - collect_bt (&bt_data); + collect_bt (&bt_data, TRUE); elapsed = (now - profiler->startup_time) / 10000; if (do_debug) { int len; @@ -2689,6 +2693,14 @@ mono_profiler_startup (const char *desc) do_debug = 1; continue; } + if ((opt = match_option (p, "sampling-real", NULL)) != p) { + sampling_mode = MONO_PROFILER_STAT_MODE_REAL; + continue; + } + if ((opt = match_option (p, "sampling-process", NULL)) != p) { + sampling_mode = MONO_PROFILER_STAT_MODE_PROCESS; + continue; + } if ((opt = match_option (p, "heapshot", &val)) != p) { events &= ~MONO_PROFILE_ALLOCATIONS; events &= ~MONO_PROFILE_ENTER_LEAVE; @@ -2778,6 +2790,7 @@ mono_profiler_startup (const char *desc) if (do_mono_sample && sample_type == SAMPLE_CYCLES) { events |= MONO_PROFILE_STATISTICAL; + mono_profiler_set_statistical_mode (sampling_mode, 1000000 / sample_freq); mono_profiler_install_statistical (mono_sample_hit); } diff --git a/mono/tests/Makefile.am b/mono/tests/Makefile.am index 7d448d374ad..6268cadb4f0 100644 --- a/mono/tests/Makefile.am +++ b/mono/tests/Makefile.am @@ -43,6 +43,7 @@ STRESS_TESTS_SRC= \ monitor-stress.cs \ thread-stress.cs \ gc-stress.cs \ + gc-copy-stress.cs \ gc-graystack-stress.cs \ exit-stress.cs \ process-stress.cs \ @@ -435,7 +436,8 @@ endif if X86 if HOST_WIN32 -PLATFORM_DISABLED_TESTS=async-exc-compilation.exe finally_guard.exe finally_block_ending_in_dead_bb.exe +PLATFORM_DISABLED_TESTS=async-exc-compilation.exe finally_guard.exe finally_block_ending_in_dead_bb.exe \ + bug-18026.exe monitor.exe threadpool-exceptions5.exe endif endif @@ -934,13 +936,11 @@ SGEN_TESTS = \ SGEN_CONFIGURATIONS = \ "|plain" \ - "major=marksweep-par|ms-par" \ "major=marksweep-conc|ms-conc" \ "major=marksweep-conc,minor=split|ms-conc-split" \ "minor=split|ms-split" \ "minor=split,alloc-ratio=95|ms-split-95" \ "|plain-clear-at-gc|clear-at-gc" \ - "major=marksweep-par|ms-par-clear-at-gc|clear-at-gc" \ "major=marksweep-conc|ms-conc-clear-at-gc|clear-at-gc" \ "minor=split|ms-split-clear-at-gc|clear-at-gc" @@ -1319,7 +1319,6 @@ OOM_TESTS = \ test-oom: $(OOM_TESTS) @for fn in $+ ; do \ echo "Testing $$fn ..."; \ - MONO_GC_PARAMS=max-heap-size=16m,major=marksweep-par MONO_ENV_OPTIONS="--gc=sgen" $(RUNTIME) $$fn > $$fn.stdout || exit 1; \ MONO_GC_PARAMS=max-heap-size=16m MONO_ENV_OPTIONS="--gc=sgen" $(RUNTIME) $$fn > $$fn.stdout || exit 1; \ MONO_GC_PARAMS=max-heap-size=16m $(RUNTIME) $$fn > $$fn.stdout || exit 1; \ done diff --git a/mono/tests/bug-17537-helper.cs b/mono/tests/bug-17537-helper.cs new file mode 100644 index 00000000000..315bb47f4e4 --- /dev/null +++ b/mono/tests/bug-17537-helper.cs @@ -0,0 +1,10 @@ +using System; +using System.IO; + +public class Test { + public static int Main(string[] args) + { + Console.WriteLine ("Hello from bug-17537-helper!"); + return 0; + } +} diff --git a/mono/tests/bug-17537.cs b/mono/tests/bug-17537.cs new file mode 100644 index 00000000000..747ac361f80 --- /dev/null +++ b/mono/tests/bug-17537.cs @@ -0,0 +1,41 @@ +using System; +using System.IO; +using System.Diagnostics; + +public class Test { + public static int Main(string[] args) + { + // Only run this test on Unix + int pl = (int) Environment.OSVersion.Platform; + if ((pl != 4) && (pl != 6) && (pl != 128)) { + return 0; + } + + // Try to invoke the helper assembly + // Return 0 only if it is successful + try + { + var name = "bug-17537-helper.exe"; + Console.WriteLine ("Launching subprocess: {0}", name); + var p = new Process(); + p.StartInfo.FileName = Path.Combine (AppDomain.CurrentDomain.BaseDirectory + name); + p.StartInfo.UseShellExecute = false; + + var result = p.Start(); + p.WaitForExit(1000); + if (result) { + Console.WriteLine ("Subprocess started successfully"); + return 0; + } else { + Console.WriteLine ("Subprocess failure"); + return 1; + } + } + catch (Exception e) + { + Console.WriteLine ("Subprocess exception"); + Console.WriteLine (e.Message); + return 1; + } + } +} diff --git a/mono/tests/gc-copy-stress.cs b/mono/tests/gc-copy-stress.cs new file mode 100644 index 00000000000..130f33f8284 --- /dev/null +++ b/mono/tests/gc-copy-stress.cs @@ -0,0 +1,35 @@ +using System; + +class T { + + static int count = 1000000; + static int loops = 20; + static int persist_factor = 10; + + static object obj; + + static object[] persist; + static int persist_idx; + + static void work () { + persist = new object[count / persist_factor + 1]; + persist_idx = 0; + for (int i = 0; i < count; ++i) { + obj = new object (); + if (i % persist_factor == 0) + persist[persist_idx++] = obj; + } + } + + static void Main (string[] args) { + if (args.Length > 0) + loops = int.Parse (args [0]); + if (args.Length > 1) + count = int.Parse (args [1]); + if (args.Length > 2) + persist_factor = int.Parse (args [2]); + for (int i = 0; i < loops; ++i) { + work (); + } + } +} diff --git a/mono/tests/libtest.c b/mono/tests/libtest.c index e057944bbd7..ceecaf02ae4 100644 --- a/mono/tests/libtest.c +++ b/mono/tests/libtest.c @@ -5313,6 +5313,20 @@ mono_test_marshal_return_lpwstr (void) 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 diff --git a/mono/tests/pinvoke2.cs b/mono/tests/pinvoke2.cs index 71c51a7d814..edf9a6dad45 100644 --- a/mono/tests/pinvoke2.cs +++ b/mono/tests/pinvoke2.cs @@ -71,6 +71,11 @@ public struct DelegateStruct { 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)] @@ -1800,5 +1805,16 @@ public static int test_0_native_thiscall () 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; + } } diff --git a/mono/tests/stress-runner.pl b/mono/tests/stress-runner.pl index 24d5b9db8d5..165b1d877a3 100755 --- a/mono/tests/stress-runner.pl +++ b/mono/tests/stress-runner.pl @@ -72,6 +72,13 @@ 'arg-knob' => 2, # loops 'ratio' => 10, }, + 'gc-copy-stress' => { + 'program' => 'gc-copy-stress.exe', + # loops, count, persist_factor + 'args' => [250, 500000, 10], + 'arg-knob' => 1, # count + 'ratio' => 4, + }, 'thread-stress' => { 'program' => 'thread-stress.exe', # loops diff --git a/mono/tests/test-runner.cs b/mono/tests/test-runner.cs index ce0d65e7418..24caf07cc13 100644 --- a/mono/tests/test-runner.cs +++ b/mono/tests/test-runner.cs @@ -301,6 +301,7 @@ public static int Main (String[] args) { lock (monitor) { foreach (Process p in processes) { Console.WriteLine (process_data [p].test); + p.Kill (); } } return 1; diff --git a/mono/unit-tests/.gitignore b/mono/unit-tests/.gitignore index 0b2579b6eae..aee3344f537 100644 --- a/mono/unit-tests/.gitignore +++ b/mono/unit-tests/.gitignore @@ -8,3 +8,4 @@ /test-gc-memfuncs /test-mono-linked-list-set /test-sgen-qsort +/test-conc-hashtable diff --git a/mono/utils/Makefile.am b/mono/utils/Makefile.am index 09410cda403..c2c8a0d790c 100644 --- a/mono/utils/Makefile.am +++ b/mono/utils/Makefile.am @@ -32,6 +32,7 @@ monoutils_sources = \ mono-math.c \ mono-mmap.c \ mono-mmap.h \ + mono-mmap-internal.h \ mono-mutex.c \ mono-mutex.h \ mono-networkinterfaces.c \ @@ -99,6 +100,10 @@ monoutils_sources = \ mono-threads-mach.c \ mono-threads-mach-helper.c \ mono-threads-windows.c \ + mono-threads-linux.c \ + mono-threads-freebsd.c \ + mono-threads-openbsd.c \ + mono-threads-android.c \ mono-threads.h \ mono-tls.h \ mono-tls.c \ diff --git a/mono/utils/lock-free-alloc.c b/mono/utils/lock-free-alloc.c index 4befb3b86a0..33fed096ea4 100644 --- a/mono/utils/lock-free-alloc.c +++ b/mono/utils/lock-free-alloc.c @@ -113,6 +113,7 @@ struct _MonoLockFreeAllocDescriptor { MonoLockFreeAllocator *heap; volatile Anchor anchor; unsigned int slot_size; + unsigned int block_size; unsigned int max_count; gpointer sb; #ifndef DESC_AVAIL_DUMMY @@ -123,12 +124,11 @@ struct _MonoLockFreeAllocDescriptor { #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 */ @@ -139,41 +139,34 @@ prot_flags_for_activate (int activate) 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); } @@ -198,7 +191,7 @@ desc_alloc (void) 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; @@ -214,7 +207,7 @@ desc_alloc (void) 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); @@ -251,7 +244,7 @@ desc_retire (Descriptor *desc) 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 @@ -271,7 +264,7 @@ desc_alloc (void) 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 @@ -388,7 +381,7 @@ alloc_from_active_or_partial (MonoLockFreeAllocator *heap) 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; @@ -409,17 +402,12 @@ alloc_from_active_or_partial (MonoLockFreeAllocator *heap) 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; /* @@ -433,6 +421,12 @@ alloc_from_new_sb (MonoLockFreeAllocator *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. */ @@ -465,22 +459,23 @@ mono_lock_free_alloc (MonoLockFreeAllocator *heap) } 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; @@ -530,7 +525,7 @@ static void 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 @@ -607,12 +602,15 @@ mono_lock_free_allocator_check_consistency (MonoLockFreeAllocator *heap) } 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 diff --git a/mono/utils/lock-free-alloc.h b/mono/utils/lock-free-alloc.h index ed07a2971a5..84935646d37 100644 --- a/mono/utils/lock-free-alloc.h +++ b/mono/utils/lock-free-alloc.h @@ -33,6 +33,7 @@ typedef struct { MonoLockFreeQueue partial; unsigned int slot_size; + unsigned int block_size; } MonoLockFreeAllocSizeClass; struct _MonoLockFreeAllocDescriptor; @@ -42,11 +43,15 @@ typedef struct { 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; diff --git a/mono/utils/mono-compiler.h b/mono/utils/mono-compiler.h index c1d0e27a49c..d3c41ba44df 100644 --- a/mono/utils/mono-compiler.h +++ b/mono/utils/mono-compiler.h @@ -161,7 +161,7 @@ #define MONO_THREAD_VAR_OFFSET(var,offset) (offset) = -1 #endif -#elif defined(__APPLE__) && (defined(__i386__) || defined(__x86_64__)) +#elif defined(TARGET_MACH) && (defined(__i386__) || defined(__x86_64__)) #define MONO_HAVE_FAST_TLS #define MONO_FAST_TLS_SET(x,y) pthread_setspecific(x, y) @@ -198,10 +198,12 @@ #endif #include -#define isnan(x) _isnan(x) #define trunc(x) (((x) < 0) ? ceil((x)) : floor((x))) +#if _MSC_VER < 1800 /* VS 2013 */ +#define isnan(x) _isnan(x) #define isinf(x) (_isnan(x) ? 0 : (_fpclass(x) == _FPCLASS_NINF) ? -1 : (_fpclass(x) == _FPCLASS_PINF) ? 1 : 0) #define isnormal(x) _finite(x) +#endif #define popen _popen #define pclose _pclose @@ -245,5 +247,13 @@ typedef SSIZE_T ssize_t; #define MONO_ALWAYS_INLINE #endif +#ifdef __GNUC__ +#define MONO_NEVER_INLINE __attribute__((noinline)) +#elif defined(_MSC_VER) +#define MONO_NEVER_INLINE __declspec(noinline) +#else +#define MONO_NEVER_INLINE +#endif + #endif /* __UTILS_MONO_COMPILER_H__*/ diff --git a/mono/utils/mono-context.c b/mono/utils/mono-context.c index bc0286485fc..c52d0442f46 100644 --- a/mono/utils/mono-context.c +++ b/mono/utils/mono-context.c @@ -15,6 +15,10 @@ #include +#ifdef HOST_WIN32 +#include +#endif + #ifdef __sun #define REG_EAX EAX #define REG_EBX EBX @@ -53,6 +57,18 @@ mono_sigctx_to_monoctx (void *sigctx, MonoContext *mctx) mctx->esi = UCONTEXT_REG_ESI (ctx); mctx->edi = UCONTEXT_REG_EDI (ctx); mctx->eip = UCONTEXT_REG_EIP (ctx); +#elif defined(HOST_WIN32) + CONTEXT *context = (CONTEXT*)sigctx; + + mctx->eip = context->Eip; + mctx->edi = context->Edi; + mctx->esi = context->Esi; + mctx->ebx = context->Ebx; + mctx->edx = context->Edx; + mctx->ecx = context->Ecx; + mctx->eax = context->Eax; + mctx->ebp = context->Ebp; + mctx->esp = context->Esp; #else struct sigcontext *ctx = (struct sigcontext *)sigctx; @@ -85,6 +101,18 @@ mono_monoctx_to_sigctx (MonoContext *mctx, void *sigctx) UCONTEXT_REG_ESI (ctx) = mctx->esi; UCONTEXT_REG_EDI (ctx) = mctx->edi; UCONTEXT_REG_EIP (ctx) = mctx->eip; +#elif defined(HOST_WIN32) + CONTEXT *context = (CONTEXT*)sigctx; + + context->Eip = mctx->eip; + context->Edi = mctx->edi; + context->Esi = mctx->esi; + context->Ebx = mctx->ebx; + context->Edx = mctx->edx; + context->Ecx = mctx->ecx; + context->Eax = mctx->eax; + context->Ebp = mctx->ebp; + context->Esp = mctx->esp; #else struct sigcontext *ctx = (struct sigcontext *)sigctx; @@ -104,6 +132,10 @@ mono_monoctx_to_sigctx (MonoContext *mctx, void *sigctx) #include +#ifdef HOST_WIN32 +#include +#endif + void mono_sigctx_to_monoctx (void *sigctx, MonoContext *mctx) { @@ -131,6 +163,26 @@ mono_sigctx_to_monoctx (void *sigctx, MonoContext *mctx) mctx->r14 = UCONTEXT_REG_R14 (ctx); mctx->r15 = UCONTEXT_REG_R15 (ctx); mctx->rip = UCONTEXT_REG_RIP (ctx); +#elif defined(HOST_WIN32) + CONTEXT *context = (CONTEXT*)sigctx; + + mctx->rip = context->Rip; + mctx->rax = context->Rax; + mctx->rcx = context->Rcx; + mctx->rdx = context->Rdx; + mctx->rbx = context->Rbx; + mctx->rsp = context->Rsp; + mctx->rbp = context->Rbp; + mctx->rsi = context->Rsi; + mctx->rdi = context->Rdi; + mctx->r8 = context->R8; + mctx->r9 = context->R9; + mctx->r10 = context->R10; + mctx->r11 = context->R11; + mctx->r12 = context->R12; + mctx->r13 = context->R13; + mctx->r14 = context->R14; + mctx->r15 = context->R15; #else MonoContext *ctx = (MonoContext *)sigctx; @@ -181,6 +233,26 @@ mono_monoctx_to_sigctx (MonoContext *mctx, void *sigctx) UCONTEXT_REG_R14 (ctx) = mctx->r14; UCONTEXT_REG_R15 (ctx) = mctx->r15; UCONTEXT_REG_RIP (ctx) = mctx->rip; +#elif defined(HOST_WIN32) + CONTEXT *context = (CONTEXT*)sigctx; + + context->Rip = mctx->rip; + context->Rax = mctx->rax; + context->Rcx = mctx->rcx; + context->Rdx = mctx->rdx; + context->Rbx = mctx->rbx; + context->Rsp = mctx->rsp; + context->Rbp = mctx->rbp; + context->Rsi = mctx->rsi; + context->Rdi = mctx->rdi; + context->R8 = mctx->r8; + context->R9 = mctx->r9; + context->R10 = mctx->r10; + context->R11 = mctx->r11; + context->R12 = mctx->r12; + context->R13 = mctx->r13; + context->R14 = mctx->r14; + context->R15 = mctx->r15; #else MonoContext *ctx = (MonoContext *)sigctx; diff --git a/mono/utils/mono-context.h b/mono/utils/mono-context.h index 11254802fc4..3b01b49f066 100755 --- a/mono/utils/mono-context.h +++ b/mono/utils/mono-context.h @@ -236,12 +236,12 @@ extern void mono_context_get_current (void *); : "rdx", "memory") #endif -#if !defined(HOST_WIN32) #define MONO_ARCH_HAS_MONO_CONTEXT 1 -#endif #elif (defined(__arm__) && !defined(MONO_CROSS_COMPILE)) || (defined(TARGET_ARM)) /* defined(__x86_64__) */ +#include + typedef struct { mgreg_t pc; mgreg_t regs [16]; @@ -281,6 +281,8 @@ typedef struct { ctx.pc = ctx.regs [15]; \ } while (0) +#define MONO_ARCH_HAS_MONO_CONTEXT 1 + #elif (defined(__aarch64__) && !defined(MONO_CROSS_COMPILE)) || (defined(TARGET_ARM64)) #include @@ -546,7 +548,18 @@ typedef struct ucontext MonoContext; #endif +/* + * The naming is misleading, the SIGCTX argument should be the platform's context + * structure (ucontext_c on posix, CONTEXT on windows). + */ void mono_sigctx_to_monoctx (void *sigctx, MonoContext *mctx) MONO_INTERNAL; + +/* + * This will not completely initialize SIGCTX since MonoContext contains less + * information that the system context. The caller should obtain a SIGCTX from + * the system, and use this function to override the parts of it which are + * also in MonoContext. + */ void mono_monoctx_to_sigctx (MonoContext *mctx, void *sigctx) MONO_INTERNAL; #endif /* __MONO_MONO_CONTEXT_H__ */ diff --git a/mono/utils/mono-dl.c b/mono/utils/mono-dl.c index b59ab2d5aae..04e9165b7c0 100644 --- a/mono/utils/mono-dl.c +++ b/mono/utils/mono-dl.c @@ -124,7 +124,7 @@ w32_dlerror (void) wchar_t* buf = NULL; DWORD code = GetLastError (); - if (FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, + if (FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&buf, 0, NULL)) { ret = g_utf16_to_utf8 (buf, wcslen(buf), NULL, NULL, NULL); diff --git a/mono/utils/mono-error-internals.h b/mono/utils/mono-error-internals.h index 80672403089..ac2394fa41c 100644 --- a/mono/utils/mono-error-internals.h +++ b/mono/utils/mono-error-internals.h @@ -32,6 +32,9 @@ mono_error_set_error (MonoError *error, int error_code, const char *msg_format, void mono_error_set_assembly_load (MonoError *error, const char *assembly_name, const char *msg_format, ...) MONO_INTERNAL; +void +mono_error_set_assembly_load_simple (MonoError *error, const char *assembly_name, gboolean refection_only) MONO_INTERNAL; + void mono_error_set_type_load_class (MonoError *error, MonoClass *klass, const char *msg_format, ...) MONO_INTERNAL; @@ -68,6 +71,9 @@ mono_error_set_from_loader_error (MonoError *error) MONO_INTERNAL; MonoException* mono_error_prepare_exception (MonoError *error, MonoError *error_out) MONO_INTERNAL; +MonoException* +mono_error_convert_to_exception (MonoError *error) MONO_INTERNAL; + void mono_error_raise_exception (MonoError *error) MONO_INTERNAL; diff --git a/mono/utils/mono-error.c b/mono/utils/mono-error.c index a59de349f30..63d6fcc00f8 100644 --- a/mono/utils/mono-error.c +++ b/mono/utils/mono-error.c @@ -188,6 +188,16 @@ mono_error_set_assembly_load (MonoError *oerror, const char *assembly_name, cons set_error_message (); } + +void +mono_error_set_assembly_load_simple (MonoError *oerror, const char *assembly_name, gboolean refection_only) +{ + if (refection_only) + mono_error_set_assembly_load (oerror, assembly_name, "Cannot resolve dependency to assembly because it has not been preloaded. When using the ReflectionOnly APIs, dependent assemblies must be pre-loaded or loaded on demand through the ReflectionOnlyAssemblyResolve event."); + else + mono_error_set_assembly_load (oerror, assembly_name, "Could not load file or assembly or one of its dependencies."); +} + void mono_error_set_type_load_class (MonoError *oerror, MonoClass *klass, const char *msg_format, ...) { @@ -321,10 +331,7 @@ mono_error_set_from_loader_error (MonoError *oerror) break; case MONO_EXCEPTION_FILE_NOT_FOUND: - if (loader_error->ref_only) - mono_error_set_assembly_load (oerror, loader_error->assembly_name, "Cannot resolve dependency to assembly because it has not been preloaded. When using the ReflectionOnly APIs, dependent assemblies must be pre-loaded or loaded on demand through the ReflectionOnlyAssemblyResolve event."); - else - mono_error_set_assembly_load (oerror, loader_error->assembly_name, "Could not load file or assembly or one of its dependencies."); + mono_error_set_assembly_load_simple (oerror, loader_error->assembly_name, loader_error->ref_only); break; case MONO_EXCEPTION_METHOD_ACCESS: @@ -629,20 +636,18 @@ mono_error_prepare_exception (MonoError *oerror, MonoError *error_out) } /* -Raises the exception of @error. -Does nothing if @error has a success error code. -Aborts in case of a double fault. This happens when it can't recover from an error caused by trying -to construct the first exception object. -The error object @error is cleaned up. +Convert this MonoError to an exception if it's faulty or return NULL. +The error object is cleant after. */ -void -mono_error_raise_exception (MonoError *target_error) + +MonoException* +mono_error_convert_to_exception (MonoError *target_error) { MonoError error; MonoException *ex; if (mono_error_ok (target_error)) - return; + return NULL; ex = mono_error_prepare_exception (target_error, &error); if (!mono_error_ok (&error)) { @@ -654,6 +659,21 @@ mono_error_raise_exception (MonoError *target_error) mono_error_cleanup (&error); } mono_error_cleanup (target_error); + return ex; +} - mono_raise_exception (ex); + +/* +Raises the exception of @error. +Does nothing if @error has a success error code. +Aborts in case of a double fault. This happens when it can't recover from an error caused by trying +to construct the first exception object. +The error object @error is cleaned up. +*/ +void +mono_error_raise_exception (MonoError *target_error) +{ + MonoException *ex = mono_error_convert_to_exception (target_error); + if (ex) + mono_raise_exception (ex); } diff --git a/mono/utils/mono-mmap-internal.h b/mono/utils/mono-mmap-internal.h new file mode 100644 index 00000000000..1818e5c303d --- /dev/null +++ b/mono/utils/mono-mmap-internal.h @@ -0,0 +1,28 @@ +/* + * 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__ */ + diff --git a/mono/utils/mono-mmap.c b/mono/utils/mono-mmap.c index 60ef156b15a..6caf9628380 100644 --- a/mono/utils/mono-mmap.c +++ b/mono/utils/mono-mmap.c @@ -29,6 +29,7 @@ #endif #include "mono-mmap.h" +#include "mono-mmap-internal.h" #include "mono-proclib.h" #ifndef MAP_ANONYMOUS @@ -243,6 +244,12 @@ mono_shared_area_instances (void **array, int count) return 0; } +int +mono_pages_not_faulted (void *addr, size_t length) +{ + return -1; +} + #else #if defined(HAVE_MMAP) @@ -443,6 +450,30 @@ mono_mprotect (void *addr, size_t length, int flags) } #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 */ @@ -481,6 +512,13 @@ mono_mprotect (void *addr, size_t length, int flags) } 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) diff --git a/mono/utils/mono-poll.c b/mono/utils/mono-poll.c old mode 100644 new mode 100755 index 7326254c35b..5e5adfe2f00 --- a/mono/utils/mono-poll.c +++ b/mono/utils/mono-poll.c @@ -20,6 +20,11 @@ mono_poll (mono_pollfd *ufds, unsigned int nfds, int timeout) } #else +#ifdef HOST_WIN32 +/* For select */ +#include +#endif + int mono_poll (mono_pollfd *ufds, unsigned int nfds, int timeout) { diff --git a/mono/utils/mono-proclib.c b/mono/utils/mono-proclib.c index 3f032f9d22c..1303b5b4d44 100644 --- a/mono/utils/mono-proclib.c +++ b/mono/utils/mono-proclib.c @@ -105,6 +105,10 @@ mono_process_list (int *size) 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; diff --git a/mono/utils/mono-sigcontext.h b/mono/utils/mono-sigcontext.h index 05817a842f3..f61f3dd3ee3 100644 --- a/mono/utils/mono-sigcontext.h +++ b/mono/utils/mono-sigcontext.h @@ -4,6 +4,9 @@ #include #if defined(PLATFORM_ANDROID) #include +#ifdef HAVE_UCONTEXT_H +#include +#endif #endif #ifdef HAVE_UNISTD_H @@ -16,9 +19,6 @@ #if defined(TARGET_X86) -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__DragonFly__) -#include -#endif #if defined(__APPLE__) #include #endif @@ -87,7 +87,7 @@ #define UCONTEXT_REG_EIP(ctx) (((ucontext_t*)(ctx))->uc_mcontext.gregs [EIP]) #else -#if defined(TARGET_ANDROID) +#if defined(PLATFORM_ANDROID) && !defined(HAVE_UCONTEXT_H) /* No ucontext.h as of NDK v6b */ typedef int greg_t; #define NGREG 19 diff --git a/mono/utils/mono-signal-handler.h b/mono/utils/mono-signal-handler.h index 3a01146d5e1..fbe798eeb0e 100644 --- a/mono/utils/mono-signal-handler.h +++ b/mono/utils/mono-signal-handler.h @@ -12,18 +12,48 @@ #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 diff --git a/mono/utils/mono-threads-freebsd.c b/mono/utils/mono-threads-freebsd.c index 7cbbca14b57..cdee0ab4061 100644 --- a/mono/utils/mono-threads-freebsd.c +++ b/mono/utils/mono-threads-freebsd.c @@ -2,6 +2,7 @@ #if defined(__FreeBSD__) +#include #include #include diff --git a/mono/utils/mono-threads-mach.c b/mono/utils/mono-threads-mach.c index f4ad2637e57..6270c57f1d6 100644 --- a/mono/utils/mono-threads-mach.c +++ b/mono/utils/mono-threads-mach.c @@ -11,18 +11,19 @@ #if defined(__MACH__) +/* For pthread_main_np, pthread_get_stackaddr_np and pthread_get_stacksize_np */ +#define _DARWIN_C_SOURCE 1 + #include #include #include #include #include +#include #include #include #include -#include -#include - void mono_threads_init_platform (void) { @@ -47,7 +48,7 @@ mono_threads_core_needs_abort_syscall (void) } gboolean -mono_threads_core_suspend (MonoThreadInfo *info) +mono_threads_core_suspend (MonoThreadInfo *info, gboolean interrupt_kernel) { kern_return_t ret; gboolean res; @@ -148,4 +149,24 @@ mono_threads_core_set_name (MonoNativeThreadId tid, const char *name) /* pthread_setnmae_np() on Mac is not documented and doesn't receive thread id. */ } +void +mono_threads_core_get_stack_bounds (guint8 **staddr, size_t *stsize) +{ + *staddr = (guint8*)pthread_get_stackaddr_np (pthread_self()); + *stsize = pthread_get_stacksize_np (pthread_self()); + +#ifdef TARGET_OSX + /* + * Mavericks reports stack sizes as 512kb: + * http://permalink.gmane.org/gmane.comp.java.openjdk.hotspot.devel/11590 + * https://bugs.openjdk.java.net/browse/JDK-8020753 + */ + if (pthread_main_np () && *stsize == 512 * 1024) + *stsize = 2048 * mono_pagesize (); +#endif + + /* staddr points to the start of the stack, not the end */ + *staddr -= *stsize; +} + #endif diff --git a/mono/utils/mono-threads-posix.c b/mono/utils/mono-threads-posix.c index 8a21c553054..5fb6fc51e15 100644 --- a/mono/utils/mono-threads-posix.c +++ b/mono/utils/mono-threads-posix.c @@ -9,17 +9,6 @@ #include -#if defined(TARGET_OSX) -/* For pthread_main_np () */ -#define _DARWIN_C_SOURCE 1 -#include -#endif - -#if defined(__OpenBSD__) || defined(__FreeBSD__) -#include -#include -#endif - #include #include #include @@ -34,11 +23,6 @@ extern int tkill (pid_t tid, int signal); #endif -#if defined(PLATFORM_MACOSX) && defined(HAVE_PTHREAD_GET_STACKADDR_NP) -void *pthread_get_stackaddr_np(pthread_t); -size_t pthread_get_stacksize_np(pthread_t); -#endif - #if defined(_POSIX_VERSION) || defined(__native_client__) #include #include @@ -55,6 +39,10 @@ typedef struct { HANDLE handle; } StartInfo; +#ifdef PLATFORM_ANDROID +static int no_interrupt_signo; +#endif + static void* inner_start_thread (void *arg) { @@ -185,113 +173,6 @@ mono_threads_core_resume_created (MonoThreadInfo *info, MonoNativeThreadId tid) MONO_SEM_POST (&info->create_suspended_sem); } -void -mono_threads_core_get_stack_bounds (guint8 **staddr, size_t *stsize) -{ -#if defined(HAVE_PTHREAD_GET_STACKSIZE_NP) && defined(HAVE_PTHREAD_GET_STACKADDR_NP) - /* Mac OS X */ - *staddr = (guint8*)pthread_get_stackaddr_np (pthread_self()); - *stsize = pthread_get_stacksize_np (pthread_self()); - -#ifdef TARGET_OSX - /* - * Mavericks reports stack sizes as 512kb: - * http://permalink.gmane.org/gmane.comp.java.openjdk.hotspot.devel/11590 - * https://bugs.openjdk.java.net/browse/JDK-8020753 - */ - if (pthread_main_np () && *stsize == 512 * 1024) - *stsize = 2048 * mono_pagesize (); -#endif - - /* staddr points to the start of the stack, not the end */ - *staddr -= *stsize; - - /* When running under emacs, sometimes staddr is not aligned to a page size */ - *staddr = (guint8*)((gssize)*staddr & ~(mono_pagesize() - 1)); - return; - -#elif (defined(HAVE_PTHREAD_GETATTR_NP) || defined(HAVE_PTHREAD_ATTR_GET_NP)) && defined(HAVE_PTHREAD_ATTR_GETSTACK) - /* Linux, BSD */ - - pthread_attr_t attr; - guint8 *current = (guint8*)&attr; - - *staddr = NULL; - *stsize = (size_t)-1; - - pthread_attr_init (&attr); - -#if defined(HAVE_PTHREAD_GETATTR_NP) - /* Linux */ - pthread_getattr_np (pthread_self(), &attr); - -#elif defined(HAVE_PTHREAD_ATTR_GET_NP) - /* BSD */ - pthread_attr_get_np (pthread_self(), &attr); - -#else -#error Cannot determine which API is needed to retrieve pthread attributes. -#endif - - pthread_attr_getstack (&attr, (void**)staddr, stsize); - pthread_attr_destroy (&attr); - - if (*staddr) - g_assert ((current > *staddr) && (current < *staddr + *stsize)); - - /* When running under emacs, sometimes staddr is not aligned to a page size */ - *staddr = (guint8*)((gssize)*staddr & ~(mono_pagesize () - 1)); - return; - -#elif defined(__OpenBSD__) - /* OpenBSD */ - /* TODO : Determine if this code is actually still needed. It may already be covered by the case above. */ - - pthread_attr_t attr; - guint8 *current = (guint8*)&attr; - - *staddr = NULL; - *stsize = (size_t)-1; - - pthread_attr_init (&attr); - - stack_t ss; - int rslt; - - rslt = pthread_stackseg_np(pthread_self(), &ss); - g_assert (rslt == 0); - - *staddr = (guint8*)((size_t)ss.ss_sp - ss.ss_size); - *stsize = ss.ss_size; - - pthread_attr_destroy (&attr); - - if (*staddr) - g_assert ((current > *staddr) && (current < *staddr + *stsize)); - - /* When running under emacs, sometimes staddr is not aligned to a page size */ - *staddr = (guint8*)((gssize)*staddr & ~(mono_pagesize () - 1)); - return; - -#elif defined(sun) || defined(__native_client__) - /* Solaris/Illumos, NaCl */ - pthread_attr_t attr; - pthread_attr_init (&attr); - pthread_attr_getstacksize (&attr, &stsize); - pthread_attr_destroy (&attr); - *staddr = NULL; - return; - -#else - /* FIXME: It'd be better to use the 'error' preprocessor macro here so we know - at compile-time if the target platform isn't supported. */ -#warning "Unable to determine how to retrieve a thread's stack-bounds for this platform in 'mono_thread_get_stack_bounds()'." - *staddr = NULL; - *stsize = 0; - return; -#endif -} - gboolean mono_threads_core_yield (void) { @@ -359,6 +240,50 @@ mono_threads_core_open_thread_handle (HANDLE handle, MonoNativeThreadId tid) return handle; } +gpointer +mono_threads_core_prepare_interrupt (HANDLE thread_handle) +{ + return wapi_prepare_interrupt_thread (thread_handle); +} + +void +mono_threads_core_finish_interrupt (gpointer wait_handle) +{ + wapi_finish_interrupt_thread (wait_handle); +} + +void +mono_threads_core_self_interrupt (void) +{ + wapi_self_interrupt (); +} + +void +mono_threads_core_clear_interruption (void) +{ + wapi_clear_interruption (); +} + +int +mono_threads_pthread_kill (MonoThreadInfo *info, int signum) +{ +#if defined (PLATFORM_ANDROID) + int result, old_errno = errno; + result = tkill (info->native_handle, signum); + if (result < 0) { + result = errno; + errno = old_errno; + } + return result; +#elif defined(__native_client__) + /* Workaround pthread_kill abort() in NaCl glibc. */ + return 0; +#else + return pthread_kill (mono_thread_info_get_tid (info), signum); +#endif + +} + #if !defined (__MACH__) #if !defined(__native_client__) @@ -404,7 +329,7 @@ suspend_signal_handler (int _dummy, siginfo_t *info, void *context) #endif static void -mono_posix_add_signal_handler (int signo, gpointer handler) +mono_posix_add_signal_handler (int signo, gpointer handler, int flags) { #if !defined(__native_client__) /*FIXME, move the code from mini to utils and do the right thing!*/ @@ -414,7 +339,7 @@ mono_posix_add_signal_handler (int signo, gpointer handler) sa.sa_sigaction = handler; sigemptyset (&sa.sa_mask); - sa.sa_flags = SA_SIGINFO; + sa.sa_flags = SA_SIGINFO | flags; ret = sigaction (signo, &sa, &previous_sa); g_assert (ret != -1); @@ -425,39 +350,36 @@ void mono_threads_init_platform (void) { #if !defined(__native_client__) + int abort_signo; + /* FIXME we should use all macros from mini to make this more portable FIXME it would be very sweet if sgen could end up using this too. */ - if (mono_thread_info_new_interrupt_enabled ()) - mono_posix_add_signal_handler (mono_thread_get_abort_signal (), suspend_signal_handler); + if (!mono_thread_info_new_interrupt_enabled ()) + return; + abort_signo = mono_thread_get_abort_signal (); + mono_posix_add_signal_handler (abort_signo, suspend_signal_handler, 0); + +#ifdef PLATFORM_ANDROID + /* + * Lots of android native code can't handle the EINTR caused by + * the normal abort signal, so use a different signal for the + * no interruption case, which is used by sdb. + * FIXME: Use this on all platforms. + * SIGUSR1 is used by dalvik/art. + */ + no_interrupt_signo = SIGUSR2; + g_assert (abort_signo != no_interrupt_signo); + mono_posix_add_signal_handler (abort_signo, suspend_signal_handler, SA_RESTART); +#endif #endif } -/*nothing to be done here since suspend always abort syscalls due using signals*/ void mono_threads_core_interrupt (MonoThreadInfo *info) { -} - -int -mono_threads_pthread_kill (MonoThreadInfo *info, int signum) -{ -#if defined (PLATFORM_ANDROID) - int result, old_errno = errno; - result = tkill (info->native_handle, signum); - if (result < 0) { - result = errno; - errno = old_errno; - } - return result; -#elif defined(__native_client__) - /* Workaround pthread_kill abort() in NaCl glibc. */ - return 0; -#else - return pthread_kill (mono_thread_info_get_tid (info), signum); -#endif - + /* Handled in mono_threads_core_suspend () */ } void @@ -478,10 +400,17 @@ mono_threads_core_needs_abort_syscall (void) } gboolean -mono_threads_core_suspend (MonoThreadInfo *info) +mono_threads_core_suspend (MonoThreadInfo *info, gboolean interrupt_kernel) { /*FIXME, check return value*/ - mono_threads_pthread_kill (info, mono_thread_get_abort_signal ()); +#ifdef PLATFORM_ANDROID + if (interrupt_kernel) + mono_threads_pthread_kill (info, no_interrupt_signo); + else + mono_threads_pthread_kill (info, mono_thread_get_abort_signal ()); +#else + mono_threads_pthread_kill (info, mono_thread_get_abort_signal ()); +#endif while (MONO_SEM_WAIT (&info->begin_suspend_semaphore) != 0) { /* g_assert (errno == EINTR); */ } @@ -505,7 +434,7 @@ mono_threads_platform_register (MonoThreadInfo *info) MONO_SEM_INIT (&info->begin_suspend_semaphore, 0); #if defined (PLATFORM_ANDROID) - info->native_handle = (gpointer) gettid (); + info->native_handle = gettid (); #endif } diff --git a/mono/utils/mono-threads-windows.c b/mono/utils/mono-threads-windows.c old mode 100644 new mode 100755 index 2ab2e6596e5..02bd26e0c79 --- a/mono/utils/mono-threads-windows.c +++ b/mono/utils/mono-threads-windows.c @@ -12,6 +12,7 @@ #if defined(HOST_WIN32) #include +#include #include @@ -20,10 +21,23 @@ mono_threads_init_platform (void) { } +static void CALLBACK +interrupt_apc (ULONG_PTR param) +{ +} + void mono_threads_core_interrupt (MonoThreadInfo *info) { - g_assert (0); + DWORD id = mono_thread_info_get_tid (info); + HANDLE handle; + + handle = OpenThread (THREAD_ALL_ACCESS, FALSE, id); + g_assert (handle); + + QueueUserAPC ((PAPCFUNC)interrupt_apc, handle, (ULONG_PTR)NULL); + + CloseHandle (handle); } void @@ -44,15 +58,75 @@ mono_threads_core_self_suspend (MonoThreadInfo *info) } gboolean -mono_threads_core_suspend (MonoThreadInfo *info) +mono_threads_core_suspend (MonoThreadInfo *info, gboolean interrupt_kernel) { - g_assert_not_reached (); + DWORD id = mono_thread_info_get_tid (info); + HANDLE handle; + DWORD result; + gboolean res; + + g_assert (id != GetCurrentThreadId ()); + + handle = OpenThread (THREAD_ALL_ACCESS, FALSE, id); + g_assert (handle); + + result = SuspendThread (handle); + if (result == (DWORD)-1) { + fprintf (stderr, "could not suspend thread %x (handle %p): %d\n", id, handle, GetLastError ()); fflush (stderr); + CloseHandle (handle); + return FALSE; + } + + CloseHandle (handle); + + res = mono_threads_get_runtime_callbacks ()->thread_state_init_from_handle (&info->suspend_state, info); + g_assert (res); + + return TRUE; } gboolean mono_threads_core_resume (MonoThreadInfo *info) { - g_assert_not_reached (); + DWORD id = mono_thread_info_get_tid (info); + HANDLE handle; + DWORD result; + + handle = OpenThread (THREAD_ALL_ACCESS, FALSE, id); + g_assert (handle); + + if (info->async_target) { + MonoContext ctx; + CONTEXT context; + gboolean res; + + ctx = info->suspend_state.ctx; + mono_threads_get_runtime_callbacks ()->setup_async_callback (&ctx, info->async_target, info->user_data); + info->async_target = info->user_data = NULL; + + context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL; + + if (!GetThreadContext (handle, &context)) { + CloseHandle (handle); + return FALSE; + } + + g_assert (context.ContextFlags & CONTEXT_INTEGER); + g_assert (context.ContextFlags & CONTEXT_CONTROL); + + mono_monoctx_to_sigctx (&ctx, &context); + + context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL; + res = SetThreadContext (handle, &context); + g_assert (res); + } + + result = ResumeThread (handle); + g_assert (result != (DWORD)-1); + + CloseHandle (handle); + + return result != (DWORD)-1; } void @@ -175,8 +249,7 @@ mono_threads_core_resume_created (MonoThreadInfo *info, MonoNativeThreadId tid) } #if HAVE_DECL___READFSDWORD==0 -static __inline__ __attribute__((always_inline)) -unsigned long long +static MONO_ALWAYS_INLINE unsigned long long __readfsdword (unsigned long offset) { unsigned long value; @@ -263,9 +336,58 @@ mono_threads_core_open_thread_handle (HANDLE handle, MonoNativeThreadId tid) return OpenThread (THREAD_ALL_ACCESS, TRUE, tid); } +#if !defined(__GNUC__) +const DWORD MS_VC_EXCEPTION=0x406D1388; +#pragma pack(push,8) +typedef struct tagTHREADNAME_INFO +{ + DWORD dwType; // Must be 0x1000. + LPCSTR szName; // Pointer to name (in user addr space). + DWORD dwThreadID; // Thread ID (-1=caller thread). + DWORD dwFlags; // Reserved for future use, must be zero. +} THREADNAME_INFO; +#pragma pack(pop) +#endif + void mono_threads_core_set_name (MonoNativeThreadId tid, const char *name) { +#if !defined(__GNUC__) + /* http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx */ + THREADNAME_INFO info; + info.dwType = 0x1000; + info.szName = name; + info.dwThreadID = tid; + info.dwFlags = 0; + + __try { + RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info ); + } + __except(EXCEPTION_EXECUTE_HANDLER) { + } +#endif +} + + +gpointer +mono_threads_core_prepare_interrupt (HANDLE thread_handle) +{ + return NULL; +} + +void +mono_threads_core_finish_interrupt (gpointer wait_handle) +{ +} + +void +mono_threads_core_self_interrupt (void) +{ +} + +void +mono_threads_core_clear_interruption (void) +{ } #endif diff --git a/mono/utils/mono-threads.c b/mono/utils/mono-threads.c index 195a919c3e7..dd500372404 100644 --- a/mono/utils/mono-threads.c +++ b/mono/utils/mono-threads.c @@ -14,6 +14,7 @@ #include #include #include +#include #include @@ -143,7 +144,7 @@ register_thread (MonoThreadInfo *info, gpointer baseptr) 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; } @@ -425,7 +426,7 @@ mono_thread_info_suspend_sync (MonoNativeThreadId tid, gboolean interrupt_kernel return info; } - if (!mono_threads_core_suspend (info)) { + if (!mono_threads_core_suspend (info, interrupt_kernel)) { MONO_SEM_POST (&info->suspend_semaphore); mono_hazard_pointer_clear (hp, 1); *error_condition = "Could not suspend thread"; @@ -604,7 +605,7 @@ mono_thread_info_safe_suspend_sync (MonoNativeThreadId id, gboolean interrupt_ke 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; } @@ -613,7 +614,7 @@ mono_thread_info_safe_suspend_sync (MonoNativeThreadId id, gboolean interrupt_ke 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; @@ -730,11 +731,13 @@ mono_thread_info_new_interrupt_enabled (void) #if defined (HAVE_BOEHM_GC) && !defined (USE_INCLUDED_LIBGC) return FALSE; #endif - /*port not done*/ #if defined(HOST_WIN32) - return FALSE; + return !disable_new_interrupt; +#endif +#if defined (__i386__) || defined(__x86_64__) + return !disable_new_interrupt; #endif -#if defined (__i386__) +#if defined(__arm__) return !disable_new_interrupt; #endif return FALSE; @@ -787,7 +790,16 @@ mono_threads_create_thread (LPTHREAD_START_ROUTINE start, gpointer arg, guint32 void mono_thread_info_get_stack_bounds (guint8 **staddr, size_t *stsize) { + guint8 *current = (guint8 *)&stsize; mono_threads_core_get_stack_bounds (staddr, stsize); + if (!*staddr) + return; + + /* Sanity check the result */ + g_assert ((current > *staddr) && (current < *staddr + *stsize)); + + /* When running under emacs, sometimes staddr is not aligned to a page size */ + *staddr = (guint8*)((gssize)*staddr & ~(mono_pagesize () - 1)); } gboolean @@ -842,7 +854,7 @@ mono_thread_info_open_handle (void) } /* - * mono_thread_info_open_handle: + * mono_threads_open_thread_handle: * * Return a io-layer/win32 handle for the thread identified by HANDLE/TID. * The handle need to be closed by calling CloseHandle () when it is no @@ -859,3 +871,41 @@ mono_thread_info_set_name (MonoNativeThreadId tid, const char *name) { mono_threads_core_set_name (tid, name); } + +/* + * mono_thread_info_prepare_interrupt: + * + * See wapi_prepare_interrupt (). + */ +gpointer +mono_thread_info_prepare_interrupt (HANDLE thread_handle) +{ + return mono_threads_core_prepare_interrupt (thread_handle); +} + +void +mono_thread_info_finish_interrupt (gpointer wait_handle) +{ + mono_threads_core_finish_interrupt (wait_handle); +} + +void +mono_thread_info_interrupt (HANDLE thread_handle) +{ + gpointer wait_handle; + + wait_handle = mono_thread_info_prepare_interrupt (thread_handle); + mono_thread_info_finish_interrupt (wait_handle); +} + +void +mono_thread_info_self_interrupt (void) +{ + mono_threads_core_self_interrupt (); +} + +void +mono_thread_info_clear_interruption (void) +{ + mono_threads_core_clear_interruption (); +} diff --git a/mono/utils/mono-threads.h b/mono/utils/mono-threads.h index d97543313c9..f09a957e84f 100644 --- a/mono/utils/mono-threads.h +++ b/mono/utils/mono-threads.h @@ -302,6 +302,21 @@ mono_thread_info_exit (void); HANDLE mono_thread_info_open_handle (void); +gpointer +mono_thread_info_prepare_interrupt (HANDLE thread_handle); + +void +mono_thread_info_finish_interrupt (gpointer wait_handle); + +void +mono_thread_info_interrupt (HANDLE thread_handle); + +void +mono_thread_info_self_interrupt (void); + +void +mono_thread_info_clear_interruption (void); + HANDLE mono_threads_create_thread (LPTHREAD_START_ROUTINE start, gpointer arg, guint32 stack_size, guint32 creation_flags, MonoNativeThreadId *out_tid); @@ -313,17 +328,15 @@ mono_threads_open_thread_handle (HANDLE handle, MonoNativeThreadId tid) MONO_INT #if !defined(HOST_WIN32) -#if !defined(__MACH__) /*Use this instead of pthread_kill */ int mono_threads_pthread_kill (THREAD_INFO_TYPE *info, int signum) MONO_INTERNAL; -#endif #endif /* !defined(HOST_WIN32) */ /* Plartform specific functions DON'T use them */ void mono_threads_init_platform (void) MONO_INTERNAL; //ok -gboolean mono_threads_core_suspend (THREAD_INFO_TYPE *info) MONO_INTERNAL; +gboolean mono_threads_core_suspend (THREAD_INFO_TYPE *info, gboolean interrupt_kernel) MONO_INTERNAL; gboolean mono_threads_core_resume (THREAD_INFO_TYPE *info) MONO_INTERNAL; void mono_threads_platform_register (THREAD_INFO_TYPE *info) MONO_INTERNAL; //ok void mono_threads_platform_free (THREAD_INFO_TYPE *info) MONO_INTERNAL; @@ -339,6 +352,10 @@ void mono_threads_core_unregister (THREAD_INFO_TYPE *info) MONO_INTERNAL; HANDLE mono_threads_core_open_handle (void) MONO_INTERNAL; HANDLE mono_threads_core_open_thread_handle (HANDLE handle, MonoNativeThreadId tid) MONO_INTERNAL; void mono_threads_core_set_name (MonoNativeThreadId tid, const char *name) MONO_INTERNAL; +gpointer mono_threads_core_prepare_interrupt (HANDLE thread_handle); +void mono_threads_core_finish_interrupt (gpointer wait_handle); +void mono_threads_core_self_interrupt (void); +void mono_threads_core_clear_interruption (void); MonoNativeThreadId mono_native_thread_id_get (void) MONO_INTERNAL; diff --git a/mono/utils/sha1.c b/mono/utils/sha1.c index c33043c91db..7dec326b2ec 100644 --- a/mono/utils/sha1.c +++ b/mono/utils/sha1.c @@ -44,18 +44,18 @@ #define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); typedef union { - u_int8_t c[64]; - u_int32_t l[16]; + guint8 c[64]; + guint32 l[16]; } CHAR64LONG16; /* * Hash a single 512-bit block. This is the core of the algorithm. */ void -SHA1Transform(u_int32_t state[5], const u_int8_t buffer[SHA1_BLOCK_LENGTH]) +SHA1Transform(guint32 state[5], const guint8 buffer[SHA1_BLOCK_LENGTH]) { - u_int32_t a, b, c, d, e; - u_int8_t workspace[SHA1_BLOCK_LENGTH]; + guint32 a, b, c, d, e; + guint8 workspace[SHA1_BLOCK_LENGTH]; CHAR64LONG16 *block = (CHAR64LONG16 *)workspace; (void)memcpy(block, buffer, SHA1_BLOCK_LENGTH); @@ -122,7 +122,7 @@ SHA1Init(SHA1_CTX *context) * Run your data through this. */ void -SHA1Update(SHA1_CTX *context, const u_int8_t *data, size_t len) +SHA1Update(SHA1_CTX *context, const guint8 *data, size_t len) { size_t i, j; @@ -132,7 +132,7 @@ SHA1Update(SHA1_CTX *context, const u_int8_t *data, size_t len) (void)memcpy(&context->buffer[j], data, (i = 64-j)); SHA1Transform(context->state, context->buffer); for ( ; i + 63 < len; i += 64) - SHA1Transform(context->state, (u_int8_t *)&data[i]); + SHA1Transform(context->state, (guint8 *)&data[i]); j = 0; } else { i = 0; @@ -147,28 +147,28 @@ SHA1Update(SHA1_CTX *context, const u_int8_t *data, size_t len) void SHA1Pad(SHA1_CTX *context) { - u_int8_t finalcount[8]; - u_int i; + guint8 finalcount[8]; + guint i; for (i = 0; i < 8; i++) { - finalcount[i] = (u_int8_t)((context->count >> + finalcount[i] = (guint8)((context->count >> ((7 - (i & 7)) * 8)) & 255); /* Endian independent */ } - SHA1Update(context, (u_int8_t *)"\200", 1); + SHA1Update(context, (guint8 *)"\200", 1); while ((context->count & 504) != 448) - SHA1Update(context, (u_int8_t *)"\0", 1); + SHA1Update(context, (guint8 *)"\0", 1); SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ } void -SHA1Final(u_int8_t digest[SHA1_DIGEST_LENGTH], SHA1_CTX *context) +SHA1Final(guint8 digest[SHA1_DIGEST_LENGTH], SHA1_CTX *context) { - u_int i; + guint i; SHA1Pad(context); if (digest) { for (i = 0; i < SHA1_DIGEST_LENGTH; i++) { - digest[i] = (u_int8_t) + digest[i] = (guint8) ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); } memset(context, 0, sizeof(*context)); diff --git a/mono/utils/sha1.h b/mono/utils/sha1.h index b0aff8111c3..588518266ca 100644 --- a/mono/utils/sha1.h +++ b/mono/utils/sha1.h @@ -9,27 +9,29 @@ #ifndef _SHA1_H #define _SHA1_H +#include + #define SHA1_BLOCK_LENGTH 64 #define SHA1_DIGEST_LENGTH 20 #define SHA1_DIGEST_STRING_LENGTH (SHA1_DIGEST_LENGTH * 2 + 1) typedef struct { - u_int32_t state[5]; - u_int64_t count; - u_int8_t buffer[SHA1_BLOCK_LENGTH]; + guint32 state[5]; + guint64 count; + guint8 buffer[SHA1_BLOCK_LENGTH]; } SHA1_CTX; -__BEGIN_DECLS +G_BEGIN_DECLS void SHA1Init(SHA1_CTX *); void SHA1Pad(SHA1_CTX *); -void SHA1Transform(u_int32_t [5], const u_int8_t [SHA1_BLOCK_LENGTH]); -void SHA1Update(SHA1_CTX *, const u_int8_t *, size_t); -void SHA1Final(u_int8_t [SHA1_DIGEST_LENGTH], SHA1_CTX *); +void SHA1Transform(guint32 [5], const guint8 [SHA1_BLOCK_LENGTH]); +void SHA1Update(SHA1_CTX *, const guint8 *, size_t); +void SHA1Final(guint8 [SHA1_DIGEST_LENGTH], SHA1_CTX *); char *SHA1End(SHA1_CTX *, char *); char *SHA1File(const char *, char *); char *SHA1FileChunk(const char *, char *, off_t, off_t); -char *SHA1Data(const u_int8_t *, size_t, char *); -__END_DECLS +char *SHA1Data(const guint8 *, size_t, char *); +G_END_DECLS #define HTONDIGEST(x) do { \ x[0] = htonl(x[0]); \ diff --git a/msvc/genmdesc.vcxproj b/msvc/genmdesc.vcxproj index d3c7511cd49..34efcacfd5c 100644 --- a/msvc/genmdesc.vcxproj +++ b/msvc/genmdesc.vcxproj @@ -18,6 +18,7 @@ x64 + {B7098DFA-31E6-4006-8A15-1C9A4E925149} genmdesc @@ -131,7 +132,7 @@ Disabled ..\libgc\include;..\;..\mono\;..\eglib\src;%(AdditionalIncludeDirectories) - _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) + _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) true EnableFastChecks MultiThreadedDebugDLL @@ -218,7 +219,7 @@ MinSpace OnlyExplicitInline ..\libgc\include;..\;..\mono\;..\eglib\src;%(AdditionalIncludeDirectories) - 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) + 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) true MultiThreadedDLL true @@ -338,4 +339,4 @@ - \ No newline at end of file + diff --git a/msvc/libgc.vcxproj b/msvc/libgc.vcxproj index 08bcfa0ba8c..db5bfab6d46 100644 --- a/msvc/libgc.vcxproj +++ b/msvc/libgc.vcxproj @@ -75,7 +75,7 @@ Disabled ..\libgc\include;%(AdditionalIncludeDirectories) - _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) + _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) true EnableFastChecks MultiThreadedDebugDLL @@ -95,7 +95,7 @@ MinSpace ..\libgc\include;%(AdditionalIncludeDirectories) - 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) + 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) MultiThreadedDLL true @@ -115,7 +115,7 @@ Disabled ..\libgc\include;%(AdditionalIncludeDirectories) - _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 + _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 true EnableFastChecks MultiThreadedDebugDLL @@ -138,7 +138,7 @@ MinSpace ..\libgc\include;%(AdditionalIncludeDirectories) - 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) + 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) MultiThreadedDLL true diff --git a/msvc/libmonoruntime.vcxproj b/msvc/libmonoruntime.vcxproj index 3635bdae2d5..c65a603ff9f 100644 --- a/msvc/libmonoruntime.vcxproj +++ b/msvc/libmonoruntime.vcxproj @@ -57,6 +57,7 @@ + @@ -98,9 +99,6 @@ - - - @@ -466,4 +464,4 @@ - \ No newline at end of file + diff --git a/msvc/libtest.vcxproj b/msvc/libtest.vcxproj index 0fa69f3a15d..8e35a6e7659 100644 --- a/msvc/libtest.vcxproj +++ b/msvc/libtest.vcxproj @@ -18,6 +18,7 @@ x64 + {5A435710-E6D2-4DD4-9B3F-A7239A32C6F4} libtest @@ -199,4 +200,4 @@ - \ No newline at end of file + diff --git a/msvc/mono.def b/msvc/mono.def index 61d1779c336..72c3c4c0d7e 100644 --- a/msvc/mono.def +++ b/msvc/mono.def @@ -537,7 +537,6 @@ mono_metadata_guid_heap mono_metadata_implmap_from_method mono_metadata_init mono_metadata_interfaces_from_typedef -mono_metadata_load_generic_param_constraints mono_metadata_load_generic_params mono_metadata_locate mono_metadata_locate_token diff --git a/msvc/mono.props b/msvc/mono.props index 7fe3206e248..ffec2840f23 100644 --- a/msvc/mono.props +++ b/msvc/mono.props @@ -1,4 +1,4 @@ - + $(MSBuildProjectDirectory)\.. @@ -9,10 +9,11 @@ - __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) + __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_ + 4273;4005 Mswsock.lib;ws2_32.lib;ole32.lib;oleaut32.lib;psapi.lib;version.lib;advapi32.lib;winmm.lib;kernel32.lib;$(AdditionalDependencies) - \ No newline at end of file + diff --git a/msvc/profiler-logging.vcxproj b/msvc/profiler-logging.vcxproj index 2d28de55104..b4576542797 100644 --- a/msvc/profiler-logging.vcxproj +++ b/msvc/profiler-logging.vcxproj @@ -118,7 +118,7 @@ Disabled ..\libgc\include;..\;..\mono\;..\mono\jit;..\mono\eglib\src;..\..\mono\eglib\src;%(AdditionalIncludeDirectories) - 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) + 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) true EnableFastChecks MultiThreadedDebugDLL @@ -140,7 +140,7 @@ Disabled ..\libgc\include;..\;..\mono\;..\mono\jit;..\mono\eglib\src;..\..\mono\eglib\src;%(AdditionalIncludeDirectories) - 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) + 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) EnableFastChecks MultiThreadedDebugDLL diff --git a/runtime/Makefile.am b/runtime/Makefile.am index 2d9c2886dbc..ca34a6f396f 100644 --- a/runtime/Makefile.am +++ b/runtime/Makefile.am @@ -168,7 +168,7 @@ CLEANFILES = etc/mono/config # depend on $(symlinks) to ensure 'etc/mono' directory exists etc/mono/config: ../data/config Makefile $(symlinks) d=`cd ../support && pwd`; \ - sed 's,target="$(prefix)/lib/libMonoPosixHelper$(libsuffix)",target="'$$d'/libMonoPosixHelper.la",' ../data/config > $@t + sed 's,target="$(prefix)/$(reloc_libdir)/libMonoPosixHelper$(libsuffix)",target="'$$d'/libMonoPosixHelper.la",' ../data/config > $@t if test -z "$(libgdiplus_loc)"; then :; else \ sed 's,target="$(libgdiplus_install_loc)",target="$(libgdiplus_loc)",' $@t > $@tt; \ mv -f $@tt $@t; fi diff --git a/scripts/.gitignore b/scripts/.gitignore index 09042162780..ff0b717d53a 100644 --- a/scripts/.gitignore +++ b/scripts/.gitignore @@ -3,6 +3,7 @@ /al1 /al2 /caspol +/cert-sync /cert2spc /certmgr /cccheck diff --git a/scripts/Makefile.am b/scripts/Makefile.am index edaf17c7671..64f6d5cf6ae 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -77,6 +77,7 @@ scripts_4_0 = \ prj2make$(SCRIPT_SUFFIX) \ soapsuds$(SCRIPT_SUFFIX) \ caspol$(SCRIPT_SUFFIX) \ + cert-sync$(SCRIPT_SUFFIX) \ cert2spc$(SCRIPT_SUFFIX) \ certmgr$(SCRIPT_SUFFIX) \ chktrust$(SCRIPT_SUFFIX) \ @@ -166,11 +167,7 @@ EXTRA_DIST = \ 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 diff --git a/tools/locale-builder/Driver.cs b/tools/locale-builder/Driver.cs index 1a44d5eb7e1..f42f5cf90b4 100644 --- a/tools/locale-builder/Driver.cs +++ b/tools/locale-builder/Driver.cs @@ -1073,10 +1073,14 @@ Cannot really be used it's too different to .NET and most app rely on it // Apply global rule first el = node.SelectSingleNode ("dayPeriods/dayPeriodContext/dayPeriodWidth[@type='wide']/dayPeriod[@type='am']"); + // Manual edits for exact .net compatiblity switch (ci.Name) { case "en-AU": df.AMDesignator = "AM"; break; + case "en-NZ": + df.AMDesignator = "a.m."; + break; default: if (el != null) df.AMDesignator = el.InnerText; @@ -1092,6 +1096,9 @@ Cannot really be used it's too different to .NET and most app rely on it case "en-AU": df.PMDesignator = "PM"; break; + case "en-NZ": + df.PMDesignator = "p.m."; + break; default: if (el != null) df.PMDesignator = el.InnerText; diff --git a/winconfig.h b/winconfig.h index 0c690d3a35c..b6d74e1cb41 100644 --- a/winconfig.h +++ b/winconfig.h @@ -13,11 +13,7 @@ #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 */ /* @@ -198,9 +194,7 @@ /* #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 */